Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.ruby > #2915 > unrolled thread
| Started by | Fearless Fool <r@alum.mit.edu> |
|---|---|
| First post | 2011-04-15 00:16 -0500 |
| Last post | 2011-04-16 23:40 +0200 |
| Articles | 13 — 6 participants |
Back to article view | Back to comp.lang.ruby
looking for an "inversion" pattern Fearless Fool <r@alum.mit.edu> - 2011-04-15 00:16 -0500
Re: looking for an "inversion" pattern Fearless Fool <r@alum.mit.edu> - 2011-04-15 01:27 -0500
Re: looking for an "inversion" pattern Robert Klemme <shortcutter@googlemail.com> - 2011-04-15 04:24 -0500
Re: looking for an "inversion" pattern Fearless Fool <r@alum.mit.edu> - 2011-04-15 10:40 -0500
Re: looking for an "inversion" pattern Robert Klemme <shortcutter@googlemail.com> - 2011-04-16 15:29 +0200
Re: looking for an "inversion" pattern Kevin Mahler <kevin.mahler@yahoo.com> - 2011-04-15 02:14 -0500
Re: looking for an "inversion" pattern Fearless Fool <r@alum.mit.edu> - 2011-04-15 02:43 -0500
Re: looking for an "inversion" pattern Kevin Mahler <kevin.mahler@yahoo.com> - 2011-04-15 08:44 -0500
Re: looking for an "inversion" pattern 7stud -- <bbxx789_05ss@yahoo.com> - 2011-04-16 13:20 -0500
Re: looking for an "inversion" pattern 7stud -- <bbxx789_05ss@yahoo.com> - 2011-04-16 13:43 -0500
Re: looking for an "inversion" pattern Jesús Gabriel y Galán <jgabrielygalan@gmail.com> - 2011-04-15 02:45 -0500
Re: looking for an "inversion" pattern Brian Candler <b.candler@pobox.com> - 2011-04-16 16:14 -0500
Re: looking for an "inversion" pattern Robert Klemme <shortcutter@googlemail.com> - 2011-04-16 23:40 +0200
| From | Fearless Fool <r@alum.mit.edu> |
|---|---|
| Date | 2011-04-15 00:16 -0500 |
| Subject | looking for an "inversion" pattern |
| Message-ID | <d0c168880ff1c65dd84fc6d70778ddb2@ruby-forum.com> |
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/.
[toc] | [next] | [standalone]
| From | Fearless Fool <r@alum.mit.edu> |
|---|---|
| Date | 2011-04-15 01:27 -0500 |
| Message-ID | <7c9986702d2a6acd3748e6cca228d8da@ruby-forum.com> |
| In reply to | #2915 |
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/.
[toc] | [prev] | [next] | [standalone]
| From | Robert Klemme <shortcutter@googlemail.com> |
|---|---|
| Date | 2011-04-15 04:24 -0500 |
| Message-ID | <BANLkTikFjzEuhMevuXJ6ZGSHA6h=MNTnjA@mail.gmail.com> |
| In reply to | #2917 |
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.
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. :-)
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
--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
[toc] | [prev] | [next] | [standalone]
| From | Fearless Fool <r@alum.mit.edu> |
|---|---|
| Date | 2011-04-15 10:40 -0500 |
| Message-ID | <9781d8dfa4b6039362d09f98e7b7036e@ruby-forum.com> |
| In reply to | #2927 |
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/.
[toc] | [prev] | [next] | [standalone]
| From | Robert Klemme <shortcutter@googlemail.com> |
|---|---|
| Date | 2011-04-16 15:29 +0200 |
| Message-ID | <90tjukFgaiU1@mid.individual.net> |
| In reply to | #2949 |
On 15.04.2011 17:40, Fearless Fool wrote:
> 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
--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
[toc] | [prev] | [next] | [standalone]
| From | Kevin Mahler <kevin.mahler@yahoo.com> |
|---|---|
| Date | 2011-04-15 02:14 -0500 |
| Message-ID | <fe2a1539e193df32600e0c6768313e7e@ruby-forum.com> |
| In reply to | #2915 |
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/.
[toc] | [prev] | [next] | [standalone]
| From | Fearless Fool <r@alum.mit.edu> |
|---|---|
| Date | 2011-04-15 02:43 -0500 |
| Message-ID | <8168e82bf280948bb58750b7b5e9632e@ruby-forum.com> |
| In reply to | #2921 |
@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/.
[toc] | [prev] | [next] | [standalone]
| From | Kevin Mahler <kevin.mahler@yahoo.com> |
|---|---|
| Date | 2011-04-15 08:44 -0500 |
| Message-ID | <7955c9f83df5347bbe5fc000bc9e93f6@ruby-forum.com> |
| In reply to | #2922 |
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/.
[toc] | [prev] | [next] | [standalone]
| From | 7stud -- <bbxx789_05ss@yahoo.com> |
|---|---|
| Date | 2011-04-16 13:20 -0500 |
| Message-ID | <ae7c406b849430b336b88ff7712ea683@ruby-forum.com> |
| In reply to | #2921 |
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/.
[toc] | [prev] | [next] | [standalone]
| From | 7stud -- <bbxx789_05ss@yahoo.com> |
|---|---|
| Date | 2011-04-16 13:43 -0500 |
| Message-ID | <56fa7979e91b731d6aa10e9f26926e09@ruby-forum.com> |
| In reply to | #3018 |
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/.
[toc] | [prev] | [next] | [standalone]
| From | Jesús Gabriel y Galán <jgabrielygalan@gmail.com> |
|---|---|
| Date | 2011-04-15 02:45 -0500 |
| Message-ID | <BANLkTin7haFE5RJKAKRVsto0ohsmAFEsyw@mail.gmail.com> |
| In reply to | #2915 |
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. 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.
[toc] | [prev] | [next] | [standalone]
| From | Brian Candler <b.candler@pobox.com> |
|---|---|
| Date | 2011-04-16 16:14 -0500 |
| Message-ID | <c9351f67cbcb09e73dec51721abdc873@ruby-forum.com> |
| In reply to | #2915 |
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/.
[toc] | [prev] | [next] | [standalone]
| From | Robert Klemme <shortcutter@googlemail.com> |
|---|---|
| Date | 2011-04-16 23:40 +0200 |
| Message-ID | <90ugngF3ieU1@mid.individual.net> |
| In reply to | #3029 |
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)
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
--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.ruby
csiph-web