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.



171
172
173
# File 'lib/commander/user_interaction.rb', line 171

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'


231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/commander/user_interaction.rb', line 231

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}") ? File.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.



213
214
215
216
217
# File 'lib/commander/user_interaction.rb', line 213

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

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

Choose from a set array of choices.



29
30
31
32
# File 'lib/commander/user_interaction.rb', line 29

def choose(message = nil, *choices, &)
  say message if 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>


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

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


147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/commander/user_interaction.rb', line 147

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.



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/commander/user_interaction.rb', line 246

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


199
200
201
202
203
204
205
206
207
208
# File 'lib/commander/user_interaction.rb', line 199

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
ensure
  $stdin, $stdout = orig_stdin, orig_stdout if block
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


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

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



21
22
23
24
25
# File 'lib/commander/user_interaction.rb', line 21

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


289
290
291
292
293
# File 'lib/commander/user_interaction.rb', line 289

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.



358
359
360
361
362
# File 'lib/commander/user_interaction.rb', line 358

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'



79
80
81
82
83
# File 'lib/commander/user_interaction.rb', line 79

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'



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

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'



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

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


119
120
121
# File 'lib/commander/user_interaction.rb', line 119

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