diff --git a/bin/rss.rb b/bin/rss.rb
index 4b74116..6a319c5 100755
--- a/bin/rss.rb
+++ b/bin/rss.rb
@@ -62,7 +62,7 @@ class Blag
def find_post dir, slug
# technically should look for slug.md, slug.html.md, etc.
- File.join dir, slug + '.html.md'
+ File.join dir, slug + '.md'
end
def posts
diff --git a/public/css/style.css.less b/public/css/style.css.less
index a10b90c..0a7650b 100644
--- a/public/css/style.css.less
+++ b/public/css/style.css.less
@@ -291,7 +291,13 @@ ul.audio audio {
vertical-align: middle;
}
-table.code pre {
- width: 100%;
- overflow: scroll;
+pre {
+ background-color: darken(@background, 5%);
+ padding: 0.5rem;
+}
+
+pre.line-numbers {
+ float: left;
+ margin-top: 0;
+ color: #888;
}
diff --git a/public/css/typocode.css b/public/css/typocode.css
index 0f2a043..d7ef7ee 100644
--- a/public/css/typocode.css
+++ b/public/css/typocode.css
@@ -42,13 +42,11 @@
background-color:#eee;
padding:2px;
margin:5px;
- margin-left:1em;
- margin-bottom:1em;
}
.typocode pre {
- padding: 0px;
- margin: 0px;
+ padding: 0.2rem 0.5rem;
+ margin: 0;
border: none;
background: transparent;
font-family: monospace;
@@ -58,20 +56,7 @@
.typocode .lineno {
text-align: right;
- /* color: #B00;*/
+ color: #B00;
font-family: monospace;
- padding-right: 1em;
-}
-
-code {
- font-family: "Andale Mono", "Lucida Typewriter", "Bitstream Vera Sans Mono", fixed-width, monospace;
- font-size: 0.9em;
-}
-
-pre {
- background: #555;
- border: 1px dashed #5189ea;
- margin-bottom: 30px;
- margin-top: -10px;
- padding: 5px;
+ padding-right: 1rem;
}
diff --git a/public/f/island.css b/public/f/island.css
deleted file mode 100644
index f1c16a0..0000000
--- a/public/f/island.css
+++ /dev/null
@@ -1,438 +0,0 @@
-/* Island screen styles */
-
-body {
- font: 1em/1.15em "Hoefler Text", Georgia, "Adobe Garamond Pro", Palatino, "Times New Roman", serif;
- color: #eee;
- background: #000;
- margin: 5px;
-}
-
-#leftcolumn {
- width: 23%;
- float: right;
- margin: 0 10px 0 20px;
- text-align: right;
-}
-
-#header {
-/* text-align: center;*/
-}
-
-#content {
-/* padding-top: 50px;*/
- width: 72%;
- float: left;
-}
-
-#main {
-}
-
-#search {
- padding: 3px;
-}
-
-#sidebar {
-}
-
-#footer {
- text-align: center;
-/* background: #333;*/
- border-top: 1px solid #666;
- padding-bottom: 5px;
- clear: both;
-}
-
-#footer a { border: none; }
-#footer img { border: none; }
-
-/*+-------------------------------------------+
-| LINKS |
-+-------------------------------------------+*/
-
-a {
- color: #5189ea;
- text-decoration: none;
- border-bottom: 1px dotted #3179ca;
- padding-top: 2px;
-}
-
-a:hover {
- background: #ffa;
- color: #000;
-}
-
-/*+-------------------------------------------+
-| UTILITY |
-+-------------------------------------------+*/
-
-h1, h2, h3, h4, h5, h6 {
- margin: 0;
- padding: 0;
-}
-
-form, div { padding: 0; margin: 0; }
-p { margin: 0 0 1em 0; padding: 0; }
-img {
- border: 0;
- padding: 5px;
-}
-
-/*+-------------------------------------------+
-| HEADER |
-+-------------------------------------------+*/
-
-#header h1 {
- margin-top: 30px;
- font-size: 5em;
-}
-
-#header h1 a {
- color: #ffa;
- background: inherit;
- text-decoration: none;
- border-bottom: none;
-}
-
-#header h1 a:hover {
- background: #000;
-}
-
-#header h2 {
- color: #555;
- padding-top: .2em;
- font-size: 1.2em;
- letter-spacing: 2px;
-}
-
-/*+-------------------------------------------+
-| SEARCH |
-+-------------------------------------------+*/
-
-#sform {
- padding-top: 15px;
-}
-
-#search-results {
- text-align: left;
- padding-bottom: 5px;
- border-bottom: 1px dotted #666;
-}
-
-/*+-------------------------------------------+
-| POST |
-+-------------------------------------------+*/
-
-.post {
- padding: 10px 0 10px 0;
- margin: 5px 0 15px 5px;
-/* clear: left;*/
-}
-
-.post h2 {
- font-size: 140%;
- line-height: 1.4em;
- margin: 5px 0;
-/* padding-top: 15px;*/
-}
-
-.post h3 {
- margin: 5px 0;
-}
-
-.post h2 a {
- color: #fff;
- text-decoration: none;
- border: none;
-}
-
-.post h2 a:before {
- content: '# ';
-}
-
-.post h2 a:hover {
- color: #ffa;
- background: #000;
-}
-
-.post p {
- margin-left: 5px;
-}
-
-p.meta {
- font-size: 75%;
- text-align: right;
- margin-right: 15px;
-/* border-right: 1px solid #999;*/
-/* float: left;*/
-/* width: 75px;*/
-}
-
-p.auth {
- font-size: 85%;
- font-weight: bold;
- color: #999;
-}
-
-/*+-------------------------------------------+
-| COMMENTS |
-+-------------------------------------------+*/
-
-.comment-list li, #preview {
- background: #666;
- padding: 5px;
- margin-bottom: 8px;
- color: #eee;
- /*border-right: 20px solid #d3e0ea;*/
- min-height: 60px;
-}
-
-.gravatar {
- float: right;
- padding: 0 5px;
-}
-
-/*+-------------------------------------------+
-| SIDEBAR |
-+-------------------------------------------+*/
-
-#sidebar h3 {
- font-size: 110%;
- line-height: 1.5em;
- color: #ff9d47;
- margin-top: 15px;
- margin-bottom: 2px;
- text-transform: lowercase;
-}
-
-#sidebar h3:before {
- content: "<< ";
- font-size: small;
-}
-#sidebar h3:after {
- content: " >>";
- font-size: small;
-}
-
-#sidebar h3 a {
- color: #ff9d47;
- border-bottom: 1px dotted #ff9d47;
-}
-
-#sidebar h3 a:hover {
- color: #000;
- background: #ffa;
-}
-
-#sidebar ul {
- text-align: right;
- margin: 0;
- padding: 0;
- list-style-type: none;
-}
-
-#sidebar ul li {
-/* background: url(http://web.archive.org/web/20060321041209/http://sami.samhuri.net/images/theme/small_arrow.png) 45% no-repeat;*/
-/* padding-left: 12px;*/
-}
-
-#sidebar a.feed,
-#sidebar a.feed:link,
-#sidebar a.feed:hover {
- display: inline;
- border: none;
- background: #000;
-}
-
-/*+-------------------------------------------+
-| FOOTER |
-+-------------------------------------------+*/
-
-#footer ul {
- margin: 0;
- padding: 10px 0 0 0;
- list-style: none;
-}
-
-#footer ul li {
- display: inline;
- margin: 0;
- padding: 0 5px 0 0;
- font-size: 100%;
-}
-
-/*+-------------------------------------------+
-| FORMS |
-+-------------------------------------------+*/
-
-input, textarea, select {
- border: 1px solid #8ab3d1;
- background: #f9f9f9;
-}
-
-.frm-tbl td { vertical-align: top; padding: 5px; }
-td#frm-btns { text-align: right; }
-
-#comment_body { height: 220px; }
-#form-submit-button { background: #d3e0ea; }
-
-/*+-------------------------------------------+
-| MISC |
-+-------------------------------------------+*/
-
-.powered { border: none; }
-.powered img { margin-top: 20px; }
-.pullquote {
- width: 30%;
- float:right;
- font: 150%/1.5em Times, Helvetica, "Times New Roman", serif;
- color: #666;
- margin:10px;
- background: url(http://web.archive.org/web/20060321041209/http://sami.samhuri.net/images/theme/q-close.gif) no-repeat 70% 100% !important;
- background /**/:url(); /* removing quote graphic in IE5+ */
- padding: 0 25px 5px 0;
-}
-.pullquote:first-letter {
- background: url(http://web.archive.org/web/20060321041209/http://sami.samhuri.net/images/theme/q-open.gif) no-repeat left top !important;
- padding:5px 2px 10px 35px!important;
- padding /**/:0px; /* resetting padding in IE5+ */
- background /**/: url(); /* removing quote graphic in IE5+ */
-}
-
-.light-bg { background: #666; padding: 2px; }
-.clearfix:after {
- content: ".";
- display: block;
- height: 0;
- clear: both;
- visibility: hidden;
-}
-
-#errors {
- color: red;
-}
-
-.admintools {
- float: right;
- background-color: #fff;
- font-size: smaller;
- padding: 0 2px;
- margin: 0 1px;
- color: #ccc;
- border: 1px solid #ccc;
-}
-
-.admintools:hover {
- color: #c00;
- border: 1px solid #c00;
-}
-
-a[name] { border: none; }
-
-/* Hides from IE-mac \*/
-* html .clearfix {height: 1%;}
-/* End hide from IE-mac */
-
-#categories li em, #archives li em
-{
- color: #98B4D1;
- font-size: smaller;
-}
-
-/* Syntax highlighting */
-.typocode_ruby .normal {}
-.typocode_ruby .comment { color: #005; font-style: italic; }
-.typocode_ruby .keyword { color: #A00; font-weight: bold; }
-.typocode_ruby .method { color: #077; }
-.typocode_ruby .class { color: #074; }
-.typocode_ruby .module { color: #050; }
-.typocode_ruby .punct { color: #447; font-weight: bold; }
-.typocode_ruby .symbol { color: #099; }
-.typocode_ruby .string { color: #944; background: #FFE; }
-.typocode_ruby .char { color: #F07; }
-.typocode_ruby .ident { color: #004; }
-.typocode_ruby .constant { color: #07F; }
-.typocode_ruby .regex { color: #B66; background: #FEF; }
-.typocode_ruby .number { color: #F99; }
-.typocode_ruby .attribute { color: #7BB; }
-.typocode_ruby .global { color: #7FB; }
-.typocode_ruby .expr { color: #227; }
-.typocode_ruby .escape { color: #277; }
-.typocode_xml .normal {}
-.typocode_xml .namespace { color: #B66; font-weight: bold; }
-.typocode_xml .tag { color: #F88; }
-.typocode_xml .comment { color: #005; font-style: italic; }
-.typocode_xml .punct { color: #447; font-weight: bold; }
-.typocode_xml .string { color: #944; }
-.typocode_xml .number { color: #F99; }
-.typocode_xml .attribute { color: #BB7; }
-.typocode_yaml .normal {}
-.typocode_yaml .document { font-weight: bold; color: #07F; }
-.typocode_yaml .type { font-weight: bold; color: #05C; }
-.typocode_yaml .key { color: #F88; }
-.typocode_yaml .comment { color: #005; font-style: italic; }
-.typocode_yaml .punct { color: #447; font-weight: bold; }
-.typocode_yaml .string { color: #944; }
-.typocode_yaml .number { color: #F99; }
-.typocode_yaml .time { color: #F99; }
-.typocode_yaml .date { color: #F99; }
-.typocode_yaml .ref { color: #944; }
-.typocode_yaml .anchor { color: #944; }
-
-.typocode {
- background-color:#eee;
- padding:2px;
- margin:5px;
- margin-left:1em;
- margin-bottom:1em;
-}
-
-.typocode pre {
- padding: 0px;
- margin: 0px;
- border: none;
- background: transparent;
- font-family: monospace;
- overflow:auto;
-}
-
-
-.typocode .lineno {
- text-align: right;
- /* color: #B00;*/
- font-family: monospace;
- padding-right: 1em;
-}
-
-code {
- font-family: "Andale Mono", "Lucida Typewriter", "Bitstream Vera Sans Mono", fixed-width, monospace;
-/* font-size: 120%;*/
-}
-
-pre {
- background: #555;
- border: 1px dashed #5189ea;
- margin-bottom: 30px;
- margin-top: -10px;
- padding: 5px;
-}
-
-/*+-------------------------------------------+
-| TAGLIST |
-+-------------------------------------------+*/
-
-ul#taglist li {
- display: inline;
- line-height: 3em;
-}
-
-.tags .tags0 { font-size: 1.0em; }
-.tags .tags1 { font-size: 1.2em; }
-.tags .tags2 { font-size: 1.4em; }
-.tags .tags3 { font-size: 1.6em; }
-.tags .tags4 { font-size: 1.8em; }
-.tags .tags5 { font-size: 2.0em; }
-.tags .tags6 { font-size: 2.2em; }
-.tags .tags7 { font-size: 2.4em; }
-.tags .tags8 { font-size: 2.6em; }
-.tags .tags9 { font-size: 2.8em; }
-.tags .tags10 { font-size: 3.0em; }
diff --git a/public/posts/2006/02/_data.json b/public/posts/2006/02/_data.json
index dd264f9..15f1164 100644
--- a/public/posts/2006/02/_data.json
+++ b/public/posts/2006/02/_data.json
@@ -85,7 +85,7 @@
"author": "Sami Samhuri",
"url": "/posts/2006/02/obligatory-post-about-ruby-on-rails",
"styles": [
- "typocode"
+ "/css/typocode.css"
]
},
"textmate-snippets-for-rails-assertions": {
@@ -118,7 +118,10 @@
"textmate"
],
"author": "Sami Samhuri",
- "url": "/posts/2006/02/textmate-move-selection-to-self-down"
+ "url": "/posts/2006/02/textmate-move-selection-to-self-down",
+ "styles": [
+ "/css/typocode.css"
+ ]
},
"textmate-insert-text-into-self-down": {
"title": "TextMate: Insert text into self.down",
@@ -137,7 +140,7 @@
"author": "Sami Samhuri",
"url": "/posts/2006/02/textmate-insert-text-into-self-down",
"styles": [
- "typocode"
+ "/css/typocode.css"
]
},
"intelligent-migration-snippets-0_1-for-textmate": {
@@ -172,7 +175,7 @@
"author": "Sami Samhuri",
"url": "/posts/2006/02/sjs-rails-bundle-0_2-for-textmate",
"styles": [
- "typocode"
+ "/css/typocode.css"
]
}
}
diff --git a/public/posts/2006/02/first-post.html.md b/public/posts/2006/02/first-post.md
similarity index 100%
rename from public/posts/2006/02/first-post.html.md
rename to public/posts/2006/02/first-post.md
diff --git a/public/posts/2006/02/girlfriend-x.html.md b/public/posts/2006/02/girlfriend-x.md
similarity index 100%
rename from public/posts/2006/02/girlfriend-x.html.md
rename to public/posts/2006/02/girlfriend-x.md
diff --git a/public/posts/2006/02/intelligent-migration-snippets-0_1-for-textmate.html.md b/public/posts/2006/02/intelligent-migration-snippets-0_1-for-textmate.md
similarity index 100%
rename from public/posts/2006/02/intelligent-migration-snippets-0_1-for-textmate.html.md
rename to public/posts/2006/02/intelligent-migration-snippets-0_1-for-textmate.md
diff --git a/public/posts/2006/02/jump-to-viewcontroller-in-textmate.html.md b/public/posts/2006/02/jump-to-viewcontroller-in-textmate.md
similarity index 100%
rename from public/posts/2006/02/jump-to-viewcontroller-in-textmate.html.md
rename to public/posts/2006/02/jump-to-viewcontroller-in-textmate.md
diff --git a/public/posts/2006/02/obligatory-post-about-ruby-on-rails.html.md b/public/posts/2006/02/obligatory-post-about-ruby-on-rails.md
similarity index 100%
rename from public/posts/2006/02/obligatory-post-about-ruby-on-rails.html.md
rename to public/posts/2006/02/obligatory-post-about-ruby-on-rails.md
diff --git a/public/posts/2006/02/sjs-rails-bundle-0_2-for-textmate.html.md b/public/posts/2006/02/sjs-rails-bundle-0_2-for-textmate.md
similarity index 100%
rename from public/posts/2006/02/sjs-rails-bundle-0_2-for-textmate.html.md
rename to public/posts/2006/02/sjs-rails-bundle-0_2-for-textmate.md
diff --git a/public/posts/2006/02/some-textmate-snippets-for-rails-migrations.html.md b/public/posts/2006/02/some-textmate-snippets-for-rails-migrations.md
similarity index 100%
rename from public/posts/2006/02/some-textmate-snippets-for-rails-migrations.html.md
rename to public/posts/2006/02/some-textmate-snippets-for-rails-migrations.md
diff --git a/public/posts/2006/02/textmate-insert-text-into-self-down.html.md b/public/posts/2006/02/textmate-insert-text-into-self-down.md
similarity index 96%
rename from public/posts/2006/02/textmate-insert-text-into-self-down.html.md
rename to public/posts/2006/02/textmate-insert-text-into-self-down.md
index 93fba90..20a4a88 100644
--- a/public/posts/2006/02/textmate-insert-text-into-self-down.html.md
+++ b/public/posts/2006/02/textmate-insert-text-into-self-down.md
@@ -46,9 +46,9 @@
The macro I'm thinking of to invoke this is tab-triggered and will simply:
-- Select word (⌃W)
- - Delete (⌫)
- - Select to end of file (⇧⌘↓)
+- Select word (
⌃W)
+ - Delete (
⌫)
+ - Select to end of file (
⇧⌘↓)
- Run command "Put in self.down"
diff --git a/public/posts/2006/02/textmate-move-selection-to-self-down.html.md b/public/posts/2006/02/textmate-move-selection-to-self-down.md
similarity index 100%
rename from public/posts/2006/02/textmate-move-selection-to-self-down.html.md
rename to public/posts/2006/02/textmate-move-selection-to-self-down.md
diff --git a/public/posts/2006/02/textmate-snippets-for-rails-assertions.html.md b/public/posts/2006/02/textmate-snippets-for-rails-assertions.md
similarity index 100%
rename from public/posts/2006/02/textmate-snippets-for-rails-assertions.html.md
rename to public/posts/2006/02/textmate-snippets-for-rails-assertions.md
diff --git a/public/posts/2006/02/touch-screen-on-steroids.html.md b/public/posts/2006/02/touch-screen-on-steroids.md
similarity index 100%
rename from public/posts/2006/02/touch-screen-on-steroids.html.md
rename to public/posts/2006/02/touch-screen-on-steroids.md
diff --git a/public/posts/2006/02/urban-extreme-gymnastics.html.md b/public/posts/2006/02/urban-extreme-gymnastics.md
similarity index 100%
rename from public/posts/2006/02/urban-extreme-gymnastics.html.md
rename to public/posts/2006/02/urban-extreme-gymnastics.md
diff --git a/public/posts/2006/03/generate-selfdown-in-your-rails-migrations.html.md b/public/posts/2006/03/generate-selfdown-in-your-rails-migrations.md
similarity index 100%
rename from public/posts/2006/03/generate-selfdown-in-your-rails-migrations.html.md
rename to public/posts/2006/03/generate-selfdown-in-your-rails-migrations.md
diff --git a/public/posts/2006/03/i-dont-mind-fairplay-either.html.md b/public/posts/2006/03/i-dont-mind-fairplay-either.md
similarity index 100%
rename from public/posts/2006/03/i-dont-mind-fairplay-either.html.md
rename to public/posts/2006/03/i-dont-mind-fairplay-either.md
diff --git a/public/posts/2006/03/spore.html.md b/public/posts/2006/03/spore.md
similarity index 100%
rename from public/posts/2006/03/spore.html.md
rename to public/posts/2006/03/spore.md
diff --git a/public/posts/2006/04/zsh-terminal-goodness-on-os-x.html.md b/public/posts/2006/04/zsh-terminal-goodness-on-os-x.md
similarity index 100%
rename from public/posts/2006/04/zsh-terminal-goodness-on-os-x.html.md
rename to public/posts/2006/04/zsh-terminal-goodness-on-os-x.md
diff --git a/public/posts/2006/05/os-x-and-fitts-law.html.md b/public/posts/2006/05/os-x-and-fitts-law.md
similarity index 100%
rename from public/posts/2006/05/os-x-and-fitts-law.html.md
rename to public/posts/2006/05/os-x-and-fitts-law.md
diff --git a/public/posts/2006/05/wikipediafs-on-linux-in-python.html.md b/public/posts/2006/05/wikipediafs-on-linux-in-python.md
similarity index 100%
rename from public/posts/2006/05/wikipediafs-on-linux-in-python.html.md
rename to public/posts/2006/05/wikipediafs-on-linux-in-python.md
diff --git a/public/posts/2006/06/apple-pays-attention-to-detail.html.md b/public/posts/2006/06/apple-pays-attention-to-detail.md
similarity index 100%
rename from public/posts/2006/06/apple-pays-attention-to-detail.html.md
rename to public/posts/2006/06/apple-pays-attention-to-detail.md
diff --git a/public/posts/2006/06/ich-bin-auslnder-und-spreche-nicht-gut-deutsch.html.md b/public/posts/2006/06/ich-bin-auslnder-und-spreche-nicht-gut-deutsch.md
similarity index 100%
rename from public/posts/2006/06/ich-bin-auslnder-und-spreche-nicht-gut-deutsch.html.md
rename to public/posts/2006/06/ich-bin-auslnder-und-spreche-nicht-gut-deutsch.md
diff --git a/public/posts/2006/06/never-buy-a-german-keyboard.html.md b/public/posts/2006/06/never-buy-a-german-keyboard.md
similarity index 100%
rename from public/posts/2006/06/never-buy-a-german-keyboard.html.md
rename to public/posts/2006/06/never-buy-a-german-keyboard.md
diff --git a/public/posts/2006/06/theres-nothing-regular-about-regular-expressions.html.md b/public/posts/2006/06/theres-nothing-regular-about-regular-expressions.md
similarity index 100%
rename from public/posts/2006/06/theres-nothing-regular-about-regular-expressions.html.md
rename to public/posts/2006/06/theres-nothing-regular-about-regular-expressions.md
diff --git a/public/posts/2006/07/class-method-instance-method-it-doesnt-matter-to-php.html.md b/public/posts/2006/07/class-method-instance-method-it-doesnt-matter-to-php.md
similarity index 100%
rename from public/posts/2006/07/class-method-instance-method-it-doesnt-matter-to-php.html.md
rename to public/posts/2006/07/class-method-instance-method-it-doesnt-matter-to-php.md
diff --git a/public/posts/2006/07/late-static-binding.html.md b/public/posts/2006/07/late-static-binding.md
similarity index 100%
rename from public/posts/2006/07/late-static-binding.html.md
rename to public/posts/2006/07/late-static-binding.md
diff --git a/public/posts/2006/07/ruby-and-rails-have-spoiled-me-rotten.html.md b/public/posts/2006/07/ruby-and-rails-have-spoiled-me-rotten.md
similarity index 100%
rename from public/posts/2006/07/ruby-and-rails-have-spoiled-me-rotten.html.md
rename to public/posts/2006/07/ruby-and-rails-have-spoiled-me-rotten.md
diff --git a/public/posts/2006/07/ubuntu-linux-for-linux-users-please.html.md b/public/posts/2006/07/ubuntu-linux-for-linux-users-please.md
similarity index 100%
rename from public/posts/2006/07/ubuntu-linux-for-linux-users-please.html.md
rename to public/posts/2006/07/ubuntu-linux-for-linux-users-please.md
diff --git a/public/posts/2006/07/working-with-the-zend-framework.html.md b/public/posts/2006/07/working-with-the-zend-framework.md
similarity index 100%
rename from public/posts/2006/07/working-with-the-zend-framework.html.md
rename to public/posts/2006/07/working-with-the-zend-framework.md
diff --git a/public/posts/2006/08/where-are-my-headphones.html.md b/public/posts/2006/08/where-are-my-headphones.md
similarity index 100%
rename from public/posts/2006/08/where-are-my-headphones.html.md
rename to public/posts/2006/08/where-are-my-headphones.md
diff --git a/public/posts/2006/09/buffalo-buffalo-buffalo-buffalo-buffalo-buffalo-buffalo-buffalo.html.md b/public/posts/2006/09/buffalo-buffalo-buffalo-buffalo-buffalo-buffalo-buffalo-buffalo.md
similarity index 100%
rename from public/posts/2006/09/buffalo-buffalo-buffalo-buffalo-buffalo-buffalo-buffalo-buffalo.html.md
rename to public/posts/2006/09/buffalo-buffalo-buffalo-buffalo-buffalo-buffalo-buffalo-buffalo.md
diff --git a/public/posts/2006/09/some-features-you-might-have-missed-in-itunes-7.html.md b/public/posts/2006/09/some-features-you-might-have-missed-in-itunes-7.md
similarity index 100%
rename from public/posts/2006/09/some-features-you-might-have-missed-in-itunes-7.html.md
rename to public/posts/2006/09/some-features-you-might-have-missed-in-itunes-7.md
diff --git a/public/posts/2006/12/coping-with-windows-xp-activiation-on-a-mac.html.md b/public/posts/2006/12/coping-with-windows-xp-activiation-on-a-mac.md
similarity index 100%
rename from public/posts/2006/12/coping-with-windows-xp-activiation-on-a-mac.html.md
rename to public/posts/2006/12/coping-with-windows-xp-activiation-on-a-mac.md
diff --git a/public/posts/2007/03/digg-v4-reply-to-replies-greasemonkey-script.html.md b/public/posts/2007/03/digg-v4-reply-to-replies-greasemonkey-script.md
similarity index 100%
rename from public/posts/2007/03/digg-v4-reply-to-replies-greasemonkey-script.html.md
rename to public/posts/2007/03/digg-v4-reply-to-replies-greasemonkey-script.md
diff --git a/public/posts/2007/03/diggscuss-0_9.html.md b/public/posts/2007/03/diggscuss-0_9.md
similarity index 100%
rename from public/posts/2007/03/diggscuss-0_9.html.md
rename to public/posts/2007/03/diggscuss-0_9.md
diff --git a/public/posts/2007/03/full-screen-cover-flow.html.md b/public/posts/2007/03/full-screen-cover-flow.md
similarity index 100%
rename from public/posts/2007/03/full-screen-cover-flow.html.md
rename to public/posts/2007/03/full-screen-cover-flow.md
diff --git a/public/posts/2007/04/a-triple-booting-schizophrenic-macbook.html.md b/public/posts/2007/04/a-triple-booting-schizophrenic-macbook.md
similarity index 88%
rename from public/posts/2007/04/a-triple-booting-schizophrenic-macbook.html.md
rename to public/posts/2007/04/a-triple-booting-schizophrenic-macbook.md
index b8cf2dc..c4e16c2 100644
--- a/public/posts/2007/04/a-triple-booting-schizophrenic-macbook.html.md
+++ b/public/posts/2007/04/a-triple-booting-schizophrenic-macbook.md
@@ -2,7 +2,7 @@ The steps are well documented so I won’t get into detail here but if you have
* Install OS X to a single partition filling your disk (optionally use your existing OS X intall)
* Install rEFIt (no need to reboot just yet)
- * Re-partition your disk into 3 partitions with diskutil resizeVolume, reboot and confirm it all works
+ * Re-partition your disk into 3 partitions with diskutil resizeVolume, reboot and confirm it all works
* Boot the Vista install DVD and install to disk0s4 aka Partition 4
* Install Gentoo (or other distro) to disk0s3 aka /dev/sda3
@@ -14,7 +14,7 @@ My initial experience with Vista is quite good. Sadly the
- 1
-2
-3
-4
- |
- # extend ActiveRecord::Base with find_or_create and find_or_initialize.
-ActiveRecord::Base.class_eval do
- include ActiveRecordExtensions
-end |
-
-
-
-
- 1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-11
-12
-13
-14
-15
-16
-17
-18
-19
-20
-21
-22
-23
-24
-25
-26
-27
-28
-29
-30
-31
-32
-33
-34
-35
-36
-37
-38
-39
-40
-41
- |
- module ActiveRecordExtensions
- def self.included(base)
- base.extend(ClassMethods)
- end
-
- module ClassMethods
- def find_or_initialize(params)
- find_or_do('initialize', params)
- end
-
- def find_or_create(params)
- find_or_do('create', params)
- end
-
- private
-
- # Find a record that matches the attributes given in the +params+ hash, or do +action+
- # to retrieve a new object with the given parameters and return that.
- def find_or_do(action, params)
- # if an id is given just find the record directly
- self.find(params[:id])
-
- rescue ActiveRecord::RecordNotFound => e
- attrs = {} # hash of attributes passed in params
-
- # search for valid attributes in params
- self.column_names.map(&:to_sym).each do |attrib|
- # skip unknown columns, and the id field
- next if params[attrib].nil? || attrib == :id
-
- attrs[attrib] = params[attrib]
- end
-
- # no valid params given, return nil
- return nil if attrs.empty?
-
- # call the appropriate ActiveRecord finder method
- self.send("find_or_#{action}_by_#{attrs.keys.join('_and_')}", *attrs.values)
- end
- end
-end |
-
-
diff --git a/public/posts/2007/04/activerecord-base_find_or_create-and-find_or_initialize.md b/public/posts/2007/04/activerecord-base_find_or_create-and-find_or_initialize.md
new file mode 100644
index 0000000..592cc98
--- /dev/null
+++ b/public/posts/2007/04/activerecord-base_find_or_create-and-find_or_initialize.md
@@ -0,0 +1,100 @@
+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.
+
+Enough chat, here's the self-explanatory code:
+
+1
+2
+3
+4
+
+# extend ActiveRecord::Base with find_or_create and find_or_initialize.
+ActiveRecord::Base.class_eval do
+ include ActiveRecordExtensions
+end
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+
+module ActiveRecordExtensions
+ def self.included(base)
+ base.extend(ClassMethods)
+ end
+
+ module ClassMethods
+ def find_or_initialize(params)
+ find_or_do('initialize', params)
+ end
+
+ def find_or_create(params)
+ find_or_do('create', params)
+ end
+
+ private
+
+ # Find a record that matches the attributes given in the +params+ hash, or do +action+
+ # to retrieve a new object with the given parameters and return that.
+ def find_or_do(action, params)
+ # if an id is given just find the record directly
+ self.find(params[:id])
+
+ rescue ActiveRecord::RecordNotFound => e
+ attrs = {} # hash of attributes passed in params
+
+ # search for valid attributes in params
+ self.column_names.map(&:to_sym).each do |attrib|
+ # skip unknown columns, and the id field
+ next if params[attrib].nil? || attrib == :id
+
+ attrs[attrib] = params[attrib]
+ end
+
+ # no valid params given, return nil
+ return nil if attrs.empty?
+
+ # call the appropriate ActiveRecord finder method
+ self.send("find_or_#{action}_by_#{attrs.keys.join('_and_')}", *attrs.values)
+ end
+ end
+end
diff --git a/public/posts/2007/04/funny-how-code-can-be-beautiful.html.md b/public/posts/2007/04/funny-how-code-can-be-beautiful.md
similarity index 100%
rename from public/posts/2007/04/funny-how-code-can-be-beautiful.html.md
rename to public/posts/2007/04/funny-how-code-can-be-beautiful.md
diff --git a/public/posts/2007/04/getting-to-know-vista.html.md b/public/posts/2007/04/getting-to-know-vista.md
similarity index 100%
rename from public/posts/2007/04/getting-to-know-vista.html.md
rename to public/posts/2007/04/getting-to-know-vista.md
diff --git a/public/posts/2007/04/quickly-inserting-millions-of-rows-with-mysql-innodb.html.md b/public/posts/2007/04/quickly-inserting-millions-of-rows-with-mysql-innodb.md
similarity index 79%
rename from public/posts/2007/04/quickly-inserting-millions-of-rows-with-mysql-innodb.html.md
rename to public/posts/2007/04/quickly-inserting-millions-of-rows-with-mysql-innodb.md
index 1c6d1c8..565e27d 100644
--- a/public/posts/2007/04/quickly-inserting-millions-of-rows-with-mysql-innodb.html.md
+++ b/public/posts/2007/04/quickly-inserting-millions-of-rows-with-mysql-innodb.md
@@ -22,9 +22,9 @@ According to [a post on a MySQL mailing list](http://lists.mysql.com/mysql/12924
### innodb_data_file_path ###
-On Gentoo this one bit me right in the ass, and I mentioned it above. It specifies how large the files used to store your data can be, and how many of them there are. The default setting is almost sane: ibdata1:10M:autoextend:max:128M. Limiting the total size to 128M caused my test to fail after inserting several million rows.
+On Gentoo this one bit me right in the ass, and I mentioned it above. It specifies how large the files used to store your data can be, and how many of them there are. The default setting is almost sane: ibdata1:10M:autoextend:max:128M. Limiting the total size to 128M caused my test to fail after inserting several million rows.
-Simply removing max:128M solves the problem. The resulting setting tells the InnoDB engine to use one file, named ibdata1 which is initially 10M in size and grows as required.
+Simply removing max:128M solves the problem. The resulting setting tells the InnoDB engine to use one file, named ibdata1 which is initially 10M in size and grows as required.
### innodb_log_file_size ###
@@ -36,10 +36,10 @@ Again I only went as far as the Gentoo config to learn about this setting. They
### Save my.cnf and restart mysqld ###
-That’s it for the MySQL config. Restart mysqld however you do that on your platform. sudo /etc/init.d/mysql restart should look familiar to many *nix users.
+That’s it for the MySQL config. Restart mysqld however you do that on your platform. sudo /etc/init.d/mysql restart should look familiar to many *nix users.
Now you should be able to insert dozens and indeed hundreds of millions of rows into your InnoDB tables. Sadly this brought little performance gains to the table. MySQL wraps single queries in implicit transactions. Wrapping everything in a transaction may work, but inevitably something will go wrong and you may want the ability to resume inserting the rows instead of starting all over.
-The solution now is to execute SET AUTOCOMMIT=0 before inserting the data, and then issuing a COMMIT when you’re done. With all that in place I’m inserting 14,000,000 rows into both MyISAM and InnoDB tables in 30 minutes. MyISAM is still ~ 2 min faster, but as I said earlier this is adequate for now. Prior to all this it took several hours to insert 14,000,000 rows so I am happy.
+The solution now is to execute SET AUTOCOMMIT=0 before inserting the data, and then issuing a COMMIT when you’re done. With all that in place I’m inserting 14,000,000 rows into both MyISAM and InnoDB tables in 30 minutes. MyISAM is still ~ 2 min faster, but as I said earlier this is adequate for now. Prior to all this it took several hours to insert 14,000,000 rows so I am happy.
Now you can enjoy the speed MyISAM is known for with your InnoDB tables. Consider the data integrity a bonus! ;-)
diff --git a/public/posts/2007/05/_data.json b/public/posts/2007/05/_data.json
index 95739e5..995092b 100644
--- a/public/posts/2007/05/_data.json
+++ b/public/posts/2007/05/_data.json
@@ -85,7 +85,10 @@
"extensions"
],
"author": "Sami Samhuri",
- "url": "/posts/2007/05/enumerable-pluck-and-string-to_proc-for-ruby"
+ "url": "/posts/2007/05/enumerable-pluck-and-string-to_proc-for-ruby",
+ "styles": [
+ "/css/typocode.css"
+ ]
},
"dumping-objects-to-the-browser-in-rails": {
"title": "Dumping Objects to the Browser in Rails",
@@ -95,7 +98,10 @@
"rails"
],
"author": "Sami Samhuri",
- "url": "/posts/2007/05/dumping-objects-to-the-browser-in-rails"
+ "url": "/posts/2007/05/dumping-objects-to-the-browser-in-rails",
+ "styles": [
+ "/css/typocode.css"
+ ]
},
"cheating-at-life-in-general": {
"title": "Cheating at Life in General",
diff --git a/public/posts/2007/05/a-new-way-to-look-at-networking.html.md b/public/posts/2007/05/a-new-way-to-look-at-networking.md
similarity index 100%
rename from public/posts/2007/05/a-new-way-to-look-at-networking.html.md
rename to public/posts/2007/05/a-new-way-to-look-at-networking.md
diff --git a/public/posts/2007/05/a-scheme-parser-in-haskell-part-1.html.md b/public/posts/2007/05/a-scheme-parser-in-haskell-part-1.md
similarity index 88%
rename from public/posts/2007/05/a-scheme-parser-in-haskell-part-1.html.md
rename to public/posts/2007/05/a-scheme-parser-in-haskell-part-1.md
index 1700e92..497be5e 100644
--- a/public/posts/2007/05/a-scheme-parser-in-haskell-part-1.html.md
+++ b/public/posts/2007/05/a-scheme-parser-in-haskell-part-1.md
@@ -15,21 +15,21 @@ parseNumber :: liftM (Number . read) $ many1 digit
Okay that's pretty simple right? Let's break it down, first looking at the right-hand side of the $ operator, then the left.
- * many1 digit reads as many decimal digits as it can.
+ * many1 digit reads as many decimal digits as it can.
* Number . read is a function composition just like we're used to using in math. It applies read to its argument, then applies Number to that result.
- * liftM is concisely and effectively defined elsewhere, and I'll borrow their description:
+ * liftM is concisely and effectively defined elsewhere, and I'll borrow their description:
- liftM f m lets a non-monadic function f operate on the contents of monad m
+ liftM f m lets a non-monadic function f operate on the contents of monad m
-liftM's type is also quite telling: liftM :: (Monad m) => (a -> b) -> (m a -> m b)
+liftM's type is also quite telling: liftM :: (Monad m) => (a -> b) -> (m a -> m b)
In a nutshell liftM turns a function from a to b to a function from a monad containing a to a monad containing b.
-That results in a function on the left-hand side of $, which operates on and outputs a monad. The content of the input monad is a String. The content of the output monad is a LispVal (defined earlier in the tutorial). Specifically it is a Number.
+That results in a function on the left-hand side of $, which operates on and outputs a monad. The content of the input monad is a String. The content of the output monad is a LispVal (defined earlier in the tutorial). Specifically it is a Number.
-The $ acts similar to a pipe in $FAVOURITE_SHELL, and is right associative which means the expression on the right is passed to the expression (function) on the left. It's exactly the same as (liftM (Number . read)) (many1 digit) except it looks cleaner. If you know LISP or Scheme (sadly I do not) then it's analogous to the apply function.
+The $ acts similar to a pipe in $FAVOURITE_SHELL, and is right associative which means the expression on the right is passed to the expression (function) on the left. It's exactly the same as (liftM (Number . read)) (many1 digit) except it looks cleaner. If you know LISP or Scheme (sadly I do not) then it's analogous to the apply function.
So how does a Haskell newbie go about re-writing that using other notations which haven't even been explained in the tutorial? Clearly one must search the web and read as much as they can until they understand enough to figure it out (which is one thing I like about the tutorial). If you're lazy like me, here are 3 equivalent pieces of code for you to chew on. parseNumber's type is Parser LispVal (Parser is a monad).
diff --git a/public/posts/2007/05/cheating-at-life-in-general.html.md b/public/posts/2007/05/cheating-at-life-in-general.md
similarity index 100%
rename from public/posts/2007/05/cheating-at-life-in-general.html.md
rename to public/posts/2007/05/cheating-at-life-in-general.md
diff --git a/public/posts/2007/05/dtrace-ruby-goodness-for-sun.html.md b/public/posts/2007/05/dtrace-ruby-goodness-for-sun.md
similarity index 100%
rename from public/posts/2007/05/dtrace-ruby-goodness-for-sun.html.md
rename to public/posts/2007/05/dtrace-ruby-goodness-for-sun.md
diff --git a/public/posts/2007/05/dumping-objects-to-the-browser-in-rails.html.md b/public/posts/2007/05/dumping-objects-to-the-browser-in-rails.md
similarity index 93%
rename from public/posts/2007/05/dumping-objects-to-the-browser-in-rails.html.md
rename to public/posts/2007/05/dumping-objects-to-the-browser-in-rails.md
index 48247a9..6eca1da 100644
--- a/public/posts/2007/05/dumping-objects-to-the-browser-in-rails.html.md
+++ b/public/posts/2007/05/dumping-objects-to-the-browser-in-rails.md
@@ -1,7 +1,7 @@
Here's an easy way to solve a problem that may have nagged you as it did me. Simply using foo.inspect 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 PrettyPrint module so we just need to use it.
-Unfortunately typing <%= PP.pp(@something, '') %>
to quickly debug some possibly large object (or collection) can get old fast so we need a shortcut.
+Unfortunately typing <%= PP.pp(@something, '') %>
to quickly debug some possibly large object (or collection) can get old fast so we need a shortcut.
Taking the definition of Object#pp_s from the extensions project it's trivial to create a helper method to just dump out an object in a reasonable manner.
diff --git a/public/posts/2007/05/enumerable-pluck-and-string-to_proc-for-ruby.html.md b/public/posts/2007/05/enumerable-pluck-and-string-to_proc-for-ruby.md
similarity index 99%
rename from public/posts/2007/05/enumerable-pluck-and-string-to_proc-for-ruby.html.md
rename to public/posts/2007/05/enumerable-pluck-and-string-to_proc-for-ruby.md
index eee5219..ecee11b 100644
--- a/public/posts/2007/05/enumerable-pluck-and-string-to_proc-for-ruby.html.md
+++ b/public/posts/2007/05/enumerable-pluck-and-string-to_proc-for-ruby.md
@@ -115,4 +115,4 @@ I wrote another version without using the various #to_proc methods
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.
-*Update #1: Fixed a potential performance issue in Enumerable#to_proc by saving the results of to_proc in @procs.*
+*Update #1: Fixed a potential performance issue in Enumerable#to_proc by saving the results of to_proc in @procs.*
diff --git a/public/posts/2007/05/finnish-court-rules-css-ineffective-at-protecting-dvds.html.md b/public/posts/2007/05/finnish-court-rules-css-ineffective-at-protecting-dvds.md
similarity index 100%
rename from public/posts/2007/05/finnish-court-rules-css-ineffective-at-protecting-dvds.html.md
rename to public/posts/2007/05/finnish-court-rules-css-ineffective-at-protecting-dvds.md
diff --git a/public/posts/2007/05/gotta-love-the-ferry-ride.html.md b/public/posts/2007/05/gotta-love-the-ferry-ride.md
similarity index 100%
rename from public/posts/2007/05/gotta-love-the-ferry-ride.html.md
rename to public/posts/2007/05/gotta-love-the-ferry-ride.md
diff --git a/public/posts/2007/05/i-cant-wait-to-see-what-matt-stone-trey-parker-do-with-this.html.md b/public/posts/2007/05/i-cant-wait-to-see-what-matt-stone-trey-parker-do-with-this.md
similarity index 100%
rename from public/posts/2007/05/i-cant-wait-to-see-what-matt-stone-trey-parker-do-with-this.html.md
rename to public/posts/2007/05/i-cant-wait-to-see-what-matt-stone-trey-parker-do-with-this.md
diff --git a/public/posts/2007/05/inspirado.html.md b/public/posts/2007/05/inspirado.md
similarity index 100%
rename from public/posts/2007/05/inspirado.html.md
rename to public/posts/2007/05/inspirado.md
diff --git a/public/posts/2007/05/iphone-humour.html.md b/public/posts/2007/05/iphone-humour.md
similarity index 100%
rename from public/posts/2007/05/iphone-humour.html.md
rename to public/posts/2007/05/iphone-humour.md
diff --git a/public/posts/2007/05/rails-plugins-link-dump.html.md b/public/posts/2007/05/rails-plugins-link-dump.md
similarity index 100%
rename from public/posts/2007/05/rails-plugins-link-dump.html.md
rename to public/posts/2007/05/rails-plugins-link-dump.md
diff --git a/public/posts/2007/05/typo-and-i-are-friends-again.html.md b/public/posts/2007/05/typo-and-i-are-friends-again.md
similarity index 85%
rename from public/posts/2007/05/typo-and-i-are-friends-again.html.md
rename to public/posts/2007/05/typo-and-i-are-friends-again.md
index fb2bed5..cc9c80e 100644
--- a/public/posts/2007/05/typo-and-i-are-friends-again.html.md
+++ b/public/posts/2007/05/typo-and-i-are-friends-again.md
@@ -2,6 +2,6 @@
Add to that the random HTTP 500 errors which were very noticeable while I was trying to fix that post and I was about to write my own blog or switch to WordPress.
-I don't love WP so I decided to just upgrade Typo instead. I was using Typo 2.6, and the current stable version is 4.1. They skipped version 3 to preclude any confusion that may have ensued between Typo v3 and the CMS Typo3. So it really isn't a big upgrade and it went perfectly. I checked out a new copy of the repo because I had some difficulty getting svn switch --relocate to work, configured the database settings and issued a rake db:migrate, copied my theme over and it all just worked. Bravo Typo team, that's how an upgrade should work.
+I don't love WP so I decided to just upgrade Typo instead. I was using Typo 2.6, and the current stable version is 4.1. They skipped version 3 to preclude any confusion that may have ensued between Typo v3 and the CMS Typo3. So it really isn't a big upgrade and it went perfectly. I checked out a new copy of the repo because I had some difficulty getting svn switch --relocate to work, configured the database settings and issued a rake db:migrate, copied my theme over and it all just worked. Bravo Typo team, that's how an upgrade should work.
No more random 500 errors, things seem faster (better caching perhaps), and that troublesome post is troublesome no more. I am happy with Typo again.
diff --git a/public/posts/2007/06/301-moved-permanently.html.md b/public/posts/2007/06/301-moved-permanently.md
similarity index 100%
rename from public/posts/2007/06/301-moved-permanently.html.md
rename to public/posts/2007/06/301-moved-permanently.md
diff --git a/public/posts/2007/06/back-on-gentoo-trying-new-things.html.md b/public/posts/2007/06/back-on-gentoo-trying-new-things.md
similarity index 100%
rename from public/posts/2007/06/back-on-gentoo-trying-new-things.html.md
rename to public/posts/2007/06/back-on-gentoo-trying-new-things.md
diff --git a/public/posts/2007/06/begging-the-question.html.md b/public/posts/2007/06/begging-the-question.md
similarity index 100%
rename from public/posts/2007/06/begging-the-question.html.md
rename to public/posts/2007/06/begging-the-question.md
diff --git a/public/posts/2007/06/controlling-volume-via-the-keyboard-on-linux.html.md b/public/posts/2007/06/controlling-volume-via-the-keyboard-on-linux.md
similarity index 100%
rename from public/posts/2007/06/controlling-volume-via-the-keyboard-on-linux.html.md
rename to public/posts/2007/06/controlling-volume-via-the-keyboard-on-linux.md
diff --git a/public/posts/2007/06/emacs-for-textmate-junkies.html.md b/public/posts/2007/06/emacs-for-textmate-junkies.html.md
deleted file mode 100644
index 87ebe6b..0000000
--- a/public/posts/2007/06/emacs-for-textmate-junkies.html.md
+++ /dev/null
@@ -1,133 +0,0 @@
-*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.*
-
-*Update #3: I should read the Emacs manual sometime, especially since I have it in dead-tree form. Check out skeleton pairs in the Emacs manual.*
-
-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 ' (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 mailing list post has a solution for surrounding the current region with tags, which served as a great starting point.
-
-
-
- 1
-2
-3
-4
-5
-6
-7
- |
- (defun surround-region-with-tag (tag-name beg end)
- (interactive "sTag name: \nr")
- (save-excursion
- (goto-char beg)
- (insert "<" tag-name ">")
- (goto-char (+ end 2 (length tag-name)))
- (insert "</" tag-name ">"))) |
-
-
-
-With a little modification I now have the following in my ~/.emacs file:
-
-
-
- 1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-11
-12
-13
-14
-15
-16
-17
-18
-19
-20
-21
-22
-23
-24
-25
-26
-27
-28
-29
-30
-31
-32
-33
-34
-35
-36
-37
-38
-39
-40
-41
-42
-43
-44
-45
-46
-47
- |
- ;; help out a TextMate junkie
-
-(defun wrap-region (left right beg end)
- "Wrap the region in arbitrary text, LEFT goes to the left and RIGHT goes to the right."
- (interactive)
- (save-excursion
- (goto-char beg)
- (insert left)
- (goto-char (+ end (length left)))
- (insert right)))
-
-(defmacro wrap-region-with-function (left right)
- "Returns a function which, when called, will interactively `wrap-region-or-insert' using LEFT and RIGHT."
- `(lambda () (interactive)
- (wrap-region-or-insert ,left ,right)))
-
-(defun wrap-region-with-tag-or-insert ()
- (interactive)
- (if (and mark-active transient-mark-mode)
- (call-interactively 'wrap-region-with-tag)
- (insert "<")))
-
-(defun wrap-region-with-tag (tag beg end)
- "Wrap the region in the given HTML/XML tag using `wrap-region'. If any
-attributes are specified then they are only included in the opening tag."
- (interactive "*sTag (including attributes): \nr")
- (let* ((elems (split-string tag " "))
- (tag-name (car elems))
- (right (concat "</" tag-name ">")))
- (if (= 1 (length elems))
- (wrap-region (concat "<" tag-name ">") right beg end)
- (wrap-region (concat "<" tag ">") right beg end))))
-
-(defun wrap-region-or-insert (left right)
- "Wrap the region with `wrap-region' if an active region is marked, otherwise insert LEFT at point."
- (interactive)
- (if (and mark-active transient-mark-mode)
- (wrap-region left right (region-beginning) (region-end))
- (insert left)))
-
-(global-set-key "'" (wrap-region-with-function "'" "'"))
-(global-set-key "\"" (wrap-region-with-function "\"" "\""))
-(global-set-key "`" (wrap-region-with-function "`" "`"))
-(global-set-key "(" (wrap-region-with-function "(" ")"))
-(global-set-key "[" (wrap-region-with-function "[" "]"))
-(global-set-key "{" (wrap-region-with-function "{" "}"))
-(global-set-key "<" 'wrap-region-with-tag-or-insert) ;; I opted not to have a wrap-with-angle-brackets |
-
-
-
-Download wrap-region.el
-
-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.
diff --git a/public/posts/2007/06/emacs-for-textmate-junkies.md b/public/posts/2007/06/emacs-for-textmate-junkies.md
new file mode 100644
index 0000000..d160c31
--- /dev/null
+++ b/public/posts/2007/06/emacs-for-textmate-junkies.md
@@ -0,0 +1,128 @@
+*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.*
+
+*Update #3: I should read the Emacs manual sometime, especially since I have it in dead-tree form. Check out skeleton pairs in the Emacs manual.*
+
+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 ' (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 mailing list post has a solution for surrounding the current region with tags, which served as a great starting point.
+
+
+1
+2
+3
+4
+5
+6
+7
+
+(defun surround-region-with-tag (tag-name beg end)
+ (interactive "sTag name: \nr")
+ (save-excursion
+ (goto-char beg)
+ (insert "<" tag-name ">")
+ (goto-char (+ end 2 (length tag-name)))
+ (insert "</" tag-name ">")))
+
+
+With a little modification I now have the following in my ~/.emacs file:
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+
+;; help out a TextMate junkie
+
+(defun wrap-region (left right beg end)
+ "Wrap the region in arbitrary text, LEFT goes to the left and RIGHT goes to the right."
+ (interactive)
+ (save-excursion
+ (goto-char beg)
+ (insert left)
+ (goto-char (+ end (length left)))
+ (insert right)))
+
+(defmacro wrap-region-with-function (left right)
+ "Returns a function which, when called, will interactively `wrap-region-or-insert' using LEFT and RIGHT."
+ `(lambda () (interactive)
+ (wrap-region-or-insert ,left ,right)))
+
+(defun wrap-region-with-tag-or-insert ()
+ (interactive)
+ (if (and mark-active transient-mark-mode)
+ (call-interactively 'wrap-region-with-tag)
+ (insert "<")))
+
+(defun wrap-region-with-tag (tag beg end)
+ "Wrap the region in the given HTML/XML tag using `wrap-region'. If any
+attributes are specified then they are only included in the opening tag."
+ (interactive "*sTag (including attributes): \nr")
+ (let* ((elems (split-string tag " "))
+ (tag-name (car elems))
+ (right (concat "</" tag-name ">")))
+ (if (= 1 (length elems))
+ (wrap-region (concat "<" tag-name ">") right beg end)
+ (wrap-region (concat "<" tag ">") right beg end))))
+
+(defun wrap-region-or-insert (left right)
+ "Wrap the region with `wrap-region' if an active region is marked, otherwise insert LEFT at point."
+ (interactive)
+ (if (and mark-active transient-mark-mode)
+ (wrap-region left right (region-beginning) (region-end))
+ (insert left)))
+
+(global-set-key "'" (wrap-region-with-function "'" "'"))
+(global-set-key "\"" (wrap-region-with-function "\"" "\""))
+(global-set-key "`" (wrap-region-with-function "`" "`"))
+(global-set-key "(" (wrap-region-with-function "(" ")"))
+(global-set-key "[" (wrap-region-with-function "[" "]"))
+(global-set-key "{" (wrap-region-with-function "{" "}"))
+(global-set-key "<" 'wrap-region-with-tag-or-insert) ;; I opted not to have a wrap-with-angle-brackets
+
+↓ Download wrap-region.el
+
+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.
diff --git a/public/posts/2007/06/emacs-tagify-region-or-insert-tag.html.md b/public/posts/2007/06/emacs-tagify-region-or-insert-tag.md
similarity index 100%
rename from public/posts/2007/06/emacs-tagify-region-or-insert-tag.html.md
rename to public/posts/2007/06/emacs-tagify-region-or-insert-tag.md
diff --git a/public/posts/2007/06/embrace-the-database.html.md b/public/posts/2007/06/embrace-the-database.md
similarity index 100%
rename from public/posts/2007/06/embrace-the-database.html.md
rename to public/posts/2007/06/embrace-the-database.md
diff --git a/public/posts/2007/06/floating-point-in-elschemo.html.md b/public/posts/2007/06/floating-point-in-elschemo.html.md
deleted file mode 100644
index aa12b5b..0000000
--- a/public/posts/2007/06/floating-point-in-elschemo.html.md
+++ /dev/null
@@ -1,441 +0,0 @@
-### Parsing floating point numbers ###
-
-The first task is extending the LispVal type to grok floats.
-
-
-
- 1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-11
-12
-13
-14
-15
- |
- type LispInt = Integer
-type LispFloat = Float
-
--- numeric data types
-data LispNum = Integer LispInt
- | Float LispFloat
-
--- data types
-data LispVal = Atom String
- | List [LispVal]
- | DottedList [LispVal] LispVal
- | Number LispNum
- | Char Char
- | String String
- | ... |
-
-
-
-The reason for using the new LispNum type and not just throwing a new Float Float 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).
-
-ElSchemo now parses negative numbers so I'll start with 2 helper functions that are used when parsing both integers and floats:
-
-
-
- 1
-2
-3
-4
-5
-6
-7
- |
- parseSign :: Parser Char
-parseSign = do try (char '-')
- <|> do optional (char '+')
- return '+'
-
-applySign :: Char -> LispNum -> LispNum
-applySign sign n = if sign == '-' then negate n else n |
-
-
-
-parseSign 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.
-
-applySign takes a sign character and a LispNum and negates it if necessary, returning a LispNum.
-
-Armed with these 2 functions we can now parse floating point numbers in decimal. Conforming to R5RS an optional #d prefix is allowed.
-
-
-
- 1
-2
-3
-4
-5
-6
-7
-8
- |
- parseFloat :: Parser LispVal
-parseFloat = do optional (string "#d")
- sign <- parseSign
- whole <- many1 digit
- char '.'
- fract <- many1 digit
- return . Number $ applySign sign (makeFloat whole fract)
- where makeFloat whole fract = Float . fst . head . readFloat $ whole ++ "." ++ fract |
-
-
-
-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 makeFloat. makeFloat in turn delegates the work to the readFloat library function, extracts the result and constructs a LispNum for it.
-
-The last step for parsing is to modify parseExpr to try and parse floats.
-
-
-
- 1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-11
-12
-13
-14
- |
- -- Integers, floats, characters and atoms can all start with a # so wrap those with try.
--- (Left factor the grammar in the future)
-parseExpr :: Parser LispVal
-parseExpr = (try parseFloat)
- <|> (try parseInteger)
- <|> (try parseChar)
- <|> parseAtom
- <|> parseString
- <|> parseQuoted
- <|> do char '('
- x <- (try parseList) <|> parseDottedList
- char ')'
- return x
- <|> parseComment |
-
-
-
-### Displaying the floats ###
-
-
-That's it for parsing, now let's provide a way to display these suckers. LispVal is an instance of show, where show = showVal so showVal is our first stop. Remembering that LispVal now has a single Number constructor we modify it accordingly:
-
-
-
- 1
-2
-3
-4
-5
-6
-7
- |
- showVal (Number n) = showNum n
-
-showNum :: LispNum -> String
-showNum (Integer contents) = show contents
-showNum (Float contents) = show contents
-
-instance Show LispNum where show = showNum |
-
-
-
-One last, and certainly not least, step is to modify eval so that numbers evaluate to themselves.
-
-
- eval env val@(Number _) = return val
-
-There's a little more housekeeping to be done such as fixing integer?, number?, implementing float? 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 2.5 or -10.88 they will be understood. Now try adding them:
-
- (+ 2.5 1.1)
- Invalid type: expected integer, found 2.5
-
-Oops, we don't know how to operate on floats yet!
-
-### Operating on floats ###
-
-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 LispNum, it's just the way I did it and it seems to work. There's a bunch of boilerplate necessary to make LispNum 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.
-
-
-
- 1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-11
-12
-13
-14
-15
-16
-17
-18
-19
-20
-21
-22
-23
-24
-25
-26
-27
-28
-29
-30
-31
-32
-33
-34
-35
-36
-37
-38
-39
-40
-41
-42
-43
-44
-45
-46
-47
-48
-49
-50
-51
-52
-53
-54
-55
-56
-57
-58
-59
-60
-61
-62
-63
-64
-65
-66
-67
-68
-69
-70
- |
- lispNumEq :: LispNum -> LispNum -> Bool
-lispNumEq (Integer arg1) (Integer arg2) = arg1 == arg2
-lispNumEq (Integer arg1) (Float arg2) = (fromInteger arg1) == arg2
-lispNumEq (Float arg1) (Float arg2) = arg1 == arg2
-lispNumEq (Float arg1) (Integer arg2) = arg1 == (fromInteger arg2)
-
-instance Eq LispNum where (==) = lispNumEq
-
-lispNumPlus :: LispNum -> LispNum -> LispNum
-lispNumPlus (Integer x) (Integer y) = Integer $ x + y
-lispNumPlus (Integer x) (Float y) = Float $ (fromInteger x) + y
-lispNumPlus (Float x) (Float y) = Float $ x + y
-lispNumPlus (Float x) (Integer y) = Float $ x + (fromInteger y)
-
-lispNumMinus :: LispNum -> LispNum -> LispNum
-lispNumMinus (Integer x) (Integer y) = Integer $ x - y
-lispNumMinus (Integer x) (Float y) = Float $ (fromInteger x) - y
-lispNumMinus (Float x) (Float y) = Float $ x - y
-lispNumMinus (Float x) (Integer y) = Float $ x - (fromInteger y)
-
-lispNumMult :: LispNum -> LispNum -> LispNum
-lispNumMult (Integer x) (Integer y) = Integer $ x * y
-lispNumMult (Integer x) (Float y) = Float $ (fromInteger x) * y
-lispNumMult (Float x) (Float y) = Float $ x * y
-lispNumMult (Float x) (Integer y) = Float $ x * (fromInteger y)
-
-lispNumDiv :: LispNum -> LispNum -> LispNum
-lispNumDiv (Integer x) (Integer y) = Integer $ x `div` y
-lispNumDiv (Integer x) (Float y) = Float $ (fromInteger x) / y
-lispNumDiv (Float x) (Float y) = Float $ x / y
-lispNumDiv (Float x) (Integer y) = Float $ x / (fromInteger y)
-
-lispNumAbs :: LispNum -> LispNum
-lispNumAbs (Integer x) = Integer (abs x)
-lispNumAbs (Float x) = Float (abs x)
-
-lispNumSignum :: LispNum -> LispNum
-lispNumSignum (Integer x) = Integer (signum x)
-lispNumSignum (Float x) = Float (signum x)
-
-instance Num LispNum where
- (+) = lispNumPlus
- (-) = lispNumMinus
- (*) = lispNumMult
- abs = lispNumAbs
- signum = lispNumSignum
- fromInteger x = Integer x
-
-
-lispNumToRational :: LispNum -> Rational
-lispNumToRational (Integer x) = toRational x
-lispNumToRational (Float x) = toRational x
-
-instance Real LispNum where
- toRational = lispNumToRational
-
-
-lispIntQuotRem :: LispInt -> LispInt -> (LispInt, LispInt)
-lispIntQuotRem n d = quotRem n d
-
-lispIntToInteger :: LispInt -> Integer
-lispIntToInteger x = x
-
-lispNumLessThanEq :: LispNum -> LispNum -> Bool
-lispNumLessThanEq (Integer x) (Integer y) = x <= y
-lispNumLessThanEq (Integer x) (Float y) = (fromInteger x) <= y
-lispNumLessThanEq (Float x) (Integer y) = x <= (fromInteger y)
-lispNumLessThanEq (Float x) (Float y) = x <= y
-
-instance Ord LispNum where (<=) = lispNumLessThanEq |
-
-
-
-Phew, ok with that out of the way now we can actually extend our operators to work with any type of LispNum. Our Scheme operators are defined using the functions numericBinop and numBoolBinop. First we'll slightly modify our definition of primitives:
-
-
-
- 1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-11
-12
-13
-14
-15
- |
- primitives :: [(String, [LispVal] -> ThrowsError LispVal)]
-primitives = [("+", numericBinop (+)),
- ("-", subtractOp),
- ("*", numericBinop (*)),
- ("/", floatBinop (/)),
- ("mod", integralBinop mod),
- ("quotient", integralBinop quot),
- ("remainder", integralBinop rem),
- ("=", numBoolBinop (==)),
- ("<", numBoolBinop (<)),
- (">", numBoolBinop (>)),
- ("/=", numBoolBinop (/=)),
- (">=", numBoolBinop (>=)),
- ("<=", numBoolBinop (<=)),
- ...] |
-
-
-
-Note that mod, quotient, and remainder are only defined for integers and as such use integralBinop, while division (/) is only defined for floating point numbers using floatBinop. subtractOp is different to support unary usage, e.g. (- 4) => -4, but it uses numericBinop internally when more than 1 argument is given. On to the implementation! First extend unpackNum to work with any LispNum, and provide separate unpackInt and unpackFloat functions to handle both kinds of LispNum.
-
-
-
- 1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-11
-12
-13
-14
-15
- |
- unpackNum :: LispVal -> ThrowsError LispNum
-unpackNum (Number (Integer n)) = return $ Integer n
-unpackNum (Number (Float n)) = return $ Float n
-unpackNum notNum = throwError $ TypeMismatch "number" notNum
-
-unpackInt :: LispVal -> ThrowsError Integer
-unpackInt (Number (Integer n)) = return n
-unpackInt (List [n]) = unpackInt n
-unpackInt notInt = throwError $ TypeMismatch "integer" notInt
-
-unpackFloat :: LispVal -> ThrowsError Float
-unpackFloat (Number (Float f)) = return f
-unpackFloat (Number (Integer f)) = return $ fromInteger f
-unpackFloat (List [f]) = unpackFloat f
-unpackFloat notFloat = throwError $ TypeMismatch "float" notFloat |
-
-
-
-The initial work of separating integers and floats into the LispNum abstraction, and the code I said would be handy shortly, are going to be really handy here. There's relatively no change in numericBinop except for the type signature. integralBinop and floatBinop 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.
-
-
-
- 1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-11
-12
-13
-14
-15
-16
-17
-18
- |
- numericBinop :: (LispNum -> LispNum -> LispNum) -> [LispVal] -> ThrowsError LispVal
-numericBinop op singleVal@[_] = throwError $ NumArgs 2 singleVal
-numericBinop op params = mapM unpackNum params >>= return . Number . foldl1 op
-
-integralBinop :: (LispInt -> LispInt -> LispInt) -> [LispVal] -> ThrowsError LispVal
-integralBinop op singleVal@[_] = throwError $ NumArgs 2 singleVal
-integralBinop op params = mapM unpackInt params >>= return . Number . Integer . foldl1 op
-
-floatBinop :: (LispFloat -> LispFloat -> LispFloat) -> [LispVal] -> ThrowsError LispVal
-floatBinop op singleVal@[_] = throwError $ NumArgs 2 singleVal
-floatBinop op params = mapM unpackFloat params >>= return . Number . Float . foldl1 op
-
-subtractOp :: [LispVal] -> ThrowsError LispVal
-subtractOp num@[_] = unpackNum (head num) >>= return . Number . negate
-subtractOp params = numericBinop (-) params
-
-numBoolBinop :: (LispNum -> LispNum -> Bool) -> [LispVal] -> ThrowsError LispVal
-numBoolBinop op params = boolBinop unpackNum op params |
-
-
-
-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!
-
-
-Next time I'll go over some of the special forms I have added, including short-circuiting and and or forms and the full repetoire of let, let*, and letrec. Stay tuned!
diff --git a/public/posts/2007/06/floating-point-in-elschemo.md b/public/posts/2007/06/floating-point-in-elschemo.md
new file mode 100644
index 0000000..e28e02d
--- /dev/null
+++ b/public/posts/2007/06/floating-point-in-elschemo.md
@@ -0,0 +1,423 @@
+### Parsing floating point numbers ###
+
+The first task is extending the LispVal type to grok floats.
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+
+type LispInt = Integer
+type LispFloat = Float
+
+-- numeric data types
+data LispNum = Integer LispInt
+ | Float LispFloat
+
+-- data types
+data LispVal = Atom String
+ | List [LispVal]
+ | DottedList [LispVal] LispVal
+ | Number LispNum
+ | Char Char
+ | String String
+ | ...
+
+
+The reason for using the new LispNum type and not just throwing a new Float Float 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).
+
+ElSchemo now parses negative numbers so I'll start with 2 helper functions that are used when parsing both integers and floats:
+
+
+1
+2
+3
+4
+5
+6
+7
+
+parseSign :: Parser Char
+parseSign = do try (char '-')
+ <|> do optional (char '+')
+ return '+'
+
+applySign :: Char -> LispNum -> LispNum
+applySign sign n = if sign == '-' then negate n else n
+
+
+parseSign 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.
+
+applySign takes a sign character and a LispNum and negates it if necessary, returning a LispNum.
+
+Armed with these 2 functions we can now parse floating point numbers in decimal. Conforming to R5RS an optional #d prefix is allowed.
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+
+parseFloat :: Parser LispVal
+parseFloat = do optional (string "#d")
+ sign <- parseSign
+ whole <- many1 digit
+ char '.'
+ fract <- many1 digit
+ return . Number $ applySign sign (makeFloat whole fract)
+ where makeFloat whole fract = Float . fst . head . readFloat $ whole ++ "." ++ fract
+
+
+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 makeFloat. makeFloat in turn delegates the work to the readFloat library function, extracts the result and constructs a LispNum for it.
+
+The last step for parsing is to modify parseExpr to try and parse floats.
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+
+-- Integers, floats, characters and atoms can all start with a # so wrap those with try.
+-- (Left factor the grammar in the future)
+parseExpr :: Parser LispVal
+parseExpr = (try parseFloat)
+ <|> (try parseInteger)
+ <|> (try parseChar)
+ <|> parseAtom
+ <|> parseString
+ <|> parseQuoted
+ <|> do char '('
+ x <- (try parseList) <|> parseDottedList
+ char ')'
+ return x
+ <|> parseComment
+
+
+### Displaying the floats ###
+
+
+That's it for parsing, now let's provide a way to display these suckers. LispVal is an instance of show, where show = showVal so showVal is our first stop. Remembering that LispVal now has a single Number constructor we modify it accordingly:
+
+
+1
+2
+3
+4
+5
+6
+7
+
+showVal (Number n) = showNum n
+
+showNum :: LispNum -> String
+showNum (Integer contents) = show contents
+showNum (Float contents) = show contents
+
+instance Show LispNum where show = showNum
+
+
+One last, and certainly not least, step is to modify eval so that numbers evaluate to themselves.
+
+
+ eval env val@(Number _) = return val
+
+There's a little more housekeeping to be done such as fixing integer?, number?, implementing float? 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 2.5 or -10.88 they will be understood. Now try adding them:
+
+ (+ 2.5 1.1)
+ Invalid type: expected integer, found 2.5
+
+Oops, we don't know how to operate on floats yet!
+
+### Operating on floats ###
+
+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 LispNum, it's just the way I did it and it seems to work. There's a bunch of boilerplate necessary to make LispNum 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.
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+
+lispNumEq :: LispNum -> LispNum -> Bool
+lispNumEq (Integer arg1) (Integer arg2) = arg1 == arg2
+lispNumEq (Integer arg1) (Float arg2) = (fromInteger arg1) == arg2
+lispNumEq (Float arg1) (Float arg2) = arg1 == arg2
+lispNumEq (Float arg1) (Integer arg2) = arg1 == (fromInteger arg2)
+
+instance Eq LispNum where (==) = lispNumEq
+
+lispNumPlus :: LispNum -> LispNum -> LispNum
+lispNumPlus (Integer x) (Integer y) = Integer $ x + y
+lispNumPlus (Integer x) (Float y) = Float $ (fromInteger x) + y
+lispNumPlus (Float x) (Float y) = Float $ x + y
+lispNumPlus (Float x) (Integer y) = Float $ x + (fromInteger y)
+
+lispNumMinus :: LispNum -> LispNum -> LispNum
+lispNumMinus (Integer x) (Integer y) = Integer $ x - y
+lispNumMinus (Integer x) (Float y) = Float $ (fromInteger x) - y
+lispNumMinus (Float x) (Float y) = Float $ x - y
+lispNumMinus (Float x) (Integer y) = Float $ x - (fromInteger y)
+
+lispNumMult :: LispNum -> LispNum -> LispNum
+lispNumMult (Integer x) (Integer y) = Integer $ x * y
+lispNumMult (Integer x) (Float y) = Float $ (fromInteger x) * y
+lispNumMult (Float x) (Float y) = Float $ x * y
+lispNumMult (Float x) (Integer y) = Float $ x * (fromInteger y)
+
+lispNumDiv :: LispNum -> LispNum -> LispNum
+lispNumDiv (Integer x) (Integer y) = Integer $ x `div` y
+lispNumDiv (Integer x) (Float y) = Float $ (fromInteger x) / y
+lispNumDiv (Float x) (Float y) = Float $ x / y
+lispNumDiv (Float x) (Integer y) = Float $ x / (fromInteger y)
+
+lispNumAbs :: LispNum -> LispNum
+lispNumAbs (Integer x) = Integer (abs x)
+lispNumAbs (Float x) = Float (abs x)
+
+lispNumSignum :: LispNum -> LispNum
+lispNumSignum (Integer x) = Integer (signum x)
+lispNumSignum (Float x) = Float (signum x)
+
+instance Num LispNum where
+ (+) = lispNumPlus
+ (-) = lispNumMinus
+ (*) = lispNumMult
+ abs = lispNumAbs
+ signum = lispNumSignum
+ fromInteger x = Integer x
+
+
+lispNumToRational :: LispNum -> Rational
+lispNumToRational (Integer x) = toRational x
+lispNumToRational (Float x) = toRational x
+
+instance Real LispNum where
+ toRational = lispNumToRational
+
+
+lispIntQuotRem :: LispInt -> LispInt -> (LispInt, LispInt)
+lispIntQuotRem n d = quotRem n d
+
+lispIntToInteger :: LispInt -> Integer
+lispIntToInteger x = x
+
+lispNumLessThanEq :: LispNum -> LispNum -> Bool
+lispNumLessThanEq (Integer x) (Integer y) = x <= y
+lispNumLessThanEq (Integer x) (Float y) = (fromInteger x) <= y
+lispNumLessThanEq (Float x) (Integer y) = x <= (fromInteger y)
+lispNumLessThanEq (Float x) (Float y) = x <= y
+
+instance Ord LispNum where (<=) = lispNumLessThanEq
+
+
+Phew, ok with that out of the way now we can actually extend our operators to work with any type of LispNum. Our Scheme operators are defined using the functions numericBinop and numBoolBinop. First we'll slightly modify our definition of primitives:
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+
+primitives :: [(String, [LispVal] -> ThrowsError LispVal)]
+primitives = [("+", numericBinop (+)),
+ ("-", subtractOp),
+ ("*", numericBinop (*)),
+ ("/", floatBinop (/)),
+ ("mod", integralBinop mod),
+ ("quotient", integralBinop quot),
+ ("remainder", integralBinop rem),
+ ("=", numBoolBinop (==)),
+ ("<", numBoolBinop (<)),
+ (">", numBoolBinop (>)),
+ ("/=", numBoolBinop (/=)),
+ (">=", numBoolBinop (>=)),
+ ("<=", numBoolBinop (<=)),
+ ...]
+
+
+Note that mod, quotient, and remainder are only defined for integers and as such use integralBinop, while division (/) is only defined for floating point numbers using floatBinop. subtractOp is different to support unary usage, e.g. (- 4) => -4, but it uses numericBinop internally when more than 1 argument is given. On to the implementation! First extend unpackNum to work with any LispNum, and provide separate unpackInt and unpackFloat functions to handle both kinds of LispNum.
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+
+unpackNum :: LispVal -> ThrowsError LispNum
+unpackNum (Number (Integer n)) = return $ Integer n
+unpackNum (Number (Float n)) = return $ Float n
+unpackNum notNum = throwError $ TypeMismatch "number" notNum
+
+unpackInt :: LispVal -> ThrowsError Integer
+unpackInt (Number (Integer n)) = return n
+unpackInt (List [n]) = unpackInt n
+unpackInt notInt = throwError $ TypeMismatch "integer" notInt
+
+unpackFloat :: LispVal -> ThrowsError Float
+unpackFloat (Number (Float f)) = return f
+unpackFloat (Number (Integer f)) = return $ fromInteger f
+unpackFloat (List [f]) = unpackFloat f
+unpackFloat notFloat = throwError $ TypeMismatch "float" notFloat
+
+
+The initial work of separating integers and floats into the LispNum abstraction, and the code I said would be handy shortly, are going to be really handy here. There's relatively no change in numericBinop except for the type signature. integralBinop and floatBinop 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.
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+
+numericBinop :: (LispNum -> LispNum -> LispNum) -> [LispVal] -> ThrowsError LispVal
+numericBinop op singleVal@[_] = throwError $ NumArgs 2 singleVal
+numericBinop op params = mapM unpackNum params >>= return . Number . foldl1 op
+
+integralBinop :: (LispInt -> LispInt -> LispInt) -> [LispVal] -> ThrowsError LispVal
+integralBinop op singleVal@[_] = throwError $ NumArgs 2 singleVal
+integralBinop op params = mapM unpackInt params >>= return . Number . Integer . foldl1 op
+
+floatBinop :: (LispFloat -> LispFloat -> LispFloat) -> [LispVal] -> ThrowsError LispVal
+floatBinop op singleVal@[_] = throwError $ NumArgs 2 singleVal
+floatBinop op params = mapM unpackFloat params >>= return . Number . Float . foldl1 op
+
+subtractOp :: [LispVal] -> ThrowsError LispVal
+subtractOp num@[_] = unpackNum (head num) >>= return . Number . negate
+subtractOp params = numericBinop (-) params
+
+numBoolBinop :: (LispNum -> LispNum -> Bool) -> [LispVal] -> ThrowsError LispVal
+numBoolBinop op params = boolBinop unpackNum op params
+
+
+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!
+
+
+Next time I'll go over some of the special forms I have added, including short-circuiting and and or forms and the full repetoire of let, let*, and letrec. Stay tuned!
diff --git a/public/posts/2007/06/more-scheming-with-haskell.html.md b/public/posts/2007/06/more-scheming-with-haskell.md
similarity index 85%
rename from public/posts/2007/06/more-scheming-with-haskell.html.md
rename to public/posts/2007/06/more-scheming-with-haskell.md
index eecf614..169d8d1 100644
--- a/public/posts/2007/06/more-scheming-with-haskell.html.md
+++ b/public/posts/2007/06/more-scheming-with-haskell.md
@@ -54,27 +54,25 @@ The trickiest part of all this was figuring out how to use the various rea
It still takes me some time to knit together meaningful Haskell statements. Tonight I spent said time cobbling together an implementation of cond as a new special form. Have a look at the code. The explanation follows.
-
- 1
-2
-3
-4
-5
-6
-7
-8
-9
- |
- eval env (List (Atom "cond" : List (Atom "else" : exprs) : [])) =
- liftM last $ mapM (eval env) exprs
-eval env (List (Atom "cond" : List (pred : conseq) : rest)) =
- do result <- eval env $ pred
- case result of
- Bool False -> case rest of
- [] -> return $ List []
- _ -> eval env $ List (Atom "cond" : rest)
- _ -> liftM last $ mapM (eval env) conseq |
-
+1
+2
+3
+4
+5
+6
+7
+8
+9
+
+eval env (List (Atom "cond" : List (Atom "else" : exprs) : [])) =
+ liftM last $ mapM (eval env) exprs
+eval env (List (Atom "cond" : List (pred : conseq) : rest)) =
+ do result <- eval env $ pred
+ case result of
+ Bool False -> case rest of
+ [] -> return $ List []
+ _ -> eval env $ List (Atom "cond" : rest)
+ _ -> liftM last $ mapM (eval env) conseq
* __Lines 1-2:__ Handle else clauses by evaluating the given expression(s), returning the last result. It must come first or it's overlapped by the next pattern.
diff --git a/public/posts/2007/06/propaganda-makes-me-sick.html.md b/public/posts/2007/06/propaganda-makes-me-sick.md
similarity index 95%
rename from public/posts/2007/06/propaganda-makes-me-sick.html.md
rename to public/posts/2007/06/propaganda-makes-me-sick.md
index b8dbc2b..a9f1bb7 100644
--- a/public/posts/2007/06/propaganda-makes-me-sick.html.md
+++ b/public/posts/2007/06/propaganda-makes-me-sick.md
@@ -1,6 +1,6 @@
Things like this in modern times are surprising. Can't people spot this phony crap for what it is?
-First they put away the dealers, keep our kids safe and off the streets
+First they put away the dealers, keep our kids safe and off the streets
Then they put away the prostitutes, keep married men cloistered at home
Then they shooed away the bums, and they beat and bashed the queers
Turned away asylum-seekers, fed us suspicions and fears
@@ -26,5 +26,5 @@ And piss, while sucking on a giant pacifier
A country of adult infants, a legion of mental midgets
A country of adult infants, a country of adult infants
All regaining their unconsciousness
-
+
—from the song Regaining Unconsciousness, by NOFX
diff --git a/public/posts/2007/06/recent-ruby-and-rails-regales.html.md b/public/posts/2007/06/recent-ruby-and-rails-regales.md
similarity index 100%
rename from public/posts/2007/06/recent-ruby-and-rails-regales.html.md
rename to public/posts/2007/06/recent-ruby-and-rails-regales.md
diff --git a/public/posts/2007/06/reinventing-the-wheel.html.md b/public/posts/2007/06/reinventing-the-wheel.md
similarity index 100%
rename from public/posts/2007/06/reinventing-the-wheel.html.md
rename to public/posts/2007/06/reinventing-the-wheel.md
diff --git a/public/posts/2007/06/rtfm.html.md b/public/posts/2007/06/rtfm.md
similarity index 100%
rename from public/posts/2007/06/rtfm.html.md
rename to public/posts/2007/06/rtfm.md
diff --git a/public/posts/2007/06/so-long-typo-and-thanks-for-all-the-timeouts.html.md b/public/posts/2007/06/so-long-typo-and-thanks-for-all-the-timeouts.md
similarity index 63%
rename from public/posts/2007/06/so-long-typo-and-thanks-for-all-the-timeouts.html.md
rename to public/posts/2007/06/so-long-typo-and-thanks-for-all-the-timeouts.md
index 969f93b..c970ca6 100644
--- a/public/posts/2007/06/so-long-typo-and-thanks-for-all-the-timeouts.html.md
+++ b/public/posts/2007/06/so-long-typo-and-thanks-for-all-the-timeouts.md
@@ -4,23 +4,21 @@ Recently I had looked at converting Typo to Mephisto and it seemed pretty painle
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 RAILS_ENV=production script/console and typed something similar to the following:
-
- 1
-2
-3
-4
-5
-6
-7
- |
- require 'converters/base'
-require 'converters/typo'
-articles = Typo::Article.find(:all).map {|a| [a, Article.find_by_permalink(a.permalink)] }
-articles.each do |ta, ma|
- next if ma.nil?
- ma.tags << Tag.find_or_create(ta.categories.map(&:name))
-end |
-
+1
+2
+3
+4
+5
+6
+7
+
+require 'converters/base'
+require 'converters/typo'
+articles = Typo::Article.find(:all).map {|a| [a, Article.find_by_permalink(a.permalink)] }
+articles.each do |ta, ma|
+ next if ma.nil?
+ ma.tags << Tag.find_or_create(ta.categories.map(&:name))
+end
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.
diff --git a/public/posts/2007/06/testspec-on-rails-declared-awesome-just-one-catch.html.md b/public/posts/2007/06/testspec-on-rails-declared-awesome-just-one-catch.html.md
deleted file mode 100644
index 8b315f1..0000000
--- a/public/posts/2007/06/testspec-on-rails-declared-awesome-just-one-catch.html.md
+++ /dev/null
@@ -1,89 +0,0 @@
-This last week I've been getting to know test/spec via err's test/spec on rails plugin. I have to say that I really dig this method of testing my code and I look forward to trying out some actual BDD in the future.
-
-I did hit a little snag with functional testing though. The method of declaring which controller to use takes the form:
-
-
-
-
- |
- use_controller :foo |
-
-
-
-and can be placed in the setup method, like so:
-
-
-
- 1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-11
-12
-13
-14
-15
- |
- # in test/functional/sessions_controller_test.rb
-
-context "A guest" do
- fixtures :users
-
- setup do
- use_controller :sessions
- end
-
- specify "can login" do
- post :create, :username => 'sjs', :password => 'blah'
- response.should.redirect_to user_url(users(:sjs))
- ...
- end
-end |
-
-
-
-This is great and the test will work. But let's say that I have another controller that guests can access:
-
-
-
- 1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-11
-12
-13
- |
- # in test/functional/foo_controller_test.rb
-
-context "A guest" do
- setup do
- use_controller :foo
- end
-
- specify "can do foo stuff" do
- get :fooriffic
- status.should.be :success
- ...
- end
-end |
-
-
-
-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 rake test:functionals 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 fooriffic can't be found in SessionsController, it lives in FooController 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 setup methods are all added to a list and each one is executed, not just the one in the same context 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.
-
-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.
diff --git a/public/posts/2007/06/testspec-on-rails-declared-awesome-just-one-catch.md b/public/posts/2007/06/testspec-on-rails-declared-awesome-just-one-catch.md
new file mode 100644
index 0000000..248372b
--- /dev/null
+++ b/public/posts/2007/06/testspec-on-rails-declared-awesome-just-one-catch.md
@@ -0,0 +1,83 @@
+This last week I've been getting to know test/spec via err's test/spec on rails plugin. I have to say that I really dig this method of testing my code and I look forward to trying out some actual BDD in the future.
+
+I did hit a little snag with functional testing though. The method of declaring which controller to use takes the form:
+
+
+
+
+use_controller :foo
+
+
+and can be placed in the setup method, like so:
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+
+# in test/functional/sessions_controller_test.rb
+
+context "A guest" do
+ fixtures :users
+
+ setup do
+ use_controller :sessions
+ end
+
+ specify "can login" do
+ post :create, :username => 'sjs', :password => 'blah'
+ response.should.redirect_to user_url(users(:sjs))
+ ...
+ end
+end
+
+
+This is great and the test will work. But let's say that I have another controller that guests can access:
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+
+# in test/functional/foo_controller_test.rb
+
+context "A guest" do
+ setup do
+ use_controller :foo
+ end
+
+ specify "can do foo stuff" do
+ get :fooriffic
+ status.should.be :success
+ ...
+ end
+end
+
+
+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 rake test:functionals 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 fooriffic can't be found in SessionsController, it lives in FooController 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 setup methods are all added to a list and each one is executed, not just the one in the same context 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.
+
+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.
diff --git a/public/posts/2007/07/a-textmate-tip-for-emacs-users.html.md b/public/posts/2007/07/a-textmate-tip-for-emacs-users.md
similarity index 100%
rename from public/posts/2007/07/a-textmate-tip-for-emacs-users.html.md
rename to public/posts/2007/07/a-textmate-tip-for-emacs-users.md
diff --git a/public/posts/2007/07/people.html.md b/public/posts/2007/07/people.md
similarity index 100%
rename from public/posts/2007/07/people.html.md
rename to public/posts/2007/07/people.md
diff --git a/public/posts/2007/07/rushcheck-quickcheck-for-ruby.html.md b/public/posts/2007/07/rushcheck-quickcheck-for-ruby.md
similarity index 100%
rename from public/posts/2007/07/rushcheck-quickcheck-for-ruby.html.md
rename to public/posts/2007/07/rushcheck-quickcheck-for-ruby.md
diff --git a/public/posts/2007/07/see-your-regular-expressions-in-emacs.html.md b/public/posts/2007/07/see-your-regular-expressions-in-emacs.md
similarity index 100%
rename from public/posts/2007/07/see-your-regular-expressions-in-emacs.html.md
rename to public/posts/2007/07/see-your-regular-expressions-in-emacs.md
diff --git a/public/posts/2007/08/5-ways-to-avoid-looking-like-a-jerk-on-the-internet.html.md b/public/posts/2007/08/5-ways-to-avoid-looking-like-a-jerk-on-the-internet.md
similarity index 100%
rename from public/posts/2007/08/5-ways-to-avoid-looking-like-a-jerk-on-the-internet.html.md
rename to public/posts/2007/08/5-ways-to-avoid-looking-like-a-jerk-on-the-internet.md
diff --git a/public/posts/2007/08/captivating-little-creatures.html.md b/public/posts/2007/08/captivating-little-creatures.md
similarity index 100%
rename from public/posts/2007/08/captivating-little-creatures.html.md
rename to public/posts/2007/08/captivating-little-creatures.md
diff --git a/public/posts/2007/08/catch-compiler-errors-at-runtime.html.md b/public/posts/2007/08/catch-compiler-errors-at-runtime.md
similarity index 100%
rename from public/posts/2007/08/catch-compiler-errors-at-runtime.html.md
rename to public/posts/2007/08/catch-compiler-errors-at-runtime.md
diff --git a/public/posts/2007/08/cheat-from-emacs.html.md b/public/posts/2007/08/cheat-from-emacs.md
similarity index 100%
rename from public/posts/2007/08/cheat-from-emacs.html.md
rename to public/posts/2007/08/cheat-from-emacs.md
diff --git a/public/posts/2007/08/cheat-productively-in-emacs.html.md b/public/posts/2007/08/cheat-productively-in-emacs.md
similarity index 100%
rename from public/posts/2007/08/cheat-productively-in-emacs.html.md
rename to public/posts/2007/08/cheat-productively-in-emacs.md
diff --git a/public/posts/2007/08/elschemo-boolean-logic-and-branching.html.md b/public/posts/2007/08/elschemo-boolean-logic-and-branching.md
similarity index 60%
rename from public/posts/2007/08/elschemo-boolean-logic-and-branching.html.md
rename to public/posts/2007/08/elschemo-boolean-logic-and-branching.md
index 32cb095..0ec44a9 100644
--- a/public/posts/2007/08/elschemo-boolean-logic-and-branching.html.md
+++ b/public/posts/2007/08/elschemo-boolean-logic-and-branching.md
@@ -38,25 +38,23 @@ concise language. My explanations may be redundant because of this.
### lispAnd ###
-
- 1
-2
-3
-4
-5
-6
-7
-8
- |
- lispAnd :: Env -> [LispVal] -> IOThrowsError LispVal
-lispAnd env [] = return $ Bool True
-lispAnd env [pred] = eval env pred
-lispAnd env (pred:rest) = do
- result <- eval env pred
- case result of
- Bool False -> return result
- _ -> lispAnd env rest |
-
+1
+2
+3
+4
+5
+6
+7
+8
+
+lispAnd :: Env -> [LispVal] -> IOThrowsError LispVal
+lispAnd env [] = return $ Bool True
+lispAnd env [pred] = eval env pred
+lispAnd env (pred:rest) = do
+ result <- eval env pred
+ case result of
+ Bool False -> return result
+ _ -> lispAnd env rest
Starting with the trivial case, and returns #t with zero
@@ -79,25 +77,23 @@ just complicates things but it's a viable solution.
Predictably this is quite similar to lispAnd.
-
- 1
-2
-3
-4
-5
-6
-7
-8
- |
- lispOr :: Env -> [LispVal] -> IOThrowsError LispVal
-lispOr env [] = return $ Bool False
-lispOr env [pred] = eval env pred
-lispOr env (pred:rest) = do
- result <- eval env pred
- case result of
- Bool False -> lispOr env rest
- _ -> return result |
-
+1
+2
+3
+4
+5
+6
+7
+8
+
+lispOr :: Env -> [LispVal] -> IOThrowsError LispVal
+lispOr env [] = return $ Bool False
+lispOr env [pred] = eval env pred
+lispOr env (pred:rest) = do
+ result <- eval env pred
+ case result of
+ Bool False -> lispOr env rest
+ _ -> return result
With no arguments lispOr returns #f, and with one argument it
@@ -114,13 +110,11 @@ ElSchemo. It maps a list of expressions to their values by evaluating
each one in the given environment.
-
- 1
-2
- |
- evalExprs :: Env -> [LispVal] -> IOThrowsError [LispVal]
-evalExprs env exprs = mapM (eval env) exprs |
-
+1
+2
+
+evalExprs :: Env -> [LispVal] -> IOThrowsError [LispVal]
+evalExprs env exprs = mapM (eval env) exprs
### lispCond ###
@@ -128,21 +122,19 @@ each one in the given environment.
Again, lispCond has the same type as eval.
-
- 1
-2
-3
-4
-5
-6
- |
- lispCond :: Env -> [LispVal] -> IOThrowsError LispVal
-lispCond env (List (pred:conseq) : rest) = do
- result <- eval env pred
- case result of
- Bool False -> if null rest then return result else lispCond env rest
- _ -> liftM last $ evalExprs env conseq |
-
+1
+2
+3
+4
+5
+6
+
+lispCond :: Env -> [LispVal] -> IOThrowsError LispVal
+lispCond env (List (pred:conseq) : rest) = do
+ result <- eval env pred
+ case result of
+ Bool False -> if null rest then return result else lispCond env rest
+ _ -> liftM last $ evalExprs env conseq
Unlike Lisp – which uses a predicate of T (true) – Scheme uses a
@@ -165,15 +157,13 @@ expressions and return the value of the last one.
Now all that's left is to hook up the new functions in eval.
-
- 1
-2
-3
- |
- eval env (List (Atom "and" : params)) = lispAnd env params
-eval env (List (Atom "or" : params)) = lispOr env params
-eval env (List (Atom "cond" : params)) = lispCond env params |
-
+1
+2
+3
+
+eval env (List (Atom "and" : params)) = lispAnd env params
+eval env (List (Atom "or" : params)) = lispOr env params
+eval env (List (Atom "cond" : params)) = lispCond env params
You could, of course, throw the entire definitions in eval itself but eval is big
diff --git a/public/posts/2007/08/opera-is-pretty-slick.html.md b/public/posts/2007/08/opera-is-pretty-slick.md
similarity index 100%
rename from public/posts/2007/08/opera-is-pretty-slick.html.md
rename to public/posts/2007/08/opera-is-pretty-slick.md
diff --git a/public/posts/2007/08/snap-crunchle-pop.html.md b/public/posts/2007/08/snap-crunchle-pop.md
similarity index 100%
rename from public/posts/2007/08/snap-crunchle-pop.html.md
rename to public/posts/2007/08/snap-crunchle-pop.md
diff --git a/public/posts/2007/09/learning-lisp-read-pcl.html.md b/public/posts/2007/09/learning-lisp-read-pcl.md
similarity index 100%
rename from public/posts/2007/09/learning-lisp-read-pcl.html.md
rename to public/posts/2007/09/learning-lisp-read-pcl.md
diff --git a/public/posts/2007/09/python-and-ruby-brain-dump.html.md b/public/posts/2007/09/python-and-ruby-brain-dump.md
similarity index 100%
rename from public/posts/2007/09/python-and-ruby-brain-dump.html.md
rename to public/posts/2007/09/python-and-ruby-brain-dump.md
diff --git a/public/posts/2007/10/gtkpod-in-gutsy-got-you-groaning.html.md b/public/posts/2007/10/gtkpod-in-gutsy-got-you-groaning.md
similarity index 62%
rename from public/posts/2007/10/gtkpod-in-gutsy-got-you-groaning.html.md
rename to public/posts/2007/10/gtkpod-in-gutsy-got-you-groaning.md
index 340483a..adfe1d4 100644
--- a/public/posts/2007/10/gtkpod-in-gutsy-got-you-groaning.html.md
+++ b/public/posts/2007/10/gtkpod-in-gutsy-got-you-groaning.md
@@ -13,30 +13,29 @@ Now that you know what to do I'll give you what you probably wanted at the begin
↓ gtkpod-aac-fix.sh
-
- 1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-11
-12
- |
- mkdir /tmp/gtkpod-fix
-cd /tmp/gtkpod-fix
-wget http://ftp.uni-kl.de/debian-multimedia/pool/main/libm/libmpeg4ip/libmp4v2-0_1.5.0.1-0.3_amd64.deb
-wget http://ftp.uni-kl.de/debian-multimedia/pool/main/libm/libmpeg4ip/libmp4v2-dev_1.5.0.1-0.3_amd64.deb
-wget http://ftp.uni-kl.de/debian-multimedia/pool/main/libm/libmpeg4ip/libmpeg4ip-0_1.5.0.1-0.3_amd64.deb
-wget http://ftp.uni-kl.de/debian-multimedia/pool/main/libm/libmpeg4ip/libmpeg4ip-dev_1.5.0.1-0.3_amd64.deb
-for f in *.deb; do sudo gdebi -n "$f"; done
-svn co https://gtkpod.svn.sourceforge.net/svnroot/gtkpod/gtkpod/trunk gtkpod
-cd gtkpod
-./autogen.sh --with-mp4v2 && make && sudo make install
-cd
-rm -rf /tmp/gtkpod-fix |
-
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+
+
+mkdir /tmp/gtkpod-fix
+cd /tmp/gtkpod-fix
+wget http://ftp.uni-kl.de/debian-multimedia/pool/main/libm/libmpeg4ip/libmp4v2-0_1.5.0.1-0.3_amd64.deb
+wget http://ftp.uni-kl.de/debian-multimedia/pool/main/libm/libmpeg4ip/libmp4v2-dev_1.5.0.1-0.3_amd64.deb
+wget http://ftp.uni-kl.de/debian-multimedia/pool/main/libm/libmpeg4ip/libmpeg4ip-0_1.5.0.1-0.3_amd64.deb
+wget http://ftp.uni-kl.de/debian-multimedia/pool/main/libm/libmpeg4ip/libmpeg4ip-dev_1.5.0.1-0.3_amd64.deb
+for f in *.deb; do sudo gdebi -n "$f"; done
+svn co https://gtkpod.svn.sourceforge.net/svnroot/gtkpod/gtkpod/trunk gtkpod
+cd gtkpod
+./autogen.sh --with-mp4v2 && make && sudo make install
+cd
+rm -rf /tmp/gtkpod-fix
\ No newline at end of file
diff --git a/public/posts/2008/01/random-pet-peeve-of-the-day.html.md b/public/posts/2008/01/random-pet-peeve-of-the-day.md
similarity index 100%
rename from public/posts/2008/01/random-pet-peeve-of-the-day.html.md
rename to public/posts/2008/01/random-pet-peeve-of-the-day.md
diff --git a/public/posts/2008/02/thoughts-on-arc.html.md b/public/posts/2008/02/thoughts-on-arc.md
similarity index 100%
rename from public/posts/2008/02/thoughts-on-arc.html.md
rename to public/posts/2008/02/thoughts-on-arc.md
diff --git a/public/posts/2008/03/project-euler-code-repo-in-arc.html.md b/public/posts/2008/03/project-euler-code-repo-in-arc.md
similarity index 100%
rename from public/posts/2008/03/project-euler-code-repo-in-arc.html.md
rename to public/posts/2008/03/project-euler-code-repo-in-arc.md
diff --git a/public/posts/2009/11/using-emacs-to-develop-mojo-apps-for-webos.html.md b/public/posts/2009/11/using-emacs-to-develop-mojo-apps-for-webos.md
similarity index 100%
rename from public/posts/2009/11/using-emacs-to-develop-mojo-apps-for-webos.html.md
rename to public/posts/2009/11/using-emacs-to-develop-mojo-apps-for-webos.md
diff --git a/public/posts/2010/01/a-preview-of-mach-o-file-generation.html.md b/public/posts/2010/01/a-preview-of-mach-o-file-generation.md
similarity index 100%
rename from public/posts/2010/01/a-preview-of-mach-o-file-generation.html.md
rename to public/posts/2010/01/a-preview-of-mach-o-file-generation.md
diff --git a/public/posts/2010/01/basics-of-the-mach-o-file-format.html.md b/public/posts/2010/01/basics-of-the-mach-o-file-format.md
similarity index 94%
rename from public/posts/2010/01/basics-of-the-mach-o-file-format.html.md
rename to public/posts/2010/01/basics-of-the-mach-o-file-format.md
index 8e6c247..e74a904 100644
--- a/public/posts/2010/01/basics-of-the-mach-o-file-format.html.md
+++ b/public/posts/2010/01/basics-of-the-mach-o-file-format.md
@@ -54,7 +54,7 @@ diagram showing the layout of such a file:
The Mach header contains the architecture (cpu type), the type of
file (object in our case), and the number of segments. There is more
to it but that's about all we care about. To see exactly what's in a
-Mach header fire up a shell and type otool -h /bin/zsh (on a
+Mach header fire up a shell and type otool -h /bin/zsh (on a
Mac).
Using
@@ -122,18 +122,18 @@ constants as well.
Looking at real Mach-O files
To see the segments and sections of an object file, run
-otool -l /usr/lib/crt1.o. -l is for load commands.
+otool -l /usr/lib/crt1.o. -l is for load commands.
If you want to see why we stick to generating object files instead of
-executables run otool -l /bin/zsh. They are complicated
+executables run otool -l /bin/zsh. They are complicated
beasts.
If you want to see the actual data for a section otool provides a
couple of ways to do this. The first is to use
-otool -d <segment> <section> for an arbitrary
+otool -d <segment> <section> for an arbitrary
section. To see the contents of a well-known section, such as __text
-in the __TEXT segment, use otool -t /usr/bin/true. You can
+in the __TEXT segment, use otool -t /usr/bin/true. You can
also disassemble the __text section with
-otool -tv /usr/bin/true.
+otool -tv /usr/bin/true.
You'll get to know otool quite well if you work with Mach-O.
diff --git a/public/posts/2010/01/working-with-c-style-structs-in-ruby.html.md b/public/posts/2010/01/working-with-c-style-structs-in-ruby.md
similarity index 100%
rename from public/posts/2010/01/working-with-c-style-structs-in-ruby.html.md
rename to public/posts/2010/01/working-with-c-style-structs-in-ruby.md
diff --git a/public/posts/2010/11/37signals-chalk-dissected.html.md b/public/posts/2010/11/37signals-chalk-dissected.md
similarity index 100%
rename from public/posts/2010/11/37signals-chalk-dissected.html.md
rename to public/posts/2010/11/37signals-chalk-dissected.md
diff --git a/public/posts/2011/11/lights.html.md b/public/posts/2011/11/lights.md
similarity index 100%
rename from public/posts/2011/11/lights.html.md
rename to public/posts/2011/11/lights.md
diff --git a/public/posts/2011/11/recovering-old-posts.html.md b/public/posts/2011/11/recovering-old-posts.md
similarity index 100%
rename from public/posts/2011/11/recovering-old-posts.html.md
rename to public/posts/2011/11/recovering-old-posts.md
diff --git a/public/posts/2011/12/i-see-http.html.md b/public/posts/2011/12/i-see-http.md
similarity index 100%
rename from public/posts/2011/12/i-see-http.html.md
rename to public/posts/2011/12/i-see-http.md
diff --git a/public/posts/2011/12/my-kind-of-feature-checklist.html.md b/public/posts/2011/12/my-kind-of-feature-checklist.md
similarity index 100%
rename from public/posts/2011/12/my-kind-of-feature-checklist.html.md
rename to public/posts/2011/12/my-kind-of-feature-checklist.md
diff --git a/public/posts/2011/12/new-release-of-firefox-for-android-optimized-for-tablets.html.md b/public/posts/2011/12/new-release-of-firefox-for-android-optimized-for-tablets.md
similarity index 100%
rename from public/posts/2011/12/new-release-of-firefox-for-android-optimized-for-tablets.html.md
rename to public/posts/2011/12/new-release-of-firefox-for-android-optimized-for-tablets.md
diff --git a/public/posts/2011/12/pure-css3-images-hmm-maybe-later.html.md b/public/posts/2011/12/pure-css3-images-hmm-maybe-later.md
similarity index 100%
rename from public/posts/2011/12/pure-css3-images-hmm-maybe-later.html.md
rename to public/posts/2011/12/pure-css3-images-hmm-maybe-later.md
diff --git a/public/posts/2011/12/static-url-shortener-using-htaccess.html.md b/public/posts/2011/12/static-url-shortener-using-htaccess.md
similarity index 100%
rename from public/posts/2011/12/static-url-shortener-using-htaccess.html.md
rename to public/posts/2011/12/static-url-shortener-using-htaccess.md
diff --git a/public/posts/2011/12/the-broken-pixel-theory.html.md b/public/posts/2011/12/the-broken-pixel-theory.md
similarity index 100%
rename from public/posts/2011/12/the-broken-pixel-theory.html.md
rename to public/posts/2011/12/the-broken-pixel-theory.md
diff --git a/public/posts/2012/01/fujitsu-has-lost-their-mind.html.md b/public/posts/2012/01/fujitsu-has-lost-their-mind.md
similarity index 100%
rename from public/posts/2012/01/fujitsu-has-lost-their-mind.html.md
rename to public/posts/2012/01/fujitsu-has-lost-their-mind.md
diff --git a/public/posts/2012/01/recovering-from-a-computer-science-education.html.md b/public/posts/2012/01/recovering-from-a-computer-science-education.md
similarity index 100%
rename from public/posts/2012/01/recovering-from-a-computer-science-education.html.md
rename to public/posts/2012/01/recovering-from-a-computer-science-education.md
diff --git a/public/posts/2012/01/sopa-lives-and-mpaa-calls-protests-an-abuse-of-power.html.md b/public/posts/2012/01/sopa-lives-and-mpaa-calls-protests-an-abuse-of-power.md
similarity index 100%
rename from public/posts/2012/01/sopa-lives-and-mpaa-calls-protests-an-abuse-of-power.html.md
rename to public/posts/2012/01/sopa-lives-and-mpaa-calls-protests-an-abuse-of-power.md
diff --git a/public/posts/2012/01/the-40-standup-desk.html.md b/public/posts/2012/01/the-40-standup-desk.md
similarity index 100%
rename from public/posts/2012/01/the-40-standup-desk.html.md
rename to public/posts/2012/01/the-40-standup-desk.md
diff --git a/public/posts/2012/01/yak-shaving.html.md b/public/posts/2012/01/yak-shaving.md
similarity index 100%
rename from public/posts/2012/01/yak-shaving.html.md
rename to public/posts/2012/01/yak-shaving.md
diff --git a/public/posts/2013/03/zelda-tones-for-ios.html.md b/public/posts/2013/03/zelda-tones-for-ios.md
similarity index 100%
rename from public/posts/2013/03/zelda-tones-for-ios.html.md
rename to public/posts/2013/03/zelda-tones-for-ios.md
diff --git a/public/posts/2013/09/linky.html.md b/public/posts/2013/09/linky.md
similarity index 100%
rename from public/posts/2013/09/linky.html.md
rename to public/posts/2013/09/linky.md
diff --git a/public/posts/2014/02/ember-structure.html.md b/public/posts/2014/02/ember-structure.md
similarity index 100%
rename from public/posts/2014/02/ember-structure.html.md
rename to public/posts/2014/02/ember-structure.md