牛骨文教育服务平台(让学习变的简单)
  • 避免无谓的元编程。

  • 写一个函数库时不要使核心类混乱(不要使用 monkey patch)。

  • 倾向使用区块形式的 class_eval 而不是字符串插值(string-interpolated)的形式。

    • 当你使用字符串插值形式时,总是提供 __FILE__ 及 __LINE__,使你的 backtrace 看起来有意义:

      class_eval "def use_relative_model_naming?; true; end", __FILE__, __LINE__
      
    • 倾向使用 define_method 而不是 class_eval{ def ... }

  • 当使用 class_eval (或其它的 eval)搭配字符串插值时,添加一个注解区块,来演示如果做了插值的样子(我从 Rails 代码学来的一个实践):

    # activesupport/lib/active_support/core_ext/string/output_safety.rb
    UNSAFE_STRING_METHODS.each do |unsafe_method|
      if "String".respond_to?(unsafe_method)
        class_eval <<-EOT, __FILE__, __LINE__ + 1
          def #{unsafe_method}(*args, &block) # def capitalize(*args, &block)
            to_str.#{unsafe_method}(*args, &block) # to_str.capitalize(*args, &block)
          end # end
    
          def #{unsafe_method}!(*args) # def capitalize!(*args)
            @dirty = true # @dirty = true
            super # super
          end # end
        EOT
      end
    end
    
  • 元编程避免使用 method_missing。会让 Backtraces 变得很凌乱;行为没有列在 #methods 里;拼错的方法调用可能默默的工作(nukes.launch_state = false)。考虑使用 delegation, proxy, 或是 define_method 来取代。如果你必须使用 method_missing

    • 确保 也定义了 respond_to_missing?
    • 仅捕捉字首定义良好的方法,像是 find_by_*——让你的代码愈肯定(assertive) 愈好。
    • 在语句的最后调用 super
    • delegate 到确定的、非魔法方法中:

      # 差
      def method_missing?(meth, *args, &block)
        if /^find_by_(?<prop>.*)/ =~ meth
          # ... lots of code to do a find_by
        else
          super
        end
      end
      
      # 好
      def method_missing?(meth, *args, &block)
        if /^find_by_(?<prop>.*)/ =~ meth
          find_by(prop, *args, &block)
        else
          super
        end
      end
      
      # 最好的方式,可能是每个可找到的属性被声明后,使用 define_method。