Python like __getattr__ for Ruby / JRuby

707 Views Asked by At

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") ).

3

There are 3 best solutions below

1
On

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 :)

0
On

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     
0
On

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.