jnunemaker-mongomapper 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,3 +3,4 @@
3
3
  coverage
4
4
  rdoc
5
5
  pkg
6
+ *~
data/History CHANGED
@@ -1,3 +1,16 @@
1
+ 0.2.0 7/7/2009
2
+ * 2 major additions (observers, associations), several minor additions, and a few bug fixes
3
+ * Added observers
4
+ * many now supports embedded docs or docs in another collection (dcu on github)
5
+ * added belongs_to association (dcu)
6
+ * added validates_uniqueness_of (dcu)
7
+ * added :unique key shortcut to add validates_uniqueness_of automatically
8
+ * now tracking descendants of document (dcu)
9
+ * added validates_exclusion_of and validates_inclusion_of
10
+ * Bumped required version of validatable for callback fixes
11
+ * More thorough use of converting find conditions and options to mongo speak
12
+ * #attributes= no longer bombs when given nil
13
+
1
14
  0.1.2 7/3/2009
2
15
  * 2 minor changes
3
16
  * Straightened out callbacks and added validate, validate_on_create and validate_on_update.
data/Rakefile CHANGED
@@ -13,7 +13,7 @@ begin
13
13
 
14
14
  gem.add_dependency('activesupport')
15
15
  gem.add_dependency('mongodb-mongo', '0.9')
16
- gem.add_dependency('jnunemaker-validatable', '1.7.0')
16
+ gem.add_dependency('jnunemaker-validatable', '1.7.1')
17
17
 
18
18
  gem.add_development_dependency('mocha', '0.9.4')
19
19
  gem.add_development_dependency('jnunemaker-matchy', '0.4.0')
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.2.0
data/lib/mongomapper.rb CHANGED
@@ -3,7 +3,7 @@ require 'rubygems'
3
3
 
4
4
  gem 'activesupport'
5
5
  gem 'mongodb-mongo', '0.9'
6
- gem 'jnunemaker-validatable', '1.7.0'
6
+ gem 'jnunemaker-validatable', '1.7.1'
7
7
 
8
8
  require 'activesupport'
9
9
  require 'mongo'
@@ -16,6 +16,20 @@ require dir + 'finder_options'
16
16
  require dir + 'rails_compatibility'
17
17
  require dir + 'save_with_validation'
18
18
  require dir + 'serialization'
19
+ require dir + 'callbacks'
20
+ require dir + 'observing'
21
+ require dir + 'validations'
22
+
23
+ require dir + 'associations/proxy'
24
+ require dir + 'associations/array_proxy'
25
+ require dir + 'associations/base'
26
+
27
+ require dir + 'associations/has_many_proxy'
28
+ require dir + 'associations/has_many_embedded_proxy'
29
+ require dir + 'associations/belongs_to_proxy'
30
+ require dir + 'associations/polymorphic_belongs_to_proxy'
31
+ require dir + 'associations'
32
+
19
33
  require dir + 'embedded_document'
20
34
  require dir + 'document'
21
35
 
@@ -27,20 +41,20 @@ module MongoMapper
27
41
  super("Validation failed: #{@document.errors.full_messages.join(", ")}")
28
42
  end
29
43
  end
30
-
44
+
31
45
  def self.connection
32
46
  @@connection ||= XGen::Mongo::Driver::Mongo.new
33
47
  end
34
-
48
+
35
49
  def self.connection=(new_connection)
36
50
  @@connection = new_connection
37
51
  end
38
-
52
+
39
53
  def self.database=(name)
40
54
  @@database = MongoMapper.connection.db(name)
41
55
  end
42
-
56
+
43
57
  def self.database
44
58
  @@database
45
59
  end
46
- end
60
+ end
@@ -0,0 +1,69 @@
1
+ module MongoMapper
2
+ module Associations
3
+ module ClassMethods
4
+ def belongs_to(association_id, options = {})
5
+ association = create_association(:belongs_to, association_id, options)
6
+
7
+ ref_id = "#{association_id}_id"
8
+ key ref_id, String
9
+
10
+ define_method("#{ref_id}=") do |value|
11
+ write_attribute(ref_id, value)
12
+ end
13
+
14
+ if options[:polymorphic]
15
+ ref_type = "#{association_id}_type"
16
+ key ref_type, String
17
+
18
+ define_method("#{ref_type}=") do |value|
19
+ write_attribute(ref_type, value)
20
+ end
21
+ end
22
+
23
+ define_association_methods(association)
24
+
25
+ self
26
+ end
27
+
28
+ def many(association_id, options = {})
29
+ association = create_association(:many, association_id, options)
30
+ define_association_methods(association)
31
+
32
+ self
33
+ end
34
+
35
+ def associations
36
+ @associations ||= HashWithIndifferentAccess.new
37
+ end
38
+
39
+ private
40
+ def create_association(type, name, options)
41
+ association = Associations::Base.new(type, name, options)
42
+ associations[association.name] = association
43
+ association
44
+ end
45
+
46
+ def define_association_methods(association)
47
+ define_method(association.name) do
48
+ get_proxy(association)
49
+ end
50
+
51
+ define_method("#{association.name}=") do |value|
52
+ get_proxy(association).replace(value)
53
+ value
54
+ end
55
+ end
56
+ end
57
+
58
+ module InstanceMethods
59
+ def get_proxy(association)
60
+ proxy = self.instance_variable_get(association.ivar)
61
+ if proxy.nil?
62
+ proxy = association.proxy_class.new(self, association)
63
+ self.instance_variable_set(association.ivar, proxy)
64
+ end
65
+ proxy
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,6 @@
1
+ module MongoMapper
2
+ module Associations
3
+ class ArrayProxy < Proxy
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,50 @@
1
+ module MongoMapper
2
+ module Associations
3
+ class Base
4
+ attr_reader :type, :name, :options
5
+
6
+ def initialize(type, name, options = {})
7
+ @options = options
8
+ @type = type
9
+ @name = name
10
+ end
11
+
12
+ def klass
13
+ class_name.constantize
14
+ end
15
+
16
+ def class_name
17
+ @class_name ||= begin
18
+ if cn = options[:class_name]
19
+ cn
20
+ elsif @type == :many
21
+ name.to_s.singularize.camelize
22
+ else
23
+ name.to_s.camelize
24
+ end
25
+ end
26
+ end
27
+
28
+ def ivar
29
+ @ivar ||= "@_#{name}"
30
+ end
31
+
32
+ def proxy_class
33
+ case @type
34
+ when :belongs_to
35
+ if @options[:polymorphic]
36
+ PolymorphicBelongsToProxy
37
+ else
38
+ BelongsToProxy
39
+ end
40
+ when :many
41
+ if self.klass.embeddable?
42
+ HasManyEmbeddedProxy
43
+ else
44
+ HasManyProxy
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,26 @@
1
+ module MongoMapper
2
+ module Associations
3
+ class BelongsToProxy < Proxy
4
+ def replace(v)
5
+ ref_id = "#{@association.name}_id"
6
+
7
+ if v
8
+ v.save if v.new?
9
+ @owner.__send__(:write_attribute, ref_id, v.id)
10
+ else
11
+ @owner.__send__(:write_attribute, ref_id, nil)
12
+ end
13
+
14
+ reload_target
15
+ end
16
+
17
+ protected
18
+ def find_target
19
+ ref = @owner.__send__(:read_attribute, "#{@association.name}_id")
20
+ if ref
21
+ @association.klass.find(ref)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ module MongoMapper
2
+ module Associations
3
+ class HasManyEmbeddedProxy < ArrayProxy
4
+ def replace(v)
5
+ @_values = v.map { |e| e.kind_of?(EmbeddedDocument) ? e.attributes : e }
6
+ @target = nil
7
+
8
+ reload_target
9
+ end
10
+
11
+ protected
12
+ def find_target
13
+ (@_values || []).map do |e|
14
+ @association.klass.new(e)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ module MongoMapper
2
+ module Associations
3
+ class HasManyProxy < ArrayProxy
4
+ def replace(v)
5
+ if load_target
6
+ @target.map(&:destroy)
7
+ end
8
+
9
+ v.each do |o|
10
+ @owner.save if @owner.new?
11
+ o.__send__(:write_attribute, self.foreign_key, @owner.id)
12
+ o.save
13
+ o
14
+ end
15
+ reload_target
16
+ end
17
+
18
+ protected
19
+ def find_target
20
+ @association.klass.find(:all, {:conditions => {self.foreign_key => @owner.id}})
21
+ end
22
+
23
+ def foreign_key
24
+ @association.options[:foreign_key] || @owner.class.name.underscore.gsub("/", "_") + "_id"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,31 @@
1
+ module MongoMapper
2
+ module Associations
3
+ class PolymorphicBelongsToProxy < Proxy
4
+ def replace(v)
5
+ ref_id = "#{@association.name}_id"
6
+ ref_type = "#{@association.name}_type"
7
+
8
+ if v
9
+ v.save if v.new?
10
+ @owner.__send__(:write_attribute, ref_id, v.id)
11
+ @owner.__send__(:write_attribute, ref_type, v.class.name)
12
+ else
13
+ @owner.__send__(:write_attribute, ref_id, nil)
14
+ @owner.__send__(:write_attribute, ref_type, nil)
15
+ end
16
+ @owner.save
17
+
18
+ reload_target
19
+ end
20
+
21
+ protected
22
+ def find_target
23
+ ref_id = @owner.__send__(:read_attribute, "#{@association.name}_id")
24
+ ref_type = @owner.__send__(:read_attribute, "#{@association.name}_type")
25
+ if ref_id && ref_type
26
+ ref_type.constantize.find(ref_id)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,60 @@
1
+ module MongoMapper
2
+ module Associations
3
+ class Proxy
4
+ attr_reader :owner, :association
5
+
6
+ instance_methods.each do |m|
7
+ undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/
8
+ end
9
+
10
+ def initialize(owner, association)
11
+ @owner= owner
12
+ @association = association
13
+
14
+ reset
15
+ end
16
+
17
+ def respond_to?(*methods)
18
+ (load_target && @target.respond_to?(*methods))
19
+ end
20
+
21
+ def reset
22
+ @target = nil
23
+ end
24
+
25
+ def reload_target
26
+ reset
27
+ load_target
28
+ self
29
+ end
30
+
31
+ def send(method, *args)
32
+ load_target
33
+ @target.send(method, *args)
34
+ end
35
+
36
+ def replace(v)
37
+ raise NotImplementedError
38
+ end
39
+
40
+ protected
41
+ def method_missing(method, *args)
42
+ if load_target
43
+ if block_given?
44
+ @target.send(method, *args) { |*block_args| yield(*block_args) }
45
+ else
46
+ @target.send(method, *args)
47
+ end
48
+ end
49
+ end
50
+
51
+ def load_target
52
+ @target ||= find_target
53
+ end
54
+
55
+ def find_target
56
+ raise NotImplementedError
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,106 @@
1
+ module MongoMapper
2
+ module Callbacks
3
+ def self.included(model) #:nodoc:
4
+ model.class_eval do
5
+ extend Observable
6
+ include ActiveSupport::Callbacks
7
+
8
+ define_callbacks *%w(
9
+ before_save after_save before_create after_create before_update after_update before_validation
10
+ after_validation before_validation_on_create after_validation_on_create before_validation_on_update
11
+ after_validation_on_update before_destroy after_destroy
12
+ )
13
+
14
+ [:create_or_update, :valid?, :create, :update, :destroy].each do |method|
15
+ alias_method_chain method, :callbacks
16
+ end
17
+ end
18
+ end
19
+
20
+ def before_save() end
21
+
22
+ def after_save() end
23
+ def create_or_update_with_callbacks #:nodoc:
24
+ return false if callback(:before_save) == false
25
+ if result = create_or_update_without_callbacks
26
+ callback(:after_save)
27
+ end
28
+ result
29
+ end
30
+ private :create_or_update_with_callbacks
31
+
32
+ def before_create() end
33
+
34
+ def after_create() end
35
+ def create_with_callbacks #:nodoc:
36
+ return false if callback(:before_create) == false
37
+ result = create_without_callbacks
38
+ callback(:after_create)
39
+ result
40
+ end
41
+ private :create_with_callbacks
42
+
43
+ def before_update() end
44
+
45
+ def after_update() end
46
+
47
+ def update_with_callbacks(*args) #:nodoc:
48
+ return false if callback(:before_update) == false
49
+ result = update_without_callbacks(*args)
50
+ callback(:after_update)
51
+ result
52
+ end
53
+ private :update_with_callbacks
54
+
55
+ def before_validation() end
56
+
57
+ def after_validation() end
58
+
59
+ def before_validation_on_create() end
60
+
61
+ def after_validation_on_create() end
62
+
63
+ def before_validation_on_update() end
64
+
65
+ def after_validation_on_update() end
66
+
67
+ def valid_with_callbacks? #:nodoc:
68
+ return false if callback(:before_validation) == false
69
+ result = new? ? callback(:before_validation_on_create) : callback(:before_validation_on_update)
70
+ return false if false == result
71
+
72
+ result = valid_without_callbacks?
73
+ callback(:after_validation)
74
+
75
+ new? ? callback(:after_validation_on_create) : callback(:after_validation_on_update)
76
+ return result
77
+ end
78
+
79
+ def before_destroy() end
80
+
81
+ def after_destroy() end
82
+ def destroy_with_callbacks #:nodoc:
83
+ return false if callback(:before_destroy) == false
84
+ result = destroy_without_callbacks
85
+ callback(:after_destroy)
86
+ result
87
+ end
88
+
89
+ private
90
+ def callback(method)
91
+ result = run_callbacks(method) { |result, object| false == result }
92
+
93
+ if result != false && respond_to_without_attributes?(method)
94
+ result = send(method)
95
+ end
96
+
97
+ notify(method)
98
+ return result
99
+ end
100
+
101
+ def notify(method) #:nodoc:
102
+ self.class.changed
103
+ self.class.notify_observers(method, self)
104
+ end
105
+ end
106
+ end