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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/lib/accessor.rb +45 -0
  3. data/lib/action.rb +127 -0
  4. data/lib/action_stack.rb +44 -0
  5. data/lib/{Clone.rb → clone.rb} +11 -11
  6. data/lib/config.rb +48 -0
  7. data/lib/control.rb +81 -0
  8. data/lib/experiment.rb +99 -0
  9. data/lib/meta.rb +75 -0
  10. data/lib/meta/array_meta.rb +32 -0
  11. data/lib/meta/boolean_meta.rb +26 -0
  12. data/lib/meta/float_meta.rb +26 -0
  13. data/lib/meta/integer_meta.rb +26 -0
  14. data/lib/meta/{NullMeta.rb → null_meta.rb} +21 -19
  15. data/lib/meta/object_meta.rb +35 -0
  16. data/lib/meta/string_meta.rb +26 -0
  17. data/lib/meta_builder.rb +100 -0
  18. data/lib/reflection.rb +123 -0
  19. data/lib/reflekt.rb +277 -0
  20. data/lib/renderer.rb +38 -0
  21. data/lib/rule.rb +54 -0
  22. data/lib/rule_set.rb +110 -0
  23. data/lib/rule_set_aggregator.rb +260 -0
  24. data/lib/rules/array_rule.rb +94 -0
  25. data/lib/rules/boolean_rule.rb +43 -0
  26. data/lib/rules/float_rule.rb +55 -0
  27. data/lib/rules/integer_rule.rb +55 -0
  28. data/lib/rules/null_rule.rb +35 -0
  29. data/lib/rules/object_rule.rb +42 -0
  30. data/lib/rules/string_rule.rb +75 -0
  31. data/lib/web/index.html +3 -4
  32. metadata +46 -29
  33. data/lib/Accessor.rb +0 -37
  34. data/lib/Action.rb +0 -88
  35. data/lib/ActionStack.rb +0 -44
  36. data/lib/Aggregator.rb +0 -260
  37. data/lib/Config.rb +0 -42
  38. data/lib/Control.rb +0 -83
  39. data/lib/Meta.rb +0 -71
  40. data/lib/MetaBuilder.rb +0 -84
  41. data/lib/Reflection.rb +0 -195
  42. data/lib/Reflekt.rb +0 -243
  43. data/lib/Renderer.rb +0 -39
  44. data/lib/Rule.rb +0 -52
  45. data/lib/RuleSet.rb +0 -109
  46. data/lib/meta/ArrayMeta.rb +0 -34
  47. data/lib/meta/BooleanMeta.rb +0 -26
  48. data/lib/meta/FloatMeta.rb +0 -26
  49. data/lib/meta/IntegerMeta.rb +0 -26
  50. data/lib/meta/StringMeta.rb +0 -26
  51. data/lib/rules/ArrayRule.rb +0 -88
  52. data/lib/rules/BooleanRule.rb +0 -47
  53. data/lib/rules/FloatRule.rb +0 -57
  54. data/lib/rules/IntegerRule.rb +0 -57
  55. data/lib/rules/NullRule.rb +0 -33
  56. 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