reflekt 0.7.2 → 0.9.5
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 +37 -0
- data/lib/Control.rb +33 -0
- data/lib/Execution.rb +47 -0
- data/lib/Reflection.rb +163 -0
- data/lib/Reflekt.rb +223 -0
- data/lib/Renderer.rb +38 -0
- data/lib/Rule.rb +32 -0
- data/lib/RulePool.rb +44 -0
- data/lib/Ruler.rb +124 -0
- data/lib/ShadowStack.rb +56 -0
- data/lib/rules/FloatRule.rb +24 -0
- data/lib/rules/IntegerRule.rb +27 -0
- data/lib/rules/StringRule.rb +24 -0
- data/lib/web/style.css +13 -1
- data/lib/web/template.html.erb +71 -15
- metadata +16 -4
- data/lib/reflekt.rb +0 -277
data/lib/Renderer.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
class Renderer
|
2
|
+
|
3
|
+
def initialize(path, output_path)
|
4
|
+
@path = path
|
5
|
+
@output_path = output_path
|
6
|
+
end
|
7
|
+
|
8
|
+
##
|
9
|
+
# Render results.
|
10
|
+
##
|
11
|
+
def render()
|
12
|
+
|
13
|
+
# Get JSON.
|
14
|
+
json = File.read("#{@output_path}/db.json")
|
15
|
+
|
16
|
+
# Save HTML.
|
17
|
+
template = File.read("#{@path}/web/template.html.erb")
|
18
|
+
rendered = ERB.new(template).result(binding)
|
19
|
+
File.open("#{@output_path}/index.html", 'w+') do |f|
|
20
|
+
f.write rendered
|
21
|
+
end
|
22
|
+
|
23
|
+
# Add JS.
|
24
|
+
javascript = File.read("#{@path}/web/script.js")
|
25
|
+
File.open("#{@output_path}/script.js", 'w+') do |f|
|
26
|
+
f.write javascript
|
27
|
+
end
|
28
|
+
|
29
|
+
# Add CSS.
|
30
|
+
stylesheet = File.read("#{@path}/web/style.css")
|
31
|
+
File.open("#{@output_path}/style.css", 'w+') do |f|
|
32
|
+
f.write stylesheet
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
end
|
data/lib/Rule.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
################################################################################
|
2
|
+
# RULES
|
3
|
+
#
|
4
|
+
# Abstract class.
|
5
|
+
# See lib/rules for rules.
|
6
|
+
################################################################################
|
7
|
+
|
8
|
+
require 'set'
|
9
|
+
|
10
|
+
class Rule
|
11
|
+
|
12
|
+
# Each rule intitalises itself.
|
13
|
+
def initialize()
|
14
|
+
@values = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
# Each rule loads up an array of values.
|
18
|
+
def load(value)
|
19
|
+
@values << value
|
20
|
+
end
|
21
|
+
|
22
|
+
# Each rule trains on values to determine its patterns.
|
23
|
+
def train()
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
# Each rule compares the data it has with the data it's given.
|
28
|
+
def validate()
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/lib/RulePool.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
################################################################################
|
2
|
+
# RULE POOL
|
3
|
+
#
|
4
|
+
# A collection of rules generated for an argument.
|
5
|
+
# Duplicates will not be added to the sets.
|
6
|
+
################################################################################
|
7
|
+
|
8
|
+
require 'set'
|
9
|
+
require 'Rule'
|
10
|
+
|
11
|
+
class RulePool
|
12
|
+
|
13
|
+
attr_accessor :types
|
14
|
+
attr_accessor :rules
|
15
|
+
|
16
|
+
def initialize()
|
17
|
+
|
18
|
+
@types = Set.new
|
19
|
+
@rules = {}
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
def train()
|
24
|
+
|
25
|
+
rules.each do |rule|
|
26
|
+
rule.train()
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def validate(value)
|
32
|
+
result = true
|
33
|
+
|
34
|
+
rules.each do |rule|
|
35
|
+
result = rule.validate(value)
|
36
|
+
if result == false
|
37
|
+
result = false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
return result
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/lib/Ruler.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
################################################################################
|
2
|
+
# RULER
|
3
|
+
#
|
4
|
+
# Aggregate a method's inputs and output into a series of generic rules.
|
5
|
+
################################################################################
|
6
|
+
|
7
|
+
require 'RulePool'
|
8
|
+
|
9
|
+
class Ruler
|
10
|
+
|
11
|
+
INPUT = "i"
|
12
|
+
OUTPUT = "o"
|
13
|
+
TYPE = "T"
|
14
|
+
VALUE = "V"
|
15
|
+
|
16
|
+
def initialize()
|
17
|
+
|
18
|
+
# Reflections.
|
19
|
+
@controls = nil
|
20
|
+
# Arguments.
|
21
|
+
@inputs = []
|
22
|
+
@output = nil
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def load(controls)
|
27
|
+
|
28
|
+
@controls = controls
|
29
|
+
@controls.each_with_index do |control, index|
|
30
|
+
|
31
|
+
# Create rules for each input.
|
32
|
+
control[INPUT].each_with_index do |input, index|
|
33
|
+
unless input.nil?
|
34
|
+
@inputs[index] = load_rule_pool(@inputs[index], input[TYPE], input[VALUE])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Create rules for the output.
|
39
|
+
output = control[OUTPUT]
|
40
|
+
unless control[OUTPUT].nil?
|
41
|
+
@output = load_rule_pool(@output, output[TYPE], output[VALUE])
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
def load_rule_pool(rule_pool, type, value)
|
49
|
+
|
50
|
+
if rule_pool.nil?
|
51
|
+
rule_pool = RulePool.new()
|
52
|
+
end
|
53
|
+
|
54
|
+
# Track data type.
|
55
|
+
rule_pool.types << type
|
56
|
+
|
57
|
+
# Get rule for this data type.
|
58
|
+
rule = nil
|
59
|
+
|
60
|
+
case type
|
61
|
+
when "Integer"
|
62
|
+
unless rule_pool.rules.key? IntegerRule
|
63
|
+
rule = IntegerRule.new()
|
64
|
+
rule_pool.rules << rule
|
65
|
+
else
|
66
|
+
rule = rule_pool.rules[IntegerRule]
|
67
|
+
end
|
68
|
+
when "String"
|
69
|
+
unless rule_pool.rules.key? StringRule
|
70
|
+
rule = StringRule.new()
|
71
|
+
rule_pool.rules << rule
|
72
|
+
else
|
73
|
+
rule = rule_pool.rules[IntegerRule]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Add value to rule.
|
78
|
+
unless rule.nil?
|
79
|
+
rule.load(value)
|
80
|
+
end
|
81
|
+
|
82
|
+
return rule_pool
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
def train()
|
87
|
+
|
88
|
+
@inputs.each do |rule_pool|
|
89
|
+
unless rule_pool.nil?
|
90
|
+
rule_pool.train()
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
unless @output.nil?
|
95
|
+
@output.train()
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
def validate_inputs(inputs)
|
101
|
+
result = true
|
102
|
+
|
103
|
+
inputs.each_with_index do |value, index|
|
104
|
+
rule_pool = @inputs[index]
|
105
|
+
unless rule_pool.validate(input)
|
106
|
+
result = false
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
return result
|
111
|
+
end
|
112
|
+
|
113
|
+
def validate_output(output)
|
114
|
+
result = true
|
115
|
+
|
116
|
+
rule_pool = @output
|
117
|
+
unless rule_pool.validate(output)
|
118
|
+
result = false
|
119
|
+
end
|
120
|
+
|
121
|
+
return result
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
data/lib/ShadowStack.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
################################################################################
|
2
|
+
# SHADOW STACK
|
3
|
+
#
|
4
|
+
# Track the executions in a call stack.
|
5
|
+
################################################################################
|
6
|
+
|
7
|
+
class ShadowStack
|
8
|
+
|
9
|
+
def initialize()
|
10
|
+
@bottom = nil
|
11
|
+
@top = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def peek()
|
15
|
+
@top
|
16
|
+
end
|
17
|
+
|
18
|
+
def base()
|
19
|
+
@bottom
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Push Execution.
|
24
|
+
#
|
25
|
+
# @param object - The object being executed.
|
26
|
+
# @param args - The arguments being executed.
|
27
|
+
#
|
28
|
+
# @return Execution - The new execution.
|
29
|
+
##
|
30
|
+
def push(execution)
|
31
|
+
|
32
|
+
# Reference previous execution.
|
33
|
+
if @bottom.nil?
|
34
|
+
@bottom = execution
|
35
|
+
else
|
36
|
+
execution.child = @top
|
37
|
+
@top.parent = execution
|
38
|
+
end
|
39
|
+
|
40
|
+
# Place new execution at the top of the stack.
|
41
|
+
@top = execution
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def display
|
46
|
+
display_execution_tree(@bottom)
|
47
|
+
end
|
48
|
+
|
49
|
+
def display_execution_tree(execution)
|
50
|
+
p execution
|
51
|
+
unless execution.parent == nil
|
52
|
+
display_execution_tree(execution.parent)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class FloatRule < Rule
|
2
|
+
|
3
|
+
attr_accessor :min
|
4
|
+
attr_accessor :max
|
5
|
+
|
6
|
+
def initialize()
|
7
|
+
@min = nil
|
8
|
+
@max = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def load(value)
|
12
|
+
@values << value
|
13
|
+
end
|
14
|
+
|
15
|
+
def train()
|
16
|
+
# TODO.
|
17
|
+
end
|
18
|
+
|
19
|
+
def validate()
|
20
|
+
# TODO.
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class IntegerRule < Rule
|
2
|
+
|
3
|
+
attr_accessor :min
|
4
|
+
attr_accessor :max
|
5
|
+
|
6
|
+
def initialize()
|
7
|
+
@min = nil
|
8
|
+
@max = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def load(value)
|
12
|
+
@values << value
|
13
|
+
end
|
14
|
+
|
15
|
+
def train()
|
16
|
+
numbers = @values.select {|num| num.class == Integer }
|
17
|
+
numbers.sort!
|
18
|
+
@min = numbers.first
|
19
|
+
@max = numbers.last
|
20
|
+
end
|
21
|
+
|
22
|
+
def validate()
|
23
|
+
return false if value < rule.min
|
24
|
+
return false if value > rule.max
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class StringRule < Rule
|
2
|
+
|
3
|
+
attr_accessor :min_length
|
4
|
+
attr_accessor :max_length
|
5
|
+
|
6
|
+
def initialize()
|
7
|
+
@min_length = nil
|
8
|
+
@max_length = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def load(value)
|
12
|
+
@values << value
|
13
|
+
end
|
14
|
+
|
15
|
+
def train()
|
16
|
+
# TODO.
|
17
|
+
end
|
18
|
+
|
19
|
+
def validate()
|
20
|
+
# TODO.
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/lib/web/style.css
CHANGED
@@ -22,6 +22,7 @@ body {
|
|
22
22
|
/* Structure */
|
23
23
|
ul.classes,
|
24
24
|
ul.methods,
|
25
|
+
ul.controls,
|
25
26
|
ul.reflections {
|
26
27
|
padding-left: 0;
|
27
28
|
}
|
@@ -49,8 +50,17 @@ li.method-container {
|
|
49
50
|
background: #D04700;
|
50
51
|
}
|
51
52
|
|
53
|
+
/* Buttons. */
|
54
|
+
.method .buttons {
|
55
|
+
margin-left: auto;
|
56
|
+
margin-right: 1rem;
|
57
|
+
}
|
58
|
+
.buttons button {
|
59
|
+
padding: 1rem 2rem;
|
60
|
+
}
|
61
|
+
|
52
62
|
/* Stats. */
|
53
|
-
.stats {
|
63
|
+
.class .stats {
|
54
64
|
margin-left: auto;
|
55
65
|
}
|
56
66
|
.stat {
|
@@ -85,6 +95,7 @@ li.method-container {
|
|
85
95
|
}
|
86
96
|
|
87
97
|
/* Reflection. */
|
98
|
+
.control,
|
88
99
|
.reflection {
|
89
100
|
list-style: none;
|
90
101
|
margin-left: 2rem;
|
@@ -95,6 +106,7 @@ li.method-container {
|
|
95
106
|
padding: 0.5rem 1.5rem;
|
96
107
|
margin-bottom: 0.3rem;
|
97
108
|
}
|
109
|
+
.control .time,
|
98
110
|
.reflection .time {
|
99
111
|
color: #777777;
|
100
112
|
margin-right: 2rem;
|
data/lib/web/template.html.erb
CHANGED
@@ -32,17 +32,18 @@
|
|
32
32
|
|
33
33
|
function getData() {
|
34
34
|
|
35
|
-
var
|
36
|
-
console.log("REFLECTIONS:");
|
37
|
-
console.log(reflections);
|
35
|
+
var data = JSON.parse(<%= json %>);
|
38
36
|
var results = {};
|
39
37
|
|
40
|
-
|
41
|
-
|
38
|
+
console.log("DATA:");
|
39
|
+
console.log(data);
|
40
|
+
|
41
|
+
if ('reflekt' in data) {
|
42
|
+
delete(data.reflekt);
|
42
43
|
}
|
43
44
|
|
44
45
|
// Classes.
|
45
|
-
for ([class_id, class_value] of Object.entries(
|
46
|
+
for ([class_id, class_value] of Object.entries(data)) {
|
46
47
|
|
47
48
|
// Class pass rate.
|
48
49
|
results[class_id] = {
|
@@ -57,17 +58,17 @@
|
|
57
58
|
// Methods.
|
58
59
|
for ([method_id, method] of Object.entries(class_value)) {
|
59
60
|
|
60
|
-
//
|
61
|
-
var pass_count = method.reduce(function(obj, v) {
|
61
|
+
// Reflection pass rate.
|
62
|
+
var pass_count = method.reflections.reduce(function(obj, v) {
|
62
63
|
obj[v[STATUS]] = (obj[v[STATUS]] || 0) + 1;
|
63
64
|
return obj;
|
64
65
|
}, {});
|
65
66
|
|
66
|
-
var pass_rate = (pass_count[PASS] / method.length) * 100;
|
67
|
+
var pass_rate = (pass_count[PASS] / method.reflections.length) * 100;
|
67
68
|
results[class_id]['methods'][method_id] = {
|
68
69
|
'stats': {
|
69
70
|
'pass_rate': pass_rate,
|
70
|
-
'test_count': method.length,
|
71
|
+
'test_count': method.reflections.length,
|
71
72
|
'pass_count': pass_count[PASS]
|
72
73
|
}
|
73
74
|
};
|
@@ -79,7 +80,7 @@
|
|
79
80
|
}
|
80
81
|
|
81
82
|
// Class pass rate.
|
82
|
-
results[class_id]['stats']['test_count'] += method.length;
|
83
|
+
results[class_id]['stats']['test_count'] += method.reflections.length;
|
83
84
|
results[class_id]['stats']['pass_count'] += pass_count[PASS];
|
84
85
|
|
85
86
|
}
|
@@ -97,7 +98,7 @@
|
|
97
98
|
}
|
98
99
|
|
99
100
|
return {
|
100
|
-
|
101
|
+
data: data,
|
101
102
|
results: results
|
102
103
|
};
|
103
104
|
}
|
@@ -134,15 +135,19 @@
|
|
134
135
|
<template x-for="[method_id, method] in Object.entries(klass['methods'])" :key="method_id">
|
135
136
|
<li class="method-container">
|
136
137
|
|
137
|
-
<div class="status-row method" x-bind:class="`${method.status}`"
|
138
|
+
<div class="status-row method" x-bind:class="`${method.status}`" :class="{ 'active': method['show_reflections'] }" :class="{ 'active': method['show_controls'] }">
|
138
139
|
<h3 x-text="`${method_id}()`"></h3>
|
140
|
+
<div class="buttons">
|
141
|
+
<button @click="method['show_controls'] = !method['show_controls']">Controls</button>
|
142
|
+
<button @click="method['show_reflections'] = !method['show_reflections']">Reflections</button>
|
143
|
+
</div>
|
139
144
|
<div class="stats">
|
140
145
|
<div class="stat" x-text="`${method.stats.pass_rate.toFixed(2)}%`"></div>
|
141
146
|
</div>
|
142
147
|
</div>
|
143
148
|
|
144
|
-
<ul class="reflections" x-show="method['
|
145
|
-
<template x-for="[reflection_id, reflection] in Object.entries(
|
149
|
+
<ul class="reflections" x-show="method['show_reflections']">
|
150
|
+
<template x-for="[reflection_id, reflection] in Object.entries(data[class_id][method_id].reflections)">
|
146
151
|
|
147
152
|
<li class="reflection">
|
148
153
|
|
@@ -192,6 +197,57 @@
|
|
192
197
|
</template>
|
193
198
|
</ul>
|
194
199
|
|
200
|
+
<ul class="controls" x-show="method['show_controls']">
|
201
|
+
<template x-for="[control_id, control] in Object.entries(data[class_id][method_id].controls)">
|
202
|
+
|
203
|
+
<li class="control">
|
204
|
+
|
205
|
+
<div class="time" x-text="`${new Date(control.t * 1000).getFullYear()}/${new Date(control.t * 1000).getMonth() + 1}/${new Date(control.t * 1000).getDate()} ${new Date(control.t * 1000).getHours()}:${new Date(control.t * 1000).getMinutes()}:${new Date(control.t * 1000).getSeconds()}`"></div>
|
206
|
+
|
207
|
+
<template x-for="[input_id, input] in Object.entries(control.i)">
|
208
|
+
|
209
|
+
<div class="info">
|
210
|
+
<h4>Input</h4>
|
211
|
+
<div class="info-items">
|
212
|
+
<div class="info-item">
|
213
|
+
<strong>Type:</strong><div class="input" x-text="input.T"></div>
|
214
|
+
</div>
|
215
|
+
<template x-if="input.V != undefined">
|
216
|
+
<div class="info-item">
|
217
|
+
<strong>Value:</strong><pre><div class="output" x-text="input.V"></div></pre>
|
218
|
+
</div>
|
219
|
+
</template>
|
220
|
+
<template x-if="input.C != undefined">
|
221
|
+
<div class="info-item">
|
222
|
+
<strong>Count:</strong><div class="input" x-text="input.C"></div>
|
223
|
+
</div>
|
224
|
+
</template>
|
225
|
+
</div>
|
226
|
+
</div>
|
227
|
+
|
228
|
+
</template>
|
229
|
+
|
230
|
+
<div class="info">
|
231
|
+
<h4>Output</h4>
|
232
|
+
<div class="info-items">
|
233
|
+
<div class="info-item">
|
234
|
+
<strong>Type:</strong><div class="output" x-text="control.o.T"></div>
|
235
|
+
</div>
|
236
|
+
<template x-if="control.o.C != undefined">
|
237
|
+
<div class="info-item">
|
238
|
+
<strong>Count:</strong><div class="output" x-text="control.o.C"></div>
|
239
|
+
</div>
|
240
|
+
</template>
|
241
|
+
<div class="info-item">
|
242
|
+
<strong>Value:</strong><pre><div class="output" x-text="control.o.V"></div></pre>
|
243
|
+
</div>
|
244
|
+
</div>
|
245
|
+
</div>
|
246
|
+
</li>
|
247
|
+
|
248
|
+
</template>
|
249
|
+
</ul>
|
250
|
+
|
195
251
|
</li>
|
196
252
|
</template>
|
197
253
|
</ul>
|