harp 0.2.4 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- data/examples/usage.rb +10 -10
- data/lib/harp.rb +41 -74
- metadata +4 -4
data/examples/usage.rb
CHANGED
@@ -11,33 +11,33 @@ class UsefulThing
|
|
11
11
|
include Harp
|
12
12
|
|
13
13
|
# Set it up
|
14
|
-
|
14
|
+
setup_harp do |harp|
|
15
15
|
|
16
|
-
|
17
|
-
commands =
|
16
|
+
command("help") do
|
17
|
+
commands = harp.command_names
|
18
18
|
puts "* Available commands: " << commands.sort.join(" ")
|
19
19
|
puts "* Tab completion works for commands."
|
20
20
|
end
|
21
21
|
|
22
22
|
# Harp provides a "quit" command by default, but you can
|
23
23
|
# override it to add value.
|
24
|
-
|
24
|
+
command("quit") do
|
25
25
|
puts "Farewell to the girl with the sun in her eyes."
|
26
26
|
exit
|
27
27
|
end
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
on_bang do |args|
|
32
|
-
system args.first
|
33
|
-
end
|
29
|
+
## Set up a handler for a command where the first token is "!"
|
30
|
+
## I.e., shell out like Vim does.
|
31
|
+
#on_bang do |args|
|
32
|
+
#system args.first
|
33
|
+
#end
|
34
34
|
|
35
35
|
# define a command that calls an instance method of your class.
|
36
36
|
# The block parameter is always an array, even if your regex
|
37
37
|
# had only one match group.
|
38
38
|
# This command will only accept a single-word argument (no
|
39
39
|
# whitespace allowed).
|
40
|
-
|
40
|
+
command("use", :adverb) do |args|
|
41
41
|
self.use(args.first)
|
42
42
|
end
|
43
43
|
|
data/lib/harp.rb
CHANGED
@@ -5,24 +5,24 @@ require "readline"
|
|
5
5
|
Readline.completion_append_character = nil
|
6
6
|
#Readline.basic_word_break_characters = ""
|
7
7
|
|
8
|
+
require "harp/dispatcher"
|
8
9
|
|
9
10
|
module Harp
|
10
11
|
def self.included(mod)
|
11
12
|
mod.module_eval do
|
12
|
-
@
|
13
|
-
def self.repl
|
14
|
-
@repl
|
15
|
-
end
|
13
|
+
@dispatcher = Dispatcher.new
|
16
14
|
|
17
|
-
def self.
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
@repl.on("") do
|
23
|
-
puts "Giving me the silent treatment, eh?"
|
15
|
+
def self.setup_harp(&block)
|
16
|
+
dispatcher = @dispatcher
|
17
|
+
# This should either be baked in to REPL, or non-existent.
|
18
|
+
@dispatcher.command("quit") do
|
19
|
+
exit
|
24
20
|
end
|
25
|
-
@
|
21
|
+
@dispatcher.instance_exec(dispatcher, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.repl
|
25
|
+
REPL.new(@dispatcher)
|
26
26
|
end
|
27
27
|
|
28
28
|
def repl
|
@@ -34,9 +34,9 @@ module Harp
|
|
34
34
|
class REPL
|
35
35
|
|
36
36
|
attr_reader :store, :commands
|
37
|
-
def initialize
|
38
|
-
@
|
39
|
-
@commands =
|
37
|
+
def initialize(dispatcher)
|
38
|
+
@dispatcher = dispatcher
|
39
|
+
@commands = dispatcher.commands.keys
|
40
40
|
Readline.completion_proc = self.method(:complete)
|
41
41
|
end
|
42
42
|
|
@@ -45,29 +45,27 @@ module Harp
|
|
45
45
|
when /^\s*!/
|
46
46
|
# if we're in the middle of a bang-exec command, completion
|
47
47
|
# should look at the file system.
|
48
|
-
self.
|
48
|
+
self.complete_path(str)
|
49
49
|
else
|
50
50
|
# otherwise use the internal dict.
|
51
|
-
self.
|
51
|
+
self.complete_term(str)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
def
|
55
|
+
def complete_path(str)
|
56
56
|
Dir.glob("#{str}*")
|
57
57
|
end
|
58
58
|
|
59
|
-
def
|
59
|
+
def complete_term(str)
|
60
60
|
# Terms can be either commands or indexes into the configuration
|
61
61
|
# data structure. No command contains a ".", so that's the test
|
62
62
|
# we use to distinguish.
|
63
63
|
bits = str.split(".")
|
64
64
|
if bits.size > 1
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
# E.g., if the configuration contains foo.bar.baz, this code
|
70
|
-
# will offer both "foo" and "foo.bar.baz" as completions for "fo".
|
65
|
+
# An attempt to allow completion of either full configuration index
|
66
|
+
# strings, or of component parts. E.g., if the configuration contains
|
67
|
+
# foo.bar.baz, this code will offer both "foo" and "foo.bar.baz"
|
68
|
+
# as completions for "fo".
|
71
69
|
v1 = @completions.grep(/^#{Regexp.escape(str)}/)
|
72
70
|
v2 = @completions.grep(/^#{Regexp.escape(bits.last)}/)
|
73
71
|
(v1 + v2.map {|x| (bits.slice(0..-2) << x).join(".") }).uniq
|
@@ -87,63 +85,32 @@ module Harp
|
|
87
85
|
str.gsub(/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]/, "")
|
88
86
|
end
|
89
87
|
|
90
|
-
def on(*pattern, &block)
|
91
|
-
pattern.flatten.each do |pattern|
|
92
|
-
@patterns[pattern] = block
|
93
|
-
self.add_command(pattern)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
# Helper for defining the action for the "!" command.
|
98
|
-
# Typically used to shell out, a la Vim.
|
99
|
-
def on_bang(&block)
|
100
|
-
on(/^\!\s*(.*)$/, &block)
|
101
|
-
end
|
102
|
-
|
103
|
-
def add_command(pattern)
|
104
|
-
if pattern.is_a?(String)
|
105
|
-
@commands << pattern
|
106
|
-
else
|
107
|
-
bits = pattern.source.split(" ")
|
108
|
-
# TODO: figure out why you did this, then document it.
|
109
|
-
if bits.size > 1
|
110
|
-
@commands << bits.first
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
88
|
def run(context)
|
116
89
|
@completions = context.completions rescue Set.new
|
117
90
|
@run = true
|
118
91
|
puts
|
119
|
-
while @run && line = Readline.readline("<3: ", true)
|
120
|
-
|
121
|
-
|
122
|
-
|
92
|
+
while @run && (line = Readline.readline("<3: ", true).strip)
|
93
|
+
if line[0] == "!"
|
94
|
+
system(line.slice(1..-1))
|
95
|
+
next
|
96
|
+
end
|
123
97
|
|
124
|
-
|
125
|
-
|
126
|
-
|
98
|
+
if line.empty?
|
99
|
+
next
|
100
|
+
end
|
127
101
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
if $1
|
138
|
-
# if the regex had a group (based on the assumption that $1
|
139
|
-
# represents the result of the === that matched), call the block
|
140
|
-
# with all the group matches as arguments.
|
141
|
-
context.instance_exec($~[1..-1], &block)
|
102
|
+
name, *args = line.split(/\s+/)
|
103
|
+
|
104
|
+
# TODO: check for bang command
|
105
|
+
if command = @dispatcher.commands[name]
|
106
|
+
if block = command.block_for(args)
|
107
|
+
context.instance_exec(args, &block)
|
108
|
+
else
|
109
|
+
puts "invalid arguments for command"
|
110
|
+
end
|
142
111
|
else
|
143
|
-
|
112
|
+
puts "command not found"
|
144
113
|
end
|
145
|
-
else
|
146
|
-
puts "command not found"
|
147
114
|
end
|
148
115
|
end
|
149
116
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: harp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.6
|
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-09-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: starter
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.1.
|
21
|
+
version: 0.1.1
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.1.
|
29
|
+
version: 0.1.1
|
30
30
|
description:
|
31
31
|
email:
|
32
32
|
executables: []
|