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.


188
189
190
# File 'lib/commander/user_interaction.rb', line 188

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'

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

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.


237
238
239
240
241
# File 'lib/commander/user_interaction.rb', line 237

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.


43
44
45
46
# File 'lib/commander/user_interaction.rb', line 43

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>

117
118
119
# File 'lib/commander/user_interaction.rb', line 117

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


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

def converse prompt, responses = {}
  i, commands = 0, responses.map { |key, value| value.inspect }.join(',')
  statement = responses.inject '' do |statement, (key, value)|
    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.


272
273
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
# File 'lib/commander/user_interaction.rb', line 272

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

217
218
219
220
221
222
223
224
# File 'lib/commander/user_interaction.rb', line 217

def io input = nil, output = nil, &block
  $stdin = File.new(input) if input
  $stdout = File.new(output, 'r+') if output
  if block
    yield
    reset_io
  end
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

57
58
59
# File 'lib/commander/user_interaction.rb', line 57

def log action, *args
  say '%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 '*'.


34
35
36
37
38
# File 'lib/commander/user_interaction.rb', line 34

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 = {}, &block) ⇒ 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

313
314
315
316
317
# File 'lib/commander/user_interaction.rb', line 313

def progress arr, options = {}, &block
  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.


341
342
343
344
345
# File 'lib/commander/user_interaction.rb', line 341

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

.reset_ioObject

Reset IO to initial constant streams.


229
230
231
# File 'lib/commander/user_interaction.rb', line 229

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'

97
98
99
100
101
# File 'lib/commander/user_interaction.rb', line 97

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'

69
70
71
72
73
# File 'lib/commander/user_interaction.rb', line 69

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'

83
84
85
86
87
# File 'lib/commander/user_interaction.rb', line 83

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


139
140
141
# File 'lib/commander/user_interaction.rb', line 139

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