add a basic blog, all posts listed in index

This commit is contained in:
Sami Samhuri 2010-12-06 10:54:42 -08:00
parent 512a68bcfd
commit 86915cf555
12 changed files with 1680 additions and 0 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
*.tmproj
.DS_Store
_blog

98
assets/blog.css Normal file
View file

@ -0,0 +1,98 @@
body { background-color: #a6bcd1
; font-family: 'DejaVu Serif', 'xHoefler Text', Georgia, serif
; margin: 0
}
h1 { text-align: right
; font-size: 4em
; font-weight: normal
; margin: 0
; padding: 0.2em
; color: #9ab
}
h1 a { color: #9ab
; border-bottom: none
}
a { color: #24a }
a.img { border: none }
#breadcrumbs { font-size: 1.5em
; color: #444
; position: absolute
; top: 0.3em
; left: 0.3em
}
#breadcrumbs a { text-shadow: none
; color: #444
; border: none
; text-decoration: underline
}
article { width: 60%
; min-width: 400px
; max-width: 800px
; margin: 0 auto
; color: #222
; padding-left: 3em
; padding-bottom: 5em
; line-height: 1.2em
}
article h1 { text-align: left
; font-size: 2em
; font-weight: normal
; color: #222
; text-shadow: #f7f7f7 1px 1px 5px
; margin: 1em 0
}
article h1 a { color: #222
; text-decoration: underline
; border-bottom: none
}
article h2 { font-size: 1.6em
; font-weight: normal
; margin: 1em 0
; padding: 0
; color: #222
}
time { color: #444 }
footer { text-align: center
; font-size: 1.2em
; margin: 0
; padding: 1em
; background-color: #f7f7f7
; border-top: solid 1px #666
; border-bottom: solid 1px #999
}
footer a { border-bottom: none
; color: #25c
}
/* iPhone */
@media only screen and (max-device-width:480px) {
h1 { font-size: 2em
; margin-top: 1em
}
h2 { font-size: 1em }
#breadcrumbs { font-size: 0.8em }
article { width: 80%
; min-width: 100px
; max-width: 800px
; padding-left: 1em
; padding-bottom: 3em
}
footer { font-size: 1em }
}

46
blog.rb Executable file
View file

@ -0,0 +1,46 @@
#!/usr/bin/env ruby
require 'rubygems'
require 'json'
require 'rdiscount'
require 'mustache'
srcdir = ARGV.shift.to_s
destdir = ARGV.shift.to_s
unless File.directory?(srcdir) && File.directory?(destdir)
puts 'usage: blog.rb <source dir> <dest dir>'
exit 1
end
template = File.read(File.join('templates', 'blog', 'post.html'))
Posts = JSON.parse(File.read(File.join(srcdir, 'posts.json')))
posts = Posts['published'].map do |filename|
lines = File.readlines(File.join(srcdir, filename))
post = { :filename => filename }
loop do
line = lines.shift.strip
m = line.match(/(\w+):/)
if m && param = m[1].downcase
post[param] = line.sub(Regexp.new('^' + param + ':\s*', 'i'), '').strip
elsif line.match(/^----\s*$/)
lines.shift while lines.first.strip.empty?
break
else
puts "ignoring unknown header: #{line}"
end
end
post[:content] = lines.join
post[:body] = RDiscount.new(post[:content]).to_html
post[:html] = Mustache.render(template, post)
post
end
index_template = File.read(File.join('templates', 'blog', 'index.html'))
index_html = Mustache.render(index_template, { :posts => posts })
File.open(File.join(destdir, 'index.html'), 'w') {|f| f.puts(index_html) }
posts.each do |post|
File.open(File.join(destdir, post[:filename]), 'w') {|f| f.puts(post[:html]) }
end

11
blog.sh Executable file
View file

@ -0,0 +1,11 @@
#!/bin/sh
if [[ ! -d _blog ]]; then
git clone git://github.com/samsonjs/blog.git _blog
else
cd _blog
git pull
cd ..
fi
./blog.rb _blog

View file

@ -0,0 +1,272 @@
<!doctype html>
<meta charset=utf-8>
<meta name=viewport content=width=device-width>
<title>37signals' Chalk Dissected :: samhuri.net</title>
<link rel=stylesheet href=../assets/blog.css>
<script>
var _gaq = _gaq || [];
_gaq.push( ['_setAccount', 'UA-214054-5']
, ['_trackPageview']
);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<nav id=breadcrumbs><a href=../>samhuri.net</a> &rarr; <a href=index.html>blog</a></nav>
<header>
<h1><a href=index.html>sjs' blog</a></h1>
</header>
<article>
<header>
<h1>37signals' Chalk Dissected</h1>
<time>November 4, 2010</time>
</header>
<p><i>Update 2010-11-05: I dove into the JavaScript a little and explained most of it. Sam Stephenson <a href="https://twitter.com/sstephenson/status/553490682216449">tweeted</a> that Chalk is written in <a href="http://jashkenas.github.com/coffee-script/">CoffeeScript</a> and compiled on the fly when served using <a href="https://github.com/sstephenson/brochure">Brochure</a>. That's hot! (for those unaware Sam Stephenson works at 37signals, and is also the man behind <a href="http://www.prototypejs.org/">Prototype</a>.)</i></p>
<p><a href="http://37signals.com/">37signals</a> recently released a blackboard web app for iPad called <a href="http://chalk.37signals.com/">Chalk</a>.</p>
<p>It includes <a href="http://mir.aculo.us/">Thomas Fuchs</a> new mobile JS framework <a href="https://github.com/madrobby/zepto">Zepto</a>, a few images, iOS SpringBoard icon, and of course HTML, CSS, and JavaScript. It weighs in at about 244k including 216k of images. HTML, CSS, and JavaScript are not minified (except Zepto), but they are gzipped. Because the image-to-text ratio is high gzip can only shave off 12k. There is absolutely nothing there that isn't required though. The code and resources are very tight, readable, and beautiful.</p>
<p>The manifest is a nice summary of the contents, and allows browsers to cache the app for offline use. Combine this with mobile Safari's "Add to Home Screen" button and you have yourself a free chalkboard app that works offline.</p>
<pre><code>CACHE MANIFEST
/
/zepto.min.js
/chalk.js
/images/background.jpg
/images/chalk.png
/images/chalk-sprites.png
/images/chalk-tile-erase.jpg
/images/chalk-tile-red.png
/images/chalk-tile-white.png
/stylesheets/chalk.css
</code></pre>
<p>Not much there, just 10 requests to fetch the whole thing. 11 including the manifest. In we go.</p>
<p>&nbsp;</p>
<h2>HTML</h2>
<p>2k, 61 lines. 10 of which are Google Analytics JavaScript. Let's glance at some of it.<p>
<script src="https://gist.github.com/663655.js?file=chalk.html"></script>
<p>Standard html5 doctype, and a manifest for <a href="http://diveintohtml5.org/offline.html">application caching</a>.</p>
<p>The rest of the HTML is mainly structural. There is not a single text node in the entire tree (excluding whitespace). The chalkboard is a canvas element and an image element used to render the canvas contents as an image for sharing. The other elements are just sprites and buttons. There are div elements for the light switch and shade (a dimmer on each side), share button, instructions on sharing, close button, ledge, chalk, eraser and corresponding indicators. Phew, that was a mouthful. (oblig: "that's what she said!")</p>
<p>The interesting thing about the HTML is that without any JavaScript or CSS the document would be a completely blank white page (except for a strange looking share button w/ no title). Talk about progressive enhancement. Here's a look at the HTML:</p>
<script src="https://gist.github.com/663642.js?file=chalk.html"></script>
<p>Onward.</p>
<p>&nbsp;</p>
<h2>Zepto</h2>
<p>Zepto is a <i>tiny</i>, modern JS framework for mobile WebKit browsers such as those found on iPhone and Android handsets. I'm not going to cover it here but I'll mention that it's similar in feel to jQuery. In fact it tries to mimic jQuery very closely to make migrations from Zepto to jQuery easy, and vice versa. The reason it weighs in at just under 6k (2k gzipped) is that it doesn't overreach or have to support legacy crap like IE6. It was started by Thomas Fuchs so you know it's good.</p>
<p>&nbsp;</p>
<h2>Display (CSS &amp; Images)</h2>
<p>6.6k, 385 lines. This is basically half of the text portion, excluding Zepto. There are 6 images including one called chalk-sprites.png. Interesting. Let's look at the background first though.</p>
<p>&nbsp;</p>
<h3>Background</h3>
<p>&nbsp;</p>
<div align="center">
<a href="http://samhuri.net/Chalk/images/background.jpg"><img height="473" src="http://samhuri.net/Chalk/images/background.jpg" style="border: 0;" width="512" /></a><br />
background.jpg 1024x946px</div>
<p>The background is the blackboard itself, and is almost square at 1024x946. The cork border and light switch are there too. This is set as the background-image of the html element and is positioned at a negative x or y in order to centre it properly. <a href="https://developer.mozilla.org/En/CSS/Media_queries">CSS media queries</a> are used to detect the screen's orientation. This way the same image is used for both orientations, clever.</p>
<script src="https://gist.github.com/663656.js?file=chalk-01.css">
</script>
<p>&nbsp;</p>
<h3>Chalkboard</h3>
<p>Just a canvas element positioned over the chalkboard using media queries. There's also an image element called "output" used to render an image for sharing.</p>
<script src="https://gist.github.com/663675.js?file=chalk-chalkboard.css">
</script>
<p>&nbsp;</p>
<h3>Sprites</h3>
<p>&nbsp;</p>
<div align="center" id="sprites">
<img height="534" src="http://samhuri.net/Chalk/images/chalk-sprites.png" width="502" /><br />
chalk-sprites.png </div>
<p>Sprites are used for all the other elements: ledge, chalk, eraser, tool indicator, share button, instructions, and close button (to leave the sharing mode). Positioned using CSS, standard stuff. There is white text alongside those green arrows. If you want to see it we'll have to <a href="#" onclick="document.getElementById('sprites').style.backgroundColor = '#000'; return false">change the background to black</a>.</p>
<p>&nbsp;</p>
<h3>Light Switch &amp; Shade</h3>
<p>When you touch the light switch on the left side of the chalkboard - only visible in landscape orientation - the cork border dims and the ledge and share button disappear, leaving the chalkboard under the spotlight all classy like. The shade consists of two "dimmer" div elements inside a shade div, which is hidden by default.</p>
<p>The dimmers background color is black at 67% opacity. The shade element fades in using -webkit-transition: on its visibility property while the dimmers use CSS3 transitions on their background. The dimmers are positioned using media queries as well, one on each side of the board. Interestingly their parent shade has a height and width of 0. Rather than each having a unique id they just have the class "dim" and the :nth-child pseudo-class selector is used to position them independently.</p>
<script src="https://gist.github.com/663664.js?file=chalk-02.css">
</script>
<p>If you took a look at the HTML before you'll have noticed there's no shade class defined on the body element. Looks like they're using JavaScript to add the shade class to body, triggering the transitions to the visible shades and setting the dimmers backgrounds to black at the same time, causing the fading effect. The shade fades in while the ledge and share button fade out.</p>
<p>The light switch itself is displayed only in landscape orientation, again using a media query.</p>
<p>&nbsp;</p>
<h3>Tools</h3>
<p>There are 2 layers to the tools on the ledge. There are the images of the tools and their indicators, but also an anchor element for each tool that acts as targets to select them. When tools are select the indicators fade in and out using CSS3 transitions on opacity by adding and removing the class "active" on the tool.</p>
<script src="https://gist.github.com/663693.js?file=chalk-indicators.css">
</script>
<p>There are pattern images for each colour of chalk, and one for the the eraser. The eraser "pattern" is the entire blackboard so erasing it doesn't look ugly. I love that kind of attention to detail.<p>
<p>&nbsp;</p>
<h3>Sharing</h3>
<p>The shade effect that happens when you hit the share button is similar to the shade effect used for the light switch. It's a bit more complex as the sharing instructions are positioned differently in portrait and landscape orientations, but there's nothing really new in there (that I can see).</p>
<p>The rest of the CSS is largely presentational stuff like removing margins and padding, and positioning using lots of media queries. You can see it all at <a href="http://chalk.37signals.com/stylesheets/chalk.css">chalk.37signals.com/stylesheets/chalk.css</a>.</p>
<p>&nbsp;</p>
<h2>JavaScript (and CoffeeScript)</h2>
<p>5.5k in about 170 lines. That's just half the size of the CSS.</p>
<p><i>Sam Stephenson <a href="https://gist.github.com/664351">shared the original CoffeeScript source</a> with us. It's about 150 lines, and is a bit easier to read as CS is far cleaner than JS.</i></p>
<p>The bulk of the magic is done w/ hardware accelerated CSS3 rather than slow JS animation using setInterval and setTimeout to change properties. That sort of thing isn't novel anymore anyway. The fact that JS is really only used for drawing and toggling CSS classes is pretty awesome!</p>
<p>The entire contents of the JS reside inside the DOMContentLoaded event handler attached to window.</p>
<p>&nbsp;</p>
<h3>Initialization</h3>
<p>&nbsp;</p>
<script src="https://gist.github.com/664206.js?file=chalk-init.js"></script>
<p>First we get a handle on all the elements and the canvas' 2d drawing context. I almost want to say views and controls as it really feels just like hooking up a controller and view in a desktop GUI app. Sometimes the line between dynamic web page and web app are blurred, not so here. Chalk is 100% app.</p>
<p>The canvas' dimensions and pen are initialized in lines 13 - 19, and then the chalkboard background is drawn onto the canvas using the <code>drawImage()</code> method.</p>
<p>The canvas offsets are cached for calculations, and are updated when the window fires the "orientationChange" event. Next up tools (a.k.a. pens) are created and initialized.</p>
<p>&nbsp;</p>
<h3>Tools</h3>
<p>&nbsp;</p>
<script src="https://gist.github.com/664214.js?file=chalk-tools.js"></script>
<p><code>createPattern(name, callback)</code> loads one of the pattern images, chalk-tile-*, and then creates a pattern in the drawing context and passes it to the given callback.</p>
<p><code>setStroke(pattern, width)</code> effectively sets the pen used for drawing, described as a pattern & stroke width. The patterns are initialized and the white pen is passed to setStroke since it's the default tool.</p>
<p>The last part defines the 3 tools, note that the active tool "white_chalk" is at the end. Also note that the tool names are the ids of the target elements in the ledge. <code>activateTool(tool)</code> accepts a tool name. The tool to activate is moved to the end of the tools array on lines 31-32, activeTool is set to the given tool as well on line 32. The reason for moving the active tool to the end of the array is revealed in the for loop on line 34, the order of the tools array determines their z-index ordering (highest number is in front). Then the 'active' CSS class is added to the active tool to show the indicator, and then the pen is set by assigning a pen to the context's <code>strokeStyle</code> property.</p>
<p>Finally the white_chalk tool is activated and the click event for the tool targets is setup.</p>
<p>&nbsp;</p>
<h3>Drawing</h3>
<p>&nbsp;</p>
<script src="https://gist.github.com/664235.js?file=chalk-drawing.js"></script>
<p>Drawing is done by listening for touch events on the canvas element. An array of points to draw is initialized to a 1-element array containing <code>null</code>. Null values make the draw function break up the line being drawn by skipping the next point in the array. x and y coords are initialized in touchstart, points are appended to the points array in touchmove, and the touchend handler appends two points and null to the points array to end the line. I'm not sure why <code>[x, y]</code> is used as the points in the touchend handler rather than coords from the event. Please leave a comment if you know why!</p>
<p>The draw function is called for each point in the points array at 30ms intervals. A line is started by calling <code>context.beginPath()</code>, each point is drawn, and then the line is ended with <code>context.stroke()</code>. <strike>The 2nd condition of the while loop ensures that we don't draw for too long, as bad things would happen if the function were executed a 2nd time while it was already running.</strike></p>
<p><b>Sam Stephenson was kind enough to clarify these points. <a href="#Blog1_cmt-1187434093983456531">See his comment below</a> the post for clarification on using [x, y] in the touchend handler and the 10ms limit when drawing points.</b></p>
<p>&nbsp;</p>
<h3>Light Switch &amp; Shade</h3>
<p>&nbsp;</p>
<script src="https://gist.github.com/664260.js?file=chalk-shade.js"></script>
<p>When the light switch is touched (or clicked) the shade class on the body element is toggled. Nothing to it.</p>
<p>&nbsp;</p>
<h3>Sharing</h3>
<p>&nbsp;</p>
<script src="https://gist.github.com/664263.js?file=chalk-share.js"></script>
<p>The share window is opened after a 10ms delay, just enough time for any drawing to be completed before rendering the image. The image is created by assigning the result of canvas' <code>toDataURL()</code> method to the output image element's src attribute.</p>
<p>When the share window is closed the output image element gets its src set to the sprites image. <strike>I'm not sure why that was done.</strike> <i>As Sam mentions in <a href="#Blog1_cmt-118743409398345653">his comment below</a>, this is done to reclaim the memory used by the rendered image.</i></p>
<p>The rest of the code there just sets up event handlers and toggles CSS classes.</p>
<p>&nbsp;</p>
<h2>That's it!</h2>
<p>That about covers it. Don't have an iPad? <a href="http://samhuri.net/Chalk/index.html">Play around with it anyway</a>, but be warned that you can't draw anything. You can select chalk and the eraser and hit the light switch. I instinctively tried touching my MacBook's display but alas it doesn't magically respond to touches, lame.</p>
<p>Have fun drawing. Thanks to 37signals for a beautiful (and useful) example of a few modern web technologies.</p>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
<script>function addLineNumbersToAllGists() {
$('.gist').each( function() {
_addLineNumbersToGist('#' + $(this).attr('id'));
});
}
function addLineNumbersToGist(id) {
_addLineNumbersToGist('#gist-' + id);
}
function _addLineNumbersToGist(css_selector) {
$(document).ready( function() {
$(css_selector + ' .line').each(function(i, e) {
$(this).prepend(
$('<div/>').css({
'float' : 'left',
'width': '30px',
'font-weight' : 'bold',
'color': '#808080'
}).text(++i)
);
});
});
}
addLineNumbersToAllGists();
</script>
</article>
<footer>
<a href=https://twitter.com/_sjs>@_sjs</a>
</footer>

View file

@ -0,0 +1,66 @@
<!doctype html>
<meta charset=utf-8>
<meta name=viewport content=width=device-width>
<title>A preview of Mach-O file generation :: samhuri.net</title>
<link rel=stylesheet href=../assets/blog.css>
<script>
var _gaq = _gaq || [];
_gaq.push( ['_setAccount', 'UA-214054-5']
, ['_trackPageview']
);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<nav id=breadcrumbs><a href=../>samhuri.net</a> &rarr; <a href=index.html>blog</a></nav>
<header>
<h1><a href=index.html>sjs' blog</a></h1>
</header>
<article>
<header>
<h1>A preview of Mach-O file generation</h1>
<time>January 20, 2010</time>
</header>
<p>This month I got back into an x86 compiler I started last May. It lives <a
href="https://github.com/samsonjs/compiler">on github</a>.</p>
<p>The code is a bit of a mess but it mostly works. It generates Mach object
files that are linked with gcc to produce executable binaries.</p>
<p>The Big Refactoring of January 2010 has come to an end and the tests pass
again, even if printing is broken it prints <i>something</i>, and more
importantly compiles test/test_huge.code into something that works.</p>
<p>After print is fixed I can clean up the code before implementing anything
new. I wasn't sure if I'd get back into this or not and am pretty excited
about it. I'm learning a lot from this project.</p>
<p>If you are following the Mach-O posts you might want to look at
asm/machofile.rb, a library for creating Mach-O files. Using it is quite
straightforward, an example is in asm/binary.rb, in the #output method.</p>
<p>Definitely time for bed now!</p>
</article>
<footer>
<a href=https://twitter.com/_sjs>@_sjs</a>
</footer>

View file

@ -0,0 +1,289 @@
<!doctype html>
<meta charset=utf-8>
<meta name=viewport content=width=device-width>
<title>Basics of the Mach-O file format :: samhuri.net</title>
<link rel=stylesheet href=../assets/blog.css>
<script>
var _gaq = _gaq || [];
_gaq.push( ['_setAccount', 'UA-214054-5']
, ['_trackPageview']
);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<nav id=breadcrumbs><a href=../>samhuri.net</a> &rarr; <a href=index.html>blog</a></nav>
<header>
<h1><a href=index.html>sjs' blog</a></h1>
</header>
<article>
<header>
<h1>Basics of the Mach-O file format</h1>
<time>January 18, 2010</time>
</header>
<p><i>This post is part of a series on generating basic x86 Mach-O files
with Ruby. The
<a href="working-with-c-style-structs-in-ruby.html">
first post</a> introduced CStruct, a Ruby class used to serialize
simple struct-like objects.</i></p>
<p>Please note that the best way to learn about Mach-O properly is to
read Apple's
<a href="http://developer.apple.com/Mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html#//apple_ref/doc/uid/TP40000895-CH248-SW3">
documentation on Mach-O</a>, which is pretty good combined with the
comments in /usr/include/mach-o/*.h. These posts will only cover
the basics necessary to generate a simple object file for linking with
ld or gcc, and are not meant to be comprehensive.</p>
<h2>Mach-O File Format Overview</h2>
<p>A Mach-O file consists of 2 main pieces: the <b>header</b> and
the <b>data</b>. The header is basically a map of the file describing
what it contains and the position of everything contained in it. The
data comes directly after the header and consists of a number of
binary blobs of data, one after the other.</p>
<p>The header contains 3 types of records: the <b>Mach header</b>,
<b>segments</b>, and <b>sections</b>. Each binary blob is described
by a named section in the header. Sections are grouped into one or
more named segments. The Mach header is just one part of the header
and should not be confused with the entire header. It contains
information about the file as a whole, and specifies the number of
segments as well.</p>
<p>Take a quick look at <b>Figure 1</b> in
<a href="http://developer.apple.com/Mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html#//apple_ref/doc/uid/TP40000895-CH248-SW3">
Apple's Mach-O overview</a>, which illustrates this quite nicely.</p>
<p>A very basic Mach object file consists of a header followed by single
blob of machine code. That blob could be described by a single
section named __text, inside a single nameless segment. Here's a
diagram showing the layout of such a file:</p>
<pre>
,---------------------------,
Header | Mach header |
| Segment 1 |
| Section 1 (__text) | --,
|---------------------------| |
Data | blob | &lt;-'
'---------------------------'
</pre>
<h2>The Mach Header</h2>
<p>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 <tt>otool -h /bin/zsh</tt> (on a
Mac).</p>
<p>Using
<a href="working-with-c-style-structs-in-ruby.html">
CStruct</a> we define the Mach header like so:</p>
<script src="http://gist.github.com/280635.js"></script>
<h2>Segments</h2>
<p>Segments, or <b>segment commands</b>, specify where in memory the
segment should be loaded by the OS, and the number of bytes to
allocate for that segment. They also specify which bytes inside the
file are part of that segment, and how many sections it contains.</p>
<p>One benefit to generating an object file rather than an executable is
that we let the linker worry about some details. One of those details
is where in memory segments will ultimately end up.</p>
<p>Names are optional and can be arbitrary, but the convention is to
name segments with uppercase letters preceded by two underscores,
e.g. __DATA or __TEXT </p>
<p>The code exposes some more details about segment commands, but should
be easy enough to follow.</p>
<script src="http://gist.github.com/280642.js"></script>
<h2>Sections</h2>
<p>All sections within a segment are described one after the other
directly after each segment command. Sections define their name,
address in memory, size, offset of section data within the file, and
segment name. The segment name might seem redundant but in the next
post we'll see why this is useful information to have in the section
header.</p>
<p>Sections can optionally specify a map to addresses within their
binary blob, called a <b>relocation table</b>. This is used by the
linker. Since we're letting the linker work out where to place
everything in memory the addresses inside our machine code will need
to be updated.</p>
<p>By convention segments are named with lowercase letters preceded by
two underscores, e.g. __bss or __text</p>
<p>Finally, the Ruby code describing section structs:</p>
<script src="http://gist.github.com/280643.js"></script>
<h2>macho.rb</h2>
<p>As much of the Mach-O format as we need is defined in
<a href="http://github.com/samsonjs/compiler/blob/master/asm/macho.rb">
asm/macho.rb</a>. The Mach header, Segment commands, sections,
relocation tables, and symbol table structs are all there, with a few
constants as well.</p>
<p>I'll cover symbol tables and relocation tables in my next post.</p>
<h2>Looking at real Mach-O files</h2>
<p>To see the segments and sections of an object file, run
<tt>otool -l /usr/lib/crt1.o</tt>. <b>-l</b> is for load commands.
If you want to see why we stick to generating object files instead of
executables run <tt>otool -l /bin/zsh</tt>. They are complicated
beasts.</p>
<p>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
<tt>otool -d &lt;segment&gt; &lt;section&gt;</tt> for an arbitrary
section. To see the contents of a well-known section, such as __text
in the __TEXT segment, use <tt>otool -t /usr/bin/true</tt>. You can
also disassemble the __text section with
<tt>otool -tv /usr/bin/true</tt>.</p>
<p>You'll get to know otool quite well if you work with Mach-O.</p>
<h2>Take a break</h2>
<p>That was probably a lot to digest, and to make real sense of it you
might need to read some of the
<a href="http://developer.apple.com/Mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html#//apple_ref/doc/uid/TP40000895-CH248-SW3">
official documentation</a>.</p>
<p>We're close to being able to describe a minimal Mach object file
that can be linked, and the resulting binary executed. By the end of
the next post we'll be there.</p>
<p><i>(You can almost do that with what we know now. If you
create a Mach file with a Mach header (ncmds=1), a single unnamed
segment (nsects=1), and then a section named __text with a segment
name of __TEXT, and some x86 machine code as the section data, you
would almost have a useful Mach object file.)</i></p>
<p>Till next time, happy hacking!</p>
</article>
<footer>
<a href=https://twitter.com/_sjs>@_sjs</a>
</footer>

693
blog/index.html Normal file
View file

@ -0,0 +1,693 @@
<!doctype html>
<meta charset=utf-8>
<meta name=viewport content=width=device-width>
<title>blog :: samhuri.net</title>
<link rel=stylesheet href=../assets/blog.css>
<script>
var _gaq = _gaq || [];
_gaq.push( ['_setAccount', 'UA-214054-5']
, ['_trackPageview']
);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<nav id=breadcrumbs><a href=../>samhuri.net</a></nav>
<header>
<h1><a href=index.html>sjs' blog</a></h1>
</header>
<article>
<header>
<h1><a href=37signals-chalk-dissected.html>37signals' Chalk Dissected</a></h1>
<time>November 4, 2010</time>
</header>
<p><i>Update 2010-11-05: I dove into the JavaScript a little and explained most of it. Sam Stephenson <a href="https://twitter.com/sstephenson/status/553490682216449">tweeted</a> that Chalk is written in <a href="http://jashkenas.github.com/coffee-script/">CoffeeScript</a> and compiled on the fly when served using <a href="https://github.com/sstephenson/brochure">Brochure</a>. That's hot! (for those unaware Sam Stephenson works at 37signals, and is also the man behind <a href="http://www.prototypejs.org/">Prototype</a>.)</i></p>
<p><a href="http://37signals.com/">37signals</a> recently released a blackboard web app for iPad called <a href="http://chalk.37signals.com/">Chalk</a>.</p>
<p>It includes <a href="http://mir.aculo.us/">Thomas Fuchs</a> new mobile JS framework <a href="https://github.com/madrobby/zepto">Zepto</a>, a few images, iOS SpringBoard icon, and of course HTML, CSS, and JavaScript. It weighs in at about 244k including 216k of images. HTML, CSS, and JavaScript are not minified (except Zepto), but they are gzipped. Because the image-to-text ratio is high gzip can only shave off 12k. There is absolutely nothing there that isn't required though. The code and resources are very tight, readable, and beautiful.</p>
<p>The manifest is a nice summary of the contents, and allows browsers to cache the app for offline use. Combine this with mobile Safari's "Add to Home Screen" button and you have yourself a free chalkboard app that works offline.</p>
<pre><code>CACHE MANIFEST
/
/zepto.min.js
/chalk.js
/images/background.jpg
/images/chalk.png
/images/chalk-sprites.png
/images/chalk-tile-erase.jpg
/images/chalk-tile-red.png
/images/chalk-tile-white.png
/stylesheets/chalk.css
</code></pre>
<p>Not much there, just 10 requests to fetch the whole thing. 11 including the manifest. In we go.</p>
<p>&nbsp;</p>
<h2>HTML</h2>
<p>2k, 61 lines. 10 of which are Google Analytics JavaScript. Let's glance at some of it.<p>
<script src="https://gist.github.com/663655.js?file=chalk.html"></script>
<p>Standard html5 doctype, and a manifest for <a href="http://diveintohtml5.org/offline.html">application caching</a>.</p>
<p>The rest of the HTML is mainly structural. There is not a single text node in the entire tree (excluding whitespace). The chalkboard is a canvas element and an image element used to render the canvas contents as an image for sharing. The other elements are just sprites and buttons. There are div elements for the light switch and shade (a dimmer on each side), share button, instructions on sharing, close button, ledge, chalk, eraser and corresponding indicators. Phew, that was a mouthful. (oblig: "that's what she said!")</p>
<p>The interesting thing about the HTML is that without any JavaScript or CSS the document would be a completely blank white page (except for a strange looking share button w/ no title). Talk about progressive enhancement. Here's a look at the HTML:</p>
<script src="https://gist.github.com/663642.js?file=chalk.html"></script>
<p>Onward.</p>
<p>&nbsp;</p>
<h2>Zepto</h2>
<p>Zepto is a <i>tiny</i>, modern JS framework for mobile WebKit browsers such as those found on iPhone and Android handsets. I'm not going to cover it here but I'll mention that it's similar in feel to jQuery. In fact it tries to mimic jQuery very closely to make migrations from Zepto to jQuery easy, and vice versa. The reason it weighs in at just under 6k (2k gzipped) is that it doesn't overreach or have to support legacy crap like IE6. It was started by Thomas Fuchs so you know it's good.</p>
<p>&nbsp;</p>
<h2>Display (CSS &amp; Images)</h2>
<p>6.6k, 385 lines. This is basically half of the text portion, excluding Zepto. There are 6 images including one called chalk-sprites.png. Interesting. Let's look at the background first though.</p>
<p>&nbsp;</p>
<h3>Background</h3>
<p>&nbsp;</p>
<div align="center">
<a href="http://samhuri.net/Chalk/images/background.jpg"><img height="473" src="http://samhuri.net/Chalk/images/background.jpg" style="border: 0;" width="512" /></a><br />
background.jpg 1024x946px</div>
<p>The background is the blackboard itself, and is almost square at 1024x946. The cork border and light switch are there too. This is set as the background-image of the html element and is positioned at a negative x or y in order to centre it properly. <a href="https://developer.mozilla.org/En/CSS/Media_queries">CSS media queries</a> are used to detect the screen's orientation. This way the same image is used for both orientations, clever.</p>
<script src="https://gist.github.com/663656.js?file=chalk-01.css">
</script>
<p>&nbsp;</p>
<h3>Chalkboard</h3>
<p>Just a canvas element positioned over the chalkboard using media queries. There's also an image element called "output" used to render an image for sharing.</p>
<script src="https://gist.github.com/663675.js?file=chalk-chalkboard.css">
</script>
<p>&nbsp;</p>
<h3>Sprites</h3>
<p>&nbsp;</p>
<div align="center" id="sprites">
<img height="534" src="http://samhuri.net/Chalk/images/chalk-sprites.png" width="502" /><br />
chalk-sprites.png </div>
<p>Sprites are used for all the other elements: ledge, chalk, eraser, tool indicator, share button, instructions, and close button (to leave the sharing mode). Positioned using CSS, standard stuff. There is white text alongside those green arrows. If you want to see it we'll have to <a href="#" onclick="document.getElementById('sprites').style.backgroundColor = '#000'; return false">change the background to black</a>.</p>
<p>&nbsp;</p>
<h3>Light Switch &amp; Shade</h3>
<p>When you touch the light switch on the left side of the chalkboard - only visible in landscape orientation - the cork border dims and the ledge and share button disappear, leaving the chalkboard under the spotlight all classy like. The shade consists of two "dimmer" div elements inside a shade div, which is hidden by default.</p>
<p>The dimmers background color is black at 67% opacity. The shade element fades in using -webkit-transition: on its visibility property while the dimmers use CSS3 transitions on their background. The dimmers are positioned using media queries as well, one on each side of the board. Interestingly their parent shade has a height and width of 0. Rather than each having a unique id they just have the class "dim" and the :nth-child pseudo-class selector is used to position them independently.</p>
<script src="https://gist.github.com/663664.js?file=chalk-02.css">
</script>
<p>If you took a look at the HTML before you'll have noticed there's no shade class defined on the body element. Looks like they're using JavaScript to add the shade class to body, triggering the transitions to the visible shades and setting the dimmers backgrounds to black at the same time, causing the fading effect. The shade fades in while the ledge and share button fade out.</p>
<p>The light switch itself is displayed only in landscape orientation, again using a media query.</p>
<p>&nbsp;</p>
<h3>Tools</h3>
<p>There are 2 layers to the tools on the ledge. There are the images of the tools and their indicators, but also an anchor element for each tool that acts as targets to select them. When tools are select the indicators fade in and out using CSS3 transitions on opacity by adding and removing the class "active" on the tool.</p>
<script src="https://gist.github.com/663693.js?file=chalk-indicators.css">
</script>
<p>There are pattern images for each colour of chalk, and one for the the eraser. The eraser "pattern" is the entire blackboard so erasing it doesn't look ugly. I love that kind of attention to detail.<p>
<p>&nbsp;</p>
<h3>Sharing</h3>
<p>The shade effect that happens when you hit the share button is similar to the shade effect used for the light switch. It's a bit more complex as the sharing instructions are positioned differently in portrait and landscape orientations, but there's nothing really new in there (that I can see).</p>
<p>The rest of the CSS is largely presentational stuff like removing margins and padding, and positioning using lots of media queries. You can see it all at <a href="http://chalk.37signals.com/stylesheets/chalk.css">chalk.37signals.com/stylesheets/chalk.css</a>.</p>
<p>&nbsp;</p>
<h2>JavaScript (and CoffeeScript)</h2>
<p>5.5k in about 170 lines. That's just half the size of the CSS.</p>
<p><i>Sam Stephenson <a href="https://gist.github.com/664351">shared the original CoffeeScript source</a> with us. It's about 150 lines, and is a bit easier to read as CS is far cleaner than JS.</i></p>
<p>The bulk of the magic is done w/ hardware accelerated CSS3 rather than slow JS animation using setInterval and setTimeout to change properties. That sort of thing isn't novel anymore anyway. The fact that JS is really only used for drawing and toggling CSS classes is pretty awesome!</p>
<p>The entire contents of the JS reside inside the DOMContentLoaded event handler attached to window.</p>
<p>&nbsp;</p>
<h3>Initialization</h3>
<p>&nbsp;</p>
<script src="https://gist.github.com/664206.js?file=chalk-init.js"></script>
<p>First we get a handle on all the elements and the canvas' 2d drawing context. I almost want to say views and controls as it really feels just like hooking up a controller and view in a desktop GUI app. Sometimes the line between dynamic web page and web app are blurred, not so here. Chalk is 100% app.</p>
<p>The canvas' dimensions and pen are initialized in lines 13 - 19, and then the chalkboard background is drawn onto the canvas using the <code>drawImage()</code> method.</p>
<p>The canvas offsets are cached for calculations, and are updated when the window fires the "orientationChange" event. Next up tools (a.k.a. pens) are created and initialized.</p>
<p>&nbsp;</p>
<h3>Tools</h3>
<p>&nbsp;</p>
<script src="https://gist.github.com/664214.js?file=chalk-tools.js"></script>
<p><code>createPattern(name, callback)</code> loads one of the pattern images, chalk-tile-*, and then creates a pattern in the drawing context and passes it to the given callback.</p>
<p><code>setStroke(pattern, width)</code> effectively sets the pen used for drawing, described as a pattern & stroke width. The patterns are initialized and the white pen is passed to setStroke since it's the default tool.</p>
<p>The last part defines the 3 tools, note that the active tool "white_chalk" is at the end. Also note that the tool names are the ids of the target elements in the ledge. <code>activateTool(tool)</code> accepts a tool name. The tool to activate is moved to the end of the tools array on lines 31-32, activeTool is set to the given tool as well on line 32. The reason for moving the active tool to the end of the array is revealed in the for loop on line 34, the order of the tools array determines their z-index ordering (highest number is in front). Then the 'active' CSS class is added to the active tool to show the indicator, and then the pen is set by assigning a pen to the context's <code>strokeStyle</code> property.</p>
<p>Finally the white_chalk tool is activated and the click event for the tool targets is setup.</p>
<p>&nbsp;</p>
<h3>Drawing</h3>
<p>&nbsp;</p>
<script src="https://gist.github.com/664235.js?file=chalk-drawing.js"></script>
<p>Drawing is done by listening for touch events on the canvas element. An array of points to draw is initialized to a 1-element array containing <code>null</code>. Null values make the draw function break up the line being drawn by skipping the next point in the array. x and y coords are initialized in touchstart, points are appended to the points array in touchmove, and the touchend handler appends two points and null to the points array to end the line. I'm not sure why <code>[x, y]</code> is used as the points in the touchend handler rather than coords from the event. Please leave a comment if you know why!</p>
<p>The draw function is called for each point in the points array at 30ms intervals. A line is started by calling <code>context.beginPath()</code>, each point is drawn, and then the line is ended with <code>context.stroke()</code>. <strike>The 2nd condition of the while loop ensures that we don't draw for too long, as bad things would happen if the function were executed a 2nd time while it was already running.</strike></p>
<p><b>Sam Stephenson was kind enough to clarify these points. <a href="#Blog1_cmt-1187434093983456531">See his comment below</a> the post for clarification on using [x, y] in the touchend handler and the 10ms limit when drawing points.</b></p>
<p>&nbsp;</p>
<h3>Light Switch &amp; Shade</h3>
<p>&nbsp;</p>
<script src="https://gist.github.com/664260.js?file=chalk-shade.js"></script>
<p>When the light switch is touched (or clicked) the shade class on the body element is toggled. Nothing to it.</p>
<p>&nbsp;</p>
<h3>Sharing</h3>
<p>&nbsp;</p>
<script src="https://gist.github.com/664263.js?file=chalk-share.js"></script>
<p>The share window is opened after a 10ms delay, just enough time for any drawing to be completed before rendering the image. The image is created by assigning the result of canvas' <code>toDataURL()</code> method to the output image element's src attribute.</p>
<p>When the share window is closed the output image element gets its src set to the sprites image. <strike>I'm not sure why that was done.</strike> <i>As Sam mentions in <a href="#Blog1_cmt-118743409398345653">his comment below</a>, this is done to reclaim the memory used by the rendered image.</i></p>
<p>The rest of the code there just sets up event handlers and toggles CSS classes.</p>
<p>&nbsp;</p>
<h2>That's it!</h2>
<p>That about covers it. Don't have an iPad? <a href="http://samhuri.net/Chalk/index.html">Play around with it anyway</a>, but be warned that you can't draw anything. You can select chalk and the eraser and hit the light switch. I instinctively tried touching my MacBook's display but alas it doesn't magically respond to touches, lame.</p>
<p>Have fun drawing. Thanks to 37signals for a beautiful (and useful) example of a few modern web technologies.</p>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
<script>function addLineNumbersToAllGists() {
$('.gist').each( function() {
_addLineNumbersToGist('#' + $(this).attr('id'));
});
}
function addLineNumbersToGist(id) {
_addLineNumbersToGist('#gist-' + id);
}
function _addLineNumbersToGist(css_selector) {
$(document).ready( function() {
$(css_selector + ' .line').each(function(i, e) {
$(this).prepend(
$('<div/>').css({
'float' : 'left',
'width': '30px',
'font-weight' : 'bold',
'color': '#808080'
}).text(++i)
);
});
});
}
addLineNumbersToAllGists();
</script>
</article>
<article>
<header>
<h1><a href=a-preview-of-mach-o-file-generation.html>A preview of Mach-O file generation</a></h1>
<time>January 20, 2010</time>
</header>
<p>This month I got back into an x86 compiler I started last May. It lives <a
href="https://github.com/samsonjs/compiler">on github</a>.</p>
<p>The code is a bit of a mess but it mostly works. It generates Mach object
files that are linked with gcc to produce executable binaries.</p>
<p>The Big Refactoring of January 2010 has come to an end and the tests pass
again, even if printing is broken it prints <i>something</i>, and more
importantly compiles test/test_huge.code into something that works.</p>
<p>After print is fixed I can clean up the code before implementing anything
new. I wasn't sure if I'd get back into this or not and am pretty excited
about it. I'm learning a lot from this project.</p>
<p>If you are following the Mach-O posts you might want to look at
asm/machofile.rb, a library for creating Mach-O files. Using it is quite
straightforward, an example is in asm/binary.rb, in the #output method.</p>
<p>Definitely time for bed now!</p>
</article>
<article>
<header>
<h1><a href=basics-of-the-mach-o-file-format.html>Basics of the Mach-O file format</a></h1>
<time>January 18, 2010</time>
</header>
<p><i>This post is part of a series on generating basic x86 Mach-O files
with Ruby. The
<a href="working-with-c-style-structs-in-ruby.html">
first post</a> introduced CStruct, a Ruby class used to serialize
simple struct-like objects.</i></p>
<p>Please note that the best way to learn about Mach-O properly is to
read Apple's
<a href="http://developer.apple.com/Mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html#//apple_ref/doc/uid/TP40000895-CH248-SW3">
documentation on Mach-O</a>, which is pretty good combined with the
comments in /usr/include/mach-o/*.h. These posts will only cover
the basics necessary to generate a simple object file for linking with
ld or gcc, and are not meant to be comprehensive.</p>
<h2>Mach-O File Format Overview</h2>
<p>A Mach-O file consists of 2 main pieces: the <b>header</b> and
the <b>data</b>. The header is basically a map of the file describing
what it contains and the position of everything contained in it. The
data comes directly after the header and consists of a number of
binary blobs of data, one after the other.</p>
<p>The header contains 3 types of records: the <b>Mach header</b>,
<b>segments</b>, and <b>sections</b>. Each binary blob is described
by a named section in the header. Sections are grouped into one or
more named segments. The Mach header is just one part of the header
and should not be confused with the entire header. It contains
information about the file as a whole, and specifies the number of
segments as well.</p>
<p>Take a quick look at <b>Figure 1</b> in
<a href="http://developer.apple.com/Mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html#//apple_ref/doc/uid/TP40000895-CH248-SW3">
Apple's Mach-O overview</a>, which illustrates this quite nicely.</p>
<p>A very basic Mach object file consists of a header followed by single
blob of machine code. That blob could be described by a single
section named __text, inside a single nameless segment. Here's a
diagram showing the layout of such a file:</p>
<pre>
,---------------------------,
Header | Mach header |
| Segment 1 |
| Section 1 (__text) | --,
|---------------------------| |
Data | blob | &lt;-'
'---------------------------'
</pre>
<h2>The Mach Header</h2>
<p>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 <tt>otool -h /bin/zsh</tt> (on a
Mac).</p>
<p>Using
<a href="working-with-c-style-structs-in-ruby.html">
CStruct</a> we define the Mach header like so:</p>
<script src="http://gist.github.com/280635.js"></script>
<h2>Segments</h2>
<p>Segments, or <b>segment commands</b>, specify where in memory the
segment should be loaded by the OS, and the number of bytes to
allocate for that segment. They also specify which bytes inside the
file are part of that segment, and how many sections it contains.</p>
<p>One benefit to generating an object file rather than an executable is
that we let the linker worry about some details. One of those details
is where in memory segments will ultimately end up.</p>
<p>Names are optional and can be arbitrary, but the convention is to
name segments with uppercase letters preceded by two underscores,
e.g. __DATA or __TEXT </p>
<p>The code exposes some more details about segment commands, but should
be easy enough to follow.</p>
<script src="http://gist.github.com/280642.js"></script>
<h2>Sections</h2>
<p>All sections within a segment are described one after the other
directly after each segment command. Sections define their name,
address in memory, size, offset of section data within the file, and
segment name. The segment name might seem redundant but in the next
post we'll see why this is useful information to have in the section
header.</p>
<p>Sections can optionally specify a map to addresses within their
binary blob, called a <b>relocation table</b>. This is used by the
linker. Since we're letting the linker work out where to place
everything in memory the addresses inside our machine code will need
to be updated.</p>
<p>By convention segments are named with lowercase letters preceded by
two underscores, e.g. __bss or __text</p>
<p>Finally, the Ruby code describing section structs:</p>
<script src="http://gist.github.com/280643.js"></script>
<h2>macho.rb</h2>
<p>As much of the Mach-O format as we need is defined in
<a href="http://github.com/samsonjs/compiler/blob/master/asm/macho.rb">
asm/macho.rb</a>. The Mach header, Segment commands, sections,
relocation tables, and symbol table structs are all there, with a few
constants as well.</p>
<p>I'll cover symbol tables and relocation tables in my next post.</p>
<h2>Looking at real Mach-O files</h2>
<p>To see the segments and sections of an object file, run
<tt>otool -l /usr/lib/crt1.o</tt>. <b>-l</b> is for load commands.
If you want to see why we stick to generating object files instead of
executables run <tt>otool -l /bin/zsh</tt>. They are complicated
beasts.</p>
<p>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
<tt>otool -d &lt;segment&gt; &lt;section&gt;</tt> for an arbitrary
section. To see the contents of a well-known section, such as __text
in the __TEXT segment, use <tt>otool -t /usr/bin/true</tt>. You can
also disassemble the __text section with
<tt>otool -tv /usr/bin/true</tt>.</p>
<p>You'll get to know otool quite well if you work with Mach-O.</p>
<h2>Take a break</h2>
<p>That was probably a lot to digest, and to make real sense of it you
might need to read some of the
<a href="http://developer.apple.com/Mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html#//apple_ref/doc/uid/TP40000895-CH248-SW3">
official documentation</a>.</p>
<p>We're close to being able to describe a minimal Mach object file
that can be linked, and the resulting binary executed. By the end of
the next post we'll be there.</p>
<p><i>(You can almost do that with what we know now. If you
create a Mach file with a Mach header (ncmds=1), a single unnamed
segment (nsects=1), and then a section named __text with a segment
name of __TEXT, and some x86 machine code as the section data, you
would almost have a useful Mach object file.)</i></p>
<p>Till next time, happy hacking!</p>
</article>
<article>
<header>
<h1><a href=working-with-c-style-structs-in-ruby.html>Working with C-style structs in Ruby</a></h1>
<time>January 17, 2010</time>
</header>
<p>This is the beginning of a series on generating Mach-O object files in
Ruby. We start small by introducing some Ruby tools that are useful when
working with binary data. Subsequent articles will cover a subset of the
Mach-O file format, then generating Mach object files suitable for linking
with ld or gcc to produce working executables. A basic knowledge of Ruby and C
are assumed. You can likely wing it on the Ruby side of things if you know any
similar languages.</p>
<p>First we need to read and write structured binary files with Ruby. <a
href="http://ruby-doc.org/core/classes/Array.html#M002222">Array#pack</a> and
<a
href="http://ruby-doc.org/core/classes/String.html#M000760">String#unpack</a>
get the job done at a low level, but every time I use them I have to look up
the documentation. It would also be nice to encapsulate serializing and
deserializing into classes describing the various binary data structures. The
built-in <a href="http://ruby-doc.org/core/classes/Struct.html">Struct
class</a> sounds promising but did not meet my needs, nor was it easily
extended to meet them.</p>
<p>Meet <a
href="http://github.com/samsonjs/compiler/blob/master/asm/cstruct.rb#files">CStruct</a>,
a class that you can use to describe a binary structure, somewhat similar to
how you would do it in C. Subclassing CStruct results in a class whose
instances can be serialized, and unserialized, with little effort. You can
subclass descendants of CStruct to extend them with additional members.
CStruct does not implement much more than is necessary for the compiler. For
example there is no support for floating point. If you want to use this for
more general purpose tasks be warned that it may require some work. Anything
supported by Array#pack is fairly easy to add though.</p>
<p>First a quick example and then we'll get into the CStruct class itself. In
C you may write the following to have one struct "inherit" from another:</p>
<p><script src="http://gist.github.com/279790.js"></script></p>
<p>With CStruct in Ruby that translates to:</p>
<p><script src="http://gist.github.com/279794.js"></script></p>
<p>CStructs act like Ruby's built-in Struct to a certain extent. They are
instantiated the same way, by passing values to #new in the same order they
are defined in the class. You can find out the size (in bytes) of a CStruct
instance using the #bytesize method, or of any member using #sizeof(name).</p>
<p>The most important method (for us) is #serialize, which returns a binary
string representing the contents of the CStruct.</p>
<p>(I know that CStruct.new_from_bin should be called CStruct.unserialize, you
can see where my focus was when I wrote it.)</p>
<p>CStruct#serialize automatically creates a "pack pattern", which is an array
of strings used to pack each member in turn. The pack pattern is mapped to the
result of calling Array#pack on each corresponding member, and then the
resulting strings are joined together. Serializing strings complicates matters
so we cannot build up a pack pattern string and then serialize it in one go,
but conceptually it's quite similar.</p>
<p>Unserializing is the same process in reverse, and was mainly added for
completeness and testing purposes.</p>
<p>That's about all you need to know to use CStruct. The code needs some work
but I decided to just go with what I have already so I can get on with the
more interesting and fun tasks.</p>
<p><i>Next in this series: <a
href="basics-of-the-mach-o-file-format.html">Basics
of the Mach-O file format</a></i><p>
</article>
<footer>
<a href=https://twitter.com/_sjs>@_sjs</a>
</footer>

View file

@ -0,0 +1,138 @@
<!doctype html>
<meta charset=utf-8>
<meta name=viewport content=width=device-width>
<title>Working with C-style structs in Ruby :: samhuri.net</title>
<link rel=stylesheet href=../assets/blog.css>
<script>
var _gaq = _gaq || [];
_gaq.push( ['_setAccount', 'UA-214054-5']
, ['_trackPageview']
);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<nav id=breadcrumbs><a href=../>samhuri.net</a> &rarr; <a href=index.html>blog</a></nav>
<header>
<h1><a href=index.html>sjs' blog</a></h1>
</header>
<article>
<header>
<h1>Working with C-style structs in Ruby</h1>
<time>January 17, 2010</time>
</header>
<p>This is the beginning of a series on generating Mach-O object files in
Ruby. We start small by introducing some Ruby tools that are useful when
working with binary data. Subsequent articles will cover a subset of the
Mach-O file format, then generating Mach object files suitable for linking
with ld or gcc to produce working executables. A basic knowledge of Ruby and C
are assumed. You can likely wing it on the Ruby side of things if you know any
similar languages.</p>
<p>First we need to read and write structured binary files with Ruby. <a
href="http://ruby-doc.org/core/classes/Array.html#M002222">Array#pack</a> and
<a
href="http://ruby-doc.org/core/classes/String.html#M000760">String#unpack</a>
get the job done at a low level, but every time I use them I have to look up
the documentation. It would also be nice to encapsulate serializing and
deserializing into classes describing the various binary data structures. The
built-in <a href="http://ruby-doc.org/core/classes/Struct.html">Struct
class</a> sounds promising but did not meet my needs, nor was it easily
extended to meet them.</p>
<p>Meet <a
href="http://github.com/samsonjs/compiler/blob/master/asm/cstruct.rb#files">CStruct</a>,
a class that you can use to describe a binary structure, somewhat similar to
how you would do it in C. Subclassing CStruct results in a class whose
instances can be serialized, and unserialized, with little effort. You can
subclass descendants of CStruct to extend them with additional members.
CStruct does not implement much more than is necessary for the compiler. For
example there is no support for floating point. If you want to use this for
more general purpose tasks be warned that it may require some work. Anything
supported by Array#pack is fairly easy to add though.</p>
<p>First a quick example and then we'll get into the CStruct class itself. In
C you may write the following to have one struct "inherit" from another:</p>
<p><script src="http://gist.github.com/279790.js"></script></p>
<p>With CStruct in Ruby that translates to:</p>
<p><script src="http://gist.github.com/279794.js"></script></p>
<p>CStructs act like Ruby's built-in Struct to a certain extent. They are
instantiated the same way, by passing values to #new in the same order they
are defined in the class. You can find out the size (in bytes) of a CStruct
instance using the #bytesize method, or of any member using #sizeof(name).</p>
<p>The most important method (for us) is #serialize, which returns a binary
string representing the contents of the CStruct.</p>
<p>(I know that CStruct.new_from_bin should be called CStruct.unserialize, you
can see where my focus was when I wrote it.)</p>
<p>CStruct#serialize automatically creates a "pack pattern", which is an array
of strings used to pack each member in turn. The pack pattern is mapped to the
result of calling Array#pack on each corresponding member, and then the
resulting strings are joined together. Serializing strings complicates matters
so we cannot build up a pack pattern string and then serialize it in one go,
but conceptually it's quite similar.</p>
<p>Unserializing is the same process in reverse, and was mainly added for
completeness and testing purposes.</p>
<p>That's about all you need to know to use CStruct. The code needs some work
but I decided to just go with what I have already so I can get on with the
more interesting and fun tasks.</p>
<p><i>Next in this series: <a
href="basics-of-the-mach-o-file-format.html">Basics
of the Mach-O file format</a></i><p>
</article>
<footer>
<a href=https://twitter.com/_sjs>@_sjs</a>
</footer>

View file

@ -30,6 +30,8 @@
<ul>
<li><a href=proj>projects</a></li>
<li class=ie-bullet>&bull;</li>
<li><a href=blog>blog</a></li>
<li class=ie-bullet>&bull;</li>
<li><a href=json-diff>json-diff</a></li>
<li class=ie-bullet>&bull;</li>
<li><a href=riak-js>riak-js docs</a></li>

33
templates/blog/index.html Normal file
View file

@ -0,0 +1,33 @@
<!doctype html>
<meta charset=utf-8>
<meta name=viewport content=width=device-width>
<title>blog :: samhuri.net</title>
<link rel=stylesheet href=../assets/blog.css>
<script>
var _gaq = _gaq || [];
_gaq.push( ['_setAccount', 'UA-214054-5']
, ['_trackPageview']
);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<nav id=breadcrumbs><a href=../>samhuri.net</a></nav>
<header>
<h1><a href=index.html>sjs' blog</a></h1>
</header>
{{#posts}}
<article>
<header>
<h1><a href={{filename}}>{{title}}</a></h1>
<time>{{date}}</time>
</header>
{{{body}}}
</article>
{{/posts}}
<footer>
<a href=https://twitter.com/_sjs>@_sjs</a>
</footer>

31
templates/blog/post.html Normal file
View file

@ -0,0 +1,31 @@
<!doctype html>
<meta charset=utf-8>
<meta name=viewport content=width=device-width>
<title>{{title}} :: samhuri.net</title>
<link rel=stylesheet href=../assets/blog.css>
<script>
var _gaq = _gaq || [];
_gaq.push( ['_setAccount', 'UA-214054-5']
, ['_trackPageview']
);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<nav id=breadcrumbs><a href=../>samhuri.net</a> &rarr; <a href=index.html>blog</a></nav>
<header>
<h1><a href=index.html>sjs' blog</a></h1>
</header>
<article>
<header>
<h1>{{title}}</h1>
<time>{{date}}</time>
</header>
{{{body}}}
</article>
<footer>
<a href=https://twitter.com/_sjs>@_sjs</a>
</footer>