reflekt 0.9.1 → 0.9.7

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: 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