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.
Files changed (90) hide show
  1. checksums.yaml +7 -0
  2. data/README +541 -3
  3. data/Rakefile +15 -6
  4. data/lib/ame-1.0.rb +31 -0
  5. data/lib/ame-1.0/argument.rb +63 -0
  6. data/lib/ame-1.0/arguments.rb +44 -0
  7. data/lib/ame-1.0/arguments/complete.rb +37 -0
  8. data/lib/ame-1.0/arguments/optional.rb +34 -0
  9. data/lib/ame-1.0/arguments/undefined.rb +71 -0
  10. data/lib/ame-1.0/class.rb +436 -0
  11. data/lib/ame-1.0/flag.rb +101 -0
  12. data/lib/{ame → ame-1.0}/help.rb +1 -1
  13. data/lib/ame-1.0/help/delegate.rb +19 -0
  14. data/lib/ame-1.0/help/terminal.rb +132 -0
  15. data/lib/ame-1.0/method.rb +75 -0
  16. data/lib/ame-1.0/method/undefined.rb +184 -0
  17. data/lib/ame-1.0/methods.rb +40 -0
  18. data/lib/ame-1.0/multioption.rb +36 -0
  19. data/lib/ame-1.0/option.rb +37 -0
  20. data/lib/ame-1.0/optional.rb +31 -0
  21. data/lib/ame-1.0/options.rb +68 -0
  22. data/lib/ame-1.0/options/undefined.rb +114 -0
  23. data/lib/ame-1.0/root.rb +174 -0
  24. data/lib/ame-1.0/splat.rb +16 -0
  25. data/lib/ame-1.0/splus.rb +22 -0
  26. data/lib/ame-1.0/switch.rb +39 -0
  27. data/lib/ame-1.0/types.rb +60 -0
  28. data/lib/ame-1.0/types/boolean.rb +13 -0
  29. data/lib/ame-1.0/types/enumeration.rb +40 -0
  30. data/lib/ame-1.0/types/float.rb +11 -0
  31. data/lib/{ame → ame-1.0}/types/integer.rb +3 -3
  32. data/lib/{ame → ame-1.0}/types/string.rb +2 -2
  33. data/lib/ame-1.0/types/symbol.rb +9 -0
  34. data/lib/ame-1.0/version.rb +62 -0
  35. data/test/unit/ame-1.0.rb +4 -0
  36. data/test/unit/ame-1.0/argument.rb +46 -0
  37. data/test/unit/ame-1.0/arguments.rb +63 -0
  38. data/test/unit/ame-1.0/arguments/complete.rb +4 -0
  39. data/test/unit/ame-1.0/arguments/optional.rb +4 -0
  40. data/test/unit/ame-1.0/arguments/undefined.rb +63 -0
  41. data/test/unit/ame-1.0/class.rb +4 -0
  42. data/test/unit/ame-1.0/flag.rb +31 -0
  43. data/test/unit/ame-1.0/help.rb +4 -0
  44. data/test/unit/ame-1.0/help/delegate.rb +4 -0
  45. data/test/unit/{ame/help/console.rb → ame-1.0/help/terminal.rb} +34 -23
  46. data/test/unit/ame-1.0/method.rb +4 -0
  47. data/test/unit/ame-1.0/method/undefined.rb +33 -0
  48. data/test/unit/ame-1.0/methods.rb +9 -0
  49. data/test/unit/ame-1.0/multioption.rb +4 -0
  50. data/test/unit/ame-1.0/option.rb +11 -0
  51. data/test/unit/ame-1.0/optional.rb +9 -0
  52. data/test/unit/ame-1.0/options.rb +149 -0
  53. data/test/unit/ame-1.0/options/undefined.rb +33 -0
  54. data/test/unit/ame-1.0/root.rb +4 -0
  55. data/test/unit/ame-1.0/splat.rb +9 -0
  56. data/test/unit/ame-1.0/splus.rb +4 -0
  57. data/test/unit/ame-1.0/switch.rb +15 -0
  58. data/test/unit/ame-1.0/types.rb +4 -0
  59. data/test/{ame → unit/ame-1.0}/types/boolean.rb +0 -0
  60. data/test/unit/ame-1.0/types/enumeration.rb +4 -0
  61. data/test/unit/ame-1.0/types/float.rb +7 -0
  62. data/test/{ame → unit/ame-1.0}/types/integer.rb +0 -0
  63. data/test/{ame → unit/ame-1.0}/types/string.rb +0 -0
  64. data/test/unit/ame-1.0/types/symbol.rb +5 -0
  65. data/test/unit/ame-1.0/version.rb +4 -0
  66. metadata +690 -60
  67. data/lib/ame.rb +0 -26
  68. data/lib/ame/argument.rb +0 -56
  69. data/lib/ame/arguments.rb +0 -65
  70. data/lib/ame/class.rb +0 -117
  71. data/lib/ame/help/console.rb +0 -96
  72. data/lib/ame/method.rb +0 -94
  73. data/lib/ame/methods.rb +0 -30
  74. data/lib/ame/option.rb +0 -50
  75. data/lib/ame/options.rb +0 -102
  76. data/lib/ame/root.rb +0 -57
  77. data/lib/ame/splat.rb +0 -12
  78. data/lib/ame/types.rb +0 -29
  79. data/lib/ame/types/array.rb +0 -16
  80. data/lib/ame/types/boolean.rb +0 -16
  81. data/lib/ame/version.rb +0 -5
  82. data/test/ame/types/array.rb +0 -13
  83. data/test/unit/ame/argument.rb +0 -66
  84. data/test/unit/ame/arguments.rb +0 -106
  85. data/test/unit/ame/method.rb +0 -40
  86. data/test/unit/ame/methods.rb +0 -10
  87. data/test/unit/ame/option.rb +0 -75
  88. data/test/unit/ame/options.rb +0 -136
  89. data/test/unit/ame/root.rb +0 -15
  90. data/test/unit/ame/splat.rb +0 -11
@@ -0,0 +1,4 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ Expectations do
4
+ end
@@ -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
@@ -0,0 +1,4 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ Expectations do
4
+ end
@@ -0,0 +1,4 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ Expectations do
4
+ end
@@ -0,0 +1,7 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ Expectations do
4
+ expect 0.1 do Ame::Types::Float.parse('0.1') end
5
+ expect Ame::MalformedArgument do Ame::Types::Float.parse('') end
6
+ expect Ame::MalformedArgument do Ame::Types::Float.parse('junk') end
7
+ end
@@ -0,0 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ Expectations do
4
+ expect :'junk' do Ame::Types::Symbol.parse('junk') end
5
+ end
@@ -0,0 +1,4 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ Expectations do
4
+ end
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.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: 2011-10-25 00:00:00.000000000 Z
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: &14761848 !ruby/object:Gem::Requirement
17
- none: false
57
+ requirement: !ruby/object:Gem::Requirement
18
58
  requirements:
19
59
  - - ~>
20
60
  - !ruby/object:Gem::Version
21
- version: '2.0'
61
+ version: '3.0'
22
62
  type: :development
23
63
  prerelease: false
24
- version_requirements: *14761848
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: rbtags
27
- requirement: &14761368 !ruby/object:Gem::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: 0.1.0
75
+ version: '3.1'
33
76
  type: :development
34
77
  prerelease: false
35
- version_requirements: *14761368
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: &14760576 !ruby/object:Gem::Requirement
39
- none: false
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: 0.6.0
103
+ version: '1.2'
44
104
  type: :development
45
105
  prerelease: false
46
- version_requirements: *14760576
47
- description: ! '# Ame #
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
- Ame is a simple command-line parser and build system. Its aim is to replace
645
+ § Licensing
51
646
 
52
- the need for other command-line parsers and Rake.
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
- email: now@bitwi.se
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/class.rb
63
- - lib/ame/help/console.rb
64
- - lib/ame/help.rb
65
- - lib/ame/method.rb
66
- - lib/ame/methods.rb
67
- - lib/ame/option.rb
68
- - lib/ame/options.rb
69
- - lib/ame/root.rb
70
- - lib/ame/splat.rb
71
- - lib/ame/types/array.rb
72
- - lib/ame/types/boolean.rb
73
- - lib/ame/types/integer.rb
74
- - lib/ame/types/string.rb
75
- - lib/ame/types.rb
76
- - lib/ame/version.rb
77
- - lib/ame.rb
78
- - test/ame/types/array.rb
79
- - test/ame/types/boolean.rb
80
- - test/ame/types/integer.rb
81
- - test/ame/types/string.rb
82
- - test/unit/ame/argument.rb
83
- - test/unit/ame/arguments.rb
84
- - test/unit/ame/help/console.rb
85
- - test/unit/ame/method.rb
86
- - test/unit/ame/methods.rb
87
- - test/unit/ame/option.rb
88
- - test/unit/ame/options.rb
89
- - test/unit/ame/root.rb
90
- - test/unit/ame/splat.rb
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://github.com/now/ame
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: 1.8.10
744
+ rubygems_version: 2.0.14
115
745
  signing_key:
116
746
  specification_version: 4
117
- summary: Ame is a simple command-line parser and build system.
747
+ summary: Ame provides a simple command-line interface API for Ruby¹.
118
748
  test_files: []