# Rs 0.1

**URL:** <https://www.ruby-forum.com/t/rs-0-1/71897>\
**Category:** Ruby\
**Created:** [October 12, 2006, 5:38am UTC](https://www.ruby-forum.com/t/rs-0-1/71897 "2006-10-12T05:38:40Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![rue](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/b77776/32.png) [@rue](https://www.ruby-forum.com/u/rue)\
**Post date:** [October 12, 2006, 5:38am UTC](https://www.ruby-forum.com/t/rs-0-1/71897/1 "2006-10-12T05:38:40Z")

</div>

rs is a project to implement a non-traditional object-oriented shell in  
Ruby.

The three main features will be the simple power of Ruby as the shell  
scripting  
language, an objectlike interface to files and object piping.

This is a preliminary release, mainly to re-introduce the project and  
invite developers to join up.

=== Authors  
See doc/AUTHORS.

=== Licence  
See doc/LICENCE.

=== Communication

- IRC:  
##rs on [irc.freenode.net](http://irc.freenode.net)

- Mailing list:  
[http://projects.kittensoft.org/mailman/listinfo/rs-dev\_projects.kittensoft.org](http://projects.kittensoft.org/mailman/listinfo/rs-dev_projects.kittensoft.org)

=== Documentation  
[http://projects.kittensoft.org/rs/rdoc/index.html](http://projects.kittensoft.org/rs/rdoc/index.html)

=== Features

- Execution of arbitrary Ruby
- Pipes, input redirection
- FileSystemObjects which encapsulate paths and files

A development roadmap is at doc/TODO.roadmap

=== Download  
==== Developers  
Anyone interested in developing rs should read doc/HOWTO.development.

- darcs get [http://repos.kittensoft.org/rs](http://repos.kittensoft.org/rs)
- [http://files.kittensoft.org/rs/rs-dev-0.1.tar.gz](http://files.kittensoft.org/rs/rs-dev-0.1.tar.gz)

==== Users

- [http://files.kittensoft.org/rs/rs-0.1.tar.gz](http://files.kittensoft.org/rs/rs-0.1.tar.gz)

=== Installation  
It is advised that developers do not install the program locally at  
this point but rather use bin/rs directly. Users may use the provided  
setup.rb script:

sudo ruby setup.rb all

=== Using  
See doc/HOWTO.using.

=== Customizing  
rs will load ~/.rsrc if it exists. This file is executed as a .rb and  
can be used for defining methods, setting $config variables and even  
modifying rs itself.

=== Current issues and bugs  
The entire project is in flux. Think of it as an exploratory programming  
experiment that will stretch all the way until 0.9 at which point the  
real program will be extracted from the codebase at the time.

- Generally not production-ready.
- Cannot be used as a login shell.
- Inconsistent and incomplete internal model.
- The ‘lexer’ for determining completeness of Ruby statements is very  
weak.
- Tests, though relatively extensive, mainly ensure that the correct  
operation  
is present. Work is needed in testing for failure.

=== Statistic  
The codebase is slightly under 500 lines with around 1750 lines of tests  
(a 7:2 ratio) with 90+ specifications and 300+ assertions.

=== Dependencies  
==== Bundled

- Test::Spec by Christian N., [http://chneukirchen.org](http://chneukirchen.org).  
Developers only.
- FlexMock by Jim W., [http://onestepback.org/software/flexmock](http://onestepback.org/software/flexmock).  
Developers only.

==== Unbundled

- None

=== Special thanks

- Everyone who contributed to the original ruSH code.
- The Ruby hackers. I never appreciated the UNIXness of Ruby enough.

=== Copyright  
Copyright (c) 2005-2006 by the Authors. All rights reserved.

---

<div class="post-metadata">

**Author:** ![rue](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/b77776/32.png) [@rue](https://www.ruby-forum.com/u/rue)\
**Post date:** [October 12, 2006, 7:08am UTC](https://www.ruby-forum.com/t/rs-0-1/71897/2 "2006-10-12T07:08:31Z")

</div>

Eero S. wrote:

> rs is a project to implement a non-traditional object-oriented shell in Ruby.
> 
> The three main features will be the simple power of Ruby as the shell scripting  
> language, an objectlike interface to files and object piping.
> 
> This is a preliminary release, mainly to re-introduce the project and  
> invite developers to join up.

Different from ruSH? [1]  
How so?

-Justin

[1][http://rubyforge.org/projects/rush/](http://rubyforge.org/projects/rush/)

---

<div class="post-metadata">

**Author:** ![rue](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/b77776/32.png) [@rue](https://www.ruby-forum.com/u/rue)\
**Post date:** [October 18, 2006, 10:38am UTC](https://www.ruby-forum.com/t/rs-0-1/71897/3 "2006-10-18T10:38:44Z")

</div>

> “Eero S.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote in message  
> === Documentation  
> [http://projects.kittensoft.org/rs/rdoc/index.html](http://projects.kittensoft.org/rs/rdoc/index.html)

I love the doc/SPECS. Makes for very nice test/documentation!

---

<div class="post-metadata">

**Author:** ![rue](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/b77776/32.png) [@rue](https://www.ruby-forum.com/u/rue)\
**Post date:** [October 18, 2006, 10:38am UTC](https://www.ruby-forum.com/t/rs-0-1/71897/4 "2006-10-18T10:38:52Z")

</div>

On 2006.10.12 14:06, Justin C. wrote:

> > 
> 
> Different from ruSH? [1]  
> How so?

It is different in that I scrapped the code in ruSH and started over.  
The ideas remain broadly the same, currently with the benefit of not  
having a Curses interface which simplifies trying it out.

The approach is a bit different this time, starting from working TDD.

---

<div class="post-metadata">

**Author:** ![rue](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/b77776/32.png) [@rue](https://www.ruby-forum.com/u/rue)\
**Post date:** [October 18, 2006, 10:39am UTC](https://www.ruby-forum.com/t/rs-0-1/71897/5 "2006-10-18T10:39:50Z")

</div>

On 2006.10.12 12:38, Eero S. wrote:

> rs is a project to implement a non-traditional object-oriented shell in Ruby.

And of course I forget to enter the most important part. Examples!

= Examples  
Using rs.

== General notes  
rs uses Readline which means that you can use the arrow  
keys to go up and down in history and back and forth in  
the current line.

== Executing Ruby code  
You should be able to execute any Ruby code on the line:

rs\> 5 + 6  
=\> 11  
rs\>

rs\> class Foo  
…\> def bar  
…\> puts ‘Baz’  
…\> end  
…\> end  
=\> nil  
rs\> Foo.new.bar  
Baz  
=\> nil  
rs\>

== Output and environment control  
You can affect the output using $config values of ruby\_return,  
prompt and continuation\_prompt. $config (and $env) behave like  
OpenStructs with the distinction that a method ending with ?  
returns a boolean and one ending with ! will set the attribute  
to true.

The prompts are #evaled so you can put arbitrary code in there.  
Be mindful that a static string has to be enclosed in quotes for  
it to work properly.

rs\> 1 + 1  
=\> 2  
rs\> $config.ruby\_return = false  
rs\> 1 + 1  
rs\> $config.ruby\_return!  
=\> true  
rs\>

rs\> $config.prompt  
=\> “'rs\> '”  
rs\> $config.prompt = ‘"#{Dir.pwd}\> "’  
=\> ‘"#{Dir.pwd}\> "’  
/tmp\> class Foo  
…\> end  
/tmp\> $config.continuation\_prompt = $config.prompt  
=\> ‘"#{Dir.pwd}\> "’  
/tmp\> class Foo  
/tmp\> end  
/tmp\> $config.prompt = “'rs\> '”; $config.continuation\_prompt = “’…\>  
'”

== FileSystemObjects  
FSOs give a relatively object-like interface to files and paths  
and incorporate several File, FileUtils, Dir etc. methods.

rs\> ‘/tmp’.to\_fso.methods.sort  
=\> ["/", “\<”, “\<\<”, “==”, “===”, “=~”, “\>”, “\>\>”, “ **id** ”,  
“ **send** ”,  
“append\_to”, “args”, “basename”, “blockdev?”, “cat”, “cd”,  
“chardev?”,  
“chmod”, “chmod\_R”, “chown”, “chown\_R”, “class”, “clone”, “compare”,  
“cp”, “cp\_r”, “directory?”, “dirname”, “display”, “dup”, “eql?”,  
“equal?”,  
“exec”, “executable?”, “executable\_real?”, “exist?”, “exists?”,  
“extend”,  
“extname”, “file?”, “find”, “freeze”, “frozen?”, “ftype”, “glob”,  
“grpowned?”,  
“hash”, “id”, “inspect”, “install”, “instance\_eval”, “instance\_of?”,  
“instance\_variable\_get”, “instance\_variable\_set”,  
“instance\_variables”,  
“is\_a?”, “kind\_of?”, “ln”, “ln\_s”, “ln\_sf”, “lstat”, “method”,  
“methods”,  
“mkdir”, “mkdir\_p”, “mv”, “nil?”, “object\_id”, “owned?”, “path”,  
“pipe”,  
“pipe?”, “private\_methods”, “protected\_methods”, “public\_methods”,  
“readable?”,  
“readable\_real?”, “readlink”, “relative\_path”, “respond\_to?”, “rm”,  
“rm\_r”,  
“rm\_rf”, “rmdir”, “run”, “send”, “setgid?”, “setuid?”,  
“singleton\_methods”,  
“size”, “size?”, “socket?”, “split”, “stat”, “sticky?”, “symlink”,  
“symlink?”,  
“taint”, “tainted?”, “to\_a”, “to\_os”, “to\_s”, “touch”, “truncate”,  
“type”,  
“umask”, “unlink”, “untaint”, “writable?”, “writable\_real?”,  
“write\_to”, “zero?”, “|”]  
rs\>

Generally, these methods behave exactly as their Ruby counterparts with  
the path  
of the FSO given as the file to operate on. For example:

rs\> ‘/tmp’.to\_fso.directory?  
=\> true  
rs\> ‘/tmp/quux’.to\_fso.exist?  
=\> false  
rs\> ‘/tmp’.to\_fso.cd {’./quux’.to\_fso.touch}  
=\> nil  
rs\> ‘/tmp/quux’.to\_fso.exist?  
=\> true  
rs\> ‘/tmp/quux’.to\_fso.rm  
=\> [’/tmp/quux’]  
rs\> ‘/tmp/quux’.to\_fso.exist?  
=\> false

You could of course put the FSO in a variable to avoid the  
repetition–also, if  
you feel like metaprogramming a bit, you could put a  
String#method\_missing in your  
~/.rsrc so that you can skip the #to\_fso (which will eventually go away,  
of course).

== Executing programs  
FSOs containing executable files may (unsurprisingly) be executed. One  
thing to  
know about the processing of FSOs is that currently any filename that  
does not  
start with ./, …/, / or ~/ is considered to be ‘unqualified’ and must  
exist in  
$PATH. In addition to this, unknown methods at the top-level are first  
treated  
as unqualified files (falling back on normal if not found). The UI  
provides  
special handling and will automatically run executables. Arguments may  
also be  
given.

rs\> ‘ls’.to\_fso.run  
…  
=\> nil  
rs\> ls  
…  
=\> nil  
rs\> ls ‘-la’  
…  
=\> nil  
rs\> ‘ls’.to\_fso.args(’-l’)  
…  
=\> nil  
rs\>

== Input redirection  
More or less arbitrary objects can be ‘redirected’, \> indicating  
overwriting  
and \>\> appending. In both cases, the file will be created if it does not  
exist.

rs\> ‘/tmp/foo’.to\_fso.touch  
=\> ["/tmp/foo"]  
rs\> ‘/tmp/foo’.to\_fso.cat  
=\> nil  
rs\> ‘/tmp/foo’.to\_fso \< “Foo”  
=\> 3  
rs\> ‘/tmp/foo’.to\_fso.cat  
Foo  
=\> nil  
rs\> ‘/tmp/foo’.to\_fso \<\< 45  
=\> 2  
rs\> ‘/tmp/foo’.to\_fso.cat  
Foo45  
=\> nil  
rs\> ‘/tmp/nonexist’.to\_fso \< ‘/tmp/foo’.to\_fso.read  
=\> 5  
rs\> ‘/tmp/nonexist’.to\_fso.cat  
Foo45  
=\> nil  
rs\>

The opposite should also work:

rs\> ‘/tmp/nonexist’.to\_fso.cat  
Foo45  
=\> nil  
rs\> 78 \>\> ‘/tmp/nonexist’.to\_fso  
=\> 2  
rs\> ‘/tmp/nonexist’.to\_fso.cat  
Foo4578  
=\> nil  
rs\>

There are a few exceptions. If the ‘input’ is an Array, it is  
recursively  
joined with newlines. If the input is an executable FSO, it will be run  
and the result written as a String. Thirdly, if the file TO which the  
input  
is going is executable, it is converted to an ObjectStream instead. This  
brings us to our next topic.

== Pipes  
Executable programs (and/or static input) can be chained together to  
an arbitrary degree using ObjectStreams, also known as pipes.

The result of a piping operation can be queried with #result (this is  
done automatically by the UI if the value of the expression is an OS).

Alternatively, an iterator interface is exposed with #each (an other  
Enumerable methods).

A few modifications take place on a Ruby object being piped: Arrays are  
newline-joined, #to\_proc objects are #called and everything else is set  
to its #to\_s representation.

rs\> ls | wc  
8 8 46  
=\> nil  
rs\> (ls | wc).result  
=\> [" 8 8 46"]  
rs\> “foo\nbar” | wc(’-l’)  
2  
=\> nil  
rs\> “foo\nbar” | wc(’-l’)  
2  
=\> nil  
rs\> (ls | tr(‘a-z A-Z’)).each {|f| p f.reverse}  
“ELIFEKAR”  
“SCRAD\_”  
“NIB”  
“OOB”  
“COD”  
“BIL”  
“BR.PUTES”  
“TSET”  
=\> #IO:0x65be40  
rs\> lambda {“foo\nbar”} | wc  
2 2 8  
=\> nil  
rs\>
