Class: Expectr::Lambda

Inherits:
Object
  • Object
show all
Includes:
Interface
Defined in:
lib/expectr/lambda.rb,
lib/expectr/errstr.rb

Overview

Internal: The Expectr::Lambda Class contains the interface to interacting with ruby objects transparently via lambdas in a manner consistent with other Expectr interfaces.

All methods with the prefix ‘interface_’ in their name will return a Proc designed to be defined as an instance method in the primary Expectr object. These methods will all be documented as if they are the Proc in question.

Defined Under Namespace

Modules: Errstr

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Interface

#init_instance, #interface_prepare_interact_interface, #interface_restore_environment

Constructor Details

#initialize(reader, writer) ⇒ Lambda

Public: Initialize a new Expectr::Lambda object.

reader - Lambda which is meant to be interacted with as if it were

analogous to STDIN for a child process.

writer - Lambda which is meant to be interacted with as if it were

analogous to STDOUT for a child process.

Raises TypeError if arguments aren’t of type Proc.



25
26
27
28
29
30
31
32
# File 'lib/expectr/lambda.rb', line 25

def initialize(reader, writer)
  unless reader.kind_of?(Proc) && writer.kind_of?(Proc)
    raise(TypeError, Errstr::PROC_EXPECTED)
  end

  @reader = reader
  @writer = writer
end

Instance Attribute Details

#readerObject (readonly)

Returns the value of attribute reader.



14
15
16
# File 'lib/expectr/lambda.rb', line 14

def reader
  @reader
end

#writerObject (readonly)

Returns the value of attribute writer.



15
16
17
# File 'lib/expectr/lambda.rb', line 15

def writer
  @writer
end

Class Method Details

.spawn(reader, writer, args = {}) ⇒ Object

Public: Present a streamlined interface to create a new Expectr instance.

reader - Lambda which is meant to be interacted with as if it were

analogous to STDIN for a child process.

writer - Lambda which is meant to be interacted with as if it were

analogous to STDOUT for a child process.

args - A Hash used to specify options for the new object, per

Expectr#initialize.

Returns a new Expectr object



44
45
46
47
48
49
# File 'lib/expectr/lambda.rb', line 44

def self.spawn(reader, writer, args = {})
  args[:interface] = :lambda
  args[:reader] = reader
  args[:writer] = writer
  Expectr.new('', args)
end

Instance Method Details

#interface_interact_threadObject

Public: Create a Thread containing the loop which is responsible for handling input from the user in interact mode.

Returns a Thread containing the running loop.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/expectr/lambda.rb', line 93

def interface_interact_thread
  -> {
    Thread.new do
      env = prepare_interact_environment
      input = ''

      while @interact
        if select([$stdin], nil, nil, 1)
          c = $stdin.getc.chr
          send c unless c.nil?
        end
      end

      restore_environment(env)
    end
  }
end

#interface_output_loopObject

Internal: Call the writer lambda, reading the output, forcing UTF-8 and appending to the internal buffer and printing to $stdout if appropriate.

Returns nothing.



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/expectr/lambda.rb', line 115

def interface_output_loop
  -> {
    buf = ''
    loop do
      buf.clear

      begin
        buf << @writer.call.to_s
      rescue Errno::EIO # Lambda is signaling that execution should end.
        return
      end
      process_output(buf)
    end
  }
end

#interface_prepare_interact_environmentObject

Public: Prepare the operating environment for interact mode, set the interact flag to true.

Returns a Hash containing old signal handlers and tty parameters.



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/expectr/lambda.rb', line 66

def interface_prepare_interact_environment
  -> {
    env = {sig: {}}

    # Save old tty settings and set up the new environment
    env[:tty] = `stty -g`
    `stty -icanon min 1 time 0 -echo`

    # SIGINT should be sent to the child as \C-c
    env[:sig]['INT'] = trap 'INT' do
      send "\C-c"
    end

    # SIGTSTP should be sent to the process as \C-z
    env[:sig]['TSTP'] = trap 'TSTP' do
      send "\C-z"
    end

    @interact = true
    env
  }
end

#interface_sendObject

Public: Send input to the active child process.

args - Arguments to pass to the reader interface.

Returns nothing.



56
57
58
59
60
# File 'lib/expectr/lambda.rb', line 56

def interface_send
  ->(args) {
    @reader.call(*args)
  }
end