reflekt 1.0.5 → 1.0.10
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/accessor.rb +45 -0
- data/lib/action.rb +127 -0
- data/lib/action_stack.rb +44 -0
- data/lib/{Clone.rb → clone.rb} +11 -11
- data/lib/config.rb +48 -0
- data/lib/control.rb +81 -0
- data/lib/experiment.rb +99 -0
- data/lib/meta.rb +75 -0
- data/lib/meta/array_meta.rb +32 -0
- data/lib/meta/boolean_meta.rb +26 -0
- data/lib/meta/float_meta.rb +26 -0
- data/lib/meta/integer_meta.rb +26 -0
- data/lib/meta/{NullMeta.rb → null_meta.rb} +21 -19
- data/lib/meta/object_meta.rb +35 -0
- data/lib/meta/string_meta.rb +26 -0
- data/lib/meta_builder.rb +100 -0
- data/lib/reflection.rb +123 -0
- data/lib/reflekt.rb +277 -0
- data/lib/renderer.rb +38 -0
- data/lib/rule.rb +54 -0
- data/lib/rule_set.rb +110 -0
- data/lib/rule_set_aggregator.rb +260 -0
- data/lib/rules/array_rule.rb +94 -0
- data/lib/rules/boolean_rule.rb +43 -0
- data/lib/rules/float_rule.rb +55 -0
- data/lib/rules/integer_rule.rb +55 -0
- data/lib/rules/null_rule.rb +35 -0
- data/lib/rules/object_rule.rb +42 -0
- data/lib/rules/string_rule.rb +75 -0
- data/lib/web/index.html +3 -4
- metadata +46 -29
- data/lib/Accessor.rb +0 -37
- data/lib/Action.rb +0 -88
- data/lib/ActionStack.rb +0 -44
- data/lib/Aggregator.rb +0 -260
- data/lib/Config.rb +0 -42
- data/lib/Control.rb +0 -83
- data/lib/Meta.rb +0 -71
- data/lib/MetaBuilder.rb +0 -84
- data/lib/Reflection.rb +0 -195
- data/lib/Reflekt.rb +0 -243
- data/lib/Renderer.rb +0 -39
- data/lib/Rule.rb +0 -52
- data/lib/RuleSet.rb +0 -109
- data/lib/meta/ArrayMeta.rb +0 -34
- data/lib/meta/BooleanMeta.rb +0 -26
- data/lib/meta/FloatMeta.rb +0 -26
- data/lib/meta/IntegerMeta.rb +0 -26
- data/lib/meta/StringMeta.rb +0 -26
- data/lib/rules/ArrayRule.rb +0 -88
- data/lib/rules/BooleanRule.rb +0 -47
- data/lib/rules/FloatRule.rb +0 -57
- data/lib/rules/IntegerRule.rb +0 -57
- data/lib/rules/NullRule.rb +0 -33
- data/lib/rules/StringRule.rb +0 -81
@@ -0,0 +1,260 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Aggregate control metadata into rule sets.
|
3
|
+
# Validate reflections against aggregated controls.
|
4
|
+
#
|
5
|
+
# @pattern Singleton
|
6
|
+
#
|
7
|
+
# @hierachy
|
8
|
+
# 1. RuleSetAggregator <- YOU ARE HERE
|
9
|
+
# 2. RuleSet
|
10
|
+
# 3. Rule
|
11
|
+
################################################################################
|
12
|
+
|
13
|
+
require_relative 'rule_set'
|
14
|
+
|
15
|
+
module Reflekt
|
16
|
+
class RuleSetAggregator
|
17
|
+
|
18
|
+
##
|
19
|
+
# @param meta_map [Hash] The rules that apply to each meta type.
|
20
|
+
##
|
21
|
+
def initialize(meta_map)
|
22
|
+
@meta_map = meta_map
|
23
|
+
# Key rule sets by class and method.
|
24
|
+
@rule_sets = {}
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Create aggregated rule sets from control metadata.
|
29
|
+
#
|
30
|
+
# @stage Called on setup.
|
31
|
+
# @param controls [Array] Controls with metadata.
|
32
|
+
# @TODO Revert string keys to symbols once "Fix Rowdb.get(path)" bug fixed.
|
33
|
+
##
|
34
|
+
def train(controls)
|
35
|
+
|
36
|
+
# On first use there are no previous controls.
|
37
|
+
return if controls.nil?
|
38
|
+
|
39
|
+
controls.each do |control|
|
40
|
+
|
41
|
+
klass = control["class"].to_sym
|
42
|
+
method = control["method"].to_sym
|
43
|
+
|
44
|
+
##
|
45
|
+
# INPUT
|
46
|
+
##
|
47
|
+
|
48
|
+
# Singular null input.
|
49
|
+
if control["inputs"].nil?
|
50
|
+
train_input(klass, method, nil, 0)
|
51
|
+
# Multiple inputs.
|
52
|
+
else
|
53
|
+
control["inputs"].each_with_index do |meta, arg_num|
|
54
|
+
train_input(klass, method, meta, arg_num)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# OUTPUT
|
60
|
+
##
|
61
|
+
|
62
|
+
# Get rule set.
|
63
|
+
output_rule_set = get_output_rule_set(klass, method)
|
64
|
+
if output_rule_set.nil?
|
65
|
+
output_rule_set = RuleSet.new(@meta_map)
|
66
|
+
set_output_rule_set(klass, method, output_rule_set)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Train on metadata.
|
70
|
+
output_rule_set.train(Meta.deserialize(control["output"]))
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
def train_input(klass, method, meta, arg_num)
|
77
|
+
|
78
|
+
# Get deserialized meta.
|
79
|
+
meta = Meta.deserialize(meta)
|
80
|
+
|
81
|
+
# Get rule set.
|
82
|
+
rule_set = get_input_rule_set(klass, method, arg_num)
|
83
|
+
if rule_set.nil?
|
84
|
+
rule_set = RuleSet.new(@meta_map)
|
85
|
+
set_input_rule_set(klass, method, arg_num, rule_set)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Train on metadata.
|
89
|
+
rule_set.train(meta)
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# Validate inputs.
|
95
|
+
#
|
96
|
+
# @stage Called when validating a control reflection.
|
97
|
+
# @param inputs [Array] The method's arguments.
|
98
|
+
# @param input_rule_sets [Array] The RuleSets to validate each input with.
|
99
|
+
##
|
100
|
+
def test_inputs(inputs, input_rule_sets)
|
101
|
+
|
102
|
+
# Default result to PASS.
|
103
|
+
result = true
|
104
|
+
|
105
|
+
# Validate each argument against each rule set for that argument.
|
106
|
+
inputs.each_with_index do |input, arg_num|
|
107
|
+
|
108
|
+
unless input_rule_sets[arg_num].nil?
|
109
|
+
|
110
|
+
rule_set = input_rule_sets[arg_num]
|
111
|
+
|
112
|
+
unless rule_set.test(input)
|
113
|
+
result = false
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
return result
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
##
|
124
|
+
# Validate output.
|
125
|
+
#
|
126
|
+
# @stage Called when validating a reflection.
|
127
|
+
# @param output [Dynamic] The method's return value.
|
128
|
+
# @param output_rule_set [RuleSet] The rule set to validate the output with.
|
129
|
+
##
|
130
|
+
def test_output(output, output_rule_set)
|
131
|
+
|
132
|
+
# Default to a PASS result.
|
133
|
+
result = true
|
134
|
+
|
135
|
+
unless output_rule_set.nil?
|
136
|
+
|
137
|
+
# Validate output rule set for that argument.
|
138
|
+
unless output_rule_set.test(output)
|
139
|
+
result = false
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
return result
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
##
|
149
|
+
# Get aggregated RuleSets for all inputs.
|
150
|
+
#
|
151
|
+
# @stage Called when building a reflection.
|
152
|
+
# @param klass [Symbol]
|
153
|
+
# @param method [Symbol]
|
154
|
+
# @return [Array]
|
155
|
+
##
|
156
|
+
def get_input_rule_sets(klass, method)
|
157
|
+
@rule_sets.dig(klass, method, :inputs)
|
158
|
+
end
|
159
|
+
|
160
|
+
##
|
161
|
+
# Get an aggregated RuleSet for an output.
|
162
|
+
#
|
163
|
+
# @stage Called when building a reflection.
|
164
|
+
# @param klass [Symbol]
|
165
|
+
# @param method [Symbol]
|
166
|
+
# @return [RuleSet]
|
167
|
+
##
|
168
|
+
def get_output_rule_set(klass, method)
|
169
|
+
@rule_sets.dig(klass, method, :output)
|
170
|
+
end
|
171
|
+
|
172
|
+
##
|
173
|
+
# Get the base rule type for a data type.
|
174
|
+
##
|
175
|
+
def self.value_to_rule_type(value)
|
176
|
+
|
177
|
+
data_type = value.class
|
178
|
+
|
179
|
+
rule_types = {
|
180
|
+
Array => ArrayRule,
|
181
|
+
TrueClass => BooleanRule,
|
182
|
+
FalseClass => BooleanRule,
|
183
|
+
Float => FloatRule,
|
184
|
+
Integer => IntegerRule,
|
185
|
+
NilClass => NullRule,
|
186
|
+
String => StringRule
|
187
|
+
}
|
188
|
+
|
189
|
+
return rule_types[data_type]
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
def self.testable?(args, input_rule_sets)
|
194
|
+
|
195
|
+
args.each_with_index do |arg, arg_num|
|
196
|
+
|
197
|
+
rule_type = value_to_rule_type(arg)
|
198
|
+
if input_rule_sets[arg_num].rules[rule_type].nil?
|
199
|
+
return false
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
|
204
|
+
return true
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
##############################################################################
|
209
|
+
# HELPERS
|
210
|
+
##############################################################################
|
211
|
+
|
212
|
+
private
|
213
|
+
|
214
|
+
##
|
215
|
+
# Get an aggregated RuleSet for an input.
|
216
|
+
#
|
217
|
+
# @param klass [Symbol]
|
218
|
+
# @param method [Symbol]
|
219
|
+
# @return [RuleSet]
|
220
|
+
##
|
221
|
+
def get_input_rule_set(klass, method, arg_num)
|
222
|
+
@rule_sets.dig(klass, method, :inputs, arg_num)
|
223
|
+
end
|
224
|
+
|
225
|
+
##
|
226
|
+
# Set an aggregated RuleSet for an input.
|
227
|
+
#
|
228
|
+
# @param klass [Symbol]
|
229
|
+
# @param method [Symbol]
|
230
|
+
##
|
231
|
+
def set_input_rule_set(klass, method, arg_num, rule_set)
|
232
|
+
|
233
|
+
# Set defaults.
|
234
|
+
@rule_sets[klass] = {} unless @rule_sets.key? klass
|
235
|
+
@rule_sets[klass][method] = {} unless @rule_sets[klass].key? method
|
236
|
+
@rule_sets[klass][method][:inputs] = [] unless @rule_sets[klass][method].key? :inputs
|
237
|
+
# Set value.
|
238
|
+
@rule_sets[klass][method][:inputs][arg_num] = rule_set
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
##
|
243
|
+
# Set an aggregated RuleSet for an output.
|
244
|
+
#
|
245
|
+
# @param klass [Symbol]
|
246
|
+
# @param method [Symbol]
|
247
|
+
# @param rule_set [RuleSet]
|
248
|
+
##
|
249
|
+
def set_output_rule_set(klass, method, rule_set)
|
250
|
+
|
251
|
+
# Set defaults.
|
252
|
+
@rule_sets[klass] = {} unless @rule_sets.key? klass
|
253
|
+
@rule_sets[klass][method] = {} unless @rule_sets[klass].key? method
|
254
|
+
# Set value.
|
255
|
+
@rule_sets[klass][method][:output] = rule_set
|
256
|
+
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
260
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require_relative '../rule'
|
2
|
+
|
3
|
+
module Reflekt
|
4
|
+
class ArrayRule < Rule
|
5
|
+
|
6
|
+
def initialize()
|
7
|
+
@type = :array
|
8
|
+
@min = nil
|
9
|
+
@max = nil
|
10
|
+
@min_length = nil
|
11
|
+
@max_length = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
##
|
15
|
+
# @param meta [ArrayMeta]
|
16
|
+
##
|
17
|
+
def train(meta)
|
18
|
+
if Meta.numeric? meta[:min]
|
19
|
+
# Min value.
|
20
|
+
meta_min = meta[:min].to_i
|
21
|
+
if @min.nil?
|
22
|
+
@min = meta_min
|
23
|
+
else
|
24
|
+
@min = meta_min if meta_min < @min
|
25
|
+
end
|
26
|
+
|
27
|
+
# Max value.
|
28
|
+
meta_max = meta[:max].to_i
|
29
|
+
if @max.nil?
|
30
|
+
@max = meta_max
|
31
|
+
else
|
32
|
+
@max = meta_max if meta_max > @max
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Min length.
|
37
|
+
if @min_length.nil?
|
38
|
+
@min_length = meta[:length]
|
39
|
+
else
|
40
|
+
@min_length = meta[:length] if meta[:length] < @min_length
|
41
|
+
end
|
42
|
+
|
43
|
+
# Max length.
|
44
|
+
if @max_length.nil?
|
45
|
+
@max_length = meta[:length]
|
46
|
+
else
|
47
|
+
@max_length = meta[:length] if meta[:length] > @max_length
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# @param value [Array]
|
53
|
+
##
|
54
|
+
def test(value)
|
55
|
+
# Handle empty value.
|
56
|
+
return true if value.empty? && @min_length == 0 && @max_length == 0
|
57
|
+
|
58
|
+
unless value.empty?
|
59
|
+
# Numbers only; if the value is a string then there will be no min/max.
|
60
|
+
unless @min.nil? || @max.nil?
|
61
|
+
return false if value.min() < @min
|
62
|
+
return false if value.max() > @max
|
63
|
+
end
|
64
|
+
|
65
|
+
# Min/max length.
|
66
|
+
return false if value.length < @min_length
|
67
|
+
return false if value.length > @max_length
|
68
|
+
end
|
69
|
+
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
def result()
|
74
|
+
{
|
75
|
+
:type => @type,
|
76
|
+
:min => @min,
|
77
|
+
:max => @max,
|
78
|
+
:min_length => @min_length,
|
79
|
+
:max_length => @max_length
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
def random()
|
84
|
+
array = Array.new(rand(@min_length..@max_length))
|
85
|
+
|
86
|
+
array.each_with_index do |item, index|
|
87
|
+
array[index] = rand(@min..@max)
|
88
|
+
end
|
89
|
+
|
90
|
+
return array
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'set'
|
2
|
+
require_relative '../rule'
|
3
|
+
|
4
|
+
module Reflekt
|
5
|
+
class BooleanRule < Rule
|
6
|
+
|
7
|
+
def initialize()
|
8
|
+
@type = :bool
|
9
|
+
@booleans = Set.new()
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# @param meta [BooleanMeta]
|
14
|
+
##
|
15
|
+
def train(meta)
|
16
|
+
value = meta[:value]
|
17
|
+
|
18
|
+
unless value.nil?
|
19
|
+
@booleans << value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# @param value [Boolean]
|
25
|
+
##
|
26
|
+
def test(value)
|
27
|
+
# Booleans are stored as strings.
|
28
|
+
@booleans.include? value.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
def result()
|
32
|
+
{
|
33
|
+
:type => @type,
|
34
|
+
:booleans => @booleans
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def random()
|
39
|
+
@booleans.to_a.sample
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative '../rule'
|
2
|
+
|
3
|
+
module Reflekt
|
4
|
+
class FloatRule < Rule
|
5
|
+
|
6
|
+
def initialize()
|
7
|
+
@type = :float
|
8
|
+
@min = nil
|
9
|
+
@max = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# @param meta [FloatMeta]
|
14
|
+
##
|
15
|
+
def train(meta)
|
16
|
+
value = meta[:value]
|
17
|
+
|
18
|
+
if @min.nil?
|
19
|
+
@min = value
|
20
|
+
else
|
21
|
+
@min = value if value < @min
|
22
|
+
end
|
23
|
+
|
24
|
+
if @max.nil?
|
25
|
+
@max = value
|
26
|
+
else
|
27
|
+
@max = value if value > @max
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# @param value [Float]
|
33
|
+
##
|
34
|
+
def test(value)
|
35
|
+
# Numbers only; if the value is a string then there will be no min/max.
|
36
|
+
unless @min.nil? || @max.nil?
|
37
|
+
return false if value < @min
|
38
|
+
return false if value > @max
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def result()
|
43
|
+
{
|
44
|
+
:type => @type,
|
45
|
+
:min => @min,
|
46
|
+
:max => @max
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def random()
|
51
|
+
rand(@min..@max)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|