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.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/README.md +51 -17
- data/bin/mac-wifi +174 -151
- data/mac-wifi.gemspec +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ad551f63f23b9370fc52e8206e4b7314efd99e3
|
4
|
+
data.tar.gz: b2d4b85d37dc5e964f2dd7fe054233fcd54f66c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef70403c2cbd5731e2835a79ea6334278c34746c06970cf074e3a6006e520d343d90d91db070007b7cfd7c96b065ee9e942b3f495c308cb3f56dbeee24bb7a47
|
7
|
+
data.tar.gz: 5a8ccde48e2cf1e28b9f4cdaaaa02f97ef39b4657988fd318e3f9fbc75a67e0e0f824e189eaba72de2c608c53aa65d5733c3f2d00f3bc178433608d8768fc7b4
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
# mac-wifi
|
2
2
|
|
3
|
-
|
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
|
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
|
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
|
-
|
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|
|
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
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
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
|
248
|
-
|
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
|
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
|
-
|
115
|
-
#
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
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
|
-
|
226
|
-
|
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
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
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
|
-
|
298
|
-
|
299
|
-
|
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
|
-
|
346
|
-
|
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
|
-
|
368
|
-
|
369
|
-
|
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] -
|
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 =
|
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(:
|
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
|
-
|
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(
|
707
|
-
Command.new(
|
708
|
-
Command.new(
|
709
|
-
Command.new(
|
710
|
-
Command.new(
|
711
|
-
Command.new(
|
712
|
-
Command.new(
|
713
|
-
Command.new(
|
714
|
-
Command.new(
|
715
|
-
Command.new(
|
716
|
-
Command.new(
|
717
|
-
Command.new(
|
718
|
-
Command.new(
|
719
|
-
Command.new(
|
720
|
-
Command.new(
|
721
|
-
Command.new(
|
722
|
-
Command.new(
|
723
|
-
Command.new(
|
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.
|
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
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
|
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-
|
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:
|