mongo_mapper 0.13.0 → 0.13.1

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mongo_mapper.rb +3 -0
  3. data/lib/mongo_mapper/connection.rb +4 -3
  4. data/lib/mongo_mapper/document.rb +2 -0
  5. data/lib/mongo_mapper/extensions/symbol.rb +18 -0
  6. data/lib/mongo_mapper/plugins/accessible.rb +10 -1
  7. data/lib/mongo_mapper/plugins/associations/base.rb +5 -1
  8. data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +9 -0
  9. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +0 -0
  10. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +0 -0
  11. data/lib/mongo_mapper/plugins/associations/one_embedded_polymorphic_proxy.rb +0 -0
  12. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +0 -0
  13. data/lib/mongo_mapper/plugins/associations/proxy.rb +2 -2
  14. data/lib/mongo_mapper/plugins/counter_cache.rb +78 -0
  15. data/lib/mongo_mapper/plugins/indexes.rb +0 -0
  16. data/lib/mongo_mapper/plugins/keys.rb +14 -2
  17. data/lib/mongo_mapper/plugins/modifiers.rb +0 -0
  18. data/lib/mongo_mapper/plugins/querying/decorated_plucky_query.rb +0 -0
  19. data/lib/mongo_mapper/plugins/rails.rb +1 -0
  20. data/lib/mongo_mapper/plugins/sci.rb +0 -0
  21. data/lib/mongo_mapper/plugins/stats.rb +19 -0
  22. data/lib/mongo_mapper/plugins/validations.rb +1 -1
  23. data/lib/mongo_mapper/railtie.rb +3 -3
  24. data/lib/mongo_mapper/version.rb +1 -1
  25. data/spec/functional/counter_cache_spec.rb +146 -0
  26. data/spec/functional/document_spec.rb +28 -0
  27. data/spec/functional/indexes_spec.rb +0 -0
  28. data/spec/functional/keys_spec.rb +31 -0
  29. data/spec/functional/sci_spec.rb +0 -0
  30. data/spec/functional/stats_spec.rb +74 -0
  31. data/spec/quality_spec.rb +51 -0
  32. data/spec/unit/associations/proxy_spec.rb +5 -0
  33. data/spec/unit/extensions_spec.rb +24 -0
  34. data/spec/unit/key_spec.rb +0 -0
  35. data/spec/unit/model_generator_spec.rb +0 -0
  36. data/spec/unit/rails_spec.rb +5 -0
  37. metadata +28 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cd7ff4dfcd2b6bce162c7b55ba45e8c00e38a461
4
- data.tar.gz: 673686bd40a1c139e2045b5397802239cd5d894c
3
+ metadata.gz: 3e78985587a63e18283384630db3c316ee260b20
4
+ data.tar.gz: 5f2d55cbe5df4c2f8322088cb9f0edfaa84a69e9
5
5
  SHA512:
6
- metadata.gz: 36943d83bc3ddff1cd8c82d8bddfdde2fa3dfae12800f4c93260480185925e1f34e5a8622b7682b176a318579ee723339286a5c5b99678e9731301e475fb183b
7
- data.tar.gz: 039605ede2145f91ef107e39dc91d43db57906be355737198fe0a1cff97a2eeb821a9a9460fa977f1a2cc520cdf07c1177994db5ad623e298203e50e6f5838a4
6
+ metadata.gz: cf19d01f18a16676486f87db3e0db2c6894c6542f8492ed63b72cd9dbb24ae4dd90f26c5ec226a98fdc1636539a5a9a410c813bffba5923fa95a06fcc873bc4b
7
+ data.tar.gz: 0b915ec964c1bafa1c3432061d91800029f291ce7799945830129d5c4109b1c2c21902ed8eb31ebb6c5648cb46c4775fe692d46614078ba001dabc95606ca3d0
data/lib/mongo_mapper.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # encoding: UTF-8
2
2
  require 'plucky'
3
+ require 'active_support'
3
4
  require 'active_support/core_ext'
4
5
  require 'active_model'
5
6
  require "mongo_mapper/railtie" if defined?(Rails)
@@ -35,6 +36,7 @@ module MongoMapper
35
36
  autoload :Callbacks, 'mongo_mapper/plugins/callbacks'
36
37
  autoload :Caching, 'mongo_mapper/plugins/caching'
37
38
  autoload :Clone, 'mongo_mapper/plugins/clone'
39
+ autoload :CounterCache, 'mongo_mapper/plugins/counter_cache'
38
40
  autoload :Dirty, 'mongo_mapper/plugins/dirty'
39
41
  autoload :Document, 'mongo_mapper/plugins/document'
40
42
  autoload :DynamicQuerying, 'mongo_mapper/plugins/dynamic_querying'
@@ -57,6 +59,7 @@ module MongoMapper
57
59
  autoload :Sci, 'mongo_mapper/plugins/sci'
58
60
  autoload :Scopes, 'mongo_mapper/plugins/scopes'
59
61
  autoload :Serialization, 'mongo_mapper/plugins/serialization'
62
+ autoload :Stats, 'mongo_mapper/plugins/stats'
60
63
  autoload :Timestamps, 'mongo_mapper/plugins/timestamps'
61
64
  autoload :Userstamps, 'mongo_mapper/plugins/userstamps'
62
65
  autoload :Validations, 'mongo_mapper/plugins/validations'
@@ -78,11 +78,12 @@ module MongoMapper
78
78
  options[:ssl] = env['ssl']
79
79
  end
80
80
 
81
- MongoMapper.connection = if env['hosts']
81
+ MongoMapper.connection = if env.key?('hosts')
82
+ klass = (env.key?("mongos") || env.key?("sharded")) ? Mongo::MongoShardedClient : Mongo::MongoReplicaSetClient
82
83
  if env['hosts'].first.is_a?(String)
83
- Mongo::MongoReplicaSetClient.new( env['hosts'], options )
84
+ klass.new( env['hosts'], options )
84
85
  else
85
- Mongo::MongoReplicaSetClient.new( *env['hosts'].push(options) )
86
+ klass.new( *env['hosts'].push(options) )
86
87
  end
87
88
  else
88
89
  Mongo::MongoClient.new(env['host'], env['port'], options)
@@ -28,6 +28,7 @@ module MongoMapper
28
28
  include Plugins::Sci
29
29
  include Plugins::Scopes
30
30
  include Plugins::Serialization
31
+ include Plugins::Stats
31
32
  include Plugins::Timestamps
32
33
  include Plugins::Userstamps
33
34
  include Plugins::Touch
@@ -35,6 +36,7 @@ module MongoMapper
35
36
  include Plugins::EmbeddedCallbacks
36
37
  include Plugins::Callbacks # for now callbacks needs to be after validations
37
38
  include Plugins::IdentityMap
39
+ include Plugins::CounterCache
38
40
 
39
41
  included do
40
42
  extend Plugins
@@ -0,0 +1,18 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Extensions
4
+ module Symbol
5
+ def to_mongo(value)
6
+ value && value.to_s.to_sym
7
+ end
8
+
9
+ def from_mongo(value)
10
+ value && value.to_s.to_sym
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ class Symbol
17
+ extend MongoMapper::Extensions::Symbol
18
+ end
@@ -45,7 +45,16 @@ module MongoMapper
45
45
  protected
46
46
  def filter_inaccessible_attrs(attrs)
47
47
  return attrs if !accessible_attributes? || attrs.blank?
48
- attrs.dup.delete_if { |key, val| !accessible_attributes.include?(key.to_sym) }
48
+ attrs.dup.delete_if { |key, val| attribute_inaccessible?(key.to_sym) }
49
+ end
50
+
51
+ def attribute_inaccessible?(attribute)
52
+ unless accessible_attributes.include?(attribute)
53
+ message = "Can't mass-assign protected attribute: #{attribute}"
54
+ MongoMapper.logger ? MongoMapper.logger.warn(message) : puts(message)
55
+
56
+ return true
57
+ end
49
58
  end
50
59
  end
51
60
  end
@@ -6,7 +6,7 @@ module MongoMapper
6
6
  attr_reader :name, :options, :query_options
7
7
 
8
8
  # Options that should not be considered MongoDB query options/criteria
9
- AssociationOptions = [:as, :class, :class_name, :dependent, :extend, :foreign_key, :in, :polymorphic, :autosave, :touch]
9
+ AssociationOptions = [:as, :class, :class_name, :dependent, :extend, :foreign_key, :in, :polymorphic, :autosave, :touch, :counter_cache]
10
10
 
11
11
  def initialize(name, options={}, &extension)
12
12
  @name, @options, @query_options, @original_options = name.to_sym, {}, {}, options
@@ -43,6 +43,10 @@ module MongoMapper
43
43
  !!@options[:touch]
44
44
  end
45
45
 
46
+ def counter_cache?
47
+ !!@options[:counter_cache]
48
+ end
49
+
46
50
  def type_key_name
47
51
  "_type"
48
52
  end
@@ -20,6 +20,7 @@ module MongoMapper
20
20
  model.key type_key_name, String unless model.key?(type_key_name) if polymorphic?
21
21
  super
22
22
  add_touch_callbacks if touch?
23
+ add_counter_cache if counter_cache?
23
24
  end
24
25
 
25
26
  def autosave?
@@ -46,7 +47,15 @@ module MongoMapper
46
47
  @model.after_save(method_name)
47
48
  @model.after_touch(method_name)
48
49
  @model.after_destroy(method_name)
50
+ end
51
+
52
+ def add_counter_cache
53
+ options = {}
54
+ if @options[:counter_cache] && @options[:counter_cache] != true
55
+ options[:field] = @options[:counter_cache]
56
+ end
49
57
 
58
+ @model.counter_cache name, options
50
59
  end
51
60
  end
52
61
  end
@@ -91,12 +91,12 @@ module MongoMapper
91
91
  proxy_respond_to?(*args) || (load_target && target.respond_to?(*args))
92
92
  end
93
93
 
94
- def send(method, *args)
94
+ def send(method, *args, &block)
95
95
  if proxy_respond_to?(method, true)
96
96
  super
97
97
  else
98
98
  load_target
99
- target.send(method, *args)
99
+ target.send(method, *args, &block)
100
100
  end
101
101
  end
102
102
 
@@ -0,0 +1,78 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ # Counter Caching for MongoMapper::Document
4
+ #
5
+ # Examples:
6
+ #
7
+ # class Post
8
+ # belongs_to :user
9
+ # counter_cache :user
10
+ # end
11
+ #
12
+ # or:
13
+ #
14
+ # class Post
15
+ # belongs_to :user
16
+ # counter_cache :user, :custom_posts_count
17
+ # end
18
+ #
19
+ # Field names follow rails conventions, so counter_cache :user will increment the Integer field `posts_count' on User
20
+ #
21
+ # Alternatively, you can also use the more common ActiveRecord syntax:
22
+ #
23
+ # class Post
24
+ # belongs_to :user, :counter_cache => true
25
+ # end
26
+ #
27
+ # Or with an alternative field name:
28
+ #
29
+ # class Post
30
+ # belongs_to :user, :counter_cache => :custom_posts_count
31
+ # end
32
+ #
33
+ module CounterCache
34
+ class InvalidCounterCacheError < StandardError; end
35
+
36
+ extend ActiveSupport::Concern
37
+
38
+ module ClassMethods
39
+ def counter_cache(association_name, options = {})
40
+ options.symbolize_keys!
41
+
42
+ field = options[:field] ?
43
+ options[:field] :
44
+ "#{self.collection_name.gsub(/.*\./, '')}_count"
45
+
46
+ association = associations[association_name]
47
+
48
+ if !association
49
+ raise InvalidCounterCacheError, "You must define an association with name `#{association_name}' on model #{self}"
50
+ end
51
+
52
+ association_class = association.klass
53
+ key_names = association_class.keys.keys
54
+
55
+ if !key_names.include?(field.to_s)
56
+ raise InvalidCounterCacheError, "Missing `key #{field.to_sym.inspect}, Integer, :default => 0' on model #{association_class}"
57
+ end
58
+
59
+ after_create do
60
+ if obj = self.send(association_name)
61
+ obj.increment(field => 1)
62
+ obj.write_attribute(field, obj.read_attribute(field) + 1)
63
+ end
64
+ true
65
+ end
66
+
67
+ after_destroy do
68
+ if obj = self.send(association_name)
69
+ obj.decrement(field => 1)
70
+ obj.write_attribute(field, obj.read_attribute(field) - 1)
71
+ end
72
+ true
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
File without changes
@@ -246,8 +246,20 @@ module MongoMapper
246
246
  a_name = [name]
247
247
 
248
248
  _validators.reject!{ |key, _| key == name }
249
- _validate_callbacks.reject! {|callback| callback.raw_filter.attributes == a_name }
249
+ remove_validate_callbacks a_name
250
250
  end
251
+
252
+ def remove_validate_callbacks(a_name)
253
+ chain = _validate_callbacks.dup.reject do |callback|
254
+ f = callback.raw_filter
255
+ f.respond_to?(:attributes) && f.attributes == a_name
256
+ end
257
+ reset_callbacks(:validate)
258
+ chain.each do |callback|
259
+ set_callback 'validate', callback.raw_filter
260
+ end
261
+ end
262
+
251
263
  end
252
264
 
253
265
  def initialize(attrs={})
@@ -293,7 +305,7 @@ module MongoMapper
293
305
 
294
306
  embedded_associations.each do |association|
295
307
  if documents = instance_variable_get(association.ivar)
296
- if association.instance_of?(Associations::OneAssociation)
308
+ if association.is_a?(Associations::OneAssociation)
297
309
  attrs[association.name] = documents.to_mongo
298
310
  else
299
311
  attrs[association.name] = documents.map(&:to_mongo)
File without changes
@@ -36,6 +36,7 @@ module MongoMapper
36
36
 
37
37
  def write_attribute(name, value)
38
38
  self[name] = value
39
+ self[name]
39
40
  end
40
41
 
41
42
  def write_key(name, value)
File without changes
@@ -0,0 +1,19 @@
1
+ # encoding: UTF-8
2
+
3
+ module MongoMapper
4
+ module Plugins
5
+ module Stats
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ def stats
10
+ stats = collection.stats
11
+
12
+ Struct.new(*stats.keys.collect { |key| key.underscore.to_sym }).new(*stats.values)
13
+ rescue
14
+ nil
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -34,7 +34,7 @@ module MongoMapper
34
34
  end
35
35
 
36
36
  if ::ActiveModel::VERSION::MAJOR < 4 ||
37
- (::ActiveModel::VERSION::MAJOR == 4 && ::ActiveModel::VERSION::MINOR == 0)
37
+ (::ActiveModel::VERSION::MAJOR == 4 && ::ActiveModel::VERSION::MINOR == 0)
38
38
 
39
39
  def setup(klass)
40
40
  @klass = klass
@@ -14,9 +14,9 @@ module MongoMapper
14
14
  # Rescue responses similar to ActiveRecord.
15
15
  # For rails 3.0 and 3.1
16
16
  if Rails.version < "3.2"
17
- ActionDispatch::ShowExceptions.rescue_responses['MongoMapper::DocumentNotFound'] = :not_found,
18
- ActionDispatch::ShowExceptions.rescue_responses['MongoMapper::InvalidKey'] = :unprocessable_entity,
19
- ActionDispatch::ShowExceptions.rescue_responses['MongoMapper::InvalidScheme'] = :unprocessable_entity,
17
+ ActionDispatch::ShowExceptions.rescue_responses['MongoMapper::DocumentNotFound'] = :not_found
18
+ ActionDispatch::ShowExceptions.rescue_responses['MongoMapper::InvalidKey'] = :unprocessable_entity
19
+ ActionDispatch::ShowExceptions.rescue_responses['MongoMapper::InvalidScheme'] = :unprocessable_entity
20
20
  ActionDispatch::ShowExceptions.rescue_responses['MongoMapper::NotSupported'] = :unprocessable_entity
21
21
  else
22
22
  # For rails 3.2 and 4.0
@@ -1,4 +1,4 @@
1
1
  # encoding: UTF-8
2
2
  module MongoMapper
3
- Version = '0.13.0'
3
+ Version = '0.13.1'
4
4
  end
@@ -0,0 +1,146 @@
1
+ require 'spec_helper'
2
+
3
+ module CounterCacheFixtureModels
4
+ class User
5
+ include MongoMapper::Document
6
+
7
+ key :posts_count, Integer, :default => 0
8
+
9
+ has_many :posts,
10
+ :class_name => "CounterCacheFixtureModels::Post"
11
+ end
12
+
13
+ class Post
14
+ include MongoMapper::Document
15
+
16
+ key :comments_count, Integer, :default => 0
17
+ key :some_custom_comments_count, Integer, :default => 0
18
+
19
+ has_many :comments,
20
+ :class_name => "CounterCacheFixtureModels::Comment"
21
+
22
+ belongs_to :user,
23
+ :counter_cache => true,
24
+ :class_name => "CounterCacheFixtureModels::User"
25
+ end
26
+
27
+ class Comment
28
+ include MongoMapper::Document
29
+
30
+ belongs_to :post,
31
+ :counter_cache => true,
32
+ :class_name => "CounterCacheFixtureModels::Post"
33
+ end
34
+
35
+ class CustomComment
36
+ include MongoMapper::Document
37
+
38
+ belongs_to :post,
39
+ :counter_cache => :some_custom_comments_count,
40
+ :class_name => "CounterCacheFixtureModels::Post"
41
+ end
42
+ end
43
+
44
+ describe MongoMapper::Plugins::CounterCache do
45
+ before do
46
+ @post_class = CounterCacheFixtureModels::Post
47
+ @comment_class = CounterCacheFixtureModels::Comment
48
+ @user_class = CounterCacheFixtureModels::User
49
+ @custom_comment_class = CounterCacheFixtureModels::CustomComment
50
+ end
51
+
52
+ it "should have a key with posts_count defaulting to 0" do
53
+ @post_class.new.comments_count.should == 0
54
+ end
55
+
56
+ it "should update the count when a new object is created" do
57
+ post = @post_class.new
58
+ comment = @comment_class.new
59
+
60
+ post.save!
61
+
62
+ comment.post = post
63
+ comment.save!
64
+
65
+ post.reload
66
+ post.comments_count.should == 1
67
+
68
+ second_comment = @comment_class.new
69
+ second_comment.post = post
70
+ second_comment.save!
71
+
72
+ post.reload
73
+ post.comments_count.should == 2
74
+ end
75
+
76
+ it "should decrease the count by one when an object is destroyed" do
77
+ post = @post_class.new
78
+ comment = @comment_class.new
79
+
80
+ post.save!
81
+
82
+ comment.post = post
83
+ comment.save!
84
+
85
+ post.reload
86
+ post.comments_count.should == 1
87
+
88
+ comment.destroy
89
+ post.reload
90
+ post.comments_count.should == 0
91
+ end
92
+
93
+ it "should use the correct association name" do
94
+ @user = @user_class.new
95
+ @post = @post_class.new
96
+
97
+ @user.save!
98
+ @post.user = @user
99
+ @post.save!
100
+
101
+ @user.reload
102
+ @user.posts_count.should == 1
103
+ end
104
+
105
+ it "should be able to use a custom field name" do
106
+ @post = @post_class.new
107
+ @custom_comment = @custom_comment_class.new
108
+
109
+ @post.save!
110
+ @custom_comment.post = @post
111
+ @custom_comment.save!
112
+
113
+ @post.reload
114
+ @post.some_custom_comments_count.should == 1
115
+ end
116
+
117
+ it "should thrown an error if there is no association" do
118
+ lambda {
119
+ CounterCacheFixtureModels.module_eval do
120
+ class CommentWithInvalidAssociation
121
+ include MongoMapper::Document
122
+
123
+ belongs_to :post,
124
+ :class_name => "CounterCacheFixtureModels::Post"
125
+
126
+ counter_cache :foo
127
+ end
128
+ end
129
+ }.should raise_error(MongoMapper::Plugins::CounterCache::InvalidCounterCacheError, "You must define an association with name `foo' on model CommentWithInvalidAssociation")
130
+ end
131
+
132
+ it "should thown a sensible error if the field is not defined on the target object" do
133
+ lambda {
134
+ CounterCacheFixtureModels.module_eval do
135
+ class CommentWithBadRefenceField
136
+ include MongoMapper::Document
137
+
138
+ belongs_to :post,
139
+ :class_name => "CounterCacheFixtureModels::Post"
140
+
141
+ counter_cache :post, :field => :invalid_field
142
+ end
143
+ end
144
+ }.should raise_error(MongoMapper::Plugins::CounterCache::InvalidCounterCacheError, "Missing `key :invalid_field, Integer, :default => 0' on model CounterCacheFixtureModels::Post")
145
+ end
146
+ end
@@ -130,6 +130,34 @@ describe "Document" do
130
130
  end
131
131
  end
132
132
 
133
+ context "symbol key" do
134
+ before do
135
+ @document.key :foo, Symbol, :default => lambda { 123 }
136
+ end
137
+
138
+ it "should return default value" do
139
+ doc = @document.new
140
+ doc.foo.should == :'123'
141
+ end
142
+
143
+ it "should return symbol value" do
144
+ doc = @document.create :foo => 'qwerty'
145
+ doc.foo.should == :qwerty
146
+
147
+ doc.set :foo => 'poiuyt'
148
+ doc.reload
149
+ doc.foo.should == :poiuyt
150
+
151
+ doc.foo = 'asdf'
152
+ doc.foo.should == :asdf
153
+ end
154
+
155
+ it "should return typecasted value" do
156
+ doc = @document.new
157
+ (doc.foo = 'qwerty').should == 'qwerty'
158
+ end
159
+ end
160
+
133
161
  it "should have instance method for collection" do
134
162
  @document.new.collection.name.should == @document.collection.name
135
163
  end
File without changes
@@ -296,4 +296,35 @@ describe "Keys" do
296
296
  end
297
297
  end
298
298
  end
299
+
300
+ describe "removing keys" do
301
+ DocWithRemovedKey = Doc do
302
+ key :something
303
+ validates_uniqueness_of :something
304
+ remove_key :something
305
+ end
306
+
307
+ it 'should remove the key' do
308
+ DocWithRemovedKey.keys.should_not have_key "_something"
309
+ end
310
+
311
+ it 'should remove validations' do
312
+ DocWithRemovedKey._validate_callbacks.should be_empty
313
+ end
314
+ end
315
+
316
+ describe "removing keys in the presence of a validation method" do
317
+ DocWithRemovedValidator = Doc do
318
+ key :something
319
+ validate :something_valid?
320
+ remove_key :something
321
+
322
+ def something_valid?; true; end
323
+ end
324
+
325
+ it 'should remove the key' do
326
+ DocWithRemovedKey.keys.should_not have_key "_something"
327
+ end
328
+
329
+ end
299
330
  end
File without changes
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Stats" do
4
+ before(:each) do
5
+ class ::Docs
6
+ include MongoMapper::Document
7
+ key :title, String
8
+ key :published_at, Time
9
+ end
10
+
11
+ Docs.collection.drop
12
+ end
13
+
14
+ context "with no documents present" do
15
+ it "should return nil" do
16
+ expect(Docs.stats).to eq(nil)
17
+ end
18
+ end
19
+
20
+ context "with documents present" do
21
+ before do
22
+ # Make sure that there is at least one document stored
23
+ Docs.create!
24
+ end
25
+
26
+ it "should have the correct count" do
27
+ expect(Docs.stats.count).to eq(Docs.collection.stats['count'])
28
+ end
29
+
30
+ it "should have the correct namespace" do
31
+ expect(Docs.stats.ns).to eq(Docs.collection.stats['ns'])
32
+ end
33
+
34
+ it "should have the correct size" do
35
+ expect(Docs.stats.size).to eq(Docs.collection.stats['size'])
36
+ end
37
+
38
+ it "should have the correct storage size" do
39
+ expect(Docs.stats.storage_size).to eq(Docs.collection.stats['storageSize'])
40
+ end
41
+
42
+ it "should have the correct average object size" do
43
+ expect(Docs.stats.avg_obj_size).to eq(Docs.collection.stats['avgObjSize'])
44
+ end
45
+
46
+ it "should have the correct number of extents" do
47
+ expect(Docs.stats.num_extents).to eq(Docs.collection.stats['numExtents'])
48
+ end
49
+
50
+ it "should have the correct number of indexes" do
51
+ expect(Docs.stats.nindexes).to eq(Docs.collection.stats['nindexes'])
52
+ end
53
+
54
+ it "should have the correct last extent size" do
55
+ expect(Docs.stats.last_extent_size).to eq(Docs.collection.stats['lastExtentSize'])
56
+ end
57
+
58
+ it "should have the correct padding factor" do
59
+ expect(Docs.stats.padding_factor).to eq(Docs.collection.stats['paddingFactor'])
60
+ end
61
+
62
+ it "should have the correct system flags" do
63
+ expect(Docs.stats.system_flags).to eq(Docs.collection.stats['systemFlags'])
64
+ end
65
+
66
+ it "should have the correct user flags" do
67
+ expect(Docs.stats.user_flags).to eq(Docs.collection.stats['userFlags'])
68
+ end
69
+
70
+ it "should have the correct total index size" do
71
+ expect(Docs.stats.total_index_size).to eq(Docs.collection.stats['totalIndexSize'])
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,51 @@
1
+ if defined?(Encoding) && Encoding.default_external != "UTF-8"
2
+ Encoding.default_external = "UTF-8"
3
+ end
4
+
5
+ describe "The library itself" do
6
+ def check_for_tab_characters(filename)
7
+ failing_lines = []
8
+ File.readlines(filename).each_with_index do |line,number|
9
+ failing_lines << number + 1 if line =~ /\t/
10
+ end
11
+
12
+ unless failing_lines.empty?
13
+ "#{filename} has tab characters on lines #{failing_lines.join(', ')}"
14
+ end
15
+ end
16
+
17
+ def check_for_extra_spaces(filename)
18
+ failing_lines = []
19
+ File.readlines(filename).each_with_index do |line,number|
20
+ next if line =~ /^\s+#.*\s+\n$/
21
+ failing_lines << number + 1 if line =~ /\s+\n$/
22
+ end
23
+
24
+ unless failing_lines.empty?
25
+ "#{filename} has spaces on the EOL on lines #{failing_lines.join(', ')}"
26
+ end
27
+ end
28
+
29
+ RSpec::Matchers.define :be_well_formed do
30
+ failure_message_for_should do |actual|
31
+ actual.join("\n")
32
+ end
33
+
34
+ match do |actual|
35
+ actual.empty?
36
+ end
37
+ end
38
+
39
+ it "has no malformed whitespace" do
40
+ exempt = /\.gitmodules|\.marshal|fixtures|vendor|ssl_certs|kill|LICENSE/
41
+ error_messages = []
42
+ Dir.chdir(File.expand_path("../..", __FILE__)) do
43
+ `git ls-files`.split("\n").each do |filename|
44
+ next if filename =~ exempt
45
+ error_messages << check_for_tab_characters(filename)
46
+ error_messages << check_for_extra_spaces(filename)
47
+ end
48
+ end
49
+ expect(error_messages.compact).to be_well_formed
50
+ end
51
+ end
@@ -96,5 +96,10 @@ describe "Proxy" do
96
96
  it "should not work if neither the proxy or target respond to method" do
97
97
  lambda { @proxy.send(:gsub) }.should raise_error
98
98
  end
99
+
100
+ it "should work if a proc is passed" do
101
+ p = Proc.new {|x| x+1}
102
+ @proxy.send(:collect, &p).should == [2,3]
103
+ end
99
104
  end
100
105
  end
@@ -391,4 +391,28 @@ describe "Support" do
391
391
  end
392
392
  end
393
393
  end
394
+
395
+ context "Symbol.to_mongo" do
396
+ it "should convert value to_sym" do
397
+ Symbol.to_mongo('asdfasdfasdf').should == :asdfasdfasdf
398
+ end
399
+
400
+ it "should convert string if not string" do
401
+ Symbol.to_mongo(123).should == :'123'
402
+ end
403
+
404
+ it "should return nil for nil" do
405
+ Symbol.to_mongo(nil).should be_nil
406
+ end
407
+ end
408
+
409
+ context "Symbol.from_mongo" do
410
+ it "should convert value to_sym" do
411
+ Symbol.from_mongo(:asdfasdfasdf).should == :asdfasdfasdf
412
+ end
413
+
414
+ it "should return nil for nil" do
415
+ Symbol.from_mongo(nil).should be_nil
416
+ end
417
+ end
394
418
  end
File without changes
File without changes
@@ -66,6 +66,11 @@ describe "Rails integration" do
66
66
  @klass.new(:bar => 'Setting Foo').foo.should == 'Setting Foo'
67
67
  end
68
68
 
69
+ it "should return the type casted value from write attribute" do
70
+ obj = @klass.new
71
+ obj.write_attribute(:foo, true).should == "true"
72
+ end
73
+
69
74
  context '#to_param' do
70
75
  it "should be nil if not persisted" do
71
76
  @klass.new.tap do |doc|
metadata CHANGED
@@ -1,71 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongo_mapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.13.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Nunemaker
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-01 00:00:00.000000000 Z
11
+ date: 2014-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
15
- version_requirements: !ruby/object:Gem::Requirement
15
+ requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - '>='
18
18
  - !ruby/object:Gem::Version
19
19
  version: 3.0.0
20
- requirement: !ruby/object:Gem::Requirement
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
21
23
  requirements:
22
24
  - - '>='
23
25
  - !ruby/object:Gem::Version
24
26
  version: 3.0.0
25
- prerelease: false
26
- type: :runtime
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activesupport
29
- version_requirements: !ruby/object:Gem::Requirement
29
+ requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '>='
32
32
  - !ruby/object:Gem::Version
33
33
  version: '3.0'
34
- requirement: !ruby/object:Gem::Requirement
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
35
37
  requirements:
36
38
  - - '>='
37
39
  - !ruby/object:Gem::Version
38
40
  version: '3.0'
39
- prerelease: false
40
- type: :runtime
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: plucky
43
- version_requirements: !ruby/object:Gem::Requirement
43
+ requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ~>
46
46
  - !ruby/object:Gem::Version
47
47
  version: 0.6.5
48
- requirement: !ruby/object:Gem::Requirement
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
49
51
  requirements:
50
52
  - - ~>
51
53
  - !ruby/object:Gem::Version
52
54
  version: 0.6.5
53
- prerelease: false
54
- type: :runtime
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: mongo
57
- version_requirements: !ruby/object:Gem::Requirement
57
+ requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
61
  version: '1.8'
62
- requirement: !ruby/object:Gem::Requirement
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
63
65
  requirements:
64
66
  - - ~>
65
67
  - !ruby/object:Gem::Version
66
68
  version: '1.8'
67
- prerelease: false
68
- type: :runtime
69
69
  description: MongoMapper is a Object-Document Mapper for Ruby and Rails
70
70
  email:
71
71
  - nunemaker@gmail.com
@@ -112,6 +112,7 @@ files:
112
112
  - lib/mongo_mapper/extensions/ordered_hash.rb
113
113
  - lib/mongo_mapper/extensions/set.rb
114
114
  - lib/mongo_mapper/extensions/string.rb
115
+ - lib/mongo_mapper/extensions/symbol.rb
115
116
  - lib/mongo_mapper/extensions/time.rb
116
117
  - lib/mongo_mapper/locale/en.yml
117
118
  - lib/mongo_mapper/middleware/identity_map.rb
@@ -142,6 +143,7 @@ files:
142
143
  - lib/mongo_mapper/plugins/caching.rb
143
144
  - lib/mongo_mapper/plugins/callbacks.rb
144
145
  - lib/mongo_mapper/plugins/clone.rb
146
+ - lib/mongo_mapper/plugins/counter_cache.rb
145
147
  - lib/mongo_mapper/plugins/dirty.rb
146
148
  - lib/mongo_mapper/plugins/document.rb
147
149
  - lib/mongo_mapper/plugins/dumpable.rb
@@ -168,6 +170,7 @@ files:
168
170
  - lib/mongo_mapper/plugins/sci.rb
169
171
  - lib/mongo_mapper/plugins/scopes.rb
170
172
  - lib/mongo_mapper/plugins/serialization.rb
173
+ - lib/mongo_mapper/plugins/stats.rb
171
174
  - lib/mongo_mapper/plugins/timestamps.rb
172
175
  - lib/mongo_mapper/plugins/touch.rb
173
176
  - lib/mongo_mapper/plugins/userstamps.rb
@@ -198,6 +201,7 @@ files:
198
201
  - spec/functional/binary_spec.rb
199
202
  - spec/functional/caching_spec.rb
200
203
  - spec/functional/callbacks_spec.rb
204
+ - spec/functional/counter_cache_spec.rb
201
205
  - spec/functional/dirty_spec.rb
202
206
  - spec/functional/document_spec.rb
203
207
  - spec/functional/dumpable_spec.rb
@@ -217,10 +221,12 @@ files:
217
221
  - spec/functional/safe_spec.rb
218
222
  - spec/functional/sci_spec.rb
219
223
  - spec/functional/scopes_spec.rb
224
+ - spec/functional/stats_spec.rb
220
225
  - spec/functional/timestamps_spec.rb
221
226
  - spec/functional/touch_spec.rb
222
227
  - spec/functional/userstamps_spec.rb
223
228
  - spec/functional/validations_spec.rb
229
+ - spec/quality_spec.rb
224
230
  - spec/spec_helper.rb
225
231
  - spec/support/matchers.rb
226
232
  - spec/support/models.rb
@@ -258,7 +264,7 @@ homepage: http://mongomapper.com
258
264
  licenses:
259
265
  - MIT
260
266
  metadata: {}
261
- post_install_message:
267
+ post_install_message:
262
268
  rdoc_options: []
263
269
  require_paths:
264
270
  - lib
@@ -273,9 +279,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
273
279
  - !ruby/object:Gem::Version
274
280
  version: '0'
275
281
  requirements: []
276
- rubyforge_project:
282
+ rubyforge_project:
277
283
  rubygems_version: 2.2.2
278
- signing_key:
284
+ signing_key:
279
285
  specification_version: 4
280
286
  summary: A Ruby Object Mapper for Mongo
281
287
  test_files: []