<commit_before>#####
# = LICENSE
#
# Copyright 2012 <NAME> Licensed under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#

require 'thread'
require 'ruby_expect/procedure'
require 'pty'

#####
#
#
module RubyExpect
  #####
  # This is the main class used to interact with IO objects An Expect object can
  # be used to send and receive data on any read/write IO object.
  #
  class Expect
    # Any data that was in the accumulator buffer before match in the last expect call
    # if the last call to expect resulted in a timeout, then before is an empty string
    attr_reader :before

    # The exact string that matched in the last expect call
    attr_reader :match

    # The MatchData object from the last expect call or nil upon a timeout
    attr_reader :last_match

    # The accumulator buffer populated by read_loop.  Only access this if you really
    # know what you are doing!
    attr_reader :buffer

    #####
    # Create a new Expect object for the given IO object
    #
    # There are two ways to create a new Expect object.  The first is to supply
    # a single IO object with a read/write mode.  The second method is to supply
    # a read file handle as the first argument and a write file handle as the
    # second argument.
    #
    # +args+::
    #   at most 3 arguments, 1 or 2 IO objects (read/write or read + write and
    #   an optional options hash.  The only currently supported option is :debug
    #   (default false) which, if enabled, will send data received on the input
    #   filehandle to STDOUT
    #
    # +block+::
    #   An optional block called upon initialization.  See procedure
    #
    # == Examples
    #
    #   # expect with a read/write filehandle
    #   exp = Expect.new(rwfh)
    #
    #   # expect with separate read and write filehandles
    #   exp = Expect.new(rfh, wfh)
    #
    #   # turning on debugging
    #   exp = Expect.new(rfh, wfh, :debug => true)
    #
    def initialize *args, &block
      options = {}
      if (args.last.is_a?(Hash))
        options = args.pop
      end

      raise ArgumentError("First argument must be an IO object") unless (args[0].is_a?(IO))
      if (args.size == 1)
        @write_fh = args.shift
        @read_fh = @write_fh
      elsif (args.size == 2)
        raise ArgumentError("Second argument must be an IO object") unless (args[1].is_a?(IO))
        @write_fh = args.shift
        @read_fh = args.shift
      else
        raise ArgumentError.new("either specify a read/write IO object, or a read IO object and a write IO object")
      end
      
      raise "Input file handle is not readable!" unless (@read_fh.stat.readable?)
      raise "Output file handle is not writable!" unless (@write_fh.stat.writable?)

      @buffer_sem = Mutex.new
      @buffer_cv = ConditionVariable.new
      @debug = options[:debug] || false
      @buffer = ''
      @before = ''
      @match = ''
      @timeout = 0

      read_loop # start the read thread

      unless (block.nil?)
        procedure(&block)
      end
    end

    #####
    # Spawn a command and interact with it
    #
    # +command+::
    #   The command to execute
    #
    # +block+::
    #   Optional block to call and run a procedure in
    #
    def self.spawn command, &block
      shell_in, shell_out = PTY.spawn(command)
      return RubyExpect::Expect.new(shell_out, shell_in, &block)
    end

    #####
    # Perform a series of 'expects' using the DSL defined in Procedure
    #
    # +block+::
    #   The block will be called in the context of a new Procedure object
    #
    # == Example
    #
    #    exp = Expect.new(io)
    #    exp.procedure do
    #     each do
    #       expect /first expected line/ do
    #         send "some text to send"
    #       end
    #
    #       expect /second expected line/ do<commit_msg>Added options argument to spawn method<commit_after>#####
# = LICENSE
#
# Copyright 2012 <NAME> Licensed under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#

require 'thread'
require 'ruby_expect/procedure'
require 'pty'

#####
#
#
module RubyExpect
  #####
  # This is the main class used to interact with IO objects An Expect object can
  # be used to send and receive data on any read/write IO object.
  #
  class Expect
    # Any data that was in the accumulator buffer before match in the last expect call
    # if the last call to expect resulted in a timeout, then before is an empty string
    attr_reader :before

    # The exact string that matched in the last expect call
    attr_reader :match

    # The MatchData object from the last expect call or nil upon a timeout
    attr_reader :last_match

    # The accumulator buffer populated by read_loop.  Only access this if you really
    # know what you are doing!
    attr_reader :buffer

    #####
    # Create a new Expect object for the given IO object
    #
    # There are two ways to create a new Expect object.  The first is to supply
    # a single IO object with a read/write mode.  The second method is to supply
    # a read file handle as the first argument and a write file handle as the
    # second argument.
    #
    # +args+::
    #   at most 3 arguments, 1 or 2 IO objects (read/write or read + write and
    #   an optional options hash.  The only currently supported option is :debug
    #   (default false) which, if enabled, will send data received on the input
    #   filehandle to STDOUT
    #
    # +block+::
    #   An optional block called upon initialization.  See procedure
    #
    # == Examples
    #
    #   # expect with a read/write filehandle
    #   exp = Expect.new(rwfh)
    #
    #   # expect with separate read and write filehandles
    #   exp = Expect.new(rfh, wfh)
    #
    #   # turning on debugging
    #   exp = Expect.new(rfh, wfh, :debug => true)
    #
    def initialize *args, &block
      options = {}
      if (args.last.is_a?(Hash))
        options = args.pop
      end

      raise ArgumentError("First argument must be an IO object") unless (args[0].is_a?(IO))
      if (args.size == 1)
        @write_fh = args.shift
        @read_fh = @write_fh
      elsif (args.size == 2)
        raise ArgumentError("Second argument must be an IO object") unless (args[1].is_a?(IO))
        @write_fh = args.shift
        @read_fh = args.shift
      else
        raise ArgumentError.new("either specify a read/write IO object, or a read IO object and a write IO object")
      end
      
      raise "Input file handle is not readable!" unless (@read_fh.stat.readable?)
      raise "Output file handle is not writable!" unless (@write_fh.stat.writable?)

      @buffer_sem = Mutex.new
      @buffer_cv = ConditionVariable.new
      @debug = options[:debug] || false
      @buffer = ''
      @before = ''
      @match = ''
      @timeout = 0

      read_loop # start the read thread

      unless (block.nil?)
        procedure(&block)
      end
    end

    #####
    # Spawn a command and interact with it
    #
    # +command+::
    #   The command to execute
    #
    # +block+::
    #   Optional block to call and run a procedure in
    #
    def self.spawn command, options = {}, &block
      shell_in, shell_out = PTY.spawn(command)
      return RubyExpect::Expect.new(shell_out, shell_in, options, &block)
    end

    #####
    # Perform a series of 'expects' using the DSL defined in Procedure
    #
    # +block+::
    #   The block will be called in the context of a new Procedure object
    #
    # == Example
    #
    #    exp = Expect.new(io)
    #    exp.procedure do
    #     each do
    #       expect /first expected line/ do
    #         send "some text to send"
    #       end
    #
    #       expect /second expected line/ do
{'fraction_non_alphanumeric': 0.08443363446838081, 'fraction_numerical': 0.003706277507528376, 'mean_word_length': 2.4512390087929656, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '2941234', 'n_tokens_mistral': 2509, 'n_tokens_neox': 2428, 'n_words': 1038}