harp 0.2.6 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
data/examples/usage.rb CHANGED
@@ -1,3 +1,4 @@
1
+ $:.unshift "#{File.expand_path(File.dirname(__FILE__))}/../lib"
1
2
  require "harp"
2
3
 
3
4
  class UsefulThing
@@ -12,32 +13,26 @@ class UsefulThing
12
13
 
13
14
  # Set it up
14
15
  setup_harp do |harp|
16
+ command_names = harp.command_names.select {|name| name.size > 1 }
15
17
 
16
- command("help") do
17
- commands = harp.command_names
18
- puts "* Available commands: " << commands.sort.join(" ")
18
+ command("help", :alias => "h") do
19
+ puts "* Available commands: " << command_names.sort.join(", ")
19
20
  puts "* Tab completion works for commands."
20
21
  end
21
22
 
22
- # Harp provides a "quit" command by default, but you can
23
+ # Harp's repl provides a "quit" command by default, but you can
23
24
  # override it to add value.
24
- command("quit") do
25
+ command("quit", :alias => "q") do
25
26
  puts "Farewell to the girl with the sun in her eyes."
26
27
  exit
27
28
  end
28
29
 
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
-
35
30
  # define a command that calls an instance method of your class.
36
31
  # The block parameter is always an array, even if your regex
37
32
  # had only one match group.
38
33
  # This command will only accept a single-word argument (no
39
34
  # whitespace allowed).
40
- command("use", :adverb) do |args|
35
+ command("use", :adverb, :alias => "abuse") do |args|
41
36
  self.use(args.first)
42
37
  end
43
38
 
@@ -45,5 +40,5 @@ class UsefulThing
45
40
 
46
41
  end
47
42
 
48
- UsefulThing.new.repl
43
+ #UsefulThing.new.repl
49
44
 
data/lib/harp.rb CHANGED
@@ -1,119 +1,37 @@
1
- # stdlib
2
- require "set"
3
- require "readline"
4
-
5
- Readline.completion_append_character = nil
6
- #Readline.basic_word_break_characters = ""
7
-
8
- require "harp/dispatcher"
1
+ require "harp/command_manager"
2
+ require "harp/repl"
3
+ require "harp/cli"
9
4
 
10
5
  module Harp
11
6
  def self.included(mod)
12
7
  mod.module_eval do
13
- @dispatcher = Dispatcher.new
8
+ @command_manager = CommandManager.new
14
9
 
15
10
  def self.setup_harp(&block)
16
- dispatcher = @dispatcher
11
+ command_manager = @command_manager
17
12
  # This should either be baked in to REPL, or non-existent.
18
- @dispatcher.command("quit") do
13
+ @command_manager.command("quit") do
19
14
  exit
20
15
  end
21
- @dispatcher.instance_exec(dispatcher, &block)
16
+ @command_manager.instance_exec(command_manager, &block)
22
17
  end
23
18
 
24
19
  def self.repl
25
- REPL.new(@dispatcher)
20
+ REPL.new(@command_manager)
26
21
  end
27
22
 
28
23
  def repl
29
24
  self.class.repl.run(self)
30
25
  end
31
- end
32
- end
33
-
34
- class REPL
35
-
36
- attr_reader :store, :commands
37
- def initialize(dispatcher)
38
- @dispatcher = dispatcher
39
- @commands = dispatcher.commands.keys
40
- Readline.completion_proc = self.method(:complete)
41
- end
42
-
43
- def complete(str)
44
- case Readline.line_buffer
45
- when /^\s*!/
46
- # if we're in the middle of a bang-exec command, completion
47
- # should look at the file system.
48
- self.complete_path(str)
49
- else
50
- # otherwise use the internal dict.
51
- self.complete_term(str)
52
- end
53
- end
54
-
55
- def complete_path(str)
56
- Dir.glob("#{str}*")
57
- end
58
26
 
59
- def complete_term(str)
60
- # Terms can be either commands or indexes into the configuration
61
- # data structure. No command contains a ".", so that's the test
62
- # we use to distinguish.
63
- bits = str.split(".")
64
- if bits.size > 1
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".
69
- v1 = @completions.grep(/^#{Regexp.escape(str)}/)
70
- v2 = @completions.grep(/^#{Regexp.escape(bits.last)}/)
71
- (v1 + v2.map {|x| (bits.slice(0..-2) << x).join(".") }).uniq
72
- else
73
- self.command_complete(str) +
74
- @completions.grep(/^#{Regexp.escape(str)}/)
27
+ def self.cli
28
+ CLI.new(@command_manager)
75
29
  end
76
- end
77
-
78
- def command_complete(str)
79
- @commands.grep(/^#{Regexp.escape(str)}/)
80
- end
81
-
82
- def sanitize(str)
83
- # ANSI code stripper regex cargo culted from
84
- # http://www.commandlinefu.com/commands/view/3584/remove-color-codes-special-characters-with-sed
85
- str.gsub(/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]/, "")
86
- end
87
-
88
- def run(context)
89
- @completions = context.completions rescue Set.new
90
- @run = true
91
- puts
92
- while @run && (line = Readline.readline("<3: ", true).strip)
93
- if line[0] == "!"
94
- system(line.slice(1..-1))
95
- next
96
- end
97
-
98
- if line.empty?
99
- next
100
- end
101
30
 
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
111
- else
112
- puts "command not found"
113
- end
31
+ def cli
32
+ self.class.cli.run(self)
114
33
  end
115
34
  end
116
-
117
35
  end
118
36
 
119
37
  end
data/lib/harp/cli.rb ADDED
@@ -0,0 +1,24 @@
1
+
2
+ module Harp
3
+
4
+ class CLI
5
+
6
+ def initialize(command_manager)
7
+ @command_manager = command_manager
8
+ @commands = command_manager.commands.keys
9
+ end
10
+
11
+ def run(context)
12
+ name, *args = parse(ARGV)
13
+ @command_manager.handle(name, args, context)
14
+ end
15
+
16
+ def parse(array)
17
+ array
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+
24
+
@@ -0,0 +1,74 @@
1
+ module Harp
2
+
3
+ class CommandManager
4
+
5
+ attr_reader :commands
6
+ def initialize
7
+ @commands = {}
8
+ end
9
+
10
+ def handle(name, args, context)
11
+ block = find_command(name, args)
12
+ context.instance_exec(args, &block)
13
+ end
14
+
15
+ def find_command(name, args)
16
+ if command = @commands[name]
17
+ if block = command.block_for(args)
18
+ return block
19
+ else
20
+ raise ArgumentError, "Invalid arguments for command."
21
+ end
22
+ else
23
+ raise ArgumentError, "Command not found: '#{name}'."
24
+ end
25
+ end
26
+
27
+ def command(command_name, *spec, &block)
28
+ names = [command_name]
29
+ if spec.last.is_a?(Hash)
30
+ options = spec.pop
31
+ if command_alias = options[:alias]
32
+ names << command_alias
33
+ end
34
+ end
35
+ names.each do |name|
36
+ command = @commands[name] ||= Command.new(name)
37
+ command.add_spec(spec, block)
38
+ end
39
+ end
40
+
41
+ def command_names
42
+ @commands.keys.sort
43
+ end
44
+
45
+ end
46
+
47
+ class Command
48
+ def initialize(name)
49
+ @name = name
50
+ @blocks = {}
51
+ end
52
+
53
+ def add_spec(spec, block)
54
+ # TODO validate block and arity
55
+ @blocks[spec]= block
56
+ end
57
+
58
+ def block_for(args)
59
+ @blocks.each do |spec, block|
60
+ if match(spec, args)
61
+ return block
62
+ end
63
+ end
64
+ return nil
65
+ end
66
+
67
+ def match(spec, args)
68
+ spec.size == args.size
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+
data/lib/harp/repl.rb ADDED
@@ -0,0 +1,94 @@
1
+ # stdlib
2
+ require "set"
3
+ require "readline"
4
+
5
+ Readline.completion_append_character = nil
6
+ #Readline.basic_word_break_characters = ""
7
+
8
+ module Harp
9
+
10
+ class REPL
11
+
12
+ def initialize(command_manager)
13
+ @command_manager = command_manager
14
+ Readline.completion_proc = self.method(:complete)
15
+ end
16
+
17
+ def commands
18
+ @command_manager.commands.keys
19
+ end
20
+
21
+ def complete(str)
22
+ case Readline.line_buffer
23
+ when /^\s*!/
24
+ # if we're in the middle of a bang-exec command, completion
25
+ # should look at the file system.
26
+ self.complete_path(str)
27
+ else
28
+ # otherwise use the internal dict.
29
+ self.complete_term(str)
30
+ end
31
+ end
32
+
33
+ def complete_path(str)
34
+ Dir.glob("#{str}*")
35
+ end
36
+
37
+ def complete_term(str)
38
+ # Terms can be either commands or indexes into the configuration
39
+ # data structure. No command contains a ".", so that's the test
40
+ # we use to distinguish.
41
+ bits = str.split(".")
42
+ if bits.size > 1
43
+ # An attempt to allow completion of either full configuration index
44
+ # strings, or of component parts. E.g., if the configuration contains
45
+ # foo.bar.baz, this code will offer both "foo" and "foo.bar.baz"
46
+ # as completions for "fo".
47
+ v1 = @completions.grep(/^#{Regexp.escape(str)}/)
48
+ v2 = @completions.grep(/^#{Regexp.escape(bits.last)}/)
49
+ (v1 + v2.map {|x| (bits.slice(0..-2) << x).join(".") }).uniq
50
+ else
51
+ self.command_complete(str) +
52
+ @completions.grep(/^#{Regexp.escape(str)}/)
53
+ end
54
+ end
55
+
56
+ def command_complete(str)
57
+ commands.grep(/^#{Regexp.escape(str)}/)
58
+ end
59
+
60
+ def sanitize(str)
61
+ # ANSI code stripper regex cargo culted from
62
+ # http://www.commandlinefu.com/commands/view/3584/remove-color-codes-special-characters-with-sed
63
+ str.gsub(/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]/, "")
64
+ end
65
+
66
+ def run(context)
67
+ @completions = context.completions rescue Set.new
68
+ @run = true
69
+ puts
70
+ while @run && (line = Readline.readline("<3: ", true).strip)
71
+ # Treat ! as the shell out command
72
+ if line[0] == "!"
73
+ system(line.slice(1..-1))
74
+ next
75
+ end
76
+
77
+ if line.empty?
78
+ next
79
+ end
80
+
81
+ name, *args = line.split(/\s+/)
82
+
83
+ begin
84
+ @command_manager.handle(name, args, context)
85
+ rescue ArgumentError => e
86
+ puts e.message
87
+ end
88
+ end
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+
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.6
4
+ version: 0.2.7
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-09-10 00:00:00.000000000 Z
12
+ date: 2012-09-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: starter
@@ -35,8 +35,11 @@ extra_rdoc_files: []
35
35
  files:
36
36
  - README.md
37
37
  - LICENSE
38
- - lib/harp.rb
39
38
  - examples/usage.rb
39
+ - lib/harp/cli.rb
40
+ - lib/harp/command_manager.rb
41
+ - lib/harp/repl.rb
42
+ - lib/harp.rb
40
43
  homepage: https://github.com/automatthew/harp
41
44
  licenses: []
42
45
  post_install_message: