ame 0.1.1 → 1.0.1
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.
- checksums.yaml +7 -0
- data/README +541 -3
- data/Rakefile +15 -6
- data/lib/ame-1.0.rb +31 -0
- data/lib/ame-1.0/argument.rb +63 -0
- data/lib/ame-1.0/arguments.rb +44 -0
- data/lib/ame-1.0/arguments/complete.rb +37 -0
- data/lib/ame-1.0/arguments/optional.rb +34 -0
- data/lib/ame-1.0/arguments/undefined.rb +71 -0
- data/lib/ame-1.0/class.rb +436 -0
- data/lib/ame-1.0/flag.rb +101 -0
- data/lib/{ame → ame-1.0}/help.rb +1 -1
- data/lib/ame-1.0/help/delegate.rb +19 -0
- data/lib/ame-1.0/help/terminal.rb +132 -0
- data/lib/ame-1.0/method.rb +75 -0
- data/lib/ame-1.0/method/undefined.rb +184 -0
- data/lib/ame-1.0/methods.rb +40 -0
- data/lib/ame-1.0/multioption.rb +36 -0
- data/lib/ame-1.0/option.rb +37 -0
- data/lib/ame-1.0/optional.rb +31 -0
- data/lib/ame-1.0/options.rb +68 -0
- data/lib/ame-1.0/options/undefined.rb +114 -0
- data/lib/ame-1.0/root.rb +174 -0
- data/lib/ame-1.0/splat.rb +16 -0
- data/lib/ame-1.0/splus.rb +22 -0
- data/lib/ame-1.0/switch.rb +39 -0
- data/lib/ame-1.0/types.rb +60 -0
- data/lib/ame-1.0/types/boolean.rb +13 -0
- data/lib/ame-1.0/types/enumeration.rb +40 -0
- data/lib/ame-1.0/types/float.rb +11 -0
- data/lib/{ame → ame-1.0}/types/integer.rb +3 -3
- data/lib/{ame → ame-1.0}/types/string.rb +2 -2
- data/lib/ame-1.0/types/symbol.rb +9 -0
- data/lib/ame-1.0/version.rb +62 -0
- data/test/unit/ame-1.0.rb +4 -0
- data/test/unit/ame-1.0/argument.rb +46 -0
- data/test/unit/ame-1.0/arguments.rb +63 -0
- data/test/unit/ame-1.0/arguments/complete.rb +4 -0
- data/test/unit/ame-1.0/arguments/optional.rb +4 -0
- data/test/unit/ame-1.0/arguments/undefined.rb +63 -0
- data/test/unit/ame-1.0/class.rb +4 -0
- data/test/unit/ame-1.0/flag.rb +31 -0
- data/test/unit/ame-1.0/help.rb +4 -0
- data/test/unit/ame-1.0/help/delegate.rb +4 -0
- data/test/unit/{ame/help/console.rb → ame-1.0/help/terminal.rb} +34 -23
- data/test/unit/ame-1.0/method.rb +4 -0
- data/test/unit/ame-1.0/method/undefined.rb +33 -0
- data/test/unit/ame-1.0/methods.rb +9 -0
- data/test/unit/ame-1.0/multioption.rb +4 -0
- data/test/unit/ame-1.0/option.rb +11 -0
- data/test/unit/ame-1.0/optional.rb +9 -0
- data/test/unit/ame-1.0/options.rb +149 -0
- data/test/unit/ame-1.0/options/undefined.rb +33 -0
- data/test/unit/ame-1.0/root.rb +4 -0
- data/test/unit/ame-1.0/splat.rb +9 -0
- data/test/unit/ame-1.0/splus.rb +4 -0
- data/test/unit/ame-1.0/switch.rb +15 -0
- data/test/unit/ame-1.0/types.rb +4 -0
- data/test/{ame → unit/ame-1.0}/types/boolean.rb +0 -0
- data/test/unit/ame-1.0/types/enumeration.rb +4 -0
- data/test/unit/ame-1.0/types/float.rb +7 -0
- data/test/{ame → unit/ame-1.0}/types/integer.rb +0 -0
- data/test/{ame → unit/ame-1.0}/types/string.rb +0 -0
- data/test/unit/ame-1.0/types/symbol.rb +5 -0
- data/test/unit/ame-1.0/version.rb +4 -0
- metadata +690 -60
- data/lib/ame.rb +0 -26
- data/lib/ame/argument.rb +0 -56
- data/lib/ame/arguments.rb +0 -65
- data/lib/ame/class.rb +0 -117
- data/lib/ame/help/console.rb +0 -96
- data/lib/ame/method.rb +0 -94
- data/lib/ame/methods.rb +0 -30
- data/lib/ame/option.rb +0 -50
- data/lib/ame/options.rb +0 -102
- data/lib/ame/root.rb +0 -57
- data/lib/ame/splat.rb +0 -12
- data/lib/ame/types.rb +0 -29
- data/lib/ame/types/array.rb +0 -16
- data/lib/ame/types/boolean.rb +0 -16
- data/lib/ame/version.rb +0 -5
- data/test/ame/types/array.rb +0 -13
- data/test/unit/ame/argument.rb +0 -66
- data/test/unit/ame/arguments.rb +0 -106
- data/test/unit/ame/method.rb +0 -40
- data/test/unit/ame/methods.rb +0 -10
- data/test/unit/ame/option.rb +0 -75
- data/test/unit/ame/options.rb +0 -136
- data/test/unit/ame/root.rb +0 -15
- data/test/unit/ame/splat.rb +0 -11
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
Expectations do
|
4
|
+
expect 'shallow' do
|
5
|
+
Ame::Switch.new('', 'thread', 'style', nil, 'shallow', 'd').process({}, [], '--thread', nil)
|
6
|
+
end
|
7
|
+
|
8
|
+
expect 'deep' do
|
9
|
+
Ame::Switch.new('', 'thread', 'style', nil, 'shallow', 'd').process({}, [], '--thread', 'deep')
|
10
|
+
end
|
11
|
+
|
12
|
+
expect :deep do
|
13
|
+
Ame::Switch.new('', 'thread', 'style', nil, Ame::Types::Enumeration[:shallow, :deep], 'd').process({}, [], '--thread', 'deep')
|
14
|
+
end
|
15
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
metadata
CHANGED
@@ -1,118 +1,748 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ame
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Nikolai Weibull
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2015-10-31 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: inventory
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: inventory-rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: inventory-rake-tasks-yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.4'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.4'
|
14
55
|
- !ruby/object:Gem::Dependency
|
15
56
|
name: lookout
|
16
|
-
requirement:
|
17
|
-
none: false
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
18
58
|
requirements:
|
19
59
|
- - ~>
|
20
60
|
- !ruby/object:Gem::Version
|
21
|
-
version: '
|
61
|
+
version: '3.0'
|
22
62
|
type: :development
|
23
63
|
prerelease: false
|
24
|
-
version_requirements:
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
25
69
|
- !ruby/object:Gem::Dependency
|
26
|
-
name:
|
27
|
-
requirement:
|
28
|
-
none: false
|
70
|
+
name: lookout-rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
29
72
|
requirements:
|
30
73
|
- - ~>
|
31
74
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
75
|
+
version: '3.1'
|
33
76
|
type: :development
|
34
77
|
prerelease: false
|
35
|
-
version_requirements:
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.1'
|
36
83
|
- !ruby/object:Gem::Dependency
|
37
84
|
name: yard
|
38
|
-
requirement:
|
39
|
-
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.8.0
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.8.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: yard-heuristics
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
40
100
|
requirements:
|
41
101
|
- - ~>
|
42
102
|
- !ruby/object:Gem::Version
|
43
|
-
version:
|
103
|
+
version: '1.2'
|
44
104
|
type: :development
|
45
105
|
prerelease: false
|
46
|
-
version_requirements:
|
47
|
-
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.2'
|
111
|
+
description: |2
|
112
|
+
Ame
|
113
|
+
|
114
|
+
Ame provides a simple command-line interface API for Ruby¹. It can be used
|
115
|
+
to provide both simple interfaces like that of ‹rm›² and complex ones like
|
116
|
+
that of ‹git›³. It uses Ruby’s own classes, methods, and argument lists to
|
117
|
+
provide an interface that is both simple to use from the command-line side
|
118
|
+
and from the Ruby side. The provided command-line interface is flexible and
|
119
|
+
follows commond standards for command-line processing.
|
120
|
+
|
121
|
+
¹ See http://ruby-lang.org/
|
122
|
+
² See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/rm.html
|
123
|
+
³ See http://git-scm.com/docs/
|
124
|
+
|
125
|
+
§ Usage
|
126
|
+
|
127
|
+
Let’s begin by looking at two examples, one where we mimic the POSIX¹
|
128
|
+
command-line interface to the ‹rm› command. Looking at the entry² in the
|
129
|
+
standard, ‹rm› takes the following options:
|
130
|
+
|
131
|
+
= -f. = Do not prompt for confirmation.
|
132
|
+
= -i. = Prompt for confirmation.
|
133
|
+
= -R. = Remove file hierarchies.
|
134
|
+
= -r. = Equivalent to /-r/.
|
135
|
+
|
136
|
+
It also takes the following arguments:
|
137
|
+
|
138
|
+
= FILE. = A pathname or directory entry to be removed.
|
139
|
+
|
140
|
+
And actually allows one or more of these /FILE/ arguments to be given.
|
141
|
+
|
142
|
+
We also note that the ‹rm› command is described as a command to “remove
|
143
|
+
directory entries”.
|
144
|
+
|
145
|
+
¹ See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html
|
146
|
+
² See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/rm.html
|
147
|
+
|
148
|
+
Let’s turn this specification into one using Ame’s API. We begin by adding
|
149
|
+
a flag for each of the options listed above:
|
150
|
+
|
151
|
+
class Rm < Ame::Root
|
152
|
+
flag 'f', '', false, 'Do not prompt for confirmation'
|
153
|
+
flag 'i', '', nil, 'Prompt for confirmation' do |options|
|
154
|
+
options['f'] = false
|
155
|
+
end
|
156
|
+
flag 'R', '', false, 'Remove file hierarchies'
|
157
|
+
flag 'r', '', nil, 'Equivalent to -R' do |options|
|
158
|
+
options['r'] = true
|
159
|
+
end
|
160
|
+
|
161
|
+
A flag¹ is a boolean option that doesn’t take an argument. Each flag gets
|
162
|
+
a short and long name, where an empty name means that there’s no
|
163
|
+
corresponding short or long name for the flag, a default value (true,
|
164
|
+
false, or nil), and a description of what the flag does. Each flag can
|
165
|
+
also optionally take a block that can do further processing. In this case
|
166
|
+
we use this block to modify the Hash that maps option names to their values
|
167
|
+
passed to the block to set other flags’ values than the ones that the block
|
168
|
+
is associated with. As these flags (‘i’ and ‘r’) aren’t themselves of
|
169
|
+
interest, their default values have been set to nil, which means that they
|
170
|
+
won’t be included in the Hash that maps option names to their values when
|
171
|
+
passed to the method.
|
172
|
+
|
173
|
+
¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#flag-class-method
|
174
|
+
|
175
|
+
There are quite a few other kinds of options besides flags that can be
|
176
|
+
defined using Ame, but flags are all that are required for this example.
|
177
|
+
We’ll get to the other kinds in later examples.
|
178
|
+
|
179
|
+
Next we add a “splus” argument.
|
180
|
+
|
181
|
+
splus 'FILE', String, 'File to remove'
|
182
|
+
|
183
|
+
A splus¹ argument is like a Ruby “splat”, that is, an Array argument at the
|
184
|
+
end of the argument list to a method preceded by a star, except that a
|
185
|
+
splus requires at least one argument. A splus argument gets a name for the
|
186
|
+
argument (‹FILE›), the type of argument it represents (String), and a
|
187
|
+
description.
|
188
|
+
|
189
|
+
¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#splus-class-method
|
190
|
+
|
191
|
+
Then we add a description of the command (method) itself:
|
192
|
+
|
193
|
+
description 'Remove directory entries'
|
194
|
+
|
195
|
+
Descriptions¹ will be used in help output to assist the user in using the
|
196
|
+
command.
|
197
|
+
|
198
|
+
¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#description-class-method
|
199
|
+
|
200
|
+
Finally, we add the Ruby method that’ll implement the command (all
|
201
|
+
preceding code included here for completeness):
|
202
|
+
|
203
|
+
class Rm < Ame::Root
|
204
|
+
version '1.0.0'
|
205
|
+
|
206
|
+
flag 'f', '', false, 'Do not prompt for confirmation'
|
207
|
+
flag 'i', '', nil, 'Prompt for confirmation' do |options|
|
208
|
+
options['f'] = false
|
209
|
+
end
|
210
|
+
flag 'R', '', false, 'Remove file hierarchies'
|
211
|
+
flag 'r', '', nil, 'Equivalent to -R' do |options|
|
212
|
+
options['r'] = true
|
213
|
+
end
|
214
|
+
splus 'FILE', String, 'File to remove'
|
215
|
+
description 'Remove directory entries'
|
216
|
+
def rm(files, options = {})
|
217
|
+
require 'fileutils'
|
218
|
+
FileUtils.send options['R'] ? :rm_r : :rm,
|
219
|
+
[first] + rest, :force => options['f']
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
Actually, another bit of code was also added, namely
|
224
|
+
|
225
|
+
version '1.0.0'
|
226
|
+
|
227
|
+
This sets the version¹ String of the command. This information is used
|
228
|
+
when the command is invoked with the “‹--version›” flag. This flag is
|
229
|
+
automatically added, so you don’t need to add it yourself. Another flag,
|
230
|
+
“‹--help›”, is also added automatically. When given, this flag’ll make Ame
|
231
|
+
output usage information of the command.
|
232
|
+
|
233
|
+
¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#version-class-method
|
234
|
+
|
235
|
+
To actually run the command, all you need to do is invoke
|
236
|
+
|
237
|
+
Rm.process
|
238
|
+
|
239
|
+
This’ll invoke the command using the command-line arguments stored in
|
240
|
+
‹ARGV›, but you can also specify other ones if you want to:
|
241
|
+
|
242
|
+
Rm.process 'rm', %w[-r /tmp/*]
|
243
|
+
|
244
|
+
The first argument to #process¹ is the name of the method to invoke, which
|
245
|
+
defaults to ‹File.basename($0)›, and the second argument is an Array of
|
246
|
+
Strings that should be processed as command-line arguments passed to the
|
247
|
+
command.
|
248
|
+
|
249
|
+
¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#process-class-method
|
250
|
+
|
251
|
+
If you’d store the complete ‹Rm› class defined above in a file called ‹rm›
|
252
|
+
and add ‹#! /usr/bin/ruby -w› at the beginning and ‹Rm.process› at the end,
|
253
|
+
you’d have a fully functional ‹rm› command (after making it executable).
|
254
|
+
Let’s see it in action:
|
255
|
+
|
256
|
+
% rm --help
|
257
|
+
Usage: rm [OPTIONS]... FILE...
|
258
|
+
Remove directory entries
|
259
|
+
|
260
|
+
Arguments:
|
261
|
+
FILE... File to remove
|
262
|
+
|
263
|
+
Options:
|
264
|
+
-R Remove file hierarchies
|
265
|
+
-f Do not prompt for confirmation
|
266
|
+
--help Display help for this method
|
267
|
+
-i Prompt for confirmation
|
268
|
+
-r Equivalent to -R
|
269
|
+
--version Display version information
|
270
|
+
% rm --version
|
271
|
+
rm 1.0.0
|
272
|
+
|
273
|
+
Some commands are more complex than ‹rm›. For example, ‹git›¹ has a rather
|
274
|
+
complex command-line interface. We won’t mimic it all here, but let’s
|
275
|
+
introduce the rest of the Ame API using a fake ‹git› clone as an example.
|
276
|
+
|
277
|
+
¹ See http://git-scm.com/docs/
|
278
|
+
|
279
|
+
‹Git› uses sub-commands to achieve most things. Implementing sub-commands
|
280
|
+
with Ame is done using a “dispatch”. We’ll discuss dispatches in more
|
281
|
+
detail later, but suffice it to say that a dispatch delegates processing to
|
282
|
+
a child class that’ll handle the sub-command in question. We begin by
|
283
|
+
defining our main ‹git› command using a class called ‹Git› under the
|
284
|
+
‹Git::CLI› namespace:
|
285
|
+
|
286
|
+
module Git end
|
287
|
+
class Git::CLI < Ame::Root
|
288
|
+
version '1.0.0'
|
289
|
+
class Git < Ame::Class
|
290
|
+
description 'The stupid content tracker'
|
291
|
+
def initialize; end
|
292
|
+
|
293
|
+
We’re setting things up to use the ‹Git› class as a dispatch in the
|
294
|
+
‹Git::CLI› class. The description on the ‹initialize› method will be used
|
295
|
+
as a description of the ‹git› dispatch command itself.
|
296
|
+
|
297
|
+
Next, let’s add the ‹format-patch›¹ sub-command:
|
298
|
+
|
299
|
+
description 'Prepare patches for e-mail submission'
|
300
|
+
flag ?n, 'numbered', false, 'Name output in [PATCH n/m] format'
|
301
|
+
flag ?N, 'no-numbered', nil,
|
302
|
+
'Name output in [PATCH] format' do |options|
|
303
|
+
options['numbered'] = false
|
304
|
+
end
|
305
|
+
toggle ?s, 'signoff', false,
|
306
|
+
'Add Signed-off-by: line to the commit message'
|
307
|
+
switch '', 'thread', 'STYLE', nil,
|
308
|
+
Ame::Types::Enumeration[:shallow, :deep],
|
309
|
+
'Controls addition of In-Reply-To and References headers'
|
310
|
+
flag '', 'no-thread', nil,
|
311
|
+
'Disables addition of In-Reply-To and Reference headers' do |options, _|
|
312
|
+
options.delete 'thread'
|
313
|
+
end
|
314
|
+
option '', 'start-number', 'N', 1,
|
315
|
+
'Start numbering the patches at N instead of 1'
|
316
|
+
multioption '', 'to', 'ADDRESS', String,
|
317
|
+
'Add a To: header to the email headers'
|
318
|
+
optional 'SINCE', 'N/A', 'Generate patches for commits after SINCE'
|
319
|
+
def format_patch(since = '', options = {})
|
320
|
+
p since, options
|
321
|
+
end
|
322
|
+
|
323
|
+
¹ See http://git-scm.com/docs/git-format-patch/
|
324
|
+
|
325
|
+
We’re using quite a few new Ame commands here. Let’s look at each in turn:
|
326
|
+
|
327
|
+
toggle ?s, 'signoff', false,
|
328
|
+
'Add Signed-off-by: line to the commit message'
|
329
|
+
|
330
|
+
A “toggle”¹ is a flag that also has an inverse. Beyond the flags ‘s’ and
|
331
|
+
“signoff”, the toggle also defines “no-signoff”, which will set “signoff”
|
332
|
+
to false. This is useful if you want to support configuration files that
|
333
|
+
set “signoff”’s default to true, but still allow it to be overridden on the
|
334
|
+
command line.
|
335
|
+
|
336
|
+
¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#toggle-class-method
|
337
|
+
|
338
|
+
When using the short form of a toggle (and flag and switch), multiple ones
|
339
|
+
may be juxtaposed after the initial one. For example, “‹-sn›” is
|
340
|
+
equivalent to “‹-s -n›” to “git format-patch›”.
|
341
|
+
|
342
|
+
switch '', 'thread', 'STYLE', nil,
|
343
|
+
Ame::Types::Enumeration[:shallow, :deep],
|
344
|
+
'Controls addition of In-Reply-To and References headers'
|
345
|
+
|
346
|
+
A “switch”¹ is an option that takes an optional argument. This allows you
|
347
|
+
to have separate defaults for when the switch isn’t present on the command
|
348
|
+
line and for when it’s given without an argument. The third argument to a
|
349
|
+
switch is the name of the argument. We’re also introducing a new concept
|
350
|
+
here in ‹Ame::Types::Enumeration›. An enumeration² allows you to limit the
|
351
|
+
allowed input to a set of Symbols. An enumeration also has a default value
|
352
|
+
in the first item to its constructor (which is aliased as ‹.[]›). In this
|
353
|
+
case, the “thread” switch defaults to nil, but, when given, will default to
|
354
|
+
‹:shallow› if no argument is given. If an argument is given it must be
|
355
|
+
either “shallow” or “deep”. A switch isn’t required to take an enumeration
|
356
|
+
as its argument default and can take any kind of default value for its
|
357
|
+
argument that Ame knows how to handle. We’ll look at this in more detail
|
358
|
+
later, but know that the type of the default value will be used to inform
|
359
|
+
Ame how to parse a command-line argument into a Ruby value.
|
360
|
+
|
361
|
+
An argument to a switch must be given, in this case, as “‹--thread=deep›”
|
362
|
+
on the command line.
|
363
|
+
|
364
|
+
¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#switch-class-method
|
365
|
+
² See http://disu.se/software/ame-1.0/api/user/Ame/Types/Enumeration/
|
366
|
+
|
367
|
+
option '', 'start-number', 'N', 1,
|
368
|
+
'Start numbering the patches at N instead of 1'
|
369
|
+
|
370
|
+
An “option”¹ is an option that takes an argument. The argument must always
|
371
|
+
be present and may be given, in this case, as “‹--start-number=2›” or
|
372
|
+
“‹--start-number 2›” on the command line. For a short-form option,
|
373
|
+
anything that follows the option is seen as an argument, so assuming that
|
374
|
+
“start-number” also had a short name of ‘S’, “‹-S2›” would be equivalent to
|
375
|
+
“‹-S 2›”, which would be equivalent to “‹--start-number 2›”. Note that
|
376
|
+
“‹-snS2›” would still work as expected.
|
377
|
+
|
378
|
+
¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#option-class-method
|
379
|
+
|
380
|
+
multioption '', 'to', 'ADDRESS', String,
|
381
|
+
'Add a To: header to the email headers'
|
382
|
+
|
383
|
+
A “multioption”¹ is an option that takes an argument and may be repeated
|
384
|
+
any number of times. Each argument will be added to an Array stored in the
|
385
|
+
Hash that maps option names to their values. Instead of taking a default
|
386
|
+
argument, it takes a type for the argument (String, in this case). Again,
|
387
|
+
types are used to inform Ame how to parse command-line arguments into Ruby
|
388
|
+
values.
|
389
|
+
|
390
|
+
¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#multioption-class-method
|
391
|
+
|
392
|
+
optional 'SINCE', 'N/A', 'Generate patches for commits after SINCE'
|
393
|
+
|
394
|
+
An “optional”¹ argument is an argument that isn’t required. If it’s not
|
395
|
+
present on the command line it’ll get its default value (the String
|
396
|
+
‹'N/A'›, in this case).
|
397
|
+
|
398
|
+
¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#optional-class-method
|
399
|
+
|
400
|
+
We’ve now covered all kinds of options and one new kind of argument. There
|
401
|
+
are three more types of argument (one that we’ve already seen and two new)
|
402
|
+
that we’ll look into now: “argument”, “splat”, and “splus”.
|
403
|
+
|
404
|
+
description 'Annotate file lines with commit information'
|
405
|
+
argument 'FILE', String, 'File to annotate'
|
406
|
+
def annotate(file)
|
407
|
+
p file
|
408
|
+
end
|
409
|
+
|
410
|
+
An “argument”¹ is an argument that’s required. If it’s not present on the
|
411
|
+
command line, an error will be raised (and by default reported to the
|
412
|
+
terminal). As it’s required, it doesn’t take a default, but rather a type.
|
413
|
+
|
414
|
+
¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#argument-class-method
|
415
|
+
|
416
|
+
description 'Add file contents to the index'
|
417
|
+
splat 'PATHSPEC', String, 'Files to add content from'
|
418
|
+
def add(paths)
|
419
|
+
p paths
|
420
|
+
end
|
421
|
+
|
422
|
+
A “splat”¹ is an argument that’s not required, but may be given any number
|
423
|
+
of times. The type of a splat is the type of one argument and the type of
|
424
|
+
a splat as a whole is an Array of values of that type.
|
425
|
+
|
426
|
+
¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#splat-class-method
|
427
|
+
|
428
|
+
description 'Display gitattributes information'
|
429
|
+
splus 'PATHNAME', String, 'Files to list attributes of'
|
430
|
+
def check_attr(paths)
|
431
|
+
p paths
|
432
|
+
end
|
433
|
+
|
434
|
+
A “splus”¹ is an argument that’s required, but may also be given any number
|
435
|
+
of times. The type of a splus is the type of one argument and the type of
|
436
|
+
a splus as a whole is an Array of values of that type.
|
437
|
+
|
438
|
+
¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#splus-class-method
|
439
|
+
|
440
|
+
Now that we’ve seen all kinds of options and arguments, let’s look on an
|
441
|
+
additional tool at our disposal, the dispatch¹.
|
442
|
+
|
443
|
+
class Remote < Ame::Class
|
444
|
+
description 'Manage set of remote repositories'
|
445
|
+
def initialize; end
|
446
|
+
|
447
|
+
description 'Shows a list of existing remotes'
|
448
|
+
flag 'v', 'verbose', false, 'Show remote URL after name'
|
449
|
+
def list(options = {})
|
450
|
+
p options
|
451
|
+
end
|
452
|
+
|
453
|
+
description 'Adds a remote named NAME for the repository at URL'
|
454
|
+
argument 'name', String, 'Name of the remote to add'
|
455
|
+
argument 'url', String, 'URL to the repository of the remote to add'
|
456
|
+
def add(name, url)
|
457
|
+
p name, url
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
¹ See http://disu.se/software/ame-1.0/api/user/Ame/Class#dispatch-class-method
|
462
|
+
|
463
|
+
Here we’re defining a child class to Git::CLI::Git called “Remote” that
|
464
|
+
doesn’t introduce anything new. Then we set up the dispatch:
|
465
|
+
|
466
|
+
dispatch Remote, :default => 'list'
|
467
|
+
|
468
|
+
This adds a method called “remote” to Git::CLI::Git that will dispatch
|
469
|
+
processing of the command line to an instance of the Remote class when
|
470
|
+
“‹git remote›” is seen on the command line. The “remote” method expects an
|
471
|
+
argument that’ll be used to decide what sub-command to execute. Here we’ve
|
472
|
+
specified that in the absence of such an argument, the “list” method should
|
473
|
+
be invoked.
|
474
|
+
|
475
|
+
We add the same kind of dispatch to Git under Git::CLI:
|
476
|
+
|
477
|
+
dispatch Git
|
478
|
+
|
479
|
+
and then we’re done. Here’s all the previous code in its entirety:
|
480
|
+
|
481
|
+
module Git end
|
482
|
+
class Git::CLI < Ame::Root
|
483
|
+
version '1.0.0'
|
484
|
+
class Git < Ame::Class
|
485
|
+
description 'The stupid content tracker'
|
486
|
+
def initialize; end
|
487
|
+
|
488
|
+
description 'Prepare patches for e-mail submission'
|
489
|
+
flag ?n, 'numbered', false, 'Name output in [PATCH n/m] format'
|
490
|
+
flag ?N, 'no-numbered', nil,
|
491
|
+
'Name output in [PATCH] format' do |options|
|
492
|
+
options['numbered'] = false
|
493
|
+
end
|
494
|
+
toggle ?s, 'signoff', false,
|
495
|
+
'Add Signed-off-by: line to the commit message'
|
496
|
+
switch '', 'thread', 'STYLE', nil,
|
497
|
+
Ame::Types::Enumeration[:shallow, :deep],
|
498
|
+
'Controls addition of In-Reply-To and References headers'
|
499
|
+
flag '', 'no-thread', nil,
|
500
|
+
'Disables addition of In-Reply-To and Reference headers' do |options, _|
|
501
|
+
options.delete 'thread'
|
502
|
+
end
|
503
|
+
option '', 'start-number', 'N', 1,
|
504
|
+
'Start numbering the patches at N instead of 1'
|
505
|
+
multioption '', 'to', 'ADDRESS', String,
|
506
|
+
'Add a To: header to the email headers'
|
507
|
+
optional 'SINCE', 'N/A', 'Generate patches for commits after SINCE'
|
508
|
+
def format_patch(since = '', options = {})
|
509
|
+
p since, options
|
510
|
+
end
|
511
|
+
|
512
|
+
description 'Annotate file lines with commit information'
|
513
|
+
argument 'FILE', String, 'File to annotate'
|
514
|
+
def annotate(file)
|
515
|
+
p file
|
516
|
+
end
|
517
|
+
|
518
|
+
description 'Add file contents to the index'
|
519
|
+
splat 'PATHSPEC', String, 'Files to add content from'
|
520
|
+
def add(paths)
|
521
|
+
p paths
|
522
|
+
end
|
523
|
+
|
524
|
+
description 'Display gitattributes information'
|
525
|
+
splus 'PATHNAME', String, 'Files to list attributes of'
|
526
|
+
def check_attr(paths)
|
527
|
+
p paths
|
528
|
+
end
|
529
|
+
|
530
|
+
class Remote < Ame::Class
|
531
|
+
description 'Manage set of remote repositories'
|
532
|
+
def initialize; end
|
533
|
+
|
534
|
+
description 'Shows a list of existing remotes'
|
535
|
+
flag 'v', 'verbose', false, 'Show remote URL after name'
|
536
|
+
def list(options = {})
|
537
|
+
p options
|
538
|
+
end
|
539
|
+
|
540
|
+
description 'Adds a remote named NAME for the repository at URL'
|
541
|
+
argument 'name', String, 'Name of the remote to add'
|
542
|
+
argument 'url', String, 'URL to the repository of the remote to add'
|
543
|
+
def add(name, url)
|
544
|
+
p name, url
|
545
|
+
end
|
546
|
+
end
|
547
|
+
dispatch Remote, :default => 'list'
|
548
|
+
end
|
549
|
+
dispatch Git
|
550
|
+
end
|
551
|
+
|
552
|
+
If we put this code in a file called “git” and add ‹#! /usr/bin/ruby -w› at
|
553
|
+
the beginning and ‹Git::CLI.process› at the end, you’ll have a very
|
554
|
+
incomplete git command-line interface on your hands. Let’s look at what
|
555
|
+
some of its ‹--help› output looks like:
|
556
|
+
|
557
|
+
% git --help
|
558
|
+
Usage: git [OPTIONS]... METHOD [ARGUMENTS]...
|
559
|
+
The stupid content tracker
|
560
|
+
|
561
|
+
Arguments:
|
562
|
+
METHOD Method to run
|
563
|
+
[ARGUMENTS]... Arguments to pass to METHOD
|
564
|
+
|
565
|
+
Options:
|
566
|
+
--help Display help for this method
|
567
|
+
--version Display version information
|
568
|
+
|
569
|
+
Methods:
|
570
|
+
add Add file contents to the index
|
571
|
+
annotate Annotate file lines with commit information
|
572
|
+
check-attr Display gitattributes information
|
573
|
+
format-patch Prepare patches for e-mail submission
|
574
|
+
remote Manage set of remote repositories
|
575
|
+
% git format-patch --help
|
576
|
+
Usage: git format-patch [OPTIONS]... [SINCE]
|
577
|
+
Prepare patches for e-mail submission
|
578
|
+
|
579
|
+
Arguments:
|
580
|
+
[SINCE=N/A] Generate patches for commits after SINCE
|
581
|
+
|
582
|
+
Options:
|
583
|
+
-N, --no-numbered Name output in [PATCH] format
|
584
|
+
--help Display help for this method
|
585
|
+
-n, --numbered Name output in [PATCH n/m] format
|
586
|
+
--no-thread Disables addition of In-Reply-To and Reference headers
|
587
|
+
-s, --signoff Add Signed-off-by: line to the commit message
|
588
|
+
--start-number=N Start numbering the patches at N instead of 1
|
589
|
+
--thread[=STYLE] Controls addition of In-Reply-To and References headers
|
590
|
+
--to=ADDRESS* Add a To: header to the email headers
|
591
|
+
% git remote --help
|
592
|
+
Usage: git remote [OPTIONS]... [METHOD] [ARGUMENTS]...
|
593
|
+
Manage set of remote repositories
|
594
|
+
|
595
|
+
Arguments:
|
596
|
+
[METHOD=list] Method to run
|
597
|
+
[ARGUMENTS]... Arguments to pass to METHOD
|
598
|
+
|
599
|
+
Options:
|
600
|
+
--help Display help for this method
|
601
|
+
|
602
|
+
Methods:
|
603
|
+
add Adds a remote named NAME for the repository at URL
|
604
|
+
list Shows a list of existing remotes
|
605
|
+
|
606
|
+
§ API
|
607
|
+
|
608
|
+
The previous section gave an introduction to the whole user API in an
|
609
|
+
informal and introductory way. For an indepth reference to the user API,
|
610
|
+
see the {user API documentation}¹.
|
611
|
+
|
612
|
+
¹ See http://disu.se/software/ame-1.0/api/user/Ame/
|
613
|
+
|
614
|
+
If you want to extend the API or use it in some way other than as a
|
615
|
+
command-line-interface writer, see the {developer API documentation}¹.
|
616
|
+
|
617
|
+
¹ See http://disu.se/software/ame-1.0/api/developer/Ame/
|
618
|
+
|
619
|
+
§ Financing
|
620
|
+
|
621
|
+
Currently, most of my time is spent at my day job and in my rather busy
|
622
|
+
private life. Please motivate me to spend time on this piece of software
|
623
|
+
by donating some of your money to this project. Yeah, I realize that
|
624
|
+
requesting money to develop software is a bit, well, capitalistic of me.
|
625
|
+
But please realize that I live in a capitalistic society and I need money
|
626
|
+
to have other people give me the things that I need to continue living
|
627
|
+
under the rules of said society. So, if you feel that this piece of
|
628
|
+
software has helped you out enough to warrant a reward, please PayPal a
|
629
|
+
donation to now@disu.se¹. Thanks! Your support won’t go unnoticed!
|
630
|
+
|
631
|
+
¹ Send a donation:
|
632
|
+
https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=now@disu.se&item_name=Ame
|
633
|
+
|
634
|
+
§ Reporting Bugs
|
635
|
+
|
636
|
+
Please report any bugs that you encounter to the {issue tracker}¹.
|
637
|
+
|
638
|
+
¹ See https://github.com/now/ame/issues
|
639
|
+
|
640
|
+
§ Authors
|
48
641
|
|
642
|
+
Nikolai Weibull wrote the code, the tests, the documentation, and this
|
643
|
+
README.
|
49
644
|
|
50
|
-
|
645
|
+
§ Licensing
|
51
646
|
|
52
|
-
|
647
|
+
Ame is free software: you may redistribute it and/or modify it under the
|
648
|
+
terms of the {GNU Lesser General Public License, version 3}¹ or later², as
|
649
|
+
published by the {Free Software Foundation}³.
|
53
650
|
|
54
|
-
|
55
|
-
|
651
|
+
¹ See http://disu.se/licenses/lgpl-3.0/
|
652
|
+
² See http://gnu.org/licenses/
|
653
|
+
³ See http://fsf.org/
|
654
|
+
email:
|
655
|
+
- now@disu.se
|
56
656
|
executables: []
|
57
657
|
extensions: []
|
58
658
|
extra_rdoc_files: []
|
59
659
|
files:
|
60
|
-
- lib/ame/argument.rb
|
61
|
-
- lib/ame/arguments.rb
|
62
|
-
- lib/ame/
|
63
|
-
- lib/ame/
|
64
|
-
- lib/ame/
|
65
|
-
- lib/ame/
|
66
|
-
- lib/ame/
|
67
|
-
- lib/ame/
|
68
|
-
- lib/ame/
|
69
|
-
- lib/ame/
|
70
|
-
- lib/ame/
|
71
|
-
- lib/ame/
|
72
|
-
- lib/ame/
|
73
|
-
- lib/ame/
|
74
|
-
- lib/ame/
|
75
|
-
- lib/ame/
|
76
|
-
- lib/ame/
|
77
|
-
- lib/ame.rb
|
78
|
-
-
|
79
|
-
-
|
80
|
-
-
|
81
|
-
-
|
82
|
-
-
|
83
|
-
-
|
84
|
-
-
|
85
|
-
-
|
86
|
-
-
|
87
|
-
-
|
88
|
-
-
|
89
|
-
-
|
90
|
-
-
|
660
|
+
- lib/ame-1.0/argument.rb
|
661
|
+
- lib/ame-1.0/arguments.rb
|
662
|
+
- lib/ame-1.0/arguments/undefined.rb
|
663
|
+
- lib/ame-1.0/arguments/optional.rb
|
664
|
+
- lib/ame-1.0/arguments/complete.rb
|
665
|
+
- lib/ame-1.0/class.rb
|
666
|
+
- lib/ame-1.0/flag.rb
|
667
|
+
- lib/ame-1.0/help.rb
|
668
|
+
- lib/ame-1.0/help/terminal.rb
|
669
|
+
- lib/ame-1.0/help/delegate.rb
|
670
|
+
- lib/ame-1.0/method.rb
|
671
|
+
- lib/ame-1.0/method/undefined.rb
|
672
|
+
- lib/ame-1.0/methods.rb
|
673
|
+
- lib/ame-1.0/switch.rb
|
674
|
+
- lib/ame-1.0/option.rb
|
675
|
+
- lib/ame-1.0/multioption.rb
|
676
|
+
- lib/ame-1.0/optional.rb
|
677
|
+
- lib/ame-1.0/options.rb
|
678
|
+
- lib/ame-1.0/options/undefined.rb
|
679
|
+
- lib/ame-1.0/root.rb
|
680
|
+
- lib/ame-1.0/splus.rb
|
681
|
+
- lib/ame-1.0/splat.rb
|
682
|
+
- lib/ame-1.0/types.rb
|
683
|
+
- lib/ame-1.0/types/boolean.rb
|
684
|
+
- lib/ame-1.0/types/enumeration.rb
|
685
|
+
- lib/ame-1.0/types/float.rb
|
686
|
+
- lib/ame-1.0/types/integer.rb
|
687
|
+
- lib/ame-1.0/types/string.rb
|
688
|
+
- lib/ame-1.0/types/symbol.rb
|
689
|
+
- lib/ame-1.0.rb
|
690
|
+
- lib/ame-1.0/version.rb
|
691
|
+
- test/unit/ame-1.0/argument.rb
|
692
|
+
- test/unit/ame-1.0/arguments.rb
|
693
|
+
- test/unit/ame-1.0/arguments/undefined.rb
|
694
|
+
- test/unit/ame-1.0/arguments/optional.rb
|
695
|
+
- test/unit/ame-1.0/arguments/complete.rb
|
696
|
+
- test/unit/ame-1.0/class.rb
|
697
|
+
- test/unit/ame-1.0/flag.rb
|
698
|
+
- test/unit/ame-1.0/help.rb
|
699
|
+
- test/unit/ame-1.0/help/terminal.rb
|
700
|
+
- test/unit/ame-1.0/help/delegate.rb
|
701
|
+
- test/unit/ame-1.0/method.rb
|
702
|
+
- test/unit/ame-1.0/method/undefined.rb
|
703
|
+
- test/unit/ame-1.0/methods.rb
|
704
|
+
- test/unit/ame-1.0/switch.rb
|
705
|
+
- test/unit/ame-1.0/option.rb
|
706
|
+
- test/unit/ame-1.0/multioption.rb
|
707
|
+
- test/unit/ame-1.0/optional.rb
|
708
|
+
- test/unit/ame-1.0/options.rb
|
709
|
+
- test/unit/ame-1.0/options/undefined.rb
|
710
|
+
- test/unit/ame-1.0/root.rb
|
711
|
+
- test/unit/ame-1.0/splus.rb
|
712
|
+
- test/unit/ame-1.0/splat.rb
|
713
|
+
- test/unit/ame-1.0/types.rb
|
714
|
+
- test/unit/ame-1.0/types/boolean.rb
|
715
|
+
- test/unit/ame-1.0/types/enumeration.rb
|
716
|
+
- test/unit/ame-1.0/types/float.rb
|
717
|
+
- test/unit/ame-1.0/types/integer.rb
|
718
|
+
- test/unit/ame-1.0/types/string.rb
|
719
|
+
- test/unit/ame-1.0/types/symbol.rb
|
720
|
+
- test/unit/ame-1.0.rb
|
721
|
+
- test/unit/ame-1.0/version.rb
|
91
722
|
- README
|
92
723
|
- Rakefile
|
93
|
-
homepage: http://
|
94
|
-
licenses:
|
724
|
+
homepage: http://disu.se/software/ame-1.0/
|
725
|
+
licenses:
|
726
|
+
- LGPLv3+
|
95
727
|
metadata: {}
|
96
728
|
post_install_message:
|
97
729
|
rdoc_options: []
|
98
730
|
require_paths:
|
99
731
|
- lib
|
100
732
|
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
-
none: false
|
102
733
|
requirements:
|
103
|
-
- -
|
734
|
+
- - '>='
|
104
735
|
- !ruby/object:Gem::Version
|
105
736
|
version: '0'
|
106
737
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
-
none: false
|
108
738
|
requirements:
|
109
|
-
- -
|
739
|
+
- - '>='
|
110
740
|
- !ruby/object:Gem::Version
|
111
741
|
version: '0'
|
112
742
|
requirements: []
|
113
743
|
rubyforge_project:
|
114
|
-
rubygems_version:
|
744
|
+
rubygems_version: 2.0.14
|
115
745
|
signing_key:
|
116
746
|
specification_version: 4
|
117
|
-
summary: Ame
|
747
|
+
summary: Ame provides a simple command-line interface API for Ruby¹.
|
118
748
|
test_files: []
|