ruy 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|