reflekt 0.9.7 → 1.0.2

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
@@ -17,12 +26,12 @@ class Execution
17
26
  ##
18
27
  # Create Execution.
19
28
  #
20
- # @param Object object - The calling object.
21
- # @param Symbol method - The calling method.
22
- # @param Integer number - The number of reflections to create per execution.
23
- # @param ShadowStack stack - The shadow execution call stack.
29
+ # @param object [Object] The calling object.
30
+ # @param method [Symbol] The calling method.
31
+ # @param reflect_amount [Integer] The number of reflections to create per execution.
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
@@ -0,0 +1,71 @@
1
+ ################################################################################
2
+ # Metadata for input and output.
3
+ #
4
+ # @pattern Abstract class
5
+ # @see lib/meta for each meta.
6
+ #
7
+ # @hierachy
8
+ # 1. Execution
9
+ # 2. Reflection
10
+ # 3. Meta <- YOU ARE HERE
11
+ ################################################################################
12
+
13
+ class Meta
14
+
15
+ ##
16
+ # Each meta defines its type.
17
+ ##
18
+ def initialize()
19
+ @type = nil
20
+ end
21
+
22
+ ##
23
+ # Each meta loads values.
24
+ #
25
+ # @param value [Dynamic]
26
+ ##
27
+ def load(value)
28
+ end
29
+
30
+ ##
31
+ # Each meta serializes metadata.
32
+ #
33
+ # @return [Hash]
34
+ ##
35
+ def serialize()
36
+ {}
37
+ end
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
+
71
+ end
@@ -0,0 +1,84 @@
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
@@ -1,95 +1,158 @@
1
+ ################################################################################
2
+ # A snapshot of simulated 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. Execution
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
+
1
25
  class Reflection
2
26
 
3
- attr_accessor :clone
27
+ attr_reader :status
4
28
 
5
29
  ##
6
30
  # Create a Reflection.
7
31
  #
8
- # @param Execution execution - The Execution that created this Reflection.
9
- # @param Integer number - Multiple Reflections can be created per Execution.
10
- # @param Ruler ruler - The RuleSets for this class/method.
32
+ # @param execution [Execution] The Execution that created this Reflection.
33
+ # @param number [Integer] Multiple Reflections can be created per Execution.
34
+ # @param aggregator [Aggregator] The aggregated RuleSet for this class/method.
11
35
  ##
12
- def initialize(execution, number, ruler)
36
+ def initialize(execution, number, aggregator)
13
37
 
14
38
  @execution = execution
15
39
  @unique_id = execution.unique_id + number
16
40
  @number = number
17
41
 
18
42
  # Dependency.
19
- @ruler = ruler
43
+ @aggregator = aggregator
20
44
 
21
45
  # Caller.
22
46
  @klass = execution.klass
23
47
  @method = execution.method
24
48
 
25
- # Arguments.
26
- @inputs = []
49
+ # Metadata.
50
+ @inputs = nil
27
51
  @output = nil
28
52
 
29
53
  # Clone the execution's calling object.
54
+ # TODO: Abstract away into Clone class.
30
55
  @clone = execution.caller_object.clone
31
- @clone_id = nil
32
56
 
33
57
  # Result.
34
58
  @status = :pass
35
59
  @time = Time.now.to_i
60
+ @message = nil
36
61
 
37
62
  end
38
63
 
39
64
  ##
40
65
  # Reflect on a method.
41
66
  #
42
- # Creates a shadow execution stack.
43
- #
44
- # @param *args - The method's arguments.
45
- #
46
- # @return - A reflection hash.
67
+ # Creates a shadow execution.
68
+ # @param *args [Dynamic] The method's arguments.
47
69
  ##
48
70
  def reflect(*args)
49
71
 
50
- # Get RuleSets.
51
- input_rule_sets = @ruler.get_input_rule_sets(@klass, @method)
52
- output_rule_set = @ruler.get_output_rule_set(@klass, @method)
53
-
54
- # Create deviated arguments.
55
- args.each do |arg|
56
- case arg
57
- when Integer
58
- @inputs << rand(999)
59
- else
60
- @inputs << arg
61
- end
62
- end
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)
63
75
 
64
- # Action method with new arguments.
65
- begin
76
+ # When arguments exist.
77
+ unless args.size == 0
66
78
 
67
- # Validate input with controls.
79
+ # Create random arguments from aggregated rule sets.
68
80
  unless input_rule_sets.nil?
69
- unless @ruler.validate_inputs(@inputs, input_rule_sets)
81
+
82
+ # Base random arguments on the types of the current arguments.
83
+ if Aggregator.testable?(args, input_rule_sets)
84
+
85
+ args = randomize(args, input_rule_sets)
86
+
87
+ # TODO: Fallback to argument types from aggregated control rule sets
88
+ # when arg types not testable or reflect_amount above 3.
89
+ else
70
90
  @status = :fail
71
91
  end
92
+
72
93
  end
73
94
 
95
+ # Create metadata for each argument.
96
+ # TODO: Create metadata for other inputs such as properties on the instance.
97
+ @inputs = MetaBuilder.create_many(args)
98
+
99
+ end
100
+
101
+ # Action method with new/old arguments.
102
+ begin
103
+
74
104
  # Run reflection.
75
- @output = @clone.send(@method, *@inputs)
105
+ output = @clone.send(@method, *args)
106
+ @output = MetaBuilder.create(output)
76
107
 
77
- # Validate output with controls.
108
+ # Validate output against aggregated control rule sets.
78
109
  unless output_rule_set.nil?
79
- unless @ruler.validate_output(@output, output_rule_set)
110
+ unless @aggregator.test_output(output, output_rule_set)
80
111
  @status = :fail
81
112
  end
82
113
  end
83
114
 
84
- # When fail.
115
+ # When a system error occurs.
85
116
  rescue StandardError => message
117
+
86
118
  @status = :fail
87
119
  @message = message
120
+
88
121
  end
89
122
 
90
123
  end
91
124
 
92
- def result()
125
+ ##
126
+ # Create random values for each argument from control reflections.
127
+ #
128
+ # @param args [Dynamic] The arguments to create random values for.
129
+ # @param input_rule_sets [Array] Aggregated rule sets for each argument.
130
+ #
131
+ # @return [Dynamic] Random arguments.
132
+ ##
133
+ def randomize(args, input_rule_sets)
134
+
135
+ random_args = []
136
+
137
+ args.each_with_index do |arg, arg_num|
138
+
139
+ rule_type = Aggregator.value_to_rule_type(arg)
140
+ agg_rule = input_rule_sets[arg_num].rules[rule_type]
141
+
142
+ random_args << agg_rule.random()
143
+
144
+ end
145
+
146
+ return random_args
147
+
148
+ end
149
+
150
+ ##
151
+ # Get the results of the reflection.
152
+ #
153
+ # @return [Hash] Reflection metadata.
154
+ ##
155
+ def serialize()
93
156
 
94
157
  # The ID of the first execution in the ShadowStack.
95
158
  base_id = nil
@@ -107,66 +170,23 @@ class Reflection
107
170
  :class => @klass,
108
171
  :method => @method,
109
172
  :status => @status,
110
- :input => normalize_input(@inputs),
111
- :output => normalize_output(@output),
112
- :message => @message
173
+ :message => @message,
174
+ :inputs => nil,
175
+ :output => nil,
113
176
  }
114
177
 
115
- return reflection
116
- end
117
-
118
- ##
119
- # Normalize inputs.
120
- #
121
- # @param args - The actual inputs.
122
- # @return - A generic inputs representation.
123
- ##
124
- def normalize_input(args)
125
- inputs = []
126
- args.each do |arg|
127
- input = {
128
- :type => arg.class.to_s
129
- }
130
- if (arg.class == Array)
131
- input[:count] = arg.count
178
+ unless @inputs.nil?
179
+ reflection[:inputs] = []
180
+ @inputs.each do |meta|
181
+ reflection[:inputs] << meta.serialize()
132
182
  end
133
- inputs << input
134
183
  end
135
- inputs
136
- end
137
184
 
138
- ##
139
- # Normalize output.
140
- #
141
- # @param input - The actual output.
142
- # @return - A generic output representation.
143
- ##
144
- def normalize_output(arg)
145
-
146
- input = {
147
- :type => arg.class.to_s
148
- }
149
-
150
- if (arg.class == Array || arg.class == Hash)
151
- input[:count] = arg.count
152
- elsif (arg.class == TrueClass || arg.class == FalseClass)
153
- input[:type] = :Boolean
185
+ unless @output.nil?
186
+ reflection[:output] = @output.serialize()
154
187
  end
155
188
 
156
- return input
157
-
158
- end
159
-
160
- def normalize_value(value)
161
-
162
- unless value.nil?
163
- value = value.to_s.gsub(/\r?\n/, " ").to_s
164
- if value.length >= 30
165
- value = value[0, value.rindex(/\s/,30)].rstrip() + '...'
166
- end
167
- end
168
-
169
- return value
189
+ return reflection
170
190
 
171
191
  end
172
192