cri 2.0b1 → 2.0rc1

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.
data/README.md CHANGED
@@ -1,7 +1,121 @@
1
1
  Cri
2
2
  ===
3
3
 
4
- Cri is a library for building easy-to-use commandline tools.
4
+ Cri is a library for building easy-to-use commandline tools with support for
5
+ nested commands.
6
+
7
+ Usage
8
+ -----
9
+
10
+ The central concept in Cri is the _command_, which has option definitions as
11
+ well as code for actually executing itself. In Cri, the commandline tool
12
+ itself is a command as well.
13
+
14
+ Here’s a sample command definition:
15
+
16
+ command = Cri::Command.define do
17
+ name 'dostuff'
18
+ usage 'dostuff [options]'
19
+ aliases :ds, :stuff
20
+ summary 'does stuff'
21
+ description 'This command does a lot of stuff. I really mean a lot.'
22
+
23
+ flag :h, :help, 'show help for this command' do |value, cmd|
24
+ puts cmd.help
25
+ exit 0
26
+ end
27
+ flag :m, :more, 'do even more stuff'
28
+ option :s, :stuff, 'specify stuff to do', :argument => :required
29
+
30
+ run do |opts, args, cmd|
31
+ stuff = opts[:stuff] || 'generic stuff'
32
+ puts "Doing #{stuff}!"
33
+
34
+ if opts[:more]
35
+ puts 'Doing it even more!'
36
+ end
37
+ end
38
+ end
39
+
40
+ To run this command, invoke the `#run` method with the raw arguments. For
41
+ example, for a root command (the commandline tool itself), the command could
42
+ be called like this:
43
+
44
+ command.run(ARGS)
45
+
46
+ Each command has automatically generated help. This help can be printed using
47
+ {Cri::Command#help}; something like this will be shown:
48
+
49
+ usage: dostuff [options]
50
+
51
+ does stuff
52
+
53
+ This command does a lot of stuff. I really mean a lot.
54
+
55
+ options:
56
+
57
+ -h --help show help for this command
58
+ -m --more do even more stuff
59
+ -s --stuff specify stuff to do
60
+
61
+ Let’s disect the command definition and start with the first five lines:
62
+
63
+ name 'dostuff'
64
+ usage 'dostuff [options]'
65
+ aliases :ds, :stuff
66
+ summary 'does stuff'
67
+ description 'This command does a lot of stuff. I really mean a lot.'
68
+
69
+ These lines of the command definition specify the name of the command (or the
70
+ commandline tool, if the command is the root command), the usage, a list of
71
+ aliases that can be used to call this command, a one-line summary and a (long)
72
+ description. The usage should not include a “usage:” prefix nor the name of
73
+ the supercommand, because the latter will be automatically prepended.
74
+
75
+ Aliases don’t make sense for root commands, but for subcommands they do.
76
+
77
+ The next few lines contain the command’s option definitions:
78
+
79
+ flag :h, :help, 'show help for this command' do |value, cmd|
80
+ puts cmd.help
81
+ exit 0
82
+ end
83
+ flag :m, :more, 'do even more stuff'
84
+ option :s, :stuff, 'specify stuff to do', :argument => :required
85
+
86
+ Options can be defined using the following methods:
87
+
88
+ * {Cri::CommandDSL#option} or {Cri::CommandDSL#opt}
89
+ * {Cri::CommandDSL#flag} (implies forbidden argument)
90
+ * {Cri::CommandDSL#required} (implies required argument)
91
+ * {Cri::CommandDSL#optional} (implies optional argument)
92
+
93
+ Each of the above methods also take a block, which will be executed when the
94
+ option is found. The argument to the block are the option value (`true` in
95
+ case the option does not have an argument) and the command.
96
+
97
+ The last part of the command defines the execution itself:
98
+
99
+ run do |opts, args, cmd|
100
+ stuff = opts[:stuff] || 'generic stuff'
101
+ puts "Doing #{stuff}!"
102
+
103
+ if opts[:more]
104
+ puts 'Doing it even more!'
105
+ end
106
+ end
107
+
108
+ The {Cri::CommandDSL#run} method takes a block with the actual code to
109
+ execute. This block takes three arguments: the options, any arguments passed
110
+ to the command, and the command itself.
111
+
112
+ Commands can have subcommands. For example, the `git` commandline tool would be represented by a command that has subcommands named `commit`, `add`, and so on. Commands with subcommands do not use a run block; execution will always be dispatched to a subcommand (or none, if no subcommand is found).
113
+
114
+ To add a command as a subcommand to another command, use the {Cri::Command#add_command} method, like this:
115
+
116
+ root_cmd.add_command cmd_add
117
+ root_cmd.add_command cmd_commit
118
+ root.cmd.add_command cmd_init
5
119
 
6
120
  Contributors
7
121
  ------------
data/lib/cri.rb CHANGED
@@ -2,20 +2,22 @@
2
2
 
3
3
  module Cri
4
4
 
5
- # @todo Document
5
+ # A generic error class for all Cri-specific errors.
6
6
  class Error < ::StandardError
7
7
  end
8
8
 
9
- # @todo Document
9
+ # Error that will be raised when an implementation for a method or command
10
+ # is missing. For commands, this may mean that a run block is missing.
10
11
  class NotImplementedError < Error
11
12
  end
12
13
 
13
- # @todo Document
14
+ # Error that will be raised when no help is available because the help
15
+ # command has no supercommand for which to show help.
14
16
  class NoHelpAvailableError < Error
15
17
  end
16
18
 
17
19
  # The current Cri version.
18
- VERSION = '2.0b1'
20
+ VERSION = '2.0rc1'
19
21
 
20
22
  autoload 'Command', 'cri/command'
21
23
  autoload 'CommandDSL', 'cri/command_dsl'
data/lib/cri/command.rb CHANGED
@@ -45,35 +45,49 @@ module Cri
45
45
 
46
46
  end
47
47
 
48
- # @todo Document
48
+ # @return [Cri::Command, nil] This command’s supercommand, or nil if the
49
+ # command has no supercommand
49
50
  attr_accessor :supercommand
50
51
 
51
- # @todo document
52
+ # @return [Set<Cri::Command>] This command’s subcommands
52
53
  attr_accessor :commands
53
54
  alias_method :subcommands, :commands
54
55
 
55
- # @todo Document
56
+ # @return [String] The name
56
57
  attr_accessor :name
57
58
 
58
- # @todo Document
59
+ # @return [Array<String>] A list of aliases for this command that can be
60
+ # used to invoke this command
59
61
  attr_accessor :aliases
60
62
 
61
- # @todo Document
62
- attr_accessor :short_desc
63
+ # @return [String] The short description (“summary”)
64
+ attr_accessor :summary
63
65
 
64
- # @todo Document
65
- attr_accessor :long_desc
66
+ # @return [String] The long description (“description”)
67
+ attr_accessor :description
66
68
 
67
- # @todo Document
69
+ # @return [String] The usage, without the “usage:” prefix and without the
70
+ # supercommands’ names.
68
71
  attr_accessor :usage
69
72
 
70
- # @todo Document
73
+ # @return [Array<Hash>] The list of option definitions
71
74
  attr_accessor :option_definitions
72
75
 
73
- # @todo Document
76
+ # @return [Proc] The block that should be executed when invoking this
77
+ # command (ignored for commands with subcommands)
74
78
  attr_accessor :block
75
79
 
76
- # @todo Document
80
+ # Creates a new command using the DSL. If a string is given, the command
81
+ # will be defined using the string; if a block is given, the block will be
82
+ # used instead.
83
+ #
84
+ # If the block has one parameter, the block will be executed in the same
85
+ # context with the command DSL as its parameter. If the block has no
86
+ # parameters, the block will be executed in the context of the DSL.
87
+ #
88
+ # @param [String, nil] The string containing the command’s definition
89
+ #
90
+ # @return [Cri::Command] The newly defined command
77
91
  def self.define(string=nil, &block)
78
92
  dsl = Cri::CommandDSL.new
79
93
  if string
@@ -86,13 +100,19 @@ module Cri
86
100
  dsl.command
87
101
  end
88
102
 
89
- # @todo Document
103
+ # Returns a new command that has support for the `-h`/`--help` option and
104
+ # also has a `help` subcommand. It is intended to be modified (adding
105
+ # name, summary, description, other subcommands, …)
106
+ #
107
+ # @return [Cri::Command] A basic root command
90
108
  def self.new_basic_root
91
109
  filename = File.dirname(__FILE__) + '/commands/basic_root.rb'
92
110
  self.define(File.read(filename))
93
111
  end
94
112
 
95
- # @todo Document
113
+ # Returns a new command that implements showing help.
114
+ #
115
+ # @return [Cri::Command] A basic help command
96
116
  def self.new_basic_help
97
117
  filename = File.dirname(__FILE__) + '/commands/basic_help.rb'
98
118
  self.define(File.read(filename))
@@ -100,11 +120,17 @@ module Cri
100
120
 
101
121
  def initialize
102
122
  @aliases = Set.new
103
- @commands = Set.new # TODO make this a hash (name -> cmd)
123
+ @commands = Set.new
104
124
  @option_definitions = Set.new
105
125
  end
106
126
 
107
- # @todo Document
127
+ # Modifies the command using the DSL.
128
+ #
129
+ # If the block has one parameter, the block will be executed in the same
130
+ # context with the command DSL as its parameter. If the block has no
131
+ # parameters, the block will be executed in the context of the DSL.
132
+ #
133
+ # @return [Cri::Command] The command itself
108
134
  def modify(&block)
109
135
  dsl = Cri::CommandDSL.new(self)
110
136
  if block.arity == 0
@@ -115,7 +141,8 @@ module Cri
115
141
  self
116
142
  end
117
143
 
118
- # @todo Document
144
+ # @return [Hash] The option definitions for the command itself and all its
145
+ # ancestors
119
146
  def global_option_definitions
120
147
  res = Set.new
121
148
  res.merge(option_definitions)
@@ -123,13 +150,22 @@ module Cri
123
150
  res
124
151
  end
125
152
 
126
- # @todo Document
153
+ # Adds the given command as a subcommand to the current command.
154
+ #
155
+ # @param [Cri::Command] command The command to add as a subcommand
156
+ #
157
+ # @return [void]
127
158
  def add_command(command)
128
159
  @commands << command
129
160
  command.supercommand = self
130
161
  end
131
162
 
132
- # @todo Document
163
+ # Defines a new subcommand for the current command using the DSL.
164
+ #
165
+ # @param [String, nil] name The name of the subcommand, or nil if no name
166
+ # should be set (yet)
167
+ #
168
+ # @return [Cri::Command] The subcommand
133
169
  def define_command(name=nil, &block)
134
170
  # Execute DSL
135
171
  dsl = Cri::CommandDSL.new
@@ -149,7 +185,9 @@ module Cri
149
185
  # Returns the commands that could be referred to with the given name. If
150
186
  # the result contains more than one command, the name is ambiguous.
151
187
  #
152
- # @todo Document
188
+ # @param [String] name The full, partial or aliases name of the command
189
+ #
190
+ # @return [Array<Cri::Command>] A list of commands matching the given name
153
191
  def commands_named(name)
154
192
  # Find by exact name or alias
155
193
  @commands.each do |cmd|
@@ -163,9 +201,15 @@ module Cri
163
201
  end
164
202
  end
165
203
 
166
- # Returns the command with the given name.
204
+ # Returns the command with the given name. This method will display error
205
+ # messages and exit in case of an error (unknown or ambiguous command).
206
+ #
207
+ # The name can be a full command name, a partial command name (e.g. “com”
208
+ # for “commit”) or an aliased command name (e.g. “ci” for “commit”).
167
209
  #
168
- # @todo Document
210
+ # @param [String] name The full, partial or aliases name of the command
211
+ #
212
+ # @return [Cri::Command] The command with the given name
169
213
  def command_named(name)
170
214
  commands = commands_named(name)
171
215
 
@@ -181,7 +225,14 @@ module Cri
181
225
  end
182
226
  end
183
227
 
184
- # @todo Document
228
+ # Runs the command with the given commandline arguments.
229
+ #
230
+ # @param [Array<String>] opts_and_args A list of unparsed arguments
231
+ #
232
+ # @param [Hash] parent_opts A hash of options already handled by the
233
+ # supercommand
234
+ #
235
+ # @return [void]
185
236
  def run(opts_and_args, parent_opts={})
186
237
  if subcommands.empty?
187
238
  # Parse
@@ -240,15 +291,15 @@ module Cri
240
291
  end
241
292
 
242
293
  # Append short description
243
- if short_desc
294
+ if summary
244
295
  text << "\n"
245
- text << short_desc + "\n"
296
+ text << summary + "\n"
246
297
  end
247
298
 
248
299
  # Append long description
249
- if long_desc
300
+ if description
250
301
  text << "\n"
251
- text << long_desc.wrap_and_indent(78, 4) + "\n"
302
+ text << description.wrap_and_indent(78, 4) + "\n"
252
303
  end
253
304
 
254
305
  # Append subcommands
@@ -260,7 +311,7 @@ module Cri
260
311
  self.commands.each do |cmd|
261
312
  text << sprintf(" %-#{length+4}s %s\n",
262
313
  cmd.name,
263
- cmd.short_desc)
314
+ cmd.summary)
264
315
  end
265
316
  end
266
317
 
@@ -2,76 +2,155 @@
2
2
 
3
3
  module Cri
4
4
 
5
- # @todo Document
5
+ # The command DSL is a class that is used for building and modifying
6
+ # commands.
6
7
  class CommandDSL
7
8
 
9
+ # @param [Cri::Command, nil] command The command to modify, or nil if a
10
+ # new command should be created
8
11
  def initialize(command=nil)
9
12
  @command = command || Cri::Command.new
10
13
  end
11
14
 
12
- # @todo Document
15
+ # @return [Cri::Command] The built command
13
16
  def command
14
17
  @command
15
18
  end
16
19
 
17
- # @todo Document
18
- def subcommand(cmd=nil, &block)
19
- if cmd.nil?
20
- cmd = Cri::Command.define(&block)
20
+ # Adds a subcommand to the current command. The command can either be
21
+ # given explicitly, or a block can be given that defines the command.
22
+ #
23
+ # @param [Cri::Command, nil] command The command to add as a subcommand,
24
+ # or nil if the block should be used to define the command that will be
25
+ # added as a subcommand
26
+ #
27
+ # @return [void]
28
+ def subcommand(command=nil, &block)
29
+ if command.nil?
30
+ command = Cri::Command.define(&block)
21
31
  end
22
32
 
23
- @command.add_command(cmd)
33
+ @command.add_command(command)
24
34
  end
25
35
 
26
- # @todo Document
36
+ # Sets the command name.
37
+ #
38
+ # @param [String] arg The new command name
39
+ #
40
+ # @return [void]
27
41
  def name(arg)
28
42
  @command.name = arg
29
43
  end
30
44
 
31
- # @todo Document
45
+ # Sets the command aliases.
46
+ #
47
+ # @param [String, Symbol, Array] args The new command aliases
48
+ #
49
+ # @return [void]
32
50
  def aliases(*args)
33
- @command.aliases = args.flatten
51
+ @command.aliases = args.flatten.map { |a| a.to_s }
34
52
  end
35
53
 
36
- # @todo Document
54
+ # Sets the command summary.
55
+ #
56
+ # @param [String] arg The new command summary
57
+ #
58
+ # @return [void]
37
59
  def summary(arg)
38
- @command.short_desc = arg
60
+ @command.summary = arg
39
61
  end
40
62
 
41
- # @todo Document
63
+ # Sets the command description.
64
+ #
65
+ # @param [String] arg The new command description
66
+ #
67
+ # @return [void]
42
68
  def description(arg)
43
- @command.long_desc = arg
69
+ @command.description = arg
44
70
  end
45
71
 
46
- # @todo Document
72
+ # Sets the command usage. The usage should not include the “usage:”
73
+ # prefix, nor should it include the command names of the supercommand.
74
+ #
75
+ # @param [String] arg The new command usage
76
+ #
77
+ # @return [void]
47
78
  def usage(arg)
48
79
  @command.usage = arg
49
80
  end
50
81
 
51
- # @todo Document
82
+ # Adds a new option to the command. If a block is given, it will be
83
+ # executed when the option is successfully parsed.
84
+ #
85
+ # @param [String, Symbol] short The short option name
86
+ #
87
+ # @param [String, Symbol] long The long option name
88
+ #
89
+ # @param [String] desc The option description
90
+ #
91
+ # @option params [:forbidden, :required, :optional] :argument Whether the
92
+ # argument is forbidden, required or optional
93
+ #
94
+ # @return [void]
52
95
  def option(short, long, desc, params={}, &block)
53
96
  requiredness = params[:argument] || :forbidden
54
97
  self.add_option(short, long, desc, requiredness, block)
55
98
  end
56
99
  alias_method :opt, :option
57
100
 
58
- # @todo Document
101
+ # Adds a new option with a required argument to the command. If a block is
102
+ # given, it will be executed when the option is successfully parsed.
103
+ #
104
+ # @param [String, Symbol] short The short option name
105
+ #
106
+ # @param [String, Symbol] long The long option name
107
+ #
108
+ # @param [String] desc The option description
109
+ #
110
+ # @return [void]
111
+ #
112
+ # @see {#option}
59
113
  def required(short, long, desc, &block)
60
114
  self.add_option(short, long, desc, :required, block)
61
115
  end
62
116
 
63
- # @todo Document
117
+ # Adds a new option with a forbidden argument to the command. If a block
118
+ # is given, it will be executed when the option is successfully parsed.
119
+ #
120
+ # @param [String, Symbol] short The short option name
121
+ #
122
+ # @param [String, Symbol] long The long option name
123
+ #
124
+ # @param [String] desc The option description
125
+ #
126
+ # @return [void]
127
+ #
128
+ # @see {#option}
64
129
  def flag(short, long, desc, &block)
65
130
  self.add_option(short, long, desc, :forbidden, block)
66
131
  end
67
132
  alias_method :forbidden, :flag
68
133
 
69
- # @todo Document
134
+ # Adds a new option with an optional argument to the command. If a block
135
+ # is given, it will be executed when the option is successfully parsed.
136
+ #
137
+ # @param [String, Symbol] short The short option name
138
+ #
139
+ # @param [String, Symbol] long The long option name
140
+ #
141
+ # @param [String] desc The option description
142
+ #
143
+ # @return [void]
144
+ #
145
+ # @see {#option}
70
146
  def optional(short, long, desc, &block)
71
147
  self.add_option(short, long, desc, :optional, block)
72
148
  end
73
149
 
74
- # @todo Document
150
+ # Sets the run block to the given block. The given block should have two
151
+ # or three arguments (options, arguments, and optionally the command).
152
+ #
153
+ # @return [void]
75
154
  def run(&block)
76
155
  unless block.arity != 2 || block.arity != 3
77
156
  raise ArgumentError,
@@ -83,7 +162,6 @@ module Cri
83
162
 
84
163
  protected
85
164
 
86
- # @todo Document
87
165
  def add_option(short, long, desc, argument, block)
88
166
  @command.option_definitions << {
89
167
  :short => short.to_s,
@@ -4,7 +4,9 @@ module Cri::CoreExtensions
4
4
 
5
5
  module String
6
6
 
7
- # @todo Document
7
+ # Extracts individual paragraphs (separated by two newlines).
8
+ #
9
+ # @return [Array<String>] A list of paragraphs in the string
8
10
  def to_paragraphs
9
11
  lines = self.scan(/([^\n]+\n|[^\n]*$)/).map { |s| s[0].strip }
10
12
 
@@ -22,10 +24,13 @@ module Cri::CoreExtensions
22
24
 
23
25
  # Word-wraps and indents the string.
24
26
  #
25
- # +width+:: The maximal width of each line. This also includes indentation,
26
- # i.e. the actual maximal width of the text is width-indentation.
27
+ # @param [Number] width The maximal width of each line. This also includes
28
+ # indentation, i.e. the actual maximal width of the text is
29
+ # `width`-`indentation`.
30
+ #
31
+ # @param [Number] indentation The number of spaces to indent each line.
27
32
  #
28
- # +indentation+:: The number of spaces to indent each wrapped line.
33
+ # @return [String] The word-wrapped and indented string
29
34
  def wrap_and_indent(width, indentation)
30
35
  # Split into paragraphs
31
36
  paragraphs = self.to_paragraphs
@@ -3,6 +3,58 @@
3
3
  module Cri
4
4
 
5
5
  # Cri::OptionParser is used for parsing commandline options.
6
+ #
7
+ # Option definitions are hashes with the keys `:short`, `:long` and
8
+ # `:argument` (optionally `:description` but this is not used by the
9
+ # option parser, only by the help generator). `:short` is the short,
10
+ # one-character option, without the `-` prefix. `:long` is the long,
11
+ # multi-character option, without the `--` prefix. `:argument` can be
12
+ # :required (if an argument should be provided to the option), :optional
13
+ # (if an argument may be provided) or :forbidden (if an argument should
14
+ # not be provided).
15
+ #
16
+ # A sample array of definition hashes could look like this:
17
+ #
18
+ # [
19
+ # { :short => 'a', :long => 'all', :argument => :forbidden },
20
+ # { :short => 'p', :long => 'port', :argument => :required },
21
+ # ]
22
+ #
23
+ # For example, the following commandline options (which should not be
24
+ # passed as a string, but as an array of strings):
25
+ #
26
+ # foo -xyz -a hiss -s -m please --level 50 --father=ani -n luke squeak
27
+ #
28
+ # with the following option definitions:
29
+ #
30
+ # [
31
+ # { :short => 'x', :long => 'xxx', :argument => :forbidden },
32
+ # { :short => 'y', :long => 'yyy', :argument => :forbidden },
33
+ # { :short => 'z', :long => 'zzz', :argument => :forbidden },
34
+ # { :short => 'a', :long => 'all', :argument => :forbidden },
35
+ # { :short => 's', :long => 'stuff', :argument => :optional },
36
+ # { :short => 'm', :long => 'more', :argument => :optional },
37
+ # { :short => 'l', :long => 'level', :argument => :required },
38
+ # { :short => 'f', :long => 'father', :argument => :required },
39
+ # { :short => 'n', :long => 'name', :argument => :required }
40
+ # ]
41
+ #
42
+ # will be translated into:
43
+ #
44
+ # {
45
+ # :arguments => [ 'foo', 'hiss', 'squeak' ],
46
+ # :options => {
47
+ # :xxx => true,
48
+ # :yyy => true,
49
+ # :zzz => true,
50
+ # :all => true,
51
+ # :stuff => true,
52
+ # :more => 'please',
53
+ # :level => '50',
54
+ # :father => 'ani',
55
+ # :name => 'luke'
56
+ # }
57
+ # }
6
58
  class OptionParser
7
59
 
8
60
  # Error that will be raised when an unknown option is encountered.
@@ -49,6 +101,13 @@ module Cri
49
101
 
50
102
  # Parses the commandline arguments. See the instance `parse` method for
51
103
  # details.
104
+ #
105
+ # @param [Array<String>] arguments_and_options An array containing the
106
+ # commandline arguments (will probably be `ARGS` for a root command)
107
+ #
108
+ # @param [Array<Hash>] definitions An array of option definitions
109
+ #
110
+ # @return [Cri::OptionParser] The option parser self
52
111
  def self.parse(arguments_and_options, definitions)
53
112
  self.new(arguments_and_options, definitions).run
54
113
  end
@@ -56,7 +115,7 @@ module Cri
56
115
  # Creates a new parser with the given options/arguments and definitions.
57
116
  #
58
117
  # @param [Array<String>] arguments_and_options An array containing the
59
- # commandline arguments
118
+ # commandline arguments (will probably be `ARGS` for a root command)
60
119
  #
61
120
  # @param [Array<Hash>] definitions An array of option definitions
62
121
  def initialize(arguments_and_options, definitions)
@@ -83,80 +142,17 @@ module Cri
83
142
  @running = false
84
143
  end
85
144
 
86
- # Parses the commandline arguments into options and arguments
87
- #
88
- # +arguments_and_options+ is an array of commandline arguments and
89
- # options. This will usually be +ARGV+.
90
- #
91
- # +definitions+ contains a list of hashes defining which options are
92
- # allowed and how they will be handled. Such a hash has three keys:
93
- #
94
- # :short:: The short name of the option, e.g. +a+. Do not include the '-'
95
- # prefix.
96
- #
97
- # :long:: The long name of the option, e.g. +all+. Do not include the '--'
98
- # prefix.
99
- #
100
- # :argument:: Whether this option's argument is required (:required),
101
- # optional (:optional) or forbidden (:forbidden).
102
- #
103
- # A sample array of definition hashes could look like this:
104
- #
105
- # [
106
- # { :short => 'a', :long => 'all', :argument => :forbidden },
107
- # { :short => 'p', :long => 'port', :argument => :required },
108
- # ]
145
+ # Parses the commandline arguments into options and arguments.
109
146
  #
110
147
  # During parsing, two errors can be raised:
111
148
  #
112
- # IllegalOptionError:: An unrecognised option was encountered, i.e. an
113
- # option that is not present in the list of option
114
- # definitions.
115
- #
116
- # OptionRequiresAnArgumentError:: An option was found that did not have a
117
- # value, even though this value was
118
- # required.
119
- #
120
- # What will be returned, is a hash with two keys, :arguments and :options.
121
- # The :arguments value contains a list of arguments, and the :options
122
- # value contains a hash with key-value pairs for each option. Options
123
- # without values will have a +nil+ value instead.
124
- #
125
- # For example, the following commandline options (which should not be
126
- # passed as a string, but as an array of strings):
149
+ # @raise IllegalOptionError if an unrecognised option was encountered,
150
+ # i.e. an option that is not present in the list of option definitions
127
151
  #
128
- # foo -xyz -a hiss -s -m please --level 50 --father=ani -n luke squeak
152
+ # @raise OptionRequiresAnArgumentError if an option was found that did not
153
+ # have a value, even though this value was required.
129
154
  #
130
- # with the following option definitions:
131
- #
132
- # [
133
- # { :short => 'x', :long => 'xxx', :argument => :forbidden },
134
- # { :short => 'y', :long => 'yyy', :argument => :forbidden },
135
- # { :short => 'z', :long => 'zzz', :argument => :forbidden },
136
- # { :short => 'a', :long => 'all', :argument => :forbidden },
137
- # { :short => 's', :long => 'stuff', :argument => :optional },
138
- # { :short => 'm', :long => 'more', :argument => :optional },
139
- # { :short => 'l', :long => 'level', :argument => :required },
140
- # { :short => 'f', :long => 'father', :argument => :required },
141
- # { :short => 'n', :long => 'name', :argument => :required }
142
- # ]
143
- #
144
- # will be translated into:
145
- #
146
- # {
147
- # :arguments => [ 'foo', 'hiss', 'squeak' ],
148
- # :options => {
149
- # :xxx => true,
150
- # :yyy => true,
151
- # :zzz => true,
152
- # :all => true,
153
- # :stuff => true,
154
- # :more => 'please',
155
- # :level => '50',
156
- # :father => 'ani',
157
- # :name => 'luke'
158
- # }
159
- # }
155
+ # @return [Cri::OptionParser] The option parser self
160
156
  def run
161
157
  @running = true
162
158
 
@@ -241,8 +237,7 @@ module Cri
241
237
  add_argument(e)
242
238
  end
243
239
  end
244
-
245
- { :options => options, :arguments => arguments }
240
+ self
246
241
  ensure
247
242
  @running = false
248
243
  end
@@ -31,8 +31,8 @@ class Cri::CommandDSLTestCase < Cri::TestCase
31
31
  # Check
32
32
  assert_equal 'moo', command.name
33
33
  assert_equal 'dunno whatever', command.usage
34
- assert_equal 'does stuff', command.short_desc
35
- assert_equal 'This command does a lot of stuff.', command.long_desc
34
+ assert_equal 'does stuff', command.summary
35
+ assert_equal 'This command does a lot of stuff.', command.description
36
36
 
37
37
  # Check options
38
38
  expected_option_definitions = Set.new([
@@ -63,4 +63,16 @@ class Cri::CommandDSLTestCase < Cri::TestCase
63
63
  assert_equal 'sub', command.subcommands.to_a[0].name
64
64
  end
65
65
 
66
+ def test_aliases
67
+ # Define
68
+ dsl = Cri::CommandDSL.new
69
+ dsl.instance_eval do
70
+ aliases :moo, :aah
71
+ end
72
+ command = dsl.command
73
+
74
+ # Check
75
+ assert_equal %w( aah moo ), command.aliases.sort
76
+ end
77
+
66
78
  end
@@ -6,10 +6,10 @@ class Cri::OptionParserTestCase < Cri::TestCase
6
6
  input = %w( foo bar baz )
7
7
  definitions = []
8
8
 
9
- result = Cri::OptionParser.parse(input, definitions)
9
+ parser = Cri::OptionParser.parse(input, definitions)
10
10
 
11
- assert_equal({}, result[:options])
12
- assert_equal([ 'foo', 'bar', 'baz' ], result[:arguments])
11
+ assert_equal({}, parser.options)
12
+ assert_equal([ 'foo', 'bar', 'baz' ], parser.arguments)
13
13
  end
14
14
 
15
15
  def test_parse_with_invalid_option
@@ -19,7 +19,7 @@ class Cri::OptionParserTestCase < Cri::TestCase
19
19
  result = nil
20
20
 
21
21
  assert_raises(Cri::OptionParser::IllegalOptionError) do
22
- result = Cri::OptionParser.parse(input, definitions)
22
+ parser = Cri::OptionParser.parse(input, definitions)
23
23
  end
24
24
  end
25
25
 
@@ -29,9 +29,9 @@ class Cri::OptionParserTestCase < Cri::TestCase
29
29
  { :long => 'aaa', :short => 'a', :argument => :forbidden }
30
30
  ]
31
31
 
32
- result = Cri::OptionParser.parse(input, definitions)
32
+ parser = Cri::OptionParser.parse(input, definitions)
33
33
 
34
- assert(!result[:options][:aaa])
34
+ assert(!parser.options[:aaa])
35
35
  end
36
36
 
37
37
  def test_parse_with_long_valueless_option
@@ -40,10 +40,10 @@ class Cri::OptionParserTestCase < Cri::TestCase
40
40
  { :long => 'aaa', :short => 'a', :argument => :forbidden }
41
41
  ]
42
42
 
43
- result = Cri::OptionParser.parse(input, definitions)
43
+ parser = Cri::OptionParser.parse(input, definitions)
44
44
 
45
- assert(result[:options][:aaa])
46
- assert_equal([ 'foo', 'bar' ], result[:arguments])
45
+ assert(parser.options[:aaa])
46
+ assert_equal([ 'foo', 'bar' ], parser.arguments)
47
47
  end
48
48
 
49
49
  def test_parse_with_long_valueful_option
@@ -52,10 +52,10 @@ class Cri::OptionParserTestCase < Cri::TestCase
52
52
  { :long => 'aaa', :short => 'a', :argument => :required }
53
53
  ]
54
54
 
55
- result = Cri::OptionParser.parse(input, definitions)
55
+ parser = Cri::OptionParser.parse(input, definitions)
56
56
 
57
- assert_equal({ :aaa => 'xxx' }, result[:options])
58
- assert_equal([ 'foo', 'bar' ], result[:arguments])
57
+ assert_equal({ :aaa => 'xxx' }, parser.options)
58
+ assert_equal([ 'foo', 'bar' ], parser.arguments)
59
59
  end
60
60
 
61
61
  def test_parse_with_long_valueful_equalsign_option
@@ -64,10 +64,10 @@ class Cri::OptionParserTestCase < Cri::TestCase
64
64
  { :long => 'aaa', :short => 'a', :argument => :required }
65
65
  ]
66
66
 
67
- result = Cri::OptionParser.parse(input, definitions)
67
+ parser = Cri::OptionParser.parse(input, definitions)
68
68
 
69
- assert_equal({ :aaa => 'xxx' }, result[:options])
70
- assert_equal([ 'foo', 'bar' ], result[:arguments])
69
+ assert_equal({ :aaa => 'xxx' }, parser.options)
70
+ assert_equal([ 'foo', 'bar' ], parser.arguments)
71
71
  end
72
72
 
73
73
  def test_parse_with_long_valueful_option_with_missing_value
@@ -79,7 +79,7 @@ class Cri::OptionParserTestCase < Cri::TestCase
79
79
  result = nil
80
80
 
81
81
  assert_raises(Cri::OptionParser::OptionRequiresAnArgumentError) do
82
- result = Cri::OptionParser.parse(input, definitions)
82
+ parser = Cri::OptionParser.parse(input, definitions)
83
83
  end
84
84
  end
85
85
 
@@ -93,7 +93,7 @@ class Cri::OptionParserTestCase < Cri::TestCase
93
93
  result = nil
94
94
 
95
95
  assert_raises(Cri::OptionParser::OptionRequiresAnArgumentError) do
96
- result = Cri::OptionParser.parse(input, definitions)
96
+ parser = Cri::OptionParser.parse(input, definitions)
97
97
  end
98
98
  end
99
99
 
@@ -103,10 +103,10 @@ class Cri::OptionParserTestCase < Cri::TestCase
103
103
  { :long => 'aaa', :short => 'a', :argument => :optional }
104
104
  ]
105
105
 
106
- result = Cri::OptionParser.parse(input, definitions)
106
+ parser = Cri::OptionParser.parse(input, definitions)
107
107
 
108
- assert(result[:options][:aaa])
109
- assert_equal([ 'foo' ], result[:arguments])
108
+ assert(parser.options[:aaa])
109
+ assert_equal([ 'foo' ], parser.arguments)
110
110
  end
111
111
 
112
112
  def test_parse_with_long_valueful_option_with_optional_value
@@ -115,10 +115,10 @@ class Cri::OptionParserTestCase < Cri::TestCase
115
115
  { :long => 'aaa', :short => 'a', :argument => :optional }
116
116
  ]
117
117
 
118
- result = Cri::OptionParser.parse(input, definitions)
118
+ parser = Cri::OptionParser.parse(input, definitions)
119
119
 
120
- assert_equal({ :aaa => 'xxx' }, result[:options])
121
- assert_equal([ 'foo' ], result[:arguments])
120
+ assert_equal({ :aaa => 'xxx' }, parser.options)
121
+ assert_equal([ 'foo' ], parser.arguments)
122
122
  end
123
123
 
124
124
  def test_parse_with_long_valueless_option_with_optional_value_and_more_options
@@ -129,12 +129,12 @@ class Cri::OptionParserTestCase < Cri::TestCase
129
129
  { :long => 'ccc', :short => 'c', :argument => :forbidden }
130
130
  ]
131
131
 
132
- result = Cri::OptionParser.parse(input, definitions)
132
+ parser = Cri::OptionParser.parse(input, definitions)
133
133
 
134
- assert(result[:options][:aaa])
135
- assert(result[:options][:bbb])
136
- assert(result[:options][:ccc])
137
- assert_equal([ 'foo' ], result[:arguments])
134
+ assert(parser.options[:aaa])
135
+ assert(parser.options[:bbb])
136
+ assert(parser.options[:ccc])
137
+ assert_equal([ 'foo' ], parser.arguments)
138
138
  end
139
139
 
140
140
  def test_parse_with_short_valueless_options
@@ -143,10 +143,10 @@ class Cri::OptionParserTestCase < Cri::TestCase
143
143
  { :long => 'aaa', :short => 'a', :argument => :forbidden }
144
144
  ]
145
145
 
146
- result = Cri::OptionParser.parse(input, definitions)
146
+ parser = Cri::OptionParser.parse(input, definitions)
147
147
 
148
- assert(result[:options][:aaa])
149
- assert_equal([ 'foo', 'bar' ], result[:arguments])
148
+ assert(parser.options[:aaa])
149
+ assert_equal([ 'foo', 'bar' ], parser.arguments)
150
150
  end
151
151
 
152
152
  def test_parse_with_short_valueful_option_with_missing_value
@@ -158,7 +158,7 @@ class Cri::OptionParserTestCase < Cri::TestCase
158
158
  result = nil
159
159
 
160
160
  assert_raises(Cri::OptionParser::OptionRequiresAnArgumentError) do
161
- result = Cri::OptionParser.parse(input, definitions)
161
+ parser = Cri::OptionParser.parse(input, definitions)
162
162
  end
163
163
  end
164
164
 
@@ -170,12 +170,12 @@ class Cri::OptionParserTestCase < Cri::TestCase
170
170
  { :long => 'ccc', :short => 'c', :argument => :forbidden }
171
171
  ]
172
172
 
173
- result = Cri::OptionParser.parse(input, definitions)
173
+ parser = Cri::OptionParser.parse(input, definitions)
174
174
 
175
- assert(result[:options][:aaa])
176
- assert(result[:options][:bbb])
177
- assert(result[:options][:ccc])
178
- assert_equal([ 'foo', 'bar' ], result[:arguments])
175
+ assert(parser.options[:aaa])
176
+ assert(parser.options[:bbb])
177
+ assert(parser.options[:ccc])
178
+ assert_equal([ 'foo', 'bar' ], parser.arguments)
179
179
  end
180
180
 
181
181
  def test_parse_with_short_combined_valueful_options_with_missing_value
@@ -189,7 +189,7 @@ class Cri::OptionParserTestCase < Cri::TestCase
189
189
  result = nil
190
190
 
191
191
  assert_raises(Cri::OptionParser::OptionRequiresAnArgumentError) do
192
- result = Cri::OptionParser.parse(input, definitions)
192
+ parser = Cri::OptionParser.parse(input, definitions)
193
193
  end
194
194
  end
195
195
 
@@ -203,7 +203,7 @@ class Cri::OptionParserTestCase < Cri::TestCase
203
203
  result = nil
204
204
 
205
205
  assert_raises(Cri::OptionParser::OptionRequiresAnArgumentError) do
206
- result = Cri::OptionParser.parse(input, definitions)
206
+ parser = Cri::OptionParser.parse(input, definitions)
207
207
  end
208
208
  end
209
209
 
@@ -213,10 +213,10 @@ class Cri::OptionParserTestCase < Cri::TestCase
213
213
  { :long => 'aaa', :short => 'a', :argument => :optional }
214
214
  ]
215
215
 
216
- result = Cri::OptionParser.parse(input, definitions)
216
+ parser = Cri::OptionParser.parse(input, definitions)
217
217
 
218
- assert(result[:options][:aaa])
219
- assert_equal([ 'foo' ], result[:arguments])
218
+ assert(parser.options[:aaa])
219
+ assert_equal([ 'foo' ], parser.arguments)
220
220
  end
221
221
 
222
222
  def test_parse_with_short_valueful_option_with_optional_value
@@ -225,10 +225,10 @@ class Cri::OptionParserTestCase < Cri::TestCase
225
225
  { :long => 'aaa', :short => 'a', :argument => :optional }
226
226
  ]
227
227
 
228
- result = Cri::OptionParser.parse(input, definitions)
228
+ parser = Cri::OptionParser.parse(input, definitions)
229
229
 
230
- assert_equal({ :aaa => 'xxx' }, result[:options])
231
- assert_equal([ 'foo' ], result[:arguments])
230
+ assert_equal({ :aaa => 'xxx' }, parser.options)
231
+ assert_equal([ 'foo' ], parser.arguments)
232
232
  end
233
233
 
234
234
  def test_parse_with_short_valueless_option_with_optional_value_and_more_options
@@ -239,32 +239,32 @@ class Cri::OptionParserTestCase < Cri::TestCase
239
239
  { :long => 'ccc', :short => 'c', :argument => :forbidden }
240
240
  ]
241
241
 
242
- result = Cri::OptionParser.parse(input, definitions)
242
+ parser = Cri::OptionParser.parse(input, definitions)
243
243
 
244
- assert(result[:options][:aaa])
245
- assert(result[:options][:bbb])
246
- assert(result[:options][:ccc])
247
- assert_equal([ 'foo' ], result[:arguments])
244
+ assert(parser.options[:aaa])
245
+ assert(parser.options[:bbb])
246
+ assert(parser.options[:ccc])
247
+ assert_equal([ 'foo' ], parser.arguments)
248
248
  end
249
249
 
250
250
  def test_parse_with_single_hyphen
251
251
  input = %w( foo - bar )
252
252
  definitions = []
253
253
 
254
- result = Cri::OptionParser.parse(input, definitions)
254
+ parser = Cri::OptionParser.parse(input, definitions)
255
255
 
256
- assert_equal({}, result[:options])
257
- assert_equal([ 'foo', '-', 'bar' ], result[:arguments])
256
+ assert_equal({}, parser.options)
257
+ assert_equal([ 'foo', '-', 'bar' ], parser.arguments)
258
258
  end
259
259
 
260
260
  def test_parse_with_end_marker
261
261
  input = %w( foo bar -- -x --yyy -abc )
262
262
  definitions = []
263
263
 
264
- result = Cri::OptionParser.parse(input, definitions)
264
+ parser = Cri::OptionParser.parse(input, definitions)
265
265
 
266
- assert_equal({}, result[:options])
267
- assert_equal([ 'foo', 'bar', '-x', '--yyy', '-abc' ], result[:arguments])
266
+ assert_equal({}, parser.options)
267
+ assert_equal([ 'foo', 'bar', '-x', '--yyy', '-abc' ], parser.arguments)
268
268
  end
269
269
 
270
270
  def test_parse_with_end_marker_between_option_key_and_value
@@ -274,7 +274,7 @@ class Cri::OptionParserTestCase < Cri::TestCase
274
274
  ]
275
275
 
276
276
  assert_raises(Cri::OptionParser::OptionRequiresAnArgumentError) do
277
- result = Cri::OptionParser.parse(input, definitions)
277
+ parser = Cri::OptionParser.parse(input, definitions)
278
278
  end
279
279
  end
280
280
 
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: cri
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: 3
5
- version: 2.0b1
5
+ version: 2.0rc1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Denis Defreyne
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-06-22 00:00:00 Z
13
+ date: 2011-06-26 00:00:00 Z
14
14
  dependencies: []
15
15
 
16
16
  description: Cri allows building easy-to-use commandline interfaces with support for subcommands.