MichaelPapileの応答は本質的に正しいです。ただし、知っておきたい技術的なニュアンスがいくつかあるので、少し詳しく説明したいと思います。railscastsとfactory_girlのコードを調べたところ、パズルには、 :admin => trueargがユーザーファクトリのadmin属性を作成する方法を説明する追加のピースがいくつかあると思います。属性の追加は、実際にはFactoryのinitialize()メソッドを介して行われるわけではありませんが、Michaelが指摘したように、このメソッドは実際に新しいユーザーファクトリオブジェクトを構築するために呼び出されています。
この説明には、同様の質問を調査する方法を確認したい場合に備えて、私が行ったすべての手順を含めます。
元の投稿の日付は2月17日なので、その日付に厳密に一致するバージョンのrailscastを調べました。
私はそのGemfileを調べました:
https://github.com/ryanb/railscasts/blob/d124319f4ca2a2367c1fa705f5c8229cce70921d/Gemfile
18行目:
gem "factory_girl_rails"
次に、2月17日の日付に最も近いfactory_girl_railsのコミットを確認しました。
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
したがって、railscastsでのFactory呼び出しは、実際には、同じファイルにある「デフォルト戦略」を呼び出す便利なメソッドを呼び出しています。
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
ここでの名前は:userです。したがって、ユーザーファクトリでdefault_strategyを呼び出したいと思います。Michael Papileが指摘したように、このユーザーファクトリは、ファクトリのクラス定義であると最初に考えていたrailscastsコードによって定義および登録されました。
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
:createがデフォルトの戦略です。factory_girlに戻って、 createのdefを見つけます。
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
createストラテジーは、ここで定義されている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_class(この場合はProxy :: Create )でnewを呼び出すことによって構築されます。これは、次のように定義されています。
https://thoughtbot/factory_girl/blob/9fb8a3b40f24f0c8477776133a2f9cd654ca1c8c/lib/factory_girl/proxy/create.rb
基本的に知っておく必要があるのは、プロキシが新しいユーザーファクトリオブジェクトを構築し、ファクトリオブジェクトが作成される前後にコールバックを呼び出すことだけです。
runメソッドに戻ると、元々 Factoryコンビニエンスメソッド(この場合は:admin => true )に渡されたすべての追加の引数がオーバーライドとしてラベル付けされていることがわかります。次に、プロキシオブジェクトはsetメソッドを呼び出し、各属性名と値のペアを引数として渡します。
set()メソッドは、 Proxyの親クラスであるBuildクラスの一部です。
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スペックコードが作成するユーザーファクトリの属性として設定される方法です。
必要に応じて、「プログラミングデザインパターン」をグーグルで検索し、ファクトリー、プロキシ、ビルダー、ストラテジーのパターンについて読むことができます。
MichaelPapileは次のように書いています。
http://www.ruby-doc.org/core/classes/Kernel.html配列や文字列などの構造は似ています。私は彼らが今それをどのように行ったかを理解しようとしています。
それでも興味がある場合は、カーネルドキュメントに表示される配列と文字列は、実際には、これらのタイプの新しいオブジェクトを作成するために使用されるファクトリメソッドにすぎません。そのため、新しいメソッドの呼び出しは必要ありません。これらは実際にはコンストラクター呼び出しではありませんが、ArrayオブジェクトとStringオブジェクトを割り当てて初期化するため、内部では、これらのタイプのオブジェクトに対してinitialize()を呼び出すのと同じことを行います。(ただし、CではもちろんRubyではありません)