<commit_before># encoding: utf-8

require "nake/colors"
require "nake/argv"

module Nake
  TaskNotFound ||= Class.new(StandardError)
  ConfigurationError ||= Class.new(StandardError)

  class Task
    def self.[](name)
      name = name.to_s
      self.tasks[name] || self.find_in_aliases(name)
    end

    # @private
    def self.find_in_aliases(name)
      _, task = self.tasks.find { |_, task| task.aliases.include?(name) }
      return task
    end

    def self.[]=(name, task)
      self.tasks[name.to_s] = task
    end

    # @protected use Task[name] resp. Task[name] = task
    def self.tasks
      @@tasks ||= Hash.new
    end

    # return existing task if task with given name already exist
    def self.new(name, *dependencies, &block)
      task = self[name]
      task && task.setup(*dependencies, &block) || super(name, *dependencies, &block)
    end

    attr_accessor :name, :description, :dependencies, :hidden, :original_args
    attr_reader :blocks, :aliases
    def initialize(name, *dependencies, &block)
      @aliases, @hidden = Array.new, false
      # This is a bit weird, but it's best solution
      # when we want to keep API simple and keep it
      # as one object even if it has more names
      if name.respond_to?(:join) # array
        name, *aliases = name
        self.aliases.push(*aliases)
      end
      @name, @blocks = name.to_sym, Array.new
      @dependencies  = Array.new
      self.register
      self.setup(*dependencies, &block)
    end

    def config
      @config ||= Hash.new do |hash, key|
        raise ConfigurationError, "Configuration key #{key} in task #{name} doesn't exist"
      end
    end

    def setup(*dependencies, &block)
      self.dependencies.push(*dependencies)
      self.instance_exec(self, &block) if block
      return self
    end

    def define(&block)
      @blocks.push(block)
    end

    def hidden?
      @hidden
    end

    def run(args)
      self.original_args = args
      opts = args.extend(ArgvParsingMixin).extract!
      self.call(args, opts)
    end

    # NOTE: the reason why we don't have splat for args is that when we have Task["-T"]
    # which doesn't have any args and options, we wall just call it without any arguments,
    # but when we use splat, then we will have to call it at least with Hash.new for options
    def call(args = Array.new, options = Hash.new)
      unless self.dependencies.empty?
        info "Invoking task #{name}"
        self.invoke_dependencies(*args, options)
      end
      unless self.blocks.empty?
        note "Executing task #{name} with arguments #{args.inspect} and options #{options.inspect}"
        self.blocks.each do |block|
          if block.arity.eql?(0)
            block.call
          else
            block.call(*args, options)
          end
        end
      end
    end

    def reset!
      self.dependencies.clear
      self.blocks.clear
      self.aliases.clear
    end<commit_msg>Refactored for new ARGV parsing<commit_after># encoding: utf-8

require "nake/colors"
require "nake/argv"

module Nake
  TaskNotFound ||= Class.new(StandardError)
  ConfigurationError ||= Class.new(StandardError)

  class Task
    def self.[](name)
      name = name.to_s
      self.tasks[name] || self.find_in_aliases(name)
    end

    # @private
    def self.find_in_aliases(name)
      _, task = self.tasks.find { |_, task| task.aliases.include?(name) }
      return task
    end

    def self.[]=(name, task)
      self.tasks[name.to_s] = task
    end

    # @protected use Task[name] resp. Task[name] = task
    def self.tasks
      @@tasks ||= Hash.new
    end

    # return existing task if task with given name already exist
    def self.new(name, *dependencies, &block)
      task = self[name]
      task && task.setup(*dependencies, &block) || super(name, *dependencies, &block)
    end

    attr_accessor :name, :description, :dependencies, :hidden, :original_args
    attr_reader :blocks, :aliases
    def initialize(name, *dependencies, &block)
      @aliases, @hidden = Array.new, false
      # This is a bit weird, but it's best solution
      # when we want to keep API simple and keep it
      # as one object even if it has more names
      if name.respond_to?(:join) # array
        name, *aliases = name
        self.aliases.push(*aliases)
      end
      @name, @blocks = name.to_sym, Array.new
      @dependencies  = Array.new
      self.register
      self.setup(*dependencies, &block)
    end

    def config
      @config ||= Hash.new do |hash, key|
        raise ConfigurationError, "Configuration key #{key} in task #{name} doesn't exist"
      end
    end

    def setup(*dependencies, &block)
      self.dependencies.push(*dependencies)
      self.instance_exec(self, &block) if block
      return self
    end

    def define(&block)
      @blocks.push(block)
    end

    def hidden?
      @hidden
    end

    def run(args)
      self.original_args = args
      self.call(args, ArgvParser.extract(args))
    end

    # NOTE: the reason why we don't have splat for args is that when we have Task["-T"]
    # which doesn't have any args and options, we wall just call it without any arguments,
    # but when we use splat, then we will have to call it at least with Hash.new for options
    def call(args = Array.new, options = Hash.new)
      unless self.dependencies.empty?
        info "Invoking task #{name}"
        self.invoke_dependencies(*args, options)
      end
      unless self.blocks.empty?
        note "Executing task #{name} with arguments #{args.inspect} and options #{options.inspect}"
        self.blocks.each do |block|
          if block.arity.eql?(0)
            block.call
          else
            block.call(*args, options)
          end
        end
      end
    end

    def reset!
      self.dependencies.clear
      self.blocks.clear
      self.aliases.clear
    end
{'fraction_non_alphanumeric': 0.10207907293796864, 'fraction_numerical': 0.0006816632583503749, 'mean_word_length': 2.430157802454705, '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': '3344188', 'n_tokens_mistral': 1807, 'n_tokens_neox': 1744, 'n_words': 553}