Displaying articles with tag

rs 0.1 released!

Posted by rue, Sat Oct 14 00:54:00 UTC 2006

The preliminary release of rs is out! You can view the documentation for more information.

  1. darcs repository
  2. Releases

Using rs

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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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> '/home/me'.to_fso.cd
/home/me> '/tmp'.to_fso.cd
/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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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:
1
2
3
4
5
6
7
8
9
10
11
12
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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:
1
2
3
4
5
6
7
8
9
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.
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
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> 

0 comments | Filed Under: rs | Tags: