reflekt 0.9.9 → 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 +4 -4
- data/lib/Accessor.rb +2 -0
- data/lib/Aggregator.rb +123 -82
- data/lib/Clone.rb +31 -0
- data/lib/Config.rb +7 -1
- data/lib/Control.rb +44 -15
- data/lib/Execution.rb +12 -3
- data/lib/Meta.rb +12 -0
- data/lib/MetaBuilder.rb +31 -4
- data/lib/Reflection.rb +65 -37
- data/lib/Reflekt.rb +68 -45
- data/lib/Rule.rb +11 -1
- data/lib/RuleSet.rb +26 -4
- data/lib/meta/ArrayMeta.rb +2 -1
- data/lib/meta/BooleanMeta.rb +5 -2
- data/lib/meta/FloatMeta.rb +26 -0
- data/lib/meta/IntegerMeta.rb +4 -1
- data/lib/meta/StringMeta.rb +4 -1
- data/lib/rules/ArrayRule.rb +14 -1
- data/lib/rules/BooleanRule.rb +6 -3
- data/lib/rules/FloatRule.rb +57 -0
- data/lib/rules/IntegerRule.rb +6 -1
- data/lib/rules/StringRule.rb +25 -1
- data/lib/web/README.md +3 -3
- data/lib/web/bundle.js +5 -5
- data/lib/web/server.js +45 -49
- metadata +9 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e94e86e6d558012df59e1aebfdbbb7c2bf70a2e849e9a186795a3e4d5cb648f0
|
4
|
+
data.tar.gz: 9db428f6c518c06fbddb83e0abd9920b9dc30344846827b5c9505c3f2bc111c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2a7ecf3adb9e06f7f3a09d507265c035bf3c641193711c64fea512b03973696c8ef9278d59eedf43ee83dd03a0f5f552026f0b2f6ba6182c6361bb35a211bf7
|
7
|
+
data.tar.gz: f002c69e490b63dd065e5f0ba0b40e9dcbbe980f71e7df66da01b1bc37b2dfe1081c9e58a3024b388b96628cc98422875a5b90f1e9227327f3241bc5d61450b0
|
data/lib/Accessor.rb
CHANGED
@@ -18,6 +18,7 @@ class Accessor
|
|
18
18
|
attr_accessor :renderer
|
19
19
|
attr_accessor :path
|
20
20
|
attr_accessor :output_path
|
21
|
+
attr_accessor :error
|
21
22
|
|
22
23
|
def initialize()
|
23
24
|
|
@@ -29,6 +30,7 @@ class Accessor
|
|
29
30
|
@renderer = nil
|
30
31
|
@path = nil
|
31
32
|
@output_path = nil
|
33
|
+
@error = false
|
32
34
|
|
33
35
|
end
|
34
36
|
|
data/lib/Aggregator.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
################################################################################
|
2
|
-
# Aggregate
|
3
|
-
# Validate
|
2
|
+
# Aggregate control metadata into rule sets.
|
3
|
+
# Validate reflections against aggregated controls.
|
4
4
|
#
|
5
5
|
# @pattern Singleton
|
6
6
|
#
|
@@ -26,89 +26,33 @@ class Aggregator
|
|
26
26
|
end
|
27
27
|
|
28
28
|
##
|
29
|
-
#
|
30
|
-
#
|
31
|
-
# @param klass [Symbol]
|
32
|
-
# @param method [Symbol]
|
33
|
-
# @return [Array]
|
34
|
-
##
|
35
|
-
def get_input_rule_sets(klass, method)
|
36
|
-
return @rule_sets.dig(klass, method, :inputs)
|
37
|
-
end
|
38
|
-
|
39
|
-
##
|
40
|
-
# Get an aggregated RuleSet for an input.
|
41
|
-
#
|
42
|
-
# @param klass [Symbol]
|
43
|
-
# @param method [Symbol]
|
44
|
-
# @return [RuleSet]
|
45
|
-
##
|
46
|
-
def get_input_rule_set(klass, method, arg_num)
|
47
|
-
@rule_sets.dig(klass, method, :inputs, arg_num)
|
48
|
-
end
|
49
|
-
|
50
|
-
##
|
51
|
-
# Get an aggregated RuleSet for an output.
|
52
|
-
#
|
53
|
-
# @param klass [Symbol]
|
54
|
-
# @param method [Symbol]
|
55
|
-
# @return [RuleSet]
|
56
|
-
##
|
57
|
-
def get_output_rule_set(klass, method)
|
58
|
-
@rule_sets.dig(klass, method, :output)
|
59
|
-
end
|
60
|
-
|
61
|
-
##
|
62
|
-
# Set an aggregated RuleSet for an input.
|
63
|
-
#
|
64
|
-
# @param klass [Symbol]
|
65
|
-
# @param method [Symbol]
|
66
|
-
##
|
67
|
-
def set_input_rule_set(klass, method, arg_num, rule_set)
|
68
|
-
# Set defaults.
|
69
|
-
@rule_sets[klass] = {} unless @rule_sets.key? klass
|
70
|
-
@rule_sets[klass][method] = {} unless @rule_sets[klass].key? method
|
71
|
-
@rule_sets[klass][method][:inputs] = [] unless @rule_sets[klass][method].key? :inputs
|
72
|
-
# Set value.
|
73
|
-
@rule_sets[klass][method][:inputs][arg_num] = rule_set
|
74
|
-
end
|
75
|
-
|
76
|
-
##
|
77
|
-
# Set an aggregated RuleSet for an output.
|
29
|
+
# Create aggregated rule sets from control metadata.
|
78
30
|
#
|
79
|
-
# @
|
80
|
-
# @param
|
81
|
-
# @
|
31
|
+
# @stage Called on setup.
|
32
|
+
# @param controls [Array] Controls with metadata.
|
33
|
+
# @TODO Revert string keys to symbols once "Fix Rowdb.get(path)" bug fixed.
|
82
34
|
##
|
83
|
-
def
|
84
|
-
# Set defaults.
|
85
|
-
@rule_sets[klass] = {} unless @rule_sets.key? klass
|
86
|
-
@rule_sets[klass][method] = {} unless @rule_sets[klass].key? method
|
87
|
-
# Set value.
|
88
|
-
@rule_sets[klass][method][:output] = rule_set
|
89
|
-
end
|
90
|
-
|
91
|
-
##
|
92
|
-
# Create aggregated rule sets from reflection metadata.
|
93
|
-
#
|
94
|
-
# @param reflections [Array] Controls with metadata.
|
95
|
-
##
|
96
|
-
def train(reflections)
|
35
|
+
def train(controls)
|
97
36
|
|
98
|
-
# On first use there are no previous
|
99
|
-
return if
|
37
|
+
# On first use there are no previous controls.
|
38
|
+
return if controls.nil?
|
100
39
|
|
101
|
-
|
40
|
+
controls.each do |control|
|
102
41
|
|
103
|
-
klass =
|
104
|
-
method =
|
42
|
+
klass = control["class"].to_sym
|
43
|
+
method = control["method"].to_sym
|
105
44
|
|
106
45
|
##
|
107
46
|
# INPUT
|
108
47
|
##
|
109
48
|
|
110
|
-
unless
|
111
|
-
|
49
|
+
unless control["inputs"].nil?
|
50
|
+
control["inputs"].each_with_index do |meta, arg_num|
|
51
|
+
|
52
|
+
# TODO: Remove once "Fix Rowdb.get(path)" bug fixed.
|
53
|
+
meta = meta.transform_keys(&:to_sym)
|
54
|
+
# Deserialize meta type to symbol.
|
55
|
+
meta[:type] = meta[:type].to_sym
|
112
56
|
|
113
57
|
# Get rule set.
|
114
58
|
rule_set = get_input_rule_set(klass, method, arg_num)
|
@@ -135,7 +79,7 @@ class Aggregator
|
|
135
79
|
end
|
136
80
|
|
137
81
|
# Train on metadata.
|
138
|
-
output_rule_set.train(
|
82
|
+
output_rule_set.train(control["output"])
|
139
83
|
|
140
84
|
end
|
141
85
|
|
@@ -144,22 +88,23 @@ class Aggregator
|
|
144
88
|
##
|
145
89
|
# Validate inputs.
|
146
90
|
#
|
91
|
+
# @stage Called when validating a reflection.
|
147
92
|
# @param inputs [Array] The method's arguments.
|
148
93
|
# @param input_rule_sets [Array] The RuleSets to validate each input with.
|
149
94
|
##
|
150
|
-
def
|
95
|
+
def test_inputs(inputs, input_rule_sets)
|
151
96
|
|
152
|
-
# Default to
|
97
|
+
# Default result to PASS.
|
153
98
|
result = true
|
154
99
|
|
155
|
-
# Validate each argument against each
|
100
|
+
# Validate each argument against each rule set for that argument.
|
156
101
|
inputs.each_with_index do |input, arg_num|
|
157
102
|
|
158
103
|
unless input_rule_sets[arg_num].nil?
|
159
104
|
|
160
105
|
rule_set = input_rule_sets[arg_num]
|
161
106
|
|
162
|
-
unless rule_set.
|
107
|
+
unless rule_set.test(input)
|
163
108
|
result = false
|
164
109
|
end
|
165
110
|
|
@@ -173,10 +118,11 @@ class Aggregator
|
|
173
118
|
##
|
174
119
|
# Validate output.
|
175
120
|
#
|
121
|
+
# @stage Called when validating a reflection.
|
176
122
|
# @param output [Dynamic] The method's return value.
|
177
123
|
# @param output_rule_set [RuleSet] The RuleSet to validate the output with.
|
178
124
|
##
|
179
|
-
def
|
125
|
+
def test_output(output, output_rule_set)
|
180
126
|
|
181
127
|
# Default to a PASS result.
|
182
128
|
result = true
|
@@ -184,7 +130,7 @@ class Aggregator
|
|
184
130
|
unless output_rule_set.nil?
|
185
131
|
|
186
132
|
# Validate output RuleSet for that argument.
|
187
|
-
unless output_rule_set.
|
133
|
+
unless output_rule_set.test(output)
|
188
134
|
result = false
|
189
135
|
end
|
190
136
|
|
@@ -194,4 +140,99 @@ class Aggregator
|
|
194
140
|
|
195
141
|
end
|
196
142
|
|
143
|
+
##
|
144
|
+
# Get aggregated RuleSets for all inputs.
|
145
|
+
#
|
146
|
+
# @stage Called when building a reflection.
|
147
|
+
# @param klass [Symbol]
|
148
|
+
# @param method [Symbol]
|
149
|
+
# @return [Array]
|
150
|
+
##
|
151
|
+
def get_input_rule_sets(klass, method)
|
152
|
+
@rule_sets.dig(klass, method, :inputs)
|
153
|
+
end
|
154
|
+
|
155
|
+
##
|
156
|
+
# Get an aggregated RuleSet for an output.
|
157
|
+
#
|
158
|
+
# @stage Called when building a reflection.
|
159
|
+
# @param klass [Symbol]
|
160
|
+
# @param method [Symbol]
|
161
|
+
# @return [RuleSet]
|
162
|
+
##
|
163
|
+
def get_output_rule_set(klass, method)
|
164
|
+
@rule_sets.dig(klass, method, :output)
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
# Get the base rule type for a data type.
|
169
|
+
##
|
170
|
+
def self.value_to_rule_type(value)
|
171
|
+
|
172
|
+
data_type = value.class
|
173
|
+
|
174
|
+
rule_types = {
|
175
|
+
Array => ArrayRule,
|
176
|
+
TrueClass => BooleanRule,
|
177
|
+
FalseClass => BooleanRule,
|
178
|
+
Float => FloatRule,
|
179
|
+
Integer => IntegerRule,
|
180
|
+
String => StringRule
|
181
|
+
}
|
182
|
+
|
183
|
+
return rule_types[data_type]
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
##############################################################################
|
188
|
+
# HELPERS
|
189
|
+
##############################################################################
|
190
|
+
|
191
|
+
private
|
192
|
+
|
193
|
+
##
|
194
|
+
# Get an aggregated RuleSet for an input.
|
195
|
+
#
|
196
|
+
# @param klass [Symbol]
|
197
|
+
# @param method [Symbol]
|
198
|
+
# @return [RuleSet]
|
199
|
+
##
|
200
|
+
def get_input_rule_set(klass, method, arg_num)
|
201
|
+
@rule_sets.dig(klass, method, :inputs, arg_num)
|
202
|
+
end
|
203
|
+
|
204
|
+
##
|
205
|
+
# Set an aggregated RuleSet for an input.
|
206
|
+
#
|
207
|
+
# @param klass [Symbol]
|
208
|
+
# @param method [Symbol]
|
209
|
+
##
|
210
|
+
def set_input_rule_set(klass, method, arg_num, rule_set)
|
211
|
+
|
212
|
+
# Set defaults.
|
213
|
+
@rule_sets[klass] = {} unless @rule_sets.key? klass
|
214
|
+
@rule_sets[klass][method] = {} unless @rule_sets[klass].key? method
|
215
|
+
@rule_sets[klass][method][:inputs] = [] unless @rule_sets[klass][method].key? :inputs
|
216
|
+
# Set value.
|
217
|
+
@rule_sets[klass][method][:inputs][arg_num] = rule_set
|
218
|
+
|
219
|
+
end
|
220
|
+
|
221
|
+
##
|
222
|
+
# Set an aggregated RuleSet for an output.
|
223
|
+
#
|
224
|
+
# @param klass [Symbol]
|
225
|
+
# @param method [Symbol]
|
226
|
+
# @param rule_set [RuleSet]
|
227
|
+
##
|
228
|
+
def set_output_rule_set(klass, method, rule_set)
|
229
|
+
|
230
|
+
# Set defaults.
|
231
|
+
@rule_sets[klass] = {} unless @rule_sets.key? klass
|
232
|
+
@rule_sets[klass][method] = {} unless @rule_sets[klass].key? method
|
233
|
+
# Set value.
|
234
|
+
@rule_sets[klass][method][:output] = rule_set
|
235
|
+
|
236
|
+
end
|
237
|
+
|
197
238
|
end
|
data/lib/Clone.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
################################################################################
|
2
|
+
# A clone of the instance that a reflection calls methods on,
|
3
|
+
# as well as any other instances that those methods may lead to.
|
4
|
+
#
|
5
|
+
# @note
|
6
|
+
# Not currently in use due to bug where "send" needs to be called directly
|
7
|
+
# on object, not indirectly through clone which results in "undefined method".
|
8
|
+
#
|
9
|
+
# @hierachy
|
10
|
+
# 1. Execution
|
11
|
+
# 2. Reflection
|
12
|
+
# 3. Clone <- YOU ARE HERE
|
13
|
+
################################################################################
|
14
|
+
|
15
|
+
class Clone
|
16
|
+
|
17
|
+
def initialize(execution)
|
18
|
+
|
19
|
+
# Clone the execution's calling object.
|
20
|
+
@caller_object_clone = execution.caller_object.clone
|
21
|
+
|
22
|
+
# TODO: Clone any other instances that this clone references.
|
23
|
+
# TODO: Replace clone's references to these new instances.
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
def action(method, *new_args)
|
28
|
+
@caller_object_clone.send(method, *new_args)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/lib/Config.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
class Config
|
2
2
|
|
3
|
+
attr_accessor :enabled
|
3
4
|
attr_accessor :reflect_amount
|
4
5
|
attr_accessor :reflect_limit
|
5
6
|
attr_accessor :meta_map
|
@@ -8,8 +9,12 @@ class Config
|
|
8
9
|
|
9
10
|
def initialize()
|
10
11
|
|
12
|
+
# Reflekt is enabled by default and should be disabled on production.
|
13
|
+
@enabled = true
|
14
|
+
|
11
15
|
# The amount of reflections to create per method call.
|
12
|
-
|
16
|
+
# A control reflection is created in addition to this.
|
17
|
+
@reflect_amount = 5
|
13
18
|
|
14
19
|
# The maximum amount of reflections that can be created per instance/method.
|
15
20
|
# A method called thousands of times doesn't need that many reflections.
|
@@ -20,6 +25,7 @@ class Config
|
|
20
25
|
:array => [ArrayRule],
|
21
26
|
:bool => [BooleanRule],
|
22
27
|
:int => [IntegerRule],
|
28
|
+
:float => [FloatRule],
|
23
29
|
:string => [StringRule]
|
24
30
|
}
|
25
31
|
|
data/lib/Control.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
################################################################################
|
2
2
|
# A shapshot of real data.
|
3
3
|
#
|
4
|
+
# A control's @number property will always be zero.
|
5
|
+
#
|
4
6
|
# @hierachy
|
5
7
|
# 1. Execution
|
6
|
-
# 2. Control
|
7
|
-
# 3.
|
8
|
+
# 2. Control <- YOU ARE HERE
|
9
|
+
# 3. Meta
|
8
10
|
################################################################################
|
9
11
|
|
10
12
|
require 'Reflection'
|
@@ -15,27 +17,54 @@ class Control < Reflection
|
|
15
17
|
##
|
16
18
|
# Reflect on a method.
|
17
19
|
#
|
18
|
-
# Creates a shadow execution
|
19
|
-
#
|
20
|
-
# @param method [Symbol] The name of the method.
|
21
|
-
# @param *args [Args] The method arguments.
|
22
|
-
# @return [Hash] A reflection hash.
|
20
|
+
# Creates a shadow execution.
|
21
|
+
# @param *args [Dynamic] The method's arguments.
|
23
22
|
##
|
24
23
|
def reflect(*args)
|
25
24
|
|
26
|
-
#
|
27
|
-
|
25
|
+
# Get aggregated rule sets.
|
26
|
+
input_rule_sets = @aggregator.get_input_rule_sets(@klass, @method)
|
27
|
+
output_rule_set = @aggregator.get_output_rule_set(@klass, @method)
|
28
|
+
|
29
|
+
# When arguments exist.
|
30
|
+
unless args.size == 0
|
31
|
+
|
32
|
+
# When aggregated rule sets exist.
|
33
|
+
unless input_rule_sets.nil?
|
34
|
+
|
35
|
+
# Validate arguments against aggregated rule sets.
|
36
|
+
unless @aggregator.test_inputs(args, input_rule_sets)
|
37
|
+
@status = :fail
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
# Create metadata for each argument.
|
43
|
+
# TODO: Create metadata for other inputs such as properties on the instance.
|
44
|
+
@inputs = MetaBuilder.create_many(args)
|
28
45
|
|
29
|
-
|
46
|
+
end
|
47
|
+
|
48
|
+
# Action method with new/old arguments.
|
30
49
|
begin
|
50
|
+
|
51
|
+
# Run reflection.
|
31
52
|
output = @clone.send(@method, *args)
|
32
|
-
|
53
|
+
@output = MetaBuilder.create(output)
|
54
|
+
|
55
|
+
# Validate output with aggregated control rule sets.
|
56
|
+
unless output_rule_set.nil?
|
57
|
+
unless @aggregator.test_output(output, output_rule_set)
|
58
|
+
@status = :fail
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# When a system error occurs.
|
33
63
|
rescue StandardError => message
|
34
|
-
|
64
|
+
|
65
|
+
@status = :error
|
35
66
|
@message = message
|
36
|
-
|
37
|
-
else
|
38
|
-
@status = :pass
|
67
|
+
|
39
68
|
end
|
40
69
|
|
41
70
|
end
|
data/lib/Execution.rb
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
################################################################################
|
2
|
+
# A shadow execution.
|
3
|
+
#
|
4
|
+
# @hierachy
|
5
|
+
# 1. Execution <- YOU ARE HERE
|
6
|
+
# 2. Reflection
|
7
|
+
# 3. Meta
|
8
|
+
################################################################################
|
9
|
+
|
1
10
|
class Execution
|
2
11
|
|
3
12
|
attr_accessor :unique_id
|
@@ -19,10 +28,10 @@ class Execution
|
|
19
28
|
#
|
20
29
|
# @param object [Object] The calling object.
|
21
30
|
# @param method [Symbol] The calling method.
|
22
|
-
# @param
|
31
|
+
# @param reflect_amount [Integer] The number of reflections to create per execution.
|
23
32
|
# @param stack [ShadowStack] The shadow execution call stack.
|
24
33
|
##
|
25
|
-
def initialize(caller_object, method,
|
34
|
+
def initialize(caller_object, method, reflect_amount, stack)
|
26
35
|
|
27
36
|
@time = Time.now.to_i
|
28
37
|
@unique_id = @time + rand(1..99999)
|
@@ -42,7 +51,7 @@ class Execution
|
|
42
51
|
|
43
52
|
# Reflections.
|
44
53
|
@control = nil
|
45
|
-
@reflections = Array.new(
|
54
|
+
@reflections = Array.new(reflect_amount)
|
46
55
|
|
47
56
|
# State.
|
48
57
|
if @stack.peek() == nil
|