Ответ Майкла Папиле по сути правильный. Однако я бы хотел немного подробнее остановиться на этом, поскольку есть некоторые технические нюансы, о которых вы, возможно, пожелаете знать. Я просмотрел код для railscasts и factory_girl и считаю, что есть несколько дополнительных кусочков головоломки, которые объясняют, как заканчивается : admin => true arg создание атрибута admin фабрики пользователей. Добавление атрибута на самом деле не происходит с помощью метода * initialize () Factory , хотя, как указал Майкл, этот метод действительно вызывается при создании нового объекта фабрики пользователя.
Я собираюсь включить в это объяснение все шаги, которые я предпринял на тот случай, если вы хотите узнать, как поступить с такими же вопросами, которые у вас могут возникнуть.
Поскольку ваш оригинальный пост датирован 17 февраля, я посмотрел версию railscasts , которая близко соответствует этой дате.
Я посмотрел в своем Gemfile:
https://github.com/ryanb/railscasts/blob/d124319f4ca2a2367c1fa705f5c8229cce70921d/Gemfile
Строка 18:
gem "factory_girl_rails"
Затем я проверил фиксацию factory_girl_rails , которая наиболее близко соответствовала дате 17 февраля.
https://github.com/thoughtbot/factory_girl_rails/blob/544868740c3e26d8a5e8337940f9de4990b1cd0b/factory_girl_rails.gemspec
Строка 16:
s.add_runtime_dependency('factory_girl', '~> 2.0.0.beta')
factory_girl версия 2.0.0.beta было не так легко найти. Там нет тегов GitHub с таким именем, поэтому я просто выбрал наиболее близкие по дате фиксации.
https://thoughtbot/factory_girl/blob/9fb8a3b40f24f0c8477776133a2f9cd654ca1c8c/lib/factory_girl/syntax/vintage.rb
Линии 122-128:
# Shortcut for Factory.default_strategy.
#
# Example:
# Factory(:user, :name => 'Joe')
def Factory(name, attrs = {})
Factory.default_strategy(name, attrs)
end
Таким образом, вызов Factory в railscasts фактически вызывает вспомогательный метод, который вызывает "стратегию по умолчанию", которая находится в том же файле:
Строки 39-52:
# Executes the default strategy for the given factory. This is usually create,
# but it can be overridden for each factory.
#
# Arguments:
# * name: +Symbol+ or +String+
# The name of the factory that should be used.
# * overrides: +Hash+
# Attributes to overwrite for this instance.
#
# Returns: +Object+
# The result of the default strategy.
def self.default_strategy(name, overrides = {})
self.send(FactoryGirl.find(name).default_strategy, name, overrides)
end
Обратите внимание, что FactoryGirl.find вызывается для получения объекта, для которого вызывается default_strategy . find метод разрешается здесь:
https://thoughtbot/factory_girl/blob/9fb8a3b40f24f0c8477776133a2f9cd654ca1c8c/lib/factory_girl/registry.rb
Строки 12-14:
def find(name)
@items[name.to_sym] or raise ArgumentError.new("Not registered: #{name.to_s}")
end
Здесь имя : пользователь . Таким образом, мы хотим вызвать default_strategy на фабрике user . Как отметил Майкл Папиле, эта фабрика пользователей была определена и зарегистрирована кодом Railscasts, который вы изначально считали определением класса для Factory.
https://ryanb/railscasts/blob/d124319f4ca2a2367c1fa705f5c8229cce70921d/spec/factories.rb
Строки 23-25:
Factory.define :user do |f|
f.sequence(:github_username) { |n| "foo#{n}" }
end
Итак, изучая стратегию по умолчанию для фабрики пользователей, я осмотрел проект Railscasts и обнаружил следующее:
https://ryanb/railscasts/blob/d124319f4ca2a2367c1fa705f5c8229cce70921d/spec/factories.rb
Строки 43-45:
def default_strategy #:nodoc:
@options[:default_strategy] || :create
end
: создать - стратегия по умолчанию. Мы возвращаемся к factory_girl , чтобы найти определение для create .
https://thoughtbot/factory_girl/blob/9fb8a3b40f24f0c8477776133a2f9cd654ca1c8c/lib/factory_girl/syntax/methods.rb
Строки 37-55:
# Generates, saves, and returns an instance from this factory. Attributes can
# be individually overridden by passing in a Hash of attribute => value
# pairs.
#
# Instances are saved using the +save!+ method, so ActiveRecord models will
# raise ActiveRecord::RecordInvalid exceptions for invalid attribute sets.
#
# Arguments:
# * name: +Symbol+ or +String+
# The name of the factory that should be used.
# * overrides: +Hash+
# Attributes to overwrite for this instance.
#
# Returns: +Object+
# A saved instance of the class this factory generates, with generated
# attributes assigned.
def create(name, overrides = {})
FactoryGirl.find(name).run(Proxy::Create, overrides)
end
Стратегия создания вызывает метод run , определенный здесь:
https://thoughtbot/factory_girl/blob/9fb8a3b40f24f0c8477776133a2f9cd654ca1c8c/lib/factory_girl/factory.rb
Строки 86-97:
def run(proxy_class, overrides) #:nodoc:
proxy = proxy_class.new(build_class)
overrides = symbolize_keys(overrides)
overrides.each {|attr, val| proxy.set(attr, val) }
passed_keys = overrides.keys.collect {|k| FactoryGirl.aliases_for(k) }.flatten
@attributes.each do |attribute|
unless passed_keys.include?(attribute.name)
attribute.add_to(proxy)
end
end
proxy.result(@to_create_block)
end
Перевод / обобщение того, что делает этот код:
Во-первых, объект proxy создается путем вызова new на proxy_class , который в данном случае Proxy :: Create, который определен здесь:
https://thoughtbot/factory_girl/blob/9fb8a3b40f24f0c8477776133a2f9cd654ca1c8c/lib/factory_girl/proxy/create.rb
В общем, все, что вам нужно знать, это то, что proxy создает новый объект фабрики пользователя и вызывает обратные вызовы до и после создания объекта фабрики.
Возвращаясь к методу run , мы видим, что все дополнительные аргументы, которые первоначально были переданы в удобный метод Factory (в данном случае : admin => true ) теперь помечены как overrides . Затем объект proxy вызывает метод set , передавая каждую пару атрибут-имя / значение в качестве аргументов.
Метод set () является частью класса Build , родительского класса Proxy .
https://thoughtbot/factory_girl/blob/9fb8a3b40f24f0c8477776133a2f9cd654ca1c8c/lib/factory_girl/proxy/build.rb
Строки 12-14:
def set(attribute, value)
@instance.send(:"#{attribute}=", value)
end
Здесь @instance относится к прокси-объекту, объекту фабрики пользователя.
Таким образом, : admin => true задается в качестве атрибута на фабрике пользователей, которую создает код спецификации railscasts.
Если хотите, можете зайти в Google «шаблоны проектирования программ» и прочитать о следующих шаблонах: Factory, Proxy, Builder, Strategy.
Майкл Папиле написал:
http://www.ruby -doc.org / core / classes / Kernel.html Обратите внимание на массив и
Строка и т. Д. Имеют аналогичные конструкции. Я пытаюсь выяснить как они
сделал это сейчас.
Если вам все еще интересно, Array и String, которые вы видите в документе Kernel, на самом деле являются просто фабричными методами, используемыми для создания новых объектов этих типов. Вот почему не требуется новый вызов метода. На самом деле они не являются вызовами конструктора, но они выделяют и инициализируют объекты Array и String, и, следовательно, под капотом делают эквивалент вызова initialize () для объектов этих типов. (В C, хотя, конечно, не Ruby)