brule 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13f788107d09cf82f121f314df0fd7247e808d4895a369afc56315aceaa21e84
4
- data.tar.gz: 92d514d8305373969d48069d5627432d8d13e136ae0f38f1a94b1368ebbfb63c
3
+ metadata.gz: 67b697b560f27e984a2ec669e672dee5b1cab777071c88d1b0ea7f1d358e4067
4
+ data.tar.gz: 3d9c7e21ca6fecc1a8b3d1b9120e15894dfc7c7e5ecd055d24fb118fb9ee11e2
5
5
  SHA512:
6
- metadata.gz: fba662d4ee2caaffba41aba4368069c1ab1aab6730fcd0b84a73a7158a799e1e34149eac0f7e37627a56bf9c16ea0f4af26298e0ef15ce0a76df0487ddbcf895
7
- data.tar.gz: 4f798d703d68a4e109b19c69469e1c86c2d16762ba45bb3cacc5cbf8ec3fe61ea64d57e1d942428d488655ea24068a541f79875071d2b3578f66d13bec02432b
6
+ metadata.gz: b7b7e87db8e466cda35e0330774818f03a75ce5d925f4dcdc394e0bdb1751a5037141bf4490cd602434d3ee56caee16526b40b3fb3fb9d8ddf4e19224a029032
7
+ data.tar.gz: 21d8166b5a3aac5cc63ef8cd1414bd2defc05eab1548d85697081d1c3d678ffc42cf9ac960399a61308db6fb99fa60e7e60610a4490ea25d1b33aa8dad13b649
data/README.md CHANGED
@@ -1,11 +1,11 @@
1
- This project aims at providing a set of tools to build somehow complex
2
- business processes or rules. It helps when:
1
+ This project aims at providing a set of tools to build complex and evolving
2
+ business rules. It helps when:
3
3
 
4
- * You decided to split the process into smaller parts working together.
5
- * You need to keep the rules evolving while maintaining the old versions.
6
- * You want to persist the rules that lead to the result of a process.
4
+ * You decided to split the computation into smaller parts working together.
5
+ * You need to keep old versions of the rules working.
6
+ * You want to persist the rules leading to a result.
7
7
  * You want to make your tests independent from your production data.
8
- * You want to introspect what lead to the result of a process.
8
+ * You want to introspect the computation of a result.
9
9
 
10
10
  ## How does it work
11
11
 
@@ -50,7 +50,7 @@ module Pricing
50
50
  end
51
51
 
52
52
  class OrderTotal < Brule::Rule
53
- config_reader :unit_price, :item_count
53
+ context_reader :unit_price, :item_count
54
54
  context_writer :price
55
55
 
56
56
  def apply
@@ -1,98 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'forwardable'
4
-
5
3
  module Brule
6
- module RuleHelpers
7
- def context_reader(*symbols)
8
- symbols.each do |symbol|
9
- define_method(symbol) { context.fetch(symbol) }
10
- end
11
- end
12
-
13
- def context_writer(*symbols)
14
- symbols.each do |symbol|
15
- define_method("#{symbol}=") { |value| context[symbol] = value }
16
- end
17
- end
18
-
19
- def context_accessor(*symbols)
20
- context_reader(*symbols)
21
- context_writer(*symbols)
22
- end
23
-
24
- def config_reader(*symbols)
25
- symbols.each do |symbol|
26
- define_method(symbol) { config.fetch(symbol) }
27
- end
28
- end
29
- end
30
-
31
- Rule = Struct.new(:config) do
32
- extend RuleHelpers
33
-
34
- attr_accessor :context
35
-
36
- def trigger?
37
- true
38
- end
39
-
40
- def apply
41
- raise NotImplementedError
42
- end
43
- end
44
-
45
- class Context
46
- extend Forwardable
47
-
48
- def_delegators :@content, :[], :fetch, :fetch_values, :key?, :[]=, :merge!
49
-
50
- def self.wrap(context)
51
- context.is_a?(self) ? context : new(context)
52
- end
53
-
54
- def initialize(hash = {})
55
- @content = hash
56
- end
57
-
58
- def initialize_copy(orig)
59
- super
60
- @content = orig.instance_variable_get(:@content).dup
61
- end
62
- end
63
-
64
- class Engine
65
- attr_reader :context
66
-
67
- def initialize(rules:)
68
- @rules = rules
69
- @history = {}
70
- end
71
-
72
- def call(context = {})
73
- @history = {}
74
- @context = Context.wrap(context)
75
- snapshot!(tag: :initial)
76
- @rules.each { |rule| apply(rule) }
77
- result
78
- end
79
-
80
- def history(key:)
81
- @history.map { |tag, content| [tag, content.fetch(key, nil)] }
82
- end
83
-
84
- private
85
-
86
- def snapshot!(tag:)
87
- @history[tag] = @context.dup
88
- end
89
-
90
- def apply(rule)
91
- rule.context = @context
92
- return unless rule.trigger?
93
-
94
- rule.apply
95
- snapshot!(tag: rule)
96
- end
97
- end
4
+ autoload :Context, 'brule/context'
5
+ autoload :Engine, 'brule/engine'
6
+ autoload :Rule, 'brule/rule'
7
+ autoload :Utils, 'brule/utils'
98
8
  end
@@ -0,0 +1,22 @@
1
+ require 'forwardable'
2
+
3
+ module Brule
4
+ class Context
5
+ extend Forwardable
6
+
7
+ def_delegators :@content, :[], :fetch, :fetch_values, :key?, :[]=, :merge!
8
+
9
+ def initialize(hash = {})
10
+ @content = hash
11
+ end
12
+
13
+ def initialize_copy(orig)
14
+ super
15
+ @content = orig.instance_variable_get(:@content).dup
16
+ end
17
+
18
+ def self.wrap(context)
19
+ context.is_a?(self) ? context : new(context)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,36 @@
1
+ module Brule
2
+ class Engine
3
+ attr_reader :context
4
+
5
+ def initialize(rules:)
6
+ @rules = rules
7
+ @history = {}
8
+ end
9
+
10
+ def call(context = {})
11
+ @history = {}
12
+ @context = Context.wrap(context)
13
+ snapshot!(tag: :initial)
14
+ @rules.each { |rule| apply(rule) }
15
+ result
16
+ end
17
+
18
+ def history(key:)
19
+ @history.map { |tag, content| [tag, content.fetch(key, nil)] }
20
+ end
21
+
22
+ private
23
+
24
+ def snapshot!(tag:)
25
+ @history[tag] = @context.dup
26
+ end
27
+
28
+ def apply(rule)
29
+ rule.context = @context
30
+ return unless rule.trigger?
31
+
32
+ rule.apply
33
+ snapshot!(tag: rule.to_tag)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,40 @@
1
+ module Brule
2
+ Rule = Struct.new(:config) do
3
+ attr_accessor :context
4
+
5
+ def trigger?
6
+ true
7
+ end
8
+
9
+ def apply
10
+ raise NotImplementedError
11
+ end
12
+
13
+ def to_tag
14
+ self
15
+ end
16
+
17
+ def self.context_reader(*symbols)
18
+ symbols.each do |symbol|
19
+ define_method(symbol) { context.fetch(symbol) }
20
+ end
21
+ end
22
+
23
+ def self.context_writer(*symbols)
24
+ symbols.each do |symbol|
25
+ define_method("#{symbol}=") { |value| context[symbol] = value }
26
+ end
27
+ end
28
+
29
+ def self.context_accessor(*symbols)
30
+ context_reader(*symbols)
31
+ context_writer(*symbols)
32
+ end
33
+
34
+ def self.config_reader(*symbols)
35
+ symbols.each do |symbol|
36
+ define_method(symbol) { config.fetch(symbol) }
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,5 @@
1
+ module Brule
2
+ module Utils
3
+ autoload :Either, 'brule/utils/either'
4
+ end
5
+ end
@@ -0,0 +1,35 @@
1
+ require 'forwardable'
2
+
3
+ module Brule
4
+ module Utils
5
+ class Either < Brule::Rule
6
+ TooManyMatches = Class.new(StandardError)
7
+ NoMatchFound = Class.new(StandardError)
8
+
9
+ extend Forwardable
10
+
11
+ def_delegators :only_match, :apply, :trigger?, :to_tag
12
+
13
+ config_reader :rules
14
+
15
+ private
16
+
17
+ def only_match
18
+ matches = rules.select do |rule|
19
+ rule.context = context
20
+ rule.trigger?
21
+ end
22
+
23
+ if matches.size >= 2
24
+ raise TooManyMatches, "Rules #{matches.join(', ')} are all a match"
25
+ end
26
+
27
+ if matches.empty?
28
+ raise NoMatchFound, "No rules from #{rules.join(', ')} is a match"
29
+ end
30
+
31
+ matches.first
32
+ end
33
+ end
34
+ end
35
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brule
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicolas Zermati
@@ -46,6 +46,11 @@ extra_rdoc_files: []
46
46
  files:
47
47
  - README.md
48
48
  - lib/brule.rb
49
+ - lib/brule/context.rb
50
+ - lib/brule/engine.rb
51
+ - lib/brule/rule.rb
52
+ - lib/brule/utils.rb
53
+ - lib/brule/utils/either.rb
49
54
  homepage: https://github.com/nicoolas25/brule-rb
50
55
  licenses:
51
56
  - MIT