mongoid_alize 0.2.0 → 0.3.1
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/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
|