mongoid_alize 0.2.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/config/locales/en.yml +1 -0
- data/lib/mongoid/alize/callback.rb +48 -13
- data/lib/mongoid/alize/callbacks/from/many.rb +5 -5
- data/lib/mongoid/alize/callbacks/from/one.rb +14 -31
- data/lib/mongoid/alize/errors/invalid_configuration.rb +16 -0
- data/lib/mongoid/alize/from_callback.rb +4 -2
- data/lib/mongoid/alize/instance_helpers.rb +25 -0
- data/lib/mongoid/alize/macros.rb +65 -42
- data/lib/mongoid/alize/to_callback.rb +104 -9
- data/lib/mongoid_alize.rb +3 -7
- data/spec/app/models/head.rb +17 -1
- data/spec/app/models/mock_object.rb +6 -0
- data/spec/app/models/person.rb +16 -0
- data/spec/helpers/macros_helper.rb +11 -7
- data/spec/mongoid/alize/callback_spec.rb +62 -6
- data/spec/mongoid/alize/callbacks/from/one_spec.rb +41 -43
- data/spec/mongoid/alize/callbacks/to/many_from_many_spec.rb +23 -17
- data/spec/mongoid/alize/callbacks/to/many_from_one_spec.rb +158 -60
- data/spec/mongoid/alize/callbacks/to/one_from_many_spec.rb +110 -42
- data/spec/mongoid/alize/callbacks/to/one_from_one_spec.rb +167 -47
- data/spec/mongoid/alize/instance_helpers_spec.rb +36 -0
- data/spec/mongoid/alize/macros_spec.rb +90 -17
- data/spec/mongoid/alize/to_callback_spec.rb +87 -18
- data/spec/mongoid_alize_spec.rb +245 -26
- data/spec/spec_helper.rb +3 -1
- metadata +6 -8
- data/lib/mongoid/alize/callbacks/to/many_from_many.rb +0 -16
- data/lib/mongoid/alize/callbacks/to/many_from_one.rb +0 -15
- data/lib/mongoid/alize/callbacks/to/one_from_many.rb +0 -15
- data/lib/mongoid/alize/callbacks/to/one_from_one.rb +0 -15
- data/lib/mongoid/alize/to_many_callback.rb +0 -50
- data/lib/mongoid/alize/to_one_callback.rb +0 -43
data/config/locales/en.yml
CHANGED
@@ -6,30 +6,34 @@ module Mongoid
|
|
6
6
|
|
7
7
|
attr_accessor :klass
|
8
8
|
attr_accessor :relation
|
9
|
-
attr_accessor :
|
9
|
+
attr_accessor :metadata
|
10
10
|
|
11
11
|
attr_accessor :inverse_klass
|
12
12
|
attr_accessor :inverse_relation
|
13
|
+
attr_accessor :inverse_metadata
|
14
|
+
|
15
|
+
attr_accessor :debug
|
13
16
|
|
14
17
|
def initialize(_klass, _relation, _fields)
|
18
|
+
self.debug = ENV["ALIZE_DEBUG"]
|
19
|
+
|
15
20
|
self.klass = _klass
|
16
21
|
self.relation = _relation
|
17
22
|
self.fields = _fields
|
18
23
|
|
19
|
-
self.
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
self.metadata = _klass.relations[_relation.to_s]
|
25
|
+
if !(self.metadata.polymorphic? &&
|
26
|
+
self.metadata.stores_foreign_key?)
|
27
|
+
self.inverse_klass = self.metadata.klass
|
28
|
+
self.inverse_relation = self.metadata.inverse
|
29
|
+
self.inverse_metadata = self.inverse_klass.relations[inverse_relation.to_s]
|
30
|
+
end
|
25
31
|
end
|
26
32
|
|
27
33
|
def attach
|
28
34
|
# implement in subclasses
|
29
35
|
end
|
30
36
|
|
31
|
-
protected
|
32
|
-
|
33
37
|
def callback_attached?(callback_type, callback_name)
|
34
38
|
!!klass.send(:"_#{callback_type}_callbacks").
|
35
39
|
map(&:raw_filter).include?(callback_name)
|
@@ -42,6 +46,7 @@ module Mongoid
|
|
42
46
|
def alias_callback
|
43
47
|
unless callback_defined?(aliased_callback_name)
|
44
48
|
klass.send(:alias_method, aliased_callback_name, callback_name)
|
49
|
+
klass.send(:public, aliased_callback_name)
|
45
50
|
end
|
46
51
|
end
|
47
52
|
|
@@ -53,13 +58,27 @@ module Mongoid
|
|
53
58
|
"denormalize_#{direction}_#{relation}"
|
54
59
|
end
|
55
60
|
|
56
|
-
def
|
57
|
-
|
61
|
+
def define_fields_method
|
62
|
+
_fields = fields
|
63
|
+
if fields.is_a?(Proc)
|
64
|
+
klass.send(:define_method, fields_method_name) do |inverse|
|
65
|
+
_fields.bind(self).call(inverse).map(&:to_s)
|
66
|
+
end
|
67
|
+
else
|
68
|
+
klass.send(:define_method, fields_method_name) do |inverse|
|
69
|
+
_fields.map(&:to_s)
|
70
|
+
end
|
71
|
+
end
|
58
72
|
end
|
59
73
|
|
60
|
-
def
|
74
|
+
def fields_method_name
|
75
|
+
"#{callback_name}_fields"
|
76
|
+
end
|
77
|
+
|
78
|
+
def field_values(source, options={})
|
79
|
+
extras = options[:id] ? "['_id']" : "[]"
|
61
80
|
<<-RUBY
|
62
|
-
|
81
|
+
(#{fields_method_name}(#{source}) + #{extras}).inject({}) { |hash, name|
|
63
82
|
hash[name] = #{source}.send(name)
|
64
83
|
hash
|
65
84
|
}
|
@@ -73,6 +92,22 @@ module Mongoid
|
|
73
92
|
def force_check
|
74
93
|
"force || self.force_denormalization"
|
75
94
|
end
|
95
|
+
|
96
|
+
def fields_to_s
|
97
|
+
if fields.is_a?(Proc)
|
98
|
+
"Proc Given"
|
99
|
+
else
|
100
|
+
fields.join(", ")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def to_s
|
105
|
+
"#{self.class.name}" +
|
106
|
+
"\nModel: #{self.klass}, Relation: #{self.relation}" + (self.metadata.polymorphic? ?
|
107
|
+
"\nPolymorphic" :
|
108
|
+
"\nInverse: #{self.inverse_klass}, Relation: #{self.inverse_relation}") +
|
109
|
+
"\nFields: #{fields_to_s}"
|
110
|
+
end
|
76
111
|
end
|
77
112
|
end
|
78
113
|
end
|
@@ -9,10 +9,12 @@ module Mongoid
|
|
9
9
|
def define_callback
|
10
10
|
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
|
11
11
|
def #{callback_name}#{force_param}
|
12
|
-
self.#{prefixed_name} = self.#{relation}.map do |
|
13
|
-
#{
|
12
|
+
self.#{prefixed_name} = self.#{relation}.map do |relation|
|
13
|
+
#{field_values("relation", :id => true)}
|
14
14
|
end
|
15
|
+
true
|
15
16
|
end
|
17
|
+
|
16
18
|
protected :#{callback_name}
|
17
19
|
CALLBACK
|
18
20
|
end
|
@@ -22,10 +24,8 @@ module Mongoid
|
|
22
24
|
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
|
23
25
|
field :#{prefixed_name}, :type => Array, :default => []
|
24
26
|
CALLBACK
|
25
|
-
end
|
26
27
|
|
27
|
-
|
28
|
-
"#{relation}_fields"
|
28
|
+
define_fields_method
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -7,19 +7,18 @@ module Mongoid
|
|
7
7
|
protected
|
8
8
|
|
9
9
|
def define_callback
|
10
|
-
field_sets = ""
|
11
|
-
fields.each do |name|
|
12
|
-
field_sets << "self.send(:#{prefixed_field_name(name)}=,
|
13
|
-
relation && relation.send(:#{name}))\n"
|
14
|
-
end
|
15
|
-
|
16
10
|
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
|
17
11
|
def #{callback_name}#{force_param}
|
18
12
|
if #{force_check} ||
|
19
|
-
#{!
|
20
|
-
|
21
|
-
|
22
|
-
|
13
|
+
#{!metadata.stores_foreign_key?} ||
|
14
|
+
self.#{metadata.key}_changed?
|
15
|
+
|
16
|
+
if relation = self.#{relation}
|
17
|
+
self.#{self.prefixed_name} = #{field_values("relation")}
|
18
|
+
else
|
19
|
+
self.#{self.prefixed_name} = nil
|
20
|
+
end
|
21
|
+
|
23
22
|
end
|
24
23
|
true
|
25
24
|
end
|
@@ -29,28 +28,12 @@ module Mongoid
|
|
29
28
|
end
|
30
29
|
|
31
30
|
def define_fields
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
field :#{prefixed_name}, :type => #{inverse_field_type(name)}
|
37
|
-
CALLBACK
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def prefixed_field_name(name)
|
43
|
-
"#{relation}_#{name}"
|
44
|
-
end
|
45
|
-
|
46
|
-
def inverse_field_type(name)
|
47
|
-
name = name.to_s
|
48
|
-
|
49
|
-
name = "_id" if name == "id"
|
50
|
-
name = "_type" if name == "type"
|
31
|
+
ensure_field_not_defined!(prefixed_name, klass)
|
32
|
+
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
|
33
|
+
field :#{prefixed_name}, :type => Hash, :default => nil
|
34
|
+
CALLBACK
|
51
35
|
|
52
|
-
|
53
|
-
(field && field.options[:type]) ? field.type : String
|
36
|
+
define_fields_method
|
54
37
|
end
|
55
38
|
end
|
56
39
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Alize
|
3
|
+
module Errors
|
4
|
+
|
5
|
+
class InvalidConfiguration < AlizeError
|
6
|
+
def initialize(reason, klass, relation)
|
7
|
+
super(
|
8
|
+
translate("invalid_configuration.#{reason}",
|
9
|
+
{ :klass => klass, :relation => relation })
|
10
|
+
)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -10,8 +10,6 @@ module Mongoid
|
|
10
10
|
set_callback
|
11
11
|
end
|
12
12
|
|
13
|
-
protected
|
14
|
-
|
15
13
|
def set_callback
|
16
14
|
unless callback_attached?("save", aliased_callback_name)
|
17
15
|
klass.set_callback(:save, :before, aliased_callback_name)
|
@@ -28,6 +26,10 @@ module Mongoid
|
|
28
26
|
!!klass.fields[prefixed_name]
|
29
27
|
end
|
30
28
|
|
29
|
+
def prefixed_name
|
30
|
+
"#{relation}_fields"
|
31
|
+
end
|
32
|
+
|
31
33
|
def direction
|
32
34
|
"from"
|
33
35
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Alize
|
3
|
+
module InstanceHelpers
|
4
|
+
|
5
|
+
attr_accessor :force_denormalization
|
6
|
+
|
7
|
+
def denormalize_from_all
|
8
|
+
run_alize_callbacks(self.class.alize_from_callbacks)
|
9
|
+
end
|
10
|
+
|
11
|
+
def denormalize_to_all
|
12
|
+
run_alize_callbacks(self.class.alize_to_callbacks)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def run_alize_callbacks(callbacks)
|
18
|
+
callbacks.each do |callback|
|
19
|
+
self.send(callback.aliased_callback_name)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/mongoid/alize/macros.rb
CHANGED
@@ -2,67 +2,90 @@ module Mongoid
|
|
2
2
|
module Alize
|
3
3
|
module Macros
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
fields = default_alize_fields(relation) if fields.empty?
|
8
|
-
|
9
|
-
one = Mongoid::Relations::One
|
10
|
-
many = Mongoid::Relations::Many
|
5
|
+
attr_accessor :alize_from_callbacks, :alize_to_callbacks
|
11
6
|
|
12
|
-
|
13
|
-
|
14
|
-
|
7
|
+
def alize(relation, *fields)
|
8
|
+
alize_from(relation, *fields)
|
9
|
+
metadata = self.relations[relation.to_s]
|
10
|
+
unless _alize_unknown_inverse?(metadata)
|
11
|
+
metadata.klass.alize_to(metadata.inverse, *fields)
|
15
12
|
end
|
13
|
+
end
|
16
14
|
|
17
|
-
|
18
|
-
|
15
|
+
def alize_from(relation, *fields)
|
16
|
+
one, many = _alize_relation_types
|
19
17
|
|
20
18
|
from_one = Mongoid::Alize::Callbacks::From::One
|
21
19
|
from_many = Mongoid::Alize::Callbacks::From::Many
|
22
20
|
|
23
|
-
|
21
|
+
klass = self
|
22
|
+
metadata = klass.relations[relation.to_s]
|
23
|
+
relation_superclass = metadata.relation.superclass
|
24
|
+
|
24
25
|
callback_klass =
|
25
26
|
case [relation_superclass]
|
26
27
|
when [one] then from_one
|
27
28
|
when [many] then from_many
|
28
29
|
end
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
new(inverse_klass, inverse_relation, fields).
|
56
|
-
attach
|
31
|
+
options = fields.extract_options!
|
32
|
+
if options[:fields]
|
33
|
+
fields = options[:fields]
|
34
|
+
elsif fields.empty? && !_alize_unknown_inverse?(metadata)
|
35
|
+
fields = metadata.klass.default_alize_fields
|
36
|
+
end
|
37
|
+
|
38
|
+
(klass.alize_from_callbacks ||= []) << callback =
|
39
|
+
callback_klass.new(klass, relation, fields)
|
40
|
+
callback.attach
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
def alize_to(relation, *fields)
|
45
|
+
one, many = _alize_relation_types
|
46
|
+
|
47
|
+
klass = self
|
48
|
+
metadata = klass.relations[relation.to_s]
|
49
|
+
relation_superclass = metadata.relation.superclass
|
50
|
+
|
51
|
+
options = fields.extract_options!
|
52
|
+
if options[:fields]
|
53
|
+
fields = options[:fields]
|
54
|
+
elsif fields.empty?
|
55
|
+
fields = klass.default_alize_fields
|
57
56
|
end
|
57
|
+
|
58
|
+
(klass.alize_to_callbacks ||= []) << callback =
|
59
|
+
Mongoid::Alize::ToCallback.new(klass, relation, fields)
|
60
|
+
callback.attach
|
61
|
+
|
58
62
|
end
|
59
63
|
|
60
|
-
def default_alize_fields
|
61
|
-
self.
|
62
|
-
fields.reject { |name, field|
|
64
|
+
def default_alize_fields
|
65
|
+
self.fields.reject { |name, field|
|
63
66
|
name =~ /^_/
|
64
67
|
}.keys
|
65
68
|
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def _alize_unknown_inverse?(metadata)
|
73
|
+
(metadata.polymorphic? && metadata.stores_foreign_key?) ||
|
74
|
+
metadata.klass.nil? ||
|
75
|
+
metadata.inverse.nil?
|
76
|
+
end
|
77
|
+
|
78
|
+
def _alize_relation_types
|
79
|
+
one = Mongoid::Relations::One
|
80
|
+
many = Mongoid::Relations::Many
|
81
|
+
|
82
|
+
def (many = many.dup).==(klass)
|
83
|
+
[Mongoid::Relations::Many,
|
84
|
+
Mongoid::Relations::Referenced::Many].map(&:name).include?(klass.name)
|
85
|
+
end
|
86
|
+
|
87
|
+
[one, many]
|
88
|
+
end
|
66
89
|
end
|
67
90
|
end
|
68
91
|
end
|
@@ -3,6 +3,8 @@ module Mongoid
|
|
3
3
|
class ToCallback < Callback
|
4
4
|
|
5
5
|
def attach
|
6
|
+
define_fields
|
7
|
+
|
6
8
|
define_callback
|
7
9
|
alias_callback
|
8
10
|
set_callback
|
@@ -12,7 +14,107 @@ module Mongoid
|
|
12
14
|
set_destroy_callback
|
13
15
|
end
|
14
16
|
|
15
|
-
|
17
|
+
def define_callback
|
18
|
+
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
|
19
|
+
|
20
|
+
def #{callback_name}#{force_param}
|
21
|
+
|
22
|
+
#{iterable_relation}.each do |relation|
|
23
|
+
next if relation.attributes.frozen?
|
24
|
+
|
25
|
+
is_one = #{is_one?}
|
26
|
+
if is_one
|
27
|
+
field_values = #{field_values("self")}
|
28
|
+
else
|
29
|
+
field_values = #{field_values("self", :id => true)}
|
30
|
+
end
|
31
|
+
|
32
|
+
prefixed_name = #{prefixed_name}
|
33
|
+
if is_one
|
34
|
+
relation.set(prefixed_name, field_values)
|
35
|
+
else
|
36
|
+
#{pull_from_inverse}
|
37
|
+
relation.push(prefixed_name, field_values)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
#{debug ? "puts \"#{callback_name}\"": ""}
|
43
|
+
true
|
44
|
+
end
|
45
|
+
protected :#{callback_name}
|
46
|
+
CALLBACK
|
47
|
+
end
|
48
|
+
|
49
|
+
def define_destroy_callback
|
50
|
+
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
|
51
|
+
|
52
|
+
def #{destroy_callback_name}
|
53
|
+
#{iterable_relation}.each do |relation|
|
54
|
+
next if relation.attributes.frozen?
|
55
|
+
|
56
|
+
is_one = #{is_one?}
|
57
|
+
prefixed_name = #{prefixed_name}
|
58
|
+
if is_one
|
59
|
+
relation.set(prefixed_name, nil)
|
60
|
+
else
|
61
|
+
#{pull_from_inverse}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
#{debug ? "puts \"#{destroy_callback_name}\"": ""}
|
66
|
+
true
|
67
|
+
end
|
68
|
+
protected :#{destroy_callback_name}
|
69
|
+
CALLBACK
|
70
|
+
end
|
71
|
+
|
72
|
+
def pull_from_inverse
|
73
|
+
<<-RUBIES
|
74
|
+
relation.pull(prefixed_name, { "_id" => self.id })
|
75
|
+
if _f = relation.send(prefixed_name)
|
76
|
+
_f.reject! do |hash|
|
77
|
+
hash["_id"] == self.id
|
78
|
+
end
|
79
|
+
end
|
80
|
+
RUBIES
|
81
|
+
end
|
82
|
+
|
83
|
+
def prefixed_name
|
84
|
+
if inverse_relation
|
85
|
+
":#{inverse_relation}_fields"
|
86
|
+
else
|
87
|
+
<<-RUBIES
|
88
|
+
(#{find_relation}[0].to_s + '_fields')
|
89
|
+
RUBIES
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def is_one?
|
94
|
+
if inverse_relation
|
95
|
+
if self.inverse_metadata.relation.superclass == Mongoid::Relations::One
|
96
|
+
"true"
|
97
|
+
else
|
98
|
+
"false"
|
99
|
+
end
|
100
|
+
else
|
101
|
+
<<-RUBIES
|
102
|
+
(#{find_relation}[1].relation.superclass == Mongoid::Relations::One)
|
103
|
+
RUBIES
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def find_relation
|
108
|
+
"relation.class.relations.find { |name, metadata| metadata.inverse == :#{relation} && metadata.class_name == self.class.name }"
|
109
|
+
end
|
110
|
+
|
111
|
+
def iterable_relation
|
112
|
+
"[self.#{relation}].flatten.compact"
|
113
|
+
end
|
114
|
+
|
115
|
+
def define_fields
|
116
|
+
define_fields_method
|
117
|
+
end
|
16
118
|
|
17
119
|
def set_callback
|
18
120
|
unless callback_attached?("save", aliased_callback_name)
|
@@ -29,6 +131,7 @@ module Mongoid
|
|
29
131
|
def alias_destroy_callback
|
30
132
|
unless callback_defined?(aliased_destroy_callback_name)
|
31
133
|
klass.send(:alias_method, aliased_destroy_callback_name, destroy_callback_name)
|
134
|
+
klass.send(:public, aliased_destroy_callback_name)
|
32
135
|
end
|
33
136
|
end
|
34
137
|
|
@@ -40,14 +143,6 @@ module Mongoid
|
|
40
143
|
"_#{aliased_destroy_callback_name}"
|
41
144
|
end
|
42
145
|
|
43
|
-
def plain_relation
|
44
|
-
"self.#{relation}"
|
45
|
-
end
|
46
|
-
|
47
|
-
def surrounded_relation
|
48
|
-
"self.#{relation} ? [self.#{relation}] : []"
|
49
|
-
end
|
50
|
-
|
51
146
|
def direction
|
52
147
|
"to"
|
53
148
|
end
|