wifi-wand 2.10.1 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 301b4e83a32c377d251c8cdef985299c26220e4c7322ba72fe43488aa050b94e
4
- data.tar.gz: 1880892a4a794728a932ca5e42830ca546c46ce55403d0cf3b2059d92381c707
3
+ metadata.gz: 5f21e7e9af16e0eea5c7d254ef75ce061fbae1ada6c707201a189ec78f9238be
4
+ data.tar.gz: ec4b2ef369ca6e3186fe02b59e57c059f89a17b03eba2cdf760035b93fdaa9b9
5
5
  SHA512:
6
- metadata.gz: a8aede3fee3958093e2c5cca0dbf8c01118d79cb2cca7cac815d83aa69f1c45a51f6fb94846cf0ec9bbbf6e5a88e29dd3644af1f5a51d3ad7d191a3c07238134
7
- data.tar.gz: 6a7ed65e40957546032570d54e36db58157885de5bc4e11723e4564e7b4d0040ec433876c8a5b5c67943130be5293ae6ad2c159cabf82147464e7abb9338fcb3
6
+ metadata.gz: a86d2fd563801ca4a3259d200de197d8811c6f46360a805b85779fc488107045c8df20f6013c69866b61bdddcc40f11ff77a338bb2e0984eef8690d86a2016fd
7
+ data.tar.gz: cd16ad95aed459d769e51539a911797f004be30e7ad9dfab8c6352d2aaa226cbadcbe46d5d0c4075c58b6f478bb1ccb3f6a66408aa932b1111cf0205d5ea2e3c
data/RELEASE_NOTES.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## v2.11.0
2
+
3
+ * Various fixes and clarifications.
4
+ * Change implementation of available_network_names to use REXML; first implemented w/position number, then XPath.
5
+ * Add attempt count to try_os_command_until in verbose mode.
6
+
1
7
  ## v2.10.1
2
8
 
3
9
  * Fix egregious bug; the 'a' command did not work if `airport` was not in the path; I should have been using the AIRPORT_CMD constant but hard coded `airport` instead.
@@ -1,5 +1,6 @@
1
1
  require_relative 'operating_systems'
2
2
  require 'ostruct'
3
+ require_relative 'error'
3
4
  require_relative 'version'
4
5
 
5
6
  module WifiWand
@@ -79,11 +80,11 @@ ro[pen] - open resource (#{OPEN_RESOURCES.help_string})
79
80
  t[ill] - returns when the desired Internet connection state is true. Options:
80
81
  1) 'on'/:on, 'off'/:off, 'conn'/:conn, or 'disc'/:disc
81
82
  2) wait interval, in seconds (optional, defaults to 0.5 seconds)
82
- w[ifion] - is the wifi on?
83
+ w[ifi_on] - is the wifi on?
83
84
  x[it] - exits this program (interactive shell mode only) (see also 'q')
84
85
 
85
86
  When in interactive shell mode:
86
- * use quotes for string parameters such as method names.
87
+ * remember to quote string literals.
87
88
  * for pry commands, use prefix `%`.
88
89
 
89
90
  "
@@ -91,7 +92,7 @@ When in interactive shell mode:
91
92
  def initialize(options)
92
93
  @options = options
93
94
  current_os = OperatingSystems.new.current_os
94
- raise "Could not determine operating system" if current_os.nil?
95
+ raise Error.new("Could not determine operating system") if current_os.nil?
95
96
  model_options = OpenStruct.new({
96
97
  verbose: options.verbose,
97
98
  wifi_port: options.wifi_port
@@ -107,8 +108,6 @@ When in interactive shell mode:
107
108
  end
108
109
 
109
110
 
110
- # Until command line option parsing is added, the only way to specify
111
- # verbose mode is in the environment variable MAC_WIFI_OPTS.
112
111
  def verbose_mode
113
112
  options.verbose
114
113
  end
@@ -177,9 +176,9 @@ When in interactive shell mode:
177
176
  begin
178
177
  require 'pry'
179
178
  rescue LoadError
180
- puts "The 'pry' gem and/or one of its prerequisites, required for running the shell, was not found." +
181
- " Please `gem install pry` or, if necessary, `sudo gem install pry`."
182
- exit(-1)
179
+ message = "The 'pry' gem and/or one of its prerequisites, required for running the shell, was not found." +
180
+ " Please `gem install pry` or, if necessary, `sudo gem install pry`."
181
+ raise Error.new(message)
183
182
  end
184
183
 
185
184
  print_help
@@ -197,13 +196,25 @@ When in interactive shell mode:
197
196
  end
198
197
 
199
198
 
200
- # For use by the shell; when typing a command and options, it is passed to process_command_line
201
- def method_missing(method_name, *method_args)
202
- method_name = method_name.to_s
203
- if find_command_action(method_name)
204
- process_command_line(method_name, method_args)
199
+ # Look up the command name and, if found, run it. If not, execute the passed block.
200
+ def attempt_command_action(command, *args, &error_handler_block)
201
+ action = find_command_action(command)
202
+
203
+ if action
204
+ action.(*args)
205
205
  else
206
- 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{}.})
206
+ error_handler_block.call
207
+ nil
208
+ end
209
+ end
210
+
211
+
212
+ # For use by the shell when the user types the DSL commands
213
+ def method_missing(method_name, *method_args)
214
+ attempt_command_action(method_name.to_s, *method_args) do
215
+ puts(%Q{"#{method_name}" is not a valid command or option. } \
216
+ << 'If you intend for this to be a string literal, ' \
217
+ << 'use quotes or %q{}/%Q{}.')
207
218
  end
208
219
  end
209
220
 
@@ -214,18 +225,16 @@ When in interactive shell mode:
214
225
  # be in a form that the Ruby interpreter will recognize as a string,
215
226
  # i.e. single or double quotes, %q, %Q, etc.
216
227
  # Otherwise it will assume it's a method name and pass it to method_missing!
217
- def process_command_line(command, args)
218
- action = find_command_action(command)
219
- if action
220
- action.(*args)
221
- else
228
+ def process_command_line
229
+ attempt_command_action(ARGV[0], *ARGV[1..-1]) do
222
230
  print_help
223
231
  raise BadCommandError.new(
224
- %Q{Unrecognized command. Command was "#{command}" and options were #{args.inspect}.})
232
+ %Q{! Unrecognized command. Command was "#{ARGV.first.inspect}" and options were #{ARGV[1..-1].inspect}.})
225
233
  end
226
234
  end
227
235
 
228
236
 
237
+
229
238
  def quit
230
239
  if interactive_mode
231
240
  exit(0)
@@ -313,7 +322,6 @@ When in interactive shell mode:
313
322
  # Performs nameserver functionality.
314
323
  # @param subcommand 'get' or no arg to get, 'clear' to clear, and an array of IP addresses to set
315
324
  def cmd_na(*args)
316
-
317
325
  subcommand = if [[], ['get']].include?(args)
318
326
  :get
319
327
  elsif args == ['clear']
@@ -473,7 +481,6 @@ When in interactive shell mode:
473
481
  && \
474
482
  command_string.length >= cmd.min_string.length # e.g. 'c' by itself should not work
475
483
  end
476
-
477
484
  result ? result.action : nil
478
485
  end
479
486
 
@@ -494,7 +501,7 @@ When in interactive shell mode:
494
501
  begin
495
502
  # By this time, the Main class has removed the command line options, and all that is left
496
503
  # in ARGV is the commands and their options.
497
- process_command_line(ARGV[0], ARGV[1..-1])
504
+ process_command_line
498
505
  rescue BadCommandError => error
499
506
  separator_line = "! #{'-' * 75} !\n"
500
507
  puts '' << separator_line << error.to_s << "\n" << separator_line
@@ -0,0 +1,4 @@
1
+ module WifiWand
2
+ class Error < RuntimeError
3
+ end
4
+ end
@@ -37,8 +37,10 @@ class Main
37
37
  choice = v[0].downcase
38
38
 
39
39
  unless formatters.keys.include?(choice)
40
- raise %Q{Output format "#{choice}" not in list of available formats} +
41
- " (#{formatters.keys.inspect})."
40
+ message = %Q{Output format "#{choice}" not in list of available formats} <<
41
+ " (#{formatters.keys})."
42
+ puts; puts message; puts
43
+ raise Error.new(message)
42
44
  end
43
45
 
44
46
  options.post_processor = formatters[choice]
@@ -2,6 +2,8 @@ require 'json'
2
2
  require 'net/http'
3
3
  require 'tempfile'
4
4
  require 'uri'
5
+ require_relative 'helpers/command_output_formatter'
6
+ require_relative '../error'
5
7
  require_relative '../../wifi-wand'
6
8
 
7
9
  module WifiWand
@@ -33,30 +35,18 @@ class BaseModel
33
35
  @verbose_mode = options.verbose
34
36
 
35
37
  if options.wifi_port && (! is_wifi_port?(options.wifi_port))
36
- raise "#{options.wifi_port} is not a Wi-Fi interface."
38
+ raise Error.new("#{options.wifi_port} is not a Wi-Fi interface.")
37
39
  end
38
40
  @wifi_port = options.wifi_port
39
41
  end
40
42
 
41
43
 
42
- def banner_line
43
- @banner_line ||= '-' * 79
44
- end
45
-
46
- def command_attempt_as_string(command)
47
- "\n\n#{banner_line}\nCommand: #{command}\n"
48
- end
49
-
50
- def command_result_as_string(output)
51
- "#{output}#{banner_line}\n\n"
52
- end
53
-
54
44
 
55
45
 
56
46
  def run_os_command(command, raise_on_error = true)
57
47
 
58
48
  if @verbose_mode
59
- puts command_attempt_as_string(command)
49
+ puts CommandOutputFormatter.command_attempt_as_string(command)
60
50
  end
61
51
 
62
52
  start_time = Time.now
@@ -64,7 +54,7 @@ class BaseModel
64
54
 
65
55
  if @verbose_mode
66
56
  puts "Duration: #{'%.4f' % [Time.now - start_time]} seconds"
67
- puts command_result_as_string(output)
57
+ puts CommandOutputFormatter.command_result_as_string(output)
68
58
  end
69
59
 
70
60
  if $?.exitstatus != 0 && raise_on_error
@@ -94,7 +84,7 @@ class BaseModel
94
84
  success = true
95
85
 
96
86
  if @verbose_mode
97
- puts command_attempt_as_string("[Calling Net:HTTP.start(#{url.host})]")
87
+ puts CommandOutputFormatter.command_attempt_as_string("[Calling Net:HTTP.start(#{url.host})]")
98
88
  end
99
89
 
100
90
  start_time = Time.now
@@ -110,7 +100,7 @@ class BaseModel
110
100
 
111
101
  if @verbose_mode
112
102
  puts "Duration: #{'%.4f' % [Time.now - start_time]} seconds"
113
- puts command_result_as_string("#{success}\n")
103
+ puts CommandOutputFormatter.command_result_as_string("#{success}\n")
114
104
  end
115
105
 
116
106
  success
@@ -146,7 +136,7 @@ class BaseModel
146
136
  password = password.to_s if password
147
137
 
148
138
  if network_name.nil? || network_name.empty?
149
- raise "A network name is required but was not provided."
139
+ raise Error.new("A network name is required but was not provided.")
150
140
  end
151
141
  wifi_on
152
142
  os_level_connect(network_name, password)
@@ -161,7 +151,7 @@ class BaseModel
161
151
  message << %Q{connected to "#{connected_network_name}" instead.}
162
152
  end
163
153
  message << ' Did you ' << (password ? "provide the correct password?" : "need to provide a password?")
164
- raise message
154
+ raise Error.new(message)
165
155
  end
166
156
  nil
167
157
  end
@@ -181,7 +171,7 @@ class BaseModel
181
171
  if preferred_networks.include?(preferred_network_name)
182
172
  os_level_preferred_network_password(preferred_network_name)
183
173
  else
184
- raise "Network #{preferred_network_name} not in preferred networks list."
174
+ raise Error.new("Network #{preferred_network_name} not in preferred networks list.")
185
175
  end
186
176
  end
187
177
 
@@ -225,12 +215,20 @@ class BaseModel
225
215
  # @stop_condition a lambda taking the command's stdout as its sole parameter
226
216
  # @return the stdout produced by the command
227
217
  def try_os_command_until(command, stop_condition, max_tries = 100)
228
- max_tries.times do
218
+
219
+ report_attempt_count = ->(attempt_count) do
220
+ puts "Command was executed #{attempt_count} time(s)." if @verbose_mode
221
+ end
222
+
223
+ max_tries.times do |n|
229
224
  stdout = run_os_command(command)
230
225
  if stop_condition.(stdout)
226
+ report_attempt_count.(n + 1)
231
227
  return stdout
232
228
  end
233
229
  end
230
+
231
+ report_attempt_count.(max_tries)
234
232
  nil
235
233
  end
236
234
 
@@ -0,0 +1,18 @@
1
+ module WifiWand
2
+ module CommandOutputFormatter
3
+
4
+ module_function
5
+
6
+ def banner_line
7
+ @banner_line ||= '-' * 79
8
+ end
9
+
10
+ def command_attempt_as_string(command)
11
+ "\n\n#{banner_line}\nCommand: #{command}\n"
12
+ end
13
+
14
+ def command_result_as_string(output)
15
+ "#{output}#{banner_line}\n\n"
16
+ end
17
+ end
18
+ end
@@ -1,8 +1,10 @@
1
1
  require 'ipaddr'
2
2
  require 'ostruct'
3
+ require 'rexml/document'
3
4
  require 'shellwords'
4
5
 
5
6
  require_relative 'base_model'
7
+ require_relative '../error'
6
8
 
7
9
  module WifiWand
8
10
 
@@ -16,6 +18,21 @@ class MacOsModel < BaseModel
16
18
  end
17
19
 
18
20
 
21
+ # Although at this time the airport command utility is predictable,
22
+ # allow putting it elsewhere in the path for overriding and easier fix
23
+ # if that location should change.
24
+ def airport_command
25
+ airport_in_path = `which airport`.chomp
26
+ if ! airport_in_path.empty?
27
+ airport_in_path
28
+ elsif File.exist?(AIRPORT_CMD)
29
+ AIRPORT_CMD
30
+ else
31
+ raise Error.new("Airport command not found.")
32
+ end
33
+ end
34
+
35
+
19
36
  # Identifies the (first) wireless network hardware port in the system, e.g. en0 or en1
20
37
  # This may not detect wifi ports with nonstandard names, such as USB wifi devices.
21
38
  def detect_wifi_port
@@ -35,7 +52,7 @@ class MacOsModel < BaseModel
35
52
  end
36
53
 
37
54
  if wifi_port_line_num.nil?
38
- raise %Q{Wifi port (e.g. "en0") not found in output of: networksetup -listallhardwareports}
55
+ raise Error.new(%Q{Wifi port (e.g. "en0") not found in output of: networksetup -listallhardwareports})
39
56
  else
40
57
  lines[wifi_port_line_num + 1].split(': ').last
41
58
  end
@@ -56,7 +73,7 @@ class MacOsModel < BaseModel
56
73
  # "DIRECT-sq-BRAVIA 02:71:cc:87:4a:8c -76 6 Y -- WPA2(PSK/AES/AES) ", #
57
74
  def available_network_info
58
75
  return nil unless wifi_on? # no need to try
59
- command = "#{AIRPORT_CMD} -s"
76
+ command = "#{airport_command} -s"
60
77
  max_attempts = 50
61
78
 
62
79
 
@@ -87,27 +104,59 @@ class MacOsModel < BaseModel
87
104
  if output
88
105
  process_tabular_data.(output)
89
106
  else
90
- raise "Unable to get available network information after #{max_attempts} attempts."
107
+ raise Error.new("Unable to get available network information after #{max_attempts} attempts.")
91
108
  end
92
109
  end
93
110
 
94
111
 
95
- # @return an array of unique available network names only, sorted alphabetically
96
- # The reason we don't use an XML parser to get the exactly correct result is that we don't want
97
- # users to need to install any external dependencies in order to run this script.
112
+ # The Mac OS airport utility (at
113
+ # /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport)
114
+ # outputs the network names right padded with spaces so there is no way to differentiate a
115
+ # network name *with* leading space(s) from one without:
116
+ #
117
+ # SSID BSSID RSSI CHANNEL HT CC SECURITY (auth/unicast/group)
118
+ # ngHub_319442NL0293C 04:a1:51:58:5b:05 -65 11 Y US WPA2(PSK/AES/AES)
119
+ # NETGEAR89_2GEXT 9c:3d:cf:11:69:b4 -67 8 Y US NONE
120
+ #
121
+ # To remedy this, they offer a "-x" option that outputs the information in (pseudo) XML.
122
+ # This XML has 'dict' elements that contain many elements. The SSID can be found in the
123
+ # XML element <string> which immediately follows an XML element whose text is "SSID_STR".
124
+ # Unfortunately, since there is no way to connect the two other than their physical location,
125
+ # the key is rather useless for XML parsing.
126
+ #
127
+ # I tried extracting the arrays of keys and strings, and finding the string element
128
+ # at the same position in the string array as the 'SSID_STR' was in the keys array.
129
+ # However, not all keys had string elements, so the index in the key array was the wrong index.
130
+ # Here is an excerpt from the XML output:
131
+ #
132
+ # <key>RSSI</key>
133
+ # <integer>-91</integer>
134
+ # <key>SSID</key>
135
+ # <data>
136
+ # TkVUR0VBUjY1
137
+ # </data>
138
+ # <key>SSID_STR</key>
139
+ # <string>NETGEAR65</string>
140
+ #
141
+ # The kludge I came up with was that the ssid was always the 2nd value in the <string> element
142
+ # array, so that's what is used here.
143
+ #
144
+ # But now even that approach has been superseded by the XPath approach now used.
145
+ #
146
+ # REXML is used here to avoid the need for the user to install Nokogiri.
98
147
  def available_network_names
148
+ # For some reason, the airport command very often returns nothing, so we need to try until
149
+ # we get data in the response:
99
150
 
100
- # awk command below kindly provided by @nohillside at https://apple.stackexchange.com/questions/320323/how-to-programmatically-get-available-wifi-networks-without-airport-utility.
101
- command = %Q{#{AIRPORT_CMD} -s -x | awk '{ if (catch == 1) { print; catch=0 } } /SSID_STR/ { catch=1 }'}
151
+ command = "#{airport_command} -s -x"
102
152
  stop_condition = ->(response) { ! [nil, ''].include?(response) }
103
-
104
153
  output = try_os_command_until(command, stop_condition)
105
- output = output.split("\n")
106
- output.map!(&:strip)
107
- output.map! { |s| s.gsub(/<\/?string>/, '') }
108
- output.sort! { |s1, s2| s1.casecmp(s2) } # sort alphabetically, case insensitively
109
- output.uniq!
110
- output
154
+ doc = REXML::Document.new(output)
155
+ xpath = '//key[text() = "SSID_STR"][1]/following-sibling::*[1]' # provided by @ScreenStaring on Twitter
156
+ REXML::XPath.match(doc, xpath) \
157
+ .map(&:text) \
158
+ .sort { |x,y| x.casecmp(y) } \
159
+ .uniq
111
160
  end
112
161
 
113
162
 
@@ -136,7 +185,7 @@ class MacOsModel < BaseModel
136
185
 
137
186
  # Returns true if wifi is on, else false.
138
187
  def wifi_on?
139
- lines = run_os_command("#{AIRPORT_CMD} -I").split("\n")
188
+ lines = run_os_command("#{airport_command} -I").split("\n")
140
189
  lines.grep("AirPort: Off").none?
141
190
  end
142
191
 
@@ -145,7 +194,7 @@ class MacOsModel < BaseModel
145
194
  def wifi_on
146
195
  return if wifi_on?
147
196
  run_os_command("networksetup -setairportpower #{wifi_port} on")
148
- wifi_on? ? nil : raise("Wifi could not be enabled.")
197
+ wifi_on? ? nil : Error.new(raise("Wifi could not be enabled."))
149
198
  end
150
199
 
151
200
 
@@ -153,7 +202,7 @@ class MacOsModel < BaseModel
153
202
  def wifi_off
154
203
  return unless wifi_on?
155
204
  run_os_command("networksetup -setairportpower #{wifi_port} off")
156
- wifi_on? ? raise("Wifi could not be disabled.") : nil
205
+ wifi_on? ? Error.new(raise("Wifi could not be disabled.")) : nil
157
206
  end
158
207
 
159
208
 
@@ -210,7 +259,7 @@ class MacOsModel < BaseModel
210
259
 
211
260
  # Returns the network currently connected to, or nil if none.
212
261
  def connected_network_name
213
- lines = run_os_command("#{AIRPORT_CMD} -I").split("\n")
262
+ lines = run_os_command("#{airport_command} -I").split("\n")
214
263
  ssid_lines = lines.grep(/ SSID:/)
215
264
  ssid_lines.empty? ? nil : ssid_lines.first.split('SSID: ').last.lstrip
216
265
  end
@@ -218,7 +267,7 @@ class MacOsModel < BaseModel
218
267
 
219
268
  # Disconnects from the currently connected network. Does not turn off wifi.
220
269
  def disconnect
221
- run_os_command("sudo #{AIRPORT_CMD} -z")
270
+ run_os_command("sudo #{airport_command} -z")
222
271
  nil
223
272
  end
224
273
 
@@ -253,7 +302,7 @@ class MacOsModel < BaseModel
253
302
  'nameservers' => nameservers_using_scutil,
254
303
  'timestamp' => Time.now,
255
304
  }
256
- more_output = run_os_command(AIRPORT_CMD + " -I")
305
+ more_output = run_os_command(airport_command + " -I")
257
306
  more_info = colon_output_to_hash(more_output)
258
307
  info.merge!(more_info)
259
308
  info.delete('AirPort') # will be here if off, but info is already in wifi_on key
@@ -285,11 +334,12 @@ class MacOsModel < BaseModel
285
334
  end
286
335
 
287
336
  unless bad_addresses.empty?
288
- raise "Bad IP addresses provided: #{bad_addresses.join(', ')}"
337
+ raise Error.new("Bad IP addresses provided: #{bad_addresses.join(', ')}")
289
338
  end
290
339
  nameservers.join(' ')
291
340
  end
292
341
  run_os_command("networksetup -setdnsservers Wi-Fi #{arg}")
342
+ nameservers
293
343
  end
294
344
 
295
345
 
@@ -313,6 +363,7 @@ class MacOsModel < BaseModel
313
363
  end
314
364
  private :colon_output_to_hash
315
365
 
366
+
316
367
  # @return array of nameserver IP addresses from /etc/resolv.conf, or nil if not found
317
368
  # Though this is strictly *not* OS-agnostic, it will be used by most OS's,
318
369
  # and can be overridden by subclasses (e.g. Windows).
@@ -0,0 +1,60 @@
1
+ module WifiWand
2
+
3
+ class ModelValidator
4
+
5
+ BASE_MODEL_ESSENTIAL_METHODS = [
6
+ :connect,
7
+ :connected_to?,
8
+ :connected_to_internet?,
9
+ :cycle_network,
10
+ :preferred_network_password,
11
+ :public_ip_address_info,
12
+ :random_mac_address,
13
+ :remove_preferred_networks,
14
+ :run_os_command,
15
+ :till,
16
+ :try_os_command_until,
17
+ :verbose_mode,
18
+ :verbose_mode=,
19
+ :wifi_port,
20
+ :wifi_port=
21
+ ]
22
+
23
+
24
+ BASE_MODEL_NONESSENTIAL_METHODS = [
25
+ ]
26
+
27
+
28
+ MAC_OS_MODEL_ESSENTIAL_METHODS = [
29
+ :airport_command,
30
+ :available_network_info,
31
+ :available_network_names,
32
+ :connected_network_name,
33
+ :detect_wifi_port,
34
+ :disconnect,
35
+ :ip_address,
36
+ :is_wifi_port?,
37
+ :mac_address,
38
+ :nameservers_using_networksetup,
39
+ :nameservers_using_resolv_conf,
40
+ :nameservers_using_scutil,
41
+ :open_resource,
42
+ :os_level_connect,
43
+ :os_level_preferred_network_password,
44
+ :preferred_networks,
45
+ :remove_preferred_network,
46
+ :set_nameservers,
47
+ :wifi_info,
48
+ :wifi_off,
49
+ :wifi_on,
50
+ :wifi_on?
51
+ ]
52
+
53
+ MAC_OS_MODEL_ESSENTIAL_METHODS = [
54
+ ]
55
+
56
+ ALL_MODEL_METHODS = BASE_MODEL_ESSENTIAL_METHODS + MAC_OS_MODEL_ESSENTIAL_METHODS
57
+
58
+
59
+ end
60
+ end
@@ -1,3 +1,4 @@
1
+ require_relative 'error'
1
2
  require_relative 'os/base_os'
2
3
  require_relative 'os/imaginary_os'
3
4
  require_relative 'os/mac_os'
@@ -31,7 +32,7 @@ class OperatingSystems
31
32
  matches = supported_operating_systems.select { |os| os.current_os_is_this_os? }
32
33
  if matches.size > 1
33
34
  matching_names = matches.map(&:display_name)
34
- raise "There should only be 1 matching OS, but there were multiple: #{matching_names.inspect}"
35
+ raise Error.new("There should only be 1 matching OS, but there were multiple: #{matching_names.inspect}")
35
36
  end
36
37
  @current_os = matches.first
37
38
  end
@@ -39,8 +40,8 @@ class OperatingSystems
39
40
  end
40
41
 
41
42
 
42
- def current_id; current_os&.id; end
43
- def current_display_name; current_os&.display_name; end
43
+ def current_id; current_os ? current_os.id : nil; end
44
+ def current_display_name; current_os ? current_os.display_name : nil; end
44
45
 
45
46
  end
46
47
  end
@@ -1,5 +1,5 @@
1
1
  module WifiWand
2
2
 
3
- VERSION = '2.10.1'
3
+ VERSION = '2.11.0'
4
4
 
5
5
  end
data/wifi-wand.gemspec CHANGED
@@ -7,8 +7,8 @@ Gem::Specification.new do |spec|
7
7
  spec.version = WifiWand::VERSION
8
8
  spec.authors = ["Keith Bennett"]
9
9
  spec.email = ["keithrbennett@gmail.com"]
10
- spec.description = %q{A command line interface for managing wifi on a Mac.}
11
- spec.summary = %q{Mac wifi utility}
10
+ spec.description = %q{A command line interface for managing WiFi on a Mac.}
11
+ spec.summary = %q{Mac WiFi utility}
12
12
  spec.homepage = "https://github.com/keithrbennett/wifi-wand"
13
13
  spec.license = "MIT"
14
14
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wifi-wand
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.10.1
4
+ version: 2.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keith Bennett
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-04-28 00:00:00.000000000 Z
11
+ date: 2018-06-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,7 +52,7 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
- description: A command line interface for managing wifi on a Mac.
55
+ description: A command line interface for managing WiFi on a Mac.
56
56
  email:
57
57
  - keithrbennett@gmail.com
58
58
  executables:
@@ -68,9 +68,12 @@ files:
68
68
  - exe/wifi-wand
69
69
  - lib/wifi-wand.rb
70
70
  - lib/wifi-wand/command_line_interface.rb
71
+ - lib/wifi-wand/error.rb
71
72
  - lib/wifi-wand/main.rb
72
73
  - lib/wifi-wand/models/base_model.rb
74
+ - lib/wifi-wand/models/helpers/command_output_formatter.rb
73
75
  - lib/wifi-wand/models/mac_os_model.rb
76
+ - lib/wifi-wand/models/model_validator.rb
74
77
  - lib/wifi-wand/operating_systems.rb
75
78
  - lib/wifi-wand/os/base_os.rb
76
79
  - lib/wifi-wand/os/imaginary_os.rb
@@ -105,5 +108,5 @@ rubyforge_project:
105
108
  rubygems_version: 2.7.6
106
109
  signing_key:
107
110
  specification_version: 4
108
- summary: Mac wifi utility
111
+ summary: Mac WiFi utility
109
112
  test_files: []