executable 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/DEMO.md DELETED
@@ -1,568 +0,0 @@
1
- = Executable
2
-
3
- Require Executable library.
4
-
5
- require 'executable'
6
-
7
-
8
- == No Subcommmands
9
-
10
- This example demonstrates using Executable::Command to create a simple command line
11
- interface without subcommands. (Note the Executable mixin could be used just
12
- as well).
13
-
14
- class NoSubCommandCLI < Executable::Command
15
-
16
- attr :result
17
-
18
- def o?
19
- @o
20
- end
21
-
22
- def o=(flag)
23
- @o = flag
24
- end
25
-
26
- def call
27
- if o?
28
- @result = "with"
29
- else
30
- @result = "without"
31
- end
32
- end
33
-
34
- end
35
-
36
- Execute the CLI on an example command line.
37
-
38
- cli = NoSubCommandCLI.run('')
39
- cli.result.assert == 'without'
40
-
41
- Execute the CLI on an example command line.
42
-
43
- cli = NoSubCommandCLI.run('-o')
44
- cli.result.assert == 'with'
45
-
46
- There are two important things to notices heres. Frist, that #main is being
47
- called in each case. It is the method called with no other subcommands are
48
- defined. And second, the fact the a `o?` method is defined to compliment the
49
- `o=` writer, informs Executable that `-o` is an option _flag_, not taking
50
- any parameters.
51
-
52
-
53
- == Multiple Subcommmands
54
-
55
- Setup an example CLI subclass.
56
-
57
- class MyCLI < Executable::Command
58
- attr :result
59
-
60
- def initialize
61
- @result = []
62
- end
63
-
64
- def g=(value)
65
- @result << "g" if value
66
- end
67
-
68
- def g?
69
- @result.include?("g")
70
- end
71
-
72
- #
73
- class C1 < self
74
- def call
75
- @result << "c1"
76
- end
77
-
78
- def o1=(value)
79
- @result << "c1_o1 #{value}"
80
- end
81
-
82
- def o2=(value)
83
- @result << "c1_o2 #{value}"
84
- end
85
- end
86
-
87
- #
88
- class C2 < Executable::Command
89
- attr :result
90
-
91
- def initialize
92
- @result = []
93
- end
94
-
95
- def call
96
- @result << "c2"
97
- end
98
-
99
- def o1=(value)
100
- @result << "c2_o1 #{value}"
101
- end
102
-
103
- def o2=(value)
104
- @result << "c2_o2" if value
105
- end
106
-
107
- def o2?
108
- @result.include?("c2_o2")
109
- end
110
- end
111
-
112
- end
113
-
114
- Instantiate and run the class on an example command line.
115
-
116
- Just a command.
117
-
118
- cli = MyCLI.run('c1')
119
- cli.result.assert == ['c1']
120
-
121
- Command with global option.
122
-
123
- cli = MyCLI.run('c1 -g')
124
- cli.result.assert == ['g', 'c1']
125
-
126
- Command with an option.
127
-
128
- cli = MyCLI.run('c1 --o1 A')
129
- cli.result.assert == ['c1_o1 A', 'c1']
130
-
131
- Command with two options.
132
-
133
- cli = MyCLI.run('c1 --o1 A --o2 B')
134
- cli.result.assert == ['c1_o1 A', 'c1_o2 B', 'c1']
135
-
136
- Try out the second command.
137
-
138
- cli = MyCLI.run('c2')
139
- cli.result.assert == ['c2']
140
-
141
- Seoncd command with an option.
142
-
143
- cli = MyCLI.run('c2 --o1 A')
144
- cli.result.assert == ['c2_o1 A', 'c2']
145
-
146
- Second command with two options.
147
-
148
- cli = MyCLI.run('c2 --o1 A --o2')
149
- cli.result.assert == ['c2_o1 A', 'c2_o2', 'c2']
150
-
151
- Since C1#main takes not arguments, if we try to issue a command
152
- that will have left over arguments, then an ArgumentError will be raised.
153
-
154
- expect ArgumentError do
155
- cli = MyCLI.run('c1 a')
156
- end
157
-
158
- How about a non-existenct subcommand.
159
-
160
- expect NotImplementedError do
161
- cli = MyCLI.run('q')
162
- cli.result.assert == ['q']
163
- end
164
-
165
- How about an option only.
166
-
167
- expect NotImplementedError do
168
- cli = MyCLI.run('-g')
169
- cli.result.assert == ['-g']
170
- end
171
-
172
- How about a non-existant options.
173
-
174
- expect Executable::NoOptionError do
175
- MyCLI.run('c1 --foo')
176
- end
177
-
178
-
179
- == Command Help
180
-
181
- Executable Commands can generate help output. It does this by extracting
182
- the commenst associated with the option methods. A description of the
183
- command itself is taken from the comment on the `#call` method. Only
184
- the first line of a comment is used, so the reset of the comment can
185
- still be catered to documention tools such as YARD and RDoc.
186
-
187
- Let's setup an example CLI subclass to demonstrate this.
188
-
189
- class MyCLI < Executable::Command
190
-
191
- # This is global option -g.
192
- # Yadda yadda yadda...
193
- def g=(bool)
194
- @g = bool
195
- end
196
-
197
- def g?; @g; end
198
-
199
- # Subcommand `c1`.
200
- class C1 < self
201
-
202
- # This does c1.
203
- def call(*args)
204
- end
205
-
206
- # This is option --o1 for c1.
207
- def o1=(value)
208
- end
209
-
210
- # This is option --o2 for c1.
211
- def o2=(value)
212
- end
213
-
214
- end
215
-
216
- # Subcommand `c2`.
217
- class C2 < self
218
-
219
- # This does c2.
220
- def call(*args)
221
- end
222
-
223
- # This is option --o1 for c2.
224
- def o1=(value)
225
- end
226
-
227
- # This is option --o2 for c2.
228
- def o2=(value)
229
- end
230
-
231
- end
232
-
233
- end
234
-
235
- === Plain Text
236
-
237
- The help output,
238
-
239
- @out = MyCLI::C1.help.to_s
240
-
241
- should be clearly laid out as follows:
242
-
243
- Usage: mycli-c1 [options...] [subcommand]
244
-
245
- This does c1.
246
-
247
- OPTIONS
248
- -g This is global option -g.
249
- --o1=VALUE This is option --o1 for c1.
250
- --o2=VALUE This is option --o2 for c1.
251
-
252
- Copyright (c) 2012
253
-
254
- === Markdown
255
-
256
- The help feature can also output ronn-style markdown,
257
-
258
- @out = MyCLI::C1.help.markdown
259
-
260
- should be clearly laid out as follows:
261
-
262
- mycli-c1(1) - This does c1.
263
- ===========================
264
-
265
- ## SYNOPSIS
266
-
267
- `mycli-c1` [options...] [subcommand]
268
-
269
- ## DESCRIPTION
270
-
271
- This does c1.
272
-
273
- ## OPTIONS
274
-
275
- * `-g`:
276
- This is global option -g.
277
-
278
- * `--o1=VALUE`:
279
- This is option --o1 for c1.
280
-
281
- * `--o2=VALUE`:
282
- This is option --o2 for c1.
283
-
284
- ## COPYRIGHT
285
-
286
- Copyright (c) 2012
287
-
288
-
289
- == Manpage
290
-
291
- If a man page is available for a given command using the #show_help
292
- method will automatically find the manpage and display it.
293
-
294
- sample = File.dirname(__FILE__) + '/samples'
295
-
296
- load(sample + '/bin/hello')
297
-
298
- manpage = Hello.cli.manpage
299
-
300
- manpage.assert == sample + '/man/hello.1'
301
-
302
-
303
-
304
- = Subclass Example
305
-
306
- Lets say we have a class that we would like to work with on
307
- the command line, but want to keep the class itself unchanaged
308
- without mixin.
309
-
310
- class Hello
311
- attr_accessor :name
312
-
313
- def initialize(name="World")
314
- @name = name
315
- end
316
-
317
- def hello
318
- @output = "Hello, #{name}!"
319
- end
320
-
321
- def output
322
- @output
323
- end
324
- end
325
-
326
- Rather then including Exectuable in the class directly, we can
327
- create a subclass and use it instead.
328
-
329
- class HelloCommand < Hello
330
- include Executable
331
-
332
- def call(*args)
333
- hello
334
- end
335
- end
336
-
337
- Now we can execute the command perfectly well.
338
-
339
- cmd = HelloCommand.execute(['hello', '--name=Fred'])
340
- cmd.output.assert == "Hello, Fred!"
341
-
342
- And the original class remains undisturbed.
343
-
344
-
345
- = README Example
346
-
347
- This is the example used in the documentation.
348
-
349
- class Example
350
- include Executable
351
-
352
- attr_switch :quiet
353
-
354
- def bread(*args)
355
- ["bread", quiet?, *args]
356
- end
357
-
358
- def butter(*args)
359
- ["butter", quiet?, *args]
360
- end
361
-
362
- # Route call to methods.
363
- def call(name, *args)
364
- meth = public_method(name)
365
- meth.call(*args)
366
- end
367
- end
368
-
369
- Use a subcommand and an argument.
370
-
371
- c, a = Example.parse(['butter', 'yum'])
372
- r = c.call(*a)
373
- r.assert == ["butter", nil, "yum"]
374
-
375
- A subcommand and a boolean option.
376
-
377
- c, a = Example.parse(['bread', '--quiet'])
378
- r = c.call(*a)
379
- r.assert == ["bread", true]
380
-
381
-
382
- == Legacy/Dispath
383
-
384
- The Dispatch mixin, which is also called Legacy b/c this is how older
385
- version of Executable worked, provides Executable with a `#call` method
386
- that automatically routes the to a method given by the first argument.
387
-
388
- class DispatchExample < Executable::Command
389
- include Legacy
390
-
391
- attr :result
392
-
393
- def foo
394
- @result = :foo
395
- end
396
-
397
- def bar
398
- @result = :bar
399
- end
400
-
401
- end
402
-
403
- Now when we invoke the command, the
404
-
405
- eg = DispatchExample.run('foo')
406
- eg.result.assert == :foo
407
-
408
- eg = DispatchExample.run('bar')
409
- eg.result.assert == :bar
410
-
411
-
412
- == OptionParser Example
413
-
414
- This example mimics the one given in optparse.rb documentation.
415
-
416
- require 'ostruct'
417
- require 'time'
418
-
419
- class ExampleCLI < Executable::Command
420
-
421
- CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary]
422
- CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" }
423
-
424
- attr :options
425
-
426
- def initialize
427
- super
428
- reset
429
- end
430
-
431
- def reset
432
- @options = OpenStruct.new
433
- @options.library = []
434
- @options.inplace = false
435
- @options.encoding = "utf8"
436
- @options.transfer_type = :auto
437
- @options.verbose = false
438
- end
439
-
440
- # Require the LIBRARY before executing your script
441
- def require=(lib)
442
- options.library << lib
443
- end
444
- alias :r= :require=
445
-
446
- # Edit ARGV files in place (make backup if EXTENSION supplied)
447
- def inplace=(ext)
448
- options.inplace = true
449
- options.extension = ext
450
- options.extension.sub!(/\A\.?(?=.)/, ".") # ensure extension begins with dot.
451
- end
452
- alias :i= :inplace=
453
-
454
- # Delay N seconds before executing
455
- # Cast 'delay' argument to a Float.
456
- def delay=(n)
457
- options.delay = n.to_float
458
- end
459
-
460
- # Begin execution at given time
461
- # Cast 'time' argument to a Time object.
462
- def time=(time)
463
- options.time = Time.parse(time)
464
- end
465
- alias :t= :time=
466
-
467
- # Specify record separator (default \\0)
468
- # Cast to octal integer.
469
- def irs=(octal)
470
- options.record_separator = octal.to_i(8)
471
- end
472
- alias :F= :irs=
473
-
474
- # Example 'list' of arguments
475
- # List of arguments.
476
- def list=(args)
477
- options.list = list.split(',')
478
- end
479
-
480
- # Keyword completion. We are specifying a specific set of arguments (CODES
481
- # and CODE_ALIASES - notice the latter is a Hash), and the user may provide
482
- # the shortest unambiguous text.
483
- CODE_LIST = (CODE_ALIASES.keys + CODES)
484
-
485
- help.option(:code, "Select encoding (#{CODE_LIST})")
486
-
487
- # Select encoding
488
- def code=(code)
489
- codes = CODE_LIST.select{ |x| /^#{code}/ =~ x }
490
- codes = codes.map{ |x| CODE_ALIASES.key?(x) ? CODE_ALIASES[x] : x }.uniq
491
- raise ArgumentError unless codes.size == 1
492
- options.encoding = codes.first
493
- end
494
-
495
- # Select transfer type (text, binary, auto)
496
- # Optional argument with keyword completion.
497
- def type=(type)
498
- raise ArgumentError unless %w{text binary auto}.include(type.downcase)
499
- options.transfer_type = type.downcase
500
- end
501
-
502
- # Run verbosely
503
- # Boolean switch.
504
- def verbose=(bool)
505
- options.verbose = bool
506
- end
507
- def verbose?
508
- @options.verbose
509
- end
510
- alias :v= :verbose=
511
- alias :v? :verbose?
512
-
513
- # Show this message
514
- # No argument, shows at tail. This will print an options summary.
515
- def help!
516
- puts help_text
517
- exit
518
- end
519
- alias :h! :help!
520
-
521
- # Show version
522
- # Another typical switch to print the version.
523
- def version?
524
- puts Executor::VERSION
525
- exit
526
- end
527
-
528
- #
529
- def call
530
- # ... main procedure here ...
531
- end
532
- end
533
-
534
- We will run some scenarios on this example to make sure it works.
535
-
536
- cli = ExampleCLI.execute('-r=facets')
537
- cli.options.library.assert == ['facets']
538
-
539
- Make sure time option parses.
540
-
541
- cli = ExampleCLI.execute('--time=2010-10-10')
542
- cli.options.time.assert == Time.parse('2010-10-10')
543
-
544
- Make sure code lookup words and is limted to the selections provided.
545
-
546
- cli = ExampleCLI.execute('--code=ji')
547
- cli.options.encoding.assert == 'iso-2022-jp'
548
-
549
- expect ArgumentError do
550
- ExampleCLI.execute('--code=xxx')
551
- end
552
-
553
- Ensure +irs+ is set to an octal number.
554
-
555
- cli = ExampleCLI.execute('-F 32')
556
- cli.options.record_separator.assert == 032
557
-
558
- Ensure extension begins with dot and inplace is set to true.
559
-
560
- cli = ExampleCLI.execute('--inplace txt')
561
- cli.options.extension.assert == '.txt'
562
- cli.options.inplace.assert == true
563
-
564
-
565
-
566
-
567
-
568
-
data/lib/executable.yml DELETED
@@ -1,71 +0,0 @@
1
- ---
2
- type: ruby
3
- revision: 2013
4
- sources:
5
- - var
6
- authors:
7
- - name: 7rans
8
- email: transfire@gmail.com
9
- organizations: []
10
- requirements:
11
- - groups:
12
- - test
13
- development: true
14
- name: qed
15
- - groups:
16
- - test
17
- development: true
18
- name: ae
19
- - groups:
20
- - build
21
- development: true
22
- name: detroit
23
- - groups:
24
- - build
25
- development: true
26
- name: simplecov
27
- conflicts: []
28
- alternatives: []
29
- resources:
30
- - type: home
31
- uri: http://rubyworks.github.com/executable
32
- label: Homepage
33
- - type: code
34
- uri: http://github.com/rubyworks/executable
35
- label: Source Code
36
- - type: bugs
37
- uri: http://github.com/rubyworks/executable/issues
38
- label: Issue Tracker
39
- - type: mail
40
- uri: http://groups.google.com/rubyworks-mailinglist
41
- label: Mailing List
42
- - type: chat
43
- uri: irc://chat.us.freenode.net#rubyworks
44
- label: IRC Channel
45
- repositories:
46
- - name: upstream
47
- scm: git
48
- uri: git://github.com/rubyworks/executable.git
49
- categories: []
50
- paths:
51
- load:
52
- - lib
53
- copyrights:
54
- - holder: Rubyworks
55
- year: '2008'
56
- license: BSD-2-Clause
57
- created: '2008-08-08'
58
- summary: Commandline Object Mapper
59
- version: 1.2.1
60
- name: executable
61
- title: Executable
62
- description: ! 'Think of Executable as a *COM*, a Commandline Object Mapper,
63
-
64
- in much the same way that ActiveRecord is an ORM,
65
-
66
- an Object Relational Mapper. A class utilizing Executable
67
-
68
- can define a complete command line tool using nothing more
69
-
70
- than Ruby''s own method definitions.'
71
- date: '2012-12-18'
@@ -1,59 +0,0 @@
1
- $:.unshift(File.dirname(__FILE__)+'/../lib')
2
-
3
- require 'microtest'
4
- require 'ae'
5
-
6
- require 'executable'
7
-
8
- class ExecutableTestCase < MicroTest::TestCase
9
-
10
- class MyCommand
11
- include Executable
12
-
13
- attr_reader :size, :quiet, :file
14
-
15
- def initialize
16
- @file = 'hey.txt' # default
17
- end
18
-
19
- def quiet=(bool)
20
- @quiet = bool
21
- end
22
-
23
- def quiet?
24
- @quiet
25
- end
26
-
27
- def size=(integer)
28
- @size = integer.to_i
29
- end
30
-
31
- def file=(fname)
32
- @file = fname
33
- end
34
-
35
- def call(*args)
36
- @args = args
37
- end
38
- end
39
-
40
- def test_boolean_optiion
41
- mc = MyCommand.execute('--quiet')
42
- mc.assert.quiet?
43
- end
44
-
45
- def test_integer_optiion
46
- mc = MyCommand.execute('--size=4')
47
- mc.size.assert == 4
48
- end
49
-
50
- def test_default_value
51
- mc = MyCommand.execute('')
52
- mc.file.assert == 'hey.txt'
53
- end
54
-
55
- #def usage_output
56
- # MyCommand.help.usage.assert == "{$0} [options] [subcommand]"
57
- #end
58
-
59
- end