0

Ruby Metaprogramming - define_method

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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí