reflekt 1.0.5 → 1.0.10
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 +45 -0
- data/lib/action.rb +127 -0
- data/lib/action_stack.rb +44 -0
- data/lib/{Clone.rb → clone.rb} +11 -11
- data/lib/config.rb +48 -0
- data/lib/control.rb +81 -0
- data/lib/experiment.rb +99 -0
- data/lib/meta.rb +75 -0
- data/lib/meta/array_meta.rb +32 -0
- data/lib/meta/boolean_meta.rb +26 -0
- data/lib/meta/float_meta.rb +26 -0
- data/lib/meta/integer_meta.rb +26 -0
- data/lib/meta/{NullMeta.rb → null_meta.rb} +21 -19
- data/lib/meta/object_meta.rb +35 -0
- data/lib/meta/string_meta.rb +26 -0
- data/lib/meta_builder.rb +100 -0
- data/lib/reflection.rb +123 -0
- data/lib/reflekt.rb +277 -0
- data/lib/renderer.rb +38 -0
- data/lib/rule.rb +54 -0
- data/lib/rule_set.rb +110 -0
- data/lib/rule_set_aggregator.rb +260 -0
- data/lib/rules/array_rule.rb +94 -0
- data/lib/rules/boolean_rule.rb +43 -0
- data/lib/rules/float_rule.rb +55 -0
- data/lib/rules/integer_rule.rb +55 -0
- data/lib/rules/null_rule.rb +35 -0
- data/lib/rules/object_rule.rb +42 -0
- data/lib/rules/string_rule.rb +75 -0
- data/lib/web/index.html +3 -4
- metadata +46 -29
- data/lib/Accessor.rb +0 -37
- data/lib/Action.rb +0 -88
- data/lib/ActionStack.rb +0 -44
- data/lib/Aggregator.rb +0 -260
- data/lib/Config.rb +0 -42
- data/lib/Control.rb +0 -83
- data/lib/Meta.rb +0 -71
- data/lib/MetaBuilder.rb +0 -84
- data/lib/Reflection.rb +0 -195
- data/lib/Reflekt.rb +0 -243
- data/lib/Renderer.rb +0 -39
- data/lib/Rule.rb +0 -52
- data/lib/RuleSet.rb +0 -109
- data/lib/meta/ArrayMeta.rb +0 -34
- data/lib/meta/BooleanMeta.rb +0 -26
- data/lib/meta/FloatMeta.rb +0 -26
- data/lib/meta/IntegerMeta.rb +0 -26
- data/lib/meta/StringMeta.rb +0 -26
- data/lib/rules/ArrayRule.rb +0 -88
- data/lib/rules/BooleanRule.rb +0 -47
- data/lib/rules/FloatRule.rb +0 -57
- data/lib/rules/IntegerRule.rb +0 -57
- data/lib/rules/NullRule.rb +0 -33
- data/lib/rules/StringRule.rb +0 -81
data/lib/MetaBuilder.rb
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
################################################################################
|
2
|
-
# Create metadata.
|
3
|
-
#
|
4
|
-
# @pattern Builder
|
5
|
-
# @see lib/meta for each meta.
|
6
|
-
################################################################################
|
7
|
-
|
8
|
-
require 'Meta'
|
9
|
-
# Require all meta.
|
10
|
-
Dir[File.join(__dir__, 'meta', '*.rb')].each { |file| require file }
|
11
|
-
|
12
|
-
class MetaBuilder
|
13
|
-
|
14
|
-
##
|
15
|
-
# Create meta.
|
16
|
-
#
|
17
|
-
# @param value
|
18
|
-
##
|
19
|
-
def self.create(value)
|
20
|
-
|
21
|
-
meta = nil
|
22
|
-
data_type = value.class.to_s
|
23
|
-
|
24
|
-
# Create meta type for matching data type.
|
25
|
-
case data_type
|
26
|
-
when "Array"
|
27
|
-
meta = ArrayMeta.new()
|
28
|
-
when "TrueClass", "FalseClass"
|
29
|
-
meta = BooleanMeta.new()
|
30
|
-
when "Float"
|
31
|
-
meta = FloatMeta.new()
|
32
|
-
when "Integer"
|
33
|
-
meta = IntegerMeta.new()
|
34
|
-
when "String"
|
35
|
-
meta = StringMeta.new()
|
36
|
-
end
|
37
|
-
|
38
|
-
unless meta.nil?
|
39
|
-
meta.load(value)
|
40
|
-
end
|
41
|
-
|
42
|
-
return meta
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
##
|
47
|
-
# Create meta for multiple values.
|
48
|
-
#
|
49
|
-
# @param values
|
50
|
-
##
|
51
|
-
def self.create_many(values)
|
52
|
-
|
53
|
-
meta = []
|
54
|
-
|
55
|
-
values.each do |value|
|
56
|
-
meta << self.create(value)
|
57
|
-
end
|
58
|
-
|
59
|
-
return meta
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
##
|
64
|
-
# @param data_type [Type]
|
65
|
-
##
|
66
|
-
def self.data_type_to_meta_type(value)
|
67
|
-
|
68
|
-
data_type = value.class
|
69
|
-
|
70
|
-
meta_types = {
|
71
|
-
Array => :array,
|
72
|
-
TrueClass => :bool,
|
73
|
-
FalseClass => :bool,
|
74
|
-
Float => :float,
|
75
|
-
Integer => :int,
|
76
|
-
NilClass => :null,
|
77
|
-
String => :string
|
78
|
-
}
|
79
|
-
|
80
|
-
return meta_types[data_type]
|
81
|
-
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
data/lib/Reflection.rb
DELETED
@@ -1,195 +0,0 @@
|
|
1
|
-
################################################################################
|
2
|
-
# A snapshot of random data.
|
3
|
-
#
|
4
|
-
# @note
|
5
|
-
# A reflection's random value is within the bounds of aggregated control rule sets
|
6
|
-
# as well as as the arg type being inputted into the current control reflection.
|
7
|
-
#
|
8
|
-
# @nomenclature
|
9
|
-
# args, inputs/output and meta represent different stages of a value.
|
10
|
-
#
|
11
|
-
# @hierachy
|
12
|
-
# 1. Action
|
13
|
-
# 2. Reflection <- YOU ARE HERE
|
14
|
-
# 3. Meta
|
15
|
-
#
|
16
|
-
# @status
|
17
|
-
# - :pass [Symbol] The reflection passes the rules.
|
18
|
-
# - :fail [Symbol] The reflection fails the rules or produces a system error.
|
19
|
-
# - :error [Symbol] The control reflection produces a system error.
|
20
|
-
################################################################################
|
21
|
-
|
22
|
-
require 'Clone'
|
23
|
-
require 'MetaBuilder'
|
24
|
-
|
25
|
-
class Reflection
|
26
|
-
|
27
|
-
attr_reader :status
|
28
|
-
|
29
|
-
##
|
30
|
-
# Create a Reflection.
|
31
|
-
#
|
32
|
-
# @param action [Action] The Action that created this Reflection.
|
33
|
-
# @param number [Integer] Multiple Reflections can be created per Action.
|
34
|
-
# @param aggregator [Aggregator] The aggregated RuleSet for this class/method.
|
35
|
-
##
|
36
|
-
def initialize(action, number, aggregator)
|
37
|
-
|
38
|
-
@action = action
|
39
|
-
@unique_id = action.unique_id + number
|
40
|
-
@number = number
|
41
|
-
|
42
|
-
# Dependency.
|
43
|
-
@aggregator = aggregator
|
44
|
-
|
45
|
-
# Caller.
|
46
|
-
@klass = action.klass
|
47
|
-
@method = action.method
|
48
|
-
|
49
|
-
# Metadata.
|
50
|
-
@inputs = nil
|
51
|
-
@output = nil
|
52
|
-
|
53
|
-
# Clone the action's calling object.
|
54
|
-
# TODO: Abstract away into Clone class.
|
55
|
-
@clone = action.caller_object.clone
|
56
|
-
|
57
|
-
# Result.
|
58
|
-
@status = :pass
|
59
|
-
@time = Time.now.to_i
|
60
|
-
@message = nil
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
##
|
65
|
-
# Reflect on a method.
|
66
|
-
#
|
67
|
-
# Creates a shadow action.
|
68
|
-
# @param *args [Dynamic] The method's arguments.
|
69
|
-
##
|
70
|
-
def reflect(*args)
|
71
|
-
|
72
|
-
# Get aggregated rule sets.
|
73
|
-
input_rule_sets = @aggregator.get_input_rule_sets(@klass, @method)
|
74
|
-
output_rule_set = @aggregator.get_output_rule_set(@klass, @method)
|
75
|
-
|
76
|
-
# Fail when no trained rule sets.
|
77
|
-
if input_rule_sets.nil?
|
78
|
-
@status = :fail
|
79
|
-
end
|
80
|
-
|
81
|
-
# When arguments exist.
|
82
|
-
unless args.size == 0
|
83
|
-
|
84
|
-
# Create random arguments from aggregated rule sets.
|
85
|
-
unless input_rule_sets.nil?
|
86
|
-
args = randomize(args, input_rule_sets)
|
87
|
-
end
|
88
|
-
|
89
|
-
# Create metadata for each argument.
|
90
|
-
# TODO: Create metadata for other inputs such as instance variables.
|
91
|
-
@inputs = MetaBuilder.create_many(args)
|
92
|
-
|
93
|
-
end
|
94
|
-
|
95
|
-
# Action method with random arguments.
|
96
|
-
begin
|
97
|
-
|
98
|
-
# Run reflection.
|
99
|
-
output = @clone.send(@method, *args)
|
100
|
-
@output = MetaBuilder.create(output)
|
101
|
-
|
102
|
-
# Validate output against aggregated control rule sets.
|
103
|
-
unless output_rule_set.nil?
|
104
|
-
unless @aggregator.test_output(output, output_rule_set)
|
105
|
-
@status = :fail
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# When a system error occurs.
|
110
|
-
rescue StandardError => message
|
111
|
-
|
112
|
-
@status = :fail
|
113
|
-
@message = message
|
114
|
-
|
115
|
-
end
|
116
|
-
|
117
|
-
end
|
118
|
-
|
119
|
-
##
|
120
|
-
# Create random values for each argument from control reflections.
|
121
|
-
#
|
122
|
-
# @param args [Dynamic] The arguments to mirror random values for.
|
123
|
-
# @param input_rule_sets [Array] Aggregated rule sets for each argument.
|
124
|
-
#
|
125
|
-
# @return [Dynamic] Random arguments.
|
126
|
-
##
|
127
|
-
def randomize(args, input_rule_sets)
|
128
|
-
|
129
|
-
random_args = []
|
130
|
-
|
131
|
-
args.each_with_index do |arg, arg_num|
|
132
|
-
|
133
|
-
# Get a random rule in the rule set.
|
134
|
-
rules = input_rule_sets[arg_num].rules
|
135
|
-
agg_rule = rules[rules.keys.sample]
|
136
|
-
|
137
|
-
# Create a random value that follows that rule.
|
138
|
-
random_args << agg_rule.random()
|
139
|
-
|
140
|
-
end
|
141
|
-
|
142
|
-
return random_args
|
143
|
-
|
144
|
-
end
|
145
|
-
|
146
|
-
##
|
147
|
-
# Get the results of the reflection.
|
148
|
-
#
|
149
|
-
# @keys
|
150
|
-
# - eid [Integer] Execution ID
|
151
|
-
# - aid [Integer] Action ID
|
152
|
-
# - rid [Integer] Reflection ID
|
153
|
-
# - num [Integer] Reflection number
|
154
|
-
#
|
155
|
-
# @return [Hash] Reflection metadata.
|
156
|
-
##
|
157
|
-
def serialize()
|
158
|
-
|
159
|
-
# Create execution ID from the ID of the first action in the ActionStack.
|
160
|
-
execution_id = @action.unique_id
|
161
|
-
unless @action.base.nil?
|
162
|
-
execution_id = @action.base.unique_id
|
163
|
-
end
|
164
|
-
|
165
|
-
# Build reflection.
|
166
|
-
reflection = {
|
167
|
-
:eid => execution_id,
|
168
|
-
:aid => @action.unique_id,
|
169
|
-
:rid => @unique_id,
|
170
|
-
:num => @number,
|
171
|
-
:time => @time,
|
172
|
-
:class => @klass,
|
173
|
-
:method => @method,
|
174
|
-
:status => @status,
|
175
|
-
:message => @message,
|
176
|
-
:inputs => nil,
|
177
|
-
:output => nil,
|
178
|
-
}
|
179
|
-
|
180
|
-
unless @inputs.nil?
|
181
|
-
reflection[:inputs] = []
|
182
|
-
@inputs.each do |meta|
|
183
|
-
reflection[:inputs] << meta.serialize()
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
unless @output.nil?
|
188
|
-
reflection[:output] = @output.serialize()
|
189
|
-
end
|
190
|
-
|
191
|
-
return reflection
|
192
|
-
|
193
|
-
end
|
194
|
-
|
195
|
-
end
|
data/lib/Reflekt.rb
DELETED
@@ -1,243 +0,0 @@
|
|
1
|
-
################################################################################
|
2
|
-
# Reflective testing.
|
3
|
-
#
|
4
|
-
# @author Maedi Prichard
|
5
|
-
#
|
6
|
-
# @flow
|
7
|
-
# 1. Reflekt is prepended to a class and setup.
|
8
|
-
# 2. When a class insantiates so does Reflekt.
|
9
|
-
# 3. An Action is created on method call.
|
10
|
-
# 4. Many Refections are created per Action.
|
11
|
-
# 5. Each Reflection executes on cloned data.
|
12
|
-
# 6. Flow is returned to the original method.
|
13
|
-
#
|
14
|
-
# @usage
|
15
|
-
# class ExampleClass
|
16
|
-
# prepend Reflekt
|
17
|
-
################################################################################
|
18
|
-
|
19
|
-
require 'set'
|
20
|
-
require 'erb'
|
21
|
-
require 'rowdb'
|
22
|
-
require 'Accessor'
|
23
|
-
require 'Action'
|
24
|
-
require 'ActionStack'
|
25
|
-
require 'Aggregator'
|
26
|
-
require 'Config'
|
27
|
-
require 'Control'
|
28
|
-
require 'Reflection'
|
29
|
-
require 'Renderer'
|
30
|
-
# Require all rules.
|
31
|
-
Dir[File.join(__dir__, 'rules', '*.rb')].each { |file| require file }
|
32
|
-
|
33
|
-
module Reflekt
|
34
|
-
|
35
|
-
def initialize(*args)
|
36
|
-
|
37
|
-
# TODO: Store counts on @@reflekt and key by instance ID.
|
38
|
-
@reflekt_counts = {}
|
39
|
-
|
40
|
-
# Get child and parent instance methods.
|
41
|
-
parent_instance_methods = self.class.superclass.instance_methods(false)
|
42
|
-
child_instance_methods = self.class.instance_methods(false)
|
43
|
-
instance_methods = parent_instance_methods + child_instance_methods
|
44
|
-
|
45
|
-
# TODO: Include core methods like "Array.include?".
|
46
|
-
instance_methods.each do |method|
|
47
|
-
|
48
|
-
@reflekt_counts[method] = 0
|
49
|
-
|
50
|
-
# When method called in flow.
|
51
|
-
self.define_singleton_method(method) do |*args|
|
52
|
-
|
53
|
-
# When Reflekt enabled and control reflection has executed without error.
|
54
|
-
if @@reflekt.config.enabled && !@@reflekt.error
|
55
|
-
|
56
|
-
# Get current action.
|
57
|
-
action = @@reflekt.stack.peek()
|
58
|
-
|
59
|
-
# Don't reflect when reflect limit reached or method skipped.
|
60
|
-
unless (@reflekt_counts[method] >= @@reflekt.config.reflect_limit) || self.class.reflekt_skipped?(method)
|
61
|
-
|
62
|
-
# When stack empty or past action done reflecting.
|
63
|
-
if action.nil? || action.has_finished_reflecting?
|
64
|
-
|
65
|
-
# Create action.
|
66
|
-
action = Action.new(self, method, @@reflekt.config.reflect_amount, @@reflekt.stack)
|
67
|
-
|
68
|
-
@@reflekt.stack.push(action)
|
69
|
-
|
70
|
-
end
|
71
|
-
|
72
|
-
##
|
73
|
-
# Reflect the action.
|
74
|
-
#
|
75
|
-
# The first method call in the action creates a reflection.
|
76
|
-
# Then method calls are shadow actions which return to the reflection.
|
77
|
-
##
|
78
|
-
if action.has_empty_reflections? && !action.is_reflecting?
|
79
|
-
action.is_reflecting = true
|
80
|
-
|
81
|
-
# Create control.
|
82
|
-
control = Control.new(action, 0, @@reflekt.aggregator)
|
83
|
-
action.control = control
|
84
|
-
|
85
|
-
# Execute control.
|
86
|
-
control.reflect(*args)
|
87
|
-
|
88
|
-
# Stop reflecting when control fails to execute.
|
89
|
-
if control.status == :error
|
90
|
-
@@reflekt.error = true
|
91
|
-
# Continue reflecting when control executes succesfully.
|
92
|
-
else
|
93
|
-
|
94
|
-
# Save control as a reflection.
|
95
|
-
@@reflekt.db.get("reflections").push(control.serialize())
|
96
|
-
|
97
|
-
# Multiple reflections per action.
|
98
|
-
action.reflections.each_with_index do |value, index|
|
99
|
-
|
100
|
-
# Create reflection.
|
101
|
-
reflection = Reflection.new(action, index + 1, @@reflekt.aggregator)
|
102
|
-
action.reflections[index] = reflection
|
103
|
-
|
104
|
-
# Execute reflection.
|
105
|
-
reflection.reflect(*args)
|
106
|
-
@reflekt_counts[method] = @reflekt_counts[method] + 1
|
107
|
-
|
108
|
-
# Save reflection.
|
109
|
-
@@reflekt.db.get("reflections").push(reflection.serialize())
|
110
|
-
|
111
|
-
end
|
112
|
-
|
113
|
-
# Save control.
|
114
|
-
@@reflekt.db.get("controls").push(control.serialize())
|
115
|
-
|
116
|
-
# Save results.
|
117
|
-
@@reflekt.db.write()
|
118
|
-
|
119
|
-
# Render results.
|
120
|
-
@@reflekt.renderer.render()
|
121
|
-
|
122
|
-
end
|
123
|
-
|
124
|
-
action.is_reflecting = false
|
125
|
-
end
|
126
|
-
|
127
|
-
end
|
128
|
-
|
129
|
-
# Don't execute skipped methods when reflecting.
|
130
|
-
unless action.is_reflecting? && self.class.reflekt_skipped?(method)
|
131
|
-
|
132
|
-
# Continue action / shadow action.
|
133
|
-
super *args
|
134
|
-
|
135
|
-
end
|
136
|
-
|
137
|
-
# When Reflekt disabled or control reflection failed.
|
138
|
-
else
|
139
|
-
|
140
|
-
# Continue action.
|
141
|
-
super *args
|
142
|
-
|
143
|
-
end
|
144
|
-
|
145
|
-
end
|
146
|
-
|
147
|
-
end
|
148
|
-
|
149
|
-
# Continue initialization.
|
150
|
-
super
|
151
|
-
|
152
|
-
end
|
153
|
-
|
154
|
-
##
|
155
|
-
# Provide Config instance to block.
|
156
|
-
##
|
157
|
-
def self.configure
|
158
|
-
yield(@@reflekt.config)
|
159
|
-
end
|
160
|
-
|
161
|
-
private
|
162
|
-
|
163
|
-
def self.prepended(base)
|
164
|
-
|
165
|
-
# Prepend class methods to the instance's singleton class.
|
166
|
-
base.singleton_class.prepend(SingletonClassMethods)
|
167
|
-
|
168
|
-
# Setup class.
|
169
|
-
@@reflekt = Accessor.new()
|
170
|
-
@@reflekt.setup ||= reflekt_setup_class
|
171
|
-
|
172
|
-
end
|
173
|
-
|
174
|
-
# Setup class.
|
175
|
-
def self.reflekt_setup_class()
|
176
|
-
|
177
|
-
# Receive configuration.
|
178
|
-
@@reflekt.config = Config.new()
|
179
|
-
|
180
|
-
# Set configuration.
|
181
|
-
@@reflekt.path = File.dirname(File.realpath(__FILE__))
|
182
|
-
|
183
|
-
# Get reflections directory path from config or current action path.
|
184
|
-
if @@reflekt.config.output_path
|
185
|
-
@@reflekt.output_path = File.join(@@reflekt.config.output_path, @@reflekt.config.output_directory)
|
186
|
-
else
|
187
|
-
@@reflekt.output_path = File.join(Dir.pwd, @@reflekt.config.output_directory)
|
188
|
-
end
|
189
|
-
|
190
|
-
# Create reflections directory.
|
191
|
-
unless Dir.exist? @@reflekt.output_path
|
192
|
-
Dir.mkdir(@@reflekt.output_path)
|
193
|
-
end
|
194
|
-
|
195
|
-
# Create database.
|
196
|
-
@@reflekt.db = Rowdb.new(@@reflekt.output_path + '/db.js')
|
197
|
-
@@reflekt.db.defaults({ :reflekt => { :api_version => 1 }})
|
198
|
-
# @TODO Fix Rowdb.get(path) not returning values at path after Rowdb.push()
|
199
|
-
db = @@reflekt.db.value()
|
200
|
-
|
201
|
-
# Create shadow stack.
|
202
|
-
@@reflekt.stack = ActionStack.new()
|
203
|
-
|
204
|
-
# Create aggregated rule sets.
|
205
|
-
@@reflekt.aggregator = Aggregator.new(@@reflekt.config.meta_map)
|
206
|
-
@@reflekt.aggregator.train(db[:controls])
|
207
|
-
|
208
|
-
# Create renderer.
|
209
|
-
@@reflekt.renderer = Renderer.new(@@reflekt.path, @@reflekt.output_path)
|
210
|
-
|
211
|
-
return true
|
212
|
-
|
213
|
-
end
|
214
|
-
|
215
|
-
module SingletonClassMethods
|
216
|
-
|
217
|
-
@@reflekt_skipped_methods = Set.new()
|
218
|
-
|
219
|
-
##
|
220
|
-
# Skip a method.
|
221
|
-
#
|
222
|
-
# @note
|
223
|
-
# Class variables cascade to child classes.
|
224
|
-
# So a reflekt_skip on the parent class will persist to the child class.
|
225
|
-
#
|
226
|
-
# @param method [Symbol] The method name.
|
227
|
-
##
|
228
|
-
def reflekt_skip(method)
|
229
|
-
@@reflekt_skipped_methods.add(method)
|
230
|
-
end
|
231
|
-
|
232
|
-
def reflekt_skipped?(method)
|
233
|
-
return true if @@reflekt_skipped_methods.include?(method)
|
234
|
-
false
|
235
|
-
end
|
236
|
-
|
237
|
-
#def reflekt_limit(amount)
|
238
|
-
# @@reflekt.reflect_limit = amount
|
239
|
-
#end
|
240
|
-
|
241
|
-
end
|
242
|
-
|
243
|
-
end
|