acclaim 0.0.7 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -12,7 +12,7 @@ application in a structured manner. Commands are classes that inherit from
12
12
 
13
13
  module App
14
14
  class Command < Acclaim::Command
15
- option :verbose, '-v', '--verbose'
15
+ option :verbose, '-V', '--verbose'
16
16
 
17
17
  when_called do |options, args|
18
18
  puts 'Hello World!'
@@ -21,17 +21,19 @@ application in a structured manner. Commands are classes that inherit from
21
21
  end
22
22
  end
23
23
 
24
+ App::Command.run *ARGV
25
+
24
26
  $ app --verbose a b c
25
27
  Hello World!
26
28
  a, b, c
27
29
 
28
- Every command has a set of options and block that is executed when it is called.
29
- The options are parsed into an object and passed to the command's block along
30
- with the remaining command line arguments. The first argument of the `option`
31
- method is the key used to store the value of the option, the other strings are
32
- either switches or a description:
30
+ Every command has a set of options and block. When the application runs, the
31
+ options are parsed into an object and passed to the command's block along with
32
+ the remaining command line arguments. The first argument of the `option` method
33
+ is the key used to store the value of the option, the other strings are either
34
+ switches or a description:
33
35
 
34
- option :verbose, '-v', '--verbose', '--run-verbosely', 'Run verbosely.'
36
+ option :verbose, '-V', '--verbose', '--run-verbosely', 'Run verbosely.'
35
37
 
36
38
  Acclaim provides especial `help` and `version` commands that may be added to
37
39
  your program. The help command will automatically generate and print a help page
@@ -56,10 +58,9 @@ version and exit. To use them:
56
58
  $ app version
57
59
  1.2.3
58
60
 
59
- Both methods can take a hash as the last parameter, which accepts the same
60
- configurations. If you don't want the options, or if you want to specify a
61
- different set of switches or a different description, you can write something
62
- like:
61
+ Both methods can take a hash as the last parameter. If you don't want the
62
+ options, or if you want to specify a different set of switches or a different
63
+ description, you can write:
63
64
 
64
65
  help options: false
65
66
  version '1.2.3', switches: %w(--version),
@@ -82,21 +83,19 @@ from an existing command:
82
83
  end
83
84
  end
84
85
 
85
- $ app do x y, z
86
- Doing something with x y, z
86
+ $ app do x y z
87
+ Doing something with x, y, z
87
88
 
88
- $ app do --what x y, z
89
+ $ app do --what x y z
89
90
  Doing x with y, z
90
91
 
91
- Options may also take an Hash as the last parameter. Among the things that can
92
+ Options may also take an hash as the last parameter. Among the things that can
92
93
  be configured is the default value for the option and its arity. The default
93
94
  value is `nil` by default and is used if the option is not given. The arity of
94
95
  the option represents the minimum number of arguments it __must__ take and the
95
- number of optional arguments it __may__ take. It is specified as an array in the
96
- form `[minimum, optional]`. Options that take zero arguments, which is the
97
- default, are flags.
98
-
99
- So, options can take from zero to an unlimited number of arguments, right?
96
+ number of optional arguments it __may__ take. It can be specified as an array in
97
+ the form `[minimum, optional]`. Options that take zero arguments, which is the
98
+ default, are called switches.
100
99
 
101
100
  class App::Command::Do < App::Command
102
101
 
@@ -107,6 +106,7 @@ So, options can take from zero to an unlimited number of arguments, right?
107
106
  what = (options.what.join ', ' rescue options.what)
108
107
  subjects = args.join ', '
109
108
  puts "Doing #{what} with #{subjects}"
109
+ end
110
110
  end
111
111
 
112
112
  $ app do --what x y z
@@ -132,9 +132,8 @@ will not work:
132
132
  $ app do --what w x --verbose y z
133
133
  Doing w, x, y, z with
134
134
 
135
- This happens because `--verbose` is an option of the main command. Since it will
136
- be parsed and deleted from the argument array, when `do` gets its turn it will
137
- be parsing the `%w(--what w x y z)` array.
135
+ This happens because `--verbose` is an option of the main command. When `do`
136
+ gets its turn it will be parsing the `%w(--what w x y z)` array.
138
137
 
139
138
  ### Option Type Handlers
140
139
 
@@ -142,8 +141,7 @@ Arguments given to options are by default strings. To make life easier, you may
142
141
  specify the type of the arguments by passing a class among the arguments:
143
142
 
144
143
  class App::Command::Do
145
- opt :when, '--when', 'When to do it.', Date,
146
- default: Date.today, arity: [1,0]
144
+ opt :when, '--when', 'When to do it.', Date, default: Date.today, arity: [1,0]
147
145
 
148
146
  action do |options, args|
149
147
  what = (options.what.join ', ' rescue options.what)
@@ -159,23 +157,33 @@ specify the type of the arguments by passing a class among the arguments:
159
157
  Merry Christmas!
160
158
  Doing w, x with y, z on 12/25/2011
161
159
 
162
- There are type handlers included for `Date`s, `Time`s, `DateTime`s, `URI`s and
163
- `String`s, but if you need more you can always write your own:
160
+ There are type handlers included for `Date`s, `Time`s, `DateTime`s, `URI`s,
161
+ `Symbol`s and `String`s, but if you need more you can always write your own:
162
+
163
+ class Person
164
+ attr_accessor :first_name, :middle_names, :last_name
165
+
166
+ def initialize(first, *others)
167
+ @first_name, @last_name, @middle_names = first, others.pop, others
168
+ end
169
+ end
170
+
171
+ Acclaim::Option::Type.add_handler_for Person do |argument|
172
+ Person.new *argument.split
173
+ end
164
174
 
165
- Acclaim::Option::Type.add_handler_for(Symbol) { |str| str.to_sym }
175
+ class App::Command::Show < App::Command
166
176
 
167
- class App::Command::Handle < App::Command
168
- opt :syms, '--symbol', '--symbols', Symbol, arity: [1,-1], required: true
177
+ # If no switches are specified, one will be derived from the key
178
+ opt :person, Person, arity: [1,0], required: true
169
179
 
170
180
  when_called do |options, args|
171
- options.syms.each { |sym| puts "#{sym.class} => #{sym.inspect}" }
181
+ puts "#{options.person.last_name}, #{options.person.first_name}"
172
182
  end
173
183
  end
174
184
 
175
- $ app handle --symbols a s d
176
- Symbol => :a
177
- Symbol => :s
178
- Symbol => :d
185
+ $ app show --person 'Matheus Afonso Martins Moreira'
186
+ Moreira, Matheus
179
187
 
180
188
  `add_handler_for` takes a class and a block, which will be called for every
181
189
  argument of that class that must be parsed.
@@ -69,6 +69,7 @@ module Acclaim
69
69
  options << Option.new(*args, &block)
70
70
  end
71
71
 
72
+ # Same as #option.
72
73
  alias :opt :option
73
74
 
74
75
  # The block which is executed when this command is called. It is given 2
@@ -78,6 +79,7 @@ module Acclaim
78
79
  @action = block
79
80
  end
80
81
 
82
+ # Same as #action.
81
83
  alias :when_called :action
82
84
 
83
85
  # Adds help subcommand and options to this command.
@@ -132,6 +134,7 @@ module Acclaim
132
134
  @action.call opts, args if @action
133
135
  end
134
136
 
137
+ # Same as #execute.
135
138
  alias :call :execute
136
139
 
137
140
  # True if this is a top-level command.
@@ -154,6 +157,7 @@ module Acclaim
154
157
  const_get(:Version).execute opts, args if opts.acclaim_version?
155
158
  end
156
159
 
160
+ # Deletes all argument separators in the given argument array.
157
161
  def delete_argument_separators_in!(args)
158
162
  args.delete_if do |arg|
159
163
  arg =~ Option::Parser::Regexp::ARGUMENT_SEPARATOR
@@ -7,7 +7,11 @@ module Acclaim
7
7
  # the elements of the array.
8
8
  class Parser
9
9
 
10
- attr_accessor :argv, :commands
10
+ # The argument array to be searched.
11
+ attr_accessor :argv
12
+
13
+ # The commands to search for.
14
+ attr_accessor :commands
11
15
 
12
16
  # Initializes a new command parser, with the given argument array and set
13
17
  # of commands to search for.
@@ -36,7 +40,7 @@ module Acclaim
36
40
 
37
41
  # Searches for one of the given commands in the argument array, and
38
42
  # returns it. Removes the string that matched the command name from
39
- # +argv+. Returns +nil if no command was found.
43
+ # +argv+. Returns +nil+ if no command was found.
40
44
  def find_command
41
45
  commands.find do |command|
42
46
  arguments_up_to_separator.include? command.line
@@ -1,13 +1,36 @@
1
1
  require 'acclaim/option/arity'
2
2
  require 'acclaim/option/parser/regexp'
3
3
  require 'acclaim/option/type'
4
+ require 'ribbon'
5
+ require 'ribbon/core_ext/array'
4
6
 
5
7
  module Acclaim
6
8
 
7
9
  # Represents a command-line option.
8
10
  class Option
9
11
 
10
- attr_accessor :key, :names, :description, :type, :default, :handler, :on_multiple
12
+ # The key used to store the value of the option.
13
+ attr_accessor :key
14
+
15
+ # The strings that refer to this option in the command line.
16
+ attr_accessor :names
17
+
18
+ # The description of this option.
19
+ attr_accessor :description
20
+
21
+ # The type the option's value will be converted to. See Option::Type.
22
+ attr_accessor :type
23
+
24
+ # The default value for the option. Default is +nil+.
25
+ attr_accessor :default
26
+
27
+ # This option's custom handler.
28
+ attr_accessor :handler
29
+
30
+ # How the parser should react when multiple instances of this option are
31
+ # found in the command line. It will, by default, replace the old value with
32
+ # the new one, but it can also collect all values or raise an error.
33
+ attr_accessor :on_multiple
11
34
 
12
35
  # Initializes a command line option. The +key+ is the object used to
13
36
  # associate this option with a value. The other arguments may be:
@@ -23,13 +46,20 @@ module Acclaim
23
46
  # [class] The <tt>Class</tt> which will be used in parameter
24
47
  # conversion. The default is <tt>String</tt>.
25
48
  #
49
+ # If no switches were specified, the +key+ will be used to derive one. See
50
+ # Option::name_from for details.
51
+ #
26
52
  # The last argument can be a hash of options, which may specify:
27
53
  #
28
- # [:arity] The number of required and optional arguments. See Arity for
29
- # defails.
30
- # [:default] The default value for this option.
31
- # [:required] Whether or not the option must be present on the command
32
- # line.
54
+ # [:arity] The number of required and optional arguments. See Arity
55
+ # for defails. Defaults to no arguments.
56
+ # [:default] The default value for this option. Defaults to +nil+.
57
+ # [:required] Whether or not the option must be present on the command
58
+ # line. Default is +false+.
59
+ # [:on_multiple] What to do if the option is encountered multiple times.
60
+ # Supported modes are <tt>:replace</tt>, <tt>:append</tt>
61
+ # and <tt>:raise</tt>. New values will replace old ones by
62
+ # default.
33
63
  #
34
64
  # Additionally, if a block is given, it will be called when the option is
35
65
  # parsed with a ribbon instance and the parameters given to the option. The
@@ -37,18 +67,20 @@ module Acclaim
37
67
  # this is not desirable consider not specifying a class to the option or
38
68
  # registering a custom type handler.
39
69
  def initialize(key, *args, &block)
40
- options = args.last.is_a?(Hash) ? args.pop : {}
41
- matches = args.select { |arg| arg.is_a? String }.group_by do |arg|
70
+ options = args.extract_ribbon!
71
+ matches = args.select do |arg|
72
+ arg.is_a? String
73
+ end.group_by do |arg|
42
74
  arg =~ Parser::Regexp::SWITCH ? true : false
43
75
  end
44
76
  klass = args.find { |arg| arg.is_a? Module }
45
77
  self.key = key
46
- self.names = matches.fetch true, []
78
+ self.names = matches.fetch(true) { [ Option.name_from(key) ] }
47
79
  self.description = matches.fetch(false, []).first
48
- self.on_multiple = options.fetch :on_multiple, :replace
49
- self.arity = options[:arity]
50
- self.default = options[:default]
51
- self.required = options[:required]
80
+ self.on_multiple = options.on_multiple? :replace
81
+ self.arity = options.arity?
82
+ self.default = options.default?
83
+ self.required = options.required?
52
84
  self.type = klass || String
53
85
  self.handler = block
54
86
  end
@@ -94,14 +126,38 @@ module Acclaim
94
126
  self.required = true
95
127
  end
96
128
 
97
- # Returns true if this option takes no arguments.
129
+ # Returns +true+ if this option takes no arguments.
98
130
  def flag?
99
131
  not arity or arity == [0, 0]
100
132
  end
101
133
 
102
- alias :bool? :flag?
134
+ # Same as <tt>flag?</tt>
135
+ alias :bool? :flag?
136
+
137
+ # Same as <tt>flag?</tt>
103
138
  alias :boolean? :flag?
104
- alias :switch? :flag?
139
+
140
+ # Same as <tt>flag?</tt>
141
+ alias :switch? :flag?
142
+
143
+ # The class methods.
144
+ class << self
145
+
146
+ # Derives a name from the given key's string representation. All
147
+ # underscores will be replaced with dashes.
148
+ #
149
+ # If the string is empty, an +ArgumentError+ will be raised. If the
150
+ # resulting name is not a valid switch, a +NameError+ will be raised.
151
+ def name_from(key)
152
+ name = key.to_s
153
+ raise ArgumentError, "Can't derive name from empty string representation." if name.empty?
154
+ name = (name.length == 1 ? '-' : '--') + name
155
+ name.gsub! '_', '-'
156
+ raise NameError, "Derived name is invalid: #{name}" unless name =~ Parser::Regexp::SWITCH
157
+ name
158
+ end
159
+
160
+ end
105
161
 
106
162
  end
107
163
  end
@@ -5,7 +5,13 @@ module Acclaim
5
5
  # and optional.
6
6
  class Arity
7
7
 
8
- attr_accessor :minimum, :optional
8
+ # The minimum number of arguments.
9
+ attr_accessor :minimum
10
+
11
+ # The number of optional arguments.
12
+ attr_accessor :optional
13
+
14
+ # Same as +minimum+.
9
15
  alias :required :minimum
10
16
 
11
17
  # Initializes this arity with a number of required parameters and a number
@@ -45,7 +51,10 @@ module Acclaim
45
51
  [ minimum, optional ]
46
52
  end
47
53
 
54
+ # Same as +to_a+.
48
55
  alias :to_ary :to_a
56
+
57
+ # Same as +to_a+.
49
58
  alias :to_array :to_a
50
59
 
51
60
  # Equivalent to <tt>to_a.hash</tt>.
@@ -62,7 +71,10 @@ module Acclaim
62
71
  to_a == arity.to_a
63
72
  end
64
73
 
74
+ # Same as <tt>==</tt>
65
75
  alias :eql? :==
76
+
77
+ # Same as <tt>==</tt>
66
78
  alias :=== :==
67
79
 
68
80
  # Returns a string in the following format:
@@ -37,7 +37,11 @@ module Acclaim
37
37
 
38
38
  end
39
39
 
40
- attr_accessor :argv, :options
40
+ # The argument array to parse.
41
+ attr_accessor :argv
42
+
43
+ # The options to be parsed.
44
+ attr_accessor :options
41
45
 
42
46
  # Initializes a new parser, with the given argument array and set of
43
47
  # options. If no option array is given, the argument array will be
@@ -4,40 +4,55 @@ module Acclaim
4
4
  # Associates a class with a handler block.
5
5
  module Type
6
6
 
7
- # Yields class, proc pairs if a block was given. Returns an enumerator
8
- # otherwise.
9
- def self.each(&block)
10
- table.each &block
11
- end
7
+ # The class methods.
8
+ class << self
12
9
 
13
- # Returns all registered classes.
14
- def self.all
15
- table.keys
16
- end
10
+ # Yields class, proc pairs if a block was given. Returns an enumerator
11
+ # otherwise.
12
+ def each(&block)
13
+ table.each &block
14
+ end
17
15
 
18
- # Registers a handler for a class.
19
- def self.register(klass, &block)
20
- table[klass] = block
21
- end
16
+ # Take advantage of each method.
17
+ include Enumerable
22
18
 
23
- # Returns the handler for the given class.
24
- def self.handler_for(klass)
25
- table[klass]
26
- end
19
+ # Returns all registered classes.
20
+ def all
21
+ table.keys
22
+ end
27
23
 
28
- class << self
24
+ # Registers a handler for a class.
25
+ def register(klass, &block)
26
+ table[klass] = block
27
+ end
28
+
29
+ # Returns the handler for the given class.
30
+ def handler_for(klass)
31
+ table.fetch klass do
32
+ raise "#{klass} does not have an associated handler"
33
+ end
34
+ end
35
+
36
+ # Same as <tt>all</tt>.
29
37
  alias registered all
38
+
39
+ # Same as <tt>register</tt>.
30
40
  alias add_handler_for register
41
+
42
+ # Same as <tt>register</tt>.
31
43
  alias accept register
44
+
45
+ # Same as <tt>handler_for</tt>.
32
46
  alias [] handler_for
33
- end
34
47
 
35
- # The hash used to associate classes with their handlers.
36
- def self.table
37
- @table ||= {}
38
- end
48
+ private
49
+
50
+ # The hash used to associate classes with their handlers.
51
+ def table
52
+ @table ||= {}
53
+ end
39
54
 
40
- private_class_method :table
55
+ end
41
56
 
42
57
  end
43
58
 
@@ -11,12 +11,12 @@ module Acclaim
11
11
  # Minor version.
12
12
  #
13
13
  # Increments denote backward-compatible changes and additions.
14
- MINOR = 0
14
+ MINOR = 1
15
15
 
16
16
  # Patch version.
17
17
  #
18
18
  # Increments denote changes in implementation.
19
- PATCH = 7
19
+ PATCH = 0
20
20
 
21
21
  # Build version.
22
22
  #
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.7
4
+ version: 0.1.0
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: 2012-01-12 00:00:00.000000000 Z
12
+ date: 2012-01-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ribbon
16
- requirement: &17514000 !ruby/object:Gem::Requirement
16
+ requirement: &22189080 !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: *17514000
24
+ version_requirements: *22189080
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &17513440 !ruby/object:Gem::Requirement
27
+ requirement: &22188500 !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: *17513440
35
+ version_requirements: *22188500
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rookie
38
- requirement: &17513000 !ruby/object:Gem::Requirement
38
+ requirement: &22188080 !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: *17513000
46
+ version_requirements: *22188080
47
47
  description: Command-line option parser and command interface.
48
48
  email: matheus.a.m.moreira@gmail.com
49
49
  executables: []
@@ -94,7 +94,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
94
94
  version: '0'
95
95
  segments:
96
96
  - 0
97
- hash: 1879446143954765838
97
+ hash: -901301498998529047
98
98
  required_rubygems_version: !ruby/object:Gem::Requirement
99
99
  none: false
100
100
  requirements:
@@ -103,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
103
  version: '0'
104
104
  segments:
105
105
  - 0
106
- hash: 1879446143954765838
106
+ hash: -901301498998529047
107
107
  requirements: []
108
108
  rubyforge_project:
109
109
  rubygems_version: 1.8.10