mongo_mapper-unstable 2010.2.28 → 2010.3.3

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -10,11 +10,11 @@ Jeweler::Tasks.new do |gem|
10
10
  gem.email = "nunemaker@gmail.com"
11
11
  gem.homepage = "http://github.com/jnunemaker/mongomapper"
12
12
  gem.authors = ["John Nunemaker"]
13
-
13
+
14
14
  gem.add_dependency('activesupport', '>= 2.3')
15
- gem.add_dependency('mongo', '0.18.3')
16
- gem.add_dependency('jnunemaker-validatable', '1.8.1')
17
-
15
+ gem.add_dependency('mongo', '0.19.1')
16
+ gem.add_dependency('jnunemaker-validatable', '1.8.3')
17
+
18
18
  gem.add_development_dependency('jnunemaker-matchy', '0.4.0')
19
19
  gem.add_development_dependency('shoulda', '2.10.2')
20
20
  gem.add_development_dependency('timecop', '0.3.1')
@@ -38,7 +38,7 @@ namespace :test do
38
38
  test.pattern = 'test/unit/**/test_*.rb'
39
39
  test.verbose = true
40
40
  end
41
-
41
+
42
42
  Rake::TestTask.new(:functionals) do |test|
43
43
  test.libs << 'test'
44
44
  test.ruby_opts << '-rubygems'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2010.02.28
1
+ 2010.03.03
@@ -17,10 +17,13 @@ module MongoMapper
17
17
  plugin Plugins::Keys
18
18
  plugin Plugins::Dirty # for now dirty needs to be after keys
19
19
  plugin Plugins::Logger
20
+ plugin Plugins::Modifiers
20
21
  plugin Plugins::Pagination
21
22
  plugin Plugins::Protected
22
23
  plugin Plugins::Rails
23
24
  plugin Plugins::Serialization
25
+ plugin Plugins::Timestamps
26
+ plugin Plugins::Userstamps
24
27
  plugin Plugins::Validations
25
28
  plugin Plugins::Callbacks # for now callbacks needs to be after validations
26
29
 
@@ -143,47 +146,6 @@ module MongoMapper
143
146
  find_each(options) { |document| document.destroy }
144
147
  end
145
148
 
146
- def increment(*args)
147
- modifier_update('$inc', args)
148
- end
149
-
150
- def decrement(*args)
151
- criteria, keys = criteria_and_keys_from_args(args)
152
- values, to_decrement = keys.values, {}
153
- keys.keys.each_with_index { |k, i| to_decrement[k] = -values[i].abs }
154
- collection.update(criteria, {'$inc' => to_decrement}, :multi => true)
155
- end
156
-
157
- def set(*args)
158
- modifier_update('$set', args)
159
- end
160
-
161
- def push(*args)
162
- modifier_update('$push', args)
163
- end
164
-
165
- def push_all(*args)
166
- modifier_update('$pushAll', args)
167
- end
168
-
169
- def push_uniq(*args)
170
- criteria, keys = criteria_and_keys_from_args(args)
171
- keys.each { |key, value | criteria[key] = {'$ne' => value} }
172
- collection.update(criteria, {'$push' => keys}, :multi => true)
173
- end
174
-
175
- def pull(*args)
176
- modifier_update('$pull', args)
177
- end
178
-
179
- def pull_all(*args)
180
- modifier_update('$pullAll', args)
181
- end
182
-
183
- def pop(*args)
184
- modifier_update('$pop', args)
185
- end
186
-
187
149
  def embeddable?
188
150
  false
189
151
  end
@@ -225,19 +187,6 @@ module MongoMapper
225
187
  database.collection(collection_name)
226
188
  end
227
189
 
228
- def timestamps!
229
- key :created_at, Time
230
- key :updated_at, Time
231
- class_eval { before_save :update_timestamps }
232
- end
233
-
234
- def userstamps!
235
- key :creator_id, ObjectId
236
- key :updater_id, ObjectId
237
- belongs_to :creator, :class_name => 'User'
238
- belongs_to :updater, :class_name => 'User'
239
- end
240
-
241
190
  def single_collection_inherited?
242
191
  keys.key?(:_type) && single_collection_inherited_superclass?
243
192
  end
@@ -258,18 +207,6 @@ module MongoMapper
258
207
  instances.size == 1 ? instances[0] : instances
259
208
  end
260
209
 
261
- def modifier_update(modifier, args)
262
- criteria, keys = criteria_and_keys_from_args(args)
263
- modifiers = {modifier => keys}
264
- collection.update(criteria, modifiers, :multi => true)
265
- end
266
-
267
- def criteria_and_keys_from_args(args)
268
- keys = args.pop
269
- criteria = args[0].is_a?(Hash) ? args[0] : {:id => args}
270
- [to_criteria(criteria), keys]
271
- end
272
-
273
210
  def assert_no_first_last_or_all(args)
274
211
  if args[0] == :first || args[0] == :last || args[0] == :all
275
212
  raise ArgumentError, "#{self}.find(:#{args}) is no longer supported, use #{self}.#{args} instead."
@@ -417,12 +354,6 @@ module MongoMapper
417
354
  @new = false
418
355
  collection.save(to_mongo, :safe => safe)
419
356
  end
420
-
421
- def update_timestamps
422
- now = Time.now.utc
423
- self[:created_at] = now if new? && !created_at?
424
- self[:updated_at] = now
425
- end
426
357
  end
427
358
  end # Document
428
359
  end # MongoMapper
@@ -13,7 +13,9 @@ module MongoMapper
13
13
  :before_validation, :after_validation,
14
14
  :before_validation_on_create, :after_validation_on_create,
15
15
  :before_validation_on_update, :after_validation_on_update,
16
- :before_destroy, :after_destroy
16
+ :before_destroy, :after_destroy,
17
+ :validate_on_create, :validate_on_update,
18
+ :validate
17
19
  )
18
20
  end
19
21
  end
@@ -48,16 +50,25 @@ module MongoMapper
48
50
  module InstanceMethods
49
51
  def valid?
50
52
  action = new? ? 'create' : 'update'
51
-
52
53
  run_callbacks(:before_validation)
53
54
  run_callbacks("before_validation_on_#{action}".to_sym)
54
55
  result = super
55
56
  run_callbacks("after_validation_on_#{action}".to_sym)
56
57
  run_callbacks(:after_validation)
57
-
58
58
  result
59
59
  end
60
60
 
61
+ # Overriding validatable's valid_for_group? to integrate validation callbacks
62
+ def valid_for_group?(group) #:nodoc:
63
+ errors.clear
64
+ run_before_validations
65
+ run_callbacks(:validate)
66
+ new? ? run_callbacks(:validate_on_create) : run_callbacks(:validate_on_update)
67
+ self.class.validate_children(self, group)
68
+ self.validate_group(group)
69
+ errors.empty?
70
+ end
71
+
61
72
  def destroy
62
73
  run_callbacks(:before_destroy)
63
74
  result = super
@@ -170,7 +170,7 @@ module MongoMapper
170
170
 
171
171
  def attributes=(attrs)
172
172
  return if attrs.blank?
173
-
173
+
174
174
  attrs.each_pair do |name, value|
175
175
  writer_method = "#{name}="
176
176
 
@@ -220,7 +220,7 @@ module MongoMapper
220
220
  def id
221
221
  _id
222
222
  end
223
-
223
+
224
224
  def id=(value)
225
225
  if self.class.using_object_id?
226
226
  value = MongoMapper.normalize_object_id(value)
@@ -262,7 +262,7 @@ module MongoMapper
262
262
  def assign_type_if_present
263
263
  self._type = self.class.name if respond_to?(:_type=)
264
264
  end
265
-
265
+
266
266
  def ensure_key_exists(name)
267
267
  self.class.key(name) unless respond_to?("#{name}=")
268
268
  end
@@ -283,11 +283,16 @@ module MongoMapper
283
283
 
284
284
  def write_key(name, value)
285
285
  key = keys[name]
286
+
287
+ if key.embeddable? && value.is_a?(key.type)
288
+ value._parent_document = self
289
+ end
290
+
286
291
  instance_variable_set "@#{name}_before_typecast", value
287
292
  instance_variable_set "@#{name}", key.set(value)
288
293
  end
289
294
  end
290
-
295
+
291
296
  class Key
292
297
  attr_accessor :name, :type, :options, :default_value
293
298
 
@@ -0,0 +1,87 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Modifiers
4
+ module ClassMethods
5
+ def increment(*args)
6
+ modifier_update('$inc', args)
7
+ end
8
+
9
+ def decrement(*args)
10
+ criteria, keys = criteria_and_keys_from_args(args)
11
+ values, to_decrement = keys.values, {}
12
+ keys.keys.each_with_index { |k, i| to_decrement[k] = -values[i].abs }
13
+ collection.update(criteria, {'$inc' => to_decrement}, :multi => true)
14
+ end
15
+
16
+ def set(*args)
17
+ modifier_update('$set', args)
18
+ end
19
+
20
+ def push(*args)
21
+ modifier_update('$push', args)
22
+ end
23
+
24
+ def push_all(*args)
25
+ modifier_update('$pushAll', args)
26
+ end
27
+
28
+ def push_uniq(*args)
29
+ criteria, keys = criteria_and_keys_from_args(args)
30
+ keys.each { |key, value | criteria[key] = {'$ne' => value} }
31
+ collection.update(criteria, {'$push' => keys}, :multi => true)
32
+ end
33
+
34
+ def pull(*args)
35
+ modifier_update('$pull', args)
36
+ end
37
+
38
+ def pull_all(*args)
39
+ modifier_update('$pullAll', args)
40
+ end
41
+
42
+ def pop(*args)
43
+ modifier_update('$pop', args)
44
+ end
45
+
46
+ private
47
+ def modifier_update(modifier, args)
48
+ criteria, keys = criteria_and_keys_from_args(args)
49
+ modifiers = {modifier => keys}
50
+ collection.update(criteria, modifiers, :multi => true)
51
+ end
52
+
53
+ def criteria_and_keys_from_args(args)
54
+ keys = args.pop
55
+ criteria = args[0].is_a?(Hash) ? args[0] : {:id => args}
56
+ [to_criteria(criteria), keys]
57
+ end
58
+ end
59
+
60
+ module InstanceMethods
61
+ def increment(hash)
62
+ self.class.increment({:_id => id}, hash)
63
+ end
64
+
65
+ def decrement(hash)
66
+ self.class.decrement({:_id => id}, hash)
67
+ end
68
+
69
+ def set(hash)
70
+ self.class.set({:_id => id}, hash)
71
+ end
72
+
73
+ def push(hash)
74
+ self.class.push({:_id => id}, hash)
75
+ end
76
+
77
+ def pull(hash)
78
+ self.class.pull({:_id => id}, hash)
79
+ end
80
+
81
+ def push_uniq(hash)
82
+ self.class.push_uniq({:_id => id}, hash)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -1,41 +1,49 @@
1
1
  module MongoMapper
2
2
  module Plugins
3
3
  module Rails
4
+ def self.configure(model)
5
+ model.extend ActiveModel::Naming if defined?(ActiveModel)
6
+ end
7
+
4
8
  module InstanceMethods
5
9
  def to_param
6
10
  id.to_s
7
11
  end
8
-
12
+
13
+ def to_model
14
+ self
15
+ end
16
+
9
17
  def new_record?
10
18
  new?
11
19
  end
12
-
20
+
13
21
  def read_attribute(name)
14
22
  self[name]
15
23
  end
16
-
24
+
17
25
  def read_attribute_before_typecast(name)
18
26
  read_key_before_typecast(name)
19
27
  end
20
-
28
+
21
29
  def write_attribute(name, value)
22
30
  self[name] = value
23
31
  end
24
32
  end
25
-
33
+
26
34
  module ClassMethods
27
35
  def has_one(*args)
28
36
  one(*args)
29
37
  end
30
-
38
+
31
39
  def has_many(*args)
32
40
  many(*args)
33
41
  end
34
-
42
+
35
43
  def column_names
36
44
  keys.keys
37
45
  end
38
-
46
+
39
47
  def human_name
40
48
  self.name.demodulize.titleize
41
49
  end
@@ -4,102 +4,72 @@ module MongoMapper
4
4
  module Plugins
5
5
  module Serialization
6
6
  def self.configure(model)
7
- model.class_eval { include Json }
7
+ model.class_eval { cattr_accessor :include_root_in_json, :instance_writer => true }
8
8
  end
9
9
 
10
- class Serializer
11
- attr_reader :options
12
-
13
- def initialize(record, options={})
14
- @record, @options = record, options.dup
15
- end
16
-
17
- def serializable_key_names
18
- key_names = @record.attributes.keys
19
-
20
- if options[:only]
21
- options.delete(:except)
22
- key_names = key_names & Array(options[:only]).collect { |n| n.to_s }
23
- else
24
- options[:except] = Array(options[:except])
25
- key_names = key_names - options[:except].collect { |n| n.to_s }
26
- end
27
-
28
- key_names
29
- end
30
-
31
- def serializable_method_names
32
- Array(options[:methods]).inject([]) do |method_attributes, name|
33
- method_attributes << name if @record.respond_to?(name.to_s)
34
- method_attributes
10
+ module InstanceMethods
11
+ def as_json options={}
12
+ options ||= {}
13
+ unless options[:only]
14
+ methods = [options.delete(:methods)].flatten.compact
15
+ methods << :id
16
+ options[:methods] = methods.uniq
35
17
  end
36
- end
37
18
 
38
- def serializable_names
39
- serializable_key_names + serializable_method_names
40
- end
19
+ except = [options.delete(:except)].flatten.compact
20
+ except << :_id
21
+ options[:except] = except
41
22
 
42
- def serializable_record
43
- returning(serializable_record = {}) do
44
- serializable_names.each { |name| serializable_record[name] = @record.send(name) }
45
- end
46
- end
23
+ # Direct rip from Rails 3 ActiveModel Serialization (#serializable_hash)
24
+ hash = begin
25
+ options[:only] = Array.wrap(options[:only]).map { |n| n.to_s }
26
+ options[:except] = Array.wrap(options[:except]).map { |n| n.to_s }
47
27
 
48
- def serialize
49
- # overwrite to implement
50
- end
28
+ attribute_names = attributes.keys.sort
29
+ if options[:only].any?
30
+ attribute_names &= options[:only]
31
+ elsif options[:except].any?
32
+ attribute_names -= options[:except]
33
+ end
51
34
 
52
- def to_s(&block)
53
- serialize(&block)
54
- end
55
- end
56
-
57
- module Json
58
- def self.included(base)
59
- base.cattr_accessor :include_root_in_json, :instance_writer => false
60
- base.extend ClassMethods
61
- end
35
+ method_names = Array.wrap(options[:methods]).inject([]) do |methods, name|
36
+ methods << name if respond_to?(name.to_s)
37
+ methods
38
+ end
62
39
 
63
- module ClassMethods
64
- def json_class_name
65
- @json_class_name ||= name.demodulize.underscore.inspect
40
+ (attribute_names + method_names).inject({}) { |hash, name|
41
+ hash[name] = send(name)
42
+ hash
43
+ }
66
44
  end
67
- end
68
-
69
- def to_json(options={})
70
- apply_to_json_defaults(options)
71
-
72
- if include_root_in_json
73
- "{#{self.class.json_class_name}: #{JsonSerializer.new(self, options).to_s}}"
74
- else
75
- JsonSerializer.new(self, options).to_s
45
+ # End rip
46
+
47
+ options.delete(:only) if options[:only].nil? or options[:only].empty?
48
+
49
+ hash.each do |key, value|
50
+ if value.is_a?(Array)
51
+ hash[key] = value.map do |item|
52
+ item.respond_to?(:as_json) ? item.as_json(options) : item
53
+ end
54
+ elsif value.is_a? Mongo::ObjectID
55
+ hash[key] = value.to_s
56
+ elsif value.respond_to?(:as_json)
57
+ hash[key] = value.as_json(options)
58
+ end
76
59
  end
60
+
61
+ # Replicate Rails 3 naming - and also bin anytihng after : for use in our dynamic classes from unit tests
62
+ hash = { ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)).gsub(/:.*/,'') => hash } if include_root_in_json
63
+ hash
77
64
  end
65
+ end
78
66
 
67
+ module ClassMethods
79
68
  def from_json(json)
80
- self.attributes = ActiveSupport::JSON.decode(json)
81
- self
69
+ self.new(ActiveSupport::JSON.decode(json))
82
70
  end
83
-
84
- class JsonSerializer < Serializer
85
- def serialize
86
- serializable_record.to_json
87
- end
88
- end
89
-
90
- private
91
- def apply_to_json_defaults(options)
92
- unless options[:only]
93
- methods = [options.delete(:methods)].flatten.compact
94
- methods << :id
95
- options[:methods] = methods.uniq
96
- end
97
-
98
- except = [options.delete(:except)].flatten.compact
99
- except << :_id
100
- options[:except] = except
101
- end
102
71
  end
72
+
103
73
  end
104
74
  end
105
75
  end
@@ -0,0 +1,21 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Timestamps
4
+ module ClassMethods
5
+ def timestamps!
6
+ key :created_at, Time
7
+ key :updated_at, Time
8
+ class_eval { before_save :update_timestamps }
9
+ end
10
+ end
11
+
12
+ module InstanceMethods
13
+ def update_timestamps
14
+ now = Time.now.utc
15
+ self[:created_at] = now if new? && !created_at?
16
+ self[:updated_at] = now
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,14 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Userstamps
4
+ module ClassMethods
5
+ def userstamps!
6
+ key :creator_id, ObjectId
7
+ key :updater_id, ObjectId
8
+ belongs_to :creator, :class_name => 'User'
9
+ belongs_to :updater, :class_name => 'User'
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -20,9 +20,12 @@ module MongoMapper
20
20
  autoload :Inspect, 'mongo_mapper/plugins/inspect'
21
21
  autoload :Keys, 'mongo_mapper/plugins/keys'
22
22
  autoload :Logger, 'mongo_mapper/plugins/logger'
23
+ autoload :Modifiers, 'mongo_mapper/plugins/modifiers'
23
24
  autoload :Protected, 'mongo_mapper/plugins/protected'
24
25
  autoload :Rails, 'mongo_mapper/plugins/rails'
25
26
  autoload :Serialization, 'mongo_mapper/plugins/serialization'
27
+ autoload :Timestamps, 'mongo_mapper/plugins/timestamps'
28
+ autoload :Userstamps, 'mongo_mapper/plugins/userstamps'
26
29
  autoload :Validations, 'mongo_mapper/plugins/validations'
27
30
  end
28
31
  end
data/lib/mongo_mapper.rb CHANGED
@@ -7,8 +7,8 @@ require 'uri'
7
7
  # if there is a better way to do this, please enlighten me!
8
8
  if self.class.const_defined?(:Gem)
9
9
  gem 'activesupport', '>= 2.3'
10
- gem 'mongo', '0.18.3'
11
- gem 'jnunemaker-validatable', '1.8.1'
10
+ gem 'mongo', '0.19.1'
11
+ gem 'jnunemaker-validatable', '1.8.3'
12
12
  end
13
13
 
14
14
  require 'active_support/all'
@@ -0,0 +1,11 @@
1
+ require 'test_helper'
2
+ require 'active_model'
3
+ require 'models'
4
+
5
+ class ActiveModelLintTest < ActiveModel::TestCase
6
+ include ActiveModel::Lint::Tests
7
+
8
+ def setup
9
+ @model = Post.new
10
+ end
11
+ end