patriarch 0.0.1 → 0.0.2
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/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
         |