Skip to content

Commit

Permalink
Handle no args/inputs. Handle control fail. Fix cloning bug.
Browse files Browse the repository at this point in the history
  • Loading branch information
maedi committed Dec 2, 2020
1 parent a3b1d48 commit 7333050
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 104 deletions.
2 changes: 2 additions & 0 deletions lib/Accessor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class Accessor
attr_accessor :renderer
attr_accessor :path
attr_accessor :output_path
attr_accessor :control_failed

def initialize()

Expand All @@ -29,6 +30,7 @@ def initialize()
@renderer = nil
@path = nil
@output_path = nil
@control_failed = false

end

Expand Down
1 change: 1 addition & 0 deletions lib/Aggregator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def initialize(meta_map)

@meta_map = meta_map
# Key rule sets by class and method.
# TODO: Possible bug "@rule_sets={nil=>{nil=>{:output=>#<RuleSet..."
@rule_sets = {}

end
Expand Down
6 changes: 5 additions & 1 deletion lib/Clone.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
# A clone of the instance that a reflection calls methods on,
# as well as any other instances that those methods may lead to.
#
# @note
# Not currently in use due to bug where "send" needs to be called directly
# on object, not indirectly through clone which results in "undefined method".
#
# @hierachy
# 1. Execution
# 2. Reflection
Expand All @@ -20,7 +24,7 @@ def initialize(execution)

end

def call(method, *new_args)
def action(method, *new_args)
@caller_object_clone.send(method, *new_args)
end

Expand Down
3 changes: 2 additions & 1 deletion lib/Config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ class Config
def initialize()

# The amount of reflections to create per method call.
@reflect_amount = 2
# A control reflection is created in addition to this.
@reflect_amount = 5

# The maximum amount of reflections that can be created per instance/method.
# A method called thousands of times doesn't need that many reflections.
Expand Down
37 changes: 6 additions & 31 deletions lib/Control.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,6 @@

class Control < Reflection

##
# Reflect on a method.
#
# Creates a shadow execution stack.
#
# @param method [Symbol] The name of the method.
# @param *args [Args] The method arguments.
# @return [Hash] A reflection hash.
##
def reflect(*args)

# Create metadata for each argument.
@inputs = MetaBuilder.create_many(args)

# Action method with new arguments.
begin
output = @clone.send(@method, *args)
# When fail.
rescue StandardError => message
@status = :fail
@message = message
# When pass.
else
@status = :pass
end

end

##
# Get the results of the control reflection.
#
Expand All @@ -63,11 +35,14 @@ def result()
:method => @method,
:status => @status,
:message => @message,
:inputs => [],
:inputs => nil,
:output => @output,
}
@inputs.each do |meta|
control[:inputs] << meta.result()
unless @inputs.nil?
control[:inputs] = []
@inputs.each do |meta|
control[:inputs] << meta.result()
end
end

return control
Expand Down
6 changes: 3 additions & 3 deletions lib/Execution.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ class Execution
#
# @param object [Object] The calling object.
# @param method [Symbol] The calling method.
# @param number [Integer] The number of reflections to create per execution.
# @param reflect_amount [Integer] The number of reflections to create per execution.
# @param stack [ShadowStack] The shadow execution call stack.
##
def initialize(caller_object, method, number, stack)
def initialize(caller_object, method, reflect_amount, stack)

@time = Time.now.to_i
@unique_id = @time + rand(1..99999)
Expand All @@ -51,7 +51,7 @@ def initialize(caller_object, method, number, stack)

# Reflections.
@control = nil
@reflections = Array.new(number)
@reflections = Array.new(reflect_amount)

# State.
if @stack.peek() == nil
Expand Down
46 changes: 29 additions & 17 deletions lib/Reflection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

class Reflection

attr_reader :status

##
# Create a Reflection.
#
Expand All @@ -36,49 +38,56 @@ def initialize(execution, number, aggregator)
@method = execution.method

# Metadata.
@inputs = []
@inputs = nil
@output = nil

# Clone the execution's calling object.
@clone = Clone.new(execution)
@clone_id = nil
# TODO: Abstract away into Clone class.
@clone = execution.caller_object.clone

# Result.
@status = :pass
@time = Time.now.to_i
@message = nil

end

##
# Reflect on a method.
#
# Creates a shadow execution stack.
# Creates a shadow execution.
# @param *args [Dynamic] The method's arguments.
##
def reflect(*args)

# Get aggregated RuleSets.
agg_input_rule_sets = @aggregator.get_input_rule_sets(@klass, @method)
agg_output_rule_set = @aggregator.get_output_rule_set(@klass, @method)
# Get arguments.
new_args = []
unless args.size == 0

# Get aggregated RuleSets.
agg_input_rule_sets = @aggregator.get_input_rule_sets(@klass, @method)
agg_output_rule_set = @aggregator.get_output_rule_set(@klass, @method)

# Create random arguments.
new_args = randomize(args)
# Create random arguments.
new_args = randomize(args)

# Create metadata for each argument.
@inputs = MetaBuilder.create_many(new_args)
# Create metadata for each argument.
@inputs = MetaBuilder.create_many(new_args)

end

# Action method with new arguments.
begin

# Validate input with aggregated control RuleSets.
unless agg_input_rule_sets.nil?
# Validate inputs against aggregated control RuleSets.
unless args.size == 0 || agg_input_rule_sets.nil?
unless @aggregator.validate_inputs(new_args, agg_input_rule_sets)
@status = :fail
end
end

# Run reflection.
output = @clone.call(@method, *new_args)
output = @clone.send(@method, *new_args)
@output = MetaBuilder.create(output)

# Validate output with aggregated control RuleSets.
Expand Down Expand Up @@ -143,11 +152,14 @@ def result()
:method => @method,
:status => @status,
:message => @message,
:inputs => [],
:inputs => nil,
:output => @output,
}
@inputs.each do |meta|
reflection[:inputs] << meta.result()
unless @inputs.nil?
reflection[:inputs] = []
@inputs.each do |meta|
reflection[:inputs] << meta.result()
end
end

return reflection
Expand Down
107 changes: 61 additions & 46 deletions lib/Reflekt.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ module Reflekt

def initialize(*args)

# TODO: Store counts on @@reflekt and key by instance ID.
@reflekt_counts = {}

# Get child and parent instance methods.
Expand All @@ -49,74 +50,88 @@ def initialize(*args)
# When method called in flow.
self.define_singleton_method(method) do |*args|

# Get current execution.
execution = @@reflekt.stack.peek()
# Don't reflect further if the control reflection fails.
unless @@reflekt.control_failed

# Don't reflect when reflect limit reached or method skipped.
unless (@reflekt_counts[method] >= @@reflekt.config.reflect_limit) || self.class.reflekt_skipped?(method)
# Get current execution.
execution = @@reflekt.stack.peek()

# When stack empty or past execution done reflecting.
if execution.nil? || execution.has_finished_reflecting?
# Don't reflect when reflect limit reached or method skipped.
unless (@reflekt_counts[method] >= @@reflekt.config.reflect_limit) || self.class.reflekt_skipped?(method)

# Create execution.
execution = Execution.new(self, method, @@reflekt.config.reflect_amount, @@reflekt.stack)
# When stack empty or past execution done reflecting.
if execution.nil? || execution.has_finished_reflecting?

@@reflekt.stack.push(execution)
# Create execution.
execution = Execution.new(self, method, @@reflekt.config.reflect_amount, @@reflekt.stack)

end
@@reflekt.stack.push(execution)

##
# Reflect the execution.
#
# The first method call in the Execution creates a Reflection.
# Subsequent method calls are shadow executions on cloned objects.
##
if execution.has_empty_reflections? && !execution.is_reflecting?
execution.is_reflecting = true
end

# Create control.
control = Control.new(execution, 1, @@reflekt.aggregator)
execution.control = control
##
# Reflect the execution.
#
# The first method call in the Execution creates a Reflection.
# Subsequent method calls are shadow executions on cloned objects.
##
if execution.has_empty_reflections? && !execution.is_reflecting?
execution.is_reflecting = true

# Execute control.
control.reflect(*args)
# Create control.
control = Control.new(execution, 0, @@reflekt.aggregator)
execution.control = control

# Save control.
@@reflekt.db.get("controls").push(control.result())
# Execute control.
control.reflect(*args)
if control.status == :fail
@@reflekt.control_failed = true
else

# Multiple reflections per execution.
execution.reflections.each_with_index do |value, index|
# Multiple reflections per execution.
execution.reflections.each_with_index do |value, index|

# Create reflection.
reflection = Reflection.new(execution, index + 1, @@reflekt.aggregator)
execution.reflections[index] = reflection
# Create reflection.
reflection = Reflection.new(execution, index + 1, @@reflekt.aggregator)
execution.reflections[index] = reflection

# Execute reflection.
reflection.reflect(*args)
@reflekt_counts[method] = @reflekt_counts[method] + 1
# Execute reflection.
reflection.reflect(*args)
@reflekt_counts[method] = @reflekt_counts[method] + 1

# Save reflection.
@@reflekt.db.get("reflections").push(reflection.result())
# Save reflection.
@@reflekt.db.get("reflections").push(reflection.result())

end
end

# Save control.
@@reflekt.db.get("controls").push(control.result())

# Save results.
@@reflekt.db.write()

# Save results.
@@reflekt.db.write()
# Render results.
@@reflekt.renderer.render()

end

# Render results.
@@reflekt.renderer.render()
execution.is_reflecting = false
end

execution.is_reflecting = false
end

end
# Don't execute skipped methods when reflecting.
unless execution.is_reflecting? && self.class.reflekt_skipped?(method)

# Don't execute skipped methods when reflecting.
unless execution.is_reflecting? && self.class.reflekt_skipped?(method)
# Continue execution / shadow execution.
super *args

# Continue execution / shadow execution.
super *args
end

# Continue execution when control fails.
else
# Execute error producing code.
super *args
end

end
Expand Down
10 changes: 5 additions & 5 deletions lib/web/bundle.js

Large diffs are not rendered by default.

0 comments on commit 7333050

Please sign in to comment.