<commit_before>require_relative "thread_attr_accessor/version"
require_relative 'core_ext/thread/parent_thread'

# `extend` this module on your class/module to get per-thread class attribute
# accessors. Example:
#
# class MyClass
#   extend ThreadAttrAccessor
#
#   thread_attr_accessor :setting
# end
#
# MyClass.setting = :original
#
# threads = [
#   Thread.new { MyClass.setting = :foo; puts MyClass.setting },
#   Thread.new { MyClass.setting = :bar; puts MyClass.setting },
# ]
#
# threads.each(&:join)
# MyClass.setting == :original # true
module ThreadAttrAccessor
  def self.thread_accessor_key(base, name)
    "#{base.name}.#{name}"
  end

  def self.search_in_ancestor_threads(key)
    ancestor = Thread.current.parent_thread

    until ancestor.nil? || (ancestor_value = ancestor[key])
      ancestor = ancestor.parent_thread
    end

    ancestor_value
  end

  def self.extended(base)
    mod = Module.new

    unless base.const_defined?(:ThreadAttributeAccessors, false)
      base.const_set(:ThreadAttributeAccessors, mod)
      base.extend(mod)
    end
  end

  def thread_attr_writer(*names, private: false, **opts)
    mod = const_get(:ThreadAttributeAccessors)

    names.each do |name|
      thread_key = ThreadAttrAccessor.thread_accessor_key(self, name)

      mod.send(:define_method, "#{name}=") do |value|
        Thread.current.thread_variable_set(thread_key, value)
      end

      if private
        mod.send :private, "#{name}="
      end
    end
  end

  def thread_attr_reader(*names, default: nil, inherit: false, private: false, **opts)
    if default && inherit
      get_default = ->(thread_key) {
        ThreadAttrAccessor.search_in_ancestor_threads(thread_key) ||
        default.call
      }
    elsif inherit
      get_default = ThreadAttrAccessor.method(:search_in_ancestor_threads)
    elsif default
      get_default = ->(*) { default.call }
    end

    if get_default
      get_value = ->(thread_key) {
        if Thread.current.thread_variable?(thread_key)
          Thread.current.thread_variable_get(thread_key)
        else
          default_value = get_default.call(thread_key)
          Thread.current.thread_variable_set(thread_key, default_value)
        end<commit_msg>Work around ruby api weirdnessess<commit_after>require_relative "thread_attr_accessor/version"
require_relative 'core_ext/thread/parent_thread'

# `extend` this module on your class/module to get per-thread class attribute
# accessors. Example:
#
# class MyClass
#   extend ThreadAttrAccessor
#
#   thread_attr_accessor :setting
# end
#
# MyClass.setting = :original
#
# threads = [
#   Thread.new { MyClass.setting = :foo; puts MyClass.setting },
#   Thread.new { MyClass.setting = :bar; puts MyClass.setting },
# ]
#
# threads.each(&:join)
# MyClass.setting == :original # true
module ThreadAttrAccessor
  def self.thread_accessor_key(base, name)
    "#{base.name}.#{name}"
  end

  def self.search_in_ancestor_threads(key)
    ancestor = Thread.current.parent_thread

    until ancestor.nil? || (ancestor_value = ancestor.thread_variable_get(key))
      ancestor = ancestor.parent_thread
    end

    ancestor_value
  end

  def self.extended(base)
    mod = Module.new

    unless base.const_defined?(:ThreadAttributeAccessors, false)
      base.const_set(:ThreadAttributeAccessors, mod)
      base.extend(mod)
    end
  end

  def thread_attr_writer(*names, private: false, **opts)
    mod = const_get(:ThreadAttributeAccessors)

    names.each do |name|
      thread_key = ThreadAttrAccessor.thread_accessor_key(self, name)

      mod.send(:define_method, "#{name}=") do |value|
        Thread.current.thread_variable_set(thread_key, value)
      end

      if private
        mod.send :private, "#{name}="
      end
    end
  end

  def thread_attr_reader(*names, default: nil, inherit: false, private: false, **opts)
    if default && inherit
      get_default = ->(thread_key) {
        ThreadAttrAccessor.search_in_ancestor_threads(thread_key) ||
        default.call
      }
    elsif inherit
      get_default = ThreadAttrAccessor.method(:search_in_ancestor_threads)
    elsif default
      get_default = ->(*) { default.call }
    end

    if get_default
      get_value = ->(thread_key) {
        if value = Thread.current.thread_variable_get(thread_key)
          value
        else
          default_value = get_default.call(thread_key)
          Thread.current.thread_variable_set(thread_key, default_value)
          default_value
        end
{'fraction_non_alphanumeric': 0.10231832367365136, 'fraction_numerical': 0.0, 'mean_word_length': 3.394711067580803, 'pattern_counts': {'":': 0, '<': 3, '<?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': '2459556', 'n_tokens_mistral': 1416, 'n_tokens_neox': 1395, 'n_words': 283}