mongomodel 0.2.3 → 0.2.4

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.
data/Gemfile CHANGED
@@ -1,8 +1,8 @@
1
1
  source "http://rubygems.org"
2
- git "git://github.com/rails/rails.git"
2
+ # git "git://github.com/rails/rails.git"
3
3
 
4
- gem "activemodel", ">= 3.0.0.beta3"
5
- gem "activesupport", ">= 3.0.0.beta3"
4
+ gem "activemodel", "= 3.0.0.beta3"
5
+ gem "activesupport", "= 3.0.0.beta3"
6
6
 
7
7
  gem "mongo", '>= 0.20.1'
8
8
  gem "bson", '>= 0.20.1'
data/Rakefile CHANGED
@@ -42,12 +42,12 @@ begin
42
42
  gem.summary = "MongoDB ORM for Ruby/Rails"
43
43
  gem.description = "MongoModel is a MongoDB ORM for Ruby/Rails similar to ActiveRecord and DataMapper."
44
44
  gem.email = "sam@sampohlenz.com"
45
- gem.homepage = "http://github.com/spohlenz/mongomodel"
45
+ gem.homepage = "http://www.mongomodel.org"
46
46
  gem.authors = ["Sam Pohlenz"]
47
47
  gem.version = MongoModel::VERSION
48
48
 
49
- gem.add_dependency('activesupport', '>= 3.0.0.beta3')
50
- gem.add_dependency('activemodel', '>= 3.0.0.beta3')
49
+ gem.add_dependency('activesupport', '= 3.0.0.beta3')
50
+ gem.add_dependency('activemodel', '= 3.0.0.beta3')
51
51
  gem.add_dependency('mongo', '>= 0.20.1')
52
52
  gem.add_dependency('bson', '>= 0.20.1')
53
53
  gem.add_development_dependency('rspec', '>= 1.3.0')
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec" }
@@ -39,6 +39,7 @@ module MongoModel
39
39
  autoload :DynamicFinder, 'mongomodel/support/dynamic_finder'
40
40
 
41
41
  autoload :Collection, 'mongomodel/support/collection'
42
+ autoload :Map, 'mongomodel/support/map'
42
43
 
43
44
  module AttributeMethods
44
45
  autoload :Read, 'mongomodel/concerns/attribute_methods/read'
@@ -53,6 +54,7 @@ module MongoModel
53
54
  autoload :Store, 'mongomodel/attributes/store'
54
55
  autoload :Typecasting, 'mongomodel/attributes/typecasting'
55
56
  autoload :Mongo, 'mongomodel/attributes/mongo'
57
+ autoload :Dirty, 'mongomodel/attributes/dirty'
56
58
  end
57
59
 
58
60
  module Associations
@@ -91,6 +93,8 @@ module MongoModel
91
93
  def self.database
92
94
  @_database ||= configuration.establish_connection
93
95
  end
96
+
97
+ require 'mongomodel/railtie' if defined?(Rails)
94
98
  end
95
99
 
96
100
  I18n.load_path << File.dirname(__FILE__) + '/mongomodel/locale/en.yml'
@@ -0,0 +1,32 @@
1
+ module MongoModel
2
+ module Attributes
3
+ module Dirty
4
+ def []=(key, value)
5
+ attr = key.to_s
6
+
7
+ # The attribute already has an unsaved change.
8
+ if changed.include?(attr)
9
+ old = changed[attr]
10
+ changed.delete(attr) if value == old
11
+ else
12
+ old = clone_attribute_value(attr)
13
+ changed[attr] = old unless value == old
14
+ end
15
+
16
+ super
17
+ end
18
+
19
+ def changed
20
+ @changed ||= {}
21
+ end
22
+
23
+ private
24
+ def clone_attribute_value(attribute_name)
25
+ value = self[attribute_name.to_sym]
26
+ value.duplicable? ? value.clone : value
27
+ rescue TypeError, NoMethodError
28
+ value
29
+ end
30
+ end
31
+ end
32
+ end
@@ -16,6 +16,11 @@ module MongoModel
16
16
  end
17
17
  end
18
18
 
19
+ def load!(hash)
20
+ from_mongo!(hash)
21
+ changed.clear
22
+ end
23
+
19
24
  def from_mongo!(hash)
20
25
  hash.each do |k, v|
21
26
  property = properties_as[k.to_s]
@@ -5,6 +5,7 @@ module MongoModel
5
5
  class Store < ActiveSupport::OrderedHash
6
6
  include Typecasting
7
7
  include Mongo
8
+ include Dirty
8
9
 
9
10
  attr_reader :instance
10
11
  delegate :properties, :to => :instance
@@ -10,8 +10,8 @@ module MongoModel
10
10
  end
11
11
 
12
12
  properties do |association|
13
- property association.foreign_key, Reference, :internal => true
14
- property association.type_key, Reference, :internal => true if association.polymorphic?
13
+ property association.foreign_key, MongoModel::Reference, :internal => true
14
+ property association.type_key, MongoModel::Reference, :internal => true if association.polymorphic?
15
15
  end
16
16
 
17
17
  methods do |association|
@@ -6,7 +6,7 @@ module MongoModel
6
6
  end
7
7
 
8
8
  def inverse_of
9
- options[:inverse_of] || owner.to_s.downcase.demodulize.singularize.to_sym
9
+ options[:inverse_of] || owner.to_s.demodulize.underscore.singularize.to_sym
10
10
  end
11
11
 
12
12
  def define!
@@ -97,7 +97,7 @@ module MongoModel
97
97
  end
98
98
 
99
99
  class Proxy < Base::Proxy
100
- # Pass these methods to the association class rather than the Array target
100
+ # Pass these methods to the scope rather than the Array target
101
101
  OVERRIDE_METHODS = [ :find ]
102
102
 
103
103
  delegate :ensure_class, :to => :association
@@ -170,11 +170,13 @@ module MongoModel
170
170
  end
171
171
 
172
172
  private
173
- def method_missing(method_id, *args, &block)
174
- if target.respond_to?(method_id) && !OVERRIDE_METHODS.include?(method_id.to_sym)
175
- super(method_id, *args, &block)
173
+ def method_missing(method, *args, &block)
174
+ if Array.method_defined?(method) && !OVERRIDE_METHODS.include?(method)
175
+ target.send(method, *args, &block)
176
+ elsif association.scoped.respond_to?(method)
177
+ association.scoped.send(method, *args, &block)
176
178
  else
177
- association.scoped.send(method_id, *args, &block)
179
+ super(method, *args, &block)
178
180
  end
179
181
  end
180
182
  end
@@ -6,7 +6,7 @@ module MongoModel
6
6
  end
7
7
 
8
8
  properties do |association|
9
- property association.property_name, Collection[Reference], :internal => true, :default => []
9
+ property association.property_name, Collection[MongoModel::Reference], :internal => true, :default => []
10
10
  end
11
11
 
12
12
  methods do |association|
@@ -13,22 +13,10 @@ module MongoModel
13
13
  def original_attributes
14
14
  attributes.merge(changed_attributes)
15
15
  end
16
-
17
- # Wrap write_attribute to remember original attribute value.
18
- def write_attribute(attr, value)
19
- attr = attr.to_s
20
-
21
- # The attribute already has an unsaved change.
22
- if changed_attributes.include?(attr)
23
- old = changed_attributes[attr]
24
- changed_attributes.delete(attr) if value == old
25
- else
26
- old = clone_attribute_value(attr)
27
- changed_attributes[attr] = old unless value == old
28
- end
29
-
30
- # Carry on.
31
- super
16
+
17
+ protected
18
+ def changed_attributes
19
+ attributes.changed
32
20
  end
33
21
  end
34
22
  end
@@ -5,7 +5,7 @@ module MongoModel
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  def initialize(attrs={})
8
- self.attributes = attrs
8
+ self.attributes = (attrs || {})
9
9
  yield self if block_given?
10
10
  end
11
11
 
@@ -51,6 +51,10 @@ module MongoModel
51
51
  docs.concat collection.embedded_documents
52
52
  end
53
53
 
54
+ attributes.values.select { |attr| attr.is_a?(Map) && attr.to <= EmbeddedDocument }.each do |map|
55
+ docs.concat map.values
56
+ end
57
+
54
58
  docs
55
59
  end
56
60
 
@@ -58,7 +62,7 @@ module MongoModel
58
62
  def from_mongo(hash)
59
63
  if hash
60
64
  doc = class_for_type(hash['_type']).new
61
- doc.attributes.from_mongo!(hash)
65
+ doc.attributes.load!(hash)
62
66
  doc
63
67
  end
64
68
  end
@@ -3,7 +3,14 @@ module MongoModel
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  def parent_document
6
- @_parent_document.is_a?(Proc) ? @_parent_document.call(self) : @_parent_document
6
+ if @_parent_document.respond_to?(:call)
7
+ case @_parent_document.arity
8
+ when 0 then @_parent_document.call
9
+ else @_parent_document.call(self)
10
+ end
11
+ else
12
+ @_parent_document
13
+ end
7
14
  end
8
15
 
9
16
  def parent_document=(doc)
@@ -57,7 +57,7 @@ module MongoModel
57
57
  end
58
58
 
59
59
  def keys
60
- @keys ||= OrderedHash.new
60
+ @keys ||= ActiveSupport::OrderedHash.new
61
61
  end
62
62
 
63
63
  def unique?
@@ -5,7 +5,7 @@ module MongoModel
5
5
 
6
6
  included do
7
7
  undef_method :id if method_defined?(:id)
8
- property :id, Reference, :as => '_id', :default => lambda { |doc| doc.generate_id }
8
+ property :id, MongoModel::Reference, :as => '_id', :default => lambda { |doc| doc.generate_id }
9
9
 
10
10
  class_inheritable_writer :collection_name
11
11
  end
@@ -16,7 +16,7 @@ module MongoModel
16
16
  reloaded = self.class.unscoped.find(id)
17
17
 
18
18
  attributes.clear
19
- attributes.from_mongo!(reloaded.attributes.to_mongo)
19
+ attributes.load!(reloaded.attributes.to_mongo)
20
20
 
21
21
  associations.values.each do |association|
22
22
  association.proxy.reset
@@ -139,7 +139,7 @@ module MongoModel
139
139
  end
140
140
 
141
141
  def instantiate(document)
142
- attributes.from_mongo!(document)
142
+ attributes.load!(document)
143
143
  set_new_record(false)
144
144
  end
145
145
  end
@@ -34,6 +34,10 @@ module MongoModel
34
34
  Collection = MongoModel::Collection
35
35
  extend Collection::PropertyDefaults
36
36
 
37
+ # Allow Map class to be used in property definitions
38
+ Map = MongoModel::Map
39
+ extend Map::PropertyDefaults
40
+
37
41
  undef_method :type if method_defined?(:type)
38
42
  property :type, String, :as => '_type', :default => lambda { |doc| doc.class.name }, :protected => true
39
43
 
@@ -11,19 +11,19 @@ en:
11
11
  accepted: "must be accepted"
12
12
  empty: "can't be empty"
13
13
  blank: "can't be blank"
14
- too_long: "is too long (maximum is {{count}} characters)"
15
- too_short: "is too short (minimum is {{count}} characters)"
16
- wrong_length: "is the wrong length (should be {{count}} characters)"
14
+ too_long: "is too long (maximum is %{count} characters)"
15
+ too_short: "is too short (minimum is %{count} characters)"
16
+ wrong_length: "is the wrong length (should be %{count} characters)"
17
17
  taken: "has already been taken"
18
18
  not_a_number: "is not a number"
19
- greater_than: "must be greater than {{count}}"
20
- greater_than_or_equal_to: "must be greater than or equal to {{count}}"
21
- equal_to: "must be equal to {{count}}"
22
- less_than: "must be less than {{count}}"
23
- less_than_or_equal_to: "must be less than or equal to {{count}}"
19
+ greater_than: "must be greater than %{count}"
20
+ greater_than_or_equal_to: "must be greater than or equal to %{count}"
21
+ equal_to: "must be equal to %{count}"
22
+ less_than: "must be less than %{count}"
23
+ less_than_or_equal_to: "must be less than or equal to %{count}"
24
24
  odd: "must be odd"
25
25
  even: "must be even"
26
- document_invalid: "Validation failed: {{errors}}"
26
+ document_invalid: "Validation failed: %{errors}"
27
27
  # Append your own errors here or at the model/attributes scope.
28
28
 
29
29
  # You can define own errors for models or model attributes.
@@ -32,7 +32,7 @@ en:
32
32
  # For example,
33
33
  # models:
34
34
  # user:
35
- # blank: "This is a custom blank message for {{model}}: {{attribute}}"
35
+ # blank: "This is a custom blank message for %{model}: %{attribute}"
36
36
  # attributes:
37
37
  # login:
38
38
  # blank: "This is a custom blank message for User login"
@@ -0,0 +1,22 @@
1
+ module MongoModel
2
+ class Railtie < Rails::Railtie
3
+ initializer "mongomodel.logger" do
4
+ MongoModel.logger ||= ::Rails.logger
5
+ end
6
+
7
+ initializer "mongomodel.rescue_responses" do
8
+ ActionDispatch::ShowExceptions.rescue_responses['MongoModel::DocumentNotFound'] = :not_found
9
+ end
10
+
11
+ initializer "mongomodel.database_configuration" do |app|
12
+ require 'erb'
13
+
14
+ config = Pathname.new(app.paths.config.to_a.first).join("mongomodel.yml")
15
+
16
+ if File.exists?(config)
17
+ mongomodel_configuration = YAML::load(ERB.new(IO.read(config)).result)
18
+ MongoModel.configuration = mongomodel_configuration[Rails.env]
19
+ end
20
+ end
21
+ end
22
+ end
@@ -5,7 +5,7 @@ module MongoModel
5
5
  property = super(name, *args, &block)
6
6
 
7
7
  if property.type <= Collection
8
- property.options[:default] ||= property.type.new
8
+ property.options[:default] ||= lambda { property.type.new }
9
9
  end
10
10
 
11
11
  property
@@ -4,7 +4,12 @@ require 'active_support/core_ext/hash/except'
4
4
  module MongoModel
5
5
  class Configuration
6
6
  def initialize(options)
7
- @options = DEFAULTS.merge(options).stringify_keys
7
+ case options
8
+ when Hash
9
+ @options = DEFAULTS.merge(options).stringify_keys
10
+ when String
11
+ super(parse(options))
12
+ end
8
13
  end
9
14
 
10
15
  def host
@@ -19,9 +24,19 @@ module MongoModel
19
24
  @options['database']
20
25
  end
21
26
 
27
+ def username
28
+ @options['username']
29
+ end
30
+
31
+ def password
32
+ @options['password']
33
+ end
34
+
22
35
  def establish_connection
23
36
  @connection ||= Mongo::Connection.new(host, port, connection_options)
24
37
  @database = @connection.db(database)
38
+ @database.authenticate(username, password) if username.present?
39
+ @database
25
40
  end
26
41
 
27
42
  def use_database(database)
@@ -30,7 +45,7 @@ module MongoModel
30
45
  end
31
46
 
32
47
  def connection_options
33
- @options.except('host', 'port', 'database').symbolize_keys
48
+ @options.except('host', 'port', 'database', 'username', 'password').symbolize_keys
34
49
  end
35
50
 
36
51
  DEFAULTS = {
@@ -38,11 +53,25 @@ module MongoModel
38
53
  'port' => 27017,
39
54
  'database' => 'mongomodel-default',
40
55
  'pool_size' => 5,
41
- 'timeout' => 5
56
+ 'timeout' => 5,
57
+ 'logger' => MongoModel.logger
42
58
  }
43
59
 
44
60
  def self.defaults
45
61
  new({})
46
62
  end
63
+
64
+ private
65
+ def parse(str)
66
+ uri = URI.parse(str)
67
+
68
+ {
69
+ 'host' => uri.host,
70
+ 'port' => uri.port,
71
+ 'database' => uri.path.gsub(/^\//, ''),
72
+ 'username' => uri.user,
73
+ 'password' => uri.password
74
+ }
75
+ end
47
76
  end
48
77
  end
@@ -0,0 +1,149 @@
1
+ module MongoModel
2
+ class Map < Hash
3
+ module PropertyDefaults
4
+ def property(name, *args, &block) #:nodoc:
5
+ property = super(name, *args, &block)
6
+
7
+ if property.type <= Map
8
+ property.options[:default] ||= lambda { property.type.new }
9
+ end
10
+
11
+ property
12
+ end
13
+ end
14
+
15
+ class_inheritable_accessor :from
16
+ self.from = String
17
+
18
+ class_inheritable_accessor :to
19
+ self.to = Object
20
+
21
+ HASH_CONVERTER = Types.converter_for(Hash)
22
+
23
+ class << self
24
+ def [](mapping)
25
+ raise "Exactly one mapping must be specified" unless mapping.keys.size == 1
26
+
27
+ from = mapping.keys.first
28
+ to = mapping.values.first
29
+
30
+ @map_class_cache ||= {}
31
+ @map_class_cache[[from, to]] ||= begin
32
+ map = Class.new(Map)
33
+ map.from = from
34
+ map.to = to
35
+ map
36
+ end
37
+ end
38
+
39
+ def from_mongo(hash)
40
+ result = new
41
+ hash.each_pair { |k, v| result[from_converter.from_mongo(k)] = instantiate(v) }
42
+ result
43
+ end
44
+
45
+ def inspect
46
+ if self == Map
47
+ "Map"
48
+ else
49
+ "Map[#{from} => #{to}]"
50
+ end
51
+ end
52
+
53
+ def from_converter
54
+ @from_converter ||= Types.converter_for(from)
55
+ end
56
+
57
+ def to_converter
58
+ @to_converter ||= Types.converter_for(to)
59
+ end
60
+
61
+ private
62
+ def instantiate(item)
63
+ if item.is_a?(Hash) && item['_type']
64
+ item['_type'].constantize.from_mongo(item)
65
+ else
66
+ to_converter.from_mongo(item)
67
+ end
68
+ end
69
+ end
70
+
71
+ def initialize(hash={})
72
+ super()
73
+ update(hash)
74
+ end
75
+
76
+ def to_mongo
77
+ HASH_CONVERTER.to_mongo(self)
78
+ end
79
+
80
+ def [](key)
81
+ super(convert_key(key))
82
+ end
83
+
84
+ def []=(key, value)
85
+ super(convert_key(key), convert_value(value))
86
+ end
87
+
88
+ def store(key, value)
89
+ super(convert_key(key), convert_value(value))
90
+ end
91
+
92
+ def delete(key)
93
+ super(convert_key(key))
94
+ end
95
+
96
+ def fetch(key, *args, &block)
97
+ super(convert_key(key), *args, &block)
98
+ end
99
+
100
+ def key?(key)
101
+ super(convert_key(key))
102
+ end
103
+
104
+ alias_method :include?, :key?
105
+ alias_method :has_key?, :key?
106
+ alias_method :member?, :key?
107
+
108
+ def value?(value)
109
+ super(convert_value(value))
110
+ end
111
+
112
+ alias_method :has_value?, :value?
113
+
114
+ def index(value)
115
+ super(convert_value(value))
116
+ end
117
+
118
+ def update(hash)
119
+ hash.each_pair { |k, v| self[k] = v }
120
+ self
121
+ end
122
+
123
+ def replace(hash)
124
+ clear
125
+ update(hash)
126
+ end
127
+
128
+ def merge(hash)
129
+ dup.update(super(hash))
130
+ end
131
+
132
+ def merge!(hash)
133
+ update(merge(hash))
134
+ end
135
+
136
+ def values_at(*keys)
137
+ super(*keys.map { |k| convert_key(k) })
138
+ end
139
+
140
+ private
141
+ def convert_key(key)
142
+ self.class.from_converter.cast(key)
143
+ end
144
+
145
+ def convert_value(value)
146
+ self.class.to_converter.cast(value)
147
+ end
148
+ end
149
+ end
@@ -1,3 +1,5 @@
1
+ require 'set'
2
+
1
3
  require 'mongomodel/support/types/object'
2
4
  require 'mongomodel/support/types/string'
3
5
  require 'mongomodel/support/types/integer'
@@ -8,6 +10,7 @@ require 'mongomodel/support/types/date'
8
10
  require 'mongomodel/support/types/time'
9
11
  require 'mongomodel/support/types/custom'
10
12
  require 'mongomodel/support/types/array'
13
+ require 'mongomodel/support/types/set'
11
14
  require 'mongomodel/support/types/hash'
12
15
 
13
16
  module MongoModel
@@ -21,6 +24,7 @@ module MongoModel
21
24
  ::Date => Types::Date.new,
22
25
  ::Time => Types::Time.new,
23
26
  ::Array => Types::Array.new,
27
+ ::Set => Types::Set.new,
24
28
  ::Hash => Types::Hash.new
25
29
  }
26
30
 
@@ -0,0 +1,9 @@
1
+ module MongoModel
2
+ module Types
3
+ class Set < Array
4
+ def cast(obj)
5
+ ::Set.new(::Array.wrap(obj))
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,3 +1,3 @@
1
1
  module MongoModel
2
- VERSION = "0.2.3"
2
+ VERSION = "0.2.4"
3
3
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mongomodel}
8
- s.version = "0.2.3"
8
+ s.version = "0.2.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Sam Pohlenz"]
12
- s.date = %q{2010-04-30}
12
+ s.date = %q{2010-05-17}
13
13
  s.default_executable = %q{console}
14
14
  s.description = %q{MongoModel is a MongoDB ORM for Ruby/Rails similar to ActiveRecord and DataMapper.}
15
15
  s.email = %q{sam@sampohlenz.com}
@@ -24,8 +24,10 @@ Gem::Specification.new do |s|
24
24
  "LICENSE",
25
25
  "README.md",
26
26
  "Rakefile",
27
+ "autotest/discover.rb",
27
28
  "bin/console",
28
29
  "lib/mongomodel.rb",
30
+ "lib/mongomodel/attributes/dirty.rb",
29
31
  "lib/mongomodel/attributes/mongo.rb",
30
32
  "lib/mongomodel/attributes/store.rb",
31
33
  "lib/mongomodel/attributes/typecasting.rb",
@@ -68,11 +70,13 @@ Gem::Specification.new do |s|
68
70
  "lib/mongomodel/document/validations/uniqueness.rb",
69
71
  "lib/mongomodel/embedded_document.rb",
70
72
  "lib/mongomodel/locale/en.yml",
73
+ "lib/mongomodel/railtie.rb",
71
74
  "lib/mongomodel/support/collection.rb",
72
75
  "lib/mongomodel/support/configuration.rb",
73
76
  "lib/mongomodel/support/core_extensions.rb",
74
77
  "lib/mongomodel/support/dynamic_finder.rb",
75
78
  "lib/mongomodel/support/exceptions.rb",
79
+ "lib/mongomodel/support/map.rb",
76
80
  "lib/mongomodel/support/mongo_operator.rb",
77
81
  "lib/mongomodel/support/mongo_options.rb",
78
82
  "lib/mongomodel/support/mongo_order.rb",
@@ -91,6 +95,7 @@ Gem::Specification.new do |s|
91
95
  "lib/mongomodel/support/types/hash.rb",
92
96
  "lib/mongomodel/support/types/integer.rb",
93
97
  "lib/mongomodel/support/types/object.rb",
98
+ "lib/mongomodel/support/types/set.rb",
94
99
  "lib/mongomodel/support/types/string.rb",
95
100
  "lib/mongomodel/support/types/symbol.rb",
96
101
  "lib/mongomodel/support/types/time.rb",
@@ -129,6 +134,7 @@ Gem::Specification.new do |s|
129
134
  "spec/mongomodel/embedded_document_spec.rb",
130
135
  "spec/mongomodel/mongomodel_spec.rb",
131
136
  "spec/mongomodel/support/collection_spec.rb",
137
+ "spec/mongomodel/support/map_spec.rb",
132
138
  "spec/mongomodel/support/mongo_operator_spec.rb",
133
139
  "spec/mongomodel/support/mongo_options_spec.rb",
134
140
  "spec/mongomodel/support/mongo_order_spec.rb",
@@ -148,10 +154,10 @@ Gem::Specification.new do |s|
148
154
  "spec/support/matchers/run_callbacks.rb",
149
155
  "spec/support/models.rb"
150
156
  ]
151
- s.homepage = %q{http://github.com/spohlenz/mongomodel}
157
+ s.homepage = %q{http://www.mongomodel.org}
152
158
  s.rdoc_options = ["--charset=UTF-8"]
153
159
  s.require_paths = ["lib"]
154
- s.rubygems_version = %q{1.3.6}
160
+ s.rubygems_version = %q{1.3.7}
155
161
  s.summary = %q{MongoDB ORM for Ruby/Rails}
156
162
  s.test_files = [
157
163
  "spec/mongomodel/attributes/store_spec.rb",
@@ -187,6 +193,7 @@ Gem::Specification.new do |s|
187
193
  "spec/mongomodel/embedded_document_spec.rb",
188
194
  "spec/mongomodel/mongomodel_spec.rb",
189
195
  "spec/mongomodel/support/collection_spec.rb",
196
+ "spec/mongomodel/support/map_spec.rb",
190
197
  "spec/mongomodel/support/mongo_operator_spec.rb",
191
198
  "spec/mongomodel/support/mongo_options_spec.rb",
192
199
  "spec/mongomodel/support/mongo_order_spec.rb",
@@ -209,22 +216,22 @@ Gem::Specification.new do |s|
209
216
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
210
217
  s.specification_version = 3
211
218
 
212
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
213
- s.add_runtime_dependency(%q<activesupport>, [">= 3.0.0.beta3"])
214
- s.add_runtime_dependency(%q<activemodel>, [">= 3.0.0.beta3"])
219
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
220
+ s.add_runtime_dependency(%q<activesupport>, ["= 3.0.0.beta3"])
221
+ s.add_runtime_dependency(%q<activemodel>, ["= 3.0.0.beta3"])
215
222
  s.add_runtime_dependency(%q<mongo>, [">= 0.20.1"])
216
223
  s.add_runtime_dependency(%q<bson>, [">= 0.20.1"])
217
224
  s.add_development_dependency(%q<rspec>, [">= 1.3.0"])
218
225
  else
219
- s.add_dependency(%q<activesupport>, [">= 3.0.0.beta3"])
220
- s.add_dependency(%q<activemodel>, [">= 3.0.0.beta3"])
226
+ s.add_dependency(%q<activesupport>, ["= 3.0.0.beta3"])
227
+ s.add_dependency(%q<activemodel>, ["= 3.0.0.beta3"])
221
228
  s.add_dependency(%q<mongo>, [">= 0.20.1"])
222
229
  s.add_dependency(%q<bson>, [">= 0.20.1"])
223
230
  s.add_dependency(%q<rspec>, [">= 1.3.0"])
224
231
  end
225
232
  else
226
- s.add_dependency(%q<activesupport>, [">= 3.0.0.beta3"])
227
- s.add_dependency(%q<activemodel>, [">= 3.0.0.beta3"])
233
+ s.add_dependency(%q<activesupport>, ["= 3.0.0.beta3"])
234
+ s.add_dependency(%q<activemodel>, ["= 3.0.0.beta3"])
228
235
  s.add_dependency(%q<mongo>, [">= 0.20.1"])
229
236
  s.add_dependency(%q<bson>, [">= 0.20.1"])
230
237
  s.add_dependency(%q<rspec>, [">= 1.3.0"])
@@ -3,12 +3,16 @@ require 'spec_helper'
3
3
  module MongoModel
4
4
  specs_for(Document) do
5
5
  describe "has_many association" do
6
- define_class(:Book, Document) do
6
+ define_class(:MyBook, Document) do
7
7
  has_many :chapters
8
8
  end
9
9
 
10
10
  it "should default to :by => :foreign_key" do
11
- Book.associations[:chapters].should be_a(Associations::HasManyByForeignKey)
11
+ MyBook.associations[:chapters].should be_a(Associations::HasManyByForeignKey)
12
+ end
13
+
14
+ it "should set default inverse_of value" do
15
+ MyBook.associations[:chapters].inverse_of.should == :my_book
12
16
  end
13
17
  end
14
18
 
@@ -31,6 +31,10 @@ module MongoModel
31
31
  described_class.should be_an_abstract_class
32
32
  end
33
33
 
34
+ it "should instantiate with nil" do
35
+ described_class.new(nil).should be_an_instance_of(described_class)
36
+ end
37
+
34
38
  describe "subclasses" do
35
39
  define_class(:TestDocument, described_class)
36
40
 
@@ -0,0 +1,255 @@
1
+ require 'spec_helper'
2
+
3
+ module MongoModel
4
+ describe Map do
5
+ subject { Map }
6
+
7
+ define_class(:TestDocument, EmbeddedDocument) do
8
+ property :name, String
9
+
10
+ def self.cast(name)
11
+ new(:name => name)
12
+ end
13
+ end
14
+
15
+ let(:doc) { TestDocument.new(:name => "Foobar") }
16
+
17
+ it { should be_a_subclass_of(Hash) }
18
+
19
+ it "should have from type String" do
20
+ subject.from.should == String
21
+ end
22
+
23
+ it "should have to type Object" do
24
+ subject.to.should == Object
25
+ end
26
+
27
+ it "should not show its type when inspecting" do
28
+ subject.inspect.should == "Map"
29
+ end
30
+
31
+ it "should allow any string->object mappings to be added" do
32
+ map = subject.new
33
+ map["hello"] = 123
34
+ map["foo"] = "Bonjour"
35
+ map["mydoc"] = doc
36
+ map.should == { "hello" => 123, "foo" => "Bonjour", "mydoc" => doc }
37
+ end
38
+
39
+ it "should convert to mongo representation" do
40
+ map = subject.new({ "hello" => 123, "mydoc" => doc })
41
+ map.to_mongo.should == { "hello" => 123, "mydoc" => { "_type" => 'TestDocument', "name" => "Foobar" } }
42
+ end
43
+
44
+ it "should load from mongo representation" do
45
+ map = subject.from_mongo({ "hello" => 123, "mydoc" => { "_type" => 'TestDocument', "name" => "Foobar" } })
46
+ map.should be_a(subject)
47
+ map.should == { "hello" => 123, "mydoc" => doc }
48
+ end
49
+
50
+ it "should cache map types" do
51
+ Map[Symbol => String].should equal(Map[Symbol => String])
52
+ Map[String => TestDocument].should equal(Map[String => TestDocument])
53
+ end
54
+
55
+ describe "map from String to String" do
56
+ let(:klass) { Map[String => String] }
57
+ subject { klass.new("123" => "456", "12.5" => "foobar") }
58
+
59
+ it "should show its types when inspecting" do
60
+ klass.inspect.should == "Map[String => String]"
61
+ end
62
+
63
+ it "should cast key/values when instantiating" do
64
+ map = klass.new(123 => 456, 12.5 => :foobar)
65
+ map.should == { "123" => "456", "12.5" => "foobar" }
66
+ end
67
+
68
+ it "should cast keys on []" do
69
+ subject[123].should == "456"
70
+ end
71
+
72
+ it "should cast key/values on []=" do
73
+ subject[12.5] = 456
74
+ subject["12.5"].should == "456"
75
+ end
76
+
77
+ it "should cast key/values on #store" do
78
+ subject.store(12.5, 456)
79
+ subject["12.5"].should == "456"
80
+ end
81
+
82
+ it "should cast keys on #delete" do
83
+ subject.delete(123)
84
+ subject["123"].should be_nil
85
+ end
86
+
87
+ it "should cast keys on #fetch" do
88
+ subject.fetch(123).should == "456"
89
+ subject.fetch(999, "default").should == "default"
90
+ end
91
+
92
+ it "should cast keys on #has_key?, #include?, #key?, #member?" do
93
+ subject.has_key?(123).should be_true
94
+ subject.include?(12.5).should be_true
95
+ subject.key?(123).should be_true
96
+ subject.member?(12.5).should be_true
97
+ end
98
+
99
+ it "should cast values on #has_value?, #value?" do
100
+ subject.has_value?(456).should be_true
101
+ subject.value?(456).should be_true
102
+ end
103
+
104
+ it "should cast values on #index" do
105
+ subject.index(456).should == "123"
106
+ end
107
+
108
+ it "should cast key/values on #replace" do
109
+ subject.replace(321 => 654, 5.12 => :barbaz)
110
+ subject.should == { "321" => "654", "5.12" => "barbaz" }
111
+ end
112
+
113
+ it "should cast key/values on #merge" do
114
+ map = subject.merge(321 => 654, 5.12 => :barbaz)
115
+ map.should == { "123" => "456", "12.5" => "foobar", "321" => "654", "5.12" => "barbaz" }
116
+ end
117
+
118
+ it "should cast key/values on #merge!" do
119
+ subject.merge!(321 => 654, 5.12 => :barbaz)
120
+ subject.should == { "123" => "456", "12.5" => "foobar", "321" => "654", "5.12" => "barbaz" }
121
+ end
122
+
123
+ it "should cast keys on #values_at" do
124
+ subject.values_at(12.5, 123).should == ["foobar", "456"]
125
+ end
126
+ end
127
+
128
+ describe "map from Symbol to TestDocument" do
129
+ let(:doc1) { TestDocument.new(:name => "First") }
130
+ let(:doc2) { TestDocument.new(:name => "Another") }
131
+
132
+ let(:klass) { Map[Symbol => TestDocument] }
133
+ subject { klass.new(:abc => doc1, :another => doc2) }
134
+
135
+ it "should show its types when inspecting" do
136
+ klass.inspect.should == "Map[Symbol => TestDocument]"
137
+ end
138
+
139
+ it "should cast key/values when instantiating" do
140
+ map = klass.new("foo" => "First", "123" => "Another")
141
+ map.should == { :foo => doc1, :"123" => doc2 }
142
+ end
143
+
144
+ it "should cast keys on []" do
145
+ subject["abc"].should == doc1
146
+ end
147
+
148
+ it "should cast key/values on []=" do
149
+ subject["def"] = "Another"
150
+ subject[:def].should == doc2
151
+ end
152
+
153
+ it "should cast key/values on #store" do
154
+ subject.store("def", "Another")
155
+ subject[:def].should == doc2
156
+ end
157
+
158
+ it "should cast keys on #delete" do
159
+ subject.delete("abc")
160
+ subject[:abc].should be_nil
161
+ end
162
+
163
+ it "should cast keys on #fetch" do
164
+ subject.fetch("abc").should == doc1
165
+ subject.fetch("999", "default").should == "default"
166
+ end
167
+
168
+ it "should cast keys on #has_key?, #include?, #key?, #member?" do
169
+ subject.has_key?("abc").should be_true
170
+ subject.include?("another").should be_true
171
+ subject.key?("abc").should be_true
172
+ subject.member?("another").should be_true
173
+ end
174
+
175
+ it "should cast values on #has_value?, #value?" do
176
+ subject.has_value?("First").should be_true
177
+ subject.value?("Another").should be_true
178
+ end
179
+
180
+ it "should cast values on #index" do
181
+ subject.index("First").should == :abc
182
+ end
183
+
184
+ it "should cast key/values on #replace" do
185
+ subject.replace("321" => "Bonus", "hello" => "Another")
186
+ subject.should == { :"321" => TestDocument.new(:name => "Bonus"), :hello => doc2 }
187
+ end
188
+
189
+ it "should cast key/values on #merge" do
190
+ map = subject.merge("321" => "Bonus", "hello" => "Another")
191
+ map.should == { :abc => doc1, :another => doc2, :"321" => TestDocument.new(:name => "Bonus"), :hello => doc2 }
192
+ end
193
+
194
+ it "should cast key/values on #merge!" do
195
+ subject.merge!("321" => "Bonus", "hello" => "Another")
196
+ subject.should == { :abc => doc1, :another => doc2, :"321" => TestDocument.new(:name => "Bonus"), :hello => doc2 }
197
+ end
198
+
199
+ it "should cast keys on #values_at" do
200
+ subject.values_at(:another, :abc).should == [doc2, doc1]
201
+ end
202
+ end
203
+ end
204
+
205
+ specs_for(Document, EmbeddedDocument) do
206
+ define_class(:ChildDocument, EmbeddedDocument) do
207
+ property :name, String
208
+
209
+ def self.cast(name)
210
+ new(:name => name)
211
+ end
212
+ end
213
+
214
+ describe "defining a Map property containing EmbeddedDocument values" do
215
+ define_class(:TestDocument, described_class) do
216
+ property :test_map, Map[String => ChildDocument]
217
+ end
218
+
219
+ let(:child1) { ChildDocument.new(:name => "Child 1") }
220
+ let(:child2) { ChildDocument.new(:name => "Child 2") }
221
+
222
+ subject { TestDocument.new(:test_map => { "1" => child1, "2" => child2 }) }
223
+
224
+ it "should include the map values in the embedded documents list" do
225
+ subject.embedded_documents.should include(child1, child2)
226
+ end
227
+ end
228
+
229
+ describe "defining a Map property with no default value" do
230
+ define_class(:TestDocument, described_class) do
231
+ property :test_map, Map[Symbol => ChildDocument]
232
+ end
233
+
234
+ subject { TestDocument.new }
235
+
236
+ it "should default to an empty map" do
237
+ subject.test_map.should be_an_instance_of(Map[Symbol => ChildDocument])
238
+ subject.test_map.should be_empty
239
+ end
240
+ end
241
+
242
+ describe "defining a Map property with a default value" do
243
+ define_class(:TestDocument, described_class) do
244
+ property :test_map, Map[Symbol => ChildDocument], :default => { :abc => 'abc', 'def' => 'def' }
245
+ end
246
+
247
+ subject { TestDocument.new }
248
+
249
+ it "should cast key/values to map type" do
250
+ subject.test_map[:abc].should == ChildDocument.new(:name => 'abc')
251
+ subject.test_map[:def].should == ChildDocument.new(:name => 'def')
252
+ end
253
+ end
254
+ end
255
+ end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongomodel
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 31
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
8
  - 2
8
- - 3
9
- version: 0.2.3
9
+ - 4
10
+ version: 0.2.4
10
11
  platform: ruby
11
12
  authors:
12
13
  - Sam Pohlenz
@@ -14,16 +15,18 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-04-30 00:00:00 +09:30
18
+ date: 2010-05-17 00:00:00 +09:30
18
19
  default_executable: console
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
22
  name: activesupport
22
23
  prerelease: false
23
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
24
26
  requirements:
25
- - - ">="
27
+ - - "="
26
28
  - !ruby/object:Gem::Version
29
+ hash: -1848230021
27
30
  segments:
28
31
  - 3
29
32
  - 0
@@ -36,9 +39,11 @@ dependencies:
36
39
  name: activemodel
37
40
  prerelease: false
38
41
  requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
39
43
  requirements:
40
- - - ">="
44
+ - - "="
41
45
  - !ruby/object:Gem::Version
46
+ hash: -1848230021
42
47
  segments:
43
48
  - 3
44
49
  - 0
@@ -51,9 +56,11 @@ dependencies:
51
56
  name: mongo
52
57
  prerelease: false
53
58
  requirement: &id003 !ruby/object:Gem::Requirement
59
+ none: false
54
60
  requirements:
55
61
  - - ">="
56
62
  - !ruby/object:Gem::Version
63
+ hash: 77
57
64
  segments:
58
65
  - 0
59
66
  - 20
@@ -65,9 +72,11 @@ dependencies:
65
72
  name: bson
66
73
  prerelease: false
67
74
  requirement: &id004 !ruby/object:Gem::Requirement
75
+ none: false
68
76
  requirements:
69
77
  - - ">="
70
78
  - !ruby/object:Gem::Version
79
+ hash: 77
71
80
  segments:
72
81
  - 0
73
82
  - 20
@@ -79,9 +88,11 @@ dependencies:
79
88
  name: rspec
80
89
  prerelease: false
81
90
  requirement: &id005 !ruby/object:Gem::Requirement
91
+ none: false
82
92
  requirements:
83
93
  - - ">="
84
94
  - !ruby/object:Gem::Version
95
+ hash: 27
85
96
  segments:
86
97
  - 1
87
98
  - 3
@@ -104,8 +115,10 @@ files:
104
115
  - LICENSE
105
116
  - README.md
106
117
  - Rakefile
118
+ - autotest/discover.rb
107
119
  - bin/console
108
120
  - lib/mongomodel.rb
121
+ - lib/mongomodel/attributes/dirty.rb
109
122
  - lib/mongomodel/attributes/mongo.rb
110
123
  - lib/mongomodel/attributes/store.rb
111
124
  - lib/mongomodel/attributes/typecasting.rb
@@ -148,11 +161,13 @@ files:
148
161
  - lib/mongomodel/document/validations/uniqueness.rb
149
162
  - lib/mongomodel/embedded_document.rb
150
163
  - lib/mongomodel/locale/en.yml
164
+ - lib/mongomodel/railtie.rb
151
165
  - lib/mongomodel/support/collection.rb
152
166
  - lib/mongomodel/support/configuration.rb
153
167
  - lib/mongomodel/support/core_extensions.rb
154
168
  - lib/mongomodel/support/dynamic_finder.rb
155
169
  - lib/mongomodel/support/exceptions.rb
170
+ - lib/mongomodel/support/map.rb
156
171
  - lib/mongomodel/support/mongo_operator.rb
157
172
  - lib/mongomodel/support/mongo_options.rb
158
173
  - lib/mongomodel/support/mongo_order.rb
@@ -171,6 +186,7 @@ files:
171
186
  - lib/mongomodel/support/types/hash.rb
172
187
  - lib/mongomodel/support/types/integer.rb
173
188
  - lib/mongomodel/support/types/object.rb
189
+ - lib/mongomodel/support/types/set.rb
174
190
  - lib/mongomodel/support/types/string.rb
175
191
  - lib/mongomodel/support/types/symbol.rb
176
192
  - lib/mongomodel/support/types/time.rb
@@ -209,6 +225,7 @@ files:
209
225
  - spec/mongomodel/embedded_document_spec.rb
210
226
  - spec/mongomodel/mongomodel_spec.rb
211
227
  - spec/mongomodel/support/collection_spec.rb
228
+ - spec/mongomodel/support/map_spec.rb
212
229
  - spec/mongomodel/support/mongo_operator_spec.rb
213
230
  - spec/mongomodel/support/mongo_options_spec.rb
214
231
  - spec/mongomodel/support/mongo_order_spec.rb
@@ -228,7 +245,7 @@ files:
228
245
  - spec/support/matchers/run_callbacks.rb
229
246
  - spec/support/models.rb
230
247
  has_rdoc: true
231
- homepage: http://github.com/spohlenz/mongomodel
248
+ homepage: http://www.mongomodel.org
232
249
  licenses: []
233
250
 
234
251
  post_install_message:
@@ -237,23 +254,27 @@ rdoc_options:
237
254
  require_paths:
238
255
  - lib
239
256
  required_ruby_version: !ruby/object:Gem::Requirement
257
+ none: false
240
258
  requirements:
241
259
  - - ">="
242
260
  - !ruby/object:Gem::Version
261
+ hash: 3
243
262
  segments:
244
263
  - 0
245
264
  version: "0"
246
265
  required_rubygems_version: !ruby/object:Gem::Requirement
266
+ none: false
247
267
  requirements:
248
268
  - - ">="
249
269
  - !ruby/object:Gem::Version
270
+ hash: 3
250
271
  segments:
251
272
  - 0
252
273
  version: "0"
253
274
  requirements: []
254
275
 
255
276
  rubyforge_project:
256
- rubygems_version: 1.3.6
277
+ rubygems_version: 1.3.7
257
278
  signing_key:
258
279
  specification_version: 3
259
280
  summary: MongoDB ORM for Ruby/Rails
@@ -291,6 +312,7 @@ test_files:
291
312
  - spec/mongomodel/embedded_document_spec.rb
292
313
  - spec/mongomodel/mongomodel_spec.rb
293
314
  - spec/mongomodel/support/collection_spec.rb
315
+ - spec/mongomodel/support/map_spec.rb
294
316
  - spec/mongomodel/support/mongo_operator_spec.rb
295
317
  - spec/mongomodel/support/mongo_options_spec.rb
296
318
  - spec/mongomodel/support/mongo_order_spec.rb