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 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[@name]).nil?)
63
+ unless((term = hash[name]).nil?)
64
64
  if validate(term, subject)
65
- return {@name => parse(subject, term)}
65
+ return {name => parse(subject, term)}
66
66
  else
67
- raise ArgumentInvalidException, {@name => term}
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 < Argument
113
+ class ArgumentDecorator
114
114
  include DSL::Argument
115
115
 
116
- def self.register(name)
117
- DSL::Argument::register_decorator(self, name)
116
+ def initialize(wrapped_by, wrap_with, &block)
117
+ @wrapped_by = wrapped_by
118
+ @wrap_with = wrap_with
118
119
  end
119
120
 
120
- class << self
121
- alias register_as register
121
+ def embed_argument(arg)
122
+ @wrapped_by.embed_argument(@wrap_with.new(@wrapped_with, arg))
122
123
  end
124
+ end
123
125
 
124
- def self.decoration(&block)
125
- @decor = block
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
- def self.decor
129
- @decor
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 decor
133
- self.class.decor
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 embed_argument(argument)
141
- @wrapping_decorator.embed_argument(decorate(argument))
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 < ArgumentDecorator
421
+ class Optional < ArgumentDecoration
417
422
  register_as "optional"
418
423
 
419
- decoration do
420
- def required?
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 < ArgumentDecorator
431
+ class Named < ArgumentDecoration
429
432
  register_as "named"
430
433
 
431
- decoration do
432
- alias_method(:old_consume, :consume)
433
- alias_method(:old_complete, :complete)
434
- alias_method(:old_match_terms, :match_terms)
435
- def consume(subject, arguments)
436
- if arguments.first == @name
437
- arguments.shift
438
- return old_consume(subject,arguments)
439
- else
440
- raise ArgumentInvalidException, "Name \"#{@name}\" required."
441
- end
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
- def match_terms(subject, terms, arguments)
445
- if terms.first == @name.to_s
446
- terms.shift
447
- else
448
- old_match_terms(subject, terms, arguments)
449
- end
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
- def complete(prefix, subject)
453
- if %r{^#{prefix.to_s}.*} =~ @name.to_s
454
- return [@name.to_s]
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 old_complete(prefix, subject)
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 < ArgumentDecorator
529
+ class Repeating < ArgumentDecoration
517
530
  register "repeating"
518
531
  register "many"
519
532
 
520
- decoration do
521
- def consume_hash(subject, hash)
522
- term = hash[@name]
523
- return {} if term.nil?
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
- return {@name => term.map{|it| parse(subject,it)}}
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
- def consume(subject, arguments)
534
- value = []
535
- until arguments.empty? do
536
- trying = arguments.shift
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
- def match_terms(subject, terms, arguments)
548
- validated = validate(terms.first, subject)
549
- if(validated)
550
- terms.shift
551
- else
552
- arguments.shift
553
- end
554
- return true
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 < ArgumentDecorator
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
- super(embed_in)
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 << optional.decorate(arg)
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
@@ -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]
@@ -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].new(self, &block)
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.
@@ -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
- ls_so_dirs.each do |libreadline_location|
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 File::join(*(libreadline_location + ["libreadline.so"]))
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.0
7
- date: 2008-01-08 00:00:00 -08:00
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.0 RDoc
59
+ - command-set-0.9.1 RDoc
60
60
  extra_rdoc_files:
61
61
  - doc/README
62
62
  - doc/GUIDED_TOUR