Class: MacWifi::CommandLineInterface

Inherits:
Object
  • Object
show all
Defined in:
lib/mac-wifi/command_line_interface.rb

Defined Under Namespace

Classes: BadCommandError, Command, OpenResource, OpenResources

Constant Summary collapse

OPEN_RESOURCES =
OpenResources.new([
    OpenResource.new('ipc',  'https://ipchicken.com/',     'IP Chicken'),
    OpenResource.new('ipw',  'https://www.whatismyip.com', 'What is My IP'),
    OpenResource.new('spe',  'http://speedtest.net/',      'Speed Test'),
    OpenResource.new('this', 'https://github.com/keithrbennett/macwifi', 'mac-wifi Home Page'),
])
HELP_TEXT =

Help text to be used when requested by ‘h’ command, in case of unrecognized or nonexistent command, etc.

"
Command Line Switches:                    [mac-wifi version #{MacWifi::VERSION}]

-o[i,j,p,y]               - outputs data in inspect, JSON, puts, or YAML format when not in shell mode
-s                        - run in shell mode
-v                        - verbose mode (prints OS commands and their outputs)

Commands:

a[vail_nets]              - array of names of the available networks
ci                        - connected to Internet (not just wifi on)?
co[nnect] network-name    - turns wifi on, connects to network-name
cy[cle]                   - turns wifi off, then on, preserving network selection
d[isconnect]              - disconnects from current network, does not turn off wifi
h[elp]                    - prints this help
i[nfo]                    - a hash of wifi-related information
l[s_avail_nets]           - details about available networks
n[etwork_name]            - name (SSID) of currently connected network
on                        - turns wifi on
of[f]                     - turns wifi off
pa[ssword] network-name   - password for preferred network-name
pr[ef_nets]               - preferred (not necessarily available) networks
q[uit]                    - exits this program (interactive shell mode only) (see also 'x')
r[m_pref_nets] network-name - removes network-name from the preferred networks list
                          (can provide multiple names separated by spaces)
ro[pen]                   - open resource (#{OPEN_RESOURCES.help_string})
t[ill]                    - returns when the desired Internet connection state is true. Options:
                          1) 'on'/:on, 'off'/:off, 'conn'/:conn, or 'disc'/:disc
                          2) wait interval, in seconds (optional, defaults to 0.5 seconds)
w[ifion]                  - is the wifi on?
x[it]                     - exits this program (interactive shell mode only) (see also 'q')

When in interactive shell mode:
  * use quotes for string parameters such as method names.
  * for pry commands, use prefix `%`.

"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ CommandLineInterface

Returns a new instance of CommandLineInterface.



89
90
91
92
93
94
# File 'lib/mac-wifi/command_line_interface.rb', line 89

def initialize(options)
  @options = options
  @model = MacOsModel.new(verbose_mode)
  @interactive_mode = !!(options.interactive_mode)
  run_shell if @interactive_mode
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *options) ⇒ Object

For use by the shell; when typing a command and options, it is passed to process_command_line



188
189
190
191
192
193
194
195
196
# File 'lib/mac-wifi/command_line_interface.rb', line 188

def method_missing(method_name, *options)
  method_name = method_name.to_s
  method_exists = !! find_command_action(method_name)
  if method_exists
    process_command_line(method_name, options)
  else
    puts(%Q{"#{method_name}" is not a valid command or option. If you intend for this to be a string literal, use quotes or %q/Q{}.})
  end
end

Instance Attribute Details

#interactive_modeObject (readonly)

Returns the value of attribute interactive_mode.



7
8
9
# File 'lib/mac-wifi/command_line_interface.rb', line 7

def interactive_mode
  @interactive_mode
end

#modelObject (readonly)

Returns the value of attribute model.



7
8
9
# File 'lib/mac-wifi/command_line_interface.rb', line 7

def model
  @model
end

#open_resourcesObject (readonly)

Returns the value of attribute open_resources.



7
8
9
# File 'lib/mac-wifi/command_line_interface.rb', line 7

def open_resources
  @open_resources
end

#optionsObject (readonly)

Returns the value of attribute options.



7
8
9
# File 'lib/mac-wifi/command_line_interface.rb', line 7

def options
  @options
end

Instance Method Details

#awesome_print_available?Boolean

We’d like to use awesome_print if it is available, but not require it. So, we try to require it, but if that fails, we fall back to using pp (pretty print), which is included in Ruby distributions without the need to install a gem.

Returns:

  • (Boolean)

    true if awesome_print is available (after requiring it), else false after requiring ‘pp’.



113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/mac-wifi/command_line_interface.rb', line 113

def awesome_print_available?
  if @awesome_print_available.nil?  # first time here
    begin
      require 'awesome_print'
      @awesome_print_available = true
    rescue LoadError
      require 'pp'
      @awesome_print_available = false
    end
  end

  @awesome_print_available
end

#callObject



449
450
451
452
453
454
455
456
457
458
# File 'lib/mac-wifi/command_line_interface.rb', line 449

def call
  validate_command_line
  begin
    process_command_line(ARGV[0], ARGV[1..-1])
  rescue BadCommandError => error
    separator_line = "! #{'-' * 75} !\n"
    puts '' << separator_line << error.to_s << "\n" << separator_line
    exit(-1)
  end
end

#cmd_aObject



226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/mac-wifi/command_line_interface.rb', line 226

def cmd_a
  info = model.available_network_names
  if interactive_mode
    info
  else
    if post_processor
      puts post_processor.(info)
    else
      puts model.wifi_on? \
          ? "Available networks are:\n\n#{fancy_string(info)}" \
          : "Wifi is off, cannot see available networks."
    end
  end
end

#cmd_ciObject



242
243
244
245
246
247
248
249
# File 'lib/mac-wifi/command_line_interface.rb', line 242

def cmd_ci
  connected = model.connected_to_internet?
  if interactive_mode
    connected
  else
    puts (post_processor ? post_processor.(connected) : "Connected to Internet: #{connected}")
  end
end

#cmd_co(network, password = nil) ⇒ Object



252
253
254
# File 'lib/mac-wifi/command_line_interface.rb', line 252

def cmd_co(network, password = nil)
  model.connect(network, password)
end

#cmd_cyObject



257
258
259
# File 'lib/mac-wifi/command_line_interface.rb', line 257

def cmd_cy
  model.cycle_network
end

#cmd_dObject



262
263
264
# File 'lib/mac-wifi/command_line_interface.rb', line 262

def cmd_d
  model.disconnect
end

#cmd_hObject



267
268
269
# File 'lib/mac-wifi/command_line_interface.rb', line 267

def cmd_h
  print_help
end

#cmd_iObject



272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/mac-wifi/command_line_interface.rb', line 272

def cmd_i
  info = model.wifi_info
  if interactive_mode
    info
  else
    if post_processor
      puts post_processor.(info)
    else
      puts fancy_string(info)
    end
  end
end

#cmd_lsaObject



286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'lib/mac-wifi/command_line_interface.rb', line 286

def cmd_lsa
  info = model.available_network_info
  if interactive_mode
    info
  else
    if post_processor
      puts post_processor.(info)
    else
      message = model.wifi_on? ? fancy_string(info) : "Wifi is off, cannot see available networks."
      puts(message)
    end
  end
end

#cmd_nObject



301
302
303
304
305
306
307
308
309
# File 'lib/mac-wifi/command_line_interface.rb', line 301

def cmd_n
  name = model.current_network
  if interactive_mode
    name
  else
    display_name = name ? name : '[none]'
    puts (post_processor ? post_processor.(name) : %Q{Network (SSID) name: "#{display_name}"})
  end
end

#cmd_ofObject



312
313
314
# File 'lib/mac-wifi/command_line_interface.rb', line 312

def cmd_of
  model.wifi_off
end

#cmd_onObject



317
318
319
# File 'lib/mac-wifi/command_line_interface.rb', line 317

def cmd_on
  model.wifi_on
end

#cmd_pa(network) ⇒ Object



332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
# File 'lib/mac-wifi/command_line_interface.rb', line 332

def cmd_pa(network)
  password = model.preferred_network_password(network)

  if interactive_mode
    password
  else
    if post_processor
      puts post_processor.(password)
    else
      output =  %Q{Preferred network "#{model.connected_network_name}" }
      output << (password ? %Q{stored password is "#{password}".} : "has no stored password.")
      puts output
    end
  end
end

#cmd_prObject



349
350
351
352
353
354
355
356
# File 'lib/mac-wifi/command_line_interface.rb', line 349

def cmd_pr
  networks = model.preferred_networks
  if interactive_mode
    networks
  else
    puts (post_processor ? post_processor.(networks) : fancy_string(networks))
  end
end

#cmd_puObject



359
360
361
# File 'lib/mac-wifi/command_line_interface.rb', line 359

def cmd_pu
  `open https://www.whatismyip.com/`
end

#cmd_qObject



364
365
366
# File 'lib/mac-wifi/command_line_interface.rb', line 364

def cmd_q
  quit
end

#cmd_r(*options) ⇒ Object



369
370
371
372
373
374
375
376
# File 'lib/mac-wifi/command_line_interface.rb', line 369

def cmd_r(*options)
  removed_networks = model.remove_preferred_networks(*options)
  if interactive_mode
    removed_networks
  else
    puts (post_processor ? post_processor.(removed_networks) : "Removed networks: #{removed_networks.inspect}")
  end
end

#cmd_ro(*resource_codes) ⇒ Object

Use Mac OS ‘open’ command line utility



323
324
325
326
327
328
329
330
# File 'lib/mac-wifi/command_line_interface.rb', line 323

def cmd_ro(*resource_codes)
  resource_codes.each do |code|
    resource = OPEN_RESOURCES.find_by_code(code)
    if resource
      model.run_os_command("open #{resource.resource}")
    end
  end
end

#cmd_t(*options) ⇒ Object



379
380
381
382
383
# File 'lib/mac-wifi/command_line_interface.rb', line 379

def cmd_t(*options)
  target_status = options[0].to_sym
  wait_interval_in_secs = (options[1] ? Float(options[1]) : nil)
  model.till(target_status, wait_interval_in_secs)
end

#cmd_wObject



386
387
388
389
390
391
392
393
# File 'lib/mac-wifi/command_line_interface.rb', line 386

def cmd_w
  on = model.wifi_on?
  if interactive_mode
    on
  else
    puts (post_processor ? post_processor.(on) : "Wifi on: #{on}")
  end
end

#cmd_xObject



396
397
398
# File 'lib/mac-wifi/command_line_interface.rb', line 396

def cmd_x
  quit
end

#commandsObject



401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
# File 'lib/mac-wifi/command_line_interface.rb', line 401

def commands
  @commands_ ||= [
      Command.new('a',   'avail_nets',    -> (*_options) { cmd_a             }),
      Command.new('ci',  'ci',            -> (*_options) { cmd_ci            }),
      Command.new('co',  'connect',       -> (*options)  { cmd_co(*options)  }),
      Command.new('cy',  'cycle',         -> (*_options) { cmd_cy            }),
      Command.new('d',   'disconnect',    -> (*_options) { cmd_d             }),
      Command.new('h',   'help',          -> (*_options) { cmd_h             }),
      Command.new('i',   'info',          -> (*_options) { cmd_i             }),
      Command.new('l',   'ls_avail_nets', -> (*_options) { cmd_lsa           }),
      Command.new('n',   'network_name',  -> (*_options) { cmd_n             }),
      Command.new('of',  'off',           -> (*_options) { cmd_of            }),
      Command.new('on',  'on',            -> (*_options) { cmd_on            }),
      Command.new('ro',  'ropen',         -> (*options)  { cmd_ro(*options)  }),
      Command.new('pa',  'password',      -> (*options)  { cmd_pa(*options)  }),
      Command.new('pr',  'pref_nets',     -> (*_options) { cmd_pr            }),
      Command.new('q',   'quit',          -> (*_options) { cmd_q             }),
      Command.new('r',   'rm_pref_nets',  -> (*options)  { cmd_r(*options)   }),
      Command.new('t',   'till',          -> (*options)  { cmd_t(*options)   }),
      Command.new('w',   'wifion',        -> (*_options) { cmd_w             }),
      Command.new('x',   'xit',           -> (*_options) { cmd_x             })
  ]
end

#fancy_puts(object) ⇒ Object Also known as: fp



133
134
135
# File 'lib/mac-wifi/command_line_interface.rb', line 133

def fancy_puts(object)
  puts fancy_string(object)
end

#fancy_string(object) ⇒ Object



128
129
130
# File 'lib/mac-wifi/command_line_interface.rb', line 128

def fancy_string(object)
  awesome_print_available? ? object.ai : object.pretty_inspect
end

#find_command_action(command_string) ⇒ Object



426
427
428
429
430
431
432
433
434
# File 'lib/mac-wifi/command_line_interface.rb', line 426

def find_command_action(command_string)
  result = commands.detect do |cmd|
    cmd.max_string.start_with?(command_string) \
    && \
    command_string.length >= cmd.min_string.length  # e.g. 'c' by itself should not work
  end

  result ? result.action : nil
end

#post_process(object) ⇒ Object

If a post-processor has been configured (e.g. YAML or JSON), use it.



438
439
440
# File 'lib/mac-wifi/command_line_interface.rb', line 438

def post_process(object)
  post_processor ? post_processor.(object) : object
end

#post_processorObject



444
445
446
# File 'lib/mac-wifi/command_line_interface.rb', line 444

def post_processor
  options.post_processor
end


104
105
106
# File 'lib/mac-wifi/command_line_interface.rb', line 104

def print_help
  puts HELP_TEXT
end

#process_command_line(command, options) ⇒ Object

Processes the command (ARGV) and any relevant options (ARGV).

CAUTION! In interactive mode, any strings entered (e.g. a network name) MUST be in a form that the Ruby interpreter will recognize as a string, i.e. single or double quotes, %q, %Q, etc. Otherwise it will assume it’s a method name and pass it to method_missing!



205
206
207
208
209
210
211
212
213
214
# File 'lib/mac-wifi/command_line_interface.rb', line 205

def process_command_line(command, options)
  action = find_command_action(command)
  if action
    action.(*options)
  else
    print_help
    raise BadCommandError.new(
        %Q{Unrecognized command. Command was "#{command}" and options were #{options.inspect}.})
  end
end

#quitObject



217
218
219
220
221
222
223
# File 'lib/mac-wifi/command_line_interface.rb', line 217

def quit
  if interactive_mode
    exit(0)
  else
    puts "This command can only be run in shell mode."
  end
end

#run_pryObject

Pry will output the content of the method from which it was called. This small method exists solely to reduce the amount of pry’s output that is not needed here.



152
153
154
155
156
157
158
# File 'lib/mac-wifi/command_line_interface.rb', line 152

def run_pry
  binding.pry

  # the seemingly useless line below is needed to avoid pry's exiting
  # (see https://github.com/deivid-rodriguez/pry-byebug/issues/45)
  _a = nil
end

#run_shellObject

Runs a pry session in the context of this object. Commands and options specified on the command line can also be specified in the shell.



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/mac-wifi/command_line_interface.rb', line 163

def run_shell
  begin
    require 'pry'
  rescue LoadError
    puts "The 'pry' gem and/or one of its prerequisites, required for running the shell, was not found." +
             " Please `gem install pry` or, if necessary, `sudo gem install pry`."
    exit(-1)
  end

  print_help

  # Enable the line below if you have any problems with pry configuration being loaded
  # that is messing up this runtime use of pry:
  # Pry.config.should_load_rc = false

  # Strangely, this is the only thing I have found that successfully suppresses the
  # code context output, which is not useful here. Anyway, this will differentiate
  # a pry command from a DSL command, which _is_ useful here.
  Pry.config.command_prefix = '%'

  run_pry
end

#validate_command_lineObject

Asserts that a command has been passed on the command line.



140
141
142
143
144
145
146
# File 'lib/mac-wifi/command_line_interface.rb', line 140

def validate_command_line
  if ARGV.empty?
    puts "Syntax is: #{__FILE__} [options] command [command_options]"
    print_help
    exit(-1)
  end
end

#verbose_modeObject

Until command line option parsing is added, the only way to specify verbose mode is in the environment variable MAC_WIFI_OPTS.



99
100
101
# File 'lib/mac-wifi/command_line_interface.rb', line 99

def verbose_mode
  options.verbose
end