mongomodel 0.4.9 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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