reflekt 0.9.9 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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