Application example of Hook method in Ruby _ruby special topic

Source: Internet
Author: User
Tags class definition eval extend instance method

By using the Hook method, you can allow us to intervene in the lifecycle of a Ruby class or module, which can greatly improve the flexibility of programming.
The hook methods associated with the lifecycle are as follows:

Class is associated with a module

    • class#inherited
    • Module#include
    • module#prepended
    • Module#extend_object
    • module#method_added
    • Module#method_removed
    • module#method_undefined

Single-piece class-related

    • basicobject#singleton_method_added
    • Basicobject#singleton_method_removed
    • basicobject#singleton_method_undefined

Sample code

Module M1
  def self.included (othermod)
    puts "M1 is included into #{othermod}"
  end

module M2
  def self.prepended (othermod)
    puts "M2 is prepended to #{othermod}"
  end

class C
  Include M1
  include M2
end

# output
M1 is included into C
M2 is prepended to C

module M
  de F self.method_added (method)
    puts the "New Method:m##{method}" End

  def My_method;
New Method:m#my_method

In addition to some of the above listed methods, can also be overridden by a method of the parent class, some filtering operations, and then by calling the super method to complete the function of the original function, so as to achieve the effect of the hook method, the same, surround alias can also be used as a hook method of substitution.

Application examples
Task Description:

Write an action method similar to Attr_accessor's attr_checked class macro, which is used to test the value of the property, using the following method:

Class person
 include Checkedattributes

 attr_checked:age do |v|
  V >= end

me = person.new
me.age = #ok
me.age = #抛出异常

Implementation plan:

Use the Eval method to write a kernel method named Add_checked_attribute that adds a simple checksum property to the specified class
Refactor the Add_checked_attribute method, remove the Eval method, and use other means to implement
Add code block checksum
Modify Add_checked_attribute to the required attr_checked and make it available to all classes
By introducing the module, the Attr_checked method is only added to the class that introduces the function module
Step 1

Def add_checked_attribute (Klass, attribute)
 eval "
  class #{klass}
   def #{attribute}= (value)
    raise ' Invalid attribute ' unless value
    @#{attribute} = value
   end
   def #{attribute} ()
    @#{attribute}
   End
  End

Add_checked_attribute (String,: my_attr)
t = "Hello,kitty"

t.my_attr = 100
puts t.my_attr

t.my_attr = False
puts t.my_attr

This step uses the Eval method, opens the class with class and Def keywords, and defines the get and set methods of the specified property, where the set method simply evaluates whether the value is empty (nil or false) and throws an invalid attribute exception if it is.

SETP 2

Def add_checked_attribute (Klass, attribute)
 klass.class_eval do
  define_method "#{attribute}=" Do |value|
   Raise "Invaild attribute" unless value
   instance_variable_set ("@#{attribute}", value)
  end

  Define_method attribute do
   instance_variable_get ' @#{attribute} ' end end


This step replaces the Eval method, while also replacing the previous class and DEF keywords with the Class_eval and Define_method methods, and the settings and acquisition of instance variables are changed to Instance_variable_set and instance respectively. _variable_get method, the use of the first step without any difference, but some of the internal implementation of the difference.

Step 3

Def add_checked_attribute (Klass, attribute, &validation)
 klass.class_eval do
  define_method "#{attribute }= "Do |value|
   Raise "Invaild attribute" unless Validation.call (value)
   instance_variable_set ("@#{attribute}", value)
  end

  Define_method does
   instance_variable_get "@#{attribute}" end End end

add_ Checked_attribute (String,: my_attr) {|v| v >= 180}
t = "Hello,kitty"

t.my_attr = #Invaild attribute (runt Imeerror)
puts t.my_attr

t.my_attr =
puts t.my_attr #200

Nothing fancy, just adding to the code block validation, increases the flexibility of checksums, no longer limited to nil and false.

Step 4

Class class
 def attr_checked (attribute, &validation)
   Define_method "#{attribute}=" Do |value|
    Raise "Invaild attribute" unless Validation.call (value)
    instance_variable_set ("@#{attribute}", value)
   end

   Define_method does
    instance_variable_get "@#{attribute}"

end End String.add_checked (: my_attr) {|v| v >= 180}
t = "Hello,kitty"

t.my_attr = #Invaild attribute (runtimeerr OR)
puts t.my_attr

t.my_attr =
puts t.my_attr #200

Here we put the name of the method in the top-level scope in class, and since all objects are instances of class, the instance method defined here can also be accessed by all other classes in Ruby, and in the class definition, self is the current class, So it eliminates the call class parameter and Class_eval method, and we change the name of the method to attr_checked.

Step 5

Module Checkedattributes
 def self.included (base)
  base.extend classmethods
 end

module Classmethods
 def attr_checked (attribute, &validation)
   Define_method "#{attribute}=" Do |value|
    Raise "Invaild attribute" unless Validation.call (value)
    instance_variable_set ("@#{attribute}", value)
   end

   define_method do
    instance_variable_get ' @#{attribute} ' end
   end

class Person
 include checkedattributes

 attr_checked:age do |v|
  V >= End


The last step is to extend the current class through the introduced module after the Checkedattributes module is introduced, so that the current class supports the introduced method invocation, that is, the get and set method groups here.

So we've got a class macro called attr_checked, like Attr_accessor, through which you can perform the validation you want on the property.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.