* 避免無謂的元編程。
* 寫一個函數庫時不要使核心類混亂(不要使用 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?`](http://blog.marc-andre.ca/2010/11/methodmissing-politely.html)
* 僅捕捉字首定義良好的方法,像是?`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。
~~~