acclaim 0.0.6 → 0.0.7

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.
@@ -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