bombshell 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/bombshell.gemspec +1 -1
- data/features/support/env.rb +1 -1
- data/lib/bombshell.rb +8 -0
- data/lib/bombshell/completor.rb +5 -0
- data/lib/bombshell/environment.rb +3 -0
- data/lib/bombshell/irb.rb +3 -0
- data/lib/bombshell/shell.rb +66 -0
- data/lib/bombshell/shell/commands.rb +5 -0
- metadata +4 -4
data/bombshell.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
|
9
9
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
10
10
|
s.authors = ["Andy Rossmeissl"]
|
11
|
-
s.date =
|
11
|
+
s.date = "2011-04-20"
|
12
12
|
s.description = %q{Give your application or gem an interactive shell, complete with custom prompts, tab completion, and various callbacks. Commands are defined as Ruby methods and can be grouped into logical subshells.}
|
13
13
|
s.email = %q{andy@rossmeissl.net}
|
14
14
|
s.extra_rdoc_files = [
|
data/features/support/env.rb
CHANGED
data/lib/bombshell.rb
CHANGED
@@ -5,7 +5,15 @@ require 'bombshell/completor'
|
|
5
5
|
require 'bombshell/environment'
|
6
6
|
require 'bombshell/irb'
|
7
7
|
|
8
|
+
# Bombshell enables the lickety-split creation of interactive consoles
|
9
|
+
# (really just boring old custom IRB sessions).
|
10
|
+
# As a Ruby library developer, you may want to build a little shell into
|
11
|
+
# your library so that other developers can play around with it before
|
12
|
+
# adding it to their applications. In the past this has been a real PITA.
|
13
|
+
# With Bombshell it's a little easier.
|
8
14
|
module Bombshell
|
15
|
+
# Launch a shell. This is typically called from a "gem binary" executable Ruby script as described in the README.
|
16
|
+
# @param [Class] shell The shell class to launch. Must include <tt>Bombshell::Shell</tt>.
|
9
17
|
def launch(shell)
|
10
18
|
begin
|
11
19
|
failure = shell.launch(ARGV.dup)
|
data/lib/bombshell/completor.rb
CHANGED
@@ -1,15 +1,20 @@
|
|
1
1
|
module Bombshell
|
2
|
+
# A class used by <tt>IRB.start_session</tt> to handle tab completion.
|
2
3
|
class Completor
|
4
|
+
# Always initialize Completor with the shell it's completing for.
|
3
5
|
def initialize(shell)
|
4
6
|
@shell = shell
|
5
7
|
end
|
6
8
|
|
7
9
|
attr_reader :shell
|
8
10
|
|
11
|
+
# Provide completion for a given fragment.
|
12
|
+
# @param [String] fragment the fragment to complete for
|
9
13
|
def complete(fragment)
|
10
14
|
self.class.filter(shell.instance_methods).grep Regexp.new(Regexp.quote(fragment))
|
11
15
|
end
|
12
16
|
|
17
|
+
# Filter out irrelevant methods that shouldn't appear in a completion list.
|
13
18
|
def self.filter(m)
|
14
19
|
(m - Bombshell::Environment.instance_methods - Bombshell::Shell::Commands::HIDE).reject do |m|
|
15
20
|
m =~ /^_/
|
@@ -1,4 +1,7 @@
|
|
1
1
|
module Bombshell
|
2
|
+
# A (mostly) blank class like Ruby's own CleanSlate. We leave a few important methods in here; your shell shouldn't redefine them.
|
3
|
+
# It's best practice to set your shell classes to inherit from <tt>Bombshell::Environment</tt>. See the README for more details.
|
4
|
+
# @see file:README.markdown
|
2
5
|
class Environment
|
3
6
|
instance_methods.each do |m|
|
4
7
|
undef_method m if m.to_s !~ /(?:^__|^nil\?$|^send$|^instance_eval$|^define_method$|^class$|^object_id|^instance_methods$)/
|
data/lib/bombshell/irb.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
# We have to monkey patch a method into IRB here. I've tried extending it, and it doesn't work.
|
3
4
|
module IRB
|
5
|
+
# Launch a custom IRB session with the given binding, set up the prompt, and define tab completion.
|
6
|
+
# @param [Binding] binding Your shell's binding
|
4
7
|
def self.start_session(binding)
|
5
8
|
unless @__initialized
|
6
9
|
args = ARGV
|
data/lib/bombshell/shell.rb
CHANGED
@@ -1,18 +1,28 @@
|
|
1
1
|
require 'bombshell/shell/commands'
|
2
2
|
|
3
3
|
module Bombshell
|
4
|
+
# Classes include this module to become Bombshell shells.
|
4
5
|
module Shell
|
6
|
+
# Add class methods and a callback hash to your shell.
|
5
7
|
def self.included(base)
|
6
8
|
base.extend ClassMethods
|
7
9
|
base.instance_variable_set :@bombshell_callbacks, :before_launch => [], :having_launched => []
|
8
10
|
end
|
9
11
|
|
12
|
+
# IRB has pretty limited hooks for defining prompts, so we have to piggyback on your
|
13
|
+
# shell's <tt>#to_s</tt>. Hope you don't need it for something else.
|
10
14
|
def to_s
|
11
15
|
_prompt
|
12
16
|
end
|
13
17
|
|
14
18
|
include Commands
|
15
19
|
|
20
|
+
# Render and return your shell's prompt.
|
21
|
+
#
|
22
|
+
# You can define the prompt with <tt>MyShell.prompt_with</tt> and access it without rendering with <tt>MyShell.bombshell_prompt</tt>.
|
23
|
+
# @see ClassMethods#prompt_with
|
24
|
+
# @see ClassMethods#bombshell_prompt
|
25
|
+
# @return String
|
16
26
|
def _prompt
|
17
27
|
if self.class.bombshell_prompt.is_a? String
|
18
28
|
self.class.bombshell_prompt
|
@@ -25,11 +35,22 @@ module Bombshell
|
|
25
35
|
end
|
26
36
|
end
|
27
37
|
|
38
|
+
# Returns your shell's binding, which IRB needs (desperately).
|
39
|
+
# @return Binding
|
28
40
|
def get_binding
|
29
41
|
binding
|
30
42
|
end
|
31
43
|
|
44
|
+
# Class methods for your shell
|
32
45
|
module ClassMethods
|
46
|
+
# Launch the shell.
|
47
|
+
#
|
48
|
+
# You should generally call <tt>Bombshell.launch(MyShell)</tt> instead
|
49
|
+
# of <tt>MyShell.launch</tt> directly, as the former approach will handle
|
50
|
+
# exits correctly and pass command-line parameters as arguments.
|
51
|
+
# @param [Array] arguments An array of arguments that, eventually, callbacks
|
52
|
+
# might use. If you're using the <tt>Bombshell.launch</tt> wrapper, these
|
53
|
+
# will be command-line parameters.
|
33
54
|
def launch(*arguments)
|
34
55
|
@bombshell_callbacks[:before_launch].each do |callback|
|
35
56
|
callback.call(*arguments.first(callback.arity > -1 ? callback.arity : 0))
|
@@ -41,18 +62,63 @@ module Bombshell
|
|
41
62
|
::IRB.start_session(shell.get_binding)
|
42
63
|
end
|
43
64
|
|
65
|
+
# Define a callback that will get called before your shell is instantiated (and
|
66
|
+
# therefore before it is handed over to IRB).
|
67
|
+
#
|
68
|
+
# This is a great place to
|
69
|
+
# dynamically define additional instance methods on your class. If your callback
|
70
|
+
# proc asks for blockvars, Bombshell will give it as many command-line parameters
|
71
|
+
# as it needs to. Within the callback, <tt>self</tt> is your shell <i>class</i>.
|
72
|
+
# @see #having_launched
|
73
|
+
# @example
|
74
|
+
# class MyShell < Bombshell::Environment
|
75
|
+
# include Bombshell::Shell
|
76
|
+
# before_launch do
|
77
|
+
# define_method :foo
|
78
|
+
# puts 'bar'
|
79
|
+
# end
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
# @example
|
83
|
+
# class MyShell < Bombshell::Environment
|
84
|
+
# include Bombshell::Shell
|
85
|
+
# before_launch do |first_command_line_parameter, second_command_line_parameter|
|
86
|
+
# define_method :display_first_command_line_parameter
|
87
|
+
# puts first_command_line_parameter
|
88
|
+
# end
|
89
|
+
# end
|
90
|
+
# end
|
44
91
|
def before_launch(&callback)
|
45
92
|
@bombshell_callbacks[:before_launch] << callback
|
46
93
|
end
|
47
94
|
|
95
|
+
# Define a callback that will get called <i>after</i> your shell is instantiated,
|
96
|
+
# but <i>before</i> its binding is handed over to IRB. Within the callback, <tt>self</tt> is your shell <i>instance</i>.
|
97
|
+
# @see #before_launch
|
48
98
|
def having_launched(&callback)
|
49
99
|
@bombshell_callbacks[:having_launched] << callback
|
50
100
|
end
|
51
101
|
|
102
|
+
# Define your shell's prompt.
|
103
|
+
#
|
104
|
+
# You can either set your prompt to a static string, or use a Proc for a dynamic prompt.
|
105
|
+
# @param [String] p a string to be used as your shell's prompt.
|
106
|
+
# @param [Proc] prompt a Proc to be rendered whenever your shell's prompt needs to be
|
107
|
+
# displayed. Within the callback, <tt>self</tt> is your shell <i>class</i>. If your
|
108
|
+
# proc asks for a blockvar, it will be given your shell <i>instance</i>.
|
109
|
+
# @see Bombshell::Shell#_prompt
|
110
|
+
# @see #bombshell_prompt
|
52
111
|
def prompt_with(p = nil, &prompt)
|
53
112
|
@bombshell_prompt = p || prompt
|
54
113
|
end
|
55
114
|
|
115
|
+
# Read your shell's prompt
|
116
|
+
#
|
117
|
+
# Note that this method returns an <i>unrendered</i> prompt. That is, if it's defined as
|
118
|
+
# a Proc, you'll get a Proc back. If you want to get the rendered prompt, use <tt>#_prompt</tt>
|
119
|
+
# on your shell instance.
|
120
|
+
# @see #prompt_with
|
121
|
+
# @see Bombshell::Shell#_prompt
|
56
122
|
def bombshell_prompt
|
57
123
|
@bombshell_prompt
|
58
124
|
end
|
@@ -1,11 +1,16 @@
|
|
1
1
|
module Bombshell
|
2
2
|
module Shell
|
3
|
+
# Standard commands that show up in all Bombshell shells.
|
3
4
|
module Commands
|
5
|
+
# An explicit list of commands to hide from tab completion.
|
4
6
|
HIDE = [:method_missing, :get_binding, :_prompt, :to_s]
|
5
7
|
|
8
|
+
# Exit safely, accounting for the fact that we might be inside a subshell.
|
6
9
|
def quit
|
7
10
|
throw :IRB_EXIT
|
8
11
|
end
|
12
|
+
|
13
|
+
# Provide an error message for unknown commands rather than raise an exception.
|
9
14
|
def method_missing(*args)
|
10
15
|
return if [:extend, :respond_to?].include? args.first
|
11
16
|
puts "Unknown command #{args.first}"
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bombshell
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 5
|
10
|
+
version: 0.1.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Andy Rossmeissl
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-04-20 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|