Permalink
Browse files

Fix DynamicStruct so that #[] returns nil when given an unknown key.

Previously, it raised a `NoMethodError`, but we only want the error
when the method syntax is used.
  • Loading branch information...
1 parent e855afc commit 532e52b30cba217f66e42c63e740f44fa1ccedfa @myronmarston myronmarston committed Dec 12, 2012
@@ -10,35 +10,47 @@ module Interpol
# everything. This is handy so that consumers of this gem can distinguish
# between a fat-fingered field, and a field that is set to nil.
module DynamicStruct
- DEFAULT_PROC = lambda do |hash, key|
- raise NoMethodError, "undefined method `#{key}' for #{hash.inspect}"
- end
+ SAFE_METHOD_MISSING = ::Hashie::Mash.superclass.instance_method(:method_missing)
Mash = Class.new(::Hashie::Mash) do
undef sort
end
- def self.new(source)
- hash = Mash.new(source)
- recursively_freeze(hash)
- hash
+ def self.new(*args)
+ Mash.new(*args).tap do |mash|
+ mash.extend(self)
+ end
end
- def self.recursively_freeze(object)
+ def self.extended(mash)
+ recursively_extend(mash)
+ end
+
+ def self.recursively_extend(object)
case object
when Array
- object.each { |obj| recursively_freeze(obj) }
- when Hash
- set_default_proc_on(object)
- recursively_freeze(object.values)
+ object.each { |v| recursively_extend(v) }
+ when Mash
+ object.extend(self) unless object.is_a?(self)
+ object.each { |_, v| recursively_extend(v) }
+ end
+ end
+
+ def method_missing(method_name, *args, &blk)
+ if key = method_name.to_s[/\A([^?=]*)[?=]?\z/, 1]
+ unless has_key?(key)
+ return safe_method_missing(method_name, *args, &blk)
+ end
end
+
+ super
end
- def self.set_default_proc_on(hash)
- hash.default_proc = DEFAULT_PROC
+ private
+
+ def safe_method_missing(*args)
+ SAFE_METHOD_MISSING.bind(self).call(*args)
end
end
end
-require 'interpol/hash_set_default_proc_18' unless {}.respond_to?(:default_proc=)
-
@@ -1,9 +0,0 @@
-module Interpol
- module DynamicStruct
- # Hash#default_proc= isn't defined on 1.8; this is the best we can do.
- def self.set_default_proc_on(hash)
- hash.replace(Hash.new(&DEFAULT_PROC).merge(hash))
- end
- end
-end
-
@@ -34,6 +34,11 @@ module Interpol
ds.b.map(&:c).should eq([5, 4])
end
+ it 'returns nil when #[] is passed an undefined key' do
+ ds = DynamicStruct.new("a" => { "b" => { "c" => 3 } })
+ ds["b"].should eq(nil)
+ end
+
hash_methods_allowed_as_params = [:sort]
hash_methods_allowed_as_params.each do |meth|

0 comments on commit 532e52b

Please sign in to comment.