Created
December 23, 2014 05:03
-
-
Save yesnik/60389cbc330352139b29 to your computer and use it in GitHub Desktop.
Задание по Ruby 1 (ответ)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'time' | |
module Converter | |
extend Enumerable | |
@@methods = {} | |
def new(*args, &block) | |
initialize(*args, &block) | |
end | |
def initialize(*args, &block) | |
@arr = args[0] | |
convert | |
end | |
def attrb(attribute, method=nil, &block) | |
method = block if block_given? | |
@@methods[attribute] = method | |
end | |
def convert | |
@arr.map do |hash| | |
convert_hash(hash) | |
end | |
@arr | |
end | |
def convert_hash(hash) | |
hash = hash.each do |k, v| | |
new_value = convert_item(k, v) | |
hash[k] = new_value if not new_value.nil? | |
end | |
end | |
def convert_item(k, v) | |
if @@methods[k.to_sym] | |
method = @@methods[k.to_sym] | |
if method.is_a? Proc | |
method.call(v) | |
else | |
v.send(method) | |
end | |
end | |
end | |
end | |
# Пример преобразователя: | |
class Transactions | |
extend Converter | |
#attrb :uid # значение будет передаваться как есть без преобразования | |
attrb :sum, :to_f # для преобразования значения будет вызван его(значения) метод to_f '50.25'.to_f | |
# для преобразования значения будет вызван блок, | |
# который принимает исходное значение и возвращает преобразованное | |
attrb (:timestamp) { |value| Time.parse(value) } | |
end | |
transactions = Transactions.new([ | |
# входной массив хэшей где все значения - строки | |
{:uid => 'HT150', :sum => '50.25', :timestamp => '2014-04-04 05:50'}, | |
{:uid => 'HT151', :sum => '119.63', :timestamp => '2014-04-04 06:18'} | |
]) | |
# Значения преобразованы согласно правилам преобразованиия, описанным в Transactions | |
p transactions.to_a | |
# => [{:uid=>"HT150", :sum=>50.25, :timestamp=>2014-04-04 05:50:00 +0600}, | |
# {:uid=>"HT151", :sum=>119.63, :timestamp=>2014-04-04 06:18:00 +0600}] | |
p transactions.first # => {:uid=>"HT150", :sum=>50.25, :timestamp=>2014-04-04 05:50:00 +0600} | |
p transactions.select { |tx| tx[:sum] > 100 } | |
# => [{:uid => 'HT151', :sum => 119.63, :timestamp => 2014-04-04 06:18:00 +0600}] | |
=begin | |
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
Не могу понять, как нужно реализовать Converter, | |
чтобы можно было так вызвать метод sum | |
p transactions.sum # => 169.88 | |
Такое возможно, если сделать include в класс Transactions | |
другого модуля, содержащего метод sum. | |
Однако в условии класс Transactions только | |
содержит extend модуля Converter. | |
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
=end | |
#Проверка | |
class People | |
extend Converter | |
attrb :name | |
attrb :height, :to_i | |
attrb :birthday do |value| | |
Date.parse(value) | |
end | |
end | |
# Он должен будет работать так: | |
ppl = People.new([{:name => 'Vlas', :height => '205', :birthday => '1990-08-08'}]) | |
p ppl.first # => {:name => 'Vlas', :height => 205, :birthday => Wed, 08 Aug 1990} |
Владимир, спасибо большое за это замечание! Действительно, в модуле Converter используется переменная класса @@methods, которая была задумана для хранения методов, нужных для преобразования. Все бы ничего, однако данная переменная доступна для всех экземпляров классов, которые используют модуль Converter. Поэтому пришлось ее заменить на переменную экземпляра @methods, которая существует в рамках отдельно взятого экземпляра.
Исправленная версия модуля Converter:
require 'time'
module Converter
include Enumerable
def new(arr)
initialize(arr)
end
def initialize(arr)
@arr = arr
convert
self
end
def attrb(attribute, method=nil, &block)
if @methods.nil?
@methods = {}
end
method = block if block_given?
@methods[attribute] = method unless method.nil?
end
def convert
@arr.map do |hash|
convert_hash(hash)
end
end
def convert_hash(hash)
hash = hash.each do |k, v|
new_value = convert_item(k, v)
hash[k] = new_value unless new_value.nil?
end
end
def to_a
@arr
end
def each(&block)
@arr.each(&block)
end
def convert_item(k, v)
if @methods[k]
method = @methods[k]
if method.is_a? Proc
method.call(v)
else
v.send(method)
end
end
end
end
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Никита, а ведь ты не решил проблему.
определение класса ToArray изменяет поведение ToFloat