reflekt 0.9.9 → 1.0.0

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.
@@ -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
  #
@@ -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,24 @@ 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
+ String => :string
77
+ }
78
+
79
+ return meta_types[data_type]
80
+
81
+ end
82
+
56
83
  end
@@ -2,23 +2,29 @@
2
2
  # A snapshot of simulated data.
3
3
  #
4
4
  # @nomenclature
5
- # args/inputs/values are the same thing but at a different stage of lifecycle.
5
+ # args, inputs/output and meta represent different stages of a value.
6
6
  #
7
7
  # @hierachy
8
8
  # 1. Execution
9
- # 2. Reflection
10
- # 3. RuleSet
9
+ # 2. Reflection <- YOU ARE HERE
10
+ # 3. Meta
11
11
  ################################################################################
12
12
 
13
+ require 'Clone'
13
14
  require 'MetaBuilder'
14
15
 
15
16
  class Reflection
16
17
 
17
- attr_accessor :clone
18
+ attr_reader :status
18
19
 
19
20
  ##
20
21
  # Create a Reflection.
21
22
  #
23
+ # @status
24
+ # - :pass The reflection passes the rules.
25
+ # - :fail The reflection fails the rules or produces a system error.
26
+ # - :error The control reflection produces a system error.
27
+ #
22
28
  # @param execution [Execution] The Execution that created this Reflection.
23
29
  # @param number [Integer] Multiple Reflections can be created per Execution.
24
30
  # @param aggregator [Aggregator] The aggregated RuleSet for this class/method.
@@ -37,83 +43,97 @@ class Reflection
37
43
  @method = execution.method
38
44
 
39
45
  # Metadata.
40
- @inputs = []
46
+ @inputs = nil
41
47
  @output = nil
42
48
 
43
49
  # Clone the execution's calling object.
50
+ # TODO: Abstract away into Clone class.
44
51
  @clone = execution.caller_object.clone
45
- @clone_id = nil
46
52
 
47
53
  # Result.
48
54
  @status = :pass
49
55
  @time = Time.now.to_i
56
+ @message = nil
50
57
 
51
58
  end
52
59
 
53
60
  ##
54
61
  # Reflect on a method.
55
62
  #
56
- # Creates a shadow execution stack.
63
+ # Creates a shadow execution.
57
64
  # @param *args [Dynamic] The method's arguments.
58
65
  ##
59
66
  def reflect(*args)
60
67
 
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)
68
+ # Get aggregated rule sets.
69
+ input_rule_sets = @aggregator.get_input_rule_sets(@klass, @method)
70
+ output_rule_set = @aggregator.get_output_rule_set(@klass, @method)
64
71
 
65
- # Create random arguments.
66
- new_args = randomize(args)
72
+ # When arguments exist.
73
+ unless args.size == 0
67
74
 
68
- # Create metadata for each argument.
69
- @inputs = MetaBuilder.create_many(new_args)
75
+ # When aggregated rule sets exist.
76
+ unless input_rule_sets.nil?
70
77
 
71
- # Action method with new arguments.
72
- begin
78
+ # Randomize arguments from rule sets.
79
+ args = randomize(args, input_rule_sets)
73
80
 
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)
81
+ # Validate arguments against aggregated rule sets.
82
+ unless @aggregator.test_inputs(args, input_rule_sets)
77
83
  @status = :fail
78
84
  end
85
+
79
86
  end
80
87
 
88
+ # Create metadata for each argument.
89
+ # TODO: Create metadata for other inputs such as properties on the instance.
90
+ @inputs = MetaBuilder.create_many(args)
91
+
92
+ end
93
+
94
+ # Action method with new/old arguments.
95
+ begin
96
+
81
97
  # Run reflection.
82
- output = @clone.send(@method, *new_args)
98
+ output = @clone.send(@method, *args)
83
99
  @output = MetaBuilder.create(output)
84
100
 
85
- # Validate output with aggregated control RuleSets.
86
- unless agg_output_rule_set.nil?
87
- unless @aggregator.validate_output(output, agg_output_rule_set)
101
+ # Validate output with aggregated control rule sets.
102
+ unless output_rule_set.nil?
103
+ unless @aggregator.test_output(output, output_rule_set)
88
104
  @status = :fail
89
105
  end
90
106
  end
91
107
 
92
- # When fail.
108
+ # When a system error occurs.
93
109
  rescue StandardError => message
110
+
94
111
  @status = :fail
95
112
  @message = message
113
+
96
114
  end
97
115
 
98
116
  end
99
117
 
100
118
  ##
101
- # Create random values for each argument.
119
+ # Create random values for each argument from control reflections.
102
120
  #
103
121
  # @param args [Dynamic] The arguments to create random values for.
122
+ # @param input_rule_sets [Array] Aggregated rule sets for each argument.
123
+ #
104
124
  # @return [Dynamic] Random arguments.
105
125
  ##
106
- def randomize(args)
126
+ def randomize(args, input_rule_sets)
107
127
 
108
128
  random_args = []
109
129
 
110
- args.each do |arg|
111
- case arg
112
- when Integer
113
- random_args << rand(999)
114
- else
115
- random_args << arg
116
- end
130
+ args.each_with_index do |arg, arg_num|
131
+
132
+ rule_type = Aggregator.value_to_rule_type(arg)
133
+ agg_rule = input_rule_sets[arg_num].rules[rule_type]
134
+
135
+ random_args << agg_rule.random()
136
+
117
137
  end
118
138
 
119
139
  return random_args
@@ -144,11 +164,19 @@ class Reflection
144
164
  :method => @method,
145
165
  :status => @status,
146
166
  :message => @message,
147
- :inputs => [],
148
- :output => @output,
167
+ :inputs => nil,
168
+ :output => nil,
149
169
  }
150
- @inputs.each do |meta|
151
- reflection[:inputs] << meta.result()
170
+
171
+ unless @inputs.nil?
172
+ reflection[:inputs] = []
173
+ @inputs.each do |meta|
174
+ reflection[:inputs] << meta.result()
175
+ end
176
+ end
177
+
178
+ unless @output.nil?
179
+ reflection[:output] = @output.result()
152
180
  end
153
181
 
154
182
  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.result())
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.result())
110
+
111
+ end
112
+
113
+ # Save control.
114
+ @@reflekt.db.get("controls").push(control.result())
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
@@ -13,6 +13,8 @@
13
13
 
14
14
  class Rule
15
15
 
16
+ attr_reader :type
17
+
16
18
  ##
17
19
  # Each rule trains on metadata to determine its boundaries.
18
20
  #
@@ -31,7 +33,7 @@ class Rule
31
33
  end
32
34
 
33
35
  ##
34
- # Each rule provides metadata.
36
+ # Each rule provides results.
35
37
  #
36
38
  # @return [Hash]
37
39
  ##
@@ -39,4 +41,12 @@ class Rule
39
41
  {}
40
42
  end
41
43
 
44
+ ##
45
+ # Each rule provides a random example that matches the rule's boundaries.
46
+ #
47
+ # @return [Dynamic] A random value.
48
+ ##
49
+ def random()
50
+ end
51
+
42
52
  end
@@ -12,6 +12,7 @@
12
12
  ################################################################################
13
13
 
14
14
  require 'set'
15
+ require 'MetaBuilder'
15
16
 
16
17
  class RuleSet
17
18
 
@@ -22,9 +23,14 @@ class RuleSet
22
23
  ##
23
24
  def initialize(meta_map)
24
25
 
26
+ # The rules that apply to meta types.
25
27
  @meta_map = meta_map
28
+
29
+ # The types of meta this rule set applies to.
30
+ # Rules are only validated on their supported meta type.
31
+ @meta_types = Set.new()
32
+
26
33
  @rules = {}
27
- @types = Set.new()
28
34
 
29
35
  end
30
36
 
@@ -38,7 +44,7 @@ class RuleSet
38
44
  unless meta.nil? || meta[:type].nil?
39
45
 
40
46
  meta_type = meta[:type]
41
- @types << meta_type
47
+ @meta_types << meta_type
42
48
 
43
49
  # Get rule types for this meta type.
44
50
  if @meta_map.key? meta_type
@@ -46,7 +52,7 @@ class RuleSet
46
52
 
47
53
  # Ensure rule exists.
48
54
  if @rules[rule_type].nil?
49
- @rules << rule_type.new()
55
+ @rules[rule_type] = rule_type.new()
50
56
  end
51
57
 
52
58
  # Train rule.
@@ -55,10 +61,25 @@ class RuleSet
55
61
  end
56
62
  end
57
63
 
58
- return self
64
+ end
65
+
66
+ end
67
+
68
+ def test(value)
69
+ result = true
70
+
71
+ # Only test data type on rule of matching meta type.
72
+ meta_type = MetaBuilder.data_type_to_meta_type(value)
59
73
 
74
+ @rules.each do |klass, rule|
75
+ if (rule.type == meta_type)
76
+ unless rule.test(value)
77
+ result = false
78
+ end
79
+ end
60
80
  end
61
81
 
82
+ return result
62
83
  end
63
84
 
64
85
  ##
@@ -78,4 +99,5 @@ class RuleSet
78
99
 
79
100
  end
80
101
 
102
+
81
103
  end