reflekt 0.9.1 → 0.9.7

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: 3589292c5c5cba2f3d7c7d5e1d7e02ee1052afe7339929cfa058b787b89c3158
4
- data.tar.gz: d33c6774d53d4b7a0978fcfc48fa00e22f3684ccd51e5d42676f01831fb84291
3
+ metadata.gz: 6df15da98e45aecc17c3594c000b6234f77afde5ce89541104bc3afe7eb5a221
4
+ data.tar.gz: 3f1446eb16bdcd214d3df924d0b2df0017bc26b073c5c94e36d1094849a9b1ef
5
5
  SHA512:
6
- metadata.gz: 2e3120f544d87057b4783a4e6e76a9689844f17ed1ad602c8b2c5e5ee241285ef83e276b56fbdb33da0d167c68077eca6f851e859a28392718a26ed129ab18e7
7
- data.tar.gz: 47d323198d8d27585ef5fb0d493eca120d0cd2ff532a6578ef3b7490ccbc9e4fc38757bab8fb2ad4ab6c05c0a9fd721b27a5925a90c95503c0de5d4fb7483e12
6
+ metadata.gz: e84519473c26febf3522119e66b25708abc1f05271c01b498debcb00c69eaf4b8bc244e43374737fef49e946304529c0efc2e6fceade3629c4ccef5503f1d3fa
7
+ data.tar.gz: 8faa3f80665504b4e5ffb182b7e9977234bd13e2f17aa5fac41636068b30ea07bfbf5aa580bee6deae2bb8e5fa6ea0ea7dc09505ce0a28bbf8797bb785aea0bb
@@ -0,0 +1,38 @@
1
+ ################################################################################
2
+ # ACCESSOR
3
+ #
4
+ # Access variables via one object to avoid polluting the caller class scope.
5
+ #
6
+ # Some variables are not accessed via Accessor:
7
+ # - @reflekt_counts on the instance
8
+ # - @reflekt_enabled on the instance
9
+ # - @@reflekt_skipped_methods on the instance's singleton class
10
+ ################################################################################
11
+
12
+ class Accessor
13
+
14
+ attr_accessor :setup
15
+ attr_accessor :db
16
+ attr_accessor :stack
17
+ attr_accessor :ruler
18
+ attr_accessor :renderer
19
+ attr_accessor :path
20
+ attr_accessor :output_path
21
+ attr_accessor :reflect_amount
22
+ attr_accessor :reflect_limit
23
+
24
+ def initialize()
25
+
26
+ @setup = nil
27
+ @db = nil
28
+ @stack = nil
29
+ @ruler = nil
30
+ @renderer = nil
31
+ @path = nil
32
+ @output_path = nil
33
+ @reflect_amount = nil
34
+ @reflect_limit = nil
35
+
36
+ end
37
+
38
+ end
@@ -2,6 +2,32 @@ require 'Reflection'
2
2
 
3
3
  class Control < Reflection
4
4
 
5
- # TODO.
5
+ ##
6
+ # Reflect on a method.
7
+ #
8
+ # Creates a shadow execution stack.
9
+ #
10
+ # @param method - The name of the method.
11
+ # @param *args - The method arguments.
12
+ #
13
+ # @return - A reflection hash.
14
+ ##
15
+ def reflect(*args)
16
+
17
+ @inputs = *args
18
+
19
+ # Action method with new arguments.
20
+ begin
21
+ @output = @clone.send(@method, *@inputs)
22
+ # When fail.
23
+ rescue StandardError => message
24
+ @status = :fail
25
+ @message = message
26
+ # When pass.
27
+ else
28
+ @status = :pass
29
+ end
30
+
31
+ end
6
32
 
7
33
  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
@@ -1,35 +1,38 @@
1
1
  class Reflection
2
2
 
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
-
16
3
  attr_accessor :clone
17
4
 
18
- def initialize(execution, method, is_control)
5
+ ##
6
+ # Create a Reflection.
7
+ #
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.
11
+ ##
12
+ def initialize(execution, number, ruler)
19
13
 
20
14
  @execution = execution
21
- @method = method
22
- @is_control = is_control
15
+ @unique_id = execution.unique_id + number
16
+ @number = number
17
+
18
+ # Dependency.
19
+ @ruler = ruler
20
+
21
+ # Caller.
22
+ @klass = execution.klass
23
+ @method = execution.method
23
24
 
24
- # Clone the execution's object.
25
- @clone = execution.object.clone
25
+ # Arguments.
26
+ @inputs = []
27
+ @output = nil
28
+
29
+ # Clone the execution's calling object.
30
+ @clone = execution.caller_object.clone
26
31
  @clone_id = nil
27
32
 
28
33
  # Result.
29
- @status = nil
34
+ @status = :pass
30
35
  @time = Time.now.to_i
31
- @input = []
32
- @output = nil
33
36
 
34
37
  end
35
38
 
@@ -38,51 +41,78 @@ class Reflection
38
41
  #
39
42
  # Creates a shadow execution stack.
40
43
  #
41
- # @param method - The name of the method.
42
- # @param *args - The method arguments.
44
+ # @param *args - The method's arguments.
43
45
  #
44
46
  # @return - A reflection hash.
45
47
  ##
46
48
  def reflect(*args)
47
49
 
48
- # Reflect on real world arguments.
49
- if @is_control
50
- @input = *args
51
- # Reflect on deviated arguments.
52
- else
53
- args.each do |arg|
54
- case arg
55
- when Integer
56
- @input << rand(9999)
57
- else
58
- @input << arg
59
- end
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
60
61
  end
61
62
  end
62
63
 
63
64
  # Action method with new arguments.
64
65
  begin
65
- @output = @clone.send(@method, *@input)
66
+
67
+ # Validate input with controls.
68
+ unless input_rule_sets.nil?
69
+ unless @ruler.validate_inputs(@inputs, input_rule_sets)
70
+ @status = :fail
71
+ end
72
+ end
73
+
74
+ # Run reflection.
75
+ @output = @clone.send(@method, *@inputs)
76
+
77
+ # Validate output with controls.
78
+ unless output_rule_set.nil?
79
+ unless @ruler.validate_output(@output, output_rule_set)
80
+ @status = :fail
81
+ end
82
+ end
83
+
66
84
  # When fail.
67
85
  rescue StandardError => message
68
- @status = MESSAGE
86
+ @status = :fail
69
87
  @message = message
70
- # When pass.
71
- else
72
- @status = PASS
73
88
  end
74
89
 
75
90
  end
76
91
 
77
92
  def result()
93
+
94
+ # The ID of the first execution in the ShadowStack.
95
+ base_id = nil
96
+ unless @execution.base == nil
97
+ base_id = @execution.base.unique_id
98
+ end
99
+
78
100
  # Build reflection.
79
101
  reflection = {
80
- TIME => @time,
81
- STATUS => @status,
82
- INPUT => normalize_input(@input),
83
- OUTPUT => normalize_output(@output),
84
- MESSAGE => @message
102
+ :base_id => base_id,
103
+ :exe_id => @execution.unique_id,
104
+ :ref_id => @unique_id,
105
+ :ref_num => @number,
106
+ :time => @time,
107
+ :class => @klass,
108
+ :method => @method,
109
+ :status => @status,
110
+ :input => normalize_input(@inputs),
111
+ :output => normalize_output(@output),
112
+ :message => @message
85
113
  }
114
+
115
+ return reflection
86
116
  end
87
117
 
88
118
  ##
@@ -95,11 +125,10 @@ class Reflection
95
125
  inputs = []
96
126
  args.each do |arg|
97
127
  input = {
98
- TYPE => arg.class.to_s,
99
- VALUE => normalize_value(arg)
128
+ :type => arg.class.to_s
100
129
  }
101
130
  if (arg.class == Array)
102
- input[COUNT] = arg.count
131
+ input[:count] = arg.count
103
132
  end
104
133
  inputs << input
105
134
  end
@@ -112,20 +141,19 @@ class Reflection
112
141
  # @param input - The actual output.
113
142
  # @return - A generic output representation.
114
143
  ##
115
- def normalize_output(input)
144
+ def normalize_output(arg)
116
145
 
117
- output = {
118
- TYPE => input.class.to_s,
119
- VALUE => normalize_value(input)
146
+ input = {
147
+ :type => arg.class.to_s
120
148
  }
121
149
 
122
- if (input.class == Array || input.class == Hash)
123
- output[COUNT] = input.count
124
- elsif (input.class == TrueClass || input.class == FalseClass)
125
- output[TYPE] = :Boolean
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
126
154
  end
127
155
 
128
- return output
156
+ return input
129
157
 
130
158
  end
131
159
 
@@ -1,37 +1,32 @@
1
- require 'set'
2
- require 'erb'
3
- require 'rowdb'
4
- require 'Control'
5
- require 'Execution'
6
- require 'Reflection'
7
- require 'ShadowStack'
8
-
9
1
  ################################################################################
10
- # REFLEKT
2
+ # REFLEKT - By Maedi Prichard.
11
3
  #
12
4
  # An Execution is created each time a method is called.
13
- # Multiple Refections are created per Execution.
14
- # These Reflections execute on a ShadowStack on cloned objects.
5
+ # Many Refections are created per Execution.
6
+ # Each Reflection executes on a ShadowStack on cloned data.
15
7
  # Then flow is returned to the original method and normal execution continues.
16
8
  #
17
9
  # Usage:
18
- #
19
10
  # class ExampleClass
20
11
  # prepend Reflekt
21
12
  ################################################################################
22
13
 
23
- module Reflekt
24
-
25
- # The amount of reflections to create per method call.
26
- @@reflekt_reflect_amount = 2
14
+ require 'set'
15
+ require 'erb'
16
+ require 'rowdb'
17
+ require 'Accessor'
18
+ require 'Control'
19
+ require 'Execution'
20
+ require 'Reflection'
21
+ require 'Renderer'
22
+ require 'Ruler'
23
+ require 'ShadowStack'
27
24
 
28
- # Limit the amount of reflections that can be created per instance method.
29
- # A method called thousands of times doesn't need that many reflections.
30
- @@reflection_limit = 10
25
+ module Reflekt
31
26
 
32
27
  def initialize(*args)
33
28
 
34
- @reflection_counts = {}
29
+ @reflekt_counts = {}
35
30
 
36
31
  # Get instance methods.
37
32
  # TODO: Include parent methods like "Array.include?".
@@ -40,23 +35,24 @@ module Reflekt
40
35
  # Don't process skipped methods.
41
36
  next if self.class.reflekt_skipped?(method)
42
37
 
43
- @reflection_counts[method] = 0
38
+ @reflekt_counts[method] = 0
44
39
 
45
40
  # When method called in flow.
46
41
  self.define_singleton_method(method) do |*args|
47
42
 
48
43
  # Don't reflect when limit reached.
49
- unless @reflection_counts[method] >= @@reflection_limit
44
+ unless @reflekt_counts[method] >= @@reflekt.reflect_limit
50
45
 
51
46
  # Get current execution.
52
- execution = @@reflekt_stack.peek()
47
+ execution = @@reflekt.stack.peek()
53
48
 
54
49
  # When stack empty or past execution done reflecting.
55
50
  if execution.nil? || execution.has_finished_reflecting?
56
51
 
57
52
  # Create execution.
58
- execution = Execution.new(self, @@reflekt_reflect_amount)
59
- @@reflekt_stack.push(execution)
53
+ execution = Execution.new(self, method, @@reflekt.reflect_amount, @@reflekt.stack)
54
+
55
+ @@reflekt.stack.push(execution)
60
56
 
61
57
  end
62
58
 
@@ -66,47 +62,43 @@ module Reflekt
66
62
  if execution.has_empty_reflections? && !execution.is_reflecting?
67
63
  execution.is_reflecting = true
68
64
 
69
- class_name = execution.caller_class.to_s
70
- method_name = method.to_s
71
-
72
65
  # Create control.
73
- control = Control.new(execution, method, true)
66
+ control = Control.new(execution, 1, @@reflekt.ruler)
74
67
  execution.control = control
75
68
 
76
69
  # Execute control.
77
70
  control.reflect(*args)
78
71
 
79
72
  # Save control.
80
- @@reflekt_db.get("#{class_name}.#{method_name}.controls").push(control.result())
73
+ @@reflekt.db.get("controls").push(control.result())
81
74
 
82
75
  # Multiple reflections per execution.
83
76
  execution.reflections.each_with_index do |value, index|
84
77
 
85
78
  # Create reflection.
86
- reflection = Reflection.new(execution, method, false)
79
+ reflection = Reflection.new(execution, index + 1, @@reflekt.ruler)
87
80
  execution.reflections[index] = reflection
88
81
 
89
82
  # Execute reflection.
90
83
  reflection.reflect(*args)
84
+ @reflekt_counts[method] = @reflekt_counts[method] + 1
91
85
 
92
86
  # Save reflection.
93
- @@reflekt_db.get("#{class_name}.#{method_name}.reflections").push(reflection.result())
87
+ @@reflekt.db.get("reflections").push(reflection.result())
94
88
 
95
89
  end
96
90
 
97
91
  # Save results.
98
- @@reflekt_db.write()
92
+ @@reflekt.db.write()
99
93
 
100
94
  # Render results.
101
- reflekt_render()
95
+ @@reflekt.renderer.render()
102
96
 
103
97
  execution.is_reflecting = false
104
98
  end
105
99
 
106
100
  end
107
101
 
108
- @reflection_counts[method] = @reflection_counts[method] + 1
109
-
110
102
  # Continue execution / shadow execution.
111
103
  super *args
112
104
 
@@ -119,42 +111,17 @@ module Reflekt
119
111
 
120
112
  end
121
113
 
122
- ##
123
- # Render results.
124
- ##
125
- def reflekt_render()
126
-
127
- # Get JSON.
128
- @@reflekt_json = File.read("#{@@reflekt_output_path}/db.json")
129
-
130
- # Save HTML.
131
- template = File.read("#{@@reflekt_path}/web/template.html.erb")
132
- rendered = ERB.new(template).result(binding)
133
- File.open("#{@@reflekt_output_path}/index.html", 'w+') do |f|
134
- f.write rendered
135
- end
136
-
137
- # Add JS.
138
- javascript = File.read("#{@@reflekt_path}/web/script.js")
139
- File.open("#{@@reflekt_output_path}/script.js", 'w+') do |f|
140
- f.write javascript
141
- end
142
-
143
- # Add CSS.
144
- stylesheet = File.read("#{@@reflekt_path}/web/style.css")
145
- File.open("#{@@reflekt_output_path}/style.css", 'w+') do |f|
146
- f.write stylesheet
147
- end
148
-
149
- end
150
-
151
114
  private
152
115
 
153
116
  def self.prepended(base)
117
+
154
118
  # Prepend class methods to the instance's singleton class.
155
119
  base.singleton_class.prepend(SingletonClassMethods)
156
120
 
157
- @@reflekt_setup ||= reflekt_setup_class
121
+ # Setup class.
122
+ @@reflekt = Accessor.new()
123
+ @@reflekt.setup ||= reflekt_setup_class
124
+
158
125
  end
159
126
 
160
127
  # Setup class.
@@ -165,26 +132,58 @@ module Reflekt
165
132
  $ENV[:reflekt] ||= $ENV[:reflekt] = {}
166
133
 
167
134
  # Set configuration.
168
- @@reflekt_path = File.dirname(File.realpath(__FILE__))
135
+ @@reflekt.path = File.dirname(File.realpath(__FILE__))
169
136
 
170
- # Create reflection tree.
171
- @@reflekt_stack = ShadowStack.new()
172
-
173
- # Build reflections directory.
137
+ # Get reflections directory path from config.
174
138
  if $ENV[:reflekt][:output_path]
175
- @@reflekt_output_path = File.join($ENV[:reflekt][:output_path], 'reflections')
176
- # Build reflections directory in current execution path.
139
+ @@reflekt.output_path = File.join($ENV[:reflekt][:output_path], 'reflections')
140
+ # Get reflections directory path from current execution path.
177
141
  else
178
- @@reflekt_output_path = File.join(Dir.pwd, 'reflections')
142
+ @@reflekt.output_path = File.join(Dir.pwd, 'reflections')
179
143
  end
144
+
180
145
  # Create reflections directory.
181
- unless Dir.exist? @@reflekt_output_path
182
- Dir.mkdir(@@reflekt_output_path)
146
+ unless Dir.exist? @@reflekt.output_path
147
+ Dir.mkdir(@@reflekt.output_path)
183
148
  end
184
149
 
185
150
  # Create database.
186
- @@reflekt_db = Rowdb.new(@@reflekt_output_path + '/db.json')
187
- @@reflekt_db.defaults({ :reflekt => { :api_version => 1 }}).write()
151
+ @@reflekt.db = Rowdb.new(@@reflekt.output_path + '/db.js')
152
+ @@reflekt.db.defaults({ :reflekt => { :api_version => 1 }})
153
+
154
+ # Create shadow execution stack.
155
+ @@reflekt.stack = ShadowStack.new()
156
+
157
+ # Create rules.
158
+ @@reflekt.ruler = Ruler.new()
159
+ # TODO: Fix Rowdb.get(path) not returning values at path after Rowdb.push()?
160
+ values = @@reflekt.db.value()
161
+ values.each do |klass, class_values|
162
+
163
+ class_values.each do |method_name, method_items|
164
+ next if method_items.nil?
165
+ next unless method_items.class == Hash
166
+ if method_items.key? "controls"
167
+
168
+ method = method_name.to_sym
169
+
170
+ @@reflekt.ruler.load(klass, method, method_items['controls'])
171
+ @@reflekt.ruler.train(klass, method)
172
+
173
+ end
174
+ end
175
+
176
+ end
177
+
178
+ # The amount of reflections to create per method call.
179
+ @@reflekt.reflect_amount = 2
180
+
181
+ # Limit the amount of reflections that can be created per instance method.
182
+ # A method called thousands of times doesn't need that many reflections.
183
+ @@reflekt.reflect_limit = 10
184
+
185
+ # Create renderer.
186
+ @@reflekt.renderer = Renderer.new(@@reflekt.path, @@reflekt.output_path)
188
187
 
189
188
  return true
190
189
  end
@@ -208,7 +207,7 @@ module Reflekt
208
207
  end
209
208
 
210
209
  def reflekt_limit(amount)
211
- @@reflection_limit = amount
210
+ @@reflekt.reflect_limit = amount
212
211
  end
213
212
 
214
213
  end