reflekt 0.9.8 → 1.0.3
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 +5 -5
- data/lib/Aggregator.rb +144 -86
- data/lib/Clone.rb +31 -0
- data/lib/Config.rb +42 -0
- data/lib/Control.rb +53 -15
- data/lib/Execution.rb +15 -6
- data/lib/Meta.rb +48 -4
- data/lib/MetaBuilder.rb +34 -6
- data/lib/Reflection.rb +73 -38
- data/lib/Reflekt.rb +104 -66
- data/lib/Rule.rb +19 -3
- data/lib/RuleSet.rb +59 -55
- data/lib/ShadowStack.rb +2 -0
- data/lib/meta/ArrayMeta.rb +34 -0
- data/lib/meta/BooleanMeta.rb +26 -0
- data/lib/meta/FloatMeta.rb +26 -0
- data/lib/meta/IntegerMeta.rb +3 -4
- data/lib/meta/NullMeta.rb +34 -0
- data/lib/meta/StringMeta.rb +4 -5
- data/lib/rules/ArrayRule.rb +88 -0
- data/lib/rules/BooleanRule.rb +47 -0
- data/lib/rules/FloatRule.rb +57 -0
- data/lib/rules/IntegerRule.rb +8 -2
- data/lib/rules/NullRule.rb +36 -0
- data/lib/rules/StringRule.rb +26 -2
- data/lib/web/README.md +3 -3
- data/lib/web/bundle.js +5 -5
- data/lib/web/server.js +45 -49
- metadata +16 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d09b97f103669d2806a5c6e32da41e978fecff763c558d5aa8fb0739bf8e984a
|
4
|
+
data.tar.gz: 5f40bbfaa6444d452a0f91c1371d0d9aa75a5cd7edd5da8e36ac81d7f0c7532d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7198d5f60ee546e1becc9e7e75141705b0f4a01214e70bba2ba597872b2ff7dbd0cd60deb877a18fde3b4c25ba48ce94bede291bd9ddc089c3d195710dd5728
|
7
|
+
data.tar.gz: 23b79441dfa54881f1a537d259f686b8528f950aa1caac960c43403d7f5f24301a903ba99cc84d7bf1e743f6f6e16001141cff40a8c70139bf55032f38193131
|
data/lib/Accessor.rb
CHANGED
@@ -2,14 +2,15 @@
|
|
2
2
|
# Access variables via one object to avoid polluting the caller class scope.
|
3
3
|
#
|
4
4
|
# @pattern Singleton
|
5
|
+
#
|
5
6
|
# @note Some variables are not accessed via Accessor:
|
6
7
|
# - @reflekt_counts on the instance
|
7
|
-
# - @reflekt_enabled on the instance
|
8
8
|
# - @@reflekt_skipped_methods on the instance's singleton class
|
9
9
|
################################################################################
|
10
10
|
|
11
11
|
class Accessor
|
12
12
|
|
13
|
+
attr_accessor :config
|
13
14
|
attr_accessor :setup
|
14
15
|
attr_accessor :db
|
15
16
|
attr_accessor :stack
|
@@ -17,11 +18,11 @@ class Accessor
|
|
17
18
|
attr_accessor :renderer
|
18
19
|
attr_accessor :path
|
19
20
|
attr_accessor :output_path
|
20
|
-
attr_accessor :
|
21
|
-
attr_accessor :reflect_limit
|
21
|
+
attr_accessor :error
|
22
22
|
|
23
23
|
def initialize()
|
24
24
|
|
25
|
+
@config = nil
|
25
26
|
@setup = nil
|
26
27
|
@db = nil
|
27
28
|
@stack = nil
|
@@ -29,8 +30,7 @@ class Accessor
|
|
29
30
|
@renderer = nil
|
30
31
|
@path = nil
|
31
32
|
@output_path = nil
|
32
|
-
@
|
33
|
-
@reflect_limit = nil
|
33
|
+
@error = false
|
34
34
|
|
35
35
|
end
|
36
36
|
|
data/lib/Aggregator.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
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
|
#
|
7
7
|
# @hierachy
|
8
|
-
# 1. Aggregator
|
8
|
+
# 1. Aggregator <- YOU ARE HERE
|
9
9
|
# 2. RuleSet
|
10
10
|
# 3. Rule
|
11
11
|
################################################################################
|
@@ -14,102 +14,47 @@ require 'RuleSet'
|
|
14
14
|
|
15
15
|
class Aggregator
|
16
16
|
|
17
|
-
def initialize()
|
18
|
-
|
19
|
-
# Key rule sets by class and method.
|
20
|
-
@rule_sets = {}
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
##
|
25
|
-
# Get aggregated RuleSets for all inputs.
|
26
|
-
#
|
27
|
-
# @param klass [Symbol]
|
28
|
-
# @param method [Symbol]
|
29
|
-
# @return [Array]
|
30
|
-
##
|
31
|
-
def get_input_rule_sets(klass, method)
|
32
|
-
return @rule_sets.dig(klass, method, :inputs)
|
33
|
-
end
|
34
|
-
|
35
|
-
##
|
36
|
-
# Get an aggregated RuleSet for an input.
|
37
|
-
#
|
38
|
-
# @param klass [Symbol]
|
39
|
-
# @param method [Symbol]
|
40
|
-
# @return [RuleSet]
|
41
17
|
##
|
42
|
-
|
43
|
-
@rule_sets.dig(klass, method, :inputs, arg_num)
|
44
|
-
end
|
45
|
-
|
18
|
+
# @param meta_map [Hash] The rules that apply to each meta type.
|
46
19
|
##
|
47
|
-
|
48
|
-
#
|
49
|
-
# @param klass [Symbol]
|
50
|
-
# @param method [Symbol]
|
51
|
-
# @return [RuleSet]
|
52
|
-
##
|
53
|
-
def get_output_rule_set(klass, method)
|
54
|
-
@rule_sets.dig(klass, method, :output)
|
55
|
-
end
|
20
|
+
def initialize(meta_map)
|
56
21
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
# @param klass [Symbol]
|
61
|
-
# @param method [Symbol]
|
62
|
-
##
|
63
|
-
def set_input_rule_set(klass, method, arg_num, rule_set)
|
64
|
-
# Set defaults.
|
65
|
-
@rule_sets[klass] = {} unless @rule_sets.key? klass
|
66
|
-
@rule_sets[klass][method] = {} unless @rule_sets[klass].key? method
|
67
|
-
@rule_sets[klass][method][:inputs] = [] unless @rule_sets[klass][method].key? :inputs
|
68
|
-
# Set value.
|
69
|
-
@rule_sets[klass][method][:inputs][arg_num] = rule_set
|
70
|
-
end
|
22
|
+
@meta_map = meta_map
|
23
|
+
# Key rule sets by class and method.
|
24
|
+
@rule_sets = {}
|
71
25
|
|
72
|
-
##
|
73
|
-
# Set an aggregated RuleSet for an output.
|
74
|
-
#
|
75
|
-
# @param klass [Symbol]
|
76
|
-
# @param method [Symbol]
|
77
|
-
# @param rule_set [RuleSet]
|
78
|
-
##
|
79
|
-
def set_output_rule_set(klass, method, rule_set)
|
80
|
-
# Set defaults.
|
81
|
-
@rule_sets[klass] = {} unless @rule_sets.key? klass
|
82
|
-
@rule_sets[klass][method] = {} unless @rule_sets[klass].key? method
|
83
|
-
# Set value.
|
84
|
-
@rule_sets[klass][method][:output] = rule_set
|
85
26
|
end
|
86
27
|
|
87
28
|
##
|
88
|
-
# Create aggregated rule sets from
|
29
|
+
# Create aggregated rule sets from control metadata.
|
89
30
|
#
|
90
|
-
# @
|
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.
|
91
34
|
##
|
92
|
-
def train(
|
35
|
+
def train(controls)
|
93
36
|
|
94
|
-
# On first use there are no previous
|
95
|
-
return if
|
37
|
+
# On first use there are no previous controls.
|
38
|
+
return if controls.nil?
|
96
39
|
|
97
|
-
|
40
|
+
controls.each do |control|
|
98
41
|
|
99
|
-
klass =
|
100
|
-
method =
|
42
|
+
klass = control["class"].to_sym
|
43
|
+
method = control["method"].to_sym
|
101
44
|
|
102
45
|
##
|
103
46
|
# INPUT
|
104
47
|
##
|
105
48
|
|
106
|
-
unless
|
107
|
-
|
49
|
+
unless control["inputs"].nil?
|
50
|
+
control["inputs"].each_with_index do |meta, arg_num|
|
51
|
+
|
52
|
+
meta = Meta.deserialize(meta)
|
108
53
|
|
109
54
|
# Get rule set.
|
110
55
|
rule_set = get_input_rule_set(klass, method, arg_num)
|
111
56
|
if rule_set.nil?
|
112
|
-
rule_set = RuleSet.new()
|
57
|
+
rule_set = RuleSet.new(@meta_map)
|
113
58
|
set_input_rule_set(klass, method, arg_num, rule_set)
|
114
59
|
end
|
115
60
|
|
@@ -126,12 +71,12 @@ class Aggregator
|
|
126
71
|
# Get rule set.
|
127
72
|
output_rule_set = get_output_rule_set(klass, method)
|
128
73
|
if output_rule_set.nil?
|
129
|
-
output_rule_set = RuleSet.new()
|
74
|
+
output_rule_set = RuleSet.new(@meta_map)
|
130
75
|
set_output_rule_set(klass, method, output_rule_set)
|
131
76
|
end
|
132
77
|
|
133
78
|
# Train on metadata.
|
134
|
-
output_rule_set.train(
|
79
|
+
output_rule_set.train(Meta.deserialize(control["output"]))
|
135
80
|
|
136
81
|
end
|
137
82
|
|
@@ -140,22 +85,23 @@ class Aggregator
|
|
140
85
|
##
|
141
86
|
# Validate inputs.
|
142
87
|
#
|
88
|
+
# @stage Called when validating a reflection.
|
143
89
|
# @param inputs [Array] The method's arguments.
|
144
90
|
# @param input_rule_sets [Array] The RuleSets to validate each input with.
|
145
91
|
##
|
146
|
-
def
|
92
|
+
def test_inputs(inputs, input_rule_sets)
|
147
93
|
|
148
|
-
# Default to
|
94
|
+
# Default result to PASS.
|
149
95
|
result = true
|
150
96
|
|
151
|
-
# Validate each argument against each
|
97
|
+
# Validate each argument against each rule set for that argument.
|
152
98
|
inputs.each_with_index do |input, arg_num|
|
153
99
|
|
154
100
|
unless input_rule_sets[arg_num].nil?
|
155
101
|
|
156
102
|
rule_set = input_rule_sets[arg_num]
|
157
103
|
|
158
|
-
unless rule_set.
|
104
|
+
unless rule_set.test(input)
|
159
105
|
result = false
|
160
106
|
end
|
161
107
|
|
@@ -169,10 +115,11 @@ class Aggregator
|
|
169
115
|
##
|
170
116
|
# Validate output.
|
171
117
|
#
|
118
|
+
# @stage Called when validating a reflection.
|
172
119
|
# @param output [Dynamic] The method's return value.
|
173
120
|
# @param output_rule_set [RuleSet] The RuleSet to validate the output with.
|
174
121
|
##
|
175
|
-
def
|
122
|
+
def test_output(output, output_rule_set)
|
176
123
|
|
177
124
|
# Default to a PASS result.
|
178
125
|
result = true
|
@@ -180,7 +127,7 @@ class Aggregator
|
|
180
127
|
unless output_rule_set.nil?
|
181
128
|
|
182
129
|
# Validate output RuleSet for that argument.
|
183
|
-
unless output_rule_set.
|
130
|
+
unless output_rule_set.test(output)
|
184
131
|
result = false
|
185
132
|
end
|
186
133
|
|
@@ -190,4 +137,115 @@ class Aggregator
|
|
190
137
|
|
191
138
|
end
|
192
139
|
|
140
|
+
##
|
141
|
+
# Get aggregated RuleSets for all inputs.
|
142
|
+
#
|
143
|
+
# @stage Called when building a reflection.
|
144
|
+
# @param klass [Symbol]
|
145
|
+
# @param method [Symbol]
|
146
|
+
# @return [Array]
|
147
|
+
##
|
148
|
+
def get_input_rule_sets(klass, method)
|
149
|
+
@rule_sets.dig(klass, method, :inputs)
|
150
|
+
end
|
151
|
+
|
152
|
+
##
|
153
|
+
# Get an aggregated RuleSet for an output.
|
154
|
+
#
|
155
|
+
# @stage Called when building a reflection.
|
156
|
+
# @param klass [Symbol]
|
157
|
+
# @param method [Symbol]
|
158
|
+
# @return [RuleSet]
|
159
|
+
##
|
160
|
+
def get_output_rule_set(klass, method)
|
161
|
+
@rule_sets.dig(klass, method, :output)
|
162
|
+
end
|
163
|
+
|
164
|
+
##
|
165
|
+
# Get the base rule type for a data type.
|
166
|
+
##
|
167
|
+
def self.value_to_rule_type(value)
|
168
|
+
|
169
|
+
data_type = value.class
|
170
|
+
|
171
|
+
rule_types = {
|
172
|
+
Array => ArrayRule,
|
173
|
+
TrueClass => BooleanRule,
|
174
|
+
FalseClass => BooleanRule,
|
175
|
+
Float => FloatRule,
|
176
|
+
Integer => IntegerRule,
|
177
|
+
NilClass => NullRule,
|
178
|
+
String => StringRule
|
179
|
+
}
|
180
|
+
|
181
|
+
return rule_types[data_type]
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
def self.testable?(args, input_rule_sets)
|
186
|
+
|
187
|
+
args.each_with_index do |arg, arg_num|
|
188
|
+
|
189
|
+
rule_type = value_to_rule_type(arg)
|
190
|
+
if input_rule_sets[arg_num].rules[rule_type].nil?
|
191
|
+
return false
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
return true
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
##############################################################################
|
201
|
+
# HELPERS
|
202
|
+
##############################################################################
|
203
|
+
|
204
|
+
private
|
205
|
+
|
206
|
+
##
|
207
|
+
# Get an aggregated RuleSet for an input.
|
208
|
+
#
|
209
|
+
# @param klass [Symbol]
|
210
|
+
# @param method [Symbol]
|
211
|
+
# @return [RuleSet]
|
212
|
+
##
|
213
|
+
def get_input_rule_set(klass, method, arg_num)
|
214
|
+
@rule_sets.dig(klass, method, :inputs, arg_num)
|
215
|
+
end
|
216
|
+
|
217
|
+
##
|
218
|
+
# Set an aggregated RuleSet for an input.
|
219
|
+
#
|
220
|
+
# @param klass [Symbol]
|
221
|
+
# @param method [Symbol]
|
222
|
+
##
|
223
|
+
def set_input_rule_set(klass, method, arg_num, rule_set)
|
224
|
+
|
225
|
+
# Set defaults.
|
226
|
+
@rule_sets[klass] = {} unless @rule_sets.key? klass
|
227
|
+
@rule_sets[klass][method] = {} unless @rule_sets[klass].key? method
|
228
|
+
@rule_sets[klass][method][:inputs] = [] unless @rule_sets[klass][method].key? :inputs
|
229
|
+
# Set value.
|
230
|
+
@rule_sets[klass][method][:inputs][arg_num] = rule_set
|
231
|
+
|
232
|
+
end
|
233
|
+
|
234
|
+
##
|
235
|
+
# Set an aggregated RuleSet for an output.
|
236
|
+
#
|
237
|
+
# @param klass [Symbol]
|
238
|
+
# @param method [Symbol]
|
239
|
+
# @param rule_set [RuleSet]
|
240
|
+
##
|
241
|
+
def set_output_rule_set(klass, method, rule_set)
|
242
|
+
|
243
|
+
# Set defaults.
|
244
|
+
@rule_sets[klass] = {} unless @rule_sets.key? klass
|
245
|
+
@rule_sets[klass][method] = {} unless @rule_sets[klass].key? method
|
246
|
+
# Set value.
|
247
|
+
@rule_sets[klass][method][:output] = rule_set
|
248
|
+
|
249
|
+
end
|
250
|
+
|
193
251
|
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
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
class Config
|
2
|
+
|
3
|
+
attr_accessor :enabled
|
4
|
+
attr_accessor :reflect_amount
|
5
|
+
attr_accessor :reflect_limit
|
6
|
+
attr_accessor :meta_map
|
7
|
+
attr_accessor :output_path
|
8
|
+
attr_accessor :output_directory
|
9
|
+
|
10
|
+
def initialize()
|
11
|
+
|
12
|
+
# Reflekt is enabled by default and should be disabled on production.
|
13
|
+
@enabled = true
|
14
|
+
|
15
|
+
# The amount of reflections to create per method call.
|
16
|
+
# A control reflection is created in addition to this.
|
17
|
+
@reflect_amount = 5
|
18
|
+
|
19
|
+
# The maximum amount of reflections that can be created per instance/method.
|
20
|
+
# A method called thousands of times doesn't need that many reflections.
|
21
|
+
@reflect_limit = 10
|
22
|
+
|
23
|
+
# The rules that apply to meta types.
|
24
|
+
@meta_map = {
|
25
|
+
:array => [ArrayRule],
|
26
|
+
:bool => [BooleanRule],
|
27
|
+
:int => [IntegerRule],
|
28
|
+
:float => [FloatRule],
|
29
|
+
:null => [NullRule],
|
30
|
+
:string => [StringRule]
|
31
|
+
}
|
32
|
+
|
33
|
+
# An absolute path to the directory that contains the output directory.
|
34
|
+
# Defaults to current execution path.
|
35
|
+
@output_path = nil
|
36
|
+
|
37
|
+
# Name of output directory.
|
38
|
+
@output_directory = "reflections"
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/lib/Control.rb
CHANGED
@@ -1,10 +1,21 @@
|
|
1
1
|
################################################################################
|
2
2
|
# A shapshot of real data.
|
3
3
|
#
|
4
|
+
# @note
|
5
|
+
# A control's @number property will always be zero.
|
6
|
+
#
|
7
|
+
# @nomenclature
|
8
|
+
# args, inputs/output and meta represent different stages of a value.
|
9
|
+
#
|
4
10
|
# @hierachy
|
5
11
|
# 1. Execution
|
6
|
-
# 2. Control
|
7
|
-
# 3.
|
12
|
+
# 2. Control <- YOU ARE HERE
|
13
|
+
# 3. Meta
|
14
|
+
#
|
15
|
+
# @status
|
16
|
+
# - :pass [Symbol] The reflection passes the rules.
|
17
|
+
# - :fail [Symbol] The reflection fails the rules or produces a system error.
|
18
|
+
# - :error [Symbol] The control reflection produces a system error.
|
8
19
|
################################################################################
|
9
20
|
|
10
21
|
require 'Reflection'
|
@@ -15,27 +26,54 @@ class Control < Reflection
|
|
15
26
|
##
|
16
27
|
# Reflect on a method.
|
17
28
|
#
|
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.
|
29
|
+
# Creates a shadow execution.
|
30
|
+
# @param *args [Dynamic] The method's arguments.
|
23
31
|
##
|
24
32
|
def reflect(*args)
|
25
33
|
|
26
|
-
#
|
27
|
-
|
34
|
+
# Get aggregated rule sets.
|
35
|
+
input_rule_sets = @aggregator.get_input_rule_sets(@klass, @method)
|
36
|
+
output_rule_set = @aggregator.get_output_rule_set(@klass, @method)
|
37
|
+
|
38
|
+
# When arguments exist.
|
39
|
+
unless args.size == 0
|
40
|
+
|
41
|
+
# When aggregated rule sets exist.
|
42
|
+
unless input_rule_sets.nil?
|
43
|
+
|
44
|
+
# Validate arguments against aggregated rule sets.
|
45
|
+
unless @aggregator.test_inputs(args, input_rule_sets)
|
46
|
+
@status = :fail
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
28
50
|
|
29
|
-
|
51
|
+
# Create metadata for each argument.
|
52
|
+
# TODO: Create metadata for other inputs such as properties on the instance.
|
53
|
+
@inputs = MetaBuilder.create_many(args)
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
# Action method with new/old arguments.
|
30
58
|
begin
|
59
|
+
|
60
|
+
# Run reflection.
|
31
61
|
output = @clone.send(@method, *args)
|
32
|
-
|
62
|
+
@output = MetaBuilder.create(output)
|
63
|
+
|
64
|
+
# Validate output with aggregated control rule sets.
|
65
|
+
unless output_rule_set.nil?
|
66
|
+
unless @aggregator.test_output(output, output_rule_set)
|
67
|
+
@status = :fail
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# When a system error occurs.
|
33
72
|
rescue StandardError => message
|
34
|
-
|
73
|
+
|
74
|
+
@status = :error
|
35
75
|
@message = message
|
36
|
-
|
37
|
-
else
|
38
|
-
@status = :pass
|
76
|
+
|
39
77
|
end
|
40
78
|
|
41
79
|
end
|