reflekt 0.9.2 → 0.9.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 21ac72b1a4f8bf9bd182f1d1ae5464d11aa87ab0f38c6fa418c9a3e73ff33a5d
4
- data.tar.gz: bfd3a381c930d910e3b293e835877712734eecc2a51c7949e7f4747b67377058
3
+ metadata.gz: c5b9e88d60fea03ebe06c430b489cb1295b8d56ec76f30982721a709a406f0af
4
+ data.tar.gz: 948f53a8b72f5befda3e175029edfdb017d98b3b8fd41998ab95b5f6b0a6b95e
5
5
  SHA512:
6
- metadata.gz: e9b62612aa60d91bf591eae59c9797c97e9b54fdafd58d2785ed4fdfa8c7bc256cd288e13dd9e83d4fd8d11fbdbe043ce0660f6ba82878f8fd5eabb224d691b0
7
- data.tar.gz: 9a38959ce057bdf3f4e7e2091f0aa6666be940e356b5865952a7e9e7749958d77f8beb68d2fd8f9a252f047bb45bccc756b3f9af793c85e3031a4f0cab541c74
6
+ metadata.gz: e70f287d10e70e3ac8ab3e01881ed6d8bb79f881c9af5530f39c7dd29997021ddf246d1129467503cfb3c6efb0589604648876c64bda917e8b970cb278a79fb3
7
+ data.tar.gz: ef005f855d7c3d1002eb059a73ecf742645841d4d3d0bd416a84b549e2e7d5b63a8bc216e8fe1404bf20c383a8e0a10c54740458e40382fa9591f9c67f3a075c
@@ -0,0 +1,37 @@
1
+ ################################################################################
2
+ # Access variables via one object to avoid polluting the caller class scope.
3
+ #
4
+ # @pattern Singleton
5
+ # @note Some variables are not accessed via Accessor:
6
+ # - @reflekt_counts on the instance
7
+ # - @reflekt_enabled on the instance
8
+ # - @@reflekt_skipped_methods on the instance's singleton class
9
+ ################################################################################
10
+
11
+ class Accessor
12
+
13
+ attr_accessor :setup
14
+ attr_accessor :db
15
+ attr_accessor :stack
16
+ attr_accessor :aggregator
17
+ attr_accessor :renderer
18
+ attr_accessor :path
19
+ attr_accessor :output_path
20
+ attr_accessor :reflect_amount
21
+ attr_accessor :reflect_limit
22
+
23
+ def initialize()
24
+
25
+ @setup = nil
26
+ @db = nil
27
+ @stack = nil
28
+ @aggregator = nil
29
+ @renderer = nil
30
+ @path = nil
31
+ @output_path = nil
32
+ @reflect_amount = nil
33
+ @reflect_limit = nil
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,193 @@
1
+ ################################################################################
2
+ # Aggregate reflection metadata into rule sets.
3
+ # Validate reflection arguments against aggregates.
4
+ #
5
+ # @pattern Singleton
6
+ #
7
+ # @hierachy
8
+ # 1. Aggregator
9
+ # 2. RuleSet
10
+ # 3. Rule
11
+ ################################################################################
12
+
13
+ require 'RuleSet'
14
+
15
+ class Aggregator
16
+
17
+ def initialize()
18
+
19
+ # Key rule sets by class and method.
20
+ @rule_sets = {}
21
+
22
+ end
23
+
24
+ ##
25
+ # Get aggregated RuleSets for all inputs.
26
+ #
27
+ # @param klass [Symbol]
28
+ # @param method [Symbol]
29
+ # @return [Array]
30
+ ##
31
+ def get_input_rule_sets(klass, method)
32
+ return @rule_sets.dig(klass, method, :inputs)
33
+ end
34
+
35
+ ##
36
+ # Get an aggregated RuleSet for an input.
37
+ #
38
+ # @param klass [Symbol]
39
+ # @param method [Symbol]
40
+ # @return [RuleSet]
41
+ ##
42
+ def get_input_rule_set(klass, method, arg_num)
43
+ @rule_sets.dig(klass, method, :inputs, arg_num)
44
+ end
45
+
46
+ ##
47
+ # Get an aggregated RuleSet for an output.
48
+ #
49
+ # @param klass [Symbol]
50
+ # @param method [Symbol]
51
+ # @return [RuleSet]
52
+ ##
53
+ def get_output_rule_set(klass, method)
54
+ @rule_sets.dig(klass, method, :output)
55
+ end
56
+
57
+ ##
58
+ # Set an aggregated RuleSet for an input.
59
+ #
60
+ # @param klass [Symbol]
61
+ # @param method [Symbol]
62
+ ##
63
+ def set_input_rule_set(klass, method, arg_num, rule_set)
64
+ # Set defaults.
65
+ @rule_sets[klass] = {} unless @rule_sets.key? klass
66
+ @rule_sets[klass][method] = {} unless @rule_sets[klass].key? method
67
+ @rule_sets[klass][method][:inputs] = [] unless @rule_sets[klass][method].key? :inputs
68
+ # Set value.
69
+ @rule_sets[klass][method][:inputs][arg_num] = rule_set
70
+ end
71
+
72
+ ##
73
+ # Set an aggregated RuleSet for an output.
74
+ #
75
+ # @param klass [Symbol]
76
+ # @param method [Symbol]
77
+ # @param rule_set [RuleSet]
78
+ ##
79
+ def set_output_rule_set(klass, method, rule_set)
80
+ # Set defaults.
81
+ @rule_sets[klass] = {} unless @rule_sets.key? klass
82
+ @rule_sets[klass][method] = {} unless @rule_sets[klass].key? method
83
+ # Set value.
84
+ @rule_sets[klass][method][:output] = rule_set
85
+ end
86
+
87
+ ##
88
+ # Create aggregated rule sets from reflection metadata.
89
+ #
90
+ # @param reflections [Array] Controls with metadata.
91
+ ##
92
+ def train(reflections)
93
+
94
+ # On first use there are no previous reflections.
95
+ return if reflections.nil?
96
+
97
+ reflections.each do |reflection|
98
+
99
+ klass = reflection[:class]
100
+ method = reflection[:method]
101
+
102
+ ##
103
+ # INPUT
104
+ ##
105
+
106
+ unless reflection[:inputs].nil?
107
+ reflection[:inputs].each_with_index do |meta, arg_num|
108
+
109
+ # Get rule set.
110
+ rule_set = get_input_rule_set(klass, method, arg_num)
111
+ if rule_set.nil?
112
+ rule_set = RuleSet.new()
113
+ set_input_rule_set(klass, method, arg_num, rule_set)
114
+ end
115
+
116
+ # Train on metadata.
117
+ rule_set.train(meta)
118
+
119
+ end
120
+ end
121
+
122
+ ##
123
+ # OUTPUT
124
+ ##
125
+
126
+ # Get rule set.
127
+ output_rule_set = get_output_rule_set(klass, method)
128
+ if output_rule_set.nil?
129
+ output_rule_set = RuleSet.new()
130
+ set_output_rule_set(klass, method, output_rule_set)
131
+ end
132
+
133
+ # Train on metadata.
134
+ output_rule_set.train(reflection[:output])
135
+
136
+ end
137
+
138
+ end
139
+
140
+ ##
141
+ # Validate inputs.
142
+ #
143
+ # @param inputs [Array] The method's arguments.
144
+ # @param input_rule_sets [Array] The RuleSets to validate each input with.
145
+ ##
146
+ def validate_inputs(inputs, input_rule_sets)
147
+
148
+ # Default to a PASS result.
149
+ result = true
150
+
151
+ # Validate each argument against each RuleSet for that argument.
152
+ inputs.each_with_index do |input, arg_num|
153
+
154
+ unless input_rule_sets[arg_num].nil?
155
+
156
+ rule_set = input_rule_sets[arg_num]
157
+
158
+ unless rule_set.validate_rule(input)
159
+ result = false
160
+ end
161
+
162
+ end
163
+ end
164
+
165
+ return result
166
+
167
+ end
168
+
169
+ ##
170
+ # Validate output.
171
+ #
172
+ # @param output [Dynamic] The method's return value.
173
+ # @param output_rule_set [RuleSet] The RuleSet to validate the output with.
174
+ ##
175
+ def validate_output(output, output_rule_set)
176
+
177
+ # Default to a PASS result.
178
+ result = true
179
+
180
+ unless output_rule_set.nil?
181
+
182
+ # Validate output RuleSet for that argument.
183
+ unless output_rule_set.validate_rule(output)
184
+ result = false
185
+ end
186
+
187
+ end
188
+
189
+ return result
190
+
191
+ end
192
+
193
+ end
@@ -1,4 +1,14 @@
1
+ ################################################################################
2
+ # A shapshot of real data.
3
+ #
4
+ # @hierachy
5
+ # 1. Execution
6
+ # 2. Control
7
+ # 3. RuleSet
8
+ ################################################################################
9
+
1
10
  require 'Reflection'
11
+ require 'MetaBuilder'
2
12
 
3
13
  class Control < Reflection
4
14
 
@@ -7,25 +17,25 @@ class Control < Reflection
7
17
  #
8
18
  # Creates a shadow execution stack.
9
19
  #
10
- # @param method - The name of the method.
11
- # @param *args - The method arguments.
12
- #
13
- # @return - A reflection hash.
20
+ # @param method [Symbol] The name of the method.
21
+ # @param *args [Args] The method arguments.
22
+ # @return [Hash] A reflection hash.
14
23
  ##
15
24
  def reflect(*args)
16
25
 
17
- @input = *args
26
+ # Create metadata for each argument.
27
+ @inputs = MetaBuilder.create_many(args)
18
28
 
19
29
  # Action method with new arguments.
20
30
  begin
21
- @output = @clone.send(@method, *@input)
31
+ output = @clone.send(@method, *args)
22
32
  # When fail.
23
33
  rescue StandardError => message
24
- @status = FAIL
34
+ @status = :fail
25
35
  @message = message
26
36
  # When pass.
27
37
  else
28
- @status = PASS
38
+ @status = :pass
29
39
  end
30
40
 
31
41
  end
@@ -1,24 +1,56 @@
1
1
  class Execution
2
2
 
3
- attr_accessor :object
3
+ attr_accessor :unique_id
4
+ attr_accessor :caller_object
4
5
  attr_accessor :caller_id
5
6
  attr_accessor :caller_class
7
+ attr_accessor :klass
8
+ attr_accessor :method
9
+ attr_accessor :base
6
10
  attr_accessor :parent
7
11
  attr_accessor :child
8
12
  attr_accessor :control
9
13
  attr_accessor :reflections
10
14
  attr_accessor :is_reflecting
15
+ attr_accessor :is_base
11
16
 
12
- def initialize(object, reflection_count)
17
+ ##
18
+ # Create Execution.
19
+ #
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.
24
+ ##
25
+ def initialize(caller_object, method, number, stack)
13
26
 
14
- @object = object
15
- @caller_id = object.object_id
16
- @caller_class = object.class
27
+ @time = Time.now.to_i
28
+ @unique_id = @time + rand(1..99999)
29
+ @base = nil
17
30
  @parent = nil
18
31
  @child = nil
19
32
 
20
- @control = []
21
- @reflections = Array.new(reflection_count)
33
+ # Dependency.
34
+ @stack = stack
35
+
36
+ # Caller.
37
+ @caller_object = caller_object
38
+ @caller_id = caller_object.object_id
39
+ @caller_class = caller_object.class
40
+ @klass = @caller_class.to_s.to_sym
41
+ @method = method
42
+
43
+ # Reflections.
44
+ @control = nil
45
+ @reflections = Array.new(number)
46
+
47
+ # State.
48
+ if @stack.peek() == nil
49
+ @is_base = true
50
+ else
51
+ @is_base = false
52
+ @base = @stack.base()
53
+ end
22
54
  @is_reflecting = false
23
55
 
24
56
  end
@@ -0,0 +1,27 @@
1
+ ################################################################################
2
+ # Meta for input and output. All meta behave the same.
3
+ #
4
+ # @pattern Abstract class.
5
+ # @see lib/meta for each meta.
6
+ ################################################################################
7
+
8
+ class Meta
9
+
10
+ ##
11
+ # Each meta loads values.
12
+ #
13
+ # @param value [Dynamic]
14
+ ##
15
+ def load(value)
16
+ end
17
+
18
+ ##
19
+ # Each meta provides metadata.
20
+ #
21
+ # @return [Hash]
22
+ ##
23
+ def result()
24
+ {}
25
+ end
26
+
27
+ end
@@ -0,0 +1,56 @@
1
+ ################################################################################
2
+ # Create Meta.
3
+ #
4
+ # @pattern Builder.
5
+ # @see lib/meta for each meta.
6
+ ################################################################################
7
+
8
+ require 'Meta'
9
+ require_relative './meta/IntegerMeta'
10
+ require_relative './meta/StringMeta'
11
+
12
+ class MetaBuilder
13
+
14
+ ##
15
+ # Create meta.
16
+ #
17
+ # @param value
18
+ ##
19
+ def self.create(value)
20
+
21
+ meta = nil
22
+
23
+ # Creates values for matching data type.
24
+ case value.class.to_s
25
+ when "Integer"
26
+ meta = IntegerMeta.new()
27
+ when "String"
28
+ meta = StringMeta.new()
29
+ end
30
+
31
+ unless meta.nil?
32
+ meta.load(value)
33
+ end
34
+
35
+ return meta
36
+
37
+ end
38
+
39
+ ##
40
+ # Create meta for multiple values.
41
+ #
42
+ # @param values
43
+ ##
44
+ def self.create_many(values)
45
+
46
+ meta = []
47
+
48
+ values.each do |value|
49
+ meta << self.create(value)
50
+ end
51
+
52
+ return meta
53
+
54
+ end
55
+
56
+ end
@@ -1,35 +1,52 @@
1
- class Reflection
1
+ ################################################################################
2
+ # A snapshot of simulated data.
3
+ #
4
+ # @nomenclature
5
+ # args/inputs/values are the same thing but at a different stage of lifecycle.
6
+ #
7
+ # @hierachy
8
+ # 1. Execution
9
+ # 2. Reflection
10
+ # 3. RuleSet
11
+ ################################################################################
12
+
13
+ require 'MetaBuilder'
2
14
 
3
- # Keys.
4
- TIME = "t"
5
- INPUT = "i"
6
- OUTPUT = "o"
7
- TYPE = "T"
8
- COUNT = "C"
9
- VALUE = "V"
10
- STATUS = "s"
11
- MESSAGE = "m"
12
- # Values.
13
- PASS = "p"
14
- FAIL = "f"
15
+ class Reflection
15
16
 
16
17
  attr_accessor :clone
17
18
 
18
- def initialize(execution, method, ruler)
19
+ ##
20
+ # Create a Reflection.
21
+ #
22
+ # @param execution [Execution] The Execution that created this Reflection.
23
+ # @param number [Integer] Multiple Reflections can be created per Execution.
24
+ # @param aggregator [Aggregator] The aggregated RuleSet for this class/method.
25
+ ##
26
+ def initialize(execution, number, aggregator)
19
27
 
20
28
  @execution = execution
21
- @method = method
22
- @ruler = ruler
29
+ @unique_id = execution.unique_id + number
30
+ @number = number
31
+
32
+ # Dependency.
33
+ @aggregator = aggregator
34
+
35
+ # Caller.
36
+ @klass = execution.klass
37
+ @method = execution.method
23
38
 
24
- # Clone the execution's object.
25
- @clone = execution.object.clone
39
+ # Metadata.
40
+ @inputs = []
41
+ @output = nil
42
+
43
+ # Clone the execution's calling object.
44
+ @clone = execution.caller_object.clone
26
45
  @clone_id = nil
27
46
 
28
47
  # Result.
29
- @status = nil
48
+ @status = :pass
30
49
  @time = Time.now.to_i
31
- @inputs = []
32
- @output = nil
33
50
 
34
51
  end
35
52
 
@@ -37,121 +54,104 @@ class Reflection
37
54
  # Reflect on a method.
38
55
  #
39
56
  # Creates a shadow execution stack.
40
- #
41
- # @param method - The name of the method.
42
- # @param *args - The method arguments.
43
- #
44
- # @return - A reflection hash.
57
+ # @param *args [Dynamic] The method's arguments.
45
58
  ##
46
59
  def reflect(*args)
47
60
 
48
- # Create deviated arguments.
49
- args.each do |arg|
50
- case arg
51
- when Integer
52
- @inputs << rand(999)
53
- else
54
- @inputs << arg
55
- end
56
- end
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)
64
+
65
+ # Create random arguments.
66
+ new_args = randomize(args)
67
+
68
+ # Create metadata for each argument.
69
+ @inputs = MetaBuilder.create_many(new_args)
57
70
 
58
71
  # Action method with new arguments.
59
72
  begin
60
- # Validate input with controls.
61
- unless @ruler.nil?
62
- if @ruler.validate_inputs(@execution.caller_class, @method, @inputs)
63
- @status = PASS
64
- else
65
- @status = FAIL
73
+
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
66
78
  end
67
79
  end
80
+
68
81
  # Run reflection.
69
- @output = @clone.send(@method, *@inputs)
82
+ output = @clone.send(@method, *new_args)
83
+ @output = MetaBuilder.create(output)
84
+
85
+ # Validate output with aggregated control RuleSets.
86
+ unless agg_output_rule_set.nil?
87
+ unless @aggregator.validate_output(output, agg_output_rule_set)
88
+ @status = :fail
89
+ end
90
+ end
91
+
70
92
  # When fail.
71
93
  rescue StandardError => message
72
- @status = FAIL
94
+ @status = :fail
73
95
  @message = message
74
- # When pass.
75
- else
76
- # Validate output with controls.
77
- unless @ruler.nil?
78
- if @ruler.validate_output(@execution.caller_class, @method, @output)
79
- @status = PASS
80
- else
81
- @status = FAIL
82
- end
83
- return
84
- end
85
- @status = PASS
86
96
  end
87
97
 
88
98
  end
89
99
 
90
- def result()
91
- # Build reflection.
92
- reflection = {
93
- TIME => @time,
94
- STATUS => @status,
95
- INPUT => normalize_input(@inputs),
96
- OUTPUT => normalize_output(@output),
97
- MESSAGE => @message
98
- }
99
- end
100
-
101
100
  ##
102
- # Normalize inputs.
101
+ # Create random values for each argument.
103
102
  #
104
- # @param args - The actual inputs.
105
- # @return - A generic inputs representation.
103
+ # @param args [Dynamic] The arguments to create random values for.
104
+ # @return [Dynamic] Random arguments.
106
105
  ##
107
- def normalize_input(args)
108
- inputs = []
106
+ def randomize(args)
107
+
108
+ random_args = []
109
+
109
110
  args.each do |arg|
110
- input = {
111
- TYPE => arg.class.to_s,
112
- VALUE => normalize_value(arg)
113
- }
114
- if (arg.class == Array)
115
- input[COUNT] = arg.count
111
+ case arg
112
+ when Integer
113
+ random_args << rand(999)
114
+ else
115
+ random_args << arg
116
116
  end
117
- inputs << input
118
117
  end
119
- inputs
118
+
119
+ return random_args
120
+
120
121
  end
121
122
 
122
123
  ##
123
- # Normalize output.
124
+ # Get the results of the reflection.
124
125
  #
125
- # @param input - The actual output.
126
- # @return - A generic output representation.
126
+ # @return [Hash] Reflection metadata.
127
127
  ##
128
- def normalize_output(input)
129
-
130
- output = {
131
- TYPE => input.class.to_s,
132
- VALUE => normalize_value(input)
133
- }
128
+ def result()
134
129
 
135
- if (input.class == Array || input.class == Hash)
136
- output[COUNT] = input.count
137
- elsif (input.class == TrueClass || input.class == FalseClass)
138
- output[TYPE] = :Boolean
130
+ # The ID of the first execution in the ShadowStack.
131
+ base_id = nil
132
+ unless @execution.base == nil
133
+ base_id = @execution.base.unique_id
139
134
  end
140
135
 
141
- return output
142
-
143
- end
144
-
145
- def normalize_value(value)
146
-
147
- unless value.nil?
148
- value = value.to_s.gsub(/\r?\n/, " ").to_s
149
- if value.length >= 30
150
- value = value[0, value.rindex(/\s/,30)].rstrip() + '...'
151
- end
136
+ # Build reflection.
137
+ reflection = {
138
+ :base_id => base_id,
139
+ :exe_id => @execution.unique_id,
140
+ :ref_id => @unique_id,
141
+ :ref_num => @number,
142
+ :time => @time,
143
+ :class => @klass,
144
+ :method => @method,
145
+ :status => @status,
146
+ :message => @message,
147
+ :inputs => [],
148
+ :output => @output,
149
+ }
150
+ @inputs.each do |meta|
151
+ reflection[:inputs] << meta.result()
152
152
  end
153
153
 
154
- return value
154
+ return reflection
155
155
 
156
156
  end
157
157