Proc#call Proc#call , the lambda construct, as well as the concepts of a class instance variable (instances variables are variables whose names begin with the dog) and class variables (class variables are variables whose names begin with two dogs):Proc Proc - class for blocks that can be called unnamed (anonymous) methods that can be created directly in expressions;b.call(*args) expression executes b , and returns the result of the execution; instead of call you can use square brackets.lambda {|a,...| ... } lambda {|a,...| ... } - creates a block, for example b = lambda {|x,y,z| x+y+z} b = lambda {|x,y,z| x+y+z} will create a block that adds three numbers, in particular, the expression b[1,2,3] will return 6 ;{ ... } or do ... end ; for example ary.inject{|a,b| a * b} ary.inject{|a,b| a * b} will pass inside the inject method a block that multiplies two numbers;Exception “ uninitialized class variable .. in ... ” occurs;a = 1 <br>
b = lambda { puts a }<br>
b.call # 1 <br>
a = 2 <br>
b.call # 2 <br>
# - <br>
class Abc <br>
attr_accessor :bar <br>
def foo <br>
@bar ||= 0 <br>
x = 5 <br>
lambda { puts @bar , x, self .class; }<br>
end <br>
end <br>
<br>
x = 10 <br>
a = Abc .new<br>
b = a.foo<br>
b.call # 0, 5 Abc <br>
a.bar += 1 <br>
x = 10 <br>
b.call # 1, 5, Abc <br>
# bar a b, <br>
# ( ) -- <br>
# ; - <br>
# foo, @a x, <br>
# , <br>
# , foo . <br>
<br>
lambda or with a block passed to the method, either with braces or with a do ... end construct.foo method on the instance a of some class Abc .@bar and a block is returned, whichx and self.class .b.call " is b.call , the @bar variable @bar not visible (or rather, it simply does not exist in this context).b block leads to the output of the variable @bar object a , which, as it were, is not suitable here. This is explained by the fact that the block was created in the context of the execution of the foo method of the object a , and in this context all the instance variables of the object a were visible.class Abc <br>
attr_accessor :block <br>
def do_it <br>
@a = 1 <br>
block.call<br>
end <br>
end <br>
<br>
c = 1 <br>
a = Abc .new<br>
a.block = lambda { puts " c= #{ c } " }<br>
a.do_it # 1; <br>
# - <br>
# <br>
<br>
a.block = lambda { puts " @a= #{ @a .inspect } " }<br>
a.do_it # nil, .. @ , <br>
# " " a.block. <br>
# a.block Abc#foo <br>
# Abc#foo a.block <br>
lambda construction:class Abc <br>
def do_it (&block)<br>
@a = 1 <br>
block.call<br>
end <br>
end <br>
<br>
c = 1 <br>
a = Abc .new<br>
a.do_it {puts " c= #{ c } " } <br>
a.do_it { puts " @a= #{ @a .inspect } " }<br>
<br>
self equal to this object are visible from the body of the method. Instance variables of other objects are not visible.self as some method that can be defined in its own way in each context.def and class constructs. They usually lead to a change in the visibility of the instance variables, class variables and a change in the value of the expression self .Ruby - this is an object of class Binding Binding Each block has a binding , and this binding can be passed as the second argument to the eval method: “run this code in this context”:class Abc <br>
attr_accessor :x <br>
def inner_block <br>
lambda {| x | x * @factor }<br>
end <br>
end <br>
<br>
a = Abc .new<br>
b = a.inner_block<br>
eval ( " @factor = 7 " , b.binding)<br>
puts b[ 10 ] # 70 <br>
eval ( " @x = 6 * @factor " , b.binding)<br>
puts ax # 42
instance_eval :class Abc <br>
attr_accessor :x <br>
end <br>
<br>
a = Abc .new<br>
a.instance_eval( " @factor = 7 " )<br>
a.instance_eval( " @x = 6 * @factor " )<br>
puts ax # 42
Binding class object) to the concept of a real context, we need to store both the call stack and all objects that are in this stack, and this becomes a real problem. Example of access to the call stack:def backtrace <br>
begin <br>
raise Exception .new( '' )<br>
rescue Exception =>e<br>
e.backtrace[ 1 ..- 1 ]<br>
end <br>
end <br>
<br>
def f <br>
g<br>
end <br>
<br>
def g <br>
puts backtrace.join( " \n " )<br>
end <br>
<br>
f<br>
<br>
make_rescued.rb: 15: in `g ' make_rescued.rb: 11: in `f ' make_rescued.rb: 18
ary.map{|i| i*i} ary.map{|i| i*i} or users.map{|u| e.email} users.map{|u| e.email} , I would not want to deal with closures. But often it is simply not possible to predict that from the visible namespace will be used by the block, since, in principle, an eval or a method call with an associated block, which, in turn, can request the block.binding value passed to it, can occur in a block . do with him what he wants. You should also be afraid of the send(m, *args) expression, since this can be send('eval', *args) . It is possible to create a block with a minimal context as follows: " block = class << Object.new; lambda { ... } end ". Perhaps it makes sense to optimize (first of all I want to get rid of the call stack clinging to the closures) to come up with a new language construct like glob_do ... end to create blocks whose general context is a global context in which self is equal to the special main object.Source: https://habr.com/ru/post/50665/
All Articles