command-set 0.9.0 → 0.9.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.
- data/doc/argumentDSL +0 -2
- data/lib/command-set/arguments.rb +115 -101
- data/lib/command-set/command-common.rb +3 -2
- data/lib/command-set/command.rb +0 -16
- data/lib/command-set/dsl.rb +4 -2
- data/lib/command-set/results.rb +0 -7
- data/lib/command-set/text-interpreter.rb +11 -4
- metadata +3 -3
data/doc/argumentDSL
CHANGED
@@ -16,10 +16,8 @@ Decorator methods, and the classes they add:
|
|
16
16
|
|
17
17
|
+repeating+:: Repeating
|
18
18
|
+many+:: Repeating
|
19
|
-
+multi+:: AlternatingArgument
|
20
19
|
+named+:: Named
|
21
20
|
+optional+:: Optional
|
22
|
-
+alternating+:: AlternatingArgument
|
23
21
|
|
24
22
|
The shorthand argument methods are:
|
25
23
|
|
@@ -39,7 +39,7 @@ module Command
|
|
39
39
|
#The completion should be an array of completion options. If the completions have a common
|
40
40
|
#prefix, completion will enter it for the user. As a clever trick for providing hints:
|
41
41
|
# [ "This is a hint", "" ]
|
42
|
-
def complete(prefix, subject)
|
42
|
+
def complete(original_terms, prefix, subject)
|
43
43
|
raise NotImplementedError, "complete not implemented in #{self.class.name}"
|
44
44
|
end
|
45
45
|
|
@@ -60,11 +60,11 @@ module Command
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def consume_hash(subject, hash)
|
63
|
-
unless((term = hash[
|
63
|
+
unless((term = hash[name]).nil?)
|
64
64
|
if validate(term, subject)
|
65
|
-
return {
|
65
|
+
return {name => parse(subject, term)}
|
66
66
|
else
|
67
|
-
raise ArgumentInvalidException, {
|
67
|
+
raise ArgumentInvalidException, {name => term}
|
68
68
|
end
|
69
69
|
end
|
70
70
|
return {}
|
@@ -110,41 +110,46 @@ module Command
|
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
113
|
-
class ArgumentDecorator
|
113
|
+
class ArgumentDecorator
|
114
114
|
include DSL::Argument
|
115
115
|
|
116
|
-
def
|
117
|
-
|
116
|
+
def initialize(wrapped_by, wrap_with, &block)
|
117
|
+
@wrapped_by = wrapped_by
|
118
|
+
@wrap_with = wrap_with
|
118
119
|
end
|
119
120
|
|
120
|
-
|
121
|
-
|
121
|
+
def embed_argument(arg)
|
122
|
+
@wrapped_by.embed_argument(@wrap_with.new(@wrapped_with, arg))
|
122
123
|
end
|
124
|
+
end
|
123
125
|
|
124
|
-
|
125
|
-
|
126
|
+
class ArgumentDecoration < Argument
|
127
|
+
class << self
|
128
|
+
def register(name)
|
129
|
+
DSL::Argument::register_decorator(self, name)
|
130
|
+
end
|
131
|
+
alias register_as register
|
126
132
|
end
|
127
133
|
|
128
|
-
|
129
|
-
|
134
|
+
Argument.instance_methods(false).each do |method|
|
135
|
+
class_eval(<<-EOM, __FILE__, __LINE__)
|
136
|
+
def #{method}(*args, &block)
|
137
|
+
decorated.#{method}(*args, &block)
|
138
|
+
end
|
139
|
+
EOM
|
130
140
|
end
|
131
141
|
|
132
|
-
def
|
133
|
-
|
142
|
+
def pretty_print_instance_variables
|
143
|
+
["@decorated"]
|
134
144
|
end
|
135
145
|
|
136
|
-
def initialize(up)
|
146
|
+
def initialize(up, down)
|
137
147
|
@wrapping_decorator = up
|
148
|
+
@decorated = down
|
138
149
|
end
|
139
150
|
|
140
|
-
def
|
141
|
-
@
|
142
|
-
end
|
143
|
-
|
144
|
-
def decorate(argument)
|
145
|
-
block = decor
|
146
|
-
(class << argument; self; end).class_eval &block
|
147
|
-
return argument
|
151
|
+
def decorated
|
152
|
+
@decorated
|
148
153
|
end
|
149
154
|
end
|
150
155
|
|
@@ -153,7 +158,7 @@ module Command
|
|
153
158
|
register "number", Range
|
154
159
|
register "range"
|
155
160
|
|
156
|
-
def complete(prefix, subject)
|
161
|
+
def complete(terms, prefix, subject)
|
157
162
|
return [] unless validate(prefix, subject)
|
158
163
|
return [prefix]
|
159
164
|
end
|
@@ -176,7 +181,7 @@ module Command
|
|
176
181
|
register "regexp", Regexp
|
177
182
|
register "regex"
|
178
183
|
|
179
|
-
def complete(prefix, subject)
|
184
|
+
def complete(terms, prefix, subject)
|
180
185
|
return [prefix]
|
181
186
|
end
|
182
187
|
|
@@ -227,7 +232,7 @@ module Command
|
|
227
232
|
File::Separator
|
228
233
|
end
|
229
234
|
|
230
|
-
def complete(prefix, subject)
|
235
|
+
def complete(terms, prefix, subject)
|
231
236
|
list = []
|
232
237
|
options = basis(subject)
|
233
238
|
search_path = options[:dirs].dup
|
@@ -340,7 +345,7 @@ module Command
|
|
340
345
|
register "array", Array
|
341
346
|
register "choose"
|
342
347
|
|
343
|
-
def complete(prefix, subject)
|
348
|
+
def complete(terms, prefix, subject)
|
344
349
|
return basis(subject).grep(%r{^#{prefix}.*})
|
345
350
|
end
|
346
351
|
|
@@ -354,7 +359,7 @@ module Command
|
|
354
359
|
register "string", String
|
355
360
|
register "any"
|
356
361
|
|
357
|
-
def complete(prefix, subject)
|
362
|
+
def complete(terms, prefix, subject)
|
358
363
|
return [basis(subject), ""]
|
359
364
|
end
|
360
365
|
|
@@ -392,7 +397,7 @@ module Command
|
|
392
397
|
@process = proc &prok
|
393
398
|
end
|
394
399
|
|
395
|
-
def complete(prefix, subject)
|
400
|
+
def complete(terms, prefix, subject)
|
396
401
|
return @process.call(prefix, subject)
|
397
402
|
end
|
398
403
|
|
@@ -413,50 +418,58 @@ module Command
|
|
413
418
|
#Most common decorator. Tags a argument as omitable. Otherwise, the
|
414
419
|
#interpreter will return an error to the user if they leave out an
|
415
420
|
#argument. Optional arguments that aren't provided are set to nil.
|
416
|
-
class Optional <
|
421
|
+
class Optional < ArgumentDecoration
|
417
422
|
register_as "optional"
|
418
423
|
|
419
|
-
|
420
|
-
|
421
|
-
false
|
422
|
-
end
|
424
|
+
def required?
|
425
|
+
false
|
423
426
|
end
|
424
427
|
end
|
425
428
|
|
426
429
|
#Indicated that the name of the argument has to appear on the command line
|
427
430
|
#before it will be recognized. Useful for optional or alternating arguments
|
428
|
-
class Named <
|
431
|
+
class Named < ArgumentDecoration
|
429
432
|
register_as "named"
|
430
433
|
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
434
|
+
def initialize(*args)
|
435
|
+
super
|
436
|
+
@name_pos = nil
|
437
|
+
end
|
438
|
+
|
439
|
+
def consume(subject, arguments)
|
440
|
+
if arguments.first == name
|
441
|
+
arguments.shift
|
442
|
+
return decorated.consume(subject,arguments)
|
443
|
+
else
|
444
|
+
raise ArgumentInvalidException, "Name \"#{name}\" required."
|
442
445
|
end
|
446
|
+
end
|
443
447
|
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
448
|
+
def match_terms(subject, terms, arguments)
|
449
|
+
if terms.first == name.to_s
|
450
|
+
@name_pos = terms.length
|
451
|
+
terms.shift
|
452
|
+
decorated.match_terms(subject, terms, arguments)
|
453
|
+
else
|
454
|
+
arguments.shift
|
450
455
|
end
|
456
|
+
end
|
451
457
|
|
452
|
-
|
453
|
-
|
454
|
-
|
458
|
+
def complete(terms, prefix, subject)
|
459
|
+
if not @name_pos.nil? and terms[-@name_pos] == name.to_s
|
460
|
+
return decorated.complete(terms, prefix, subject)
|
461
|
+
else
|
462
|
+
if %r{^#{prefix.to_s}.*} =~ name.to_s
|
463
|
+
return [name.to_s]
|
455
464
|
else
|
456
|
-
return
|
465
|
+
return []
|
457
466
|
end
|
458
467
|
end
|
459
468
|
end
|
469
|
+
|
470
|
+
def validate(term, subject)
|
471
|
+
return term == name || super
|
472
|
+
end
|
460
473
|
end
|
461
474
|
|
462
475
|
|
@@ -472,7 +485,7 @@ module Command
|
|
472
485
|
@process = proc &block
|
473
486
|
end
|
474
487
|
|
475
|
-
def complete(prefix, subject)
|
488
|
+
def complete(terms, prefix, subject)
|
476
489
|
return @process[[*prefix], subject]
|
477
490
|
end
|
478
491
|
|
@@ -513,58 +526,59 @@ module Command
|
|
513
526
|
# repeating.file_argument :some_files
|
514
527
|
#
|
515
528
|
#Will collect an array into +some_files+ of validated files.
|
516
|
-
class Repeating <
|
529
|
+
class Repeating < ArgumentDecoration
|
517
530
|
register "repeating"
|
518
531
|
register "many"
|
519
532
|
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
term = [*term]
|
526
|
-
if term.find{|it| not validate(it, subject)}
|
527
|
-
raise ArgumentInvalidException, {@name => term}
|
533
|
+
def consume_hash(subject, hash)
|
534
|
+
result = [*names].inject({}) do |arg_hash, name|
|
535
|
+
terms = hash[name]
|
536
|
+
if terms.nil?
|
537
|
+
arg_hash
|
528
538
|
else
|
529
|
-
|
539
|
+
[*terms].inject(arg_hash) do |a_h, term|
|
540
|
+
merge_hashes(a_h, decorated.consume_hash(subject, {name => term}))
|
541
|
+
end
|
530
542
|
end
|
531
543
|
end
|
544
|
+
return result
|
545
|
+
end
|
532
546
|
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
if(validate(trying, subject))
|
538
|
-
value << trying
|
539
|
-
else
|
540
|
-
arguments.unshift(trying)
|
541
|
-
break
|
542
|
-
end
|
543
|
-
end
|
544
|
-
return {@name => value}
|
547
|
+
def consume(subject, arguments)
|
548
|
+
result = {}
|
549
|
+
until arguments.empty? or not validate(arguments.first, subject) do
|
550
|
+
merge_hashes(result, decorated.consume(subject, arguments))
|
545
551
|
end
|
552
|
+
return result
|
553
|
+
end
|
546
554
|
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
+
def match_terms(subject, terms, arguments)
|
556
|
+
old_length = terms.length + 1
|
557
|
+
while terms.length < old_length and not terms.empty? do
|
558
|
+
old_length = terms.length
|
559
|
+
decorated.match_terms(subject, terms, arguments.dup)
|
560
|
+
end
|
561
|
+
|
562
|
+
arguments.shift
|
563
|
+
return true
|
564
|
+
end
|
565
|
+
|
566
|
+
def merge_hashes(hash, other_hash)
|
567
|
+
other_hash.each_pair do |name, value|
|
568
|
+
hash[name] ||= []
|
569
|
+
hash[name] << value
|
555
570
|
end
|
571
|
+
return hash
|
556
572
|
end
|
557
573
|
end
|
558
574
|
|
559
575
|
#Allows several arguments to share a position. Pass a block to the
|
560
576
|
#"decorator" method with the argument declarations inside. The first
|
561
577
|
#argument that can parse the input will be assigned - others will get nil.
|
562
|
-
class AlternatingArgument <
|
563
|
-
register "alternating"
|
564
|
-
register "multi"
|
578
|
+
class AlternatingArgument < Argument
|
565
579
|
# initialize(embed_in){ yield if block_given? }
|
566
580
|
def initialize(embed_in, &block)
|
567
|
-
|
581
|
+
@wrapping_decorator = embed_in
|
568
582
|
@names = []
|
569
583
|
@sub_arguments = []
|
570
584
|
self.instance_eval &block
|
@@ -581,9 +595,9 @@ module Command
|
|
581
595
|
end
|
582
596
|
end
|
583
597
|
|
584
|
-
def complete(prefix, subject)
|
598
|
+
def complete(terms, prefix, subject)
|
585
599
|
return sub_arguments.inject([]) do |list, sub_arg|
|
586
|
-
list.concat sub_arg.complete(prefix, subject)
|
600
|
+
list.concat sub_arg.complete(terms, prefix, subject)
|
587
601
|
end
|
588
602
|
end
|
589
603
|
|
@@ -600,6 +614,7 @@ module Command
|
|
600
614
|
term = arguments.first
|
601
615
|
catcher = first_catch(term, subject)
|
602
616
|
result = catcher.consume(subject, arguments)
|
617
|
+
return result if @name.nil?
|
603
618
|
return result.merge({@name => result[catcher.name]})
|
604
619
|
end
|
605
620
|
|
@@ -610,14 +625,13 @@ module Command
|
|
610
625
|
end
|
611
626
|
#If a hash is used for arguments that includes more than one of alternating argument's sub-arguments, the behavior is undefined
|
612
627
|
def consume_hash(subject, hash)
|
613
|
-
result = {}
|
614
|
-
begin
|
615
|
-
result.merge! super(subject, hash)
|
616
|
-
rescue OutOfArgumentsException; end
|
617
|
-
|
618
|
-
return @sub_arguments.inject(result) do |result, arg|
|
628
|
+
result = @sub_arguments.inject({}) do |result, arg|
|
619
629
|
result.merge arg.consume_hash(subject, hash)
|
620
630
|
end
|
631
|
+
unless @name.nil?
|
632
|
+
result[@name] = parse(subject, hash[@name])
|
633
|
+
end
|
634
|
+
return result
|
621
635
|
end
|
622
636
|
|
623
637
|
def match_terms(subject, terms, arguments)
|
@@ -637,7 +651,7 @@ module Command
|
|
637
651
|
|
638
652
|
def embed_argument(arg)
|
639
653
|
@names << arg.name
|
640
|
-
@sub_arguments <<
|
654
|
+
@sub_arguments << Optional.new(self, arg)
|
641
655
|
end
|
642
656
|
private
|
643
657
|
|
@@ -74,7 +74,8 @@ module Command
|
|
74
74
|
visitor = SetVisitor.new(:prefix => prefix,
|
75
75
|
:subject => subject,
|
76
76
|
:completion_list => [],
|
77
|
-
:arguments => []
|
77
|
+
:arguments => [],
|
78
|
+
:original_terms => terms.dup)
|
78
79
|
def visitor.arrive_at(terms, node)
|
79
80
|
self.arguments = node.argument_list.dup
|
80
81
|
image = subject.get_image(node.subject_requirements)
|
@@ -93,7 +94,7 @@ module Command
|
|
93
94
|
def visitor.command_out_of_terms(node)
|
94
95
|
image = subject.get_image(node.subject_requirements)
|
95
96
|
arguments.each do |handler|
|
96
|
-
self.completion_list += handler.complete(prefix, image)
|
97
|
+
self.completion_list += handler.complete(original_terms, prefix, image)
|
97
98
|
break unless handler.omittable?
|
98
99
|
end
|
99
100
|
end
|
data/lib/command-set/command.rb
CHANGED
@@ -246,22 +246,6 @@ module Command
|
|
246
246
|
return docs.join(" ").wrap(width)
|
247
247
|
end
|
248
248
|
|
249
|
-
def completion_list(terms, prefix, subject)
|
250
|
-
arguments = argument_list.dup
|
251
|
-
subject = subject.get_image(subject_requirements)
|
252
|
-
|
253
|
-
until(terms.empty? or arguments.empty?) do
|
254
|
-
arguments.first.match_terms(subject, terms, arguments)
|
255
|
-
end
|
256
|
-
|
257
|
-
completion = []
|
258
|
-
arguments.each do |handler|
|
259
|
-
completion += handler.complete(prefix, subject)
|
260
|
-
break unless handler.omittable?
|
261
|
-
end
|
262
|
-
return completion
|
263
|
-
end
|
264
|
-
|
265
249
|
def create_argument_methods
|
266
250
|
names = (argument_list + parent_arguments).inject([]) do |list, arg|
|
267
251
|
list + [*arg.names]
|
data/lib/command-set/dsl.rb
CHANGED
@@ -281,7 +281,7 @@ Action:: utility functions within the command action block
|
|
281
281
|
#Don't look to closely at the source. It does bad things.
|
282
282
|
def create_decorator(&block)
|
283
283
|
me = /:in `([^']*)/.match(caller(0)[0])[1]
|
284
|
-
return @@decorator_map[me]
|
284
|
+
return ArgumentDecorator.new(self, @@decorator_map[me], &block)
|
285
285
|
end
|
286
286
|
|
287
287
|
#This method functions analogously to create_decorator, except it
|
@@ -328,11 +328,13 @@ Action:: utility functions within the command action block
|
|
328
328
|
#alternating argument is a series of arguments, any of which could be
|
329
329
|
#set. They either need to be of distinct types, or use +named+ to
|
330
330
|
#distinguish between them.
|
331
|
-
def alternating_argument(name, &block)
|
331
|
+
def alternating_argument(name=nil, &block)
|
332
332
|
arg = AlternatingArgument.new(self, &block)
|
333
333
|
arg.name(name)
|
334
334
|
end
|
335
335
|
|
336
|
+
alias alternating alternating_argument
|
337
|
+
|
336
338
|
#The method used to instantiate arguments based on their values.
|
337
339
|
#Searches all registered Argument classes, from children up, until one
|
338
340
|
#admits to being able to create arguments based on the value.
|
data/lib/command-set/results.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'delegate'
|
2
1
|
require 'command-set/result-list'
|
3
2
|
|
4
3
|
module Kernel
|
@@ -88,12 +87,6 @@ module Command
|
|
88
87
|
__setobj__(__getobj__.dup)
|
89
88
|
end
|
90
89
|
|
91
|
-
#This looks gnarly, but DelegateClass takes out methods defined by
|
92
|
-
#Kernel -- Which usually makes sense, but IO has a bunch of methods that
|
93
|
-
#Kernel defines to basically delegate to an IO.... I have a headache
|
94
|
-
#now.
|
95
|
-
#It might just make sense to explicitly do the delegation, rather than
|
96
|
-
#use DelegateClass
|
97
90
|
methods = IO.public_instance_methods(false)
|
98
91
|
methods -= self.public_instance_methods(false)
|
99
92
|
methods |= ['class']
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'readline'
|
2
2
|
require 'command-set'
|
3
3
|
require 'dl/import'
|
4
|
-
require 'logger'
|
5
4
|
require 'command-set/interpreter'
|
6
5
|
|
7
6
|
#This really locks text-interpreter down to Linux, maybe Unix-like
|
@@ -28,16 +27,24 @@ module Readline
|
|
28
27
|
rescue Exception
|
29
28
|
end
|
30
29
|
|
31
|
-
|
30
|
+
libreadline_names = %w{libreadline.so libreadline.dylib libreadline.dll}
|
31
|
+
|
32
|
+
libreadline_paths = ls_so_dirs.inject([]) do |list, dir|
|
33
|
+
list + libreadline_names.map do |name|
|
34
|
+
File::join(*(dir + [name]))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
libreadline_paths.each do |path|
|
32
39
|
begin
|
33
|
-
dlload
|
40
|
+
dlload path
|
34
41
|
RLLB = symbol("rl_line_buffer")
|
35
42
|
found_libreadline = true
|
36
43
|
break
|
37
44
|
rescue RuntimeError
|
38
45
|
end
|
39
46
|
end
|
40
|
-
|
47
|
+
|
41
48
|
raise RuntimeError,"couldn't find libreadline.so" unless found_libreadline
|
42
49
|
|
43
50
|
def self.line_buffer
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: command-set
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.9.
|
7
|
-
date: 2008-01-
|
6
|
+
version: 0.9.1
|
7
|
+
date: 2008-01-11 00:00:00 -08:00
|
8
8
|
summary: Framework for interactive programs focused around a DSL for commands
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -56,7 +56,7 @@ rdoc_options:
|
|
56
56
|
- --main
|
57
57
|
- Command
|
58
58
|
- --title
|
59
|
-
- command-set-0.9.
|
59
|
+
- command-set-0.9.1 RDoc
|
60
60
|
extra_rdoc_files:
|
61
61
|
- doc/README
|
62
62
|
- doc/GUIDED_TOUR
|