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.
Files changed (32) hide show
  1. data/config/locales/en.yml +1 -0
  2. data/lib/mongoid/alize/callback.rb +48 -13
  3. data/lib/mongoid/alize/callbacks/from/many.rb +5 -5
  4. data/lib/mongoid/alize/callbacks/from/one.rb +14 -31
  5. data/lib/mongoid/alize/errors/invalid_configuration.rb +16 -0
  6. data/lib/mongoid/alize/from_callback.rb +4 -2
  7. data/lib/mongoid/alize/instance_helpers.rb +25 -0
  8. data/lib/mongoid/alize/macros.rb +65 -42
  9. data/lib/mongoid/alize/to_callback.rb +104 -9
  10. data/lib/mongoid_alize.rb +3 -7
  11. data/spec/app/models/head.rb +17 -1
  12. data/spec/app/models/mock_object.rb +6 -0
  13. data/spec/app/models/person.rb +16 -0
  14. data/spec/helpers/macros_helper.rb +11 -7
  15. data/spec/mongoid/alize/callback_spec.rb +62 -6
  16. data/spec/mongoid/alize/callbacks/from/one_spec.rb +41 -43
  17. data/spec/mongoid/alize/callbacks/to/many_from_many_spec.rb +23 -17
  18. data/spec/mongoid/alize/callbacks/to/many_from_one_spec.rb +158 -60
  19. data/spec/mongoid/alize/callbacks/to/one_from_many_spec.rb +110 -42
  20. data/spec/mongoid/alize/callbacks/to/one_from_one_spec.rb +167 -47
  21. data/spec/mongoid/alize/instance_helpers_spec.rb +36 -0
  22. data/spec/mongoid/alize/macros_spec.rb +90 -17
  23. data/spec/mongoid/alize/to_callback_spec.rb +87 -18
  24. data/spec/mongoid_alize_spec.rb +245 -26
  25. data/spec/spec_helper.rb +3 -1
  26. metadata +6 -8
  27. data/lib/mongoid/alize/callbacks/to/many_from_many.rb +0 -16
  28. data/lib/mongoid/alize/callbacks/to/many_from_one.rb +0 -15
  29. data/lib/mongoid/alize/callbacks/to/one_from_many.rb +0 -15
  30. data/lib/mongoid/alize/callbacks/to/one_from_one.rb +0 -15
  31. data/lib/mongoid/alize/to_many_callback.rb +0 -50
  32. data/lib/mongoid/alize/to_one_callback.rb +0 -43
@@ -1,23 +1,18 @@
1
1
  require 'mongoid/alize/errors/alize_error'
2
2
  require 'mongoid/alize/errors/invalid_field'
3
3
  require 'mongoid/alize/errors/already_defined_field'
4
+ require 'mongoid/alize/errors/invalid_configuration'
4
5
 
5
6
  require 'mongoid/alize/callback'
6
7
 
7
8
  require 'mongoid/alize/from_callback.rb'
8
9
  require 'mongoid/alize/to_callback.rb'
9
- require 'mongoid/alize/to_one_callback.rb'
10
- require 'mongoid/alize/to_many_callback.rb'
11
10
 
12
11
  require 'mongoid/alize/callbacks/from/one.rb'
13
12
  require 'mongoid/alize/callbacks/from/many.rb'
14
13
 
15
- require 'mongoid/alize/callbacks/to/one_from_one.rb'
16
- require 'mongoid/alize/callbacks/to/one_from_many.rb'
17
- require 'mongoid/alize/callbacks/to/many_from_one.rb'
18
- require 'mongoid/alize/callbacks/to/many_from_many.rb'
19
-
20
14
  require 'mongoid/alize/macros'
15
+ require 'mongoid/alize/instance_helpers'
21
16
 
22
17
  I18n.load_path << File.join(File.dirname(__FILE__), "..", "config", "locales", "en.yml")
23
18
 
@@ -27,6 +22,7 @@ module Mongoid
27
22
 
28
23
  included do
29
24
  extend Mongoid::Alize::Macros
25
+ include Mongoid::Alize::InstanceHelpers
30
26
  end
31
27
  end
32
28
  end
@@ -8,7 +8,7 @@ class Head
8
8
  # to whom it's attached
9
9
  belongs_to :person
10
10
 
11
- # in who's possession it is
11
+ # in whose possession it is
12
12
  belongs_to :captor, :class_name => "Person", :inverse_of => :heads
13
13
 
14
14
  # who'd otherwise like to possess it
@@ -20,7 +20,23 @@ class Head
20
20
  # a relation with no inverse
21
21
  has_many :admirer, :class_name => "Person", :inverse_of => nil
22
22
 
23
+ # a polymorphic one-to-one relation
24
+ belongs_to :nearest, :polymorphic => true
25
+
26
+ # a polymorphic one-to-many relation
27
+ has_many :below_people, :class_name => "Person", :as => :above
28
+
23
29
  def density
24
30
  "low"
25
31
  end
32
+
33
+ # example of one way to handling attribute selection
34
+ # for polymorphic associations or generally using the proc fields option
35
+ def alize_fields(inverse)
36
+ if inverse.is_a?(Person)
37
+ [:name, :location]
38
+ else
39
+ [:id]
40
+ end
41
+ end
26
42
  end
@@ -0,0 +1,6 @@
1
+ # explicit mock object class due to this issue - https://github.com/btakita/rr/issues/44
2
+ class MockObject
3
+ def to_ary
4
+ nil
5
+ end
6
+ end
@@ -17,8 +17,24 @@ class Person
17
17
  # the only head that is watching
18
18
  belongs_to :seen_by, :class_name => "Head", :inverse_of => :sees
19
19
 
20
+ # a polymorphic one-to-one relation
21
+ has_one :nearest_head, :class_name => "Head", :as => :nearest
22
+
23
+ # a polymorphic one-to-many relation
24
+ belongs_to :above, :polymorphic => true
25
+
20
26
  def location
21
27
  "Paris"
22
28
  end
29
+
30
+ # example of one way to handling attribute selection
31
+ # for polymorphic associations or generally using the proc fields option
32
+ def alize_fields(inverse)
33
+ if inverse.is_a?(Head)
34
+ [:size]
35
+ else
36
+ [:id]
37
+ end
38
+ end
23
39
  end
24
40
 
@@ -9,15 +9,15 @@ module MacrosHelper
9
9
  end
10
10
 
11
11
  def tns
12
- Mongoid::Alize::Callbacks::To
12
+ Mongoid::Alize::ToCallback
13
13
  end
14
14
 
15
15
  def it_should_set_callbacks(klass, inverse_klass, relation, inverse_relation, fns, tns)
16
16
  fields = [:fake]
17
17
 
18
18
  it "should use #{fns} to pull" do
19
- obj_mock = Object.new
20
- obj_stub = Object.new
19
+ obj_mock = MockObject.new
20
+ obj_stub = MockObject.new
21
21
 
22
22
  stub(tns).new { obj_stub }
23
23
  stub(obj_stub).attach
@@ -25,12 +25,14 @@ module MacrosHelper
25
25
 
26
26
  mock(fns).new(klass, relation, fields) { obj_mock }
27
27
  mock(obj_mock).attach
28
- klass.send(:alize, relation, *fields)
28
+ klass.send(:alize_from, relation, *fields)
29
+
30
+ klass.alize_from_callbacks.should == [obj_mock]
29
31
  end
30
32
 
31
33
  it "should use #{tns} to push" do
32
- obj_stub = Object.new
33
- obj_mock = Object.new
34
+ obj_stub = MockObject.new
35
+ obj_mock = MockObject.new
34
36
 
35
37
  stub(fns).new { obj_stub }
36
38
  stub(obj_stub).attach
@@ -38,7 +40,9 @@ module MacrosHelper
38
40
 
39
41
  mock(tns).new(inverse_klass, inverse_relation, fields) { obj_mock }
40
42
  mock(obj_mock).attach
41
- klass.send(:alize, relation, *fields)
43
+ inverse_klass.send(:alize_to, inverse_relation, *fields)
44
+
45
+ inverse_klass.alize_to_callbacks.should == [obj_mock]
42
46
  end
43
47
  end
44
48
  end
@@ -33,24 +33,32 @@ describe Mongoid::Alize::Callback do
33
33
  callback.relation.should == :person
34
34
  callback.inverse_klass = Person
35
35
  callback.inverse_relation = :head
36
+ callback.inverse_metadata.should == Person.relations["head"]
36
37
  callback.fields.should == [:name, :created_at]
37
38
  end
38
39
 
39
- it "should add force_denormalization attribute to klass and inverse klass" do
40
- callback = new_callback
41
- Head.new.force_denormalization = true
42
- Person.new.force_denormalization = true
40
+ it "should not set inverses for the child in a polymorphic association" do
41
+ callback = klass.new(Head, :nearest, [:size])
42
+ callback.inverse_klass.should be_nil
43
+ callback.inverse_relation.should be_nil
44
+ end
45
+
46
+ it "should set inverses for the parent in a polymorphic association" do
47
+ callback = klass.new(Person, :nearest_head, [:size])
48
+ callback.inverse_klass.should == Head
49
+ callback.inverse_relation.should == :nearest
43
50
  end
44
51
  end
45
52
 
46
- describe "with callback " do
53
+ describe "with callback" do
47
54
  before do
48
55
  @callback = new_callback
49
56
  end
50
57
 
51
58
  describe "#alias_callback" do
52
- it "should alias the callback on the klass" do
59
+ it "should alias the callback on the klass and make it public" do
53
60
  mock(@callback.klass).alias_method("denormalize_spec_person", "_denormalize_spec_person")
61
+ mock(@callback.klass).public("denormalize_spec_person")
54
62
  @callback.send(:alias_callback)
55
63
  end
56
64
 
@@ -61,5 +69,53 @@ describe Mongoid::Alize::Callback do
61
69
  end
62
70
  end
63
71
  end
72
+
73
+ describe "name helpers" do
74
+ before do
75
+ @callback = new_callback
76
+ end
77
+
78
+ it "should have a callback name" do
79
+ @callback.callback_name.should == "_denormalize_spec_person"
80
+ end
81
+
82
+ it "should have aliased callback name" do
83
+ @callback.aliased_callback_name.should == "denormalize_spec_person"
84
+ end
85
+
86
+ it "should add _fields to the callback name" do
87
+ @callback.fields_method_name.should == "_denormalize_spec_person_fields"
88
+ end
89
+ end
90
+
91
+ describe "define fields method" do
92
+ def define_fields_method
93
+ @callback.send(:define_fields_method)
94
+ end
95
+
96
+ describe "when fields is an array" do
97
+ before do
98
+ @callback = new_callback
99
+ end
100
+
101
+ it "should return the fields w/ to_s applied" do
102
+ define_fields_method
103
+ @head = Head.new
104
+ @head.send("_denormalize_spec_person_fields", nil).should == ["name", "created_at"]
105
+ end
106
+ end
107
+
108
+ describe "when fields is a proc" do
109
+ before do
110
+ @callback = klass.new(Head, :person, lambda { |inverse| [:name, :created_at] })
111
+ end
112
+
113
+ it "should return the fields w/ to_s applied" do
114
+ define_fields_method
115
+ @head = Head.new
116
+ @head.send("_denormalize_spec_person_fields", Person.new).should == ["name", "created_at"]
117
+ end
118
+ end
119
+ end
64
120
  end
65
121
 
@@ -14,39 +14,29 @@ describe Mongoid::Alize::Callbacks::From::One do
14
14
  end
15
15
 
16
16
  describe "#define_fields" do
17
- it "should add properly typed, prefixed fields from the relation" do
18
- callback = klass.new(Head, :person, [:name, :created_at])
19
- callback.send(:define_fields)
20
- Head.fields["person_name"].type.should == String
21
- Head.fields["person_created_at"].type.should == Time
22
- end
23
-
24
- it "should define as a string field that's not defined" do
25
- callback = klass.new(Head, :person, [:location])
26
- callback.send(:define_fields)
27
- Head.fields["person_location"].type.should == String
28
- end
29
-
30
- it "should not add the field if the field already exists" do
31
- Head.class_eval do
32
- field :person_name
17
+ describe "with an array of fields" do
18
+ it "should add a field generated from %{relation}_fields" do
19
+ callback = new_callback
20
+ callback.send(:define_fields)
21
+ Head.fields["person_fields"].type.should == Hash
33
22
  end
34
- callback = klass.new(Head, :person, [:name])
35
- dont_allow(Head).field
36
- callback.send(:define_fields)
37
- end
38
23
 
39
- it "should not add the field if it already exists b/c of another relation" do
40
- callback = klass.new(Head, :person, [:id])
41
- dont_allow(Head).field
42
- callback.send(:define_fields)
43
- end
24
+ it "should default the field to nil" do
25
+ callback = new_callback
26
+ callback.send(:define_fields)
27
+ Head.new.person_fields.should be_nil
28
+ end
44
29
 
45
- it "should allow the id and type of the inverse to be denormalized without an extra _" do
46
- callback = klass.new(Person, :head, [:id, :type])
47
- callback.send(:define_fields)
48
- Person.fields["head_id"].type.should == BSON::ObjectId
49
- Person.fields["head_type"].type.should == String
30
+ it "should raise an already defined field error if the field already exists" do
31
+ Head.class_eval do
32
+ field :person_fields
33
+ end
34
+ callback = new_callback
35
+ expect {
36
+ callback.send(:define_fields)
37
+ }.to raise_error(Mongoid::Alize::Errors::AlreadyDefinedField,
38
+ "person_fields is already defined on the Head model.")
39
+ end
50
40
  end
51
41
  end
52
42
 
@@ -55,37 +45,43 @@ describe Mongoid::Alize::Callbacks::From::One do
55
45
  @head.send(:_denormalize_from_person, force)
56
46
  end
57
47
 
58
- before do
48
+ def person_fields
49
+ { "name"=> "Bob",
50
+ "location" => "Paris",
51
+ "created_at"=> @now.to_s(:utc) }
52
+ end
53
+
54
+ def create_models
59
55
  @head = Head.create
60
56
  @person = Person.create(:name => @name = "Bob",
61
57
  :created_at => @now = Time.now)
58
+ end
62
59
 
60
+ before do
63
61
  @callback = new_callback
64
62
  @callback.send(:define_fields)
63
+ create_models
65
64
  @callback.send(:define_callback)
66
-
67
- @head.relations["person"].should be_stores_foreign_key
68
65
  end
69
66
 
70
67
  it "should set fields from a changed relation" do
71
68
  @head.person = @person
72
69
  @head.should be_person_id_changed
73
70
  run_callback
74
- @head.person_name.should == @name
75
- @head.person_created_at.to_i.should == @now.to_i
76
- @head.person_location.should == "Paris"
71
+ @head.person_fields.should == person_fields
77
72
  end
78
73
 
79
- it "should assign nil values if the changed relation is nil" do
74
+ it "should set no fields from a nil relation" do
80
75
  @head.person = @person
81
76
  @head.save!
82
77
  @head.person = nil
83
78
  @head.should be_person_id_changed
84
79
  run_callback
85
- @head.person_name.should be_nil
80
+ @head.person_fields.should == nil
86
81
  end
87
82
 
88
83
  it "should not run if the relation has not changed" do
84
+ @head.relations["person"].should be_stores_foreign_key
89
85
  @head.should_not be_person_id_changed
90
86
  dont_allow(@head).person
91
87
  run_callback
@@ -111,20 +107,22 @@ describe Mongoid::Alize::Callbacks::From::One do
111
107
  end
112
108
 
113
109
  before do
110
+ @callback = klass.new(Person, :head, [:size])
111
+ @callback.send(:define_fields)
112
+
114
113
  @person = Person.create
115
114
  @head = Head.create(:size => 5)
116
115
 
117
- @callback = klass.new(Person, :head, [:size])
118
- @callback.send(:define_fields)
119
116
  @callback.send(:define_callback)
120
-
121
117
  @person.relations["head"].should_not be_stores_foreign_key
122
118
  end
123
119
 
124
120
  it "should set values from a changed relation" do
125
121
  @person.head = @head
126
122
  run_callback
127
- @person.head_size.should == 5
123
+ @person.head_fields.should == {
124
+ "size" => 5
125
+ }
128
126
  end
129
127
 
130
128
  it "should set values from a a nil relation" do
@@ -132,7 +130,7 @@ describe Mongoid::Alize::Callbacks::From::One do
132
130
  @person.save!
133
131
  @person.head = nil
134
132
  run_callback
135
- @person.head_size.should be_nil
133
+ @person.head_fields.should be_nil
136
134
  end
137
135
 
138
136
  it "should run even if the relation has not changed" do
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Mongoid::Alize::Callbacks::To::ManyFromMany do
3
+ describe Mongoid::Alize::ToCallback do
4
4
  def klass
5
- Mongoid::Alize::Callbacks::To::ManyFromMany
5
+ Mongoid::Alize::ToCallback
6
6
  end
7
7
 
8
8
  def args
@@ -24,30 +24,33 @@ describe Mongoid::Alize::Callbacks::To::ManyFromMany do
24
24
  { "_id" => "SomeObjectId" }
25
25
  end
26
26
 
27
- before do
28
- Head.class_eval do
29
- field :wanted_by_fields, type: Array
30
- end
31
-
27
+ def create_models
32
28
  @head = Head.create(
33
29
  :wanted_by => [@person = Person.create(:name => "Bob",
34
30
  :created_at => @now = Time.now)])
35
31
  @person.wants = [@head]
36
-
37
- @callback = new_callback
38
32
  end
39
33
 
40
- describe "#define_callback" do
41
- before do
42
- @callback.send(:define_callback)
34
+ before do
35
+ Head.class_eval do
36
+ field :wanted_by_fields, type: Array, :default => []
43
37
  end
38
+ end
44
39
 
40
+ describe "#define_callback" do
45
41
  def run_callback
46
42
  @person.send(:_denormalize_to_wants)
47
43
  end
48
44
 
45
+ before do
46
+ @callback = new_callback
47
+ @callback.send(:define_fields)
48
+ create_models
49
+ @callback.send(:define_callback)
50
+ end
51
+
49
52
  it "should push the fields to the relation" do
50
- @head.wanted_by_fields.should be_nil
53
+ @head.wanted_by_fields.should == []
51
54
  run_callback
52
55
  @head.wanted_by_fields.should == [wanted_by_fields]
53
56
  end
@@ -67,14 +70,17 @@ describe Mongoid::Alize::Callbacks::To::ManyFromMany do
67
70
  end
68
71
 
69
72
  describe "#define_destroy_callback" do
70
- before do
71
- @callback.send(:define_destroy_callback)
72
- end
73
-
74
73
  def run_destroy_callback
75
74
  @person.send(:_denormalize_destroy_to_wants)
76
75
  end
77
76
 
77
+ before do
78
+ @callback = new_callback
79
+ @callback.send(:define_fields)
80
+ create_models
81
+ @callback.send(:define_destroy_callback)
82
+ end
83
+
78
84
  it "should pull first any existing array entries matching the _id" do
79
85
  @head.wanted_by_fields = [wanted_by_fields, other_wanted_by]
80
86
  @head.save!