shell_shock 0.0.1 → 0.0.2

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.
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