Still Working with Ruby
A blog about Ruby updates, tools, editors tweaks, new gems, and random snippets. I also explore edgy parts of Ruby over at Idiosyncratic Ruby.

Use fresh Ruby as your shell!

We love Ruby. And we love the command line. So… the shell needs to be rubyfied ;).

Fresh is a new gem, trying to achieve this.

Updated for fresh version 0.2.0.

Fresh tries to detect automatically, if your expression should be a Ruby or a shell command. Basically, this is done by a regexp similar to this one: /^\w+\s+.*/ (match a single word followed by at least one space)

~/a/ripl-fresh> 3.times{ puts "This is Ruby" }
This is Ruby
This is Ruby
This is Ruby
=> 3
~/a/ripl-fresh> cd lib/ripl
~/a/ripl-fresh/lib/ripl> ls
fresh  fresh.rb
~/a/ripl-fresh/lib/ripl> vim fresh.rb
~/a/ripl-fresh/lib/ripl> cd -
~/a/ripl-fresh> cal
   November 2010
Su Mo Tu We Th Fr Sa
    1  2  3  4  5  6
 7  8  9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

The command used (as single word or first part of the regex) is looked for in Ripl.config[:fresh_system_commands] which contains the commands available in your path.

You can also force the line to be interpreted as Ruby by prefixing it with a space, or to force interpretation as system command by prefixing it with ^:

~/a/ripl-fresh>  cal
NameError: undefined local variable or method `cal' for main:Object
~/a/ripl-fresh> mv [TAB]
.README.rdoc.swp  CHANGELOG.rdoc    README.rdoc       bin/           pkg/
.gemspec          LICENSE.txt       Rakefile          blog.textile      lib/              
~/a/ripl-fresh> mv LICENSE.txt LICENSE

Fresh comes with a very basic auto-completion: currently, only path completion and (sometimes) command completion is supported.

You can also use the command output in Ruby by assigning it to a Ruby expression. This is done like this:

~/a/ripl-fresh> ls => a
~/a/ripl-fresh> a
=> ["bin", "CHANGELOG.rdoc", "", "fresh.gemspec", "lib", "LICENSE", "pkg", "Rakefile", "README.rdoc"]
~/a/ripl-fresh> a.size
=> 9

Further information on github ;)

Creative Commons License

omg | November 24, 2010

J-_-L | November 24, 2010

Hi. rush feels different. It's a cool project, but it goes another way. In fresh, not every command you are writing is Ruby and has to obey its syntax - so you can, for example, call system commands with their string arguments, without using commas or quotes. However, rush has a much better interaction between the system calls and Ruby manipulation of those.

joeyrobert | November 25, 2010

Can you pipe process information into Ruby lambdas? That would be a killer feature. Good work so far.

grosser | November 25, 2010

Looks promising!

njs | November 25, 2010

Looks interesting ... will give it a try!

Just a thought - perhaps you could investigate using some method_missing magic, so that if the variable/method isn't defined in ruby (as in your 'cal' example), it tries executing at the shell.

(Could be some gotchas I haven't considered, but it was just a quick thought ...)

Spakman | November 25, 2010

Interesting looking stuff - well done!

I've also been creating a shell in Ruby. Urchin ( is an implementation of a more standard Unix shell - job control, pipelines and the like.

I was planning to delimit Ruby code with special strings, but your regex approach has me reconsidering if there's another way...

yonkeltron | November 25, 2010

I wonder if a regex isn't rather fragile. Have you considered a more robust approach, possibly with a parser or a durable guessing strategy? Since the grammar of the shell is much less complex than the grammar of Ruby itself, you could first try to see if the command is a shell command and, if not, pass it to Ruby for evaluation.

J-_-L | November 25, 2010

Thanks for this nice feedback :)
@joeyrobert Yep, that would be cool ;).
@njs I've thought about it, but I think I'll keep that <code>method_missing</code> space clean and only use the regex detection
@Spakman Thanks for that pointer, I'll take a look at it
@yonkeltron I'll defenitely stick to the regex approach for some time, but maybe change that later and/or add tests ;)

Daniel | November 25, 2010

I wrote rubsh quite awhile ago to do this. Feel free to try it out. No pipes to ruby commands, and no jobs management however, but works pretty well.

Pavel | November 25, 2010

It can be interesting, I think i should try ...

Aki | May 15, 2011

By the way, in the file lib/bond/completions/ripl-fresh.rb the everything_completion causes some completions to fail. Filename completions work, method completions work, but if I try to tab a ruby word, it gives me error. So:

file[Tab] <= works
[Space]Object.[Tab] <= works
[Space]Obje[Tab][Tab] <= throws:
Bond Error: Failed during completion action with 'undefined method `+' for nil:NilClass'.

Commenting out the completion in ripl-fresh.rb makes everything work again.

J-_-L | May 22, 2011

@Aki: Thanks for the feeback, I'll take a look at this.