<commit_before>module Clockwork
  class Event
    attr_accessor :job, :last

    def initialize(manager, period, job, block, options={})
      @manager = manager
      @period = period
      @job = job
      @at = At.parse(options[:at])
      @last = nil
      @block = block
      @if = options[:if]
      @thread = options[:thread]
      @timezone = options[:tz]
    end

    def to_s
      @job
    end

    def convert_timezone(t)
      @timezone ? t.in_time_zone(@timezone) : t
    end

    def time?(t)
      t = convert_timezone(t)
      elapsed_ready = (@last.nil? or (t - @last).to_i >= @period)
      elapsed_ready and (@at.nil? or @at.ready?(t)) and (@if.nil? or @if.call(t))
    end

    def thread?
      @thread
    end

    def run(t)
      t = convert_timezone(t)
      @last = t

      if thread?
        if @manager.thread_available?
          Thread.new { execute }
        else
          log_error "Threads exhausted; skipping #{self}"
        end
      else
        execute
      end
    end

    def execute
      @block.call(@job)
    rescue => e
      log_error e
      handle_error e
    end

    def log_error(e)
      @manager.config[:logger].error(e)
    end

    def exception_message(e)
      msg = [ "Exception #{e.class} -> #{e.message}" ]

      base = File.expand_path(Dir.pwd) + '/'
      e.backtrace.each do |t|
        msg << "   #{File.expand_path(t).gsub(/#{base}/, '')}"
      end

      msg.join("\n")
    end

    def handle_error(e)
      if @manager.get_error_handler
        @manager.get_error_handler.call(e)
      end
    end
  end
end<commit_msg>Memoize error handler<commit_after>module Clockwork
  class Event
    attr_accessor :job, :last

    def initialize(manager, period, job, block, options={})
      @manager = manager
      @period = period
      @job = job
      @at = At.parse(options[:at])
      @last = nil
      @block = block
      @if = options[:if]
      @thread = options[:thread]
      @timezone = options[:tz]
    end

    def to_s
      @job
    end

    def convert_timezone(t)
      @timezone ? t.in_time_zone(@timezone) : t
    end

    def time?(t)
      t = convert_timezone(t)
      elapsed_ready = (@last.nil? or (t - @last).to_i >= @period)
      elapsed_ready and (@at.nil? or @at.ready?(t)) and (@if.nil? or @if.call(t))
    end

    def thread?
      @thread
    end

    def run(t)
      t = convert_timezone(t)
      @last = t

      if thread?
        if @manager.thread_available?
          Thread.new { execute }
        else
          log_error "Threads exhausted; skipping #{self}"
        end
      else
        execute
      end
    end

    def execute
      @block.call(@job)
    rescue => e
      log_error e
      handle_error e
    end

    def log_error(e)
      @manager.config[:logger].error(e)
    end

    def exception_message(e)
      msg = [ "Exception #{e.class} -> #{e.message}" ]

      base = File.expand_path(Dir.pwd) + '/'
      e.backtrace.each do |t|
        msg << "   #{File.expand_path(t).gsub(/#{base}/, '')}"
      end

      msg.join("\n")
    end

    def handle_error(e)
      if handler = @manager.get_error_handler
        handler.call(e)
      end
    end
  end
end
{'fraction_non_alphanumeric': 0.12645120803263257, 'fraction_numerical': 0.0, 'mean_word_length': 1.8929219600725953, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, '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': '2812170', 'n_tokens_mistral': 1096, 'n_tokens_neox': 1077, 'n_words': 258}