switches.rb 0.9.15

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 +7 -0
  2. data/README.md +211 -0
  3. data/lib/Switches.rb +471 -0
  4. data/spec/all.rb +222 -0
  5. data/switches.rb.gemspec +23 -0
  6. metadata +47 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f576247bc19561658a5bef4cda1a46f90e62b569fa15a6800507e5aeb05e7601
4
+ data.tar.gz: c5c805d86f2c5fa6d3cb757118d6024c9dea9261b6ec0172e4c8c0c73018d7c8
5
+ SHA512:
6
+ metadata.gz: e355d5bbb5bf7ee88fd4dabd45761d7eeb4ea2d20bc443228cf9881929411d605ab92c594d0d66c4d081bd16f1d4c896caf597f938f1a1d92cf4877531b6658b
7
+ data.tar.gz: 1f8f0162b5eb238df5e8e6143fe69348754fcfab16d31cb9480e378e31459fc974472916dab1cf00910c1adfa3a1422eb776ce9f93adf6c637a94d0faf5ade16
data/README.md ADDED
@@ -0,0 +1,211 @@
1
+ # Switches
2
+
3
+ ## Description
4
+
5
+ Switches provides for a nice wrapper to OptionParser to also act as a store for switches supplied.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'switches'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install switches
20
+
21
+
22
+ ## Usage
23
+
24
+ ```Ruby
25
+
26
+ # With optional switch
27
+
28
+ switches = Switches.new do |s|
29
+ s.set(:a)
30
+ # OR
31
+ s.optional(:a)
32
+ end
33
+ switches.a
34
+
35
+ # With argument required
36
+
37
+ switches = Switches.new do |s|
38
+ s.set!(:a)
39
+ # OR
40
+ s.optional!(:a)
41
+ end
42
+ switches.a
43
+
44
+ # With switch required
45
+
46
+ switches = Switches.new do |s|
47
+ s.set(:a, required: true)
48
+ # OR
49
+ s.required(:a)
50
+ end
51
+ switches.a
52
+
53
+ # With switch and argument required
54
+
55
+ switches = Switches.new do |s|
56
+ s.set!(:a, required: true)
57
+ # OR
58
+ s.required!(:a)
59
+ end
60
+ switches.a
61
+
62
+ # With boolean switch
63
+
64
+ switches = Switches.new do |s|
65
+ s.set(:a?)
66
+ # OR
67
+ s.boolean(:a)
68
+ end
69
+ switches.a?
70
+
71
+ # With a default value
72
+
73
+ switches = Switches.new do |s|
74
+ s.set(:a, default: 31)
75
+ end
76
+ switches.a # => 31
77
+
78
+ # With switch cast to an integer
79
+
80
+ switches = Switches.new(include_casting_interface_methods: true) do |s|
81
+ s.set(:a, cast: Integer)
82
+ # OR
83
+ s.set(:a, type: Integer)
84
+ # OR
85
+ s.set(:a, class: Integer)
86
+ # OR
87
+ s.integer(:a)
88
+ end
89
+ switches.a.class # => Integer
90
+
91
+ # With switch cast to a float
92
+
93
+ switches = Switches.new(include_casting_interface_methods: true) do |s|
94
+ s.set(:a, cast: Float)
95
+ # OR
96
+ s.set(:a, type: Float)
97
+ # OR
98
+ s.set(:a, class: Float)
99
+ # OR
100
+ s.float(:a)
101
+ end
102
+ switches.a.class # => Float
103
+
104
+ # With switch cast to an array
105
+
106
+ switches = Switches.new(include_casting_interface_methods: true) do |s|
107
+ s.set(:a, cast: Array)
108
+ # OR
109
+ s.set(:a, type: Array)
110
+ # OR
111
+ s.set(:a, class: Array)
112
+ # OR
113
+ s.float(:a)
114
+ end
115
+ switches.a.class # => Array
116
+
117
+ # With switch cast to a regex
118
+
119
+ switches = Switches.new(include_casting_interface_methods: true) do |s|
120
+ s.set(:a, cast: Regexp)
121
+ # OR
122
+ s.set(:a, type: Regexp)
123
+ # OR
124
+ s.set(:a, class: Regexp)
125
+ # OR
126
+ s.regexp(:a)
127
+ end
128
+ switches.a.class # => Regexp
129
+
130
+ # With a default value and cast to an integer
131
+
132
+ switches = Switches.new(include_casting_interface_methods: true) do |s|
133
+ s.set(:a, default: 31, cast: Integer)
134
+ # OR
135
+ s.set(:a, default: 31, type: Integer)
136
+ # OR
137
+ s.set(:a, default: 31, class: Integer)
138
+ # OR
139
+ s.integer(:a, default: 31)
140
+ end
141
+ switches.a # => 31 if no argument supplied
142
+ switches.a.class # => Integer
143
+
144
+ # With a description of the switch
145
+
146
+ switches = Switches.new do |s|
147
+ s.set(:a){'This is the -a switch.'}
148
+ end
149
+
150
+ # With a banner
151
+
152
+ switches = Switches.new do |s|
153
+ s.banner = 'Here is a banner for the switches.'
154
+ end
155
+
156
+ # Return a hash instead of an object of class Switches
157
+
158
+ switches = Switches.new(to_h: true) do |s|
159
+ s.set(:a)
160
+ end
161
+ # OR
162
+ switches = Switches.as_h do |s|
163
+ s.set(:a)
164
+ end
165
+
166
+ switches[:a]
167
+ switches.class # => Hash
168
+
169
+ # Without a block
170
+
171
+ switches = Switches.new
172
+ switches.set(:a)
173
+ switches.parse!
174
+ switches.a
175
+
176
+ # With an action
177
+
178
+ switches = Switches.new do |s|
179
+ switches.perform(:a){puts 'a'}
180
+ switches.parse! # => a
181
+
182
+ # With an action uses the argument
183
+
184
+ switches = Switches.new do |s|
185
+ switches.perform(:a){|block_arg| puts block_arg.upcase}
186
+ switches.parse! # => A
187
+
188
+ # With multiple features combined
189
+
190
+ switches = Switches.new(include_casting_interface_methods: true, to_h: true) do |s|
191
+ s.set(:a, default: 31, cast: Integer){'This is the switch -a. It has a default of 31.'}
192
+ # OR
193
+ s.set(:a, default: 31, type: Integer){'This is the switch -a. It has a default of 31.'}
194
+ # OR
195
+ s.set(:a, default: 31, class: Integer){'This is the switch -a. It has a default of 31.'}
196
+ # OR
197
+ s.integer(:a, default: 31){'This is the switch -a. It has a default of 31.'}
198
+ end
199
+ switches[:a] # => 31 if no argument supplied
200
+ switches.a.class # => Integer
201
+ switches.class # => Hash
202
+
203
+ ```
204
+
205
+ ## Contributing
206
+
207
+ 1. Fork it ( https://github.com/thoran/HTTP/fork )
208
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
209
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
210
+ 4. Push to the branch (`git push origin my-new-feature`)
211
+ 5. Create a new pull request
data/lib/Switches.rb ADDED
@@ -0,0 +1,471 @@
1
+ # Switches.rb
2
+ # Switches
3
+
4
+ # 20180403
5
+ # 0.9.15
6
+
7
+ # Description: Switches provides for a nice wrapper to OptionParser to also act as a store for switches supplied.
8
+
9
+ # Todo:
10
+ # 1. Clean up #set. Done as of 0.4.0.
11
+ # 2. Reinstitute some specs. Done as of 0.9.8.
12
+
13
+ # Ideas:
14
+ # 1. Use ! for options with required switches? Done as of 0.6.0. (Changed to being for required arguments in 0.9.0 however.)
15
+ # 2. Do away with optional arguments entirely. Since when does anyone want to specify a non-boolean switch and then supply no arguments anyway?... OK, maybe sometimes, but this is pretty obscure IMO. OK, bad idea. These can be used as action oriented sub-commands.
16
+ # 3. Allow for any one of the switches OpenStruct methods to assign values for any of the other associated methods, so as it is more than a read once switch and can be used for storage through out the application; although this might be stepping on Attributes.rb's toes?...
17
+
18
+ # Notes:
19
+ # 1. A limitation is the inability to use the switch, "-?", since there is no Ruby method, #?.
20
+ # 2. An additional limitation is that the Switches class cannot have methods which are the same as any OptionParser methods since these will be forwarded to the OptionParser instance, @op.
21
+ # 3. In 0.9.0 there is finally now a clear demarcation between switch arguments and switches themselves being mandatory or optional.
22
+ # 4. It mostly makes sense that the Switches interface methods are bang methods, since it is modifying that switch in place with a required argument, rather than relying upon a default or otherwise set value elsewhere and presumably later than when the switch was set.
23
+
24
+ # Dependencies:
25
+ # 1. Standard Ruby Library.
26
+
27
+ # Changes since 0.8:
28
+ # (Renamed this project/class from Options to Switches since there are required switches now and required options don't make sense.)
29
+ # 1. /Options/Switches/.
30
+ # 2. /RequiredOptionMissing/RequiredSwitchMissing/.
31
+ # 3. /String#boolean_arg?/String#boolean_switch?/.
32
+ # 4. Other references to options changed to switches.
33
+ # 5. + Switches#required/mandatory/necessary.
34
+ # 6. + Swtiches#optional.
35
+ # 7. + Switches#supplied_switches.
36
+ # 8. + Switches#set_unused_switches_to_nil.
37
+ # 9. ~ self-run section to reflect new interface.
38
+ # 0/1 (Removed ! from switch setting methods and moved those to the Switches interface methods.)
39
+ # 10. + Switches#do_set.
40
+ # 11. ~ Switches#set.
41
+ # 12. + Switches#set!.
42
+ # 13. + Switches#required!.
43
+ # 14. - String#required_arg?.
44
+ # 15. ~ Switches#on_args + requires_argument.
45
+ # 1/2 (Added casting to nominated Ruby classes.)
46
+ # 16. ~ Switches#on_args + options.
47
+ # 17. + Array#extract_options!.
48
+ # 18. + Switches#allowed.
49
+ # 19. + Switches#allowed!.
50
+ # 20. + Swithces#mandatory.
51
+ # 21. + Switches#necessary.
52
+ # 22. ~ Switches#do_set + ...options.
53
+ # 23. ~ Switches#on_args + ...options[:cast].
54
+ # 24. ~ self-run section to do a simple test of casting.
55
+ # 2/3 (Renaming the library file.)
56
+ # 25. /Options.rb/Switches.rb/.
57
+ # 3/4 (+ casting interface methods)
58
+ # 26. + CastingInterfaceMethods#integer(!).
59
+ # 27. + CastingInterfaceMethods#float(!).
60
+ # 28. + CastingInterfaceMethods#array(!).
61
+ # 29. + CastingInterfaceMethods#regex(p)(!).
62
+ # 30. + CastingInterfaceMethods#boolean(!).
63
+ # 31. ~ Switches#initialize + include_casting_interface_methods.
64
+ # 32. /String#short_arg?/String#short_switch?/.
65
+ # 33. /String#long_arg?/String#long_switch?/.
66
+ # 34. ~ Switches#on_args - boolean_switch.
67
+ # 4/5 (Added default values for switches.)
68
+ # 35. ~ CastingInterfaceMethods to extract any options before pushing a cast option, since it was overwriting for those casting interface methods.
69
+ # 36. ~ Switches#initialize, + @defaults.
70
+ # 37. /Switches#set_unused_switches_to_nil/Switches#set_unused_switches/.
71
+ # 38. ~ Switches#set_unused_switches, so as it handles setting unused switches with a default.
72
+ # 5/6 (Setting of defaults was overriding supplied switch values.)
73
+ # 39. ~ Switches#set_unused_switches, to make use of #switch_defaults and #unused_switches.
74
+ # 40. + Switches#switch_defaults, as an interface method since it might be useful for querying at some point?
75
+ # 41. + Switches#unused_switches, also as an interface method since it might also be useful for querying at some point?
76
+ # 42. ~ Switches#on_args, so as to enable alternate hash keys (:type and :class) for type casting.
77
+ # 43. ~ self-run section to reflect the optionalness/optionality(?) of summaries.
78
+ # 6/7 (Some small tidyups and removal of self-run section.)
79
+ # 44. ~ Switches#on_args, shorter when handling casting arguments.
80
+ # 45. /unused_switches/unset_switches/.
81
+ # 46. ~ Switches#check_required_switches, so that the message is not being assigned until a switch is missing.
82
+ # 47. Removed the self-run section and moved it to ./test/run.rb.
83
+ # 7/8 (Addition of #perform and #perform! methods, as well the #do_action method and changes to #on_args to facilitate #perform* methods.)
84
+ # 48. ~ Switches#on_args, so as if a block is supplied which is not returning a String, then it will not be placed into the on_args argument list.
85
+ # 49. + Switches#perform, interface for actions which don't require an argument.
86
+ # 50. + Switches#perform!, interface for actions which do require an argument.
87
+ # 51. + Switches#do_action, executes a block when called by either of #perform or #perform!.
88
+ # 8/9
89
+ # 52. ~ Switches#check_required_switches, so as it now assembles the complete list of missing switches rather than failing on and reporting only the first.
90
+ # 53. + Switches#required_perform
91
+ # 54. + Switches#required_perform!
92
+ # 55. - OptionParse#soft_parse, since this was never used here, but only in Attributes.
93
+ # 56. + Object#default_is(et.al.)
94
+ # 57. + NilClass#default_is(et.al.) overrides Object#default_is for the specific case of nil.
95
+ # 58. /switches_defaults/switches_with_defaults/.
96
+ # 59. + Array#peek_options.
97
+ # 60. + Array#poke_options!.
98
+ # 61. + Array#all_but_last.
99
+ # 62. + Array#last!.
100
+ # 63. + Module#alias_methods.
101
+ # 64. ~ CastingInterfaceMethods, to make use of Array#poke_options.
102
+ # 65. + CastingInterfaceMethods#flag.
103
+ # 66. + Switches.as_h (and associated aliased interfaces).
104
+ # 67. ~ Switches#initialize, arguments are now a splat with the intention of allowing both casting_interface_methods and as_h being specified as a hash supplied to the initialiser.
105
+ # 68. ~ Switches, to make use of Module#alias_methods.
106
+ # 69. ~ Switches, to make use of Array#peek_options and Array#poke_options!.
107
+ # 70. + Switches#required_perform.
108
+ # 71. + Switches#required_perform!.
109
+ # 72. + Switches#switches_with_defaults.
110
+ # 73. + Switches#switches_with_castings.
111
+ # 74. + Swtiches#to_h.
112
+ # 75. + Switches#set_if_required_switch.
113
+ # 76. + Switches#set_switches_with_defaults.
114
+ # 77. ~ Switches#parse!, + set_switches_with_defaults() and + to_h().
115
+ # 78. ~ Switches#do_set, + set_if_required_switch().
116
+ # 79. ~ Switches#do_action, + set_if_required_switch().
117
+ # 80. ~ Switches#on_args, so as it can handle castings.
118
+ # 9/10
119
+ # 81. + OpenStruct#to_h.
120
+ # 82. ~ Switches#to_h.
121
+ # 10/11 (Whoops! The defaults were overwriting the supplied settings.)
122
+ # 83. ~ Switches#set_switches_with_defaults to check if a setting had been set before applying a default value.
123
+ # 10/11
124
+ # 84.
125
+ # 11/12 (Removed default aliases for default_to, since it clashes with the mail gem's Mail::Message#default method.)
126
+ # 85. - Object#default.
127
+ # 86. - NilClass#default.
128
+ # 12/13
129
+ # 87. Swapped out a couple of @settings.instance_variable_get(:@table)'s for OpenStruct#to_h's.
130
+ # 13/14
131
+ # 88. README is now markdown.
132
+ # 89. - examples directory
133
+ # 90. Version number bump to 0.9.14.
134
+ # 91. Turned into a gem (+ switches.gemspec).
135
+ # 14/15
136
+ # 92. switches gem name taken, so renamed the gem to switches.rb.
137
+ # 93. Version number bump to 0.9.15.
138
+ # 94. Tidied some comments in spec/all.rb.
139
+
140
+ require 'optparse'
141
+ require 'ostruct'
142
+
143
+ class OpenStruct
144
+
145
+ def to_h
146
+ @table
147
+ end
148
+
149
+ end
150
+
151
+ class String
152
+
153
+ def short_switch?
154
+ self =~ /^.$/ || self =~ /^.\?$/ || self =~ /^.\!$/
155
+ end
156
+
157
+ def long_switch?
158
+ (self =~ /^..+$/ && !short_switch?) || self =~ /^..+\?$/ || self =~ /^..+!$/
159
+ end
160
+
161
+ def boolean_switch?
162
+ self =~ /\?$/
163
+ end
164
+
165
+ end
166
+
167
+ class Array
168
+
169
+ def extract_options!
170
+ last.is_a?(::Hash) ? pop : {}
171
+ end
172
+
173
+ def peek_options
174
+ last.is_a?(::Hash) ? last : {}
175
+ end
176
+
177
+ def poke_options!(h)
178
+ self << self.extract_options!.merge(h)
179
+ end
180
+
181
+ alias_method :last!, :pop
182
+
183
+ def all_but_last
184
+ d = self.dup
185
+ d.last!
186
+ d
187
+ end
188
+
189
+ end
190
+
191
+ class Object
192
+
193
+ def default_is(o)
194
+ self
195
+ end
196
+ alias_method :defaults_to, :default_is
197
+ alias_method :default_to, :default_is
198
+
199
+ end
200
+
201
+ class NilClass
202
+
203
+ def default_is(o)
204
+ o
205
+ end
206
+ alias_method :defaults_to, :default_is
207
+ alias_method :default_to, :default_is
208
+
209
+ end
210
+
211
+ class Module
212
+
213
+ def alias_methods(*args)
214
+ args.all_but_last.each{|e| alias_method e.to_sym, args.last.to_sym}
215
+ end
216
+
217
+ end
218
+
219
+ module CastingInterfaceMethods
220
+
221
+ def integer(*attrs, &block)
222
+ attrs.poke_options!({:cast => Integer})
223
+ set(*attrs, &block)
224
+ end
225
+
226
+ def integer!(*attrs, &block)
227
+ attrs.poke_options!({:cast => Integer})
228
+ set!(*attrs, &block)
229
+ end
230
+
231
+ def float(*attrs, &block)
232
+ attrs.poke_options!({:cast => Float})
233
+ set(*attrs, &block)
234
+ end
235
+
236
+ def float!(*attrs, &block)
237
+ attrs.poke_options!({:cast => Float})
238
+ set!(*attrs, &block)
239
+ end
240
+
241
+ def array(*attrs, &block)
242
+ attrs.poke_options!({:cast => Array})
243
+ set(*attrs, &block)
244
+ end
245
+
246
+ def array!(*attrs, &block)
247
+ attrs.poke_options!({:cast => Array})
248
+ set!(*attrs, &block)
249
+ end
250
+
251
+ def regexp(*attrs, &block)
252
+ attrs.poke_options!({:cast => Regexp})
253
+ set(*attrs, &block)
254
+ end
255
+ alias_method :regex, :regexp
256
+
257
+ def regexp!(*attrs, &block)
258
+ attrs.poke_options!({:cast => Regexp})
259
+ set!(*attrs, &block)
260
+ end
261
+ alias_method :regex!, :regexp!
262
+
263
+ def boolean(*attrs, &block)
264
+ attrs.collect!{|a| a.to_s =~ /\?$/ ? a : (a.to_s + '?').to_sym}
265
+ set(*attrs, &block)
266
+ end
267
+ alias_method :flag, :boolean
268
+
269
+ end
270
+
271
+ class RequiredSwitchMissing < RuntimeError; end
272
+
273
+ class Switches
274
+
275
+ class << self
276
+
277
+ def as_h(*args)
278
+ switches = new(*args)
279
+ switches.to_h
280
+ end
281
+ alias_methods :to_h, :as_hash, :as_a_hash, :as_h
282
+
283
+ end
284
+
285
+ attr_accessor :settings
286
+
287
+ def initialize(*args)
288
+ options = args.extract_options!
289
+ self.class.send(:include, CastingInterfaceMethods) if options[:include_casting_interface_methods].default_is(true)
290
+ @as_h = (options[:as_h] || options[:to_h] || options[:as_hash] || options[:as_a_hash]).default_is(false)
291
+ @settings = OpenStruct.new
292
+ @op = OptionParser.new
293
+ @required_switches = []
294
+ @all_switches = []
295
+ @defaults = {}
296
+ @castings = {}
297
+ if block_given?
298
+ yield self
299
+ parse!
300
+ end
301
+ end
302
+
303
+ def set(*attrs, &block)
304
+ do_set(false, *attrs, &block)
305
+ end
306
+ alias_methods :optional_switch, :optional, :set
307
+
308
+ def set!(*attrs, &block)
309
+ do_set(true, *attrs, &block)
310
+ end
311
+ alias_methods :optional_switch!, :optional!, :set!
312
+
313
+ def required(*attrs, &block)
314
+ attrs.poke_options!({:required => true})
315
+ set(*attrs, &block)
316
+ end
317
+ alias_method :required_switch, :required
318
+
319
+ def required!(*attrs, &block)
320
+ attrs.poke_options!({:required => true})
321
+ set!(*attrs, &block)
322
+ end
323
+ alias_method :required_switch!, :required!
324
+
325
+ def perform(*attrs, &block)
326
+ do_action(false, *attrs, &block)
327
+ end
328
+ alias_methods :optionally_perform, :optional_perform, :perform
329
+
330
+ def perform!(*attrs, &block)
331
+ do_action(true, *attrs, &block)
332
+ end
333
+ alias_methods :optionally_perform!, :optional_perform!, :perform!
334
+
335
+ def required_perform(*attrs, &block)
336
+ attrs.poke_options!({:required => true})
337
+ perform(*attrs, &block)
338
+ end
339
+
340
+ def required_perform!(*attrs, &block)
341
+ attrs.poke_options!({:required => true})
342
+ perform!(*attrs, &block)
343
+ end
344
+
345
+ def parse!
346
+ @op.parse!
347
+ check_required_switches
348
+ set_switches_with_defaults
349
+ set_unset_switches
350
+ to_h if @as_h
351
+ end
352
+
353
+ def supplied_switches
354
+ @settings.to_h.keys.collect{|s| s.to_s}
355
+ end
356
+
357
+ def switches_with_defaults
358
+ @defaults.keys.collect{|default| default.to_s}
359
+ end
360
+
361
+ def switches_with_castings
362
+ @castings.keys.collect{|default| default.to_s}
363
+ end
364
+
365
+ def unset_switches
366
+ @all_switches - supplied_switches - switches_with_defaults
367
+ end
368
+
369
+ def to_h
370
+ @settings.to_h
371
+ end
372
+
373
+ private
374
+
375
+ def do_set(requires_argument, *attrs, &block)
376
+ set_if_required_switch(*attrs)
377
+ options = attrs.extract_options!
378
+ @all_switches = @all_switches + attrs.collect{|a| a.to_s}
379
+ @op.on(*on_args(requires_argument, options, *attrs, &block)) do |o|
380
+ attrs.each do |attr|
381
+ @settings.send(attr.to_s + '=', o)
382
+ end
383
+ end
384
+ end
385
+
386
+ def do_action(requires_argument, *attrs, &block)
387
+ attrs.each do |attr|
388
+ @settings.send(attr.to_s + '=', nil) # Needs to be set prior to checking for required switches, since that check relies upon the key having been set in @settings.
389
+ end
390
+ set_if_required_switch(*attrs)
391
+ options = attrs.extract_options!
392
+ @all_switches = @all_switches + attrs.collect{|a| a.to_s}
393
+ @op.on(*on_args(requires_argument, options, *attrs)) do |o|
394
+ yield o if block
395
+ end
396
+ end
397
+
398
+ def method_missing(method_name, *args, &block)
399
+ if (@op.methods - Switches.instance_methods).include?(method_name.to_s)
400
+ @op.send(method_name.to_s, *args, &block)
401
+ else
402
+ @settings.send(method_name.to_s, *args, &block)
403
+ end
404
+ end
405
+
406
+ def on_args(requires_argument, options, *attrs, &block)
407
+ on_args = []
408
+ attrs.collect{|e| e.to_s}.each do |attr|
409
+ @defaults[attr] = options[:default] if options[:default]
410
+ @castings[attr] = (options[:cast] || options[:type] || options[:class]) if (options[:cast] || options[:type] || options[:class])
411
+ on_args << "-#{attr.long_switch? ? '-' : ''}#{attr.to_s.delete('?')}"
412
+ end
413
+ if requires_argument
414
+ on_args << (on_args.pop + ' REQUIRED_ARGUMENT')
415
+ elsif !!attrs.last.to_s.boolean_switch?
416
+ on_args << (on_args.pop)
417
+ else
418
+ on_args << (on_args.pop + ' [OPTIONAL_ARGUMENT]')
419
+ end
420
+ on_args << (options[:cast] || options[:type] || options[:class]) if (options[:cast] || options[:type] || options[:class])
421
+ if block
422
+ yield_result = yield
423
+ on_args << yield_result if yield_result.class == String
424
+ end
425
+ on_args
426
+ end
427
+
428
+ def check_required_switches
429
+ messages = []
430
+ @required_switches.each do |required_switch|
431
+ unless supplied_switches.include?(required_switch)
432
+ messages << "required switch, -#{required_switch.long_switch? ? '-' : ''}#{required_switch.to_s.delete('?')}, is missing"
433
+ end
434
+ end
435
+ unless messages.empty?
436
+ raise RequiredSwitchMissing, messages.join("\n")
437
+ end
438
+ end
439
+
440
+ def set_switches_with_defaults
441
+ switches_with_defaults.each do |switch|
442
+ if @settings.to_h[switch.to_sym].nil?
443
+ if switches_with_castings.include?(switch)
444
+ cast_value = (
445
+ case @castings[switch]
446
+ when Integer; @defaults[switch].to_i
447
+ when Float; @defaults[switch].to_f
448
+ when Array; @defaults[switch].to_a
449
+ when Regexp; Regexp.new(@defaults[switch])
450
+ end
451
+ )
452
+ @settings.send(switch + '=', cast_value)
453
+ else
454
+ @settings.send(switch + '=', @defaults[switch])
455
+ end
456
+ end
457
+ end
458
+ end
459
+
460
+ def set_unset_switches
461
+ unset_switches.each{|switch| @settings.send(switch + '=', nil)}
462
+ end
463
+
464
+ def set_if_required_switch(*attrs)
465
+ if (attrs.peek_options[:required] || attrs.peek_options[:required_switch])
466
+ attrs.extract_options!
467
+ @required_switches = @required_switches + attrs.collect{|a| a.to_s}
468
+ end
469
+ end
470
+
471
+ end
data/spec/all.rb ADDED
@@ -0,0 +1,222 @@
1
+ require "#{File.dirname(__FILE__)}/../lib/Switches"
2
+
3
+ class Array
4
+
5
+ alias_method :empty!, :clear
6
+
7
+ end
8
+
9
+ describe Switches do
10
+
11
+ describe ".new" do
12
+
13
+ it "should return an object of class Switches" do
14
+ Switches.new.class.should == Switches
15
+ end
16
+
17
+ end
18
+
19
+ describe "#set" do
20
+
21
+ def setup(switches_string = '')
22
+ ARGV.empty!
23
+ switches_string.split.each{|a| ARGV << a}
24
+ Switches.new do |s|
25
+ s.set :v?, :verbose?
26
+ s.set :p, :port
27
+ s.set :host, :h
28
+ end
29
+ end
30
+
31
+ it "should set a short boolean switch or flag to true when supplied with a short switch" do
32
+ setup('-v').v?.should == true
33
+ end
34
+
35
+ it "should set a long boolean switch value to true when supplied with a short switch" do
36
+ setup('-v').verbose?.should == true
37
+ end
38
+
39
+ it "should set a short boolean switch or flag to true when supplied with a long switch" do
40
+ setup('--verbose').v?.should == true
41
+ end
42
+
43
+ it "should set a long boolean switch or flag to true when supplied with a long switch" do
44
+ setup('--verbose').verbose?.should == true
45
+ end
46
+
47
+ it "should set a short switch value to the value supplied when supplied with a short switch" do
48
+ setup('-p 22').p.should == '22'
49
+ end
50
+
51
+ it "should set a long switch value to the value supplied when supplied with a short switch" do
52
+ setup('-p 22').port.should == '22'
53
+ end
54
+
55
+ it "should set a short switch value to the value supplied when supplied with a long switch" do
56
+ setup('--port 22').p.should == '22'
57
+ end
58
+
59
+ it "should set a long switch value to the value supplied when supplied with a long switch" do
60
+ setup('--port 22').port.should == '22'
61
+ end
62
+
63
+ it "shouldn't matter in which order the short and long switches are given" do
64
+ setup('-h example.com').h.should == 'example.com'
65
+ setup('--host example.com').h.should == 'example.com'
66
+ end
67
+
68
+ end # describe "#set"
69
+
70
+ describe "#set!" do
71
+
72
+ def setup(switches_string = '')
73
+ ARGV.empty!
74
+ switches_string.split.each{|a| ARGV << a}
75
+ Switches.new do |s|
76
+ s.set! :p, :port
77
+ end
78
+ end
79
+
80
+ it "should set a short switch value to the argument supplied with a short switch" do
81
+ setup('-p 22').p.should == '22'
82
+ end
83
+
84
+ it "should set a long switch value to the argument supplied with a short switch" do
85
+ setup('-p 22').port.should == '22'
86
+ end
87
+
88
+ it "should set a short switch value to the argument supplied with a long switch" do
89
+ setup('--port 22').p.should == '22'
90
+ end
91
+
92
+ it "should set a long switch value to the argument supplied with a long switch" do
93
+ setup('--port 22').port.should == '22'
94
+ end
95
+
96
+ it "should raise a MissingArgument error when no argument is supplied to a short switch" do
97
+ switches = lambda{setup('-p')}
98
+ switches.should{raise MissingArgument}
99
+ end
100
+
101
+ it "should raise a MissingArgument error when no argument is supplied to a long switch" do
102
+ switches = lambda{setup('--port')}
103
+ switches.should{raise MissingArgument}
104
+ end
105
+
106
+ end # describe "#set!"
107
+
108
+ describe "#required" do
109
+
110
+ def setup(switches_string = '')
111
+ ARGV.empty!
112
+ switches_string.split.each{|a| ARGV << a}
113
+ Switches.new do |s|
114
+ s.required :p, :port
115
+ end
116
+ end
117
+
118
+ it "should set a short switch value to the argument supplied with a short switch" do
119
+ setup('-p 22').p.should == '22'
120
+ end
121
+
122
+ it "should set a long switch value to the argument supplied with a short switch" do
123
+ setup('-p 22').port.should == '22'
124
+ end
125
+
126
+ it "should set a short switch value to the argument supplied with a long switch" do
127
+ setup('--port 22').p.should == '22'
128
+ end
129
+
130
+ it "should set a long switch value to the argument supplied with a long switch" do
131
+ setup('--port 22').port.should == '22'
132
+ end
133
+
134
+ it "should raise a RequiredSwitchMissing error no switch is supplied" do
135
+ switches = lambda{setup}
136
+ switches.should{raise RequiredSwitchMissing}
137
+ end
138
+
139
+ end # describe "#required"
140
+
141
+ describe "#required!" do
142
+
143
+ def setup(switches_string = '')
144
+ ARGV.empty!
145
+ switches_string.split.each{|a| ARGV << a}
146
+ Switches.new do |s|
147
+ s.required! :p, :port
148
+ end
149
+ end
150
+
151
+ it "should set a short switch value to the argument supplied with a short switch" do
152
+ setup('-p 22').p.should == '22'
153
+ end
154
+
155
+ it "should set a long switch value to the argument supplied with a short switch" do
156
+ setup('-p 22').port.should == '22'
157
+ end
158
+
159
+ it "should set a short switch value to the argument supplied with a long switch" do
160
+ setup('--port 22').p.should == '22'
161
+ end
162
+
163
+ it "should set a long switch value to the argument supplied with a long switch" do
164
+ setup('--port 22').port.should == '22'
165
+ end
166
+
167
+ it "should raise a MissingArgument error when no argument is supplied to a short switch" do
168
+ switches = lambda{setup('-p')}
169
+ switches.should{raise MissingArgument}
170
+ end
171
+
172
+ it "should raise a MissingArgument error when no argument is supplied to a long switch" do
173
+ switches = lambda{setup('-p')}
174
+ switches.should{raise MissingArgument}
175
+ end
176
+
177
+ it "should raise a RequiredSwitchMissing error no switch is supplied" do
178
+ switches = lambda{setup}
179
+ switches.should{raise RequiredSwitchMissing}
180
+ end
181
+
182
+ end # describe "#required!"
183
+
184
+ describe "#perform" do
185
+
186
+ def setup(switches_string = '')
187
+ ARGV.empty!
188
+ switches_string.split.each{|a| ARGV << a}
189
+ Switches.new do |s|
190
+ s.perform(:action){an_action}
191
+ end
192
+ end
193
+
194
+ def an_action
195
+ 'value'
196
+ end
197
+
198
+ it "should send(:an_action)"
199
+
200
+ end # describe "#perform"
201
+
202
+ describe "#perform!" do
203
+
204
+ def setup(switches_string = '')
205
+ ARGV.empty!
206
+ switches_string.split.each{|a| ARGV << a}
207
+ Switches.new do |s|
208
+ s.perform(:action){an_action}
209
+ end
210
+ end
211
+
212
+ def an_action
213
+ 'value'
214
+ end
215
+
216
+ it "should send(:an_action)"
217
+
218
+ it "should require a block parameter"
219
+
220
+ end # describe "#perform!"
221
+
222
+ end # describe Switches
@@ -0,0 +1,23 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'switches.rb' # I would have preferred 'switches', but there's a gem with the name of switches.
3
+
4
+ s.version = '0.9.15'
5
+ s.date = '2018-04-03'
6
+
7
+ s.summary = "The easiest way to provide switches to a Ruby program."
8
+ s.description = "Switches provides for a nice wrapper to OptionParser to also act as a store for switches supplied."
9
+ s.author = 'thoran'
10
+ s.email = 'code@thoran.com'
11
+ s.homepage = "http://github.com/thoran/switches"
12
+
13
+ s.files = [
14
+ 'README.md',
15
+ 'switches.rb.gemspec',
16
+ Dir['lib/**/*.rb'],
17
+ Dir['spec/**/*.rb']
18
+ ].flatten
19
+
20
+ s.require_paths = ['lib']
21
+
22
+ s.has_rdoc = false
23
+ end
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: switches.rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.15
5
+ platform: ruby
6
+ authors:
7
+ - thoran
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-04-03 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Switches provides for a nice wrapper to OptionParser to also act as a
14
+ store for switches supplied.
15
+ email: code@thoran.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - README.md
21
+ - lib/Switches.rb
22
+ - spec/all.rb
23
+ - switches.rb.gemspec
24
+ homepage: http://github.com/thoran/switches
25
+ licenses: []
26
+ metadata: {}
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 2.7.4
44
+ signing_key:
45
+ specification_version: 4
46
+ summary: The easiest way to provide switches to a Ruby program.
47
+ test_files: []