-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d1fbccf
commit a616859
Showing
3 changed files
with
172 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
= bombshell | ||
|
||
Ever wanted to give dudes the ability to explore your library interactively? Like, with a custom IRB-like shell/console? | ||
|
||
Really, you did? Weird. | ||
|
||
== Simple example | ||
|
||
`pizza/bin/pizza`: | ||
|
||
{% highlight ruby %} | ||
#!/usr/bin/env ruby | ||
$:.unshift(File.dirname(__FILE__) + '/../lib') unless $:.include?(File.dirname(__FILE__) + '/../lib') | ||
|
||
require 'rubygems' | ||
require 'pizza' | ||
Bombshell.launch(Pizza::Shell) | ||
{% endhighlight %} | ||
|
||
`pizza/lib/pizza/shell.rb`: | ||
{% highlight ruby %} | ||
require 'bombshell' | ||
|
||
module Pizza | ||
class Shell < Bombshell::Environment | ||
include Bombshell::Shell | ||
|
||
prompt_with 'pizzabot' | ||
|
||
def order(size) | ||
Pizza::Order.new(:size => size).place! | ||
puts 'Your pizza has been ordered! Super!' | ||
end | ||
end | ||
end | ||
{% endhighlight %} | ||
|
||
Let's try it out: | ||
> $ pizza | ||
> pizzabot> order 'large' | ||
> Your pizza has been ordered! Super! | ||
> pizzabot> | ||
== Prompts | ||
|
||
You set your prompt like this: | ||
|
||
{% highlight ruby %} | ||
prompt_with 'pizza_bot_loves_you' | ||
{% endhighlight %} | ||
|
||
Or like this: | ||
|
||
{% highlight ruby %} | ||
prompt_with do | ||
"pizza_bot / #{Time.now}" # binding is on your shell *class* | ||
end | ||
{% endhighlight %} | ||
|
||
Or even like this: | ||
|
||
{% highlight ruby %} | ||
prompt_with do |shell| | ||
"pizza_bot / #{shell.size}" # the block gets the shell *instance* when it asks for it | ||
end | ||
{% endhighlight %} | ||
|
||
== Callbacks | ||
|
||
You can set callbacks like this: | ||
|
||
{% highlight ruby %} | ||
before_launch do | ||
init # binding is on your shell *class* | ||
end | ||
|
||
before_launch do |size| | ||
Pizza.default_size = size # the block gets as many command-line parameters as you ask for | ||
end | ||
|
||
having_launched do | ||
puts size if size # binding is on your shell *instance* | ||
end | ||
{% endhighlight %} | ||
|
||
== Subshells | ||
|
||
If you dump all of your functionality into one shell, things could get a little messy. That's why we have *subshells*: | ||
|
||
`pizza/lib/pizza/shell.rb`: | ||
{% highlight ruby %} | ||
require 'bombshell' | ||
|
||
module Pizza | ||
class Shell < Bombshell::Environment | ||
include Bombshell::Shell | ||
prompt_with 'pizzabot' | ||
|
||
def pizza | ||
Order.launch | ||
end | ||
end | ||
end | ||
{% endhighlight %} | ||
|
||
`pizza/lib/pizza/shell/order.rb`: | ||
{% highlight ruby %} | ||
require 'bombshell' | ||
|
||
module Pizza | ||
class Shell | ||
class Order < Bombshell::Environment | ||
include Bombshell::Shell | ||
prompt_with 'new order' | ||
|
||
def size(s) | ||
@size = s | ||
puts 'You got it!' | ||
end | ||
|
||
def topping(t) | ||
@toppings ||= [] | ||
@toppings << t | ||
puts "Added #{t}" | ||
end | ||
|
||
def order | ||
Pizza::Order.new :size => @size, :toppings => @toppings | ||
puts 'Coming right up!' | ||
quit | ||
end | ||
end | ||
end | ||
end | ||
{% endhighlight %} | ||
|
||
And now we have . . . | ||
|
||
Let's try it out: | ||
|
||
> pizzabot> pizza | ||
> new order> size 'large' | ||
> You got it! | ||
> new order> topping 'pepperoni' | ||
> Added pepperoni | ||
> new order> order | ||
> Coming right up! | ||
> pizzabot> | ||
== Tab completion | ||
|
||
It's there. Give it a whirl with TAB. | ||
|
||
== To use: | ||
|
||
* Create a class for your shell and `include Bombshell::Shell`. You should also set this class to inherit from `Bombshell::Environment` as that will ensure your shell doesn't have any extraneous "commands" (i.e. methods) inherited from Object. (If you'd rather use a different basis---like `CleanSlate`---or `undef` methods yourself, go right ahead.) | ||
|
||
* Define your commands as instance methods on this class. There's nothing *too* funny going on here, it's just Ruby. | ||
|
||
* Kick off the shell with Bombshell.launch(YourShellClass). It's possible to do this from IRB but it's kind of messy (constant reassignment warnings). Instead, set up a "binary" for yourself like `pizza/bin/pizza` at the top of this file. | ||
|
||
== Hints: | ||
|
||
* Give your users a `help` command! | ||
* Use subshells for hierarchical interactivity! | ||
* Provide as thin of a wrapper you can above your library! We want to see what's going on! | ||
|
||
== Copyright | ||
|
||
Copyright (c) 2011 Andy Rossmeissl. See LICENSE.txt for | ||
further details. |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,18 +11,13 @@ require 'rake' | |
|
||
require 'jeweler' | ||
Jeweler::Tasks.new do |gem| | ||
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options | ||
gem.name = "bombshell" | ||
gem.homepage = "http://github.com/rossmeissl/bombshell" | ||
gem.license = "MIT" | ||
gem.summary = %Q{Custom IRB consoles made easy} | ||
gem.description = %Q{Custom IRB consoles made easy} | ||
gem.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.} | ||
gem.email = "[email protected]" | ||
gem.authors = ["Andy Rossmeissl"] | ||
# Include your dependencies below. Runtime dependencies are required when using your gem, | ||
# and development dependencies are only needed for development (ie running rake tasks, tests, etc) | ||
# gem.add_runtime_dependency 'jabber4r', '> 0.1' | ||
# gem.add_development_dependency 'rspec', '> 1.2.3' | ||
end | ||
Jeweler::RubygemsDotOrgTasks.new | ||
|
||
|