Dynamically adding methods to a Ruby class

J

John Lam

------=_Part_1009_17822430.1134619669875
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

I just finished writing the first spike for my Ruby CLR bridge tonight, and
I'm wondering if there might be a better (or more efficient) way to add
instance methods to a class object than this:

class Module
def const_missing(symbol)
obj =3D Class.new
obj.class_eval %{
def initialize
...
end

def method_missing(name, *params)
...
end
}
const_set(symbol, obj)
end
end

Thanks,
-John
http://www.iunknown.com

PS If you're wondering what the code in the ... blocks do, read my write-up
of this code at: http://www.iunknown.com/articles/2005/12/14/hello-rubyclr

------=_Part_1009_17822430.1134619669875--
 
E

Eero Saynatkari

John said:
I just finished writing the first spike for my Ruby CLR bridge tonight,
and
I'm wondering if there might be a better (or more efficient) way to add
instance methods to a class object than this:

class Module
def const_missing(symbol)
obj = Class.new
obj.class_eval %{
def initialize
...
end

def method_missing(name, *params)
...
end
}
const_set(symbol, obj)
end
end

Not really, except for using define_method (which has
some limitations that would probably make it unsuitable
for a #method_missing implementation). The 'Class methods'
thread had pretty much this exact implementation..

Perhaps some sort of a prototype-based approach?
Thanks,
-John
http://www.iunknown.com

PS If you're wondering what the code in the ... blocks do, read my
write-up
of this code at:
http://www.iunknown.com/articles/2005/12/14/hello-rubyclr


E
 
B

Brian Takita

------=_Part_1404_14770385.1134633131166
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Hello John,

This isn't quite as cool as a prototype, but here is another possible type
of solution:

class Dynamic
attr_reader :dynamic_methods

def initialize
@dynamic_methods =3D Hash.new
end

alias alias_method_missing method_missing

def method_missing(name, *args)
unless @dynamic_methods.include?(name)
alias_method_missing(name, *args)
return
end

@dynamic_methods[name].call(*args)
end
end

d =3D Dynamic.new

# You can also use Proc.new instead of lambda
d.dynamic_methods[:test] =3D lambda do |*args|
puts 'test ' + args.to_s
end

d.test(1, 2)
# test 12

Of course you could add the method that you describe in your link:

d.dynamic_methods[:Count] =3D lambda do |*args|
create_ruby_instance_method(self.class, 'Count') do
include 'System.Collections'
ldarg_2
call 'static Marshal::ToClrObject(VALUE)'
call 'ArrayList::get_Count()'
call 'static Marshal::ToRubyNumber(Int32)'
ret
end
self.Count
end

--
Brian Takita
http://freeopinion.org

Not really, except for using define_method (which has
some limitations that would probably make it unsuitable
for a #method_missing implementation). The 'Class methods'
thread had pretty much this exact implementation..

Perhaps some sort of a prototype-based approach?



E

------=_Part_1404_14770385.1134633131166--
 
B

Brian Takita

------=_Part_1576_24643030.1134634661329
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Oops...
In the :Count method I defined, self isn't the same as in the method you
defined.

caller[1] probably would be the object you are looking for as long as that
method gets called through :method_missing in this case. :self could be use=
d
if the dynamic method is defined in the class though.

d.dynamic_methods[:Count] =3D lambda do |*args|
create_ruby_instance_method(caller[1].class, 'Count') do
include 'System.Collections'
ldarg_2
call 'static Marshal::ToClrObject(VALUE)'
call 'ArrayList::get_Count()'
call 'static Marshal::ToRubyNumber(Int32)'
ret
end
caller[1].Count
end

--
Brian Takita
http://freeopinion.org

Hello John,

This isn't quite as cool as a prototype, but here is another possible typ= e
of solution:

class Dynamic
attr_reader :dynamic_methods

def initialize
@dynamic_methods =3D Hash.new
end

alias alias_method_missing method_missing

def method_missing(name, *args)
unless @dynamic_methods.include?(name)
alias_method_missing(name, *args)
return
end

@dynamic_methods[name].call(*args)
end
end

d =3D Dynamic.new

# You can also use Proc.new instead of lambda
d.dynamic_methods[:test] =3D lambda do |*args|
puts 'test ' + args.to_s
end

d.test(1, 2)
# test 12

Of course you could add the method that you describe in your link:

d.dynamic_methods[:Count] =3D lambda do |*args|
create_ruby_instance_method( self.class, 'Count') do
include 'System.Collections'
ldarg_2
call 'static Marshal::ToClrObject(VALUE)'
call 'ArrayList::get_Count()'
call 'static Marshal::ToRubyNumber(Int32)'
ret
end
self.Count
end

--
Brian Takita
http://freeopinion.org

Not really, except for using define_method (which has
some limitations that would probably make it unsuitable
for a #method_missing implementation). The 'Class methods'
thread had pretty much this exact implementation..

Perhaps some sort of a prototype-based approach?



E

------=_Part_1576_24643030.1134634661329--
 
R

Robert Klemme

John said:
I just finished writing the first spike for my Ruby CLR bridge
tonight, and I'm wondering if there might be a better (or more
efficient) way to add instance methods to a class object than this:

class Module
def const_missing(symbol)
obj = Class.new
obj.class_eval %{
def initialize
...
end

def method_missing(name, *params)
...
end
}
const_set(symbol, obj)
end
end

class Module
def const_missing(symbol)
obj = Class.new do
def initialize
...
end

def method_missing(name, *params)
...
end
end
const_set(symbol, obj)
end
end

Note that this might have adversary effects on other code if consts spring
into existence just like that.

Kind regards

robert
 
J

John Lam

------=_Part_7592_19298189.1134658766492
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Note that this might have adversary effects on other code if consts sprin= g
into existence just like that.

I trimmed most of the code out of that example for clarity, but there will
be a bunch of code that will looks up valid types to instantiate and will
punt to an old_method_missing call if the constant name is an invalid type.

Thanks for the constructor block suggestion - I did have a version sometime
last night that used that feature, but I can't recall why I changed it.

Cheers,
-John
http://www.iunknown.com

------=_Part_7592_19298189.1134658766492--
 
J

John Lam

------=_Part_7860_31507486.1134659656510
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Thanks for the suggestion, Brian.

The code in method_missing will use reflection to generate the shim on the
fly, so I don't need to keep a list of methods that have been generated. Th=
e
shim is added as an instance method to the class object, so subsequent call=
s
will always go via the shim and not via method_missing.

Cheers,
-John
http://www.iunknown.com

------=_Part_7860_31507486.1134659656510--
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,150
Members
46,696
Latest member
BarbraOLog

Latest Threads

Top