consolize 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/LICENSE +9 -0
  2. data/README.md +81 -0
  3. data/examples/usage.rb +49 -0
  4. data/lib/consolize.rb +157 -0
  5. metadata +85 -0
data/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ Copyright (c) 2012 Matthew King
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8
+
9
+
data/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # Consolize
2
+
3
+ A mixin for creating application consoles with Readline support.
4
+
5
+ ## Example
6
+
7
+ ```ruby
8
+ gem install consolize
9
+
10
+ require "consolize"
11
+
12
+ class UsefulThing
13
+
14
+ # define all the useful methods and behaviors you need
15
+ def use(adverb)
16
+ puts "You used me #{adverb}!"
17
+ end
18
+
19
+ # Mix it in
20
+ include Consolize
21
+
22
+ # Set it up
23
+ setup_console do |console|
24
+
25
+ on("help") do
26
+ commands = console.commands
27
+ puts "* Available commands: " << commands.sort.join(" ")
28
+ puts "* Tab completion works for commands."
29
+ end
30
+
31
+ # Consolize provides a "quit" command by default, but you can
32
+ # override it to add value.
33
+ on("quit") do
34
+ puts "Farewell to the girl with the sun in her eyes."
35
+ exit
36
+ end
37
+
38
+ # Set up a handler for a command where the first token is "!"
39
+ # I.e., shell out like Vim does.
40
+ on_bang do |args|
41
+ system args.first
42
+ end
43
+
44
+ # define a command that calls an instance method of your class.
45
+ # The block parameter is always an array, even if your regex
46
+ # had only one match group.
47
+ # This command will only accept a single-word argument (no
48
+ # whitespace allowed).
49
+ on(/use (\S+)$/) do |args|
50
+ self.use(args.first)
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+
57
+ UsefulThing.new.console
58
+ ```
59
+
60
+
61
+ ## Usage
62
+
63
+
64
+ $ ruby -I lib/ examples/usage.rb
65
+
66
+ <3: help
67
+ * Available commands: help quit use
68
+ * Tab completion works for commands.
69
+ <3: use well
70
+ You used me well!
71
+ <3: use badly
72
+ You used me badly!
73
+ <3: use without proper care
74
+ command not found
75
+ <3: ! ls
76
+ LICENSE README.md consolize.gemspec examples lib
77
+ <3: quit
78
+ Farewell to the girl with the sun in her eyes.
79
+
80
+
81
+
data/examples/usage.rb ADDED
@@ -0,0 +1,49 @@
1
+ require "consolize"
2
+
3
+ class UsefulThing
4
+
5
+ # define all the useful methods and behaviors you need
6
+ def use(adverb)
7
+ puts "You used me #{adverb}!"
8
+ end
9
+
10
+ # Mix it in
11
+ include Consolize
12
+
13
+ # Set it up
14
+ setup_console do |console|
15
+
16
+ on("help") do
17
+ commands = console.commands
18
+ puts "* Available commands: " << commands.sort.join(" ")
19
+ puts "* Tab completion works for commands."
20
+ end
21
+
22
+ # Consolize provides a "quit" command by default, but you can
23
+ # override it to add value.
24
+ on("quit") do
25
+ puts "Farewell to the girl with the sun in her eyes."
26
+ exit
27
+ end
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
34
+
35
+ # define a command that calls an instance method of your class.
36
+ # The block parameter is always an array, even if your regex
37
+ # had only one match group.
38
+ # This command will only accept a single-word argument (no
39
+ # whitespace allowed).
40
+ on(/use (\S+)$/) do |args|
41
+ self.use(args.first)
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+
48
+ UsefulThing.new.console
49
+
data/lib/consolize.rb ADDED
@@ -0,0 +1,157 @@
1
+ # stdlib
2
+ require "set"
3
+
4
+ # others
5
+ require "rubygems"
6
+ gem "rb-readline"
7
+ require "readline"
8
+
9
+ Readline.completion_append_character = nil
10
+ #Readline.basic_word_break_characters = ""
11
+
12
+
13
+ module Consolize
14
+ def self.included(mod)
15
+ mod.module_eval do
16
+ @console = Console.new
17
+ def self.console
18
+ @console
19
+ end
20
+
21
+ def self.setup_console(&block)
22
+ console = @console
23
+ @console.on("quit") do
24
+ console.exit
25
+ end
26
+ @console.on("") do
27
+ puts "Giving me the silent treatment, eh?"
28
+ end
29
+ @console.instance_exec(console, &block)
30
+ end
31
+
32
+ def console
33
+ self.class.console.run(self)
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ class Console
40
+
41
+ attr_reader :store, :commands
42
+ def initialize
43
+ @patterns = {}
44
+ @commands = Set.new
45
+ Readline.completion_proc = self.method(:complete)
46
+ end
47
+
48
+ def complete(str)
49
+ case Readline.line_buffer
50
+ when /^\s*!/
51
+ # if we're in the middle of a bang-exec command, completion
52
+ # should look at the file system.
53
+ self.dir_complete(str)
54
+ else
55
+ # otherwise use the internal dict.
56
+ self.term_complete(str)
57
+ end
58
+ end
59
+
60
+ def dir_complete(str)
61
+ Dir.glob("#{str}*")
62
+ end
63
+
64
+ def term_complete(str)
65
+ # Terms can be either commands or indexes into the configuration
66
+ # data structure. No command contains a ".", so that's the test
67
+ # we use to distinguish.
68
+ bits = str.split(".")
69
+ if bits.size > 1
70
+ # Somebody should have documented this when he wrote it, because
71
+ # he now does not remember exactly what he was trying to achieve.
72
+ # He thinks that it's an attempt to allow completion of either
73
+ # full configuration index strings, or of component parts.
74
+ # E.g., if the configuration contains foo.bar.baz, this code
75
+ # will offer both "foo" and "foo.bar.baz" as completions for "fo".
76
+ v1 = @completions.grep(/^#{Regexp.escape(str)}/)
77
+ v2 = @completions.grep(/^#{Regexp.escape(bits.last)}/)
78
+ (v1 + v2.map {|x| (bits.slice(0..-2) << x).join(".") }).uniq
79
+ else
80
+ self.command_complete(str) +
81
+ @completions.grep(/^#{Regexp.escape(str)}/)
82
+ end
83
+ end
84
+
85
+ def command_complete(str)
86
+ @commands.grep(/^#{Regexp.escape(str)}/)
87
+ end
88
+
89
+ def sanitize(str)
90
+ # ANSI code stripper regex cargo culted from
91
+ # http://www.commandlinefu.com/commands/view/3584/remove-color-codes-special-characters-with-sed
92
+ str.gsub(/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]/, "")
93
+ end
94
+
95
+ def on(*pattern, &block)
96
+ pattern.flatten.each do |pattern|
97
+ @patterns[pattern] = block
98
+ self.add_command(pattern)
99
+ end
100
+ end
101
+
102
+ # Helper for defining the action for the "!" command.
103
+ # Typically used to shell out, a la Vim.
104
+ def on_bang(&block)
105
+ on(/^\!\s*(.*)$/, &block)
106
+ end
107
+
108
+ def add_command(pattern)
109
+ if pattern.is_a?(String)
110
+ @commands << pattern
111
+ else
112
+ bits = pattern.source.split(" ")
113
+ # TODO: figure out why you did this, then document it.
114
+ if bits.size > 1
115
+ @commands << bits.first
116
+ end
117
+ end
118
+ end
119
+
120
+ def run(context)
121
+ @completions = context.completions rescue Set.new
122
+ @run = true
123
+ puts
124
+ while @run && line = Readline.readline("<3: ", true)
125
+ self.parse(context, line.chomp)
126
+ end
127
+ end
128
+
129
+ def exit
130
+ @run = false
131
+ end
132
+
133
+ # Attempt to find a registered command that matches the input
134
+ # string. Upon failure, print an encouraging message.
135
+ def parse(context, input_string)
136
+ _p, block= @patterns.detect do |pattern, block|
137
+ pattern === input_string
138
+ end
139
+ if block
140
+ # Perlish global ugliness necessitated by the use of
141
+ # Enumerable#detect above. FIXME.
142
+ if $1
143
+ # if the regex had a group (based on the assumption that $1
144
+ # represents the result of the === that matched), call the block
145
+ # with all the group matches as arguments.
146
+ context.instance_exec($~[1..-1], &block)
147
+ else
148
+ context.instance_eval(&block)
149
+ end
150
+ else
151
+ puts "command not found"
152
+ end
153
+ end
154
+
155
+ end
156
+
157
+
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: consolize
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
+ platform: ruby
12
+ authors:
13
+ - Matthew King
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-08-01 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rb-readline
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - "="
28
+ - !ruby/object:Gem::Version
29
+ hash: 11
30
+ segments:
31
+ - 0
32
+ - 4
33
+ - 2
34
+ version: 0.4.2
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description:
38
+ email:
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ files:
46
+ - README.md
47
+ - LICENSE
48
+ - lib/consolize.rb
49
+ - examples/usage.rb
50
+ has_rdoc: true
51
+ homepage: https://github.com/automatthew/consolize
52
+ licenses: []
53
+
54
+ post_install_message:
55
+ rdoc_options: []
56
+
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ hash: 3
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ requirements: []
78
+
79
+ rubyforge_project:
80
+ rubygems_version: 1.6.2
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: A mixin for creating application consoles with Readline support
84
+ test_files: []
85
+