harp 0.2.4 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/examples/usage.rb +10 -10
  2. data/lib/harp.rb +41 -74
  3. 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
- setup_repl do |repl|
14
+ setup_harp do |harp|
15
15
 
16
- on("help") do
17
- commands = repl.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
- on("quit") do
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
- # 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
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
- on(/use (\S+)$/) do |args|
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
- @repl = REPL.new
13
- def self.repl
14
- @repl
15
- end
13
+ @dispatcher = Dispatcher.new
16
14
 
17
- def self.setup_repl(&block)
18
- repl = @repl
19
- @repl.on("quit") do
20
- repl.exit
21
- end
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
- @repl.instance_exec(repl, &block)
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
- @patterns = {}
39
- @commands = Set.new
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.dir_complete(str)
48
+ self.complete_path(str)
49
49
  else
50
50
  # otherwise use the internal dict.
51
- self.term_complete(str)
51
+ self.complete_term(str)
52
52
  end
53
53
  end
54
54
 
55
- def dir_complete(str)
55
+ def complete_path(str)
56
56
  Dir.glob("#{str}*")
57
57
  end
58
58
 
59
- def term_complete(str)
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
- # Somebody should have documented this when he wrote it, because
66
- # he now does not remember exactly what he was trying to achieve.
67
- # He thinks that it's an attempt to allow completion of either
68
- # full configuration index strings, or of component parts.
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
- self.parse(context, line.chomp)
121
- end
122
- end
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
- def exit
125
- @run = false
126
- end
98
+ if line.empty?
99
+ next
100
+ end
127
101
 
128
- # Attempt to find a registered command that matches the input
129
- # string. Upon failure, print an encouraging message.
130
- def parse(context, input_string)
131
- _p, block= @patterns.detect do |pattern, block|
132
- pattern === input_string
133
- end
134
- if block
135
- # Perlish global ugliness necessitated by the use of
136
- # Enumerable#detect above. FIXME.
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
- context.instance_eval(&block)
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
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-08-31 00:00:00.000000000 Z
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.0
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.0
29
+ version: 0.1.1
30
30
  description:
31
31
  email:
32
32
  executables: []