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 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