Skip to content

Instantly share code, notes, and snippets.

@yesnik
Created December 23, 2014 05:03
Show Gist options
  • Save yesnik/60389cbc330352139b29 to your computer and use it in GitHub Desktop.
Save yesnik/60389cbc330352139b29 to your computer and use it in GitHub Desktop.
Задание по Ruby 1 (ответ)
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}
@vkuznetsov
Copy link

Никита, а ведь ты не решил проблему.

class ToFloat
  extend Converter
  attrb :value, :to_f
end

class ToArray
  extend Converter
  attrb(:value) { |v| [v] }
end

floats = ToFloat.new([{value: '10'}])
p floats.first[:value] # =>  ["10"]

определение класса ToArray изменяет поведение ToFloat

@yesnik
Copy link
Author

yesnik commented Dec 25, 2014

Владимир, спасибо большое за это замечание! Действительно, в модуле 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