ruy 0.2.0 → 0.2.1
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 +4 -4
- data/lib/ruy.rb +4 -124
- data/lib/ruy/conditions.rb +1 -4
- data/lib/ruy/conditions/assert.rb +1 -2
- data/lib/ruy/conditions/between.rb +1 -5
- data/lib/ruy/conditions/day_of_week.rb +44 -0
- data/lib/ruy/conditions/eq.rb +1 -3
- data/lib/ruy/conditions/except.rb +1 -4
- data/lib/ruy/conditions/greater_than_or_equal.rb +1 -5
- data/lib/ruy/conditions/include.rb +1 -5
- data/lib/ruy/conditions/included.rb +1 -5
- data/lib/ruy/conditions/less_than.rb +1 -3
- data/lib/ruy/conditions/less_than_or_equal.rb +1 -3
- data/lib/ruy/conditions/tz.rb +8 -2
- data/lib/ruy/context.rb +10 -0
- data/lib/ruy/outcome.rb +22 -0
- data/lib/ruy/rule.rb +7 -63
- data/lib/ruy/rule_set.rb +61 -0
- data/lib/ruy/time_pattern.rb +84 -24
- data/lib/ruy/variable_context.rb +24 -0
- metadata +6 -19
- data/lib/ruy/adapters.rb +0 -6
- data/lib/ruy/adapters/file_adapter.rb +0 -28
- data/lib/ruy/adapters/sequel_adapter.rb +0 -40
- data/lib/ruy/rule_storage.rb +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1892173ce87ec0352f8eb0058be130276ac3992d
|
4
|
+
data.tar.gz: 56e8ecb959603b387278c3c7b771eace0cd797dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bdc7bc60c215ca1514262f9b9ff0cce49208590e9fc5597440698a68678c40be21bd740b3539504409f137d433affe2e88ba09df9166f72f3b84e1d4b7cb88bc
|
7
|
+
data.tar.gz: 889a05b473558941b51c3eb4c3ffdd07eb786aef86b2dc8043bb4d51813b9608079f5795285beba19362bec7dd9f830ef8b907e9d69774bfbb4364d8587a6bf2
|
data/lib/ruy.rb
CHANGED
@@ -1,127 +1,7 @@
|
|
1
1
|
require_relative 'ruy/rule'
|
2
|
-
require_relative 'ruy/
|
2
|
+
require_relative 'ruy/rule_set'
|
3
3
|
require_relative 'ruy/conditions'
|
4
|
-
require_relative 'ruy/
|
4
|
+
require_relative 'ruy/context'
|
5
|
+
require_relative 'ruy/variable_context'
|
6
|
+
require_relative 'ruy/outcome'
|
5
7
|
require_relative 'ruy/time_pattern'
|
6
|
-
|
7
|
-
module Ruy
|
8
|
-
class RuleSet < Rule
|
9
|
-
|
10
|
-
attr_reader :name
|
11
|
-
attr_reader :outcomes
|
12
|
-
attr_accessor :metadata
|
13
|
-
|
14
|
-
def initialize
|
15
|
-
super
|
16
|
-
|
17
|
-
@outcomes = []
|
18
|
-
@fallback = nil
|
19
|
-
@metadata = {}
|
20
|
-
end
|
21
|
-
|
22
|
-
def [](key)
|
23
|
-
@metadata[key]
|
24
|
-
end
|
25
|
-
|
26
|
-
def []=(key, value)
|
27
|
-
@metadata[key] = value
|
28
|
-
end
|
29
|
-
|
30
|
-
def call(ctx)
|
31
|
-
var_ctx = VariableContext.new(ctx, @vars)
|
32
|
-
if @apply = super(var_ctx)
|
33
|
-
compute_outcome(var_ctx)
|
34
|
-
else
|
35
|
-
@fallback
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def apply?
|
40
|
-
@apply
|
41
|
-
end
|
42
|
-
|
43
|
-
def compute_outcome(var_ctx)
|
44
|
-
@outcomes.each do |outcome|
|
45
|
-
result = outcome.call(var_ctx)
|
46
|
-
unless result.nil?
|
47
|
-
return result
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
nil
|
52
|
-
end
|
53
|
-
|
54
|
-
def to_hash
|
55
|
-
if @outcomes.any?
|
56
|
-
super.merge({ outcomes: @outcomes.map { |o| o.to_hash } })
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def fallback(value)
|
61
|
-
@fallback = value
|
62
|
-
end
|
63
|
-
|
64
|
-
def outcome(value, &block)
|
65
|
-
outcome = Outcome.new(value)
|
66
|
-
outcome.instance_exec(&block) if block_given?
|
67
|
-
@outcomes << outcome
|
68
|
-
end
|
69
|
-
|
70
|
-
def method_missing(m, *args, &block)
|
71
|
-
super
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
class Context < Hash
|
76
|
-
def self.from_hash(hash)
|
77
|
-
ctx = Context.new
|
78
|
-
ctx.merge!(hash)
|
79
|
-
|
80
|
-
ctx
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
class Outcome < Rule
|
85
|
-
attr_reader :value
|
86
|
-
|
87
|
-
def initialize(value)
|
88
|
-
super()
|
89
|
-
|
90
|
-
@value = value
|
91
|
-
@params = [@value]
|
92
|
-
end
|
93
|
-
|
94
|
-
def call(ctx)
|
95
|
-
@value if super(ctx)
|
96
|
-
end
|
97
|
-
|
98
|
-
def ==(o)
|
99
|
-
o.kind_of?(Outcome) &&
|
100
|
-
value == o.value &&
|
101
|
-
conditions == o.conditions
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
# Context that can resolve variable access
|
106
|
-
class VariableContext
|
107
|
-
def initialize(ctx, vars = {})
|
108
|
-
@ctx = ctx
|
109
|
-
@vars = vars
|
110
|
-
@resolved_vars = {}
|
111
|
-
end
|
112
|
-
|
113
|
-
# Resolve the given attr from the variables or the context
|
114
|
-
# If attribute can't be resolved then throw an exception
|
115
|
-
#
|
116
|
-
# @param [Symbol] attr
|
117
|
-
# @return [Object]
|
118
|
-
def resolve(attr)
|
119
|
-
if @vars.include?(attr)
|
120
|
-
@resolved_vars[attr] ||= @ctx.instance_exec(&@vars[attr])
|
121
|
-
else
|
122
|
-
@ctx.fetch(attr) { |key| @ctx[key.to_s] }
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
end
|
data/lib/ruy/conditions.rb
CHANGED
@@ -3,6 +3,7 @@ require_relative 'conditions/any'
|
|
3
3
|
require_relative 'conditions/assert'
|
4
4
|
require_relative 'conditions/between'
|
5
5
|
require_relative 'conditions/cond'
|
6
|
+
require_relative 'conditions/day_of_week'
|
6
7
|
require_relative 'conditions/eq'
|
7
8
|
require_relative 'conditions/except'
|
8
9
|
require_relative 'conditions/greater_than_or_equal'
|
@@ -11,7 +12,3 @@ require_relative 'conditions/included'
|
|
11
12
|
require_relative 'conditions/less_than'
|
12
13
|
require_relative 'conditions/less_than_or_equal'
|
13
14
|
require_relative 'conditions/tz'
|
14
|
-
|
15
|
-
module Ruy
|
16
|
-
module Conditions; end
|
17
|
-
end
|
@@ -12,14 +12,10 @@ module Ruy
|
|
12
12
|
# @param to Range upper bound
|
13
13
|
# @yield a block in the context of the current rule
|
14
14
|
def initialize(attr, from, to, &block)
|
15
|
-
super
|
16
|
-
|
15
|
+
super
|
17
16
|
@attr = attr
|
18
17
|
@from = from
|
19
18
|
@to = to
|
20
|
-
|
21
|
-
@params = [@attr, @from, @to]
|
22
|
-
|
23
19
|
instance_exec(&block) if block_given?
|
24
20
|
end
|
25
21
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'tzinfo'
|
3
|
+
|
4
|
+
module Ruy
|
5
|
+
module Conditions
|
6
|
+
|
7
|
+
# Expects that a Time object's date corresponds to a specified day of the week
|
8
|
+
class DayOfWeek < Ruy::Rule
|
9
|
+
DAYS_INTO_WEEK = %w(sunday monday tuesday wednesday thursday friday saturday)
|
10
|
+
attr_reader :attr, :value, :tz_identifier
|
11
|
+
|
12
|
+
# @param attr
|
13
|
+
# @param value
|
14
|
+
# @param tz_identifier
|
15
|
+
def initialize(attr, value, tz_identifier = 'UTC')
|
16
|
+
super
|
17
|
+
@attr = attr
|
18
|
+
@value = value
|
19
|
+
@tz_identifier = tz_identifier
|
20
|
+
@tz = TZInfo::Timezone.get(tz_identifier)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @param [Ruy::VariableContext] var_ctx
|
24
|
+
def call(var_ctx)
|
25
|
+
resolved = var_ctx.resolve(@attr)
|
26
|
+
cmp = @tz.utc_to_local(resolved.to_time.utc)
|
27
|
+
|
28
|
+
if @value.is_a?(Fixnum)
|
29
|
+
cmp.wday == @value
|
30
|
+
else
|
31
|
+
DAYS_INTO_WEEK.include?(@value.to_s) && cmp.send("#{@value}?")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param o
|
36
|
+
def ==(o)
|
37
|
+
o.kind_of?(DayOfWeek) &&
|
38
|
+
attr == o.attr &&
|
39
|
+
value == o.value &&
|
40
|
+
tz_identifier == o.tz_identifier
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/ruy/conditions/eq.rb
CHANGED
@@ -13,12 +13,9 @@ module Ruy
|
|
13
13
|
# @param value Non-expected value
|
14
14
|
# @yield a block in the context of the current rule
|
15
15
|
def initialize(attr = nil, value = nil, &block)
|
16
|
-
super
|
17
|
-
|
16
|
+
super
|
18
17
|
@attr = attr
|
19
18
|
@value = value
|
20
|
-
@params = [@attr, @value]
|
21
|
-
|
22
19
|
instance_exec(&block) if block_given?
|
23
20
|
end
|
24
21
|
|
@@ -9,13 +9,9 @@ module Ruy
|
|
9
9
|
# @param value
|
10
10
|
# @yield a block in the context of the current rule
|
11
11
|
def initialize(attr, value, &block)
|
12
|
-
super
|
13
|
-
|
12
|
+
super
|
14
13
|
@attr = attr
|
15
14
|
@value = value
|
16
|
-
|
17
|
-
@params = [@attr, @value]
|
18
|
-
|
19
15
|
instance_exec(&block) if block_given?
|
20
16
|
end
|
21
17
|
|
@@ -9,13 +9,9 @@ module Ruy
|
|
9
9
|
# @param values Expected set of values
|
10
10
|
# @yield a block in the context of the current rule
|
11
11
|
def initialize(attr, values, &block)
|
12
|
-
super
|
13
|
-
|
12
|
+
super
|
14
13
|
@attr = attr
|
15
14
|
@values = values
|
16
|
-
|
17
|
-
@params = [@attr, @values]
|
18
|
-
|
19
15
|
instance_exec(&block) if block_given?
|
20
16
|
end
|
21
17
|
|
@@ -9,13 +9,9 @@ module Ruy
|
|
9
9
|
# @param value Expected set of values
|
10
10
|
# @yield a block in the context of the current rule
|
11
11
|
def initialize(attr, value, &block)
|
12
|
-
super
|
13
|
-
|
12
|
+
super
|
14
13
|
@attr = attr
|
15
14
|
@value = value
|
16
|
-
|
17
|
-
@params = [@attr, @value]
|
18
|
-
|
19
15
|
instance_exec(&block) if block_given?
|
20
16
|
end
|
21
17
|
|
data/lib/ruy/conditions/tz.rb
CHANGED
@@ -8,9 +8,8 @@ module Ruy
|
|
8
8
|
class TZ < Ruy::Rule
|
9
9
|
# @param [String] tz_identifier String representing IANA's time zone identifier.
|
10
10
|
def initialize(tz_identifier)
|
11
|
-
super
|
11
|
+
super
|
12
12
|
@tz_identifier = tz_identifier
|
13
|
-
@params = [@tz_identifier]
|
14
13
|
end
|
15
14
|
|
16
15
|
# @param [Ruy::VariableContext] var_ctx
|
@@ -20,6 +19,13 @@ module Ruy
|
|
20
19
|
end
|
21
20
|
end
|
22
21
|
|
22
|
+
# Adds a DayOfWeek condition
|
23
|
+
#
|
24
|
+
# @param (see Ruy::Conditions::DayOfWeek#initialize)
|
25
|
+
def day_of_week(attr, dow)
|
26
|
+
@conditions << DayOfWeek.new(attr, dow, @tz_identifier)
|
27
|
+
end
|
28
|
+
|
23
29
|
# Intercepts an 'eq' call to the superclass and enhances its arguments
|
24
30
|
#
|
25
31
|
# @param (see Ruy::Conditions::Eq#initialize)
|
data/lib/ruy/context.rb
ADDED
data/lib/ruy/outcome.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Ruy
|
2
|
+
class Outcome < Rule
|
3
|
+
attr_reader :value
|
4
|
+
|
5
|
+
def initialize(value)
|
6
|
+
super
|
7
|
+
@value = value
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(ctx)
|
11
|
+
if super(ctx)
|
12
|
+
@value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def ==(o)
|
17
|
+
o.kind_of?(Outcome) &&
|
18
|
+
value == o.value &&
|
19
|
+
conditions == o.conditions
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/ruy/rule.rb
CHANGED
@@ -1,63 +1,13 @@
|
|
1
1
|
module Ruy
|
2
|
-
|
3
|
-
# Returns a constant using a qualified constant name string
|
4
|
-
#
|
5
|
-
# @param [String] name
|
6
|
-
# @return [Object]
|
7
|
-
def self.qualified_const_get(name)
|
8
|
-
root = Object
|
9
|
-
name.split('::').each do |klass|
|
10
|
-
root = root.const_get(klass)
|
11
|
-
end
|
12
|
-
|
13
|
-
root
|
14
|
-
end
|
15
|
-
|
16
|
-
# A rule is a set of conditions
|
17
2
|
class Rule
|
18
|
-
|
19
3
|
attr_reader :conditions
|
20
4
|
attr_reader :vars
|
21
5
|
|
22
|
-
def initialize
|
6
|
+
def initialize(*args)
|
23
7
|
@conditions = []
|
24
8
|
@vars = {}
|
25
9
|
@attrs = {}
|
26
|
-
@params =
|
27
|
-
end
|
28
|
-
|
29
|
-
# Serialize a rule object as a hash
|
30
|
-
#
|
31
|
-
# @return [Hash]
|
32
|
-
def to_hash
|
33
|
-
ret = { node: self.class.name, params: params }
|
34
|
-
ret[:conditions] = @conditions.map(&:to_hash) if @conditions.any?
|
35
|
-
|
36
|
-
ret
|
37
|
-
end
|
38
|
-
|
39
|
-
# Look to the given keys, and load the rule nodes in their values
|
40
|
-
#
|
41
|
-
# @param [Array<Symbol>] keys
|
42
|
-
# @param [Hash] hash
|
43
|
-
# @return [Ruy::Rule]
|
44
|
-
def load_rule_objects_from(hash, *keys)
|
45
|
-
keys.each do |key|
|
46
|
-
if hash.has_key?(key)
|
47
|
-
hash[key].each { |o| self.send(key) << Ruy::Rule.from_hash(o) }
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
self
|
52
|
-
end
|
53
|
-
|
54
|
-
# Load a new role from it hash representation
|
55
|
-
#
|
56
|
-
# @param [Hash] hash
|
57
|
-
# @return [Ruy::Rule]
|
58
|
-
def self.from_hash(hash)
|
59
|
-
rule = Ruy.qualified_const_get(hash[:node]).new(*hash[:params])
|
60
|
-
rule.load_rule_objects_from(hash, :conditions, :outcomes)
|
10
|
+
@params = args
|
61
11
|
end
|
62
12
|
|
63
13
|
# Adds an All condition.
|
@@ -155,7 +105,8 @@ module Ruy
|
|
155
105
|
|
156
106
|
# Adds a TZ condition block
|
157
107
|
#
|
158
|
-
# @param [String] tz_identifier String representing IANA's
|
108
|
+
# @param [String] tz_identifier String representing IANA's
|
109
|
+
# time zone identifier. Defaults to UTC if none passed.
|
159
110
|
# @yield Evaluates the given block in the context of the TZ rule
|
160
111
|
def tz(tz_identifier = 'UTC', &block)
|
161
112
|
cond = Conditions::TZ.new(tz_identifier)
|
@@ -183,7 +134,8 @@ module Ruy
|
|
183
134
|
|
184
135
|
# Defines a variable.
|
185
136
|
#
|
186
|
-
# If both value and block are given,
|
137
|
+
# If both value and block are given,
|
138
|
+
# only the block will be taken into account.
|
187
139
|
#
|
188
140
|
# @param name The name of the variable
|
189
141
|
# @param value The value of the variable
|
@@ -217,14 +169,6 @@ module Ruy
|
|
217
169
|
vars.keys == o.vars.keys
|
218
170
|
end
|
219
171
|
|
220
|
-
private
|
221
|
-
|
222
|
-
# Getter method for rules params. It returns all the params without nil objects
|
223
|
-
#
|
224
|
-
# @return [Array<Object>]
|
225
|
-
def params
|
226
|
-
@params.compact
|
227
|
-
end
|
228
|
-
|
229
172
|
end
|
173
|
+
|
230
174
|
end
|
data/lib/ruy/rule_set.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module Ruy
|
2
|
+
class RuleSet < Rule
|
3
|
+
attr_reader :outcomes
|
4
|
+
attr_accessor :metadata
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
@outcomes = []
|
9
|
+
@fallback = nil
|
10
|
+
@metadata = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def outcome(value, &block)
|
14
|
+
outcome = Outcome.new(value)
|
15
|
+
outcome.instance_exec(&block) if block_given?
|
16
|
+
@outcomes << outcome
|
17
|
+
end
|
18
|
+
|
19
|
+
def fallback(value)
|
20
|
+
@fallback = value
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(ctx)
|
24
|
+
var_ctx = VariableContext.new(ctx, @vars)
|
25
|
+
if @apply = super(var_ctx)
|
26
|
+
compute_outcome(var_ctx)
|
27
|
+
else
|
28
|
+
@fallback
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def [](key)
|
33
|
+
@metadata[key]
|
34
|
+
end
|
35
|
+
|
36
|
+
def []=(key, value)
|
37
|
+
@metadata[key] = value
|
38
|
+
end
|
39
|
+
|
40
|
+
def apply?
|
41
|
+
@apply
|
42
|
+
end
|
43
|
+
|
44
|
+
def compute_outcome(var_ctx)
|
45
|
+
@outcomes.each do |outcome|
|
46
|
+
result = outcome.call(var_ctx)
|
47
|
+
unless result.nil?
|
48
|
+
return result
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def method_missing(m, *args, &block)
|
56
|
+
super
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
data/lib/ruy/time_pattern.rb
CHANGED
@@ -4,54 +4,114 @@ module Ruy
|
|
4
4
|
class TimePattern
|
5
5
|
include Comparable
|
6
6
|
|
7
|
-
|
7
|
+
WELL_FORMED_TS_EXP = /^(?<year>\d{4}|\*)-(?<month>\d{2}|\*)-(?<day>\d{2}|\*)T(?<hour>\d{2}|\*):(?<minute>\d{2}|\*):(?<second>\d{2}|\*)(z(?<time_zone>\S+))?$/
|
8
8
|
|
9
|
-
attr_reader :
|
9
|
+
attr_reader :year, :month, :day, :hour, :min, :sec, :time_zone, :tz, :local,
|
10
|
+
:utc, :utc_offset
|
10
11
|
|
11
|
-
# @param [String] pattern String representing a Ruy's
|
12
|
-
#
|
12
|
+
# @param [String] pattern String representing a Ruy's
|
13
|
+
# well-formed timestamp pattern
|
14
|
+
# @param [String] tz_identifier String representing IANA's
|
15
|
+
# time zone identifier. Defaults to UTC if none passed.
|
13
16
|
def initialize(pattern, tz_identifier = 'UTC')
|
14
|
-
|
17
|
+
unless match_data = pattern.match(WELL_FORMED_TS_EXP)
|
18
|
+
raise ArgumentError, "#{pattern.inspect} is malformed"
|
19
|
+
end
|
15
20
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
@pattern = pattern
|
22
|
+
|
23
|
+
@year = match_data[:year] == '*' ? nil : match_data[:year].to_i
|
24
|
+
@month = match_data[:month] == '*' ? nil : match_data[:month].to_i
|
25
|
+
@day = match_data[:day] == '*' ? nil : match_data[:day].to_i
|
26
|
+
@hour = match_data[:hour] == '*' ? nil : match_data[:hour].to_i
|
27
|
+
@min = match_data[:minute] == '*' ? nil : match_data[:minute].to_i
|
28
|
+
@sec = match_data[:second] == '*' ? nil : match_data[:second].to_i
|
29
|
+
@time_zone = match_data[:time_zone]
|
23
30
|
|
24
31
|
# Store the TZInfo::Timezone object corresponding to the specified time zone
|
25
|
-
@tz = TZInfo::Timezone.get(tz_identifier)
|
32
|
+
@tz = TZInfo::Timezone.get(@time_zone || tz_identifier)
|
26
33
|
|
27
34
|
# Store a Time object with values based on the specified time zone
|
28
|
-
@
|
35
|
+
@local = Time.new(year || 0, month, day, hour, min, sec, '+00:00')
|
29
36
|
|
30
37
|
# Store a Time object with values based on UTC
|
31
|
-
@
|
38
|
+
@utc = @tz.local_to_utc(@local)
|
39
|
+
@utc_offset = @tz.current_period.utc_total_offset
|
32
40
|
end
|
33
41
|
|
34
|
-
# Implements Ruby's spaceship operator to work with
|
42
|
+
# Implements Ruby's spaceship operator to work with Time objects.
|
43
|
+
# Uses Object's spaceship operator if passed object
|
44
|
+
# does not respond to #to_time.
|
35
45
|
#
|
36
|
-
# @param [
|
46
|
+
# @param [#to_time]
|
37
47
|
# @return [Fixnum]
|
38
|
-
def <=>(
|
39
|
-
|
48
|
+
def <=>(o)
|
49
|
+
if o.respond_to?(:to_time)
|
50
|
+
time = o.to_time
|
51
|
+
time_to_local = @tz.utc_to_local(time.utc)
|
52
|
+
|
53
|
+
self_time = Time.gm(
|
54
|
+
self.year || time_to_local.year,
|
55
|
+
self.month || time_to_local.month,
|
56
|
+
self.day || time_to_local.day,
|
57
|
+
self.hour || time_to_local.hour,
|
58
|
+
self.min || time_to_local.min,
|
59
|
+
self.sec || time_to_local.sec,
|
60
|
+
Rational(time_to_local.nsec, 1000)
|
61
|
+
)
|
62
|
+
|
63
|
+
@tz.local_to_utc(self_time) <=> time
|
64
|
+
|
65
|
+
else
|
66
|
+
super
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Overrides Object equal operator and uses Comparable equality
|
71
|
+
# for Time objects.
|
72
|
+
# Uses identity comparison if passed object does not respond to #to_time.
|
73
|
+
#
|
74
|
+
# @param [#to_time]
|
75
|
+
# @return [Boolean]
|
76
|
+
def ==(o)
|
77
|
+
if o.is_a?(self.class)
|
78
|
+
return year == o.year &&
|
79
|
+
month == o.month &&
|
80
|
+
day == o.day &&
|
81
|
+
hour == o.hour &&
|
82
|
+
min == o.min &&
|
83
|
+
sec == o.sec &&
|
84
|
+
time_zone == o.time_zone
|
85
|
+
elsif o.respond_to?(:to_time)
|
86
|
+
super
|
87
|
+
else
|
88
|
+
equal?(o)
|
89
|
+
end
|
40
90
|
end
|
41
91
|
|
42
|
-
# Returns a well-formed Ruy timestamp with IANA time zone identifier
|
92
|
+
# Returns a well-formed Ruy timestamp with IANA time zone identifier
|
93
|
+
# representing the current TimePattern object.
|
43
94
|
#
|
44
95
|
# @return [String]
|
45
96
|
def to_s
|
46
|
-
@
|
97
|
+
@pattern
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns a representation of the time pattern
|
101
|
+
#
|
102
|
+
# @return [String]
|
103
|
+
def inspect
|
104
|
+
@pattern
|
47
105
|
end
|
48
106
|
|
49
|
-
# Overrides Ruby's method missing call to redirect calls
|
50
|
-
#
|
107
|
+
# Overrides Ruby's method missing call to redirect calls
|
108
|
+
# to the stored Time object in case it responds to the missing method.
|
109
|
+
# Will call to super in case it doesn't.
|
51
110
|
#
|
52
111
|
# @param (see BasicObject#method_missing)
|
53
112
|
def method_missing(method, *args)
|
54
|
-
@
|
113
|
+
@utc.respond_to?(method) ? @utc.send(method, *args) : super
|
55
114
|
end
|
115
|
+
|
56
116
|
end
|
57
117
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Ruy
|
2
|
+
# Context that can resolve variable access
|
3
|
+
class VariableContext
|
4
|
+
def initialize(ctx, vars)
|
5
|
+
@ctx = ctx
|
6
|
+
@vars = vars
|
7
|
+
|
8
|
+
@resolved_vars = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
# Resolve the given attr from the variables or the context
|
12
|
+
# If attribute can't be resolved then throw an exception
|
13
|
+
#
|
14
|
+
# @param [Symbol] attr
|
15
|
+
# @return [Object]
|
16
|
+
def resolve(attr)
|
17
|
+
if @vars.include?(attr)
|
18
|
+
@resolved_vars[attr] ||= @ctx.instance_exec(&@vars[attr])
|
19
|
+
else
|
20
|
+
@ctx.fetch(attr) { |key| @ctx[key.to_s] }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Moove-IT
|
@@ -38,20 +38,6 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3.1'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: sequel
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '4.12'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '4.12'
|
55
41
|
description:
|
56
42
|
email:
|
57
43
|
executables: []
|
@@ -59,15 +45,13 @@ extensions: []
|
|
59
45
|
extra_rdoc_files: []
|
60
46
|
files:
|
61
47
|
- lib/ruy.rb
|
62
|
-
- lib/ruy/adapters.rb
|
63
|
-
- lib/ruy/adapters/file_adapter.rb
|
64
|
-
- lib/ruy/adapters/sequel_adapter.rb
|
65
48
|
- lib/ruy/conditions.rb
|
66
49
|
- lib/ruy/conditions/all.rb
|
67
50
|
- lib/ruy/conditions/any.rb
|
68
51
|
- lib/ruy/conditions/assert.rb
|
69
52
|
- lib/ruy/conditions/between.rb
|
70
53
|
- lib/ruy/conditions/cond.rb
|
54
|
+
- lib/ruy/conditions/day_of_week.rb
|
71
55
|
- lib/ruy/conditions/eq.rb
|
72
56
|
- lib/ruy/conditions/except.rb
|
73
57
|
- lib/ruy/conditions/greater_than_or_equal.rb
|
@@ -76,9 +60,12 @@ files:
|
|
76
60
|
- lib/ruy/conditions/less_than.rb
|
77
61
|
- lib/ruy/conditions/less_than_or_equal.rb
|
78
62
|
- lib/ruy/conditions/tz.rb
|
63
|
+
- lib/ruy/context.rb
|
64
|
+
- lib/ruy/outcome.rb
|
79
65
|
- lib/ruy/rule.rb
|
80
|
-
- lib/ruy/
|
66
|
+
- lib/ruy/rule_set.rb
|
81
67
|
- lib/ruy/time_pattern.rb
|
68
|
+
- lib/ruy/variable_context.rb
|
82
69
|
homepage: https://github.com/Moove-it/ruy
|
83
70
|
licenses:
|
84
71
|
- MIT
|
data/lib/ruy/adapters.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
module Ruy
|
2
|
-
module Adapters
|
3
|
-
class FileAdapter
|
4
|
-
#
|
5
|
-
# @param [String] directory
|
6
|
-
def initialize(directory)
|
7
|
-
@directory = directory
|
8
|
-
end
|
9
|
-
|
10
|
-
# Load all the rule files in the directory specified when the adapter
|
11
|
-
# was created
|
12
|
-
#
|
13
|
-
# @return [Array<Ruy::RuleSet]
|
14
|
-
def load_rules
|
15
|
-
rules = []
|
16
|
-
|
17
|
-
Dir.glob("#{@directory}/*.rb") do |rule_file|
|
18
|
-
rule_set = Ruy::RuleSet.new
|
19
|
-
rule_set.instance_eval(File.read(rule_file))
|
20
|
-
|
21
|
-
rules << rule_set
|
22
|
-
end
|
23
|
-
|
24
|
-
rules
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
require 'sequel'
|
2
|
-
require 'json'
|
3
|
-
|
4
|
-
module Ruy
|
5
|
-
module Adapters
|
6
|
-
class SequelAdapter
|
7
|
-
def initialize(connection_data)
|
8
|
-
@db = initialize_connection(connection_data)
|
9
|
-
end
|
10
|
-
|
11
|
-
# Load all the rule objects in the specified database.
|
12
|
-
#
|
13
|
-
# @return [Array<Ruy::RuleSet>]
|
14
|
-
def load_rules(params = {})
|
15
|
-
options = { rules_table: 'event_rules',
|
16
|
-
serialized_data_column: 'data' }.merge(params)
|
17
|
-
|
18
|
-
dataset = @db[options[:rules_table]].all
|
19
|
-
dataset.collect do |row|
|
20
|
-
rule_set = Ruy::RuleSet.from_hash(
|
21
|
-
JSON.parse(row[options[:serialized_data_column]], symbolize_names: true)
|
22
|
-
)
|
23
|
-
|
24
|
-
yield row, rule_set if block_given?
|
25
|
-
rule_set
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
#
|
31
|
-
# @param [Hash] connection_data
|
32
|
-
# @return []
|
33
|
-
def initialize_connection(connection_data)
|
34
|
-
Sequel.connect(adapter: connection_data[:adapter],
|
35
|
-
host: connection_data[:host], database: connection_data[:database],
|
36
|
-
user: connection_data[:user], password: connection_data[:password])
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
data/lib/ruy/rule_storage.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
module Ruy
|
2
|
-
class RuleStorage
|
3
|
-
attr_writer :adapter
|
4
|
-
|
5
|
-
def initialize(adapter, rules = [])
|
6
|
-
@adapter = adapter
|
7
|
-
@rules = rules
|
8
|
-
end
|
9
|
-
|
10
|
-
# Evaluate the given context against all the loaded rules
|
11
|
-
#
|
12
|
-
# @param [Hash] ctx
|
13
|
-
# @return [Array<Object>]
|
14
|
-
def evaluate_all(ctx)
|
15
|
-
@rules.map { |rule| rule.call(ctx) }.compact
|
16
|
-
end
|
17
|
-
|
18
|
-
# The first rule that apply will return the method
|
19
|
-
#
|
20
|
-
# @param [Hash] ctx
|
21
|
-
# @return [Object]
|
22
|
-
def evaluate_first(ctx)
|
23
|
-
@rules.each do |rule|
|
24
|
-
result = rule.call(ctx)
|
25
|
-
return result if rule.apply?
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
# Load all the rules from the adapter
|
30
|
-
#
|
31
|
-
def load_rules(params = {}, &block)
|
32
|
-
@rules = @adapter.load_rules(params, &block)
|
33
|
-
end
|
34
|
-
alias_method :relaod, :load_rules
|
35
|
-
end
|
36
|
-
end
|