Module: Reflekt

Includes:
LitCLI
Defined in:
lib/meta.rb,
lib/rule.rb,
lib/clone.rb,
lib/action.rb,
lib/config.rb,
lib/control.rb,
lib/reflekt.rb,
lib/accessor.rb,
lib/renderer.rb,
lib/rule_set.rb,
lib/experiment.rb,
lib/reflection.rb,
lib/action_stack.rb,
lib/meta_builder.rb,
lib/meta/null_meta.rb,
lib/meta/array_meta.rb,
lib/meta/float_meta.rb,
lib/rules/null_rule.rb,
lib/meta/object_meta.rb,
lib/meta/string_meta.rb,
lib/rules/array_rule.rb,
lib/rules/float_rule.rb,
lib/meta/boolean_meta.rb,
lib/meta/integer_meta.rb,
lib/rules/object_rule.rb,
lib/rules/string_rule.rb,
lib/rules/boolean_rule.rb,
lib/rules/integer_rule.rb,
lib/rule_set_aggregator.rb

Overview

Track the actions in a shadow call stack.

Defined Under Namespace

Modules: SingletonClassMethods Classes: Accessor, Action, ActionStack, ArrayMeta, ArrayRule, BooleanMeta, BooleanRule, Clone, Config, Control, Experiment, FloatMeta, FloatRule, IntegerMeta, IntegerRule, Meta, MetaBuilder, NullMeta, NullRule, ObjectMeta, ObjectRule, Reflection, Renderer, Rule, RuleSet, RuleSetAggregator, StringMeta, StringRule

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.configure {|@@reflekt.config| ... } ⇒ Object

Configure Config singleton.

Yields:

  • (@@reflekt.config)

172
173
174
175
176
# File 'lib/reflekt.rb', line 172

def self.configure
  reflekt_setup_class()

  yield(@@reflekt.config)
end

.count(klass, method) ⇒ Object


159
160
161
162
# File 'lib/reflekt.rb', line 159

def self.count(klass, method)
  count = @@reflekt.counts.dig(klass.object_id, method) || 0
  count
end

.get_methods(klass) ⇒ Object

Get child and parent instance methods.

TODO: Include methods from all ancestors. TODO: Include core methods like β€œArray.include?”.


62
63
64
65
66
67
# File 'lib/reflekt.rb', line 62

def self.get_methods(klass)
  child_instance_methods = klass.class.instance_methods(false)
  parent_instance_methods = klass.class.superclass.instance_methods(false)

  return child_instance_methods + parent_instance_methods
end

.increase_count(klass, method) ⇒ Object


164
165
166
167
# File 'lib/reflekt.rb', line 164

def self.increase_count(klass, method)
  caller_id = klass.object_id
  @@reflekt.counts[caller_id][method] = @@reflekt.counts[caller_id][method] + 1
end

.override_method(klass, method) ⇒ Object

Override a method.

Parameters:

  • klass (Dynamic)

    The class to override.

  • method (Method)

    The method to override.


75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/reflekt.rb', line 75

def self.override_method(klass, method)
  klass.define_singleton_method(method) do |*args|

    # When method called in flow.
    if @reflekt_initialized

      ##
      # Reflect-Execute loop.
      #
      # Reflect each method before finally executing it.
      #
      # @loop
      #   1. The first method call creates an action
      #   2. The action creates reflections and calls the method again
      #   3. Subsequent method calls execute these reflections
      #   4. Each reflection executes on cloned data
      #   5. The original method call completes execution
      #
      # @see https://reflekt.dev/docs/reflect-execute-loop
      ##

      unless @@reflekt.error

        action = @@reflekt.stack.peek()

        # New action when old action done reflecting.
        if action.nil? || action.has_finished_loop?
          πŸ”₯"^ Create action for #{method}()", :info, :action, klass.class
          action = Action.new(klass, method, @@reflekt.config, @@reflekt.db, @@reflekt.stack, @@reflekt.aggregator)
          @@reflekt.stack.push(action)
        end

        ##
        # REFLECT
        ##

        unless action.is_reflecting? && klass.class.reflekt_skipped?(method) || Reflekt.count(klass, method) >= @@reflekt.config.reflect_limit
          unless action.is_actioned?
            action.is_actioned = true
            action.is_reflecting = true

            action.reflect(*args)
            if action.control.status == :error
              @@reflekt.error = action.control.message
            end

            # Render results.
            @@reflekt.renderer.render()

            action.is_reflecting = false
          end
        else
          πŸ”₯"> Skip reflection of #{method}()", :skip, :reflect, klass.class
        end

        ##
        # EXECUTE
        ##

        unless action.is_reflecting? && klass.class.reflekt_skipped?(method)
          πŸ”₯"> Execute #{method}()", :info, :execute, klass.class
          super *args
        end

      # Finish execution if control encounters unrecoverable error.
      else
        πŸ”₯"Reflection error, finishing original execution...", :error, :reflect, klass.class
        super *args
      end

    # When method called in constructor.
    else
      p "Reflection unsupported in constructor for #{method}()", :info, :setup, klass.class
      super *args
    end
  end
end

.setup_count(klass, method) ⇒ Object


153
154
155
156
157
# File 'lib/reflekt.rb', line 153

def self.setup_count(klass, method)
  caller_id = klass.object_id
  @@reflekt.counts[caller_id] = {} unless @@reflekt.counts.has_key? caller_id
  @@reflekt.counts[caller_id][method] = 0 unless @@reflekt.counts[caller_id].has_key? method
end

Instance Method Details

#initialize(*args) ⇒ Object

Setup Reflekt per class. Override methods on class instantiation.


37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/reflekt.rb', line 37

def initialize(*args)
  if @@reflekt.config.enabled
    @reflekt_initialized = false

    πŸ”₯"Initialize", :info, :setup, self.class

    # Override methods.
    Reflekt.get_methods(self).each do |method|
      Reflekt.setup_count(self, method)
      Reflekt.override_method(self, method)
    end

    @reflekt_initialized = true
  end

  # Continue initialization.
  super
end