cri 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OWExM2ZhMjgwODJmMmVhMGU5ZTg2YTQzN2EwYTgwYjI2NzM3MzRhYw==
5
+ data.tar.gz: !binary |-
6
+ NTJjOWQ4ZDZjOGEzZmUzMDg4ZGQ4NzIyMWQ4NDQ5MTcyZjI4NWNkOA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ YjU3YTNjYWMyZDI3ZTM5Y2FkMGY1NDQ4YTcxYWU1YWNlYmEwNDg1YWE2ODhi
10
+ OGNhZjdiOGMyZGQ2MzUwOWZjMmQxNDVjYjAyYWM3ZTFhYjE4NzEwNzUzYjk4
11
+ N2RlMDdkM2IzYWU4MGRhNDExMTFkZmY5NWYzYWNhNmM1OTgzMGE=
12
+ data.tar.gz: !binary |-
13
+ NjUzMWY0NjY2ZTU5ZmE3ZGZjMWMzMjQ0OGE2ZGRlMzFkOTE4NTIyODcwNDU4
14
+ MTkyZGRlMjNmNmY1MzVmMmJlNzVhZmQ0N2E2ZmYyMjcxYmU2M2NhYzVhMWU2
15
+ MmI1ZGQyNWQ0NjU1ZmU0NDEzNjdhMjA0ZTEwMjFkYTM4YTQ0MDg=
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
@@ -0,0 +1,22 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ cri (2.4.0)
5
+ colored (>= 1.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ colored (1.2)
11
+ minitest (5.0.6)
12
+ rake (10.1.0)
13
+ yard (0.8.7)
14
+
15
+ PLATFORMS
16
+ ruby
17
+
18
+ DEPENDENCIES
19
+ cri!
20
+ minitest
21
+ rake
22
+ yard
data/NEWS.md CHANGED
@@ -1,6 +1,13 @@
1
1
  Cri News
2
2
  ========
3
3
 
4
+ 2.4.0
5
+ -----
6
+
7
+ * Allowed either short or long option to be, eh, optional [Ken Coar]
8
+ * Fixed wrap-and-indent behavior [Ken Coar]
9
+ * Moved version information into `cri/version`
10
+
4
11
  2.3.0
5
12
  -----
6
13
 
data/README.md CHANGED
@@ -20,12 +20,12 @@ Here’s a sample command definition:
20
20
  summary 'does stuff'
21
21
  description 'This command does a lot of stuff. I really mean a lot.'
22
22
 
23
- flag :h, :help, 'show help for this command' do |value, cmd|
23
+ flag :h, :help, 'show help for this command' do |value, cmd|
24
24
  puts cmd.help
25
25
  exit 0
26
26
  end
27
- flag :m, :more, 'do even more stuff'
28
- option :s, :stuff, 'specify stuff to do', :argument => :required
27
+ flag nil, :more, 'do even more stuff'
28
+ option :s, :stuff, 'specify stuff to do', :argument => :required
29
29
 
30
30
  run do |opts, args, cmd|
31
31
  stuff = opts[:stuff] || 'generic stuff'
@@ -55,7 +55,7 @@ Each command has automatically generated help. This help can be printed using
55
55
  options:
56
56
 
57
57
  -h --help show help for this command
58
- -m --more do even more stuff
58
+ --more do even more stuff
59
59
  -s --stuff specify stuff to do
60
60
 
61
61
  Let’s disect the command definition and start with the first five lines:
@@ -76,12 +76,12 @@ Aliases don’t make sense for root commands, but for subcommands they do.
76
76
 
77
77
  The next few lines contain the command’s option definitions:
78
78
 
79
- flag :h, :help, 'show help for this command' do |value, cmd|
79
+ flag :h, :help, 'show help for this command' do |value, cmd|
80
80
  puts cmd.help
81
81
  exit 0
82
82
  end
83
- flag :m, :more, 'do even more stuff'
84
- option :s, :stuff, 'specify stuff to do', :argument => :required
83
+ flag nil, :more, 'do even more stuff'
84
+ option :s, :stuff, 'specify stuff to do', :argument => :required
85
85
 
86
86
  Options can be defined using the following methods:
87
87
 
@@ -90,6 +90,11 @@ Options can be defined using the following methods:
90
90
  * {Cri::CommandDSL#required} (implies required argument)
91
91
  * {Cri::CommandDSL#optional} (implies optional argument)
92
92
 
93
+ All these methods take the short option form as their first argument, and a
94
+ long option form as their second argument. Either the short or the long form
95
+ can be nil, but not both (because that would not make any sense). In the
96
+ example above, the `--more` option has no short form.
97
+
93
98
  Each of the above methods also take a block, which will be executed when the
94
99
  option is found. The argument to the block are the option value (`true` in
95
100
  case the option does not have an argument) and the command.
@@ -125,9 +130,8 @@ To add a command as a subcommand to another command, use the {Cri::Command#add_c
125
130
  Contributors
126
131
  ------------
127
132
 
128
- (In alphabetical order)
129
-
130
133
  * Toon Willems
134
+ * Ken Coar
131
135
 
132
136
  Thanks for Lee “injekt” Jarvis for [Slop][1], which has inspired the design of Cri 2.0.
133
137
 
data/Rakefile CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  # Rake etc
6
6
  require 'rake'
7
+ require 'minitest'
7
8
  require 'minitest/unit'
8
9
 
9
10
  # Cri itself
@@ -32,7 +33,7 @@ task :test do
32
33
 
33
34
  $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
34
35
 
35
- MiniTest::Unit.autorun
36
+ MiniTest.autorun
36
37
 
37
38
  require 'test/helper.rb'
38
39
 
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  $LOAD_PATH.unshift(File.expand_path('../lib/', __FILE__))
4
- require 'cri'
4
+ require 'cri/version'
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = 'cri'
@@ -20,6 +20,10 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.add_dependency('colored', '>= 1.2')
22
22
 
23
+ s.add_development_dependency('rake')
24
+ s.add_development_dependency('minitest')
25
+ s.add_development_dependency('yard')
26
+
23
27
  s.rdoc_options = [ '--main', 'README.md' ]
24
28
  s.extra_rdoc_files = [ 'ChangeLog', 'LICENSE', 'README.md', 'NEWS.md' ]
25
29
  end
data/lib/cri.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ require 'cri/version'
2
3
 
3
4
  module Cri
4
5
 
@@ -16,9 +17,6 @@ module Cri
16
17
  class NoHelpAvailableError < Error
17
18
  end
18
19
 
19
- # The current Cri version.
20
- VERSION = '2.3.0'
21
-
22
20
  autoload 'Command', 'cri/command'
23
21
  autoload 'CommandDSL', 'cri/command_dsl'
24
22
  autoload 'CommandRunner', 'cri/command_runner'
@@ -371,17 +371,18 @@ module Cri
371
371
  if self.supercommand
372
372
  groups["options for #{self.supercommand.name}"] = self.supercommand.global_option_definitions
373
373
  end
374
- length = groups.values.inject(&:+).map { |o| o[:long].size }.max
374
+ length = groups.values.inject(&:+).map { |o| o[:long].to_s.size }.max
375
375
  groups.each_pair do |name, defs|
376
376
  unless defs.empty?
377
377
  text << "\n"
378
378
  text << "#{name}".formatted_as_title
379
379
  text << "\n"
380
- defs.sort { |x,y| x[:long] <=> y[:long] }.each do |opt_def|
380
+ ordered_defs = defs.sort_by { |x| x[:short] || x[:long] }
381
+ ordered_defs.each do |opt_def|
381
382
  text << sprintf(
382
- " -%1s --%-#{length+4}s",
383
- opt_def[:short],
384
- opt_def[:long]).formatted_as_option
383
+ " %-2s %-#{length+6}s",
384
+ opt_def[:short] ? ('-' + opt_def[:short]) : '',
385
+ opt_def[:long] ? ('--' + opt_def[:long]) : '').formatted_as_option
385
386
 
386
387
  text << opt_def[:desc] << "\n"
387
388
  end
@@ -400,7 +401,7 @@ module Cri
400
401
 
401
402
  def handle_options(opts)
402
403
  opts.each_pair do |key, value|
403
- opt_def = global_option_definitions.find { |o| o[:long] == key.to_s }
404
+ opt_def = global_option_definitions.find { |o| (o[:long] || o[:short]) == key.to_s }
404
405
  block = opt_def[:block]
405
406
  block.call(value, self) if block
406
407
  end
@@ -92,9 +92,9 @@ module Cri
92
92
  # Adds a new option to the command. If a block is given, it will be
93
93
  # executed when the option is successfully parsed.
94
94
  #
95
- # @param [String, Symbol] short The short option name
95
+ # @param [String, Symbol, nil] short The short option name
96
96
  #
97
- # @param [String, Symbol] long The long option name
97
+ # @param [String, Symbol, nil] long The long option name
98
98
  #
99
99
  # @param [String] desc The option description
100
100
  #
@@ -111,9 +111,9 @@ module Cri
111
111
  # Adds a new option with a required argument to the command. If a block is
112
112
  # given, it will be executed when the option is successfully parsed.
113
113
  #
114
- # @param [String, Symbol] short The short option name
114
+ # @param [String, Symbol, nil] short The short option name
115
115
  #
116
- # @param [String, Symbol] long The long option name
116
+ # @param [String, Symbol, nil] long The long option name
117
117
  #
118
118
  # @param [String] desc The option description
119
119
  #
@@ -127,9 +127,9 @@ module Cri
127
127
  # Adds a new option with a forbidden argument to the command. If a block
128
128
  # is given, it will be executed when the option is successfully parsed.
129
129
  #
130
- # @param [String, Symbol] short The short option name
130
+ # @param [String, Symbol, nil] short The short option name
131
131
  #
132
- # @param [String, Symbol] long The long option name
132
+ # @param [String, Symbol, nil] long The long option name
133
133
  #
134
134
  # @param [String] desc The option description
135
135
  #
@@ -144,9 +144,9 @@ module Cri
144
144
  # Adds a new option with an optional argument to the command. If a block
145
145
  # is given, it will be executed when the option is successfully parsed.
146
146
  #
147
- # @param [String, Symbol] short The short option name
147
+ # @param [String, Symbol, nil] short The short option name
148
148
  #
149
- # @param [String, Symbol] long The long option name
149
+ # @param [String, Symbol, nil] long The long option name
150
150
  #
151
151
  # @param [String] desc The option description
152
152
  #
@@ -189,9 +189,13 @@ module Cri
189
189
  protected
190
190
 
191
191
  def add_option(short, long, desc, argument, block)
192
+ if short.nil? && long.nil?
193
+ raise ArgumentError, "short and long options cannot both be nil"
194
+ end
195
+
192
196
  @command.option_definitions << {
193
- :short => short.to_s,
194
- :long => long.to_s,
197
+ :short => short.nil? ? nil : short.to_s,
198
+ :long => long.nil? ? nil : long.to_s,
195
199
  :desc => desc,
196
200
  :argument => argument,
197
201
  :block => block }
@@ -33,6 +33,8 @@ module Cri::CoreExtensions
33
33
  #
34
34
  # @return [String] The word-wrapped and indented string
35
35
  def wrap_and_indent(width, indentation)
36
+ indented_width = width - indentation
37
+ indent = ' ' * indentation
36
38
  # Split into paragraphs
37
39
  paragraphs = self.to_paragraphs
38
40
 
@@ -45,7 +47,7 @@ module Cri::CoreExtensions
45
47
  # Split into words
46
48
  paragraph.split(/\s/).each do |word|
47
49
  # Begin new line if it's too long
48
- if (line + ' ' + word).length >= width
50
+ if (line + ' ' + word).length >= indented_width
49
51
  lines << line
50
52
  line = ''
51
53
  end
@@ -56,7 +58,7 @@ module Cri::CoreExtensions
56
58
  lines << line
57
59
 
58
60
  # Join lines
59
- lines.map { |l| ' '*indentation + l }.join("\n")
61
+ lines.map { |l| indent + l }.join("\n")
60
62
  end.join("\n\n")
61
63
  end
62
64
 
@@ -194,10 +194,10 @@ module Cri
194
194
  end
195
195
 
196
196
  # Store option
197
- add_option(definition[:long].to_sym, option_value)
197
+ add_option(definition, option_value)
198
198
  else
199
199
  # Store option
200
- add_option(definition[:long].to_sym, true)
200
+ add_option(definition, true)
201
201
  end
202
202
  # Handle -xyz options
203
203
  elsif e =~ /^-./ and !@no_more_options
@@ -226,10 +226,10 @@ module Cri
226
226
  end
227
227
 
228
228
  # Store option
229
- add_option(definition[:long].to_sym, option_value)
229
+ add_option(definition, option_value)
230
230
  else
231
231
  # Store option
232
- add_option(definition[:long].to_sym, true)
232
+ add_option(definition, true)
233
233
  end
234
234
  end
235
235
  # Handle normal arguments
@@ -244,7 +244,8 @@ module Cri
244
244
 
245
245
  private
246
246
 
247
- def add_option(key, value)
247
+ def add_option(definition, value)
248
+ key = (definition[:long] || definition[:short]).to_sym
248
249
  options[key] = value
249
250
  delegate.option_added(key, value, self) unless delegate.nil?
250
251
  end
@@ -0,0 +1,6 @@
1
+ module Cri
2
+
3
+ # The current Cri version.
4
+ VERSION = '2.4.0'
5
+
6
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'stringio'
4
4
 
5
- class Cri::TestCase < MiniTest::Unit::TestCase
5
+ class Cri::TestCase < Minitest::Test
6
6
 
7
7
  def setup
8
8
  @orig_io = capture_io
@@ -263,6 +263,19 @@ class Cri::CommandTestCase < Cri::TestCase
263
263
  bare_cmd.help
264
264
  end
265
265
 
266
+ def test_help_with_optional_options
267
+ cmd = Cri::Command.define do
268
+ name 'build'
269
+ flag :s, nil, 'short'
270
+ flag nil, :long, 'long'
271
+ end
272
+ help = cmd.help
273
+
274
+ assert_match(/--long.*-s/m, help)
275
+ assert_match(/^\e\[33m --long \e\[0mlong$/, help)
276
+ assert_match(/^\e\[33m -s \e\[0mshort$/, help)
277
+ end
278
+
266
279
  def test_modify_with_block_argument
267
280
  cmd = Cri::Command.define do |c|
268
281
  c.name 'build'
@@ -46,6 +46,48 @@ class Cri::CommandDSLTestCase < Cri::TestCase
46
46
  assert_equal expected_option_definitions, actual_option_definitions
47
47
  end
48
48
 
49
+ def test_optional_options
50
+ # Define
51
+ dsl = Cri::CommandDSL.new
52
+ dsl.instance_eval do
53
+ name 'moo'
54
+ usage 'dunno whatever'
55
+ summary 'does stuff'
56
+ description 'This command does a lot of stuff.'
57
+
58
+ flag :s, nil, 'short'
59
+ flag nil, :long, 'long'
60
+
61
+ run do |opts, args|
62
+ $did_it_work = :probably
63
+ end
64
+ end
65
+ command = dsl.command
66
+
67
+ # Run
68
+ $did_it_work = :sadly_not
69
+ command.run(%w( -s --long ))
70
+ assert_equal :probably, $did_it_work
71
+
72
+ # Check options
73
+ expected_option_definitions = Set.new([
74
+ { :short => 's', :long => nil, :desc => 'short', :argument => :forbidden, :block => nil },
75
+ { :short => nil, :long => 'long', :desc => 'long', :argument => :forbidden, :block => nil }
76
+ ])
77
+ actual_option_definitions = Set.new(command.option_definitions)
78
+ assert_equal expected_option_definitions, actual_option_definitions
79
+ end
80
+
81
+ def test_optional_options
82
+ # Define
83
+ dsl = Cri::CommandDSL.new
84
+ assert_raises ArgumentError do
85
+ dsl.instance_eval do
86
+ flag nil, nil, 'meh'
87
+ end
88
+ end
89
+ end
90
+
49
91
  def test_subcommand
50
92
  # Define
51
93
  dsl = Cri::CommandDSL.new
@@ -15,7 +15,7 @@ class Cri::CoreExtTestCase < Cri::TestCase
15
15
 
16
16
  def test_string_wrap_and_indent_without_indent
17
17
  original = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, " +
18
- "sed do eiusmod tempor incididunt ut labore et dolore " +
18
+ "sed do eiusmod tempor incididunt ut labore et dolore " +
19
19
  "magna aliqua."
20
20
 
21
21
  expected = "Lorem ipsum dolor sit amet, consectetur\n" +
@@ -29,27 +29,51 @@ class Cri::CoreExtTestCase < Cri::TestCase
29
29
 
30
30
  def test_string_wrap_and_indent_with_indent
31
31
  original = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, " +
32
- "sed do eiusmod tempor incididunt ut labore et dolore " +
32
+ "sed do eiusmod tempor incididunt ut labore et dolore " +
33
33
  "magna aliqua."
34
34
 
35
35
  expected = " Lorem ipsum dolor sit amet,\n" +
36
- " consectetur adipisicing elit, sed\n" +
37
- " do eiusmod tempor incididunt ut\n" +
38
- " labore et dolore magna aliqua."
36
+ " consectetur adipisicing elit,\n" +
37
+ " sed do eiusmod tempor\n" +
38
+ " incididunt ut labore et dolore\n" +
39
+ " magna aliqua."
39
40
 
40
41
  actual = original.wrap_and_indent(36, 4)
41
42
  assert_equal expected, actual
42
43
  end
43
44
 
45
+ def test_string_wrap_and_indent_with_large_indent
46
+ original = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, " +
47
+ "sed do eiusmod tempor incididunt ut labore et dolore " +
48
+ "magna aliqua."
49
+
50
+ expected = " Lorem ipsum\n" +
51
+ " dolor sit\n" +
52
+ " amet,\n" +
53
+ " consectetur\n" +
54
+ " adipisicing\n" +
55
+ " elit, sed do\n" +
56
+ " eiusmod\n" +
57
+ " tempor\n" +
58
+ " incididunt ut\n" +
59
+ " labore et\n" +
60
+ " dolore magna\n" +
61
+ " aliqua."
62
+
63
+ actual = original.wrap_and_indent(44, 30)
64
+ assert_equal expected, actual
65
+ end
66
+
44
67
  def test_string_wrap_and_indent_with_multiple_lines
45
68
  original = "Lorem ipsum dolor sit\namet, consectetur adipisicing elit, " +
46
- "sed do\neiusmod tempor incididunt ut\nlabore et dolore " +
69
+ "sed do\neiusmod tempor incididunt ut\nlabore et dolore " +
47
70
  "magna\naliqua."
48
71
 
49
72
  expected = " Lorem ipsum dolor sit amet,\n" +
50
- " consectetur adipisicing elit, sed\n" +
51
- " do eiusmod tempor incididunt ut\n" +
52
- " labore et dolore magna aliqua."
73
+ " consectetur adipisicing elit,\n" +
74
+ " sed do eiusmod tempor\n" +
75
+ " incididunt ut labore et dolore\n" +
76
+ " magna aliqua."
53
77
 
54
78
  actual = original.wrap_and_indent(36, 4)
55
79
  assert_equal expected, actual
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cri
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
5
- prerelease:
4
+ version: 2.4.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Denis Defreyne
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-06-05 00:00:00.000000000 Z
11
+ date: 2013-08-31 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: colored
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ! '>='
20
18
  - !ruby/object:Gem::Version
@@ -22,11 +20,52 @@ dependencies:
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ! '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
30
69
  description: Cri allows building easy-to-use commandline interfaces with support for
31
70
  subcommands.
32
71
  email: denis.defreyne@stoneship.org
@@ -39,6 +78,8 @@ extra_rdoc_files:
39
78
  - NEWS.md
40
79
  files:
41
80
  - ChangeLog
81
+ - Gemfile
82
+ - Gemfile.lock
42
83
  - LICENSE
43
84
  - NEWS.md
44
85
  - Rakefile
@@ -51,6 +92,7 @@ files:
51
92
  - lib/cri/core_ext/string.rb
52
93
  - lib/cri/core_ext.rb
53
94
  - lib/cri/option_parser.rb
95
+ - lib/cri/version.rb
54
96
  - lib/cri.rb
55
97
  - test/helper.rb
56
98
  - test/test_base.rb
@@ -64,6 +106,7 @@ files:
64
106
  - .gemtest
65
107
  homepage: http://stoneship.org/software/cri/
66
108
  licenses: []
109
+ metadata: {}
67
110
  post_install_message:
68
111
  rdoc_options:
69
112
  - --main
@@ -71,22 +114,20 @@ rdoc_options:
71
114
  require_paths:
72
115
  - lib
73
116
  required_ruby_version: !ruby/object:Gem::Requirement
74
- none: false
75
117
  requirements:
76
118
  - - ! '>='
77
119
  - !ruby/object:Gem::Version
78
120
  version: '0'
79
121
  required_rubygems_version: !ruby/object:Gem::Requirement
80
- none: false
81
122
  requirements:
82
123
  - - ! '>='
83
124
  - !ruby/object:Gem::Version
84
125
  version: '0'
85
126
  requirements: []
86
127
  rubyforge_project:
87
- rubygems_version: 1.8.24
128
+ rubygems_version: 2.0.3
88
129
  signing_key:
89
- specification_version: 3
130
+ specification_version: 4
90
131
  summary: a library for building easy-to-use commandline tools
91
132
  test_files: []
92
133
  has_rdoc: