patriarch 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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