reflekt 0.9.2 → 0.9.8

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