prompt 0.0.3 → 0.1.0
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/CHANGELOG.md +7 -0
- data/README.md +12 -14
- data/examples/file_manager +6 -4
- data/examples/mud +2 -2
- data/lib/prompt/application.rb +23 -8
- data/lib/prompt/command.rb +38 -52
- data/lib/prompt/command_not_found.rb +0 -3
- data/lib/prompt/console/builtins.rb +1 -1
- data/lib/prompt/console/console_module.rb +39 -7
- data/lib/prompt/dsl.rb +6 -8
- data/lib/prompt/dsl_helper.rb +18 -15
- data/lib/prompt/matcher.rb +13 -0
- data/lib/prompt/multi_matcher.rb +21 -0
- data/lib/prompt/parameter.rb +10 -18
- data/lib/prompt/prompt_module.rb +1 -1
- data/lib/prompt/simple_matcher.rb +13 -0
- data/spec/prompt/command_spec.rb +78 -71
- data/spec/prompt/console_spec.rb +79 -0
- data/spec/spec_helper.rb +17 -0
- metadata +10 -7
- data/lib/prompt/glob_parameter.rb +0 -17
- data/lib/prompt/proc_parameter.rb +0 -18
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
This is updated when a new version is pushed to http://rubygems.org
|
4
4
|
|
5
|
+
## 0.1.0 (Mar 8, 2011)
|
6
|
+
|
7
|
+
* DSL change: `desc` was renamed to `group`
|
8
|
+
* Tab completion will now list only the completions for the current word, instead of
|
9
|
+
the whole command. This makes it behave like bash and works much better with `*params`
|
10
|
+
* Hitting ENTER with an empty line will no longer print a Command Not Found error
|
11
|
+
|
5
12
|
## 0.0.3 (Feb 22, 2011)
|
6
13
|
|
7
14
|
* DSL change: `variable` & `dynamic_variable` were renamed to `param`
|
data/README.md
CHANGED
@@ -16,7 +16,7 @@ Commands are defined with a Sinatra-inspired DSL:
|
|
16
16
|
require 'prompt'
|
17
17
|
extend Prompt::DSL
|
18
18
|
|
19
|
-
|
19
|
+
group "Move"
|
20
20
|
|
21
21
|
param :direction, "A cardinal direction", %w(north east south west)
|
22
22
|
|
@@ -24,7 +24,7 @@ command "go :direction", "Walk in the specified direction" do |direction|
|
|
24
24
|
puts "You walked #{direction} and were eaten by a grue."
|
25
25
|
end
|
26
26
|
|
27
|
-
|
27
|
+
group "Interact"
|
28
28
|
|
29
29
|
command "look", "Look around" do
|
30
30
|
puts "You're in a dark room."
|
@@ -44,7 +44,7 @@ Tab completion is hooked up automatically after you define your commands and par
|
|
44
44
|
$ my_app
|
45
45
|
> g<TAB>
|
46
46
|
> go <TAB>
|
47
|
-
|
47
|
+
east north south west
|
48
48
|
> go n<TAB>
|
49
49
|
> go north
|
50
50
|
|
@@ -86,12 +86,12 @@ The `help` command is built-in. It will print all of the commands that you've d
|
|
86
86
|
You can put commands in logical groups. This only affects how help is printed.
|
87
87
|
|
88
88
|
```ruby
|
89
|
-
|
89
|
+
group "File commands"
|
90
90
|
|
91
91
|
command ...
|
92
92
|
command ...
|
93
93
|
|
94
|
-
|
94
|
+
group "Directory commands"
|
95
95
|
|
96
96
|
command ...
|
97
97
|
```
|
@@ -112,30 +112,28 @@ Here, the parameters are named `first` and `last`. Their values are be passed a
|
|
112
112
|
Each `:parameter` only matches a single word. If you want to match multiple words to one parameter, use a `*parameter`.
|
113
113
|
|
114
114
|
```ruby
|
115
|
-
command "
|
116
|
-
puts "You
|
115
|
+
command "cp *file :dest" do |files, dest|
|
116
|
+
puts "You copied #{files.length} files to #{dest}"
|
117
117
|
end
|
118
118
|
```
|
119
119
|
|
120
120
|
### Defining parameters
|
121
121
|
|
122
|
-
It's not necessary to define a parameter before using it in a command, but doing so will allow you to provide a useful description and
|
122
|
+
It's not necessary to define a parameter before using it in a command, but doing so will allow you to provide a useful description and list of possible completions for the parameter.
|
123
123
|
|
124
124
|
```ruby
|
125
125
|
param :name, "Description"
|
126
126
|
```
|
127
127
|
|
128
|
-
### Specifying
|
128
|
+
### Specifying parameter completions
|
129
129
|
|
130
|
-
You can specify
|
130
|
+
You can specify the completions for a parameter as a static list:
|
131
131
|
|
132
132
|
```ruby
|
133
|
-
param :
|
133
|
+
param :color, "A color", %w(red green blue)
|
134
134
|
```
|
135
135
|
|
136
|
-
|
137
|
-
|
138
|
-
Instead of a static list, you can specify a block that will dynamically return a list of valid values for a parameter. These will also be expanded when using tab completion.
|
136
|
+
or as a dynamically-generated one:
|
139
137
|
|
140
138
|
```ruby
|
141
139
|
param :file, "JPG file" do
|
data/examples/file_manager
CHANGED
@@ -8,7 +8,7 @@ def change_prompt dir
|
|
8
8
|
Prompt.application.prompt = "#{@pwd}> "
|
9
9
|
end
|
10
10
|
|
11
|
-
@pwd = File.
|
11
|
+
@pwd = File.expand_path Dir.pwd
|
12
12
|
change_prompt @pwd
|
13
13
|
|
14
14
|
param :dir, "Directory" do
|
@@ -18,7 +18,7 @@ param :dir, "Directory" do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
command "cd :dir", "Change directory" do |dir|
|
21
|
-
@pwd = File.
|
21
|
+
@pwd = File.expand_path File.join(@pwd, dir)
|
22
22
|
change_prompt @pwd
|
23
23
|
end
|
24
24
|
|
@@ -38,9 +38,11 @@ command "pwd", "Print current directory" do
|
|
38
38
|
puts @pwd
|
39
39
|
end
|
40
40
|
|
41
|
-
param :
|
41
|
+
param :file, "File" do
|
42
|
+
Dir.entries(@pwd)
|
43
|
+
end
|
42
44
|
|
43
|
-
command "cp *
|
45
|
+
command "cp *file :dir", "Copy one or more files to dest" do |files, dir|
|
44
46
|
puts "Copying #{files.length} file(s) to #{dir}"
|
45
47
|
# doesn't actually do it...
|
46
48
|
end
|
data/examples/mud
CHANGED
@@ -7,7 +7,7 @@ extend Prompt::DSL
|
|
7
7
|
GRUE = 3
|
8
8
|
@moves = 0
|
9
9
|
|
10
|
-
|
10
|
+
group "Move"
|
11
11
|
|
12
12
|
param :direction, "A cardinal direction", %w(north east south west)
|
13
13
|
|
@@ -20,7 +20,7 @@ command "go :direction", "Walk in the specified direction" do |direction|
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
|
23
|
+
group "Interact"
|
24
24
|
|
25
25
|
command "look", "Look around" do
|
26
26
|
if @moves < GRUE
|
data/lib/prompt/application.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require 'prompt/command_group'
|
2
2
|
require 'prompt/command'
|
3
|
+
require 'prompt/matcher'
|
4
|
+
require 'prompt/simple_matcher'
|
5
|
+
require 'prompt/multi_matcher'
|
3
6
|
|
4
7
|
module Prompt
|
5
8
|
class Application
|
@@ -11,7 +14,7 @@ module Prompt
|
|
11
14
|
@prompt = "> "
|
12
15
|
end
|
13
16
|
|
14
|
-
def
|
17
|
+
def select_group desc
|
15
18
|
@current_command_group_name = desc
|
16
19
|
end
|
17
20
|
|
@@ -19,22 +22,32 @@ module Prompt
|
|
19
22
|
current_command_group.commands << command
|
20
23
|
end
|
21
24
|
|
22
|
-
def exec
|
25
|
+
def exec words
|
23
26
|
commands.each do |command|
|
24
|
-
args = command.match(
|
27
|
+
args = command.match(words)
|
25
28
|
return command.run(args) if args
|
26
29
|
end
|
27
|
-
raise CommandNotFound.new
|
30
|
+
raise CommandNotFound.new
|
28
31
|
ensure
|
29
32
|
clear_cached_values
|
30
33
|
end
|
31
34
|
|
32
|
-
def completions
|
33
|
-
|
35
|
+
def completions line_starting_with, word_starting_with
|
36
|
+
args = Console.split(line_starting_with)
|
37
|
+
last_idx = index_of_last_word(line_starting_with)
|
38
|
+
all_expansions(args[0,last_idx], word_starting_with)
|
34
39
|
end
|
35
40
|
|
36
41
|
private
|
37
42
|
|
43
|
+
def index_of_last_word line
|
44
|
+
ss = StringScanner.new(line)
|
45
|
+
ss.scan(/\s+/)
|
46
|
+
idx = 0
|
47
|
+
idx += 1 while ss.scan(/[^\s]+\s+/)
|
48
|
+
idx
|
49
|
+
end
|
50
|
+
|
38
51
|
def clear_cached_values
|
39
52
|
commands.each do |c|
|
40
53
|
c.clear_cached_values
|
@@ -45,8 +58,10 @@ module Prompt
|
|
45
58
|
@command_groups.map(&:commands).flatten(1)
|
46
59
|
end
|
47
60
|
|
48
|
-
def all_expansions
|
49
|
-
commands.map
|
61
|
+
def all_expansions(args, partial_arg)
|
62
|
+
commands.select { |c| c.could_match? args }.map do |c|
|
63
|
+
c.expansions(args.length, partial_arg)
|
64
|
+
end.flatten(1)
|
50
65
|
end
|
51
66
|
|
52
67
|
def current_command_group
|
data/lib/prompt/command.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
require 'strscan'
|
2
2
|
require 'prompt/parameter'
|
3
|
+
require 'prompt/console/console_module'
|
3
4
|
|
4
5
|
module Prompt
|
5
6
|
class Command
|
6
7
|
|
7
8
|
SEP = "\036" # RS - record separator
|
8
|
-
S_QUOTED_ARG = /'([^']*)'/
|
9
|
-
D_QUOTED_ARG = /"([^"]*)"/
|
10
|
-
UNQUOTED_ARG = /[^\s]+/
|
11
9
|
|
12
10
|
attr :name
|
13
11
|
attr :desc
|
@@ -19,28 +17,27 @@ module Prompt
|
|
19
17
|
@action = block
|
20
18
|
|
21
19
|
@name = words.join(" ")
|
22
|
-
@
|
20
|
+
@matchers = words.select {|w| w.kind_of?(Matcher) }
|
21
|
+
@parameters = @matchers.map { |m| m.parameter }
|
23
22
|
end
|
24
23
|
|
25
24
|
def run args
|
26
25
|
@action.call *args
|
27
26
|
end
|
28
27
|
|
29
|
-
def match
|
30
|
-
if
|
31
|
-
@
|
28
|
+
def match words
|
29
|
+
if args = regex.match(words.join(SEP))
|
30
|
+
@matchers.map {|m| m.matches(args[m.parameter.name]) }
|
32
31
|
end
|
33
32
|
end
|
34
33
|
|
35
|
-
def expansions
|
36
|
-
expand @words
|
37
|
-
end
|
38
|
-
|
39
34
|
def usage
|
40
35
|
@words.map do |word|
|
41
36
|
case word
|
42
|
-
when
|
43
|
-
"<#{word.name}>"
|
37
|
+
when MultiMatcher
|
38
|
+
"<#{word.parameter.name}> ..."
|
39
|
+
when Matcher
|
40
|
+
"<#{word.parameter.name}>"
|
44
41
|
else
|
45
42
|
word
|
46
43
|
end
|
@@ -53,30 +50,43 @@ module Prompt
|
|
53
50
|
end
|
54
51
|
end
|
55
52
|
|
56
|
-
|
53
|
+
def expansions(word_idx, starting_with)
|
54
|
+
# TODO - combine glob parameters with any that follow
|
55
|
+
word = @words[0..word_idx].find { |w| w.kind_of? MultiMatcher }
|
56
|
+
word = word || @words[word_idx]
|
57
|
+
|
58
|
+
return [] if word.nil?
|
59
|
+
|
60
|
+
case word
|
61
|
+
when Matcher
|
62
|
+
word.parameter.expansions(starting_with)
|
63
|
+
when String
|
64
|
+
word.start_with?(starting_with) ? [word] : []
|
65
|
+
end
|
66
|
+
end
|
57
67
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
args << arg
|
68
|
+
def could_match?(words)
|
69
|
+
words.each_with_index do |w, i|
|
70
|
+
word = @words[i]
|
71
|
+
case word
|
72
|
+
when nil
|
73
|
+
return false
|
74
|
+
when MultiMatcher
|
75
|
+
return true
|
76
|
+
when String
|
77
|
+
return false unless word.start_with?(w)
|
69
78
|
end
|
70
|
-
ss.scan(/\s+/)
|
71
79
|
end
|
72
|
-
|
80
|
+
return true
|
73
81
|
end
|
74
82
|
|
83
|
+
private
|
84
|
+
|
75
85
|
def regex
|
76
86
|
begin
|
77
87
|
regex_strs = @words.map do |word|
|
78
88
|
case word
|
79
|
-
when
|
89
|
+
when Matcher
|
80
90
|
word.regex
|
81
91
|
else
|
82
92
|
Regexp.escape(word)
|
@@ -86,29 +96,5 @@ module Prompt
|
|
86
96
|
end
|
87
97
|
end
|
88
98
|
|
89
|
-
def expand a
|
90
|
-
return [] if a.empty?
|
91
|
-
|
92
|
-
head = a[0]
|
93
|
-
tail = a[1..-1]
|
94
|
-
|
95
|
-
case head
|
96
|
-
when Parameter
|
97
|
-
head = head.expansions
|
98
|
-
else
|
99
|
-
head = [head]
|
100
|
-
end
|
101
|
-
|
102
|
-
return head if tail.empty?
|
103
|
-
|
104
|
-
result = []
|
105
|
-
head.each do |h|
|
106
|
-
expand(tail).each do |e|
|
107
|
-
result << "#{h} #{e}"
|
108
|
-
end
|
109
|
-
end
|
110
|
-
result
|
111
|
-
end
|
112
|
-
|
113
99
|
end
|
114
100
|
end
|
@@ -1,13 +1,15 @@
|
|
1
1
|
require 'readline'
|
2
2
|
require 'prompt'
|
3
|
+
require 'strscan'
|
3
4
|
|
4
5
|
module Prompt
|
5
6
|
module Console
|
6
7
|
|
7
8
|
HISTORY_MAX_SIZE = 100
|
8
9
|
|
9
|
-
CompletionProc = proc do |
|
10
|
-
|
10
|
+
CompletionProc = proc do |word_starting_with|
|
11
|
+
line_starting_with = Readline.line_buffer[0...Readline.point]
|
12
|
+
Prompt.application.completions(line_starting_with, word_starting_with)
|
11
13
|
end
|
12
14
|
|
13
15
|
def self.start(history_file = nil)
|
@@ -19,17 +21,17 @@ module Prompt
|
|
19
21
|
save_history history_file if history_file
|
20
22
|
end
|
21
23
|
|
22
|
-
Readline.basic_word_break_characters = ""
|
23
|
-
Readline.completion_append_character = " "
|
24
24
|
Readline.completion_proc = CompletionProc
|
25
25
|
|
26
26
|
load_history history_file if history_file
|
27
27
|
|
28
28
|
while line = Readline.readline(Prompt.application.prompt, true)
|
29
29
|
begin
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
words = split(line)
|
31
|
+
next if words == []
|
32
|
+
Prompt.application.exec words
|
33
|
+
rescue CommandNotFound
|
34
|
+
STDERR.puts "Command not found: #{line}"
|
33
35
|
end
|
34
36
|
end
|
35
37
|
end
|
@@ -51,5 +53,35 @@ module Prompt
|
|
51
53
|
end
|
52
54
|
end
|
53
55
|
|
56
|
+
private
|
57
|
+
|
58
|
+
S_QUOTED_ARG = /'([^']*)'/
|
59
|
+
D_QUOTED_ARG = /"([^"]*)"/
|
60
|
+
UNQUOTED_ARG = /[^\s]+/
|
61
|
+
|
62
|
+
# Splits a command string into an argument (word) list.
|
63
|
+
# This understands how to make "quoted strings" into a single word
|
64
|
+
def self.split command
|
65
|
+
args = []
|
66
|
+
ss = StringScanner.new(command)
|
67
|
+
ss.scan(/\s+/)
|
68
|
+
until ss.eos?
|
69
|
+
arg = ""
|
70
|
+
while true
|
71
|
+
segment = if ss.scan(S_QUOTED_ARG) or ss.scan(D_QUOTED_ARG)
|
72
|
+
ss[1]
|
73
|
+
else
|
74
|
+
ss.scan(UNQUOTED_ARG)
|
75
|
+
end
|
76
|
+
break unless segment
|
77
|
+
arg << segment
|
78
|
+
end
|
79
|
+
args << arg
|
80
|
+
ss.scan(/\s+/)
|
81
|
+
end
|
82
|
+
args
|
83
|
+
end
|
84
|
+
|
85
|
+
|
54
86
|
end # module Console
|
55
87
|
end
|
data/lib/prompt/dsl.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
require 'prompt/parameter'
|
2
|
-
require 'prompt/proc_parameter'
|
3
|
-
require 'prompt/glob_parameter'
|
4
2
|
require 'prompt/dsl_helper'
|
5
3
|
|
6
4
|
module Prompt
|
@@ -12,11 +10,11 @@ module Prompt
|
|
12
10
|
else
|
13
11
|
"Commands"
|
14
12
|
end
|
15
|
-
Prompt.application.
|
13
|
+
Prompt.application.select_group(name)
|
16
14
|
end
|
17
15
|
|
18
|
-
def
|
19
|
-
Prompt.application.
|
16
|
+
def group desc
|
17
|
+
Prompt.application.select_group(desc)
|
20
18
|
end
|
21
19
|
|
22
20
|
def command(name, desc = nil, &block)
|
@@ -28,10 +26,10 @@ module Prompt
|
|
28
26
|
def param(name, desc, values = nil, &block)
|
29
27
|
@parameters = [] unless defined? @parameters
|
30
28
|
raise "parameter :#{name} is already defined" if @parameters.find {|v| v.name == name}
|
31
|
-
if block
|
32
|
-
|
29
|
+
@parameters << if block
|
30
|
+
Parameter.new(name, desc, &block)
|
33
31
|
else
|
34
|
-
|
32
|
+
Parameter.new(name, desc, values)
|
35
33
|
end
|
36
34
|
end
|
37
35
|
|
data/lib/prompt/dsl_helper.rb
CHANGED
@@ -1,25 +1,28 @@
|
|
1
|
+
require 'prompt/simple_matcher'
|
2
|
+
require 'prompt/multi_matcher'
|
3
|
+
|
1
4
|
module Prompt
|
2
5
|
module DSLHelper
|
3
6
|
|
4
|
-
# Split command into an array of Strings and
|
7
|
+
# Split command into an array of Strings and Matchers
|
5
8
|
def self.words command_name, parameters
|
6
9
|
command_name.strip.split(/\s+/).map do |word|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
desc = param ? param.desc : nil
|
17
|
-
GlobParameter.new(sym, desc)
|
18
|
-
else
|
19
|
-
word
|
20
|
-
end
|
10
|
+
if word[0] == ":"
|
11
|
+
param = find_param word, parameters
|
12
|
+
SimpleMatcher.new param
|
13
|
+
elsif word[0] == "*"
|
14
|
+
param = find_param word, parameters
|
15
|
+
MultiMatcher.new param
|
16
|
+
else
|
17
|
+
word
|
18
|
+
end
|
21
19
|
end
|
22
20
|
end
|
23
21
|
|
22
|
+
def self.find_param word, parameters
|
23
|
+
sym = word[1..-1].to_sym
|
24
|
+
parameters.find {|p| p.name == sym} || Parameter.new(sym)
|
25
|
+
end
|
26
|
+
|
24
27
|
end
|
25
28
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Prompt
|
2
|
+
class MultiMatcher < Matcher
|
3
|
+
|
4
|
+
def regex
|
5
|
+
"(?<#{parameter.name}>([^#{SEP}]*)(#{SEP}[^#{SEP}]*)*)"
|
6
|
+
end
|
7
|
+
|
8
|
+
def matches s
|
9
|
+
return [""] if s.length == 0
|
10
|
+
ss = StringScanner.new(s)
|
11
|
+
r = Regexp.new "[^#{SEP}]*"
|
12
|
+
res = []
|
13
|
+
until ss.eos?
|
14
|
+
ss.scan /#{SEP}/
|
15
|
+
res << ss.scan(r)
|
16
|
+
end
|
17
|
+
res
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/prompt/parameter.rb
CHANGED
@@ -3,34 +3,26 @@ module Prompt
|
|
3
3
|
|
4
4
|
attr :name
|
5
5
|
attr :desc
|
6
|
-
attr :values
|
7
6
|
|
8
|
-
def initialize(name, desc = nil, values = nil)
|
7
|
+
def initialize(name, desc = nil, values = nil, &block)
|
9
8
|
@name = name
|
10
9
|
@desc = desc
|
11
|
-
@values = values
|
10
|
+
@values = values || []
|
11
|
+
@proc = block if block_given?
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
|
16
|
-
"(?<#{name}>#{values.map{|v| Regexp.escape(v)}.join("|")})"
|
17
|
-
else
|
18
|
-
"(?<#{name}>([^#{Prompt::Command::SEP}]*))"
|
19
|
-
end
|
14
|
+
def clear_cached_values
|
15
|
+
@cached_value = nil
|
20
16
|
end
|
21
17
|
|
22
|
-
def expansions
|
23
|
-
if
|
24
|
-
|
25
|
-
(v =~ /\s/) ? "\"#{v}\"" : v
|
26
|
-
end
|
18
|
+
def expansions(starting_with = "")
|
19
|
+
all = if @proc
|
20
|
+
@cached_value = @proc.call
|
27
21
|
else
|
28
|
-
|
22
|
+
@values
|
29
23
|
end
|
30
|
-
end
|
31
24
|
|
32
|
-
|
33
|
-
s
|
25
|
+
all.grep /^#{starting_with}/
|
34
26
|
end
|
35
27
|
|
36
28
|
end
|
data/lib/prompt/prompt_module.rb
CHANGED
data/spec/prompt/command_spec.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
|
-
require 'prompt
|
2
|
-
require '
|
3
|
-
require 'prompt/glob_parameter'
|
1
|
+
require 'prompt'
|
2
|
+
require 'spec_helper'
|
4
3
|
|
5
4
|
include Prompt
|
6
5
|
|
7
6
|
describe Prompt::Command do
|
8
7
|
|
9
8
|
DIRECTIONS = %w{n e s w}
|
10
|
-
SPEEDS = %w{
|
9
|
+
SPEEDS = %w{slow slower}
|
11
10
|
|
12
11
|
describe "#match" do
|
13
12
|
|
@@ -16,13 +15,11 @@ describe Prompt::Command do
|
|
16
15
|
it "matches correctly" do
|
17
16
|
c = Command.new ["hi"]
|
18
17
|
|
19
|
-
c.match("hi").should == []
|
20
|
-
c.match("hi ").should == []
|
21
|
-
c.match(" hi").should == []
|
18
|
+
c.match(["hi"]).should == []
|
22
19
|
|
23
|
-
c.match("bye").should be_nil
|
24
|
-
c.match("h").should be_nil
|
25
|
-
c.match("").should be_nil
|
20
|
+
c.match(["bye"]).should be_nil
|
21
|
+
c.match(["h"]).should be_nil
|
22
|
+
c.match([""]).should be_nil
|
26
23
|
end
|
27
24
|
|
28
25
|
end
|
@@ -30,35 +27,24 @@ describe Prompt::Command do
|
|
30
27
|
describe "hi :name" do
|
31
28
|
|
32
29
|
it "matches correctly" do
|
33
|
-
c = Command.new ["hi",
|
30
|
+
c = Command.new ["hi", matcher(:name)]
|
34
31
|
|
35
|
-
c.match("hi guy").should == ["guy"]
|
36
|
-
c.match("hi
|
37
|
-
c.match("hi
|
38
|
-
c.match('hi "some guy"').should == ["some guy"]
|
39
|
-
c.match('hi ""').should == [""]
|
32
|
+
c.match(["hi", "guy"]).should == ["guy"]
|
33
|
+
c.match(["hi", "some guy"]).should == ["some guy"]
|
34
|
+
c.match(["hi", ""]).should == [""]
|
40
35
|
|
41
|
-
c.match("
|
42
|
-
c.match(
|
43
|
-
c.match('hi \'"').should == ['\'"']
|
44
|
-
|
45
|
-
c.match("higuy").should be_nil
|
46
|
-
c.match("higuy guy").should be_nil
|
47
|
-
|
48
|
-
c.match(" hi guy").should == ["guy"]
|
49
|
-
c.match("hi guy").should == ["guy"]
|
50
|
-
c.match("hi guy ").should == ["guy"]
|
36
|
+
c.match(["higuy"]).should be_nil
|
37
|
+
c.match(["higuy", "guy"]).should be_nil
|
51
38
|
end
|
52
39
|
|
53
40
|
it "matches correctly (with parameter value constraint)" do
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
c.match("hi
|
58
|
-
c.match("hi
|
59
|
-
c.match("hi charlie rose").should
|
60
|
-
c.match("hi zack").should
|
61
|
-
c.match("hi ali").should be_nil
|
41
|
+
name = Parameter.new(:name, "", ["alice", "bob", "charlie rose"])
|
42
|
+
c = Command.new ["hi", matcher(name)]
|
43
|
+
|
44
|
+
c.match(["hi", "alice"]).should == ["alice"]
|
45
|
+
c.match(["hi", "bob"]).should == ["bob"]
|
46
|
+
c.match(["hi", "charlie rose"]).should == ["charlie rose"]
|
47
|
+
c.match(["hi", "zack"]).should == ["zack"]
|
62
48
|
end
|
63
49
|
|
64
50
|
end
|
@@ -66,11 +52,12 @@ describe Prompt::Command do
|
|
66
52
|
describe "hi :first :last" do
|
67
53
|
|
68
54
|
it "matches correctly" do
|
69
|
-
c = Command.new ["hi",
|
55
|
+
c = Command.new ["hi", matcher(:first), matcher(:last)]
|
56
|
+
|
57
|
+
c.match(%w(hi agent smith)).should == ["agent", "smith"]
|
70
58
|
|
71
|
-
c.match(
|
72
|
-
c.match(
|
73
|
-
c.match("hi agent smith guy").should be_nil
|
59
|
+
c.match(%w(hi agent)).should be_nil
|
60
|
+
c.match(%w(hi agent smith guy)).should be_nil
|
74
61
|
end
|
75
62
|
|
76
63
|
end
|
@@ -78,14 +65,12 @@ describe Prompt::Command do
|
|
78
65
|
describe "say *stuff" do
|
79
66
|
|
80
67
|
it "matches correctly" do
|
81
|
-
c = Command.new ["say",
|
82
|
-
|
83
|
-
c.match("say hello").should == [["hello"]]
|
84
|
-
c.match("say hello world").should == [["hello", "world"]]
|
85
|
-
c.match("say
|
86
|
-
c.match("say
|
87
|
-
c.match("say 'hello world'").should == [["hello world"]]
|
88
|
-
c.match('say "hello world"').should == [["hello world"]]
|
68
|
+
c = Command.new ["say", multi_matcher(:stuff)]
|
69
|
+
|
70
|
+
c.match(["say", "hello"]).should == [["hello"]]
|
71
|
+
c.match(["say", "hello", "world"]).should == [["hello", "world"]]
|
72
|
+
c.match(["say", ""]).should == [[""]]
|
73
|
+
c.match(["say", "hello", ""]).should == [["hello", ""]]
|
89
74
|
end
|
90
75
|
|
91
76
|
end
|
@@ -93,12 +78,13 @@ describe Prompt::Command do
|
|
93
78
|
describe "say *stuff :adverb" do
|
94
79
|
|
95
80
|
it "matches correctly" do
|
96
|
-
c = Command.new ["say",
|
81
|
+
c = Command.new ["say", multi_matcher(:stuff), matcher(:adverb)]
|
82
|
+
|
83
|
+
c.match(["say", "hello", "world"]).should == [["hello"], "world"]
|
84
|
+
c.match(["say", "hello", "world", "loudly"]).should == [["hello", "world"], "loudly"]
|
85
|
+
c.match(["say", "hello", "world loudly"]).should == [["hello"], "world loudly"]
|
97
86
|
|
98
|
-
c.match("say hello").should be_nil
|
99
|
-
c.match("say hello loudly").should == [["hello"], "loudly"]
|
100
|
-
c.match("say hello world loudly").should == [["hello", "world"], "loudly"]
|
101
|
-
c.match("say hello 'world loudly'").should == [["hello"], "world loudly"]
|
87
|
+
c.match(["say", "hello"]).should be_nil
|
102
88
|
end
|
103
89
|
|
104
90
|
end
|
@@ -106,12 +92,12 @@ describe Prompt::Command do
|
|
106
92
|
describe "say *first *second" do
|
107
93
|
|
108
94
|
it "matches correctly" do
|
109
|
-
c = Command.new ["say",
|
95
|
+
c = Command.new ["say", multi_matcher(:first), multi_matcher(:second)]
|
110
96
|
|
111
|
-
c.match("say one").should be_nil
|
112
|
-
c.match("say one two").should == [["one"], ["two"]]
|
113
|
-
c.match("say one two three").should == [["one", "two"], ["three"]]
|
114
|
-
c.match("say one
|
97
|
+
c.match(["say", "one"]).should be_nil
|
98
|
+
c.match(["say", "one", "two"]).should == [["one"], ["two"]]
|
99
|
+
c.match(["say", "one", "two", "three"]).should == [["one", "two"], ["three"]]
|
100
|
+
c.match(["say", "one", "two three"]).should == [["one"], ["two three"]]
|
115
101
|
end
|
116
102
|
|
117
103
|
end
|
@@ -121,37 +107,58 @@ describe Prompt::Command do
|
|
121
107
|
describe "#parameters" do
|
122
108
|
it "returns correctly" do
|
123
109
|
color = Parameter.new(:color, "")
|
124
|
-
flavor =
|
110
|
+
flavor = Parameter.new(:flavor, "")
|
125
111
|
|
126
112
|
Command.new(["one"]).parameters.should == []
|
127
|
-
Command.new(["one", color]).parameters.should == [color]
|
128
|
-
Command.new(["one", color, flavor]).parameters == [color, flavor]
|
113
|
+
Command.new(["one", matcher(color)]).parameters.should == [color]
|
114
|
+
Command.new(["one", matcher(color), matcher(flavor)]).parameters == [color, flavor]
|
129
115
|
end
|
130
116
|
end
|
131
117
|
|
132
118
|
describe "#expansions" do
|
119
|
+
|
133
120
|
it "expands correctly with no parameters" do
|
134
|
-
Command.new
|
121
|
+
c = Command.new ["one"]
|
122
|
+
c.expansions(0, "").should == ["one"]
|
123
|
+
c.expansions(0, "on").should == ["one"]
|
124
|
+
c.expansions(0, "z").should == []
|
125
|
+
c.expansions(1, "").should == []
|
126
|
+
|
127
|
+
c = Command.new ["help", "-v"]
|
128
|
+
c.expansions(0, "").should == ["help"]
|
129
|
+
c.expansions(0, "he").should == ["help"]
|
130
|
+
c.expansions(0, "z").should == []
|
131
|
+
c.expansions(1, "").should == ["-v"]
|
132
|
+
c.expansions(1, "-v").should == ["-v"]
|
133
|
+
c.expansions(1, "z").should == []
|
135
134
|
end
|
136
135
|
|
137
136
|
it "expands correctly with undefined parameters" do
|
138
|
-
Command.new(["go",
|
137
|
+
c = Command.new(["go", matcher(:dir)])
|
138
|
+
c.expansions(0, "").should == ["go"]
|
139
|
+
c.expansions(0, "g").should == ["go"]
|
140
|
+
c.expansions(0, "go").should == ["go"]
|
141
|
+
c.expansions(1, "").should == []
|
139
142
|
end
|
140
143
|
|
141
144
|
it "expands correctly with defined parameters" do
|
142
145
|
dir = Parameter.new(:dir, "", DIRECTIONS)
|
146
|
+
c = Command.new(["go", matcher(dir)])
|
147
|
+
c.expansions(1, "").should == DIRECTIONS
|
148
|
+
|
143
149
|
speed = Parameter.new(:speed, "", SPEEDS)
|
144
|
-
Command.new(["go", dir
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
"go s quickly", "go s slowly",
|
149
|
-
"go w quickly", "go w slowly"]
|
150
|
+
c = Command.new(["go", matcher(dir), matcher(speed)])
|
151
|
+
c.expansions(2, "").should == SPEEDS
|
152
|
+
c.expansions(2, "slow").should == SPEEDS
|
153
|
+
c.expansions(2, "slowe").should == ["slower"]
|
150
154
|
end
|
151
155
|
|
152
|
-
it"expands correctly if parameter values have spaces" do
|
156
|
+
it "expands correctly if parameter values have spaces" do
|
153
157
|
speed = Parameter.new(:speed, "", ["fast", "very fast"])
|
154
|
-
Command.new(["go", speed])
|
158
|
+
c = Command.new(["go", matcher(speed)])
|
159
|
+
c.expansions(1, "").should == ['fast', 'very fast']
|
160
|
+
c.expansions(1, "f").should == ['fast']
|
161
|
+
c.expansions(1, "v").should == ['very fast']
|
155
162
|
end
|
156
163
|
end
|
157
164
|
|
@@ -160,8 +167,8 @@ describe Prompt::Command do
|
|
160
167
|
color = Parameter.new(:color, "")
|
161
168
|
|
162
169
|
Command.new(["one"]).usage.should == "one"
|
163
|
-
Command.new(["one", color]).usage.should == "one <color>"
|
164
|
-
Command.new(["one", color, "three"]).usage.should == "one <color> three"
|
170
|
+
Command.new(["one", matcher(color)]).usage.should == "one <color>"
|
171
|
+
Command.new(["one", matcher(color), "three"]).usage.should == "one <color> three"
|
165
172
|
end
|
166
173
|
end
|
167
174
|
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'prompt'
|
2
|
+
|
3
|
+
include Prompt
|
4
|
+
|
5
|
+
describe Prompt::Console do
|
6
|
+
describe ".split" do
|
7
|
+
|
8
|
+
context "simple words" do
|
9
|
+
{
|
10
|
+
"hi" => %w(hi),
|
11
|
+
"one two" => %w(one two),
|
12
|
+
"one :two" => %w(one :two),
|
13
|
+
"one *two" => %w(one *two),
|
14
|
+
"one_two" => %w(one_two)
|
15
|
+
}.each do |line, words|
|
16
|
+
it line do
|
17
|
+
Console.split(line).should == words
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "extra whitespace" do
|
23
|
+
{
|
24
|
+
" hi" => %w(hi),
|
25
|
+
"hi " => %w(hi),
|
26
|
+
" hi " => %w(hi),
|
27
|
+
"one two" => %w(one two),
|
28
|
+
}.each do |line, words|
|
29
|
+
it line do
|
30
|
+
Console.split(line).should == words
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "quoted strings" do
|
36
|
+
{
|
37
|
+
"say 'hello'" => %w(say hello),
|
38
|
+
'say "hello"' => %w(say hello),
|
39
|
+
"say 'hi world'" => ["say", "hi world"],
|
40
|
+
'say "hi world"' => ["say", "hi world"],
|
41
|
+
'say ""' => ["say", ""],
|
42
|
+
"say ''" => ["say", ""],
|
43
|
+
"say '' ok" => ["say", "", "ok"],
|
44
|
+
"say 'hi world'" => ["say", "hi world"]
|
45
|
+
}.each do |line, words|
|
46
|
+
it line do
|
47
|
+
Console.split(line).should == words
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "unmatched quotes" do
|
53
|
+
{
|
54
|
+
"'" => %w('),
|
55
|
+
'"' => %w("),
|
56
|
+
"alice's" => %w(alice's),
|
57
|
+
'alice"s' => %w(alice"s),
|
58
|
+
"'one' 'two" => %w(one 'two)
|
59
|
+
}.each do |line, words|
|
60
|
+
it line do
|
61
|
+
Console.split(line).should == words
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "quoted substrings" do
|
67
|
+
{
|
68
|
+
"'one'two" => %w(onetwo),
|
69
|
+
"'one''two'" => %w(onetwo),
|
70
|
+
"'one'\"two\"" => %w(onetwo)
|
71
|
+
}.each do |line, words|
|
72
|
+
it line do
|
73
|
+
Console.split(line).should == words
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'prompt/matcher'
|
2
|
+
|
3
|
+
def matcher(symbol_or_parameter)
|
4
|
+
SimpleMatcher.new(param(symbol_or_parameter))
|
5
|
+
end
|
6
|
+
|
7
|
+
def multi_matcher(symbol_or_parameter)
|
8
|
+
MultiMatcher.new(param(symbol_or_parameter))
|
9
|
+
end
|
10
|
+
|
11
|
+
def param(symbol_or_parameter)
|
12
|
+
if symbol_or_parameter.kind_of? Parameter
|
13
|
+
symbol_or_parameter
|
14
|
+
else
|
15
|
+
Parameter.new(symbol_or_parameter)
|
16
|
+
end
|
17
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prompt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-03-08 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Prompt makes it easy to build slick command-line applications with Tab
|
15
15
|
Completion, Command History, and Built-in Help
|
@@ -30,12 +30,15 @@ files:
|
|
30
30
|
- lib/prompt/console.rb
|
31
31
|
- lib/prompt/dsl.rb
|
32
32
|
- lib/prompt/dsl_helper.rb
|
33
|
-
- lib/prompt/
|
33
|
+
- lib/prompt/matcher.rb
|
34
|
+
- lib/prompt/multi_matcher.rb
|
34
35
|
- lib/prompt/parameter.rb
|
35
|
-
- lib/prompt/proc_parameter.rb
|
36
36
|
- lib/prompt/prompt_module.rb
|
37
|
+
- lib/prompt/simple_matcher.rb
|
37
38
|
- lib/prompt.rb
|
38
39
|
- spec/prompt/command_spec.rb
|
40
|
+
- spec/prompt/console_spec.rb
|
41
|
+
- spec/spec_helper.rb
|
39
42
|
- examples/file_manager
|
40
43
|
- examples/mud
|
41
44
|
homepage: http://github.com/mudynamics/prompt
|
@@ -49,16 +52,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
49
52
|
requirements:
|
50
53
|
- - ! '>='
|
51
54
|
- !ruby/object:Gem::Version
|
52
|
-
version:
|
55
|
+
version: 1.9.2
|
53
56
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
57
|
none: false
|
55
58
|
requirements:
|
56
59
|
- - ! '>='
|
57
60
|
- !ruby/object:Gem::Version
|
58
|
-
version:
|
61
|
+
version: '0'
|
59
62
|
requirements: []
|
60
63
|
rubyforge_project:
|
61
|
-
rubygems_version: 1.8.
|
64
|
+
rubygems_version: 1.8.11
|
62
65
|
signing_key:
|
63
66
|
specification_version: 3
|
64
67
|
summary: A small framework that makes it easy to build slick command-line applications
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module Prompt
|
2
|
-
class GlobParameter < Parameter
|
3
|
-
|
4
|
-
def initialize(name, desc = nil)
|
5
|
-
super(name, desc)
|
6
|
-
end
|
7
|
-
|
8
|
-
def regex
|
9
|
-
"(?<#{name}>(([^#{Prompt::Command::SEP}]*)#{Prompt::Command::SEP}?)+)"
|
10
|
-
end
|
11
|
-
|
12
|
-
def matches s
|
13
|
-
s.split(Prompt::Command::SEP)
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
17
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
module Prompt
|
2
|
-
class ProcParameter < Parameter
|
3
|
-
|
4
|
-
def initialize(name, desc, &block)
|
5
|
-
super(name, desc, nil)
|
6
|
-
@proc = block
|
7
|
-
end
|
8
|
-
|
9
|
-
def values
|
10
|
-
@cached_value ||= @proc.call
|
11
|
-
end
|
12
|
-
|
13
|
-
def clear_cached_value
|
14
|
-
@cached_value = nil
|
15
|
-
end
|
16
|
-
|
17
|
-
end
|
18
|
-
end
|