mac-wifi 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: