Displaying articles with tag

Spaces Keyboard Shortcuts

Posted by rue, Wed Mar 12 04:41:00 UTC 2008

Spaces is nice to have on OS X—it is just the concept of workspaces moved to Aqua. The only problem with it is that it relies heavily on the mouse/GUI side of things. You can switch workspaces easily enough with Cmd + number but moving windows around is a bit trickier. The least inconvenient way of doing this is to click on the desired window and while keeping the mouse button pressed, use the Cmd + number for the desired workspace. Hopefully next update will allow something like Shift + Cmd + number to move the currently focused window.

0 comments | Filed Under: mac | Tags:

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:

pdumpfs

Posted by rue, Wed Sep 13 02:33:00 UTC 2006

Found a nice utility for daily backups, a port from Plan9’s fabled dumpfs called pdumpfs. It does directory-based incremental backups after creating a baseline, stores them in a /backups/2006/09/12/directory-style path and is easy as hell to use:

pdumpfs /home/name /backup > /backup/log 2> /backup/errlog
In my case, I set up a cronjob to do exactly that and /backup is actually a NFS mount on a newly minted Solaris 10 fileserver on which I will have more later.

0 comments | Filed Under: | Tags:

ruSH is now rs

Posted by rue, Sun Sep 10 01:45:00 UTC 2006

Someone asked about ruSH on ruby-talk at a time when I had been pondering about making an interim announcement myself. I am working on a Ruby shell again though I deleted all previous work (except from the repository, of course) and have renamed the project rs.

The approach is slightly different this time. The 0.1 release which is hopefully not too far off will feature most of the basic functionality but in pure Ruby syntax. 0.2, eventually, would add a parser for more traditional-looking shell syntax. Currently I am pretty close to 0.1 but I am revisiting the piping (or ObjectStreaming) a bit to add some simplicity :)

Contrived syntax difference example:
1
2
3
4
5
6
7
8
# 0.1 Normal
ls('-la').| .map {|i| i.reverse}  >> '~/revls.txt'

# 0.1 Strict (this should be optional for certain environs)
ls('-la').pipe_to.map {|i| i.reverse}.append_to '~/revls.txt'.to_fso

# 0.2
ls -la | .map {|i| i.reverse} >> ~/revls.txt
The standard stuff, being able to treat files as objects like foo.mp3.play (to some to-be-determined degree) via plugins etc. is still in the plan as well as the rs-enabled system commands and passing stuff around as YAML instead of plain text.

1 comment | Filed Under: rs | Tags: