Ruby Metaprogramming - define_method
Bài đăng này đã không được cập nhật trong 7 năm
Dear friends, in the article before I had an introduction to metaprogramming in Ruby and how to use the some function. To follow up the topic of metaprogramming in Ruby, this article I will mention define_methodand some of its applications.
Before the start, I have a small sample of the class:
class Dog
def initialize name
.@name = name
end
def is_dog?; true; end
end
Here you have a Dog class - also known as the dog. I have a dog, named it the "mic". To create the "mic", I will type:
a = Dog.new "mic"
a.is_dog?
=> true
As you can see, I have created a dog named dog1 mic, but I had no method name in the Dog class, I just know there's an instance variable called name is assigned to his dog. So how I can know your dog's name was created? The answer is because of the method instance_eval:
dog1.instance_eval{@name}
=> "mic"
So we were able to know the dog's name, but the statement seems a bit long and rather confusing. I'm going to declare a more concise method to obtain the name of the "mic" her:
dog1.instance_eval do
def name
.@name
end
end
dog1.name
=> "mic"
dog1.define_singleton_method :name do
.@name
end
dog1.name
=> "mic"
dog2.name
=> NoMethodError: undefined method `name' for...
And we did have a way for his dog name. But, if I may add another dog, I would not be able to use the method which his name was declared for the "mic" to use for the "join":
dog2 = Dog.new "join"
dog2.is_dog?
=> true
dog2.instance_eval{@name}
=> "join"
dog2.name
=> NoMethodError: undefined method `name' for...
So we can not use instance_evalto declare methods common to many objects of class Dog is. This method will be very useful if we need to declare private methods for a specific audience, but if you need to declare the method used for more specific audiences, perhaps we will need a tool like class_eval:
Dog.class_eval do
def name
.@name
end
end
dog1.name
=> "mic"
dog2.name
=> "join"
Thus, thanks to the two methods instance_eval, and class_evalwe were able to declare method applies only to a single object and the method is applicable to a wide audience. But, there is another method that can be used as a substitute for his two aforementioned methods; that is define_method.
class Dog
[...]
def define_name
define_method "name" do
.@name
end
end
define_method "kick" do
"My " << .@name
end
end
dog1.name
=> NoMethodError: undefined method `name` for ...
dog1.define_name
dog1.name
=> "join"
dog1.kick
=> "My mic"
dog2.kick
=> "My join"
Dog.send(:define_method, :name) do
.@name
end
Other than instance_evaland class_evalis 2 public method, define_methodis private method. Therefore, we can only use it within the class to declare it, In the example above, you have to declare the methods kick in define_method, instead of using def kick; "My " << @name; endas normal. And I have also created a method define_name. Only dogs have been called define_namethe new method name. When only want to use a method for a certain number of objects, we declared that method through a different method. But why use define_methodthat is not a traditional function declaration?
The answer is in its versatility:
With define_method, we can declare the method with arbitrary names, depending on the context of use. This is what a traditional declared impossible. On the other hand, define_methodalso help us to "save" the line of code. Example:
def a
@a
end
def b
@b
end
def c
@c
end
...
%w(a b c ...).do |x|
define_method x do
instance_variable_get "@#{x}"
end
end
In short, define_methodas an improved eval, allowing us Automation program while ensuring the safety part of it.
In addition to the methods declared in define_methoda little longer than declared by defthe use of conventional and define_methodmay be confusing for our code, then everything else is almost fine. We can use define_methodin some cases to more stores some time writing code, the simplest is in the example above.
All rights reserved