mongomodel 0.4.9 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. data/.travis.yml +30 -0
  2. data/Gemfile +1 -1
  3. data/README.md +7 -1
  4. data/Rakefile +0 -2
  5. data/gemfiles/mongo_mapper.gemfile +6 -7
  6. data/gemfiles/mongoid.gemfile +6 -7
  7. data/gemfiles/rails-3.1.gemfile +5 -6
  8. data/gemfiles/rails-3.2.gemfile +5 -6
  9. data/gemfiles/rails-4-observers.gemfile +6 -8
  10. data/gemfiles/rails-4-protected-attributes.gemfile +6 -8
  11. data/gemfiles/rails-4.gemfile +5 -7
  12. data/lib/mongomodel.rb +1 -0
  13. data/lib/mongomodel/concerns/associations/has_many_by_ids.rb +6 -1
  14. data/lib/mongomodel/concerns/attribute_methods/forbidden.rb +17 -0
  15. data/lib/mongomodel/concerns/attribute_methods/multi_parameter_assignment.rb +1 -1
  16. data/lib/mongomodel/concerns/attributes.rb +5 -0
  17. data/lib/mongomodel/concerns/properties.rb +2 -2
  18. data/lib/mongomodel/concerns/serialization.rb +15 -6
  19. data/lib/mongomodel/embedded_document.rb +1 -0
  20. data/lib/mongomodel/railtie.rb +7 -5
  21. data/lib/mongomodel/support/scope.rb +2 -9
  22. data/lib/mongomodel/support/scope/array_methods.rb +21 -0
  23. data/lib/mongomodel/support/types/date_time.rb +18 -5
  24. data/lib/mongomodel/version.rb +1 -1
  25. data/spec/mongomodel/attributes/store_spec.rb +9 -5
  26. data/spec/mongomodel/concerns/activemodel_spec.rb +13 -13
  27. data/spec/mongomodel/concerns/associations/belongs_to_spec.rb +65 -65
  28. data/spec/mongomodel/concerns/associations/has_many_by_ids_spec.rb +128 -121
  29. data/spec/mongomodel/concerns/attributes_spec.rb +11 -2
  30. data/spec/mongomodel/concerns/logging_spec.rb +1 -1
  31. data/spec/mongomodel/concerns/observing_spec.rb +1 -1
  32. data/spec/mongomodel/concerns/serialization/json_serialization_spec.rb +26 -10
  33. data/spec/mongomodel/concerns/timestamps_spec.rb +5 -5
  34. data/spec/mongomodel/document/indexes_spec.rb +1 -1
  35. data/spec/mongomodel/document/validations/uniqueness_spec.rb +1 -1
  36. data/spec/mongomodel/document/validations_spec.rb +1 -1
  37. data/spec/mongomodel/document_spec.rb +1 -1
  38. data/spec/mongomodel/mongomodel_spec.rb +1 -1
  39. data/spec/mongomodel/support/mongo_order_spec.rb +2 -2
  40. data/spec/mongomodel/support/paginator_spec.rb +3 -3
  41. data/spec/mongomodel/support/property_spec.rb +12 -6
  42. data/spec/mongomodel/support/scope_spec.rb +24 -14
  43. data/spec/support/helpers/document_finder_stubs.rb +5 -5
  44. data/spec/support/matchers/find_with.rb +2 -2
  45. metadata +6 -4
  46. data/Appraisals +0 -46
@@ -11,9 +11,10 @@ module MongoModel
11
11
  Array => [ 1, 2, 3, "hello", :world, [99, 100] ],
12
12
  Hash => { :rabbit => 'hat', 'hello' => 12345 }.with_indifferent_access,
13
13
  Date => Date.today,
14
+ CustomClass => CustomClass.new('hello'),
15
+ # Pre-cast Time and DateTime to remove microseconds
14
16
  Time => Types::Time.new.cast(Time.now),
15
- DateTime => Types::DateTime.new.cast(DateTime.now),
16
- CustomClass => CustomClass.new('hello')
17
+ DateTime => Types::DateTime.new.cast(DateTime.now.in_time_zone)
17
18
  }
18
19
 
19
20
  specs_for(Document, EmbeddedDocument) do
@@ -117,6 +118,14 @@ module MongoModel
117
118
  subject.attributes = { :non_property => 'property value' }
118
119
  subject.read_attribute(:non_property).should == 'property value'
119
120
  end
121
+
122
+ if defined?(ActiveModel::ForbiddenAttributesProtection)
123
+ it "raises ActiveModel::ForbiddenAttributesError when passed an unpermitted strong_params hash" do
124
+ expect {
125
+ subject.attributes = double(:permitted? => false)
126
+ }.to raise_error(ActiveModel::ForbiddenAttributesError)
127
+ end
128
+ end
120
129
  end
121
130
 
122
131
  describe "#new" do
@@ -5,7 +5,7 @@ module MongoModel
5
5
  describe "logging" do
6
6
  define_class(:TestDocument, described_class)
7
7
 
8
- let(:logger) { mock('logger').as_null_object }
8
+ let(:logger) { double('logger').as_null_object }
9
9
  before(:each) { MongoModel.logger = logger }
10
10
 
11
11
  it "has a logger reader on the class" do
@@ -22,7 +22,7 @@ module MongoModel
22
22
  end
23
23
 
24
24
  it "invokes the TestObserver singleton's after_save method after saving" do
25
- callback = stub
25
+ callback = double
26
26
  callback.should_receive(:call).with(subject)
27
27
 
28
28
  TestObserver.instance.callback = callback
@@ -15,18 +15,21 @@ module MongoModel
15
15
  end
16
16
 
17
17
  let(:instance) do
18
- TestModel.new(:name => 'Hello World', :age => 25, :paid => true, :prefs => { :foo => 'bar' }, :internal => 'hideme')
18
+ TestModel.new(:id => "abc-123", :name => 'Hello World', :age => 25, :paid => true, :prefs => { :foo => 'bar' }, :internal => 'hideme')
19
19
  end
20
20
 
21
- it "includes root in json" do
22
- begin
23
- TestModel.include_root_in_json = true
24
-
25
- json = instance.to_json
26
- json.should match(/^\{"test_model":\{/)
27
- ensure
28
- TestModel.include_root_in_json = false
29
- end
21
+ it "includes root in the JSON response when include_root_in_json = true" do
22
+ TestModel.include_root_in_json = true
23
+
24
+ json = instance.to_json
25
+ json.should match(/^\{"test_model":\{/)
26
+ end
27
+
28
+ it "does not include root in the JSON response when include_root_in_json = false" do
29
+ TestModel.include_root_in_json = false
30
+
31
+ json = instance.to_json
32
+ json.should_not match(/^\{"test_model":\{/)
30
33
  end
31
34
 
32
35
  it "encodes all public attributes" do
@@ -37,6 +40,13 @@ module MongoModel
37
40
  json.should match(/"prefs":\{"foo":"bar"\}/)
38
41
  end
39
42
 
43
+ if described_class == Document
44
+ it "encodes the id" do
45
+ json = instance.to_json
46
+ json.should match(/"id":"abc-123"/)
47
+ end
48
+ end
49
+
40
50
  it "does not encode internal attributes" do
41
51
  json = instance.to_json
42
52
  json.should_not match(/"internal":"hideme"/)
@@ -63,5 +73,11 @@ module MongoModel
63
73
  json.should match(/"hello":"Hi friend!"/)
64
74
  json.should match(/"type":"TestModel"/)
65
75
  end
76
+
77
+ it "encodes keys in the serializable_hash as strings" do
78
+ hash = instance.serializable_hash(:methods => :hello)
79
+ hash.should have_key("name")
80
+ hash.should have_key("hello")
81
+ end
66
82
  end
67
83
  end
@@ -39,7 +39,7 @@ module MongoModel
39
39
 
40
40
  before(:each) do
41
41
  @now = Types::Time.new.cast(Time.now)
42
- Time.stub!(:now).and_return(@now)
42
+ Time.stub(:now).and_return(@now)
43
43
  end
44
44
 
45
45
  it "sets the updated_at property to the current time when saved" do
@@ -92,7 +92,7 @@ module MongoModel
92
92
 
93
93
  before(:each) do
94
94
  @now = Types::Time.new.cast(Time.now)
95
- Time.stub!(:now).and_return(@now)
95
+ Time.stub(:now).and_return(@now)
96
96
  end
97
97
 
98
98
  it "sets the created_at property to the current time when created" do
@@ -103,11 +103,11 @@ module MongoModel
103
103
  it "does not change the created_at property when updated" do
104
104
  @next = 1.day.from_now
105
105
 
106
- Time.stub!(:now).and_return(@now)
106
+ Time.stub(:now).and_return(@now)
107
107
 
108
108
  doc.save
109
109
 
110
- Time.stub!(:now).and_return(@next)
110
+ Time.stub(:now).and_return(@next)
111
111
 
112
112
  doc.save
113
113
  subject.created_at.should == @now
@@ -152,7 +152,7 @@ module MongoModel
152
152
  @today = Date.today
153
153
  @tomorrow = 1.day.from_now
154
154
 
155
- Time.stub!(:now).and_return(@tomorrow)
155
+ Time.stub(:now).and_return(@tomorrow)
156
156
 
157
157
  doc.save
158
158
  subject.created_on.should == @today
@@ -18,7 +18,7 @@ module MongoModel
18
18
  end
19
19
 
20
20
  it "inherits indexes from parent classes" do
21
- index = mock('index')
21
+ index = double('index')
22
22
  Article.indexes << index
23
23
  subclass(Article).indexes.should include(index)
24
24
  end
@@ -5,7 +5,7 @@ module MongoModel
5
5
  describe "validates_uniqueness_of" do
6
6
  shared_examples_for "beating the race condition" do
7
7
  before(:each) do
8
- subject.stub!(:valid?).and_return(true, false)
8
+ subject.stub(:valid?).and_return(true, false)
9
9
  end
10
10
 
11
11
  describe "save" do
@@ -21,7 +21,7 @@ module MongoModel
21
21
 
22
22
  describe "#save!" do
23
23
  before(:each) do
24
- subject.errors.stub!(:full_messages).and_return(["first error", "second error"])
24
+ subject.errors.stub(:full_messages).and_return(["first error", "second error"])
25
25
  end
26
26
 
27
27
  it "raises a MongoModel::DocumentInvalid exception" do
@@ -10,7 +10,7 @@ module MongoModel
10
10
  property = Document.properties[:id]
11
11
  property.name.should == :id
12
12
  property.as.should == '_id'
13
- property.default(mock('instance', :generate_id => 'abc-123')).should == 'abc-123'
13
+ property.default(double('instance', :generate_id => 'abc-123')).should == 'abc-123'
14
14
  end
15
15
 
16
16
  describe "equality" do
@@ -42,7 +42,7 @@ describe MongoModel do
42
42
  end
43
43
 
44
44
  it "has a logger accessor" do
45
- logger = mock('logger').as_null_object
45
+ logger = double('logger').as_null_object
46
46
  MongoModel.logger = logger
47
47
  MongoModel.logger.should == logger
48
48
  end
@@ -14,7 +14,7 @@ module MongoModel
14
14
 
15
15
  describe "#to_sort" do
16
16
  it "converts to mongo sort array" do
17
- model = mock('model', :properties => mock('properties', :[] => nil))
17
+ model = double('model', :properties => double('properties', :[] => nil))
18
18
  subject.to_sort(model).should == [['name', :ascending], ['age', :descending]]
19
19
  end
20
20
  end
@@ -94,7 +94,7 @@ module MongoModel
94
94
  describe "#to_sort" do
95
95
  context "given property" do
96
96
  it "uses property as value to convert to mongo sort" do
97
- property = mock('property', :as => '_name')
97
+ property = double('property', :as => '_name')
98
98
  subject.to_sort(property).should == ['_name', :ascending]
99
99
  end
100
100
  end
@@ -2,8 +2,8 @@ require 'spec_helper'
2
2
 
3
3
  module MongoModel
4
4
  describe Paginator do
5
- let(:entries) { [stub] * 10 }
6
- let(:scope) { stub(:count => 35, :limit => entries).as_null_object }
5
+ let(:entries) { [double] * 10 }
6
+ let(:scope) { double(:count => 35, :limit => entries).as_null_object }
7
7
  let(:page) { 2 }
8
8
  let(:per_page) { 10 }
9
9
 
@@ -32,7 +32,7 @@ module MongoModel
32
32
  end
33
33
 
34
34
  context "last page" do
35
- let(:entries) { [stub] * 5 }
35
+ let(:entries) { [double] * 5 }
36
36
  before { scope.stub(:count => nil) }
37
37
 
38
38
  let(:page) { 4 }
@@ -19,7 +19,7 @@ module MongoModel
19
19
  end
20
20
 
21
21
  it "defaults to nil" do
22
- subject.default(mock('document instance')).should be_nil
22
+ subject.default(double('document instance')).should be_nil
23
23
  end
24
24
 
25
25
  it "equals a property with the same name and type" do
@@ -47,7 +47,7 @@ module MongoModel
47
47
  end
48
48
 
49
49
  it "defaults to custom default" do
50
- subject.default(mock('document instance')).should == 21
50
+ subject.default(double('document instance')).should == 21
51
51
  end
52
52
 
53
53
  it "equals a property with the same name, type and options" do
@@ -61,10 +61,16 @@ module MongoModel
61
61
  end
62
62
 
63
63
  context "with callable default" do
64
- subject { Property.new(:age, Integer, :default => lambda { |doc| doc.answer }) }
65
-
66
- it "calls lambda with given instance" do
67
- subject.default(mock('document instance', :answer => 42)).should == 42
64
+ let(:document) { double('document instance', :answer => 42) }
65
+
66
+ it "calls the proc yielding the instance" do
67
+ property = Property.new(:age, Integer, :default => lambda { |doc| doc.answer })
68
+ property.default(document).should == 42
69
+ end
70
+
71
+ it "calls the proc in the context of the instance" do
72
+ property = Property.new(:age, Integer, :default => proc { answer })
73
+ property.default(document).should == 42
68
74
  end
69
75
  end
70
76
 
@@ -278,23 +278,33 @@ module MongoModel
278
278
  end
279
279
 
280
280
  describe "#select" do
281
- it "returns a new scope" do
282
- subject.select(:author).should be_an_instance_of(Scope)
283
- end
281
+ context "when no block is given" do
282
+ it "returns a new scope" do
283
+ subject.select(:author).should be_an_instance_of(Scope)
284
+ end
284
285
 
285
- it "is not loaded" do
286
- subject.to_a
287
- subject.select(:author).should_not be_loaded
288
- end
286
+ it "is not loaded" do
287
+ subject.to_a
288
+ subject.select(:author).should_not be_loaded
289
+ end
290
+
291
+ it "adds individual select values" do
292
+ select_scope = subject.select(:author)
293
+ select_scope.select_values.should == subject.select_values + [:author]
294
+ end
289
295
 
290
- it "adds individual select values" do
291
- select_scope = subject.select(:author)
292
- select_scope.select_values.should == subject.select_values + [:author]
296
+ it "adds multiple select values" do
297
+ select_scope = subject.select(:author, :published)
298
+ select_scope.select_values.should == subject.select_values + [:author, :published]
299
+ end
293
300
  end
294
301
 
295
- it "adds multiple select values" do
296
- select_scope = subject.select(:author, :published)
297
- select_scope.select_values.should == subject.select_values + [:author, :published]
302
+ context "when a block given" do
303
+ it "passed block to to_a#select" do
304
+ blk = lambda { |*args| true }
305
+ subject.to_a.should_receive(:select).with(&blk)
306
+ subject.select(&blk)
307
+ end
298
308
  end
299
309
  end
300
310
 
@@ -780,7 +790,7 @@ module MongoModel
780
790
  it "loads total entries using count when auto-detection not possible" do
781
791
  paginator = nil
782
792
 
783
- subject.stub!(:count).and_return(57)
793
+ subject.stub(:count).and_return(57)
784
794
  model.should_find(finder_options.merge(:offset => 0, :limit => 5), posts) {
785
795
  paginator = subject.paginate(:per_page => 5)
786
796
  }
@@ -4,13 +4,13 @@ module DocumentFinderStubs
4
4
  include RSpec::Mocks::ExampleMethods
5
5
 
6
6
  def stub_find(result)
7
- find_result = mock('find result', :to_a => result.map { |doc| doc.to_mongo }, :count => result.size).as_null_object
8
- collection.stub!(:find).and_return(find_result)
7
+ find_result = double('find result', :to_a => result.map { |doc| doc.to_mongo }, :count => result.size).as_null_object
8
+ collection.stub(:find).and_return(find_result)
9
9
  end
10
10
 
11
11
  def should_find(expected={}, result=[])
12
12
  selector, options = MongoModel::MongoOptions.new(self, expected).to_a
13
- find_result = mock('find result', :to_a => result.map { |doc| doc.to_mongo }).as_null_object
13
+ find_result = double('find result', :to_a => result.map { |doc| doc.to_mongo }).as_null_object
14
14
  collection.should_receive(:find).once.with(selector, options).and_return(find_result)
15
15
  yield if block_given?
16
16
  end
@@ -22,7 +22,7 @@ module DocumentFinderStubs
22
22
 
23
23
  def should_count(expected={}, result=[])
24
24
  selector, options = MongoModel::MongoOptions.new(self, expected).to_a
25
- find_result = mock('find result', :count => result).as_null_object
25
+ find_result = double('find result', :count => result).as_null_object
26
26
  collection.should_receive(:find).once.with(selector, options).and_return(find_result)
27
27
  yield if block_given?
28
28
  end
@@ -33,7 +33,7 @@ module DocumentFinderStubs
33
33
  end
34
34
 
35
35
  def stub_delete
36
- collection.stub!(:remove)
36
+ collection.stub(:remove)
37
37
  end
38
38
 
39
39
  def should_delete(conditions={})
@@ -4,7 +4,7 @@ RSpec::Matchers.define(:find_with) do |find_options|
4
4
  match do |klass|
5
5
  selector, options = MongoModel::MongoOptions.new(klass, find_options).to_a
6
6
 
7
- result = mock('find result', :to_a => (@result || []).map { |d| d.to_mongo })
7
+ result = double('find result', :to_a => (@result || []).map { |d| d.to_mongo })
8
8
  klass.collection.should_receive(:find).once.with(selector, options).and_return(result)
9
9
 
10
10
  true
@@ -21,7 +21,7 @@ RSpec::Matchers.define(:count_with) do |find_options|
21
21
 
22
22
  match do |klass|
23
23
  selector, options = MongoModel::MongoOptions.new(klass, find_options).to_a
24
- result = mock('find result')
24
+ result = double('find result')
25
25
 
26
26
  klass.collection.should_receive(:find).once.with(selector, options).and_return(result)
27
27
  result.should_receive(:count).once.and_return(@count || 5)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongomodel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.9
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-23 00:00:00.000000000 Z
12
+ date: 2013-08-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -116,7 +116,7 @@ extensions: []
116
116
  extra_rdoc_files: []
117
117
  files:
118
118
  - .gitignore
119
- - Appraisals
119
+ - .travis.yml
120
120
  - Gemfile
121
121
  - Guardfile
122
122
  - LICENSE
@@ -148,6 +148,7 @@ files:
148
148
  - lib/mongomodel/concerns/attribute_methods.rb
149
149
  - lib/mongomodel/concerns/attribute_methods/before_type_cast.rb
150
150
  - lib/mongomodel/concerns/attribute_methods/dirty.rb
151
+ - lib/mongomodel/concerns/attribute_methods/forbidden.rb
151
152
  - lib/mongomodel/concerns/attribute_methods/multi_parameter_assignment.rb
152
153
  - lib/mongomodel/concerns/attribute_methods/nested.rb
153
154
  - lib/mongomodel/concerns/attribute_methods/protected.rb
@@ -196,6 +197,7 @@ files:
196
197
  - lib/mongomodel/support/paginator.rb
197
198
  - lib/mongomodel/support/reference.rb
198
199
  - lib/mongomodel/support/scope.rb
200
+ - lib/mongomodel/support/scope/array_methods.rb
199
201
  - lib/mongomodel/support/scope/batches.rb
200
202
  - lib/mongomodel/support/scope/dynamic_finders.rb
201
203
  - lib/mongomodel/support/scope/finder_methods.rb
@@ -300,7 +302,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
300
302
  version: '0'
301
303
  segments:
302
304
  - 0
303
- hash: -157518307966196905
305
+ hash: -3084382199068025224
304
306
  required_rubygems_version: !ruby/object:Gem::Requirement
305
307
  none: false
306
308
  requirements:
data/Appraisals DELETED
@@ -1,46 +0,0 @@
1
- RAILS_3_1 = "3.1.10"
2
- RAILS_3_2 = "3.2.11"
3
-
4
- appraise "rails-3.1" do
5
- gem "activesupport", RAILS_3_1
6
- gem "activemodel", RAILS_3_1
7
- end
8
-
9
- appraise "rails-3.2" do
10
- gem "activesupport", RAILS_3_2
11
- gem "activemodel", RAILS_3_2
12
- end
13
-
14
- if RUBY_VERSION >= "1.9"
15
- appraise "rails-4" do
16
- gem "activesupport", :git => "https://github.com/rails/rails.git"
17
- gem "activemodel", :git => "https://github.com/rails/rails.git"
18
- gem "journey", :git => "https://github.com/rails/journey.git"
19
- end
20
-
21
- appraise "rails-4-protected-attributes" do
22
- gem "activesupport", :git => "https://github.com/rails/rails.git"
23
- gem "activemodel", :git => "https://github.com/rails/rails.git"
24
- gem "protected_attributes", :git=>"https://github.com/rails/protected_attributes.git"
25
- gem "journey", :git => "https://github.com/rails/journey.git"
26
- end
27
-
28
- appraise "rails-4-observers" do
29
- gem "activesupport", :git => "https://github.com/rails/rails.git"
30
- gem "activemodel", :git => "https://github.com/rails/rails.git"
31
- gem "rails-observers", :git => "https://github.com/rails/rails-observers.git"
32
- gem "journey", :git => "https://github.com/rails/journey.git"
33
- end
34
-
35
- appraise "mongoid" do
36
- gem "mongoid"
37
- gem "activesupport", RAILS_3_2
38
- gem "activemodel", RAILS_3_2
39
- end
40
- end
41
-
42
- appraise "mongo_mapper" do
43
- gem "mongo_mapper"
44
- gem "activesupport", RAILS_3_2
45
- gem "activemodel", RAILS_3_2
46
- end