acclaim 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  *.lock
2
2
  doc/
3
+ .yardoc/
@@ -1,24 +1,27 @@
1
1
  #!/usr/bin/env gem build
2
2
  # encoding: utf-8
3
- $:.unshift File.expand_path('../lib', __FILE__)
4
3
 
5
- require 'acclaim/version'
4
+ Gem::Specification.new 'acclaim' do |gem|
6
5
 
7
- Gem::Specification.new('acclaim') do |gem|
6
+ current_directory = File.dirname __FILE__
7
+ version_file = File.expand_path "#{gem.name}.version", current_directory
8
8
 
9
- gem.version = Acclaim::Version::STRING
10
- gem.summary = 'Command-line option parser and command interface.'
11
- gem.description = gem.summary
12
- gem.homepage = 'https://github.com/matheusmoreira/acclaim'
9
+ gem.version = File.read(version_file).chomp
10
+
11
+ gem.summary = 'Command-line option parser and command interface.'
12
+ gem.homepage = 'https://github.com/matheusmoreira/acclaim'
13
13
 
14
14
  gem.author = 'Matheus Afonso Martins Moreira'
15
- gem.email = 'matheus.a.m.moreira@gmail.com'
15
+ gem.email = 'matheus.a.m.moreira@gmail.com'
16
16
 
17
17
  gem.files = `git ls-files`.split "\n"
18
18
 
19
+ gem.add_runtime_dependency 'jewel'
19
20
  gem.add_runtime_dependency 'ribbon'
20
21
 
21
- gem.add_development_dependency 'rspec'
22
+ gem.add_development_dependency 'redcarpet'
22
23
  gem.add_development_dependency 'rookie'
24
+ gem.add_development_dependency 'rspec'
25
+ gem.add_development_dependency 'yard'
23
26
 
24
27
  end
@@ -0,0 +1 @@
1
+ 0.4.0
@@ -1,7 +1,14 @@
1
- # Acclaim is a command line option parsing and command interface for Ruby.
1
+ # Command line option parsing and command interface for Ruby.
2
+ #
3
+ # @author Matheus Afonso Martins Moreira
4
+ # @since 0.0.1
2
5
  module Acclaim
3
6
  end
4
7
 
5
- %w(command option version).each do |file|
6
- require file.prepend 'acclaim/'
7
- end
8
+ %w(
9
+
10
+ acclaim/command
11
+ acclaim/gem
12
+ acclaim/option
13
+
14
+ ).each { |file| require file }
@@ -1,8 +1,15 @@
1
- %w(option option/parser option/parser/regexp).each do |file|
2
- require file.prepend 'acclaim/'
3
- end
1
+ %w(
2
+
3
+ acclaim/command/dsl
4
+ acclaim/command/parser
5
+ acclaim/option
6
+ acclaim/option/parser
7
+ acclaim/option/parser/regexp
4
8
 
5
- %w(ribbon ribbon/core_extensions/object).each { |file| require file }
9
+ ribbon
10
+ ribbon/core_extensions/object
11
+
12
+ ).each { |file| require file }
6
13
 
7
14
  module Acclaim
8
15
 
@@ -42,177 +49,19 @@ module Acclaim
42
49
  # Verbose? yes
43
50
  # Doing testing with acclaim and safeguard!
44
51
  class Command
52
+ end
45
53
 
46
- # Module containing the class methods every command class should inherit.
47
- module ClassMethods
48
-
49
- # String which calls this command.
50
- def line(*args)
51
- @line = args.first unless args.empty?
52
- @line ||= (name.gsub(/^.*::/, '').downcase rescue nil)
53
- end
54
-
55
- # Commands which may be given to this command.
56
- def subcommands
57
- @subcommands ||= []
58
- end
59
-
60
- # The options this command can take.
61
- def options
62
- @options ||= []
63
- end
64
-
65
- # Adds an option to this command.
66
- def option(*args, &block)
67
- options << Option.new(*args, &block)
68
- end
69
-
70
- # Same as #option.
71
- alias opt option
72
-
73
- # The block which is executed when this command is called. It is given 2
74
- # parameters; the first is an Ribbon instance which can be queried for
75
- # settings information; the second is the remaining command line.
76
- def action(&block)
77
- @action = block
78
- end
79
-
80
- # Same as #action.
81
- alias when_called action
82
-
83
- # Adds help subcommand and options to this command.
84
- def help(*args)
85
- Help.create(self, *args)
86
- end
87
-
88
- # Adds help subcommand and options to this command.
89
- def version(*args)
90
- Version.create(self, *args)
91
- end
92
-
93
- # Parses the argument array using this command's set of options.
94
- def parse_options!(args)
95
- Option::Parser.new(args, options).parse!
96
- end
97
-
98
- # Looks for this command's subcommands in the argument array.
99
- def parse_subcommands!(args)
100
- Command::Parser.new(args, subcommands).parse!
101
- end
102
-
103
- # Invokes this command with a fresh set of option values.
104
- def run(*args)
105
- invoke args
106
- rescue Option::Parser::Error => error
107
- $stderr.puts error.message
108
- end
109
-
110
- # Parses the argument array. The argument array will be searched for
111
- # subcommands; if one is found, it will be invoked, if not, this command
112
- # will be executed. A subcommand may be anywhere in the array as long as
113
- # it is before an argument separator, which is tipically a double dash
114
- # (<tt>--</tt>) and may be omitted.
115
- #
116
- # All argument separators will be deleted from the argument array before a
117
- # command is executed.
118
- def invoke(args = [], opts = {})
119
- opts = Ribbon.wrap opts
120
- opts.merge! parse_options!(args)
121
- handle_special_options! opts, args
122
- if subcommand = parse_subcommands!(args)
123
- subcommand.invoke args, opts
124
- else
125
- delete_argument_separators_in! args
126
- execute opts, args
127
- end
128
- end
129
-
130
- # Calls this command's action block with the given option values and
131
- # arguments.
132
- def execute(opts, args)
133
- @action.call opts, args if @action
134
- end
135
-
136
- # Same as #execute.
137
- alias call execute
138
-
139
- # True if this is a top-level command.
140
- def root?
141
- superclass == Acclaim::Command
142
- end
143
-
144
- # Returns all command ancestors of this command.
145
- def command_ancestors
146
- ancestors - Acclaim::Command.ancestors
147
- end
148
-
149
- # Returns the root of the command hierarchy.
150
- def root
151
- command_ancestors.last
152
- end
153
-
154
- # Returns the sequence of commands from #root that leads to this command.
155
- def command_path
156
- command_ancestors.reverse
157
- end
158
-
159
- # Computes the full command line of this command, which takes parent
160
- # commands into account.
161
- #
162
- # class Command < Acclaim::Command
163
- # class Do < Command
164
- # class Something < Do
165
- # end
166
- # end
167
- # end
168
- #
169
- # Command::Do::Something.full_line
170
- # => "do something"
171
- #
172
- # Command::Do::Something.full_line include_root: true
173
- # => "command do something"
174
- def full_line(*args)
175
- options = args.extract_ribbon!
176
- command_path.tap do |path|
177
- path.shift unless options.include_root?
178
- end.map(&:line).join ' '
179
- end
180
-
181
- private
182
-
183
- # Handles special options such as <tt>--help</tt> or <tt>--version</tt>.
184
- def handle_special_options!(opts, args)
185
- const_get(:Help).execute opts, args if opts.acclaim_help?
186
- const_get(:Version).execute opts, args if opts.acclaim_version?
187
- # TODO:
188
- # possibly rescue a NameError and warn user
189
- # fix bug:
190
- # calling this method causes a subcommand to be executed even if it
191
- # wasn't given on the command line. This may result up to **three**
192
- # commands (help, version and the actual command) running in one
193
- # invocation.
194
- end
195
-
196
- # Deletes all argument separators in the given argument array.
197
- def delete_argument_separators_in!(args)
198
- args.delete_if do |arg|
199
- arg =~ Option::Parser::Regexp::ARGUMENT_SEPARATOR
200
- end
201
- end
202
-
203
- end
54
+ class << Command
204
55
 
205
56
  # Add the class methods to the subclass and add it to this command's list of
206
57
  # subcommands.
207
- def self.inherited(sub)
208
- sub.extend ClassMethods
209
- subcommands << sub if respond_to? :subcommands
58
+ #
59
+ # @param [Class] command the class that inherited from this command
60
+ def inherited(command)
61
+ command.extend Command::DSL
62
+ subcommands << command if respond_to? :subcommands
210
63
  end
211
64
 
212
65
  end
213
66
 
214
67
  end
215
-
216
- %w(help parser version).each do |command|
217
- require command.prepend 'acclaim/command/'
218
- end
@@ -0,0 +1,181 @@
1
+ require 'acclaim/command/dsl/root'
2
+
3
+ module Acclaim
4
+ class Command
5
+
6
+ # Module containing the methods that make up the domain-specific language
7
+ # used to create commands.
8
+ #
9
+ # @author Matheus Afonso Martins Moreira
10
+ # @since 0.4.0
11
+ module DSL
12
+
13
+ # The string used to invoke this command from the command line.
14
+ #
15
+ # @overload line
16
+ # If not set, will try to figure out the name from the command's class.
17
+ #
18
+ # @return [String] the name used to invoke this command
19
+ #
20
+ # @overload line(string)
21
+ # Uses the given string to invoke this command.
22
+ #
23
+ # @param [String, nil] string the new command name
24
+ # @return [String] the name used to invoke this command
25
+ def line(*arguments)
26
+ @line = arguments.first unless arguments.empty?
27
+ @line ||= (name.gsub(/^.*::/, '').downcase if respond_to? :name)
28
+ end
29
+
30
+ # Commands which may be given to this command.
31
+ #
32
+ # @return [Array] this command's subcommands
33
+ def subcommands
34
+ @subcommands ||= []
35
+ end
36
+
37
+ # The options this command can take.
38
+ #
39
+ # @return [Array] the options this command takes
40
+ def options
41
+ @options ||= []
42
+ end
43
+
44
+ # Adds an option to this command.
45
+ #
46
+ # @see Acclaim::Option#initialize
47
+ def option(*arguments, &block)
48
+ options << Option.new(*arguments, &block)
49
+ end
50
+
51
+ alias opt option
52
+
53
+ # The block which is executed when this command is called.
54
+ #
55
+ # @yieldparam [Ribbon] options a Ribbon instance which associates options
56
+ # with their corresponding values
57
+ # @yieldparam [Array] arguments the arguments that remained in the command
58
+ # line
59
+ # @return [Proc, nil] the given block
60
+ def action(&block)
61
+ @action = block if block.respond_to? :call
62
+ @action
63
+ end
64
+
65
+ alias when_called action
66
+
67
+ # Parses the argument array using this command's set of options.
68
+ def parse_options_in!(arguments)
69
+ Option::Parser.new(arguments, options).parse!
70
+ end
71
+
72
+ # Looks for this command's subcommands in the argument array.
73
+ def parse_subcommands_in!(arguments)
74
+ Command::Parser.new(arguments, subcommands).parse!
75
+ end
76
+
77
+ # Invokes this command with a fresh set of option values.
78
+ def run(*arguments)
79
+ invoke arguments
80
+ rescue Option::Parser::Error => error
81
+ $stderr.puts error.message
82
+ end
83
+
84
+ # Parses the argument array. The argument array will be searched for
85
+ # subcommands; if one is found, it will be invoked, if not, this command
86
+ # will be executed. A subcommand may be anywhere in the array as long as
87
+ # it is before an argument separator, which is tipically a double dash
88
+ # (<tt>--</tt>) and may be omitted.
89
+ #
90
+ # All argument separators will be deleted from the argument array before a
91
+ # command is executed.
92
+ def invoke(arguments = [], options = [])
93
+ options = options + self.options
94
+ subcommand = parse_subcommands_in! arguments
95
+ if subcommand.nil?
96
+ parsed_options = Option::Parser.new(arguments, options).parse!
97
+ delete_argument_separators_in! arguments
98
+ execute parsed_options, arguments
99
+ else
100
+ subcommand.invoke arguments, options
101
+ end
102
+ end
103
+
104
+ # Calls this command's action block with the given option values and
105
+ # arguments.
106
+ def execute(options, arguments)
107
+ @action.call options, arguments if @action.respond_to? :call
108
+ end
109
+
110
+ alias call execute
111
+
112
+ # True if this is a top-level command.
113
+ def root?
114
+ superclass == Acclaim::Command
115
+ end
116
+
117
+ # Returns all command ancestors of this command.
118
+ def command_ancestors
119
+ ancestors - Acclaim::Command.ancestors
120
+ end
121
+
122
+ # Returns the root of the command hierarchy.
123
+ def root
124
+ command_ancestors.last
125
+ end
126
+
127
+ # Returns the sequence of commands from #root that leads to this command.
128
+ def command_path
129
+ command_ancestors.reverse
130
+ end
131
+
132
+ # Computes the full command line of this command, which takes parent
133
+ # commands into account.
134
+ #
135
+ # class Command < Acclaim::Command
136
+ # class Do < Command
137
+ # class Something < Do
138
+ # end
139
+ # end
140
+ # end
141
+ #
142
+ # Command::Do::Something.full_line
143
+ # => "do something"
144
+ #
145
+ # Command::Do::Something.full_line include_root: true
146
+ # => "command do something"
147
+ def full_line(*arguments)
148
+ options = arguments.extract_ribbon!
149
+ command_path.tap do |path|
150
+ path.shift unless options.include_root?
151
+ end.map(&:line).join ' '
152
+ end
153
+
154
+ private
155
+
156
+ # Handles special options such as <tt>--help</tt> or <tt>--version</tt>.
157
+ def handle_special_options!(options, arguments)
158
+ const_get(:Help).execute options, arguments if options.acclaim_help?
159
+ const_get(:Version).execute options, arguments if options.acclaim_version?
160
+ # TODO:
161
+ # possibly rescue a NameError and warn user
162
+ # fix bug:
163
+ # calling this method causes a subcommand to be executed even if it
164
+ # wasn't given on the command line. This may result up to **three**
165
+ # commands (help, version and the actual command) running in one
166
+ # invocation.
167
+ end
168
+
169
+ # Deletes all argument separators in the given argument array.
170
+ def delete_argument_separators_in!(arguments)
171
+ arguments.delete_if do |arg|
172
+ arg =~ Option::Parser::Regexp::ARGUMENT_SEPARATOR
173
+ end
174
+ end
175
+
176
+ include Root
177
+
178
+ end
179
+
180
+ end
181
+ end
@@ -0,0 +1,36 @@
1
+ %w(
2
+
3
+ acclaim/command/help
4
+ acclaim/command/version
5
+
6
+ ).each { |file| require file }
7
+
8
+ module Acclaim
9
+ class Command
10
+ module DSL
11
+
12
+ # Methods that only work with root commands.
13
+ #
14
+ # @author Matheus Afonso Martins Moreira
15
+ # @since 0.4.0
16
+ module Root
17
+
18
+ # Adds help subcommand and options to this command.
19
+ #
20
+ # @see Acclaim::Command::Help.create
21
+ def help(*arguments, &block)
22
+ Help.create root, *arguments, &block
23
+ end
24
+
25
+ # Adds version subcommand and options to this command.
26
+ #
27
+ # @see Acclaim::Command::Help.create
28
+ def version(*arguments, &block)
29
+ Version.create root, *arguments, &block
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,17 @@
1
+ require 'jewel'
2
+
3
+ module Acclaim
4
+
5
+ # Acclaim gem information and metadata.
6
+ #
7
+ # @author Matheus Afonso Martins Moreira
8
+ # @since 0.4.0
9
+ class Gem < Jewel::Gem
10
+
11
+ root '../..'
12
+
13
+ specification ::Gem::Specification.load root.join('acclaim.gemspec').to_s
14
+
15
+ end
16
+
17
+ end
@@ -139,7 +139,7 @@ module Acclaim
139
139
 
140
140
  # Returns +true+ if this option takes no arguments.
141
141
  def flag?
142
- arity and arity.none?
142
+ arity.none?
143
143
  end
144
144
 
145
145
  # Same as <tt>flag?</tt>
@@ -151,6 +151,22 @@ module Acclaim
151
151
  # Same as <tt>flag?</tt>
152
152
  alias switch? flag?
153
153
 
154
+ # Generate human-readable string containing this option's data.
155
+ #
156
+ # @return [String] string describing this option
157
+ def inspect
158
+ '#<%s %s (%s) %s = %s %s %s %s>' % [
159
+ self.class.name,
160
+ key,
161
+ names.join('|'),
162
+ type.inspect,
163
+ default.inspect,
164
+ arity.inspect,
165
+ on_multiple,
166
+ if required? then :required else :optional end
167
+ ]
168
+ end
169
+
154
170
  end
155
171
 
156
172
  class << Option
@@ -1,11 +1,19 @@
1
- %w(error regexp).each { |file| require file.prepend 'acclaim/option/parser/' }
1
+ %w(
2
2
 
3
- require 'ribbon'
3
+ acclaim/option/parser/error
4
+ acclaim/option/parser/regexp
5
+
6
+ ribbon
7
+
8
+ ).each { |file| require file }
4
9
 
5
10
  module Acclaim
6
11
  class Option
7
12
 
8
13
  # Parses arrays of strings and returns an Options instance containing data.
14
+ #
15
+ # @author Matheus Afonso Martins Moreira
16
+ # @since 0.0.1
9
17
  class Parser
10
18
 
11
19
  include Parser::Regexp
@@ -24,11 +32,15 @@ module Acclaim
24
32
  self.options = options || []
25
33
  end
26
34
 
27
- # Parses the meaning of the options given to this parser. If none were
28
- # given, the argument array will be preprocessed only. Any parsed options
29
- # and arguments will be removed from the argument array, so pass in a
30
- # duplicate if you need the original.
35
+ # Parses the given argument array, looking for the given {Option options}
36
+ # and their arguments if any.
37
+ #
38
+ # If no options were given, the argument array will be preprocessed only.
39
+ #
40
+ # @note Parsed options and their parameters will be removed from the
41
+ # argument array.
31
42
  #
43
+ # @example
32
44
  # include Acclaim
33
45
  #
34
46
  # args = %w(-F log.txt --verbose arg1 arg2)
@@ -37,22 +49,49 @@ module Acclaim
37
49
  # options << Option.new(:verbose)
38
50
  #
39
51
  # Option::Parser.new(args, options).parse!
40
- # => {file: "log.txt", verbose: true}
52
+ # # => {file: "log.txt", verbose: true}
41
53
  #
42
54
  # args
43
- # => ["arg1", "arg2"]
55
+ # # => ["arg1", "arg2"]
44
56
  def parse!
45
57
  preprocess_argv!
46
- parse_values!
58
+ parse_values!.tap do
59
+ delete_options_from_argv!
60
+ end
47
61
  end
48
62
 
49
63
  private
50
64
 
65
+ # List of arguments that are to be removed from argv, identified by their
66
+ # index.
67
+ #
68
+ # @return [Array] the indexes of options marked for deletion
69
+ # @see #delete_options_from_argv!
70
+ # @since 0.4.0
71
+ def deleted_options
72
+ @deleted_options ||= []
73
+ end
74
+
75
+ # Deletes all marked options from argv.
76
+ #
77
+ # @note The list of removed indexes will be discarded.
78
+ #
79
+ # @see #deleted_options
80
+ # @since 0.4.0
81
+ def delete_options_from_argv!
82
+ argv.delete_if.with_index do |argument, index|
83
+ deleted_options.include? index
84
+ end
85
+ ensure
86
+ deleted_options.clear
87
+ end
88
+
51
89
  # Preprocesses the argument array.
52
90
  def preprocess_argv!
53
91
  split_multiple_short_options!
54
92
  normalize_parameters!
55
93
  argv.compact!
94
+ check_for_errors!
56
95
  end
57
96
 
58
97
  # Splits multiple short options.
@@ -73,6 +112,8 @@ module Acclaim
73
112
  # %w(--switch=PARAM1,PARAM2) => %w(--switch PARAM1 PARAM2)
74
113
  # %w(--switch=PARAM1,) => %w(--switch PARAM1)
75
114
  # %w(--switch=,PARAM2) => [ '--switch', '', 'PARAM2' ]
115
+ #
116
+ # @since 0.0.3
76
117
  def normalize_parameters!
77
118
  argv.find_all { |arg| arg =~ SWITCH_PARAM_EQUALS }.each do |switch|
78
119
  switch_index = argv.index switch
@@ -83,48 +124,79 @@ module Acclaim
83
124
  end
84
125
  end
85
126
 
127
+ # Checks to see if the arguments have any errors
128
+ #
129
+ # @since 0.4.0
130
+ def check_for_errors!
131
+ ensure_required_options_are_present!
132
+ raise_on_multiple_options!
133
+ end
134
+
135
+ # Ensures all options are present in the argument array; raises a parser
136
+ # error otherwise.
137
+ #
138
+ # @since 0.4.0
139
+ def ensure_required_options_are_present!
140
+ options.find_all(&:required?).each do |option|
141
+ Error.raise_missing_required option if argv.find_all do |argument|
142
+ option =~ argument
143
+ end.empty?
144
+ end
145
+ end
146
+
147
+ # Raises a parser error if multiple switches were found for an option that
148
+ # explicitly disallowed it.
149
+ #
150
+ # @since 0.4.0
151
+ def raise_on_multiple_options!
152
+ options.find_all do |option|
153
+ option.on_multiple == :raise
154
+ end.each do |option|
155
+ Error.raise_multiple option if argv.find_all do |argument|
156
+ option =~ argument
157
+ end.count > 1
158
+ end
159
+ end
160
+
86
161
  # Parses the options and their arguments, associating that information
87
162
  # with a Ribbon instance.
163
+ #
164
+ # @since 0.0.3
88
165
  def parse_values!
89
166
  values = Ribbon.wrap
90
- options.each do |option|
91
- key = option.key
92
- values[key] = option.default unless values.has_key? key
93
- switches = argv.find_all { |switch| option =~ switch }
94
- Error.raise_missing_required option if option.required? and switches.empty?
95
- Error.raise_multiple option if option.on_multiple == :raise and switches.count > 1
96
- switches.each do |switch|
167
+ argv.each_with_index do |argument, index|
168
+ options.find_all do |option|
169
+ option =~ argument
170
+ end.each do |option|
171
+ key = option.key
172
+ values[key] = option.default unless values.has_key? key
97
173
  if option.flag?
98
174
  found_boolean option, values.ribbon
99
- argv.delete_at argv.index(switch)
175
+ deleted_options << index
100
176
  else
101
- params = extract_parameters_of! option, switch
102
- found_params_for option, params, values.ribbon
177
+ parameters = extract_parameters_of! option, index
178
+ found_params_for option, parameters, values.ribbon
103
179
  end
104
180
  end
105
181
  end
106
182
  values
107
183
  end
108
184
 
109
- # Finds the +switch+ in #argv and scans the next +option.arity.total+
110
- # elements if +option.arity.bound?+ is +true+, or all parameters
111
- # otherwise. In either case, the algorithm will stop if it finds +nil+,
112
- # another switch or an argument separator among the parameters.
185
+ # Starting from the given index, extracts parameters from the following
186
+ # arguments. Stops if it finds nil, another switch, an argument separator,
187
+ # or if enough values have been found according to the option's arity.
188
+ #
189
+ # @note All arguments scanned, in addition to the option at the given
190
+ # index, will be marked for deletion.
113
191
  #
114
- # Deletes the switch and every value that was extracted from #argv. Raises
115
- # an Error if the number of parameters found is less than
116
- # +option.arity.required+.
117
- def extract_parameters_of!(option, switch)
192
+ # @return [Array] the parameters for the given option found in argv
193
+ # @raise [Parser::Error] if not enough arguments are found
194
+ # @since 0.0.4
195
+ def extract_parameters_of!(option, index)
118
196
  arity = option.arity
119
- switch_index = argv.index switch
120
- len = if arity.bound?
121
- switch_index + arity.total
122
- else
123
- argv.length - 1
124
- end
125
- params = argv[switch_index + 1, len]
197
+ length = if arity.bound? then index + arity.total else argv.length - 1 end
126
198
  values = []
127
- params.each do |param|
199
+ argv[index + 1, length].each do |param|
128
200
  case param
129
201
  when nil, SWITCH, ARGUMENT_SEPARATOR then break
130
202
  else
@@ -134,7 +206,9 @@ module Acclaim
134
206
  end
135
207
  count = values.count
136
208
  Error.raise_wrong_arg_number count, *arity if count < arity.required
137
- argv.slice! switch_index..(switch_index + count)
209
+ limit = index + count
210
+ range = index..limit
211
+ deleted_options.push *range
138
212
  values
139
213
  end
140
214
 
@@ -148,6 +222,8 @@ module Acclaim
148
222
  # so. In this case, the value of the option will always be an array.
149
223
  #
150
224
  # The parameters will be converted according to the option's type.
225
+ #
226
+ # @since 0.0.6
151
227
  def found_params_for(option, params = [], ribbon = Ribbon.new)
152
228
  params = option.convert_parameters *params
153
229
  if handler = option.handler then handler.call ribbon, params
@@ -162,6 +238,8 @@ module Acclaim
162
238
  # If the option has an custom handler associated, it will be called with
163
239
  # only the option values as the first argument. Otherwise, the value will
164
240
  # be set to <tt>true</tt>.
241
+ #
242
+ # @since 0.0.6
165
243
  def found_boolean(option, ribbon = Ribbon.new)
166
244
  if handler = option.handler then handler.call ribbon
167
245
  else ribbon[option.key] = true end
@@ -201,6 +201,31 @@ describe Acclaim::Option::Parser do
201
201
  end
202
202
  end
203
203
 
204
+ context 'which contains one option with unbound aritiy and one boolean option' do
205
+ let(:options) { [ Acclaim::Option.new(:boolean), Acclaim::Option.new(:parameters, arity: [1, -1]) ] }
206
+
207
+ context 'and the arguments are such that the boolean option is between the parameters' do
208
+ let!(:args) { %w(--parameters a b c d --boolean e f g) }
209
+
210
+ it 'should parse from left to right, stopping at the boolean option' do
211
+ subject.parse!
212
+ args.should == %w(e f g)
213
+ end
214
+
215
+ context 'the parsed ribbon' do
216
+ let(:ribbon) { subject.parse! }
217
+
218
+ it 'should cointain the correct value for boolean' do
219
+ ribbon.parameters.should == %w(a b c d)
220
+ end
221
+
222
+ it 'should cointain the correct value for parameters' do
223
+ ribbon.boolean.should be_true
224
+ end
225
+ end
226
+ end
227
+ end
228
+
204
229
  context 'containing an option which' do
205
230
  let!(:options) { [ Acclaim::Option.new(:files, '-f', arity: [1,0], on_multiple: on_multiple, &block) ] }
206
231
  let!(:args) { %w(-f f1 -f f2 -f f3) }
@@ -15,17 +15,45 @@ describe Acclaim::Option do
15
15
  subject.key.should == key
16
16
  end
17
17
 
18
- context 'when given multiple strings' do
18
+ context 'when given multiple switches' do
19
19
  let(:switches) { %w(-s --switch) }
20
+
21
+ context 'directly' do
22
+ let(:args) { [*switches] }
23
+
24
+ it 'should find the switches' do
25
+ subject.names.should == switches
26
+ end
27
+ end
28
+
29
+ context 'as an array' do
30
+ let(:args) { [switches] }
31
+
32
+ it 'should find the switches' do
33
+ subject.names.should == switches
34
+ end
35
+ end
36
+ end
37
+
38
+ context 'when given a description string' do
20
39
  let(:description) { 'Description' }
21
- let(:args) { [*switches, description] }
22
40
 
23
- it 'should find the switches' do
24
- subject.names.should == switches
41
+ context 'by itself' do
42
+ let(:args) { [description] }
43
+
44
+ it 'should find the description' do
45
+ subject.description.should == description
46
+ end
25
47
  end
26
48
 
27
- it 'should find the description' do
28
- subject.description.should == description
49
+ context 'with another description specified in the options hash' do
50
+ let(:description_from_options_hash) { 'Description from options hash' }
51
+ let(:options_hash) { { description: description_from_options_hash } }
52
+ let(:args) { [description, options_hash] }
53
+
54
+ it 'should use the description from the options hash' do
55
+ subject.description.should == description_from_options_hash
56
+ end
29
57
  end
30
58
  end
31
59
 
@@ -114,6 +142,27 @@ describe Acclaim::Option do
114
142
  end
115
143
  end
116
144
  end
145
+
146
+ context 'that specifies a description' do
147
+ let(:hash) { { description: description } }
148
+
149
+ context 'as a regular string' do
150
+ let(:description) { 'Description' }
151
+
152
+ it 'should use the string as the description' do
153
+ subject.description.should == description
154
+ end
155
+ end
156
+
157
+ context 'as a block' do
158
+ let(:description) { -> { 'Description' } }
159
+
160
+ it 'should call the block and use return value as the description' do
161
+ value = description.call
162
+ subject.description.should == value
163
+ end
164
+ end
165
+ end
117
166
  end
118
167
 
119
168
  context 'when not given a block' do
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.3.2
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-10 00:00:00.000000000 Z
12
+ date: 2012-06-22 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: jewel
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
14
30
  - !ruby/object:Gem::Dependency
15
31
  name: ribbon
16
32
  requirement: !ruby/object:Gem::Requirement
@@ -28,7 +44,7 @@ dependencies:
28
44
  - !ruby/object:Gem::Version
29
45
  version: '0'
30
46
  - !ruby/object:Gem::Dependency
31
- name: rspec
47
+ name: redcarpet
32
48
  requirement: !ruby/object:Gem::Requirement
33
49
  none: false
34
50
  requirements:
@@ -59,7 +75,39 @@ dependencies:
59
75
  - - ! '>='
60
76
  - !ruby/object:Gem::Version
61
77
  version: '0'
62
- description: Command-line option parser and command interface.
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: yard
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description:
63
111
  email: matheus.a.m.moreira@gmail.com
64
112
  executables: []
65
113
  extensions: []
@@ -72,13 +120,17 @@ files:
72
120
  - README.markdown
73
121
  - Rakefile
74
122
  - acclaim.gemspec
123
+ - acclaim.version
75
124
  - lib/acclaim.rb
76
125
  - lib/acclaim/command.rb
126
+ - lib/acclaim/command/dsl.rb
127
+ - lib/acclaim/command/dsl/root.rb
77
128
  - lib/acclaim/command/help.rb
78
129
  - lib/acclaim/command/help/template.rb
79
130
  - lib/acclaim/command/help/template/command.erb
80
131
  - lib/acclaim/command/parser.rb
81
132
  - lib/acclaim/command/version.rb
133
+ - lib/acclaim/gem.rb
82
134
  - lib/acclaim/option.rb
83
135
  - lib/acclaim/option/arity.rb
84
136
  - lib/acclaim/option/parser.rb
@@ -97,7 +149,6 @@ files:
97
149
  - lib/acclaim/option/type/symbol.rb
98
150
  - lib/acclaim/option/type/time.rb
99
151
  - lib/acclaim/option/type/uri.rb
100
- - lib/acclaim/version.rb
101
152
  - spec/acclaim/command_spec.rb
102
153
  - spec/acclaim/option/arity_spec.rb
103
154
  - spec/acclaim/option/parser/regexp_spec.rb
@@ -117,7 +168,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
117
168
  version: '0'
118
169
  segments:
119
170
  - 0
120
- hash: 4033184433190617249
171
+ hash: 3293933185562874440
121
172
  required_rubygems_version: !ruby/object:Gem::Requirement
122
173
  none: false
123
174
  requirements:
@@ -126,7 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
126
177
  version: '0'
127
178
  segments:
128
179
  - 0
129
- hash: 4033184433190617249
180
+ hash: 3293933185562874440
130
181
  requirements: []
131
182
  rubyforge_project:
132
183
  rubygems_version: 1.8.24
@@ -1,31 +0,0 @@
1
- module Acclaim
2
-
3
- # Acclaim's version.
4
- module Version
5
-
6
- # Major version.
7
- #
8
- # Increments denote backward-incompatible changes and additions.
9
- MAJOR = 0
10
-
11
- # Minor version.
12
- #
13
- # Increments denote backward-compatible changes and additions.
14
- MINOR = 3
15
-
16
- # Patch version.
17
- #
18
- # Increments denote changes in implementation.
19
- PATCH = 2
20
-
21
- # Build version.
22
- #
23
- # Used for pre-release versions.
24
- BUILD = nil
25
-
26
- # Complete version string, which is every individual version number joined
27
- # by a dot (<tt>'.'</tt>), in descending order of prescedence.
28
- STRING = [ MAJOR, MINOR, PATCH, BUILD ].compact.join '.'
29
-
30
- end
31
- end