4

Is there something like Python __getattr__ for Ruby? In Python, obj.__getattr__ is called when an undefined attribute (method or property) is referenced. I found method_missing in Ruby but it doesn't work for properties.

My use case is: I'm testing Mirah as a JRuby -> Java compiler. In standard JRuby, the Swing methods and attributes are "Rubyfied" (eg: label.setText "x" => label.text = "x"), but not in Mirah, because Mirah doesn't have a propietary runtime library like JRuby. Then, I want to get the attribute references in runtime and map each call to the corresponding Swing method (label.text => label.getText() / label.text = "x" => label.setText("x") ).

PabloG
  • 25,761
  • 10
  • 46
  • 59
  • Possible duplicate of: http://stackoverflow.com/questions/786412/what-is-the-ruby-equivalent-of-pythons-getattr – jsalonen Nov 28 '11 at 19:11
  • 1
    @jsalonen: no duplicate, `getattr` <> `__getattr__`. Python getattr is similar to Ruby "method": obj.getattr("value") is equivalent to obj.value. `__getattr__` is a 'magic' method that is called when an undefined attribute is referenced – PabloG Nov 28 '11 at 19:26

3 Answers3

3

I'm not sure this covers your use case, but in general, method_missing should do the trick. How would you expect a Ruby class to know the difference between an undefined method and an undefined "property"? All it knows is that it has been passed a name that it does not recognize. Was it supposed to be a method or an property? Who knows? Unless you are talking about setter attributes, in which case, there is a = appended to the name:

 class X
   def method_missing name,*args
     puts "missing '#{name}' called with #{args}"
   end
 end  

.

> x = X.new
=> #<X:0xe6b322>
> x.unknown_method
missing 'unknown_method' called with []
=> nil
> x.unknown_property
missing 'unknown_property' called with []
=> nil
> x.unknown_property= 42
missing 'unknown_property=' called with [42]
=> 42     
AShelly
  • 34,686
  • 15
  • 91
  • 152
1

JRuby does this transformation in Java code, by walking the reflected class's methods and adding aliases for the Ruby names. You can do this from Ruby as well. Mirah has access to the actual java.lang.Class instances for all classes you're compiling against, and as a result could do this same name aliasing as part of the compiler phases.

The details on how exactly to do this are left as an exercise for the reader :)

  • I suppose I can do it using `object.methods' and then something like `:add_method` (I'm a Ruby/Mirah newbie, sorry if I didn't understand you correctly). But I was looking for a dynamic solution because it's the approach I would use if resolving this problem in Python, and being Ruby so similar to Python -at least for me-, when I found `method_missing` I assume there was a way to do the same for the attributes. Anyway, keep up the good work with JRuby! – PabloG Nov 28 '11 at 19:49
0

Objects in Ruby do not have "properties". They have instance variables (private variables storing data per instance) and methods that may access these variables.

Because parentheses are optional in Ruby method calls, and because syntax sugar allows you to write obj.foo = 42 as a nicer way of invoking the method obj.foo=( 42 ), you may think that these are properties. They are not; they are methods indistinguishable from any other.

This code:

class Foo
   attr_accessor :bar
end
f = Foo.new
f.bar = 42
puts f.bar  #=> 42

is exactly the same as this (much longer) code:

class Foo
  def bar
    @bar
  end
  def bar=( val )
    @bar = val
  end
end
f = Foo.new
f.bar=( 42 )
puts( f.bar() ) #=> 42

The attr_* methods actually create methods for you.

Phrogz
  • 296,393
  • 112
  • 651
  • 745