mongomodel 0.2.3 → 0.2.4

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