Вы звоните define_compounds(DateTimeComposer::attrs)
в конце определения модуля InstanceMethods
.На этом этапе в коде attrs
все еще является пустым массивом, а self
является модулем InstanceMethods
.
Это означает, что никакие методы не будут определены, и даже если бы они были, они были быпривязан к метаклассу InstanceMethods
, что делает их методами класса этого модуля, а не методами экземпляра вашего Account
класса.
Это происходит потому, что вызовы методов внутри модуля InstanceMethods
Определение оценивается так, как его видит интерпретатор ruby, , а не , когда вы звоните include ActiveRecordExtensions::InstanceMethods
.Следствием этого является то, что можно запускать произвольный код в самых необычных местах, например, в пределах определения класса .
. Для решения проблемы вы можете использовать included
обратный вызов , предоставляемый ruby, который вызывается всякий раз, когда модуль включен в другой:
module InstanceMethods
# mod is the Class or Module that included this module.
def included(mod)
DateTimeComposer::attrs.each do |attr|
mod.instance_eval <<-METHODS
def #{attr.to_s}_to
puts 'tes'
end
METHODS
end
end
end
В качестве дополнительного предложения, вы должны быть в состоянии достичь того же результата, просто определяяметоды при вызове compound_datetime
, устраняя тем самым зависимость от глобальной переменной класса attrs
.
Однако, если вы должны иметь доступ к полям, которые были объявлены как составные datetime, вы должны использовать переменные экземпляра класса, которые являются уникальными для каждого класса и не разделяются в иерархии:
module ClassMethods
def compound_datetime(*attrs)
@datetime_compounds = attrs
attrs.each do |attr|
instance_eval <<-METHODS
def #{attr.to_s}_to
puts 'tes'
end
METHODS
end
end
def datetime_compounds; @datetime_compounds; end;
end
class Account < ActiveRecord::Base
compound_datetime :sales_at, :published_at
end
class AnotherModel < ActiveRecord::Base
compound_datetime :attr1, :attr2
end
Account.datetime_compounds
=> [ :sales_at, :published_at ]
AnotherModel.datetime_compounds
=> [ :attr1, :attr2 ]