lib/hashery/property_hash.rb in hashery-1.4.0 vs lib/hashery/property_hash.rb in hashery-1.5.0
- old
+ new
@@ -1,96 +1,192 @@
-require 'hashery/propertyhash'
+# A PropertyHash is the same as a regular Hash except it strictly limits the
+# allowed keys.
+#
+# There are two ways to use it.
+#
+# 1) As an object in itself.
+#
+# h = PropertyHash.new(:a=>1, :b=>2)
+# h[:a] #=> 1
+# h[:a] = 3
+# h[:a] #=> 3
+#
+# But if we try to set key that was not fixed, then we will get an error.
+#
+# h[:x] = 5 #=> ArgumentError
+#
+# 2) As a superclass.
+#
+# class MyPropertyHash < PropertyHash
+# property :a, :default => 1
+# property :b, :default => 2
+# end
+#
+# h = MyPropertyHash.new
+# h[:a] #=> 1
+# h[:a] = 3
+# h[:a] #=> 3
+#
+# Again, if we try to set key that was not fixed, then we will get an error.
+#
+# h[:x] = 5 #=> ArgumentError
+#
+class PropertyHash < Hash
+
+ #
+ def self.properties
+ @properties ||= (
+ parent = ancestors[1]
+ if parent.respond_to?(:properties)
+ parent.properties
+ else
+ {}
+ end
+ )
+ end
+
+ #
+ def self.property(key, opts={})
+ properties[key] = opts[:default]
+ end
+
+ #
+ def initialize(properties={})
+ super()
+ fixed = self.class.properties.merge(properties)
+ replace(fixed)
+ end
+
+ #
+ def []=(k,v)
+ assert_key!(k)
+ super(k,v)
+ end
+
+ #
+ def update(h)
+ h.keys.each{ |k| assert_key!(k) }
+ super(h)
+ end
+
+ #
+ def merge!(h)
+ h.keys.each{ |k| assert_key!(k) }
+ super(h)
+ end
+
+ #
+ def <<(a)
+ k,v = *a
+ self[k] = v
+ end
+
+ # Add a new acceptable key.
+ # TODO: Should this be supported?
+ def accept_key!(k,v=nil)
+ self[k] = v
+ end
+
+ private
+
+ def assert_key!(key)
+ unless key?(key)
+ raise ArgumentError, "The key '#{key}' is not defined for this FixedHash."
+ end
+ end
+
+end