command-set 0.9.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|