clamp 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -1,7 +1,7 @@
1
1
  Clamp
2
2
  =====
3
3
 
4
- "Clamp" is a minimal framework for command-line utilities.
4
+ "Clamp" is a minimal framework for command-line utilities.
5
5
 
6
6
  It handles boring stuff like parsing the command-line, and generating help, so you can get on with making your command actually do stuff.
7
7
 
@@ -42,7 +42,7 @@ Calling `run` on a command class creates an instance of it, then invokes it usin
42
42
 
43
43
  SpeakCommand.run
44
44
 
45
- Class-level methods like `option` and `parameter` declare attributes (in a similar way to `attr_accessor`), and arrange for them to be populated automatically based on command-line arguments. They are also used to generate `help` documentation.
45
+ Class-level methods like `option` and `parameter` declare attributes (in a similar way to `attr_accessor`), and arrange for them to be populated automatically based on command-line arguments. They are also used to generate `help` documentation.
46
46
 
47
47
  Declaring options
48
48
  -----------------
@@ -82,12 +82,20 @@ Some options are just boolean flags. Pass "`:flag`" as the second parameter to
82
82
 
83
83
  For flag options, Clamp appends "`?`" to the generated reader method; ie. you get a method called "`#verbose?`", rather than just "`#verbose`".
84
84
 
85
- Negatable flags are easy to generate, too:
85
+ Negatable flags are easy to generate, too:
86
86
 
87
87
  option "--[no-]force", :flag, "be forceful (or not)"
88
88
 
89
89
  Clamp will handle both "`--force`" and "`--no-force`" options, setting the value of "`#force?`" appropriately.
90
90
 
91
+ ### Required options
92
+
93
+ Although 'required option' is a an oxymoron, Clamp lets you mark an option as required, and will verify that a value is provided:
94
+
95
+ option "--password", "PASSWORD", "the secret password", :required => true
96
+
97
+ Note that it makes no sense to mark a `:flag` option, or one with a `:default`, as `:required`.
98
+
91
99
  Declaring parameters
92
100
  --------------------
93
101
 
@@ -125,8 +133,8 @@ Clamp will verify that all required (ie. non-optional) parameters are present, a
125
133
 
126
134
  ### Validation block
127
135
 
128
- Both `option` and `parameter` accept an optional block. If present, the block will be
129
- called with the raw string option argument, and is expected to coerce it to
136
+ Both `option` and `parameter` accept an optional block. If present, the block will be
137
+ called with the raw string option argument, and is expected to coerce it to
130
138
  the correct type, e.g.
131
139
 
132
140
  option "--port", "PORT", "port to listen on" do |s|
@@ -143,19 +151,17 @@ If the block raises an ArgumentError, Clamp will catch it, and report that the v
143
151
  While Clamp provides an attribute-writer method for each declared option or parameter, you always have the option of overriding it to provide custom argument-handling logic, e.g.
144
152
 
145
153
  parameter "SERVER", "location of server"
146
-
154
+
147
155
  def server=(server)
148
156
  @server_address, @server_port = server.split(":")
149
157
  end
150
158
 
151
159
  ### Default values
152
160
 
153
- Default values can be specified for options:
161
+ Default values can be specified for options, and optional parameters:
154
162
 
155
163
  option "--flavour", "FLAVOUR", "ice-cream flavour", :default => "chocolate"
156
164
 
157
- and also for optional parameters
158
-
159
165
  parameter "[HOST]", "server host", :default => "localhost"
160
166
 
161
167
  For more advanced cases, you can also specify default values by defining a method called "`default_#{attribute_name}`":
@@ -168,6 +174,18 @@ For more advanced cases, you can also specify default values by defining a metho
168
174
  http_port + 1
169
175
  end
170
176
 
177
+ ### Environment variable support
178
+
179
+ Options (and optional parameters) can also be associated with environment variables:
180
+
181
+ option "--port", "PORT", "the port to listen on", :environment_variable => "MYAPP_PORT" do |val|
182
+ val.to_i
183
+ end
184
+
185
+ parameter "[HOST]", "server address", :environment_variable => "MYAPP_HOST"
186
+
187
+ Clamp will check the specified envariables in the absence of values supplied on the command line, before looking for a default value.
188
+
171
189
  Declaring Subcommands
172
190
  ---------------------
173
191
 
@@ -184,15 +202,15 @@ Unsuprisingly, subcommands are declared using the `subcommand` method. e.g.
184
202
  end
185
203
 
186
204
  end
187
-
205
+
188
206
  end
189
207
 
190
208
  Clamp generates an anonymous subclass of the current class, to represent the subcommand. Alternatively, you can provide an explicit subcommand class:
191
-
209
+
192
210
  class MainCommand < Clamp::Command
193
211
 
194
212
  subcommand "init", "Initialize the repository", InitCommand
195
-
213
+
196
214
  end
197
215
 
198
216
  class InitCommand < Clamp::Command
@@ -210,7 +228,7 @@ You can set a default subcommand, at the class level, as follows:
210
228
  class MainCommand < Clamp::Command
211
229
 
212
230
  self.default_subcommand = "status"
213
-
231
+
214
232
  subcommand "status", "Display current status" do
215
233
 
216
234
  def execute
@@ -218,7 +236,7 @@ You can set a default subcommand, at the class level, as follows:
218
236
  end
219
237
 
220
238
  end
221
-
239
+
222
240
  end
223
241
 
224
242
  Then, if when no SUBCOMMAND argument is provided, the default will be selected.
@@ -227,7 +245,7 @@ Then, if when no SUBCOMMAND argument is provided, the default will be selected.
227
245
 
228
246
  Options are inheritable, so any options declared for a command are supported for it's sub-classes (e.g. those created using `subcommand`). Parameters, on the other hand, are not inherited - each subcommand must declare it's own parameter list.
229
247
 
230
- Note that, if a subcommand accepts options, they must be specified on the command-line _after_ the subcommand name.
248
+ Note that, if a subcommand accepts options, they must be specified on the command-line _after_ the subcommand name.
231
249
 
232
250
  Getting help
233
251
  ------------
@@ -271,4 +289,4 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
271
289
  Contributing to Clamp
272
290
  ---------------------
273
291
 
274
- Source-code for Clamp is [on Github](https://github.com/mdub/clamp).
292
+ Source-code for Clamp is [on Github](https://github.com/mdub/clamp).
data/examples/admin ADDED
@@ -0,0 +1,22 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # An example of subcommands
4
+
5
+ require "clamp"
6
+
7
+ class AdminCommand < Clamp::Command
8
+
9
+ option "--timeout", "SECONDS", "connection timeout", :default => 5, :environment_variable => "MYAPP_TIMEOUT" do |x|
10
+ Integer(x)
11
+ end
12
+
13
+ parameter "HOST", "server address"
14
+ parameter "[PORT]", "server port", :default => 80, :environment_variable => "MYAPP_PORT"
15
+
16
+ def execute
17
+ puts "trying to connect to #{host} on port #{port} (waiting up to #{timeout} seconds)"
18
+ end
19
+
20
+ end
21
+
22
+ AdminCommand.run
data/examples/gitdown CHANGED
@@ -15,17 +15,22 @@ module GitDown
15
15
  exit(0)
16
16
  end
17
17
 
18
+ def say(message)
19
+ message = message.upcase if verbose?
20
+ puts message
21
+ end
22
+
18
23
  end
19
24
 
20
25
  class CloneCommand < AbstractCommand
21
-
26
+
22
27
  parameter "REPOSITORY", "repository to clone"
23
28
  parameter "[DIR]", "working directory", :default => "."
24
29
 
25
30
  def execute
26
- raise NotImplementedError
31
+ say "cloning to #{dir}"
27
32
  end
28
-
33
+
29
34
  end
30
35
 
31
36
  class PullCommand < AbstractCommand
@@ -33,23 +38,27 @@ module GitDown
33
38
  option "--[no-]commit", :flag, "Perform the merge and commit the result."
34
39
 
35
40
  def execute
36
- raise NotImplementedError
41
+ say "pulling"
37
42
  end
38
-
43
+
39
44
  end
40
45
 
41
46
  class StatusCommand < AbstractCommand
42
-
47
+
43
48
  option ["-s", "--short"], :flag, "Give the output in the short-format."
44
49
 
45
50
  def execute
46
- raise NotImplementedError
51
+ if short?
52
+ say "good"
53
+ else
54
+ say "it's all good ..."
55
+ end
47
56
  end
48
-
57
+
49
58
  end
50
59
 
51
60
  class MainCommand < AbstractCommand
52
-
61
+
53
62
  subcommand "clone", "Clone a remote repository.", CloneCommand
54
63
  subcommand "pull", "Fetch and merge updates.", PullCommand
55
64
  subcommand "status", "Display status of local repository.", StatusCommand
@@ -2,14 +2,10 @@ module Clamp
2
2
 
3
3
  class Attribute
4
4
 
5
- attr_reader :description, :attribute_name, :default_value
5
+ attr_reader :description, :attribute_name, :default_value, :environment_variable
6
6
 
7
7
  def help_rhs
8
- rhs = description
9
- if defined?(@default_value)
10
- rhs += " (default: #{@default_value.inspect})"
11
- end
12
- rhs
8
+ description + default_description
13
9
  end
14
10
 
15
11
  def help
@@ -32,6 +28,17 @@ module Clamp
32
28
  "#{attribute_name}="
33
29
  end
34
30
 
31
+ private
32
+
33
+ def default_description
34
+ default_sources = [
35
+ ("$#{@environment_variable}" if defined?(@environment_variable)),
36
+ (@default_value.inspect if defined?(@default_value))
37
+ ].compact
38
+ return "" if default_sources.empty?
39
+ " (default: " + default_sources.join(", or ") + ")"
40
+ end
41
+
35
42
  end
36
43
 
37
- end
44
+ end
data/lib/clamp/command.rb CHANGED
@@ -46,7 +46,9 @@ module Clamp
46
46
  #
47
47
  def parse(arguments)
48
48
  @remaining_arguments = arguments.dup
49
+ parse_environment_options
49
50
  parse_options
51
+ parse_environment_parameters
50
52
  parse_parameters
51
53
  parse_subcommand
52
54
  handle_remaining_arguments
data/lib/clamp/option.rb CHANGED
@@ -14,6 +14,19 @@ module Clamp
14
14
  if options.has_key?(:default)
15
15
  @default_value = options[:default]
16
16
  end
17
+ if options.has_key?(:environment_variable)
18
+ @environment_variable = options[:environment_variable]
19
+ end
20
+ if options.has_key?(:required)
21
+ @required = options[:required]
22
+ # Do some light validation for conflicting settings.
23
+ if options.has_key?(:default)
24
+ raise ArgumentError, "Specifying a :default value also :required doesn't make sense"
25
+ end
26
+ if type == :flag
27
+ raise ArgumentError, "A required flag (boolean) doesn't make sense."
28
+ end
29
+ end
17
30
  end
18
31
 
19
32
  attr_reader :switches, :type
@@ -30,6 +43,10 @@ module Clamp
30
43
  recognised_switches.member?(switch)
31
44
  end
32
45
 
46
+ def required?
47
+ @required
48
+ end
49
+
33
50
  def flag?
34
51
  @type == :flag
35
52
  end
@@ -3,23 +3,45 @@ module Clamp
3
3
 
4
4
  module Parsing
5
5
 
6
+ # For :flag options with environment variables attached, this is a list
7
+ # of possible values that are accepted as 'true'
8
+ #
9
+ # Example:
10
+ #
11
+ # option "--foo", :flag, "Use foo", :environment_variable => "FOO"
12
+ #
13
+ # All of these will set 'foo' to true:
14
+ #
15
+ # FOO=1 ./myprogram
16
+ # FOO=true ./myprogram
17
+ # FOO=yes ./myprogram
18
+ # FOO=on ./myprogram
19
+ # FOO=enable ./myprogram
20
+ #
21
+ # See {Clamp::Command.option} for more information.
22
+ TRUTHY_ENVIRONMENT_VALUES = %w(1 yes enable on true)
23
+
6
24
  protected
7
25
 
8
26
  def parse_options
9
- while remaining_arguments.first =~ /^-/
27
+ while remaining_arguments.first =~ /\A-/
10
28
 
11
29
  switch = remaining_arguments.shift
12
30
  break if switch == "--"
13
31
 
14
32
  case switch
15
- when /^(-\w)(.+)$/ # combined short options
33
+ when /\A(-\w)(.+)\z/m # combined short options
16
34
  switch = $1
17
- remaining_arguments.unshift("-#{$2}")
18
- when /^(--[^=]+)=(.*)/
35
+ if find_option(switch).flag?
36
+ remaining_arguments.unshift("-" + $2)
37
+ else
38
+ remaining_arguments.unshift($2)
39
+ end
40
+ when /\A(--[^=]+)=(.*)\z/m
19
41
  switch = $1
20
42
  remaining_arguments.unshift($2)
21
43
  end
22
-
44
+
23
45
  option = find_option(switch)
24
46
  value = option.extract_value(switch, remaining_arguments)
25
47
 
@@ -30,16 +52,43 @@ module Clamp
30
52
  end
31
53
 
32
54
  end
55
+
56
+ # Verify that all required options are present
57
+ self.class.recognised_options.each do |option|
58
+ # If this option is required and the value is nil, there's an error.
59
+ if option.required? and send(option.attribute_name).nil?
60
+ message = "option '#{option.switches.first}'"
61
+ if option.environment_variable
62
+ message += " (or env #{option.environment_variable})"
63
+ end
64
+ message += " is required"
65
+ signal_usage_error message
66
+ end
67
+ end
68
+ end
69
+
70
+ def parse_environment_options
71
+ self.class.recognised_options.each do |option|
72
+ next if option.environment_variable.nil?
73
+ next unless ENV.has_key?(option.environment_variable)
74
+ value = ENV[option.environment_variable]
75
+ if option.flag?
76
+ # Set true if the environment value is truthy.
77
+ send("#{option.attribute_name}=", TRUTHY_ENVIRONMENT_VALUES.include?(value))
78
+ else
79
+ send("#{option.attribute_name}=", value)
80
+ end
81
+ end
33
82
  end
34
83
 
35
84
  private
36
85
 
37
86
  def find_option(switch)
38
- self.class.find_option(switch) ||
87
+ self.class.find_option(switch) ||
39
88
  signal_usage_error("Unrecognised option '#{switch}'")
40
89
  end
41
90
 
42
91
  end
43
92
 
44
93
  end
45
- end
94
+ end
@@ -14,6 +14,9 @@ module Clamp
14
14
  if options.has_key?(:default)
15
15
  @default_value = options[:default]
16
16
  end
17
+ if options.has_key?(:environment_variable)
18
+ @environment_variable = options[:environment_variable]
19
+ end
17
20
  end
18
21
 
19
22
  attr_reader :name, :attribute_name
@@ -18,6 +18,18 @@ module Clamp
18
18
 
19
19
  end
20
20
 
21
+ def parse_environment_parameters
22
+
23
+ self.class.parameters.each do |parameter|
24
+ next if parameter.environment_variable.nil?
25
+ next unless ENV.has_key?(parameter.environment_variable)
26
+ # Set the parameter value if it's environment variable is present
27
+ value = ENV[parameter.environment_variable]
28
+ send("#{parameter.attribute_name}=", value)
29
+ end
30
+
31
+ end
32
+
21
33
  end
22
34
 
23
35
  end
data/lib/clamp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Clamp
2
- VERSION = "0.3.1".freeze
2
+ VERSION = "0.4.0".freeze
3
3
  end
@@ -1,3 +1,4 @@
1
+
1
2
  require 'spec_helper'
2
3
 
3
4
  describe Clamp::Command do
@@ -110,6 +111,124 @@ describe Clamp::Command do
110
111
 
111
112
  end
112
113
 
114
+ describe "with :environment_variable value" do
115
+
116
+ before do
117
+ @command.class.option "--port", "PORT", "port to listen on", :default => 4321, :environment_variable => "PORT" do |value|
118
+ value.to_i
119
+ end
120
+ end
121
+
122
+ it "should use the default if neither flag nor env var are present" do
123
+ ENV.delete("PORT")
124
+ @command.parse([])
125
+ @command.port.should == 4321
126
+ end
127
+
128
+ it "should use the env value if present (instead of default)" do
129
+ ENV["PORT"] = rand(10000).to_s
130
+ @command.parse([])
131
+ @command.port.should == ENV["PORT"].to_i
132
+ end
133
+
134
+ it "should use the the flag value if present (instead of env)" do
135
+ ENV["PORT"] = "12345"
136
+ @command.parse(%w(--port 1500))
137
+ @command.port.should == 1500
138
+ end
139
+
140
+ describe "#help" do
141
+
142
+ it "describes the default value and env usage" do
143
+ @command.help.should include("port to listen on (default: $PORT, or 4321)")
144
+ end
145
+
146
+ end
147
+
148
+ end
149
+
150
+ describe "with :environment_variable value on a :flag option" do
151
+
152
+ before do
153
+ @command.class.option "--[no-]enable", :flag, "enable?", :default => false, :environment_variable => "ENABLE"
154
+ end
155
+
156
+ it "should use the default if neither flag nor env var are present" do
157
+ @command.parse([])
158
+ @command.enable?.should == false
159
+ end
160
+
161
+ Clamp::Option::Parsing::TRUTHY_ENVIRONMENT_VALUES.each do |value|
162
+ it "should use environment value '#{value}' to mean true" do
163
+ ENV["ENABLE"] = value
164
+ @command.parse([])
165
+ @command.enable?.should == true
166
+ end
167
+ end
168
+
169
+ # Make sure tests fail if ever the TRUTHY_ENVIRONMENT_VALUES loses a
170
+ # value. This is just a safety check to make sure maintainers update
171
+ # any relevant docs and aware that they could be breaking compatibility.
172
+ it "should accept only these values as 'truthy' environment values: 1, yes, enable, on, true" do
173
+ Clamp::Option::Parsing::TRUTHY_ENVIRONMENT_VALUES.should == %w(1 yes enable on true)
174
+ end
175
+
176
+ it "should use an env value other than truthy ones to mean false" do
177
+ [nil, "0", "no", "whatever"].each do |val|
178
+ ENV["ENABLE"] = val
179
+ @command.parse([])
180
+ @command.enable?.should == false
181
+ end
182
+ end
183
+
184
+ it "should use the the flag value if present (instead of env)" do
185
+ ENV["ENABLE"] = "1"
186
+ @command.parse(%w(--no-enable))
187
+ @command.enable?.should == false
188
+ end
189
+
190
+ end
191
+
192
+ describe "with :required value" do
193
+
194
+ before do
195
+ @command.class.option "--port", "PORT", "port to listen on", :required => true
196
+ end
197
+
198
+ it "should fail if a required option is not provided" do
199
+ expect { @command.parse([]) }.to raise_error(Clamp::UsageError)
200
+ end
201
+
202
+ it "should succeed if a required option is provided" do
203
+ @command.parse(["--port", "12345"])
204
+ end
205
+
206
+ end
207
+
208
+ describe "with :required value with :env" do
209
+
210
+ before do
211
+ @command.class.option "--port", "PORT", "port to listen on", :required => true, :environment_variable => "PORT"
212
+ end
213
+
214
+ it "should fail if a required option is not provided" do
215
+ ENV.delete("PORT")
216
+ expect { @command.parse([]) }.to raise_error(Clamp::UsageError)
217
+ end
218
+
219
+ it "should succeed if a required option is provided via arguments" do
220
+ ENV.delete("PORT")
221
+ @command.parse(["--port", "12345"])
222
+ end
223
+
224
+ it "should succeed if a required option is provided via env" do
225
+ ENV["PORT"] = "12345"
226
+ @command.parse([])
227
+ end
228
+
229
+ end
230
+
231
+
113
232
  describe "with a block" do
114
233
 
115
234
  before do
@@ -178,6 +297,18 @@ describe Clamp::Command do
178
297
 
179
298
  end
180
299
 
300
+ describe "with a value appended to a short option" do
301
+
302
+ before do
303
+ @command.parse(%w(-fstrawberry))
304
+ end
305
+
306
+ it "works as though the value were separated" do
307
+ @command.flavour.should == "strawberry"
308
+ end
309
+
310
+ end
311
+
181
312
  describe "with combined short options" do
182
313
 
183
314
  before do
@@ -213,6 +344,20 @@ describe Clamp::Command do
213
344
 
214
345
  end
215
346
 
347
+ describe "with multi-line arguments that look like options" do
348
+
349
+ before do
350
+ @command.parse(["foo\n--flavour=strawberry", "bar\n-cblue"])
351
+ end
352
+
353
+ it "treats them as positional arguments" do
354
+ @command.arguments.should == ["foo\n--flavour=strawberry", "bar\n-cblue"]
355
+ @command.flavour.should be_nil
356
+ @command.color.should be_nil
357
+ end
358
+
359
+ end
360
+
216
361
  describe "with an option terminator" do
217
362
 
218
363
  it "considers everything after the terminator to be an argument" do
@@ -438,6 +583,40 @@ describe Clamp::Command do
438
583
 
439
584
  end
440
585
 
586
+ describe "with :environment_variable value" do
587
+
588
+ before do
589
+ @command.class.parameter "[FILE]", "a file", :environment_variable => "FILE",
590
+ :default => "/dev/null"
591
+ end
592
+
593
+ it "should use the default if neither flag nor env var are present" do
594
+ @command.parse([])
595
+ @command.file.should == "/dev/null"
596
+ end
597
+
598
+ it "should use the env value if present (instead of default)" do
599
+ ENV["FILE"] = "/etc/motd"
600
+ @command.parse([])
601
+ @command.file.should == ENV["FILE"]
602
+ end
603
+
604
+ it "should use the the flag value if present (instead of env)" do
605
+ ENV["FILE"] = "/etc/motd"
606
+ @command.parse(%w(/bin/sh))
607
+ @command.file.should == "/bin/sh"
608
+ end
609
+
610
+ describe "#help" do
611
+
612
+ it "describes the default value and env usage" do
613
+ @command.help.should include(%{ (default: $FILE, or "/dev/null")})
614
+ end
615
+
616
+ end
617
+
618
+ end
619
+
441
620
  end
442
621
 
443
622
  describe "with no parameters declared" do
@@ -503,6 +682,17 @@ describe Clamp::Command do
503
682
 
504
683
  end
505
684
 
685
+ describe "with multi-line arguments" do
686
+
687
+ it "parses them correctly" do
688
+ @command.parse(["foo\nhi", "bar", "baz"])
689
+ @command.x.should == "foo\nhi"
690
+ @command.y.should == "bar"
691
+ @command.z.should == "baz"
692
+ end
693
+
694
+ end
695
+
506
696
  describe "with too many arguments" do
507
697
 
508
698
  it "raises a UsageError" do
@@ -57,7 +57,7 @@ describe Clamp::Option do
57
57
  end
58
58
 
59
59
  describe "flag" do
60
-
60
+
61
61
  before do
62
62
  @option = Clamp::Option.new("--verbose", :flag, "Blah blah blah")
63
63
  end
@@ -69,11 +69,11 @@ describe Clamp::Option do
69
69
  end
70
70
 
71
71
  end
72
-
72
+
73
73
  end
74
74
 
75
75
  describe "negatable flag" do
76
-
76
+
77
77
  before do
78
78
  @option = Clamp::Option.new("--[no-]force", :flag, "Force installation")
79
79
  end
@@ -91,7 +91,7 @@ describe Clamp::Option do
91
91
  end
92
92
 
93
93
  end
94
-
94
+
95
95
  describe "#attribute_name" do
96
96
 
97
97
  it "is derived from the (long) switch" do
@@ -99,7 +99,7 @@ describe Clamp::Option do
99
99
  end
100
100
 
101
101
  end
102
-
102
+
103
103
  end
104
104
 
105
105
  describe "with both short and long switches" do
@@ -123,7 +123,40 @@ describe Clamp::Option do
123
123
 
124
124
  end
125
125
 
126
+ describe "with an associated environment variable" do
127
+
128
+ before do
129
+ @option = Clamp::Option.new("-x", "X", "mystery option", :environment_variable => "APP_X")
130
+ end
131
+
132
+ describe "#help" do
133
+
134
+ it "describes environment variable" do
135
+ @option.help.should == ["-x X", "mystery option (default: $APP_X)"]
136
+ end
137
+
138
+ end
139
+
140
+ describe "and a default value" do
141
+
142
+ before do
143
+ @option = Clamp::Option.new("-x", "X", "mystery option", :environment_variable => "APP_X", :default => "xyz")
144
+ end
145
+
146
+ describe "#help" do
147
+
148
+ it "describes both environment variable and default" do
149
+ @option.help.should == ["-x X", %{mystery option (default: $APP_X, or "xyz")}]
150
+ end
151
+
152
+ end
153
+
154
+ end
155
+
156
+ end
157
+
126
158
  describe "in subcommand" do
159
+
127
160
  before do
128
161
 
129
162
  @command = Class.new(Clamp::Command) do
@@ -145,5 +178,19 @@ describe Clamp::Option do
145
178
  end
146
179
 
147
180
  end
148
-
181
+
182
+ describe "a required option" do
183
+ it "rejects :default" do
184
+ expect do
185
+ Clamp::Option.new("--key-file", "FILE", "SSH identity",
186
+ :required => true, :default => "hello")
187
+ end.to raise_error(ArgumentError)
188
+ end
189
+
190
+ it "rejects :flag options" do
191
+ expect do
192
+ Clamp::Option.new("--awesome", :flag, "Be awesome?", :required => true)
193
+ end.to raise_error(ArgumentError)
194
+ end
195
+ end
149
196
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clamp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-03 00:00:00.000000000 Z
12
+ date: 2012-05-13 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! "Clamp provides an object-model for command-line utilities. \nIt handles
15
15
  parsing of command-line options, and generation of usage help.\n"
@@ -24,6 +24,7 @@ files:
24
24
  - README.markdown
25
25
  - Rakefile
26
26
  - clamp.gemspec
27
+ - examples/admin
27
28
  - examples/flipflop
28
29
  - examples/fubar
29
30
  - examples/gitdown
@@ -64,7 +65,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
64
65
  version: '0'
65
66
  segments:
66
67
  - 0
67
- hash: -1856448867096069066
68
+ hash: -1903818616036317857
68
69
  required_rubygems_version: !ruby/object:Gem::Requirement
69
70
  none: false
70
71
  requirements:
@@ -73,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
74
  version: '0'
74
75
  segments:
75
76
  - 0
76
- hash: -1856448867096069066
77
+ hash: -1903818616036317857
77
78
  requirements: []
78
79
  rubyforge_project:
79
80
  rubygems_version: 1.8.21