I'm looking at converting some code over from BlankSlate to BasicObject,
but hit a roadblock: I can't figure out any way to do the equivalent of
class Foo < BlankSlate
def initialize
@secret = 99
end
end
foo = Foo.new
foo.instance_eval {@secret}
Any suggestions?
- Sam Ruby
on 04.01.2008 04:07
on 04.01.2008 05:26
Hi,
In message "Re: BasicObject.instance_eval"
on Fri, 4 Jan 2008 12:06:06 +0900, Sam Ruby <rubys@intertwingly.net>
writes:
|I'm looking at converting some code over from BlankSlate to BasicObject,
|but hit a roadblock: I can't figure out any way to do the equivalent of
|
|class Foo < BlankSlate
| def initialize
| @secret = 99
| end
|end
|
|foo = Foo.new
|foo.instance_eval {@secret}
|
|Any suggestions?
Hmm, that's tough question. Since BasicObject should not have as few
methods as possible to do the method_missing trick, instance_eval is
not among one of few methods it has.
Currently, it has ==, equal? !, !=, __send__, method_missing,
singleton_method_added, singleton_method_removed, and
singleton_method_undefined. Should we add instance_eval as well?
matz.
on 04.01.2008 05:33
On Jan 3, 2008 10:06 PM, Sam Ruby <rubys@intertwingly.net> wrote: > foo.instance_eval {@secret} > > Any suggestions? Interesting situation. Part of me would want Ruby to allow something like: # Doesn't work obviously... Object.instance_method(:instance_eval).bind(foo).call {@secret} On the other hand, it isn't hard to write a method that can be used to extract information w/o dirtying the interface: class << BasicObject def accessor_for(name) @accessors_for ||= {} unless @accessors_for[name] tmp = "__tmp#{Thread.current.object_id}__" class_eval %[ def #{tmp} #{name} end ] accessors_for[name] = instance_method(tmp) undef_method(tmp) end lambda {|obj| @accessors_for[name].bind(obj).call} end end Now you can use: BasicObject.accessor_for('@test').call(foo) Not perfect (I really don't like using class_eval + undef_method like that), but it does work and it does avoid making a complete mess of the namespace with __ methods. Maybe an alternative that Ruby 1.9 could provide would be a few useful methods like instance_eval available as unbound methods via the class: # No need to force Object instance methods to work on BasicObject # if there are a few special cases made via the class. BasicObject.unbound_instance_eval.bind(foo).call {@secret} Brian.
on 04.01.2008 05:40
On Jan 3, 2008, at 10:25 PM, Yukihiro Matsumoto <matz@ruby-lang.org> wrote: > | > > Hmm, that's tough question. Since BasicObject should not have as few > methods as possible to do the method_missing trick, instance_eval is > not among one of few methods it has. > > Currently, it has ==, equal? !, !=, __send__, method_missing, > singleton_method_added, singleton_method_removed, and > singleton_method_undefined. Should we add instance_eval as well? > > matz. One of the most frequent things I've done in the past with BlankSlate is to define method_missing and delegate to it by passing the object a block via instance_eval. I am all for keeping BasicObject basic but instance_eval is, at least for me, a very common use case. marcel
on 04.01.2008 05:41
Yukihiro Matsumoto wrote: > | @secret = 99 > not among one of few methods it has. > > Currently, it has ==, equal? !, !=, __send__, method_missing, > singleton_method_added, singleton_method_removed, and > singleton_method_undefined. Should we add instance_eval as well? The code in question is from Builder::CSS [1]. Adding instance_eval would help this one use case. An alternative would be to add a method to Proc or perhaps to Kernel. If none of those were done, I see no reason why BlankSlate couldn't continue to be used. I guess the question comes down to: what purpose was BasicObject intended for? - Sam Ruby [1] http://builder.rubyforge.org/svn/trunk/lib/builder/css.rb
on 04.01.2008 05:45
On Jan 3, 2008, at 10:32 PM, Brian Mitchell wrote: > Not perfect (I really don't like using class_eval + undef_method like > that), but it does work and it does avoid making a complete mess of > the namespace with __ methods. Maybe an alternative that Ruby 1.9 > could provide would be a few useful methods like instance_eval > available as unbound methods via the class: > > # No need to force Object instance methods to work on BasicObject > # if there are a few special cases made via the class. > BasicObject.unbound_instance_eval.bind(foo).call {@secret} Or even have a BasicObject method, which by default just reurns a BasicObject class. Then define + on it, which then binds those unbound methods into a singleton instance, so you could write class Foo < BasicObject + :instance_eval ... end Dave
on 04.01.2008 12:44
Hi -- On Fri, 4 Jan 2008, Brian Mitchell wrote: >> foo = Foo.new > extract information w/o dirtying the interface: > ] > accessors_for[name] = instance_method(tmp) > undef_method(tmp) > end > lambda {|obj| @accessors_for[name].bind(obj).call} > end > end > > Now you can use: > > BasicObject.accessor_for('@test').call(foo) However, until the question of the metaclass/Class thing is resolved, you end up with this: irb(main):001:0> class << BasicObject; def x; 1; end; end => nil irb(main):002:0> String.x => 1 In other words, #accessor_for will be defined directly on Class. As per the other thread, I believe this must be a bug, but I'm waiting for a pronouncement. David
on 04.01.2008 15:20
On Jan 3, 2008, at 10:25 PM, Yukihiro Matsumoto wrote: > | > > Hmm, that's tough question. Since BasicObject should not have as few > methods as possible to do the method_missing trick, instance_eval is > not among one of few methods it has. > > Currently, it has ==, equal? !, !=, __send__, method_missing, > singleton_method_added, singleton_method_removed, and > singleton_method_undefined. Should we add instance_eval as well? I feel like instance_eval() is a pretty basic Ruby method and thus valuable to have in BasicObject. I also feel like there's not much danger that it will conflict with an intent to catch an "instance_eval" message in method_missing(). James Edward Gray II
on 04.01.2008 15:52
On Jan 4, 2008 6:43 AM, David A. Black <dblack@rubypal.com> wrote: > >> def initialize > > > > tmp = "__tmp#{Thread.current.object_id}__" > > end > irb(main):002:0> String.x > => 1 > > In other words, #accessor_for will be defined directly on Class. As > per the other thread, I believe this must be a bug, but I'm waiting > for a pronouncement. Good catch. I think it might be related to [ruby-core:14690]. Brian.
on 04.01.2008 17:43
Hi,
In message "Re: BasicObject.instance_eval"
on Fri, 4 Jan 2008 13:40:52 +0900, Sam Ruby <rubys@intertwingly.net>
writes:
|Adding instance_eval would help this one use case. An alternative would
|be to add a method to Proc or perhaps to Kernel. If none of those were
|done, I see no reason why BlankSlate couldn't continue to be used.
|
|I guess the question comes down to: what purpose was BasicObject
|intended for?
The primary purpose is to replace BlankSlate so that defining
instance_eval seems important. I will add it to the trunk.
Thank you.
matz.
on 04.01.2008 17:56
Hi,
In message "Re: BasicObject.instance_eval"
on Fri, 4 Jan 2008 13:45:18 +0900, Dave Thomas <dave@pragprog.com>
writes:
|Or even have a BasicObject method, which by default just reurns a
|BasicObject class. Then define + on it, which then binds those
|unbound methods into a singleton instance, so you could write
|
|
| class Foo < BasicObject + :instance_eval
| ...
| end
Interesting idea. I'd rather try similar idea with Traits in Ruby
2.0 in the future.
matz.
on 05.01.2008 01:46
James Gray wrote: >> | >> > danger that it will conflict with an intent to catch an "instance_eval" > message in method_missing(). Perhaps to be sure it should have an "internal" name... __internal_eval__ or something - Charlie
on 05.01.2008 01:48
Charles Oliver Nutter wrote:
> __internal_eval__ or something
Oops, of course I meant __instance_eval__
- Charlie