patriarch 0.1.0 → 0.2.0

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/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  redis_reclip_cleaner.rb
2
2
  spec/dummy
3
+ stats.svg
3
4
  *.gem
4
5
  *.rbc
5
6
  *.swp
@@ -1,13 +1,25 @@
1
1
  require 'verbs'
2
2
  require 'patriarch'
3
3
 
4
+
4
5
  module Patriarch
6
+
7
+ # Patriarch::Behaviours is meant to be included into any class we want to enhance with Patriarch handled behaviours
8
+ # Thus it defines the +included+ hook so we enhance the class in which it is included freely and add to
9
+ # it some class methods defined into Patriarch::Behaviours::ClassMethods
10
+ # We define there the +add_behaviour+ method that does three things :
11
+ # * it generates an anonymous module containing tool methods defined ad-hoc in function of the arguments supplied
12
+ # * it includes another module that lives into a generated file in lib/ allowing us to override existing methods or add new ones if we wish
13
+ # * it defines instance methods for the class allowing instances to call behaviour actions
5
14
  module Behaviours
6
15
 
16
+ # Exception raised when +add_behaviour+ declaration in a class has wrong syntax
7
17
  class AddBehaviourSyntaxError < Exception ; end
18
+ class AddBehaviourDependencyError < Exception ; end
8
19
 
9
20
  class << self
10
21
 
22
+ # Helper function to complete the anonymous module we include later in the process in the enhanced model class
11
23
  def complete_custom_active_module_bipartite(module_to_complete,relation_type,acted_on_model_list)
12
24
  module_to_complete.class_eval do
13
25
 
@@ -123,7 +135,25 @@ module Patriarch
123
135
 
124
136
  def included(klass)
125
137
  klass.extend ClassMethods
126
- klass.extend ActiveModel::Callbacks
138
+ #klass.extend ActiveModel::Callbacks
139
+ unless klass.respond_to?(:before_destroy) && klass.respond_to?(:after_destroy)
140
+ raise AddBehaviourDependencyError, "class #{klass.name} including Patriarch::Behaviours does not support callbacks"
141
+ end
142
+
143
+ klass.class_eval do
144
+
145
+ before_destroy :compute_redis_dependencies
146
+ def compute_redis_dependencies
147
+ @redis_destroy_transac_object = Patriarch::ToolServices::RedisCleanerService.instance.clean_all(self)
148
+ end
149
+
150
+ after_destroy :clean_redis_dependencies
151
+ def clean_redis_dependencies
152
+ @redis_destroy_transac_object.execute
153
+ end
154
+
155
+ end
156
+
127
157
  class << klass;
128
158
  # not sure if should add an alias like behaviours here
129
159
  # might override other behaviour methods from other namespaces
@@ -213,7 +243,34 @@ module Patriarch
213
243
  self.send(:include,methods_mod)
214
244
  # include in which we can overwite the methods of the previous custom module included there ...
215
245
  self.send(:include,"Patriarch::Behaviours::#{behaviour.classify}::ToolsMethods".constantize)
246
+ # TODO disjonction register tripartite
247
+ # register the behaviour we just added
248
+ self.patriarch_behaviours ||= { }
249
+
250
+ if options[:via]
251
+ self.patriarch_behaviours[behaviour.underscore.to_sym] ||= { :on => [], :by => [], :via => [] }
252
+ elsif options[:medium_between]
253
+ self.patriarch_behaviours[behaviour.underscore.to_sym] ||= { :medium_between => [] }
254
+ end
216
255
 
256
+ if options[:via]
257
+ if options[:on]
258
+ self.patriarch_behaviours[behaviour.underscore.to_sym][:on] << options[:on]
259
+ self.patriarch_behaviours[behaviour.underscore.to_sym][:on].uniq!
260
+ self.patriarch_behaviours[behaviour.underscore.to_sym][:on].flatten!
261
+ elsif options[:by]
262
+ self.patriarch_behaviours[behaviour.underscore.to_sym][:by] << options[:by]
263
+ self.patriarch_behaviours[behaviour.underscore.to_sym][:by].uniq!
264
+ self.patriarch_behaviours[behaviour.underscore.to_sym][:by].flatten!
265
+ end
266
+ self.patriarch_behaviours[behaviour.underscore.to_sym][:via] << options[:via]
267
+ self.patriarch_behaviours[behaviour.underscore.to_sym][:via].uniq!
268
+ self.patriarch_behaviours[behaviour.underscore.to_sym][:via].flatten!
269
+ elsif options[:medium_between]
270
+ self.patriarch_behaviours[behaviour.underscore.to_sym][:medium_between] << options[:medium_between]
271
+ self.patriarch_behaviours[behaviour.underscore.to_sym][:medium_between].uniq!
272
+ self.patriarch_behaviours[behaviour.underscore.to_sym][:medium_between]
273
+ end
217
274
  end
218
275
 
219
276
  def add_bipartite_behaviour(behaviour,options)
@@ -288,7 +345,6 @@ module Patriarch
288
345
  self.send(:include,"Patriarch::Behaviours::#{behaviour.classify}::ToolsMethods".constantize)
289
346
 
290
347
  # register the behaviour we just added
291
- # TODO disjonction bi/tripart
292
348
  self.patriarch_behaviours ||= { }
293
349
  self.patriarch_behaviours[behaviour.underscore.to_sym] ||= { :on => [], :by =>[] }
294
350
  if options[:on]
@@ -48,8 +48,6 @@ class Patriarch::DAOServices::RetrieverService < Patriarch::Service
48
48
  medium_id = transaction_item.medium_id
49
49
  medium_type = transaction_item.medium_type
50
50
 
51
- puts "#{medium_type} - #{medium_id}"
52
-
53
51
  if Redis::Objects.constants.map(&:to_s).include?("#{dao_info[:type].pluralize.camelize}")
54
52
  redis_dao_class = "Redis::#{dao_info[:type].camelize}".constantize
55
53
  else
@@ -1,39 +1,94 @@
1
1
  class Patriarch::ToolServices::RedisCleanerService < Patriarch::Service
2
2
 
3
3
  # Shall be tested before implementation ...
4
- def clean_all(calling_entity)
5
- calling_entity.patriarch_behaviours.keys.each do |behaviour|
6
- clean_behaviour(calling_entity,behaviour)
4
+ def clean_all(calling_entity,options={})
5
+ transac = options[:transac] || Patriarch::TransactionServices::TransactionManagerService.instance.new_transaction("clean_all".to_sym)
6
+ options = { :transac => transac }
7
+
8
+ calling_entity.class.patriarch_behaviours.keys.each do |behaviour|
9
+ clean_behaviour(calling_entity,behaviour,options)
7
10
  end
11
+
12
+ transac
8
13
  end
9
14
 
10
- def clean_behaviour(calling_entity,behaviour)
15
+ def clean_behaviour(calling_entity,behaviour,options={})
11
16
  my_behaviours = calling_entity.class.patriarch_behaviours
12
17
 
13
18
  if my_behaviours.include? behaviour.to_s.underscore.to_sym
14
- if my_behaviours[behaviour.to_s.underscore.to_sym][:medium_between]
15
- clean_tripartite_behaviour(calling_entity,behaviour)
19
+ if my_behaviours[behaviour.to_s.underscore.to_sym][:medium_between] || my_behaviours[behaviour.to_s.underscore.to_sym][:via]
20
+ clean_tripartite_behaviour(calling_entity,behaviour,options)
16
21
  else
17
- clean_bipartite_behaviour(calling_entity,behaviour)
22
+ clean_bipartite_behaviour(calling_entity,behaviour,options)
18
23
  end
19
24
  end
20
25
  end
21
26
 
22
- def clean_bipartite_behaviour(calling_entity,behaviour)
23
- #
24
- # FIXME Shall clean in one blow, need to prevent transaction from "propagating"
27
+
28
+ #Copiepat
29
+ def clean_tripartite_behaviour(calling_entity,behaviour,options={})
30
+ my_behaviours = calling_entity.class.patriarch_behaviours
25
31
 
26
- # include option to transmit transaction and prevent it from execute
32
+ # Compute names based on conventions
33
+ progressive_present_behaviour =
34
+ (Verbs::Conjugator.conjugate behaviour.to_s.underscore.to_sym, :aspect => :progressive).split(/ /).last
35
+
36
+ transac = options[:transac] || Patriarch::TransactionServices::TransactionManagerService.instance.new_transaction("clean_#{behaviour.to_s}".to_sym)
37
+ options = { :transac => transac, :stop_execution => true}
38
+
39
+ if my_behaviours.include? behaviour.to_s.underscore.to_sym
40
+
41
+ # Dealing with active behaviour
42
+ if my_behaviours[behaviour.to_s.underscore.to_sym][:on]
43
+ acted_on_models = my_behaviours[behaviour.to_s.underscore.to_sym][:on]
44
+ via_models = my_behaviours[behaviour.to_s.underscore.to_sym][:via]
45
+ acted_on_models.each do |acted_on_model|
46
+ via_models.each do |via_model|
47
+ calling_entity.send("#{acted_on_model.to_s.tableize}_i_#{behaviour.to_s}_via_#{via_model.to_s.tableize}", :with_medium => true).each do |tripartite_hash|
48
+ target_i_behaved_on = Array(acted_on_model.to_s.classify.constantize.find(tripartite_hash[:target])).first
49
+ medium_for_behaviour = Array(via_model.to_s.classify.constantize.find(tripartite_hash[:medium])).first
50
+ calling_entity.send(Patriarch.undo(behaviour.to_s).underscore,target_i_behaved_on,medium_for_behaviour,options)
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ # Dealing with passive behaviour
57
+ if my_behaviours[behaviour.to_s.underscore.to_sym][:by]
58
+ targetted_by_models = my_behaviours[behaviour.to_s.underscore.to_sym][:by]
59
+ via_models = my_behaviours[behaviour.to_s.underscore.to_sym][:via]
60
+ targetted_by_models.each do |targetted_by_model|
61
+ via_models.each do |via_model|
62
+ calling_entity.send("#{targetted_by_model.to_s.tableize}_#{progressive_present_behaviour}_me_via_#{via_model.to_s.tableize}", :with_medium => true).each do |tripartite_hash|
63
+ #
64
+ actor_that_behaved_on_me = Array(targetted_by_model.to_s.classify.constantize.find(tripartite_hash[:actor])).first
65
+ medium_for_behaviour = Array(via_model.to_s.classify.constantize.find(tripartite_hash[:medium])).first
66
+ #
67
+ actor_that_behaved_on_me.send(Patriarch.undo(behaviour.to_s).underscore,calling_entity,medium_for_behaviour,options)
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ # Dealing with medium behaviour
74
+ if my_behaviours[behaviour.to_s.underscore.to_sym][:medium_between]
75
+ #do nothing, we do not take care of data relative to medium ...
76
+ end
77
+ end # if my_behaviours.include?
78
+
79
+ transac
80
+ end #clean_tripartite_behaviour
81
+
82
+
27
83
 
28
- # Shall provide an option (:hard) that justs get the job done without heavey transaction stuff if performances
29
- # are aching. Not now, for we have a transaction protecting us we go this way
84
+ def clean_bipartite_behaviour(calling_entity,behaviour,options={})
30
85
  my_behaviours = calling_entity.class.patriarch_behaviours
31
86
 
32
87
  # Compute names based on conventions
33
88
  progressive_present_behaviour =
34
89
  (Verbs::Conjugator.conjugate behaviour.to_s.underscore.to_sym, :aspect => :progressive).split(/ /).last
35
90
 
36
- transac = Patriarch::TransactionServices::TransactionManagerService.instance.new_transaction("clean_#{behaviour.to_s}".to_sym)
91
+ transac = options[:transac] || Patriarch::TransactionServices::TransactionManagerService.instance.new_transaction("clean_#{behaviour.to_s}".to_sym)
37
92
  options = { :transac => transac, :stop_execution => true}
38
93
 
39
94
  if my_behaviours.include? behaviour.to_s.underscore.to_sym
@@ -59,6 +114,6 @@ class Patriarch::ToolServices::RedisCleanerService < Patriarch::Service
59
114
  end
60
115
  end # if my_behaviours.include?
61
116
 
62
- transac.execute
63
- end # #clean_behaviour
117
+ transac
118
+ end # #clean_bipartite_behaviour
64
119
  end # class Patriarch ...
@@ -24,21 +24,34 @@ class Patriarch::ToolServices::RedisExtractorService < Patriarch::Service
24
24
  result = ids_from_redis
25
25
  end
26
26
 
27
- if options[:tripartite]
28
- if options[:with_scores]
29
- if options[:protagonist_type] == :actor
30
- result.map!{ |triplet_id_with_score| [triplet_id_with_score.first[0],tuple.last]}
31
- elsif options[:protagonist_type] == :target
32
- result.map!{ |triplet_id_with_score| [triplet_id_with_score.first[1],tuple.last]}
33
- end
34
- else
35
- if options[:protagonist_type] == :actor
36
- result.map!{ |triplet_id| triplet_id[0] }
37
- elsif options[:protagonist_type] == :target
38
- result.map!{ |triplet_id| triplet_id[1] }
27
+ #TODO Document me ...
28
+ if options[:with_medium]
29
+ # obv tripartite, particular case so we don't need scores here
30
+ result.map!{ |triplet_id| {:actor => triplet_id[0].to_i, :target => triplet_id[1].to_i, :medium => triplet_id[2].to_i} }
31
+ return result
32
+ else
33
+ if options[:tripartite]
34
+ if options[:with_scores]
35
+ if options[:protagonist_type] == :actor
36
+ result.map!{ |triplet_id_with_score| [triplet_id_with_score.first[0],tuple.last]}
37
+ elsif options[:protagonist_type] == :target
38
+ result.map!{ |triplet_id_with_score| [triplet_id_with_score.first[1],tuple.last]}
39
+ #elsif options[:protagonist_type] == :medium
40
+ # result.map!{ |triplet_id_with_score| [triplet_id_with_score.first[2],tuple.last]}
41
+ end
42
+ else
43
+ if options[:protagonist_type] == :actor
44
+ result.map!{ |triplet_id| triplet_id[0] }
45
+ elsif options[:protagonist_type] == :target
46
+ result.map!{ |triplet_id| triplet_id[1] }
47
+ #elsif options[:protagonist_type] == :medium
48
+ # result.map!{ |triplet_id| triplet_id[2] }
49
+ end
39
50
  end
40
51
  end
41
- end
52
+ end
53
+
54
+ # Add an option to handle cases where we need to retrieve medium as well ...
42
55
 
43
56
  result.map! do |x|
44
57
  if x.is_a? Array
@@ -52,6 +65,11 @@ class Patriarch::ToolServices::RedisExtractorService < Patriarch::Service
52
65
  end
53
66
 
54
67
  def get_models_from_ids(calling_entity,model,get_id_method,options={})
68
+ if options[:with_medium]
69
+ id_hash_from_redis = calling_entity.send(get_id_method,options)
70
+ return id_hash_from_redis
71
+ end
72
+
55
73
  if options[:with_scores]
56
74
  ids_with_scores_from_redis = calling_entity.send(get_id_method,options)
57
75
  ids_with_scores_from_redis.map! do |id,score|
@@ -40,11 +40,18 @@ module Patriarch
40
40
  end
41
41
 
42
42
  # Executes the calls to redis in one block here.
43
+ #--
44
+ # XXX Take care when decoupling redis logoc from gem later
45
+ #++
43
46
  def execute
44
- $redis.multi do
45
- steps.each do |step|
46
- step.execute
47
+ begin
48
+ $redis.multi do
49
+ steps.each do |step|
50
+ step.execute
51
+ end
47
52
  end
53
+ rescue Redis::BaseError => e #TODO find redis exception
54
+ raise ActiveRecord::Rollback, "redis error #{e.class.name} occured hence triggered transaction rollback"
48
55
  end
49
56
  end
50
57
 
@@ -46,4 +46,4 @@ module Patriarch
46
46
  queue << proc
47
47
  end
48
48
  end
49
- end
49
+ end
@@ -1,3 +1,3 @@
1
1
  module Patriarch
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/patriarch.gemspec CHANGED
@@ -14,12 +14,14 @@ Gem::Specification.new do |spec|
14
14
 
15
15
  # Main dependencies
16
16
  spec.add_runtime_dependency "verbs"
17
- spec.add_runtime_dependency "rails"
18
17
  spec.add_runtime_dependency "railties"
19
-
18
+ spec.add_runtime_dependency "activerecord"
19
+
20
20
  # Dependencies needed for testing
21
21
  spec.add_development_dependency "rspec"
22
- # TODO run with autotest
22
+ spec.add_development_dependency "activerecord"
23
+ spec.add_development_dependency "sqlite3"
24
+ # TODO run with autotest/guard
23
25
 
24
26
  # Other options ...
25
27
  spec.files = `git ls-files`.split($\)
@@ -3,19 +3,17 @@ require 'spec_helper'
3
3
  describe Patriarch::Behaviours do
4
4
  describe '#add_behaviour' do
5
5
 
6
- let(:monster) { Monster.new }
7
- let(:fallen_angel) { FallenAngel.new }
8
- let(:love_letter) { LoveLetter.new }
6
+ let(:monster) { Monster.create }
7
+ let(:fallen_angel) { FallenAngel.create }
8
+ let(:love_letter) { LoveLetter.create }
9
9
 
10
10
 
11
11
 
12
12
  context 'on a bipartite' do
13
13
 
14
- before do
15
- # Monster is the actor model and FallenAngel the target model here
14
+ before(:all) do
16
15
  Monster.add_behaviour :like, :on => [:fallenAngel]
17
16
  FallenAngel.add_behaviour :like, :by => [:monster]
18
- monster.like fallen_angel
19
17
  end
20
18
 
21
19
  context "call from a model including Patriarch::Behaviours" do
@@ -82,9 +80,11 @@ describe Patriarch::Behaviours do
82
80
  monster.undo_like(fallen_angel, :stop_execution => true).should be_an_instance_of(Patriarch::Transaction)
83
81
  end
84
82
 
85
- before(:all) { monster.like fallen_angel }
83
+
86
84
 
87
85
  context 'when doing behaviour' do
86
+ before(:all) { monster.like fallen_angel }
87
+
88
88
  it "allows actor to remember target id" do
89
89
  monster.fallen_angels_i_like_ids.should == [fallen_angel.id]
90
90
  end
@@ -100,38 +100,43 @@ describe Patriarch::Behaviours do
100
100
  it "allows target to remember actor instance" do
101
101
  fallen_angel.monsters_liking_me.should == [monster]
102
102
  end
103
+
104
+ after(:all) { monster.undo_like fallen_angel }
103
105
  end
104
106
 
105
107
  context 'when undoing behaviour' do
108
+ before(:all) do
109
+ monster.like fallen_angel
110
+ monster.undo_like fallen_angel
111
+ end
112
+
106
113
  it "erase target id from actor's memory" do
107
- monster.fallen_angels_i_like_ids.should == [fallen_angel.id]
114
+ monster.fallen_angels_i_like_ids.should be_empty
108
115
  end
109
116
 
110
117
  it "erase target instance from actor's memory" do
111
- monster.fallen_angels_i_like.should == [fallen_angel]
118
+ monster.fallen_angels_i_like.should be_empty
112
119
  end
113
120
 
114
121
  it "erase actor id from target's memory" do
115
- fallen_angel.monsters_liking_me_ids.should == [monster.id]
122
+ fallen_angel.monsters_liking_me_ids.should be_empty
116
123
  end
117
124
 
118
125
  it "erase actor instance from target's memory" do
119
- fallen_angel.monsters_liking_me.should == [monster]
120
- end
126
+ fallen_angel.monsters_liking_me.should be_empty
127
+ end
121
128
  end
122
129
 
123
- after(:all) { monster.undo_like fallen_angel }
124
130
  end
125
131
  end # context bipartite
126
132
 
127
133
  context 'on a tripartite' do
128
134
 
129
- before do
135
+ before(:all) do
130
136
  # Monster is the actor model and FallenAngel the target model here
131
137
  Monster.add_behaviour :praise, :on => [:fallenAngel], :via => [:loveLetter]
132
138
  FallenAngel.add_behaviour :praise, :by => [:monster], :via => [:loveLetter]
133
139
  LoveLetter.add_behaviour :praise, :medium_between => [:monster,:fallenAngel]
134
- monster.praise(fallen_angel,love_letter)
135
140
  end
136
141
 
137
142
  context "call from a model including Patriarch::Behaviours" do
@@ -187,9 +192,11 @@ describe Patriarch::Behaviours do
187
192
  monster.praise(fallen_angel, love_letter, :stop_execution => true).should be_an_instance_of(Patriarch::Transaction)
188
193
  end
189
194
 
190
- before(:all) { monster.praise fallen_angel,love_letter }
195
+
191
196
 
192
197
  context 'when doing behaviour' do
198
+ before(:all) { monster.praise fallen_angel,love_letter }
199
+
193
200
  it "allows actor to remember target id" do
194
201
  monster.fallen_angels_i_praise_via_love_letters_ids.should == [fallen_angel.id]
195
202
  end
@@ -205,27 +212,34 @@ describe Patriarch::Behaviours do
205
212
  it "allows target to remember actor instance" do
206
213
  fallen_angel.monsters_praising_me_via_love_letters.should == [monster]
207
214
  end
215
+
216
+ after(:all) { monster.undo_praise fallen_angel,love_letter }
208
217
  end
209
218
 
210
219
  context 'when undoing behaviour' do
220
+ before(:all) do
221
+ monster.praise fallen_angel,love_letter
222
+ monster.undo_praise fallen_angel,love_letter
223
+ end
224
+
211
225
  it "erase target id from actor's memory" do
212
- monster.fallen_angels_i_praise_via_love_letters_ids.should == [fallen_angel.id]
226
+ monster.fallen_angels_i_praise_via_love_letters_ids.should be_empty
213
227
  end
214
228
 
215
229
  it "erase target instance from actor's memory" do
216
- monster.fallen_angels_i_praise_via_love_letters.should == [fallen_angel]
230
+ monster.fallen_angels_i_praise_via_love_letters.should be_empty
217
231
  end
218
232
 
219
233
  it "erase actor id from target's memory" do
220
- fallen_angel.monsters_praising_me_via_love_letters_ids.should == [monster.id]
234
+ fallen_angel.monsters_praising_me_via_love_letters_ids.should be_empty
221
235
  end
222
236
 
223
237
  it "erase actor instance from target's memory" do
224
- fallen_angel.monsters_praising_me_via_love_letters.should == [monster]
238
+ fallen_angel.monsters_praising_me_via_love_letters.should be_empty
225
239
  end
226
240
  end
227
241
 
228
- after(:all) { monster.undo_praise fallen_angel,love_letter }
242
+
229
243
  end
230
244
  end # context tripartite
231
245
 
@@ -2,8 +2,8 @@ require 'spec_helper'
2
2
 
3
3
  describe Patriarch::DAOServices::BipartiteRelationshipBuilderService do
4
4
 
5
- let(:monster) { Monster.new }
6
- let(:fallen_angel) { FallenAngel.new }
5
+ let(:monster) { Monster.create }
6
+ let(:fallen_angel) { FallenAngel.create }
7
7
  let(:instance) { Patriarch::DAOServices::BipartiteRelationshipBuilderService.instance }
8
8
 
9
9
  before(:each) do
@@ -2,9 +2,9 @@ require 'spec_helper'
2
2
 
3
3
  describe Patriarch::DAOServices::TripartiteRelationshipBuilderService do
4
4
 
5
- let(:monster) { Monster.new }
6
- let(:fallen_angel) { FallenAngel.new }
7
- let(:love_letter) { LoveLetter.new }
5
+ let(:monster) { Monster.create }
6
+ let(:fallen_angel) { FallenAngel.create }
7
+ let(:love_letter) { LoveLetter.create }
8
8
  let(:instance) { Patriarch::DAOServices::TripartiteRelationshipBuilderService.instance }
9
9
 
10
10
  before(:each) do
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'entities including Patriarch::Behaviours #destroy' do
4
+
5
+ before(:all) do
6
+ Monster.add_behaviour :lure, :by => [:fallenAngel]
7
+ FallenAngel.add_behaviour :lure, :on => [:monster]
8
+ Monster.add_behaviour :like, :on => [:fallenAngel]
9
+ FallenAngel.add_behaviour :like, :by => [:monster]
10
+
11
+ # Tripartite behaviour ...
12
+ FallenAngel.add_behaviour :praise, :on => [:monster], :via => [:loveLetter]
13
+ Monster.add_behaviour :praise, :by => [:fallenAngel], :via => [:loveLetter]
14
+ LoveLetter.add_behaviour :praise, :medium_between => [:fallenAngel,:monster]
15
+ end
16
+
17
+ let(:monster) { Monster.create }
18
+ let(:beast) { Monster.create }
19
+ let(:love_letter) { LoveLetter.create }
20
+
21
+ it "performs redis clean callbacks when other callbacks are ok" do
22
+ f = FallenAngel.create
23
+ m = Monster.create
24
+ f.lure m
25
+ m.like f
26
+ f.destroy
27
+ f.monsters_i_lure.should be_empty
28
+ f.monsters_liking_me.should be_empty
29
+ m.fallen_angels_i_like.include?(f).should be_false
30
+ m.fallen_angels_luring_me.include?(f).should be_false
31
+ end
32
+
33
+ context ' when another callback fails' do
34
+
35
+ # they do not trigger a rollback when they return false
36
+ before(:all) do
37
+ FallenAngel.class_eval do
38
+ around_destroy :callback_fail
39
+ def callback_fail
40
+ raise ActiveRecord::Rollback, "a callback failed" unless @redis_destroy_transac_object.nil?
41
+ end
42
+ end
43
+ end
44
+
45
+ # This works with ActiveRecord as expected
46
+ it "rollbacks redis clean" do
47
+ f = FallenAngel.create
48
+ m = Monster.create
49
+ f.lure m
50
+ m.like f
51
+ f.destroy
52
+ f.monsters_i_lure.should == [m]
53
+ f.monsters_liking_me.should == [m]
54
+ m.fallen_angels_i_like.include?(f).should be_true
55
+ m.fallen_angels_luring_me.include?(f).should be_true
56
+ end
57
+ end
58
+
59
+ context "when redis transaction fails" do
60
+ before(:all) do
61
+ FallenAngel.class_eval do
62
+ around_destroy :callback_fail
63
+ def callback_fail
64
+ # This will trigger Redis::CommandError if executed ...
65
+ proc = Proc.new { $redis.hset "lal", "lil", 3 }
66
+ proc_ = Proc.new { $redis.get "lal" }
67
+ @redis_destroy_transac_object.add_to_queue proc
68
+ @redis_destroy_transac_object.add_to_queue proc_
69
+ puts @redis_destroy_transac_object.inspect
70
+ end
71
+ end
72
+ end
73
+
74
+ it "rollbacks sql transaction" do
75
+ f = FallenAngel.create
76
+ m = Monster.create
77
+ f.lure m
78
+ f.destroy #should fail
79
+ f.destroyed?.should be_false
80
+ end
81
+ end
82
+ end
@@ -2,8 +2,21 @@ require 'spec_helper'
2
2
 
3
3
  describe Patriarch::ToolServices::RedisCleanerService.instance do
4
4
 
5
- let(:monster) { Monster.new }
6
- let(:beast) { Monster.new }
5
+ before(:all) do
6
+ Monster.add_behaviour :lure, :by => [:fallenAngel]
7
+ FallenAngel.add_behaviour :lure, :on => [:monster]
8
+ Monster.add_behaviour :like, :on => [:fallenAngel]
9
+ FallenAngel.add_behaviour :like, :by => [:monster]
10
+
11
+ # Tripartite behaviour ...
12
+ FallenAngel.add_behaviour :praise, :on => [:monster], :via => [:loveLetter]
13
+ Monster.add_behaviour :praise, :by => [:fallenAngel], :via => [:loveLetter]
14
+ LoveLetter.add_behaviour :praise, :medium_between => [:fallenAngel,:monster]
15
+ end
16
+
17
+ let(:monster) { Monster.create }
18
+ let(:beast) { Monster.create }
19
+ let(:love_letter) { LoveLetter.create }
7
20
  # Wrong usage when summoning several times fallen_angel within tests; bad knowledge of
8
21
  # let is in cause i think
9
22
  # let(:fallen_angel) { FallenAngel.new }
@@ -11,35 +24,56 @@ describe Patriarch::ToolServices::RedisCleanerService.instance do
11
24
 
12
25
  context "#clean_all" do
13
26
  it "removes presence into other sets for each behaviour" do
14
- pending("implement this")
15
- end
16
-
17
- it "removes presence into other set for a given behaviour" do
18
- pending("implement this")
27
+ f = FallenAngel.create
28
+ m = Monster.create
29
+ f.lure m
30
+ m.like f
31
+ instance.clean_all(f).execute
32
+ f.monsters_i_lure.should be_empty
33
+ f.monsters_liking_me.should be_empty
34
+ m.fallen_angels_i_like.include?(f).should be_false
35
+ m.fallen_angels_luring_me.include?(f).should be_false
19
36
  end
20
37
  end
21
38
 
22
39
  context "#clean_behaviour" do
23
40
  it "removes given behaviour binds on self" do
24
- f = FallenAngel.new
25
- f.lure Monster.new
26
- instance.clean_behaviour(f,:lure)
41
+ f = FallenAngel.create
42
+ f.lure Monster.create
43
+ instance.clean_behaviour(f,:lure).execute
27
44
  f.monsters_i_lure.should be_empty
28
45
  end
29
46
 
30
47
  it "removes given behaviour binds on other entities" do
31
- f = FallenAngel.new
32
- f.lure Monster.new
33
- instance.clean_behaviour(f,:lure)
34
- beast.fallen_angels_luring_me.include?(f).should be_false
35
- monster.fallen_angels_luring_me.include?(f).should be_false
48
+ f = FallenAngel.create
49
+ m = Monster.create
50
+ b = Monster.create
51
+ f.lure m
52
+ f.lure b
53
+ instance.clean_behaviour(f,:lure).execute
54
+ b.fallen_angels_luring_me.include?(f).should be_false
55
+ m.fallen_angels_luring_me.include?(f).should be_false
36
56
  end
37
57
 
58
+ it "removes given tripartite behaviour binds on other entities" do
59
+ f = FallenAngel.create
60
+ f.praise monster,love_letter
61
+ instance.clean_behaviour(f,:praise).execute
62
+ monster.fallen_angels_praising_me_via_love_letters.include?(f).should be_false
63
+ end
64
+
65
+ it "removes given tripartite behaviour binds on self" do
66
+ f = FallenAngel.create
67
+ f.praise monster,love_letter
68
+ instance.clean_behaviour(f,:praise).execute
69
+ f.monsters_i_praise_via_love_letters.include?(monster).should be_false
70
+ end
71
+
38
72
  it "runs within a unique transaction" do
39
- f = FallenAngel.new
40
- 10.times { |t| f.lure Monster.new }
73
+ f = FallenAngel.create
74
+ 10.times { |t| f.lure Monster.create }
41
75
  before_count = Patriarch::TransactionServices::TransactionManagerService.instance.count
42
- instance.clean_behaviour(f,:lure)
76
+ instance.clean_behaviour(f,:lure).execute
43
77
  after_count = Patriarch::TransactionServices::TransactionManagerService.instance.count
44
78
  (after_count - before_count).should eq(1)
45
79
  end
@@ -2,9 +2,9 @@ require 'spec_helper'
2
2
 
3
3
  describe Patriarch::Transaction do
4
4
 
5
- let(:monster) { Monster.new }
6
- let(:fallen_angel) { FallenAngel.new }
7
- let(:love_letter) { LoveLetter.new }
5
+ let(:monster) { Monster.create }
6
+ let(:fallen_angel) { FallenAngel.create }
7
+ let(:love_letter) { LoveLetter.create }
8
8
  let(:transaction_step){ Patriarch::TransactionStep.new(:pick_up,monster,fallen_angel,love_letter) }
9
9
  let(:transaction) { Patriarch::Transaction.new(:transaction_test,42) }
10
10
 
@@ -2,21 +2,21 @@ require 'spec_helper'
2
2
 
3
3
  describe Patriarch::TransactionStep do
4
4
 
5
- let(:monster) { Monster.new }
6
- let(:fallen_angel) { FallenAngel.new }
7
- let(:love_letter) { LoveLetter.new }
5
+ let(:monster) { Monster.create }
6
+ let(:fallen_angel) { FallenAngel.create }
7
+ let(:love_letter) { LoveLetter.create }
8
8
  let(:transaction_step){ Patriarch::TransactionStep.new(:pick_up,monster,fallen_angel,love_letter) }
9
9
 
10
10
  it "#actor returns the actor instance" do
11
- transaction_step.actor.should == [monster]
11
+ transaction_step.actor.should == monster
12
12
  end
13
13
 
14
14
  it "#medium returns the medium instance" do
15
- transaction_step.medium.should == [love_letter]
15
+ transaction_step.medium.should == love_letter
16
16
  end
17
17
 
18
18
  it "#target returns the target instance" do
19
- transaction_step.target.should == [fallen_angel]
19
+ transaction_step.target.should == fallen_angel
20
20
  end
21
21
 
22
22
  it "#add_to_queue appends proc to queue" do
@@ -24,6 +24,6 @@ describe Patriarch::TransactionStep do
24
24
  q = Proc.new { p "do_nothing"}
25
25
  transaction_step.add_to_queue p
26
26
  transaction_step.add_to_queue q
27
- transaction_step.queue.should ==[p,q]
27
+ transaction_step.queue.should == [p,q]
28
28
  end
29
29
  end
data/spec/spec_helper.rb CHANGED
@@ -6,24 +6,17 @@ require 'redis/objects'
6
6
  require 'redis/objects/hashes'
7
7
  require 'redis/objects/sorted_sets'
8
8
 
9
+ # Test if we do not need to load gems loaded through dev dependencies into gemspecs
9
10
  require 'patriarch'
10
- require 'active_model'
11
+ require 'active_record'
11
12
  require 'action_view'
12
13
  require 'rails/generators'
13
14
  require 'rspec/autorun'
14
15
 
15
- #require File.expand_path("../../lib/generators/patriarch/behaviour_generator", __FILE__)
16
-
17
16
  RSpec.configure do |config|
18
- # ## Mock Framework
19
- #
20
- # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
21
- #
22
- # config.mock_with :mocha
23
- # config.mock_with :flexmock
24
- # config.mock_with :rr
25
17
  end
26
18
 
19
+ # Setting up redis-database
27
20
  $redis=Redis.new(:host => 'localhost', :port => 6379, :db => 8)
28
21
  $redis.flushdb
29
22
 
@@ -34,118 +27,51 @@ puts "Cleaning previous dummy"
34
27
  `yes|rm -r #{dummy_location + "/*"}`
35
28
 
36
29
  # Destroy previously initialized files in dummy, clean up !
37
- puts "Generating files to be tested in a dummy"
38
30
 
39
- puts "Installing gem .."
40
- Patriarch::Generators::InstallGenerator.start(%w(fake_arg),:destination_root => dummy_location)
31
+ puts "Gem set up ..."
32
+ capture(:stdout) { Patriarch::Generators::InstallGenerator.start(%w(fake_arg),:destination_root => dummy_location) }
41
33
 
42
- # Initialize files in dummy :)
34
+ puts "Storing files created during behaviour generation in a dummy repository"
43
35
  # Capture prevents stdout outputs from code between curly braces to be displayed
44
- # This avoid polluting user interface
45
- Patriarch::Generators::BehaviourGenerator.start(%w(like),{:destination_root => dummy_location})
46
- Patriarch::Generators::BehaviourGenerator.start(%w(lure),{:destination_root => dummy_location})
47
- Patriarch::Generators::BehaviourGenerator.start(%w(praise tripartite),{:destination_root => dummy_location})
36
+ # This avoid polluting user interface with file generators output
37
+ capture(:stdout) { Patriarch::Generators::BehaviourGenerator.start(%w(like),{:destination_root => dummy_location}) }
38
+ capture(:stdout) { Patriarch::Generators::BehaviourGenerator.start(%w(lure),{:destination_root => dummy_location}) }
39
+ capture(:stdout) { Patriarch::Generators::BehaviourGenerator.start(%w(praise tripartite),{:destination_root => dummy_location}) }
48
40
 
49
- #Enhance load_path with dummy located files ...
41
+ # Enhance load_path with dummy located files ...
50
42
  $LOAD_PATH << File.expand_path("../../spec/dummy/lib", __FILE__)
51
- $LOAD_PATH << File.expand_path("../../lib", __FILE__)
52
43
 
53
- # load files living in the dummy using initilizer like in a rails situation
44
+ # Load files living in the dummy using an initilizer to mimic rails behaviour
54
45
  require File.expand_path("../../spec/dummy/config/initializers/patriarch", __FILE__)
55
46
 
56
- class Monster
57
- attr_reader :id
58
-
59
- class << self
60
- attr_accessor :count, :object_mapping
61
- end
62
-
63
- self.count = 1
64
- self.object_mapping = {}
65
-
66
- def initialize
67
- @id = self.class.count
68
- self.class.count += 1
69
- self.class.object_mapping.merge!({@id => self.object_id})
70
- end
71
-
72
- def self.find(ids)
73
- ids = Array(ids)
74
- result = []
75
- ids.each do |id|
76
- object_ref = self.object_mapping[id]
77
- record = ObjectSpace._id2ref(object_ref)
78
- result << record unless record.nil?
79
- end
80
- result
81
- end
82
- end
47
+ # We define 3 similar classes to play tests
48
+ class Monster < ActiveRecord::Base; include Patriarch::Behaviours; end
49
+ class FallenAngel < ActiveRecord::Base; include Patriarch::Behaviours; end
50
+ class LoveLetter < ActiveRecord::Base; include Patriarch::Behaviours; end
83
51
 
84
- class FallenAngel
85
- attr_reader :id
86
-
87
- class << self
88
- attr_accessor :count, :object_mapping
89
- end
52
+ # Setting standalone database to run tests
53
+ ActiveRecord::Base.establish_connection(
54
+ :adapter => "sqlite3",
55
+ :database => ":memory:"
56
+ )
90
57
 
91
- self.count = 1
92
- self.object_mapping = {}
93
-
94
- def initialize
95
- @id = self.class.count
96
- self.class.count += 1
97
- self.class.object_mapping.merge!({@id => self.object_id})
98
- end
58
+ # Load minimal schema for database
99
59
 
100
- def self.find(ids)
101
- ids = Array(ids)
102
- result = []
103
- ids.each do |id|
104
- object_ref = self.object_mapping[id]
105
- record = ObjectSpace._id2ref(object_ref)
106
- result << record unless record.nil?
107
- end
108
- result
109
- end
110
- end
60
+ ActiveRecord::Schema.define do
111
61
 
112
- class LoveLetter
113
- attr_reader :id
114
-
115
- class << self
116
- attr_accessor :count, :object_mapping
62
+ create_table "fallen_angels", :force => true do |t|
63
+ t.datetime "created_at", :null => false
64
+ t.datetime "updated_at", :null => false
117
65
  end
118
66
 
119
- self.count = 1
120
- self.object_mapping = {}
121
-
122
- def initialize
123
- @id = self.class.count
124
- self.class.count += 1
125
- self.class.object_mapping.merge!({@id => self.object_id})
67
+ create_table "love_letters", :force => true do |t|
68
+ t.datetime "created_at", :null => false
69
+ t.datetime "updated_at", :null => false
126
70
  end
127
71
 
128
- def self.find(ids)
129
- ids = Array(ids)
130
- result = []
131
- ids.each do |id|
132
- object_ref = self.object_mapping[id]
133
- record = ObjectSpace._id2ref(object_ref)
134
- result << record unless record.nil?
135
- end
136
- result
72
+ create_table "monsters", :force => true do |t|
73
+ t.datetime "created_at", :null => false
74
+ t.datetime "updated_at", :null => false
137
75
  end
138
- end
139
-
140
- Monster.send(:include,Patriarch::Behaviours)
141
- FallenAngel.send(:include,Patriarch::Behaviours)
142
- LoveLetter.send(:include,Patriarch::Behaviours)
143
-
144
- Monster.add_behaviour :like, :on => [:fallenAngel]
145
- Monster.add_behaviour :lure, :by => [:fallenAngel]
146
- FallenAngel.add_behaviour :like, :by => [:monster]
147
- FallenAngel.add_behaviour :lure, :on => [:monster]
148
76
 
149
- LoveLetter.add_behaviour :praise, :medium_between => [:monster,:fallenAngel]
150
- Monster.add_behaviour :praise, :on => [:fallenAngel], :via => [:LoveLetter]
151
- FallenAngel.add_behaviour :praise, :by => [:monster], :via => [:LoveLetter]
77
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: patriarch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-30 00:00:00.000000000 Z
12
+ date: 2012-12-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: verbs
16
- requirement: &16105280 !ruby/object:Gem::Requirement
16
+ requirement: &12624080 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *16105280
24
+ version_requirements: *12624080
25
25
  - !ruby/object:Gem::Dependency
26
- name: rails
27
- requirement: &16104860 !ruby/object:Gem::Requirement
26
+ name: railties
27
+ requirement: &12623660 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *16104860
35
+ version_requirements: *12623660
36
36
  - !ruby/object:Gem::Dependency
37
- name: railties
38
- requirement: &16104440 !ruby/object:Gem::Requirement
37
+ name: activerecord
38
+ requirement: &12623240 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,32 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *16104440
46
+ version_requirements: *12623240
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec
49
- requirement: &16104020 !ruby/object:Gem::Requirement
49
+ requirement: &12622820 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *12622820
58
+ - !ruby/object:Gem::Dependency
59
+ name: activerecord
60
+ requirement: &12622400 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *12622400
69
+ - !ruby/object:Gem::Dependency
70
+ name: sqlite3
71
+ requirement: &12621980 !ruby/object:Gem::Requirement
50
72
  none: false
51
73
  requirements:
52
74
  - - ! '>='
@@ -54,7 +76,7 @@ dependencies:
54
76
  version: '0'
55
77
  type: :development
56
78
  prerelease: false
57
- version_requirements: *16104020
79
+ version_requirements: *12621980
58
80
  description: Patriach is about adding behaviours on the fly to good old active record
59
81
  models.
60
82
  email:
@@ -106,6 +128,7 @@ files:
106
128
  - spec/lib/patriarch/behaviours_spec.rb
107
129
  - spec/lib/patriarch/dao_services/bipartite_relationship_builder_spec.rb
108
130
  - spec/lib/patriarch/dao_services/tripartite_relationship_builder_spec.rb
131
+ - spec/lib/patriarch/destroy_entity_spec.rb
109
132
  - spec/lib/patriarch/redis_mapper_service_spec.rb
110
133
  - spec/lib/patriarch/retriever_service_spec.rb
111
134
  - spec/lib/patriarch/tool_services/redis_cleaner_service_spec.rb
@@ -142,6 +165,7 @@ test_files:
142
165
  - spec/lib/patriarch/behaviours_spec.rb
143
166
  - spec/lib/patriarch/dao_services/bipartite_relationship_builder_spec.rb
144
167
  - spec/lib/patriarch/dao_services/tripartite_relationship_builder_spec.rb
168
+ - spec/lib/patriarch/destroy_entity_spec.rb
145
169
  - spec/lib/patriarch/redis_mapper_service_spec.rb
146
170
  - spec/lib/patriarch/retriever_service_spec.rb
147
171
  - spec/lib/patriarch/tool_services/redis_cleaner_service_spec.rb