reflekt 0.9.9 → 1.0.4

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.
@@ -1,3 +1,12 @@
1
+ ################################################################################
2
+ # A shadow execution.
3
+ #
4
+ # @hierachy
5
+ # 1. Execution <- YOU ARE HERE
6
+ # 2. Reflection
7
+ # 3. Meta
8
+ ################################################################################
9
+
1
10
  class Execution
2
11
 
3
12
  attr_accessor :unique_id
@@ -19,10 +28,10 @@ class Execution
19
28
  #
20
29
  # @param object [Object] The calling object.
21
30
  # @param method [Symbol] The calling method.
22
- # @param number [Integer] The number of reflections to create per execution.
31
+ # @param reflect_amount [Integer] The number of reflections to create per execution.
23
32
  # @param stack [ShadowStack] The shadow execution call stack.
24
33
  ##
25
- def initialize(caller_object, method, number, stack)
34
+ def initialize(caller_object, method, reflect_amount, stack)
26
35
 
27
36
  @time = Time.now.to_i
28
37
  @unique_id = @time + rand(1..99999)
@@ -42,7 +51,7 @@ class Execution
42
51
 
43
52
  # Reflections.
44
53
  @control = nil
45
- @reflections = Array.new(number)
54
+ @reflections = Array.new(reflect_amount)
46
55
 
47
56
  # State.
48
57
  if @stack.peek() == nil
@@ -3,10 +3,22 @@
3
3
  #
4
4
  # @pattern Abstract class
5
5
  # @see lib/meta for each meta.
6
+ #
7
+ # @hierachy
8
+ # 1. Execution
9
+ # 2. Reflection
10
+ # 3. Meta <- YOU ARE HERE
6
11
  ################################################################################
7
12
 
8
13
  class Meta
9
14
 
15
+ ##
16
+ # Each meta defines its type.
17
+ ##
18
+ def initialize()
19
+ @type = nil
20
+ end
21
+
10
22
  ##
11
23
  # Each meta loads values.
12
24
  #
@@ -16,12 +28,44 @@ class Meta
16
28
  end
17
29
 
18
30
  ##
19
- # Each meta provides metadata.
31
+ # Each meta serializes metadata.
20
32
  #
21
33
  # @return [Hash]
22
34
  ##
23
- def result()
35
+ def serialize()
24
36
  {}
25
37
  end
26
38
 
39
+ ##############################################################################
40
+ # CLASS
41
+ ##############################################################################
42
+
43
+ ##
44
+ # Deserialize metadata.
45
+ #
46
+ # @todo Deserialize should create a Meta object.
47
+ # @todo Require each Meta type to handle its own deserialization.
48
+ #
49
+ # @param meta [Hash] The metadata to deserialize.
50
+ # @param meta [Hash]
51
+ ##
52
+ def self.deserialize(meta)
53
+
54
+ # Convert nil meta into NullMeta.
55
+ # Meta is nil when there are no @inputs or @output on the method.
56
+ if meta.nil?
57
+ return NullMeta.new().serialize()
58
+ end
59
+
60
+ # Symbolize keys.
61
+ # TODO: Remove once "Fix Rowdb.get(path)" bug fixed.
62
+ meta = meta.transform_keys(&:to_sym)
63
+
64
+ # Symbolize type value.
65
+ meta[:type] = meta[:type].to_sym
66
+
67
+ return meta
68
+
69
+ end
70
+
27
71
  end
@@ -6,8 +6,8 @@
6
6
  ################################################################################
7
7
 
8
8
  require 'Meta'
9
- require_relative './meta/IntegerMeta'
10
- require_relative './meta/StringMeta'
9
+ # Require all meta.
10
+ Dir[File.join(__dir__, 'meta', '*.rb')].each { |file| require file }
11
11
 
12
12
  class MetaBuilder
13
13
 
@@ -19,9 +19,16 @@ class MetaBuilder
19
19
  def self.create(value)
20
20
 
21
21
  meta = nil
22
+ data_type = value.class.to_s
22
23
 
23
- # Creates values for matching data type.
24
- case value.class.to_s
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()
25
32
  when "Integer"
26
33
  meta = IntegerMeta.new()
27
34
  when "String"
@@ -53,4 +60,25 @@ class MetaBuilder
53
60
 
54
61
  end
55
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
+
56
84
  end
@@ -1,20 +1,30 @@
1
1
  ################################################################################
2
- # A snapshot of simulated data.
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.
3
7
  #
4
8
  # @nomenclature
5
- # args/inputs/values are the same thing but at a different stage of lifecycle.
9
+ # args, inputs/output and meta represent different stages of a value.
6
10
  #
7
11
  # @hierachy
8
12
  # 1. Execution
9
- # 2. Reflection
10
- # 3. RuleSet
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.
11
20
  ################################################################################
12
21
 
22
+ require 'Clone'
13
23
  require 'MetaBuilder'
14
24
 
15
25
  class Reflection
16
26
 
17
- attr_accessor :clone
27
+ attr_reader :status
18
28
 
19
29
  ##
20
30
  # Create a Reflection.
@@ -37,83 +47,91 @@ class Reflection
37
47
  @method = execution.method
38
48
 
39
49
  # Metadata.
40
- @inputs = []
50
+ @inputs = nil
41
51
  @output = nil
42
52
 
43
53
  # Clone the execution's calling object.
54
+ # TODO: Abstract away into Clone class.
44
55
  @clone = execution.caller_object.clone
45
- @clone_id = nil
46
56
 
47
57
  # Result.
48
58
  @status = :pass
49
59
  @time = Time.now.to_i
60
+ @message = nil
50
61
 
51
62
  end
52
63
 
53
64
  ##
54
65
  # Reflect on a method.
55
66
  #
56
- # Creates a shadow execution stack.
67
+ # Creates a shadow execution.
57
68
  # @param *args [Dynamic] The method's arguments.
58
69
  ##
59
70
  def reflect(*args)
60
71
 
61
- # Get aggregated RuleSets.
62
- agg_input_rule_sets = @aggregator.get_input_rule_sets(@klass, @method)
63
- agg_output_rule_set = @aggregator.get_output_rule_set(@klass, @method)
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)
64
75
 
65
- # Create random arguments.
66
- new_args = randomize(args)
76
+ # When arguments exist.
77
+ unless args.size == 0
67
78
 
68
- # Create metadata for each argument.
69
- @inputs = MetaBuilder.create_many(new_args)
79
+ # Create random arguments from aggregated rule sets.
80
+ unless input_rule_sets.nil?
81
+ args = randomize(args, input_rule_sets)
82
+ end
70
83
 
71
- # Action method with new arguments.
72
- begin
84
+ # Create metadata for each argument.
85
+ # TODO: Create metadata for other inputs such as properties on the instance.
86
+ @inputs = MetaBuilder.create_many(args)
73
87
 
74
- # Validate input with aggregated control RuleSets.
75
- unless agg_input_rule_sets.nil?
76
- unless @aggregator.validate_inputs(new_args, agg_input_rule_sets)
77
- @status = :fail
78
- end
79
- end
88
+ end
89
+
90
+ # Action method with new/old arguments.
91
+ begin
80
92
 
81
93
  # Run reflection.
82
- output = @clone.send(@method, *new_args)
94
+ output = @clone.send(@method, *args)
83
95
  @output = MetaBuilder.create(output)
84
96
 
85
- # Validate output with aggregated control RuleSets.
86
- unless agg_output_rule_set.nil?
87
- unless @aggregator.validate_output(output, agg_output_rule_set)
97
+ # Validate output against aggregated control rule sets.
98
+ unless output_rule_set.nil?
99
+ unless @aggregator.test_output(output, output_rule_set)
88
100
  @status = :fail
89
101
  end
90
102
  end
91
103
 
92
- # When fail.
104
+ # When a system error occurs.
93
105
  rescue StandardError => message
106
+
94
107
  @status = :fail
95
108
  @message = message
109
+
96
110
  end
97
111
 
98
112
  end
99
113
 
100
114
  ##
101
- # Create random values for each argument.
115
+ # Create random values for each argument from control reflections.
116
+ #
117
+ # @param args [Dynamic] The arguments to mirror random values for.
118
+ # @param input_rule_sets [Array] Aggregated rule sets for each argument.
102
119
  #
103
- # @param args [Dynamic] The arguments to create random values for.
104
120
  # @return [Dynamic] Random arguments.
105
121
  ##
106
- def randomize(args)
122
+ def randomize(args, input_rule_sets)
107
123
 
108
124
  random_args = []
109
125
 
110
- args.each do |arg|
111
- case arg
112
- when Integer
113
- random_args << rand(999)
114
- else
115
- random_args << arg
116
- end
126
+ args.each_with_index do |arg, arg_num|
127
+
128
+ # Get a random rule in the rule set.
129
+ rules = input_rule_sets[arg_num].rules
130
+ agg_rule = rules[rules.keys.sample]
131
+
132
+ # Create a random value that follows that rule.
133
+ random_args << agg_rule.random()
134
+
117
135
  end
118
136
 
119
137
  return random_args
@@ -125,7 +143,7 @@ class Reflection
125
143
  #
126
144
  # @return [Hash] Reflection metadata.
127
145
  ##
128
- def result()
146
+ def serialize()
129
147
 
130
148
  # The ID of the first execution in the ShadowStack.
131
149
  base_id = nil
@@ -144,11 +162,19 @@ class Reflection
144
162
  :method => @method,
145
163
  :status => @status,
146
164
  :message => @message,
147
- :inputs => [],
148
- :output => @output,
165
+ :inputs => nil,
166
+ :output => nil,
149
167
  }
150
- @inputs.each do |meta|
151
- reflection[:inputs] << meta.result()
168
+
169
+ unless @inputs.nil?
170
+ reflection[:inputs] = []
171
+ @inputs.each do |meta|
172
+ reflection[:inputs] << meta.serialize()
173
+ end
174
+ end
175
+
176
+ unless @output.nil?
177
+ reflection[:output] = @output.serialize()
152
178
  end
153
179
 
154
180
  return reflection
@@ -34,6 +34,7 @@ module Reflekt
34
34
 
35
35
  def initialize(*args)
36
36
 
37
+ # TODO: Store counts on @@reflekt and key by instance ID.
37
38
  @reflekt_counts = {}
38
39
 
39
40
  # Get child and parent instance methods.
@@ -49,72 +50,94 @@ module Reflekt
49
50
  # When method called in flow.
50
51
  self.define_singleton_method(method) do |*args|
51
52
 
52
- # Get current execution.
53
- execution = @@reflekt.stack.peek()
53
+ # When Reflekt enabled and control reflection has executed without error.
54
+ if @@reflekt.config.enabled && !@@reflekt.error
54
55
 
55
- # Don't reflect when reflect limit reached or method skipped.
56
- unless (@reflekt_counts[method] >= @@reflekt.config.reflect_limit) || self.class.reflekt_skipped?(method)
56
+ # Get current execution.
57
+ execution = @@reflekt.stack.peek()
57
58
 
58
- # When stack empty or past execution done reflecting.
59
- if execution.nil? || execution.has_finished_reflecting?
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)
60
61
 
61
- # Create execution.
62
- execution = Execution.new(self, method, @@reflekt.config.reflect_amount, @@reflekt.stack)
62
+ # When stack empty or past execution done reflecting.
63
+ if execution.nil? || execution.has_finished_reflecting?
63
64
 
64
- @@reflekt.stack.push(execution)
65
+ # Create execution.
66
+ execution = Execution.new(self, method, @@reflekt.config.reflect_amount, @@reflekt.stack)
65
67
 
66
- end
68
+ @@reflekt.stack.push(execution)
69
+
70
+ end
67
71
 
68
- ##
69
- # Reflect the execution.
70
- #
71
- # The first method call in the Execution creates a Reflection.
72
- # Subsequent method calls are shadow executions on cloned objects.
73
- ##
74
- if execution.has_empty_reflections? && !execution.is_reflecting?
75
- execution.is_reflecting = true
72
+ ##
73
+ # Reflect the execution.
74
+ #
75
+ # The first method call in the execution creates a reflection.
76
+ # Then method calls are shadow executions which return to the reflection.
77
+ ##
78
+ if execution.has_empty_reflections? && !execution.is_reflecting?
79
+ execution.is_reflecting = true
76
80
 
77
- # Create control.
78
- control = Control.new(execution, 1, @@reflekt.aggregator)
79
- execution.control = control
81
+ # Create control.
82
+ control = Control.new(execution, 0, @@reflekt.aggregator)
83
+ execution.control = control
80
84
 
81
- # Execute control.
82
- control.reflect(*args)
85
+ # Execute control.
86
+ control.reflect(*args)
83
87
 
84
- # Save control.
85
- @@reflekt.db.get("controls").push(control.result())
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
86
93
 
87
- # Multiple reflections per execution.
88
- execution.reflections.each_with_index do |value, index|
94
+ # Save control as reflection.
95
+ @@reflekt.db.get("reflections").push(control.serialize())
89
96
 
90
- # Create reflection.
91
- reflection = Reflection.new(execution, index + 1, @@reflekt.aggregator)
92
- execution.reflections[index] = reflection
97
+ # Multiple reflections per execution.
98
+ execution.reflections.each_with_index do |value, index|
93
99
 
94
- # Execute reflection.
95
- reflection.reflect(*args)
96
- @reflekt_counts[method] = @reflekt_counts[method] + 1
100
+ # Create reflection.
101
+ reflection = Reflection.new(execution, index + 1, @@reflekt.aggregator)
102
+ execution.reflections[index] = reflection
97
103
 
98
- # Save reflection.
99
- @@reflekt.db.get("reflections").push(reflection.result())
104
+ # Execute reflection.
105
+ reflection.reflect(*args)
106
+ @reflekt_counts[method] = @reflekt_counts[method] + 1
100
107
 
101
- end
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()
102
118
 
103
- # Save results.
104
- @@reflekt.db.write()
119
+ # Render results.
120
+ @@reflekt.renderer.render()
105
121
 
106
- # Render results.
107
- @@reflekt.renderer.render()
122
+ end
123
+
124
+ execution.is_reflecting = false
125
+ end
108
126
 
109
- execution.is_reflecting = false
110
127
  end
111
128
 
112
- end
129
+ # Don't execute skipped methods when reflecting.
130
+ unless execution.is_reflecting? && self.class.reflekt_skipped?(method)
131
+
132
+ # Continue execution / shadow execution.
133
+ super *args
134
+
135
+ end
113
136
 
114
- # Don't execute skipped methods when reflecting.
115
- unless execution.is_reflecting? && self.class.reflekt_skipped?(method)
137
+ # When Reflekt disabled or control reflection failed.
138
+ else
116
139
 
117
- # Continue execution / shadow execution.
140
+ # Continue execution.
118
141
  super *args
119
142
 
120
143
  end