<commit_before>module Comprise
  class ListComprehension
    def initialize(lists)
      vars = lists.values
      enum = init_enum(vars.shift)

      @context    = Struct.new(*lists.keys)
      @enumerator = vars.inject(enum) do |enum, var|
        if var.respond_to? :call
          enum.flat_map { |other| @context.new(*other).instance_exec(&var).map { |x| other + [x] } }
        else
          enum.flat_map { |other| var.map { |x| other + [x] } }
        end
      end
    end

    def to_a
      @enumerator.to_a
    end

    def map
      @enumerator.map { |values| @context.new(*values).instance_exec(&Proc.new) }
    end

    def inspect
      "#<#{self.class.name}:#{self.object_id}>"
    end

    private
    def init_enum(var)
      var = var.respond_to?(:call) ? var.call : var
      var = var.lazy if var.respond_to? :lazy
      var.map { |x| [x] }
    end
  end
end

module Kernel
  def listcomp(lists)
    comprehension = Comprise::ListComprehension.new(lists)

    if block_given?
      comprehension.map(&Proc.new)
    else
      comprehension
    end
  end
end<commit_msg>More useful internal naming of variables & simplification of 'context' creation.<commit_after>module Comprise
  class ListComprehension
    def initialize(lists)
      values         = lists.values
      @context_klass = Struct.new(*lists.keys)
      @enumerator    = values.inject(init_enumerator(values.shift)) do |enumerator, enum_or_proc|
        if enum_or_proc.respond_to? :call
          enumerator.flat_map { |other| new_context(other).instance_exec(&enum_or_proc).map { |x| other + [x] } }
        else
          enumerator.flat_map { |other| enum_or_proc.map { |x| other + [x] } }
        end
      end
    end

    def to_a
      @enumerator.to_a
    end

    def map
      @enumerator.map { |values| new_context(values).instance_exec(&Proc.new) }
    end

    def inspect
      "#<#{self.class.name}:#{self.object_id}>"
    end

    private
    def new_context(values)
      @context_klass.new(*values)
    end

    def init_enumerator(enum_or_proc)
      enumerator = enum_or_proc.respond_to?(:call) ? enum_or_proc.call : enum_or_proc
      enumerator = enumerator.lazy if enumerator.respond_to? :lazy
      enumerator.map { |x| [x] }
    end
  end
end

module Kernel
  def listcomp(lists)
    comprehension = Comprise::ListComprehension.new(lists)

    if block_given?
      comprehension.map(&Proc.new)
    else
      comprehension
    end
  end
end
{'fraction_non_alphanumeric': 0.11074918566775244, 'fraction_numerical': 0.0, 'mean_word_length': 2.550578034682081, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, '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': '228141', 'n_tokens_mistral': 844, 'n_tokens_neox': 843, 'n_words': 174}