harp 0.2.4 → 0.2.6
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/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: []
|