Permalink
Browse files

decouple from Hashie::Dash and remove hashie dependency

  • Loading branch information...
1 parent 93b7374 commit 54a2150d7fda411e8cb030ff783b6d4444500d0c @mislav committed Jul 24, 2011
Showing with 310 additions and 267 deletions.
  1. +1 −2 Gemfile
  2. +16 −20 Gemfile.lock
  3. +14 −235 lib/mingo.rb
  4. +7 −9 lib/mingo/changes.rb
  5. +12 −0 lib/mingo/many_proxy.rb
  6. +64 −0 lib/mingo/properties.rb
  7. +0 −1 mingo.gemspec
  8. +196 −0 spec/mingo_spec.rb
View
@@ -4,5 +4,4 @@ gem 'activemodel'
gem 'mongo'
gem 'mongo_ext'
gem 'bson_ext'
-gem 'hashie', '< 1.0'
-gem 'rspec', '~> 2.0.0.beta.20'
+gem 'rspec'
View
@@ -1,38 +1,34 @@
GEM
remote: http://rubygems.org/
specs:
- activemodel (3.0.7)
- activesupport (= 3.0.7)
+ activemodel (3.0.9)
+ activesupport (= 3.0.9)
builder (~> 2.1.2)
i18n (~> 0.5.0)
- activesupport (3.0.7)
- bson (1.3.0)
- bson_ext (1.3.0)
+ activesupport (3.0.9)
+ bson (1.3.1)
+ bson_ext (1.3.1)
builder (2.1.2)
diff-lcs (1.1.2)
- hashie (0.4.0)
i18n (0.5.0)
- mongo (1.3.0)
- bson (>= 1.3.0)
+ mongo (1.3.1)
+ bson (>= 1.3.1)
mongo_ext (0.19.3)
- rspec (2.0.1)
- rspec-core (~> 2.0.1)
- rspec-expectations (~> 2.0.1)
- rspec-mocks (~> 2.0.1)
- rspec-core (2.0.1)
- rspec-expectations (2.0.1)
- diff-lcs (>= 1.1.2)
- rspec-mocks (2.0.1)
- rspec-core (~> 2.0.1)
- rspec-expectations (~> 2.0.1)
+ rspec (2.6.0)
+ rspec-core (~> 2.6.0)
+ rspec-expectations (~> 2.6.0)
+ rspec-mocks (~> 2.6.0)
+ rspec-core (2.6.4)
+ rspec-expectations (2.6.0)
+ diff-lcs (~> 1.1.2)
+ rspec-mocks (2.6.0)
PLATFORMS
ruby
DEPENDENCIES
activemodel
bson_ext
- hashie (< 1.0)
mongo
mongo_ext
- rspec (~> 2.0.0.beta.20)
+ rspec
View
@@ -1,7 +1,6 @@
require 'active_support/core_ext/hash/conversions'
require 'mongo'
require 'active_model'
-require 'hashie/dash'
BSON::ObjectId.class_eval do
def self.[](id)
@@ -13,14 +12,15 @@ def id
end
end
-class Mingo < Hashie::Dash
+class Mingo < Hash
include ActiveModel::Conversion
extend ActiveModel::Translation
+ autoload :Properties, 'mingo/properties'
autoload :Cursor, 'mingo/cursor'
autoload :Connection, 'mingo/connection'
autoload :Finders, 'mingo/finders'
- autoload :ManyProxy, 'mingo/many_proxy'
+ autoload :Many, 'mingo/many_proxy'
autoload :Persistence, 'mingo/persistence'
autoload :Callbacks, 'mingo/callbacks'
autoload :Changes, 'mingo/changes'
@@ -29,29 +29,20 @@ class Mingo < Hashie::Dash
extend Connection
extend Finders
-
# highly experimental stuff
- def self.many(property, *args, &block)
- proxy_class = block_given?? Class.new(ManyProxy, &block) : ManyProxy
- ivar = "@#{property}"
-
- define_method(property) {
- (instance_variable_defined?(ivar) && instance_variable_get(ivar)) ||
- instance_variable_set(ivar, proxy_class.new(self, property, *args))
- }
- end
-
- include Module.new {
- def initialize(obj = nil)
- if obj and obj['_id'].is_a? BSON::ObjectId
- # a doc loaded straight from the db
- merge!(obj)
- else
- super
+ extend Many
+
+ def initialize(obj = nil)
+ super()
+ if obj
+ # a doc loaded straight from the db?
+ if obj['_id'].is_a? BSON::ObjectId then merge!(obj)
+ else obj.each { |prop, value| self.send("#{prop}=", value) }
end
end
- }
-
+ end
+
+ include Properties
include Persistence
include Callbacks
include Changes
@@ -60,219 +51,7 @@ def id
self['_id']
end
- # overwrite these to avoid checking for declared properties
- # (which is default behavior in Dash)
- def [](property)
- _regular_reader(property.to_s)
- end
-
- def []=(property, value)
- _regular_writer(property.to_s, value)
- end
-
- # keys are already strings
- def stringify_keys() self end
- alias :stringify_keys! :stringify_keys
-
def ==(other)
other.is_a?(self.class) and other.id == self.id
end
end
-
-if $0 == __FILE__
- require 'rspec'
-
- Mingo.connect('mingo')
-
- class User < Mingo
- property :name
- property :age
- end
-
- describe User do
- before :all do
- User.collection.remove
- end
-
- it "obtains an ID by saving" do
- user = build :name => 'Mislav'
- user.should_not be_persisted
- user.id.should be_nil
- user.save
- raw_doc(user.id)['name'].should == 'Mislav'
- user.should be_persisted
- user.id.should be_a(BSON::ObjectId)
- end
-
- it "tracks changes attribute" do
- user = build
- user.should_not be_changed
- user.name = 'Mislav'
- user.should be_changed
- user.changes.keys.should include(:name)
- user.name = 'Mislav2'
- user.changes[:name].should == [nil, 'Mislav2']
- user.save
- user.should_not be_changed
- end
-
- it "forgets changed attribute when reset to original value" do
- user = create :name => 'Mislav'
- user.name = 'Mislav2'
- user.should be_changed
- user.name = 'Mislav'
- user.should_not be_changed
- end
-
- it "has a human model name" do
- described_class.model_name.human.should == 'User'
- end
-
- it "can reload values from the db" do
- user = create :name => 'Mislav'
- user.update '$unset' => {:name => 1}, '$set' => {:age => 26}
- user.age.should be_nil
- user.reload
- user.age.should == 26
- user.name.should be_nil
- end
-
- it "saves only changed values" do
- user = create :name => 'Mislav', :age => 26
- user.update '$inc' => {:age => 1}
- user.name = 'Mislav2'
- user.save
- user.reload
- user.name.should == 'Mislav2'
- user.age.should == 27
- end
-
- it "unsets values set to nil" do
- user = create :name => 'Mislav', :age => 26
- user.age = nil
- user.save
-
- raw_doc(user.id).tap do |doc|
- doc.should_not have_key('age')
- doc.should have_key('name')
- end
- end
-
- context "existing doc" do
- before do
- @id = described_class.collection.insert :name => 'Mislav', :age => 26
- end
-
- it "finds a doc by string ID" do
- user = described_class.first(@id.to_s)
- user.id.should == @id
- user.name.should == 'Mislav'
- user.age.should == 26
- end
-
- it "is unchanged after loading" do
- user = described_class.first(@id)
- user.should_not be_changed
- user.age = 27
- user.should be_changed
- user.changes.keys.should == [:age]
- end
-
- it "doesn't get changed by an inspect" do
- user = described_class.first(@id)
- # triggers AS stringify_keys, which dups the Dash and writes to it,
- # which mutates the @changes hash from the original Dash
- user.inspect
- user.should_not be_changed
- end
- end
-
- it "returns nil for non-existing doc" do
- doc = described_class.first('nonexist' => 1)
- doc.should be_nil
- end
-
- it "compares with another record" do
- one = create :name => "One"
- two = create :name => "Two"
- one.should_not == two
-
- one_dup = described_class.first(one.id)
- one_dup.should == one
- end
-
- it "returns a custom cursor" do
- cursor = described_class.collection.find({})
- cursor.should respond_to(:empty?)
- end
-
- context "cursor reverse" do
- it "can't reverse no order" do
- lambda {
- described_class.find({}).reverse
- }.should raise_error
- end
-
- it "reverses simple order" do
- cursor = described_class.find({}, :sort => :name).reverse
- cursor.order.should == [[:name, -1]]
- end
-
- it "reverses simple desc order" do
- cursor = described_class.find({}, :sort => [:name, :desc]).reverse
- cursor.order.should == [[:name, 1]]
- end
-
- it "reverses simple nested desc order" do
- cursor = described_class.find({}, :sort => [[:name, :desc]]).reverse
- cursor.order.should == [[:name, 1]]
- end
-
- it "can't reverse complex order" do
- lambda {
- described_class.find({}, :sort => [[:name, :desc], [:other, :asc]]).reverse
- }.should raise_error
- end
-
- it "reverses find by ids" do
- cursor = described_class.find([1,3,5]).reverse
- cursor.selector.should == {:_id => {"$in" => [5,3,1]}}
- end
- end
-
- context "find by ids" do
- before :all do
- @docs = [create, create, create]
- @doc1, @doc2, @doc3 = *@docs
- end
-
- it "orders results by ids" do
- results = described_class.find([@doc3.id, @doc1.id, @doc2.id]).to_a
- results.should == [@doc3, @doc1, @doc2]
- end
-
- it "handles limit + skip" do
- cursor = described_class.find([@doc3.id, @doc1.id, @doc2.id]).limit(1).skip(2)
- cursor.to_a.should == [@doc2]
- end
-
- it "returns correct count" do
- cursor = described_class.find([@doc3.id, @doc1.id, @doc2.id]).limit(1).skip(2)
- cursor.next_document
- cursor.count.should == 3
- end
- end
-
- def build(*args)
- described_class.new(*args)
- end
-
- def create(*args)
- described_class.create(*args)
- end
-
- def raw_doc(selector)
- described_class.first(selector, :transformer => nil)
- end
- end
-end
View
@@ -10,20 +10,20 @@ def initialize(*args)
@changes = {}
super
end
+
+ def []=(key, value)
+ record_change(key, value)
+ super
+ end
def changed?
changes.any?
end
private
-
- def _regular_writer(key, value)
- track_change(key, value)
- super
- end
- def track_change(key, value)
- old_value = _regular_reader(key)
+ def record_change(key, value)
+ old_value = self[key]
unless value == old_value
memo = (changes[key.to_sym] ||= [old_value])
memo[0] == value ? changes.delete(key.to_sym) : (memo[1] = value)
@@ -34,8 +34,6 @@ def clear_changes
changes.clear
end
- private
-
def values_for_update
changes.inject('$set' => {}, '$unset' => {}) do |doc, (key, values)|
value = values[1]
Oops, something went wrong.

0 comments on commit 54a2150

Please sign in to comment.