diff options
author | José Valim <jose.valim@gmail.com> | 2011-12-08 20:21:48 +0100 |
---|---|---|
committer | José Valim <jose.valim@gmail.com> | 2011-12-08 20:28:09 +0100 |
commit | d1abf29e796a86cbac315da217f3fe7addb88106 (patch) | |
tree | 63456927eb5a45b45581f7b81f82e89c7196e2c7 /activesupport/lib/active_support | |
parent | 7280787a53436046e992305a235e66e4fb458e0f (diff) | |
download | rails-d1abf29e796a86cbac315da217f3fe7addb88106.tar.gz rails-d1abf29e796a86cbac315da217f3fe7addb88106.tar.bz2 rails-d1abf29e796a86cbac315da217f3fe7addb88106.zip |
Remove NilClass whiners feature.
Removing this feature causes boost in performance when using Ruby 1.9.
Ruby 1.9 started to do implicit conversions using `to_ary` and `to_str`
in some STDLIB methods (like Array#join). To do such implicit conversions,
Ruby 1.9 always dispatches the method and rescues the NoMethodError exception
in case one is raised.
Therefore, since the whiners feature defined NilClass#method_missing, such
implicit conversions for nil became much, much slower. In fact, just defining
NilClass#method_missing (even without the whiners feature) already causes a
massive slow down. Here is a snippet that shows such slow down:
require "benchmark"
Benchmark.realtime { 1_000.times { [nil,nil,nil].join } }
class NilClass
def method_missing(*args)
raise NoMethodError
end
end
Benchmark.realtime { 1_000.times { [nil,nil,nil].join } }
Diffstat (limited to 'activesupport/lib/active_support')
-rw-r--r-- | activesupport/lib/active_support/whiny_nil.rb | 42 |
1 files changed, 2 insertions, 40 deletions
diff --git a/activesupport/lib/active_support/whiny_nil.rb b/activesupport/lib/active_support/whiny_nil.rb index 577db5018e..a065233679 100644 --- a/activesupport/lib/active_support/whiny_nil.rb +++ b/activesupport/lib/active_support/whiny_nil.rb @@ -1,21 +1,6 @@ # Extensions to +nil+ which allow for more helpful error messages for people who # are new to Rails. # -# Ruby raises NoMethodError if you invoke a method on an object that does not -# respond to it: -# -# $ ruby -e nil.destroy -# -e:1: undefined method `destroy' for nil:NilClass (NoMethodError) -# -# With these extensions, if the method belongs to the public interface of the -# classes in NilClass::WHINERS the error message suggests which could be the -# actual intended class: -# -# $ rails runner nil.destroy -# ... -# You might have expected an instance of ActiveRecord::Base. -# ... -# # NilClass#id exists in Ruby 1.8 (though it is deprecated). Since +id+ is a fundamental # method of Active Record models NilClass#id is redefined as well to raise a RuntimeError # and warn the user. She probably wanted a model database identifier and the 4 @@ -25,36 +10,13 @@ # By default it is on in development and test modes, and it is off in production # mode. class NilClass - METHOD_CLASS_MAP = Hash.new - def self.add_whiner(klass) - methods = klass.public_instance_methods - public_instance_methods - class_name = klass.name - methods.each { |method| METHOD_CLASS_MAP[method.to_sym] = class_name } + ActiveSupport::Deprecation.warn "NilClass.add_whiner is deprecated and this functionality is " \ + "removed from Rails versions as it affects Ruby 1.9 performance.", caller end - add_whiner ::Array - # Raises a RuntimeError when you attempt to call +id+ on +nil+. def id raise RuntimeError, "Called id for nil, which would mistakenly be #{object_id} -- if you really wanted the id of nil, use object_id", caller end - - private - def method_missing(method, *args) - if klass = METHOD_CLASS_MAP[method] - raise_nil_warning_for klass, method, caller - else - super - end - end - - # Raises a NoMethodError when you attempt to call a method on +nil+. - def raise_nil_warning_for(class_name = nil, selector = nil, with_caller = nil) - message = "You have a nil object when you didn't expect it!" - message << "\nYou might have expected an instance of #{class_name}." if class_name - message << "\nThe error occurred while evaluating nil.#{selector}" if selector - - raise NoMethodError, message, with_caller || caller - end end |