shell_shock 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.rdoc +65 -5
  2. data/lib/shell_shock/context.rb +49 -16
  3. metadata +23 -9
data/README.rdoc CHANGED
@@ -14,10 +14,70 @@ A library for creating command line shell application.
14
14
 
15
15
  == Usage
16
16
 
17
- Here's a sample shell application using shell shock:
17
+ The basic idea is that you create classes with the ShellShock::Context mixin. Start a shell by instantiating the class and executing the push method. Any number of nested shells may be pushed and exit falls back to the previous shell.
18
18
 
19
- require '
19
+ These classes represent a shell context with a number of commands registered. These commands are matched with tab completion. In addition to registered commands, 'exit', 'quit', 'help' and '?' are always available.
20
20
 
21
- class RootContext
22
-
23
- end
21
+ Each command must have an execute method that accepts a string (the remaining content after the command name). Commands may also implement usage and help methods. They may also implement a completion method so may have arbitrarily complex completion rules per parameter.
22
+
23
+ Here's a sample shell application using shell shock. It has 'cd' and 'cat' commands. 'cd' performs tab completion for directories and execution enters a nested context. 'cat' performs tab completion for files and execution dumps the file content.
24
+
25
+ require 'shell_shock/context'
26
+
27
+ class CatFileCommand
28
+ def initialize path
29
+ @path = path
30
+ end
31
+
32
+ def usage
33
+ '<file name>'
34
+ end
35
+
36
+ def help
37
+ 'displays the content of a file'
38
+ end
39
+
40
+ def completion text
41
+ Dir.glob("#{@path}/#{text}*").select {|f| File.file?(f) }
42
+ end
43
+
44
+ def execute path
45
+ File.open(path) {|f| f.each_with_index {|l,i| puts "#{i+1}: #{l}" } }
46
+ end
47
+ end
48
+
49
+ class ChangeDirectoryCommand
50
+ def initialize path
51
+ @path = path
52
+ end
53
+
54
+ def usage
55
+ '<directory name>'
56
+ end
57
+
58
+ def help
59
+ 'switches to a new shell context in the specified directory'
60
+ end
61
+
62
+ def completion text
63
+ Dir.glob("#{@path}/#{text}*").select {|f| File.directory?(f) }
64
+ end
65
+
66
+ def execute text
67
+ DirectoryContext.new(text).push
68
+ end
69
+ end
70
+
71
+ class DirectoryContext
72
+ include ShellShock::Context
73
+
74
+ def initialize path
75
+ @prompt_text = "#{path} > "
76
+ @commands = {
77
+ 'cd' => ChangeDirectoryCommand.new(path),
78
+ 'cat' => CatFileCommand.new(path)
79
+ }
80
+ end
81
+ end
82
+
83
+ DirectoryContext.new('.').push
@@ -1,15 +1,28 @@
1
- require 'readline'
2
1
  require 'rubygems'
3
- require 'active_support/inflector'
2
+ require 'readline'
4
3
 
5
4
  module ShellShock
6
5
  module Context
7
6
  def refresh
8
- commands = respond_to?(:refresh_commands) ? refresh_commands : []
9
- Readline.completion_proc = lambda do |text|
10
- (commands + @commands.keys + ['quit', 'exit']).grep( /^#{Regexp.escape(text)}/ ).sort
11
- end
7
+ refresh_commands if respond_to?(:refresh_commands)
12
8
  Readline.completer_word_break_characters = ''
9
+ Readline.completion_proc = lambda do |word|
10
+ name, *words = word.scan(/[\w?]+/)
11
+ if name
12
+ command = @commands[name]
13
+ if command
14
+ if command.respond_to?(:completion)
15
+ rest = words || []
16
+ completions = command.completion(rest.join(' ')).map {|c| "#{name} #{c}" }
17
+ return completions
18
+ else
19
+ return []
20
+ end
21
+ end
22
+ end
23
+
24
+ @commands.keys.grep( /^#{Regexp.escape(word)}/ ).sort
25
+ end
13
26
  end
14
27
 
15
28
  def push
@@ -18,14 +31,14 @@ module ShellShock
18
31
  while line = Readline.readline(@prompt_text, true)
19
32
  line.strip!
20
33
  case line
21
- when 'quit','exit'
22
- return
23
- when /(\w+) (.*)/
34
+ when /^([\w?]+) (.*)/
35
+ return if ['quit', 'exit'].include?($1)
24
36
  process_command $1, $2
25
- when /(\w+)/
37
+ when /^([\w?]+)/
38
+ return if ['quit', 'exit'].include?($1)
26
39
  process_command $1
27
40
  else
28
- puts 'unknown command'
41
+ puts "can not process line \"#{line}\""
29
42
  end
30
43
  puts
31
44
  refresh
@@ -36,16 +49,36 @@ module ShellShock
36
49
  puts
37
50
  end
38
51
 
52
+ def display_help_for_command command_name
53
+ command = @commands[command_name]
54
+ if command
55
+ @io.say "Command \"#{command_name}\""
56
+ @io.say "Usage: #{command_name} #{command.usage}" if command.respond_to?(:usage)
57
+ @io.say "Help:\n #{command.help}" if command.respond_to?(:help)
58
+ else
59
+ puts "no help available for command \"#{command_name}\""
60
+ end
61
+ end
62
+
63
+ def process_help command=nil
64
+ if command
65
+ display_help_for_command command
66
+ else
67
+ @io.say "Available commands:"
68
+ @commands.keys.sort.each { |command| @io.say command }
69
+ @io.say
70
+ end
71
+ end
72
+
39
73
  def process_command name, parameter=nil
40
- m = "#{name}_command".to_sym
41
- if respond_to?(m)
42
- send(m, parameter)
74
+ if ['?', 'help'].include?(name)
75
+ process_help parameter
43
76
  return
44
- end
77
+ end
45
78
  if @commands[name]
46
79
  @commands[name].execute parameter
47
80
  else
48
- @io.say 'unknown command'
81
+ @io.say "unknown command \"#{name}\""
49
82
  end
50
83
  end
51
84
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 2
9
+ version: 0.0.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Mark Ryall
@@ -14,23 +14,37 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-11 00:00:00 +10:00
17
+ date: 2010-04-13 00:00:00 +10:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- name: activesupport
21
+ name: rake
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - ~>
26
26
  - !ruby/object:Gem::Version
27
27
  segments:
28
- - 2
29
- - 3
30
- - 5
31
- version: 2.3.5
32
- type: :runtime
28
+ - 0
29
+ - 8
30
+ - 7
31
+ version: 0.8.7
32
+ type: :development
33
33
  version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: gemesis
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ - 0
44
+ - 3
45
+ version: 0.0.3
46
+ type: :development
47
+ version_requirements: *id002
34
48
  description: |
35
49
  This is just some code extracted from a few command line gems i've created (shh and cardigan).
36
50