Forum: Ruby Dynamically adding methods to a Ruby class

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
2c8df79b2a68a7532af01d8851f7fa2d?d=identicon&s=25 John Lam (Guest)
on 2005-12-15 05:10
(Received via mailing list)
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

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
Fe9b2d0628c0943af374b2fe5b320a82?d=identicon&s=25 Eero Saynatkari (rue)
on 2005-12-15 05:43
John Lam wrote:
> 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
A0599814ceddc2e283792f4e47c57f5e?d=identicon&s=25 Brian Takita (Guest)
on 2005-12-15 08:52
(Received via mailing list)
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 = 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 = Dynamic.new

# You can also use Proc.new instead of lambda
d.dynamic_methods[:test] = 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] = 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
A0599814ceddc2e283792f4e47c57f5e?d=identicon&s=25 Brian Takita (Guest)
on 2005-12-15 09:19
(Received via mailing list)
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
used
if the dynamic method is defined in the class though.

d.dynamic_methods[:Count] = 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
5befe95e6648daec3dd5728cd36602d0?d=identicon&s=25 Robert Klemme (Guest)
on 2005-12-15 11:38
(Received via mailing list)
John Lam wrote:
>       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
2c8df79b2a68a7532af01d8851f7fa2d?d=identicon&s=25 John Lam (Guest)
on 2005-12-15 16:00
(Received via mailing list)
On 12/15/05, Robert Klemme <bob.news@gmx.net> wrote:
>
> Note that this might have adversary effects on other code if consts spring
> 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
2c8df79b2a68a7532af01d8851f7fa2d?d=identicon&s=25 John Lam (Guest)
on 2005-12-15 16:15
(Received via mailing list)
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.
The
shim is added as an instance method to the class object, so subsequent
calls
will always go via the shim and not via method_missing.

Cheers,
-John
http://www.iunknown.com
This topic is locked and can not be replied to.