<commit_before>require "shell_command/version"
require 'open3'

module ShellCommand

  class Exception < StandardError
  end

  #
  # @attr [Process::Status] status
  #   The status of the command.
  #
  # @attr [String] stderr
  #   The output written by the command to standard error.
  #
  # @attr [String] stdout
  #   The output written by the command to standard output.
  #
  class Command < Struct.new(:status, :stderr, :stdout)

    def method_missing method, *args, &block
      if status.respond_to?(method)
        status.send(method, *args, &block)
      else
        super
      end
    end

    def respond_to_missing? method, include_private = false
      status.respond_to?(method, include_private)
    end

  end

  #
  # @param [String] *args
  #   A command and its arguments to execute (if any).
  #
  # @yieldparam [ShellCommand::Command] command
  #   Yields {ShellCommand::Command} if a block is given.
  #
  # @return [ShellCommand::Command]
  #   Returns a {ShellCommand::Command}
  #
  def run *args
    if args.empty?
      raise ArgumentError, 'Wrong number of arguments (0 for 1)'
    end

    Open3.popen3(*args) do |_, stdout, stderr, thr|
      status  = thr.value
      command = Command.new(status, stderr.read, stdout.read)

      if block_given?
        yield(command)
      else
        command
      end
    end
  end
  module_function :run

  #
  # @param
  #   (see #run)
  #
  # @raise [ShellCommand::Exception]
  #   If the command is unsuccessful (e.g: > 0 exit status code)
  #
  # @return
  #   (see #run)
  #
  def run! *args
    command = run(*args)

    if command.success?<commit_msg>Don't read from streams unless they're asked for<commit_after>require "shell_command/version"
require 'open3'

module ShellCommand

  class Exception < StandardError
  end

  #
  # @attr [Process::Status] status
  #   The status of the command.
  #
  # @attr [String] stderr
  #   The output written by the command to standard error.
  #
  # @attr [String] stdout
  #   The output written by the command to standard output.
  #
  class Command

    def initialize status, stderr_stream, stdout_stream
      @stdout_stream = stdout_stream
      @stderr_stream = stderr_stream
      @status = status
    end

    def stdout
      @stdout_stream.read
    end

    def strerr
      @stderr_stream.read
    end

    def method_missing method, *args, &block
      if @status.respond_to?(method)
        @status.send(method, *args, &block)
      else
        super
      end
    end

    def respond_to_missing? method, include_private = false
      @status.respond_to?(method, include_private)
    end

  end

  #
  # @param [String] *args
  #   A command and its arguments to execute (if any).
  #
  # @yieldparam [ShellCommand::Command] command
  #   Yields {ShellCommand::Command} if a block is given.
  #
  # @return [ShellCommand::Command]
  #   Returns a {ShellCommand::Command}
  #
  def run *args
    if args.empty?
      raise ArgumentError, 'Wrong number of arguments (0 for 1)'
    end

    Open3.popen3(*args) do |_, stdout, stderr, thr|
      status  = thr.value
      command = Command.new(status, stderr, stdout)

      if block_given?
        yield(command)
      else
        command
      end
    end
  end
  module_function :run

  #
  # @param
  #   (see #run)
  #
  # @raise [ShellCommand::Exception]
  #   If the command is unsuccessful (e.g: > 0 exit status code)
  #
  # @return
  #   (see #run)
  #
  def run! *args
    command = run(*args)

    if command.success?
{'fraction_non_alphanumeric': 0.09721432632177374, 'fraction_numerical': 0.0034110289937464467, 'mean_word_length': 2.57258883248731, 'pattern_counts': {'":': 0, '<': 6, '<?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': '1960484', 'n_tokens_mistral': 1157, 'n_tokens_neox': 1125, 'n_words': 339}