Module: Commander::UI

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.



185
186
187
# File 'lib/commander/user_interaction.rb', line 185

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'


253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/commander/user_interaction.rb', line 253

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.



234
235
236
237
238
# File 'lib/commander/user_interaction.rb', line 234

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, *choices) ⇒ Object

Choose from a set array of choices.



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

def choose message, *choices
  say message
  super(*choices)
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



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

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.



269
270
271
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
# File 'lib/commander/user_interaction.rb', line 269

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


214
215
216
217
218
219
220
221
# File 'lib/commander/user_interaction.rb', line 214

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


310
311
312
313
314
# File 'lib/commander/user_interaction.rb', line 310

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.



338
339
340
341
342
# File 'lib/commander/user_interaction.rb', line 338

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.



226
227
228
# File 'lib/commander/user_interaction.rb', line 226

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) ⇒ Object

Speak message using voice which defaults to ‘Alex’, which is one of the better voices.

Examples

speak 'What is your favorite food? '
food = ask 'favorite food?: '
speak "wow, I like #{food} too. We have so much alike."

Notes

  • MacOS only



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

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