diff --git a/lib/mongo/util/ordered_hash.rb b/lib/mongo/util/ordered_hash.rb index 8cdbdde..f52c02e 100644 --- a/lib/mongo/util/ordered_hash.rb +++ b/lib/mongo/util/ordered_hash.rb @@ -32,65 +32,82 @@ class OrderedHash < Hash # We only need the body of this class if the RUBY_VERSION is before 1.9 if RUBY_VERSION < '1.9' + attr_accessor :ordered_keys - attr_accessor :ordered_keys - - def keys - @ordered_keys || [] - end - - def []=(key, value) - @ordered_keys ||= [] - @ordered_keys << key unless @ordered_keys.include?(key) - super(key, value) - end - - def each - @ordered_keys ||= [] - @ordered_keys.each { |k| yield k, self[k] } - end - - def values - collect { |k, v| v } - end - - def merge(other) - oh = self.dup - oh.merge!(other) - oh - end - - def merge!(other) - @ordered_keys ||= [] - @ordered_keys += other.keys # unordered if not an OrderedHash - @ordered_keys.uniq! - super(other) - end - - def inspect - str = '{' - str << (@ordered_keys || []).collect { |k| "\"#{k}\"=>#{self.[](k).inspect}" }.join(", ") - str << '}' - end - - def delete(key, &block) - @ordered_keys.delete(key) if @ordered_keys - super - end - - def delete_if(&block) - self.each { |k,v| - if yield k, v - delete(k) + def self.[] *args + oh = OrderedHash.new + if Hash === args[0] + oh.merge! args[0] + elsif (args.size % 2) != 0 + raise ArgumentError, "odd number of elements for Hash" + else + 0.step(args.size - 1, 2) do |key| + value = key + 1 + oh[args[key]] = args[value] + end end - } + oh + end + + def initialize(*a, &b) + super + @ordered_keys = [] + end + + def keys + @ordered_keys || [] + end + + def []=(key, value) + @ordered_keys ||= [] + @ordered_keys << key unless @ordered_keys.include?(key) + super(key, value) + end + + def each + @ordered_keys ||= [] + @ordered_keys.each { |k| yield k, self[k] } + end + + def values + collect { |k, v| v } + end + + def merge(other) + oh = self.dup + oh.merge!(other) + oh + end + + def merge!(other) + @ordered_keys ||= [] + @ordered_keys += other.keys # unordered if not an OrderedHash + @ordered_keys.uniq! + super(other) + end + + def inspect + str = '{' + str << (@ordered_keys || []).collect { |k| "\"#{k}\"=>#{self.[](k).inspect}" }.join(", ") + str << '}' + end + + def delete(key, &block) + @ordered_keys.delete(key) if @ordered_keys + super + end + + def delete_if(&block) + self.each { |k,v| + if yield k, v + delete(k) + end + } + end + + def clear + super + @ordered_keys = [] + end end - - def clear - super - @ordered_keys = [] - end - - end # Ruby before 1.9 - end diff --git a/tests/test_db_api.rb b/tests/test_db_api.rb index 8f0e197..0a4d521 100644 --- a/tests/test_db_api.rb +++ b/tests/test_db_api.rb @@ -53,6 +53,10 @@ class DBAPITest < Test::Unit::TestCase oid = @@coll.save(oh) assert_equal 'foo', @@coll.find_first(:_id => oid)['b'] + + oh = OrderedHash['a' => 1, 'b' => 'foo'] + oid = @@coll.save(oh) + assert_equal 'foo', @@coll.find_first(:_id => oid)['b'] end def test_insert_multiple diff --git a/tests/test_ordered_hash.rb b/tests/test_ordered_hash.rb index c7d3798..0c2aed1 100644 --- a/tests/test_ordered_hash.rb +++ b/tests/test_ordered_hash.rb @@ -12,6 +12,15 @@ class OrderedHashTest < Test::Unit::TestCase @ordered_keys = %w(c a z) end + def test_initialize + a = OrderedHash.new + a['x'] = 1 + a['y'] = 2 + + b = OrderedHash['x' => 1, 'y' => 2] + assert_equal a, b + end + def test_empty assert_equal [], OrderedHash.new.keys end