1. ホーム
  2. スクリプト・コラム
  3. ルビートピックス

Rubyメタプログラミングの注目すべき点

2022-02-03 19:32:39

  無限ループのメタプログラミングを避ける。

    コアクラスを乱立させずに関数のライブラリを書く(モンキーパッチは使わない)。

    コードブロック形式は、文字列補間形式で使用するのが最適です。
        文字列補間形式を使用する場合は、バックトラックを有意義なものにするために、必ず __FILE__ と __LINE__ を指定してください。

 class_eval 'def use_relative_model_naming?; true; end', __FILE__, __LINE__



        define_method は class_eval{ def ... と一緒に使うのがベストです。}

    class_eval(または他のeval)と文字列補間を使用する場合、コメントブロックを追加して挿入時に表示されるようにします(これはrailsのコードから学んだ慣習です)。

 # from 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を使うのは避けましょう。バックトラックが面倒になりますし、#methodsにその習慣が記載されておらず、スペルミスのメソッドも黙って動いているかもしれません。method_missingを使用します。
        respond_to_missingも定義されていることを確認しますか?
        find_by_*のように語頭で定義されたメソッドのみを捕捉する - コードは主張が強いほど良いのです。
        文末にsuperを呼び出す
        定義された非魔法的なメソッドに委譲する。

 # bad
 def method_missing?(meth, *args, &block)
  if /^find_by_(? <prop>. *)/ =~ meth
  # ... lots of code to do a find_by
  else
  super
  end
 end

 # good
 def method_missing?(meth, *args, &block)
  if /^find_by_(? <prop>. *)/ =~ meth
  find_by(prop, *args, &block)
  else
  super
  end
 end

 # best of all, though, would to define_method as each findable attribute is declared