Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > class_eval doesn't find const_missing

Reply
Thread Tools

class_eval doesn't find const_missing

 
 
Andrew Berkeley
Guest
Posts: n/a
 
      04-21-2011
I am trying to write a DSL which uses method_missing and const_missing
to catch upper and lowercase names (specified in isolation) and fetch
the asscoated (already initialized) objects. This works great until I
need to use class_eval which seemingly doesn't follow the custom
const_missing method.

Here's a more simple example of a class with a constant and
#method_missing and #const_missing methods.

class DummyClass

NAME = 'dummy constant'

def self.method_missing(method,*args,&block)
return "this #{method} was captured by #method_missing"
end

def self.const_missing(constant)
return "this #{constant} was captured by #const_missing"
end

end

Accessing the constant is no problem
> DummyClass::NAME

=> "dummy constant"

Unknown methods and constants are handled as expected
> DummyClass::ANOTHER_CONSTANT

=> "this ANOTHER_CONSTANT was captured by #const_missing"
> DummyClass.some_method

=> "this some_method was captured by #method_missing"

Accessing the constant via class_eval is variable - it works when
evaluating strings but not blocks.
> DummyClass.class_eval "NAME"

=> "dummy constant"
> DummyClass.class_eval {NAME}

NameError: uninitialized constant NAME
from (irb):14
from (irb):14:in `class_eval'
from (irb):14
from :0

This is partly understood since blocks are scoped to the context in
which they were created. But even if the explicit constant is not
recognised, why isn't the class #const_missing method invoked?

Does the class_eval method allow the method_missing method to be used?
> DummyClass.class_eval "dummy_method"

=> "this dummy_method was captured by #method_missing"
> DummyClass.class_eval {dummy_method}

=> "this dummy_method was captured by #method_missing"

Yes. #method_missing works as expected, in both string and block
formats. So only #const_missing is causing a problem.

Interestingly, an explicit call to #const_missing inside a class_eval
block DOES work.
> DummyClass.class_eval {const_missing :ANOTHER_CONSTANT}

=> "this ANOTHER_CONSTANT was captured by #const_missing"

Anybody understand this, and is there a way to get around it?

Cheers

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

 
Reply With Quote
 
 
 
 
Brian Candler
Guest
Posts: n/a
 
      04-21-2011
If you add this code:

class Object
def self.const_missing(constant)
return "this #{constant} found in obj!"
end
end

Then you get the following:

>> DummyClass.class_eval "NAME"

=> "dummy constant"
>> DummyClass.class_eval {NAME}

=> "this NAME found in obj!"
>> NAME

=> "this NAME found in obj!"

Not sure if that helps you much, but it seems that class_eval doesn't
affect the constant lookup in the way that you'd like.

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

 
Reply With Quote
 
 
 
 
Stephen Prater
Guest
Posts: n/a
 
      04-21-2011
http://stackoverflow.com/questions/3...val-class-eval

Const lookup varies between 1.8, 1.9.1, and 1.9.2.

Basically, constants are lexically scoped.

You can use "const_get" I believe to lookup your constant in the
current binding rather than in the lexical scope.

stephen

On Apr 21, 2011, at 2:20 PM, Andrew Berkeley wrote:

> I am trying to write a DSL which uses method_missing and const_missing
> to catch upper and lowercase names (specified in isolation) and fetch
> the asscoated (already initialized) objects. This works great until I
> need to use class_eval which seemingly doesn't follow the custom
> const_missing method.
>
> Here's a more simple example of a class with a constant and
> #method_missing and #const_missing methods.
>
> class DummyClass
>
> NAME = 'dummy constant'
>
> def self.method_missing(method,*args,&block)
> return "this #{method} was captured by #method_missing"
> end
>
> def self.const_missing(constant)
> return "this #{constant} was captured by #const_missing"
> end
>
> end
>
> Accessing the constant is no problem
>> DummyClass::NAME

> => "dummy constant"
>
> Unknown methods and constants are handled as expected
>> DummyClass::ANOTHER_CONSTANT

> => "this ANOTHER_CONSTANT was captured by #const_missing"
>> DummyClass.some_method

> => "this some_method was captured by #method_missing"
>
> Accessing the constant via class_eval is variable - it works when
> evaluating strings but not blocks.
>> DummyClass.class_eval "NAME"

> => "dummy constant"
>> DummyClass.class_eval {NAME}

> NameError: uninitialized constant NAME
> from (irb):14
> from (irb):14:in `class_eval'
> from (irb):14
> from :0
>
> This is partly understood since blocks are scoped to the context in
> which they were created. But even if the explicit constant is not
> recognised, why isn't the class #const_missing method invoked?
>
> Does the class_eval method allow the method_missing method to be used?
>> DummyClass.class_eval "dummy_method"

> => "this dummy_method was captured by #method_missing"
>> DummyClass.class_eval {dummy_method}

> => "this dummy_method was captured by #method_missing"
>
> Yes. #method_missing works as expected, in both string and block
> formats. So only #const_missing is causing a problem.
>
> Interestingly, an explicit call to #const_missing inside a class_eval
> block DOES work.
>> DummyClass.class_eval {const_missing :ANOTHER_CONSTANT}

> => "this ANOTHER_CONSTANT was captured by #const_missing"
>
> Anybody understand this, and is there a way to get around it?
>
> Cheers
>
> --
> Posted via http://www.ruby-forum.com/.
>
>



 
Reply With Quote
 
7stud --
Guest
Posts: n/a
 
      04-21-2011
Andrew Berkeley wrote in post #994369:
>
> Interestingly, an explicit call to #const_missing inside a class_eval
> block DOES work.
>> DummyClass.class_eval {const_missing :ANOTHER_CONSTANT}

> => "this ANOTHER_CONSTANT was captured by #const_missing"
>
> Anybody understand this, and is there a way to get around it?
>


This line:

DummyClass.class_eval {const_missing :ANOTHER_CONSTANT}

is equivalent to:

DummyClass.class_eval {
self.const_missing(:ANOTHER_CONSTANT)
}

And because class_eval() changes self inside the block to be equal to
the receiver, the above is equivalent to:

DummyClass.class_eval {
DummyClass.const_missing(:ANOTHER_CONSTANT)
}

...producing the output you see.


Also, note the output here:

DummyClass.class_eval do
puts self::NAME
end

--output:--
dummy constant

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

 
Reply With Quote
 
7stud --
Guest
Posts: n/a
 
      04-21-2011
Stephen Prater wrote in post #994391:
>

http://stackoverflow.com/questions/3...val-class-eval
>
> Const lookup varies between 1.8, 1.9.1, and 1.9.2.
>
> Basically, constants are lexically scoped.
>
> You can use "const_get" I believe to lookup your constant in the
> current binding rather than in the lexical scope.
>


That works for me in ruby 1.9.2:

DummyClass.class_eval do
puts const_get(:NAME)
end

--output:--
dummy constant

That makes sense because the call is really:

puts self.const_get(:NAME)

and because self is equal to DummyClass, that is equivalent to:

puts DummyClass.const_get(:NAME)

which like class_eval'ing a string does the lookup in the "directory"
DummyClass.

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

 
Reply With Quote
 
7stud --
Guest
Posts: n/a
 
      04-21-2011
7stud -- wrote in post #994396:
>
> In "The Well-Grounded Rubyist" David Black explains that constants are
> like files in a file system, and depending on what "directory" you are
> currently in, it will determine the "path name" to the constant that you
> are interested in retrieving. It seems that class_eval does not affect
> the path name to a constant. But then I don't understand how
> class_eval'ing a string changes that.
>



Here is a blog post from 2007 asking the exact same question:

http://www.pgrs.net/2007/9/12/ruby-c...-in-class_eval

As one person replied, constants are looked up by the parser, so their
lexical scope determines the proper 'path' to the constant; while
eval'ing a string happens in the 'dynamic scope' at runtime.

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

 
Reply With Quote
 
Andrew Berkeley
Guest
Posts: n/a
 
      04-22-2011
Thanks People - very helpful and seems pretty clear what's going on
then. A lesson learned for me!

The Object monkeypatch appears to work well for what I was wanting to
do..

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

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Module#const_missing redefinition El Barto Ruby 2 10-05-2005 08:26 PM
Obtaining object in const_missing T. Sawyer Ruby 3 08-20-2004 04:04 PM
const_missing Elias Athanasopoulos Ruby 5 07-14-2004 06:54 PM
Using Module#const_missing for resolving "external" classes Thomas Ruby 1 09-01-2003 09:56 PM
const_missing Hal E. Fulton Ruby 2 08-21-2003 07:25 PM



Advertisments