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.

[View source]

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'
[View source]

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.

[View source]

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.

[View source]

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>
[View source]

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

[View source]

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.

[View source]

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
[View source]

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
[View source]

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 ‘*’.

[View source]

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
[View source]

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.

[View source]

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.

[View source]

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'
[View source]

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'
[View source]

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'
[View source]

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

[View source]

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