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
@@ -0,0 +1,30 @@
1
+ language: ruby
2
+
3
+ services:
4
+ - mongodb
5
+
6
+ rvm:
7
+ - 1.8.7
8
+ - 1.9.3
9
+ - 2.0.0
10
+
11
+ gemfile:
12
+ - gemfiles/rails-3.1.gemfile
13
+ - gemfiles/rails-3.2.gemfile
14
+ - gemfiles/rails-4.gemfile
15
+ - gemfiles/rails-4-observers.gemfile
16
+ - gemfiles/rails-4-protected-attributes.gemfile
17
+ - gemfiles/mongo_mapper.gemfile
18
+ - gemfiles/mongoid.gemfile
19
+
20
+ matrix:
21
+ exclude:
22
+ - rvm: 1.8.7
23
+ gemfile: gemfiles/rails-4.gemfile
24
+ - rvm: 1.8.7
25
+ gemfile: gemfiles/rails-4-observers.gemfile
26
+ - rvm: 1.8.7
27
+ gemfile: gemfiles/rails-4-protected-attributes.gemfile
28
+ - rvm: 1.8.7
29
+ gemfile: gemfiles/mongoid.gemfile
30
+
data/Gemfile CHANGED
@@ -2,6 +2,6 @@ source "http://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem "appraisal", "~> 0.3.6"
6
5
  gem "bson_ext", "~> 1.8"
7
6
  gem "tzinfo"
7
+ gem "rake"
data/README.md CHANGED
@@ -3,6 +3,8 @@ MongoModel
3
3
 
4
4
  MongoModel is a Ruby ORM for interfacing with [MongoDB](http://www.mongodb.org/) databases.
5
5
 
6
+ [![Build Status](https://travis-ci.org/spohlenz/mongomodel.png?branch=master)](https://travis-ci.org/spohlenz/mongomodel)
7
+
6
8
 
7
9
  Installation
8
10
  ============
@@ -19,7 +21,11 @@ For performance, you should probably also install the BSON C extensions:
19
21
  Using with Rails 3
20
22
  ==================
21
23
 
22
- Setup config/mongomodel.yml:
24
+ Add MongoModel to your Gemfile (and run `bundle install`):
25
+
26
+ gem 'mongomodel'
27
+
28
+ Create the configuration file `config/mongomodel.yml`:
23
29
 
24
30
  rails generate mongo_model:config DATABASENAME
25
31
 
data/Rakefile CHANGED
@@ -1,8 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'bundler/setup'
3
3
 
4
- require 'appraisal'
5
-
6
4
  task :default => :spec
7
5
 
8
6
  begin
@@ -1,12 +1,11 @@
1
- # This file was generated by Appraisal
1
+ source "https://rubygems.org"
2
2
 
3
- source "http://rubygems.org"
3
+ gem "activesupport", "3.2.13"
4
+ gem "activemodel", "3.2.13"
5
+ gem "mongo_mapper"
4
6
 
5
- gem "appraisal", "~> 0.3.6"
6
7
  gem "bson_ext", "~> 1.8"
7
8
  gem "tzinfo"
8
- gem "mongo_mapper"
9
- gem "activesupport", "3.2.11"
10
- gem "activemodel", "3.2.11"
9
+ gem "rake"
11
10
 
12
- gemspec :path=>"../"
11
+ gemspec :path => "../"
@@ -1,12 +1,11 @@
1
- # This file was generated by Appraisal
1
+ source "https://rubygems.org"
2
2
 
3
- source "http://rubygems.org"
3
+ gem "activesupport", "3.2.13"
4
+ gem "activemodel", "3.2.13"
5
+ gem "mongoid"
4
6
 
5
- gem "appraisal", "~> 0.3.6"
6
7
  gem "bson_ext", "~> 1.8"
7
8
  gem "tzinfo"
8
- gem "mongoid"
9
- gem "activesupport", "3.2.11"
10
- gem "activemodel", "3.2.11"
9
+ gem "rake"
11
10
 
12
- gemspec :path=>"../"
11
+ gemspec :path => "../"
@@ -1,11 +1,10 @@
1
- # This file was generated by Appraisal
1
+ source "https://rubygems.org"
2
2
 
3
- source "http://rubygems.org"
3
+ gem "activesupport", "3.1.12"
4
+ gem "activemodel", "3.1.12"
4
5
 
5
- gem "appraisal", "~> 0.3.6"
6
6
  gem "bson_ext", "~> 1.8"
7
7
  gem "tzinfo"
8
- gem "activesupport", "3.1.10"
9
- gem "activemodel", "3.1.10"
8
+ gem "rake"
10
9
 
11
- gemspec :path=>"../"
10
+ gemspec :path => "../"
@@ -1,11 +1,10 @@
1
- # This file was generated by Appraisal
1
+ source "https://rubygems.org"
2
2
 
3
- source "http://rubygems.org"
3
+ gem "activesupport", "3.2.13"
4
+ gem "activemodel", "3.2.13"
4
5
 
5
- gem "appraisal", "~> 0.3.6"
6
6
  gem "bson_ext", "~> 1.8"
7
7
  gem "tzinfo"
8
- gem "activesupport", "3.2.11"
9
- gem "activemodel", "3.2.11"
8
+ gem "rake"
10
9
 
11
- gemspec :path=>"../"
10
+ gemspec :path => "../"
@@ -1,13 +1,11 @@
1
- # This file was generated by Appraisal
1
+ source "https://rubygems.org"
2
2
 
3
- source "http://rubygems.org"
3
+ gem "activesupport", :github => "rails/rails", :branch => "4-0-stable"
4
+ gem "activemodel", :github => "rails/rails", :branch => "4-0-stable"
5
+ gem "rails-observers", :github => "rails/rails-observers"
4
6
 
5
- gem "appraisal", "~> 0.3.6"
6
7
  gem "bson_ext", "~> 1.8"
7
8
  gem "tzinfo"
8
- gem "activesupport", :git=>"https://github.com/rails/rails.git"
9
- gem "activemodel", :git=>"https://github.com/rails/rails.git"
10
- gem "rails-observers", :git=>"https://github.com/rails/rails-observers.git"
11
- gem "journey", :git=>"https://github.com/rails/journey.git"
9
+ gem "rake"
12
10
 
13
- gemspec :path=>"../"
11
+ gemspec :path => "../"
@@ -1,13 +1,11 @@
1
- # This file was generated by Appraisal
1
+ source "https://rubygems.org"
2
2
 
3
- source "http://rubygems.org"
3
+ gem "activesupport", :github => "rails/rails", :branch => "4-0-stable"
4
+ gem "activemodel", :github => "rails/rails", :branch => "4-0-stable"
5
+ gem "protected_attributes", :github => "rails/protected_attributes"
4
6
 
5
- gem "appraisal", "~> 0.3.6"
6
7
  gem "bson_ext", "~> 1.8"
7
8
  gem "tzinfo"
8
- gem "activesupport", :git=>"https://github.com/rails/rails.git"
9
- gem "activemodel", :git=>"https://github.com/rails/rails.git"
10
- gem "protected_attributes", :git=>"https://github.com/rails/protected_attributes.git"
11
- gem "journey", :git=>"https://github.com/rails/journey.git"
9
+ gem "rake"
12
10
 
13
- gemspec :path=>"../"
11
+ gemspec :path => "../"
@@ -1,12 +1,10 @@
1
- # This file was generated by Appraisal
1
+ source "https://rubygems.org"
2
2
 
3
- source "http://rubygems.org"
3
+ gem "activesupport", :github => "rails/rails", :branch => "4-0-stable"
4
+ gem "activemodel", :github => "rails/rails", :branch => "4-0-stable"
4
5
 
5
- gem "appraisal", "~> 0.3.6"
6
6
  gem "bson_ext", "~> 1.8"
7
7
  gem "tzinfo"
8
- gem "activesupport", :git=>"https://github.com/rails/rails.git"
9
- gem "activemodel", :git=>"https://github.com/rails/rails.git"
10
- gem "journey", :git=>"https://github.com/rails/journey.git"
8
+ gem "rake"
11
9
 
12
- gemspec :path=>"../"
10
+ gemspec :path => "../"
@@ -66,6 +66,7 @@ module MongoModel
66
66
  autoload :Query, 'mongomodel/concerns/attribute_methods/query'
67
67
  autoload :BeforeTypeCast, 'mongomodel/concerns/attribute_methods/before_type_cast'
68
68
  autoload :Protected, 'mongomodel/concerns/attribute_methods/protected'
69
+ autoload :Forbidden, 'mongomodel/concerns/attribute_methods/forbidden'
69
70
  autoload :Dirty, 'mongomodel/concerns/attribute_methods/dirty'
70
71
  autoload :Nested, 'mongomodel/concerns/attribute_methods/nested'
71
72
  autoload :MultiParameterAssignment, 'mongomodel/concerns/attribute_methods/multi_parameter_assignment'
@@ -49,7 +49,12 @@ module MongoModel
49
49
  end
50
50
 
51
51
  def find_target
52
- ids.any? ? Array.wrap(definition.scope.find(ids - new_document_ids)) + new_documents : []
52
+ if ids.any?
53
+ docs = Array.wrap(definition.scope.where(:id.in => (ids - new_document_ids))) + new_documents
54
+ docs.sort_by { |doc| ids.index(doc.id) }
55
+ else
56
+ []
57
+ end
53
58
  end
54
59
 
55
60
  def build(*args, &block)
@@ -0,0 +1,17 @@
1
+ require "active_model/forbidden_attributes_protection"
2
+
3
+ module MongoModel
4
+ module AttributeMethods
5
+ module Forbidden
6
+ extend ActiveSupport::Concern
7
+
8
+ def assign_attributes(attrs, options={})
9
+ if attrs.respond_to?(:permitted?) && !attrs.permitted?
10
+ raise ActiveModel::ForbiddenAttributesError
11
+ else
12
+ super
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -3,7 +3,7 @@ module MongoModel
3
3
  module MultiParameterAssignment
4
4
  extend ActiveSupport::Concern
5
5
 
6
- def attributes=(attrs)#:nodoc:
6
+ def assign_attributes(attrs, options={})#:nodoc:
7
7
  super(transform_multiparameter_attributes(attrs))
8
8
  end
9
9
 
@@ -63,6 +63,11 @@ module MongoModel
63
63
 
64
64
  docs
65
65
  end
66
+
67
+ protected
68
+ def sanitize_for_mass_assignment(attrs, options={})
69
+ attrs
70
+ end
66
71
 
67
72
  module ClassMethods
68
73
  def from_mongo(hash)
@@ -59,8 +59,8 @@ module MongoModel
59
59
 
60
60
  if default.is_a?(Proc)
61
61
  case default.arity
62
- when 0 then default.call
63
- else default.call(instance)
62
+ when 0 then instance.instance_exec(&default)
63
+ else instance.instance_exec(instance, &default)
64
64
  end
65
65
  else
66
66
  default.duplicable? ? default.dup : default
@@ -7,11 +7,11 @@ module MongoModel
7
7
  def serializable_hash(given_options = nil)
8
8
  options = given_options ? given_options.dup : {}
9
9
 
10
- options[:only] = Array.wrap(options[:only]).map { |n| n.to_s }
11
- options[:except] = Array.wrap(options[:except]).map { |n| n.to_s }
10
+ options[:only] = Array.wrap(options[:only]).map { |n| n.to_s }
11
+ options[:except] = Array.wrap(options[:except]).map { |n| n.to_s }
12
+ options[:methods] = Array.wrap(options[:methods]).map { |n| n.to_s }
12
13
 
13
- attribute_names = attributes.keys.map { |k| k.to_s }.sort
14
- attribute_names -= self.class.internal_properties.map { |p| p.name.to_s }
14
+ attribute_names = attributes_for_serialization
15
15
 
16
16
  if options[:only].any?
17
17
  attribute_names &= options[:only]
@@ -19,8 +19,8 @@ module MongoModel
19
19
  attribute_names -= options[:except]
20
20
  end
21
21
 
22
- method_names = Array.wrap(options[:methods]).inject([]) do |methods, name|
23
- methods << name if respond_to?(name.to_s)
22
+ method_names = options[:methods].inject([]) do |methods, name|
23
+ methods << name if respond_to?(name)
24
24
  methods
25
25
  end
26
26
 
@@ -29,5 +29,14 @@ module MongoModel
29
29
  hash
30
30
  }
31
31
  end
32
+
33
+ protected
34
+ def attributes_for_serialization
35
+ properties.reject { |name, property|
36
+ property.internal? && name != :id
37
+ }.map { |name, property|
38
+ name.to_s
39
+ }.sort
40
+ end
32
41
  end
33
42
  end
@@ -23,6 +23,7 @@ module MongoModel
23
23
  include AttributeMethods::Dirty
24
24
  include AttributeMethods::Nested
25
25
  include AttributeMethods::MultiParameterAssignment
26
+ include AttributeMethods::Forbidden if defined?(ActiveModel::ForbiddenAttributesProtection)
26
27
 
27
28
  include Logging
28
29
  include RecordStatus
@@ -58,12 +58,14 @@ module MongoModel
58
58
  end
59
59
 
60
60
  initializer "mongomodel.observers" do |app|
61
- MongoModel::EmbeddedDocument.observers = app.config.mongomodel.observers || []
61
+ if defined?(ActiveModel::Observing)
62
+ MongoModel::EmbeddedDocument.observers = app.config.mongomodel.observers || []
63
+ end
62
64
  end
63
-
64
- # Lazily initialize observer instances
65
- config.after_initialize do
66
- ActiveSupport.on_load(:mongomodel) do
65
+
66
+ # Initialize observer instances if available
67
+ ActiveSupport.on_load(:mongomodel) do
68
+ if respond_to?(:instantiate_observers)
67
69
  instantiate_observers
68
70
 
69
71
  ActionDispatch::Reloader.to_prepare do
@@ -5,6 +5,7 @@ module MongoModel
5
5
  MULTI_VALUE_METHODS = [ :select, :order, :where ]
6
6
  SINGLE_VALUE_METHODS = [ :limit, :offset, :from ]
7
7
 
8
+ autoload :ArrayMethods, 'mongomodel/support/scope/array_methods'
8
9
  autoload :SpawnMethods, 'mongomodel/support/scope/spawn_methods'
9
10
  autoload :QueryMethods, 'mongomodel/support/scope/query_methods'
10
11
  autoload :FinderMethods, 'mongomodel/support/scope/finder_methods'
@@ -13,7 +14,7 @@ module MongoModel
13
14
  autoload :Pagination, 'mongomodel/support/scope/pagination'
14
15
  autoload :Batches, 'mongomodel/support/scope/batches'
15
16
 
16
- include Batches, Pagination, DynamicFinders, LoadMethods, FinderMethods, QueryMethods, SpawnMethods
17
+ include Batches, Pagination, DynamicFinders, LoadMethods, FinderMethods, ArrayMethods, QueryMethods, SpawnMethods
17
18
 
18
19
  delegate :inspect, :as_json, :to => :to_a
19
20
 
@@ -53,14 +54,6 @@ module MongoModel
53
54
  loaded? ? @documents.empty? : count.zero?
54
55
  end
55
56
 
56
- def any?(&block)
57
- if block_given?
58
- to_a.any?(&block)
59
- else
60
- !empty?
61
- end
62
- end
63
-
64
57
  def count
65
58
  _find.count
66
59
  end
@@ -0,0 +1,21 @@
1
+ module MongoModel
2
+ class Scope
3
+ module ArrayMethods
4
+ def any?(&block)
5
+ if block_given?
6
+ to_a.any?(&block)
7
+ else
8
+ !empty?
9
+ end
10
+ end
11
+
12
+ def select(*args, &block)
13
+ if block_given?
14
+ to_a.select(&block)
15
+ else
16
+ super
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -13,7 +13,7 @@ module MongoModel
13
13
  when ::String
14
14
  cast(::DateTime.parse(value))
15
15
  else
16
- value.to_datetime.change(:usec => 0)
16
+ round_microseconds(value.to_datetime.utc) if value
17
17
  end
18
18
  rescue
19
19
  nil
@@ -23,16 +23,29 @@ module MongoModel
23
23
  to_time(value.utc) if value
24
24
  end
25
25
 
26
- def from_mongo(value)
27
- time = value.respond_to?(:in_time_zone) ? value.in_time_zone : value
28
- time.to_datetime
26
+ def from_mongo(t)
27
+ ::DateTime.civil(t.year, t.month, t.day, t.hour, t.min, t.sec + Rational(t.usec, 1000000)) if t
29
28
  end
30
29
 
31
30
  private
32
31
  # Define our own to_time method as DateTime.to_time in ActiveSupport may return
33
32
  # the DateTime object unchanged, whereas BSON expects an actual Time object.
34
33
  def to_time(dt)
35
- ::Time.utc(dt.year, dt.month, dt.day, dt.hour, dt.min, dt.sec)
34
+ ::Time.utc(dt.year, dt.month, dt.day, dt.hour, dt.min, dt.sec, sec_fraction(dt).to_f * 1000000)
35
+ end
36
+
37
+ def sec_fraction(dt)
38
+ if RUBY_VERSION <= "1.8.7"
39
+ # Ruby 1.8.7 DateTime#sec_fraction unit is in days
40
+ dt.sec_fraction * 86400
41
+ else
42
+ dt.sec_fraction
43
+ end
44
+ end
45
+
46
+ def round_microseconds(dt)
47
+ seconds = dt.sec + sec_fraction(dt)
48
+ dt.change(:sec => Rational((seconds * 1000).round, 1000))
36
49
  end
37
50
  end
38
51
  end