reflekt 0.9.7 → 1.0.2
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 +9 -10
- data/lib/Aggregator.rb +251 -0
- data/lib/Clone.rb +31 -0
- data/lib/Config.rb +42 -0
- data/lib/Control.rb +62 -14
- data/lib/Execution.rb +15 -6
- data/lib/Meta.rb +71 -0
- data/lib/MetaBuilder.rb +84 -0
- data/lib/Reflection.rb +109 -89
- data/lib/Reflekt.rb +118 -90
- data/lib/Renderer.rb +5 -0
- data/lib/Rule.rb +37 -17
- data/lib/RuleSet.rb +72 -42
- data/lib/ShadowStack.rb +9 -10
- 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 +26 -0
- data/lib/meta/NullMeta.rb +34 -0
- data/lib/meta/StringMeta.rb +26 -0
- data/lib/rules/ArrayRule.rb +88 -0
- data/lib/rules/BooleanRule.rb +47 -0
- data/lib/rules/FloatRule.rb +40 -11
- data/lib/rules/IntegerRule.rb +36 -10
- data/lib/rules/NullRule.rb +36 -0
- data/lib/rules/StringRule.rb +60 -8
- data/lib/web/README.md +3 -3
- data/lib/web/bundle.js +5 -5
- data/lib/web/gitignore.txt +7 -0
- data/lib/web/index.html +3 -0
- data/lib/web/server.js +45 -49
- metadata +22 -8
- data/lib/Ruler.rb +0 -192
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f9ff9a7d13d77e0e468cf961d6ef1dd6dd2c381b6d3d4fb1a1799b59aa1fdc6
|
4
|
+
data.tar.gz: 8bb82ca18b00bd0a1e329bd94557a164eff90fb607fbbcbfa6ef8b026f4619c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d22878d22a93be41323d89b6a718808f78fa61c8cc186ddde480a5298ea1a1ae1fc49576141186d3dee7c02a29295c67a59e41aa732ec1e9dc3b4fd878e7add
|
7
|
+
data.tar.gz: 2d759df0674e8dc496ae92b585588b2a927c8aa7bda0368be8265705e1340af60ebe393c84b059dd2516d23cb8f7577b7baa4fe016f1a17ed3934a9fbcc084a2
|
data/lib/Accessor.rb
CHANGED
@@ -1,37 +1,36 @@
|
|
1
1
|
################################################################################
|
2
|
-
# ACCESSOR
|
3
|
-
#
|
4
2
|
# Access variables via one object to avoid polluting the caller class scope.
|
5
3
|
#
|
6
|
-
#
|
4
|
+
# @pattern Singleton
|
5
|
+
#
|
6
|
+
# @note Some variables are not accessed via Accessor:
|
7
7
|
# - @reflekt_counts on the instance
|
8
|
-
# - @reflekt_enabled on the instance
|
9
8
|
# - @@reflekt_skipped_methods on the instance's singleton class
|
10
9
|
################################################################################
|
11
10
|
|
12
11
|
class Accessor
|
13
12
|
|
13
|
+
attr_accessor :config
|
14
14
|
attr_accessor :setup
|
15
15
|
attr_accessor :db
|
16
16
|
attr_accessor :stack
|
17
|
-
attr_accessor :
|
17
|
+
attr_accessor :aggregator
|
18
18
|
attr_accessor :renderer
|
19
19
|
attr_accessor :path
|
20
20
|
attr_accessor :output_path
|
21
|
-
attr_accessor :
|
22
|
-
attr_accessor :reflect_limit
|
21
|
+
attr_accessor :error
|
23
22
|
|
24
23
|
def initialize()
|
25
24
|
|
25
|
+
@config = nil
|
26
26
|
@setup = nil
|
27
27
|
@db = nil
|
28
28
|
@stack = nil
|
29
|
-
@
|
29
|
+
@aggregator = nil
|
30
30
|
@renderer = nil
|
31
31
|
@path = nil
|
32
32
|
@output_path = nil
|
33
|
-
@
|
34
|
-
@reflect_limit = nil
|
33
|
+
@error = false
|
35
34
|
|
36
35
|
end
|
37
36
|
|
data/lib/Aggregator.rb
ADDED
@@ -0,0 +1,251 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Aggregate control metadata into rule sets.
|
3
|
+
# Validate reflections against aggregated controls.
|
4
|
+
#
|
5
|
+
# @pattern Singleton
|
6
|
+
#
|
7
|
+
# @hierachy
|
8
|
+
# 1. Aggregator <- YOU ARE HERE
|
9
|
+
# 2. RuleSet
|
10
|
+
# 3. Rule
|
11
|
+
################################################################################
|
12
|
+
|
13
|
+
require 'RuleSet'
|
14
|
+
|
15
|
+
class Aggregator
|
16
|
+
|
17
|
+
##
|
18
|
+
# @param meta_map [Hash] The rules that apply to each meta type.
|
19
|
+
##
|
20
|
+
def initialize(meta_map)
|
21
|
+
|
22
|
+
@meta_map = meta_map
|
23
|
+
# Key rule sets by class and method.
|
24
|
+
@rule_sets = {}
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
# Create aggregated rule sets from control metadata.
|
30
|
+
#
|
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.
|
34
|
+
##
|
35
|
+
def train(controls)
|
36
|
+
|
37
|
+
# On first use there are no previous controls.
|
38
|
+
return if controls.nil?
|
39
|
+
|
40
|
+
controls.each do |control|
|
41
|
+
|
42
|
+
klass = control["class"].to_sym
|
43
|
+
method = control["method"].to_sym
|
44
|
+
|
45
|
+
##
|
46
|
+
# INPUT
|
47
|
+
##
|
48
|
+
|
49
|
+
unless control["inputs"].nil?
|
50
|
+
control["inputs"].each_with_index do |meta, arg_num|
|
51
|
+
|
52
|
+
meta = Meta.deserialize(meta)
|
53
|
+
|
54
|
+
# Get rule set.
|
55
|
+
rule_set = get_input_rule_set(klass, method, arg_num)
|
56
|
+
if rule_set.nil?
|
57
|
+
rule_set = RuleSet.new(@meta_map)
|
58
|
+
set_input_rule_set(klass, method, arg_num, rule_set)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Train on metadata.
|
62
|
+
rule_set.train(meta)
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# OUTPUT
|
69
|
+
##
|
70
|
+
|
71
|
+
# Get rule set.
|
72
|
+
output_rule_set = get_output_rule_set(klass, method)
|
73
|
+
if output_rule_set.nil?
|
74
|
+
output_rule_set = RuleSet.new(@meta_map)
|
75
|
+
set_output_rule_set(klass, method, output_rule_set)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Train on metadata.
|
79
|
+
output_rule_set.train(Meta.deserialize(control["output"]))
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# Validate inputs.
|
87
|
+
#
|
88
|
+
# @stage Called when validating a reflection.
|
89
|
+
# @param inputs [Array] The method's arguments.
|
90
|
+
# @param input_rule_sets [Array] The RuleSets to validate each input with.
|
91
|
+
##
|
92
|
+
def test_inputs(inputs, input_rule_sets)
|
93
|
+
|
94
|
+
# Default result to PASS.
|
95
|
+
result = true
|
96
|
+
|
97
|
+
# Validate each argument against each rule set for that argument.
|
98
|
+
inputs.each_with_index do |input, arg_num|
|
99
|
+
|
100
|
+
unless input_rule_sets[arg_num].nil?
|
101
|
+
|
102
|
+
rule_set = input_rule_sets[arg_num]
|
103
|
+
|
104
|
+
unless rule_set.test(input)
|
105
|
+
result = false
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
return result
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# Validate output.
|
117
|
+
#
|
118
|
+
# @stage Called when validating a reflection.
|
119
|
+
# @param output [Dynamic] The method's return value.
|
120
|
+
# @param output_rule_set [RuleSet] The RuleSet to validate the output with.
|
121
|
+
##
|
122
|
+
def test_output(output, output_rule_set)
|
123
|
+
|
124
|
+
# Default to a PASS result.
|
125
|
+
result = true
|
126
|
+
|
127
|
+
unless output_rule_set.nil?
|
128
|
+
|
129
|
+
# Validate output RuleSet for that argument.
|
130
|
+
unless output_rule_set.test(output)
|
131
|
+
result = false
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
return result
|
137
|
+
|
138
|
+
end
|
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
|
+
|
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,31 +1,79 @@
|
|
1
|
+
################################################################################
|
2
|
+
# A shapshot of real data.
|
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
|
+
#
|
10
|
+
# @hierachy
|
11
|
+
# 1. Execution
|
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.
|
19
|
+
################################################################################
|
20
|
+
|
1
21
|
require 'Reflection'
|
22
|
+
require 'MetaBuilder'
|
2
23
|
|
3
24
|
class Control < Reflection
|
4
25
|
|
5
26
|
##
|
6
27
|
# Reflect on a method.
|
7
28
|
#
|
8
|
-
# Creates a shadow execution
|
9
|
-
#
|
10
|
-
# @param method - The name of the method.
|
11
|
-
# @param *args - The method arguments.
|
12
|
-
#
|
13
|
-
# @return - A reflection hash.
|
29
|
+
# Creates a shadow execution.
|
30
|
+
# @param *args [Dynamic] The method's arguments.
|
14
31
|
##
|
15
32
|
def reflect(*args)
|
16
33
|
|
17
|
-
|
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
|
50
|
+
|
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)
|
18
54
|
|
19
|
-
|
55
|
+
end
|
56
|
+
|
57
|
+
# Action method with new/old arguments.
|
20
58
|
begin
|
21
|
-
|
22
|
-
|
59
|
+
|
60
|
+
# Run reflection.
|
61
|
+
output = @clone.send(@method, *args)
|
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.
|
23
72
|
rescue StandardError => message
|
24
|
-
|
73
|
+
|
74
|
+
@status = :error
|
25
75
|
@message = message
|
26
|
-
|
27
|
-
else
|
28
|
-
@status = :pass
|
76
|
+
|
29
77
|
end
|
30
78
|
|
31
79
|
end
|