publish a bunch of old recovered posts

This commit is contained in:
Sami Samhuri 2011-12-11 01:04:10 -08:00
parent 1a58766347
commit c62cf020ff
619 changed files with 16009 additions and 240699 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
wayback/node_modules

BIN
files/assert_snippets.zip Normal file

Binary file not shown.

260
files/cheat.el Normal file
View file

@ -0,0 +1,260 @@
;; cheat.el
;; Time-stamp: <2007-08-22 10:00:04 sjs>
;;
;; Copyright (c) 2007 Sami Samhuri <sami.samhuri@gmail.com>
;;
;; See http://sami.samhuri.net/2007/08/10/cheat-from-emacs for updates.
;;
;; License
;;
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License
;; as published by the Free Software Foundation; either version 2
;; of the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;;
;;
;; Provide a handy interface to cheat.
;; See http://cheat.errtheblog.com for details on cheat itself.
;;
;; sjs 2007.08.21
;; * Cache the list of cheat sheets, update it once a day (configurable).
;; * Strictly complete cheat sheet names.
(defvar *cheat-host* "cheat.errtheblog.com")
(defvar *cheat-port* "80")
(defvar *cheat-uri* (concat *cheat-host* ":" *cheat-port*))
(defvar *cheat-directory* "~/.cheat")
(defvar *cheat-sheets-cache-file* (concat *cheat-directory* "/sheets"))
(defvar *cheat-last-sheet* nil
"Name of the most recently viewed cheat sheet.")
(defvar *cheat-sheet-history* nil
"List of the most recently viewed cheat sheets.")
(defconst +seconds-per-day+ 86400)
(defvar *cheat-cache-ttl* +seconds-per-day+
"The minimum age of a stale cache file, in seconds.")
;;; interactive functions
(defun cheat (name &optional silent)
"Show the specified cheat sheet.
If SILENT is non-nil then do not print any output, but return it
as a string instead."
(interactive (list (cheat-read-sheet-name)))
(if silent
(cheat-command-silent name)
(cheat-command name)))
(defun cheat-sheets ()
"List all cheat sheets."
(interactive)
(cheat-command "sheets"))
(defun cheat-recent ()
"Show recently added cheat sheets."
(interactive)
(cheat-command "recent"))
(defun cheat-clear-cache ()
"Clear the local cheat cache, located in ~/.cheat."
(interactive)
(cheat-command "--clear-cache")
(make-directory *cheat-directory*))
(defun cheat-versions (name)
"Version history of the specified cheat sheet."
(interactive (list (cheat-read-sheet-name)))
(cheat-command name "--versions"))
(defun cheat-diff (name version)
"Show the diff between the given version and the current version of the named cheat.
If VERSION is of the form m:n then show the diff between versions m and n."
(interactive (list (cheat-read-sheet-name)
(read-string "Cheat version(s): ")))
(cheat-command name "--diff" version))
(defun cheat-add-current-buffer (name)
"Add a new cheat with the specified name and the current buffer as the body."
(interactive "sCheat name: \n")
(post-cheat name (buffer-string) t)
(if (interactive-p)
(print (concat "Cheat added (" name ")"))))
(defun cheat-edit (name)
"Fetch the named cheat and open a buffer containing its body.
The cheat can be saved with `cheat-save-current-buffer'."
(interactive (list (cheat-read-sheet-name)))
(cheat-clear-cache name) ; make sure we're working with the latest version
(switch-to-buffer (get-buffer-create (cheat->buffer name)))
(insert (cheat-body name))
(if (interactive-p)
(print "Run `cheat-save-current-buffer' when you're done editing.")))
(defun cheat-save-current-buffer ()
"Save the current buffer using the buffer name for the title and the contents as the body."
(interactive)
(let ((name (buffer->cheat (buffer-name (current-buffer)))))
(post-cheat name (buffer-string))
;; TODO check for errors and kill the buffer on success
(if (interactive-p)
(print (concat "Cheat saved (" name ")")))
(cheat-clear-cache name)
(cheat name)))
;;; helpers
;; this is from rails-lib.el in the emacs-rails package
(defun string-join (separator strings)
"Join all STRINGS using SEPARATOR."
(mapconcat 'identity strings separator))
(defun blank (thing)
"Return T if THING is nil or an empty string, otherwise nil."
(or (null thing)
(and (stringp thing)
(= 0 (length thing)))))
(defun cheat-command (&rest rest)
"Run the cheat command with the given arguments, display the output."
(interactive "sArguments for cheat: \n")
(shell-command (concat "cheat " (string-join " " rest))))
(defun cheat-command-to-string (&rest rest)
"Run the cheat command with the given arguments and return the output as a string. Display nothing."
(shell-command-to-string (concat "cheat " (string-join " " rest))))
(defalias 'cheat-command-silent 'cheat-command-to-string)
(defun cheat-read-sheet-name (&optional prompt)
"Get the name of an existing cheat sheet, prompting with completion and history.
The name of the sheet read is stored in *cheat-last-sheet* unless it was blank."
(let* ((default (when (blank prompt) *cheat-last-sheet*))
(prompt (or prompt
(if (not (blank default))
(concat "Cheat name (default: " default "): ")
"Cheat name: ")))
(name (completing-read prompt
(cheat-sheets-list t)
nil
t
nil
'*cheat-sheet-history*
default)))
(when (not (blank name))
(setq *cheat-last-sheet* name))
name))
(defun cheat-sheets-list (&optional fetch-if-missing-or-stale)
"Get a list of all cheat sheets.
Return the cached list in *cheat-sheets-cache-file* if it's
readable and `cheat-cache-stale-p' returns nil.
When there is no cache or a stale cache, and
FETCH-IF-MISSING-OR-STALE is non-nil, cache the list and then
return it.
Otherwise return nil."
(cond ((and (file-readable-p *cheat-sheets-cache-file*)
(not (cheat-cache-stale-p)))
(save-excursion
(let* ((buffer (find-file *cheat-sheets-cache-file*))
(sheets (split-string (buffer-string))))
(kill-buffer buffer)
sheets)))
(fetch-if-missing-or-stale
(cheat-cache-list)
(cheat-sheets-list))
(t nil)))
(defun cheat-fetch-list ()
"Fetch a fresh list of all cheat sheets."
(nthcdr 3 (split-string (cheat-command-to-string "sheets"))))
(defun cheat-cache-list ()
"Cache the list of cheat sheets in *cheat-sheets-cache-file*. Return the list."
(when (not (file-exists-p *cheat-directory*))
(make-directory *cheat-directory*))
(save-excursion
(let ((buffer (find-file *cheat-sheets-cache-file*))
(sheets (cheat-fetch-list)))
(insert (string-join "\n" sheets))
(basic-save-buffer)
(kill-buffer buffer)
sheets)))
(defun cheat-cache-stale-p ()
"Non-nil if the cache in *cheat-sheets-cache-file* is more than *cheat-cache-ttl* seconds old.q
If the cache file does not exist then it is considered stale.
Also see `cheat-cache-sheets'."
(or (null (file-exists-p *cheat-sheets-cache-file*))
(let* ((now (float-time (current-time)))
(last-mod (float-time (sixth (file-attributes *cheat-sheets-cache-file*))))
(age (- now last-mod)))
(> age *cheat-cache-ttl*))))
(defun cheat-body (name)
"Call out to Ruby to load the YAML and return just the body."
(shell-command-to-string
(concat "ruby -ryaml -e '"
"puts YAML.load_file(File.expand_path(\"~/.cheat/"
name ".yml\")).to_a[0][-1]'")))
(defun url-http-post (url args)
"Send ARGS to URL as a POST request."
(let ((url-request-method "POST")
(url-request-extra-headers
'(("Content-Type" . "application/x-www-form-urlencoded")))
(url-request-data
(concat (mapconcat (lambda (arg)
(concat (url-hexify-string (car arg))
"="
(url-hexify-string (cdr arg))))
args
"&")
"\r\n")))
;; `kill-url-buffer' to discard the result
;; `switch-to-url-buffer' to view the results (debugging).
(url-retrieve url 'kill-url-buffer)))
(defun kill-url-buffer (status)
"Kill the buffer returned by `url-retrieve'."
(kill-buffer (current-buffer)))
(defun switch-to-url-buffer (status)
"Switch to the buffer returned by `url-retreive'.
The buffer contains the raw HTTP response sent by the server."
(switch-to-buffer (current-buffer)))
(defun post-cheat (title body &optional new)
(let ((uri (concat "http://" *cheat-uri* "/w/" (if new "" title))))
(url-http-post uri `(("sheet_title" . ,title)
("sheet_body" . ,body)
("from_gem" . "1")))))
(defun buffer->cheat (name)
(substring name 7 (- (length name) 1)))
(defun cheat->buffer (name)
(concat "*cheat-" name "*"))
(provide 'cheat)

35
files/german_keys.txt Normal file
View file

@ -0,0 +1,35 @@
DVORAK
------
§1234567890[]
±!@#$%^&*(){}
',.pyfgcrl/=
"<>PYFGCRL?+
aoeuidhtns-\
AOEUIDHTNS_|
`;qjkxbmwvz
~:QJKXBMWVZ
QWERTY
------
§12344567890-=
±!@#$%^&*()_+
qwertyuiop[]
QWERTYUIOP{}
asdfghjkl;'\
ASDFGHJKL:"|
`zxcvbnm,./
~ZXCVBNM<>?
QWERTZ (German)
---------------
^1234567890ß´
°!"§$%&/()=?`

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

34
files/tagify.el Normal file
View file

@ -0,0 +1,34 @@
(defun wrap-region (left right)
"Wrap the region in arbitrary text, LEFT goes to the left and RIGHT goes to the right."
(interactive)
(let ((beg (region-beginning))
(end (region-end)))
(goto-char beg)
(insert left)
(goto-char (+ end (length left)))
(insert right)
(goto-char (+ end (length left) (length right)))))
(defun tagify-region-or-insert-self (arg)
"If there is a visible region, call `tagify-region-or-insert', otherwise
call `self-insert-command' passing it any prefix arg given."
(interactive "*P")
(if (and mark-active transient-mark-mode)
(call-interactively 'tagify-region-or-insert-tag)
(self-insert-command (prefix-numeric-value arg))))
(defun tagify-region-or-insert-tag (tag)
"If there is a visible region, wrap it in the given HTML/XML tag using
`wrap-region'. If any attributes are specified then they are only included
in the opening tag.
Otherwise insert the opening and closing tags and position point between the two."
(interactive "*sTag (including attributes): \n")
(let* ((open (concat "<" tag ">"))
(close (concat "</" (car (split-string tag " ")) ">")))
(if (and mark-active transient-mark-mode)
(wrap-region open close)
(insert (concat open close))
(backward-char (length close)))))
(provide 'tagify)

View file

Before

Width:  |  Height:  |  Size: 139 B

After

Width:  |  Height:  |  Size: 139 B

BIN
images/keyboard.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 KiB

View file

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View file

@ -5,6 +5,6 @@ Author: sjs
Tags: life
----
so its 2am and i should be asleep, but instead im setting up a blog. i got a new desk last night and so today i finally got my apartment re-arranged and its much better now. thats it for now… time to sleep.
so it's 2am and i should be asleep, but instead i'm setting up a blog. i got a new desk last night and so today i finally got my apartment re-arranged and it's much better now. that's it for now... time to sleep.
(speaking of sleep, this new <a href="http://www.musuchouse.com/">sleeping bag</a> design makes so much sense. awesome.)

View file

@ -5,10 +5,10 @@ Author: sjs
Tags: technology, touch
----
If you thought the PowerBooks two-finger scrolling was cool check out this touch screen:
If you thought the PowerBook's two-finger scrolling was cool check out this touch screen:
<a href="http://mrl.nyu.edu/~jhan/ftirtouch/">Multi-Touch Interaction Research</a>
> While touch sensing is commonplace for single points of contact, multi-touch sensing enables a user to interact with a system with more than one finger at a time, as in chording and bi-manual operations. Such sensing devices are inherently also able to accommodate multiple users simultaneously, which is especially useful for larger interaction scenarios such as interactive walls and tabletops.
> "While touch sensing is commonplace for single points of contact, multi-touch sensing enables a user to interact with a system with more than one finger at a time, as in chording and bi-manual operations. Such sensing devices are inherently also able to accommodate multiple users simultaneously, which is especially useful for larger interaction scenarios such as interactive walls and tabletops."
This is really amazing. Forget traditional tablet PCs <i>this</i> is revolutionary and useful in so many applications. I hope this kind of technology is mainstream by 2015.
This is really amazing. Forget traditional tablet PCs... <i>this</i> is revolutionary and useful in so many applications. I hope this kind of technology is mainstream by 2015.

View file

@ -5,8 +5,8 @@ Author: sjs
Tags: crazy, funny
----
This is hilarious! Someone wrote software that manages a “parallel” dating style.
This is hilarious! Someone wrote software that manages a "parallel" dating style.
> In addition to storing each womans contact information and picture, the Girlfriend profiles include a Score Card where you track her sexual preferences, her menstrual cycles and how she styles her pubic hair.
> In addition to storing each woman's contact information and picture, the Girlfriend profiles include a Score Card where you track her sexual preferences, her menstrual cycles and how she styles her pubic hair.
Its called [Girlfriend X](http://www.wired.com/news/columns/0,70231-0.html), but thats a link to an article about it. I didnt go to the actual website. I just thing its amusing someone went through the trouble to do this. Maybe theres a demand for it. *\*shrug\**
It's called [Girlfriend X](http://www.wired.com/news/columns/0,70231-0.html), but that's a link to an article about it. I didn't go to the actual website. I just thing it's amusing someone went through the trouble to do this. Maybe there's a demand for it. *\*shrug\**

View file

@ -5,4 +5,4 @@ Author: sjs
Tags: hacking, rails, textmate, rails, textmate
----
<a href="http://blog.inquirylabs.com/2006/02/17/controller-to-view-and-back-again-in-textmate/trackback/">Duane</a> came up with a way to jump to the controller method for the view youre editing, or vice versa in TextMate while coding using Rails. This is a huge time-saver, thanks!
<a href="http://blog.inquirylabs.com/2006/02/17/controller-to-view-and-back-again-in-textmate/trackback/">Duane</a> came up with a way to jump to the controller method for the view you're editing, or vice versa in TextMate while coding using Rails. This is a huge time-saver, thanks!

View file

@ -5,57 +5,48 @@ Author: sjs
Tags: textmate, rails, hacking, rails, snippets, textmate
----
<p>My arsenal of snippets and macros in TextMate is building as I read through the rails canon, <a href="http://web.archive.org/web/20060615034816/http://www.pragmaticprogrammer.com/titles/rails/" title="Agile Web Development With Rails">Agile Web Development</a> Im only 150 pages in so I havent had to add much so far because I started with the bundle found on the <a href="http://web.archive.org/web/20060615034816/http://wiki.rubyonrails.org/rails/pages/TextMate">rails wiki</a>. The main ones so far are for migrations.</p><p>Initially I wrote a snippet for adding a table and one for dropping a table, but I dont want to write it twice every time! If Im adding a table in <strong>up</strong> then I probably want to drop it in <strong>down</strong>.</p>
My arsenal of snippets and macros in TextMate is building as I read through the rails canon, <a href="http://www.pragmaticprogrammer.com/titles/rails/" title="Agile Web Development With Rails">Agile Web Development...</a> I'm only 150 pages in so I haven't had to add much so far because I started with the bundle found on the <a href="http://wiki.rubyonrails.org/rails/pages/TextMate">rails wiki</a>. The main ones so far are for migrations.
<p>What I did was create one snippet that writes both lines, then its just a matter of cut &amp; paste to get it in <strong>down</strong>. The drop_table line should be inserted in the correct method, but that doesnt seem possible. I hope Im wrong!</p>
Initially I wrote a snippet for adding a table and one for dropping a table, but I don't want to write it twice every time! If I'm adding a table in **up** then I probably want to drop it in **down**.
<p>Scope should be <em>source.ruby.rails</em> and the triggers I use are above the snippets. </p>
What I did was create one snippet that writes both lines, then it's just a matter of cut & paste to get it in **down**. The drop_table line should be inserted in the correct method, but that doesn't seem possible. I hope I'm wrong!
<p>&nbsp;</p>
Scope should be *source.ruby.rails* and the triggers I use are above the snippets.
<p>mcdt: <strong>M</strong>igration <strong>C</strong>reate and <strong>D</strong>rop <strong>T</strong>able</p>
mcdt: **M**igration **C**reate and **D**rop **T**able
<pre><code>create_table "${1:table}" do |t|
create_table "${1:table}" do |t|
$0
end
${2:drop_table "$1"}
</code></pre>
<p>mcc: <strong>M</strong>igration <strong>C</strong>reate <strong>C</strong>olumn</p>
mcc: **M**igration **C**reate **C**olumn
<pre><code>t.column "${1:title}", :${2:string}
</code></pre>
t.column "${1:title}", :${2:string}
<p>marc: <strong>M</strong>igration <strong>A</strong>dd and <strong>R</strong>emove <strong>C</strong>olumn</p>
marc: **M**igration **A**dd and **R**emove **C**olumn
<pre><code>add_column "${1:table}", "${2:column}", :${3:string}
add_column "${1:table}", "${2:column}", :${3:string}
${4:remove_column "$1", "$2"}
</code></pre>
<p>I realize this might not be for everyone, so here are my original 4 snippets that do the work of <em>marc</em> and <em>mcdt</em>.</p>
I realize this might not be for everyone, so here are my original 4 snippets that do the work of *marc* and *mcdt*.
<p>&nbsp;</p>
mct: **M**igration **C**reate **T**able
<p>mct: <strong>M</strong>igration <strong>C</strong>reate <strong>T</strong>able</p>
<pre><code>create_table "${1:table}" do |t|
create_table "${1:table}" do |t|
$0
end
</code></pre>
<p>mdt: <strong>M</strong>igration <strong>D</strong>rop <strong>T</strong>able</p>
mdt: **M**igration **D**rop **T**able
<pre><code>drop_table "${1:table}"
</code></pre>
drop_table "${1:table}"
<p>mac: <strong>M</strong>igration <strong>A</strong>dd <strong>C</strong>olumn</p>
mac: **M**igration **A**dd **C**olumn
<pre><code>add_column "${1:table}", "${2:column}", :${3:string}
</code></pre>
add_column "${1:table}", "${2:column}", :${3:string}
<p>mrc: <strong>M</strong>igration <strong>R</strong>remove <strong>C</strong>olumn</p>
mrc: **M**igration **R**remove **C**olumn
<pre><code>remove_column "${1:table}", "${2:column}"
</code></pre>
remove_column "${1:table}", "${2:column}"
<p>Ill be adding more snippets and macros. There should be a central place where the rails bundle can be improved and extended. Maybe there is</p>
I'll be adding more snippets and macros. There should be a central place where the rails bundle can be improved and extended. Maybe there is...

View file

@ -6,21 +6,21 @@ Tags: rails, coding, hacking, migration, rails, testing
Styles: typocode
----
<p><em>Im a Rails newbie and eager to learn. I welcome any suggestions or criticism you have. You can direct them to <a href="mailto:sjs@uvic.ca">my inbox</a> or leave me a comment below.</em></p>
<p><em>I'm a Rails newbie and eager to learn. I welcome any suggestions or criticism you have. You can direct them to <a href="mailto:sjs@uvic.ca">my inbox</a> or leave me a comment below.</em></p>
<p>I finally set myself up with a blog. I mailed my dad the address and mentioned that it was running <a href="http://www.typosphere.org/">Typo</a>, which is written in <a href="http://www.rubyonrails.com/">Ruby on Rails</a>. The fact that it is written in Rails was a big factor in my decision. I am currently reading <a href="http://www.pragmaticprogrammer.com/titles/rails/">Agile Web Development With Rails</a> and it will be great to use Typo as a learning tool, since I will be modifying my blog anyways regardless of what language its written in.</p>
<p>I finally set myself up with a blog. I mailed my dad the address and mentioned that it was running <a href="http://www.typosphere.org/">Typo</a>, which is written in <a href="http://www.rubyonrails.com/">Ruby on Rails</a>. The fact that it is written in Rails was a big factor in my decision. I am currently reading <a href="http://www.pragmaticprogrammer.com/titles/rails/">Agile Web Development With Rails</a> and it will be great to use Typo as a learning tool, since I will be modifying my blog anyways regardless of what language it's written in.</p>
<p>Clearly Rails made an impression on me somehow or I wouldnt be investing this time on it. But my dad asked me a very good question:</p>
<p>Clearly Rails made an impression on me somehow or I wouldn't be investing this time on it. But my dad asked me a very good question:</p>
> Rails? What is so special about it? I looked at your page and it looks pretty normal to me. I miss the point of this new Rails technique for web development.
<p>Its unlikely that he was surprised at my lengthy response, but I was. I have been known to write him long messages on topics that interest me. However, Ive only been learning Rails for two weeks or so. Could I possibly have so much to say about it already? Apparently I do.</p><h2>Ruby on Rails background</h2>
<p>It's unlikely that he was surprised at my lengthy response, but I was. I have been known to write him long messages on topics that interest me. However, I've only been learning Rails for two weeks or so. Could I possibly have so much to say about it already? Apparently I do.</p><h2>Ruby on Rails background</h2>
<p>I assume a pretty basic knowledge of what Rails is, so if youre not familiar with it nows a good time to read something on the official <a href="http://www.rubyonrails.com/">Rails website</a> and watch the infamous <a href="http://www.rubyonrails.com/screencasts">15-minute screencast</a>, where Rails creator, <a href="http://www.loudthinking.com/">David Heinemeier Hansson</a>, creates a simple blog application.</p>
<p>I assume a pretty basic knowledge of what Rails is, so if you're not familiar with it now's a good time to read something on the official <a href="http://www.rubyonrails.com/">Rails website</a> and watch the infamous <a href="http://www.rubyonrails.com/screencasts">15-minute screencast</a>, where Rails creator, <a href="http://www.loudthinking.com/">David Heinemeier Hansson</a>, creates a simple blog application.</p>
<p>The screencasts are what sparked my curiosity, but they hardly scratch the surface of Rails. After that I spent hours reading whatever I could find about Rails before deciding to take the time to learn it well. As a result, a lot of what you read here will sound familiar if youve read other blogs and articles about Rails. This post wasnt planned so theres no list of references yet. I hope to add some links though so please contact me if any ideas or paraphrasing here is from your site, or if you know who I should give credit to.</p>
<p>The screencasts are what sparked my curiosity, but they hardly scratch the surface of Rails. After that I spent hours reading whatever I could find about Rails before deciding to take the time to learn it well. As a result, a lot of what you read here will sound familiar if you've read other blogs and articles about Rails. This post wasn't planned so there's no list of references yet. I hope to add some links though so please contact me if any ideas or paraphrasing here is from your site, or if you know who I should give credit to.</p>
<h2>Rails through my eyes</h2>
@ -29,34 +29,34 @@ Styles: typocode
<p>Rails is like my Black &amp; Decker toolkit. I have a hammer, power screwdriver, tape measure, needle-nose pliers, wire cutters, a level, etc. This is exactly what I need—no more, no less. It helps me get things done quickly and easily that would otherwise be painful and somewhat difficult. I can pick up the tools and use them without much training. Therefore I am instantly productive with them.</p>
<p>The kit is suitable for many people who need these things at home, such as myself. Companies build skyscrapers and huge malls and apartments, and they clearly need more powerful tools than I. There are others that just need to drive in a nail to hang a picture, in which case the kit I have is overkill. Theyre better off just buying and using a single hammer. I happen to fall in the big grey middle <a href="http://web.archive.org/web/20070316171839/http://poignantguide.net/ruby/chapter-3.html#section2">chunk</a>, not the other two.</p>
<p>The kit is suitable for many people who need these things at home, such as myself. Companies build skyscrapers and huge malls and apartments, and they clearly need more powerful tools than I. There are others that just need to drive in a nail to hang a picture, in which case the kit I have is overkill. They're better off just buying and using a single hammer. I happen to fall in the big grey middle <a href="http://web.archive.org/web/20070316171839/http://poignantguide.net/ruby/chapter-3.html#section2">chunk</a>, not the other two.</p>
<p>Im a university student. I code because its satisfying and fun to create software. I do plan on coding for a living when I graduate. I dont work with ancient databases, or create monster sites like Amazon, Google, or Ebay. The last time I started coding a website from scratch I was using <a href="http://www.php.net/"><span class="caps">PHP</span></a>, that was around the turn of the millennium. [It was a fan site for a <a href="http://www.nofx.org/">favourite band</a> of mine.]</p>
<p>I'm a university student. I code because it's satisfying and fun to create software. I do plan on coding for a living when I graduate. I don't work with ancient databases, or create monster sites like Amazon, Google, or Ebay. The last time I started coding a website from scratch I was using <a href="http://www.php.net/">PHP</a>, that was around the turn of the millennium. [It was a fan site for a <a href="http://www.nofx.org/">favourite band</a> of mine.]</p>
<p>After a year or so I realized I didnt have the time to do it properly (ie. securely and cleanly) if I wanted it to be done relatively soon. A slightly customized <a href="http://www.mediawiki.org/wiki/MediaWiki">MediaWiki</a> promptly took its place. It did all that I needed quite well, just in a less specific way.</p>
<p>After a year or so I realized I didn't have the time to do it properly (ie. securely and cleanly) if I wanted it to be done relatively soon. A slightly customized <a href="http://www.mediawiki.org/wiki/MediaWiki">MediaWiki</a> promptly took it's place. It did all that I needed quite well, just in a less specific way.</p>
<p>The wiki is serving my site extremely well, but theres still that itch to create my <strong>own</strong> site. I feel if Rails was around back then I may have been able to complete the project in a timely manner. I was also frustrated with <span class="caps">PHP</span>. Part of that is likely due to a lack of experience and of formal programming education at that time, but it was still not fun for me. It wasnt until I started learning Rails that I thought “<em>hey, I could create that site pretty quickly using this!</em></p>
<p>The wiki is serving my site extremely well, but there's still that itch to create my <strong>own</strong> site. I feel if Rails was around back then I may have been able to complete the project in a timely manner. I was also frustrated with PHP. Part of that is likely due to a lack of experience and of formal programming education at that time, but it was still not fun for me. It wasn't until I started learning Rails that I thought "<em>hey, I could create that site pretty quickly using this!</em>"</p>
<p>Rails fits my needs like a glove, and this is where it shines. Many professionals are making money creating sites in Rails, so Im not trying to say its for amateurs only or something equally silly.</p>
<p>Rails fits my needs like a glove, and this is where it shines. Many professionals are making money creating sites in Rails, so I'm not trying to say it's for amateurs only or something equally silly.</p>
<h2>Web Frameworks and iPods?</h2>
<p>Some might say I have merely been swept up in hype and am following the herd. You may be right, and thats okay. Im going to tell you a story. There was a guy who didnt get one of the oh-so-shiny iPods for a long time, though they looked neat. His discman plays mp3 CDs, and that was good enough for him. The latest iPod, which plays video, was sufficiently cool enough for him to forget that <strong>everyone</strong> at his school has an iPod and he would be trendy just like them now.</p>
<p>Some might say I have merely been swept up in hype and am following the herd. You may be right, and that's okay. I'm going to tell you a story. There was a guy who didn't get one of the oh-so-shiny iPods for a long time, though they looked neat. His discman plays mp3 CDs, and that was good enough for him. The latest iPod, which plays video, was sufficiently cool enough for him to forget that <strong>everyone</strong> at his school has an iPod and he would be trendy just like them now.</p>
<p>Shocker ending: he is I, and I am him. Now I know why everyone has one of those shiny devices. iPods and web frameworks have little in common except that many believe both the iPod and Rails are all hype and flash. Ive realized that something creating this kind of buzz may actually just be a good product. I feel that this is the only other thing the iPod and Rails have in common: they are both <strong>damn good</strong>. Enough about the iPod, everyone hates hearing about it. My goal is to write about the other thing everyone is tired of hearing about.</p>
<p>Shocker ending: he is I, and I am him. Now I know why everyone has one of those shiny devices. iPods and web frameworks have little in common except that many believe both the iPod and Rails are all hype and flash. I've realized that something creating this kind of buzz may actually just be a good product. I feel that this is the only other thing the iPod and Rails have in common: they are both <strong>damn good</strong>. Enough about the iPod, everyone hates hearing about it. My goal is to write about the other thing everyone is tired of hearing about.</p>
<h2>Why is Rails special?</h2>
<p><strong>Rails is not magic.</strong> There are no exclusive JavaScript libraries or <span class="caps">HTML</span> tags. We all have to produce pages that render in the same web browsers. My dad was correct, there <em>is</em> nothing special about my website either. Its more or less a stock Typo website.</p>
<p><strong>Rails is not magic.</strong> There are no exclusive JavaScript libraries or HTML tags. We all have to produce pages that render in the same web browsers. My dad was correct, there <em>is</em> nothing special about my website either. It's more or less a stock Typo website.</p>
<p>So what makes developing with Rails different? For me there are four big things that set Rails apart from the alternatives:</p>
@ -70,19 +70,19 @@ Styles: typocode
</ol>
<h3><span class="caps">MVC 101</span> <em>(or, Separating data, function, and design)</em></h3>
<h3>MVC 101 <em>(or, Separating data, function, and design)</em></h3>
<p>Now Im sure youve heard about separating content from design. Rails takes that one step further from just using <span class="caps">CSS</span> to style your website. It uses whats known as the <span class="caps">MVC</span> paradigm: <strong>Model-View-Controller</strong>. This is a tried and tested development method. Id used <span class="caps">MVC</span> before in Cocoa programming on Mac <span class="caps">OS X</span>, so I was already sold on this point.</p>
<p>Now I'm sure you've heard about separating content from design. Rails takes that one step further from just using CSS to style your website. It uses what's known as the MVC paradigm: <strong>Model-View-Controller</strong>. This is a tried and tested development method. I'd used MVC before in Cocoa programming on Mac OS X, so I was already sold on this point.</p>
<ul>
<li>The model deals with your data. If youre creating an online store you have a product model, a shopping cart model, a customer model, etc. The model takes care of storing this data in the database (persistence), and presenting it to you as an object you can manipulate at runtime.</li>
<li>The model deals with your data. If you're creating an online store you have a product model, a shopping cart model, a customer model, etc. The model takes care of storing this data in the database (persistence), and presenting it to you as an object you can manipulate at runtime.</li>
</ul>
<ul>
<li>The view deals <em>only</em> with presentation. Thats it, honestly. An interface to your app.</li>
<li>The view deals <em>only</em> with presentation. That's it, honestly. An interface to your app.</li>
</ul>
@ -91,7 +91,7 @@ Styles: typocode
</ul>
<p>Of course this is not exclusive to Rails, but its an integral part of its design.</p>
<p>Of course this is not exclusive to Rails, but it's an integral part of it's design.</p>
<h3>Readability</h3>
@ -108,7 +108,7 @@ Styles: typocode
<span class="ident">belongs_to</span> <span class="symbol">:user</span>
<span class="punct">...</span></code></pre></div>
<p><code>dependent =&gt; true</code> means <em>if an article is deleted, its comments go with it</em>. Dont worry if you dont understand it all, this is just for you to see some actual Rails code.</p>
<p><code>dependent =&gt; true</code> means <em>if an article is deleted, it's comments go with it</em>. Don't worry if you don't understand it all, this is just for you to see some actual Rails code.</p>
<p>In the Comment model you have:</p>
@ -126,7 +126,7 @@ Styles: typocode
<p>(I snuck in some validations as well)</p>
<p>But look how it reads! Read it out loud. Id bet that my mom would more or less follow this, and shes anything but a programmer. Thats not to say programming should be easy for grandma, <strong>but code should be easily understood by humans</strong>. Let the computer understand things that are natural for me to type, since were making it understand a common language anyways.</p>
<p>But look how it reads! Read it out loud. I'd bet that my mom would more or less follow this, and she's anything but a programmer. That's not to say programming should be easy for grandma, <strong>but code should be easily understood by humans</strong>. Let the computer understand things that are natural for me to type, since we're making it understand a common language anyways.</p>
<p>Ruby and Ruby on Rails allow and encourage you to write beautiful code. That is so much more important than you may realize, because it leads to many other virtues. Readability is obvious, and hence maintainability. You must read code to understand and modify it. Oh, and happy programmers will be more productive than frustrated programmers.</p>
@ -135,7 +135,7 @@ Styles: typocode
<h3 id="migrations">Database Migrations</h3>
<p>Heres one more life-saver: migrations. Migrations are a way to version your database schema from within Rails. So you have a table, call it <code>albums</code>, and you want to add the date the album was released. You could modify the database directly, but thats not fun. Even if you only have one server, all your configuration will be in one central place, the app. And Rails doesnt care if you have PostgreSQL, MySQL, or SQLite behind it. You can develop and test on SQLite and deploy on MySQL and the migrations will just work in both environments.</p>
<p>Here's one more life-saver: migrations. Migrations are a way to version your database schema from within Rails. So you have a table, call it <code>albums</code>, and you want to add the date the album was released. You could modify the database directly, but that's not fun. Even if you only have one server, all your configuration will be in one central place, the app. And Rails doesn't care if you have PostgreSQL, MySQL, or SQLite behind it. You can develop and test on SQLite and deploy on MySQL and the migrations will just work in both environments.</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">class </span><span class="class">AddDateReleased</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Migration</span>
@ -149,49 +149,49 @@ Styles: typocode
<span class="keyword">end</span>
<span class="keyword">end</span></code></pre></div>
<p>Then you run the migration (<code>rake migrate</code> does that) and boom, your up to date. If youre wondering, the <code>self.down</code> method indeed implies that you can take this the other direction as well. Think <code>rake migrate VERSION=X</code>.</p>
<p>Then you run the migration (<code>rake migrate</code> does that) and boom, your up to date. If you're wondering, the <code>self.down</code> method indeed implies that you can take this the other direction as well. Think <code>rake migrate VERSION=X</code>.</p>
<p><em>Along with the other screencasts is one on <a href="http://www.rubyonrails.org/screencasts">migrations</a> featuring none other than David Hansson. You should take a look, its the third video.</em></p>
<p><em>Along with the other screencasts is one on <a href="http://www.rubyonrails.org/screencasts">migrations</a> featuring none other than David Hansson. You should take a look, it's the third video.</em></p>
<h3>Testing so easy it hurts</h3>
<p>To start a rails project you type <code>rails project_name</code> and it creates a directory structure with a fresh project in it. This includes a directory appropriately called <em>test</em> which houses unit tests for the project. When you generate models and controllers it creates test stubs for you in that directory. Basically, it makes it so easy to test that youre a fool not to do it. As someone wrote on their site: <em>It means never having to say <strong>I introduced a new bug while fixing another.</strong></em></p>
<p>To start a rails project you type <code>rails project_name</code> and it creates a directory structure with a fresh project in it. This includes a directory appropriately called <em>test</em> which houses unit tests for the project. When you generate models and controllers it creates test stubs for you in that directory. Basically, it makes it so easy to test that you're a fool not to do it. As someone wrote on their site: <em>It means never having to say "<strong>I introduced a new bug while fixing another.</strong>"</em></p>
<p>Rails builds on the unit testing that comes with Ruby. On a larger scale, that means that Rails is unlikely to flop on you because it is regularly tested using the same method. Ruby is unlikely to flop for the same reason. That makes me look good as a programmer. If you code for a living then its of even more value to you.</p>
<p>Rails builds on the unit testing that comes with Ruby. On a larger scale, that means that Rails is unlikely to flop on you because it is regularly tested using the same method. Ruby is unlikely to flop for the same reason. That makes me look good as a programmer. If you code for a living then it's of even more value to you.</p>
<p><em>I dont know why it hurts. Maybe it hurts developers working with other frameworks or languages to see us have it so nice and easy.</em></p>
<p><em>I don't know why it hurts. Maybe it hurts developers working with other frameworks or languages to see us have it so nice and easy.</em></p>
<h2>Wrapping up</h2>
<p>Rails means I have fun doing web development instead of being frustrated (CSS hacks aside). David Hansson may be right when he said you have to have been soured by Java or <span class="caps">PHP</span> to fully appreciate Rails, but that doesnt mean you wont enjoy it if you <em>do</em> like Java or <span class="caps">PHP</span>.</p>
<p>Rails means I have fun doing web development instead of being frustrated (CSS hacks aside). David Hansson may be right when he said you have to have been soured by Java or PHP to fully appreciate Rails, but that doesn't mean you won't enjoy it if you <em>do</em> like Java or PHP.</p>
<p><a href="http://www.relevancellc.com/blogs/wp-trackback.php?p=31">Justin Gehtland</a> rewrote a Java app using Rails and the number of lines of code of the Rails version was very close to that of the <span class="caps">XML</span> configuration for the Java version. Java has strengths, libraries available <strong>now</strong> seems to be a big one, but its too big for my needs. If youre like me then maybe youll enjoy Rails as much as I do.</p>
<p><a href="http://www.relevancellc.com/blogs/wp-trackback.php?p=31">Justin Gehtland</a> rewrote a Java app using Rails and the number of lines of code of the Rails version was very close to that of the XML configuration for the Java version. Java has strengths, libraries available <strong>now</strong> seems to be a big one, but it's too big for my needs. If you're like me then maybe you'll enjoy Rails as much as I do.</p>
<h2>Youre not done, you lied to me!</h2>
<h2>You're not done, you lied to me!</h2>
<p>Sort of there are a few things that it seems standard to include when someone writes about how Rails saved their life and gave them hope again. For completeness sake, I feel compelled to mention some principles common amongst those who develop Rails, and those who develop on Rails. Its entirely likely that theres nothing new for you here unless youre new to Rails or to programming, in which case I encourage you to read on.</p>
<p>Sort of... there are a few things that it seems standard to include when someone writes about how Rails saved their life and gave them hope again. For completeness sake, I feel compelled to mention some principles common amongst those who develop Rails, and those who develop on Rails. It's entirely likely that there's nothing new for you here unless you're new to Rails or to programming, in which case I encourage you to read on.</p>
<h3><span class="caps">DRY</span></h3>
<h3>DRY</h3>
<p>Rails follows the <span class="caps">DRY</span> principle religiously. That is, <strong>Dont Repeat Yourself</strong>. Like <span class="caps">MVC</span>, I was already sold on this. I had previously encountered it in <a href="http://www.pragmaticprogrammer.com/ppbook/index.shtml">The Pragmatic Programmer</a>. Apart from telling <em>some_model</em> it <code>belongs_to :other_model</code> and <em>other_model</em> that it <code>has_many :some_models</code> nothing has jumped out at me which violates this principle. However, I feel that reading a models code and seeing its relationships to other models right there is a Good Thing™.</p>
<p>Rails follows the DRY principle religiously. That is, <strong>Don't Repeat Yourself</strong>. Like MVC, I was already sold on this. I had previously encountered it in <a href="http://www.pragmaticprogrammer.com/ppbook/index.shtml">The Pragmatic Programmer</a>. Apart from telling <em>some_model</em> it <code>belongs_to :other_model</code> and <em>other_model</em> that it <code>has_many :some_models</code> nothing has jumped out at me which violates this principle. However, I feel that reading a model's code and seeing it's relationships to other models right there is a Good Thing™.</p>
<h3>Convention over configuration <em>(or, Perceived intelligence)</em></h3>
<p>Rails developers also have the mantra “<em>convention over configuration</em>”, which you can see from the video there. (you did watch it, didnt you? ;) Basically that just means Rails has sane defaults, but is still flexible if you dont like the defaults. You dont have to write even one line of <span class="caps">SQL</span> with Rails, but if you need greater control then you <em>can</em> write your own <span class="caps">SQL</span>. A standard cliché: <em>it makes the simple things easy and the hard possible</em>.</p>
<p>Rails' developers also have the mantra "<em>convention over configuration</em>", which you can see from the video there. (you did watch it, didn't you? ;) Basically that just means Rails has sane defaults, but is still flexible if you don't like the defaults. You don't have to write even one line of SQL with Rails, but if you need greater control then you <em>can</em> write your own SQL. A standard cliché: <em>it makes the simple things easy and the hard possible</em>.</p>
<p>Rails seems to have a level of intelligence which contributes to the wow-factor. After <a href="#migrations">these relationships</a> are defined I can now filter certain negative comments like so:</p>
@ -211,5 +211,5 @@ Styles: typocode
<h3>Code as you learn</h3>
<p>I love how Ive only been coding in Rails for a week or two and I can do so much already. Its natural, concise and takes care of the inane details. I love how I <em>know</em> that I dont even have to explain that migration example. Its plainly clear what it does to the database. It doesnt take long to get the basics down and once you do it goes <strong>fast</strong>.</p>
<p>I love how I've only been coding in Rails for a week or two and I can do so much already. It's natural, concise and takes care of the inane details. I love how I <em>know</em> that I don't even have to explain that migration example. It's plainly clear what it does to the database. It doesn't take long to get the basics down and once you do it goes <strong>fast</strong>.</p>

View file

@ -5,12 +5,12 @@ Author: sjs
Tags: textmate, rails, coding, rails, snippets, testing, textmate
----
<p>This time Ive got a few snippets for assertions. Using these to type up your tests quickly, and then hitting <strong>⌘R</strong> to run the tests without leaving TextMate, makes testing your Rails app that much more convenient. Just when you thought it was already too easy! (Dont forget that you can use <strong>⌥⌘↓</strong> to move between your code and the corresponding test case.)</p>
This time I've got a few snippets for assertions. Using these to type up your tests quickly, and then hitting **⌘R** to run the tests without leaving TextMate, makes testing your Rails app that much more convenient. Just when you thought it was already too easy! (Don't forget that you can use **⌥⌘↓** to move between your code and the corresponding test case.)
<p>This time Im posting the .plist files to make it easier for you to add them to TextMate. All you need to do is copy these to <strong>~/Library/Application Support/TextMate/Bundles/Rails.tmbundle/Snippets</strong>.</p>
This time I'm posting the .plist files to make it easier for you to add them to TextMate. All you need to do is copy these to **~/Library/Application Support/TextMate/Bundles/Rails.tmbundle/Snippets**.
<p style="text-align: center;"><a href="http://sami.samhuri.net/files/assert_snippets.zip">Assertion Snippets for Rails</a></p>
<p style="text-align: center;"><a href="/f/assert_snippets.zip">Assertion Snippets for Rails</a></p>
<p>If anyone would rather I list them all here I can do that as well. Just leave a comment.</p>
If anyone would rather I list them all here I can do that as well. Just leave a comment.
<p><em>(I wanted to include a droplet in the zip file that will copy the snippets to the right place, but my 3-hour attempt at writing the AppleScript to do so left me feeling quite bitter. Maybe I was just mistaken in thinking it would be easy to pick up AppleScript.)</em></p>
*(I wanted to include a droplet in the zip file that will copy the snippets to the right place, but my 3-hour attempt at writing the AppleScript to do so left me feeling quite bitter. Maybe I was just mistaken in thinking it would be easy to pick up AppleScript.)*

View file

@ -6,12 +6,12 @@ Tags: textmate, rails, hacking, commands, macro, rails, snippets, textmate
Styles: typocode
----
<p><em><strong><span class="caps">UPDATE</span>:</strong> I got everything working and its all packaged up <a href="2006.02.22-intelligent-migration-snippets-01-for-textmate.html">here</a>. Theres an installation script this time as well.</em></p>
<p><em><strong>UPDATE:</strong> I got everything working and it's all packaged up <a href="2006.02.22-intelligent-migration-snippets-0.1-for-textmate.html">here</a>. There's an installation script this time as well.</em></p>
<p>Thanks to <a href="http://thread.gmane.org/gmane.editors.textmate.general/8520">a helpful thread</a> on the TextMate mailing list I have the beginning of a solution to insert text at 2 (or more) locations in a file.</p>
<p>I implemented this for a new snippet I was working on for migrations, <code>rename_column</code>. Since the command is the same in self.up and self.down simply doing a reverse search for <code>rename_column</code> in my <a href="2006.02.21-textmate-move-selection-to-self-down.html">hackish macro</a> didnt return the cursor the desired location.</p><p>Thats enough introduction, heres the program to do the insertion:</p>
<p>I implemented this for a new snippet I was working on for migrations, <code>rename_column</code>. Since the command is the same in self.up and self.down simply doing a reverse search for <code>rename_column</code> in my <a href="2006.02.21-textmate-move-selection-to-self-down.html">hackish macro</a> didn't return the cursor the desired location.</p><p>That's enough introduction, here's the program to do the insertion:</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="comment">#!/usr/bin/env ruby</span>
@ -44,7 +44,7 @@ Styles: typocode
<li><strong>Save:</strong> Nothing</li>
<li><strong>Input:</strong> Selected Text or Nothing</li>
<li><strong>Output:</strong> Insert as Snippet</li>
<li><strong>Activation:</strong> Whatever you want, Im going to use a macro described below and leave this empty</li>
<li><strong>Activation:</strong> Whatever you want, I'm going to use a macro described below and leave this empty</li>
<li><strong>Scope Selector:</strong> source.ruby.rails</li>
</ul>
@ -52,11 +52,11 @@ Styles: typocode
<p>The first modification it needs is to get the lines to insert as command line arguments so we can use it for other snippets. Secondly, regardless of the <strong>Re-indent pasted text</strong> setting the text returned is indented incorrectly.</p>
The macro Im thinking of to invoke this is tab-triggered and will simply:
The macro I'm thinking of to invoke this is tab-triggered and will simply:
<ul>
<li>Select word (<tt><strong>⌃W</strong></tt>)</li>
<li>Delete (<tt><strong></strong></tt>)</li>
<li>Select to end of file (<tt><strong>⇧⌘↓</strong></tt>)</li>
<li>Run command “Put in self.down”</li>
<li>Run command "Put in self.down"</li>
</ul>

View file

@ -0,0 +1,29 @@
Title: TextMate: Move selection to self.down
Date: February 21, 2006
Timestamp: 1140510360
Author: sjs
Tags: textmate, rails, hacking, hack, macro, rails, textmate
----
<p><strong>UPDATE:</strong> <em>This is obsolete, see <a href="2006.02.21-textmate-insert-text-into-self-down.html">this post</a> for a better solution.</em></p>
<p><a href="2006.02.18-some-textmate-snippets-for-rails-migrations.html#comment-3">Duane's comment</a> prompted me to think about how to get the <code>drop_table</code> and <code>remove_column</code> lines inserted in the right place. I don't think TextMate's snippets are built to do this sort of text manipulation. It would be nicer, but a quick hack will suffice for now.</p><p>Use <acronym title="Migration Create and Drop Table">MCDT</acronym> to insert:</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="ident">create_table</span> <span class="punct">"</span><span class="string">table</span><span class="punct">"</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">t</span><span class="punct">|</span>
<span class="keyword">end</span>
<span class="ident">drop_table</span> <span class="punct">"</span><span class="string">table</span><span class="punct">"</span></code></pre></div>
<p>Then press tab once more after typing the table name to select the code <code>drop_table "table"</code>. I created a macro that cuts the selected text, finds <code>def self.down</code> and pastes the line there. Then it searches for the previous occurence of <code>create_table</code> and moves the cursor to the next line, ready for you to add some columns.</p>
<p>I have this bound to <strong>⌃⌥⌘M</strong> because it wasn't in use. If your Control key is to the left the A key it's quite comfortable to hit this combo. Copy the following file into <strong>~/Library/Application Support/TextMate/Bundles/Rails.tmbundle/Macros</strong>.</p>
<p style="text-align: center;"><a href="http://sami.samhuri.net/files/move-to-self.down.plist">Move selection to self.down</a></p>
<p>This works for the <acronym title="Migration Add and Remove Column">MARC</acronym> snippet as well. I didn't tell you the whole truth, the macro actually finds the previous occurence of <code>(create_table|add_column)</code>.</p>
<p>The caveat here is that if there is a <code>create_table</code> or <code>add_column</code> between <code>self.down</code> and the table you just added, it will jump back to the wrong spot. It's still faster than doing it all manually, but should be improved. If you use these exclusively, the order they occur in <code>self.down</code> will be opposite of that in <code>self.up</code>. That means either leaving things backwards or doing the re-ordering manually. =/</p>

View file

@ -0,0 +1,44 @@
Title: Intelligent Migration Snippets 0.1 for TextMate
Date: February 22, 2006
Timestamp: 1140607680
Author: sjs
Tags: mac os x, textmate, rails, hacking, migrations, snippets
----
*This should be working now. I've tested it under a new user account here.*
*This does requires the syncPeople bundle to be installed to work. That's ok, because you should get the [syncPeople on Rails bundle](syncPeople) anyways.*
When writing database migrations in Ruby on Rails it is common to create a table in the `self.up` method and then drop it in `self.down`. The same goes for adding, removing and renaming columns.
I wrote a Ruby program to insert code into both methods with a single snippet. All the TextMate commands and macros that you need are included.
### See it in action ###
I think this looks cool in action. Plus I like to show off what what TextMate can do to people who may not use it, or don't have a Mac. It's just over 30 seconds long and weighs in at around 700kb.
<p style="text-align: center">
<img src="/images/download.png" title="Download" alt="Download">
<a href="/f/ims-demo.mov">Download Demo Video</a>
</p>
### Features ###
There are 3 snippets which are activated by the following tab triggers:
* __mcdt__: Migration Create and Drop Table
* __marc__: Migration Add and Remove Column
* __mnc__: Migration Rename Column
### Installation ###
Run **Quick Install.app** to install these commands to your <a [syncPeople on Rails bundle](syncPeople) if it exists, and to the default Rails bundle otherwise. (I highly recommend you get the syncPeople bundle if you haven't already.)
<p style="text-align: center">
<img src="/images/download.png" title="Download" alt="Download">
<a href="/f/IntelligentMigrationSnippets-0.1.dmg">Download Intelligent Migration Snippets</a>
</p>
This is specific to Rails migrations, but there are probably other uses for something like this. You are free to use and distribute this code.
[syncPeople]: http://blog.inquirylabs.com/

View file

@ -0,0 +1,8 @@
Title: Generate self.down in your Rails migrations
Date: March 3, 2006
Timestamp: 1141450680
Author: sjs
Tags: rails, textmate, migrations, rails, textmate
----
<a href="http://lunchboxsoftware.com/">Scott</a> wrote a really <a href="http://lunchroom.lunchboxsoftware.com/articles/2005/11/29/auto-fill-your-reverse-migrations">cool program</a> that will scan `self.up` and then consult db/schema.rb to automatically fill in `self.down` for you. Brilliant!

View file

@ -0,0 +1,10 @@
Title: zsh terminal goodness on OS X
Date: April 4, 2006
Timestamp: 1144187820
Author: sjs
Tags: mac os x, apple, osx, terminal, zsh
----
<a href="http://www.apple.com/">Apple</a> released the <a href="http://docs.info.apple.com/article.html?artnum=303411">OS X 10.4.6 update</a> which fixed a <strong>really</strong> annoying bug for me. Terminal (and <a href="http://iterm.sourceforge.net/">iTerm</a>) would fail to open a new window/tab when your shell is <a href="http://zsh.sourceforge.net/">zsh</a>. iTerm would just open then immediately close the window, while Terminal would display the message: <code>[Command completed]</code> in a now-useless window.
Rebooting twice to get the fix was reminiscent of <a href="http://www.microsoft.com/windows/default.mspx">Windows</a>, but well worth it.

View file

@ -0,0 +1,14 @@
Title: Ich bin Ausländer und spreche nicht gut Deutsch
Date: June 5, 2006
Timestamp: 1149527460
Author: sjs
Tags: life, munich, seekport, work
----
How's this for an update: I'm working in Munich for the summer at a European search engine called <a href="http://www.seekport.co.uk/">Seekport</a>. The search engine isn't all they do, as right now I'm programming a desktop widget that shows live scores &amp; news from World Cup matches (in English and Arabic). I'm building it on top of the <a href="http://widgets.yahoo.com/">Yahoo! Widget Engine</a> because it needs to run on Windows. Even though I quite like the Y! Engine, I would still prefer to be coding in straight HTML, CSS & JavaScript like Dashboard programmers get to use. The Y! Engine uses XML (it is somewhat HTML-like) and JavaScript.
The place I'm living in is like a dormitory for younger people. I share a bathroom & kitchen with a German guy named Sebastian who is 21 and an artist; a stonecutter actually. I only met him briefly yesterday, but he seems nice. I'm going to teach him English, and he'll teach me German, though his English is much better than my German. It's a pretty quiet place, and we get breakfast included, dinner can be bought for €2,50, and Internet access is included as well. I brought my Mac Mini with me, and as soon as I find an AC adapter I'll be ready to go with the 'net at home. I probably won't blog again till then, since I'm at work right now.
Germany is great so far, and as soon as I get learning some German I'll be a much happier person. I consider it rude of me to expect everyone to converse with me in English, like I have to do right now.
(Oh, and they sell beer by the litre in Germany! They call it a maß.)

View file

@ -0,0 +1,14 @@
Title: Never buy a German keyboard!
Date: June 9, 2006
Timestamp: 1149841020
Author: sjs
Tags: apple, apple, german, keyboard
----
Nothing personal, but the backtick/tilde is located where the rest of the left shift key should be, and the return key is double-height, forcing the backslash/bar to the right of the dash/underscore (that'd be the apostrophe/double quote for pretty much everyone else who types qwerty). Note that I'm talking about using a German keyboard with an English layout. The German layout is flat out impossible for coding.
<a href="/images/keyboard.jpg"><img src="/images/keyboard.jpg" title="German Apple Keyboard" alt="German Apple Keyboard"></a>
For some reason it gets even worse with a German Apple keyboard. Square brackets, where for art though? Through trial and error I found them using Alt/Opt+5/6... non-Apple German keyboards I've seen use Alt Gr+8/9, which is just as bad but at least they were <strong>labeled</strong>. I know why coders here don't use the German layout! I feel uneasy just talking about it.
Here's a <a href="/f/german_keys.txt">text file</a> with each character of the 4 rows in it, normal and then shifted, in qwerty, qwertz, and dvorak. I personally think that some ways the German keys change must be some sick joke (double quote moved up to shift-2, single quote almost staying put, angle brackets being shoved aside only to put the semi-colon and colon on different keys as well). If you ask me lots of that could be avoided by getting rid of the key that replaced the backtick/tilde, and putting the 3 vowels with the umlaut (ü, ö, and ä) on Alt Gr/Opt+[aou]. But hey, I don't type in German so what do I know.

View file

@ -0,0 +1,21 @@
Title: There's nothing regular about regular expressions
Date: June 10, 2006
Timestamp: 1149928080
Author: sjs
Tags: technology, book, regex
----
I'm almost half way reading Jeffrey Friedl's book <a href="http://www.oreilly.com/catalog/regex2/">Mastering Regular Expressions</a> and I have to say that for a book on something that could potentially bore you to tears, he really does an excellent job of keeping it interesting. Even though a lot of the examples are contrived (I'm sure out of necessity), he also uses real examples of regexes that he's actually used at <a href="http://www.yahoo.com/">Yahoo!</a>.
As someone who has to know how everything works it's also an excellent lesson in patience, as he frequently says "here, take this knowledge and just accept it for now until I can explain why in the next chapter (or in 3 chapters!)". But it's all with good reason and when he does explain he does it well.
Reading about the different NFA and DFA engines and which tools use which made me go "ahhh, /that's/ why I can't do that in grep!" It's not just that I like to know how things work either, he's 100% correct about having to know information like that to wield the power of regexes in all situations. This book made me realize that regex implementations can be wildly different and that you really need to consider the job before jumping into using a specific regex flavour, as he calls them. I'm fascinated by learning why DFA regex implementations would successfully allow `^\w+=.(\\\n.)*` to match certain lines, allowing for trailing backslashes to mean continuation but why NFA engines would fail to do the same without tweaking it a bit.
It requires more thinking than the last 2 computer books I read, *Programming Ruby* (the "pixaxe" book) and *Agile Web Development With Rails* so it's noticeably slower reading. It's also the kind of book I will read more than once, for sure. There's just no way I can glean everything from it in one reading. If you use regular expressions at all then you need this book. This is starting to sound like an advertisement so I'll say no more.
QOTD, p. 329, about matching nested pairs of parens:
\(([^()]|\(([^()]|\(([^()]|\(([^()])*\))*\))*\))*\)
Wow, that's ugly.
(Don't worry, there's a much better solution on the next 2 pages after that quote.)

View file

@ -0,0 +1,41 @@
Title: Working with the Zend Framework
Date: July 6, 2006
Timestamp: 1152196560
Author: sjs
Tags: coding, technology, php, framework, php, seekport, zend
----
At <a href="http://www.seekport.co.uk/">Seekport</a> I'm currently working on an app to handle
the config of their business-to-business search engine. It's web-based and I'm using PHP, since
that's what they're re-doing the front-end in. Right now it's a big mess of Perl, the main
developer (for the front-end) is gone, and they're having trouble managing it. I have read
through it, and it's pretty dismal. They have config mixed with logic and duplicated code all
over the place. There's an 1100 line sub in one of the perl modules. Agh!
Anyway, I've been looking at basically every damn PHP framework there is and most of them
aren't that great (sorry to the devs, but they're not). It's not really necessary for my little
project, but it helps in both writing and maintaining it. Many of them are unusable because
they're still beta and have bugs, and I need to develop the app not debug a framework. Some of
them are nice, but not really what I'm looking for, such as <a
href="http://www.qcodo.com/">Qcodo</a>, which otherwise look really cool.
<a href="http://cakephp.org/">CakePHP</a> and <a
href="http://www.symfony-project.com/">Symfony</a> seem to want to be <a
href="http://www.rubyonrails.org/">Rails</a> so badly, but fall short in many ways, code beauty
being the most obvious one.
I could go on about them all, I looked at over a dozen and took at least 5 of them for a
test-drive. The only one I really think has a chance to be <em>the</em> PHP framework is the <a
href="http://framework.zend.com/">Zend Framework</a>. I really don't find it that amazing, but
it feels right, whereas the others feel very thrown-together. In other words, it does a good
job of not making it feel like PHP. ;-)
Nothing they're doing is relovutionary, and I question the inclusion of things like PDF
handling when they don't even seem to have relationships figured out, but it provides a nice
level of convenience above PHP without forcing you into their pattern of thinking. A lot of the
other frameworks I tried seemed like one, big, unbreakable unit. With Zend I can really tell
that nothing is coupled.
So I'll probably be writing some notes here about my experience with this framework. I also
hope to throw Adobe's <a href="http://labs.adobe.com/technologies/spry/">Spry</a> into the mix.
That little JS library is a lot of fun.

View file

@ -0,0 +1,14 @@
Title: Ubuntu: Linux for Linux users please
Date: July 13, 2006
Timestamp: 1152804840
Author: sjs
Tags: linux, linux, ubuntu
----
<a href="http://www.ubuntu.com/">Ubuntu</a> is a fine Linux distro, which is why it's popular. I still use <a href="http://www.gentoo.org/">Gentoo</a> on my servers but Ubuntu is fast to set up for a desktop. Linux for humans it certainly is, but dammit sometimes I want Linux like I'm used to.
It should ship with build-essentials (gcc & others) installed. It *shouldn't* ask me if I'm sure I want to restart at the GDM login screen. I have no session open and already clicked twice to choose Restart.
Other things aren't quite ready for humans yet. Network config needs some work. It's very slow to apply changes. Connecting to Windows printers should be easier (ie. let us browse to find them, or just search and present a list). Fonts aren't amazing yet, though Mac OS X has spoiled me as far as fonts are concerned.
Other than these things I think Ubuntu Dapper is a fine release. It installed on my work laptop without a problem and detected the volume keys and wireless network card flawlessly.

View file

@ -0,0 +1,50 @@
Title: Some features you might have missed in iTunes 7
Date: September 22, 2006
Timestamp: 1158969540
Author: sjs
Tags: apple, apple, itunes
----
<img src="/images/menu.png" style="float: right; margin: 10px;" title="New menu" alt="New menu">
Besides the <a href="http://www.tuaw.com/2006/09/12/walkthrough-itunes-7s-big-new-features/">big changes</a> in <a href="http://www.apple.com/itunes">iTunes 7</a> there have been some minor changes that are still pretty useful.
Here's a quick recap of a few major features:
* <a href="http://sami.samhuri.net/files/coverflow.png">Coverflow</a> built in, new views to flip through album covers and video thumbnails
* iTunes Music Store is now just the iTunes Store
* New look, no more brushed metal
* The menu on the left is more structured and easier to navigate (for me)
* Games support
And now some of the smaller gems are listed below.
<h3 style="clear: right;">Video controls</h3>
<a href="/images/itunes-controls.png"><img src="/images/itunes-controls-thumb.png" style="float: left; margin: 10px;" title="iTunes video controls" alt="iTunes video controls"></a>
Similar to the <a href="/images/quicktime-controls.png">Quicktime full screen controls</a>, iTunes now sports video controls as well. It was really annoying to have to exit fullscreen to control the video, and now we don't have to. The controls are available when you have a floating video window open as well as when you're <a href="/images/itunes-controls-fullscreen.png">full screen</a>.
<h3 style="clear: left;">Smart playlists</h3>
It's always bothered me that I couldn't remove tracks from smart playlists. After all they are supposed to be smart, so they should remember customizations to them since even the basic ones do that. They're getting smarter. You still can't add arbitrary tracks to one, but I've never wanted to do that except just now to see if you could.
### Gapless playback (and more) ###
<a href="/images/gapless.png"><img src="/images/gapless-thumb.png" style="float: right; padding: 10px;" title="Gapless playback" alt="Gapless playback"></a>
You can set tracks to be part of a gapless album, and your iPod makes use of that information too. Sweet. Another new flag is "Skip when shuffling".
There's also a new field for audio named "Album Artist", but I have no idea what that means.
<h3 style="clear: right;">More video metadata</h3>
<a href="http://sami.samhuri.net/files/metadata.png"><img src="./Some features you might have missed in iTunes 7 - samhuri.net_files/metadata-thumb.png" style="float: right:margin:10px;" title="iTunes video controls" alt="iTunes video controls"></a>
For videos you can now set the Show, Season Number, Episode Number, and Episode ID for each video. Why they let you do this for Movies and Music Videos I'm not sure, but there it is.
<h3 style="clear: right;">What's still missing?</h3>
I want to be able to change more than one movie's type to Movie, Music Video, or TV Show at once. Manually doing it for more than one season of a show gets old very fast, and I'm reluctant to write a program to let you do just that but I may if I have time.
I'm sure I have other gripes, but honestly iTunes is a full-featured app and while there's room for improvement they do get a lot right with it as well.

View file

@ -0,0 +1,106 @@
Title: Coping with Windows XP activiation on a Mac
Date: December 17, 2006
Timestamp: 1166427000
Author: sjs
Tags: parallels, windows, apple, mac os x, bootcamp
----
**Update:** This needs to be run at system startup, before you log in. I have XP Home and haven't been able to get it to run that way yet.
I can't test my method until I get XP Pro, if I get XP Pro at all. However chack left a <a href="2006.12.17-coping-with-windows-xp-activiation-on-a-mac.html#comment-1">comment</a> saying that he got it to work on XP Pro, so it seems we've got a solution here.
<hr>
### What is this about? ###
I recently deleted my <a href="http://www.microsoft.com/windowsxp/default.mspx">Windows XP</a> disk image for <a href="http://www.parallels.com/en/products/workstation/mac/">Parallels Desktop</a> and created a <a href="http://www.apple.com/macosx/bootcamp/">Boot Camp</a> partition for a new Windows XP installation. I created a new VM in Parallels and it used my Boot Camp partition without a problem. The only problem is that Windows XP Home wants to re-activate every time you change from Parallels to Boot Camp or vice versa. It's very annoying, so what can we do about it?
I was reading the Parallels forums and found out that you can <a href="http://forums.parallels.com/post30939-4.html">backup your activation</a> and <a href="http://forums.parallels.com/post32573-13.html">restore it later</a>. After reading that I developed a <a href="http://forums.parallels.com/post33487-22.html">solution</a> for automatically swapping your activation on each boot so you don't have to worry about it.
I try and stick to Linux and OS X especially for any shell work, and on Windows I would use zsh on cygwin if I use any shell at all, but I think I have managed to hack together a crude batch file to solve this activation nuisance. It's a hack but it sure as hell beats re-activating twice or more every day. It also reinforced my love of zsh and utter dislike of the Windows "shell".
If anyone actually knows how to write batch files I'd like to hear any suggestions you might have.
<hr>
### Make sure things will work ###
You will probably just want to test my method of testing for Parallels and Boot Camp first. The easiest way is to just open a command window and run this command:
ipconfig /all | find "Parallels"
If you see a line of output like **"Description . . . . : Parallels Network Adapter"** and you are in Parallels then the test works. If you see no output and you are in Boot Camp then the test works.
*If you see no output in Parallels or something is printed and you're in Boot Camp, then please double check that you copied the command line correctly, and that you really are running Windows where you think you are. ;-)*
If you're lazy then you can download <a href="http://sami.samhuri.net/files/parallels/test.bat">this test script</a> and run it in a command window. Run it in both Parallels and Boot Camp to make sure it gets them both right. The output will either be "Boot Camp" or "Parallels", and a line above that which you can just ignore.
<hr>
**NOTE:** If you're running Windows in Boot Camp right now then do Step #2 before Step #1.
<hr>
## Step #1 ##
Run Windows in Parallels, activate it, then open a command window and run:
mkdir C:\Windows\System32\Parallels
copy C:\Windows\System32\wpa.* C:\Windows\System32\Parallels
Download <a href="http://sami.samhuri.net/files/parallels/backup-parallels-wpa.bat">backup-parallels-wpa.bat</a>
<hr>
## Step #2 ##
Run Windows using Boot Camp, activate it, then run:
mkdir C:\Windows\System32\BootCamp
copy C:\Windows\System32\wpa.* C:\Windows\System32\BootCamp
Download <a href="http://sami.samhuri.net/files/parallels/backup-bootcamp-wpa.bat">backup-bootcamp-wpa.bat</a>
<hr>
## Step #3: Running the script at startup ##
Now that you have your activations backed up you need to have the correct ones copied into place every time your system boots. Save this file anywhere you want.
If you have XP Pro then you can get it to run using the Group Policy editor. Save the activate.bat script provided here anywhere and then have it run as a system service. Go Start -> Run... -> gpedit.msc [enter] Computer Configuration -> Windows Settings -> Scripts (Startup/Shutdown) -> Startup -> Add.
<p>If you have XP Home then the best you can do is run this script from your Startup folder (Start -> All Programs -> Startup), but that is not really going to work because eventually Windows will not even let you log in until you activate it. What a P.O.S.</p>
@echo off
ipconfig /all | find "Parallels" > network.tmp
for /F "tokens=14" %%x in (network.tmp) do set parallels=%x
del network.tmp
if defined parallels (
echo Parallels
copy C:\Windows\System32\Parallels\wpa.* C:\Windows\System32
) else (
echo Boot Camp
copy C:\Windows\System32\BootCamp\wpa.* C:\Windows\System32
)
Download <a href="http://sami.samhuri.net/files/parallels/activate.bat">activate.bat</a>
<hr>
### You're done! ###
That's all you have to do. You should now be able to run Windows in Boot Camp and Parallels as much as you want without re-activating the stupid thing again!
If MS doesn't get their act together with this activation bullshit then maybe the Parallels folks might have to include something hack-ish like this by default.
This method worked for me and hopefully it will work for you as well. I'm interested to know if it does or doesn't so please leave a comment or e-mail me.
<hr>
#### Off-topic rant ####
I finally bought Windows XP this week and I'm starting to regret it because of all the hoops they make you jump through to use it. I only use it to fix sites in IE because it can't render a web page properl and I didn't want to buy it just for that. I thought that it would be good to finally get a legit copy since I was using a pirated version and was sick of working around validation bullshit for updates. Now I have to work around MS's activation bullshit and it's just as bad! Screw Microsoft for putting their customers through this sort of thing. Things like this and the annoying balloons near the system tray just fuel my contempt for Windows and reinforce my love of Linux and Mac OS X.
I don't make money off any of my sites, which is why I didn't want to have to buy stupid Windows. I hate MS so much for making shitty IE the standard browser.

View file

@ -0,0 +1,12 @@
Title: Full-screen Cover Flow
Date: March 6, 2007
Timestamp: 1173217860
Author: sjs
Tags: apple, coverflow, itunes
----
<a href="http://www.apple.com/itunes/jukebox/coverflow.html">Cover Flow</a> now comes in a full-screen flavour. It's pretty sweet, but unfortunately the remote controls iTunes exactly the same so you need a mouse to flick through the covers.
That made me wonder if Front Row used this full-screen Cover Flow view for albums now, but it doesn't. I hope Apple gets on this and adds it to Front Row and the Apple TV. I'm sure it's already on their list.
I would love to be able to flick through my albums with the remote right now, but I'm not going to install one of those 3rd-party remote config tools. Guess I have to wait for Apple to do it.

View file

@ -0,0 +1,14 @@
Title: Digg v4: Reply to replies (Greasemonkey script)
Date: March 8, 2007
Timestamp: 1173424740
Author: sjs
Tags: coding, digg, firefox, userscript
----
It's nearly identical to <a href="http://userscripts.org/scripts/show/4664">the previous one</a> but works with Digg v4 and should be slightly more efficient. I'm working on making it faster because I believe it is quite inefficient as it is. It was David Bendit's (the original author) first script though so kudos to him for starting this thing because I love it. I just hate a slow greasemonkey script on pages with hundreds of comments.
Please leave me some comments if you appreciate this, or have any feedback on the code.
Happy Digging!
<a href="http://www.digg.com/software/Reply_to_reply_Greasemonkey_script_Updated_for_Digg_v4">Digg this script!</a>

View file

@ -0,0 +1,16 @@
Title: Diggscuss 0.9
Date: March 25, 2007
Timestamp: 1174834980
Author: sjs
Tags: coding, digg, firefox, userscript
----
The biggest change is that it uses XPath for the dirty work, which makes it quite a bit more readable. It's 100 lines longer than the previous version, but it does twice as much.
Now both a [reply] and a [quote] link are added to each comment. Replying to parent comments now adds @username: to the comment field as well as the links added by the script.
Regression: The link to the parent comment is no longer displayed. If you miss this then let me know and I will add it back in.
Any comments, criticism or feature requests are welcome just leave me a comment here or on userscripts.org.
Happy Digging!

View file

@ -5,14 +5,11 @@ Author: sjs
Tags: activerecord, coding, rails, ruby
----
<p>Ive extended ActiveRecord with <tt>find_or_create(params)</tt> and <tt>find_or_initialize(params)</tt>. Those are actually just wrappers around <tt>find_or_do(action, params)</tt> which does the heavy lifting.</p>
I've extended ActiveRecord with `find_or_create(params)` and `find_or_initialize(params)`. Those are actually just wrappers around `find_or_do(action, params)` which does the heavy lifting.
They work exactly as you'd expect them to work with possibly one gotcha. If you pass in an `id` attribute then it will just find that record directly. If it fails it will try and find the record using the other params as it would have done normally.
<p>They work exactly as youd expect them to work with possibly one gotcha. If you pass in an <tt>id</tt> attribute then it will just find that record directly. If it fails it will try and find the record using the other params as it would have done normally.</p>
<p>Enough chat, heres the self-explanatory code:</p>
Enough chat, here's the self-explanatory code:
<table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
@ -113,6 +110,3 @@ Tags: activerecord, coding, rails, ruby
</tt><span class="r">end</span></pre></td>
</tr></table>
<div class="extended">
<p><a href="http://web.archive.org/web/20071124024600/http://sami.samhuri.net/2007/4/11/activerecord-base-find_or_create-and-find_or_initialize">Continue reading...</a></p>
</div>

View file

@ -9,11 +9,12 @@ Tags: technology, networking
<div style="width:100%;text-align:center;">
<embed style="width:400px; height:326px;" type="application/x-shockwave-flash" src="http://video.google.com/googleplayer.swf?docId=-6972678839686672840"> </embed>
<a href="http://video.google.com/videoplay?docid=-6972678839686672840">Watch the talk on Google&#8217;s site</a>
<br>
<a href="http://video.google.com/videoplay?docid=-6972678839686672840">Watch the talk on Google's site</a>
</div>
The man is very smart and his ideas are fascinating. He has the experience and knowledge to see the big picture and what can be done to solve some of the new problems we have. He starts with the beginning of the phone networks and then goes on to briefly explain the origins of the <a href="http://web.archive.org/web/20070520022504/http://en.wikipedia.org/wiki/ARPANET">ARPAnet</a>, which evolved into the modern Internet and <span class="caps">TCP</span>/IP and the many other protocols we use daily (often behind the scenes).
The man is very smart and his ideas are fascinating. He has the experience and knowledge to see the big picture and what can be done to solve some of the new problems we have. He starts with the beginning of the phone networks and then goes on to briefly explain the origins of the <a href="http://en.wikipedia.org/wiki/ARPANET">ARPAnet</a>, which evolved into the modern Internet and TCP/IP and the many other protocols we use daily (often behind the scenes).
He explains the problems that were faced while using the phone networks for data, and how they were solved by realizing that a new problem had risen and needed a new, different solution. He then goes to explain how the Internet has changed significantly from the time it started off in research centres, schools, and government offices into what it is today (lots of identical bytes being redundantly pushed to many consumers, where broadcast would be more appropriate and efficient).
If you have some time I really suggest watching this talk. I would love to research some of the things he spoke about if I ever got the chance. I&#8217;m sure they&#8217;ll be on my mind anyway and inevitably I&#8217;ll end up playing around with layering crap onto <span class="caps">IPV6</span> and what not. Deep down I love coding in C and I think developing a protocol would be pretty fun. I&#8217;d learn a lot in any case.
If you have some time I really suggest watching this talk. I would love to research some of the things he spoke about if I ever got the chance. I'm sure they'll be on my mind anyway and inevitably I'll end up playing around with layering crap onto IPV6 and what not. Deep down I love coding in C and I think developing a protocol would be pretty fun. I'd learn a lot in any case.

View file

@ -5,6 +5,6 @@ Author: sjs
Tags: life, photo, bc, victoria
----
I lived in <a href="http://en.wikipedia.org/wiki/Victoria%2C_British_Columbia">Victoria</a> for over a year before I ever rode the <a href="http://www.bcferries.com/">ferry</a> between <a href="http://en.wikipedia.org/wiki/Vancouver_Island">Vancouver Island</a> and <a href="http://en.wikipedia.org/wiki/Tsawwassen">Tsawwassen</a> (ignoring the time I was in BC with my family about 16 years ago, that is). I always just flew in and out of Victoria directly. The ferry is awesome and the view is incredible, navigating through all those little islands. Last time I rode the ferry I snapped this shot. It&#8217;s possibly the best picture I&#8217;ve taken on that trip.
I lived in <a href="http://en.wikipedia.org/wiki/Victoria%2C_British_Columbia">Victoria</a> for over a year before I ever rode the <a href="http://www.bcferries.com/">ferry</a> between <a href="http://en.wikipedia.org/wiki/Vancouver_Island">Vancouver Island</a> and <a href="http://en.wikipedia.org/wiki/Tsawwassen">Tsawwassen</a> (ignoring the time I was in BC with my family about 16 years ago, that is). I always just flew in and out of Victoria directly. The ferry is awesome and the view is incredible, navigating through all those little islands. Last time I rode the ferry I snapped this shot. It's possibly the best picture I've taken on that trip.
<a href="http://sami.samhuri.net/files/original.jpg" class="photo"><img src="http://sami.samhuri.net/files/small.jpg" title="Sunset" alt="Sunset" /></a>

View file

@ -5,6 +5,6 @@ Author: sjs
Tags: ruby, dtrace, sun
----
Suddenly I feel the urge to try out Solaris for i386 again. Last time I gave it a shot was when it was first released, and all I ever got out of the CD was a white screen. It&#8217;s been 2-3 years since then and it should be well-tested. I&#8217;ll try to install it into a VM first using the <span class="caps">ISO</span> and potentially save myself a CD. (I don&#8217;t even think I have blank CDs lying around anymore, only DVDs.)
Suddenly I feel the urge to try out Solaris for i386 again. Last time I gave it a shot was when it was first released, and all I ever got out of the CD was a white screen. It's been 2-3 years since then and it should be well-tested. I'll try to install it into a VM first using the ISO and potentially save myself a CD. (I don't even think I have blank CDs lying around anymore, only DVDs.)
<a href="http://joyeur.com/2007/05/07/dtrace-for-ruby-is-available">The culprit.</a>

View file

@ -0,0 +1,18 @@
Title: I Can't Wait to See What Trey Parker & Matt Stone Do With This
Date: May 9, 2007
Timestamp: 1178746440
Author: sjs
Tags: crazy
----
I'd just like to say, <a href="http://news.com.com/8301-10784_3-9717828-7.html">bwa ha ha ha!</a>
Summary: Paris Hilton drove with a suspended license and is facing 45 days in jail. Now she's reaching out to lord knows who on her MySpace page to petition The Governator to pardon her. I might cry if I weren't pissing myself laughing.
Paris Hilton is out of her mind, living in some fantasy world separate from Earth. Pathetic doesn't begin to describe this plea for help from her own stupidity. She knowingly and willingly disobeyed the law, got busted, and then proceeded to claim that:
> *"She provides hope for young people all over the U.S. __and the world__. She provides beauty and excitement to (most of) our __otherwise mundane__ lives."*
I take this as a learning experience. For example, I learned that the US is no longer part of the world.
Flat out crazy, insane, not of sound mind. She is not any sort of hope, inspiration or role model for anyone.

View file

@ -5,11 +5,11 @@ Author: sjs
Tags: ruby, extensions
----
I wanted a method analogous to Prototype&#8217;s <a href="http://prototypejs.org/api/enumerable/pluck">pluck</a> and <a href="http://prototypejs.org/api/enumerable/invoke">invoke</a> in Rails for building lists for <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#M000510">options_for_select</a>. Yes, I know about <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#M000511">options_from_collection_for_select</a>.
I wanted a method analogous to Prototype's <a href="http://prototypejs.org/api/enumerable/pluck">pluck</a> and <a href="http://prototypejs.org/api/enumerable/invoke">invoke</a> in Rails for building lists for <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#M000510">options_for_select</a>. Yes, I know about <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#M000511">options_from_collection_for_select</a>.
I wanted something more general that I can use anywhere &#8211; not just in Rails &#8211; so I wrote one. In a second I&#8217;ll introduce <code>Enumerable#pluck</code>, but first we need some other methods to help implement it nicely.
I wanted something more general that I can use anywhere - not just in Rails - so I wrote one. In a second I'll introduce <code>Enumerable#pluck</code>, but first we need some other methods to help implement it nicely.
First you need <a href="http://pragdave.pragprog.com/pragdave/2005/11/symbolto_proc.html"><code>Symbol#to_proc</code></a>, which shouldn&#8217;t need an introduction. If you&#8217;re using Rails you have this already.
First you need <a href="http://pragdave.pragprog.com/pragdave/2005/11/symbolto_proc.html"><code>Symbol#to_proc</code></a>, which shouldn't need an introduction. If you're using Rails you have this already.
<div class="typocode"><div class="codetitle">Symbol#to_proc</div><pre><code class="typocode_ruby "><span class="keyword">class </span><span class="class">Symbol</span>
<span class="comment"># Turns a symbol into a proc.</span>
@ -43,7 +43,7 @@ Next we define <code>String#to_proc</code>, which is nearly identical to the <a
<span class="keyword">end</span>
</code></pre></div>
Finally there&#8217;s <code>Enumerable#to_proc</code> which returns a proc that passes its parameter through each of its members and collects their results. It&#8217;s easier to explain by example.
Finally there's <code>Enumerable#to_proc</code> which returns a proc that passes its parameter through each of its members and collects their results. It's easier to explain by example.
<div class="typocode"><div class="codetitle">Enumerable#to_proc</div><pre><code class="typocode_ruby "><span class="keyword">module </span><span class="module">Enumerable</span>
<span class="comment"># Effectively treats itself as a list of transformations, and returns a proc</span>
@ -64,7 +64,7 @@ Finally there&#8217;s <code>Enumerable#to_proc</code> which returns a proc that
<span class="keyword">end</span>
<span class="keyword">end</span></code></pre></div>
Here&#8217;s the cool part, <code>Enumerable#pluck</code> for Ruby in all its glory.
Here's the cool part, <code>Enumerable#pluck</code> for Ruby in all its glory.
<div class="typocode"><div class="codetitle">Enumerable#pluck</div><pre><code class="typocode_ruby "><span class="keyword">module </span><span class="module">Enumerable</span>
<span class="comment"># Use this to pluck values from objects, especially useful for ActiveRecord models.</span>
@ -120,6 +120,6 @@ I wrote another version without using the various <code>#to_proc</code> methods
<span class="keyword">end</span>
<span class="keyword">end</span></code></pre></div>
It&#8217;s just icing on the cake considering Ruby&#8217;s convenient block syntax, but there it is. Do with it what you will. You can change or extend any of these to support drilling down into hashes quite easily too.
It's just icing on the cake considering Ruby's convenient block syntax, but there it is. Do with it what you will. You can change or extend any of these to support drilling down into hashes quite easily too.
*<strong>Update #1:</strong> Fixed a potential performance issue in <code>Enumerable#to_proc</code> by saving the results of <code>to_proc</code> in <tt>@procs</tt>.*

View file

@ -5,13 +5,13 @@ Author: sjs
Tags: rails
----
Here&#8217;s an easy way to solve a problem that may have nagged you as it did me. Simply using <code>foo.inspect</code> to dump out some object to the browser dumps one long string which is barely useful except for short strings and the like. The ideal output is already available using the <a href="http://www.ruby-doc.org/stdlib/libdoc/prettyprint/rdoc/index.html"><code>PrettyPrint</code></a> module so we just need to use it.
Here's an easy way to solve a problem that may have nagged you as it did me. Simply using <code>foo.inspect</code> to dump out some object to the browser dumps one long string which is barely useful except for short strings and the like. The ideal output is already available using the <a href="http://www.ruby-doc.org/stdlib/libdoc/prettyprint/rdoc/index.html"><code>PrettyPrint</code></a> module so we just need to use it.
Unfortunately typing <tt><pre><%= PP.pp(@something, '') %></pre></tt> to quickly debug some possibly large object (or collection) can get old fast so we need a shortcut.
Taking the definition of <a href="http://extensions.rubyforge.org/rdoc/classes/Object.html#M000020"><code>Object#pp_s</code></a> from the <a href="http://extensions.rubyforge.org/rdoc/">extensions project</a> it&#8217;s trivial to create a helper method to just dump out an object in a reasonable manner.
Taking the definition of <a href="http://extensions.rubyforge.org/rdoc/classes/Object.html#M000020"><code>Object#pp_s</code></a> from the <a href="http://extensions.rubyforge.org/rdoc/">extensions project</a> it's trivial to create a helper method to just dump out an object in a reasonable manner.
<div class="typocode"><div class="codetitle">/app/helpers/application_helper.rb</div><pre><code class="typocode_ruby "><span class="keyword">def </span><span class="method">dump</span><span class="punct">(</span><span class="ident">thing</span><span class="punct">)</span>

View file

@ -10,8 +10,8 @@ Tags: cheat, vim, emacs, textmate
Luckily no one in the real world cares if you cheat. Most of life is open-book, but for the times when you just need to find something quick the answer, of course, is to [cheat](http://cheat.errtheblog.com/) profusely.
I&#8217;ve only checked out a few of the cheat sheets but they are of high quality and their wiki-like nature means if they suck and you have time you can help out. I was very pleased to find that there are a number of zsh cheats already.
I've only checked out a few of the cheat sheets but they are of high quality and their wiki-like nature means if they suck and you have time you can help out. I was very pleased to find that there are a number of zsh cheats already.
They certainly know the way to my heart! Ruby, Rails, TextMate*, vim*, zsh, screen. That&#8217;ll do snake. That&#8217;ll do.
They certainly know the way to my heart! Ruby, Rails, TextMate*, vim*, zsh, screen. That'll do snake. That'll do.
*\* There are cheats for emacs, jEdit, and [e](http://www.e-texteditor.com/) too if TextMate and/or vim don&#8217;t tickle your fancy.*
*\* There are cheats for emacs, jEdit, and [e](http://www.e-texteditor.com/) too if TextMate and/or vim don't tickle your fancy.*

View file

@ -11,4 +11,4 @@ Love it or hate it - even though it's not even out yet - the iPhone has spawned
[A comment on slashdot](http://apple.slashdot.org/comments.pl?sid=235163&cid=19174829):
> &#8220;I&#8217;m waiting for the iPhone-shuffle, no display, just a button to call a random person on your contacts list.&#8221;
> "I'm waiting for the iPhone-shuffle, no display, just a button to call a random person on your contacts list."

View file

@ -9,10 +9,10 @@ Tags: rails, inspirado
He recently mentioned <a href="http://spyderous.livejournal.com/88463.html">an idea</a> to foster participation in Gentoo (or any other project) by aggregating personal project plans for people to browse. I thought it sounded cool so I started coding and came up with what I call <a href="http://http://rubyforge.org/projects/inspirado/">inspirado</a>.
It&#8217;s fairly basic so far but it&#8217;s only a week old. It is RESTful and you can get <span class="caps">XML</span> for most pages by appending .xml to the <span class="caps">URL</span> (or by using curl and setting the <span class="caps">HTTP</span> Accept header). Eventually Atom and/or <span class="caps">RSS</span> should be available as well.
It's fairly basic so far but it's only a week old. It is RESTful and you can get XML for most pages by appending .xml to the URL (or by using curl and setting the HTTP Accept header). Eventually Atom and/or RSS should be available as well.
Note that everything you see there is purely for testing purposes and any changes you make are most likely going to be blown away.
There are several features on my <span class="caps">TODO</span> list but I&#8217;d love to hear about any you might have. Write to sami.samhuri@gmail.com if you have suggestions or anything else to say.
There are several features on my TODO list but I'd love to hear about any you might have. Write to sami.samhuri@gmail.com if you have suggestions or anything else to say.
(Inspirado is, of course, a Rails app.)

View file

@ -0,0 +1,8 @@
Title: Finnish court rules CSS ineffective at protecting DVDs
Date: May 26, 2007
Timestamp: 1180175040
Author: sjs
Tags: drm
----
It's nice to see people making sane calls on issues like this. <a href="http://arstechnica.com/index.ars">Ars</a> has a nice <a href="http://arstechnica.com/news.ars/post/20070525-finland-court-breaking-ineffective-copy-protection-is-permissible.html">summary</a> and there's also a <a href="http://www.turre.com/blog/?p=102">press release</a>.

View file

@ -0,0 +1,8 @@
Title: 301 moved permanently
Date: June 8, 2007
Timestamp: 1181350800
Author: sjs
Tags: life
----
Last weekend I moved out of the apartment I lived in for the last 3 1/2 years. Moving was a cinch thanks to a friend's garage, conveniently placed smack between my old place and the new one. Google maps tells me that I moved just under 3.4 km, which is 2.1 mi for the metric impaired, so it wasn't much of a move at all! My roommate and I live in the basement of a house split into 3 apartments. Our upstairs neighbours are friendly and seem pretty cool, except one lady upstairs seems a bit strange. It's a great place though and in the winter the wood stove fireplace is going to be awesome.

View file

@ -0,0 +1,35 @@
Title: so long typo (and thanks for all the timeouts)
Date: June 8, 2007
Timestamp: 1181350860
Author: sjs
Tags: mephisto, typo
----
Well for just over a year Typo ran the show. I thought I had worked out most of the kinks with Typo and Dreamhost but the latest problem I ran into was pretty major. I couldn't post new articles. If the stars aligned perfectly and I sacrificed baby animals and virgins, every now and then I could get it to work. Ok, all I really had to do was refresh several dozen times, waiting 1 minute for it to timeout every time, but it sucked nonetheless.
Recently I had looked at converting Typo to Mephisto and it seemed pretty painless. I installed Mephisto and followed whatever instructions I found via Google and it all just worked, with one caveat. The Typo converter for Mephisto only supports Typo's schema version 56, while my Typo schema was at version 61. Rather than migrate backwards I brought Mephisto's Typo converter up to date instead. If you're interested, <a href="http://sami.samhuri.net/files/mephisto_converters-typo-schema_version_61.patch">download the patch</a>. The patch is relative to vendor/plugins, so patch accordingly.
After running that code snippet to fix my tags, I decided to completely ditch categories in favour of tags. I tagged each new Mephisto article with a tag for each Typo category it had previously belonged to. I fired up <code>RAILS_ENV=production script/console</code> and typed something similar to the following:
<table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt>7<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">require <span class="s"><span class="dl">'</span><span class="k">converters/base</span><span class="dl">'</span></span><tt>
</tt>require <span class="s"><span class="dl">'</span><span class="k">converters/typo</span><span class="dl">'</span></span><tt>
</tt>articles = <span class="co">Typo</span>::<span class="co">Article</span>.find(<span class="sy">:all</span>).map {|a| [a, <span class="co">Article</span>.find_by_permalink(a.permalink)] }<tt>
</tt>articles.each <span class="r">do</span> |ta, ma|<tt>
</tt> <span class="r">next</span> <span class="r">if</span> ma.nil?<tt>
</tt> ma.tags &lt;&lt; <span class="co">Tag</span>.find_or_create(ta.categories.map(&amp;<span class="sy">:name</span>))<tt>
</tt><span class="r">end</span></pre></td>
</tr></table>
When I say something similar I mean exactly that. I just typed that from memory so it may not work, or even be syntactically correct. If any permalinks changed then you'll have to manually add new tags corresponding to old Typo categories. The only case where this bit me was when I had edited the title of an article, in which case the new Mephisto permalink matched the new title while the Typo permalink matched the initial title, whatever it was.
I really dig Mephisto so far. It's snappier than Typo and the admin interface is slick. I followed the herd and went with the scribbish theme. Perhaps I'll get around to customizing it sometime, but who knows maybe I'll like a white background for a change.

View file

@ -0,0 +1,96 @@
Title: More Scheming with Haskell
Date: June 14, 2007
Timestamp: 1181783340
Author: sjs
Tags: coding, haskell, scheme
----
It's been a little while since I wrote about Haskell and the <a href="http://sami.samhuri.net/2007/5/3/a-scheme-parser-in-haskell-part-1">Scheme interpreter</a> I've been using to learn and play with both Haskell and Scheme. I finished the tutorial and got myself a working Scheme interpreter and indeed it has been fun to use it for trying out little things now and then. (Normally I would use Emacs or Dr. Scheme for that sort of thing.) There certainly are <a href="http://www.lshift.net/blog/2007/06/11/folds-and-continuation-passing-style">interesting things</a> to try floating around da intranet. And also things to read and learn from, such as <a href="http://cubiclemuses.com/cm/blog/tags/Misp">misp</a> (via <a href="http://moonbase.rydia.net/mental/blog/programming/misp-is-a-lisp">Moonbase</a>).
*I'm going to describe two new features of my Scheme in this post. The second one is more interesting and was more fun to implement (cond).*
### Pasing Scheme integers ###
Last time I left off at parsing <a href="http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_sec_6.3.5">R5RS compliant numbers</a>, which is exercise 3.3.4 if you're following along the tutorial. Only integers in binary, octal, decimal, and hexadecimal are parsed right now. The syntaxes for those are <code>#b101010</code>, <code>#o52</code>, <code>42</code> (or <code>#d42</code>), and <code>#x2a</code>, respectively. To parse these we use the <code>readOct</code>, <code>readDec</code>, <code>readHex</code>, and <code>readInt</code> functions provided by the Numeric module, and import them thusly:
import Numeric (readOct, readDec, readHex, readInt)
In order to parse binary digits we need to write a few short functions to help us out. For some reason I couldn't find <code>binDigit</code>, <code>isBinDigit</code> and <code>readBin</code> in their respective modules but luckily they're trivial to implement. The first two are self-explanatory, as is the third if you look at the <a href="http://www.cse.ogi.edu/~diatchki/MonadTransformers/pfe.cgi?Numeric">implementation</a> of its relatives for larger bases. In a nutshell <code>readBin</code> says to: "read an integer in base 2, validating digits with <code>isBinDigit</code>."
<pre><code>-- parse a binary digit, analagous to decDigit, octDigit, hexDigit
binDigit :: Parser Char
binDigit = oneOf "01"
-- analogous to isDigit, isOctdigit, isHexDigit
isBinDigit :: Char - Bool
isBinDigit c = (c == '0' || c == '1')
-- analogous to readDec, readOct, readHex
readBin :: (Integral a) = ReadS a
readBin = readInt 2 isBinDigit digitToInt</code></pre>
The next step is to augment <code>parseNumber</code> so that it can handle R5RS numbers in addition to regular decimal numbers. To refresh, the tutorial's <code>parseNumber</code> function looks like this:
parseNumber :: Parser LispVal
parseNumber = liftM (Number . read) $ many1 digit
Three more lines in this function will give us a decent starting point:
parseNumber = do char '#'
base <- oneOf "bdox"
parseDigits base
Translation: First look for an R5RS style base, and if found call <code>parseDigits</code> with the given base to do the dirty work. If that fails then fall back to parsing a boring old string of decimal digits.
That brings us to actually parsing the numbers. <code>parseDigits</code> is simple, but there might be a more Haskell-y way of doing this.
<pre><code>-- Parse a string of digits in the given base.
parseDigits :: Char - Parser LispVal
parseDigits base = many1 d >>= return
where d = case base of
'b' -> binDigit
'd' -> digit
'o' -> octDigit
'x' -> hexDigit
</code></pre>
The trickiest part of all this was figuring out how to use the various <code>readFoo</code> functions properly. They return a list of pairs so <code>head</code> grabs the first pair and <code>fst</code> grabs the first element of the pair. Once I had that straight it was smooth sailing. Having done this, parsing R5RS characters (#\a, #\Z, #\?, ...) is a breeze so I won't bore you with that.
### The cond function ###
It still takes me some time to knit together meaningful Haskell statements. Tonight I spent said time cobbling together an implementation of <a href="http://schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-7.html#%_sec_4.1.5">cond</a> as a new special form. Have a look at the code. The explanation follows.
<table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">eval env (List (Atom "cond" : List (Atom "else" : exprs) : [])) =<tt>
</tt> liftM last $ mapM (eval env) exprs<tt>
</tt>eval env (List (Atom "cond" : List (pred : conseq) : rest)) = <tt>
</tt> do result &lt;- eval env $ pred<tt>
</tt> case result of<tt>
</tt> Bool False -&gt; case rest of<tt>
</tt> [] -&gt; return $ List []<tt>
</tt> _ -&gt; eval env $ List (Atom "cond" : rest)<tt>
</tt> _ -&gt; liftM last $ mapM (eval env) conseq</pre></td>
</tr></table>
* __Lines 1-2:__ Handle <code>else</code> clauses by evaluating the given expression(s), returning the last result. It must come first or it's overlapped by the next pattern.
* __Line 3:__ Evaluate a <code>cond</code> by splitting the first condition into <strong>predicate</strong> and <strong>consequence</strong>, tuck the remaining conditions into <code>rest</code> for later.
* __Line 4:__ Evaluate <code>pred</code>
* __Line 5:__ and if the result is:
* __Line 6:__ <code>#f</code> then look at the rest of the conditions.
* __Line 7:__ If there are no more conditions return the empty list.
* __Line 8:__ Otherwise call ourselves recursively with the remaining conditions.
* __Line 9:__ Anything other than <code>#f</code> is considered true and causes <code>conseq</code> to be evaluated and returned. Like <code>else</code>, <code>conseq</code> can be a sequence of expressions.
So far my Scheme weighs in at 621 lines, 200 more than the tutorial's final code listing. Hopefully I'll keep adding things on my TODO list and it will grow a little bit more. Now that I have <code>cond</code> it will be more fun to expand my stdlib.scm as well.

View file

@ -5,10 +5,9 @@ Author: sjs
Tags: bdd, rails, test/spec
----
<p>This last week Ive been getting to know <a href="http://web.archive.org/web/20080820115400/http://chneukirchen.org/blog/archive/2007/01/announcing-test-spec-0-3-a-bdd-interface-for-test-unit.html">test/spec</a> via <a href="http://web.archive.org/web/20080820115400/http://errtheblog.com/">errs</a> <a href="http://web.archive.org/web/20080820115400/http://require.errtheblog.com/plugins/wiki/TestSpecRails">test/spec on rails</a> plugin. I have to say that I really dig this method of testing my code and I look forward to trying out some actual <a href="http://web.archive.org/web/20080820115400/http://behaviour-driven.org/"><span class="caps">BDD</span></a> in the future.</p>
This last week I've been getting to know <a href="http://chneukirchen.org/blog/archive/2007/01/announcing-test-spec-0-3-a-bdd-interface-for-test-unit.html">test/spec</a> via <a href="http://errtheblog.com/">err's</a> <a href="http://require.errtheblog.com/plugins/wiki/TestSpecRails">test/spec on rails</a> plugin. I have to say that I really dig this method of testing my code and I look forward to trying out some actual <a href="http://behaviour-driven.org/">BDD</a> in the future.
<p>I did hit a little snag with functional testing though. The method of declaring which controller to use takes the form:</p>
I did hit a little snag with functional testing though. The method of declaring which controller to use takes the form:
<table class="CodeRay"><tr>
@ -18,7 +17,7 @@ Tags: bdd, rails, test/spec
</tr></table>
<p>and can be placed in the <code>setup</code> method, like so:</p>
and can be placed in the <code>setup</code> method, like so:
<table class="CodeRay"><tr>
@ -56,7 +55,7 @@ Tags: bdd, rails, test/spec
</tr></table>
<p>This is great and the test will work. But lets say that I have another controller that guests can access:</p>
This is great and the test will work. But let's say that I have another controller that guests can access:
<table class="CodeRay"><tr>
@ -90,10 +89,8 @@ Tags: bdd, rails, test/spec
</tr></table>
<p>This test will pass on its own as well, which is what really tripped me up. When I ran my tests individually as I wrote them, they passed. When I ran <code>rake test:functionals</code> this morning and saw over a dozen failures and errors I was pretty alarmed. Then I looked at the errors and was thoroughly confused. Of course the action <strong>fooriffic</strong> cant be found in <strong>SessionsController</strong>, it lives in <strong>FooController</strong> and thats the controller I said to use! What gives?!</p>
This test will pass on its own as well, which is what really tripped me up. When I ran my tests individually as I wrote them, they passed. When I ran <code>rake test:functionals</code> this morning and saw over a dozen failures and errors I was pretty alarmed. Then I looked at the errors and was thoroughly confused. Of course the action <strong>fooriffic</strong> can't be found in <strong>SessionsController</strong>, it lives in <strong>FooController</strong> and that's the controller I said to use! What gives?!
The problem is that test/spec only creates one context with a specific name, and re-uses that context on subsequent tests using the same context name. The various <code>setup</code> methods are all added to a list and each one is executed, not just the one in the same <code>context</code> block as the specs. I can see how that's useful, but for me right now it's just a hinderance as I'd have to uniquely name each context. "Another guest" just looks strange in a file by itself, and I want my tests to work with my brain not against it.
<p>The problem is that test/spec only creates one context with a specific name, and re-uses that context on subsequent tests using the same context name. The various <code>setup</code> methods are all added to a list and each one is executed, not just the one in the same <code>context</code> block as the specs. I can see how thats useful, but for me right now its just a hinderance as Id have to uniquely name each context. “Another guest” just looks strange in a file by itself, and I want my tests to work with my brain not against it.</p>
<p>My solution was to just create a new context each time and re-use nothing. Only 2 lines in test/spec need to be changed to achieve this, but Im not sure if what Im doing is a bad idea. My tests pass and right now thats basically all I care about though.</p>
My solution was to just create a new context each time and re-use nothing. Only 2 lines in test/spec need to be changed to achieve this, but I'm not sure if what I'm doing is a bad idea. My tests pass and right now that's basically all I care about though.

View file

@ -0,0 +1,23 @@
Title: Begging the question
Date: June 15, 2007
Timestamp: 1181933340
Author: sjs
Tags: english, life, pedantry
----
I'm currently reading <a href="http://mitpress.mit.edu/sicp/full-text/book/book.html">SICP</a> since it's highly recommended by many people, available for free, and interesting. The fact that I have a little <a href="http://sami.samhuri.net/2007/6/14/more-scheming-with-haskell">Scheme interpreter</a> to play with makes it much more fun since I can add missing functionality to it as I progress through the book, thereby learning more Haskell in the process. Yay!
Anyway I was very pleased to see the only correct usage of the phrase "begs the question" I have seen in a while. It's a pet peeve of mine, but I have submitted myself to the fact that the phrase is so oft used to mean "begs for the following question to be asked..." that it may as well be re-defined. In its correct usage the sentence seems to hang there if you try to apply the commonly mistaken meaning to it. That's all very hazy so here's the usage in SICP (emphasis my own):
<blockquote> As a case in point, consider the problem of computing square roots. We can define the square-root function as <img src="http://sami.samhuri.net/files/ch1-Z-G-4.gif" alt="">
This describes a perfectly legitimate mathematical function. We could use it to recognize whether one number is the square root of another, or to derive facts about square roots in general. On the other hand, the definition does not describe a procedure. Indeed, it tells us almost nothing about how to actually find the square root of a given number. It will not help matters to rephrase this definition in pseudo-Lisp:
<pre><code>(define (sqrt x)
(the y (and (= y 0)
(= (square y) x))))</code></pre>
<strong>This only begs the question.</strong>
</blockquote>
Begging the question is to assume what one is trying to prove (or here, define) and use that as the basis for a conclusion. Read the <a href="http://en.wikipedia.org/wiki/Begging_the_question">Wikipedia article</a> for a better definition and some nice examples.

View file

@ -0,0 +1,26 @@
Title: Back on Gentoo, trying new things
Date: June 18, 2007
Timestamp: 1182215100
Author: sjs
Tags: emacs, gentoo, linux, vim
----
I started using my Gentoo box for development again and there are a few things about Linux I didn't realize I had been missing.
### Shell completion is awesome out of the box ###
zsh has an impressive completion system but I just don't feel the urge to ever customize it extensively. I just use the basic completion stuff on OS X because it's easy. On Gentoo I have rake tasks and all sorts of other crap completed for me by including a few lines in my .zshrc (iirc a script does this automatically anyway). Generally Linux distros try to knit everything together nicely so you never even think about things like whether or not a package will have readline support, and default configs will be tweaked and enhanced beyond the official zsh package.
### Linux is stable. Really stable. ###
While people bash Microsoft daily for tying the GUI layer to the kernel, Apple seems to get away with it scot-free. I don't know if it's caused by my external display hooked up to the dock, or the Prolific Firewire chip in my external disk enclosure but something causes the mysterious "music plays till the end of the song, mouse can be moved, but nothing works" bug now and then and all I can do is a hard reset.
On Linux I currently use Fluxbox so everything is rock solid and fast (except Firefox! ;-), but in the extremely rare event that shit does hit the fan usually only a single app will crash, though sometimes X (and hence many others) go with it. A <code>sudo /etc/init.d/gdm restart</code> fixes that. The only times I've had to hard reset Linux was because of a random bug (strangely similar to my MacBook bug) with Nvidia's driver with dual head setups. All this is pretty moot since Linux is generally just stable.
Those are 2 relatively small things but the added comfort they provide is very nice.
In the spirit of switching things up I'm going to forgo my usual routine of using gvim on Linux and try out emacs. I've been frustrated with vim's lack of a decent file browser and I've never much liked the tree plugin. Vim is a fantastic editor when it comes to navigating, slicing, and dicing text. After that it sort of falls flat though. After getting hooked on TextMate I have come to love integration with all sorts of external apps such as Subversion, rake, and the shell because it makes my work easier. Emacs seems to embrace that sort of philosophy and I'm more impressed with the efforts to integrate Rails development into Emacs than vim. I'm typing this post using the Textile mode for Emacs and the markup is rendered giving me a live preview of my post. It's not WYSIWYG like Typo's preview but it's still pretty damn cool. I think can get used to emacs.
I'm just waiting for a bunch of crap to compile because I use Gentoo and soon I'll have a Gtk-enabled Emacs to work in. If I can paste to and from Firefox then I'll be happy. I'll have to open this in vim or gedit to paste it into Firefox, funny!
I'm also going to try replacing a couple of desktop apps with web alternatives. I'm starting with 2 no-brainers: mail and feeds with Gmail and Google Reader. I never got into the Gmail craze and never really even used Gmail very much. After looking at the shortcuts I think I can get used to it. Seeing j/k for up/down is always nice. Thunderbird is ok but there isn't a mail client on Linux that I really like, except mutt. That played a part in my Gmail choice. I hadn't used G-Reader before either and it seems alright, but it'll be hard to beat NetNewsWire.

View file

@ -0,0 +1,19 @@
Title: Reinventing the wheel
Date: June 20, 2007
Timestamp: 1182356820
Author: sjs
Tags: emacs, snippets
----
Emacs is very impressive. I only felt lost and unproductive for minutes and now it seems natural to use and get around in. I've got <a href="2007.06.14-more-scheming-with-haskell.html">ElSchemo</a> set as the default scheme, and running inferior processes interactively is an absolute dream. My scheme doesn't have readline support (which bothers me to the point where I've thought about adding it just so I can use the thing) but when running it under Emacs there's absoutely no need for anything like that since I have the power of my editor when interacting with any program.
There has been a considerable amount of work done to aide in Rails development which makes Emacs especially comfortable for me. I now know why people have Emacs windows maximized on their screens. Because of its age Emacs is a handy window manager that basically eliminates the need for anything like <a href="http://en.wikipedia.org/wiki/GNU_Screen">GNU screen</a> or a window manager such as <a href="http://www.nongnu.org/ratpoison/">Rat poison</a> (which is great if you like screen), just maximize that Emacs "frame" or open one for each display and get to it. If you need a shell you just split the window and run your shell, when you're done you can easily switch back to your editing and your shell will wait in the background until you need it again. With rails-mode on I can run script/console (or switch back to it) with <code>C-c C-c s c</code>. My zsh alias for script/console is <code>sc</code> and I have other similarly succint ones for other stuff, so I took right to the shortcuts for all the handy things that I no longer have to switch applications to do:
* <code>C-c C-c .</code> Run the tests for this file. If I'm in a unit test it runs it, if I'm in the model it runs the corresponding unit tests.
* <code>C-c C-c w s</code> Run the web server (script/server).
* <code>C-c C-c t</code> Run tests. The last value entered is the default choice, and the options are analogous to the rake test:* tasks.
* and so on...
The Rails integration is simply stunning and I could go on all day about the mature indentation support, the Speedbar and what not, but I won't. I'm fairly sure that Emacs has taken the place of TextMate as my weapon of choice now, on all platforms. And after only 2 days!
Anyway, the point of all this was to mention the one thing that's missing: support for <a href="2006.02.22-intelligent-migration-snippets-0.1-for-textmate.html">intelligent snippets</a> which insert text at more than one point in the document (well, they appear to do so). I don't have any E-Lisp-fu to break out and solve the deficiency but if it ever bugs me enough I might try implementing it for Emacs one day. If they were useful to me outside of writing migrations I might have more incentive to do so, but I guess they aren't useful in normal editing situations (maybe I just haven't recognised the need).

View file

@ -0,0 +1,34 @@
Title: Embrace the database
Date: June 22, 2007
Timestamp: 1182507240
Author: sjs
Tags: activerecord, rails, ruby
----
If you drink the Rails koolaid you may have read the notorious <a href="http://www.loudthinking.com/arc/2005_09.html">single layer of cleverness</a> post by <a href="http://www.loudthinking.com/">DHH</a>. <em>[5th post on the archive page]</em> In a nutshell he states that it's better to have a single point of cleverness when it comes to business logic. The reasons for this include staying agile, staying in Ruby all the time, and being able to switch the back-end DB at any time. Put the logic in ActiveRecord and use the DB as a dumb data store, that is the Rails way. It's simple. It works. You don't need to be a DBA to be a Rails developer.
<a href="http://www.stephenbartholomew.co.uk/">Stephen</a> created a Rails plugin called <a href="http://www.stephenbartholomew.co.uk/2007/6/22/dependent-raise">dependent-raise</a> which imitates a foreign key constraint inside of Rails. I want to try this out because I believe that data integrity is fairly important, but it's really starting to make me think about this single point of cleverness idea.
Are we not reinventing the wheel by employing methods such as this in our code? Capable DBs already do this sort of thing for us. I don't necessarily think it's bad to implement this sort of thing, but I think it's a symptom of NIH syndrome. Instead of reinventing this kind of thing why don't we embrace the DB as a semi-intelligent data store? The work has been done all we have to do is exploit it via Rails.
There are a few reasons that the Rails folks choose not to do so but perhaps some of them could be worked around. Adapting your solution as you progress and realise that things aren't exactly as you thought they were... I believe the word for that sort of thing is agility.
### Database agnosticism ###
From SQLite to Oracle, just configure the connection, migrate, and run your app on any database. One of the biggest Rails myths that is backed by the Rails team themselves. It takes a fair amount of work to ensure that any significant app is fully agnostic. Sure you can develop on SQLite and deploy on MySQL without much trouble but there are significant diffirences between RDBMSs that will manifest themselves if you create an app that's more than a toy. Oh, you used finder_sql? Sorry but chances are your app is no longer DB agnostic. FAIL.
**Solution:** Drop the lie. Tell people the truth. Theoretically, theory and practice are the same; in practice they are not. Be honest that it's *possible* to be DB-agnostic but can be a challenge. Under no circumstances should we shun something useful in the name of claiming to be DB-agnostic.
### Staying agile ###
If we start making use of FK constraints then we'll have to make changes to both our DB and our code. This makes change more time-consuming and error-prone which means change is less likely to happen. This goes against the grain of an agile methodology. Or does it?
**Solution:** Rails should use the features of the DB to keep data intact and fall back on an AR-only solution only if the DB doesn't support the operation. There doesn't need to be any duplication in logic rules either. If Rails could recognise a FK constraint that cascades on delete it could set up the `has_many :foos, :dependent => :destroy` relation for us. In fact I only see our code becoming DRYer (maybe even too DRY[1]).
### Staying in Ruby ###
Using the DB from within Ruby is a solved problem. I don't see why this couldn't be extended to handle more of the DB as well. Use Ruby, but use it intelligently by embracing outside tools to get the job done.
Many relationships could be derived from constraints as people have pointed out before. There are benefits to using the features of a decent RDBMS, and in some cases I think that we might be losing by not making use of them. I am not saying we should move everything to the DB, I am saying that we should exploit the implemented and debugged capabilities of our RDBMSs the best we can while practicing the agile methods we know and love, all from within Ruby.
[1] I make liberal use of <a href="http://agilewebdevelopment.com/plugins/annotate_models">annotate_models</a> as it is.

View file

@ -1,20 +1,17 @@
Title: Emacs for TextMate junkies
Date: June 22, 2007
Date: June 23, 2007
Timestamp: 1182565020
Author: sjs
Tags: emacs, textmate
----
<p><em>Update #1: What I first posted will take out your &lt; key by mistake (its available via <code>C-q &lt;</code>), it has since been revised to Do The Right Thing.</em></p>
*Update #1: What I first posted will take out your < key by mistake (it's available via `C-q <`), it has since been revised to Do The Right Thing.*
*Update #2: Thanks to an anonymouse[sic] commenter this code is a little cleaner.*
<p><em>Update #2: Thanks to an anonymouse[sic] commenter this code is a little cleaner.</em></p>
*Update #3: I should read the Emacs manual sometime, especially since I have it in dead-tree form. Check out <a href="http://www.gnu.org/software/emacs/manual/html_node/autotype/Inserting-Pairs.html">skeleton pairs</a> in the Emacs manual.*
<p><em>Update #3: I should read the Emacs manual sometime, especially since I have it in dead-tree form. Check out <a href="http://web.archive.org/web/20070626150908/http://www.gnu.org/software/emacs/manual/html_node/autotype/Inserting-Pairs.html">skeleton pairs</a> in the Emacs manual.</em></p>
<p>Despite my current infatuation with Emacs there are many reasons I started using TextMate, especially little time-savers that are very addictive. Ill talk about one of those features tonight. When you have text selected in TextMate and you hit say the <code>'</code> (single quote) then TextMate will surround the selected text with single quotes. The same goes for double quotes, parentheses, brackets, and braces. This little trick is one of my favourites so I had to come up with something similar in Emacs. It was easy since a <a href="http://web.archive.org/web/20070626150908/http://osdir.com/ml/emacs.nxml.general/2005-08/msg00002.html">mailing list post</a> has a solution for surrounding the current region with tags, which served as a great starting point.</p>
Despite my current infatuation with Emacs there are many reasons I started using TextMate, especially little time-savers that are very addictive. I'll talk about one of those features tonight. When you have text selected in TextMate and you hit say the <code>'</code> (single quote) then TextMate will surround the selected text with single quotes. The same goes for double quotes, parentheses, brackets, and braces. This little trick is one of my favourites so I had to come up with something similar in Emacs. It was easy since a <a href="http://osdir.com/ml/emacs.nxml.general/2005-08/msg00002.html">mailing list post</a> has a solution for surrounding the current region with tags, which served as a great starting point.
<table class="CodeRay"><tr>
@ -36,7 +33,7 @@ Tags: emacs, textmate
</tr></table>
<p>With a little modification I now have the following in my ~/.emacs file:</p>
With a little modification I now have the following in my ~/.emacs file:
<table class="CodeRay"><tr>
@ -138,7 +135,6 @@ Tags: emacs, textmate
</tr></table>
<p><a href="http://web.archive.org/web/20070626150908/http://sami.samhuri.net/assets/2007/6/23/wrap-region.el" alt="wrap-region.el">Download wrap-region.el</a></p>
<a href="/f/wrap-region.el" alt="wrap-region.el">Download wrap-region.el</a>
<p>That more or less sums up why I like Emacs so much. I wanted that functionality so I implemented it (barely! It was basically done for me), debugged it by immediately evaluating sexps and then trying it out, and then once it worked I reloaded my config and used the wanted feature. Thats just awesome, and shows one strength of open source.</p>
That more or less sums up why I like Emacs so much. I wanted that functionality so I implemented it (barely! It was basically done for me), debugged it by immediately evaluating sexps and then trying it out, and then once it worked I reloaded my config and used the wanted feature. That's just awesome, and shows one strength of open source.

View file

@ -5,10 +5,9 @@ Author: sjs
Tags: elschemo, haskell, scheme
----
<h3>Parsing floating point numbers</h3>
### Parsing floating point numbers ###
<p>The first task is extending the <code>LispVal</code> type to grok floats.</p>
The first task is extending the <code>LispVal</code> type to grok floats.
<table class="CodeRay"><tr>
@ -46,10 +45,9 @@ Tags: elschemo, haskell, scheme
</tr></table>
<p>The reason for using the new <code>LispNum</code> type and not just throwing a new <code>Float Float</code> constructor in there is so that functions can accept and operate on parameters of any supported numeric type. First the floating point numbers need to be parsed. For now I only parse floating point numbers in decimal because the effort to parse other bases is too great for the benefits gained (none, for me).</p>
The reason for using the new <code>LispNum</code> type and not just throwing a new <code>Float Float</code> constructor in there is so that functions can accept and operate on parameters of any supported numeric type. First the floating point numbers need to be parsed. For now I only parse floating point numbers in decimal because the effort to parse other bases is too great for the benefits gained (none, for me).
<p>ElSchemo now parses negative numbers so Ill start with 2 helper functions that are used when parsing both integers and floats:</p>
ElSchemo now parses negative numbers so I'll start with 2 helper functions that are used when parsing both integers and floats:
<table class="CodeRay"><tr>
@ -71,13 +69,11 @@ Tags: elschemo, haskell, scheme
</tr></table>
<p><code>parseSign</code> is straightforward as it follows the convention that a literal number is positive unless explicitly marked as negative with a leading minus sign. A leading plus sign is allowed but not required.</p>
<code>parseSign</code> is straightforward as it follows the convention that a literal number is positive unless explicitly marked as negative with a leading minus sign. A leading plus sign is allowed but not required.
<code>applySign</code> takes a sign character and a <code>LispNum</code> and negates it if necessary, returning a <code>LispNum</code>.
<p><code>applySign</code> takes a sign character and a <code>LispNum</code> and negates it if necessary, returning a <code>LispNum</code>.</p>
<p>Armed with these 2 functions we can now parse floating point numbers in decimal. Conforming to <span class="caps">R5RS</span> an optional <code>#d</code> prefix is allowed.</p>
Armed with these 2 functions we can now parse floating point numbers in decimal. Conforming to R5RS an optional <code>#d</code> prefix is allowed.
<table class="CodeRay"><tr>
@ -101,10 +97,9 @@ Tags: elschemo, haskell, scheme
</tr></table>
<p>The first 6 lines should be clear. Line 7 simply applies the parsed sign to the parsed number and returns it, delegating most of the work to <code>makeFloat</code>. <code>makeFloat</code> in turn delegates the work to the <code>readFloat</code> library function, extracts the result and constructs a <code>LispNum</code> for it.</p>
The first 6 lines should be clear. Line 7 simply applies the parsed sign to the parsed number and returns it, delegating most of the work to <code>makeFloat</code>. <code>makeFloat</code> in turn delegates the work to the <code>readFloat</code> library function, extracts the result and constructs a <code>LispNum</code> for it.
<p>The last step for parsing is to modify <code>parseExpr</code> to try and parse floats.</p>
The last step for parsing is to modify <code>parseExpr</code> to try and parse floats.
<table class="CodeRay"><tr>
@ -140,10 +135,10 @@ Tags: elschemo, haskell, scheme
</tr></table>
<h3>Displaying the floats</h3>
### Displaying the floats ###
<p>Thats it for parsing, now lets provide a way to display these suckers. <code>LispVal</code> is an instance of show, where <code>show</code> = <code>showVal</code> so <code>showVal</code> is our first stop. Remembering that <code>LispVal</code> now has a single <code>Number</code> constructor we modify it accordingly:</p>
That's it for parsing, now let's provide a way to display these suckers. <code>LispVal</code> is an instance of show, where <code>show</code> = <code>showVal</code> so <code>showVal</code> is our first stop. Remembering that <code>LispVal</code> now has a single <code>Number</code> constructor we modify it accordingly:
<table class="CodeRay"><tr>
@ -165,24 +160,21 @@ Tags: elschemo, haskell, scheme
</tr></table>
<p>One last, and certainly not least, step is to modify <code>eval</code> so that numbers evaluate to themselves.</p>
One last, and certainly not least, step is to modify <code>eval</code> so that numbers evaluate to themselves.
<pre><code>eval env val@(Number _) = return val</code></pre>
eval env val@(Number _) = return val
<p>Theres a little more housekeeping to be done such as fixing <code>integer?</code>, <code>number?</code>, implementing <code>float?</code> but I will leave those as an exercise to the reader, or just wait until I share the full code. As it stands now floating point numbers can be parsed and displayed. If you fire up the interpreter and type <code>2.5</code> or <code>-10.88</code> they will be understood. Now try adding them:</p>
There's a little more housekeeping to be done such as fixing <code>integer?</code>, <code>number?</code>, implementing <code>float?</code> but I will leave those as an exercise to the reader, or just wait until I share the full code. As it stands now floating point numbers can be parsed and displayed. If you fire up the interpreter and type <code>2.5</code> or <code>-10.88</code> they will be understood. Now try adding them:
(+ 2.5 1.1)
Invalid type: expected integer, found 2.5
<pre>(+ 2.5 1.1)
Invalid type: expected integer, found 2.5</pre>
Oops, we don't know how to operate on floats yet!
<p>Oops, we dont know how to operate on floats yet!</p>
### Operating on floats ###
<h3>Operating on floats</h3>
<p>Parsing was the easy part. Operating on the new floats is not necessarily difficult, but it was more work than I realized it would be. I dont claim that this is the best or the only way to operate on any <code>LispNum</code>, its just the way I did it and it seems to work. Theres a bunch of boilerplate necessary to make <code>LispNum</code> an instance of the required classes, Eq, Num, Real, and Ord. I dont think I have done this properly but for now it works. What is clearly necessary is the code that operates on different types of numbers. I think Ive specified sane semantics for coercion. This will be very handy shortly.</p>
Parsing was the easy part. Operating on the new floats is not necessarily difficult, but it was more work than I realized it would be. I don't claim that this is the best or the only way to operate on any <code>LispNum</code>, it's just the way I did it and it seems to work. There's a bunch of boilerplate necessary to make <code>LispNum</code> an instance of the required classes, Eq, Num, Real, and Ord. I don't think I have done this properly but for now it works. What is clearly necessary is the code that operates on different types of numbers. I think I've specified sane semantics for coercion. This will be very handy shortly.
<table class="CodeRay"><tr>
@ -330,7 +322,7 @@ Invalid type: expected integer, found 2.5</pre>
</tr></table>
<p>Phew, ok with that out of the way now we can actually extend our operators to work with any type of <code>LispNum</code>. Our Scheme operators are defined using the functions <code>numericBinop</code> and <code>numBoolBinop</code>. First well slightly modify our definition of <code>primitives</code>:</p>
Phew, ok with that out of the way now we can actually extend our operators to work with any type of <code>LispNum</code>. Our Scheme operators are defined using the functions <code>numericBinop</code> and <code>numBoolBinop</code>. First we'll slightly modify our definition of <code>primitives</code>:
<table class="CodeRay"><tr>
@ -368,7 +360,7 @@ Invalid type: expected integer, found 2.5</pre>
</tr></table>
<p>Note that <code>mod</code>, <code>quotient</code>, and <code>remainder</code> are only defined for integers and as such use <code>integralBinop</code>, while division (/) is only defined for floating point numbers using <code>floatBinop</code>. <code>subtractOp</code> is different to support unary usage, e.g. <code>(- 4) =&gt; -4</code>, but it uses <code>numericBinop</code> internally when more than 1 argument is given. On to the implementation! First extend <code>unpackNum</code> to work with any <code>LispNum</code>, and provide separate <code>unpackInt</code> and <code>unpackFloat</code> functions to handle both kinds of <code>LispNum</code>.</p>
Note that <code>mod</code>, <code>quotient</code>, and <code>remainder</code> are only defined for integers and as such use <code>integralBinop</code>, while division (/) is only defined for floating point numbers using <code>floatBinop</code>. <code>subtractOp</code> is different to support unary usage, e.g. <code>(- 4) =&gt; -4</code>, but it uses <code>numericBinop</code> internally when more than 1 argument is given. On to the implementation! First extend <code>unpackNum</code> to work with any <code>LispNum</code>, and provide separate <code>unpackInt</code> and <code>unpackFloat</code> functions to handle both kinds of <code>LispNum</code>.
<table class="CodeRay"><tr>
@ -406,7 +398,7 @@ Invalid type: expected integer, found 2.5</pre>
</tr></table>
<p>The initial work of separating integers and floats into the <code>LispNum</code> abstraction, and the code I said would be handy shortly, are going to be really handy here. Theres relatively no change in <code>numericBinop</code> except for the type signature. <code>integralBinop</code> and <code>floatBinop</code> are just specific versions of the same function. Im sure theres a nice Haskelly way of doing this with less repetition, and I welcome such corrections.</p>
The initial work of separating integers and floats into the <code>LispNum</code> abstraction, and the code I said would be handy shortly, are going to be really handy here. There's relatively no change in <code>numericBinop</code> except for the type signature. <code>integralBinop</code> and <code>floatBinop</code> are just specific versions of the same function. I'm sure there's a nice Haskelly way of doing this with less repetition, and I welcome such corrections.
<table class="CodeRay"><tr>
@ -450,11 +442,7 @@ Invalid type: expected integer, found 2.5</pre>
</tr></table>
<p>That was a bit of work but now ElSchemo supports floating point numbers, and if youre following along then your Scheme might too if I havent missed any important details!</p>
That was a bit of work but now ElSchemo supports floating point numbers, and if you're following along then your Scheme might too if I haven't missed any important details!
<p>Next time Ill go over some of the special forms I have added, including short-circuiting <code>and</code> and <code>or</code> forms and the full repetoire of <code>let</code>, <code>let*</code>, and <code>letrec</code>. Stay tuned!</p>
<div class="extended">
<p><a href="http://web.archive.org/web/20070628231343/http://sami.samhuri.net/2007/6/25/floating-point-in-elschemo">Continue reading...</a></p>
</div>
Next time I'll go over some of the special forms I have added, including short-circuiting <code>and</code> and <code>or</code> forms and the full repetoire of <code>let</code>, <code>let*</code>, and <code>letrec</code>. Stay tuned!

View file

@ -0,0 +1,12 @@
Title: Emacs: tagify-region-or-insert-tag
Date: June 25, 2007
Timestamp: 1182809580
Author: sjs
Tags: emacs, tagify
----
After <a href="2007.06.26-rtfm.html">axing</a> half of <a href="2007.06.23-emacs-for-textmate-junkies.html">wrap-region.el</a> I renamed it to <a href="/f/tagify.el">tagify.el</a> and improved it ever so slightly. It's leaner, and does more!
<code>tagify-region-or-insert-tag</code> does the same thing as <code>wrap-region-with-tag</code> except if there is no region it now inserts the opening and closing tags and sets point in between them. I have this bound to <code>C-z t</code>, as I use <code>C-z</code> as my personal command prefix.
<code>&lt;</code> is bound to <code>tagify-region-or-insert-self</code> which really doesn't warrant an explanation.

View file

@ -5,14 +5,13 @@ Author: sjs
Tags: propaganda
----
<p>Things <a href="http://web.archive.org/web/20080820114434/http://arstechnica.com/news.ars/post/20070625-spying-on-campus-fbi-warns-mit-harvard.html">like this</a> in modern times are surprising. Cant people spot this phony crap for what it is?</p>
Things <a href="http://arstechnica.com/news.ars/post/20070625-spying-on-campus-fbi-warns-mit-harvard.html">like this</a> in modern times are surprising. Can't people spot this phony crap for what it is?
<p><tt>First they put away the dealers, keep our kids safe and off the streets<br>
<tt>First they put away the dealers, keep our kids safe and off the streets<br>
Then they put away the prostitutes, keep married men cloistered at home<br>
Then they shooed away the bums, and they beat and bashed the queers<br>
Turned away asylum-seekers, fed us suspicions and fears<br>
We didnt raise our voice, we didnt make a fuss<br>
We didn't raise our voice, we didn't make a fuss<br>
It´s funny there was no one left to notice, when they came for us<br>
<br>
<strong>Looks like witches are in season, you better fly your flag and be aware<br>
@ -20,19 +19,19 @@ Of anyone who might fit the description, diversity is now our biggest fear<br>
Now with our conversations tapped, and our differences exposed<br>
How ya supposed to love your neighbour, with our minds and curtains
closed?<br>
We used to worry bout big brother<br>
We used to worry 'bout big brother<br>
Now we got a big father and an even bigger mother</strong><br>
<br>
And still you believe, this aristocracy gives a fuck about you<br>
They put the mock in democracy, and you swallowed every hook<br>
The sad truth is, youd rather follow the school into the net<br>
Cause swimming alone at sea, is not the kind of freedom that you
The sad truth is, you'd rather follow the school into the net<br>
'Cause swimming alone at sea, is not the kind of freedom that you
actually want<br>
So go back to your crib, and suck on a tit<br>
Bask in the warmth of your diaper, youre sitting in shit<br>
Bask in the warmth of your diaper, you're sitting in shit<br>
And piss, while sucking on a giant pacifier<br>
A country of adult infants, a legion of mental midgets<br>
A country of adult infants, a country of adult infants<br>
All regaining their unconsciousness<br>
</tt>
—from the song <a href="http://web.archive.org/web/20080820114434/http://www.nofxwiki.net/w/Lyrics:Regaining_Unconsciousness_%28song%29">Regaining Unconsciousness</a>, by <a href="http://web.archive.org/web/20080820114434/http://www.nofx.org/"><span class="caps">NOFX</span></a></p>
—from the song <a href="http://www.nofxwiki.net/w/Lyrics:Regaining_Unconsciousness_%28song%29">Regaining Unconsciousness</a>, by <a href="http://www.nofx.org/">NOFX</a>

View file

@ -0,0 +1,10 @@
Title: RTFM!
Date: June 26, 2007
Timestamp: 1182806340
Author: sjs
Tags: emacs, rtfm
----
I should read the Emacs manual sometime, especially since I have it in dead-tree form. Check out <a href="http://www.gnu.org/software/emacs/manual/html_node/autotype/Inserting-Pairs.html">skeleton pairs</a> in the Emacs manual, or better yet <code>C-h f skeleton-pair-insert-maybe</code>. skeleton-pair has already been massaged to do what you most likely want if you set the correct options. Cool. I like Emacs more every day.
This renders <a href="2007.06.23-emacs-for-textmate-junkies.html">wrap-region</a> useless, which is great! I like a trim .emacs and .emacs.d.

View file

@ -0,0 +1,26 @@
Title: Recent Ruby and Rails Regales
Date: June 28, 2007
Timestamp: 1183058580
Author: sjs
Tags: rails, rails on rules, regular expressions, ruby, sake, secure associations, regex
----
Some cool Ruby and [the former on] Rails things are springing up and I haven't written much about the two Rs lately, though I work with them daily.
### Rails on Rules ###
My friend <a href="http://jim.roepcke.com/">Jim Roepcke</a> is researching and implementing a plugin/framework designed to work with Rails called <a href="http://willingtofail.com/research/rules/index.html">Rails on Rules</a>. His inspiration is <a href="http://developer.apple.com/documentation/WebObjects/Developing_With_D2W/Architecture/chapter_3_section_13.html">the rule system</a> from <a href="http://developer.apple.com/documentation/WebObjects/WebObjects_Overview/index.html">WebObjects'</a> <a href="http://developer.apple.com/documentation/WebObjects/Developing_With_D2W/Introduction/chapter_1_section_1.html">Direct to Web</a>. He posted a good <a href="http://willingtofail.com/research/rules/example.html">example</a> for me, but this baby isn't just for template/view logic. If some of the Rails conventions were specified in a default set of rules which the developer could further customize then you basically have a nice way of doing things that you would otherwise code by hand. I think it would be a boon for the <a href="http://activescaffold.com/">ActiveScaffold</a> project. We're meeting up to talk about this soon and I'll have more to say after then, but it sounds pretty cool.
### Sake Bomb! ###
I've noticed a trend among some <a href="http://www.railsenvy.com/2007/6/11/ruby-on-rails-rake-tutorial">recent posts</a> about Rake: the authors keep talking about booze. Are we nothing but a bunch of booze hounds?! Well one can hope. There's some motivation to learn more about a tool, having more time to drink after work. This week <a href="http://ozmm.org/">Chris Wanstrath</a> dropped a <a href="http://errtheblog.com/post/6069">Sake Bomb</a> on the Ruby community. Like piston, sake is something you can just pick up and use instantly. Interestingly the different pronunciations of <code>rake</code> and <code>sake</code> help me from confusing the two on the command line... so far.
### Secure Associations (for Rails) ###
<a href="http://tuples.us/">Jordan McKible</a> released the <a href="http://tuples.us/2007/06/28/secure_associations-plugin-gets-some-love/">secure_associations</a> plugin. It lets you protect your models' *_id attributes from mass-assignment via <code>belongs_to_protected</code> and <code>has_many_protected</code>. It's a mild enhancement, but an enhancement nonetheless. This is useful to enough people that it should be in Rails proper.
### Regular expressions and strings with embedded objects ###
<a href="http://t-a-w.blogspot.com/">taw</a> taught me a <a href="http://t-a-w.blogspot.com/2007/06/regular-expressions-and-strings-with.html">new technique for simplifying regular expressions</a> by transforming the text in a reversible manner. In one example he replaced literal strings in SQL - which are easily parsed via a regex - with what he calls embedded objects. They're just tokens to identify the temporarily removed strings, but the important thing is that they don't interfere with the regexes that operate on the other parts of the SQL, which would have been very difficult to get right with the strings inside it. If I made it sound complicated just read the post, he explains it well.
If you believe anything <a href="http://steve-yegge.blogspot.com/2007/06/rich-programmer-food.html">Steve Yegge</a> says then that last regex trick may come in handy for Q&#38;D parsing in any language, be it Ruby, NBL, or whataver.

View file

@ -0,0 +1,12 @@
Title: Controlling volume via the keyboard on Linux
Date: June 30, 2007
Timestamp: 1183245180
Author: sjs
Tags: alsa, linux, ruby, volume
----
I was using Amarok's global keyboard shortcuts to control the volume of my music via the <a href="http://pfuca-store.stores.yahoo.net/haphackeylit1.html">keyboard</a> but I wanted to control the system volume as well. A quick script later and now I can control both, and thanks to libnotify I get some feedback on what happened. It's not as pretty as OS X's volume control or <a href="http://growl.info/">Growl</a> but it'll certainly do.
<a href="/f/volume.rb">&darr; Download volume.rb</a>
I save this as <strong>~/bin/volume</strong> and call it thusly: <code>volume +</code> and <code>volume -</code>. I bind Alt-+ and Alt—to those in my fluxbox config. If you don't have a preferred key binding program I recommend trying <a href="http://hocwp.free.fr/xbindkeys/xbindkeys.html">xbindkeys</a>. apt-get install, emerge, paludis -i, or rpm -i as needed.

View file

@ -0,0 +1,18 @@
Title: A TextMate tip for Emacs users
Date: July 3, 2007
Timestamp: 1183481100
Author: sjs
Tags: emacs, keyboard shortcuts, textmate
----
*Update: The only place I've seen this mentioned is in a <a href="http://macromates.com/blog/2005/screencast/#comment-660">comment</a> on the MacroMates blog.*
My Linux box is down due to a hardware failure; a cheap SATA controller to be specific. Perhaps that will be a story for another day. As a result I've been working on my MacBook and back in TextMate. Old habits. And I haven't gotten comfortable in any of the OS X Emacsen yet.
This gave me an opportunity to accidentally discover some shortcuts in TextMate. A result of the Emacs shortcuts that my fingers are already wired to, here are some TextMate keyboard shortcuts that may or may not be <a href="http://macromates.com/textmate/manual/">documented</a> (I need to RTFM some day).
* As in most Cocoa text areas, <code>C-f</code>, <code>C-b</code>, <code>C-n</code>, <code>C-p</code>, <code>C-a</code>, <code>C-e</code>, and <code>C-t</code> work as expected (and others I'm sure).
* <code>C-k</code>: behaves as a vanilla Emacs, killing till a newline or killing a bare newline. I use the word killing specifically because you can yank it back with...
* <code>C-y</code>: yanks back the last thing on the kill ring (paste history). You still have to use <code>C-S-v</code> to yank previous items.
I think TextMate may have helped ease me into Emacs without me even knowing. I had my suspicions that Allan was an Emacs fan and now I'm certain of it. I keep finding things in one that the other has, which makes switching between them easy. Well done Allan.

View file

@ -0,0 +1,8 @@
Title: RushCheck: QuickCheck for Ruby
Date: July 5, 2007
Timestamp: 1183665000
Author: sjs
Tags: quickcheck, ruby, rushcheck
----
I cannot wait to try out <a href="http://rushcheck.rubyforge.org/about.html">RushCheck</a>. It is <a href="http://www.cs.chalmers.se/~rjmh/QuickCheck/">QuickCheck</a> for Ruby. I don't have experience with QuickCheck or anything but it's clear to see how this helps you make certain your code is robust.

View file

@ -0,0 +1,12 @@
Title: See your regular expressions in Emacs
Date: July 6, 2007
Timestamp: 1183740300
Author: sjs
Tags: emacs, regex
----
First, if you are an Emacs newbie then be sure to read (at least) the introduction of <a href="http://stuff.mit.edu/iap/emacs">Being Productive with Emacs</a>. For some reason the PDF and HTML versions are slightly similar.
Anyway, it mentions <code>re-builder</code> which is an awesome little gem if you use regular expressions at all<sup>1</sup>. What this baby does is open a small window at the bottom of your screen in which you can type a regex. It is parsed as you type it and matches are highlighted in the other window. Genius.
[1] If you don't use them I encourage you to "learn them"http://regex.info/. Don't pay any attention to <a href="http://regex.info/blog/2006-09-15/247">Jamie Zawinsky</a> and his lack of appreciation for a fantastic tool.

View file

@ -0,0 +1,12 @@
Title: people
Date: July 12, 2007
Timestamp: 1184243280
Author: sjs
Tags: life, people
----
Sometimes this is difficult to remember for someone who (likes to think that he) thinks somewhat logically.
> When dealing with people, let us remember that we are not dealing with creatures of logic. We are dealing with creatures of emotion, creatures bristling with prejudices and motivated by pride and vanity.
<a href="http://en.wikipedia.org/wiki/Dale_Carnegie">Dale Carnegie</a>, *<a href="http://en.wikipedia.org/wiki/How_to_Win_Friends_and_Influence_People">How to Win Friends and Influence People</a>*

View file

@ -5,27 +5,25 @@ Author: sjs
Tags: elschemo, haskell, scheme
----
<p>Ive been developing a Scheme
I've been developing a Scheme
interpreter in Haskell called
<a href="http://web.archive.org/web/20081006064142/http://sami.samhuri.net/2007/6/25/floating-point-in-elschemo">ElSchemo</a>.
It started from <a href="http://web.archive.org/web/20081006064142/http://halogen.note.amherst.edu/~jdtang/scheme_in_48/tutorial/overview.html">Jonathans excellent Haskell
<a href="http://sami.samhuri.net/2007/6/25/floating-point-in-elschemo">ElSchemo</a>.
It started from <a href="http://halogen.note.amherst.edu/~jdtang/scheme_in_48/tutorial/overview.html">Jonathan's excellent Haskell
tutorial</a>
which I followed in order to learn both Haskell and Scheme. Basically
that means the code here is for me to get some feedback as much
as to show others how to do this kind of stuff. This may not be too
interesting if you havent at least browsed the tutorial.</p>
interesting if you haven't at least browsed the tutorial.
<p>Im going to cover 3 new special forms: <code>and</code>, <code>or</code>, and <code>cond</code>. I
I'm going to cover 3 new special forms: <code>and</code>, <code>or</code>, and <code>cond</code>. I
promised to cover the <code>let</code> family of special forms this time around
but methinks this is long enough as it is. My sincere apologies if
youve been waiting for those.</p>
you've been waiting for those.
## Short-circuiting Boolean logic ##
<h2>Short-circuiting Boolean logic</h2>
<p>Two functions from the tutorial which may irk you immediately are
Two functions from the tutorial which may irk you immediately are
<code>and</code> and <code>or</code>, defined in Scheme in the given standard library. If
your code is free of side-effects then it may not bother you so
much. It bothered me. The problem with the implementation in
@ -34,20 +32,17 @@ enters the function. Besides being inefficient by doing unnecessary work,
if any of the arguments have side-effects you can make use of short-circuiting
by using <code>and</code> to sequence actions, bailing out if any fail (by returning <code>nil</code>),
and using <code>or</code> to define a set of alternative actions which will bail out when the first in the list succeeds (by returning anything but <code>nil</code>). Had we macros then we could implement them as
macros. We dont, so well write them as special forms in Haskell.</p>
macros. We don't, so we'll write them as special forms in Haskell.
<p>Unlike the special forms defined in the tutorial Im going to
Unlike the special forms defined in the tutorial I'm going to
implement these as separate functions for clarity, rather than lump
them all in <code>eval</code>. However, they will be invoked directly from
<code>eval</code> so their type is easy; its the same as <code>eval</code>s.</p>
<code>eval</code> so their type is easy; it's the same as <code>eval</code>'s.
Code first, ask questions later. Haskell is a pretty clear and
concise language. My explanations may be redundant because of this.
<p>Code first, ask questions later. Haskell is a pretty clear and
concise language. My explanations may be redundant because of this.</p>
<h3>lispAnd</h3>
### lispAnd ###
<table class="CodeRay"><tr>
@ -71,29 +66,24 @@ concise language. My explanations may be redundant because of this.</p>
</tr></table>
<p>Starting with the trivial case, <code>and</code> returns <code>#t</code> with zero
arguments.</p>
Starting with the trivial case, <code>and</code> returns <code>#t</code> with zero
arguments.
With one argument, a single predicate, simply evaluate and
return that argument.
<p>With one argument, a single predicate, simply evaluate and
return that argument.</p>
<p>Given a list of predicates, evaluate the first and inspect its value.
Given a list of predicates, evaluate the first and inspect its value.
If the argument evaluated to <code>#f</code> then our work is done and we return
<code>#f</code>, otherwise we keep plugging along by making a recursive call with
the first argument stripped off. Eventually we will reach our base
case with only one predicate.</p>
case with only one predicate.
It's possible to eliminate the case of one predicate. I think that
just complicates things but it's a viable solution.
<p>Its possible to eliminate the case of one predicate. I think that
just complicates things but its a viable solution.</p>
### lispOr ###
<h3>lispOr</h3>
<p>Predictably this is quite similar to <code>lispAnd</code>.</p>
Predictably this is quite similar to <code>lispAnd</code>.
<table class="CodeRay"><tr>
@ -117,21 +107,18 @@ just complicates things but its a viable solution.</p>
</tr></table>
<p>With no arguments <code>lispOr</code> returns <code>#f</code>, and with one argument it
evaluates and returns the result.</p>
With no arguments <code>lispOr</code> returns <code>#f</code>, and with one argument it
evaluates and returns the result.
<p>With 2 or more arguments the first is evaluated, but this time if the
With 2 or more arguments the first is evaluated, but this time if the
result is <code>#f</code> then we continue looking for a truthy value. If the
result is anything else at all then its returned and we are done.</p>
result is anything else at all then it's returned and we are done.
## A new branching construct ##
<h2>A new branching construct</h2>
<p>First let me define a convenience function that I have added to
First let me define a convenience function that I have added to
ElSchemo. It maps a list of expressions to their values by evaluating
each one in the given environment.</p>
each one in the given environment.
<table class="CodeRay"><tr>
@ -143,10 +130,9 @@ each one in the given environment.</p>
</tr></table>
<h3>lispCond</h3>
### lispCond ###
<p>Again, <code>lispCond</code> has the same type as <code>eval</code>.</p>
Again, <code>lispCond</code> has the same type as <code>eval</code>.
<table class="CodeRay"><tr>
@ -166,27 +152,24 @@ each one in the given environment.</p>
</tr></table>
<p>Unlike Lisp which uses a predicate of <code>T</code> (true) Scheme uses a
Unlike Lisp which uses a predicate of <code>T</code> (true) Scheme uses a
predicate of <code>else</code> to trigger the default branch. When the pattern
matching on <code>Atom "else"</code> succeeds, we evaluate the default
expressions and return the value of the last one. This is one
possible base case. <code>Atom "else"</code> could be defined to evaluate to
<code>#t</code>, but we dont want <code>else</code> to be evaluated as <code>#t</code> anywhere except
in a <code>cond</code> so I have chosen this solution.</p>
<code>#t</code>, but we don't want <code>else</code> to be evaluated as <code>#t</code> anywhere except
in a <code>cond</code> so I have chosen this solution.
<p>If the first predicate is not <code>else</code> then we evaluate it and check the
If the first predicate is not <code>else</code> then we evaluate it and check the
resulting value. If we get <code>#f</code> then we look at the rest of the
statement, if its empty then we return <code>#f</code>, otherwise we recurse on
statement, if it's empty then we return <code>#f</code>, otherwise we recurse on
the rest of the parameters. If the predicate evaluates to a truthy
value that is, anything but <code>#f</code> then we evaluate the consequent
expressions and return the value of the last one.</p>
expressions and return the value of the last one.
## Plumbing ##
<h2>Plumbing</h2>
<p>Now all thats left is to hook up the new functions in <code>eval</code>.</p>
Now all that's left is to hook up the new functions in <code>eval</code>.
<table class="CodeRay"><tr>
@ -200,24 +183,17 @@ expressions and return the value of the last one.</p>
</tr></table>
<p>You could, of course, throw the entire definitions in <code>eval</code> itself but <code>eval</code> is big
enough for me as it is. <span class="caps">YMMV</span>.</p>
You could, of course, throw the entire definitions in <code>eval</code> itself but <code>eval</code> is big
enough for me as it is. YMMV.
## Done! ##
<h2>Done!</h2>
<p>So, thats a wrap. It only took 20 lines of code for the 3 new
So, that's a wrap. It only took 20 lines of code for the 3 new
special forms, and it could easily be done with less code. Next time
I will show you how to implement the various <code>let</code> functions. Really!</p>
I will show you how to implement the various <code>let</code> functions. Really!
<p><em>Do you like me describing ElSchemo piece by piece as I have been? I
*Do you like me describing ElSchemo piece by piece as I have been? I
plan on posting the Haskell code and my stdlib.scm in their entirety
sometime, and I could do that before or after I finish writing about
the features Ive developed beyond the tutorial. Just let me know in
the comments.</em></p>
<div class="extended">
<p><a href="http://web.archive.org/web/20081006064142/http://sami.samhuri.net/2007/8/2/elschemo-boolean-logic-and-branching">Continue reading...</a></p>
</div>
the features I've developed beyond the tutorial. Just let me know in
the comments.*

View file

@ -0,0 +1,38 @@
Title: Cheat from Emacs
Date: August 9, 2007
Timestamp: 1186710960
Author: sjs
Tags: Emacs
----
*Update: I had inadvertently used <code>string-join</code>, a function provided by something in my ~/.emacs.d. The script has been updated to work with a vanilla Emacs (23, but should work with 22 as well).*
*Update #2 [2007.08.10]: Editing cheats and diffs have been implemented.*
*Update #3 [2007.08.21]: I <a href="2007.08.21-cheat-productively-in-emacs.html">added completion</a> to cheat.el. The file linked on this page is still the latest version.*
We all know and love <a href="http://cheat.errtheblog.com/">cheat</a>. Now you can cheat without leaving Emacs (and without using a shell in Emacs).
Just save <a href="/f/cheat.el">cheat.el</a> in ~/.emacs.d and then <code>(require 'cheat)</code> in your ~/.emacs. I also bind <code>C-z C-c</code> to <code>cheat</code>, you may want to do something similar.
<del>You can't do everything you can do with cheat on the command line yet</del>, and for most of the commands the cheat command itself is used. *Now you can do everything the command line client does from within Emacs, though you may need to revert to using <code>cheat-command</code> (described below).*
Here's the rundown:
*Any time you enter a cheat name there are both completion and a cheat-specific history available. Unless you are adding a new cheat. In that case you should use a new, unique name (duh).*
* <code>cheat</code> Lookup a cheat sheet interactively (<code>cheat &lt;name&gt;</code>)
* <code>cheat-sheets</code> List all cheat sheets (<code>cheat sheets</code>)
* <code>cheat-recent</code> List recently added cheat sheets (<code>cheat recent</code>)
* <code>cheat-versions</code> List versions of a cheat sheet interactively (<code>cheat &lt;name&gt; --versions</code>)
* <code>cheat-clear-cache</code> Clear all cached sheets.
* <code>cheat-add-current-buffer</code> Add a new cheat using the specified name and the contents of the current buffer as the body. (<code>cheat &lt;name&gt; --add</code>)
* <code>cheat-edit</code> Retrieve a fresh copy of the named cheat and display the body in a buffer for editing.
* <code>cheat-save-current-buffer</code> Save the current cheat buffer, which should be named <code>*cheat-&lt;name&gt;*</code>.
* <code>cheat-diff</code> Show the diff between the current version and the given version of the named cheat. If the version given is of the form <em>m:n</em> then show the diff between versions <em>m</em> and <em>n</em>. (<code>cheat &lt;name&gt; --diff &lt;version&gt;</code>)
* <code>cheat-command</code> Pass any arguments you want to cheat interactively.
*(Added)* <del>I may add support for <code>--diff</code> and <code>--edit</code> in the future.</del>
Please do send me your patches so everyone can benefit from them.

View file

@ -0,0 +1,12 @@
Title: Snap, crunchle, pop
Date: August 9, 2007
Timestamp: 1186654620
Author: sjs
Tags: humans, injury, life
----
I think that every now and then we need to be reminded of the frail nature of our human bodies. Yesterday morning as I walked to my kitchen I was turning right by pivoting on my right foot when my 24 years of walking experience suddenly failed me. I clearly did something wrong, as I heard a crunching pop or two in my right ankle and went down. Luckily it's just a sprain but my foot is fairly bruised and still sore today. I'm trying to follow the <a href="http://orthopedics.about.com/cs/sprainsstrains/a/sprain_4.htm">RICE</a> method for recuperating but one can only lay down for so long before having to eat, work, use the bathroom, etc. Thank goodness I don't work on my feet or I'd be out of commission. If it still hurts next week I'm going to see a doctor but till then I'm trying not to leave my house. The idea of hopping and hobbling to a bus to go to a doctor does not thrill me in the slightest.
Oh, if you find yourself in a bind an upside down hockey stick is a decent makeshift crutch. You'll need 2 hands to operate the thing though.
At the opposite end of the spectrum there are times when we seem to be amazingly resilient creatures. Check out a documentary called *"101 Things Removed from the Human Head"* if you can find it anywhere. One of those things was a boat anchor, I kid you not.

View file

@ -0,0 +1,16 @@
Title: Opera is pretty slick
Date: August 11, 2007
Timestamp: 1186834260
Author: sjs
Tags: browsers, firefox, opera
----
Though I usually prefer free software, I don't have any problems using proprietary stuff if I think it's good. I had Firefox open for a couple of days and noticed that it was using 700M of memory. That's not a problem at all since I have 4G but it's also a lot of RAM to be in use for just one window with one tab open. The fact that Firefox gets sluggish after some time and needs to be restarted tells me that this isn't expected behaviour and is likely not due to caching for quick back/forward or whatever they claim is taking up the leaked memory.
Konqueror is ok but I'm not a huge fan of it, partly due to its kitchen-sink browser/file manager hybrid design. IMO the KDE folks should break out the file manager part, but I digress. I can't really put my finger on anything specific I dislike about Konqueror, it's just not for me. To my dismay it seems to be the snappiest browser on Linux.
The only other decent browser I know of (for Linux) is Opera so I found some quick instructions on the Ubuntu forums and shoehorned the x86 build of it into my amd64 installation. Everything went well, Flash works and all that stuff. Opera is not nearly as snappy as I like but it is still fairly pleasant to use, once you find a skin that fits into your desktop. For the record Firefox isn't snappy enough either. Apart from AdBlock I don't miss many extensions for every day browsing.
I'm not sure if I'm going to stick with it yet but I've been using it for 2 days and haven't really missed Firefox at all. Of course as soon as I do any development I need Firefox for Firebug and the Web Developer extension and such. I've yet to investigate development tools on Opera. I'm comfortable developing in Firefox already so why switch?
Man am I glad we're not in a Netscape/IE world anymore! If I open up my MacBook I can choose from at least 2 other browsers for every day browsing (Camino, Safari).

View file

@ -0,0 +1,16 @@
Title: Catch compiler errors at runtime
Date: August 19, 2007
Timestamp: 1187561820
Author: sjs
Tags: ruby
----
While coding just now I had a small epiphany about Ruby. Though Ruby is highly dynamic and compiled at runtime, that doesn't preclude one catching some mistakes at compile time. I'm not talking about mere syntax errors or anything either. The only proviso to catching mistakes at compile time is that you must have a decent chunk of code executed during compilation. One benefit of Ruby's blurring of compile time and runtime is that you can run real code at compile time. This is largely how metaprogramming tricks are pulled off elegantly and with ease in projects such as Rails.
Sure you won't get all the benefits of a strictly and/or statically typed compiler, but you can get some of them. If you have a library that makes substantial use of executing code at compile time then the mere act of loading your library causes your code to run, thus it compiles. If you <code>require</code> your lib and get <code>true</code> back then you know the code that bootstraps the runtime code is at least partially correct.
Compile time is runtime. Runtime is compile time. Just because you have to run the code to compile it doesn't mean you can't catch a good chunk of compiler errors before you send out your code. Tests will always be there for the rest of your mistakes, but if you can pull work into compile time then Ruby's compiler can augment your regular testing practices.
I admit that this is of limited use most of the time, but let it not be said that you can't catch any errors with your compiler just because you have to run your code to compile it. With Ruby the more meta you get the more the compiler rewards you.
*[Of course this is true of languages such as Common Lisp too, which make available the full programming language at compile time. I just happened to be using Ruby when I realized this.]*

View file

@ -0,0 +1,28 @@
Title: Cheat productively in Emacs
Date: August 21, 2007
Timestamp: 1187720400
Author: sjs
Tags: Emacs
----
By now you may have heard about <a href="http://cheat.errtheblog.com/">cheat</a>, the command line cheat sheet collection that's completely open to editing, wiki style. A couple of weeks ago I posted <a href="2007.08.10-cheat-from-emacs.html">cheat.el</a> which allows one to cheat from within Emacs. There's an update. However, before I get to cheat.el there's a small detour.
Cheat is not just about Ruby! A few examples of cheats available are:
* bash and zsh
* $EDITOR (if you happen to like e, TextMate, vi, emacs, RadRails, ...)
* GNU screen
* Version control (darcs, svn, git)
* Firebug
* Markdown and Textile
* Oracle and MySQL
* Regular expressions
* and of course Ruby, Rails, Capistrano, etc.
As of today, Aug-21 2007, the count is at <strong>166 cheat sheets</strong> so there's probably something there that you'll want to look up from the command line or Emacs sometime. That's enough stroking cheat's ego, but there seems to be a notion that cheat is only for Ruby stuff and that's really not the case.
So what's new in this version of cheat.el? <strong>Completion!</strong> The only thing that bothered me about cheating in Emacs was the lack of completion. It now has completion, thus it is now perfect. :) In all likeliness this won't be the last release, but I can't really foresee adding anything else to it in the near future. Enjoy!
Download it now: <a href="/f/cheat.el">cheat.el</a>
For any newcomers, just drop this into <code>~/.emacs.d</code>, <code>~/.elisp</code>, or any directory in your <code>load-path</code> and then <code>(require 'cheat)</code>. For more info check the <a href="2007.08.09-cheat-from-emacs.html">original article</a> for a rundown on the cheat commands.

View file

@ -0,0 +1,8 @@
Title: Captivating little creatures
Date: August 26, 2007
Timestamp: 1188131700
Author: sjs
Tags: games, lemmings
----
Someone posted this JavaScript implementation of an old gem on Reddit, <a href="http://www.elizium.nu/scripts/lemmings/">Lemmings</a>! There goes my Sunday! :)

View file

@ -0,0 +1,34 @@
Title: 5 ways to avoid looking like a jerk on the Internet
Date: August 30, 2007
Timestamp: 1188487500
Author: sjs
Tags: life, netiquette
----
Let me begin by stating that these are tips I have gathered by posting in many public forums on the Internet and I have learned most of these rules by making the mistakes myself. I'm not trying to point fingers at anyone or act all holier-than-thou. It's a cold, emotionless medium text is. It can be difficult to accurately convey one's feelings when typing a quick reply somewhere. <a href="http://www.penny-arcade.com/comic/2004/03/19">John Gabriel's theory</a> certainly plays a part as well, but I'll try and assume that you are generally a nice person. I also assume that we are talking about a text medium (IRC, forums, Slashdot/Reddit/Digg). None of that fancy voice or video conferencing stuff!
Also, this is not a guide on how to really be an arrogant prick, but just not look like one when you engage in conversations on the Internet. It's also not a guide on not being a jerk. Should you lack basic manners you will have to learn them elsewhere.
### Rule #1: Forget the medium ###
One thing that is quite difficult to do is look past the medium and remember that these are all real people conversing with each other. Don't type anything that you wouldn't say to their face in real life. This is, of course, not exclusive to the Internet.
### Rule #2: Remember the medium! ###
While obeying Rule #1 it's important to remember that in a text medium there is no emotion or tone to our words. If you think that smilies / emoticons are lame and for 12 year olds, well you're right. However, there's no reason for an adult to refrain from using them as well. They can be important quick clues to how your message should be interpreted. You can always rephrase what you write so that there's little ambiguity to your words, but if you're typing something quickly on Digg, Reddit or some forum then you probably aren't spell checking and proof reading each and every post.
### Rule #3: Avoid know-it-all responses ###
Starting a reply with "But ...", "Well ...", "No ...", or "Your mother's a ..." often sounds confrontational. There's obviously no harm in using these in the right context, but many times I have found that removing these from the front of a sentence can drastically alter the tone and make it clear that I am trying to converse rather than argue.
### Rule #4: Address the correct party ###
If you're not speaking directly to the reader avoid using "you" when you mean "one". This is a particularly hard one to get in the habit of doing, for me at least. I am just not used to speaking so formally but in writing it really does make a world of difference. People are defensive creatures by nature and we don't like being singled out or accused. Hell, half of the time we don't even like honest, kind advice.
### Rule #5: Accept the fact that people know more than you ###
Geeks often come across as know-it-alls. While most geeks probably do think they're rather clever (guilty as charged) they probably also know that they don't know everything. When one knows nothing of a topic it's easy to admit that others are right and they are wrong (often because they won't have an opinion on the subject yet). The trouble starts once they learn something about the matter, once they have formed opinions and ideas about it.
I'm not saying that we should all stop discussing things we're not experts on, just that we should try harder to keep open minds about things and realize that others may have some insight we do not. If in doubt, partake in civil discourse and try not to dismiss others without even asking them to back up their claims or ideas.
Cue the comments pointing out how many of these rules I broke in this very post... :)

View file

@ -0,0 +1,8 @@
Title: Learning Lisp? Read PCL
Date: September 25, 2007
Timestamp: 1190714340
Author: sjs
Tags: lisp
----
Yes, it's a book. But it's so well written you should breeze through it as if it were a <a href="http://www.gigamonkeys.com/book/">Lisp tutorial</a>!

View file

@ -0,0 +1,22 @@
Title: Python and Ruby brain dump
Date: September 26, 2007
Timestamp: 1190802840
Author: sjs
Tags: python, ruby
----
It turns out that <a href="http://dev.laptop.org/git?p=security;a=blob;f=bitfrost.txt">Python is the language of choice on the OLPC</a>, both for implementing applications and exposing to the users. There is a view source key available. I think Python is a great choice.
I've been using Ruby almost exclusively for over a year but the last week I've been doing a personal project in Python using <a href="https://storm.canonical.com/">Storm</a> (which is pretty nice btw) and <a href="http://excess.org/urwid/">urwid</a>. I'm remembering why I liked Python when I first learned it a few years ago. It may not be as elegant as Ruby, conceptually, but it sure is fun to code in. It really is executable pseudo-code for the most part.
I'm tripping up by typing <code>obj.setattr^W^Wsetattr(obj</code> and <code>def self.foo^W^Wfoo(self</code> but other than that I haven't had trouble switching back into Python. I enjoy omitting <code>end</code> statements. I enjoy Python's lack of curly braces, apart from literal dicts. I hate the fact that in Emacs, in python-mode, <code>indent-region</code> only seems to piss me off (or <code>indent-*</code> really, anything except TAB). I really like list comprehensions.
The two languages are so similar that at a glance you may think there are only shallow differences between the languages. People are always busy arguing about the boring things that every language can do (web frameworks anyone?) while ignoring the interesting differences between the languages and their corresponding ecosystems.
Python has more libraries available as it's the more popular language. The nature of software written in the languages is different though as the languages themselves are quite different.
Ruby has some Perl-ish features that make it a good sysadmin scripting language, hence we see nice tools such as <a href="http://www.capify.org/">Capistrano</a> and <a href="http://god.rubyforge.org/">god</a> written in Ruby and used by projects written in other languages.
Python is faster than Ruby so it is open to classes of software that would be cumbersome in Ruby. Source control, for example. You can write a slow SCM in Python though, as <a href="http://bazaar-vcs.org/">Bazaar</a> demonstrates. You could probably write a passable one in Ruby as well. If it didn't quite perform well enough right now it should fare better in a year's time.
I still think that my overall joy is greater when using Ruby, but if Ruby isn't the right tool for the job I'll probably look to Python next (unless some feature of the problem indicates something else would be more appropriate). The reason I chose Python for my current project is because of libs like urwid and I needed an excuse to try out Storm and brush up on my Python. ;-)

View file

@ -0,0 +1,50 @@
Title: Gtkpod in Gutsy Got You Groaning?
Date: October 29, 2007
Timestamp: 1193692440
Author: sjs
Tags: broken, gtkpod, linux, ubuntu
----
I recently upgraded the <a href="http://www.ubuntu.com/">Ubuntu</a> installation on my workstation from Feisty Fawn to Gutsy Gibbon and for the most part I am happy with the changes. One thing I don't care much for is the fact that gtkpod-aac is a sham. Ubuntu provides the gtkpod-aac package for one to transfer aac files, and thus mp4 files with aac audio tracks, to their iPod. The version in the Gutsy repos is broken. This shows a weakness in Ubuntu, and though it's rather small it is one that will piss off a lot of people who expect things to just work. The kind of people who would buy an iPod. The kind of people who use Linux. The kind of Linux users that use Ubuntu. The kicker is that <a href="https://bugs.launchpad.net/ubuntu/+source/gtkpod-aac/+bug/135178/comments/6">it doesn't look like</a> they will ship a working version of gtkpod-aac for Gutsy at all. I know it's only 6 months but that seems like an eternity when you have the same old crap to watch on your iPod for that long.
All is not lost. A kind soul left <a href="https://bugs.launchpad.net/ubuntu/+source/gtkpod-aac/+bug/135178/comments/7">a helpful comment</a> on the <a href="https://bugs.launchpad.net/ubuntu/+source/gtkpod-aac/+bug/135178">bug report</a> explaining how he got it to work. It's a pretty simple fix. Just <a href="http://www.google.ca/search?q=libmpeg4ip">google for libmpeg4ip</a> and find a <a href="http://ftp.uni-kl.de/debian-multimedia/pool/main/libm/libmpeg4ip/">Debian repo that has the following packages</a> for your architecture:
* libmpeg4ip-0
* libmpeg4ip-dev
* libmp4v2-0
* libmp4v2-dev
Download those 4 .deb files and install them. You can ignore any advise to use an older version in the official repo. Once you have those installed, download and build the latest version of gtkpod from their <a href="http://sourceforge.net/svn/?group_id=67873">Subversion repo</a>.
Now that you know what to do I'll give you what you probably wanted at the beginning. As long as you have wget, subversion, and use a Bourne-like shell this should work for you.
<a href="/f/gtkpod-aac-fix.sh">gtkpod-aac-fix.sh</a>
<table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt>11<tt>
</tt>12<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">mkdir /tmp/gtkpod-fix<tt>
</tt>cd /tmp/gtkpod-fix<tt>
</tt>wget http://ftp.uni-kl.de/debian-multimedia/pool/main/libm/libmpeg4ip/libmp4v2-0_1.5.0.1-0.3_amd64.deb<tt>
</tt>wget http://ftp.uni-kl.de/debian-multimedia/pool/main/libm/libmpeg4ip/libmp4v2-dev_1.5.0.1-0.3_amd64.deb<tt>
</tt>wget http://ftp.uni-kl.de/debian-multimedia/pool/main/libm/libmpeg4ip/libmpeg4ip-0_1.5.0.1-0.3_amd64.deb<tt>
</tt>wget http://ftp.uni-kl.de/debian-multimedia/pool/main/libm/libmpeg4ip/libmpeg4ip-dev_1.5.0.1-0.3_amd64.deb<tt>
</tt>for f in *.deb; do sudo gdebi -n "$f"; done<tt>
</tt>svn co https://gtkpod.svn.sourceforge.net/svnroot/gtkpod/gtkpod/trunk gtkpod<tt>
</tt>cd gtkpod<tt>
</tt>./autogen.sh --with-mp4v2 &amp;&amp; make &amp;&amp; sudo make install<tt>
</tt>cd<tt>
</tt>rm -rf /tmp/gtkpod-fix</pre></td>
</tr></table>

View file

@ -0,0 +1,10 @@
Title: Random pet peeve of the day
Date: January 7, 2008
Timestamp: 1199727720
Author: sjs
Tags: usability, web
----
So long since my last post, and all I'm going to do is complain. ;-) Seriously though, if you have a website and the content on said site is dated then please for the love of our almighty saviour, the <a href="http://www.venganza.org/about">Flying Spaghetti Monster</a> <em>put the date at the <strong>top</strong> of the page</em>. Don't make me scroll down to the end of the article just to see how relevant it is or just to give me some context. Not to mention that I always end up doing a "Where <em>is</em> the end? Oh crap, I passed it and now I'm in the comments, blargh!"
I'm looking at Lifehacker since they're the most recent offender I've come across, but they are definitely not the only ones guilty of this.

View file

@ -0,0 +1,42 @@
Title: Thoughts on Arc
Date: February 19, 2008
Timestamp: 1203420360
Author: sjs
Tags: lisp arc
----
*NB: This is just a braindump. There's nothing profound or particularly insightful in this post.*
You may have heard that <a href="http://www.paulgraham.com/">Paul Graham</a> recently released his pet dialect of Lisp: <a href="http://arclanguage.org/">Arc</a>. It's a relatively small language consisting of just 4500 lines of code. In just under <a href="http://arclanguage.com/install">1200 lines</a> of <a href="http://www.plt-scheme.org/">PLT Scheme</a> the core of Arc is defined. The rest of the language is written in Arc itself. The heart of that is a file arc.arc, weighing in at 1500 lines. The remaining 1000-1300 lines are spread between libraries, mainly for writing web apps: html.arc, srv.arc, app.arc, and a few others.
I'm not going to go into great detail, but Arc is a fun language. You can read all the code in one or two sittings and start hacking on it in no time. The code is simple where simple gets the job done and if you can follow <a href="http://mitpress.mit.edu/sicp/">SICP</a> then you should understand it with relative ease (assuming you're somewhat familiar with Lisp).
### Parsing, Markdown ###
I'm writing a simple parser combinators library (loosely modeled on <a href="http://legacy.cs.uu.nl/daan/parsec.html">Parsec</a>) in order to write a nice Markdown implementation. Overkill? Indeed. Parsec is a wonderful library and it is written beautifully. If I end up with something 1/2 as powerful and 1/10th as beautiful I'll be pleased. This was all in order to beef up the version of Markdown bundled with Arc so I could write a basic wiki. I've been <a href="http://arclanguage.org/item?id=1456">beaten</a> to the punch, <a href="http://arclanguage.org/item?id=2037">twice</a>! Perhaps I'll retrofit Markdown onto jgc's wiki once I get something decent finished.
### Brevity and Innovation ###
The brevity of Arc is both a blessing and a curse. On the one hand it makes for a very hacking-friendly language. It's easy/fun to try things in the REPL and write throwaway code for learning purposes. Paul's wanton removal of extraneous parentheses is a great boon. On the flip side Arc code can be a little cryptic at a first glance. While reading code there's a small period of time where you have to figure out what the short names are and what they do, but because the language is so small it's utterly trivial to grep or read the source and find out exactly how everything fits together and get the context you need. Once you're familiar with the domain then the terse names not only make sense, but they make the interesting parts of the code stand out more. I want to emphasize the pleasure of using Arc to learn. I think that Paul is on to something with the general brevity and simple nature of Arc.
Some interesting ways that Paul has reduced code is by introducing new intra-symbol operators. Besides the usual backquote/quasiquote and comma/unquote translations, several other special characters are translated when they appear within/around symbols.
There is the colon/compose operator that reduces code such as: <code>(sym (string "pre-" something "-suffix"))</code> to <code>(sym:string "pre-" something "-suffix")</code>. It can help with car/cdr chains without defining monstrosities such as <code>cadadr</code>, though whether <code>(cadadr ...)</code> is better than <code>(cadr:cadr ...)</code> is better than <code>(car (cdr (car (cdr ...))))</code> is up to you.
My favourite is the tilde to mean logical negation: <code>no</code> in Arc, <code>not</code> in most other languages. It doesn't shorten code much but it helps with parens. <code>(if (no (empty str)) ...)</code> becomes <code>(if (~empty str) ...)</code>. Not much to be said about it, but it reads very nicely in code.
Some newer ones are the dot and exclamation point to aide in the composition of functions requiring arguments. I won't go into detail as their use is trivial. If you're interested read <a href="http://arclanguage.org/item?id=2166">Paul's explanation</a> of them.
### Web programming ###
Paul has touted Arc as a good web programming language, most notably in his <a href="http://www.paulgraham.com/arcchallenge.html">Arc Challenge</a> that caused a minor stir in a few blogs and on Reddit. I'm writing a small web app for myself in Arc. I may host it somewhere public when it's useable. It's a somewhat <a href="http://pastie.caboo.se/">pastie</a>-like app specifically for storing/sharing solutions to problems over at <a href="http://projecteuler.net/">Project Euler</a>, which I recently started tackling. "What's wrong with saving the code on your hard disk without a web app?", you ask? It doesn't give me an excuse to try Arc as a web language. ;-)
So far I find that Arc is quite a nice web language. With the handy HTML tag library you can generate 90s-style, quirks-mode-compliant tag soup in a blink. I haven't had trouble producing HTML 4.01 (strict) that validates. There's no need for a template language or partials (à la Rails), you just compose tags-as-sexps using Arc itself. This turns out to be quite elegant, even if somewhat reminiscent of my first forays into web programming with PHP. I don't feel as if I'm writing a web app so much as I'm writing an app that happens to present its UI in HTML. <em>(I'm reminded a little of <a href="http://webpy.org/">web.py</a>, which I enjoy as the antithesis of Rails.)</em> I suppose it takes some discipline to separate your logic &amp; design when everything's mixed in the same file, but there's nothing stopping you from separating the logic and views into their own files if you really prefer to do it that way.
There's no distinction between GET and POST params. This surprised me, but then I thought about it and it's not a big deal for most apps, imo.
The app I'm writing is standard CRUD stuff so I haven't done anything cool using continuations yet. I plan to use call/cc for backtracking in my parser, but I'm still a ways from implementing that kind of functionality!
### Non-conclusion ###
I feel as though I should have a conclusion, but I don't. I've only been using Arc for a short time. It feels nice. I think Paul is doing a good job on the design by keeping it small, compact, and simple. Seeing as it's still in its infancy it's just a toy for me, but a toy with some decent potential. And hopefully an impact on other Lisps. Common Lisp may have industrial implementations and a 1500 page spec, but Arc is more fun and hackable. More so than Scheme, too. I think Arc has out-Schemed Scheme.

View file

@ -0,0 +1,15 @@
Title: Project Euler code repo in Arc
Date: March 3, 2008
Timestamp: 1204561440
Author: sjs
Tags: arc, project euler
----
Release early and often. This is a code repo web app for solutions to <a href="http://projecteuler.net/">Project Euler</a> problems. You can only see your own solutions so it's not that exciting yet (but it scratches my itch... once it highlights syntax). You can <a href="http://nofxwiki.net:3141/euler">try it out</a> or <a href="http://samhuri.net/euler.tgz">download the source</a>. You'll need an up-to-date copy of <a href="http://arcfn.com/2008/02/git-and-anarki-arc-repository-brief.html">Anarki</a> to untar the source in. Just run <strong>arc.sh</strong> then enter this at the REPL:
<pre><code>arc&gt; (load "euler.arc")
arc&gt; (esv)
</code></pre>
That will setup the web server on port 3141. If you want a different port then run <code>(esv 25)</code> (just to mess with 'em).

View file

@ -0,0 +1,23 @@
Title: A Static URL Shortener Using .htaccess
Date: December 10, 2011
Timestamp: 1323584949
Author: sjs
Tags: s42.ca, url, shortener, samhuri.net, url shortener
----
This blog is statically generated. A few Ruby and Node.js scripts along with a Makefile and some duct tape hold it all together. All of [samhuri.net is on Github](GH) if you want to take a look. Most of it is quite minimal, sometimes to a fault. Little improvements are made here and there and the most recent one is neat [.htaccess](htaccess-wiki) hack. I want to automatically announce new posts on Twitter so short URLs are in order.
I try to strike a reasonable balance between writing everything for this site myself and using libraries. A quick look at a few short URL projects was enough to see they weren't what I was looking for. They were all database backed servers. Comments on this blog are served up dynamically but everything else is static and I try to avoid dynamic behaviour when possible. Comments are moving to a more static system sometime. Anyway I registered the domain [s42.ca](s42) and nabbed [an algorithm for creating the short codes from Jonathan Snook](snook) before diving into TextMate to implement my idea.
The result is about two dozen additional lines of Ruby in my static generator, and a command added to a Makefile. The Ruby code generates a short URL for each of my blog posts and then creates a [RewriteRule](RewriteRule) directive to redirect that short codes to each corresponding blog post. Then the directives are dumped into a .htaccess file which is [scp](scp)'d to s42.ca when I run `make publish_blog`.
<script src="https://gist.github.com/1458844.js"></script>
I think this is a pretty neat hack and have not seen this technique anywhere else so I thought I'd share it. Maybe someone else will find it interesting or useful for their blog. How far it scales won't be a concern until I have thousands of blog posts. That sounds like a good problem for future Sami to solve should it arise.
[GH]: https://github.com/samsonjs/samhuri.net
[htaccess-wiki]: http://en.wikipedia.org/wiki/Htaccess
[s42]: http://s42.ca
[snook]: http://snook.ca/archives/php/url-shortener
[RewriteRule]: http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriterule
[scp]: http://en.wikipedia.org/wiki/Secure_copy

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,346 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Full-screen Cover Flow - samhuri.net</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta content="48.472,-123.3683" name="ICBM" />
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/xml/rsd" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/xml/rss20/article/1363/feed.xml" />
<link rel="alternate" type="application/atom+xml" title="Atom" href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/xml/atom10/article/1363/feed.xml" />
<script src="http://web.archive.org/web/20070316171948js_/http://sami.samhuri.net/javascripts/cookies.js" type="text/javascript"></script>
<script src="http://web.archive.org/web/20070316171948js_/http://sami.samhuri.net/javascripts/prototype.js" type="text/javascript"></script>
<script src="http://web.archive.org/web/20070316171948js_/http://sami.samhuri.net/javascripts/effects.js" type="text/javascript"></script>
<script src="http://web.archive.org/web/20070316171948js_/http://sami.samhuri.net/javascripts/typo.js" type="text/javascript"></script>
<script type="text/javascript"></script>
<link href="http://web.archive.org/web/20070316171948cs_/http://sami.samhuri.net/stylesheets/theme/island.css" media="all" rel="Stylesheet" type="text/css" />
<link href="http://web.archive.org/web/20070316171948cs_/http://sami.samhuri.net/stylesheets/user-styles.css" media="all" rel="Stylesheet" type="text/css" />
<link href="http://web.archive.org/web/20070316171948cs_/http://sami.samhuri.net/stylesheets/theme/print.css" media="print" rel="Stylesheet" type="text/css" />
</head>
<body>
<div id="content" class="clearfix">
<div id="main">
<!--
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<rdf:Description
rdf:about=""
trackback:ping="http://sami.samhuri.net/articles/trackback/1363"
dc:title="Full-screen Cover Flow"
dc:identifier="http://sami.samhuri.net/articles/read/1363"
dc:description="Cover Flow now comes in a full-screen flavour. It&amp;#8217;s pretty sweet, but unfortunately the remote controls iTunes exactly the same so you need a mouse to flick through the covers."
dc:creator="sjs"
dc:date="2007-03-06T13:56:43-08:00" />
</rdf:RDF>
-->
<div class="post" onmouseover="if (getCookie('is_admin') == 'yes') { Element.show('admin_article'); }" onmouseout="Element.hide('admin_article');" >
<a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/admin/content/edit/1363" class="admintools" id="admin_article" style="display: none">edit</a>
<h2>Full-screen Cover Flow</h2>
<p class="auth"><!-- Posted by <a href="mailto:sjs@uvic.ca">Sami Jensen Samhuri</a> -->
<span class="typo_date" title="Tue, 06 Mar 2007 21:51:00 GMT">Tue, 06 Mar 2007 21:51:00 GMT</span></p>
<p><a href="http://web.archive.org/web/20070316171948/http://www.apple.com/itunes/jukebox/coverflow.html">Cover Flow</a> now comes in a full-screen flavour. It&#8217;s pretty sweet, but unfortunately the remote controls iTunes exactly the same so you need a mouse to flick through the covers.</p>
<p>That made me wonder if Front Row used this full-screen Cover Flow view for albums now, but it doesn&#8217;t. I hope Apple gets on this and adds it to Front Row and the Apple TV. I&#8217;m sure it&#8217;s already on their list.</p>
<p>I would love to be able to flick through my albums with the remote right now, but I&#8217;m not going to install one of those 3rd-party remote config tools. Guess I have to wait for Apple to do it.</p>
</div>
<p class="meta">
Posted in <a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/apple" rel="tag">apple</a>&nbsp;<strong>|</strong>&nbsp;Tags <a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/tag/coverflow" rel="tag">coverflow</a>, <a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/tag/itunes" rel="tag">itunes</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/2007/03/06/full-screen-cover-flow#comments">no comments</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/2007/03/06/full-screen-cover-flow#trackbacks">no trackbacks</a>
</p>
<a name="comments"></a><h4 class="blueblk">Comments</h4>
<p class="postmetadata alt">
<small><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/2007/03/06/full-screen-cover-flow#respond">Leave a response</a></small>
</p>
<ol class="comment-list" id="commentList">
<li id="dummy_comment" style="display: none"></li>
</ol>
<a name="trackbacks"></a><h4 class="blueblk">Trackbacks</h4>
<p>
Use the following link to trackback from your own site:<br/>
<span class="light-bg">http://sami.samhuri.net/articles/trackback/1363</span>
</p>
<p class="postmetadata alt">
<small>
<a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/xml/rss20/article/1363/feed.xml" title="RSS Feed">RSS feed for this post</a>
<a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/trackback/1363" >trackback uri</a>
</small>
</p>
<form action="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/comment/1363" class="commentform" id="commentform" method="post" onsubmit="new Ajax.Updater({success:'commentList'}, '/articles/comment/1363', {asynchronous:true, evalScripts:true, insertion:Insertion.Bottom, onComplete:function(request){complete(request)}, onFailure:function(request){failure(request)}, onLoading:function(request){loading()}, parameters:Form.serialize(this)}); return false;">
<div class="comment-box">
<div id="errors"></div>
<div id="preview" style="display: none"></div>
<a name="respond"></a>
<table cellpadding="4" cellspacing="0" class="frm-tbl">
<tr>
<td><p><label for="comment_author">Your name</label></p></td>
<td> <input id="comment_author" name="comment[author]" size="20" type="text" /> <small><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/2007/03/06/full-screen-cover-flow#" onclick="Element.toggle('guest_url'); Element.toggle('guest_email'); return false;">(leave url/email &#187;)</a></small></td>
</tr>
<tr id="guest_url" style="display:none;">
<td><p><label for="comment_url">Your blog</label></p></td>
<td> <input id="comment_url" name="comment[url]" size="30" type="text" /></td>
</tr>
<tr id="guest_email" style="display:none;">
<td><p><label for="comment_email">Your email</label></p></td>
<td> <input id="comment_email" name="comment[email]" size="30" type="text" /></td>
</tr>
<tr>
<td><p><label for="comment_body">Your message</label></p></td>
<td valign="top" colspan="2">
<textarea cols="40" id="comment_body" name="comment[body]" rows="20"></textarea>
</td>
</tr>
<tr>
<td colspan="2" id="frm-btns">
<span id="comment_loading" style="display:none;"><img alt="Spinner" src="http://web.archive.org/web/20070316171948im_/http://sami.samhuri.net/images/spinner.gif" /></span>&nbsp;&nbsp;
<a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/2007/03/06/full-screen-cover-flow#" onclick="new Ajax.Updater('preview', '/articles/comment_preview', {asynchronous:true, evalScripts:true, parameters:Form.serialize('commentform'), onComplete:function(request){Element.show('preview')}}); return false;">Preview comment</a>
<input type="submit" name="submit" id="form-submit-button" value="submit" class="button" />
</td>
</tr>
</table>
</div>
</form>
<script type="text/javascript">
//<![CDATA[
show_dates_as_local_time()
//]]>
</script>
</div>
</div>
<div id="leftcolumn">
<div id="header">
<h1 id="sitename"><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/">sjs</a></h1>
<h2 id="subtitle">&nbsp;</h2>
</div>
<div id="sidebar">
<div id="search"><form action="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/search" id="sform" method="get">
<label for="q">Search: </label><input type="text" id="q" name="q" value="" size="15" />
<img alt="Spinner-blue" id="search_spinner" src="http://web.archive.org/web/20070316171948im_/http://sami.samhuri.net/images/spinner-blue.gif" style="display:none;" />
</form>
<script type="text/javascript">
//<![CDATA[
new Form.Element.Observer('q', 1, function(element, value) {new Ajax.Updater('search-results', '/live/search', {asynchronous:true, evalScripts:true, onComplete:function(request){Element.hide('search_spinner')}, onLoading:function(request){Element.show('search_spinner')}, parameters:'q=' + escape($F('q'))})})
//]]>
</script></div>
<div id="search-results"></div>
<div class="sidebar-node">
<h3>All about...</h3>
<ul>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/pages/about">a bit about me</a></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/pages/thunder">workstation</a></li>
</ul>
</div>
<div class="sidebar-node">
<h3>Categories</h3>
<ul id="categories">
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/amusement">amusement</a> <em>(5)</em></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/gentoo">gentoo</a> <em>(1)</em></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/hacking">coding</a> <em>(17)</em></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/life">life</a> <em>(5)</em></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/linux">linux</a> <em>(2)</em></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/mac-os-x">mac os x</a> <em>(7)</em></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/python">python</a> <em>(1)</em></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/rails">rails</a> <em>(12)</em></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/ruby">ruby</a> <em>(1)</em></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/technology">technology</a> <em>(5)</em></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/textmate">textmate</a> <em>(10)</em></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/apple">apple</a> <em>(8)</em></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/php">php</a> <em>(4)</em></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/windows">windows</a> <em>(1)</em></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/bootcamp">bootcamp</a> <em>(1)</em></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/parallels">parallels</a> <em>(1)</em></li>
<li><a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/category/firefox">firefox</a> <em>(1)</em></li>
</ul>
</div>
<div class="sidebar-node">
<h3>Archives</h3>
<ul id="archives">
<li>
<a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/2007/03">March 2007</a>
<em>(2)</em>
</li>
<li>
<a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/2006/12">December 2006</a>
<em>(1)</em>
</li>
<li>
<a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/2006/09">September 2006</a>
<em>(2)</em>
</li>
<li>
<a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/2006/08">August 2006</a>
<em>(1)</em>
</li>
<li>
<a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/2006/07">July 2006</a>
<em>(5)</em>
</li>
<li>
<a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/2006/06">June 2006</a>
<em>(4)</em>
</li>
<li>
<a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/2006/05">May 2006</a>
<em>(2)</em>
</li>
<li>
<a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/2006/04">April 2006</a>
<em>(1)</em>
</li>
<li>
<a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/2006/03">March 2006</a>
<em>(4)</em>
</li>
<li>
<a href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/articles/2006/02">February 2006</a>
<em>(1)</em>
</li>
</ul>
</div>
<div class="sidebar-node">
<h3>Links</h3>
<ul>
<li><a href="http://web.archive.org/web/20070316171948/http://phox.ca/cswiki/Main_Page">CSWiki</a></li>
<li><a href="http://web.archive.org/web/20070316171948/http://jim.roepcke.com/">Have Browser, Will Travel</a></li>
<li><a href="http://web.archive.org/web/20070316171948/http://blog.inquirylabs.com/">Going Up</a></li>
<li><a href="http://web.archive.org/web/20070316171948/http://www.mirage.org/">encieno</a></li>
<li><a href="http://web.archive.org/web/20070316171948/http://www.nofxwiki.net/">nofxwiki.net</a></li>
<li>sami at samhuri dot net</li>
</ul>
</div>
<div class="sidebar-node">
<ul>
<li><a class="feed" href="http://web.archive.org/web/20070316171948/http://sami.samhuri.net/xml/rss20/feed.xml" title="Articles feed"><img src="http://web.archive.org/web/20070316171948im_/http://sami.samhuri.net/files/feed-icon-48x48.png" alt="RSS 2.0" width="48" height="48" /></a></li>
<!--
-->
</ul>
</div>
<br clear="all" />
</div>
</div>
<div id="footer">
<ul>
<li><a href="http://web.archive.org/web/20070316171948/http://typo.leetsoft.com/">Typo</a></li>
<li>&bull;</li>
<li><a href="http://web.archive.org/web/20070316171948/http://validator.w3.org/check?uri=referer">Valid XHTML</a></li>
<li>&bull;</li>
<li><a href="http://web.archive.org/web/20070316171948/http://jigsaw.w3.org/css-validator/validator?uri=http://sami.samhuri.net/">Valid CSS</a></li>
</ul>
</div>
<script src="http://web.archive.org/web/20070316171948js_/http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-214054-3";
urchinTracker();
</script>
</body>
</html>
<!--
FILE ARCHIVED ON 17:19:48 Mar 16, 2007 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 2:54:23 Aug 21, 2011.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
-->

View file

@ -1,567 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- saved from url=(0081)http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/page/2 -->
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>sjs - samhuri.net</title>
<meta content="48.472,-123.3683" name="ICBM">
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/xml/rsd">
<link rel="alternate" type="application/rss+xml" title="RSS" href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/xml/rss20/feed.xml">
<link rel="alternate" type="application/atom+xml" title="Atom" href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/xml/atom10/feed.xml">
<script src="./Girlfriend X_files/cookies.js" type="text/javascript"></script>
<script src="./Girlfriend X_files/prototype.js" type="text/javascript"></script>
<script src="./Girlfriend X_files/effects.js" type="text/javascript"></script>
<script src="./Girlfriend X_files/typo.js" type="text/javascript"></script>
<script type="text/javascript"></script>
<link href="./Girlfriend X_files/island.css" media="all" rel="Stylesheet" type="text/css">
<link href="./Girlfriend X_files/user-styles.css" media="all" rel="Stylesheet" type="text/css">
<link href="./Girlfriend X_files/print.css" media="print" rel="Stylesheet" type="text/css">
<style type="text/css" style="display: none !important;">object:not([type]),object[classid$=":D27CDB6E-AE6D-11cf-96B8-444553540000"],object[classid$=":d27cdb6e-ae6d-11cf-96b8-444553540000"],object[codebase*="swflash.cab"],object[data*=".swf"],object[type="application/x-shockwave-flash"],object[src*=".swf"],object[codetype="application/x-shockwave-flash"],embed[type="application/x-shockwave-flash"],embed[src*=".swf"],embed[allowscriptaccess],embed[flashvars],embed[wmode],object[classid$=":166B1BCA-3F9C-11CF-8075-444553540000"],object[codebase*="sw.cab"],object[data*=".dcr"],object[type="application/x-director"],object[src*=".dcr"],embed[type="application/x-director"],embed[src*=".dcr"],object[classid$=":15B782AF-55D8-11D1-B477-006097098764"],object[codebase*="awswaxf.cab"],object[data*=".aam"],object[type="application/x-authorware-map"],object[src*=".aam"],embed[type="application/x-authorware-map"],embed[src*=".aam"],object[classid$="32C73088-76AE-40F7-AC40-81F62CB2C1DA"],object[type="application/ag-plugin"],object[type="application/x-silverlight"],object[type="application/x-silverlight-2"],object[source*=".xaml"],object[sourceelement*="xaml"],embed[type="application/ag-plugin"],embed[source*=".xaml"]{display: none !important;}</style></head>
<body><div id="wm-ipp" style="position: relative; padding-top: 0px; padding-right: 5px; padding-bottom: 0px; padding-left: 5px; min-height: 70px; min-width: 800px; z-index: 9000; display: block; ">
<div id="wm-ipp-inside" style="position:fixed;padding:0!important;margin:0!important;width:97%;min-width:780px;border:5px solid #000;border-top:none;background-image:url(http://staticweb.archive.org/images/toolbar/wm_tb_bk_trns.png);text-align:center;-moz-box-shadow:1px 1px 3px #333;-webkit-box-shadow:1px 1px 3px #333;box-shadow:1px 1px 3px #333;font-size:11px!important;font-family:&#39;Lucida Grande&#39;,&#39;Arial&#39;,sans-serif!important;">
<table style="border-collapse:collapse;margin:0;padding:0;width:100%;"><tbody><tr>
<td style="padding:10px;vertical-align:top;min-width:110px;">
<a href="http://wayback.archive.org/web/" title="Wayback Machine home page" style="background-color:transparent;border:none;"><img src="./Girlfriend X_files/wayback-toolbar-logo.png" alt="Wayback Machine" width="110" height="39" border="0"></a>
</td>
<td style="padding:0!important;text-align:center;vertical-align:top;width:100%;">
<table style="border-collapse:collapse;margin:0 auto;padding:0;width:570px;"><tbody><tr>
<td style="padding:3px 0;" colspan="2">
<form target="_top" method="get" action="http://wayback.archive.org/web/form-submit.jsp" name="wmtb" id="wmtb" style="margin:0!important;padding:0!important;"><input type="text" name="url" id="wmtbURL" value="http://sami.samhuri.net/articles/page/2" style="width:400px;font-size:11px;font-family:&#39;Lucida Grande&#39;,&#39;Arial&#39;,sans-serif;" onfocus="javascript:this.focus();this.select();"><input type="hidden" name="type" value="replay"><input type="hidden" name="date" value="20060614125209"><input type="submit" value="Go" style="font-size:11px;font-family:&#39;Lucida Grande&#39;,&#39;Arial&#39;,sans-serif;margin-left:5px;"><span id="wm_tb_options" style="display:block;"></span></form>
</td>
<td style="vertical-align:bottom;padding:5px 0 0 0!important;" rowspan="2">
<table style="border-collapse:collapse;width:110px;color:#99a;font-family:&#39;Helvetica&#39;,&#39;Lucida Grande&#39;,&#39;Arial&#39;,sans-serif;"><tbody>
<!-- NEXT/PREV MONTH NAV AND MONTH INDICATOR -->
<tr style="width:110px;height:16px;font-size:10px!important;">
<td style="padding-right:9px;font-size:11px!important;font-weight:bold;text-transform:uppercase;text-align:right;white-space:nowrap;overflow:visible;" nowrap="nowrap">
May
</td>
<td id="displayMonthEl" style="background:#000;color:#ff0;font-size:11px!important;font-weight:bold;text-transform:uppercase;width:34px;height:15px;padding-top:1px;text-align:center;" title="You are here: 12:52:09 Jun 14, 2006">JUN</td>
<td style="padding-left:9px;font-size:11px!important;font-weight:bold;text-transform:uppercase;white-space:nowrap;overflow:visible;" nowrap="nowrap">
<a href="http://web.archive.org/web/20060929193524/http://sami.samhuri.net/articles/page/2" style="text-decoration:none;color:#33f;font-weight:bold;background-color:transparent;border:none;" title="29 Sep 2006"><strong>SEP</strong></a>
</td>
</tr>
<!-- NEXT/PREV CAPTURE NAV AND DAY OF MONTH INDICATOR -->
<tr>
<td style="padding-right:9px;white-space:nowrap;overflow:visible;text-align:right!important;vertical-align:middle!important;" nowrap="nowrap">
<img src="./Girlfriend X_files/wm_tb_prv_off.png" alt="Previous capture" width="14" height="16" border="0">
</td>
<td id="displayDayEl" style="background:#000;color:#ff0;width:34px;height:24px;padding:2px 0 0 0;text-align:center;font-size:24px;font-weight: bold;" title="You are here: 12:52:09 Jun 14, 2006">14</td>
<td style="padding-left:9px;white-space:nowrap;overflow:visible;text-align:left!important;vertical-align:middle!important;" nowrap="nowrap">
<a href="http://web.archive.org/web/20060929193524/http://sami.samhuri.net/articles/page/2" title="19:35:24 Sep 29, 2006" style="background-color:transparent;border:none;"><img src="./Girlfriend X_files/wm_tb_nxt_on.png" alt="Next capture" width="14" height="16" border="0"></a>
</td>
</tr>
<!-- NEXT/PREV YEAR NAV AND YEAR INDICATOR -->
<tr style="width:110px;height:13px;font-size:9px!important;">
<td style="padding-right:9px;font-size:11px!important;font-weight: bold;text-align:right;white-space:nowrap;overflow:visible;" nowrap="nowrap">
2005
</td>
<td id="displayYearEl" style="background:#000;color:#ff0;font-size:11px!important;font-weight: bold;padding-top:1px;width:34px;height:13px;text-align:center;" title="You are here: 12:52:09 Jun 14, 2006">2006</td>
<td style="padding-left:9px;font-size:11px!important;font-weight: bold;white-space:nowrap;overflow:visible;" nowrap="nowrap">
<a href="http://web.archive.org/web/20071002172614/http://sami.samhuri.net/articles/page/2" style="text-decoration:none;color:#33f;font-weight:bold;background-color:transparent;border:none;" title="2 Oct 2007"><strong>2007</strong></a>
</td>
</tr>
</tbody></table>
</td>
</tr>
<tr>
<td style="vertical-align:middle;padding:0!important;">
<a href="http://wayback.archive.org/web/20060614125209*/http://sami.samhuri.net/articles/page/2" style="color:#33f;font-size:11px;font-weight:bold;background-color:transparent;border:none;" title="See a list of every capture for this URL"><strong>10 captures</strong></a>
<div style="margin:0!important;padding:0!important;color:#666;font-size:9px;padding-top:2px!important;white-space:nowrap;" title="Timespan for captures of this URL">14 Jun 06 - 9 Oct 07</div>
</td>
<td style="padding:0!important;">
<a style="position:relative; white-space:nowrap; width:400px;height:27px;" href="" id="wm-graph-anchor">
<div id="wm-ipp-sparkline" style="position:relative; white-space:nowrap; width:400px;height:27px;background-color:#fff;cursor:pointer;border-right:1px solid #ccc;" title="Explore captures for this URL">
<img id="sparklineImgId" style="position:absolute; z-index:9012; top:0px; left:0px;" onmouseover="showTrackers(&#39;inline&#39;);" onmouseout="showTrackers(&#39;none&#39;);" onmousemove="trackMouseMove(event,this)" alt="sparklines" width="400" height="27" border="0" src="./Girlfriend X_files/graph.jsp">
<img id="wbMouseTrackYearImg" style="display:none; position:absolute; z-index:9010;" width="25" height="27" border="0" src="./Girlfriend X_files/transp-yellow-pixel.png">
<img id="wbMouseTrackMonthImg" style="display:none; position:absolute; z-index:9011; " width="2" height="27" border="0" src="./Girlfriend X_files/transp-red-pixel.png">
</div>
</a>
</td>
</tr></tbody></table>
</td>
<td style="text-align:right;padding:5px;width:65px;font-size:11px!important;">
<a href="javascript:;" onclick="document.getElementById(&#39;wm-ipp&#39;).style.display=&#39;none&#39;;" style="display:block;padding-right:18px;background:url(http://staticweb.archive.org/images/toolbar/wm_tb_close.png) no-repeat 100% 0;color:#33f;font-family:&#39;Lucida Grande&#39;,&#39;Arial&#39;,sans-serif;margin-bottom:23px;background-color:transparent;border:none;" title="Close the toolbar">Close</a>
<a href="http://faq.web.archive.org/" style="display:block;padding-right:18px;background:url(http://staticweb.archive.org/images/toolbar/wm_tb_help.png) no-repeat 100% 0;color:#33f;font-family:&#39;Lucida Grande&#39;,&#39;Arial&#39;,sans-serif;background-color:transparent;border:none;" title="Get some help using the Wayback Machine">Help</a>
</td>
</tr></tbody></table>
</div>
</div>
<!-- BEGIN WAYBACK TOOLBAR INSERT -->
<script type="text/javascript" src="./Girlfriend X_files/disclaim-element.js"></script>
<script type="text/javascript" src="./Girlfriend X_files/graph-calc.js"></script>
<script type="text/javascript" src="./Girlfriend X_files/jquery.min.js"></script>
<script type="text/javascript">
//<![CDATA[
var firstDate = 820454400000;
var lastDate = 1325375999999;
var wbPrefix = "http://web.archive.org/web/";
var wbCurrentUrl = "http://sami.samhuri.net/articles/page/2";
var curYear = -1;
var curMonth = -1;
var yearCount = 16;
var firstYear = 1996;
var imgWidth=400;
var yearImgWidth = 25;
var monthImgWidth = 2;
var trackerVal = "none";
var displayDay = "14";
var displayMonth = "Jun";
var displayYear = "2006";
var prettyMonths = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
function showTrackers(val) {
if(val == trackerVal) {
return;
}
if(val == "inline") {
document.getElementById("displayYearEl").style.color = "#ec008c";
document.getElementById("displayMonthEl").style.color = "#ec008c";
document.getElementById("displayDayEl").style.color = "#ec008c";
} else {
document.getElementById("displayYearEl").innerHTML = displayYear;
document.getElementById("displayYearEl").style.color = "#ff0";
document.getElementById("displayMonthEl").innerHTML = displayMonth;
document.getElementById("displayMonthEl").style.color = "#ff0";
document.getElementById("displayDayEl").innerHTML = displayDay;
document.getElementById("displayDayEl").style.color = "#ff0";
}
document.getElementById("wbMouseTrackYearImg").style.display = val;
document.getElementById("wbMouseTrackMonthImg").style.display = val;
trackerVal = val;
}
function getElementX2(obj) {
var thing = jQuery(obj);
if((thing == undefined)
|| (typeof thing == "undefined")
|| (typeof thing.offset == "undefined")) {
return getElementX(obj);
}
return Math.round(thing.offset().left);
}
function trackMouseMove(event,element) {
var eventX = getEventX(event);
var elementX = getElementX2(element);
var xOff = eventX - elementX;
if(xOff < 0) {
xOff = 0;
} else if(xOff > imgWidth) {
xOff = imgWidth;
}
var monthOff = xOff % yearImgWidth;
var year = Math.floor(xOff / yearImgWidth);
var yearStart = year * yearImgWidth;
var monthOfYear = Math.floor(monthOff / monthImgWidth);
if(monthOfYear > 11) {
monthOfYear = 11;
}
// 1 extra border pixel at the left edge of the year:
var month = (year * 12) + monthOfYear;
var day = 1;
if(monthOff % 2 == 1) {
day = 15;
}
var dateString =
zeroPad(year + firstYear) +
zeroPad(monthOfYear+1,2) +
zeroPad(day,2) + "000000";
var monthString = prettyMonths[monthOfYear];
document.getElementById("displayYearEl").innerHTML = year + 1996;
document.getElementById("displayMonthEl").innerHTML = monthString;
// looks too jarring when it changes..
//document.getElementById("displayDayEl").innerHTML = zeroPad(day,2);
var url = wbPrefix + dateString + '/' + wbCurrentUrl;
document.getElementById('wm-graph-anchor').href = url;
//document.getElementById("wmtbURL").value="evX("+eventX+") elX("+elementX+") xO("+xOff+") y("+year+") m("+month+") monthOff("+monthOff+") DS("+dateString+") Moy("+monthOfYear+") ms("+monthString+")";
if(curYear != year) {
var yrOff = year * yearImgWidth;
document.getElementById("wbMouseTrackYearImg").style.left = yrOff + "px";
curYear = year;
}
if(curMonth != month) {
var mtOff = year + (month * monthImgWidth) + 1;
document.getElementById("wbMouseTrackMonthImg").style.left = mtOff + "px";
curMonth = month;
}
}
//]]>
</script>
<style type="text/css">body{margin-top:0!important;padding-top:0!important;min-width:800px!important;}#wm-ipp a:hover{text-decoration:underline!important;}</style>
<script type="text/javascript">
var wmDisclaimBanner = document.getElementById("wm-ipp");
if(wmDisclaimBanner != null) {
disclaimElement(wmDisclaimBanner);
}
</script>
<!-- END WAYBACK TOOLBAR INSERT -->
<div id="content" class="clearfix">
<div id="main">
<div class="post">
<h2><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/21/textmate-insert-text-into-self-down">TextMate: Insert text into self.down</a></h2>
<p class="auth"><!-- Posted by <a href="mailto:sjs@uvic.ca">Sami Jensen Samhuri</a> -->
<span class="typo_date" title="Tue, 21 Feb 2006 22:55:00 GMT">on Tuesday, February 21, 2006</span></p>
<p><em><strong><span class="caps">UPDATE</span>:</strong> I got everything working and its all packaged up <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/22/intelligent-migration-snippets-0_1">here</a>. Theres an installation script this time as well.</em></p>
<p>Thanks to <a href="http://web.archive.org/web/20060614125209/http://thread.gmane.org/gmane.editors.textmate.general/8520">a helpful thread</a> on the TextMate mailing list I have the beginning of a solution to insert text at 2 (or more) locations in a file.</p>
<p>I implemented this for a new snippet I was working on for migrations, <code>rename_column</code>. Since the command is the same in self.up and self.down simply doing a reverse search for <code>rename_column</code> in my <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/21/textmate-move-selection-to-self-down">hackish macro</a> didnt return the cursor the desired location.</p>
<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/21/textmate-insert-text-into-self-down">Read more...</a>
<p class="meta">Posted in <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/textmate" rel="tag">textmate</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/rails" rel="tag">rails</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/hacking" rel="tag">hacking</a>&nbsp;<strong>|</strong>&nbsp;Tags <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/commands" rel="tag">commands</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/macro" rel="tag">macro</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/rails" rel="tag">rails</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/snippets" rel="tag">snippets</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/textmate" rel="tag">textmate</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/21/textmate-insert-text-into-self-down#comments">no comments</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/21/textmate-insert-text-into-self-down#trackbacks">no trackbacks</a></p>
</div>
<div class="post">
<h2><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/21/textmate-move-selection-to-self-down">TextMate: Move selection to self.down</a></h2>
<p class="auth"><!-- Posted by <a href="mailto:sjs@uvic.ca">Sami Jensen Samhuri</a> -->
<span class="typo_date" title="Tue, 21 Feb 2006 08:26:00 GMT">on Tuesday, February 21, 2006</span></p>
<p><strong><span class="caps">UPDATE</span>:</strong> <em>This is obsolete, see <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/21/textmate-insert-text-into-self-down">this post</a> for a better solution.</em></p>
<p><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/18/textmate-snippets-for-rails-migrations#comment-17">Duanes comment</a> prompted me to think about how to get the <code>drop_table</code> and <code>remove_column</code> lines inserted in the right place. I dont think TextMates snippets are built to do this sort of text manipulation. It would be nicer, but a quick hack will suffice for now.</p>
<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/21/textmate-move-selection-to-self-down">Read more...</a>
<p class="meta">Posted in <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/textmate" rel="tag">textmate</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/rails" rel="tag">rails</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/hacking" rel="tag">hacking</a>&nbsp;<strong>|</strong>&nbsp;Tags <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/hack" rel="tag">hack</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/macro" rel="tag">macro</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/rails" rel="tag">rails</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/textmate" rel="tag">textmate</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/21/textmate-move-selection-to-self-down#comments">no comments</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/21/textmate-move-selection-to-self-down#trackbacks">no trackbacks</a></p>
</div>
<div class="post">
<h2><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/20/textmate-snippets-for-rails-assertions">TextMate Snippets for Rails Assertions</a></h2>
<p class="auth"><!-- Posted by <a href="mailto:sjs@uvic.ca">Sami Jensen Samhuri</a> -->
<span class="typo_date" title="Tue, 21 Feb 2006 07:52:00 GMT">on Monday, February 20, 2006</span></p>
<p>This time Ive got a few snippets for assertions. Using these to type up your tests quickly, and then hitting <strong>⌘R</strong> to run the tests without leaving TextMate, makes testing your Rails app that much more convenient. Just when you thought it was already too easy! (Dont forget that you can use <strong>⌥⌘↓</strong> to move between your code and the corresponding test case.)</p>
<p>This time Im posting the .plist files to make it easier for you to add them to TextMate. All you need to do is copy these to <strong>~/Library/Application Support/TextMate/Bundles/Rails.tmbundle/Snippets</strong>.</p>
<p style="text-align: center;;"><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/files/assert_snippets.zip">Assertion Snippets for Rails</a></p>
<p>If anyone would rather I list them all here I can do that as well. Just leave a comment.</p>
<p><em>(I wanted to include a droplet in the zip file that will copy the snippets to the right place, but my 3-hour attempt at writing the AppleScript to do so left me feeling quite bitter. Maybe I was just mistaken in thinking it would be easy to pick up AppleScript.)</em></p>
<p class="meta">Posted in <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/textmate" rel="tag">textmate</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/rails" rel="tag">rails</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/hacking" rel="tag">hacking</a>&nbsp;<strong>|</strong>&nbsp;Tags <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/rails" rel="tag">rails</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/snippets" rel="tag">snippets</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/testing" rel="tag">testing</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/textmate" rel="tag">textmate</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/20/textmate-snippets-for-rails-assertions#comments">no comments</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/20/textmate-snippets-for-rails-assertions#trackbacks">no trackbacks</a></p>
</div>
<div class="post">
<h2><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/20/now-these-are-desks">Now these are desks!</a></h2>
<p class="auth"><!-- Posted by <a href="mailto:sjs@uvic.ca">Sami Jensen Samhuri</a> -->
<span class="typo_date" title="Mon, 20 Feb 2006 13:46:00 GMT">on Monday, February 20, 2006</span></p>
<p>I will take one of <a href="http://web.archive.org/web/20060614125209/http://www.poetictech.com/">these desks</a> any day! I particularly like the “epic”. But you know when you have to contact them to hear the price thats bad, bad news. Ah well, add it to the list of things to get once I have money.</p>
<p class="meta">Posted in <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/life" rel="tag">life</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/hacking" rel="tag">hacking</a>&nbsp;<strong>|</strong>&nbsp;Tags <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/cool" rel="tag">cool</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/hacking" rel="tag">hacking</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/20/now-these-are-desks#comments">no comments</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/20/now-these-are-desks#trackbacks">no trackbacks</a></p>
</div>
<div class="post">
<h2><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/20/obligatory-post-about-ruby-on-rails">Obligatory Post about Ruby on Rails</a></h2>
<p class="auth"><!-- Posted by <a href="mailto:sjs@uvic.ca">Sami Jensen Samhuri</a> -->
<span class="typo_date" title="Mon, 20 Feb 2006 08:31:00 GMT">on Monday, February 20, 2006</span></p>
<p><em>Im a Rails newbie and eager to learn. I welcome any suggestions or criticism you have. You can direct them to <a href="mailto:sjs@uvic.ca">my inbox</a> or leave me a comment below.</em></p>
<p>I finally set myself up with a blog. I mailed my dad the address and mentioned that it was running <a href="http://web.archive.org/web/20060614125209/http://www.typosphere.org/">Typo</a>, which is written in <a href="http://web.archive.org/web/20060614125209/http://www.rubyonrails.com/">Ruby on Rails</a>. The fact that it is written in Rails was a big factor in my decision. I am currently reading <a href="http://web.archive.org/web/20060614125209/http://www.pragmaticprogrammer.com/titles/rails/">Agile Web Development With Rails</a> and it will be great to use Typo as a learning tool, since I will be modifying my blog anyways regardless of what language its written in.</p>
<p>Clearly Rails made an impression on me somehow or I wouldnt be investing this time on it. But my dad asked me a very good question:</p>
<blockquote>
<p style="border-left: 3px solid #fff; padding-left: 5px;;">Rails? What is so special about it? I looked at your page and it looks pretty normal to me. I miss the point of this new Rails technique for web development.</p>
</blockquote>
<p>Its unlikely that he was surprised at my lengthy response, but I was. I have been known to write him long messages on topics that interest me. However, Ive only been learning Rails for two weeks or so. Could I possibly have so much to say about it already? Apparently I do.</p>
<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/20/obligatory-post-about-ruby-on-rails">Read more...</a>
<p class="meta">Posted in <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/rails" rel="tag">rails</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/hacking" rel="tag">hacking</a>&nbsp;<strong>|</strong>&nbsp;Tags <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/hacking" rel="tag">hacking</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/migration" rel="tag">migration</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/rails" rel="tag">rails</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/testing" rel="tag">testing</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/20/obligatory-post-about-ruby-on-rails#comments">2 comments</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/20/obligatory-post-about-ruby-on-rails#trackbacks">no trackbacks</a></p>
</div>
<div class="post">
<h2><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/19/virtue">Virtue</a></h2>
<p class="auth"><!-- Posted by <a href="mailto:sjs@uvic.ca">Sami Jensen Samhuri</a> -->
<span class="typo_date" title="Mon, 20 Feb 2006 02:20:00 GMT">on Sunday, February 19, 2006</span></p>
<p>Man am I glad I saw <a href="http://web.archive.org/web/20060614125209/http://blog.inquirylabs.com/2006/01/20/virtue-for-tiger/trackback/">Duanes post</a> about <a href="http://web.archive.org/web/20060614125209/http://tonyarnold.com/articles/2006/02/05/virtue-0-51r76-test-release">Virtue</a>. Its a virtual desktop manager for Mac <span class="caps">OS X</span> Tiger. <a href="http://web.archive.org/web/20060614125209/http://desktopmanager.berlios.de/">Desktop Manager</a> almost had it, but it didnt quite feel right to me. This app is exactly what Ive been looking for in virtual desktops. It has bugs, but it mostly works.</p>
<p>My gentoo box has some <strong>serious</strong> competition now. Recently I feel like I spend more time developing on my Mac mini than my dual Opteron. I didnt expect that 5 months ago when I got the mini as my first Mac!</p>
<p class="meta">Posted in <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/gentoo" rel="tag">gentoo</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/mac-os-x" rel="tag">mac os x</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/hacking" rel="tag">hacking</a>&nbsp;<strong>|</strong>&nbsp;Tags <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/macosx" rel="tag">macosx</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/19/virtue#comments">2 comments</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/19/virtue#trackbacks">no trackbacks</a></p>
</div>
<div class="post">
<h2><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/19/syncpeople-on-rails-bundle-for-textmate">syncPeople on Rails Bundle for TextMate</a></h2>
<p class="auth"><!-- Posted by <a href="mailto:sjs@uvic.ca">Sami Jensen Samhuri</a> -->
<span class="typo_date" title="Sun, 19 Feb 2006 08:04:00 GMT">on Sunday, February 19, 2006</span></p>
<p>Its too fast I just cant keep up! :) Duane has posted a <a href="http://web.archive.org/web/20060614125209/http://blog.inquirylabs.com/2006/02/18/syncpeople-on-rails-06/trackback/">bundle</a> with even more than go to view/controller. Now it has:</p>
<ol>
<li>Open Controller / View — option-command-up</li>
<li>Create Partial from Selection — option-command-p</li>
<li>Intelligent Go To File — keypad enter key</li>
</ol>
<p>Id love to see a central place for rails bundle development. Well see what happens.</p>
<p class="meta">Posted in <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/textmate" rel="tag">textmate</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/rails" rel="tag">rails</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/amusement" rel="tag">amusement</a>&nbsp;<strong>|</strong>&nbsp;Tags <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/rails" rel="tag">rails</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/textmate" rel="tag">textmate</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/19/syncpeople-on-rails-bundle-for-textmate#comments">no comments</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/19/syncpeople-on-rails-bundle-for-textmate#trackbacks">no trackbacks</a></p>
</div>
<div class="post">
<h2><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/18/textmate-snippets-for-rails-migrations">Some TextMate snippets for Rails Migrations</a></h2>
<p class="auth"><!-- Posted by <a href="mailto:sjs@uvic.ca">Sami Jensen Samhuri</a> -->
<span class="typo_date" title="Sun, 19 Feb 2006 06:48:00 GMT">on Saturday, February 18, 2006</span></p>
<p>My arsenal of snippets and macros in TextMate is building as I read through the rails canon, <a href="http://web.archive.org/web/20060614125209/http://www.pragmaticprogrammer.com/titles/rails/" title="Agile Web Development With Rails">Agile Web Development…</a> Im only 150 pages in so I havent had to add much so far because I started with the bundle found on the <a href="http://web.archive.org/web/20060614125209/http://wiki.rubyonrails.org/rails/pages/TextMate">rails wiki</a>. The main ones so far are for migrations.</p>
<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/18/textmate-snippets-for-rails-migrations">Read more...</a>
<p class="meta">Posted in <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/textmate" rel="tag">textmate</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/rails" rel="tag">rails</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/hacking" rel="tag">hacking</a>&nbsp;<strong>|</strong>&nbsp;Tags <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/rails" rel="tag">rails</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/snippets" rel="tag">snippets</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/textmate" rel="tag">textmate</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/18/textmate-snippets-for-rails-migrations#comments">6 comments</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/18/textmate-snippets-for-rails-migrations#trackbacks">no trackbacks</a></p>
</div>
<div class="post">
<h2><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/18/girlfriend-x">Girlfriend X</a></h2>
<p class="auth"><!-- Posted by <a href="mailto:sjs@uvic.ca">Sami Jensen Samhuri</a> -->
<span class="typo_date" title="Sun, 19 Feb 2006 03:50:00 GMT">on Saturday, February 18, 2006</span></p>
<p>This is hilarious! Someone wrote software that manages a “parallel” dating style.</p>
<blockquote>
<p>In addition to storing each womans contact information and picture, the Girlfriend profiles include a Score Card where you track her sexual preferences, her menstrual cycles and how she styles her pubic hair.</p>
</blockquote>
<p>Its called <a href="http://web.archive.org/web/20060614125209/http://www.wired.com/news/columns/0,70231-0.html?tw=rss.index">Girlfriend X</a>, but thats a link to an article about it. I didnt go to the actual website. I just thing its amusing someone went through the trouble to do this. Maybe theres a demand for it. * shrug *</p>
<p class="meta">Posted in <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/amusement" rel="tag">amusement</a>&nbsp;<strong>|</strong>&nbsp;Tags <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/crazy" rel="tag">crazy</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/funny" rel="tag">funny</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/18/girlfriend-x#comments">no comments</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/18/girlfriend-x#trackbacks">no trackbacks</a></p>
</div>
<div class="post">
<h2><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/18/jump-to-view-controller-in-textmate">Jump to view/controller in TextMate</a></h2>
<p class="auth"><!-- Posted by <a href="mailto:sjs@uvic.ca">Sami Jensen Samhuri</a> -->
<span class="typo_date" title="Sat, 18 Feb 2006 22:51:00 GMT">on Saturday, February 18, 2006</span></p>
<p><a href="http://web.archive.org/web/20060614125209/http://blog.inquirylabs.com/2006/02/17/controller-to-view-and-back-again-in-textmate/trackback/">Duane</a> came up with a way to jump to the controller method for the view youre editing, or vice versa in TextMate while coding using Rails. This is a huge time-saver, thanks!</p>
<p class="meta">Posted in <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/hacking" rel="tag">hacking</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/rails" rel="tag">rails</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/textmate" rel="tag">textmate</a>&nbsp;<strong>|</strong>&nbsp;Tags <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/rails" rel="tag">rails</a>, <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/tag/textmate" rel="tag">textmate</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/18/jump-to-view-controller-in-textmate#comments">no comments</a>&nbsp;<strong>|</strong>&nbsp;<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02/18/jump-to-view-controller-in-textmate#trackbacks">no trackbacks</a></p>
</div>
<p id="pagination">Older posts: <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/page/1">1</a> 2 <a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/page/3">3</a> </p>
<script type="text/javascript">
//<![CDATA[
show_dates_as_local_time()
//]]>
</script>
</div>
</div>
<div id="leftcolumn">
<div id="header">
<h1 id="sitename"><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/">sjs</a></h1>
<h2 id="subtitle">&nbsp;</h2>
</div>
<div id="sidebar">
<div id="search"><form action="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/search" id="sform" method="get">
<label for="q">Search: </label><input type="text" id="q" name="q" value="" size="15">
<img alt="Spinner-blue" id="search_spinner" src="./Girlfriend X_files/spinner-blue.gif" style="display:none;">
</form>
<script type="text/javascript">
//<![CDATA[
new Form.Element.Observer('q', 1, function(element, value) {new Ajax.Updater('search-results', '/live/search', {asynchronous:true, evalScripts:true, onComplete:function(request){Element.hide('search_spinner')}, onLoading:function(request){Element.show('search_spinner')}, parameters:'q=' + escape($F('q'))})})
//]]>
</script></div>
<div id="search-results"></div>
<div class="sidebar-node">
<h3>All about...</h3>
<ul>
<li><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/pages/about">me in 3 paragraphs</a></li>
<li><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/pages/how-i-became-a-geek">geek background</a></li>
<li><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/pages/thunder">workstation</a></li>
</ul>
</div>
<div class="sidebar-node">
<h3>Categories</h3>
<ul id="categories">
<li><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/amusement">amusement</a> <em>(4)</em></li>
<li><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/gentoo">gentoo</a> <em>(1)</em></li>
<li><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/hacking">hacking</a> <em>(12)</em></li>
<li><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/life">life</a> <em>(4)</em></li>
<li><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/linux">linux</a> <em>(1)</em></li>
<li><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/mac-os-x">mac os x</a> <em>(5)</em></li>
<li><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/python">python</a> <em>(1)</em></li>
<li><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/rails">rails</a> <em>(11)</em></li>
<li><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/technology">technology</a> <em>(2)</em></li>
<li><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/textmate">textmate</a> <em>(10)</em></li>
<li><a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/category/apple">apple</a> <em>(3)</em></li>
</ul>
</div>
<div class="sidebar-node">
<h3>Archives</h3>
<ul id="archives">
<li>
<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/06">June 2006</a>
<em>(1)</em>
</li>
<li>
<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/05">May 2006</a>
<em>(2)</em>
</li>
<li>
<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/04">April 2006</a>
<em>(1)</em>
</li>
<li>
<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/03">March 2006</a>
<em>(4)</em>
</li>
<li>
<a href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/articles/2006/02">February 2006</a>
<em>(15)</em>
</li>
</ul>
</div>
<div class="sidebar-node">
<h3>Links</h3>
<ul>
<li><a href="http://web.archive.org/web/20060614125209/http://phox.ca/cswiki/Main_Page">CSWiki</a></li>
<li><a href="http://web.archive.org/web/20060614125209/http://jim.roepcke.com/">Have Browser, Will Travel</a></li>
<li><a href="http://web.archive.org/web/20060614125209/http://blog.inquirylabs.com/">Going Up</a></li>
<li><a href="http://web.archive.org/web/20060614125209/http://www.mirage.org/">encieno</a></li>
<li><a href="http://web.archive.org/web/20060614125209/http://www.nofxwiki.net/">nofxwiki.net</a></li>
</ul>
</div>
<div class="sidebar-node">
<p></p><ul>
<li><a class="feed" href="http://web.archive.org/web/20060614125209/http://sami.samhuri.net/xml/rss20/feed.xml" title="Articles feed"><img src="./Girlfriend X_files/feed-icon-48x48.png" alt="RSS 2.0" width="48" height="48"></a></li>
<!--
-->
</ul><p></p>
</div>
<br clear="all">
</div>
</div>
<div id="footer">
<ul>
<li><a href="http://web.archive.org/web/20060614125209/http://typo.leetsoft.com/">Typo</a></li>
<li></li>
<li><a href="http://web.archive.org/web/20060614125209/http://validator.w3.org/check?uri=referer">Valid XHTML</a></li>
<li></li>
<li><a href="http://web.archive.org/web/20060614125209/http://jigsaw.w3.org/css-validator/validator?uri=http://sami.samhuri.net/">Valid CSS</a></li>
</ul>
</div>
<script src="./Girlfriend X_files/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-214054-3";
urchinTracker();
</script>
<!--
FILE ARCHIVED ON 12:52:09 Jun 14, 2006 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 2:38:56 Aug 21, 2011.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
-->
<div id="footnotify_lightbox" style="position: fixed; width: 100%; height: 100%; top: 0px; left: 0px; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgba(0, 0, 0, 0.699219); display: none; background-position: initial initial; background-repeat: initial initial; "></div><div id="footnotify_holder" style="position: absolute; display: none; "><div id="footnotify_arrow" style="letter-spacing: -1px; width: 32px; margin-top: 0px; margin-right: -11px; margin-bottom: 0px; margin-left: -11px; text-align: center; font-size: 13px; padding-top: 2em; line-height: 0.9em; color: rgb(0, 0, 0); ">◢◣</div><div id="footnotify_panel" style="padding-top: 1px; padding-right: 1px; padding-bottom: 1px; padding-left: 1px; margin-top: 0px; margin-right: -240px; margin-bottom: 0px; margin-left: -240px; width: 480px; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(0, 0, 0); color: inherit; background-position: initial initial; background-repeat: initial initial; "><div id="footnotify_content" style="margin-top: 2em; margin-right: 2em; margin-bottom: 2em; margin-left: 2em; "></div></div></div><div id="footnotify_notification" style="position: fixed; top: 5px; left: 5px; z-index: 999; padding-top: 1em; padding-right: 1em; padding-bottom: 1em; padding-left: 1em; color: rgb(255, 255, 255); background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgba(0, 0, 0, 0.699219); display: none; background-position: initial initial; background-repeat: initial initial; "></div></body></html>

View file

@ -1,638 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>sjs: Back on Gentoo, trying new things</title>
<link rel="openid.server" href="http://web.archive.org/web/20071109170829/http://www.myopenid.com/server" />
<link rel="openid.delegate" href="http://web.archive.org/web/20071109170829/http://sami-samhuri.myopenid.com/" />
<meta http-equiv="X-XRDS-Location" content="http://sami-samhuri.myopenid.com/xrds" />
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="http://web.archive.org/web/20071109170829/http://feeds.feedburner.com/sjs" />
<script src="http://web.archive.org/web/20071109170829js_/http://sami.samhuri.net/javascripts/prototype.js" type="text/javascript"></script>
<link href="http://web.archive.org/web/20071109170829cs_/http://sami.samhuri.net/stylesheets/application.css" rel="stylesheet" type="text/css" />
</head>
<body>
<!-- BEGIN WAYBACK TOOLBAR INSERT -->
<script type="text/javascript" src="http://staticweb.archive.org/js/disclaim-element.js" ></script>
<script type="text/javascript" src="http://staticweb.archive.org/js/graph-calc.js" ></script>
<script type="text/javascript" src="http://staticweb.archive.org/jflot/jquery.min.js" ></script>
<script type="text/javascript">
//<![CDATA[
var firstDate = 820454400000;
var lastDate = 1325375999999;
var wbPrefix = "http://web.archive.org/web/";
var wbCurrentUrl = "http://sami.samhuri.net/2007/6/19/back-on-gentoo-trying-new-things";
var curYear = -1;
var curMonth = -1;
var yearCount = 16;
var firstYear = 1996;
var imgWidth=400;
var yearImgWidth = 25;
var monthImgWidth = 2;
var trackerVal = "none";
var displayDay = "9";
var displayMonth = "Nov";
var displayYear = "2007";
var prettyMonths = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
function showTrackers(val) {
if(val == trackerVal) {
return;
}
if(val == "inline") {
document.getElementById("displayYearEl").style.color = "#ec008c";
document.getElementById("displayMonthEl").style.color = "#ec008c";
document.getElementById("displayDayEl").style.color = "#ec008c";
} else {
document.getElementById("displayYearEl").innerHTML = displayYear;
document.getElementById("displayYearEl").style.color = "#ff0";
document.getElementById("displayMonthEl").innerHTML = displayMonth;
document.getElementById("displayMonthEl").style.color = "#ff0";
document.getElementById("displayDayEl").innerHTML = displayDay;
document.getElementById("displayDayEl").style.color = "#ff0";
}
document.getElementById("wbMouseTrackYearImg").style.display = val;
document.getElementById("wbMouseTrackMonthImg").style.display = val;
trackerVal = val;
}
function getElementX2(obj) {
var thing = jQuery(obj);
if((thing == undefined)
|| (typeof thing == "undefined")
|| (typeof thing.offset == "undefined")) {
return getElementX(obj);
}
return Math.round(thing.offset().left);
}
function trackMouseMove(event,element) {
var eventX = getEventX(event);
var elementX = getElementX2(element);
var xOff = eventX - elementX;
if(xOff < 0) {
xOff = 0;
} else if(xOff > imgWidth) {
xOff = imgWidth;
}
var monthOff = xOff % yearImgWidth;
var year = Math.floor(xOff / yearImgWidth);
var yearStart = year * yearImgWidth;
var monthOfYear = Math.floor(monthOff / monthImgWidth);
if(monthOfYear > 11) {
monthOfYear = 11;
}
// 1 extra border pixel at the left edge of the year:
var month = (year * 12) + monthOfYear;
var day = 1;
if(monthOff % 2 == 1) {
day = 15;
}
var dateString =
zeroPad(year + firstYear) +
zeroPad(monthOfYear+1,2) +
zeroPad(day,2) + "000000";
var monthString = prettyMonths[monthOfYear];
document.getElementById("displayYearEl").innerHTML = year + 1996;
document.getElementById("displayMonthEl").innerHTML = monthString;
// looks too jarring when it changes..
//document.getElementById("displayDayEl").innerHTML = zeroPad(day,2);
var url = wbPrefix + dateString + '/' + wbCurrentUrl;
document.getElementById('wm-graph-anchor').href = url;
//document.getElementById("wmtbURL").value="evX("+eventX+") elX("+elementX+") xO("+xOff+") y("+year+") m("+month+") monthOff("+monthOff+") DS("+dateString+") Moy("+monthOfYear+") ms("+monthString+")";
if(curYear != year) {
var yrOff = year * yearImgWidth;
document.getElementById("wbMouseTrackYearImg").style.left = yrOff + "px";
curYear = year;
}
if(curMonth != month) {
var mtOff = year + (month * monthImgWidth) + 1;
document.getElementById("wbMouseTrackMonthImg").style.left = mtOff + "px";
curMonth = month;
}
}
//]]>
</script>
<style type="text/css">body{margin-top:0!important;padding-top:0!important;min-width:800px!important;}#wm-ipp a:hover{text-decoration:underline!important;}</style>
<div id="wm-ipp" style="display:none; position:relative;padding:0 5px;min-height:70px;min-width:800px; z-index:9000;">
<div id="wm-ipp-inside" style="position:fixed;padding:0!important;margin:0!important;width:97%;min-width:780px;border:5px solid #000;border-top:none;background-image:url(http://staticweb.archive.org/images/toolbar/wm_tb_bk_trns.png);text-align:center;-moz-box-shadow:1px 1px 3px #333;-webkit-box-shadow:1px 1px 3px #333;box-shadow:1px 1px 3px #333;font-size:11px!important;font-family:'Lucida Grande','Arial',sans-serif!important;">
<table style="border-collapse:collapse;margin:0;padding:0;width:100%;"><tbody><tr>
<td style="padding:10px;vertical-align:top;min-width:110px;">
<a href="http://wayback.archive.org/web/" title="Wayback Machine home page" style="background-color:transparent;border:none;"><img src="http://staticweb.archive.org/images/toolbar/wayback-toolbar-logo.png" alt="Wayback Machine" width="110" height="39" border="0"/></a>
</td>
<td style="padding:0!important;text-align:center;vertical-align:top;width:100%;">
<table style="border-collapse:collapse;margin:0 auto;padding:0;width:570px;"><tbody><tr>
<td style="padding:3px 0;" colspan="2">
<form target="_top" method="get" action="http://wayback.archive.org/web/form-submit.jsp" name="wmtb" id="wmtb" style="margin:0!important;padding:0!important;"><input type="text" name="url" id="wmtbURL" value="http://sami.samhuri.net/2007/6/19/back-on-gentoo-trying-new-things" style="width:400px;font-size:11px;font-family:'Lucida Grande','Arial',sans-serif;" onfocus="javascript:this.focus();this.select();" /><input type="hidden" name="type" value="replay" /><input type="hidden" name="date" value="20071109170829" /><input type="submit" value="Go" style="font-size:11px;font-family:'Lucida Grande','Arial',sans-serif;margin-left:5px;" /><span id="wm_tb_options" style="display:block;"></span></form>
</td>
<td style="vertical-align:bottom;padding:5px 0 0 0!important;" rowspan="2">
<table style="border-collapse:collapse;width:110px;color:#99a;font-family:'Helvetica','Lucida Grande','Arial',sans-serif;"><tbody>
<!-- NEXT/PREV MONTH NAV AND MONTH INDICATOR -->
<tr style="width:110px;height:16px;font-size:10px!important;">
<td style="padding-right:9px;font-size:11px!important;font-weight:bold;text-transform:uppercase;text-align:right;white-space:nowrap;overflow:visible;" nowrap="nowrap">
Oct
</td>
<td id="displayMonthEl" style="background:#000;color:#ff0;font-size:11px!important;font-weight:bold;text-transform:uppercase;width:34px;height:15px;padding-top:1px;text-align:center;" title="You are here: 17:08:29 Nov 9, 2007">NOV</td>
<td style="padding-left:9px;font-size:11px!important;font-weight:bold;text-transform:uppercase;white-space:nowrap;overflow:visible;" nowrap="nowrap">
<a href="http://web.archive.org/web/20080820114936/http://sami.samhuri.net/2007/6/19/back-on-gentoo-trying-new-things" style="text-decoration:none;color:#33f;font-weight:bold;background-color:transparent;border:none;" title="20 Aug 2008"><strong>AUG</strong></a>
</td>
</tr>
<!-- NEXT/PREV CAPTURE NAV AND DAY OF MONTH INDICATOR -->
<tr>
<td style="padding-right:9px;white-space:nowrap;overflow:visible;text-align:right!important;vertical-align:middle!important;" nowrap="nowrap">
<img src="http://staticweb.archive.org/images/toolbar/wm_tb_prv_off.png" alt="Previous capture" width="14" height="16" border="0" />
</td>
<td id="displayDayEl" style="background:#000;color:#ff0;width:34px;height:24px;padding:2px 0 0 0;text-align:center;font-size:24px;font-weight: bold;" title="You are here: 17:08:29 Nov 9, 2007">9</td>
<td style="padding-left:9px;white-space:nowrap;overflow:visible;text-align:left!important;vertical-align:middle!important;" nowrap="nowrap">
<a href="http://web.archive.org/web/20080820114936/http://sami.samhuri.net/2007/6/19/back-on-gentoo-trying-new-things" title="11:49:36 Aug 20, 2008" style="background-color:transparent;border:none;"><img src="http://staticweb.archive.org/images/toolbar/wm_tb_nxt_on.png" alt="Next capture" width="14" height="16" border="0"/></a>
</td>
</tr>
<!-- NEXT/PREV YEAR NAV AND YEAR INDICATOR -->
<tr style="width:110px;height:13px;font-size:9px!important;">
<td style="padding-right:9px;font-size:11px!important;font-weight: bold;text-align:right;white-space:nowrap;overflow:visible;" nowrap="nowrap">
2006
</td>
<td id="displayYearEl" style="background:#000;color:#ff0;font-size:11px!important;font-weight: bold;padding-top:1px;width:34px;height:13px;text-align:center;" title="You are here: 17:08:29 Nov 9, 2007">2007</td>
<td style="padding-left:9px;font-size:11px!important;font-weight: bold;white-space:nowrap;overflow:visible;" nowrap="nowrap">
<a href="http://web.archive.org/web/20090213214100/http://sami.samhuri.net/2007/6/19/back-on-gentoo-trying-new-things" style="text-decoration:none;color:#33f;font-weight:bold;background-color:transparent;border:none;" title="13 Feb 2009"><strong>2009</strong></a>
</td>
</tr>
</tbody></table>
</td>
</tr>
<tr>
<td style="vertical-align:middle;padding:0!important;">
<a href="http://wayback.archive.org/web/20071109170829*/http://sami.samhuri.net/2007/6/19/back-on-gentoo-trying-new-things" style="color:#33f;font-size:11px;font-weight:bold;background-color:transparent;border:none;" title="See a list of every capture for this URL"><strong>3 captures</strong></a>
<div style="margin:0!important;padding:0!important;color:#666;font-size:9px;padding-top:2px!important;white-space:nowrap;" title="Timespan for captures of this URL">9 Nov 07 - 13 Feb 09</div>
</td>
<td style="padding:0!important;">
<a style="position:relative; white-space:nowrap; width:400px;height:27px;" href="" id="wm-graph-anchor">
<div id="wm-ipp-sparkline" style="position:relative; white-space:nowrap; width:400px;height:27px;background-color:#fff;cursor:pointer;border-right:1px solid #ccc;" title="Explore captures for this URL">
<img id="sparklineImgId" style="position:absolute; z-index:9012; top:0px; left:0px;"
onmouseover="showTrackers('inline');"
onmouseout="showTrackers('none');"
onmousemove="trackMouseMove(event,this)"
alt="sparklines"
width="400"
height="27"
border="0"
src="http://wayback.archive.org/jsp/graph.jsp?graphdata=400_27_1996:-1:000000000000_1997:-1:000000000000_1998:-1:000000000000_1999:-1:000000000000_2000:-1:000000000000_2001:-1:000000000000_2002:-1:000000000000_2003:-1:000000000000_2004:-1:000000000000_2005:-1:000000000000_2006:-1:000000000000_2007:10:000000000010_2008:-1:000000010000_2009:-1:010000000000_2010:-1:000000000000_2011:-1:000000000000"></img>
<img id="wbMouseTrackYearImg"
style="display:none; position:absolute; z-index:9010;"
width="25"
height="27"
border="0"
src="http://staticweb.archive.org/images/toolbar/transp-yellow-pixel.png"></img>
<img id="wbMouseTrackMonthImg"
style="display:none; position:absolute; z-index:9011; "
width="2"
height="27"
border="0"
src="http://staticweb.archive.org/images/toolbar/transp-red-pixel.png"></img>
</div>
</a>
</td>
</tr></tbody></table>
</td>
<td style="text-align:right;padding:5px;width:65px;font-size:11px!important;">
<a href="javascript:;" onclick="document.getElementById('wm-ipp').style.display='none';" style="display:block;padding-right:18px;background:url(http://staticweb.archive.org/images/toolbar/wm_tb_close.png) no-repeat 100% 0;color:#33f;font-family:'Lucida Grande','Arial',sans-serif;margin-bottom:23px;background-color:transparent;border:none;" title="Close the toolbar">Close</a>
<a href="http://faq.web.archive.org/" style="display:block;padding-right:18px;background:url(http://staticweb.archive.org/images/toolbar/wm_tb_help.png) no-repeat 100% 0;color:#33f;font-family:'Lucida Grande','Arial',sans-serif;background-color:transparent;border:none;" title="Get some help using the Wayback Machine">Help</a>
</td>
</tr></tbody></table>
</div>
</div>
<script type="text/javascript">
var wmDisclaimBanner = document.getElementById("wm-ipp");
if(wmDisclaimBanner != null) {
disclaimElement(wmDisclaimBanner);
}
</script>
<!-- END WAYBACK TOOLBAR INSERT -->
<div id="container">
<div id="header">
<h1><span><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/">sjs</a></span></h1>
<h2>geeky ramblings</h2>
</div>
<div id="page">
<div id="content">
<!--
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<rdf:Description
rdf:about=""
trackback:ping=""
dc:title="Back on Gentoo, trying new things"
dc:identifier="/2007/6/19/back-on-gentoo-trying-new-things"
dc:description="<p>I started using my Gentoo box for development again and there are a few things about Linux I didn&#8217;t realize I had been missing.</p>
<h3>Shell completion is awesome out of the box</h3>
<p>zsh has an impressive completion system but I..."
dc:creator="sjs"
dc:date="June 19, 2007 01:05" />
</rdf:RDF>
-->
<div class="hentry" id="article-79">
<h2 class="entry-title">
<a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/2007/6/19/back-on-gentoo-trying-new-things">Back on Gentoo, trying new things</a>
<span class="comment_count">0</span>
</h2>
<div class="vcard">
Posted by <span class="fn">sjs</span>
</div>
<abbr class="published" title="2007-06-19T01:05:00+00:00">on Tuesday, June 19</abbr>
<br class="clear" />
<div class="entry-content">
<p>I started using my Gentoo box for development again and there are a few things about Linux I didn&#8217;t realize I had been missing.</p>
<h3>Shell completion is awesome out of the box</h3>
<p>zsh has an impressive completion system but I just don&#8217;t feel the urge to ever customize it extensively. I just use the basic completion stuff on <span class="caps">OS X</span> because it&#8217;s easy. On Gentoo I have rake tasks and all sorts of other crap completed for me by including a few lines in my .zshrc (iirc a script does this automatically anyway). Generally Linux distros try to knit everything together nicely so you never even think about things like whether or not a package will have readline support, and default configs will be tweaked and enhanced beyond the official zsh package.</p>
<h3>Linux is stable. Really stable.</h3>
<p>While people bash Microsoft daily for tying the <span class="caps">GUI</span> layer to the kernel, Apple seems to get away with it scot-free. I don&#8217;t know if it&#8217;s caused by my external display hooked up to the dock, or the Prolific Firewire chip in my external disk enclosure but something causes the mysterious &#8220;music plays till the end of the song, mouse can be moved, but nothing works&#8221; bug now and then and all I can do is a hard reset.</p>
<p>On Linux I currently use Fluxbox so everything is rock solid and fast (except Firefox! ;-), but in the extremely rare event that shit does hit the fan usually only a single app will crash, though sometimes X (and hence many others) go with it. A <code>sudo /etc/init.d/gdm restart</code> fixes that. The only times I&#8217;ve had to hard reset Linux was because of a random bug (strangely similar to my MacBook bug) with Nvidia&#8217;s driver with dual head setups. All this is pretty moot since Linux is generally just stable.</p>
<p>Those are 2 relatively small things but the added comfort they provide is very nice.</p>
<p>In the spirit of switching things up I&#8217;m going to forgo my usual routine of using gvim on Linux and try out emacs. I&#8217;ve been frustrated with vim&#8217;s lack of a decent file browser and I&#8217;ve never much liked the tree plugin. Vim is a fantastic editor when it comes to navigating, slicing, and dicing text. After that it sort of falls flat though. After getting hooked on TextMate I have come to love integration with all sorts of external apps such as Subversion, rake, and the shell because it makes my work easier. Emacs seems to embrace that sort of philosophy and I&#8217;m more impressed with the efforts to integrate Rails development into Emacs than vim. I&#8217;m typing this post using the Textile mode for Emacs and the markup is rendered giving me a live preview of my post. It&#8217;s not <span class="caps">WYSIWYG</span> like Typo&#8217;s preview but it&#8217;s still pretty damn cool. I think can get used to emacs.</p>
<p>I&#8217;m just waiting for a bunch of crap to compile &#8211; because I use Gentoo &#8211; and soon I&#8217;ll have a Gtk-enabled Emacs to work in. If I can paste to and from Firefox then I&#8217;ll be happy. I&#8217;ll have to open this in vim or gedit to paste it into Firefox, funny!</p>
<p>I&#8217;m also going to try replacing a couple of desktop apps with web alternatives. I&#8217;m starting with 2 no-brainers: mail and feeds with Gmail and Google Reader. I never got into the Gmail craze and never really even used Gmail very much. After looking at the shortcuts I think I can get used to it. Seeing j/k for up/down is always nice. Thunderbird is ok but there isn&#8217;t a mail client on Linux that I really like, except mutt. That played a part in my Gmail choice. I hadn&#8217;t used G-Reader before either and it seems alright, but it&#8217;ll be hard to beat NetNewsWire.</p>
</div>
<ul class="meta">
<li>
Tags: <a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/emacs">emacs</a>&nbsp;<a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/gentoo">gentoo</a>&nbsp;<a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/linux">linux</a>&nbsp;<a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/vim">vim</a>&nbsp;
</li>
<li>
Meta:
<a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/2007/6/19/back-on-gentoo-trying-new-things">0 comments</a>,
<a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/2007/6/19/back-on-gentoo-trying-new-things">permalink</a>
</li>
</ul>
</div>
<h5><a name="comments">Comments</a></h5>
<p><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/2007/6/19/back-on-gentoo-trying-new-things#comment-form">Leave a response</a></p>
<div id="comments_div">
<ol id="comments" class="comments">
</ol>
</div>
<form id="comment-form" method="post" action="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/2007/6/19/back-on-gentoo-trying-new-things/comments#comment-form">
<fieldset>
<legend>Comment</legend>
<p>
<label class="text" for="comment_author">Name:</label><br/>
<input type="text" id="comment_author" name="comment[author]" value="" />
</p>
<p>
<label class="text" for="comment_author_email">Email Address:</label><br />
<input type="text" id="comment_author_email" name="comment[author_email]" value="" />
</p>
<p>
<label class="text" for="comment_author_url">Website:</label><br />
<input type="text" id="comment_author_url" name="comment[author_url]" value="" />
</p>
<p>
<label class="text" for="comment_body">Comment:</label><br />
<textarea id="comment_body" name="comment[body]"></textarea>
</p>
<div class="formactions">
<input type="submit" value="Post comment" class="submit" />
</div>
</fieldset>
</form>
</div>
<div id="sidebar">
<div class="sidebar-node">
<div id="search" class="search">
<form action="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/search" id="sform" method="get" name="sform">
<p><input type="text" id="q" name="q" value="" /></p>
</form>
</div>
</div>
<div class="sidebar-node">
<h3>Sections</h3>
<ul>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/">geeky ramblings</a> (15)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/emacs">Emacs</a> (3)</li>
</ul>
</div>
<div class="sidebar-node">
<h3>Tags</h3>
<ul>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/activerecord">activerecord</a> (2)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/alsa">alsa</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/amusement">amusement</a> (6)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/apple">apple</a> (7)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/bdd">bdd</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/bootcamp">bootcamp</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/broken">broken</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/browsers">browsers</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/buffalo">buffalo</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/bundle">bundle</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/cheat">cheat</a> (3)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/coding">coding</a> (22)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/cool">cool</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/coverflow">coverflow</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/crazy">crazy</a> (2)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/digg">digg</a> (2)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/drm">drm</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/dtrace">dtrace</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/elschemo">elschemo</a> (2)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/emacs">emacs</a> (11)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/english">english</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/extensions">extensions</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/firefox">firefox</a> (3)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/framework">framework</a> (2)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/funny">funny</a> (2)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/fuse">fuse</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/games">games</a> (2)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/gentoo">gentoo</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/german">german</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/gtkpod">gtkpod</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/haskell">haskell</a> (7)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/humans">humans</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/injury">injury</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/inspirado">inspirado</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/iphone">iphone</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/itunes">itunes</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/i_laughed_i_cried">i_laughed_i_cried</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/keyboard">keyboard</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/keyboard%20shortcuts">keyboard shortcuts</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/lemmings">lemmings</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/life">life</a> (11)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/linux">linux</a> (7)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/lisp">lisp</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/mac%20os%20x">mac os x</a> (7)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/mediawiki">mediawiki</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/mephisto">mephisto</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/migrations">migrations</a> (2)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/munich">munich</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/mysql">mysql</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/networking">networking</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/opera">opera</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/parallels">parallels</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/pedantry">pedantry</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/people">people</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/photo">photo</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/php">php</a> (4)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/propaganda">propaganda</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/python">python</a> (2)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/quickcheck">quickcheck</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/rails">rails</a> (18)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/rails%20on%20rules">rails on rules</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/regex">regex</a> (2)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/regular%20expressions">regular expressions</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/rest">rest</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/rtfm">rtfm</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/ruby">ruby</a> (14)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/rushcheck">rushcheck</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/sake">sake</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/scheme">scheme</a> (4)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/school">school</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/seaside">seaside</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/secure%20associations">secure associations</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/seekport">seekport</a> (2)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/snippets">snippets</a> (3)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/tagify">tagify</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/technology">technology</a> (6)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/test/spec">test/spec</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/textmate">textmate</a> (7)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/tips">tips</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/typo">typo</a> (2)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/ubuntu">ubuntu</a> (2)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/usability">usability</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/userscript">userscript</a> (2)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/vim">vim</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/volume">volume</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/web%20objects">web objects</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/wikipediafs">wikipediafs</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/windows">windows</a> (3)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/work">work</a> (1)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/zend">zend</a> (2)</li>
<li><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/tags/zsh">zsh</a> (1)</li>
</ul>
</div>
<div class="sidebar-node">
<h3>Friends &amp; cool blogs</h3>
<ul>
<li><a href="http://web.archive.org/web/20071109170829/http://jim.roepcke.com/">have browser, will travel</a></li>
<li><a href="http://web.archive.org/web/20071109170829/http://cassandrahill.blogspot.com/">cj's chatter</a></li>
</ul>
</div>
<div class="sidebar-node">
<p><a href="http://web.archive.org/web/20071109170829/http://twitter.com/_sjs">
<img src="http://web.archive.org/web/20071109170829im_/http://sami.samhuri.net/assets/2007/6/26/icon_twitter.png" alt="[t]" /> twitter</a></p>
</div>
<div class="sidebar-node">
<p><a href="http://web.archive.org/web/20071109170829/http://mephistoblog.com/" class="powered"><img alt="mephisto-badge-tiny" src="http://web.archive.org/web/20071109170829im_/http://sami.samhuri.net/images/mephisto-badge-tiny.png" /></a></p>
</div>
</div>
<br style="clear:both;" />
</div>
<div id="footer">
<hr />
<p><a href="http://web.archive.org/web/20071109170829/http://sami.samhuri.net/">sjs</a></p>
<ul>
<li>powered by <a href="http://web.archive.org/web/20071109170829/http://mephistoblog.com/">Mephisto</a> /
styled with <a href="http://web.archive.org/web/20071109170829/http://quotedprintable.com/pages/scribbish">scribbish</a></li>
</ul>
</div>
</div>
<script src="http://web.archive.org/web/20071109170829js_/http://www.google-analytics.com/urchin.js" type="text/javascript"> </script>
<script type="text/javascript"> _uacct = "UA-214054-3"; urchinTracker(); </script>
<script src="http://web.archive.org/web/20071109170829js_/http://feeds.feedburner.com/~s/sjs" type="text/javascript" charset="utf-8"></script>
</body>
</html>
<!--
FILE ARCHIVED ON 17:08:29 Nov 9, 2007 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 2:58:06 Aug 21, 2011.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
-->

View file

@ -1,638 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>sjs: Python and Ruby brain dump</title>
<link rel="openid.server" href="http://web.archive.org/web/20080820115439/http://www.myopenid.com/server" />
<link rel="openid.delegate" href="http://web.archive.org/web/20080820115439/http://sami-samhuri.myopenid.com/" />
<meta http-equiv="X-XRDS-Location" content="http://sami-samhuri.myopenid.com/xrds" />
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="http://web.archive.org/web/20080820115439/http://feeds.feedburner.com/sjs" />
<script src="http://web.archive.org/web/20080820115439js_/http://sami.samhuri.net/javascripts/prototype.js" type="text/javascript"></script>
<link href="http://web.archive.org/web/20080820115439cs_/http://sami.samhuri.net/stylesheets/application.css" rel="stylesheet" type="text/css" />
</head>
<body>
<!-- BEGIN WAYBACK TOOLBAR INSERT -->
<script type="text/javascript" src="http://staticweb.archive.org/js/disclaim-element.js" ></script>
<script type="text/javascript" src="http://staticweb.archive.org/js/graph-calc.js" ></script>
<script type="text/javascript" src="http://staticweb.archive.org/jflot/jquery.min.js" ></script>
<script type="text/javascript">
//<![CDATA[
var firstDate = 820454400000;
var lastDate = 1325375999999;
var wbPrefix = "http://web.archive.org/web/";
var wbCurrentUrl = "http://sami.samhuri.net/2007/9/26/python-and-ruby-brain-dump";
var curYear = -1;
var curMonth = -1;
var yearCount = 16;
var firstYear = 1996;
var imgWidth=400;
var yearImgWidth = 25;
var monthImgWidth = 2;
var trackerVal = "none";
var displayDay = "20";
var displayMonth = "Aug";
var displayYear = "2008";
var prettyMonths = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
function showTrackers(val) {
if(val == trackerVal) {
return;
}
if(val == "inline") {
document.getElementById("displayYearEl").style.color = "#ec008c";
document.getElementById("displayMonthEl").style.color = "#ec008c";
document.getElementById("displayDayEl").style.color = "#ec008c";
} else {
document.getElementById("displayYearEl").innerHTML = displayYear;
document.getElementById("displayYearEl").style.color = "#ff0";
document.getElementById("displayMonthEl").innerHTML = displayMonth;
document.getElementById("displayMonthEl").style.color = "#ff0";
document.getElementById("displayDayEl").innerHTML = displayDay;
document.getElementById("displayDayEl").style.color = "#ff0";
}
document.getElementById("wbMouseTrackYearImg").style.display = val;
document.getElementById("wbMouseTrackMonthImg").style.display = val;
trackerVal = val;
}
function getElementX2(obj) {
var thing = jQuery(obj);
if((thing == undefined)
|| (typeof thing == "undefined")
|| (typeof thing.offset == "undefined")) {
return getElementX(obj);
}
return Math.round(thing.offset().left);
}
function trackMouseMove(event,element) {
var eventX = getEventX(event);
var elementX = getElementX2(element);
var xOff = eventX - elementX;
if(xOff < 0) {
xOff = 0;
} else if(xOff > imgWidth) {
xOff = imgWidth;
}
var monthOff = xOff % yearImgWidth;
var year = Math.floor(xOff / yearImgWidth);
var yearStart = year * yearImgWidth;
var monthOfYear = Math.floor(monthOff / monthImgWidth);
if(monthOfYear > 11) {
monthOfYear = 11;
}
// 1 extra border pixel at the left edge of the year:
var month = (year * 12) + monthOfYear;
var day = 1;
if(monthOff % 2 == 1) {
day = 15;
}
var dateString =
zeroPad(year + firstYear) +
zeroPad(monthOfYear+1,2) +
zeroPad(day,2) + "000000";
var monthString = prettyMonths[monthOfYear];
document.getElementById("displayYearEl").innerHTML = year + 1996;
document.getElementById("displayMonthEl").innerHTML = monthString;
// looks too jarring when it changes..
//document.getElementById("displayDayEl").innerHTML = zeroPad(day,2);
var url = wbPrefix + dateString + '/' + wbCurrentUrl;
document.getElementById('wm-graph-anchor').href = url;
//document.getElementById("wmtbURL").value="evX("+eventX+") elX("+elementX+") xO("+xOff+") y("+year+") m("+month+") monthOff("+monthOff+") DS("+dateString+") Moy("+monthOfYear+") ms("+monthString+")";
if(curYear != year) {
var yrOff = year * yearImgWidth;
document.getElementById("wbMouseTrackYearImg").style.left = yrOff + "px";
curYear = year;
}
if(curMonth != month) {
var mtOff = year + (month * monthImgWidth) + 1;
document.getElementById("wbMouseTrackMonthImg").style.left = mtOff + "px";
curMonth = month;
}
}
//]]>
</script>
<style type="text/css">body{margin-top:0!important;padding-top:0!important;min-width:800px!important;}#wm-ipp a:hover{text-decoration:underline!important;}</style>
<div id="wm-ipp" style="display:none; position:relative;padding:0 5px;min-height:70px;min-width:800px; z-index:9000;">
<div id="wm-ipp-inside" style="position:fixed;padding:0!important;margin:0!important;width:97%;min-width:780px;border:5px solid #000;border-top:none;background-image:url(http://staticweb.archive.org/images/toolbar/wm_tb_bk_trns.png);text-align:center;-moz-box-shadow:1px 1px 3px #333;-webkit-box-shadow:1px 1px 3px #333;box-shadow:1px 1px 3px #333;font-size:11px!important;font-family:'Lucida Grande','Arial',sans-serif!important;">
<table style="border-collapse:collapse;margin:0;padding:0;width:100%;"><tbody><tr>
<td style="padding:10px;vertical-align:top;min-width:110px;">
<a href="http://wayback.archive.org/web/" title="Wayback Machine home page" style="background-color:transparent;border:none;"><img src="http://staticweb.archive.org/images/toolbar/wayback-toolbar-logo.png" alt="Wayback Machine" width="110" height="39" border="0"/></a>
</td>
<td style="padding:0!important;text-align:center;vertical-align:top;width:100%;">
<table style="border-collapse:collapse;margin:0 auto;padding:0;width:570px;"><tbody><tr>
<td style="padding:3px 0;" colspan="2">
<form target="_top" method="get" action="http://wayback.archive.org/web/form-submit.jsp" name="wmtb" id="wmtb" style="margin:0!important;padding:0!important;"><input type="text" name="url" id="wmtbURL" value="http://sami.samhuri.net/2007/9/26/python-and-ruby-brain-dump" style="width:400px;font-size:11px;font-family:'Lucida Grande','Arial',sans-serif;" onfocus="javascript:this.focus();this.select();" /><input type="hidden" name="type" value="replay" /><input type="hidden" name="date" value="20080820115439" /><input type="submit" value="Go" style="font-size:11px;font-family:'Lucida Grande','Arial',sans-serif;margin-left:5px;" /><span id="wm_tb_options" style="display:block;"></span></form>
</td>
<td style="vertical-align:bottom;padding:5px 0 0 0!important;" rowspan="2">
<table style="border-collapse:collapse;width:110px;color:#99a;font-family:'Helvetica','Lucida Grande','Arial',sans-serif;"><tbody>
<!-- NEXT/PREV MONTH NAV AND MONTH INDICATOR -->
<tr style="width:110px;height:16px;font-size:10px!important;">
<td style="padding-right:9px;font-size:11px!important;font-weight:bold;text-transform:uppercase;text-align:right;white-space:nowrap;overflow:visible;" nowrap="nowrap">
Jul
</td>
<td id="displayMonthEl" style="background:#000;color:#ff0;font-size:11px!important;font-weight:bold;text-transform:uppercase;width:34px;height:15px;padding-top:1px;text-align:center;" title="You are here: 11:54:39 Aug 20, 2008">AUG</td>
<td style="padding-left:9px;font-size:11px!important;font-weight:bold;text-transform:uppercase;white-space:nowrap;overflow:visible;" nowrap="nowrap">
<a href="http://web.archive.org/web/20090430130914/http://sami.samhuri.net/2007/9/26/python-and-ruby-brain-dump" style="text-decoration:none;color:#33f;font-weight:bold;background-color:transparent;border:none;" title="30 Apr 2009"><strong>APR</strong></a>
</td>
</tr>
<!-- NEXT/PREV CAPTURE NAV AND DAY OF MONTH INDICATOR -->
<tr>
<td style="padding-right:9px;white-space:nowrap;overflow:visible;text-align:right!important;vertical-align:middle!important;" nowrap="nowrap">
<img src="http://staticweb.archive.org/images/toolbar/wm_tb_prv_off.png" alt="Previous capture" width="14" height="16" border="0" />
</td>
<td id="displayDayEl" style="background:#000;color:#ff0;width:34px;height:24px;padding:2px 0 0 0;text-align:center;font-size:24px;font-weight: bold;" title="You are here: 11:54:39 Aug 20, 2008">20</td>
<td style="padding-left:9px;white-space:nowrap;overflow:visible;text-align:left!important;vertical-align:middle!important;" nowrap="nowrap">
<a href="http://web.archive.org/web/20090430130914/http://sami.samhuri.net/2007/9/26/python-and-ruby-brain-dump" title="13:09:14 Apr 30, 2009" style="background-color:transparent;border:none;"><img src="http://staticweb.archive.org/images/toolbar/wm_tb_nxt_on.png" alt="Next capture" width="14" height="16" border="0"/></a>
</td>
</tr>
<!-- NEXT/PREV YEAR NAV AND YEAR INDICATOR -->
<tr style="width:110px;height:13px;font-size:9px!important;">
<td style="padding-right:9px;font-size:11px!important;font-weight: bold;text-align:right;white-space:nowrap;overflow:visible;" nowrap="nowrap">
2007
</td>
<td id="displayYearEl" style="background:#000;color:#ff0;font-size:11px!important;font-weight: bold;padding-top:1px;width:34px;height:13px;text-align:center;" title="You are here: 11:54:39 Aug 20, 2008">2008</td>
<td style="padding-left:9px;font-size:11px!important;font-weight: bold;white-space:nowrap;overflow:visible;" nowrap="nowrap">
2009
</td>
</tr>
</tbody></table>
</td>
</tr>
<tr>
<td style="vertical-align:middle;padding:0!important;">
<a href="http://wayback.archive.org/web/20080820115439*/http://sami.samhuri.net/2007/9/26/python-and-ruby-brain-dump" style="color:#33f;font-size:11px;font-weight:bold;background-color:transparent;border:none;" title="See a list of every capture for this URL"><strong>2 captures</strong></a>
<div style="margin:0!important;padding:0!important;color:#666;font-size:9px;padding-top:2px!important;white-space:nowrap;" title="Timespan for captures of this URL">20 Aug 08 - 30 Apr 09</div>
</td>
<td style="padding:0!important;">
<a style="position:relative; white-space:nowrap; width:400px;height:27px;" href="" id="wm-graph-anchor">
<div id="wm-ipp-sparkline" style="position:relative; white-space:nowrap; width:400px;height:27px;background-color:#fff;cursor:pointer;border-right:1px solid #ccc;" title="Explore captures for this URL">
<img id="sparklineImgId" style="position:absolute; z-index:9012; top:0px; left:0px;"
onmouseover="showTrackers('inline');"
onmouseout="showTrackers('none');"
onmousemove="trackMouseMove(event,this)"
alt="sparklines"
width="400"
height="27"
border="0"
src="http://wayback.archive.org/jsp/graph.jsp?graphdata=400_27_1996:-1:000000000000_1997:-1:000000000000_1998:-1:000000000000_1999:-1:000000000000_2000:-1:000000000000_2001:-1:000000000000_2002:-1:000000000000_2003:-1:000000000000_2004:-1:000000000000_2005:-1:000000000000_2006:-1:000000000000_2007:-1:000000000000_2008:7:000000010000_2009:-1:000100000000_2010:-1:000000000000_2011:-1:000000000000"></img>
<img id="wbMouseTrackYearImg"
style="display:none; position:absolute; z-index:9010;"
width="25"
height="27"
border="0"
src="http://staticweb.archive.org/images/toolbar/transp-yellow-pixel.png"></img>
<img id="wbMouseTrackMonthImg"
style="display:none; position:absolute; z-index:9011; "
width="2"
height="27"
border="0"
src="http://staticweb.archive.org/images/toolbar/transp-red-pixel.png"></img>
</div>
</a>
</td>
</tr></tbody></table>
</td>
<td style="text-align:right;padding:5px;width:65px;font-size:11px!important;">
<a href="javascript:;" onclick="document.getElementById('wm-ipp').style.display='none';" style="display:block;padding-right:18px;background:url(http://staticweb.archive.org/images/toolbar/wm_tb_close.png) no-repeat 100% 0;color:#33f;font-family:'Lucida Grande','Arial',sans-serif;margin-bottom:23px;background-color:transparent;border:none;" title="Close the toolbar">Close</a>
<a href="http://faq.web.archive.org/" style="display:block;padding-right:18px;background:url(http://staticweb.archive.org/images/toolbar/wm_tb_help.png) no-repeat 100% 0;color:#33f;font-family:'Lucida Grande','Arial',sans-serif;background-color:transparent;border:none;" title="Get some help using the Wayback Machine">Help</a>
</td>
</tr></tbody></table>
</div>
</div>
<script type="text/javascript">
var wmDisclaimBanner = document.getElementById("wm-ipp");
if(wmDisclaimBanner != null) {
disclaimElement(wmDisclaimBanner);
}
</script>
<!-- END WAYBACK TOOLBAR INSERT -->
<div id="container">
<div id="header">
<h1><span><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/">sjs</a></span></h1>
<h2>geeky ramblings</h2>
</div>
<div id="page">
<div id="content">
<!--
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<rdf:Description
rdf:about=""
trackback:ping=""
dc:title="Python and Ruby brain dump"
dc:identifier="/2007/9/26/python-and-ruby-brain-dump"
dc:description="<p>It turns out that <a href="http://dev.laptop.org/git?p=security;a=blob;f=bitfrost.txt">Python is the language of choice on the <span class="caps">OLPC</span></a>, both for implementing applications and exposing to the users. There is a view so..."
dc:creator="sjs"
dc:date="September 26, 2007 10:34" />
</rdf:RDF>
-->
<div class="hentry" id="article-312">
<h2 class="entry-title">
<a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/2007/9/26/python-and-ruby-brain-dump">Python and Ruby brain dump</a>
<span class="comment_count">0</span>
</h2>
<div class="vcard">
Posted by <span class="fn">sjs</span>
</div>
<abbr class="published" title="2007-09-26T10:34:00+00:00">on Wednesday, September 26</abbr>
<br class="clear" />
<div class="entry-content">
<p>It turns out that <a href="http://web.archive.org/web/20080820115439/http://dev.laptop.org/git?p=security;a=blob;f=bitfrost.txt">Python is the language of choice on the <span class="caps">OLPC</span></a>, both for implementing applications and exposing to the users. There is a view source key available. I think Python is a great choice.</p>
<p>I&#8217;ve been using Ruby almost exclusively for over a year but the last week I&#8217;ve been doing a personal project in Python using <a href="http://web.archive.org/web/20080820115439/https://storm.canonical.com/">Storm</a> (which is pretty nice btw) and <a href="http://web.archive.org/web/20080820115439/http://excess.org/urwid/">urwid</a>. I&#8217;m remembering why I liked Python when I first learned it a few years ago. It may not be as elegant as Ruby, conceptually, but it sure is fun to code in. It really is executable pseudo-code for the most part.</p>
<p>I&#8217;m tripping up by typing <code>obj.setattr^W^Wsetattr(obj</code> and <code>def self.foo^W^Wfoo(self</code> but other than that I haven&#8217;t had trouble switching back into Python. I enjoy omitting <code>end</code> statements. I enjoy Python&#8217;s lack of curly braces, apart from literal dicts. I hate the fact that in Emacs, in python-mode, <code>indent-region</code> only seems to piss me off (or <code>indent-*</code> really, anything except <span class="caps">TAB</span>). I really like list comprehensions.</p>
<p>The two languages are so similar that at a glance you may think there are only shallow differences between the languages. People are always busy arguing about the boring things that every language can do (web frameworks anyone?) while ignoring the interesting differences between the languages and their corresponding ecosystems.</p>
<p>Python has more libraries available as it&#8217;s the more popular language. The nature of software written in the languages is different though as the languages themselves are quite different.</p>
<p>Ruby has some Perl-ish features that make it a good sysadmin scripting language, hence we see nice tools such as <a href="http://web.archive.org/web/20080820115439/http://www.capify.org/">Capistrano</a> and <a href="http://web.archive.org/web/20080820115439/http://god.rubyforge.org/">god</a> written in Ruby and used by projects written in other languages.</p>
<p>Python is faster than Ruby so it is open to classes of software that would be cumbersome in Ruby. Source control, for example. You can write a slow <span class="caps">SCM</span> in Python though, as <a href="http://web.archive.org/web/20080820115439/http://bazaar-vcs.org/">Bazaar</a> demonstrates. You could probably write a passable one in Ruby as well. If it didn&#8217;t quite perform well enough right now it should fare better in a year&#8217;s time.</p>
<p>I still think that my overall joy is greater when using Ruby, but if Ruby isn&#8217;t the right tool for the job I&#8217;ll probably look to Python next (unless some feature of the problem indicates something else would be more appropriate). The reason I chose Python for my current project is because of libs like urwid and I needed an excuse to try out Storm and brush up on my Python. ;-)</p>
</div>
<ul class="meta">
<li>
Tags: <a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/python">python</a>&nbsp;<a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/ruby">ruby</a>&nbsp;
</li>
<li>
Meta:
<a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/2007/9/26/python-and-ruby-brain-dump">0 comments</a>,
<a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/2007/9/26/python-and-ruby-brain-dump">permalink</a>
</li>
</ul>
</div>
<h5><a name="comments">Comments</a></h5>
<p><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/2007/9/26/python-and-ruby-brain-dump#comment-form">Leave a response</a></p>
<div id="comments_div">
<ol id="comments" class="comments">
</ol>
</div>
<form id="comment-form" method="post" action="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/2007/9/26/python-and-ruby-brain-dump/comments#comment-form">
<fieldset>
<legend>Comment</legend>
<p>
<label class="text" for="comment_author">Name:</label><br/>
<input type="text" id="comment_author" name="comment[author]" value="" />
</p>
<p>
<label class="text" for="comment_author_email">Email Address:</label><br />
<input type="text" id="comment_author_email" name="comment[author_email]" value="" />
</p>
<p>
<label class="text" for="comment_author_url">Website:</label><br />
<input type="text" id="comment_author_url" name="comment[author_url]" value="" />
</p>
<p>
<label class="text" for="comment_body">Comment:</label><br />
<textarea id="comment_body" name="comment[body]"></textarea>
</p>
<div class="formactions">
<input type="submit" value="Post comment" class="submit" />
</div>
</fieldset>
</form>
</div>
<div id="sidebar">
<div class="sidebar-node">
<div id="search" class="search">
<form action="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/search" id="sform" method="get" name="sform">
<p><input type="text" id="q" name="q" value="" /></p>
</form>
</div>
</div>
<div class="sidebar-node">
<h3>Sections</h3>
<ul>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/">geeky ramblings</a> (15)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/emacs">Emacs</a> (3)</li>
</ul>
</div>
<div class="sidebar-node">
<h3>Tags</h3>
<ul>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/activerecord">activerecord</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/alsa">alsa</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/amusement">amusement</a> (6)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/apple">apple</a> (6)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/arc">arc</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/bdd">bdd</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/broken">broken</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/browsers">browsers</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/buffalo">buffalo</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/bundle">bundle</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/cheat">cheat</a> (3)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/coding">coding</a> (22)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/cool">cool</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/coverflow">coverflow</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/crazy">crazy</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/digg">digg</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/drm">drm</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/dtrace">dtrace</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/dubai">dubai</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/elschemo">elschemo</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/emacs">emacs</a> (11)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/english">english</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/extensions">extensions</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/firefox">firefox</a> (3)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/framework">framework</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/funny">funny</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/fuse">fuse</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/games">games</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/gentoo">gentoo</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/german">german</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/gtkpod">gtkpod</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/haskell">haskell</a> (7)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/humans">humans</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/injury">injury</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/inspirado">inspirado</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/iphone">iphone</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/itunes">itunes</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/i_laughed_i_cried">i_laughed_i_cried</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/keyboard">keyboard</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/keyboard%20shortcuts">keyboard shortcuts</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/lemmings">lemmings</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/life">life</a> (13)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/linux">linux</a> (8)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/lisp">lisp</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/lisp%20arc">lisp arc</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/mac%20os%20x">mac os x</a> (6)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/mediawiki">mediawiki</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/mephisto">mephisto</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/migrations">migrations</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/munich">munich</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/mysql">mysql</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/networking">networking</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/opera">opera</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/pedantry">pedantry</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/people">people</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/photo">photo</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/php">php</a> (4)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/programming">programming</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/project%20euler">project euler</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/propaganda">propaganda</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/python">python</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/quickcheck">quickcheck</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/rails">rails</a> (18)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/rails%20on%20rules">rails on rules</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/regex">regex</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/regular%20expressions">regular expressions</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/rest">rest</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/rtfm">rtfm</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/ruby">ruby</a> (14)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/rushcheck">rushcheck</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/sake">sake</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/scheme">scheme</a> (4)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/school">school</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/seaside">seaside</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/secure%20associations">secure associations</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/seekport">seekport</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/snippets">snippets</a> (3)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/ssh">ssh</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/tagify">tagify</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/technology">technology</a> (6)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/test/spec">test/spec</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/textmate">textmate</a> (7)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/tips">tips</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/typo">typo</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/ubuntu">ubuntu</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/usability">usability</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/userscript">userscript</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/vacation">vacation</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/vim">vim</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/volume">volume</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/web">web</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/web%20objects">web objects</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/wikipediafs">wikipediafs</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/windows">windows</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/work">work</a> (1)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/zend">zend</a> (2)</li>
<li><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/tags/zsh">zsh</a> (1)</li>
</ul>
</div>
<div class="sidebar-node">
<h3>Friends &amp; cool blogs</h3>
<ul>
<li><a href="http://web.archive.org/web/20080820115439/http://jim.roepcke.com/">have browser, will travel</a></li>
<li><a href="http://web.archive.org/web/20080820115439/http://cassandrahill.blogspot.com/">cj's chatter</a></li>
</ul>
</div>
<div class="sidebar-node">
<p><a href="http://web.archive.org/web/20080820115439/http://twitter.com/_sjs">
<img src="http://web.archive.org/web/20080820115439im_/http://sami.samhuri.net/assets/2007/6/26/icon_twitter.png" alt="[t]" /> twitter</a></p>
</div>
<div class="sidebar-node">
<p><a href="http://web.archive.org/web/20080820115439/http://mephistoblog.com/" class="powered"><img alt="mephisto-badge-tiny" src="http://web.archive.org/web/20080820115439im_/http://sami.samhuri.net/images/mephisto-badge-tiny.png" /></a></p>
</div>
</div>
<br style="clear:both;" />
</div>
<div id="footer">
<hr />
<p><a href="http://web.archive.org/web/20080820115439/http://sami.samhuri.net/">sjs</a></p>
<ul>
<li>powered by <a href="http://web.archive.org/web/20080820115439/http://mephistoblog.com/">Mephisto</a> /
styled with <a href="http://web.archive.org/web/20080820115439/http://quotedprintable.com/pages/scribbish">scribbish</a></li>
</ul>
</div>
</div>
<script src="http://web.archive.org/web/20080820115439js_/http://www.google-analytics.com/urchin.js" type="text/javascript"> </script>
<script type="text/javascript"> _uacct = "UA-214054-3"; urchinTracker(); </script>
<script src="http://web.archive.org/web/20080820115439js_/http://feeds.feedburner.com/~s/sjs" type="text/javascript" charset="utf-8"></script>
</body>
</html>
<!--
FILE ARCHIVED ON 11:54:39 Aug 20, 2008 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 3:01:48 Aug 21, 2011.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
-->

View file

@ -1,638 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>sjs: Recent Ruby and Rails Regales</title>
<link rel="openid.server" href="http://web.archive.org/web/20071103230842/http://www.myopenid.com/server" />
<link rel="openid.delegate" href="http://web.archive.org/web/20071103230842/http://sami-samhuri.myopenid.com/" />
<meta http-equiv="X-XRDS-Location" content="http://sami-samhuri.myopenid.com/xrds" />
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="http://web.archive.org/web/20071103230842/http://feeds.feedburner.com/sjs" />
<script src="http://web.archive.org/web/20071103230842js_/http://sami.samhuri.net/javascripts/prototype.js" type="text/javascript"></script>
<link href="http://web.archive.org/web/20071103230842cs_/http://sami.samhuri.net/stylesheets/application.css" rel="stylesheet" type="text/css" />
</head>
<body>
<!-- BEGIN WAYBACK TOOLBAR INSERT -->
<script type="text/javascript" src="http://staticweb.archive.org/js/disclaim-element.js" ></script>
<script type="text/javascript" src="http://staticweb.archive.org/js/graph-calc.js" ></script>
<script type="text/javascript" src="http://staticweb.archive.org/jflot/jquery.min.js" ></script>
<script type="text/javascript">
//<![CDATA[
var firstDate = 820454400000;
var lastDate = 1325375999999;
var wbPrefix = "http://web.archive.org/web/";
var wbCurrentUrl = "http://sami.samhuri.net/2007/6/29/recent-ruby-and-rails-regales";
var curYear = -1;
var curMonth = -1;
var yearCount = 16;
var firstYear = 1996;
var imgWidth=400;
var yearImgWidth = 25;
var monthImgWidth = 2;
var trackerVal = "none";
var displayDay = "3";
var displayMonth = "Nov";
var displayYear = "2007";
var prettyMonths = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
function showTrackers(val) {
if(val == trackerVal) {
return;
}
if(val == "inline") {
document.getElementById("displayYearEl").style.color = "#ec008c";
document.getElementById("displayMonthEl").style.color = "#ec008c";
document.getElementById("displayDayEl").style.color = "#ec008c";
} else {
document.getElementById("displayYearEl").innerHTML = displayYear;
document.getElementById("displayYearEl").style.color = "#ff0";
document.getElementById("displayMonthEl").innerHTML = displayMonth;
document.getElementById("displayMonthEl").style.color = "#ff0";
document.getElementById("displayDayEl").innerHTML = displayDay;
document.getElementById("displayDayEl").style.color = "#ff0";
}
document.getElementById("wbMouseTrackYearImg").style.display = val;
document.getElementById("wbMouseTrackMonthImg").style.display = val;
trackerVal = val;
}
function getElementX2(obj) {
var thing = jQuery(obj);
if((thing == undefined)
|| (typeof thing == "undefined")
|| (typeof thing.offset == "undefined")) {
return getElementX(obj);
}
return Math.round(thing.offset().left);
}
function trackMouseMove(event,element) {
var eventX = getEventX(event);
var elementX = getElementX2(element);
var xOff = eventX - elementX;
if(xOff < 0) {
xOff = 0;
} else if(xOff > imgWidth) {
xOff = imgWidth;
}
var monthOff = xOff % yearImgWidth;
var year = Math.floor(xOff / yearImgWidth);
var yearStart = year * yearImgWidth;
var monthOfYear = Math.floor(monthOff / monthImgWidth);
if(monthOfYear > 11) {
monthOfYear = 11;
}
// 1 extra border pixel at the left edge of the year:
var month = (year * 12) + monthOfYear;
var day = 1;
if(monthOff % 2 == 1) {
day = 15;
}
var dateString =
zeroPad(year + firstYear) +
zeroPad(monthOfYear+1,2) +
zeroPad(day,2) + "000000";
var monthString = prettyMonths[monthOfYear];
document.getElementById("displayYearEl").innerHTML = year + 1996;
document.getElementById("displayMonthEl").innerHTML = monthString;
// looks too jarring when it changes..
//document.getElementById("displayDayEl").innerHTML = zeroPad(day,2);
var url = wbPrefix + dateString + '/' + wbCurrentUrl;
document.getElementById('wm-graph-anchor').href = url;
//document.getElementById("wmtbURL").value="evX("+eventX+") elX("+elementX+") xO("+xOff+") y("+year+") m("+month+") monthOff("+monthOff+") DS("+dateString+") Moy("+monthOfYear+") ms("+monthString+")";
if(curYear != year) {
var yrOff = year * yearImgWidth;
document.getElementById("wbMouseTrackYearImg").style.left = yrOff + "px";
curYear = year;
}
if(curMonth != month) {
var mtOff = year + (month * monthImgWidth) + 1;
document.getElementById("wbMouseTrackMonthImg").style.left = mtOff + "px";
curMonth = month;
}
}
//]]>
</script>
<style type="text/css">body{margin-top:0!important;padding-top:0!important;min-width:800px!important;}#wm-ipp a:hover{text-decoration:underline!important;}</style>
<div id="wm-ipp" style="display:none; position:relative;padding:0 5px;min-height:70px;min-width:800px; z-index:9000;">
<div id="wm-ipp-inside" style="position:fixed;padding:0!important;margin:0!important;width:97%;min-width:780px;border:5px solid #000;border-top:none;background-image:url(http://staticweb.archive.org/images/toolbar/wm_tb_bk_trns.png);text-align:center;-moz-box-shadow:1px 1px 3px #333;-webkit-box-shadow:1px 1px 3px #333;box-shadow:1px 1px 3px #333;font-size:11px!important;font-family:'Lucida Grande','Arial',sans-serif!important;">
<table style="border-collapse:collapse;margin:0;padding:0;width:100%;"><tbody><tr>
<td style="padding:10px;vertical-align:top;min-width:110px;">
<a href="http://wayback.archive.org/web/" title="Wayback Machine home page" style="background-color:transparent;border:none;"><img src="http://staticweb.archive.org/images/toolbar/wayback-toolbar-logo.png" alt="Wayback Machine" width="110" height="39" border="0"/></a>
</td>
<td style="padding:0!important;text-align:center;vertical-align:top;width:100%;">
<table style="border-collapse:collapse;margin:0 auto;padding:0;width:570px;"><tbody><tr>
<td style="padding:3px 0;" colspan="2">
<form target="_top" method="get" action="http://wayback.archive.org/web/form-submit.jsp" name="wmtb" id="wmtb" style="margin:0!important;padding:0!important;"><input type="text" name="url" id="wmtbURL" value="http://sami.samhuri.net/2007/6/29/recent-ruby-and-rails-regales" style="width:400px;font-size:11px;font-family:'Lucida Grande','Arial',sans-serif;" onfocus="javascript:this.focus();this.select();" /><input type="hidden" name="type" value="replay" /><input type="hidden" name="date" value="20071103230842" /><input type="submit" value="Go" style="font-size:11px;font-family:'Lucida Grande','Arial',sans-serif;margin-left:5px;" /><span id="wm_tb_options" style="display:block;"></span></form>
</td>
<td style="vertical-align:bottom;padding:5px 0 0 0!important;" rowspan="2">
<table style="border-collapse:collapse;width:110px;color:#99a;font-family:'Helvetica','Lucida Grande','Arial',sans-serif;"><tbody>
<!-- NEXT/PREV MONTH NAV AND MONTH INDICATOR -->
<tr style="width:110px;height:16px;font-size:10px!important;">
<td style="padding-right:9px;font-size:11px!important;font-weight:bold;text-transform:uppercase;text-align:right;white-space:nowrap;overflow:visible;" nowrap="nowrap">
Oct
</td>
<td id="displayMonthEl" style="background:#000;color:#ff0;font-size:11px!important;font-weight:bold;text-transform:uppercase;width:34px;height:15px;padding-top:1px;text-align:center;" title="You are here: 23:08:42 Nov 3, 2007">NOV</td>
<td style="padding-left:9px;font-size:11px!important;font-weight:bold;text-transform:uppercase;white-space:nowrap;overflow:visible;" nowrap="nowrap">
<a href="http://web.archive.org/web/20080820114537/http://sami.samhuri.net/2007/6/29/recent-ruby-and-rails-regales" style="text-decoration:none;color:#33f;font-weight:bold;background-color:transparent;border:none;" title="20 Aug 2008"><strong>AUG</strong></a>
</td>
</tr>
<!-- NEXT/PREV CAPTURE NAV AND DAY OF MONTH INDICATOR -->
<tr>
<td style="padding-right:9px;white-space:nowrap;overflow:visible;text-align:right!important;vertical-align:middle!important;" nowrap="nowrap">
<img src="http://staticweb.archive.org/images/toolbar/wm_tb_prv_off.png" alt="Previous capture" width="14" height="16" border="0" />
</td>
<td id="displayDayEl" style="background:#000;color:#ff0;width:34px;height:24px;padding:2px 0 0 0;text-align:center;font-size:24px;font-weight: bold;" title="You are here: 23:08:42 Nov 3, 2007">3</td>
<td style="padding-left:9px;white-space:nowrap;overflow:visible;text-align:left!important;vertical-align:middle!important;" nowrap="nowrap">
<a href="http://web.archive.org/web/20080820114537/http://sami.samhuri.net/2007/6/29/recent-ruby-and-rails-regales" title="11:45:37 Aug 20, 2008" style="background-color:transparent;border:none;"><img src="http://staticweb.archive.org/images/toolbar/wm_tb_nxt_on.png" alt="Next capture" width="14" height="16" border="0"/></a>
</td>
</tr>
<!-- NEXT/PREV YEAR NAV AND YEAR INDICATOR -->
<tr style="width:110px;height:13px;font-size:9px!important;">
<td style="padding-right:9px;font-size:11px!important;font-weight: bold;text-align:right;white-space:nowrap;overflow:visible;" nowrap="nowrap">
2006
</td>
<td id="displayYearEl" style="background:#000;color:#ff0;font-size:11px!important;font-weight: bold;padding-top:1px;width:34px;height:13px;text-align:center;" title="You are here: 23:08:42 Nov 3, 2007">2007</td>
<td style="padding-left:9px;font-size:11px!important;font-weight: bold;white-space:nowrap;overflow:visible;" nowrap="nowrap">
2008
</td>
</tr>
</tbody></table>
</td>
</tr>
<tr>
<td style="vertical-align:middle;padding:0!important;">
<a href="http://wayback.archive.org/web/20071103230842*/http://sami.samhuri.net/2007/6/29/recent-ruby-and-rails-regales" style="color:#33f;font-size:11px;font-weight:bold;background-color:transparent;border:none;" title="See a list of every capture for this URL"><strong>2 captures</strong></a>
<div style="margin:0!important;padding:0!important;color:#666;font-size:9px;padding-top:2px!important;white-space:nowrap;" title="Timespan for captures of this URL">3 Nov 07 - 20 Aug 08</div>
</td>
<td style="padding:0!important;">
<a style="position:relative; white-space:nowrap; width:400px;height:27px;" href="" id="wm-graph-anchor">
<div id="wm-ipp-sparkline" style="position:relative; white-space:nowrap; width:400px;height:27px;background-color:#fff;cursor:pointer;border-right:1px solid #ccc;" title="Explore captures for this URL">
<img id="sparklineImgId" style="position:absolute; z-index:9012; top:0px; left:0px;"
onmouseover="showTrackers('inline');"
onmouseout="showTrackers('none');"
onmousemove="trackMouseMove(event,this)"
alt="sparklines"
width="400"
height="27"
border="0"
src="http://wayback.archive.org/jsp/graph.jsp?graphdata=400_27_1996:-1:000000000000_1997:-1:000000000000_1998:-1:000000000000_1999:-1:000000000000_2000:-1:000000000000_2001:-1:000000000000_2002:-1:000000000000_2003:-1:000000000000_2004:-1:000000000000_2005:-1:000000000000_2006:-1:000000000000_2007:10:000000000010_2008:-1:000000010000_2009:-1:000000000000_2010:-1:000000000000_2011:-1:000000000000"></img>
<img id="wbMouseTrackYearImg"
style="display:none; position:absolute; z-index:9010;"
width="25"
height="27"
border="0"
src="http://staticweb.archive.org/images/toolbar/transp-yellow-pixel.png"></img>
<img id="wbMouseTrackMonthImg"
style="display:none; position:absolute; z-index:9011; "
width="2"
height="27"
border="0"
src="http://staticweb.archive.org/images/toolbar/transp-red-pixel.png"></img>
</div>
</a>
</td>
</tr></tbody></table>
</td>
<td style="text-align:right;padding:5px;width:65px;font-size:11px!important;">
<a href="javascript:;" onclick="document.getElementById('wm-ipp').style.display='none';" style="display:block;padding-right:18px;background:url(http://staticweb.archive.org/images/toolbar/wm_tb_close.png) no-repeat 100% 0;color:#33f;font-family:'Lucida Grande','Arial',sans-serif;margin-bottom:23px;background-color:transparent;border:none;" title="Close the toolbar">Close</a>
<a href="http://faq.web.archive.org/" style="display:block;padding-right:18px;background:url(http://staticweb.archive.org/images/toolbar/wm_tb_help.png) no-repeat 100% 0;color:#33f;font-family:'Lucida Grande','Arial',sans-serif;background-color:transparent;border:none;" title="Get some help using the Wayback Machine">Help</a>
</td>
</tr></tbody></table>
</div>
</div>
<script type="text/javascript">
var wmDisclaimBanner = document.getElementById("wm-ipp");
if(wmDisclaimBanner != null) {
disclaimElement(wmDisclaimBanner);
}
</script>
<!-- END WAYBACK TOOLBAR INSERT -->
<div id="container">
<div id="header">
<h1><span><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/">sjs</a></span></h1>
<h2>geeky ramblings</h2>
</div>
<div id="page">
<div id="content">
<!--
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<rdf:Description
rdf:about=""
trackback:ping=""
dc:title="Recent Ruby and Rails Regales"
dc:identifier="/2007/6/29/recent-ruby-and-rails-regales"
dc:description="<p>Some cool Ruby and [the former on] Rails things are springing up and I haven&#8217;t written much about the two Rs lately, though I work with them daily.</p>
<h3>Rails on Rules</h3>
<p>My friend <a href="http://jim.roepcke.com">Jim Roepck..."
dc:creator="sjs"
dc:date="June 28, 2007 19:23" />
</rdf:RDF>
-->
<div class="hentry" id="article-112">
<h2 class="entry-title">
<a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/2007/6/29/recent-ruby-and-rails-regales">Recent Ruby and Rails Regales</a>
<span class="comment_count">0</span>
</h2>
<div class="vcard">
Posted by <span class="fn">sjs</span>
</div>
<abbr class="published" title="2007-06-28T19:23:00+00:00">on Thursday, June 28</abbr>
<br class="clear" />
<div class="entry-content">
<p>Some cool Ruby and [the former on] Rails things are springing up and I haven&#8217;t written much about the two Rs lately, though I work with them daily.</p>
<h3>Rails on Rules</h3>
<p>My friend <a href="http://web.archive.org/web/20071103230842/http://jim.roepcke.com/">Jim Roepcke</a> is researching and implementing a plugin/framework designed to work with Rails called <a href="http://web.archive.org/web/20071103230842/http://willingtofail.com/research/rules/index.html">Rails on Rules</a>. His inspiration is <a href="http://web.archive.org/web/20071103230842/http://developer.apple.com/documentation/WebObjects/Developing_With_D2W/Architecture/chapter_3_section_13.html">the rule system</a> from <a href="http://web.archive.org/web/20071103230842/http://developer.apple.com/documentation/WebObjects/WebObjects_Overview/index.html">WebObjects&#8217;</a> <a href="http://web.archive.org/web/20071103230842/http://developer.apple.com/documentation/WebObjects/Developing_With_D2W/Introduction/chapter_1_section_1.html">Direct to Web</a>. He posted a good <a href="http://web.archive.org/web/20071103230842/http://willingtofail.com/research/rules/example.html">example</a> for me, but this baby isn&#8217;t just for template/view logic. If some of the Rails conventions were specified in a default set of rules which the developer could further customize then you basically have a nice way of doing things that you would otherwise code by hand. I think it would be a boon for the <a href="http://web.archive.org/web/20071103230842/http://activescaffold.com/">ActiveScaffold</a> project. We&#8217;re meeting up to talk about this soon and I&#8217;ll have more to say after then, but it sounds pretty cool.</p>
<h3>Sake Bomb!</h3>
<p>I&#8217;ve noticed a trend among some <a href="http://web.archive.org/web/20071103230842/http://www.railsenvy.com/2007/6/11/ruby-on-rails-rake-tutorial">recent posts</a> about Rake: the authors keep talking about booze. Are we nothing but a bunch of booze hounds?! Well one can hope. There&#8217;s some motivation to learn more about a tool, having more time to drink after work. This week <a href="http://web.archive.org/web/20071103230842/http://ozmm.org/">Chris Wanstrath</a> dropped a <a href="http://web.archive.org/web/20071103230842/http://errtheblog.com/post/6069">Sake Bomb</a> on the Ruby community. Like piston, sake is something you can just pick up and use instantly. Interestingly the different pronunciations of <code>rake</code> and <code>sake</code> help me from confusing the two on the command line&#8230; so far.</p>
<h3>Secure Associations (for Rails)</h3>
<p><a href="http://web.archive.org/web/20071103230842/http://tuples.us/">Jordan McKible</a> released the <a href="http://web.archive.org/web/20071103230842/http://tuples.us/2007/06/28/secure_associations-plugin-gets-some-love/">secure_associations</a> plugin. It lets you protect your models&#8217; *_id attributes from mass-assignment via <code>belongs_to_protected</code> and <code>has_many_protected</code>. It&#8217;s a mild enhancement, but an enhancement nonetheless. This is useful to enough people that it should be in Rails proper.</p>
<h3>Regular expressions and strings with embedded objects</h3>
<p><a href="http://web.archive.org/web/20071103230842/http://t-a-w.blogspot.com/">taw</a> taught me a <a href="http://web.archive.org/web/20071103230842/http://t-a-w.blogspot.com/2007/06/regular-expressions-and-strings-with.html">new technique for simplifying regular expressions</a> by transforming the text in a reversible manner. In one example he replaced literal strings in <span class="caps">SQL</span> &#8211; which are easily parsed via a regex &#8211; with what he calls embedded objects. They&#8217;re just tokens to identify the temporarily removed strings, but the important thing is that they don&#8217;t interfere with the regexes that operate on the other parts of the <span class="caps">SQL</span>, which would have been very difficult to get right with the strings inside it. If I made it sound complicated just read the post, he explains it well.</p>
<p>If you believe anything <a href="http://web.archive.org/web/20071103230842/http://steve-yegge.blogspot.com/2007/06/rich-programmer-food.html">Steve Yegge</a> says then that last regex trick may come in handy for Q&#38;D parsing in any language, be it Ruby, <span class="caps">NBL</span>, or whataver.</p>
</div>
<ul class="meta">
<li>
Tags: <a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/rails">rails</a>&nbsp;<a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/rails%20on%20rules">rails on rules</a>&nbsp;<a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/regular%20expressions">regular expressions</a>&nbsp;<a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/ruby">ruby</a>&nbsp;<a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/sake">sake</a>&nbsp;<a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/secure%20associations">secure associations</a>&nbsp;
</li>
<li>
Meta:
<a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/2007/6/29/recent-ruby-and-rails-regales">0 comments</a>,
<a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/2007/6/29/recent-ruby-and-rails-regales">permalink</a>
</li>
</ul>
</div>
<h5><a name="comments">Comments</a></h5>
<p><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/2007/6/29/recent-ruby-and-rails-regales#comment-form">Leave a response</a></p>
<div id="comments_div">
<ol id="comments" class="comments">
</ol>
</div>
<form id="comment-form" method="post" action="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/2007/6/29/recent-ruby-and-rails-regales/comments#comment-form">
<fieldset>
<legend>Comment</legend>
<p>
<label class="text" for="comment_author">Name:</label><br/>
<input type="text" id="comment_author" name="comment[author]" value="" />
</p>
<p>
<label class="text" for="comment_author_email">Email Address:</label><br />
<input type="text" id="comment_author_email" name="comment[author_email]" value="" />
</p>
<p>
<label class="text" for="comment_author_url">Website:</label><br />
<input type="text" id="comment_author_url" name="comment[author_url]" value="" />
</p>
<p>
<label class="text" for="comment_body">Comment:</label><br />
<textarea id="comment_body" name="comment[body]"></textarea>
</p>
<div class="formactions">
<input type="submit" value="Post comment" class="submit" />
</div>
</fieldset>
</form>
</div>
<div id="sidebar">
<div class="sidebar-node">
<div id="search" class="search">
<form action="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/search" id="sform" method="get" name="sform">
<p><input type="text" id="q" name="q" value="" /></p>
</form>
</div>
</div>
<div class="sidebar-node">
<h3>Sections</h3>
<ul>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/">geeky ramblings</a> (15)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/emacs">Emacs</a> (3)</li>
</ul>
</div>
<div class="sidebar-node">
<h3>Tags</h3>
<ul>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/activerecord">activerecord</a> (2)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/alsa">alsa</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/amusement">amusement</a> (6)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/apple">apple</a> (7)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/bdd">bdd</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/bootcamp">bootcamp</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/broken">broken</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/browsers">browsers</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/buffalo">buffalo</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/bundle">bundle</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/cheat">cheat</a> (3)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/coding">coding</a> (22)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/cool">cool</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/coverflow">coverflow</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/crazy">crazy</a> (2)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/digg">digg</a> (2)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/drm">drm</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/dtrace">dtrace</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/elschemo">elschemo</a> (2)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/emacs">emacs</a> (11)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/english">english</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/extensions">extensions</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/firefox">firefox</a> (3)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/framework">framework</a> (2)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/funny">funny</a> (2)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/fuse">fuse</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/games">games</a> (2)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/gentoo">gentoo</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/german">german</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/gtkpod">gtkpod</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/haskell">haskell</a> (7)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/humans">humans</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/injury">injury</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/inspirado">inspirado</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/iphone">iphone</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/itunes">itunes</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/i_laughed_i_cried">i_laughed_i_cried</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/keyboard">keyboard</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/keyboard%20shortcuts">keyboard shortcuts</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/lemmings">lemmings</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/life">life</a> (11)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/linux">linux</a> (7)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/lisp">lisp</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/mac%20os%20x">mac os x</a> (7)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/mediawiki">mediawiki</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/mephisto">mephisto</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/migrations">migrations</a> (2)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/munich">munich</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/mysql">mysql</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/networking">networking</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/opera">opera</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/parallels">parallels</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/pedantry">pedantry</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/people">people</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/photo">photo</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/php">php</a> (4)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/propaganda">propaganda</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/python">python</a> (2)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/quickcheck">quickcheck</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/rails">rails</a> (18)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/rails%20on%20rules">rails on rules</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/regex">regex</a> (2)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/regular%20expressions">regular expressions</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/rest">rest</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/rtfm">rtfm</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/ruby">ruby</a> (14)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/rushcheck">rushcheck</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/sake">sake</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/scheme">scheme</a> (4)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/school">school</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/seaside">seaside</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/secure%20associations">secure associations</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/seekport">seekport</a> (2)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/snippets">snippets</a> (3)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/tagify">tagify</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/technology">technology</a> (6)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/test/spec">test/spec</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/textmate">textmate</a> (7)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/tips">tips</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/typo">typo</a> (2)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/ubuntu">ubuntu</a> (2)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/usability">usability</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/userscript">userscript</a> (2)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/vim">vim</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/volume">volume</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/web%20objects">web objects</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/wikipediafs">wikipediafs</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/windows">windows</a> (3)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/work">work</a> (1)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/zend">zend</a> (2)</li>
<li><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/tags/zsh">zsh</a> (1)</li>
</ul>
</div>
<div class="sidebar-node">
<h3>Friends &amp; cool blogs</h3>
<ul>
<li><a href="http://web.archive.org/web/20071103230842/http://jim.roepcke.com/">have browser, will travel</a></li>
<li><a href="http://web.archive.org/web/20071103230842/http://cassandrahill.blogspot.com/">cj's chatter</a></li>
</ul>
</div>
<div class="sidebar-node">
<p><a href="http://web.archive.org/web/20071103230842/http://twitter.com/_sjs">
<img src="http://web.archive.org/web/20071103230842im_/http://sami.samhuri.net/assets/2007/6/26/icon_twitter.png" alt="[t]" /> twitter</a></p>
</div>
<div class="sidebar-node">
<p><a href="http://web.archive.org/web/20071103230842/http://mephistoblog.com/" class="powered"><img alt="mephisto-badge-tiny" src="http://web.archive.org/web/20071103230842im_/http://sami.samhuri.net/images/mephisto-badge-tiny.png" /></a></p>
</div>
</div>
<br style="clear:both;" />
</div>
<div id="footer">
<hr />
<p><a href="http://web.archive.org/web/20071103230842/http://sami.samhuri.net/">sjs</a></p>
<ul>
<li>powered by <a href="http://web.archive.org/web/20071103230842/http://mephistoblog.com/">Mephisto</a> /
styled with <a href="http://web.archive.org/web/20071103230842/http://quotedprintable.com/pages/scribbish">scribbish</a></li>
</ul>
</div>
</div>
<script src="http://web.archive.org/web/20071103230842js_/http://www.google-analytics.com/urchin.js" type="text/javascript"> </script>
<script type="text/javascript"> _uacct = "UA-214054-3"; urchinTracker(); </script>
<script src="http://web.archive.org/web/20071103230842js_/http://feeds.feedburner.com/~s/sjs" type="text/javascript" charset="utf-8"></script>
</body>
</html>
<!--
FILE ARCHIVED ON 23:08:42 Nov 3, 2007 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 2:57:50 Aug 21, 2011.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
-->

File diff suppressed because it is too large Load diff

View file

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>NodeHtmlParser</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
</natures>
</projectDescription>

View file

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>NodeHtmlParser</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
</natures>
</projectDescription>

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path=""/>
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.baseBrowserLibrary"/>
</classpath>

View file

@ -1 +0,0 @@
org.eclipse.wst.jsdt.launching.baseBrowserLibrary

View file

@ -1,108 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Node.js HTML Parser</title>
<style type="text/css">
.good {
color: #363;
}
.bad {
color: #633;
font-style: italic;
}
</style>
<script language="JavaScript">
if ((typeof JSON) != "object") {
var head = document.getElementsByTagName("head")[0];
var script = document.createElement('script');
script.type = "text/javascript";
script.src = "json2.js";
head.insertBefore(script, head.firstChild)
}
</script>
<script language="JavaScript" src="lib/node-htmlparser.js"></script>
<script language="JavaScript" src="tests/01-basic.js"></script>
<script language="JavaScript" src="tests/02-single_tag_1.js"></script>
<script language="JavaScript" src="tests/03-single_tag_2.js"></script>
<script language="JavaScript" src="tests/04-unescaped_in_script.js"></script>
<script language="JavaScript" src="tests/05-tags_in_comment.js"></script>
<script language="JavaScript" src="tests/06-comment_in_script.js"></script>
<script language="JavaScript" src="tests/07-unescaped_in_style.js"></script>
<script language="JavaScript" src="tests/08-extra_spaces_in_tag.js"></script>
<script language="JavaScript" src="tests/09-unquoted_attrib.js"></script>
<script language="JavaScript" src="tests/10-singular_attribute.js"></script>
<script language="JavaScript" src="tests/11-text_outside_tags.js"></script>
<script language="JavaScript" src="tests/12-text_only.js"></script>
<script language="JavaScript" src="tests/13-comment_in_text.js"></script>
<script language="JavaScript" src="tests/14-comment_in_text_in_script.js"></script>
<script language="JavaScript" src="tests/15-non-verbose.js"></script>
<script language="JavaScript" src="tests/16-ignore_whitespace.js"></script>
<script language="JavaScript" src="tests/17-xml_namespace.js"></script>
<script language="JavaScript" src="tests/18-enforce_empty_tags.js"></script>
<script language="JavaScript" src="tests/19-ignore_empty_tags.js"></script>
<script language="JavaScript" src="tests/20-rss.js"></script>
<script language="JavaScript" src="tests/21-atom.js"></script>
<script language="JavaScript" src="tests/22-position_data.js"></script>
<!-- //TODO: dynamic loading of test files -->
</head>
<body style="font-size: small; font-family:Arial, Helvetica, sans-serif;">
<script language="JavaScript">
var chunkSize = 5;
var testCount = 0;
var failedCount = 0;
while (Tautologistics.NodeHtmlParser.Tests.length) {
testCount++;
var test = Tautologistics.NodeHtmlParser.Tests.shift();
try {
var handlerCallback = function handlerCallback (error) {
if (error)
document.write("<hr>Handler error: " + error + "<hr>");
}
var handler = (test.type == "rss") ?
new Tautologistics.NodeHtmlParser.RssHandler(handlerCallback, test.options.handler)
:
new Tautologistics.NodeHtmlParser.DefaultHandler(handlerCallback, test.options.handler)
;
var parser = new Tautologistics.NodeHtmlParser.Parser(handler, test.options.parser);
document.write("<b>" + test.name + "</b>: ");
parser.parseComplete(test.html);
var resultComplete = handler.dom;
var chunkPos = 0;
parser.reset();
while (chunkPos < test.html.length) {
parser.parseChunk(test.html.substring(chunkPos, chunkPos + chunkSize));
chunkPos += chunkSize;
}
parser.done();
var resultChunk = handler.dom;
var testResult =
JSON.stringify(resultComplete).toString() === JSON.stringify(test.expected).toString()
&&
JSON.stringify(resultChunk).toString() === JSON.stringify(test.expected).toString()
;
document.write(testResult ? "<font class='good'>passed</font>" : "<font class='bad'>FAILED</font>");
if (!testResult) {
failedCount++;
document.write("<pre>");
document.write("<b>Complete</b>\n");
document.write(JSON.stringify(resultComplete, null, 2));
document.write("<b>Chunked</b>\n");
document.write(JSON.stringify(resultChunk, null, 2));
document.write("<h2>Expected</h2>\n");
document.write(JSON.stringify(test.expected, null, 2));
document.write("</pre>");
}
} catch (ex) {
document.write("<h1>Exception occured during test: " + ex + "</h1>")
}
document.write("<br>");
}
document.write("<hr>");
document.write("Total tests: " + testCount + "<br>");
document.write("Failed tests: " + failedCount + "<br>");
</script>
</body>
</html>

View file

@ -1,108 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Node.js HTML Parser</title>
<style type="text/css">
.good {
color: #363;
}
.bad {
color: #633;
font-style: italic;
}
</style>
<script language="JavaScript">
if ((typeof JSON) != "object") {
var head = document.getElementsByTagName("head")[0];
var script = document.createElement('script');
script.type = "text/javascript";
script.src = "json2.js";
head.insertBefore(script, head.firstChild)
}
</script>
<script language="JavaScript" src="lib/node-htmlparser.min.js"></script>
<script language="JavaScript" src="tests/01-basic.js"></script>
<script language="JavaScript" src="tests/02-single_tag_1.js"></script>
<script language="JavaScript" src="tests/03-single_tag_2.js"></script>
<script language="JavaScript" src="tests/04-unescaped_in_script.js"></script>
<script language="JavaScript" src="tests/05-tags_in_comment.js"></script>
<script language="JavaScript" src="tests/06-comment_in_script.js"></script>
<script language="JavaScript" src="tests/07-unescaped_in_style.js"></script>
<script language="JavaScript" src="tests/08-extra_spaces_in_tag.js"></script>
<script language="JavaScript" src="tests/09-unquoted_attrib.js"></script>
<script language="JavaScript" src="tests/10-singular_attribute.js"></script>
<script language="JavaScript" src="tests/11-text_outside_tags.js"></script>
<script language="JavaScript" src="tests/12-text_only.js"></script>
<script language="JavaScript" src="tests/13-comment_in_text.js"></script>
<script language="JavaScript" src="tests/14-comment_in_text_in_script.js"></script>
<script language="JavaScript" src="tests/15-non-verbose.js"></script>
<script language="JavaScript" src="tests/16-ignore_whitespace.js"></script>
<script language="JavaScript" src="tests/17-xml_namespace.js"></script>
<script language="JavaScript" src="tests/18-enforce_empty_tags.js"></script>
<script language="JavaScript" src="tests/19-ignore_empty_tags.js"></script>
<script language="JavaScript" src="tests/20-rss.js"></script>
<script language="JavaScript" src="tests/21-atom.js"></script>
<script language="JavaScript" src="tests/22-position_data.js"></script>
<!-- //TODO: dynamic loading of test files -->
</head>
<body style="font-size: small; font-family:Arial, Helvetica, sans-serif;">
<script language="JavaScript">
var chunkSize = 5;
var testCount = 0;
var failedCount = 0;
while (Tautologistics.NodeHtmlParser.Tests.length) {
testCount++;
var test = Tautologistics.NodeHtmlParser.Tests.shift();
try {
var handlerCallback = function handlerCallback (error) {
if (error)
document.write("<hr>Handler error: " + error + "<hr>");
}
var handler = (test.type == "rss") ?
new Tautologistics.NodeHtmlParser.RssHandler(handlerCallback, test.options.handler)
:
new Tautologistics.NodeHtmlParser.DefaultHandler(handlerCallback, test.options.handler)
;
var parser = new Tautologistics.NodeHtmlParser.Parser(handler, test.options.parser);
document.write("<b>" + test.name + "</b>: ");
parser.parseComplete(test.html);
var resultComplete = handler.dom;
var chunkPos = 0;
parser.reset();
while (chunkPos < test.html.length) {
parser.parseChunk(test.html.substring(chunkPos, chunkPos + chunkSize));
chunkPos += chunkSize;
}
parser.done();
var resultChunk = handler.dom;
var testResult =
JSON.stringify(resultComplete).toString() === JSON.stringify(test.expected).toString()
&&
JSON.stringify(resultChunk).toString() === JSON.stringify(test.expected).toString()
;
document.write(testResult ? "<font class='good'>passed</font>" : "<font class='bad'>FAILED</font>");
if (!testResult) {
failedCount++;
document.write("<pre>");
document.write("<b>Complete</b>\n");
document.write(JSON.stringify(resultComplete, null, 2));
document.write("<b>Chunked</b>\n");
document.write(JSON.stringify(resultChunk, null, 2));
document.write("<h2>Expected</h2>\n");
document.write(JSON.stringify(test.expected, null, 2));
document.write("</pre>");
}
} catch (ex) {
document.write("<h1>Exception occured during test: " + ex + "</h1>")
}
document.write("<br>");
}
document.write("<hr>");
document.write("Total tests: " + testCount + "<br>");
document.write("Failed tests: " + failedCount + "<br>");
</script>
</body>
</html>

View file

@ -1,33 +0,0 @@
v1.7.2
* Document position feature fixed to work correctly with chunked parsing
v1.7.1
* Document position feature disabled until it works correctly with chunked parsing
v1.7.0
* Empty tag checking switch to being case insensitive [fgnass]
* Added feature to include document position (row, col) in element data [fgnass]
* Added parser option "includeLocation" to enable document position data
v1.6.4
* Fixed 'prevElement' error [Swizec]
v1.6.3
* Updated to support being an npm package
* Fixed DomUtils.testElement()
v1.6.1
* Optimized DomUtils by up to 2-3x
v1.6.0
* Added support for RSS/Atom feeds
v1.5.0
* Added DefaultHandler option "enforceEmptyTags" so that XML can be parsed correctly
v1.4.2
* Added tests for parsing XML with namespaces
v1.4.1
* Added minified version

View file

@ -1,18 +0,0 @@
Copyright 2010, Chris Winberry <chris@winberry.net>. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

View file

@ -1,186 +0,0 @@
#NodeHtmlParser
A forgiving HTML/XML/RSS parser written in JS for both the browser and NodeJS (yes, despite the name it works just fine in any modern browser). The parser can handle streams (chunked data) and supports custom handlers for writing custom DOMs/output.
##Installing
npm install htmlparser
##Running Tests
###Run tests under node:
node runtests.js
###Run tests in browser:
View runtests.html in any browser
##Usage In Node
var htmlparser = require("node-htmlparser");
var rawHtml = "Xyz <script language= javascript>var foo = '<<bar>>';< / script><!--<!-- Waah! -- -->";
var handler = new htmlparser.DefaultHandler(function (error, dom) {
if (error)
[...do something for errors...]
else
[...parsing done, do something...]
});
var parser = new htmlparser.Parser(handler);
parser.parseComplete(rawHtml);
sys.puts(sys.inspect(handler.dom, false, null));
##Usage In Browser
var handler = new Tautologistics.NodeHtmlParser.DefaultHandler(function (error, dom) {
if (error)
[...do something for errors...]
else
[...parsing done, do something...]
});
var parser = new Tautologistics.NodeHtmlParser.Parser(handler);
parser.parseComplete(document.body.innerHTML);
alert(JSON.stringify(handler.dom, null, 2));
##Example output
[ { raw: 'Xyz ', data: 'Xyz ', type: 'text' }
, { raw: 'script language= javascript'
, data: 'script language= javascript'
, type: 'script'
, name: 'script'
, attribs: { language: 'javascript' }
, children:
[ { raw: 'var foo = \'<bar>\';<'
, data: 'var foo = \'<bar>\';<'
, type: 'text'
}
]
}
, { raw: '<!-- Waah! -- '
, data: '<!-- Waah! -- '
, type: 'comment'
}
]
##Streaming To Parser
while (...) {
...
parser.parseChunk(chunk);
}
parser.done();
##Parsing RSS/Atom Feeds
new htmlparser.RssHandler(function (error, dom) {
...
});
##DefaultHandler Options
###Usage
var handler = new htmlparser.DefaultHandler(
function (error) { ... }
, { verbose: false, ignoreWhitespace: true }
);
###Option: ignoreWhitespace
Indicates whether the DOM should exclude text nodes that consists solely of whitespace. The default value is "false".
####Example: true
The following HTML:
<font>
<br>this is the text
<font>
becomes:
[ { raw: 'font'
, data: 'font'
, type: 'tag'
, name: 'font'
, children:
[ { raw: 'br', data: 'br', type: 'tag', name: 'br' }
, { raw: 'this is the text\n'
, data: 'this is the text\n'
, type: 'text'
}
, { raw: 'font', data: 'font', type: 'tag', name: 'font' }
]
}
]
####Example: false
The following HTML:
<font>
<br>this is the text
<font>
becomes:
[ { raw: 'font'
, data: 'font'
, type: 'tag'
, name: 'font'
, children:
[ { raw: '\n\t', data: '\n\t', type: 'text' }
, { raw: 'br', data: 'br', type: 'tag', name: 'br' }
, { raw: 'this is the text\n'
, data: 'this is the text\n'
, type: 'text'
}
, { raw: 'font', data: 'font', type: 'tag', name: 'font' }
]
}
]
###Option: verbose
Indicates whether to include extra information on each node in the DOM. This information consists of the "raw" attribute (original, unparsed text found between "<" and ">") and the "data" attribute on "tag", "script", and "comment" nodes. The default value is "true".
####Example: true
The following HTML:
<a href="test.html">xxx</a>
becomes:
[ { raw: 'a href="test.html"'
, data: 'a href="test.html"'
, type: 'tag'
, name: 'a'
, attribs: { href: 'test.html' }
, children: [ { raw: 'xxx', data: 'xxx', type: 'text' } ]
}
]
####Example: false
The following HTML:
<a href="test.html">xxx</a>
becomes:
[ { type: 'tag'
, name: 'a'
, attribs: { href: 'test.html' }
, children: [ { data: 'xxx', type: 'text' } ]
}
]
###Option: enforceEmptyTags
Indicates whether the DOM should prevent children on tags marked as empty in the HTML spec. Typically this should be set to "true" HTML parsing and "false" for XML parsing. The default value is "true".
####Example: true
The following HTML:
<link>text</link>
becomes:
[ { raw: 'link', data: 'link', type: 'tag', name: 'link' }
, { raw: 'text', data: 'text', type: 'text' }
]
####Example: false
The following HTML:
<link>text</link>
becomes:
[ { raw: 'link'
, data: 'link'
, type: 'tag'
, name: 'link'
, children: [ { raw: 'text', data: 'text', type: 'text' } ]
}
]
##DomUtils
###TBD (see utils_example.js for now)
##Related Projects
Looking for CSS selectors to search the DOM? Try Node-SoupSelect, a port of SoupSelect to NodeJS: http://github.com/harryf/node-soupselect
There's also a port of hpricot to NodeJS that uses node-HtmlParser for HTML parsing: http://github.com/silentrob/Apricot

View file

@ -1,35 +0,0 @@
[ { raw: 'html',
data: 'html',
type: 'tag',
location: { line: 1, col: 1 },
name: 'html',
children:
[ { raw: '\n\n',
data: '\n\n',
type: 'text',
location: { line: 1, col: 5 } },
{ raw: 'title',
data: 'title',
type: 'tag',
location: { line: 3, col: 1 },
name: 'title',
children:
[ { raw: 'The Title',
data: 'The Title',
type: 'text',
location: { line: 3, col: 6 } } ] },
{ raw: 'body',
data: 'body',
type: 'tag',
location: { line: 3, col: 1 },
name: 'body',
children:
[ { raw: '\nHello world\n\n',
data: '\nHello world\n\n',
type: 'text',
location: { line: 3, col: 5 } } ] },
{ raw: '\n\n',
data: '\n\n',
type: 'text',
location: { line: 6, col: 6 } } ] } ]

View file

@ -1,35 +0,0 @@
[ { raw: 'html',
data: 'html',
type: 'tag',
location: { line: 1, col: 0 },
name: 'html',
children:
[ { raw: '\n\n',
data: '\n\n',
type: 'text',
location: { line: 1, col: 5 } },
{ raw: 'title',
data: 'title',
type: 'tag',
location: { line: 1, col: 0 },
name: 'title',
children:
[ { raw: 'The Title',
data: 'The Title',
type: 'text',
location: { line: 1, col: 0 } } ] },
{ raw: 'body',
data: 'body',
type: 'tag',
location: { line: 1, col: 0 },
name: 'body',
children:
[ { raw: '\nHello world\n\n',
data: '\nHello world\n\n',
type: 'text',
location: { line: 1, col: 0 } } ] },
{ raw: '\n\n',
data: '\n\n',
type: 'text',
location: { line: 1, col: 0 } } ] } ]

Some files were not shown because too many files have changed in this diff Show more