Access to permanent

Why can't I access “B” in the next from “A”, but maybe from the main environment?

module A; end A.instance_eval{B=1} B #=> 1 A::B #=> uninitialized 
+6
source share
4 answers

The idiomatic way to do this would be

  A.const_set(:B, 1) A::B #=> 1 

As for why this would not work, in Ruby 1.8 and 1.9.2+ (in 1.9.1) it was different; constant search is lexically limited. I found a good blog post with an explanation. Quote:

Please note that these rules apply to the constant definition as well as to the search. In 1.8 and 1.9.2, the constant defined in the class_evaluated block will be defined in the attached lexical field, and not in the receiver volume.

The same is true for instance_eval .

+3
source

From the instance_eval documentation (my attention):

Computes a string containing the Ruby source code or the given block in the receiver context (obj). To set the context, the self variable is set to obj, and the code executes , giving the code access to the objs instance variables.

Nothing more is being done here. In particular, persistent assignment is performed in the covering context of a block. Note:

 irb(main):001:0> module A irb(main):002:1> module B; end irb(main):003:1> B.instance_eval { C = 1 } irb(main):004:1> end => 1 irb(main):006:0> A::C => 1 
+4
source

Because.,.

., constants that are not defined in the class or module are defined by the global scope.

What is important for continuous determination is the covering lexical domain, and not the current receiver or the self value.

+4
source
 module A; end A.class_eval{B=1} B # Undefined A::B # 1 

As to why this works, I'm not sure. Sometimes I use metaprogramming this way, creating very meta-frames like Small Eigen Collider, but not in everyday work.

+1
source

Source: https://habr.com/ru/post/912782/


All Articles