diff --git a/ext/cbson/cbson.c b/ext/cbson/cbson.c index 5ff6999..5b9835a 100644 --- a/ext/cbson/cbson.c +++ b/ext/cbson/cbson.c @@ -532,7 +532,7 @@ static void write_doc(buffer_t buffer, VALUE hash, VALUE check_keys, VALUE move_ } // we have to check for an OrderedHash and handle that specially - if (strcmp(rb_obj_classname(hash), "OrderedHash") == 0) { + if (strcmp(rb_obj_classname(hash), "BSON::OrderedHash") == 0) { VALUE keys = rb_funcall(hash, rb_intern("keys"), 0); int i; for(i = 0; i < RARRAY_LEN(keys); i++) { @@ -909,7 +909,7 @@ void Init_cbson() { InvalidStringEncoding = rb_const_get(bson, rb_intern("InvalidStringEncoding")); InvalidDocument = rb_const_get(bson, rb_intern("InvalidDocument")); rb_require("bson/ordered_hash"); - OrderedHash = rb_const_get(rb_cObject, rb_intern("OrderedHash")); + OrderedHash = rb_const_get(bson, rb_intern("OrderedHash")); CBson = rb_define_module("CBson"); ext_version = rb_str_new2(VERSION); diff --git a/lib/bson/bson_ruby.rb b/lib/bson/bson_ruby.rb index d046f54..7cf0bf9 100644 --- a/lib/bson/bson_ruby.rb +++ b/lib/bson/bson_ruby.rb @@ -182,7 +182,7 @@ module BSON end @buf.rewind @buf.get_int # eat message size - doc = OrderedHash.new + doc = BSON::OrderedHash.new while @buf.more? type = @buf.get case type @@ -383,7 +383,7 @@ module BSON end def serialize_dbref_element(buf, key, val) - oh = OrderedHash.new + oh = BSON::OrderedHash.new oh['$ref'] = val.namespace oh['$id'] = val.object_id serialize_object_element(buf, key, oh, false) @@ -450,7 +450,7 @@ module BSON def serialize_array_element(buf, key, val, check_keys) # Turn array into hash with integer indices as keys - h = OrderedHash.new + h = BSON::OrderedHash.new i = 0 val.each { |v| h[i] = v; i += 1 } serialize_object_element(buf, key, h, check_keys, ARRAY) diff --git a/lib/bson/ordered_hash.rb b/lib/bson/ordered_hash.rb index 88a08eb..c732e15 100644 --- a/lib/bson/ordered_hash.rb +++ b/lib/bson/ordered_hash.rb @@ -18,123 +18,125 @@ # # Under Ruby 1.9 and greater, this class has no added methods because Ruby's # Hash already keeps its keys ordered by order of insertion. -class OrderedHash < Hash +module BSON + class OrderedHash < Hash - def ==(other) - begin - !other.nil? && - keys == other.keys && - values == other.values - rescue - false - end - end - - # 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 - - 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] } - self - end - alias :each_pair :each - - def to_a - @ordered_keys ||= [] - @ordered_keys.map { |k| [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 - - alias :update :merge! - - 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 - - def hash - code = 17 - each_pair do |key, value| - code = 37 * code + key.hash - code = 37 * code + value.hash - end - code & 0x7fffffff - end - - def eql?(o) - if o.instance_of? OrderedHash - self.hash == o.hash - else + def ==(other) + begin + !other.nil? && + keys == other.keys && + values == other.values + rescue false end end + # 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 + + def self.[] *args + oh = BSON::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] } + self + end + alias :each_pair :each + + def to_a + @ordered_keys ||= [] + @ordered_keys.map { |k| [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 BSON::OrderedHash + @ordered_keys.uniq! + super(other) + end + + alias :update :merge! + + 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 + + def hash + code = 17 + each_pair do |key, value| + code = 37 * code + key.hash + code = 37 * code + value.hash + end + code & 0x7fffffff + end + + def eql?(o) + if o.instance_of? BSON::OrderedHash + self.hash == o.hash + else + false + end + end + + end end -end +end \ No newline at end of file diff --git a/lib/mongo/collection.rb b/lib/mongo/collection.rb index 08f005b..5d279fc 100644 --- a/lib/mongo/collection.rb +++ b/lib/mongo/collection.rb @@ -373,7 +373,7 @@ module Mongo # @core indexes create_index-instance_method def create_index(spec, opts={}) opts.assert_valid_keys(:min, :max, :background, :unique, :dropDups) - field_spec = OrderedHash.new + field_spec = BSON::OrderedHash.new if spec.is_a?(String) || spec.is_a?(Symbol) field_spec[spec.to_s] = 1 elsif spec.is_a?(Array) && spec.all? {|field| field.is_a?(Array) } @@ -445,7 +445,7 @@ module Mongo # # @core findandmodify find_and_modify-instance_method def find_and_modify(opts={}) - cmd = OrderedHash.new + cmd = BSON::OrderedHash.new cmd[:findandmodify] = @name cmd.merge!(opts) cmd[:sort] = Mongo::Support.format_order_clause(opts[:sort]) if opts[:sort] @@ -478,7 +478,7 @@ module Mongo map = BSON::Code.new(map) unless map.is_a?(BSON::Code) reduce = BSON::Code.new(reduce) unless reduce.is_a?(BSON::Code) - hash = OrderedHash.new + hash = BSON::OrderedHash.new hash['mapreduce'] = self.name hash['map'] = map hash['reduce'] = reduce @@ -570,7 +570,7 @@ module Mongo # @return [Array] an array of distinct values. def distinct(key, query=nil) raise MongoArgumentError unless [String, Symbol].include?(key.class) - command = OrderedHash.new + command = BSON::OrderedHash.new command[:distinct] = @name command[:key] = key.to_s command[:query] = query @@ -652,7 +652,7 @@ module Mongo when nil nil else - h = OrderedHash.new + h = BSON::OrderedHash.new hint.to_a.each { |k| h[k] = 1 } h end diff --git a/lib/mongo/connection.rb b/lib/mongo/connection.rb index aa8fdc2..d7238be 100644 --- a/lib/mongo/connection.rb +++ b/lib/mongo/connection.rb @@ -269,7 +269,7 @@ module Mongo # @param [String] username username for authentication against from_db (>=1.3.x). # @param [String] password password for authentication against from_db (>=1.3.x). def copy_database(from, to, from_host="localhost", username=nil, password=nil) - oh = OrderedHash.new + oh = BSON::OrderedHash.new oh[:copydb] = 1 oh[:fromhost] = from_host oh[:fromdb] = from @@ -278,7 +278,7 @@ module Mongo unless username && password raise MongoArgumentError, "Both username and password must be supplied for authentication." end - nonce_cmd = OrderedHash.new + nonce_cmd = BSON::OrderedHash.new nonce_cmd[:copydbgetnonce] = 1 nonce_cmd[:fromhost] = from_host result = self["admin"].command(nonce_cmd, true, true) @@ -659,7 +659,7 @@ module Mongo BSON::BSON_RUBY.serialize_cstr(message, "#{db_name}.$cmd") message.put_int(0) message.put_int(-1) - cmd = OrderedHash.new + cmd = BSON::OrderedHash.new cmd[:getlasterror] = 1 if opts.is_a?(Hash) opts.assert_valid_keys(:w, :wtimeout, :fsync) diff --git a/lib/mongo/cursor.rb b/lib/mongo/cursor.rb index 75cb69c..ffc2ec8 100644 --- a/lib/mongo/cursor.rb +++ b/lib/mongo/cursor.rb @@ -94,7 +94,7 @@ module Mongo # # @raise [OperationFailure] on a database error. def count - command = OrderedHash["count", @collection.name, + command = BSON::OrderedHash["count", @collection.name, "query", @selector, "fields", @fields] response = @db.command(command) @@ -366,7 +366,7 @@ module Mongo def construct_query_spec return @selector if @selector.has_key?('$query') - spec = OrderedHash.new + spec = BSON::OrderedHash.new spec['$query'] = @selector spec['$orderby'] = Mongo::Support.format_order_clause(@order) if @order spec['$hint'] = @hint if @hint && @hint.length > 0 diff --git a/lib/mongo/db.rb b/lib/mongo/db.rb index e4b9815..b9f326a 100644 --- a/lib/mongo/db.rb +++ b/lib/mongo/db.rb @@ -89,7 +89,7 @@ module Mongo raise "error retrieving nonce: #{doc}" unless ok?(doc) nonce = doc['nonce'] - auth = OrderedHash.new + auth = BSON::OrderedHash.new auth['authenticate'] = 1 auth['user'] = username auth['nonce'] = nonce @@ -212,7 +212,7 @@ module Mongo end # Create a new collection. - oh = OrderedHash.new + oh = BSON::OrderedHash.new oh[:create] = name doc = command(oh.merge(options || {})) ok = doc['ok'] @@ -255,7 +255,7 @@ module Mongo # error has occurred. def error(opts={}) opts.assert_valid_keys(:w, :wtimeout, :fsync) - cmd = OrderedHash.new + cmd = BSON::OrderedHash.new cmd[:getlasterror] = 1 cmd.merge!(opts) unless opts.empty? doc = command(cmd) @@ -337,7 +337,7 @@ module Mongo code = BSON::Code.new(code) end - oh = OrderedHash.new + oh = BSON::OrderedHash.new oh[:$eval] = code oh[:args] = args doc = command(oh) @@ -354,7 +354,7 @@ module Mongo # # @raise MongoDBError if there's an error renaming the collection. def rename_collection(from, to) - oh = OrderedHash.new + oh = BSON::OrderedHash.new oh[:renameCollection] = "#{@name}.#{from}" oh[:to] = "#{@name}.#{to}" doc = command(oh, true) @@ -371,7 +371,7 @@ module Mongo # # @raise MongoDBError if there's an error renaming the collection. def drop_index(collection_name, index_name) - oh = OrderedHash.new + oh = BSON::OrderedHash.new oh[:deleteIndexes] = collection_name oh[:index] = index_name doc = command(oh) @@ -502,7 +502,7 @@ module Mongo # # @core profiling profiling_level-instance_method def profiling_level - oh = OrderedHash.new + oh = BSON::OrderedHash.new oh[:profile] = -1 doc = command(oh) raise "Error with profile command: #{doc.inspect}" unless ok?(doc) && doc['was'].kind_of?(Numeric) @@ -523,7 +523,7 @@ module Mongo # # @param [Symbol] level acceptable options are +:off+, +:slow_only+, or +:all+. def profiling_level=(level) - oh = OrderedHash.new + oh = BSON::OrderedHash.new oh[:profile] = case level when :off 0 diff --git a/lib/mongo/gridfs/grid_io.rb b/lib/mongo/gridfs/grid_io.rb index bd7c221..1001f5d 100644 --- a/lib/mongo/gridfs/grid_io.rb +++ b/lib/mongo/gridfs/grid_io.rb @@ -197,7 +197,7 @@ module Mongo private def create_chunk(n) - chunk = OrderedHash.new + chunk = BSON::OrderedHash.new chunk['_id'] = BSON::ObjectID.new chunk['n'] = n chunk['files_id'] = @files_id @@ -319,7 +319,7 @@ module Mongo end def to_mongo_object - h = OrderedHash.new + h = BSON::OrderedHash.new h['_id'] = @files_id h['filename'] = @filename if @filename h['contentType'] = @content_type @@ -335,7 +335,7 @@ module Mongo # Get a server-side md5 and validate against the client if running in safe mode. def get_md5 - md5_command = OrderedHash.new + md5_command = BSON::OrderedHash.new md5_command['filemd5'] = @files_id md5_command['root'] = @fs_name @server_md5 = @files.db.command(md5_command)['md5'] diff --git a/lib/mongo/util/conversions.rb b/lib/mongo/util/conversions.rb index 2ea211e..e692e54 100644 --- a/lib/mongo/util/conversions.rb +++ b/lib/mongo/util/conversions.rb @@ -31,7 +31,7 @@ module Mongo #:nodoc: # array_as_sort_parameters([["field1", :asc], ["field2", :desc]]) => # { "field1" => 1, "field2" => -1} def array_as_sort_parameters(value) - order_by = OrderedHash.new + order_by = BSON::OrderedHash.new if value.first.is_a? Array value.each do |param| if (param.class.name == "String") diff --git a/test/auxillary/1.4_features.rb b/test/auxillary/1.4_features.rb index ec3adb7..2c1cb19 100644 --- a/test/auxillary/1.4_features.rb +++ b/test/auxillary/1.4_features.rb @@ -150,7 +150,7 @@ class Features14Test < Test::Unit::TestCase end should "use geoNear command to return distances from a point" do - cmd = OrderedHash.new + cmd = BSON::OrderedHash.new cmd['geoNear'] = 'places' cmd['near'] = @empire_state cmd['num'] = 6 diff --git a/test/collection_test.rb b/test/collection_test.rb index 71403d3..77fcf11 100644 --- a/test/collection_test.rb +++ b/test/collection_test.rb @@ -323,14 +323,14 @@ class TestCollection < Test::Unit::TestCase assert_equal @@test.find_one(nil), @@test.find_one() assert_equal @@test.find_one({}), @@test.find_one() assert_equal @@test.find_one("hello" => "world"), @@test.find_one() - assert_equal @@test.find_one(OrderedHash["hello", "world"]), @@test.find_one() + assert_equal @@test.find_one(BSON::OrderedHash["hello", "world"]), @@test.find_one() assert @@test.find_one(nil, :fields => ["hello"]).include?("hello") assert !@@test.find_one(nil, :fields => ["foo"]).include?("hello") assert_equal ["_id"], @@test.find_one(nil, :fields => []).keys() assert_equal nil, @@test.find_one("hello" => "foo") - assert_equal nil, @@test.find_one(OrderedHash["hello", "foo"]) + assert_equal nil, @@test.find_one(BSON::OrderedHash["hello", "foo"]) assert_equal nil, @@test.find_one(ObjectID.new) assert_raise TypeError do diff --git a/test/db_api_test.rb b/test/db_api_test.rb index 5a5113b..dd06f46 100644 --- a/test/db_api_test.rb +++ b/test/db_api_test.rb @@ -46,14 +46,14 @@ class DBAPITest < Test::Unit::TestCase end def test_save_ordered_hash - oh = OrderedHash.new + oh = BSON::OrderedHash.new oh['a'] = -1 oh['b'] = 'foo' oid = @@coll.save(oh) assert_equal 'foo', @@coll.find_one(oid)['b'] - oh = OrderedHash['a' => 1, 'b' => 'foo'] + oh = BSON::OrderedHash['a' => 1, 'b' => 'foo'] oid = @@coll.save(oh) assert_equal 'foo', @@coll.find_one(oid)['b'] end @@ -187,7 +187,7 @@ class DBAPITest < Test::Unit::TestCase # Sorting using ordered hash. You can use an unordered one, but then the # order of the keys won't be guaranteed thus your sort won't make sense. - oh = OrderedHash.new + oh = BSON::OrderedHash.new oh['a'] = -1 assert_raise InvalidSortValueError do docs = @@coll.find({'a' => { '$lt' => 10 }}, :sort => oh).to_a diff --git a/test/mongo_bson/bson_test.rb b/test/mongo_bson/bson_test.rb index 0290802..3a3eaf4 100644 --- a/test/mongo_bson/bson_test.rb +++ b/test/mongo_bson/bson_test.rb @@ -123,7 +123,7 @@ class BSONTest < Test::Unit::TestCase end def test_ordered_hash - doc = OrderedHash.new + doc = BSON::OrderedHash.new doc["b"] = 1 doc["a"] = 2 doc["c"] = 3 @@ -284,16 +284,16 @@ class BSONTest < Test::Unit::TestCase end def test_put_id_first - val = OrderedHash.new + val = BSON::OrderedHash.new val['not_id'] = 1 val['_id'] = 2 roundtrip = BSON::BSON_CODER.deserialize(BSON::BSON_CODER.serialize(val, false, true).to_a) - assert_kind_of OrderedHash, roundtrip + assert_kind_of BSON::OrderedHash, roundtrip assert_equal '_id', roundtrip.keys.first val = {'a' => 'foo', 'b' => 'bar', :_id => 42, 'z' => 'hello'} roundtrip = BSON::BSON_CODER.deserialize(BSON::BSON_CODER.serialize(val, false, true).to_a) - assert_kind_of OrderedHash, roundtrip + assert_kind_of BSON::OrderedHash, roundtrip assert_equal '_id', roundtrip.keys.first end @@ -354,7 +354,7 @@ class BSONTest < Test::Unit::TestCase end def test_do_not_change_original_object - val = OrderedHash.new + val = BSON::OrderedHash.new val['not_id'] = 1 val['_id'] = 2 assert val.keys.include?('_id') @@ -426,7 +426,7 @@ class BSONTest < Test::Unit::TestCase end def test_move_id - a = OrderedHash.new + a = BSON::OrderedHash.new a['text'] = 'abc' a['key'] = 'abc' a['_id'] = 1 @@ -441,10 +441,10 @@ class BSONTest < Test::Unit::TestCase end def test_move_id_with_nested_doc - b = OrderedHash.new + b = BSON::OrderedHash.new b['text'] = 'abc' b['_id'] = 2 - c = OrderedHash.new + c = BSON::OrderedHash.new c['text'] = 'abc' c['hash'] = b c['_id'] = 3 diff --git a/test/mongo_bson/ordered_hash_test.rb b/test/mongo_bson/ordered_hash_test.rb index 31f4d0d..5481357 100644 --- a/test/mongo_bson/ordered_hash_test.rb +++ b/test/mongo_bson/ordered_hash_test.rb @@ -3,7 +3,7 @@ require 'test/test_helper' class OrderedHashTest < Test::Unit::TestCase def setup - @oh = OrderedHash.new + @oh = BSON::OrderedHash.new @oh['c'] = 1 @oh['a'] = 2 @oh['z'] = 3 @@ -11,31 +11,31 @@ class OrderedHashTest < Test::Unit::TestCase end def test_initialize - a = OrderedHash.new + a = BSON::OrderedHash.new a['x'] = 1 a['y'] = 2 - b = OrderedHash['x' => 1, 'y' => 2] + b = BSON::OrderedHash['x' => 1, 'y' => 2] assert_equal a, b end def test_hash_code - o = OrderedHash.new + o = BSON::OrderedHash.new o['number'] = 50 assert o.hash end def test_empty - assert_equal [], OrderedHash.new.keys + assert_equal [], BSON::OrderedHash.new.keys end def test_uniq list = [] - doc = OrderedHash.new + doc = BSON::OrderedHash.new doc['_id'] = 'ab12' doc['name'] = 'test' - same_doc = OrderedHash.new + same_doc = BSON::OrderedHash.new same_doc['_id'] = 'ab12' same_doc['name'] = 'test' list << doc @@ -46,23 +46,23 @@ class OrderedHashTest < Test::Unit::TestCase end def test_equality - a = OrderedHash.new + a = BSON::OrderedHash.new a['x'] = 1 a['y'] = 2 - b = OrderedHash.new + b = BSON::OrderedHash.new b['y'] = 2 b['x'] = 1 - c = OrderedHash.new + c = BSON::OrderedHash.new c['x'] = 1 c['y'] = 2 - d = OrderedHash.new + d = BSON::OrderedHash.new d['x'] = 2 d['y'] = 3 - e = OrderedHash.new + e = BSON::OrderedHash.new e['z'] = 1 e['y'] = 2 @@ -105,7 +105,7 @@ class OrderedHashTest < Test::Unit::TestCase end def test_merge - other = OrderedHash.new + other = BSON::OrderedHash.new other['f'] = 'foo' noob = @oh.merge(other) assert_equal @ordered_keys + ['f'], noob.keys @@ -113,7 +113,7 @@ class OrderedHashTest < Test::Unit::TestCase end def test_merge_bang - other = OrderedHash.new + other = BSON::OrderedHash.new other['f'] = 'foo' @oh.merge!(other) assert_equal @ordered_keys + ['f'], @oh.keys @@ -121,7 +121,7 @@ class OrderedHashTest < Test::Unit::TestCase end def test_merge_bang_with_overlap - other = OrderedHash.new + other = BSON::OrderedHash.new other['a'] = 'apple' other['c'] = 'crab' other['f'] = 'foo' @@ -141,7 +141,7 @@ class OrderedHashTest < Test::Unit::TestCase end def test_update - other = OrderedHash.new + other = BSON::OrderedHash.new other['f'] = 'foo' noob = @oh.update(other) assert_equal @ordered_keys + ['f'], noob.keys