reflekt 0.9.7 → 0.9.8
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 +4 -5
- data/lib/{Ruler.rb → Aggregator.rb} +70 -69
- data/lib/Control.rb +16 -6
- data/lib/Meta.rb +27 -0
- data/lib/MetaBuilder.rb +56 -0
- data/lib/Reflection.rb +71 -86
- data/lib/Reflekt.rb +26 -36
- data/lib/Renderer.rb +5 -0
- data/lib/Rule.rb +23 -19
- data/lib/RuleSet.rb +54 -28
- data/lib/ShadowStack.rb +8 -11
- data/lib/meta/IntegerMeta.rb +27 -0
- data/lib/meta/StringMeta.rb +27 -0
- data/lib/rules/IntegerRule.rb +30 -10
- data/lib/rules/StringRule.rb +36 -8
- data/lib/web/bundle.js +5 -5
- data/lib/web/gitignore.txt +7 -0
- data/lib/web/index.html +3 -0
- metadata +9 -5
- data/lib/rules/FloatRule.rb +0 -28
data/lib/Reflekt.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
################################################################################
|
2
|
-
#
|
2
|
+
# Reflective testing.
|
3
3
|
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# Each Reflection executes on a ShadowStack on cloned data.
|
7
|
-
# Then flow is returned to the original method and normal execution continues.
|
4
|
+
# @author
|
5
|
+
# Maedi Prichard
|
8
6
|
#
|
9
|
-
#
|
7
|
+
# @flow
|
8
|
+
# 1. An Execution is created on method call.
|
9
|
+
# 2. Many Refections are created per Execution.
|
10
|
+
# 3. Each Reflection executes on cloned data.
|
11
|
+
# 4. Flow is returned to the original method.
|
12
|
+
#
|
13
|
+
# @usage
|
10
14
|
# class ExampleClass
|
11
15
|
# prepend Reflekt
|
12
16
|
################################################################################
|
@@ -15,11 +19,11 @@ require 'set'
|
|
15
19
|
require 'erb'
|
16
20
|
require 'rowdb'
|
17
21
|
require 'Accessor'
|
22
|
+
require 'Aggregator'
|
18
23
|
require 'Control'
|
19
24
|
require 'Execution'
|
20
25
|
require 'Reflection'
|
21
26
|
require 'Renderer'
|
22
|
-
require 'Ruler'
|
23
27
|
require 'ShadowStack'
|
24
28
|
|
25
29
|
module Reflekt
|
@@ -63,7 +67,7 @@ module Reflekt
|
|
63
67
|
execution.is_reflecting = true
|
64
68
|
|
65
69
|
# Create control.
|
66
|
-
control = Control.new(execution, 1, @@reflekt.
|
70
|
+
control = Control.new(execution, 1, @@reflekt.aggregator)
|
67
71
|
execution.control = control
|
68
72
|
|
69
73
|
# Execute control.
|
@@ -76,7 +80,7 @@ module Reflekt
|
|
76
80
|
execution.reflections.each_with_index do |value, index|
|
77
81
|
|
78
82
|
# Create reflection.
|
79
|
-
reflection = Reflection.new(execution, index + 1, @@reflekt.
|
83
|
+
reflection = Reflection.new(execution, index + 1, @@reflekt.aggregator)
|
80
84
|
execution.reflections[index] = reflection
|
81
85
|
|
82
86
|
# Execute reflection.
|
@@ -130,16 +134,16 @@ module Reflekt
|
|
130
134
|
# Receive configuration.
|
131
135
|
$ENV ||= {}
|
132
136
|
$ENV[:reflekt] ||= $ENV[:reflekt] = {}
|
137
|
+
$ENV[:reflekt][:output_directory] = "reflections"
|
133
138
|
|
134
139
|
# Set configuration.
|
135
140
|
@@reflekt.path = File.dirname(File.realpath(__FILE__))
|
136
141
|
|
137
|
-
# Get reflections directory path from config.
|
142
|
+
# Get reflections directory path from config or current execution path.
|
138
143
|
if $ENV[:reflekt][:output_path]
|
139
|
-
@@reflekt.output_path = File.join($ENV[:reflekt][:output_path],
|
140
|
-
# Get reflections directory path from current execution path.
|
144
|
+
@@reflekt.output_path = File.join($ENV[:reflekt][:output_path], $ENV[:reflekt][:output_directory])
|
141
145
|
else
|
142
|
-
@@reflekt.output_path = File.join(Dir.pwd,
|
146
|
+
@@reflekt.output_path = File.join(Dir.pwd, $ENV[:reflekt][:output_directory])
|
143
147
|
end
|
144
148
|
|
145
149
|
# Create reflections directory.
|
@@ -150,30 +154,15 @@ module Reflekt
|
|
150
154
|
# Create database.
|
151
155
|
@@reflekt.db = Rowdb.new(@@reflekt.output_path + '/db.js')
|
152
156
|
@@reflekt.db.defaults({ :reflekt => { :api_version => 1 }})
|
157
|
+
# @TODO Fix Rowdb.get(path) not returning values at path after Rowdb.push()
|
158
|
+
db = @@reflekt.db.value()
|
153
159
|
|
154
|
-
# Create shadow
|
160
|
+
# Create shadow stack.
|
155
161
|
@@reflekt.stack = ShadowStack.new()
|
156
162
|
|
157
|
-
# Create
|
158
|
-
@@reflekt.
|
159
|
-
|
160
|
-
values = @@reflekt.db.value()
|
161
|
-
values.each do |klass, class_values|
|
162
|
-
|
163
|
-
class_values.each do |method_name, method_items|
|
164
|
-
next if method_items.nil?
|
165
|
-
next unless method_items.class == Hash
|
166
|
-
if method_items.key? "controls"
|
167
|
-
|
168
|
-
method = method_name.to_sym
|
169
|
-
|
170
|
-
@@reflekt.ruler.load(klass, method, method_items['controls'])
|
171
|
-
@@reflekt.ruler.train(klass, method)
|
172
|
-
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
end
|
163
|
+
# Create aggregated rule sets.
|
164
|
+
@@reflekt.aggregator = Aggregator.new()
|
165
|
+
@@reflekt.aggregator.train(db[:controls])
|
177
166
|
|
178
167
|
# The amount of reflections to create per method call.
|
179
168
|
@@reflekt.reflect_amount = 2
|
@@ -186,16 +175,17 @@ module Reflekt
|
|
186
175
|
@@reflekt.renderer = Renderer.new(@@reflekt.path, @@reflekt.output_path)
|
187
176
|
|
188
177
|
return true
|
178
|
+
|
189
179
|
end
|
190
180
|
|
191
181
|
module SingletonClassMethods
|
192
182
|
|
193
|
-
@@reflekt_skipped_methods = Set.new
|
183
|
+
@@reflekt_skipped_methods = Set.new()
|
194
184
|
|
195
185
|
##
|
196
186
|
# Skip a method.
|
197
187
|
#
|
198
|
-
# @param method
|
188
|
+
# @param method [Symbol] The method name.
|
199
189
|
##
|
200
190
|
def reflekt_skip(method)
|
201
191
|
@@reflekt_skipped_methods.add(method)
|
data/lib/Renderer.rb
CHANGED
data/lib/Rule.rb
CHANGED
@@ -1,32 +1,36 @@
|
|
1
1
|
################################################################################
|
2
|
-
#
|
2
|
+
# All rules behave the same.
|
3
3
|
#
|
4
|
-
# Abstract class.
|
5
|
-
#
|
4
|
+
# @pattern Abstract class.
|
5
|
+
# @see lib/rules for rules.
|
6
6
|
################################################################################
|
7
7
|
|
8
|
-
require 'set'
|
9
|
-
|
10
8
|
class Rule
|
11
9
|
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
##
|
11
|
+
# Each rule trains on metadata to determine its boundaries.
|
12
|
+
#
|
13
|
+
# @param meta [Meta]
|
14
|
+
##
|
15
|
+
def train(meta)
|
15
16
|
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
##
|
19
|
+
# Each rule validates a value with its boundaries.
|
20
|
+
#
|
21
|
+
# @param value [Dynamic]
|
22
|
+
# @return [Boolean] Whether the value passes or fails.
|
23
|
+
##
|
24
|
+
def test(value)
|
20
25
|
end
|
21
26
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
##
|
28
|
+
# Each rule provides metadata.
|
29
|
+
#
|
30
|
+
# @return [Hash]
|
31
|
+
##
|
32
|
+
def result()
|
33
|
+
{}
|
30
34
|
end
|
31
35
|
|
32
36
|
end
|
data/lib/RuleSet.rb
CHANGED
@@ -1,34 +1,64 @@
|
|
1
1
|
################################################################################
|
2
|
-
#
|
3
|
-
#
|
4
|
-
# A collection of unique rules that validate an argument.
|
2
|
+
# A collection of rules that validate a value.
|
5
3
|
################################################################################
|
6
4
|
|
7
5
|
require 'set'
|
8
|
-
require 'rules/FloatRule'
|
9
|
-
require 'rules/IntegerRule'
|
10
|
-
require 'rules/StringRule'
|
11
6
|
|
12
7
|
class RuleSet
|
13
8
|
|
14
|
-
attr_accessor :types
|
15
9
|
attr_accessor :rules
|
16
10
|
|
17
11
|
def initialize()
|
18
12
|
|
19
|
-
@types = Set.new
|
20
13
|
@rules = {}
|
14
|
+
@types = Set.new()
|
21
15
|
|
22
16
|
end
|
23
17
|
|
24
|
-
def
|
18
|
+
def self.create_sets(args)
|
19
|
+
|
20
|
+
rule_sets = []
|
21
|
+
|
22
|
+
args.each do |arg|
|
23
|
+
rule_sets << self.create_set(arg)
|
24
|
+
end
|
25
|
+
|
26
|
+
rule_sets
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.create_set(value)
|
30
|
+
|
31
|
+
rule_set = RuleSet.new()
|
32
|
+
value_type = value.class.to_s
|
33
|
+
|
34
|
+
# Creates values for matching data type.
|
35
|
+
case value_type
|
36
|
+
when "Integer"
|
37
|
+
rule = IntegerRule.new()
|
38
|
+
rule.train(arg)
|
39
|
+
rule_set.rules[IntegerRule] = rule
|
40
|
+
when "String"
|
41
|
+
rule = StringRule.new()
|
42
|
+
rule.train(arg)
|
43
|
+
rule_set.rules[StringRule] = rule
|
44
|
+
end
|
45
|
+
|
46
|
+
rule_set
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Train rule set on metadata.
|
51
|
+
#
|
52
|
+
# @param meta [Meta] The metadata to train on.
|
53
|
+
##
|
54
|
+
def train(meta)
|
25
55
|
|
26
56
|
# Track data type.
|
27
|
-
@types <<
|
57
|
+
@types << meta.class
|
58
|
+
type = meta.class.to_s
|
28
59
|
|
29
60
|
# Get rule for this data type.
|
30
61
|
rule = nil
|
31
|
-
|
32
62
|
case type
|
33
63
|
when "Integer"
|
34
64
|
unless @rules.key? IntegerRule
|
@@ -46,34 +76,30 @@ class RuleSet
|
|
46
76
|
end
|
47
77
|
end
|
48
78
|
|
49
|
-
#
|
79
|
+
# Train rule.
|
50
80
|
unless rule.nil?
|
51
|
-
rule.
|
81
|
+
rule.train(meta)
|
52
82
|
end
|
53
83
|
|
54
84
|
return self
|
55
85
|
|
56
86
|
end
|
57
87
|
|
58
|
-
|
88
|
+
##
|
89
|
+
# Get the results of the rules.
|
90
|
+
#
|
91
|
+
# @return [Array] The rules.
|
92
|
+
##
|
93
|
+
def result()
|
59
94
|
|
60
|
-
|
61
|
-
rule.train()
|
62
|
-
end
|
95
|
+
rules = {}
|
63
96
|
|
64
|
-
|
65
|
-
|
66
|
-
def validate_rule(value)
|
67
|
-
result = true
|
68
|
-
|
69
|
-
@rules.each do |klass, rule|
|
70
|
-
|
71
|
-
unless rule.validate(value)
|
72
|
-
result = false
|
73
|
-
end
|
97
|
+
@rules.each do |key, rule|
|
98
|
+
rules[rule.class] = rule.result()
|
74
99
|
end
|
75
100
|
|
76
|
-
return
|
101
|
+
return rules
|
102
|
+
|
77
103
|
end
|
78
104
|
|
79
105
|
end
|
data/lib/ShadowStack.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
################################################################################
|
2
|
-
#
|
3
|
-
#
|
4
|
-
# Track the executions in a call stack.
|
2
|
+
# Track the executions in a shadow call stack.
|
5
3
|
################################################################################
|
6
4
|
|
7
5
|
class ShadowStack
|
@@ -20,24 +18,23 @@ class ShadowStack
|
|
20
18
|
end
|
21
19
|
|
22
20
|
##
|
23
|
-
#
|
21
|
+
# Place Execution at the top of stack.
|
24
22
|
#
|
25
|
-
# @param
|
26
|
-
# @
|
27
|
-
#
|
28
|
-
# @return Execution - The new execution.
|
23
|
+
# @param execution [Execution] The execution to place.
|
24
|
+
# @return [Execution] The placed execution.
|
29
25
|
##
|
30
26
|
def push(execution)
|
31
27
|
|
32
|
-
#
|
28
|
+
# Place first execution at bottom of stack.
|
33
29
|
if @bottom.nil?
|
34
30
|
@bottom = execution
|
31
|
+
# Connect subsequent executions to each other.
|
35
32
|
else
|
36
|
-
execution.child = @top
|
37
33
|
@top.parent = execution
|
34
|
+
execution.child = @top
|
38
35
|
end
|
39
36
|
|
40
|
-
# Place
|
37
|
+
# Place execution at top of stack.
|
41
38
|
@top = execution
|
42
39
|
|
43
40
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'Meta'
|
2
|
+
|
3
|
+
class IntegerMeta < Meta
|
4
|
+
|
5
|
+
def initialize()
|
6
|
+
|
7
|
+
@value = nil
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# @param value [Integer]
|
13
|
+
##
|
14
|
+
def load(value)
|
15
|
+
|
16
|
+
@value = value
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def result()
|
21
|
+
{
|
22
|
+
:type => :int,
|
23
|
+
:value => @value
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'Meta'
|
2
|
+
|
3
|
+
class StringMeta < Meta
|
4
|
+
|
5
|
+
def initialize()
|
6
|
+
|
7
|
+
@length = nil
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# @param value [Integer]
|
13
|
+
##
|
14
|
+
def load(value)
|
15
|
+
|
16
|
+
@length = value.length
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def result()
|
21
|
+
{
|
22
|
+
:type => :string,
|
23
|
+
:length => @length
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/rules/IntegerRule.rb
CHANGED
@@ -3,24 +3,37 @@ require 'Rule'
|
|
3
3
|
class IntegerRule < Rule
|
4
4
|
|
5
5
|
def initialize()
|
6
|
+
|
6
7
|
@min = nil
|
7
8
|
@max = nil
|
8
9
|
|
9
|
-
super
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
##
|
13
|
+
# @param meta [IntegerMeta]
|
14
|
+
##
|
15
|
+
def train(meta)
|
16
|
+
|
17
|
+
value = meta[:value]
|
18
|
+
|
19
|
+
if @min.nil?
|
20
|
+
@min = value
|
21
|
+
else
|
22
|
+
@min = value if value < @min
|
23
|
+
end
|
24
|
+
|
25
|
+
if @max.nil?
|
26
|
+
@max = value
|
27
|
+
else
|
28
|
+
@max = value if value > @max
|
29
|
+
end
|
15
30
|
|
16
|
-
def train()
|
17
|
-
numbers = @values.select {|num| num.class == Integer }
|
18
|
-
numbers.sort!
|
19
|
-
@min = numbers.first
|
20
|
-
@max = numbers.last
|
21
31
|
end
|
22
32
|
|
23
|
-
|
33
|
+
##
|
34
|
+
# @param value [Integer]
|
35
|
+
##
|
36
|
+
def test(value)
|
24
37
|
|
25
38
|
return false if value < @min
|
26
39
|
return false if value > @max
|
@@ -28,4 +41,11 @@ class IntegerRule < Rule
|
|
28
41
|
true
|
29
42
|
end
|
30
43
|
|
44
|
+
def result()
|
45
|
+
{
|
46
|
+
:type => :int,
|
47
|
+
:value => @min # Min/max are the same.
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
31
51
|
end
|