tags:

views:

613

answers:

4
class Object
  attr_reader :foo
  def initialize
    @foo = 'bar'
  end
end

Object.new.foo # => 'bar'
''.foo # => nil
//.foo # => nil
[].foo # => nil

I want them all to return 'bar'

Am aware that you can do this already:

class Object
  def foo
    'bar'
  end
end

But I specifically want to initialize a state variable. Also note that this doesn't work.

class String
  alias_method :old_init, :initialize
  def initialize(*args)
    super
    old_init(*args)
  end
end

class Object
  attr_reader :foo
  def initialize
    @foo = 'bar'
    super
  end
end

''.foo # => nil

Nor does this:

class String
  attr_reader :foo
  def initialize
    @foo = 'bar'
  end
end

''.instance_variables # => []

I'm beginning to think that this isn't actually possible.

A: 

It's not an instance variable, but will meet the requirements of your example

class Object
  def foo
    'bar'
  end
end
DanSingerman
+3  A: 

If the thing you're trying to return (here, 'bar') requires much more setup cost than a small String, you could use the memoized version of HermanD's answer:

class Object
  def foo
    @foo ||= begin
      'bar' # something far more complicated than just "'bar'"
    end
  end
end

You could even use the memoization for cheap stuff like Strings if you really need the instance variable to be set (for some reason that I can't quite think of at them moment):

class Object
  def foo
    @foo ||= 'bar'
  end
end
James A. Rosen
+1, but this wont work if you invoke instance_variable_get before using the accessor, it's interesting that you can't rely on Object's #initialize.
krusty.ar
boy, that's a pretty awkward case, but I have _no_ _doubt_ that some obscure library will call into this and it will blow up and you'll go, "WTF?"
James A. Rosen
A: 

This isn't possible.

Ollie Saunders
I posted an example of how to do this.
Jim Schubert
A: 

This is possible.

class Object
  class << self
    Kernel.send :define_method, :foo do #Object.send to be more restrictive
      @foo = 'bar'
    end
  end
end

.

irb(main):023:0> class Object
irb(main):024:1> class << self
irb(main):025:2> Kernel.send :define_method, :foo do 
irb(main):026:3* @foo = 'bar'
irb(main):027:3> end
irb(main):028:2> end
irb(main):029:1> end
=> #<Proc:0x00007f5ac89db168@(irb):25>
irb(main):030:0> x = Object.new
=> #<Object:0x7f5ac89d6348>
irb(main):031:0> x.foo
=> "bar"
irb(main):032:0> [].foo
=> "bar"
irb(main):033:0> //.foo
=> "bar"

It's important to understand eigenclasses. Every class is implemented mysteriously by the Ruby interpreter as a hidden class type:

irb(main):001:0> class Object
irb(main):002:1>   def eigenclass
irb(main):003:2>     class << self; self; end
irb(main):004:2>   end
irb(main):005:1> end
=> nil
irb(main):006:0> x = Object.new
=> #<Object:0x7fb6f285cd10>
irb(main):007:0> x.eigenclass
=> #<Class:#<Object:0x7fb6f285cd10>>
irb(main):008:0> Object.eigenclass
=> #<Class:Object>
irb(main):009:0> Object.class
=> Class

So, in your example, when you're trying to call foo on your objects, it's operating on the class #<Object:0x7fb6f285cd10>. However, what you want it to operate on is the secret class #<Class:#<Object:0x7fb6f285cd10>>

I hope this helps!

Jim Schubert