Looking for an "inversion" pattern

I'm sure there's a clean way to do this in Ruby, but I haven't figured
it out.

I'd like to create a method +foo+ that transforms:

   my_obj.foo.some_method(*args)

to

  MyClass.some_method(my_obj, *args)

Maybe I'm overthinking this. I'll keep working on this, but in the
meantime, I'm open to suggestions.

Thanks!

-- ff

···

--
Posted via http://www.ruby-forum.com/.

Fearless Fool wrote in post #992929:

Maybe I'm overthinking this...

Meh. I s'pose I can substitute an underscore for a period:

  my_obj.foo_some_method(*args)

... whereupon this become a simple mixin on my_obj's class:

  def foo_some_method(*args) {
    MyClass.some_method(self, *args)
  }

The only potential disadvantage is that I need to write one of these for
each method. The advantages include likely to run much faster (than
constructing lambdas or invoking method_missing processing) and possibly
easier to understand and maintain than what I was originally trying to
do.

···

--
Posted via http://www.ruby-forum.com/\.

Fearless Fool wrote in post #992929:

I'd like to create a method +foo+ that transforms:

   my_obj.foo.some_method(*args)

to

  MyClass.some_method(my_obj, *args)

  class MyClass
    def self.some_method(obj, *args)
      puts "MyClass.some_method:"
      puts "obj: #{obj.inspect}"
      puts "args: #{args.inspect}"
    end
  end

  def define_foo(obj, clazz, method)
    obj.singleton_class.class_eval do
      define_method :foo do
        Class.new do
          define_method method do |*args|
            clazz.send(method, obj, *args)
          end
        end.new
      end
    end
  end

  my_obj = "my_obj thing"
  args = [1,2,3]
  define_foo(my_obj, MyClass, :some_method)
  my_obj.foo.some_method(*args)

  # =>
  # MyClass.some_method:
  # obj: "my_obj thing"
  # args: [1, 2, 3]

Returning facade or proxy objects like this can be an elegant solution
to certain problems. It's rather high on the abstraction ladder, though,
and without knowing the context I would wonder if more direct solutions
are possible.

···

--
Posted via http://www.ruby-forum.com/\.

I would create a method foo that returns a proxy that remembers which
was the original receiver. This proxy can have a method_missing
implementation that calls MyClass.xxxx passing the original receiver
and all params. For example:

ruby-1.8.7-p334 :003 > class Proxy
ruby-1.8.7-p334 :004?> def initialize target
ruby-1.8.7-p334 :005?> @target = target
ruby-1.8.7-p334 :006?> end
ruby-1.8.7-p334 :007?> def method_missing meth, *args, &blk
ruby-1.8.7-p334 :008?> MyClass.send(meth,@target,*args,&blk)
ruby-1.8.7-p334 :009?> end
ruby-1.8.7-p334 :010?> end
=> nil
ruby-1.8.7-p334 :011 > class Something
ruby-1.8.7-p334 :012?> def foo
ruby-1.8.7-p334 :013?> Proxy.new self
ruby-1.8.7-p334 :014?> end
ruby-1.8.7-p334 :015?> end
=> nil
ruby-1.8.7-p334 :016 > class MyClass
ruby-1.8.7-p334 :017?> def self.test1 obj, *args
ruby-1.8.7-p334 :018?> p [obj,*args]
ruby-1.8.7-p334 :019?> end
ruby-1.8.7-p334 :020?> end
=> nil
ruby-1.8.7-p334 :021 > my_obj = Something.new
=> #<Something:0xb72c8514>
ruby-1.8.7-p334 :022 > my_obj.foo.test1 1,2,3
[#<Something:0xb72c8514>, 1, 2, 3]

I don't know if method foo is part of your class, or maybe you can
build a method and extend the required objects with it.

Jesus.

···

On Fri, Apr 15, 2011 at 7:16 AM, Fearless Fool <r@alum.mit.edu> wrote:

I'm sure there's a clean way to do this in Ruby, but I haven't figured
it out.

I'd like to create a method +foo+ that transforms:

my_obj.foo.some_method(*args)

to

MyClass.some_method(my_obj, *args)

Maybe I'm overthinking this. I'll keep working on this, but in the
meantime, I'm open to suggestions.

Fearless Fool wrote in post #992929:

I'm sure there's a clean way to do this in Ruby, but I haven't figured
it out.

I'd like to create a method +foo+ that transforms:

   my_obj.foo.some_method(*args)

to

  MyClass.some_method(my_obj, *args)

Not sure, but would bound or unbound methods help you?

bound_method = my_obj.method(:foo)
bound_method.call(*args)

unbound_method = my_obj.class.instance_method(:foo)
unbound_method.bind(my_obj).call(*args)

···

--
Posted via http://www.ruby-forum.com/\.

@Kevin:

Kevin Mahler wrote in post #992945:

  ...
  def define_foo(obj, clazz, method)
    obj.singleton_class.class_eval do
      define_method :foo do
        Class.new do
          define_method method do |*args|
            clazz.send(method, obj, *args)
          end
        end.new
      end
    end
  end

That's some mighty fine code-fu -- back in the day I had no problem with
metaprogramming constructs in scheme, but I'm not yet at ease with the
syntax and class structure of Ruby.

Returning facade or proxy objects like this can be an elegant solution
to certain problems. It's rather high on the abstraction ladder, though,
and without knowing the context I would wonder if more direct solutions
are possible.

Well, yes -- as per my previous post. Since you must call define_foo()
for each object & method you want to cover, I don't see a lot of
advantage to the approach. But it does show off Ruby's function
defining tricks nicely.

···

--
Posted via http://www.ruby-forum.com/\.

I am sorry, I still do not understand your motivation to have a class
method which receives an instance as first argument. Isn't this
conceptually exactly what an instance method is for? Why do you need
this?

If you need this as general pattern you could always do

class X
  def method_missing(m, *a, &b)
    self.class.send(m, self, *a, &b)
  end

  def self.foo(obj, str)
    printf "%p: %s\n", obj, str
  end
end

X.new.foo 123

But I would seriously question the wisdom of this. :slight_smile:

Other than that I would follow Jesus's approach to make #foo create a
proxy instance. Here's another way to do it which would also allow
method chaining on the proxy:

class Proxy < BasicObject
  def initialize(orig, delegate)
    @orig = orig
    @delegate = delegate
  end

  def method_missing(m, *a, &b)
    res = @delegate.send(m, @orig, *a, &b)
    @orig.equal?(res) ? self : res
  end
end

class Object
  # create proxy for delegation to given
  # instance
  def proxy(delegate)
    Proxy.new(self, delegate)
  end
end

class YourClass
  def proxy
    super(MyClass)
  end
end

Kind regards

robert

···

On Fri, Apr 15, 2011 at 8:27 AM, Fearless Fool <r@alum.mit.edu> wrote:

Fearless Fool wrote in post #992929:

Maybe I'm overthinking this...

Meh. I s'pose I can substitute an underscore for a period:

my_obj.foo_some_method(*args)

... whereupon this become a simple mixin on my_obj's class:

def foo_some_method(*args) {
MyClass.some_method(self, *args)
}

The only potential disadvantage is that I need to write one of these for
each method. The advantages include likely to run much faster (than
constructing lambdas or invoking method_missing processing) and possibly
easier to understand and maintain than what I was originally trying to
do.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Kevin Mahler wrote in post #992945:

Fearless Fool wrote in post #992929:

I'd like to create a method +foo+ that transforms:

   my_obj.foo.some_method(*args)

to

  MyClass.some_method(my_obj, *args)

  class MyClass
    def self.some_method(obj, *args)
      puts "MyClass.some_method:"
      puts "obj: #{obj.inspect}"
      puts "args: #{args.inspect}"
    end
  end

  def define_foo(obj, clazz, method)
    obj.singleton_class.class_eval do
      define_method :foo do
        Class.new do
          define_method method do |*args|
            clazz.send(method, obj, *args)
          end
        end.new
      end
    end
  end

  my_obj = "my_obj thing"
  args = [1,2,3]
  define_foo(my_obj, MyClass, :some_method)
  my_obj.foo.some_method(*args)

  # =>
  # MyClass.some_method:
  # obj: "my_obj thing"
  # args: [1, 2, 3]

Returning facade or proxy objects like this can be an elegant solution
to certain problems. It's rather high on the abstraction ladder, though,
and without knowing the context I would wonder if more direct solutions
are possible.

I don't know what's conceptually easier to understand, but in ruby there
is no limit to how high you can stack singleton methods, e.g.:

obj.foo
obj.foo.some_method

If obj.foo() returns obj's singleton class, then some_method() is being
called as a class method of the singleton class. That means some_method
is a method inside the singleton class's singleton class:

obj's class
   ^
   >
   >
singleton2: some_method()
   ^
   >
   >
singleton1: foo() -> returns singleton1
   ^
   >
   >
  obj

obj.foo.some_method

And you can add as many singleton classes to the method lookup path as
you want. For instance, if you have this call:

obj.foo.some_method.do_stuff

and obj.foo.some_method() returns singleton2, then do_stuff() is being
called as a class method of singleton2, i.e. do_stuff() is a method in a
parent class, singleton3, above singleton2.

So in the original example at the top of the post, if the
creating-a-new-anonymous-class-with-a-method-named-some_method-and-returning-an-instance-of-that-class
is too hard to understand, you could do this:

class MyClass
    def self.some_method(obj, *args)
      puts "MyClass.some_method:"
      puts "obj: #{obj.inspect}"
      puts "args: #{args.inspect}"
    end
  end

  def define_foo(obj, clazz, method)
    obj.singleton_class.class_eval do
      singleton = self

      define_method :foo do
        #Class.new do
          #define_method method do |*args|
            #clazz.send(method, obj, *args)
          #end
        #end.new

        #In here, self is equal to the obj that
        #will eventually call foo()--not obj.singleton_class.
        #Hence, the need to do singleton = self above.

        singleton.singleton_class.class_eval do
          define_method method do |*args|
            clazz.send(method, obj, *args)
          end
        end

        singleton #return the singleton class
      end

    end

  end

  my_obj = "my_obj thing"
  args = [1,2,3]
  define_foo(my_obj, MyClass, :some_method)
  my_obj.foo.some_method(*args)

--output:--
MyClass.some_method:
obj: "my_obj thing"
args: [1, 2, 3]

···

--
Posted via http://www.ruby-forum.com/\.

You can only bind to instances of the original type. You cannot use #unbind and #bind to let a method be called on a different type. But this would be necessary for the OP's requirement to be fulfilled.

irb(main):001:0> class Foo
irb(main):002:1> def self.bar;123;end
irb(main):003:1> end
=> nil
irb(main):004:0> m=Foo.method(:bar).unbind
=> #<UnboundMethod: #<Class:Foo>#bar>
irb(main):005:0> f=Foo.new
=> #<Foo:0x105a24a4>
irb(main):006:0> m.bind(f)
TypeError: singleton method called for a different object
         from (irb):6:in `bind'
         from (irb):6
         from /usr/local/bin/irb19:12:in `<main>'
irb(main):007:0> m.bind(Foo)
=> #<Method: Foo.bar>
irb(main):008:0> m.bind(Foo).call
=> 123

Kind regards

  robert

···

On 16.04.2011 23:14, Brian Candler wrote:

Fearless Fool wrote in post #992929:

I'm sure there's a clean way to do this in Ruby, but I haven't figured
it out.

I'd like to create a method +foo+ that transforms:

    my_obj.foo.some_method(*args)

to

   MyClass.some_method(my_obj, *args)

Not sure, but would bound or unbound methods help you?

bound_method = my_obj.method(:foo)
bound_method.call(*args)

unbound_method = my_obj.class.instance_method(:foo)
unbound_method.bind(my_obj).call(*args)

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Fearless Fool wrote in post #992947:

  ...
  def define_foo(obj, clazz, method)
    obj.singleton_class.class_eval do
      define_method :foo do
        Class.new do
          define_method method do |*args|
            clazz.send(method, obj, *args)
          end
        end.new
      end
    end
  end

That's some mighty fine code-fu...

Um, no it's not. Inspecting from top to bottom: (a) open the singleton
class, (b) define a method, (c) create an instance of a new class (d)
define a method. This has nothing to do with code-fu.

One of the problems with Ruby is that the syntax changes depending on
the compile-time or run-time context, which is a totally arbitrary
distinction. It's a disservice to programmers because it makes them
say "code-fu" when presented with the run-time counterparts of
familiar, mundane compile-time constructs.

Don't get me started about using eval to "fix" that.

Since you must call define_foo() for each object & method you want to
cover, I don't see a lot of advantage to the approach.

You can automate it as much as you like, including removing the need
for define_foo(). Perhaps you took my code too literally.

···

--
Posted via http://www.ruby-forum.com/\.

Thanks everybody!!

@Jesús:

I like your suggestion. It is simple and does what I'm looking for.

@Robert K:

I am sorry, I still do not understand your motivation to have a class
method which receives an instance as first argument.

My motivation is that I was writing a lot of code like this:

module HasXattr
    def xattr_reference(key); Xattr.xattr_reference(self, key); end
    def xattr_store(key, value); Xattr.xattr_store(self, key, value);
end
    def xattr_has_key?(key); Xattr.xattr_has_key?(self, key); end
    def xattr_delete(key); Xattr.xattr_delete(self, key); end
    ...
end

... and I thought to myself: this is Ruby. There must be a better way.
I guess I should have shown this concrete example earlier in the thread.

@Kevin:

One of the problems with Ruby is that the syntax changes depending on
the compile-time or run-time context, which is a totally arbitrary
distinction.

As I said, I came from a scheme background where everything was
syntactically simple and life was simple. Ah, for those days. I guess
I should have said "that's mighty fine Ruby-fu", since your
understanding of Ruby far outstrips mine.

Again, thanks all...

- ff

···

--
Posted via http://www.ruby-forum.com/\.

7stud -- wrote in post #993237:

I guess since obj *is* visible in all the nested blocks, its not
strictly necessary to do the singleton = self trick--you can always get
the singleton class from obj using obj.singleton_class:

  class MyClass
    def self.some_method(obj, *args)
      puts "MyClass.some_method:"
      puts "obj: #{obj.inspect}"
      puts "args: #{args.inspect}"
    end
  end

  def define_foo(obj, clazz, method)

    obj.singleton_class.class_eval do
      define_method :foo do
        obj.singleton_class.singleton_class.class_eval do
          define_method method do |*args|
            clazz.send(method, obj, *args)
          end
        end

        obj.singleton_class
      end

    end

  end

···

--
Posted via http://www.ruby-forum.com/\.

Thanks everybody!!

You're welcome!

I am sorry, I still do not understand your motivation to have a class
method which receives an instance as first argument.

My motivation is that I was writing a lot of code like this:

module HasXattr
     def xattr_reference(key); Xattr.xattr_reference(self, key); end
     def xattr_store(key, value); Xattr.xattr_store(self, key, value);
end
     def xattr_has_key?(key); Xattr.xattr_has_key?(self, key); end
     def xattr_delete(key); Xattr.xattr_delete(self, key); end
     ...
end

.. and I thought to myself: this is Ruby. There must be a better way.
I guess I should have shown this concrete example earlier in the thread.

With my code you could do

module HasXattr
   def xattr # foo in your lingo
     proxy(Xattr)
   end
end

or directly use it in your class

module HasXattr
   def xattr # foo in your lingo
     proxy(Xattr)
   end
end

Then you can do

obj.xattr.has_key? "k"

or

obj.xattr.tap |x|
   x.store "k", "v" unless x.has_key?
end

Btw, what is Xattr? Where does it come from and what does it do? From the looks it seems to be some external storage for attributes associated with your instance which you do not want to store in the instance itself (for whatever reasons). What do you need that for?

Kind regards

  robert

···

On 15.04.2011 17:40, Fearless Fool wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/