class WifiWand::CommandLineInterface

Constants

HELP_TEXT

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

OPEN_RESOURCES
PROJECT_URL

Attributes

interactive_mode[R]
model[R]
open_resources[R]
options[R]

Public Class Methods

new(options) click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 95
def initialize(options)
  @options = options
  current_os = OperatingSystems.new.current_os
  raise Error.new("Could not determine operating system") if current_os.nil?
  model_options = OpenStruct.new({
      verbose:   options.verbose,
      wifi_port: options.wifi_port
  })

  unless awesome_print_available?
    HELP_TEXT << "For nicer output, `gem install awesome_print`.\n\n"
  end

  @model = current_os.create_model(model_options)
  @interactive_mode = !!(options.interactive_mode)
  run_shell if @interactive_mode
end

Public Instance Methods

attempt_command_action(command, *args, &error_handler_block) click to toggle source

Look up the command name and, if found, run it. If not, execute the passed block.

# File lib/wifi-wand/command_line_interface.rb, line 203
def attempt_command_action(command, *args, &error_handler_block)
  action = find_command_action(command)

  if action
    action.(*args)
  else
    error_handler_block.call
    nil
  end
end
awesome_print_available?() click to toggle source

@return true if awesome_print is available (after requiring it), else false after requiring 'pp'. 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.

# File lib/wifi-wand/command_line_interface.rb, line 128
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
call() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 514
def call
  validate_command_line
  begin
    # By this time, the Main class has removed the command line options, and all that is left
    # in ARGV is the commands and their options.
    process_command_line
  rescue BadCommandError => error
    separator_line = "! #{'-' * 75} !\n"
    puts '' << separator_line << error.to_s << "\n" << separator_line
    exit(-1)
  end
end
cmd_a() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 250
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_ci() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 266
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) click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 276
def cmd_co(network, password = nil)
  model.connect(network, password)
end
cmd_cy() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 281
def cmd_cy
  model.cycle_network
end
cmd_d() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 286
def cmd_d
  model.disconnect
end
cmd_f(*options) click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 434
def cmd_f(*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_h() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 291
def cmd_h
  print_help
end
cmd_i() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 296
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_l() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 310
def cmd_l
  info = model.available_network_info

  if interactive_mode
    info
  else
    output = ''
    unless model.wifi_on?
      output << "Wifi is off, cannot see available networks."
    else
      if post_processor
        output = post_processor.(info)
      else
        output << "\nAccess points listed in descending order of signal strength (RSSI):\n\n"
        output << fancy_string(info)
      end
    end
    puts output
  end
end
cmd_na(*args) click to toggle source

Performs nameserver functionality. @param subcommand 'get' or no arg to get, 'clear' to clear, and an array of IP addresses to set

# File lib/wifi-wand/command_line_interface.rb, line 334
def cmd_na(*args)
  subcommand = if args.empty? || args.first.to_sym == :get
    :get
  elsif args.first.to_sym == :clear
    :clear
  else
    :put
  end

  case(subcommand)
    when :get
      current_nameservers = model.nameservers_using_networksetup
      if interactive_mode
        current_nameservers
      else
        if post_processor
          puts post_processor.(current_nameservers)
        else
          current_nameservers_as_string = current_nameservers.empty? ? "[None]" : current_nameservers.join(', ')
          puts "Nameservers: #{current_nameservers_as_string}"
        end
      end
    when :clear
      model.set_nameservers(:clear)
    when :put
      new_nameservers = args
      model.set_nameservers(new_nameservers)
  end
end
cmd_ne() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 365
def cmd_ne
  name = model.connected_network_name
  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_of() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 376
def cmd_of
  model.wifi_off
end
cmd_on() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 381
def cmd_on
  model.wifi_on
end
cmd_pa(network) click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 402
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_pr() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 419
def cmd_pr
  networks = model.preferred_networks
  if interactive_mode
    networks
  else
    puts (post_processor ? post_processor.(networks) : fancy_string(networks))
  end
end
cmd_q() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 429
def cmd_q
  quit
end
cmd_ro(*resource_codes) click to toggle source

Use Mac OS 'open' command line utility

# File lib/wifi-wand/command_line_interface.rb, line 387
def cmd_ro(*resource_codes)
  resource_codes.each do |code|
    resource = OPEN_RESOURCES.find_by_code(code)
    if resource
      if code == 'spe' && Dir.exist?('/Applications/Speedtest.app/')
        model.open_application('Speedtest')
      else
        model.open_resource(resource.resource)
      end
    end
  end
  nil
end
cmd_t(*options) click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 444
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_w() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 451
def cmd_w
  on = model.wifi_on?
  if interactive_mode
    on
  else
    puts (post_processor ? post_processor.(on) : "Wifi on: #{on}")
  end
end
cmd_x() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 461
def cmd_x
  quit
end
commands() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 466
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('f',   'forget',        -> (*options)  { cmd_f(*options)   }),
      Command.new('h',   'help',          -> (*_options) { cmd_h             }),
      Command.new('i',   'info',          -> (*_options) { cmd_i             }),
      Command.new('l',   'ls_avail_nets', -> (*_options) { cmd_l             }),
      Command.new('na',  'nameservers',   -> (*options)  { cmd_na(*options)  }),
      Command.new('ne',  'network_name',  -> (*_options) { cmd_ne            }),
      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('t',   'till',          -> (*options)  { cmd_t(*options)   }),
      Command.new('u',   'url',           -> (*_options) { PROJECT_URL       }),
      Command.new('w',   'wifi_on',       -> (*_options) { cmd_w             }),
      Command.new('x',   'xit',           -> (*_options) { cmd_x             })
  ]
end
fancy_puts(object) click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 148
def fancy_puts(object)
  puts fancy_string(object)
end
Also aliased as: fp
fancy_string(object) click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 143
def fancy_string(object)
  awesome_print_available? ? object.ai : object.pretty_inspect
end
find_command_action(command_string) click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 493
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
fp(object)
Alias for: fancy_puts
method_missing(method_name, *method_args) click to toggle source

For use by the shell when the user types the DSL commands

# File lib/wifi-wand/command_line_interface.rb, line 216
def method_missing(method_name, *method_args)
  attempt_command_action(method_name.to_s, *method_args) do
    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
post_process(object) click to toggle source

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

# File lib/wifi-wand/command_line_interface.rb, line 504
def post_process(object)
  post_processor ? post_processor.(object) : object
end
post_processor() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 509
def post_processor
  options.post_processor
end
print_help() click to toggle source
process_command_line() click to toggle source

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!

# File lib/wifi-wand/command_line_interface.rb, line 231
def process_command_line
  attempt_command_action(ARGV[0], *ARGV[1..-1]) do
    print_help
    raise BadCommandError.new(
        %Q{! Unrecognized command. Command was "#{ARGV.first.inspect}" and options were #{ARGV[1..-1].inspect}.})
  end
end
quit() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 241
def quit
  if interactive_mode
    exit(0)
  else
    puts "This command can only be run in shell mode."
  end
end
run_pry() click to toggle source

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.

# File lib/wifi-wand/command_line_interface.rb, line 167
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_shell() click to toggle source

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.

# File lib/wifi-wand/command_line_interface.rb, line 178
def run_shell
  begin
    require 'pry'
  rescue LoadError
    message = "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`."
    raise Error.new(message)
  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_line() click to toggle source

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

# File lib/wifi-wand/command_line_interface.rb, line 155
def validate_command_line
  if ARGV.empty?
    puts "Syntax is: #{$0} [options] command [command_options]"
    print_help
    exit(-1)
  end
end
verbose_mode() click to toggle source
# File lib/wifi-wand/command_line_interface.rb, line 114
def verbose_mode
  options.verbose
end