Programming, which I occasionally continue to do, is gradually changing its style and is increasingly associated with metaprogramming. At the same time, it is impossible to say that normal programming is disgusted with me. Just like any programmer, I am looking for ways to become increasingly modular, short, intelligible, and flexible code, and in metaprogramming I see an untapped potential (despite the long-term endless Internet flood on metaprogramming going from Lisp). :)
I want to start a blog dedicated to Ruby metaprogramming.
The choice of Ruby is connected with the fact that the culture of metaprogramming in the environment of Ruby programmers has already been largely formed, and the elements of metaprogramming have become the fabric of the daily work of the Ruby programmer, and, besides, he is better known to me than other dynamic languages.
I read and lecture on Ruby & Rails & Metaprogramming at the Physics and Technology Institute; materials of one of the lectures can be found 
here . It is briefly about the main thing in the pictures.
')
In this blog I will try to present the topic consistently and in detail. I take a deep breath in advance, because the task is not simple. I hope for your encouraging feedback.
I'll start with a simple one - with a definition.
Metaprogramming in scripting languages ​​is a style of writing programs, which usefully uses the ability to change the namespace at runtime.
The namespace refers to classes, methods, and variables (global, local, instance variable, and class variables). Change means creating, changing, and deleting classes, methods, and variables.
It must be said that in most scripting languages ​​the namespace is constructed in no other way than in runtime mode. But many do not remember this, so I emphasized it in the definition. If we remove the unnecessary mention of runtime from the definition, then the phrase “with benefit” will remain. So the essence of it.
An example of useless programming: 
eval "s = 'eval s'; eval s"Calculator
I remember how in deep childhood I wrote for BK-0010 a program for plotting functions. The functions are hardcoded and when the program was running you could only select one function from the list and specify the range [x0, x1], and the range along the Y axis (about the miracle of programmer thought! Capable of automating everything and everyone) was automatically selected by the program.
I looked at my program in BASIC and experienced ecstasy. But then a sad thought came to me: “Ehh !!! And it’s a pity all the same, that it’s impossible to drive a formula of the function I need right during the program’s execution.
NDA ... 8th grade, 1992, Kirovo-Chepetsk. A lot of water has flowed since then, but the problems are the same!
Why am I doing this?
Here is the code for an interactive “calculator” in Ruby:
 while line = readline
   puts eval (line) .inspect
 end
or better
 while (print ">"; true) and line = readline
   puts eval (line) .inspect
 end
or right
require ' readline ' 
while line = Readline .readline ( " > " ) 
begin 
puts eval (line) .inspect 
rescue => e 
puts e.to_s + " \ n " + e.backtrace.join ( " \ n " ) 
end 
end 
Execution Example:
 artem @ laptop: ~ / meta-lectures $ ruby ​​console.rb 
 > 1 + 2
 3
 > "hello"
 "hello"
 > def fib (n) (0..1) === n?  1: fib (n-1) + fib (n-2) end
 nil
 > (0 ... 10) .map {| n |  fib (n)}
 [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
 > 1/0
 (eval): 1: in `/ ': divided by 0
 console.rb: 4
 (eval): 1  
 > exit
 artem @ laptop: ~ / meta-lectures $
In scripting languages, there is an 
eval method that receives a string and executes this string in the current context as (almost so) as if it were written by a programmer at the place of the 
eval call.
Actually, the means similar to 
eval are in compiled programming languages.
By the way, I would not refer the 
eval method to metaprogramming and would even call it an extremely harmful method for this occupation. Interactive ruby ​​| python | perl | ...- shell - perhaps one of the few examples where it should be used. Let's talk about the harm of the 
eval method further.
attr_accessor
To determine the attributes of instances of a class, the 
attr_accessor construct 
attr_accessor used even by ruby ​​novices, it is not always true that this is a beast.
The meaning of the expression 
attr_accessor from the following statement: code
class Song 
attr_accessor : title ,: length 
end 
equivalent to (by result) code
class Song 
def title 
@title 
end 
def title = (v) 
@title = v 
end 
def length 
@length 
end 
def length = (v) 
@length = v 
end 
end 
So much for the definition!
With the naked eye, it can be seen that 
attr_accessor is useful because it responds to the programmer’s internal desire to 
attr_accessor code short and intelligible. The 
attr_accessor construction can be translated as “I want set- and get-methods for the following attributes of class instances”.
The design of 
attr_accessor not even an unknown beast at all (read - it is not a built-in language construct), but an ordinary method that you can program yourself. Let's do this with the 
eval method.
def attr_accessor (* methods) 
methods.each do | method | 
eval % { 
def # { method } 
@ # { method } 
end 
def # { method } = (v) 
@ # { method } = v 
end 
     } 
end 
end 
Now, 
attr_accessor , receiving as an argument an array of attribute names, for each name, executes lines of code that define the corresponding set and get methods.
The ability to write methods like 
attr_accessor appeared because Ruby does not have the concept of defining a class or method. Having written the line " 
class Song " we just moved to some new context in which you can do normal calculations, and the construction " 
def xxx() ... end " is just one of the expressions, the result of which is always 
nil (in ruby ​​v1.8 ), and the side effect is manifested in the emergence of the " 
xxx " method in the class in the context of which this construction was executed.
Function definition fulfilled? Switched to class context? What kind of nonsense? - it is not known from where the C ++ programmer, who came here, asks. Yes exactly.
A “ 
class Song ” does not frame the definition of a class in front, but makes a transition to a special context in which the namespace scope changes; that is, there are some new methods that we can call in this context, the meanings and effects of certain instructions change, etc. etc.
The text " 
def xxx() ... end " is really an expression and is executed by the Ruby virtual machine. In this case, the inside of the method definition is not executed, but the code is translated into byte and is stored under the method name.
Q: What does class context mean?
A: This is the context in which the expression self equals some class.
Run the following code:
puts " hi1 from # { self .inspect } " 
class Abc 
puts " hi2 from # { self .inspect } " 
def hi 
puts " hi3 from # { self .inspect } " 
end 
end 
Lines with hi1 and hi2 will be printed. You will see the line with hi3 if you add
 Abc.new.hi
Total get:
 artem @ laptop: ~ / meta-lectures $ ruby ​​self_in_contexts.rb 
 hi1 from main
 hi2 from abc
 hi3 from # <Abc: 0xb7c3d9dc>
 artem @ laptop: ~ / meta-lectures $
You need to understand that when you write
 my_method (arg1, arg2)
then essentially the front is implicitly substituted with " 
self. ":
 self.my_method (arg1, arg2)
But these two expressions are not equivalent in some cases.For example, when my_method is a private method, the expression self.my_method will fail to invoke the private method. These features of the Ruby implementation are private methods and there are some methods that cannot be called via a dot.
 Okay, stop talking. 
attr_accessor above 
attr_accessor code to make it work:
class Module 
def attr_accessor (* methods) 
methods.each do | method | 
class_eval % { 
def # { method } 
@ # { method } 
end 
def # { method } = (v) 
@ # { method } = v 
end 
       } 
end 
end 
end 
What have we done? We placed the method definition in the context of the 
Module class and replaced 
eval with 
class_eval .
Why did we do that? There are reasons:
* It is not good to write methods without understanding for what objects they will be available. We need to write a method 
attr_accessor , which can be used in the context of classes (instances of class 
Class ) and modules (instances of class 
Module ). The 
Class class inherits from the 
Module class, therefore it is sufficient to define this method as a method of 
Module instances, then it will be available for both modules and classes.
* The 
class_eval method has its differences from 
eval , in particular, the latter, when executing the expression " 
def ... end ", will create a definition of a method locally living inside the 
attr_accessor method and available only during the execution of the 
attr_accessor method (this is the undocumented 
def attr_accessor inside 
def ). The 
class_eval method executes the given code in the correct context, so that the " 
def " begin to produce the desired result. The 
class_eval method 
class_eval actively used in metaprogramming precisely in the variant where its argument is a block, not a string.
So now the code works. But he is wrong. There are other 
wrong decisions , including without the " 
class Module " and " 
class_eval ". Here is one of them:
def attr_accessor (* methods) 
methods.each do | method | 
eval % { 
class # { self } 
def # { method } 
@ # { method } 
end 
def # { method } = (v) 
@ # { method } = v 
end 
end 
     } 
end 
end 
The last option is bad because you can call it not in the context of a class and get something bad, depending on what the 
self expression is in this context. For example:
s = " Class " 
s.instance_eval { attr_accessor : hahaha } 
Array .hahaha = 3 # in an unexpected way. The haray attribute of Array appeared. 
puts Array .hahaha # 
THE MOST IMPORTANT:
The described definitions of 
attr_assessor using 
eval are bad because they are not protected from the malicious intent of the enemy, nor from the stupidity of the programmer: if the value of the 
method variable is not a valid string for the method name, for example, the string " 
llalala(); puts `cat /etc/passwd`; puts ", the consequences will be unpredictable. You may not see any errors (exceptions) while executing the program; surprises will get only when “when the rocket will already fly” (c). There is nothing worse than errors that appear late, when the ends are no longer found.
Let's write, finally, the correct definition of 
attr_accessor . He, unlike the wrong, is unique:
class Module 
def attr_accessor (* methods) 
methods.each do | method | 
raise TypeError .new ( " method name is not symbol " ) unless method.is_a? ( Symbol ) 
define_method (method) do 
instance_variable_get ( " @ # { method } " ) 
end 
define_method ( " # { method } = " ) do | v | 
instance_variable_set ( " @ # { method } " , v) 
end 
end 
end 
end 
attr_accessor with default value
We often write attributes with a default value. We do this using the idiom " 
||= ", which roughly translates as "initialize what is left, what is right if it has not yet been initialized":
 class Song def length @length ||= 0 end def title @title ||= "no title" end end Song.new.length  
after this definition, the value of the 
length attribute of the new song will be 0.
According to my wish, according to my wish ... let this code work the way I want !!!:
 class Song
   attr_accessor: length,: default => 0
   attr_accessor: title,: default => "no title"
 end
Let's write for learning purposes the wrong code using 
class_eval from the string:
class Module 
def attr_accessor (* methods) 
options = methods.last.is_a? ( Hash )? methods.pop: {} 
methods.each do | method | 
class_eval % { 
def # { method } 
\ # never write like that! 
@ # { method }   # { " || = # { options [ : default ] } " if options [ : default ] } 
end 
def # { method } = (v) 
@ # { method } = v 
end 
       } 
end 
end 
endMay there be a miracle !!!
 class Song
   attr_accessor: length,: default => 42
 end
 puts Song.new.length # prints 42 !!!
Wrong code also sometimes works. But this, of course, is no reason not to be fired by the programmer who writes it.
By doing
class Song 
attr_accessor : length ,: default => 42 
attr_accessor : title ,: default => " no title " 
end 
puts Song .new.length # prints 42 !!! 
puts Song .new.title # oooooops !!! 
we get mysterious:
 artem @ laptop: ~ / meta-lectures $ ruby ​​bad_attr_accessor.rb 
 42
 (eval): 5: in `title ': stack level too deep (SystemStackError)
	 from (eval): 5: in `title '
	 from bad_attr_accessor.rb: 27
 artem @ laptop: ~ / meta-lectures $ 
Why did such a nuisance arise? The fact is that there is a fundamental problem: inserting some objects into the line is simply impossible.
Correctly the problem of 
attr_accessor with the default value is solved as follows:
class Module 
def attr_accessor (* methods) 
options = methods.last.is_a? ( Hash )? methods.pop: {} 
methods.each do | method | 
raise TypeError .new ( " method name is not symbol " ) unless method.is_a? ( Symbol ) 
define_method (method) do 
instance_variable_get ( " @ # { method } " ) || 
instance_variable_set ( " @ # { method } " , options [ : default ]) 
end 
define_method ( " # { method } = " ) do | v | 
instance_variable_set ( " @ # { method } " , v) 
end 
end 
end 
end 
So, in the examples reviewed, metaprogramming looks like writing methods that define methods.
It makes sense for a beginner metaprogrammer to google such search queries:
1. ruby ​​doc attr_accessor
2. ruby ​​doc Kernel 
eval3. ruby ​​doc Module 
class_eval4. ruby ​​doc Object 
instance_eval5. ruby ​​doc Object 
is_a?The first links are correct.
How to metaprogram without 
eval , as well as about impurities, modifier methods, which allow to transfer abstraction tasks related to caching, RPC, DSL, patterns, continuing ideas of deferred (lazy) calculations, etc. to a new level. Read in future releases of the blog.