mac-wifi 0.0.1 → 1.0.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.
Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/README.md +51 -17
  4. data/bin/mac-wifi +174 -151
  5. data/mac-wifi.gemspec +1 -1
  6. metadata +6 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5763b7c0bc11d558c50e82e2e7fd52ba6bd5e3cb
4
- data.tar.gz: 29878b297569049bff109647d9583ad6afad5a65
3
+ metadata.gz: 0ad551f63f23b9370fc52e8206e4b7314efd99e3
4
+ data.tar.gz: b2d4b85d37dc5e964f2dd7fe054233fcd54f66c6
5
5
  SHA512:
6
- metadata.gz: 5c70472f1d31785cae9a124ef5641f1157eb63549267c97773f120e4ce033588faad198bfded7f56ddb8e2eb8fbbeaae0d1ed31e20ddceaf5d0c7bd00140f8a6
7
- data.tar.gz: 32007be9ff30e8fd38996ba433386a29ee11193c868d1b37afb1bc534e11c93173c9658a116bbc66d95692a26809b8864d7a78f1e8f1d28426e3c393ba223e9b
6
+ metadata.gz: ef70403c2cbd5731e2835a79ea6334278c34746c06970cf074e3a6006e520d343d90d91db070007b7cfd7c96b065ee9e942b3f495c308cb3f56dbeee24bb7a47
7
+ data.tar.gz: 5a8ccde48e2cf1e28b9f4cdaaaa02f97ef39b4657988fd318e3f9fbc75a67e0e0f824e189eaba72de2c608c53aa65d5733c3f2d00f3bc178433608d8768fc7b4
data/Gemfile CHANGED
@@ -2,5 +2,5 @@ source "https://rubygems.org"
2
2
 
3
3
  git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
- # Specify your gem's dependencies in mac-wifi-2.gemspec
5
+ # Specify your gem's dependencies in mac-wifi.gemspec
6
6
  gemspec
data/README.md CHANGED
@@ -1,12 +1,15 @@
1
1
  # mac-wifi
2
2
 
3
- This script enables the query and management of wifi configuration and environment on a Mac.
3
+ The script installed by this gem (or otherwise copied) enables the query and management of wifi configuration and environment on a Mac.
4
+ The code encapsulates the Mac OS specific logic in a minimal class to more easily add support for other operating systems,
5
+ but as of now, only Mac OS is supported. (Feel free to add an OS!)
4
6
 
5
7
  It can be run in single-command or interactive mode. Interactive mode uses the `pry` gem,
6
8
  providing an interface familiar to Rubyists and other
7
9
  [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) users.
8
10
 
9
- It is not necessary to download this repo; this script file is all you need to run the application.
11
+ It is not necessary to download this repo or even install this gem; the `bin/mac-wifi` script file is all you need to run the application.
12
+
10
13
 
11
14
  ### Usage
12
15
 
@@ -48,6 +51,7 @@ Internally, it uses several Mac command line utilities. This is not ideal,
48
51
  I would have preferred OS system calls, but the current approach enabled me to develop
49
52
  this script quickly and simply.
50
53
 
54
+
51
55
  ### Pretty Output
52
56
 
53
57
  For nicely formatted output of the `info` command in non-interactive mode,
@@ -83,7 +87,7 @@ of stale data.
83
87
 
84
88
  If you try to run the shell, the script will require the `pry` gem, so that will need to be installed.
85
89
  `pry` in turn requires access to a `readline` library. If you encounter an error relating to finding a
86
- `readline` library, this can be fixed by installing the `pry-coolline` gem: `gem install pry-coolline`.
90
+ `readline` library, this can probably be fixed by installing the `pry-coolline` gem: `gem install pry-coolline`.
87
91
  If you are using the Ruby packaged with Mac OS, or for some other reason require root access to install
88
92
  gems, you will need to precede those commands with `sudo`:
89
93
 
@@ -105,6 +109,7 @@ session. It can be useful when:
105
109
  * you want to combine the results of commands with other OS commands
106
110
  (you can shell out to run other command line programs by preceding the command with a period (`.`).
107
111
 
112
+
108
113
  ### Using Variables in the Shell
109
114
 
110
115
  There are a couple of things (that may be surprising) to keep in mind
@@ -123,12 +128,12 @@ may override this app's commands. For example:
123
128
  => 123
124
129
  [3] pry(#<MacWifiView>)> n # 'n' no longer calls the method
125
130
  => 123
126
- [4] pry(#<MacWifiView>)> ne # but any other name starting with 'ne' will still call the method
131
+ [4] pry(#<MacWifiView>)> ne # but any other name that `network_name starts with will still call the method
127
132
  => ".@ AIS SUPER WiFi"
128
133
  [5] pry(#<MacWifiView>)> network_name
129
134
  => ".@ AIS SUPER WiFi"
130
135
  [6] pry(#<MacWifiView>)> ne_xzy123
131
- => ".@ AIS SUPER WiFi"
136
+ "ne_xyz123" is not a valid command or option. If you intend for this to be a string literal, use quotes.
132
137
  ```
133
138
 
134
139
  If you don't want to deal with this, you could use global variables, instance variables,
@@ -150,7 +155,6 @@ or constants, which will _not_ hide the methods:
150
155
  the result may be mysterious. For example, if I were write the wifi information
151
156
  to a file, this would work:
152
157
 
153
-
154
158
  ```
155
159
  [1] pry(#<MacWifiView>)> File.write('x.txt', info)
156
160
  => 431
@@ -210,8 +214,12 @@ You are connected on port en0 to .@ AIS SUPER WiFi on IP address 172.27.145.225.
210
214
  > puts "There are #{lsp.size} preferred networks."
211
215
  There are 341 preferred networks.
212
216
 
213
- # Delete all preferred networks whose names begin with "TOTTGUEST":
214
- > lsp.grep(/^TOTTGUEST/).each { |n| puts "Deleting preferred network #{n}."; rm(n) }
217
+ # Delete all preferred networks whose names begin with "TOTTGUEST", the hard way:
218
+ > lsp.grep(/^TOTTGUEST/).each { |n| rm(n) }
219
+
220
+ # Delete all preferred networks whose names begin with "TOTTGUEST", the easy way.
221
+ # rm can take multiple network names, but they must be specified as separate parameters; thus the '*'.
222
+ > rm(*lsp.grep(/^TOTTGUEST/))
215
223
 
216
224
  # Define a method to wait for the Internet connection to be active.
217
225
  # (This functionality is included in the `till` command.)
@@ -227,15 +235,34 @@ Connected!
227
235
  Connected!
228
236
  ```
229
237
 
230
- ### Cautions
231
238
 
232
- If the wifi networking changes from on to off while `till(:off)` is waiting,
233
- the program will hang indefinitely. I am currently looking into this problem.
234
- It also happens outside of this program; you can reproduce it by running `curl`,
235
- preferably on a longer running request, then turning off your wifi. This is pretty
236
- serious, and I'm considering removing the `:off` option from the `till` command.
239
+ ### Distribution, or Why All The Code is in One Humongous File
240
+
241
+ This code would be neater and easier to read if each class were in a file of its own.
242
+ The reason everything is in one file is to simplify distribution for some users.
243
+ Although installation as a gem is simple, being able to download a single file may work better when:
244
+
245
+ * the user wants to install the script once, rather than once per Ruby version and/or gemset.
246
+ * the user needs or wants to specify the exact location of the script (e.g. `~/bin`),
247
+ and/or does not want it buried in the gem directory tree (e.g. `/Users/kbennett/.rvm/gems/ruby-2.4.0/bin/mac-wifi`).
248
+ * the user is not familiar with Ruby and does not want to use the `gem` command
249
+ * the user is concerned about security and would prefer to install a single file to a known location
250
+ rather than run the gem installation
251
+ * installing gems is controlled by the user's organization, and getting authorization is not practical
252
+ * installing gems requires root access, and the user does not have root access
237
253
 
254
+ That said, installation as a gem is highly recommended, since:
238
255
 
256
+ * this will greatly simplify acquiring future fixes and enhancements
257
+ * if the user wants to use the shell mode, they will need to `gem install pry` anyway
258
+
259
+ Currently, the only gems used by the program are:
260
+
261
+ * `pry`, to provide the interactive shell
262
+ * `awesome_print` (optional), to more nicely format output in non-interactive mode
263
+
264
+ So the user can avoid installing gems altogether as long as they don't need to use the interactive shell,
265
+ and as long as they are comfortable with the less pretty output.
239
266
 
240
267
  ### Password Lookup Oddity
241
268
 
@@ -244,10 +271,17 @@ You may find it odd (I did, anyway) that even if you issue the password command
244
271
  with a graphical dialog for both a user id and password. This is no doubt
245
272
  for better security, but it's unfortunate in that it makes it impossible to fully automate this task.
246
273
 
247
- In particular, it would be nice for the `cycle` command to be able to reconnect to the original
248
- network after turning the network on. This is not possible where that network required a password.
274
+ In particular, it would be nice for the `cycle` command to be able to fetch the current network's
275
+ password, cycle the network, and then reconnect to the original network with it after turning the network on.
276
+ However, since fetching the password without user intervention is not possible, this cannot be automated.
277
+
249
278
  If you don't mind storing the network password in plain text somewhere, then you could easily
250
- automate it (e.g. `mac-wifi cycle && mac-wifi connect a-network a-password`).
279
+ automate it (e.g. `mac-wifi cycle && mac-wifi connect a-network a-password`). Also, you might find it handy
280
+ to create a script for your most commonly used networks containing something like this:
281
+
282
+ ```
283
+ mac-wifi connect my-usual-network its-password
284
+ ```
251
285
 
252
286
 
253
287
  ### License
data/bin/mac-wifi CHANGED
@@ -26,40 +26,34 @@ require 'tempfile'
26
26
  module MacWifi
27
27
 
28
28
  # This version must be kept in sync with the version in the gemspec file.
29
- VERSION = '0.0.1'
29
+ VERSION = '1.0.0'
30
30
 
31
- class Model
32
-
33
- AIRPORT_CMD = '/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport'
34
31
 
32
+ class BaseModel
35
33
 
36
34
  def initialize(verbose = false)
37
35
  @verbose_mode = verbose
38
36
  end
39
37
 
40
38
 
41
- def connected_to_internet_curl_unused?
42
-
43
- connected = false
44
-
45
- begin
46
- run_os_command('curl --silent --head http://www.google.com/')
47
- connected = true
48
- rescue OsCommandError => e
49
- if e.exitstatus == 6
50
- connected = false
51
- else
52
- raise
53
- end
54
- end
55
- connected
56
- end
57
-
58
-
59
39
  # This method returns whether or not there is a working Internet connection.
60
40
  # Because of a Mac issue which causes a request to hang if the network is turned
61
41
  # off during its lifetime, we give it only 5 seconds per try,
62
42
  # and limit the number of tries to 3.
43
+ #
44
+ # This implementation will probably strike you as overly complex. The following
45
+ # code looks like it is all that should be necessary, but unfortunately
46
+ # this implementation often hangs when wifi is turned off while curl is active
47
+ #
48
+ # def connected_to_internet?
49
+ # script = "curl --silent --head http://www.google.com/ > /dev/null ; echo $?"
50
+ # result = `#{script}`.chomp
51
+ # puts result
52
+ # result == '0'
53
+ # end
54
+
55
+ # TODO Investigate using Curl options: --connect-timeout 1 --max-time 2 --retry 0
56
+ # to greatly simplify this method.
63
57
  def connected_to_internet?
64
58
 
65
59
  tempfile = Tempfile.open('mac-wifi-')
@@ -94,7 +88,7 @@ class Model
94
88
  return get_connected_state_from_curl.()
95
89
  end
96
90
  end
97
- Process.kill('KILL', pid)
91
+ Process.kill('KILL', pid) if process_is_running.(pid)
98
92
  :hung
99
93
  end
100
94
 
@@ -111,13 +105,109 @@ class Model
111
105
 
112
106
  end
113
107
 
114
- # This implementation often hangs when wifi is turned off while curl is active
115
- # def connected_to_internet?
116
- # script = "curl --silent --head http://www.google.com/ > /dev/null ; echo $?"
117
- # result = `#{script}`.chomp
118
- # puts result
119
- # result == '0'
120
- # end
108
+
109
+ # Turns wifi off and then on, reconnecting to the originally connecting network.
110
+ def cycle_network
111
+ # TODO: Make this network name saving and restoring conditional on it not having a password.
112
+ # If the disabled code below is enabled, an error will be raised if a password is required,
113
+ # even though it is stored.
114
+ # network_name = current_network
115
+ wifi_off
116
+ wifi_on
117
+ # connect(network_name) if network_name
118
+ end
119
+
120
+
121
+ def connected_to?(network_name)
122
+ network_name == connected_network_name
123
+ end
124
+
125
+
126
+ # Connects to the passed network name, optionally with password.
127
+ # Turns wifi on first, in case it was turned off.
128
+ # Relies on subclass implementation of simple_connect().
129
+ def connect(network_name, password = nil)
130
+ if network_name.nil? || network_name.empty?
131
+ raise "A network name is required but was not provided."
132
+ end
133
+ wifi_on
134
+ simple_connect(network_name, password)
135
+
136
+ # Verify that the network is now connected:
137
+ actual_network_name = connected_network_name
138
+ unless actual_network_name == network_name
139
+ message = %Q{Expected to connect to "#{network_name}" but }
140
+ if actual_network_name
141
+ message << %Q{connected to "#{connected_network_name}" instead.}
142
+ else
143
+ message << "unable to connect to any network. Did you "
144
+ end
145
+ message << (password ? "provide the correct password?" : "need to provide a password?")
146
+ raise message
147
+ end
148
+ nil
149
+ end
150
+
151
+
152
+ # Removes the specified network(s) from the preferred network list.
153
+ # @param network_names names of networks to remove; may be empty or contain nonexistent networks
154
+ # @return names of the networks that were removed (excludes non-preexisting networks)
155
+ def remove_preferred_networks(*network_names)
156
+ networks_to_remove = network_names & preferred_networks # exclude any nonexistent networks
157
+ networks_to_remove.each do |name|
158
+ run_os_command("sudo networksetup -removepreferredwirelessnetwork " +
159
+ "#{wifi_hardware_port} #{Shellwords.shellescape(name)}")
160
+ end
161
+ networks_to_remove
162
+ end
163
+
164
+
165
+ def preferred_network_password(preferred_network_name)
166
+ if preferred_networks.include?(preferred_network_name)
167
+ simple_preferred_network_password(preferred_network_name)
168
+ else
169
+ raise "Network #{preferred_network_name} not in preferred networks list."
170
+ end
171
+ end
172
+
173
+
174
+ # Waits for the Internet connection to be in the desired state.
175
+ # @param status must be in [:conn, :disc, :off, :on]; waits for that state
176
+ # @param wait_interval_in_secs sleeps this interval between retries
177
+ #
178
+ def till(status, wait_interval_in_secs = nil)
179
+
180
+ wait_interval_in_secs ||= 0.5
181
+
182
+ exit_when = case status
183
+ when :conn
184
+ -> { connected_to_internet? }
185
+ when :disc
186
+ -> { ! connected_to_internet? }
187
+ when :on
188
+ -> { wifi_on? }
189
+ when :off
190
+ -> { ! wifi_on? }
191
+ else
192
+ raise ArgumentError.new("Option must be one of [:conn, :disc, :off, :on]. Was: #{status.inspect}")
193
+ end
194
+
195
+ loop do
196
+ return if exit_when.()
197
+ sleep(wait_interval_in_secs)
198
+ end
199
+ end
200
+
201
+ end
202
+
203
+
204
+ class MacOsModel < BaseModel
205
+
206
+ AIRPORT_CMD = '/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport'
207
+
208
+ def initialize(verbose)
209
+ super
210
+ end
121
211
 
122
212
 
123
213
  # This is determined by whether or not a line like the following appears in the output of `netstat -nr`:
@@ -205,54 +295,18 @@ class Model
205
295
  end
206
296
 
207
297
 
208
- # Turns wifi off and then on, reconnecting to the originally connecting network.
209
- def cycle_network
210
- # TODO: Make this network name saving and restoring conditional on it not having a password.
211
- # If the disabled code below is enabled, an error will be raised if a password is required,
212
- # even though it is stored.
213
- # network_name = current_network
214
- wifi_off
215
- wifi_on
216
- # connect(network_name) if network_name
217
- end
218
-
219
-
220
298
  def connected_network_name
221
299
  wifi_info['SSID']
222
300
  end
223
301
 
224
302
 
225
- def connected_to?(network_name)
226
- network_name == connected_network_name
227
- end
228
-
229
-
230
- # Connects to the passed network name, optionally with password.
231
- # Turns wifi on first, in case it was turned off.
232
- def connect(network_name, password = nil)
233
- if network_name.nil? || network_name.empty?
234
- raise "A network name is required but was not provided."
235
- end
236
- wifi_on
303
+ # This method is called by BaseModel#connect to do the OS-specific connection logic.
304
+ def simple_connect(network_name, password = nil)
237
305
  command = "networksetup -setairportnetwork #{wifi_hardware_port} " + "#{Shellwords.shellescape(network_name)}"
238
306
  if password
239
307
  command << ' ' << Shellwords.shellescape(password)
240
308
  end
241
309
  run_os_command(command)
242
-
243
- # Verify that the network is now connected:
244
- actual_network_name = connected_network_name
245
- unless actual_network_name == network_name
246
- message = %Q{Expected to connect to "#{network_name}" but }
247
- if actual_network_name
248
- message << %Q{connected to "#{connected_network_name}" instead.}
249
- else
250
- message << "unable to connect to any network. Did you "
251
- end
252
- message << (password ? "provide the correct password?" : "need to provide a password?")
253
- raise message
254
- end
255
- nil
256
310
  end
257
311
 
258
312
 
@@ -262,20 +316,16 @@ class Model
262
316
  # If not, return nil
263
317
  # else
264
318
  # raise an error
265
- def preferred_network_password(preferred_network_name)
266
- if preferred_networks.include?(preferred_network_name)
267
- command = %Q{security find-generic-password -D "AirPort network password" -a "#{preferred_network_name}" -w 2>&1}
268
- begin
269
- return run_os_command(command).chomp
270
- rescue OsCommandError => error
271
- if error.exitstatus == 44 # network has no password stored
272
- nil
273
- else
274
- raise
275
- end
319
+ def simple_preferred_network_password(preferred_network_name)
320
+ command = %Q{security find-generic-password -D "AirPort network password" -a "#{preferred_network_name}" -w 2>&1}
321
+ begin
322
+ return run_os_command(command).chomp
323
+ rescue OsCommandError => error
324
+ if error.exitstatus == 44 # network has no password stored
325
+ nil
326
+ else
327
+ raise
276
328
  end
277
- else
278
- raise "Network #{preferred_network_name} not in preferred networks list."
279
329
  end
280
330
  end
281
331
 
@@ -294,16 +344,9 @@ class Model
294
344
  end
295
345
 
296
346
 
297
- # Removes the specified network(s) from the preferred network list.
298
- # @param network_names names of networks to remove; may be empty or contain nonexistent networks
299
- # @return names of the networks that were removed (excludes non-preexisting networks)
300
- def remove_preferred_networks(*network_names)
301
- networks_to_remove = network_names & preferred_networks # exclude any nonexistent networks
302
- networks_to_remove.each do |name|
303
- run_os_command("sudo networksetup -removepreferredwirelessnetwork " +
304
- "#{wifi_hardware_port} #{Shellwords.shellescape(name)}")
305
- end
306
- networks_to_remove
347
+ def remove_preferred_network(network_name)
348
+ run_os_command("sudo networksetup -removepreferredwirelessnetwork " +
349
+ "#{wifi_hardware_port} #{Shellwords.shellescape(network_name)}")
307
350
  end
308
351
 
309
352
 
@@ -342,46 +385,17 @@ class Model
342
385
  end
343
386
 
344
387
 
345
- # Waits for the Internet connection to be in the desired state.
346
- # @param status must be in [:conn, :disc, :off, :on]; waits for that state
347
- # @param wait_interval_in_secs sleeps this interval between retries
348
- #
349
- # NOTE!: This is experimental and sometimes hangs.
350
- def till(status, wait_interval_in_secs = nil)
351
-
352
- wait_interval_in_secs ||= 0.5
353
-
354
- exit_when = case status
355
- when :conn
356
- -> { connected_to_internet? }
357
- when :disc
358
- -> { ! connected_to_internet? }
359
- when :on
360
- -> { wifi_on? }
361
- when :off
362
- -> { ! wifi_on? }
363
- else
364
- raise ArgumentError.new("Option must be one of [:conn, :disc, :off, :on]. Was: #{status.inspect}")
365
- end
388
+ class OsCommandError < RuntimeError
389
+ attr_reader :exitstatus, :command, :text
366
390
 
367
- loop do
368
- return if exit_when.()
369
- sleep(wait_interval_in_secs)
391
+ def initialize(exitstatus, command, text)
392
+ @exitstatus = exitstatus
393
+ @command = command
394
+ @text = text
370
395
  end
371
396
  end
372
397
 
373
398
 
374
- class OsCommandError < RuntimeError
375
- attr_reader :exitstatus, :command, :text
376
-
377
- def initialize(exitstatus, command, text)
378
- @exitstatus = exitstatus
379
- @command = command
380
- @text = text
381
- end
382
- end
383
-
384
-
385
399
  def run_os_command(command)
386
400
  output = `#{command} 2>&1` # join stderr with stdout
387
401
  if $?.exitstatus != 0
@@ -435,7 +449,7 @@ pa[ssword] network-name - shows password for preferred network-name
435
449
  q[uit] - exits this program (interactive shell mode only)
436
450
  r[m] network-name - removes network-name from the preferred networks list
437
451
  s[hell] - opens an interactive pry shell (command line only)
438
- t[ill] - (experimental!) returns when the desired Internet connection state is true. Options:
452
+ t[ill] - returns when the desired Internet connection state is true. Options:
439
453
  'on'/:on or 'off'/:off
440
454
  wait interval, in seconds (optional, defaults to 0.5 seconds)
441
455
  w[ifion] - is the wifi on?
@@ -449,12 +463,12 @@ When in interactive shell mode:
449
463
 
450
464
 
451
465
  def initialize
452
- @model = Model.new(verbose_mode)
466
+ @model = MacOsModel.new(verbose_mode)
453
467
  @interactive_mode = false # will be true if/when user selects shell option on command line
454
468
  end
455
469
 
456
470
 
457
- class Command < Struct.new(:regex, :action); end
471
+ class Command < Struct.new(:min_string, :max_string, :action); end
458
472
 
459
473
 
460
474
  class BadCommandError < RuntimeError
@@ -557,7 +571,8 @@ When in interactive shell mode:
557
571
 
558
572
  # For use by the shell; when typing a command and options, it is passed to process_command_line
559
573
  def method_missing(method_name, *options)
560
- method_valid = !! find_command_action(method_name.to_s)
574
+ method_name = method_name.to_s
575
+ method_valid = !! find_command_action(method_name)
561
576
  if method_valid
562
577
  process_command_line(method_name, options)
563
578
  else
@@ -703,30 +718,30 @@ When in interactive shell mode:
703
718
 
704
719
  def commands
705
720
  @commands_ ||= [
706
- Command.new(/^ci/, -> (*_options) { cmd_ci }),
707
- Command.new(/^co/, -> (*options) { cmd_co(*options) }),
708
- Command.new(/^cy/, -> (*_options) { cmd_cy }),
709
- Command.new(/^d/, -> (*_options) { cmd_d }),
710
- Command.new(/^h/, -> (*_options) { cmd_h }),
711
- Command.new(/^i/, -> (*_options) { cmd_i }),
712
- Command.new(/^lsa/, -> (*_options) { cmd_lsa }),
713
- Command.new(/^lsp/, -> (*_options) { cmd_lsp }),
714
- Command.new(/^n/, -> (*_options) { cmd_n }),
715
- Command.new(/^of/, -> (*_options) { cmd_of }),
716
- Command.new(/^on/, -> (*_options) { cmd_on }),
717
- Command.new(/^pa/, -> (*options) { cmd_pa(*options) }),
718
- Command.new(/^q/, -> (*_options) { cmd_q }),
719
- Command.new(/^r/, -> (*options) { cmd_r(*options) }),
720
- Command.new(/^s/, -> (*_options) { cmd_s }),
721
- Command.new(/^t/, -> (*options) { cmd_t(*options) }),
722
- Command.new(/^w/, -> (*_options) { cmd_w }),
723
- Command.new(/^x/, -> (*_options) { cmd_x })
721
+ Command.new('ci', 'ci', -> (*_options) { cmd_ci }),
722
+ Command.new('co', 'connect', -> (*options) { cmd_co(*options) }),
723
+ Command.new('cy', 'cycle', -> (*_options) { cmd_cy }),
724
+ Command.new('d', 'disconnect', -> (*_options) { cmd_d }),
725
+ Command.new('h', 'help', -> (*_options) { cmd_h }),
726
+ Command.new('i', 'info', -> (*_options) { cmd_i }),
727
+ Command.new('lsa', 'lsavailable', -> (*_options) { cmd_lsa }),
728
+ Command.new('lsp', 'lspreferred', -> (*_options) { cmd_lsp }),
729
+ Command.new('n', 'network_name', -> (*_options) { cmd_n }),
730
+ Command.new('of', 'off', -> (*_options) { cmd_of }),
731
+ Command.new('on', 'on', -> (*_options) { cmd_on }),
732
+ Command.new('pa', 'password', -> (*options) { cmd_pa(*options) }),
733
+ Command.new('q', 'quit', -> (*_options) { cmd_q }),
734
+ Command.new('r', 'rm', -> (*options) { cmd_r(*options) }),
735
+ Command.new('s', 'shell', -> (*_options) { cmd_s }),
736
+ Command.new('t', 'till', -> (*options) { cmd_t(*options) }),
737
+ Command.new('w', 'wifion', -> (*_options) { cmd_w }),
738
+ Command.new('x', 'xit', -> (*_options) { cmd_x })
724
739
  ]
725
740
  end
726
741
 
727
742
 
728
743
  def find_command_action(command_string)
729
- result = commands.detect { |cmd| cmd.regex.match(command_string) }
744
+ result = commands.detect { |cmd| cmd.max_string.start_with?(command_string) }
730
745
  result ? result.action : nil
731
746
  end
732
747
 
@@ -741,12 +756,11 @@ When in interactive shell mode:
741
756
  exit(-1)
742
757
  end
743
758
  end
744
-
745
759
  end
746
-
747
760
  end
748
761
 
749
762
 
763
+
750
764
  # @return true if this file is being run as a script, else false
751
765
  #
752
766
  # This file could be called as a script in either of these two ways:
@@ -763,6 +777,15 @@ def running_as_script?
763
777
  end
764
778
 
765
779
 
780
+ def assert_os_is_mac_os
781
+ uname = `uname`.chomp
782
+ unless uname == 'Darwin'
783
+ raise "This program currently works only on Mac OS. Platform is '#{uname}'."
784
+ end
785
+ end
786
+
787
+ assert_os_is_mac_os
788
+
766
789
  # If this file is being called as a script, run it.
767
790
  # Else, it may be loaded to use the model in a different way.
768
791
  if running_as_script?
data/mac-wifi.gemspec CHANGED
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
- VERSION = '0.0.1'
2
+ VERSION = '1.0.0'
3
3
 
4
4
  Gem::Specification.new do |spec|
5
5
  spec.name = "mac-wifi"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mac-wifi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keith Bennett
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-17 00:00:00.000000000 Z
11
+ date: 2017-09-24 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A command line interface for managing wifi on a Mac.
14
14
  email:
@@ -29,7 +29,7 @@ homepage: https://github.com/keithrbennett/mac-wifi
29
29
  licenses:
30
30
  - MIT
31
31
  metadata: {}
32
- post_install_message:
32
+ post_install_message:
33
33
  rdoc_options: []
34
34
  require_paths:
35
35
  - lib
@@ -44,9 +44,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
46
  requirements: []
47
- rubyforge_project:
47
+ rubyforge_project:
48
48
  rubygems_version: 2.6.13
49
- signing_key:
49
+ signing_key:
50
50
  specification_version: 4
51
51
  summary: Mac wifi utility
52
52
  test_files: