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.


193
194
195
# File 'lib/commander/user_interaction.rb', line 193

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 HighLine.default_instance.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
184
185
186
187
188
# 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 |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.


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
301
302
303
# 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

222
223
224
225
226
227
228
229
230
231
# File 'lib/commander/user_interaction.rb', line 222

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

  yield
  $stdin, $stdout = orig_stdin, orig_stdout
  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

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

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 '*'.


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

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

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.


376
377
378
379
380
# File 'lib/commander/user_interaction.rb', line 376

def replace_tokens(str, hash) #:nodoc:
  hash.inject(str) do |string, (key, value)|
    string.gsub ":#{key}", value.to_s
  end
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 HighLine.default_instance.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 HighLine.default_instance.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 HighLine.default_instance.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