rulz 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +154 -0
- data/Rakefile +1 -0
- data/lib/rulz.rb +46 -0
- data/lib/rulz/action.rb +18 -0
- data/lib/rulz/attribute.rb +40 -0
- data/lib/rulz/condition.rb +21 -0
- data/lib/rulz/conditions/comparison.rb +52 -0
- data/lib/rulz/conditions/conditions.rb +19 -0
- data/lib/rulz/conditions/container.rb +35 -0
- data/lib/rulz/conditions/string.rb +47 -0
- data/lib/rulz/definer.rb +24 -0
- data/lib/rulz/evaluator.rb +123 -0
- data/lib/rulz/rule.rb +21 -0
- data/lib/rulz/version.rb +3 -0
- data/rulz.gemspec +26 -0
- data/spec/action_spec.rb +38 -0
- data/spec/condition_spec.rb +110 -0
- data/spec/rule_spec.rb +270 -0
- data/spec/spec_helper.rb +20 -0
- metadata +129 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA1:
         | 
| 3 | 
            +
              metadata.gz: e6ec3d9f0c732273a67886c4c81dc2c6dac0dbf2
         | 
| 4 | 
            +
              data.tar.gz: f11c3808909d9eaa72bfaa51aaf55f94ba819896
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: b1bf5422a9b0552094b4504d9f8a5c3952702f30ddd31538059bf2588d909877becc6487e35cca2e74d379a52399ab93f768b273a0bcb8fe81084a04dabfcc8d
         | 
| 7 | 
            +
              data.tar.gz: 5cc2faa66281dd963a983ab2fdf6625278d7a258ba8bb4aa0336971fd3f2ecc6614841a77ef5a5a9421d56f9ad4e39cb85596c1eda1395094248b10373f549dc
         | 
    
        data/.gitignore
    ADDED
    
    
    
        data/.rspec
    ADDED
    
    
    
        data/.ruby-gemset
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            rulz
         | 
    
        data/.ruby-version
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            2.0.0-p195
         | 
    
        data/Gemfile
    ADDED
    
    
    
        data/LICENSE.txt
    ADDED
    
    | @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            Copyright (c) 2013 Chase Conklin
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            MIT License
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining
         | 
| 6 | 
            +
            a copy of this software and associated documentation files (the
         | 
| 7 | 
            +
            "Software"), to deal in the Software without restriction, including
         | 
| 8 | 
            +
            without limitation the rights to use, copy, modify, merge, publish,
         | 
| 9 | 
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 10 | 
            +
            permit persons to whom the Software is furnished to do so, subject to
         | 
| 11 | 
            +
            the following conditions:
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            The above copyright notice and this permission notice shall be
         | 
| 14 | 
            +
            included in all copies or substantial portions of the Software.
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 17 | 
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 18 | 
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| 19 | 
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         | 
| 20 | 
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         | 
| 21 | 
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         | 
| 22 | 
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,154 @@ | |
| 1 | 
            +
            # Rulz
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Rulz is a rule engine for Ruby, allowing developers to define rules in their classes.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ## Installation
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            Add this line to your application's Gemfile:
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                gem 'rulz'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            And then execute:
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                $ bundle
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            Or install it yourself as:
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                $ gem install rulz
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            ## Usage
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            In the model(s) which you want to apply rules to, include the rulz module (you may need to `require` it first):
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            	include Rulz
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            ### Defining Rules
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            #### Conditions and Actions
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            	define_rulz do
         | 
| 30 | 
            +
            		condition "less than" do |other|
         | 
| 31 | 
            +
            			it < other
         | 
| 32 | 
            +
            		end
         | 
| 33 | 
            +
            		condition "contains" do	|other|
         | 
| 34 | 
            +
            			it.contains? other
         | 
| 35 | 
            +
            		end
         | 
| 36 | 
            +
            		action "assign to user" do |user|
         | 
| 37 | 
            +
            			its.user = user
         | 
| 38 | 
            +
            		end
         | 
| 39 | 
            +
            	end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            When defining conditions, it is possible to reference other condition:
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            	condition "not equal to" do |other|
         | 
| 44 | 
            +
            		opposite_of "equal to", other
         | 
| 45 | 
            +
            	end
         | 
| 46 | 
            +
            	
         | 
| 47 | 
            +
            Actions can be combined in a similar way:
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            	action "put on shoes" do
         | 
| 50 | 
            +
            		action "put on socks"
         | 
| 51 | 
            +
            		its.feet << "shoes"
         | 
| 52 | 
            +
            	end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            The following conditions come predefined with rulz:
         | 
| 55 | 
            +
             | 
| 56 | 
            +
            * less than
         | 
| 57 | 
            +
            * greater than
         | 
| 58 | 
            +
            * equal to
         | 
| 59 | 
            +
            * not equal to
         | 
| 60 | 
            +
            * contains
         | 
| 61 | 
            +
            * does not contain
         | 
| 62 | 
            +
            * matches
         | 
| 63 | 
            +
            * does not match
         | 
| 64 | 
            +
            * like
         | 
| 65 | 
            +
            * not like
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            To load these conditions for the whole class `include` any of the following modules
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            * Rulz::Conditions::Comparison
         | 
| 70 | 
            +
            * Rulz::Conditions::Container
         | 
| 71 | 
            +
            * Rulz::Conditions::String
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            To load these conditions for a cetain attribute, call the `type` method inside the attribute block:
         | 
| 74 | 
            +
             | 
| 75 | 
            +
            	define_rulz do
         | 
| 76 | 
            +
            		attribute :foo do
         | 
| 77 | 
            +
            			type :integer
         | 
| 78 | 
            +
            		end
         | 
| 79 | 
            +
            	end
         | 
| 80 | 
            +
            	
         | 
| 81 | 
            +
            The following types are allowed:
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            * integer
         | 
| 84 | 
            +
            * float
         | 
| 85 | 
            +
            * string
         | 
| 86 | 
            +
            * array
         | 
| 87 | 
            +
            * hash
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            #### It
         | 
| 90 | 
            +
             | 
| 91 | 
            +
            "it" refers to the object that the conditions/rules are being applied to. For readability, "it" is aliased to "its"
         | 
| 92 | 
            +
             | 
| 93 | 
            +
            #### Rules
         | 
| 94 | 
            +
             | 
| 95 | 
            +
            	class Number < Fixnum
         | 
| 96 | 
            +
            		define_rulz	do
         | 
| 97 | 
            +
            			condition "even" do
         | 
| 98 | 
            +
            				it % 2 == 0
         | 
| 99 | 
            +
            			end
         | 
| 100 | 
            +
            			condition "odd" do
         | 
| 101 | 
            +
            				opposite_of "even"
         | 
| 102 | 
            +
            			end
         | 
| 103 | 
            +
            			action "make even" do
         | 
| 104 | 
            +
            				it += 1
         | 
| 105 | 
            +
            			end
         | 
| 106 | 
            +
            			rule do
         | 
| 107 | 
            +
            				where("odd") { apply! "make even" }
         | 
| 108 | 
            +
            			end
         | 
| 109 | 
            +
            		end
         | 
| 110 | 
            +
            	end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
            Conditions can also be combined in `where` statements:
         | 
| 113 | 
            +
             | 
| 114 | 
            +
            	rule do
         | 
| 115 | 
            +
            		where(["odd", "AND", "prime"]) { apply! "make even" }
         | 
| 116 | 
            +
            	end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
            Where statements can also accept the attribute method:
         | 
| 119 | 
            +
             | 
| 120 | 
            +
            	rule do
         | 
| 121 | 
            +
            		where :id => "odd" do
         | 
| 122 | 
            +
            			apply! "make even"
         | 
| 123 | 
            +
            		end
         | 
| 124 | 
            +
            	end
         | 
| 125 | 
            +
            	
         | 
| 126 | 
            +
            	rule do
         | 
| 127 | 
            +
            		where :id => ["multiple of", 5] do
         | 
| 128 | 
            +
            			apply! "make even"
         | 
| 129 | 
            +
            		end
         | 
| 130 | 
            +
            	end
         | 
| 131 | 
            +
            	
         | 
| 132 | 
            +
            When options need to be combined:
         | 
| 133 | 
            +
             | 
| 134 | 
            +
            	rule do
         | 
| 135 | 
            +
            		where [{:id => ["multiple of", 5]}, "AND", "odd"] do
         | 
| 136 | 
            +
            			apply! "make even"
         | 
| 137 | 
            +
            		end
         | 
| 138 | 
            +
            	end
         | 
| 139 | 
            +
             | 
| 140 | 
            +
             | 
| 141 | 
            +
            ### Applying Rules
         | 
| 142 | 
            +
             | 
| 143 | 
            +
            To apply rules to a single object, call the `apply_rules!` method like so:
         | 
| 144 | 
            +
             | 
| 145 | 
            +
            	m = Melon.new
         | 
| 146 | 
            +
            	m.apply_rules!
         | 
| 147 | 
            +
             | 
| 148 | 
            +
            ## Contributing
         | 
| 149 | 
            +
             | 
| 150 | 
            +
            1. Fork it
         | 
| 151 | 
            +
            2. Create your feature branch (`git checkout -b my-new-feature`)
         | 
| 152 | 
            +
            3. Commit your changes (`git commit -am 'Add some feature'`)
         | 
| 153 | 
            +
            4. Push to the branch (`git push origin my-new-feature`)
         | 
| 154 | 
            +
            5. Create new Pull Request
         | 
    
        data/Rakefile
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            require "bundler/gem_tasks"
         | 
    
        data/lib/rulz.rb
    ADDED
    
    | @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            require "rulz/version"
         | 
| 2 | 
            +
            require "rulz/definer"
         | 
| 3 | 
            +
            require "rulz/condition"
         | 
| 4 | 
            +
            require "rulz/evaluator"
         | 
| 5 | 
            +
            require "rulz/action"
         | 
| 6 | 
            +
            require "rulz/rule"
         | 
| 7 | 
            +
            require "rulz/conditions/comparison"
         | 
| 8 | 
            +
            require "rulz/conditions/container"
         | 
| 9 | 
            +
            require "rulz/conditions/string"
         | 
| 10 | 
            +
            require "rulz/attribute"
         | 
| 11 | 
            +
            require "rulz/conditions/conditions"
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            module Rulz
         | 
| 14 | 
            +
              
         | 
| 15 | 
            +
              def self.included(base)
         | 
| 16 | 
            +
                base.extend(ClassMethods)
         | 
| 17 | 
            +
                base.send(:include, InstanceMethods)
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
              
         | 
| 20 | 
            +
              module InstanceMethods
         | 
| 21 | 
            +
                def condition_true?(name, *args)
         | 
| 22 | 
            +
                  Rulz::Evaluator::Condition.new(self, name, *args).evaluate
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
                
         | 
| 25 | 
            +
                def condition_false?(name, *args)
         | 
| 26 | 
            +
                  not condition_true?(name, *args)
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
                
         | 
| 29 | 
            +
                def apply!(action, *args)
         | 
| 30 | 
            +
                  Rulz::Evaluator::Action.new(self, action, *args).evaluate
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
                
         | 
| 33 | 
            +
                def apply_rules!
         | 
| 34 | 
            +
                  Rulz::Rule.rules(self.class).each { |rule| rule.apply!(self) }
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
                
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
              
         | 
| 39 | 
            +
              module ClassMethods
         | 
| 40 | 
            +
              
         | 
| 41 | 
            +
                def define_rulz(&block)
         | 
| 42 | 
            +
                  Rulz::Definer.new(self).instance_eval &block
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
                
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
            end
         | 
    
        data/lib/rulz/action.rb
    ADDED
    
    | @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            module Rulz
         | 
| 2 | 
            +
              class Action
         | 
| 3 | 
            +
                attr_accessor :name, :proc
         | 
| 4 | 
            +
                
         | 
| 5 | 
            +
                def initialize(name, klass, proc)
         | 
| 6 | 
            +
                  @name = name
         | 
| 7 | 
            +
                  @proc = proc
         | 
| 8 | 
            +
                  klass.instance_exec self do |action|
         | 
| 9 | 
            +
                    @rulz_actions ||= []
         | 
| 10 | 
            +
                    @rulz_actions << action
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
                
         | 
| 14 | 
            +
                def self.find(klass, name)
         | 
| 15 | 
            +
                  klass.instance_variable_get(:@rulz_actions).find {|c| c.name == name }
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            module Rulz
         | 
| 2 | 
            +
              module Attribute
         | 
| 3 | 
            +
                class Block
         | 
| 4 | 
            +
                  def initialize(attr, klass, &block)
         | 
| 5 | 
            +
                    @attr = attr
         | 
| 6 | 
            +
                    @klass = klass
         | 
| 7 | 
            +
                    instance_eval &block
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
                  
         | 
| 10 | 
            +
                  def condition(name, &block)
         | 
| 11 | 
            +
                    Rulz::Attribute::Condition.new(@klass, @attr, name, block)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                  
         | 
| 14 | 
            +
                  def type(kind)
         | 
| 15 | 
            +
                    Rulz::Conditions.load_conditions(@klass, @attr, kind)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                  
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
                
         | 
| 20 | 
            +
                class Condition
         | 
| 21 | 
            +
                  attr_reader :name, :proc
         | 
| 22 | 
            +
                  def initialize(klass, attr, name, proc)
         | 
| 23 | 
            +
                    @name = name
         | 
| 24 | 
            +
                    @proc = proc
         | 
| 25 | 
            +
                    klass.instance_exec self do |condition|
         | 
| 26 | 
            +
                      conditions = instance_variable_get("@rulz_#{attr}_conditions") || []
         | 
| 27 | 
            +
                      conditions << condition
         | 
| 28 | 
            +
                      instance_variable_set("@rulz_#{attr}_conditions", conditions) 
         | 
| 29 | 
            +
                    end        
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                
         | 
| 32 | 
            +
                  def self.find(klass, attr, name)
         | 
| 33 | 
            +
                    result = klass.instance_variable_get("@rulz_#{attr}_conditions").find {|c| c.name == name }
         | 
| 34 | 
            +
                    raise ArgumentError, "Condition '#{name}' for '#{attr}' does not exist" unless result
         | 
| 35 | 
            +
                    result
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                  
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            module Rulz
         | 
| 2 | 
            +
              class Condition
         | 
| 3 | 
            +
                attr_accessor :name, :proc
         | 
| 4 | 
            +
                
         | 
| 5 | 
            +
                def initialize(name, klass, proc)
         | 
| 6 | 
            +
                  @name = name
         | 
| 7 | 
            +
                  @proc = proc
         | 
| 8 | 
            +
                  klass.instance_exec self do |condition|
         | 
| 9 | 
            +
                    @rulz_conditions ||= []
         | 
| 10 | 
            +
                    @rulz_conditions << condition 
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
                
         | 
| 14 | 
            +
                def self.find(klass, name)
         | 
| 15 | 
            +
                  result = klass.instance_eval { @rulz_conditions }.find {|c| c.name == name }
         | 
| 16 | 
            +
                  raise ArgumentError, "Condition '#{name}' does not exist" unless result
         | 
| 17 | 
            +
                  result
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
                
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
| @@ -0,0 +1,52 @@ | |
| 1 | 
            +
            module Rulz
         | 
| 2 | 
            +
              module Conditions    
         | 
| 3 | 
            +
                module Comparison
         | 
| 4 | 
            +
                  
         | 
| 5 | 
            +
                  def self.load_conditions(reciever, attr)
         | 
| 6 | 
            +
                    reciever.class_eval do
         | 
| 7 | 
            +
                      define_rulz do
         | 
| 8 | 
            +
                        attribute attr do
         | 
| 9 | 
            +
                          condition "greater than" do |other|
         | 
| 10 | 
            +
                            send(attr) > other
         | 
| 11 | 
            +
                          end
         | 
| 12 | 
            +
                    
         | 
| 13 | 
            +
                          condition "less than" do |other|
         | 
| 14 | 
            +
                            send(attr) < other
         | 
| 15 | 
            +
                          end
         | 
| 16 | 
            +
                    
         | 
| 17 | 
            +
                          condition "equal to" do |other|
         | 
| 18 | 
            +
                            send(attr) == other
         | 
| 19 | 
            +
                          end
         | 
| 20 | 
            +
                    
         | 
| 21 | 
            +
                          condition "not equal to" do |other|
         | 
| 22 | 
            +
                            opposite_of "equal to", other
         | 
| 23 | 
            +
                          end              
         | 
| 24 | 
            +
                        end
         | 
| 25 | 
            +
                      end
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                  
         | 
| 29 | 
            +
                  def self.included(base)
         | 
| 30 | 
            +
                    base.class_eval do
         | 
| 31 | 
            +
                      define_rulz do        
         | 
| 32 | 
            +
                        condition "greater than" do |other|
         | 
| 33 | 
            +
                          it > other
         | 
| 34 | 
            +
                        end
         | 
| 35 | 
            +
                    
         | 
| 36 | 
            +
                        condition "less than" do |other|
         | 
| 37 | 
            +
                          it < other
         | 
| 38 | 
            +
                        end
         | 
| 39 | 
            +
                    
         | 
| 40 | 
            +
                        condition "equal to" do |other|
         | 
| 41 | 
            +
                          it == other
         | 
| 42 | 
            +
                        end
         | 
| 43 | 
            +
                    
         | 
| 44 | 
            +
                        condition "not equal to" do |other|
         | 
| 45 | 
            +
                          opposite_of "equal to", other
         | 
| 46 | 
            +
                        end
         | 
| 47 | 
            +
                      end
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            module Rulz
         | 
| 2 | 
            +
              module Conditions
         | 
| 3 | 
            +
                def self.load_conditions(reciever, attribute, kind)
         | 
| 4 | 
            +
                  case kind
         | 
| 5 | 
            +
                  when :integer
         | 
| 6 | 
            +
                    Comparison.load_conditions(reciever, attribute)
         | 
| 7 | 
            +
                  when :float
         | 
| 8 | 
            +
                    Comparison.load_conditions(reciever, attribute)
         | 
| 9 | 
            +
                  when :string
         | 
| 10 | 
            +
                    Container.load_conditions(reciever, attribute)
         | 
| 11 | 
            +
                    String.load_conditions(reciever, attribute)
         | 
| 12 | 
            +
                  when :array
         | 
| 13 | 
            +
                    Container.load_conditions(reciever, attribute)
         | 
| 14 | 
            +
                  when :hash
         | 
| 15 | 
            +
                    Container.load_conditions(reciever, attribute)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            module Rulz
         | 
| 2 | 
            +
              module Conditions
         | 
| 3 | 
            +
                module Container
         | 
| 4 | 
            +
                  
         | 
| 5 | 
            +
                  def self.load_conditions(reciever, attr)
         | 
| 6 | 
            +
                    reciever.class_eval do
         | 
| 7 | 
            +
                      define_rulz do
         | 
| 8 | 
            +
                        attribute attr do
         | 
| 9 | 
            +
                          condition "contains" do |other|
         | 
| 10 | 
            +
                            send(attr).include? other
         | 
| 11 | 
            +
                          end
         | 
| 12 | 
            +
                          condition "does not contain" do |other|
         | 
| 13 | 
            +
                            opposite_of "contains", other
         | 
| 14 | 
            +
                          end
         | 
| 15 | 
            +
                        end
         | 
| 16 | 
            +
                      end
         | 
| 17 | 
            +
                    end
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                  
         | 
| 20 | 
            +
                  
         | 
| 21 | 
            +
                  def self.included(base)
         | 
| 22 | 
            +
                    base.class_eval do
         | 
| 23 | 
            +
                      define_rulz do
         | 
| 24 | 
            +
                        condition "contains" do |other|
         | 
| 25 | 
            +
                          it.include? other
         | 
| 26 | 
            +
                        end
         | 
| 27 | 
            +
                        condition "does not contain" do |other|
         | 
| 28 | 
            +
                          opposite_of "contains", other
         | 
| 29 | 
            +
                        end
         | 
| 30 | 
            +
                      end
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1,47 @@ | |
| 1 | 
            +
            module Rulz
         | 
| 2 | 
            +
              module Conditions
         | 
| 3 | 
            +
                module String
         | 
| 4 | 
            +
                  
         | 
| 5 | 
            +
                  def self.load_conditions(reciever, attr)
         | 
| 6 | 
            +
                    reciever.class_eval do
         | 
| 7 | 
            +
                      define_rulz do
         | 
| 8 | 
            +
                        attribute attr do
         | 
| 9 | 
            +
                          condition "does not match" do |regex|
         | 
| 10 | 
            +
                            send(attr).scan(regex).empty?
         | 
| 11 | 
            +
                          end
         | 
| 12 | 
            +
                          condition "matches" do |regex|
         | 
| 13 | 
            +
                            opposite_of "does not match", regex
         | 
| 14 | 
            +
                          end
         | 
| 15 | 
            +
                          condition "like" do |other|
         | 
| 16 | 
            +
                            send(attr).downcase == other.downcase
         | 
| 17 | 
            +
                          end
         | 
| 18 | 
            +
                          condition "not like" do |other|
         | 
| 19 | 
            +
                            opposite_of "like", other
         | 
| 20 | 
            +
                          end
         | 
| 21 | 
            +
                        end
         | 
| 22 | 
            +
                      end
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                  
         | 
| 26 | 
            +
                  def self.included(base)
         | 
| 27 | 
            +
                    base.class_eval do
         | 
| 28 | 
            +
                      include Rulz::Conditions::Container
         | 
| 29 | 
            +
                      define_rulz do
         | 
| 30 | 
            +
                        condition "does not match" do |regex|
         | 
| 31 | 
            +
                          it.scan(regex).empty?
         | 
| 32 | 
            +
                        end
         | 
| 33 | 
            +
                        condition "matches" do |regex|
         | 
| 34 | 
            +
                          opposite_of "does not match", regex
         | 
| 35 | 
            +
                        end
         | 
| 36 | 
            +
                        condition "like" do |other|
         | 
| 37 | 
            +
                          it.downcase == other.downcase
         | 
| 38 | 
            +
                        end
         | 
| 39 | 
            +
                        condition "not like" do |other|
         | 
| 40 | 
            +
                          opposite_of "like", other
         | 
| 41 | 
            +
                        end
         | 
| 42 | 
            +
                      end
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
            end
         | 
    
        data/lib/rulz/definer.rb
    ADDED
    
    | @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            module Rulz
         | 
| 2 | 
            +
              class Definer
         | 
| 3 | 
            +
                
         | 
| 4 | 
            +
                def initialize(klass)
         | 
| 5 | 
            +
                  @klass = klass
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
                
         | 
| 8 | 
            +
                def condition(name, &block)
         | 
| 9 | 
            +
                  Rulz::Condition.new(name, @klass, block)
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
                
         | 
| 12 | 
            +
                def action(name, &block)
         | 
| 13 | 
            +
                  Rulz::Action.new(name, @klass, block)
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
                
         | 
| 16 | 
            +
                def rule(&block)
         | 
| 17 | 
            +
                  Rulz::Rule.new(@klass, block)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
                
         | 
| 20 | 
            +
                def attribute(attr, &block)
         | 
| 21 | 
            +
                  Rulz::Attribute::Block.new(attr, @klass, &block)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end  
         | 
| 24 | 
            +
            end 
         | 
| @@ -0,0 +1,123 @@ | |
| 1 | 
            +
            module Rulz
         | 
| 2 | 
            +
              module Evaluator
         | 
| 3 | 
            +
                
         | 
| 4 | 
            +
                class Base
         | 
| 5 | 
            +
                  
         | 
| 6 | 
            +
                  def initialize(receiver, *args)
         | 
| 7 | 
            +
                    @receiver = receiver
         | 
| 8 | 
            +
                    @args = args || []
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
                        
         | 
| 11 | 
            +
                  def it
         | 
| 12 | 
            +
                    @receiver
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
                  
         | 
| 15 | 
            +
                  alias :its :it
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
                
         | 
| 18 | 
            +
                class Condition < Evaluator::Base
         | 
| 19 | 
            +
                  def initialize(receiver, name, *args)
         | 
| 20 | 
            +
                    @condition = Rulz::Condition.find(receiver.class, name)
         | 
| 21 | 
            +
                    super(receiver, *args)
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                  
         | 
| 24 | 
            +
                  
         | 
| 25 | 
            +
                  def condition(name, *args)
         | 
| 26 | 
            +
                    Rulz::Evaluator::Condition.new(@receiver, name, *args).evaluate
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                  
         | 
| 29 | 
            +
                  def opposite_of(name, *args)
         | 
| 30 | 
            +
                    not condition(name, *args)
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                  
         | 
| 33 | 
            +
                  def evaluate
         | 
| 34 | 
            +
                    instance_exec(*@args, &@condition.proc)
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                  
         | 
| 37 | 
            +
                    
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
                
         | 
| 40 | 
            +
                class AttributeCondition < Evaluator::Base
         | 
| 41 | 
            +
                  def initialize(receiver, attribute, name, *args)
         | 
| 42 | 
            +
                    @condition = Rulz::Attribute::Condition.find(receiver.class, attribute, name)
         | 
| 43 | 
            +
                    super(receiver, *args)
         | 
| 44 | 
            +
                    define_singleton_method attribute do
         | 
| 45 | 
            +
                      @receiver.send(attribute)
         | 
| 46 | 
            +
                    end
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                  
         | 
| 49 | 
            +
                  def evaluate
         | 
| 50 | 
            +
                    instance_exec(*@args, &@condition.proc)
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
                  
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
                
         | 
| 55 | 
            +
                class Action < Evaluator::Base
         | 
| 56 | 
            +
                  def initialize(receiver, name, *args)
         | 
| 57 | 
            +
                    @action = Rulz::Action.find(receiver.class, name)
         | 
| 58 | 
            +
                    super(receiver, *args)
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                  
         | 
| 61 | 
            +
                  def evaluate
         | 
| 62 | 
            +
                    instance_exec(*@args, &@action.proc)
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                  
         | 
| 65 | 
            +
                  def action(name, *args)
         | 
| 66 | 
            +
                    Rulz::Evaluator::Action.new(@receiver, name, *args).evaluate
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
                  
         | 
| 69 | 
            +
                  
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
                
         | 
| 72 | 
            +
                class Rule < Evaluator::Base
         | 
| 73 | 
            +
                  def initialize(receiver, proc)
         | 
| 74 | 
            +
                    @receiver = receiver
         | 
| 75 | 
            +
                    @proc = proc
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
                  
         | 
| 78 | 
            +
                  def evaluate
         | 
| 79 | 
            +
                    instance_eval(&@proc)
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
                  
         | 
| 82 | 
            +
                  def where(condition, *args, &block)
         | 
| 83 | 
            +
                    if condition.is_a? String
         | 
| 84 | 
            +
                      @receiver.instance_eval(&block) if Rulz::Evaluator::Condition.new(@receiver, condition, *args).evaluate
         | 
| 85 | 
            +
                    elsif condition.is_a? Proc
         | 
| 86 | 
            +
                      @receiver.instance_eval(&block) if condition.call(*args)
         | 
| 87 | 
            +
                    elsif condition.is_a? Array
         | 
| 88 | 
            +
                      raise ArgumentError, "Invalid condition" unless condition.include? "AND" or condition.include? "OR"
         | 
| 89 | 
            +
                      split_condition = condition.inject([[]]) do |results, element|
         | 
| 90 | 
            +
                        if ["AND", "OR"].include? element
         | 
| 91 | 
            +
                          results << {"AND" => "&&", "OR" => "||"}[element]
         | 
| 92 | 
            +
                          results << []
         | 
| 93 | 
            +
                        elsif element.is_a?(Hash)
         | 
| 94 | 
            +
                          results.pop if results.last.respond_to?(:empty?) && results.last.empty? 
         | 
| 95 | 
            +
                          results << element
         | 
| 96 | 
            +
                        else
         | 
| 97 | 
            +
                          results.last << element
         | 
| 98 | 
            +
                        end
         | 
| 99 | 
            +
                        results
         | 
| 100 | 
            +
                      end
         | 
| 101 | 
            +
                      split_condition.map! do |element|
         | 
| 102 | 
            +
                        if element.is_a?(Array)
         | 
| 103 | 
            +
                          Rulz::Evaluator::Condition.new(@receiver, *element).evaluate
         | 
| 104 | 
            +
                        elsif element.is_a?(Hash)
         | 
| 105 | 
            +
                          attribute, element = *element.first
         | 
| 106 | 
            +
                          Rulz::Evaluator::AttributeCondition.new(@receiver, attribute, *element).evaluate
         | 
| 107 | 
            +
                        else
         | 
| 108 | 
            +
                          element
         | 
| 109 | 
            +
                        end
         | 
| 110 | 
            +
                      end
         | 
| 111 | 
            +
                      @receiver.instance_eval(&block) if eval(split_condition.join(" "))
         | 
| 112 | 
            +
                    elsif condition.is_a? Hash
         | 
| 113 | 
            +
                      attribute, condition = *condition.first
         | 
| 114 | 
            +
                      @receiver.instance_eval(&block) if Rulz::Evaluator::AttributeCondition.new(@receiver, attribute, *condition).evaluate
         | 
| 115 | 
            +
                    else
         | 
| 116 | 
            +
                      raise ArgumentError, "Invalid condition"
         | 
| 117 | 
            +
                    end
         | 
| 118 | 
            +
                  end            
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
                
         | 
| 121 | 
            +
              end  
         | 
| 122 | 
            +
            end
         | 
| 123 | 
            +
             | 
    
        data/lib/rulz/rule.rb
    ADDED
    
    | @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            module Rulz
         | 
| 2 | 
            +
              class Rule
         | 
| 3 | 
            +
                attr_accessor :proc
         | 
| 4 | 
            +
                
         | 
| 5 | 
            +
                def initialize(klass, proc)
         | 
| 6 | 
            +
                  @proc = proc
         | 
| 7 | 
            +
                  klass.instance_exec self do |rule| 
         | 
| 8 | 
            +
                    @rulz_rules ||= []
         | 
| 9 | 
            +
                    @rulz_rules << rule
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
                
         | 
| 13 | 
            +
                def apply!(receiver)
         | 
| 14 | 
            +
                  Rulz::Evaluator::Rule.new(receiver, @proc).evaluate
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
                
         | 
| 17 | 
            +
                def self.rules(klass)
         | 
| 18 | 
            +
                  klass.instance_eval { @rulz_rules }
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
    
        data/lib/rulz/version.rb
    ADDED
    
    
    
        data/rulz.gemspec
    ADDED
    
    | @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            # coding: utf-8
         | 
| 2 | 
            +
            lib = File.expand_path('../lib', __FILE__)
         | 
| 3 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 4 | 
            +
            require 'rulz/version'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Gem::Specification.new do |spec|
         | 
| 7 | 
            +
              spec.name          = "rulz"
         | 
| 8 | 
            +
              spec.version       = Rulz::VERSION
         | 
| 9 | 
            +
              spec.authors       = ["Chase Conklin"]
         | 
| 10 | 
            +
              spec.email         = ["chase@conklins.net"]
         | 
| 11 | 
            +
              spec.description   = %q{Rule Engine for Ruby}
         | 
| 12 | 
            +
              spec.summary       = %q{Enables users to create mail-like rules for processing Ruby objects.}
         | 
| 13 | 
            +
              spec.homepage      = ""
         | 
| 14 | 
            +
              spec.license       = "MIT"
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              spec.files         = `git ls-files`.split($/)
         | 
| 17 | 
            +
              spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
         | 
| 18 | 
            +
              spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
         | 
| 19 | 
            +
              spec.require_paths = ["lib"]
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              spec.add_development_dependency "bundler", "~> 1.3"
         | 
| 22 | 
            +
              spec.add_development_dependency "rake"
         | 
| 23 | 
            +
              spec.add_development_dependency "rspec"
         | 
| 24 | 
            +
              spec.add_development_dependency "debugger"
         | 
| 25 | 
            +
              
         | 
| 26 | 
            +
            end
         | 
    
        data/spec/action_spec.rb
    ADDED
    
    | @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            require "spec_helper"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe "action" do
         | 
| 4 | 
            +
              before :all do
         | 
| 5 | 
            +
                
         | 
| 6 | 
            +
                class Person
         | 
| 7 | 
            +
                  attr_accessor :name
         | 
| 8 | 
            +
                  include Rulz
         | 
| 9 | 
            +
                  
         | 
| 10 | 
            +
                  def initialize(name)
         | 
| 11 | 
            +
                    @name = name
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                  
         | 
| 14 | 
            +
                  define_rulz do
         | 
| 15 | 
            +
                    action "add prefix" do |prefix|
         | 
| 16 | 
            +
                      its.name = "#{prefix} #{its.name}"
         | 
| 17 | 
            +
                    end
         | 
| 18 | 
            +
                    
         | 
| 19 | 
            +
                    action "make doctor" do
         | 
| 20 | 
            +
                      action "add prefix", "Dr."
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
                
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
              
         | 
| 27 | 
            +
              it "should act" do
         | 
| 28 | 
            +
                bobby = Person.new("Bobby")
         | 
| 29 | 
            +
                bobby.apply! "add prefix", "Mr."
         | 
| 30 | 
            +
                bobby.name.should == "Mr. Bobby"
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
              
         | 
| 33 | 
            +
              it "should be definable with other actions" do
         | 
| 34 | 
            +
                bobby = Person.new("Bobby")
         | 
| 35 | 
            +
                bobby.apply! "make doctor"
         | 
| 36 | 
            +
                bobby.name.should == "Dr. Bobby"    
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         | 
| @@ -0,0 +1,110 @@ | |
| 1 | 
            +
            require "spec_helper"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe "condition" do
         | 
| 4 | 
            +
              context "application" do
         | 
| 5 | 
            +
                before :all do
         | 
| 6 | 
            +
                  class Person
         | 
| 7 | 
            +
                    include Rulz
         | 
| 8 | 
            +
                    attr_accessor :name, :age
         | 
| 9 | 
            +
                  
         | 
| 10 | 
            +
                    def initialize(name, age)
         | 
| 11 | 
            +
                      @name = name
         | 
| 12 | 
            +
                      @age = age
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                  
         | 
| 15 | 
            +
                    define_rulz do
         | 
| 16 | 
            +
                      condition "older than" do |age|
         | 
| 17 | 
            +
                        its.age > age
         | 
| 18 | 
            +
                      end
         | 
| 19 | 
            +
                    
         | 
| 20 | 
            +
                      condition "younger than" do |age|
         | 
| 21 | 
            +
                        opposite_of "older than", age
         | 
| 22 | 
            +
                      end
         | 
| 23 | 
            +
                    
         | 
| 24 | 
            +
                      condition "middle aged" do
         | 
| 25 | 
            +
                        condition("older than", 40) and condition("younger than", 50)
         | 
| 26 | 
            +
                      end
         | 
| 27 | 
            +
                    
         | 
| 28 | 
            +
                    end      
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              
         | 
| 32 | 
            +
                it "recognizes when conditions are true" do
         | 
| 33 | 
            +
                  billy = Person.new("Billy", 54)
         | 
| 34 | 
            +
                  billy.condition_true?("older than", 50).should be_true
         | 
| 35 | 
            +
                  bobby = Person.new("Bobby", 23)
         | 
| 36 | 
            +
                  bobby.condition_true?("older than", 50).should be_false
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
              
         | 
| 39 | 
            +
                it "recognizes when conditions are false" do
         | 
| 40 | 
            +
                  bilbo = Person.new("Bilbo", 46)
         | 
| 41 | 
            +
                  bilbo.condition_false?("older than", 23).should be_false
         | 
| 42 | 
            +
                  baggins = Person.new("Baggins", 12)
         | 
| 43 | 
            +
                  baggins.condition_false?("older than", 23).should be_true    
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              
         | 
| 46 | 
            +
                it "can define conditions based on other conditions" do
         | 
| 47 | 
            +
                  bobby = Person.new("Bobby", 11)
         | 
| 48 | 
            +
                  bobby.condition_true?("younger than", 13).should be_true
         | 
| 49 | 
            +
                  billy = Person.new("Billy", 45)
         | 
| 50 | 
            +
                  billy.condition_true?("middle aged").should be_true
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
              
         | 
| 54 | 
            +
              context "come predefined in modules" do
         | 
| 55 | 
            +
                before :all do
         | 
| 56 | 
            +
                  class String
         | 
| 57 | 
            +
                    include Rulz
         | 
| 58 | 
            +
                    include Rulz::Conditions::String
         | 
| 59 | 
            +
                    include Rulz::Conditions::Comparison
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
                
         | 
| 63 | 
            +
                it "should recognize contains" do
         | 
| 64 | 
            +
                  "foobar".condition_true?("contains", "bar").should be_true
         | 
| 65 | 
            +
                  "foobar".condition_true?("contains", "baz").should be_false     
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
                
         | 
| 68 | 
            +
                it "should recognize matches" do
         | 
| 69 | 
            +
                  "123".condition_true?("matches", /[0-4][0-4][0-4]/).should be_true
         | 
| 70 | 
            +
                  "baz".condition_true?("matches",  /[0-4][0-4][0-4]/).should be_false
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
                
         | 
| 73 | 
            +
                it "should recognize does not match" do
         | 
| 74 | 
            +
                  "baz".condition_true?("does not match",  /[0-4][0-4][0-4]/).should be_true 
         | 
| 75 | 
            +
                  "123".condition_true?("does not match", /[0-4][0-4][0-4]/).should be_false           
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
                
         | 
| 78 | 
            +
                it "should recognize like" do
         | 
| 79 | 
            +
                  "abc".condition_true?("like", "ABC").should be_true
         | 
| 80 | 
            +
                  "123".condition_true?("like", "ABC").should be_false     
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
                
         | 
| 83 | 
            +
                it "should recognize not like" do
         | 
| 84 | 
            +
                  "123".condition_true?("not like", "ABC").should be_true      
         | 
| 85 | 
            +
                  "abc".condition_true?("not like", "ABC").should be_false
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
                    
         | 
| 88 | 
            +
                it "should recognize equal to" do
         | 
| 89 | 
            +
                  "abc".condition_true?("equal to", "abc").should be_true
         | 
| 90 | 
            +
                  "ABC".condition_true?("equal to", "abc").should be_false
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
                
         | 
| 93 | 
            +
                it "should recognize not equal to" do
         | 
| 94 | 
            +
                  "ABC".condition_true?("not equal to", "abc").should be_true
         | 
| 95 | 
            +
                  "abc".condition_true?("not equal to", "abc").should be_false
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
                
         | 
| 98 | 
            +
                it "should recognize greater than" do
         | 
| 99 | 
            +
                  "b".condition_true?("greater than", "a").should be_true
         | 
| 100 | 
            +
                  "a".condition_true?("greater than", "b").should be_false
         | 
| 101 | 
            +
                end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                it "should recognize less than" do
         | 
| 104 | 
            +
                  "a".condition_true?("less than", "b").should be_true
         | 
| 105 | 
            +
                  "b".condition_true?("less than", "a").should be_false
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
              
         | 
| 108 | 
            +
              end  
         | 
| 109 | 
            +
              
         | 
| 110 | 
            +
            end
         | 
    
        data/spec/rule_spec.rb
    ADDED
    
    | @@ -0,0 +1,270 @@ | |
| 1 | 
            +
            require "spec_helper"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe "rules" do
         | 
| 4 | 
            +
              context "functionality" do
         | 
| 5 | 
            +
                before :all do
         | 
| 6 | 
            +
                  class Person
         | 
| 7 | 
            +
                    attr_accessor :name, :age, :job
         | 
| 8 | 
            +
                    include Rulz
         | 
| 9 | 
            +
                  
         | 
| 10 | 
            +
                    def initialize(name, age, job = nil)
         | 
| 11 | 
            +
                      @name = name
         | 
| 12 | 
            +
                      @age = age
         | 
| 13 | 
            +
                      @job = job
         | 
| 14 | 
            +
                    end
         | 
| 15 | 
            +
                  
         | 
| 16 | 
            +
                    define_rulz do
         | 
| 17 | 
            +
                      condition "older than" do |age|
         | 
| 18 | 
            +
                        its.age > age
         | 
| 19 | 
            +
                      end
         | 
| 20 | 
            +
                      condition "younger than" do |age|
         | 
| 21 | 
            +
                        opposite_of "older than", age
         | 
| 22 | 
            +
                      end
         | 
| 23 | 
            +
                      condition "old" do
         | 
| 24 | 
            +
                        condition "older than", 50
         | 
| 25 | 
            +
                      end
         | 
| 26 | 
            +
                      condition "elderly" do
         | 
| 27 | 
            +
                        condition "older than", 80
         | 
| 28 | 
            +
                      end
         | 
| 29 | 
            +
                      condition "name is" do |name|
         | 
| 30 | 
            +
                        its.name == name
         | 
| 31 | 
            +
                      end
         | 
| 32 | 
            +
                      condition "job is" do |job|
         | 
| 33 | 
            +
                        its.job == job
         | 
| 34 | 
            +
                      end
         | 
| 35 | 
            +
                      action "add prefix" do |prefix|
         | 
| 36 | 
            +
                        its.name = "#{prefix} #{its.name}"
         | 
| 37 | 
            +
                      end
         | 
| 38 | 
            +
                      action "add suffix" do |suffix|
         | 
| 39 | 
            +
                        its.name += " #{suffix}"
         | 
| 40 | 
            +
                      end
         | 
| 41 | 
            +
                      action "add job prefix" do |prefix|
         | 
| 42 | 
            +
                        its.job = "#{prefix} #{its.job}"
         | 
| 43 | 
            +
                      end
         | 
| 44 | 
            +
                      rule do
         | 
| 45 | 
            +
                        where("old") { apply! "add prefix", "Grandpa" }
         | 
| 46 | 
            +
                      end
         | 
| 47 | 
            +
                      rule do
         | 
| 48 | 
            +
                        where("elderly") { apply! "add suffix", "Sr."}
         | 
| 49 | 
            +
                      end
         | 
| 50 | 
            +
                      rule do
         | 
| 51 | 
            +
                        where("younger than", 20) { apply! "add suffix", "Jr."}
         | 
| 52 | 
            +
                      end
         | 
| 53 | 
            +
                      rule do
         | 
| 54 | 
            +
                        where(["name is", "Prometheous", "OR", "name is", "Wisdom"]) { apply! "add suffix", "the wise" }
         | 
| 55 | 
            +
                      end
         | 
| 56 | 
            +
                      rule do
         | 
| 57 | 
            +
                        where(["job is", "Contractor", "AND", "younger than", 40]) { apply! "add job prefix", "Jr."}
         | 
| 58 | 
            +
                      end
         | 
| 59 | 
            +
                      rule do
         | 
| 60 | 
            +
                        where ["job is", "Electrician", "OR", "name is", "Bobby", "AND", "job is", "Contractor"] do
         | 
| 61 | 
            +
                          apply! "add prefix", "The skilled"
         | 
| 62 | 
            +
                        end
         | 
| 63 | 
            +
                      end
         | 
| 64 | 
            +
                    end      
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
              
         | 
| 68 | 
            +
                it "should apply when the condition is true" do
         | 
| 69 | 
            +
                  bobby = Person.new("Bobby", 52)
         | 
| 70 | 
            +
                  bobby.apply_rules!
         | 
| 71 | 
            +
                  bobby.name.should == "Grandpa Bobby"
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
              
         | 
| 74 | 
            +
                it "should not apply when the condition is false" do
         | 
| 75 | 
            +
                  bobby = Person.new("Bobby", 32)
         | 
| 76 | 
            +
                  bobby.apply_rules!
         | 
| 77 | 
            +
                  bobby.name.should == "Bobby"
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
              
         | 
| 80 | 
            +
                it "should accept conditions with arguments" do
         | 
| 81 | 
            +
                  bobby = Person.new("Bobby", 17)
         | 
| 82 | 
            +
                  bobby.apply_rules!
         | 
| 83 | 
            +
                  bobby.name.should == "Bobby Jr."
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
              
         | 
| 86 | 
            +
                it "should be combined to produce a combined effect" do
         | 
| 87 | 
            +
                  bobby = Person.new("Bobby", 87)
         | 
| 88 | 
            +
                  bobby.apply_rules!
         | 
| 89 | 
            +
                  bobby.name.should == "Grandpa Bobby Sr."
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
                
         | 
| 92 | 
            +
                it "accepts 'OR' syntax" do
         | 
| 93 | 
            +
                  wisdom = Person.new("Wisdom", 32)
         | 
| 94 | 
            +
                  wisdom.apply_rules!
         | 
| 95 | 
            +
                  wisdom.name.should == "Wisdom the wise"
         | 
| 96 | 
            +
                  prometheous = Person.new("Prometheous", 32)
         | 
| 97 | 
            +
                  prometheous.apply_rules!
         | 
| 98 | 
            +
                  prometheous.name.should == "Prometheous the wise"
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
              
         | 
| 101 | 
            +
                it "accepts 'AND' syntax" do
         | 
| 102 | 
            +
                  worker = Person.new("Worker", 32, "Contractor")
         | 
| 103 | 
            +
                  worker.apply_rules!
         | 
| 104 | 
            +
                  worker.job.should == "Jr. Contractor"
         | 
| 105 | 
            +
                
         | 
| 106 | 
            +
                  worker = Person.new("Worker", 32, "Builder")
         | 
| 107 | 
            +
                  worker.apply_rules!
         | 
| 108 | 
            +
                  worker.job.should == "Builder"    
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
              
         | 
| 111 | 
            +
                it "accepts both 'AND' and 'OR' syntax together" do
         | 
| 112 | 
            +
                  electrician = Person.new("Electrician", 32, "Electrician")
         | 
| 113 | 
            +
                  electrician.apply_rules!
         | 
| 114 | 
            +
                  electrician.name.should == "The skilled Electrician"
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
              end
         | 
| 117 | 
            +
              
         | 
| 118 | 
            +
              context "errors" do
         | 
| 119 | 
            +
                before :all do
         | 
| 120 | 
            +
                  class Cactus
         | 
| 121 | 
            +
                    include Rulz
         | 
| 122 | 
            +
                    attr_accessor :name, :age
         | 
| 123 | 
            +
                  
         | 
| 124 | 
            +
                    def initialize(name, age)
         | 
| 125 | 
            +
                      @name = name
         | 
| 126 | 
            +
                      @age = age
         | 
| 127 | 
            +
                    end
         | 
| 128 | 
            +
                  
         | 
| 129 | 
            +
                    define_rulz do
         | 
| 130 | 
            +
                      condition "older than" do |age|
         | 
| 131 | 
            +
                        its.age > age
         | 
| 132 | 
            +
                      end
         | 
| 133 | 
            +
                    
         | 
| 134 | 
            +
                      condition "younger than" do |age|
         | 
| 135 | 
            +
                        opposite_of "older than", age
         | 
| 136 | 
            +
                      end
         | 
| 137 | 
            +
                    
         | 
| 138 | 
            +
                      condition "middle aged" do
         | 
| 139 | 
            +
                        condition("older than", 40) and condition("younger than", 50)
         | 
| 140 | 
            +
                      end
         | 
| 141 | 
            +
                         
         | 
| 142 | 
            +
                      rule do
         | 
| 143 | 
            +
                        where("old") { apply! "add prefix", "Grandpa" } # "old" does not exist
         | 
| 144 | 
            +
                      end
         | 
| 145 | 
            +
                      
         | 
| 146 | 
            +
                    end      
         | 
| 147 | 
            +
                  end
         | 
| 148 | 
            +
                end
         | 
| 149 | 
            +
                
         | 
| 150 | 
            +
                it "should be raised if a condition is not found" do
         | 
| 151 | 
            +
                  bobby = Cactus.new("Bobby", 42)
         | 
| 152 | 
            +
                  expect { bobby.apply_rules! }.to raise_error ArgumentError
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
                
         | 
| 155 | 
            +
              end
         | 
| 156 | 
            +
              
         | 
| 157 | 
            +
              context "attributes" do
         | 
| 158 | 
            +
                before :all do
         | 
| 159 | 
            +
                  class Watermelon
         | 
| 160 | 
            +
                    include Rulz
         | 
| 161 | 
            +
                    attr_accessor :length, :weight, :width
         | 
| 162 | 
            +
                  
         | 
| 163 | 
            +
                    def initialize(length, weight, width=0)
         | 
| 164 | 
            +
                      @length = length
         | 
| 165 | 
            +
                      @weight = weight
         | 
| 166 | 
            +
                      @width = width
         | 
| 167 | 
            +
                    end
         | 
| 168 | 
            +
                  
         | 
| 169 | 
            +
                    define_rulz do
         | 
| 170 | 
            +
                      attribute :length do
         | 
| 171 | 
            +
                        condition "greater than" do |other_length|
         | 
| 172 | 
            +
                          length > other_length
         | 
| 173 | 
            +
                        end
         | 
| 174 | 
            +
                        condition "less than" do |other_length|
         | 
| 175 | 
            +
                          length < other_length
         | 
| 176 | 
            +
                        end
         | 
| 177 | 
            +
                      end
         | 
| 178 | 
            +
                      attribute :weight do
         | 
| 179 | 
            +
                        condition "greater than" do |other_weight|
         | 
| 180 | 
            +
                          weight > other_weight
         | 
| 181 | 
            +
                        end
         | 
| 182 | 
            +
                      end
         | 
| 183 | 
            +
                      condition "lopsided" do
         | 
| 184 | 
            +
                        its.width > its.length
         | 
| 185 | 
            +
                      end
         | 
| 186 | 
            +
                      action "cut in half" do
         | 
| 187 | 
            +
                        its.length /= 2
         | 
| 188 | 
            +
                      end
         | 
| 189 | 
            +
                      action "scoop out inside" do
         | 
| 190 | 
            +
                        action "cut in half"
         | 
| 191 | 
            +
                        its.weight /= 3
         | 
| 192 | 
            +
                      end
         | 
| 193 | 
            +
                      action "rotate" do
         | 
| 194 | 
            +
                        its.length, its.width = its.width, its.length
         | 
| 195 | 
            +
                      end
         | 
| 196 | 
            +
                      rule do
         | 
| 197 | 
            +
                        where :length => [ "greater than", 12 ] do
         | 
| 198 | 
            +
                          apply! "cut in half"
         | 
| 199 | 
            +
                        end
         | 
| 200 | 
            +
                      end
         | 
| 201 | 
            +
                      rule do
         | 
| 202 | 
            +
                        where [{:length => [ "less than", 6]}, "AND", {:weight => ["greater than", 15]}] do
         | 
| 203 | 
            +
                          apply! "scoop out inside"
         | 
| 204 | 
            +
                        end
         | 
| 205 | 
            +
                      end
         | 
| 206 | 
            +
                      rule do
         | 
| 207 | 
            +
                        where [{:length => ["less than", 6]}, "AND", "lopsided"] do
         | 
| 208 | 
            +
                          apply! "rotate"
         | 
| 209 | 
            +
                        end
         | 
| 210 | 
            +
                      end
         | 
| 211 | 
            +
                    end
         | 
| 212 | 
            +
                  end      
         | 
| 213 | 
            +
                end
         | 
| 214 | 
            +
                
         | 
| 215 | 
            +
                it "should recognize attribute conditions" do
         | 
| 216 | 
            +
                  w = Watermelon.new(13, 11)
         | 
| 217 | 
            +
                  w.apply_rules!
         | 
| 218 | 
            +
                  w.length.should == 6
         | 
| 219 | 
            +
                  m = Watermelon.new(11, 11)
         | 
| 220 | 
            +
                  m.apply_rules!
         | 
| 221 | 
            +
                  m.length.should == 11
         | 
| 222 | 
            +
                end
         | 
| 223 | 
            +
             | 
| 224 | 
            +
                it "should allow attribute conditions to be combined" do
         | 
| 225 | 
            +
                  w = Watermelon.new(4, 18)
         | 
| 226 | 
            +
                  w.apply_rules!
         | 
| 227 | 
            +
                  w.length.should == 2
         | 
| 228 | 
            +
                  w.weight.should == 6
         | 
| 229 | 
            +
                end
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                it "should allow attribute conditions to be combined with normal conditions" do
         | 
| 232 | 
            +
                  w = Watermelon.new(4, 4, 6)
         | 
| 233 | 
            +
                  w.apply_rules!
         | 
| 234 | 
            +
                  w.length.should == 6
         | 
| 235 | 
            +
                  w.width.should == 4     
         | 
| 236 | 
            +
                end
         | 
| 237 | 
            +
                
         | 
| 238 | 
            +
              end
         | 
| 239 | 
            +
              
         | 
| 240 | 
            +
              context "using predefined conditions" do
         | 
| 241 | 
            +
                class Honeydew
         | 
| 242 | 
            +
                  include Rulz
         | 
| 243 | 
            +
                  attr_accessor :diameter
         | 
| 244 | 
            +
                  
         | 
| 245 | 
            +
                  define_rulz do
         | 
| 246 | 
            +
                    attribute :diameter do
         | 
| 247 | 
            +
                      type :integer
         | 
| 248 | 
            +
                    end
         | 
| 249 | 
            +
                    action "cut in half" do
         | 
| 250 | 
            +
                      its.diameter /= 2
         | 
| 251 | 
            +
                    end
         | 
| 252 | 
            +
                    rule do
         | 
| 253 | 
            +
                      where(diameter: ["greater than", 5]) { apply! "cut in half" }
         | 
| 254 | 
            +
                    end
         | 
| 255 | 
            +
                  end
         | 
| 256 | 
            +
                  
         | 
| 257 | 
            +
                  def initialize(diameter)
         | 
| 258 | 
            +
                    @diameter = diameter
         | 
| 259 | 
            +
                  end
         | 
| 260 | 
            +
                end
         | 
| 261 | 
            +
                
         | 
| 262 | 
            +
                it "should not require conidions to be defined" do
         | 
| 263 | 
            +
                  h = Honeydew.new(6)
         | 
| 264 | 
            +
                  h.apply_rules!
         | 
| 265 | 
            +
                  h.diameter.should == 3
         | 
| 266 | 
            +
                end
         | 
| 267 | 
            +
                
         | 
| 268 | 
            +
              end
         | 
| 269 | 
            +
              
         | 
| 270 | 
            +
            end
         | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            # This file was generated by the `rspec --init` command. Conventionally, all
         | 
| 2 | 
            +
            # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
         | 
| 3 | 
            +
            # Require this file using `require "spec_helper"` to ensure that it is only
         | 
| 4 | 
            +
            # loaded once.
         | 
| 5 | 
            +
            #
         | 
| 6 | 
            +
            # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            require "rulz"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            RSpec.configure do |config|
         | 
| 11 | 
            +
              config.treat_symbols_as_metadata_keys_with_true_values = true
         | 
| 12 | 
            +
              config.run_all_when_everything_filtered = true
         | 
| 13 | 
            +
              config.filter_run :focus
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              # Run specs in random order to surface order dependencies. If you find an
         | 
| 16 | 
            +
              # order dependency and want to debug it, you can fix the order by providing
         | 
| 17 | 
            +
              # the seed, which is printed after each run.
         | 
| 18 | 
            +
              #     --seed 1234
         | 
| 19 | 
            +
              config.order = 'random'
         | 
| 20 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,129 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: rulz
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 1.0.0
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Chase Conklin
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2013-08-04 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: bundler
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - ~>
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '1.3'
         | 
| 20 | 
            +
              type: :development
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - ~>
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '1.3'
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: rake
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - '>='
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: '0'
         | 
| 34 | 
            +
              type: :development
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - '>='
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: '0'
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: rspec
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - '>='
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: '0'
         | 
| 48 | 
            +
              type: :development
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - '>='
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '0'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: debugger
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - '>='
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: '0'
         | 
| 62 | 
            +
              type: :development
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - '>='
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: '0'
         | 
| 69 | 
            +
            description: Rule Engine for Ruby
         | 
| 70 | 
            +
            email:
         | 
| 71 | 
            +
            - chase@conklins.net
         | 
| 72 | 
            +
            executables: []
         | 
| 73 | 
            +
            extensions: []
         | 
| 74 | 
            +
            extra_rdoc_files: []
         | 
| 75 | 
            +
            files:
         | 
| 76 | 
            +
            - .gitignore
         | 
| 77 | 
            +
            - .rspec
         | 
| 78 | 
            +
            - .ruby-gemset
         | 
| 79 | 
            +
            - .ruby-version
         | 
| 80 | 
            +
            - Gemfile
         | 
| 81 | 
            +
            - LICENSE.txt
         | 
| 82 | 
            +
            - README.md
         | 
| 83 | 
            +
            - Rakefile
         | 
| 84 | 
            +
            - lib/rulz.rb
         | 
| 85 | 
            +
            - lib/rulz/action.rb
         | 
| 86 | 
            +
            - lib/rulz/attribute.rb
         | 
| 87 | 
            +
            - lib/rulz/condition.rb
         | 
| 88 | 
            +
            - lib/rulz/conditions/comparison.rb
         | 
| 89 | 
            +
            - lib/rulz/conditions/conditions.rb
         | 
| 90 | 
            +
            - lib/rulz/conditions/container.rb
         | 
| 91 | 
            +
            - lib/rulz/conditions/string.rb
         | 
| 92 | 
            +
            - lib/rulz/definer.rb
         | 
| 93 | 
            +
            - lib/rulz/evaluator.rb
         | 
| 94 | 
            +
            - lib/rulz/rule.rb
         | 
| 95 | 
            +
            - lib/rulz/version.rb
         | 
| 96 | 
            +
            - rulz.gemspec
         | 
| 97 | 
            +
            - spec/action_spec.rb
         | 
| 98 | 
            +
            - spec/condition_spec.rb
         | 
| 99 | 
            +
            - spec/rule_spec.rb
         | 
| 100 | 
            +
            - spec/spec_helper.rb
         | 
| 101 | 
            +
            homepage: ''
         | 
| 102 | 
            +
            licenses:
         | 
| 103 | 
            +
            - MIT
         | 
| 104 | 
            +
            metadata: {}
         | 
| 105 | 
            +
            post_install_message: 
         | 
| 106 | 
            +
            rdoc_options: []
         | 
| 107 | 
            +
            require_paths:
         | 
| 108 | 
            +
            - lib
         | 
| 109 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 110 | 
            +
              requirements:
         | 
| 111 | 
            +
              - - '>='
         | 
| 112 | 
            +
                - !ruby/object:Gem::Version
         | 
| 113 | 
            +
                  version: '0'
         | 
| 114 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 115 | 
            +
              requirements:
         | 
| 116 | 
            +
              - - '>='
         | 
| 117 | 
            +
                - !ruby/object:Gem::Version
         | 
| 118 | 
            +
                  version: '0'
         | 
| 119 | 
            +
            requirements: []
         | 
| 120 | 
            +
            rubyforge_project: 
         | 
| 121 | 
            +
            rubygems_version: 2.0.3
         | 
| 122 | 
            +
            signing_key: 
         | 
| 123 | 
            +
            specification_version: 4
         | 
| 124 | 
            +
            summary: Enables users to create mail-like rules for processing Ruby objects.
         | 
| 125 | 
            +
            test_files:
         | 
| 126 | 
            +
            - spec/action_spec.rb
         | 
| 127 | 
            +
            - spec/condition_spec.rb
         | 
| 128 | 
            +
            - spec/rule_spec.rb
         | 
| 129 | 
            +
            - spec/spec_helper.rb
         |