<commit_before>require 'payment_schedule/component'

module PaymentSchedule
  class Instruction
    attr_accessor :required_input
    attr_accessor :helpers
    attr_accessor :components

    # TODO: memoization

    def initialize
      self.required_input = []
      self.helpers        = {}
      self.components     = {}
    end

    def [](name, row_no = nil)
      row_no ? component_get(name, row_no) : helper_get(name)
    end

    def component_get(name, row_no)
      instance_exec(row_no, &components[name][row_no]) if components.key?(name)
    end

    def helper_get(name)
      instance_exec(&helpers[name]) if helpers.key?(name)
    end

    def require_input(*keys)
      self.required_input = keys
    end

    def helper(name, &definition)
      helpers[name] = definition
    end

    def component(name, &definition)
      component = Component.new(name)
      component.instance_eval(&definition)
      components[name] = component
    end
  end
end
<commit_msg>Implement memoization for Instruction#[]<commit_after>require 'payment_schedule/component'

module PaymentSchedule
  class Instruction
    attr_accessor :required_input
    attr_accessor :helpers
    attr_accessor :components
    attr_accessor :helper_memory
    attr_accessor :component_memory

    def initialize
      self.required_input   = []
      self.helpers          = {}
      self.components       = {}
      self.helper_memory    = {}
      self.component_memory = {}
    end

    def [](name, row_no = nil)
      row_no ? component_get(name, row_no) : helper_get(name)
    end

    def component_get(name, row_no)
      return unless components.key?(name)

      memory_key     = [name, row_no].join(':')
      memoized_value = component_memory[memory_key]
      return memoized_value if memoized_value

      component_memory[memory_key] = instance_exec(
        row_no,
        &components[name][row_no]
      )
    end

    def helper_get(name)
      return unless helpers.key?(name)

      memoized_value = helper_memory[name]
      return memoized_value if memoized_value

      helper_memory[name] = instance_exec(&helpers[name])
    end

    def require_input(*keys)
      self.required_input = keys
    end

    def helper(name, &definition)
      helpers[name] = definition
    end

    def component(name, &definition)
      component = Component.new(name)
      component.instance_eval(&definition)
      components[name] = component
    end
  end
end

{'fraction_non_alphanumeric': 0.08580723871492477, 'fraction_numerical': 0.0, 'mean_word_length': 2.8679245283018866, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5813136', 'n_tokens_mistral': 743, 'n_tokens_neox': 733, 'n_words': 157}