reflekt 0.9.9 → 1.0.0

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