ruby-on-railsrubyrailscasts

Can't understand Ruby's magic


In railscasts project you can see this code:

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

The corresponding definition for the function is:

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

I can't understand how the admin parameter is passing to function, while in the function there's no word about admin parameter. Thanks


Solution

  • Factory.define is not a function definition, it is a method that takes a symbol or string (in this case user) and a block that defines the factory you are making. Factory(:user, :admin => true) makes a User object, with admin attributes. It is not calling the code in your second snippet, it is calling Factory() which initializes a factory, and selects one (in this case the one defined in second snippet). Then it passes options in hash form to Factory as well.

    Factory selects the :user factory which is very generic. The option :admin=>true just tells Factory to set the admin instance variable on User to 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
    

    So Factory(name,options) is equivalent to Factory.new(name,options) in this code.

    http://www.ruby-doc.org/core/classes/Kernel.html Notice Array and String etc have similar constructs. I am trying to figure out how they did that now.

    This is all confusing even for decent Ruby programmers. I recommend strongly the book "Metaprogramming Ruby" It is probably the best book I have read in ruby and it tells you a lot about this magic stuff.