command-set 0.8.0 → 0.8.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/GUIDED_TOUR +24 -0
- data/doc/Specifications +1 -1
- data/lib/command-set/arguments.rb +15 -1
- data/lib/command-set/command-set.rb +18 -1
- data/lib/command-set/dsl.rb +60 -30
- data/lib/command-set/text-interpreter.rb +43 -10
- metadata +5 -6
data/GUIDED_TOUR
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
The quickest way to get a handle on what CommandSet can do for you is to
|
2
|
+
look at the various pieces and get a handle on how they work together.
|
3
|
+
|
4
|
+
The rough sketch is that you enumerate a series of commands, which you then
|
5
|
+
feed to an interpreter. The interpreter will set you up with a template for
|
6
|
+
your porgram's subject, which you fill in with some defaults. Then, give
|
7
|
+
the filled in subject back to the interpreter and let it run.
|
8
|
+
|
9
|
+
Here's the appropriate places to get started:
|
10
|
+
|
11
|
+
0. DSL (Read thoroughly - especially the sub modules)
|
12
|
+
0. BaseInterpreter#subject_template
|
13
|
+
0. BaseInterpreter#subject=
|
14
|
+
0. TextInterpreter#go
|
15
|
+
|
16
|
+
A couple of handy tricks can be found at
|
17
|
+
|
18
|
+
0. BaseInterpreter#process_input
|
19
|
+
0. StandardCommands
|
20
|
+
0. QuickInterpreter
|
21
|
+
|
22
|
+
More advanced stuff that worth learning once your app is off the ground:
|
23
|
+
|
24
|
+
0. Results
|
data/doc/Specifications
CHANGED
@@ -214,6 +214,6 @@ Command::Results::Presenter driving a Formatter
|
|
214
214
|
Command::Results::Presenter driving a strict Formatter
|
215
215
|
- should send notifications in correct order
|
216
216
|
|
217
|
-
Finished in 0.
|
217
|
+
Finished in 0.24242 seconds
|
218
218
|
|
219
219
|
137 examples, 0 failures
|
@@ -176,12 +176,13 @@ module Command
|
|
176
176
|
|
177
177
|
def initialize(name, options={})
|
178
178
|
super(name)
|
179
|
+
options ||= {}
|
179
180
|
if Hash === options
|
180
181
|
@options = Defaults.merge(options)
|
181
182
|
@acceptor = @options[:acceptor]
|
182
183
|
elsif Proc === options
|
183
184
|
@options = Defaults.dup
|
184
|
-
@acceptor = options
|
185
|
+
@acceptor = proc &options
|
185
186
|
else
|
186
187
|
raise "File argument needs hash or proc!"
|
187
188
|
end
|
@@ -323,6 +324,19 @@ module Command
|
|
323
324
|
end
|
324
325
|
end
|
325
326
|
|
327
|
+
class RestOfLineArgument < StringArgument
|
328
|
+
register "rest"
|
329
|
+
|
330
|
+
def consume(subject, arguments)
|
331
|
+
term = arguments.join(" ")
|
332
|
+
arguments.clear
|
333
|
+
unless validate(term, subject)
|
334
|
+
raise ArgumentInvalidException, {@name => term}
|
335
|
+
end
|
336
|
+
return {@name => parse(subject, term)}
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
326
340
|
class ProcArgument < Argument
|
327
341
|
register "proc", Proc
|
328
342
|
|
@@ -42,7 +42,7 @@ Command::wrap_stdout
|
|
42
42
|
|
43
43
|
#:startdoc:
|
44
44
|
|
45
|
-
#Command::CommandSet is a tight little library that
|
45
|
+
#Command::CommandSet is a tight little library that lets you clearly and
|
46
46
|
#easily describe a set of commands for an interactive application. The
|
47
47
|
#command set can then be handed to one of a number of interpreters that will
|
48
48
|
#facilitate interaction with the user.
|
@@ -153,6 +153,23 @@ module Command
|
|
153
153
|
set.define_commands(&block)
|
154
154
|
return set
|
155
155
|
end
|
156
|
+
|
157
|
+
#In driver code, it's often quickest to yank in commands from a file.
|
158
|
+
#To do that, create a code file with a module in it. The module needs
|
159
|
+
#a method of the form
|
160
|
+
#
|
161
|
+
# def self.define_commands()
|
162
|
+
#
|
163
|
+
#define_commands should return a CommandSet. Then, pass the require
|
164
|
+
#path and module name to require_commands, and it'll take care of
|
165
|
+
#creating the command set. You can even call
|
166
|
+
#DSL::CommandSetDefinition#define_commands on the set that's returned
|
167
|
+
#in order to add one-off commands or fold in other command sets.
|
168
|
+
def require_commands(file, mod, cmd_path=[])
|
169
|
+
set = self.new
|
170
|
+
set.require_commands(file, mod, cmd_path)
|
171
|
+
return set
|
172
|
+
end
|
156
173
|
end
|
157
174
|
|
158
175
|
include DSL::CommandSetDefinition
|
data/lib/command-set/dsl.rb
CHANGED
@@ -37,7 +37,31 @@ Action:: utility functions within the command action block
|
|
37
37
|
@command_list[name] = command.dup
|
38
38
|
@command_list[name].parent=self
|
39
39
|
end
|
40
|
-
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
#If you've got a file dedicated to a set of commands, (and you really
|
44
|
+
#should) you can use require_commands to require it, call
|
45
|
+
#+define_commands+ on a specific Module, pick out a specific
|
46
|
+
#subcommand (by passing a path), and then including specific commands
|
47
|
+
#from it.
|
48
|
+
def require_commands(file, module_name, path = [], *commands)
|
49
|
+
require file
|
50
|
+
module_path = module_name.to_s.split("::")
|
51
|
+
mod = Object
|
52
|
+
module_path.each do |part|
|
53
|
+
mod = mod.const_get(part)
|
54
|
+
end
|
55
|
+
|
56
|
+
set = mod.define_commands
|
57
|
+
set = set.find_command(*path)
|
58
|
+
|
59
|
+
if CommandSet === set
|
60
|
+
include_commands(set, *commands)
|
61
|
+
elsif Class === set and Command > set
|
62
|
+
command(set)
|
63
|
+
else
|
64
|
+
raise RuntimeError,"#{set.inspect} isn't a CommandSet or a Command"
|
41
65
|
end
|
42
66
|
end
|
43
67
|
|
@@ -353,6 +377,40 @@ Action:: utility functions within the command action block
|
|
353
377
|
end
|
354
378
|
end
|
355
379
|
|
380
|
+
#The DSL for formatting. A lot of code will do just fine with the
|
381
|
+
#Kernel#puts #that Results intercepts. More involved output control
|
382
|
+
#starts by including CommandSet::DSL::Formatting, and using
|
383
|
+
#Formatting#list and Formatting#item to structure output for the
|
384
|
+
#formatters.
|
385
|
+
module Formatting
|
386
|
+
#To create lists and sublist of data, you can use #list to wrap code
|
387
|
+
#in a #begin_list / #end_list pair.
|
388
|
+
def list(name, options={}) #:yield:
|
389
|
+
begin_list(name, options)
|
390
|
+
yield if block_given?
|
391
|
+
end_list
|
392
|
+
end
|
393
|
+
|
394
|
+
#Tells the main collector to begin a list. Subsequent output will be
|
395
|
+
#gathered into that list. For more, check out Results::Collector
|
396
|
+
def begin_list(name, options={})
|
397
|
+
@main_collector.begin_list(name, options)
|
398
|
+
end
|
399
|
+
|
400
|
+
#Tells the main collector to end the current list. For more, check out
|
401
|
+
#Results::Collector
|
402
|
+
def end_list
|
403
|
+
@main_collector.end_list
|
404
|
+
end
|
405
|
+
|
406
|
+
#Clean way to create an item of output. Allows for various options to
|
407
|
+
#be added. The normal output method (#puts, #p, #write...) are all
|
408
|
+
#diverted within a command, and effectively create no-option items.
|
409
|
+
def item(name, options={})
|
410
|
+
@main_collector.item(name, options)
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
356
414
|
#The methods available within the DSL::CommandDefinition#action method
|
357
415
|
#
|
358
416
|
#The trickiest thing to realize about writing Commands is that a
|
@@ -365,6 +423,7 @@ Action:: utility functions within the command action block
|
|
365
423
|
#which will be local to the invocation of the command. This is
|
366
424
|
#especially useful for undo and redo.
|
367
425
|
module Action
|
426
|
+
include Formatting
|
368
427
|
|
369
428
|
#:section: Basics
|
370
429
|
|
@@ -383,35 +442,6 @@ Action:: utility functions within the command action block
|
|
383
442
|
@subject
|
384
443
|
end
|
385
444
|
|
386
|
-
#:section: Formatting
|
387
|
-
|
388
|
-
#To create lists and sublist of data, you can use #list to wrap code
|
389
|
-
#in a #begin_list / #end_list pair.
|
390
|
-
def list(name, options={}) #:yield:
|
391
|
-
begin_list(name, options)
|
392
|
-
yield if block_given?
|
393
|
-
end_list
|
394
|
-
end
|
395
|
-
|
396
|
-
#Tells the main collector to begin a list. Subsequent output will be
|
397
|
-
#gathered into that list. For more, check out Results::Collector
|
398
|
-
def begin_list(name, options={})
|
399
|
-
@main_collector.begin_list(name, options)
|
400
|
-
end
|
401
|
-
|
402
|
-
#Tells the main collector to end the current list. For more, check out
|
403
|
-
#Results::Collector
|
404
|
-
def end_list
|
405
|
-
@main_collector.end_list
|
406
|
-
end
|
407
|
-
|
408
|
-
#Clean way to create an item of output. Allows for various options to
|
409
|
-
#be added. The normal output method (#puts, #p, #write...) are all
|
410
|
-
#diverted within a command, and effectively create no-option items.
|
411
|
-
def item(name, options={})
|
412
|
-
@main_collector.item(name, options)
|
413
|
-
end
|
414
|
-
|
415
445
|
#:section: Pause and Resume
|
416
446
|
|
417
447
|
#Stop here. Return control to the user. If several commands are
|
@@ -8,16 +8,49 @@ require 'command-set/interpreter'
|
|
8
8
|
#platforms, I'm thinking. A more flexible way of doing this would rock,
|
9
9
|
#regardless of length.
|
10
10
|
module Readline
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
11
|
+
begin
|
12
|
+
extend DL::Importable
|
13
|
+
found_libreadline = false
|
14
|
+
ls_so_dirs = [
|
15
|
+
%w{lib},
|
16
|
+
%w{usr lib},
|
17
|
+
%w{usr local lib}
|
18
|
+
].each{|path| path.unshift("")}
|
19
|
+
|
20
|
+
begin
|
21
|
+
File::open("/etc/ld.so.conf", "r") do |ld_so_conf|
|
22
|
+
ld_so_conf.each do |line|
|
23
|
+
unless /^#/ =~ line or /^%s*$/ =~ line
|
24
|
+
ls_so_dirs << line.chomp.split(File::Separator)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
rescue Exception
|
20
29
|
end
|
30
|
+
|
31
|
+
ls_so_dirs.each do |libreadline_location|
|
32
|
+
begin
|
33
|
+
dlload File::join(*(libreadline_location + ["libreadline.so"]))
|
34
|
+
RLLB = symbol("rl_line_buffer")
|
35
|
+
found_libreadline = true
|
36
|
+
break
|
37
|
+
rescue RuntimeError
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
raise RuntimeError,"couldn't find libreadline.so" unless found_libreadline
|
42
|
+
|
43
|
+
def self.line_buffer
|
44
|
+
p = RLLB.ptr
|
45
|
+
if p.nil?
|
46
|
+
return p
|
47
|
+
else
|
48
|
+
return p.to_s
|
49
|
+
end
|
50
|
+
end
|
51
|
+
rescue RuntimeError => rte
|
52
|
+
warn "Couldn't find libreadline - tab-completion will be unpredictable at best."
|
53
|
+
warn "The problem was: " + rte.message
|
21
54
|
end
|
22
55
|
end
|
23
56
|
|
@@ -147,7 +180,7 @@ module Command
|
|
147
180
|
end
|
148
181
|
|
149
182
|
def get_formatter
|
150
|
-
return Results::
|
183
|
+
return Results::StrategyFormatter.new(::Command::raw_stdout)
|
151
184
|
end
|
152
185
|
|
153
186
|
def get_prompt
|
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.8.
|
7
|
-
date: 2007-
|
6
|
+
version: 0.8.1
|
7
|
+
date: 2007-12-13 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
|
@@ -47,6 +47,7 @@ files:
|
|
47
47
|
- doc/README
|
48
48
|
- doc/Specifications
|
49
49
|
- doc/argumentDSL
|
50
|
+
- GUIDED_TOUR
|
50
51
|
test_files: []
|
51
52
|
|
52
53
|
rdoc_options:
|
@@ -55,11 +56,9 @@ rdoc_options:
|
|
55
56
|
- --main
|
56
57
|
- Command
|
57
58
|
- --title
|
58
|
-
- command-set-0.8.
|
59
|
+
- command-set-0.8.1 RDoc
|
59
60
|
extra_rdoc_files:
|
60
|
-
-
|
61
|
-
- doc/Specifications
|
62
|
-
- doc/argumentDSL
|
61
|
+
- GUIDED_TOUR
|
63
62
|
executables: []
|
64
63
|
|
65
64
|
extensions: []
|