mac-wifi 1.3.0 → 2.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.
data/exe/mac-wifi CHANGED
@@ -19,13 +19,16 @@
19
19
  # License: MIT License
20
20
 
21
21
 
22
+ require 'json'
23
+ require 'yaml'
24
+
22
25
  require 'shellwords'
23
26
  require 'tempfile'
24
27
 
25
28
  module MacWifi
26
29
 
27
30
  # This version must be kept in sync with the version in the gemspec file.
28
- VERSION = '1.3.0'
31
+ VERSION = '2.0.0'
29
32
 
30
33
 
31
34
  class BaseModel
@@ -46,6 +49,19 @@ class BaseModel
46
49
  end
47
50
 
48
51
 
52
+ def run_os_command(command)
53
+ output = `#{command} 2>&1` # join stderr with stdout
54
+ if $?.exitstatus != 0
55
+ raise OsCommandError.new($?.exitstatus, command, output)
56
+ end
57
+ if @verbose_mode
58
+ puts "\n\n#{'-' * 79}\nCommand: #{command}\n\nOutput:\n#{output}#{'-' * 79}\n\n"
59
+ end
60
+ output
61
+ end
62
+ private :run_os_command
63
+
64
+
49
65
  # This method returns whether or not there is a working Internet connection.
50
66
  # Because of a Mac issue which causes a request to hang if the network is turned
51
67
  # off during its lifetime, we give it only 5 seconds per try,
@@ -135,7 +151,7 @@ class BaseModel
135
151
 
136
152
  # Connects to the passed network name, optionally with password.
137
153
  # Turns wifi on first, in case it was turned off.
138
- # Relies on subclass implementation of simple_connect().
154
+ # Relies on subclass implementation of os_level_connect().
139
155
  def connect(network_name, password = nil)
140
156
  # Allow symbols and anything responding to to_s for user convenience
141
157
  network_name = network_name.to_s if network_name
@@ -145,7 +161,7 @@ class BaseModel
145
161
  raise "A network name is required but was not provided."
146
162
  end
147
163
  wifi_on
148
- simple_connect(network_name, password)
164
+ os_level_connect(network_name, password)
149
165
 
150
166
  # Verify that the network is now connected:
151
167
  actual_network_name = connected_network_name
@@ -175,7 +191,7 @@ class BaseModel
175
191
  def preferred_network_password(preferred_network_name)
176
192
  preferred_network_name = preferred_network_name.to_s
177
193
  if preferred_networks.include?(preferred_network_name)
178
- simple_preferred_network_password(preferred_network_name)
194
+ os_level_preferred_network_password(preferred_network_name)
179
195
  else
180
196
  raise "Network #{preferred_network_name} not in preferred networks list."
181
197
  end
@@ -214,6 +230,21 @@ class BaseModel
214
230
  sleep(wait_interval_in_secs)
215
231
  end
216
232
  end
233
+
234
+
235
+ # Tries an OS command until the stop condition is true.
236
+ # @command the command to run in the OS
237
+ # @stop_condition a lambda taking the commands stdout as its sole parameter
238
+ # @return the stdout produced by the command
239
+ def try_os_command_until(command, stop_condition, max_tries = 100)
240
+ max_tries.times do
241
+ stdout = run_os_command(command)
242
+ if stop_condition.(stdout)
243
+ return stdout
244
+ end
245
+ end
246
+ nil
247
+ end
217
248
  end
218
249
 
219
250
 
@@ -266,37 +297,99 @@ class MacOsModel < BaseModel
266
297
  command = "#{AIRPORT_CMD} -s"
267
298
  max_attempts = 50
268
299
 
300
+
269
301
  reformat_line = ->(line) do
270
302
  ssid = line[0..31].strip
271
303
  "%-32.32s%s" % [ssid, line[32..-1]]
272
304
  end
273
305
 
274
- max_attempts.times do
275
- output = run_os_command(command)
276
- if output.size > 0
277
- lines = output.split("\n")
278
- header_line = lines[0]
279
- data_lines = lines[1..-1]
280
- data_lines.map! do |line|
281
- # Reformat the line so that the name is left instead of right justified
282
- reformat_line.(line)
283
- end
284
- data_lines.sort!
285
- return [reformat_line.(header_line)] + data_lines
306
+
307
+ process_tabular_data = ->(output) do
308
+ lines = output.split("\n")
309
+ header_line = lines[0]
310
+ data_lines = lines[1..-1]
311
+ data_lines.map! do |line|
312
+ # Reformat the line so that the name is left instead of right justified
313
+ reformat_line.(line)
286
314
  end
315
+ data_lines.sort!
316
+ [reformat_line.(header_line)] + data_lines
287
317
  end
288
318
 
289
319
 
290
- raise "Unable to get available network information after #{max_attempts} attempts."
320
+ output = try_os_command_until(command, ->(output) do
321
+ ! ([nil, ''].include?(output))
322
+ end)
323
+
324
+ if output
325
+ process_tabular_data.(output)
326
+ else
327
+ raise "Unable to get available network information after #{max_attempts} attempts."
328
+ end
291
329
  end
292
330
 
293
331
 
294
- # @return an array of unique available network names only, sorted alphabetically
295
- def available_network_names
296
- available_network_info[1..-1] \
332
+ def parse_network_names(info)
333
+ if info.nil?
334
+ nil
335
+ else
336
+ info[1..-1] \
297
337
  .map { |line| line[0..32].rstrip } \
298
338
  .uniq \
299
339
  .sort { |s1, s2| s1.casecmp(s2) }
340
+ end
341
+ end
342
+
343
+ # @return an array of unique available network names only, sorted alphabetically
344
+ # Kludge alert: the tabular data does not differentiate between strings with and without leading whitespace
345
+ # Therefore, we get the data once in tabular format, and another time in XML format.
346
+ # The XML element will include any leading whitespace. However, it includes all <string> elements,
347
+ # many of which are not network names.
348
+ # As an improved approximation of the correct result, for each network name found in tabular mode,
349
+ # we look to see if there is a corresponding string element with leading whitespace, and, if so,
350
+ # replace it.
351
+ #
352
+ # This will not behave correctly if a given name has occurrences with different amounts of whitespace,
353
+ # e.g. ' x' and ' x'.
354
+ #
355
+ # The reason we don't use an XML parser to get the exactly correct result is that we don't want
356
+ # users to need to install any external dependencies in order to run this script.
357
+ def available_network_names
358
+
359
+ # Parses the XML text (using grep, not XML parsing) to find
360
+ # <string> elements, and extracts the network name candidates
361
+ # containing leading spaces from it.
362
+ get_leading_space_names = ->(text) do
363
+ text.split("\n") \
364
+ .grep(%r{<string>}) \
365
+ .sort \
366
+ .uniq \
367
+ .map { |line| line.gsub("<string>", '').gsub('</string>', '').gsub("\t", '') } \
368
+ .select { |s| s[0] == ' ' }
369
+ end
370
+
371
+
372
+ output_is_valid = ->(output) { ! ([nil, ''].include?(output)) }
373
+ tabular_data = try_os_command_until("#{AIRPORT_CMD} -s", output_is_valid)
374
+ xml_data = try_os_command_until("#{AIRPORT_CMD} -s -x", output_is_valid)
375
+
376
+ if tabular_data.nil? || xml_data.nil?
377
+ raise "Unable to get available network information; please try again."
378
+ end
379
+
380
+ tabular_data_lines = tabular_data[1..-1] # omit header line
381
+ names_no_spaces = parse_network_names(tabular_data_lines.split("\n")).map(&:strip)
382
+ names_maybe_spaces = get_leading_space_names.(xml_data)
383
+
384
+ names = names_no_spaces.map do |name_no_spaces|
385
+ match = names_maybe_spaces.detect do |name_maybe_spaces|
386
+ %r{[ \t]?#{name_no_spaces}$}.match(name_maybe_spaces)
387
+ end
388
+
389
+ match ? match : name_no_spaces
390
+ end
391
+
392
+ names.sort { |s1, s2| s1.casecmp(s2) } # sort alphabetically, case insensitively
300
393
  end
301
394
 
302
395
 
@@ -344,7 +437,7 @@ class MacOsModel < BaseModel
344
437
 
345
438
 
346
439
  # This method is called by BaseModel#connect to do the OS-specific connection logic.
347
- def simple_connect(network_name, password = nil)
440
+ def os_level_connect(network_name, password = nil)
348
441
  command = "networksetup -setairportnetwork #{wifi_hardware_port} " + "#{Shellwords.shellescape(network_name)}"
349
442
  if password
350
443
  command << ' ' << Shellwords.shellescape(password)
@@ -359,7 +452,7 @@ class MacOsModel < BaseModel
359
452
  # If not, return nil
360
453
  # else
361
454
  # raise an error
362
- def simple_preferred_network_password(preferred_network_name)
455
+ def os_level_preferred_network_password(preferred_network_name)
363
456
  command = %Q{security find-generic-password -D "AirPort network password" -a "#{preferred_network_name}" -w 2>&1}
364
457
  begin
365
458
  return run_os_command(command).chomp
@@ -429,19 +522,6 @@ class MacOsModel < BaseModel
429
522
  end
430
523
 
431
524
 
432
- def run_os_command(command)
433
- output = `#{command} 2>&1` # join stderr with stdout
434
- if $?.exitstatus != 0
435
- raise OsCommandError.new($?.exitstatus, command, output)
436
- end
437
- if @verbose_mode
438
- puts "\n\n#{'-' * 79}\nCommand: #{command}\n\nOutput:\n#{output}#{'-' * 79}\n\n"
439
- end
440
- output
441
- end
442
- private :run_os_command
443
-
444
-
445
525
  # Parses output like the text below into a hash:
446
526
  # SSID: Pattara211
447
527
  # MCS: 5
@@ -461,7 +541,7 @@ end
461
541
 
462
542
  class CommandLineInterface
463
543
 
464
- attr_reader :model, :interactive_mode
544
+ attr_reader :model, :interactive_mode, :options
465
545
 
466
546
  class Command < Struct.new(:min_string, :max_string, :action); end
467
547
 
@@ -475,23 +555,29 @@ class CommandLineInterface
475
555
 
476
556
  # Help text to be used when requested by 'h' command, in case of unrecognized or nonexistent command, etc.
477
557
  HELP_TEXT = "
478
- mac-wifi version #{VERSION} -- Available commands are:
558
+ Command Line Switches: [mac-wifi version #{VERSION}]
559
+
560
+ -o[i,j,p,y] - outputs data in inspect, JSON, puts, or YAML format when not in shell mode
561
+ -s - run in shell mode
562
+ -v - verbose mode (prints OS commands and their outputs)
563
+
564
+ Commands:
479
565
 
480
- a[vailnets] - array of names of the available networks
566
+ a[vail_nets] - array of names of the available networks
481
567
  ci - connected to Internet (not just wifi on)?
482
568
  co[nnect] network-name - turns wifi on, connects to network-name
483
569
  cy[cle] - turns wifi off, then on, preserving network selection
484
570
  d[isconnect] - disconnects from current network, does not turn off wifi
485
571
  h[elp] - prints this help
486
572
  i[nfo] - a hash of wifi-related information
487
- l[savailnets] - details about available networks
573
+ l[s_avail_nets] - details about available networks
488
574
  n[etwork_name] - name (SSID) of currently connected network
489
575
  on - turns wifi on
490
576
  of[f] - turns wifi off
491
577
  pa[ssword] network-name - password for preferred network-name
492
- pr[efnets] - preferred (not necessarily available) networks
578
+ pr[ef_nets] - preferred (not necessarily available) networks
493
579
  q[uit] - exits this program (interactive shell mode only) (see also 'x')
494
- r[mprefnets] network-name - removes network-name from the preferred networks list
580
+ r[m_pref_nets] network-name - removes network-name from the preferred networks list
495
581
  (can provide multiple names separated by spaces)
496
582
  s[hell] - opens an interactive pry shell (command line only)
497
583
  t[ill] - returns when the desired Internet connection state is true. Options:
@@ -507,16 +593,18 @@ When in interactive shell mode:
507
593
  "
508
594
 
509
595
 
510
- def initialize
596
+ def initialize(options)
597
+ @options = options
511
598
  @model = MacOsModel.new(verbose_mode)
512
- @interactive_mode = false # will be changed to true if/when user selects shell option on command line
599
+ @interactive_mode = !!(options.interactive_mode)
600
+ run_shell if @interactive_mode
513
601
  end
514
602
 
515
603
 
516
604
  # Until command line option parsing is added, the only way to specify
517
605
  # verbose mode is in the environment variable MAC_WIFI_OPTS.
518
606
  def verbose_mode
519
- /-v/.match(ENV['MAC_WIFI_OPTS'])
607
+ options.verbose
520
608
  end
521
609
 
522
610
 
@@ -563,7 +651,7 @@ When in interactive shell mode:
563
651
  # Asserts that a command has been passed on the command line.
564
652
  def validate_command_line
565
653
  if ARGV.empty?
566
- puts "Syntax is: #{__FILE__} command [options]"
654
+ puts "Syntax is: #{__FILE__} [options] command [command_options]"
567
655
  print_help
568
656
  exit(-1)
569
657
  end
@@ -575,23 +663,16 @@ When in interactive shell mode:
575
663
  # that is not needed here.
576
664
  def run_pry
577
665
  binding.pry
666
+
667
+ # the seemingly useless line below is needed to avoid pry's exiting
668
+ # (see https://github.com/deivid-rodriguez/pry-byebug/issues/45)
669
+ _a = nil
578
670
  end
579
671
 
580
672
 
581
673
  # Runs a pry session in the context of this object.
582
674
  # Commands and options specified on the command line can also be specified in the shell.
583
675
  def run_shell
584
- if interactive_mode
585
- puts "Already in shell."
586
- return
587
- end
588
-
589
- @interactive_mode = true
590
-
591
- # For conveniently calling to_json or to_yaml on an object:
592
- require 'json'
593
- require 'yaml'
594
-
595
676
  begin
596
677
  require 'pry'
597
678
  rescue LoadError
@@ -656,15 +737,30 @@ When in interactive shell mode:
656
737
 
657
738
  def cmd_a
658
739
  info = model.available_network_names
659
- puts_unless_interactive(fancy_string(info))
660
- info
740
+ if interactive_mode
741
+ info
742
+ else
743
+ if post_processor
744
+ puts post_processor.(info)
745
+ else
746
+ message = if model.wifi_on?
747
+ "Available networks are:\n\n#{fancy_string(info)}"
748
+ else
749
+ "Wifi is off, cannot see available networks."
750
+ end
751
+ puts(message)
752
+ end
753
+ end
661
754
  end
662
755
 
663
756
 
664
757
  def cmd_ci
665
758
  connected = model.connected_to_internet?
666
- puts_unless_interactive("Connected to Internet: #{connected}")
667
- connected
759
+ if interactive_mode
760
+ connected
761
+ else
762
+ puts (post_processor ? post_processor.(connected) : "Connected to Internet: #{connected}")
763
+ end
668
764
  end
669
765
 
670
766
 
@@ -690,22 +786,41 @@ When in interactive shell mode:
690
786
 
691
787
  def cmd_i
692
788
  info = model.wifi_info
693
- puts_unless_interactive(fancy_string(info))
694
- info
789
+ if interactive_mode
790
+ info
791
+ else
792
+ if post_processor
793
+ puts post_processor.(info)
794
+ else
795
+ puts fancy_string(info)
796
+ end
797
+ end
695
798
  end
696
799
 
697
800
 
698
801
  def cmd_lsa
699
802
  info = model.available_network_info
700
- puts_unless_interactive(fancy_string(info))
701
- info
803
+ if interactive_mode
804
+ info
805
+ else
806
+ if post_processor
807
+ puts post_processor.(info)
808
+ else
809
+ message = model.wifi_on? ? fancy_string(info) : "Wifi is off, cannot see available networks."
810
+ puts(message)
811
+ end
812
+ end
702
813
  end
703
814
 
704
815
 
705
816
  def cmd_n
706
817
  name = model.connected_network_name
707
- puts_unless_interactive("Network (SSID) name: #{name ? name : '[none]'}")
708
- name
818
+ if interactive_mode
819
+ name
820
+ else
821
+ display_name = name ? name : '[none]'
822
+ puts (post_processor ? post_processor.(name) : %Q{Network (SSID) name: "#{display_name}"})
823
+ end
709
824
  end
710
825
 
711
826
 
@@ -722,20 +837,27 @@ When in interactive shell mode:
722
837
  def cmd_pa(network)
723
838
  password = model.preferred_network_password(network)
724
839
 
725
- unless interactive_mode
726
- output = %Q{Preferred network "#{network_name}" }
727
- output << (password ? %Q{stored password is: "#{password}".} : "has no stored password.")
728
- puts output
840
+ if interactive_mode
841
+ password
842
+ else
843
+ if post_processor
844
+ puts post_processor.(password)
845
+ else
846
+ output = %Q{Preferred network "#{model.connected_network_name}" }
847
+ output << (password ? %Q{stored password is "#{password}".} : "has no stored password.")
848
+ puts output
849
+ end
729
850
  end
730
-
731
- password
732
851
  end
733
852
 
734
853
 
735
854
  def cmd_pr
736
855
  networks = model.preferred_networks
737
- puts_unless_interactive(fancy_string(networks))
738
- networks
856
+ if interactive_mode
857
+ networks
858
+ else
859
+ puts (post_processor ? post_processor.(networks) : fancy_string(networks))
860
+ end
739
861
  end
740
862
 
741
863
 
@@ -745,12 +867,12 @@ When in interactive shell mode:
745
867
 
746
868
 
747
869
  def cmd_r(*options)
748
- model.remove_preferred_networks(*options)
749
- end
750
-
751
-
752
- def cmd_s
753
- run_shell
870
+ removed_networks = model.remove_preferred_networks(*options)
871
+ if interactive_mode
872
+ removed_networks
873
+ else
874
+ puts (post_processor ? post_processor.(removed_networks) : "Removed networks: #{removed_networks.inspect}")
875
+ end
754
876
  end
755
877
 
756
878
 
@@ -763,8 +885,11 @@ When in interactive shell mode:
763
885
 
764
886
  def cmd_w
765
887
  on = model.wifi_on?
766
- puts_unless_interactive("Wifi on: #{on}")
767
- on
888
+ if interactive_mode
889
+ on
890
+ else
891
+ puts (post_processor ? post_processor.(on) : "Wifi on: #{on}")
892
+ end
768
893
  end
769
894
 
770
895
 
@@ -775,25 +900,24 @@ When in interactive shell mode:
775
900
 
776
901
  def commands
777
902
  @commands_ ||= [
778
- Command.new('a', 'availnets', -> (*_options) { cmd_a }),
779
- Command.new('ci', 'ci', -> (*_options) { cmd_ci }),
780
- Command.new('co', 'connect', -> (*options) { cmd_co(*options) }),
781
- Command.new('cy', 'cycle', -> (*_options) { cmd_cy }),
782
- Command.new('d', 'disconnect', -> (*_options) { cmd_d }),
783
- Command.new('h', 'help', -> (*_options) { cmd_h }),
784
- Command.new('i', 'info', -> (*_options) { cmd_i }),
785
- Command.new('l', 'lsavailnets', -> (*_options) { cmd_lsa }),
786
- Command.new('n', 'network_name', -> (*_options) { cmd_n }),
787
- Command.new('of', 'off', -> (*_options) { cmd_of }),
788
- Command.new('on', 'on', -> (*_options) { cmd_on }),
789
- Command.new('pa', 'password', -> (*options) { cmd_pa(*options) }),
790
- Command.new('pr', 'prefnets', -> (*_options) { cmd_pr }),
791
- Command.new('q', 'quit', -> (*_options) { cmd_q }),
792
- Command.new('r', 'rmprefnets', -> (*options) { cmd_r(*options) }),
793
- Command.new('s', 'shell', -> (*_options) { cmd_s }),
794
- Command.new('t', 'till', -> (*options) { cmd_t(*options) }),
795
- Command.new('w', 'wifion', -> (*_options) { cmd_w }),
796
- Command.new('x', 'xit', -> (*_options) { cmd_x })
903
+ Command.new('a', 'avail_nets', -> (*_options) { cmd_a }),
904
+ Command.new('ci', 'ci', -> (*_options) { cmd_ci }),
905
+ Command.new('co', 'connect', -> (*options) { cmd_co(*options) }),
906
+ Command.new('cy', 'cycle', -> (*_options) { cmd_cy }),
907
+ Command.new('d', 'disconnect', -> (*_options) { cmd_d }),
908
+ Command.new('h', 'help', -> (*_options) { cmd_h }),
909
+ Command.new('i', 'info', -> (*_options) { cmd_i }),
910
+ Command.new('l', 'ls_avail_nets', -> (*_options) { cmd_lsa }),
911
+ Command.new('n', 'network_name', -> (*_options) { cmd_n }),
912
+ Command.new('of', 'off', -> (*_options) { cmd_of }),
913
+ Command.new('on', 'on', -> (*_options) { cmd_on }),
914
+ Command.new('pa', 'password', -> (*options) { cmd_pa(*options) }),
915
+ Command.new('pr', 'pref_nets', -> (*_options) { cmd_pr }),
916
+ Command.new('q', 'quit', -> (*_options) { cmd_q }),
917
+ Command.new('r', 'rm_pref_nets', -> (*options) { cmd_r(*options) }),
918
+ Command.new('t', 'till', -> (*options) { cmd_t(*options) }),
919
+ Command.new('w', 'wifion', -> (*_options) { cmd_w }),
920
+ Command.new('x', 'xit', -> (*_options) { cmd_x })
797
921
  ]
798
922
  end
799
923
 
@@ -809,6 +933,18 @@ When in interactive shell mode:
809
933
  end
810
934
 
811
935
 
936
+ # If a post-processor has been configured (e.g. YAML or JSON), use it.
937
+ def post_process(object)
938
+ post_processor ? post_processor.(object) : object
939
+ end
940
+
941
+
942
+
943
+ def post_processor
944
+ options.post_processor
945
+ end
946
+
947
+
812
948
  def call
813
949
  validate_command_line
814
950
  begin
@@ -822,6 +958,9 @@ When in interactive shell mode:
822
958
  end
823
959
 
824
960
 
961
+ require 'optparse'
962
+ require 'ostruct'
963
+
825
964
  class Main
826
965
 
827
966
  # @return true if this file is being run as a script, else false
@@ -873,20 +1012,57 @@ class Main
873
1012
  end
874
1013
 
875
1014
 
1015
+ # Parses the command line with Ruby's internal 'optparse'.
1016
+ # Looks for "-v" flag to set verbosity to true.
1017
+ # optparse removes what it processes from ARGV, which simplifies our command parsing.
1018
+ def parse_command_line
1019
+ options = OpenStruct.new
1020
+ OptionParser.new do |parser|
1021
+ parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
1022
+ options.verbose = v
1023
+ end
1024
+
1025
+ parser.on("-s", "--shell", "Start interactive shell") do |v|
1026
+ options.interactive_mode = true
1027
+ end
1028
+
1029
+ parser.on("-o", "--output_format FORMAT", "Format output data") do |v|
1030
+
1031
+ transformers = {
1032
+ 'i' => ->(object) { object.inspect },
1033
+ 'j' => ->(object) { JSON.pretty_generate(object) },
1034
+ 'p' => ->(object) { sio = StringIO.new; sio.puts(object); sio.string },
1035
+ 'y' => ->(object) { object.to_yaml }
1036
+ }
1037
+
1038
+ choice = v[0].downcase
1039
+
1040
+ unless transformers.keys.include?(choice)
1041
+ raise %Q{Output format "#{choice}" not in list of available formats} +
1042
+ " (#{transformers.keys.inspect})."
1043
+ end
1044
+
1045
+ options.post_processor = transformers[choice]
1046
+ end
1047
+
1048
+ parser.on("-h", "--help", "Show help") do |_help_requested|
1049
+ ARGV << 'h' # pass on the request to the command processor
1050
+ end
1051
+ end.parse!
1052
+ options
1053
+ end
1054
+
1055
+
876
1056
  def call
877
1057
  assert_os_is_mac_os
878
1058
 
1059
+ options = parse_command_line
1060
+
879
1061
  # If this file is being called as a script, run it.
880
1062
  # Else, it may be loaded to use the model in a different way.
881
1063
  if running_as_script?
882
1064
  begin
883
- MacWifi::CommandLineInterface.new.call
884
- rescue => error
885
- puts error
886
- stack_trace_filename = './mac-wifi-error-stack-trace.txt'
887
- File.write(stack_trace_filename, caller.join("\n"))
888
- puts "Exiting. Stack trace written to '#{File.expand_path(stack_trace_filename)}'."
889
- exit(-1)
1065
+ MacWifi::CommandLineInterface.new(options).call
890
1066
  end
891
1067
  end
892
1068
  end
data/mac-wifi.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
  # When changing the version, also change the version and the help text in the README.
3
- VERSION = '1.3.0'
3
+ VERSION = '2.0.0'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "mac-wifi"