info | twitter | github
J-_-L | Writings on Ruby Programming
24.11.10 03.12.10
12 comments

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/              deps.rip       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", "deps.rip", "fresh.gemspec", "lib", "LICENSE", "pkg", "Rakefile", "README.rdoc"]
~/a/ripl-fresh> a.size
=> 9

Further information on github ;)

Creative Commons License

Comments

24.11.10

omg

http://rush.heroku.com

24.11.10

J-_-L

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.

25.11.10

joeyrobert

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

25.11.10

grosser

Looks promising!

25.11.10

njs

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

25.11.10

Spakman

Interesting looking stuff - well done!

I've also been creating a shell in Ruby. Urchin (https://github.com/Spakman/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...

25.11.10

yonkeltron

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.

25.11.10

J-_-L

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 ;)

25.11.10

Daniel

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.

http://rubygems.org/gems/rubsh

25.11.10

Pavel

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

15.05.11

Aki

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.

22.05.11

J-_-L

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