Dty
Dty

Reputation: 12273

rails Foo::Engine.config.something is not defined?

I have an initializer for an engine named Foo like so:

# config/initializer/foo.rb
class Foo::Engine < ::Rails::Engine
  config.bar = 'baz'
end

But it behaves in unexpected ways:

Foo::Engine.config.bar # => 'baz' # expected
defined?(Foo::Engine.config.bar) # => nil, why?

Why is defined? nil?

Also, when I do Foo::Engine.config.inspect many things show up but bar is nowhere to be found. Why?

Upvotes: 0

Views: 109

Answers (2)

Stuart M
Stuart M

Reputation: 11588

It is because #bar is not a real method on Rails::Engine::config but is implemented via #method_missing in Rails::Railtie::Configuration. If it were a real method (implemented with def bar) defined? would return "method".

class Foo
  def bar
    'bar'
  end

  def method_missing(name, *args, &blk)
    if name == :baz
      'baz'
    end
  end
end

f = Foo.new
f.bar           # => "bar"
defined?(f.bar) # => "method"
f.baz           # => "baz"
defined?(f.baz) # => nil

And to address the second part of your question, #inspect does not include bar is because the configuration options are stored in the @@options class variable, not in an instance variable where #inspect normally looks:

def method_missing(name, *args, &blk)
  if name.to_s =~ /=$/
    @@options[$`.to_sym] = args.first
  elsif @@options.key?(name)
    @@options[name]
  else
    super
  end
end

Upvotes: 1

sjain
sjain

Reputation: 23344

As stated in the Expressions @ Programming Ruby,

The defined? operator returns nil if its argument (which can be an arbitrary expression) is not defined, otherwise it returns a description of that argument.

defined? 1 → "expression"
defined? dummy → nil
defined? printf → "method"
defined? String → "constant"
defined? $& → nil
defined? $_ → "global-variable"
defined? Math::PI → "constant"
defined? ( c,d = 1,2 ) → "assignment"
defined? 42.abs → "method"

So for classes:

ruby-1.9.2-p180 > defined? Person

 => nil

ruby-1.9.2-p180 > class Person

ruby-1.9.2-p180 ?>  end

 => nil

ruby-1.9.2-p180 > defined? Person

 => "constant"

For methods:

ruby-1.9.2-p180 > def cool

ruby-1.9.2-p180 ?>  puts "clear"

ruby-1.9.2-p180 ?>  end

 => nil

ruby-1.9.2-p180 > defined? cool

 => "method"

In your case,

defined?(options) is calling the options method and passing the result to defined?.

Thanks to @Stuart, as mentioned that its not a real method but its implemented by method_missing, there is a little magic here.

So in fact you should not be expecting the method options to be defined therefore getting nil for baz.

Upvotes: 1

Related Questions