• 3-15 《元编程》第6章 3-16 hook method


    Code That Writes Code 

    6.1 Coding your way to the weekend

    6.2 Kernel#eval, Binding#eval 

    Binding:

    Objects of class Binding(类Binding的对象) encapsulate (密封)the execution context at some particular place in the code and retain this context for future use.

    如果你想要一段已经执行的代码在今后反复使用,可以用Binding对象封装它。

    The variables, methods, value of self, and possibly an iterator block(迭代块) that can be accessed in this context are all retained. 

    变量,方法,自身的value,甚至迭代块都可以用Binding对象封装储存。

    Binding objects can be created using Kernel#binding

    eval(string [, filename [,lineno]]) → obj

    Evaluates the Ruby expression(s) in string, in the binding's context.

    Binding对象的eval方法,可以评估字符串内的Ruby表达式,并返回表达式的值。

    If the optional filename and lineno parameters are present, they will be used when reporting syntax errors.

    class Myclass
      def my_method
        @x = 1
        binding
      end
    end
     
    p b = Myclass.new.my_method
    p b.eval("@x")
    p eval("@x", b)

    #结果一样 1

    class Anotherclass
      def my_method
        # eval "self", TOPLEVEL_BINDING   #=> main
        eval("xx + yy", TOPLEVEL_BINDING)
      end
    end
     
    xx = 123
    yy = 321
    obj = Anotherclass.new
    p obj.my_method #=> 444

    TOPLEVEL_BINDING: 是预定义常量,表示顶层作用域的Binding对象。

    6.24 Strings of Code Vs Blocks 

     eval只能执行代码字符串,instance_eval和class_eval可以执行代码字符串和block

    array = [1,2,3]
    x = 'd'
    array.instance_eval("self[1] = x")
    p array #=> [1, "d", 3]
    尽量用block,代码字符串安全性低容易被攻击。同时也难以阅读和修改。

    流行的做法是禁止使用eval方法,同时用Dynamic methods和Dynamic Dispatch替代

    污染对象 

    Ruby把外部传入的对象标记为污染对象。Object#taint -> obj.

    判断: #tainted? ->true/false

    去掉污染 #untaint 

    谨慎使用安全级别p148页

    可以使用proc {}.call 作为洁净室


    6.3Hook Method: 

    Class#inherited是一个实例方法,当一个类被继承时,Ruby会调用这个方法,Class#inherited方法什么也不做,但程序员可以覆写它的行为,像这样的方法称为钩子方法。

    inherited(subclass):Callback invoked whenever a subclass of the current class is created.

    更多的钩子方法:

    Module#included,#prepended,#method_added, #method_removed, #method_undefined (只对实例方法有用),#singleton_method_added...

    这种钩子方法写在模块里,用类方法的方式定义:

    module M1
      def self.included(othermod)
        puts "m1 was included into #{othermod}"
      end
    end
     
    class C
      include M1
    end
    #=>m1 was included into C
     

    另外一种方式钩住同一个事件,:#include方法可以覆写 ,但注意写在类C中。

    我的理解类C.调用include方法,就是self.include。先是在自身调用覆写的include方法,然后用super关键字调用原始方法。

    ⚠️ 类方法是不能被继承的只能自己用。

    ⚠️ 类包含模块后默认是获得实例方法。除非用#extend

    module M
      def hello
        puts "world"
      end
    end
     
    class C
      def self.include(mod)
        puts "Called: C.include(#{mod})"
        super  #因为覆写了include,所以需要用super调用原始的include功能,否则M不会被C包含
      end 
      include(M)
    end
     
    C.new.hello✅

     类方法和钩子方法结合的技巧:P160页。 

  • 相关阅读:
    HTTP协议中常用相应的状态码总结
    mysql 用户管理
    史上最全的mysql聚合函数总结(与分组一起使用)
    jQuery+masonry实现瀑布流
    MySQL Workbench 导入导出乱码解决方法
    在Google Maps 上点击标签显示说明并保持不消失
    在Google Maps 上点击标签后显示说明
    如何在Google Maps 添加多个标记
    如何在 Google 地图中添加标记和说明
    Google Maps API3 之 Hello World
  • 原文地址:https://www.cnblogs.com/chentianwei/p/8574545.html
Copyright © 2020-2023  润新知