I can not understand the magic of Ruby

In the railscasts project, you can see this code:

before(:each) do
  login_as Factory(:user, :admin => true)
end

Corresponding function definition:

Factory.define :user do |f|
  f.sequence(:github_username) { |n| "foo#{n}" }
end

I can’t understand how the admin parameter passes to the function, and the function does not have a word about the admin parameter. Thanks

+5
source share
3 answers

Factory.define , , ( ) , factory, . Factory(:user, :admin => true) User . , Factory(), factory, ( , ). - factory.

Factory :user factory, . :admin=>true Factory, admin User true.

This is actually what it is calling in factory.rb in factory girl

def initialize(name, options = {}) #:nodoc:
  assert_valid_options(options)
  @name = factory_name_for(name)
  @options = options
  @attributes = []
end

Factory (, ) Factory.new(, ) .

http://www.ruby-doc.org/core/classes/Kernel.html Array String etc . , .

Ruby. " ". , , , .

+9

. , , , , . Railscasts factory_girl , , , : admin => true arg admin . Factory initialize(), , , .

, , , , .

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 . , 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, .

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

/ , :

-, - new proxy_class, Proxy :: Create, :

https://thoughtbot/factory_girl/blob/9fb8a3b40f24f0c8477776133a2f9cd654ca1c8c/lib/factory_girl/proxy/create.rb

, , , , .

run, , , Factory ( : admin => true), . - 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 .. . , .

, Array String, Kernel, , . . , Array String, , , initialize() . ( , , , )

+3

, - . def end. , , :user , f.

Of course, with metaprogramming, you can never be sure what the hell is going on.

-1
source

All Articles