Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Avoid define_method if possible.

  • Loading branch information...
commit afcdf9b86660a261e33b349b174979c404b31bcf 1 parent d9bca64
@josevalim josevalim authored
Showing with 39 additions and 14 deletions.
  1. +39 −14 activemodel/lib/active_model/attribute_methods.rb
View
53 activemodel/lib/active_model/attribute_methods.rb
@@ -56,6 +56,8 @@ class MissingAttributeError < NoMethodError
module AttributeMethods
extend ActiveSupport::Concern
+ COMPILABLE_REGEXP = /^[a-zA-Z_]\w*[!?=]?$/
+
module ClassMethods
# Defines an "attribute" method (like +inheritance_column+ or +table_name+).
# A new (class) method will be created with the given name. If a value is
@@ -101,10 +103,13 @@ def define_attr_method(name, value=nil, &block)
if block_given?
sing.send :define_method, name, &block
else
- if name =~ /^[a-zA-Z_]\w*[!?=]?$/
- sing.class_eval <<-eorb, __FILE__, __LINE__ + 1
- def #{name}; #{value.nil? ? 'nil' : value.to_s.inspect}; end
- eorb
+ # If we can compile the method name, do it. Otherwise use define_method.
+ # This is an important *optimization*, please don't change it. define_method
+ # has slower dispatch and consumes more memory.
+ if name =~ COMPILABLE_REGEXP
+ sing.class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{name}; #{value.nil? ? 'nil' : value.to_s.inspect}; end
+ RUBY
else
value = value.to_s if value
sing.send(:define_method, name) { value }
@@ -227,11 +232,20 @@ def attribute_method_affix(*affixes)
def alias_attribute(new_name, old_name)
attribute_method_matchers.each do |matcher|
- module_eval <<-STR, __FILE__, __LINE__ + 1
- def #{matcher.method_name(new_name)}(*args)
- send(:'#{matcher.method_name(old_name)}', *args)
+ matcher_new = matcher.method_name(new_name).to_s
+ matcher_old = matcher.method_name(old_name).to_s
+
+ if matcher_new =~ COMPILABLE_REGEXP && matcher_old =~ COMPILABLE_REGEXP
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{matcher_new}(*args)
+ send(:#{matcher_old}, *args)
+ end
+ RUBY
+ else
+ define_method(matcher_new) do |*args|
+ send(matcher_old, *args)
end
- STR
+ end
end
end
@@ -271,14 +285,25 @@ def define_attribute_methods(attr_names)
else
method_name = matcher.method_name(attr_name)
- generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
- if method_defined?(:'#{method_name}')
+ generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
+ if method_defined?('#{method_name}')
undef :'#{method_name}'
end
- define_method('#{method_name}') do |*args|
- send(:'#{matcher.method_missing_target}', '#{attr_name}', *args)
- end
- STR
+ RUBY
+
+ if method_name.to_s =~ COMPILABLE_REGEXP
+ generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{method_name}(*args)
+ send(:#{matcher.method_missing_target}, '#{attr_name}', *args)
+ end
+ RUBY
+ else
+ generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
+ define_method('#{method_name}') do |*args|
+ send('#{matcher.method_missing_target}', '#{attr_name}', *args)
+ end
+ RUBY
+ end
end
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.