acclaim 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -49,9 +49,9 @@ module Acclaim
49
49
  module ClassMethods
50
50
 
51
51
  # String which calls this command.
52
- def line(value = nil)
53
- @line = value
54
- @line ||= name.gsub(/^.*::/, '').downcase
52
+ def line(*args)
53
+ @line = args.first unless args.empty?
54
+ @line ||= (name.gsub(/^.*::/, '').downcase rescue nil)
55
55
  end
56
56
 
57
57
  # Commands which may be given to this command.
@@ -72,8 +72,8 @@ module Acclaim
72
72
  alias :opt :option
73
73
 
74
74
  # The block which is executed when this command is called. It is given 2
75
- # parameters; the first is an Ribbon::Object instance which can be queried
76
- # for settings information; the second is the remaining command line.
75
+ # parameters; the first is an Ribbon instance which can be queried for
76
+ # settings information; the second is the remaining command line.
77
77
  def action(&block)
78
78
  @action = block
79
79
  end
@@ -102,7 +102,7 @@ module Acclaim
102
102
 
103
103
  # Invokes this command with a fresh set of option values.
104
104
  def run(*args)
105
- invoke Ribbon::Object.new, args
105
+ invoke Ribbon.new, args
106
106
  rescue Option::Parser::Error => e
107
107
  puts e.message
108
108
  end
@@ -116,7 +116,7 @@ module Acclaim
116
116
  # All argument separators will be deleted from the argument array before a
117
117
  # command is executed.
118
118
  def invoke(opts, args = [])
119
- Ribbon::Object.merge! opts, parse_options!(args)
119
+ Ribbon.merge! opts, parse_options!(args)
120
120
  handle_special_options! opts, args
121
121
  if subcommand = parse_subcommands!(args)
122
122
  subcommand.invoke(opts, args)
@@ -7,7 +7,7 @@ module Acclaim
7
7
  # Represents a command-line option.
8
8
  class Option
9
9
 
10
- attr_accessor :key, :names, :description, :type, :default, :handler
10
+ attr_accessor :key, :names, :description, :type, :default, :handler, :on_multiple
11
11
 
12
12
  # Initializes a command line option. The +key+ is the object used to
13
13
  # associate this option with a value. The other arguments may be:
@@ -45,6 +45,7 @@ module Acclaim
45
45
  self.key = key
46
46
  self.names = matches.fetch true, []
47
47
  self.description = matches.fetch(false, []).first
48
+ self.on_multiple = options.fetch :on_multiple, :replace
48
49
  self.arity = options[:arity]
49
50
  self.default = options[:default]
50
51
  self.required = options[:required]
@@ -14,16 +14,25 @@ module Acclaim
14
14
 
15
15
  # Raises an Error with the following error message:
16
16
  #
17
- # Wrong number of arguments (actual for minimum)
17
+ # Wrong number of arguments (#{actual} for #{minimum})
18
18
  def self.raise_wrong_arg_number(actual, minimum, optional)
19
19
  raise self, "Wrong number of arguments (#{actual} for #{minimum})"
20
20
  end
21
21
 
22
22
  # Raises an Error with the following error message:
23
23
  #
24
- # Missing required argument (arg)
25
- def self.raise_missing_arg(arg)
26
- raise self, "Missing required argument (#{arg})"
24
+ # Missing required argument (#{option.names.join '|'})
25
+ def self.raise_missing_required(option)
26
+ names = option.names.join '|'
27
+ raise self, "Missing required argument (#{names})"
28
+ end
29
+
30
+ # Raises an error with the following error message:
31
+ #
32
+ # Multiple instances of [#{options.names.join ''}] encountered
33
+ def self.raise_multiple(option)
34
+ names = option.names.join '|'
35
+ raise self, "Multiple instances of [#{names}] encountered"
27
36
  end
28
37
 
29
38
  end
@@ -34,8 +43,8 @@ module Acclaim
34
43
  # options. If no option array is given, the argument array will be
35
44
  # preprocessed only.
36
45
  def initialize(argv, options = nil)
37
- self.argv = argv
38
- self.options = options
46
+ self.argv = argv || []
47
+ self.options = options || []
39
48
  end
40
49
 
41
50
  # Parses the meaning of the options given to this parser. If none were
@@ -51,13 +60,13 @@ module Acclaim
51
60
  # options << Option.new(:verbose, '--verbose')
52
61
  #
53
62
  # Option::Parser.new(args, options).parse!
54
- # => { Ribbon file:log.txt, verbose:true }
63
+ # => {Ribbon file: "log.txt", verbose: true}
55
64
  #
56
65
  # args
57
66
  # => ["arg1", "arg2"]
58
67
  def parse!
59
68
  preprocess_argv!
60
- parse_values! unless options.nil?
69
+ parse_values!
61
70
  end
62
71
 
63
72
  private
@@ -98,25 +107,23 @@ module Acclaim
98
107
  end
99
108
 
100
109
  # Parses the options and their arguments, associating that information
101
- # with a Ribbon::Object instance.
110
+ # with a Ribbon instance.
102
111
  def parse_values!
103
- ribbon = Ribbon::Object.new
112
+ ribbon = Ribbon.new
104
113
  options.each do |option|
105
114
  key = option.key
106
- ribbon[key] = option.default unless ribbon[key]
115
+ ribbon[key] = option.default unless Ribbon[ribbon].has_key? key
107
116
  switches = argv.find_all { |switch| option =~ switch }
108
- if switches.any?
117
+ Error.raise_missing_required option if option.required? and switches.empty?
118
+ Error.raise_multiple option if option.on_multiple == :raise and switches.count > 1
119
+ switches.each do |switch|
109
120
  if option.flag?
110
121
  found_boolean option, ribbon
111
- argv.delete *switches
122
+ argv.delete_at argv.index(switch)
112
123
  else
113
- switches.each do |switch|
114
- params = extract_parameters_of! option, switch
115
- found_params_for option, ribbon, params
116
- end
124
+ params = extract_parameters_of! option, switch
125
+ found_params_for option, params, ribbon
117
126
  end
118
- else
119
- Error.raise_missing_arg(option.names.join ' | ') if option.required?
120
127
  end
121
128
  end
122
129
  ribbon
@@ -150,8 +157,8 @@ module Acclaim
150
157
  end
151
158
  count = values.count
152
159
  Error.raise_wrong_arg_number count, *arity if count < arity.required
153
- argv.delete switch
154
- values.each { |value| argv.delete value }
160
+ argv.slice! switch_index..(switch_index + count)
161
+ values
155
162
  end
156
163
 
157
164
  # If the option has an custom handler associated, it will be called with
@@ -160,22 +167,27 @@ module Acclaim
160
167
  # <tt>params.first</tt>, if the option takes only one argument, or to
161
168
  # +params+ if it takes more.
162
169
  #
170
+ # Appends +params+ to the current values of the option if the it specifies
171
+ # so. In this case, the value of the option will always be an array.
172
+ #
163
173
  # The parameters will be converted according to the option's type.
164
- def found_params_for(option, values, params = [])
174
+ def found_params_for(option, params = [], ribbon = Ribbon.new)
165
175
  params = option.convert_parameters *params
166
- if handler = option.handler then handler.call values, params
176
+ if handler = option.handler then handler.call ribbon, params
167
177
  else
178
+ key = option.key.to_sym
168
179
  value = option.arity.total == 1 ? params.first : params
169
- values[option.key.to_sym] = value unless params.empty?
180
+ value = [*ribbon[key], *value] if option.on_multiple == :append
181
+ ribbon[option.key.to_sym] = value unless params.empty?
170
182
  end
171
183
  end
172
184
 
173
185
  # If the option has an custom handler associated, it will be called with
174
186
  # only the option values as the first argument. Otherwise, the value will
175
187
  # be set to <tt>true</tt>.
176
- def found_boolean(option, values)
177
- if handler = option.handler then handler.call values
178
- else values[option.key.to_sym] = true end
188
+ def found_boolean(option, ribbon = Ribbon.new)
189
+ if handler = option.handler then handler.call ribbon
190
+ else ribbon[option.key.to_sym] = true end
179
191
  end
180
192
 
181
193
  end
@@ -7,9 +7,6 @@ module Acclaim
7
7
 
8
8
  # Regular expression for a short option switch.
9
9
  #
10
- # Matches strings that begin with a single dash and contains only one
11
- # word character before the end of the string.
12
- #
13
10
  # Examples: <tt>-s; -_</tt>
14
11
  #
15
12
  # <tt>'-mult'</tt> should match MULTIPLE_SHORT_SWITCHES, and will be
@@ -19,11 +16,6 @@ module Acclaim
19
16
 
20
17
  # Regular expression for a long option switch.
21
18
  #
22
- # Matches strings that begin with a double dash, contain one or more
23
- # word character or digit, and can be followed by either nothing or a
24
- # single dash. The latter must be followed by one or more word character
25
- # or digit.
26
- #
27
19
  # Examples: <tt>--long; --no-feature; --with_underscore;
28
20
  # --_private-option; --1-1</tt>
29
21
  LONG_SWITCH = /\A--[\w\d]+(-[\w\d]+)*\Z/
@@ -31,24 +23,12 @@ module Acclaim
31
23
  # Regular expression for multiple short options in a single "short"
32
24
  # switch.
33
25
  #
34
- # Matches strings that begin with a single dash and are followed by 2 or
35
- # more word characters, among which is the underscore but not the dash
36
- # character.
37
- #
38
- # Examples: -xvf, -abc, -de_f
26
+ # Examples: <tt>-xvf; -abc; -de_f</tt>
39
27
  MULTIPLE_SHORT_SWITCHES = /\A-\w{2,}\Z/
40
28
 
41
29
  # Regular expression for a long switch connected to its parameters with
42
30
  # an equal sign. Multiple parameters are be separated by commas.
43
31
  #
44
- # Matches strings that begin with a double dash, are followed by one or
45
- # more word character or digit and may be followed by one dash and one
46
- # or more word character or digit.
47
- #
48
- # After that, there must be an equals sign, which must be followed by
49
- # either nothing, any number of commmas or any number of word characters
50
- # or digits.
51
- #
52
32
  # Examples:
53
33
  # <tt>
54
34
  # --switch=PARAM; --files=f1,f2,f3; --weird=,PARAM2; --empty=,,; --none=
@@ -63,15 +43,12 @@ module Acclaim
63
43
  SWITCH_PARAM_EQUALS = /\A--[\w\d]+(-[\w\d]+)*=(,*[\w\d]*)*\Z/
64
44
 
65
45
  # Regular expression for any kind of option switch.
66
- #
67
- # Matches anything that matches any of the other switch regular
68
- # expressions.
69
46
  SWITCH = /(#{SHORT_SWITCH})|(#{LONG_SWITCH})|(#{MULTIPLE_SHORT_SWITCHES})|(#{SWITCH_PARAM_EQUALS})/
70
47
 
71
48
  # Regular expression for the string that separates options and their
72
49
  # parameters from arguments like filenames.
73
50
  #
74
- # Matches strings made up of 2 or more dashes.
51
+ # Examples: <tt>--; ---</tt>
75
52
  ARGUMENT_SEPARATOR = /\A-{2,}\Z/
76
53
 
77
54
  end
@@ -16,7 +16,7 @@ module Acclaim
16
16
  # Patch version.
17
17
  #
18
18
  # Increments denote changes in implementation.
19
- PATCH = 6
19
+ PATCH = 7
20
20
 
21
21
  # Build version.
22
22
  #
@@ -0,0 +1,69 @@
1
+ require 'acclaim/command'
2
+
3
+ module Test; end
4
+ class Test::Command < Acclaim::Command; end
5
+ class Test::Command::Subcommand < Test::Command; end
6
+
7
+ describe Acclaim::Command do
8
+
9
+ describe Test::Command do
10
+ subject { Test::Command }
11
+
12
+ describe '::line' do
13
+ context 'when not given a parameter' do
14
+ it 'should return the default command name of the class' do
15
+ subject.line.should == 'command'
16
+ end
17
+ end
18
+
19
+ context 'when given a parameter' do
20
+ let(:param) { 'test2' }
21
+ before(:all) { subject.line param }
22
+ after(:all) { subject.line nil } # Reset command name.
23
+
24
+ it 'should set the command name of the class' do
25
+ subject.line.should == param
26
+ end
27
+ end
28
+ end
29
+
30
+ describe '::subcommands' do
31
+ it 'should not be empty' do
32
+ subject.subcommands.should_not be_empty
33
+ end
34
+
35
+ it 'should include the subcommand' do
36
+ subject.subcommands.should include(Test::Command::Subcommand)
37
+ end
38
+ end
39
+ end
40
+
41
+ describe Test::Command::Subcommand do
42
+ subject { Test::Command::Subcommand }
43
+
44
+ describe '::line' do
45
+ context 'when not given a parameter' do
46
+ it 'should return the default command name of the class' do
47
+ subject.line.should == 'subcommand'
48
+ end
49
+ end
50
+
51
+ context 'when given a parameter' do
52
+ let(:param) { 'subcommand2' }
53
+ before(:all) { subject.line param }
54
+ after(:all) { subject.line nil } # Reset command name.
55
+
56
+ it 'should set the command name of the class' do
57
+ subject.line.should == param
58
+ end
59
+ end
60
+ end
61
+
62
+ describe '::subcommands' do
63
+ it 'should be empty' do
64
+ subject.subcommands.should be_empty
65
+ end
66
+ end
67
+ end
68
+
69
+ end
@@ -74,8 +74,8 @@ describe Acclaim::Option::Parser do
74
74
  end
75
75
 
76
76
  context 'when not given an array of options' do
77
- it 'should not return any option values' do
78
- subject.parse!.should be_nil
77
+ it 'should return an empty ribbon' do
78
+ subject.parse!.should_not be_nil
79
79
  end
80
80
  end
81
81
 
@@ -200,6 +200,49 @@ describe Acclaim::Option::Parser do
200
200
  end
201
201
  end
202
202
  end
203
+
204
+ context 'containing an option which' do
205
+ let!(:options) { [ Acclaim::Option.new(:files, '-f', arity: [1,0], on_multiple: on_multiple, &block) ] }
206
+ let!(:args) { %w(-f f1 -f f2 -f f3) }
207
+ let(:block) { nil }
208
+
209
+ context 'replaces the previously found value' do
210
+ let(:on_multiple) { :replace }
211
+
212
+ it 'should replace the value with the last argument found' do
213
+ subject.parse!.files.should == 'f3'
214
+ end
215
+ end
216
+
217
+ context 'appends to the previously found values' do
218
+ let(:on_multiple) { :append }
219
+
220
+ it 'should return all arguments' do
221
+ subject.parse!.files.should == %w(f1 f2 f3)
222
+ end
223
+
224
+ context 'but that was passed a handler block' do
225
+ let(:block) { proc { |values| values.files = :block } }
226
+
227
+ it 'should parse all options and arguments' do
228
+ subject.parse!
229
+ args.should be_empty
230
+ end
231
+
232
+ it "should use the handler to obtain the option's value" do
233
+ subject.parse!.files.should == :block
234
+ end
235
+ end
236
+ end
237
+
238
+ context 'raises an error if encountered multiple times' do
239
+ let(:on_multiple) { :raise }
240
+
241
+ it 'should raise a parser error' do
242
+ expect { subject.parse! }.to raise_error Acclaim::Option::Parser::Error, /multiple/i
243
+ end
244
+ end
245
+ end
203
246
  end
204
247
  end
205
248
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acclaim
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-27 00:00:00.000000000 Z
12
+ date: 2012-01-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ribbon
16
- requirement: &19367260 !ruby/object:Gem::Requirement
16
+ requirement: &17514000 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *19367260
24
+ version_requirements: *17514000
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &19366760 !ruby/object:Gem::Requirement
27
+ requirement: &17513440 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *19366760
35
+ version_requirements: *17513440
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rookie
38
- requirement: &19366220 !ruby/object:Gem::Requirement
38
+ requirement: &17513000 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *19366220
46
+ version_requirements: *17513000
47
47
  description: Command-line option parser and command interface.
48
48
  email: matheus.a.m.moreira@gmail.com
49
49
  executables: []
@@ -76,6 +76,7 @@ files:
76
76
  - lib/acclaim/option/type/time.rb
77
77
  - lib/acclaim/option/type/uri.rb
78
78
  - lib/acclaim/version.rb
79
+ - spec/acclaim/command_spec.rb
79
80
  - spec/acclaim/option/arity_spec.rb
80
81
  - spec/acclaim/option/parser_spec.rb
81
82
  - spec/acclaim/option_spec.rb
@@ -93,7 +94,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
93
94
  version: '0'
94
95
  segments:
95
96
  - 0
96
- hash: 407623794010834174
97
+ hash: 1879446143954765838
97
98
  required_rubygems_version: !ruby/object:Gem::Requirement
98
99
  none: false
99
100
  requirements:
@@ -102,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
103
  version: '0'
103
104
  segments:
104
105
  - 0
105
- hash: 407623794010834174
106
+ hash: 1879446143954765838
106
107
  requirements: []
107
108
  rubyforge_project:
108
109
  rubygems_version: 1.8.10