Module: Commander::UI

Included in:
Methods
Defined in:
lib/commander/user_interaction.rb

Overview

User Interaction

Commander's user interaction module mixes in common methods which extend HighLine's functionality such as a #password method rather than calling #ask directly.

Defined Under Namespace

Modules: AskForClass Classes: ProgressBar

Class Method Summary collapse

Class Method Details

.applescript(script) ⇒ Object

Execute apple script.


191
192
193
# File 'lib/commander/user_interaction.rb', line 191

def applescript(script)
  `osascript -e "#{ script.gsub('"', '\"') }"`
end

.ask_editor(input = nil, preferred_editor = nil) ⇒ Object

Prompt an editor for input. Optionally supply initial input which is written to the editor.

preferred_editor can be hinted.

Examples

ask_editor                # => prompts EDITOR with no input
ask_editor('foo')         # => prompts EDITOR with default text of 'foo'
ask_editor('foo', 'mate -w')  # => prompts TextMate with default text of 'foo'

258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/commander/user_interaction.rb', line 258

def ask_editor(input = nil, preferred_editor = nil)
  editor = available_editor preferred_editor
  program = Commander::Runner.instance.program(:name).downcase rescue 'commander'
  tmpfile = Tempfile.new program
  begin
    tmpfile.write input if input
    tmpfile.close
    system("#{editor} #{tmpfile.path.shellescape}") ? IO.read(tmpfile.path) : nil
  ensure
    tmpfile.unlink
  end
end

.available_editor(preferred = nil) ⇒ Object

Find an editor available in path. Optionally supply the preferred editor. Returns the name as a string, nil if none is available.


239
240
241
242
243
# File 'lib/commander/user_interaction.rb', line 239

def available_editor(preferred = nil)
  [preferred, ENV['EDITOR'], 'mate -w', 'vim', 'vi', 'emacs', 'nano', 'pico']
    .compact
    .find { |name| system("hash #{name.split.first} 2>&-") }
end

.choose(message = nil, *choices, &block) ⇒ Object

Choose from a set array of choices.


41
42
43
44
# File 'lib/commander/user_interaction.rb', line 41

def choose(message = nil, *choices, &block)
  say message if message
  super(*choices, &block)
end

.color(*args) ⇒ Object

'Say' something using the specified color

Examples

color 'I am blue', :blue
color 'I am bold', :bold
color 'White on Red', :white, :on_red

Notes

You may use:
* color:    black blue cyan green magenta red white yellow
* style:    blink bold clear underline
* highligh: on_<color>

115
116
117
# File 'lib/commander/user_interaction.rb', line 115

def color(*args)
  say $terminal.color(*args)
end

.converse(prompt, responses = {}) ⇒ Object

Converse with speech recognition.

Currently a “poorman's” DSL to utilize applescript and the MacOS speech recognition server.

Examples

case converse 'What is the best food?', :cookies => 'Cookies', :unknown => 'Nothing'
when :cookies
  speak 'o.m.g. you are awesome!'
else
  case converse 'That is lame, shall I convince you cookies are the best?', :yes => 'Ok', :no => 'No', :maybe => 'Maybe another time'
  when :yes
    speak 'Well you see, cookies are just fantastic.'
  else
    speak 'Ok then, bye.'
  end
end

Notes

  • MacOS only


166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/commander/user_interaction.rb', line 166

def converse(prompt, responses = {})
  i, commands = 0, responses.map { |_key, value| value.inspect }.join(',')
  statement = responses.inject '' do |inner_statement, (key, value)|
    inner_statement <<
    (
      (i += 1) == 1 ?
      %(if response is "#{value}" then\n) :
      %(else if response is "#{value}" then\n)
    ) <<
    %(do shell script "echo '#{key}'"\n)
  end
  applescript(
    %(
    tell application "SpeechRecognitionServer"
      set response to listen for {#{commands}} with prompt "#{prompt}"
      #{statement}
      end if
    end tell
    ),
  ).strip.to_sym
end

.enable_pagingObject

Enable paging of output after called.


274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/commander/user_interaction.rb', line 274

def enable_paging
  return unless $stdout.tty?
  return unless Process.respond_to? :fork
  read, write = IO.pipe

  # Kernel.fork is not supported on all platforms and configurations.
  # As of Ruby 1.9, `Process.respond_to? :fork` should return false on
  # configurations that don't support it, but versions before 1.9 don't
  # seem to do this reliably and instead raise a NotImplementedError
  # (which is rescued below).

  if Kernel.fork
    $stdin.reopen read
    write.close
    read.close
    Kernel.select [$stdin]
    ENV['LESS'] = 'FSRX' unless ENV.key? 'LESS'
    pager = ENV['PAGER'] || 'less'
    exec pager rescue exec '/bin/sh', '-c', pager
  else
    # subprocess
    $stdout.reopen write
    $stderr.reopen write if $stderr.tty?
    write.close
    read.close
  end
rescue NotImplementedError
ensure
  write.close if write && !write.closed?
  read.close if read && !read.closed?
end

.io(input = nil, output = nil, &block) ⇒ Object

Normalize IO streams, allowing for redirection of input and/or output, for example:

$ foo              # => read from terminal I/O
$ foo in           # => read from 'in' file, output to terminal output stream
$ foo in out       # => read from 'in' file, output to 'out' file
$ foo < in > out   # => equivalent to above (essentially)

Optionally a block may be supplied, in which case IO will be reset once the block has executed.

Examples

command :foo do |c|
  c.syntax = 'foo [input] [output]'
  c.when_called do |args, options|
    # or io(args.shift, args.shift)
    io *args
    str = $stdin.gets
    puts 'input was: ' + str.inspect
  end
end

220
221
222
223
224
225
226
# File 'lib/commander/user_interaction.rb', line 220

def io(input = nil, output = nil, &block)
  $stdin = File.new(input) if input
  $stdout = File.new(output, 'r+') if output
  return unless block
  yield
  reset_io
end

.log(action, *args) ⇒ Object

'Log' an action to the terminal. This is typically used for verbose output regarding actions performed. For example:

create  path/to/file.rb
remove  path/to/old_file.rb
remove  path/to/old_file2.rb

55
56
57
# File 'lib/commander/user_interaction.rb', line 55

def log(action, *args)
  say format('%15s  %s', action, args.join(' '))
end

.password(message = 'Password: ', mask = '*') ⇒ Object

Ask the user for a password. Specify a custom message other than 'Password: ' or override the default mask of '*'.


32
33
34
35
36
# File 'lib/commander/user_interaction.rb', line 32

def password(message = 'Password: ', mask = '*')
  pass = ask(message) { |q| q.echo = mask }
  pass = password message, mask if pass.nil? || pass.empty?
  pass
end

.progress(arr, options = {}) ⇒ Object

Output progress while iterating arr.

Examples

uris = %w( http://vision-media.ca http://google.com )
progress uris, :format => "Remaining: :time_remaining" do |uri|
  res = open uri
end

317
318
319
320
321
# File 'lib/commander/user_interaction.rb', line 317

def progress(arr, options = {})
  bar = ProgressBar.new arr.length, options
  bar.show
  arr.each { |v| bar.increment yield(v) }
end

.replace_tokens(str, hash) ⇒ Object

Substitute hash's keys with their associated values in str.


348
349
350
351
352
# File 'lib/commander/user_interaction.rb', line 348

def replace_tokens(str, hash) #:nodoc:
  hash.inject(str) do |string, (key, value)|
    string.gsub ":#{key}", value.to_s
  end
end

.reset_ioObject

Reset IO to initial constant streams.


231
232
233
# File 'lib/commander/user_interaction.rb', line 231

def reset_io
  $stdin, $stdout = STDIN, STDOUT
end

.say_error(*args) ⇒ Object

'Say' something using the ERROR color (red).

Examples

say_error 'Everything is not fine'
say_error 'It is not ok', 'This is not ok too'

95
96
97
98
99
# File 'lib/commander/user_interaction.rb', line 95

def say_error(*args)
  args.each do |arg|
    say $terminal.color(arg, :red)
  end
end

.say_ok(*args) ⇒ Object

'Say' something using the OK color (green).

Examples

say_ok 'Everything is fine'
say_ok 'It is ok', 'This is ok too'

67
68
69
70
71
# File 'lib/commander/user_interaction.rb', line 67

def say_ok(*args)
  args.each do |arg|
    say $terminal.color(arg, :green)
  end
end

.say_warning(*args) ⇒ Object

'Say' something using the WARNING color (yellow).

Examples

say_warning 'This is a warning'
say_warning 'Be careful', 'Think about it'

81
82
83
84
85
# File 'lib/commander/user_interaction.rb', line 81

def say_warning(*args)
  args.each do |arg|
    say $terminal.color(arg, :yellow)
  end
end

.speak(message, voice = :Alex, rate = 175) ⇒ Object

Speak message using voice at a speaking rate of rate

Voice defaults to 'Alex', which is one of the better voices. Speaking rate defaults to 175 words per minute

Examples

speak 'What is your favorite food? '
food = ask 'favorite food?: '
speak "Wow, I like #{food} too. We have so much in common."
speak "I like #{food} as well!", "Victoria", 190

Notes

  • MacOS only


137
138
139
# File 'lib/commander/user_interaction.rb', line 137

def speak(message, voice = :Alex, rate = 175)
  Thread.new { applescript "say #{message.inspect} using #{voice.to_s.inspect} speaking rate #{rate}" }
end