aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activesupport/lib/active_support/whiny_nil.rb43
-rw-r--r--activesupport/test/whiny_nil_test.rb40
2 files changed, 83 insertions, 0 deletions
diff --git a/activesupport/lib/active_support/whiny_nil.rb b/activesupport/lib/active_support/whiny_nil.rb
new file mode 100644
index 0000000000..4a83cd585e
--- /dev/null
+++ b/activesupport/lib/active_support/whiny_nil.rb
@@ -0,0 +1,43 @@
+# Extensions to nil which allow for more helpful error messages for
+# people who are new to rails.
+#
+# The aim is to ensure that when users pass nil to methods where that isn't
+# appropriate, instead of NoMethodError and the name of some method used
+# by the framework users will see a message explaining what type of object
+# was expected.
+
+
+class NilClass
+ WHINERS = [ ActiveRecord::Base, Array ]
+
+ @@method_class_map = Hash.new
+
+ WHINERS.each do |klass|
+ methods = klass.public_instance_methods - public_instance_methods
+ methods.each do |method|
+ @@method_class_map[method.to_sym] = klass
+ end
+ end
+
+ private
+ def method_missing(method, *args, &block)
+ if @@method_class_map.include?(method)
+ raise_nil_warning_for @@method_class_map[method]
+ else
+ super
+ end
+ end
+
+ def raise_nil_warning_for(klass)
+ raise NoMethodError, NIL_WARNING_MESSAGE % klass
+ end
+
+ NIL_WARNING_MESSAGE = <<-end_message unless const_defined?(:NIL_WARNING_MESSAGE)
+WARNING: You have a nil object when you probably didn't expect it! Odds are you
+want an instance of %s instead.
+
+Look in the callstack to see where you're working with an object that could be nil.
+Investigate your methods and make sure the object is what you expect!
+ end_message
+end
+
diff --git a/activesupport/test/whiny_nil_test.rb b/activesupport/test/whiny_nil_test.rb
new file mode 100644
index 0000000000..ffa15ceeaa
--- /dev/null
+++ b/activesupport/test/whiny_nil_test.rb
@@ -0,0 +1,40 @@
+require 'test/unit'
+
+
+## mock to enable testing without activerecord
+module ActiveRecord
+ class Base
+ def save!
+ end
+ end
+end
+
+require 'active_support/whiny_nil'
+
+
+
+class WhinyNilTest < Test::Unit::TestCase
+ def test_unchanged
+ begin
+ nil.method_thats_not_in_whiners
+ rescue NoMethodError => nme
+ assert_match(/nil:NilClass/, nme.message)
+ end
+ end
+
+ def test_active_record
+ begin
+ nil.save!
+ rescue NoMethodError => nme
+ assert(!(nme.message =~ /nil:NilClass/))
+ end
+ end
+
+ def test_array
+ begin
+ nil.each
+ rescue NoMethodError => nme
+ assert(!(nme.message =~ /nil:NilClass/))
+ end
+ end
+end \ No newline at end of file