switches.rb 0.9.15
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 +7 -0
- data/README.md +211 -0
- data/lib/Switches.rb +471 -0
- data/spec/all.rb +222 -0
- data/switches.rb.gemspec +23 -0
- 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
|
data/switches.rb.gemspec
ADDED
@@ -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: []
|