patriarch 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/generators/patriarch/USAGE +8 -0
- data/lib/generators/patriarch/patriarch_generator.rb +69 -0
- data/lib/generators/patriarch/templates/after_manager_service.rb +6 -0
- data/lib/generators/patriarch/templates/after_service.rb +6 -0
- data/lib/generators/patriarch/templates/authorization_service.rb +6 -0
- data/lib/generators/patriarch/templates/before_manager_service.rb +6 -0
- data/lib/generators/patriarch/templates/before_service.rb +6 -0
- data/lib/generators/patriarch/templates/empty_behaviour_module.rb +2 -0
- data/lib/generators/patriarch/templates/manager_service.rb +29 -0
- data/lib/generators/patriarch/templates/service.rb +5 -0
- data/lib/generators/patriarch/templates/tools_methods.rb +3 -0
- data/lib/generators/patriarch/templates/undo_service.rb +5 -0
- data/lib/patriarch/authorization_service.rb +10 -0
- data/lib/patriarch/behaviours.rb +160 -0
- data/lib/patriarch/dao_services/.DAOinstancier.rb.swp +0 -0
- data/lib/patriarch/dao_services/bipartite_relationship_builder_service.rb +43 -0
- data/lib/patriarch/dao_services/redis_mapper_service.rb +41 -0
- data/lib/patriarch/dao_services/retriever_service.rb +51 -0
- data/lib/patriarch/manager_service.rb +15 -0
- data/lib/patriarch/service.rb +5 -0
- data/lib/patriarch/tool_services/redis_cleaner.rb +47 -0
- data/lib/patriarch/tool_services/redis_extractor_service.rb +37 -0
- data/lib/patriarch/transaction.rb +68 -0
- data/lib/patriarch/transaction_services/transaction_manager_service.rb +13 -0
- data/lib/patriarch/transaction_step.rb +39 -0
- data/lib/patriarch/version.rb +1 -1
- data/patriarch.gemspec +5 -2
- data/spec/lib/patriarch/add_behaviour_spec.rb +72 -0
- data/spec/lib/patriarch/bipartite_relationship_builder_spec.rb +51 -0
- data/spec/lib/patriarch/clean_reclip_spec.rb +31 -0
- data/spec/lib/patriarch/like_service_spec.rb +18 -0
- data/spec/lib/patriarch/reclip_spec.rb +39 -0
- data/spec/lib/patriarch/redis_mapper_service_spec.rb +20 -0
- data/spec/lib/patriarch/retriever_service_spec.rb +37 -0
- metadata +65 -4
@@ -0,0 +1,69 @@
|
|
1
|
+
class PatriarchGenerator < Rails::Generators::Base
|
2
|
+
source_root File.expand_path('../templates', __FILE__)
|
3
|
+
|
4
|
+
desc "Generate files needed to implement the BEHAVIOUR you specified. Don't forget to add declarations into models"
|
5
|
+
|
6
|
+
argument :behaviour, :type => :string
|
7
|
+
|
8
|
+
public
|
9
|
+
def init_directories
|
10
|
+
empty_directory "lib/patriarch/services/#{behaviour.underscore.downcase}"
|
11
|
+
empty_directory "lib/patriarch/services/#{undo(behaviour.underscore.downcase)}"
|
12
|
+
template "empty_behaviour_module.rb", "lib/patriarch/services/#{behaviour.underscore.downcase}.rb"
|
13
|
+
template "tools_methods.rb", "lib/patriarch/behaviours/#{behaviour.underscore.downcase}/tools_methods.rb"
|
14
|
+
end
|
15
|
+
|
16
|
+
def generate_services
|
17
|
+
create_services(behaviour)
|
18
|
+
# implémenter un switch ici, plus zoli ...
|
19
|
+
self.class.send(:define_method,:class_name) do
|
20
|
+
undo(behaviour).classify
|
21
|
+
end
|
22
|
+
create_undo_services(behaviour)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def class_name
|
27
|
+
behaviour.classify
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_services(behaviour)
|
31
|
+
behaviour_str = behaviour.underscore.downcase
|
32
|
+
template "authorization_service.rb", "lib/patriarch/services/#{behaviour_str}/authorization_service.rb"
|
33
|
+
|
34
|
+
template "before_manager_service.rb", "lib/patriarch/services/#{behaviour_str}/before_manager_service.rb"
|
35
|
+
template "before_service.rb", "lib/patriarch/services/#{behaviour_str}/before_service.rb"
|
36
|
+
|
37
|
+
template "manager_service.rb", "lib/patriarch/services/#{behaviour_str}/manager_service.rb"
|
38
|
+
|
39
|
+
template "service.rb", "lib/patriarch/services/#{behaviour_str}/service.rb"
|
40
|
+
|
41
|
+
|
42
|
+
template "after_manager_service.rb", "lib/patriarch/services/#{behaviour_str}/after_manager_service.rb"
|
43
|
+
template "after_service.rb", "lib/patriarch/services/#{behaviour_str}/after_service.rb"
|
44
|
+
end
|
45
|
+
|
46
|
+
def create_undo_services(behaviour)
|
47
|
+
undo_behaviour_str = undo(behaviour).underscore.downcase
|
48
|
+
|
49
|
+
template "authorization_service.rb", "lib/patriarch/services/#{undo_behaviour_str}/authorization_service.rb"
|
50
|
+
|
51
|
+
template "before_manager_service.rb", "lib/patriarch/services/#{undo_behaviour_str}/before_manager_service.rb"
|
52
|
+
template "before_service.rb", "lib/patriarch/services/#{undo_behaviour_str}/before_service.rb"
|
53
|
+
|
54
|
+
template "manager_service.rb", "lib/patriarch/services/#{undo_behaviour_str}/manager_service.rb"
|
55
|
+
|
56
|
+
template "undo_service.rb", "lib/patriarch/services/#{undo_behaviour_str}/service.rb"
|
57
|
+
|
58
|
+
template "after_manager_service.rb", "lib/patriarch/services/#{undo_behaviour_str}/after_manager_service.rb"
|
59
|
+
template "after_service.rb", "lib/patriarch/services/#{undo_behaviour_str}/after_service.rb"
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def undo(str)
|
64
|
+
undo = "undo_"
|
65
|
+
undo << str
|
66
|
+
undo
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Patriarch::Services::<%= class_name %>::ManagerService < Patriarch::ManagerService
|
2
|
+
# Return true or false
|
3
|
+
def resolve(actor, target, transac = nil)
|
4
|
+
|
5
|
+
# On plante le "drapeau" transac_first_step pour signifier le début
|
6
|
+
if transac
|
7
|
+
transac_first_step = false
|
8
|
+
else
|
9
|
+
transac_first_step = true
|
10
|
+
end
|
11
|
+
|
12
|
+
transac ||= Patriarch::TransactionServices::TransactionManagerService.instance.new_transaction(:<%= class_name.underscore.to_sym %>)
|
13
|
+
# Do not listen Loïc anymore ... DO NOT MOVE, LikeAuthorizationService needs us to build
|
14
|
+
# a transaction step
|
15
|
+
transac.add_step(:<%= class_name.underscore.to_sym %>,actor,target)
|
16
|
+
|
17
|
+
callbacks_were_completed = false
|
18
|
+
|
19
|
+
if Patriarch::Services::<%= class_name %>::AuthorizationService.instance.grant?(transac)
|
20
|
+
Patriarch::Services::<%= class_name %>::Service.instance.call(transac)
|
21
|
+
if Patriarch::Services::<%= class_name %>::AfterManagerService.instance.resolve(transac)
|
22
|
+
callbacks_were_completed = true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Si tout s'est bien passé et que les callbacks ont été exécutés
|
27
|
+
transac.execute if (transac_first_step && callbacks_were_completed)
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
#require 'patriarch/behaviours/own'
|
2
|
+
#require 'patriarch/behaviours/subscribe'
|
3
|
+
#require 'patriarch/behaviours/tagging'
|
4
|
+
#require 'patriarch/behaviours/join'
|
5
|
+
|
6
|
+
module Patriarch
|
7
|
+
module Behaviours
|
8
|
+
|
9
|
+
class AddBehaviourSyntaxError < Exception ; end
|
10
|
+
|
11
|
+
class << self
|
12
|
+
|
13
|
+
def complete_custom_active_module(module_to_complete,relation_type,acted_on_model_list)
|
14
|
+
module_to_complete.class_eval do
|
15
|
+
|
16
|
+
acted_on_model_list.each do |acted_on_model|
|
17
|
+
|
18
|
+
# Compute names based on conventions
|
19
|
+
classic_tool_method_name = "#{acted_on_model.to_s.tableize}_i_#{relation_type.to_s}"
|
20
|
+
raw_tool_method_name = classic_tool_method_name + "_ids"
|
21
|
+
redis_key = "patriarch_" + classic_tool_method_name
|
22
|
+
|
23
|
+
# Define methods with the pattern : items_i_like that returns models and items_i_like_ids that return
|
24
|
+
# Redis key has the same radical as the method in class by convention (but has a patriarch_ prefix to avoid collisions with other gems)
|
25
|
+
define_method(classic_tool_method_name) do |options={}|
|
26
|
+
Patriarch::ToolServices::RedisExtractorService.instance.
|
27
|
+
get_models_from_ids(self,acted_on_model.to_s.classify.constantize,raw_tool_method_name,options)
|
28
|
+
end
|
29
|
+
|
30
|
+
define_method(raw_tool_method_name) do |options={}|
|
31
|
+
Patriarch::ToolServices::RedisExtractorService.instance.get_ids_from_sorted_set(self,redis_key,options)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def complete_custom_passive_module(module_to_complete,relation_type,targetted_by_model_list)
|
39
|
+
module_to_complete.class_eval do
|
40
|
+
|
41
|
+
targetted_by_model_list.each do |targetted_by_model|
|
42
|
+
|
43
|
+
# Compute names based on conventions
|
44
|
+
progressive_present_relation_type = (Verbs::Conjugator.conjugate relation_type.to_sym, :aspect => :progressive).split(/ /).last
|
45
|
+
classic_tool_method_name = "#{targetted_by_model.to_s.tableize}_#{progressive_present_relation_type}_me"
|
46
|
+
raw_tool_method_name = classic_tool_method_name + "_ids"
|
47
|
+
redis_key = "patriarch_" + classic_tool_method_name
|
48
|
+
|
49
|
+
# Define methods with the pattern : items_i_like that returns models and items_i_like_ids that return
|
50
|
+
# Redis key has the same radical as the method in class by convention (but has a patriarch_ prefix to avoid collisions with other gems)
|
51
|
+
define_method(classic_tool_method_name) do |options={}|
|
52
|
+
Patriarch::ToolServices::RedisExtractorService.instance.
|
53
|
+
get_models_from_ids(self,targetted_by_model.to_s.classify.constantize,raw_tool_method_name,options)
|
54
|
+
end
|
55
|
+
|
56
|
+
define_method(raw_tool_method_name) do |options={}|
|
57
|
+
Patriarch::ToolServices::RedisExtractorService.instance.get_ids_from_sorted_set(self,redis_key,options)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def undo(str)
|
65
|
+
undo = "undo_"
|
66
|
+
undo << str
|
67
|
+
undo
|
68
|
+
end
|
69
|
+
|
70
|
+
def included(klass)
|
71
|
+
klass.extend ClassMethods
|
72
|
+
klass.extend ActiveModel::Callbacks
|
73
|
+
class << klass;
|
74
|
+
attr_accessor :patriarch_behaviours
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
module ClassMethods
|
80
|
+
def add_behaviours(*behaviours)
|
81
|
+
end
|
82
|
+
|
83
|
+
def add_behaviour(behaviour,options)
|
84
|
+
# add_behaviour :like, :by => bla, :on => [:item,:user] || :community, :as => :aimer, :reverse_as => :haïr ...
|
85
|
+
|
86
|
+
behaviour = behaviour.to_s.downcase
|
87
|
+
|
88
|
+
# Ou exclusif sur les options on et by
|
89
|
+
unless options[:by].nil? ^ options[:on].nil?
|
90
|
+
raise AddBehaviourSyntaxError, "you must not define a behaviour as active (using on) and passive at the same time (using by)"
|
91
|
+
end
|
92
|
+
|
93
|
+
methods_mod = Module.new do;
|
94
|
+
end
|
95
|
+
methods_mod.const_set(:Behaviour,behaviour)
|
96
|
+
|
97
|
+
if options[:on]
|
98
|
+
# Adds active methods and defines the hook to set callbacks on them
|
99
|
+
methods_mod.instance_eval do
|
100
|
+
|
101
|
+
# Defines the hook thing ...
|
102
|
+
# TODO
|
103
|
+
def self.included(klass)
|
104
|
+
klass.extend ActiveModel::Callbacks
|
105
|
+
klass.send(:define_model_callbacks, self.const_get(:Behaviour).to_sym, Patriarch::Behaviours.undo(self.const_get(:Behaviour)).to_sym)
|
106
|
+
end
|
107
|
+
|
108
|
+
# like
|
109
|
+
define_method(methods_mod.const_get(:Behaviour).to_sym) do |entity,options={}|
|
110
|
+
run_callbacks methods_mod.const_get(:Behaviour).to_sym do
|
111
|
+
"Patriarch::Services::#{methods_mod.const_get(:Behaviour).classify}::ManagerService".constantize.instance.resolve(self,entity)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# undo_like
|
116
|
+
define_method(Patriarch::Behaviours.undo(methods_mod.const_get(:Behaviour)).to_sym) do |entity,options={}|
|
117
|
+
run_callbacks Patriarch::Behaviours.undo(methods_mod.const_get(:Behaviour)).to_sym do
|
118
|
+
"Patriarch::Services::#{(Patriarch::Behaviours.undo(methods_mod.const_get(:Behaviour))).classify}::ManagerService".constantize.instance.resolve(self,entity)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# likes?
|
123
|
+
define_method((Verbs::Conjugator.conjugate methods_mod.const_get(:Behaviour).to_sym, :person => :third).split(/ /).last) do |entity|
|
124
|
+
self.send("#{entity.class.name.tableize}_i_#{methods_mod.const_get(:Behaviour)}_ids").include? entity.id
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
if options[:by]
|
130
|
+
methods_mod.instance_eval do
|
131
|
+
# reverse_of_likes?
|
132
|
+
# TODO find naming convention and build general ...
|
133
|
+
# define_method(:reverse_of_likes) do |entity|
|
134
|
+
# progressive_present_relation_type = (Verbs::Conjugator.conjugate methods_mod.const_get(:Behaviour).to_sym, :aspect => :progressive).split(/ /).last
|
135
|
+
# self.send("#{entity.class.name.tableize}_#{progressive_present_relation_type}_me_ids").include? entity.id
|
136
|
+
#end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
if options[:on]
|
141
|
+
acted_on_model_list = Array(options[:on])
|
142
|
+
Patriarch::Behaviours.complete_custom_active_module(methods_mod,behaviour,acted_on_model_list)
|
143
|
+
else
|
144
|
+
targetted_by_model_list = Array(options[:by])
|
145
|
+
Patriarch::Behaviours.complete_custom_passive_module(methods_mod,behaviour,targetted_by_model_list)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Finally ...
|
149
|
+
self.send(:include,methods_mod)
|
150
|
+
# include in which we can overwite the methods of the previous custom module included there ...
|
151
|
+
self.send(:include,"Patriarch::Behaviours::#{behaviour.classify}::ToolsMethods".constantize)
|
152
|
+
|
153
|
+
# register the behaviour we just added
|
154
|
+
self.patriarch_behaviours ||= []
|
155
|
+
self.patriarch_behaviours = self.patriarch_behaviours << behaviour.to_sym
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
end # Behaviours
|
160
|
+
end # Patriarch
|
Binary file
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class Patriarch::DAOServices::BipartiteRelationshipBuilderService < Patriarch::Service
|
2
|
+
def create(transaction_item)
|
3
|
+
# t => changer nom pour différencier de la date créée pour le Patriarch::Transaction
|
4
|
+
t = Time.now.to_f
|
5
|
+
dao_tab = Patriarch::DAOServices::RetrieverService.instance.call(transaction_item)
|
6
|
+
|
7
|
+
# Go hash plz
|
8
|
+
actor_dao = dao_tab[:actor]
|
9
|
+
target_dao = dao_tab[:target]
|
10
|
+
|
11
|
+
l = build_lambda_for_create(actor_dao,transaction_item.target_id,t)
|
12
|
+
ll = build_lambda_for_create(target_dao,transaction_item.actor_id,t)
|
13
|
+
|
14
|
+
# care about that, should be encapsulated into a beautiful add_to_queue method
|
15
|
+
transaction_item.add_to_queue l
|
16
|
+
transaction_item.add_to_queue ll
|
17
|
+
end
|
18
|
+
|
19
|
+
def destroy(transaction_item)
|
20
|
+
dao_tab = Patriarch::DAOServices::RetrieverService.instance.call(transaction_item)
|
21
|
+
|
22
|
+
# Go hash plz
|
23
|
+
actor_dao = dao_tab[:actor]
|
24
|
+
target_dao = dao_tab[:target]
|
25
|
+
|
26
|
+
l = lambda { actor_dao.delete transaction_item.target_id }
|
27
|
+
ll = lambda { target_dao.delete transaction_item.actor_id }
|
28
|
+
|
29
|
+
# care about that, should be encapsulated into a beautiful add_to_queue method
|
30
|
+
transaction_item.add_to_queue l
|
31
|
+
transaction_item.add_to_queue ll
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def build_lambda_for_create(dao,id,time)
|
37
|
+
if dao.is_a? Redis::SortedSet
|
38
|
+
return lambda { dao.add id, time }
|
39
|
+
else
|
40
|
+
return lambda { dao.add id }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class Patriarch::DAOServices::RedisMapperService < Patriarch::Service
|
2
|
+
def call(transac,protagonist_type)
|
3
|
+
|
4
|
+
# Getting symbols here ...
|
5
|
+
relation_type = transac.relation_type
|
6
|
+
actor_type = transac.actor_type
|
7
|
+
target_type = transac.target_type
|
8
|
+
|
9
|
+
relation_type_str = sanitize_relation_type(relation_type.to_s)
|
10
|
+
|
11
|
+
if protagonist_type == :actor
|
12
|
+
redis_config_for_actor_on(target_type,relation_type_str)
|
13
|
+
else
|
14
|
+
redis_config_for_target_by(actor_type,relation_type_str)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def redis_config_for_actor_on(model_name,relation_type_str)
|
20
|
+
# example : items_i_like ...
|
21
|
+
{
|
22
|
+
:type => "sorted_set", :key => "patriarch_#{model_name.to_s.tableize}_i_#{relation_type_str}"
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def redis_config_for_target_by(model_name,relation_type_str)
|
27
|
+
# example : items_liking_me ...
|
28
|
+
{
|
29
|
+
:type => "sorted_set", :key => "patriarch_#{model_name.to_s.tableize}_#{progressive_present(relation_type_str)}_me"
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def progressive_present(behaviour_verb)
|
34
|
+
# like becomes => liking
|
35
|
+
(Verbs::Conjugator.conjugate behaviour_verb.to_sym, :aspect => :progressive).split(/ /).last
|
36
|
+
end
|
37
|
+
|
38
|
+
def sanitize_relation_type(relation_type)
|
39
|
+
relation_type.sub(/^undo_/,'')
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class InvalidRedisTypeException < Exception
|
2
|
+
end
|
3
|
+
|
4
|
+
class Patriarch::DAOServices::RetrieverService < Patriarch::Service
|
5
|
+
# go hash
|
6
|
+
def call(transaction_item)
|
7
|
+
result = {}
|
8
|
+
result[:actor] = instantiate_DAO_for_actor(transaction_item)
|
9
|
+
result[:target] = instantiate_DAO_for_target(transaction_item)
|
10
|
+
result
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def get_DAO_info_for_actor(transaction_item)
|
16
|
+
Patriarch::DAOServices::RedisMapperService.instance.call(transaction_item,:actor)
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_DAO_info_for_target(transaction_item)
|
20
|
+
Patriarch::DAOServices::RedisMapperService.instance.call(transaction_item,:target)
|
21
|
+
end
|
22
|
+
|
23
|
+
def instantiate_DAO_for_actor(transaction_item)
|
24
|
+
dao_info = get_DAO_info_for_actor(transaction_item)
|
25
|
+
actor_id = transaction_item.actor_id
|
26
|
+
actor_type = transaction_item.actor_type
|
27
|
+
|
28
|
+
if Redis.constants.map(&:to_s).include?("#{dao_info[:type].camelize}")
|
29
|
+
redis_dao_class = "Redis::#{dao_info[:type].camelize}".constantize
|
30
|
+
else
|
31
|
+
raise InvalidRedisTypeException
|
32
|
+
end
|
33
|
+
|
34
|
+
redis_dao_class.new("#{actor_type}:#{actor_id}:#{dao_info[:key]}")
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def instantiate_DAO_for_target(transaction_item)
|
39
|
+
dao_info = get_DAO_info_for_target(transaction_item)
|
40
|
+
target_id = transaction_item.target_id
|
41
|
+
target_type = transaction_item.target_type
|
42
|
+
|
43
|
+
if Redis.constants.map(&:to_s).include?("#{dao_info[:type].camelize}")
|
44
|
+
redis_dao_class = "Redis::#{dao_info[:type].camelize}".constantize
|
45
|
+
else
|
46
|
+
raise InvalidRedisTypeException
|
47
|
+
end
|
48
|
+
redis_dao_class.new("#{target_type}:#{target_id}:#{dao_info[:key]}")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
# Interface avec les couches les plus hautes
|
4
|
+
class Patriarch::ManagerService
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
# /!\ Changer l'architecture ici, l'idée est là
|
8
|
+
#def resolve(*args, options={})
|
9
|
+
# Traitement des options
|
10
|
+
# ...
|
11
|
+
|
12
|
+
# Traitement normal
|
13
|
+
# after_resolve(*args)
|
14
|
+
#end
|
15
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class Patriarch::ToolServices::RedisExtractorService < Patriarch::Service
|
2
|
+
def clean_reclip_id(reclip_id)
|
3
|
+
# Go get the hash of this reclip to clean depencies
|
4
|
+
reclip_hash = Redis::HashKey.new("reclip:#{reclip_id}")
|
5
|
+
|
6
|
+
# Clean dependencies on the recliped_on entity, the recliper entity and the reclipped item
|
7
|
+
|
8
|
+
recliped_on_sorted_set = Redis::SortedSet.new("#{reclip_hash['recliped_on_type'].downcase}:#{reclip_hash['recliped_on_id']}:redis_reclipeds_on_me")
|
9
|
+
recliper_sorted_set = Redis::SortedSet.new("#{reclip_hash['recliper_type'].downcase}:#{reclip_hash['recliper_id']}:redis_reclipeds_by_me")
|
10
|
+
item_reclip_ids_sorted_set = Redis::SortedSet.new("item:#{reclip_hash['recliped_item_id']}:redis_reclips_of_me")
|
11
|
+
|
12
|
+
$redis.multi do
|
13
|
+
recliped_on_sorted_set.delete reclip_id # recliped_on is cleaned
|
14
|
+
recliper_sorted_set.delete reclip_id # recliper is cleaned
|
15
|
+
reclip_hash.del # hash is deleted properly
|
16
|
+
item_reclip_ids_sorted_set.delete reclip_id # item_key is cleaned from this reclip_id
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def clean_reclip_for_item_before_delete(item)
|
21
|
+
item_reclip_ids = Redis::SortedSet.new("item:#{item.id}:redis_reclips_of_me")
|
22
|
+
|
23
|
+
# For each reclip involving our item
|
24
|
+
item_reclip_ids.members.each do |reclip_id|
|
25
|
+
clean_reclip_id(reclip_id)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def clean_reclip_for_group_before_delete(group)
|
30
|
+
# Goal here is to clean reclipeds_on_me dependencies and reclipeds_by_me before the group dies
|
31
|
+
|
32
|
+
# reclipeds_on_me
|
33
|
+
reclipeds_on_me_sorted_set = group.redis_reclipeds_on_me
|
34
|
+
|
35
|
+
reclipeds_on_me_sorted_set.members.each do |reclip_id|
|
36
|
+
clean_reclip_id(reclip_id)
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# reclipeds_by_me
|
41
|
+
reclipeds_by_me_sorted_set = group.redis_reclipeds_by_me
|
42
|
+
|
43
|
+
reclipeds_by_me_sorted_set.members.each do |reclip_id|
|
44
|
+
clean_reclip_id(reclip_id)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Patriarch::ToolServices::RedisExtractorService < Patriarch::Service
|
2
|
+
def get_ids_from_sorted_set(calling_entity,redis_key,options={})
|
3
|
+
from = options[:from] || 0
|
4
|
+
limit = options[:limit] || :infinity
|
5
|
+
|
6
|
+
if limit == :infinity
|
7
|
+
to = -1
|
8
|
+
else
|
9
|
+
to = from + limit -1
|
10
|
+
end
|
11
|
+
|
12
|
+
dao = Redis::SortedSet.new("#{calling_entity.class.name.downcase}:#{calling_entity.id}:#{redis_key}")
|
13
|
+
|
14
|
+
if options[:with_scores]
|
15
|
+
# Do not use this anymore, go take the right redis objects not using this kind of methods ...
|
16
|
+
# DEGOLASSE
|
17
|
+
Redis::SortedSet.new
|
18
|
+
ids_with_scores_from_redis = dao.revrange(from,to,:with_scores => true) || []
|
19
|
+
ids_with_scores_from_redis.map{ |id,score| [id.to_i,score] }
|
20
|
+
else
|
21
|
+
ids_from_redis = dao.revrange(from,to) || []
|
22
|
+
ids_from_redis.map &:to_i
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_models_from_ids(calling_entity,model,get_id_method,options={})
|
27
|
+
if options[:with_scores]
|
28
|
+
ids_with_scores_from_redis = calling_entity.send(get_id_method,options)
|
29
|
+
ids_with_scores_from_redis.map! do |id,score|
|
30
|
+
[model.find(id),score]
|
31
|
+
end
|
32
|
+
else
|
33
|
+
ids_from_redis = calling_entity.send(get_id_method,options)
|
34
|
+
model.find(ids_from_redis)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class Patriarch::Transaction
|
2
|
+
attr_reader :id, :steps, :current_step_number
|
3
|
+
attr_reader :type
|
4
|
+
|
5
|
+
forwarded_methods_syms = [:relation_type,:actor_type,:target_type,:actor_id,:target_id,
|
6
|
+
:context,:actor,:target]
|
7
|
+
|
8
|
+
# Forward methods that are not this transaction's job to step object
|
9
|
+
forwarded_methods_syms.each do |method_sym|
|
10
|
+
define_method(method_sym) do
|
11
|
+
current_step.send(method_sym)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
# id => go $redis.incr
|
17
|
+
def initialize(type,id) #relation_type,actor,target,
|
18
|
+
@type = type
|
19
|
+
@id = id
|
20
|
+
@steps = []
|
21
|
+
@current_step_number = 0
|
22
|
+
end
|
23
|
+
|
24
|
+
# Initializes a new step and stores it in the steps array right away
|
25
|
+
# A step matches a "like", "follow", "own", etc.
|
26
|
+
# Register that we went a step further into the transaction processus
|
27
|
+
# Medium is nil by default (bipartite transactions does not require more than target/actor)
|
28
|
+
def add_step(relation_type,actor,target,medium=nil)
|
29
|
+
# Initializes a new step and stores it in the steps array right away
|
30
|
+
new_step = Patriarch::TransactionStep.new(relation_type,actor,target,medium)
|
31
|
+
|
32
|
+
# if initilization failed we should not move forward ...
|
33
|
+
raise PatriarchTransactionStepInstanciationException unless new_step
|
34
|
+
|
35
|
+
# Register that we went a step further into the transaction processus
|
36
|
+
@steps << new_step
|
37
|
+
@current_step_number += 1
|
38
|
+
end
|
39
|
+
|
40
|
+
# Executes the calls to redis in one block here.
|
41
|
+
def execute
|
42
|
+
$redis.multi do
|
43
|
+
steps.each do |step|
|
44
|
+
step.execute
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def transaction_queue
|
50
|
+
transaction_queue = []
|
51
|
+
steps.each do |step|
|
52
|
+
transaction_queue.concat(step.queue)
|
53
|
+
end
|
54
|
+
transaction_queue
|
55
|
+
end
|
56
|
+
|
57
|
+
def add_to_queue(proc)
|
58
|
+
current_step.add_to_queue(proc)
|
59
|
+
end
|
60
|
+
|
61
|
+
alias :queue :transaction_queue
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
def current_step
|
66
|
+
steps[current_step_number-1]
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
class PatriarchTransactionStepInstanciationException < Exception
|
4
|
+
end
|
5
|
+
|
6
|
+
class Patriarch::TransactionServices::TransactionManagerService < Patriarch::ManagerService
|
7
|
+
# Fill with logic to manage ressources with transactions ...
|
8
|
+
# Can registers transactions and so on ...
|
9
|
+
def new_transaction(type)
|
10
|
+
id = Time.now.to_f
|
11
|
+
Patriarch::Transaction.new(type,id)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Patriarch::TransactionStep
|
2
|
+
attr_accessor :context, :queue
|
3
|
+
|
4
|
+
def initialize(relation_type,actor,target,medium)
|
5
|
+
@context = {
|
6
|
+
:relation_type => relation_type,
|
7
|
+
:actor_type => actor.class.name.underscore.to_sym,
|
8
|
+
:target_type => target.class.name.underscore.to_sym,
|
9
|
+
:actor_id => actor.id,
|
10
|
+
:target_id => target.id,
|
11
|
+
}
|
12
|
+
@queue = []
|
13
|
+
end
|
14
|
+
|
15
|
+
# defines access methods to context fields letting it be encapsulated nicely
|
16
|
+
[:relation_type,:actor_type,:target_type,:actor_id,:target_id].each do |context_key|
|
17
|
+
define_method(context_key) do
|
18
|
+
context[context_key]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def actor
|
23
|
+
actor_type.to_s.camelize.constantize.find actor_id
|
24
|
+
end
|
25
|
+
|
26
|
+
def target
|
27
|
+
target_type.to_s.camelize.constantize.find target_id
|
28
|
+
end
|
29
|
+
|
30
|
+
def execute
|
31
|
+
queue.each do |redis_instruction|
|
32
|
+
redis_instruction.call
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_to_queue(proc)
|
37
|
+
queue << proc
|
38
|
+
end
|
39
|
+
end
|
data/lib/patriarch/version.rb
CHANGED
data/patriarch.gemspec
CHANGED
@@ -6,12 +6,15 @@ Gem::Specification.new do |spec|
|
|
6
6
|
spec.email = ["hugo@blackbid.co"]
|
7
7
|
spec.description = %q{Patriach is about adding behaviours on the fly to good old active record models.}
|
8
8
|
spec.summary = %q{Manage relationships between instances of your models easily}
|
9
|
-
spec.homepage = "https://github.com/
|
9
|
+
spec.homepage = "https://github.com/giglemad/patriarch"
|
10
10
|
|
11
11
|
spec.platform = Gem::Platform::RUBY
|
12
12
|
spec.licenses = ['MIT']
|
13
|
+
|
14
|
+
spec.add_development_dependency "rspec"
|
15
|
+
spec.add_runtime_dependency "redis-objects"
|
13
16
|
|
14
|
-
|
17
|
+
spec.files = `git ls-files`.split($\)
|
15
18
|
spec.executables = spec.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
20
|
spec.name = "patriarch"
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe Patriarch::Behaviours do
|
5
|
+
|
6
|
+
# setup with empty fake klasses here
|
7
|
+
|
8
|
+
class ModelClass;
|
9
|
+
include Patriarch::Behaviours
|
10
|
+
end
|
11
|
+
|
12
|
+
class ModelKlass;
|
13
|
+
include Patriarch::Behaviours
|
14
|
+
end
|
15
|
+
|
16
|
+
ModelClass.add_behaviour :like, :on => [:modelKlass]
|
17
|
+
ModelKlass.add_behaviour :like, :by => [:modelClass]
|
18
|
+
|
19
|
+
|
20
|
+
context "when adding a behaviour" do
|
21
|
+
it "should implement basic tool methods" do
|
22
|
+
progressive_like = (Verbs::Conjugator.conjugate :like, :aspect => :progressive).split(/ /).last
|
23
|
+
ModelClass.new.should respond_to("#{"model_klass".pluralize}_i_like")
|
24
|
+
ModelClass.new.should respond_to("#{"model_klass".pluralize}_i_like_ids")
|
25
|
+
ModelKlass.new.should respond_to("#{"model_class".pluralize}_#{progressive_like}_me")
|
26
|
+
ModelKlass.new.should respond_to("#{"model_class".pluralize}_#{progressive_like}_me_ids")
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should implement actions only on model being added behaviours with ':on' options" do
|
30
|
+
mc = ModelClass.new
|
31
|
+
mk = ModelKlass.new
|
32
|
+
mc.should respond_to(:like)
|
33
|
+
mc.should respond_to(:undo_like)
|
34
|
+
mk.should_not respond_to(:like)
|
35
|
+
mk.should_not respond_to(:undo_like)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "when using an added behaviour" do
|
40
|
+
User.add_behaviour :smoke, :on => [:User]
|
41
|
+
User.add_behaviour :smoke, :by => [:User]
|
42
|
+
|
43
|
+
before(:all) do
|
44
|
+
@userA = create_user
|
45
|
+
@userB = create_user
|
46
|
+
@userA.smoke @userB
|
47
|
+
end
|
48
|
+
|
49
|
+
it "shall play the transaction nicely" do
|
50
|
+
@userA.users_i_smoke.should == [@userB]
|
51
|
+
@userB.users_smoking_me.should == [@userA]
|
52
|
+
|
53
|
+
@userA.users_i_smoke_ids.should == [@userB.id]
|
54
|
+
@userB.users_smoking_me_ids.should == [@userA.id]
|
55
|
+
end
|
56
|
+
|
57
|
+
it "shall play reverse transaction nicely" do
|
58
|
+
@userA.undo_smoke @userB
|
59
|
+
@userA.users_i_smoke.include?(@userB).should be_false
|
60
|
+
@userB.users_smoking_me.include?(@userA).should be_false
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
# @userA.users_i_smoke_ids.should be_empty
|
65
|
+
#@userB.users_smoking_me_ids.should be_empty
|
66
|
+
end
|
67
|
+
|
68
|
+
after(:all) do
|
69
|
+
@userA.undo_smoke @userB
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Patriarch::DAOServices::BipartiteRelationshipBuilderService do
|
4
|
+
before(:each) do
|
5
|
+
@instance = Patriarch::DAOServices::BipartiteRelationshipBuilderService.instance
|
6
|
+
@user = create_user
|
7
|
+
@item = create_item(@user)
|
8
|
+
@transac ||= Patriarch::TransactionServices::TransactionManagerService.instance.new_transaction(:like)
|
9
|
+
@transac.add_step(:like,@user,@item)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "shall insert processable lambdas into queues when create is called" do
|
13
|
+
# Stubs the DAO retriever service so it gives DAO arrays back
|
14
|
+
dao_sample = {
|
15
|
+
:actor => Redis::SortedSet.new("user:1:redis_likes"),
|
16
|
+
:target => Redis::Set.new("item:1:redis_liker_users")
|
17
|
+
}
|
18
|
+
Patriarch::DAOServices::RetrieverService.instance.stub(:call).with(any_args()).and_return(dao_sample)
|
19
|
+
|
20
|
+
expect{
|
21
|
+
@instance.create(@transac)
|
22
|
+
}.to change{ @transac.transaction_queue.select{ |queue_element| queue_element.is_a? Proc}.size }.by(2)
|
23
|
+
|
24
|
+
expect{
|
25
|
+
@transac.transaction_queue.each{ |proc| proc.call }
|
26
|
+
}.to change{ $redis.keys.size}.by(2)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "shall insert processable lambdas into queues when destroy is called" do
|
30
|
+
# Stubs the DAO retriever service so it gives DAO arrays back
|
31
|
+
dao_sample = {
|
32
|
+
:actor => Redis::SortedSet.new("user:1:redis_likes"),
|
33
|
+
:target => Redis::Set.new("item:1:redis_liker_users")
|
34
|
+
}
|
35
|
+
Patriarch::DAOServices::RetrieverService.instance.stub(:call).with(any_args()).and_return(dao_sample)
|
36
|
+
|
37
|
+
|
38
|
+
expect{
|
39
|
+
@instance.destroy(@transac)
|
40
|
+
}.to change{ @transac.transaction_queue.select{ |queue_element| queue_element.is_a? Proc}.size }.by(2)
|
41
|
+
|
42
|
+
expect{
|
43
|
+
@transac.transaction_queue.each{ |proc| proc.call }
|
44
|
+
}.to change{ $redis.info["total_commands_processed"].to_i}.by(3)
|
45
|
+
end
|
46
|
+
|
47
|
+
after(:each) do
|
48
|
+
$redis.del "user:#{@user.id}:redis_likes"
|
49
|
+
$redis.del "item:#{@item.id}:redis_liker_users"
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "reclip cleaner" do
|
4
|
+
before (:each) do
|
5
|
+
@recliper_user = create_user
|
6
|
+
@item = create_item(create_user)
|
7
|
+
@recliped_on_user = create_user
|
8
|
+
@recliper_user.reclip(@item,@recliped_on_user)
|
9
|
+
@reclip_id = @item.reclips_of_me_reclips_ids.first
|
10
|
+
end
|
11
|
+
|
12
|
+
it "shall clean reclips everywhere when given a single item" do
|
13
|
+
Patriarch::Behaviours::Reclip.clean_reclip_id(@reclip_id)
|
14
|
+
|
15
|
+
@recliped_on_user.reclipeds_on_me_reclips_ids.include?(@reclip_id).should be_false
|
16
|
+
@recliper_user.reclipeds_by_me_reclips_ids.include?(@reclip_id).should be_false
|
17
|
+
@item.reclips_of_me_reclips_ids.include?(@reclip_id).should be_false
|
18
|
+
end
|
19
|
+
|
20
|
+
it "shall clean all the reclip stuff (on him, by him) of a given user properly" do
|
21
|
+
pending('like the test above but in the adequate loop')
|
22
|
+
end
|
23
|
+
|
24
|
+
it "shall clean all the reclip stuff (on him, by him) of a given group properly" do
|
25
|
+
pending('like the test above but in the adequate loop')
|
26
|
+
end
|
27
|
+
|
28
|
+
it "shall clean all the reclip stuff of a given item properly" do
|
29
|
+
pending('like the test above but in the adequate loop')
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Patriarch::Services do
|
4
|
+
before (:each) do
|
5
|
+
@user = create_user
|
6
|
+
@item = create_item(@user)
|
7
|
+
end
|
8
|
+
|
9
|
+
context "LikeService" do
|
10
|
+
it "should register like informations properly" do
|
11
|
+
# Wrong way of doing tests, test should not know about what's inside ...
|
12
|
+
Patriarch::Services::Like::ManagerService.instance.resolve(@user,@item)
|
13
|
+
Redis::SortedSet.new("user:#{@user.id}:redis_likes").members.include?(@item.id.to_s).should be_true
|
14
|
+
Redis::SortedSet.new("item:#{@item.id}:redis_liker_users").members.include?(@user.id.to_s).should be_true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "reclip" do
|
4
|
+
before (:each) do
|
5
|
+
@recliper_user = create_user
|
6
|
+
@item = create_item(create_user)
|
7
|
+
@recliped_on_user = create_user
|
8
|
+
end
|
9
|
+
|
10
|
+
it "stores informations in redis properly" do
|
11
|
+
@recliper_user.reclip(@item,@recliped_on_user)
|
12
|
+
|
13
|
+
# Guy being recliped on remembers it
|
14
|
+
@recliped_on_user.reclipeds_on_me.should == [@item]
|
15
|
+
# Recliper remembers the reclip it did
|
16
|
+
@recliper_user.reclipeds_by_me.should == [@item]
|
17
|
+
|
18
|
+
# Item
|
19
|
+
@recliper_user.reclipeds_by_me.should have(1).reclip_hash
|
20
|
+
end
|
21
|
+
|
22
|
+
it "only updates information when clipped twice" do
|
23
|
+
@recliper_user.reclip(@item,@recliped_on_user)
|
24
|
+
old_time = @recliper_user.reclipeds_by_me(:with_scores => true).first[1]
|
25
|
+
@recliper_user.reclip(@item,@recliped_on_user)
|
26
|
+
new_time = @recliper_user.reclipeds_by_me(:with_scores => true).first[1]
|
27
|
+
|
28
|
+
new_time.should_not eq(old_time)
|
29
|
+
|
30
|
+
# Guy being recliped on remembers it
|
31
|
+
@recliped_on_user.reclipeds_on_me.should == [@item]
|
32
|
+
# Recliper remembers the reclip it did
|
33
|
+
@recliper_user.reclipeds_by_me.should == [@item]
|
34
|
+
|
35
|
+
# Item
|
36
|
+
@recliper_user.reclipeds_by_me.should have(1).reclip_hash
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Patriarch::DAOServices::RedisMapperService do
|
4
|
+
before(:each) do
|
5
|
+
@instance = Patriarch::DAOServices::RedisMapperService.instance
|
6
|
+
@context = {:relation_type => :like, :actor_type => :user, :target_type => :item,
|
7
|
+
:actor_id => 1, :target_id => 1}
|
8
|
+
@transaction_item = double()
|
9
|
+
@transaction_item.stub(:context).and_return(@context)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "shall retrieve right DAO information" do
|
13
|
+
@instance.call(@transaction_item,:actor).should eq({:type => "sorted_set", :key => "redis_likes"})
|
14
|
+
@instance.call(@transaction_item,:target).should eq({:type => "sorted_set", :key => "redis_liker_users"})
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Patriarch::DAOServices::RetrieverService do
|
4
|
+
before(:each) do
|
5
|
+
@instance = Patriarch::DAOServices::RetrieverService.instance
|
6
|
+
@context = {:relation_type => :like, :actor_type => :user, :target_type => :item,
|
7
|
+
:actor_id => 1, :target_id => 1}
|
8
|
+
@transaction_item = double()
|
9
|
+
@transaction_item.stub(:actor_id).and_return(@context[:actor_id])
|
10
|
+
@transaction_item.stub(:actor_type).and_return(@context[:actor_type])
|
11
|
+
@transaction_item.stub(:target_type).and_return(@context[:target_type])
|
12
|
+
@transaction_item.stub(:target_id).and_return(@context[:target_id])
|
13
|
+
end
|
14
|
+
|
15
|
+
it "shall return nice Redis::Object instances" do
|
16
|
+
Patriarch::DAOServices::RedisMapperService.instance.should_receive(:call).twice.with(any_args()).and_return({:type => "sorted_set", :key =>"abc"})
|
17
|
+
dao_tab = @instance.call(@transaction_item)
|
18
|
+
|
19
|
+
dao_tab[:actor].key.should == "user:1:abc"
|
20
|
+
dao_tab[:actor].is_a?(Redis::SortedSet).should be_true
|
21
|
+
|
22
|
+
dao_tab[:target].key.should == "item:1:abc"
|
23
|
+
dao_tab[:target].is_a?(Redis::SortedSet).should be_true
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
it "shall reject types that are not suited" do
|
28
|
+
Patriarch::DAOServices::RedisMapperService.instance.should_receive(:call).with(any_args()).and_return({:type => "sorted", :key =>"abc"})
|
29
|
+
expect{
|
30
|
+
@instance.call(@transaction_item)
|
31
|
+
}.to raise_error(InvalidRedisTypeException)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
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.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,29 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
date: 2012-11-25 00:00:00.000000000 Z
|
13
|
-
dependencies:
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &23131200 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *23131200
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: redis-objects
|
27
|
+
requirement: &23130660 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *23130660
|
14
36
|
description: Patriach is about adding behaviours on the fly to good old active record
|
15
37
|
models.
|
16
38
|
email:
|
@@ -24,10 +46,42 @@ files:
|
|
24
46
|
- LICENSE
|
25
47
|
- README.md
|
26
48
|
- Rakefile
|
49
|
+
- lib/generators/patriarch/USAGE
|
50
|
+
- lib/generators/patriarch/patriarch_generator.rb
|
51
|
+
- lib/generators/patriarch/templates/after_manager_service.rb
|
52
|
+
- lib/generators/patriarch/templates/after_service.rb
|
53
|
+
- lib/generators/patriarch/templates/authorization_service.rb
|
54
|
+
- lib/generators/patriarch/templates/before_manager_service.rb
|
55
|
+
- lib/generators/patriarch/templates/before_service.rb
|
56
|
+
- lib/generators/patriarch/templates/empty_behaviour_module.rb
|
57
|
+
- lib/generators/patriarch/templates/manager_service.rb
|
58
|
+
- lib/generators/patriarch/templates/service.rb
|
59
|
+
- lib/generators/patriarch/templates/tools_methods.rb
|
60
|
+
- lib/generators/patriarch/templates/undo_service.rb
|
27
61
|
- lib/patriarch.rb
|
62
|
+
- lib/patriarch/authorization_service.rb
|
63
|
+
- lib/patriarch/behaviours.rb
|
64
|
+
- lib/patriarch/dao_services/.DAOinstancier.rb.swp
|
65
|
+
- lib/patriarch/dao_services/bipartite_relationship_builder_service.rb
|
66
|
+
- lib/patriarch/dao_services/redis_mapper_service.rb
|
67
|
+
- lib/patriarch/dao_services/retriever_service.rb
|
68
|
+
- lib/patriarch/manager_service.rb
|
69
|
+
- lib/patriarch/service.rb
|
70
|
+
- lib/patriarch/tool_services/redis_cleaner.rb
|
71
|
+
- lib/patriarch/tool_services/redis_extractor_service.rb
|
72
|
+
- lib/patriarch/transaction.rb
|
73
|
+
- lib/patriarch/transaction_services/transaction_manager_service.rb
|
74
|
+
- lib/patriarch/transaction_step.rb
|
28
75
|
- lib/patriarch/version.rb
|
29
76
|
- patriarch.gemspec
|
30
|
-
|
77
|
+
- spec/lib/patriarch/add_behaviour_spec.rb
|
78
|
+
- spec/lib/patriarch/bipartite_relationship_builder_spec.rb
|
79
|
+
- spec/lib/patriarch/clean_reclip_spec.rb
|
80
|
+
- spec/lib/patriarch/like_service_spec.rb
|
81
|
+
- spec/lib/patriarch/reclip_spec.rb
|
82
|
+
- spec/lib/patriarch/redis_mapper_service_spec.rb
|
83
|
+
- spec/lib/patriarch/retriever_service_spec.rb
|
84
|
+
homepage: https://github.com/giglemad/patriarch
|
31
85
|
licenses:
|
32
86
|
- MIT
|
33
87
|
post_install_message:
|
@@ -52,4 +106,11 @@ rubygems_version: 1.8.10
|
|
52
106
|
signing_key:
|
53
107
|
specification_version: 3
|
54
108
|
summary: Manage relationships between instances of your models easily
|
55
|
-
test_files:
|
109
|
+
test_files:
|
110
|
+
- spec/lib/patriarch/add_behaviour_spec.rb
|
111
|
+
- spec/lib/patriarch/bipartite_relationship_builder_spec.rb
|
112
|
+
- spec/lib/patriarch/clean_reclip_spec.rb
|
113
|
+
- spec/lib/patriarch/like_service_spec.rb
|
114
|
+
- spec/lib/patriarch/reclip_spec.rb
|
115
|
+
- spec/lib/patriarch/redis_mapper_service_spec.rb
|
116
|
+
- spec/lib/patriarch/retriever_service_spec.rb
|