<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.redartisan.com/~d/styles/atom10full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.redartisan.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en-US">
  <title>Red Artisan - Blog</title>
  <id>tag:redartisan.com,2008:mephisto/blog</id>
  <generator uri="http://mephistoblog.com" version="0.7.3">Mephisto Noh-Varr</generator>
  
  <link href="http://redartisan.com/blog" rel="alternate" type="text/html" />
  <updated>2008-07-03T04:01:59Z</updated>
  <link rel="self" href="http://feeds.redartisan.com/redartisan" type="application/atom+xml" /><entry xml:base="http://redartisan.com/">
    <author>
      <name>crafterm</name>
    </author>
    <id>tag:redartisan.com,2008-05-27:102</id>
    <published>2008-05-27T07:21:00Z</published>
    <updated>2008-07-03T04:01:59Z</updated>
    <category term="Blog" />
    <link href="http://feeds.redartisan.com/~r/redartisan/~3/298919289/sprinkle-intro" rel="alternate" type="text/html" />
    <title>Sprinkle Some Powder!</title>
<content type="html">
            &lt;p&gt;Provisioning a brand new server or VPS slice can be quite tricky, tedious and time consuming, particularly if done manually with changing software versions and configurations. &lt;/p&gt;

&lt;p&gt;In the Rails world, most of us are using virtual private servers which are instantiated from base operating system images, it takes only a few minutes to create a slice, however installing the rest of your server's stack, be it Rails, Merb or another framework is where the work begins. Provisioning in this sense, is installing all software required post operating system install.&lt;/p&gt;

&lt;p&gt;Sprinkle is a new prototype tool that you can use to provision your servers/slices. Its declarative policy/state based approach for specifying how a remote system should be provisioned with intelligent logic to support dependencies, multiple installer types and remote installation is really compelling.&lt;/p&gt;

&lt;p&gt;Several free and commercially available tools already exist to help automate the installation of software however most fall into two styles of design:&lt;/p&gt;

&lt;p&gt;1 - Task based, where the tool issues a list of commands to run on the remote system, either remotely via a network connection or smart client.&lt;br /&gt;
  2 - Policy/state based, where the tool determines what needs to be run on the remote system by examining its current and final state.&lt;/p&gt;

&lt;p&gt;Task based solutions are usually quite easy and fast to get up and running, but can be problematic as the user has to define all of the commands manually (not to mention get them right with testing). Policy/state based solutions have much more intelligence about how to modify and adapt the remote system, but often require specialized software to run remotely.&lt;/p&gt;

&lt;p&gt;Sprinkle is a prototype tool I've been working on recently in this space that merges both concepts together, using a Ruby domain specific language to declaratively describe the state of the remote system. Using Sprinkle, provisioning your brand new remote server or slice can be automated using pre-defined and/or customized scripts from a single machine at your fingertips.&lt;/p&gt;

&lt;p&gt;Sprinkle reads a script that defines a set of packages, a set of policies that define what packages should be installed on what roles of target machines, and a deployment section that defines the delivery mechanism for communicating with remote machines, and any default settings.&lt;/p&gt;

&lt;p&gt;Packages can have relationships between each other to support dependencies. Virtual packages are also supported allowing you to define a role that a package (or multiple) fulfills, with the user or Sprinkle selecting which concrete package should be used at runtime.&lt;/p&gt;

&lt;p&gt;Packages can also support arbitrary installer types, allowing you to install packages from source, gems, apt, or any other installer you'd like to employ. Installer types know what commands need to be issued to install packages, so all that needs to be specified in a script is the installer type and metadata about the package itself.&lt;/p&gt;

&lt;p&gt;In essence, Sprinkle is about defining a domain specific meta-language for describing and processing the installation of software.&lt;/p&gt;

&lt;h3&gt;Example Sprinkle Script&lt;/h3&gt;

&lt;p&gt;Here's an example Sprinkle deployment script, annotated to explain each section:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;# Annotated Example Sprinkle Rails deployment script
#
# This is an example Sprinkle script configured to install Rails from Gems, Apache, Ruby and
# Sphinx from source, and MySQL from APT on an Ubuntu system.
#
# Installation is configured to run via capistrano (and an accompanying deploy.rb recipe script).
# Source based packages are downloaded and built into /usr/local on the remote system.
#
# A sprinkle script is separated into 3 different sections. Packages, policies and deployment:


# Packages (separate files for brevity)
#
#  Defines the world of packages as we know it. Each package has a name and
#  set of metadata including its installer type (eg. apt, source, gem, etc). Packages can have
#  relationships to each other via dependencies.

require 'packages/essential'
require 'packages/rails'
require 'packages/database'
require 'packages/server'
require 'packages/search'


# Policies
#
#  Names a group of packages (optionally with versions) that apply to a particular set of roles:
#
#   Associates the rails policy to the application servers. Contains rails, and surrounding
#   packages. Note, appserver, database, webserver and search are all virtual packages defined above.
#   If there's only one implementation of a virtual package, it's selected automatically, otherwise
#   the user is requested to select which one to use.

policy :rails, :roles =&amp;gt; :app do
  requires :rails, :version =&amp;gt; '2.0.2'
  requires :appserver
  requires :database
  requires :webserver
  requires :search
end


# Deployment
#
#  Defines script wide settings such as a delivery mechanism for executing commands on the target
#  system (eg. capistrano), and installer defaults (eg. build locations, etc):
#
#   Configures sprinkle to use capistrano for delivery of commands to the remote machines (via
#   the named 'deploy' recipe). Also configures 'source' installer defaults to put package gear
#   in /usr/local

deployment do

  # mechanism for deployment
  delivery :capistrano do
    recipes 'deploy'
  end

  # source based package installer defaults
  source do
    prefix   '/usr/local'
    archives '/usr/local/sources'
    builds   '/usr/local/build'
  end

end

# End of script, given the above information, Spinkle will apply the defined policy on all roles using the
# deployment settings specified.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Given such a script, Sprinkle will apply the defined policy &lt;strong&gt;rails&lt;/strong&gt; on the target machines identified by the role &lt;strong&gt;app&lt;/strong&gt;, where the policy rails is composed of packages for the rails gem itself, an application server, webserver, search daemon, and the ruby runtime.&lt;/p&gt;

&lt;p&gt;Currently, Sprinkle uses &lt;a href="http://www.capify.org"&gt;Capistrano&lt;/a&gt; internally for communicating with remote systems, however this is pluggable as well, allowing for just about any concievable delivery mechanism in the future. The deployment section above identifies Capistrano as the delivery mechanism, specifying a local deploy.rb script that defines what roles are available, and what machines are defined within those roles.&lt;/p&gt;

&lt;p&gt;This particular script breaks the package section up into multiple files, here are some of the actual package definitions (complete example available &lt;a href="http://github.com/crafterm/sprinkle/tree/master/examples/rails"&gt;here&lt;/a&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;package :ruby do
  description 'Ruby Virtual Machine'
  version '1.8.6'
  source &amp;quot;ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-#{version}-p111.tar.gz&amp;quot; # implicit :style =&amp;gt; :gnu
  requires :ruby_dependencies
end

package :rubygems do
  description 'Ruby Gems Package Management System'
  version '1.0.1'
  source &amp;quot;http://rubyforge.org/frs/download.php/29548/rubygems-#{version}.tgz&amp;quot; do
    custom_install 'ruby setup.rb'
  end
  requires :ruby
end

package :rails do
  description 'Ruby on Rails'
  gem 'rails'
  version '2.0.2'
end

package :sphinx, :provides =&amp;gt; :search do
  description 'MySQL full text search engine'
  version '0.9.8-rc2'
  source &amp;quot;http://www.sphinxsearch.com/downloads/sphinx-#{version}.tar.gz&amp;quot;
  requires :mysql_dev
end

package :apache, :provides =&amp;gt; :webserver do
  description 'Apache 2 HTTP Server'
  version '2.2.6'
  source &amp;quot;http://apache.wildit.net.au/httpd/httpd-#{version}.tar.bz2&amp;quot; do
    enable %w( mods-shared=all proxy proxy-balancer proxy-http rewrite cache headers ssl deflate so )
    prefix &amp;quot;/opt/local/apache2-#{version}&amp;quot;
    post :install, 'install -m 755 support/apachectl /etc/init.d/apache2', 'update-rc.d -f apache2 defaults'
  end
  requires :apache_dependencies
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each package includes a description, optional version, optional list of dependencies and an installer type (also optional allowing for meta-packages).&lt;/p&gt;

&lt;p&gt;Source installers are particularly intelligent and will download, configure and install source archives from a remote location directly on the target machine. They assume GNU style source archives by default (ie. tar.gz/tar.bz2 compressed archives, configure script and make, make install style semantics), however are completely customziable to support any arbitrary build style (rubygems for example does this above), with pre and post commands.&lt;/p&gt;

&lt;p&gt;The Apache installer for example, specifies a few extra source installer options such as a set of &lt;em&gt;--enable&lt;/em&gt; options, an alternate installation prefix and a series of post installation commands to be executed.&lt;/p&gt;

&lt;p&gt;With this example configuration, lets take a look at actually using Sprinkle to provision a remote server.&lt;/p&gt;

&lt;h3&gt;Usage&lt;/h3&gt;

&lt;p&gt;Sprinkle supports several command line options:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Usage
=====

$&amp;gt; sprinkle [options]

Options are:

  -s, --script=PATH                Path to a sprinkle script to run
  -t, --test                       Process but don't perform any actions
  -v, --verbose                    Verbose output
  -c, --cloud                      Show powder cloud, ie. package hierarchy and installation order
  -h, --help                       Show this help message.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;where you can name the script to be procesed, enable testing mode or verbose output, and/or examine the cloud of packages and operations that will be performed.&lt;/p&gt;

&lt;h3&gt;Viewing the powder cloud!&lt;/h3&gt;

&lt;p&gt;Sprinkle calculates all operations to be performed on remote servers upfront which is nice, as it allows you to inspect what modifications will be made to the system before any are actually performed. Lets inspect the powder (ie. package) cloud for the above script:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; sprinkle -c -t -s rails.rb
--&amp;gt; Cloud hierarchy for policy rails

Policy rails requires package rails
        Package rails requires rubygems
                Package rubygems requires build_essential
                Package rubygems requires ruby
                        Package ruby requires build_essential
                        Package ruby requires ruby_dependencies

Policy rails requires package appserver
Selecting mongrel_cluster for virtual package appserver
        Package mongrel_cluster requires rubygems
                Package rubygems requires build_essential
                Package rubygems requires ruby
                        Package ruby requires build_essential
                        Package ruby requires ruby_dependencies
        Package mongrel_cluster requires mongrel
                Package mongrel requires rubygems
                        Package rubygems requires build_essential
                        Package rubygems requires ruby
                                Package ruby requires build_essential
                                Package ruby requires ruby_dependencies

Policy rails requires package database
Selecting mysql for virtual package database

Policy rails requires package webserver
Selecting apache for virtual package webserver
        Package apache requires build_essential
        Package apache requires apache_dependencies

Policy rails requires package search
Selecting sphinx for virtual package search
        Package sphinx requires build_essential
        Package sphinx requires mysql_dev

--&amp;gt; Normalized installation order for all packages: build_essential, ruby_dependencies, ruby, rubygems, rails, mongrel, mongrel_cluster, mysql, apache_dependencies, apache, mysql_dev, sphinx
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;-c indicates that Sprinkle should print the powder cloud (ie. the output above)&lt;br /&gt;
-t indicates that we're operating in test mode, so we won't actually perform any remote commands&lt;br /&gt;
-s identifies the Sprinkle script that should be processed  &lt;/p&gt;

&lt;p&gt;Above we can see that the policy &lt;strong&gt;rails&lt;/strong&gt; required packages &lt;strong&gt;rails&lt;/strong&gt;, &lt;strong&gt;appserver&lt;/strong&gt;, &lt;strong&gt;database&lt;/strong&gt;, &lt;strong&gt;webserver&lt;/strong&gt; and &lt;strong&gt;search&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Note that all of these packages bar &lt;strong&gt;rails&lt;/strong&gt; are actually &lt;em&gt;virtual&lt;/em&gt; packages, so Sprinkle has selected an appropriate implementation of each virtual package automatically based on the supplied package definitions. If more than one package provided an implementation of a virtual package, then the user would be given the opportunity to select which one they prefer.&lt;/p&gt;

&lt;p&gt;Under each package is a textual representation of that package's dependency tree, including all sub-dependencies, etc. Dependencies are packages that need to be installed first before a higher level package can be installed. &lt;/p&gt;

&lt;p&gt;You'll notice that several packages have the same dependencies, eg. both &lt;em&gt;rails&lt;/em&gt; and &lt;em&gt;mongrel&lt;/em&gt; require &lt;em&gt;ruby&lt;/em&gt;, which has its own dependencies as well. Sprinkle will install all packages in reverse dependency order so that lower level dependencies are installed before higher level packages, and it will also normalize the final package list to remove duplicates so that packages aren't installed multiple times unnecessarily. This is the final line in the output above which lists the actual packages to be installed and order of installation.&lt;/p&gt;

&lt;h3&gt;Provisioning a remote system&lt;/h3&gt;

&lt;p&gt;To actually provision a remote server we simply remove the &lt;em&gt;testing&lt;/em&gt; (and if desired &lt;em&gt;cloud&lt;/em&gt;) flags from the command issued above and Sprinkle will process the configuration and provision the remote system. Note for the moment, you'll need to ensure that your SSH keys are appropriately installed on the remote server under a user that has enough privileges to install software (generally the root user):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; sprinkle -s rails.rb
--&amp;gt; Installing build_essential for roles: app
--&amp;gt; Installing ruby_dependencies for roles: app
--&amp;gt; Installing ruby for roles: app
--&amp;gt; Installing rubygems for roles: app
--&amp;gt; Installing rails for roles: app
--&amp;gt; Installing mongrel for roles: app
--&amp;gt; Installing mongrel_cluster for roles: app
--&amp;gt; Installing mysql for roles: app
--&amp;gt; Installing apache_dependencies for roles: app
--&amp;gt; Installing apache for roles: app
--&amp;gt; Installing mysql_dev for roles: app
--&amp;gt; Installing sphinx for roles: app
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(its also possible to put the &lt;em&gt;#!/usr/bin/env sprinkle -c&lt;/em&gt; line at the top of a sprinkle script and make it executable).&lt;/p&gt;

&lt;p&gt;After the command is finished, all of the requested software will have been applied on your target system.&lt;/p&gt;

&lt;p&gt;If you'd like to see more action printed as commands are run, specify the --verbose (-v) flag. Internally, Capistrano tasks are dynamically defined and executed at runtime for each package's installation, using a Capistrano configuration file to identify the actual roles and hostnames associated with those roles to communicate with. The verbose option will display Capistrano activity in addition to the usual Sprinkle output.&lt;/p&gt;

&lt;p&gt;An extra benefit of leveraging Capistrano is that you can actually provision multiple servers/slices simultaneously and in parallel if desired.&lt;/p&gt;

&lt;h3&gt;I want!&lt;/h3&gt;

&lt;p&gt;If you're interested in downloading and experimenting with Sprinkle, you can clone and/or watch the &lt;a href="http://github.com/crafterm/sprinkle"&gt;project&lt;/a&gt; at GitHub, or download it from GitHub's gem server using:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; sudo gem install crafterm-sprinkle --source http://gems.github.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The official Rubyforge gem server will also be updated over the coming days as well. If you download the source, you can create a gem package for installation by:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; rake package
$&amp;gt; sudo gem install -l pkg/sprinkle-0.1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are also specs with a decent amount of coverage over the code base that you can run as well:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; rake spec
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Prerequsites&lt;/h3&gt;

&lt;p&gt;Installing the Sprinkle gem will also install all pre-requsite gems such as &lt;em&gt;activesupport&lt;/em&gt;, &lt;em&gt;highline&lt;/em&gt; and &lt;em&gt;capistrano&lt;/em&gt;. The only other pre-requisite is that you have SSH connectivity to the remote system you wish to provision, preferably with SSH keys in place to prevent passwords being asked for.&lt;/p&gt;

&lt;h3&gt;Finally&lt;/h3&gt;

&lt;p&gt;Sprinkle is a young project and while operational still in development, with several limitations. Currently, only Ubuntu/Debian has been tested as a target deployment platform, operating system abstraction and other platforms will be tested and supported in the future, along with several new features that are in the pipeline.&lt;/p&gt;

&lt;p&gt;I'm most certainly open to ideas, suggestions and thoughts about how Sprinkle can be improved and generally made better for the community, and I really welcome any bug reports, patches and suggestions. Please feel free to contact me with any comments at all.&lt;/p&gt;

&lt;h3&gt;Special Thanks!&lt;/h3&gt;

&lt;p&gt;Several people have been really helpful during the development of Sprinkle. In particular I'd like to thank &lt;a href="http://germanforblack.com/"&gt;Ben Schwarz&lt;/a&gt; and &lt;a href="http://notahat.com/"&gt;Pete Yandell&lt;/a&gt; for their initial feedback and help after my first demos. I'd also really like to thank Matthew and Jared from &lt;a href="http://www.slicehost.com/"&gt;Slicehost&lt;/a&gt; for their help and support as well.&lt;/p&gt;
          &lt;img src="http://feeds.redartisan.com/~r/redartisan/~4/298919289" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://redartisan.com/2008/5/27/sprinkle-intro</feedburner:origLink></entry>
  <entry xml:base="http://redartisan.com/">
    <author>
      <name>crafterm</name>
    </author>
    <id>tag:redartisan.com,2008-05-27:101</id>
    <published>2008-05-27T00:24:00Z</published>
    <updated>2008-05-27T00:27:21Z</updated>
    <category term="Blog" />
    <link href="http://feeds.redartisan.com/~r/redartisan/~3/298716370/twilight-emacs" rel="alternate" type="text/html" />
    <title>Twilight Theme for Emacs!</title>
<content type="html">
            &lt;p&gt;&lt;img src="http://redartisan.com/assets/2008/5/27/twilight_emacs.png" width="450" /&gt;&lt;/p&gt;

&lt;p&gt;Recently I’ve been returning to my Unix heritage and using &lt;a href="http://homepage.mac.com/zenitani/emacs-e.html"&gt;Emacs&lt;/a&gt; as my day to day editor. Its been quite an enlightening journey returning to such a powerful editor with its limitless customization and features (probably worthy of a whole separate post), although one things I do miss from TextMate are the colour themes used for syntax highlighting. &lt;/p&gt;

&lt;p&gt;Emacs has a package called &lt;strong&gt;color-theme&lt;/strong&gt; which can be used to customize font faces/colours however in comparison to the styled themes TextMate offers, most of default ones available don’t quite compare.&lt;/p&gt;

&lt;p&gt;In TextMate I used the Twilight theme quite often, so, after examining the color-theme package format, I’ve ported across the Twilight theme to Emacs, and have released it as a small &lt;a href="http://github.com/crafterm/twilight-emacs"&gt;project&lt;/a&gt; on GitHub. &lt;/p&gt;

&lt;p&gt;Its definitely a work in progress, most of the colours within Ruby mode are working as expected, but please feel free to improve anything that needs some fine tuning (eg. Rails keywords, and particularly non-Ruby modes such as dired, ERB, SCM, etc). Patches are most certainly welcome.&lt;/p&gt;
          &lt;img src="http://feeds.redartisan.com/~r/redartisan/~4/298716370" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://redartisan.com/2008/5/27/twilight-emacs</feedburner:origLink></entry>
  <entry xml:base="http://redartisan.com/">
    <author>
      <name>crafterm</name>
    </author>
    <id>tag:redartisan.com,2008-05-18:93</id>
    <published>2008-05-18T12:11:00Z</published>
    <updated>2008-05-18T12:55:44Z</updated>
    <category term="Blog" />
    <link href="http://feeds.redartisan.com/~r/redartisan/~3/292818807/dtrace-ruby" rel="alternate" type="text/html" />
    <title>Ruby &amp;&amp; DTrace!</title>
<content type="html">
            &lt;p&gt;Performance, memory and runtime analysis of software has always been a tricky subject, often requiring special debug versions of code or application specific parameters to determine what's going on. Additionally, developer debugging information can often clutter source code making it harder to see the intent and design of source.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.sun.com/bigadmin/content/dtrace/"&gt;D-Trace&lt;/a&gt; offers an interesting solution to this problem, by dynamically instrumenting your application at runtime to enable probes to report various pieces of information as to how your application is running. DTrace is a part of &lt;a href="http://sun.com/solaris/"&gt;Solaris&lt;/a&gt;, but is now also available under &lt;a href="http://www.apple.com/macosx/"&gt;Mac OS X Leopard&lt;/a&gt;. A typical installation of DTrace can offer 20,000 different types of probes (or more depending on what applications are running), from kernel level information, all the way to application specific data.&lt;/p&gt;

&lt;p&gt;Applications, such as the Ruby interpreter can also define their own domain specific probes, last year &lt;a href="https://dev.joyent.com/projects/ruby-dtrace/wiki/Ruby+DTrace"&gt;Joyent&lt;/a&gt; added support for D-Trace probes to MRI (Matz-Ruby), allowing developers to analyze runtime behaviour of their Ruby based applications. Starting with this particular &lt;a href="http://github.com/evanphx/rubinius/commit/46513843cedfe47bd5710aa3756230aa15a1570a"&gt;commit&lt;/a&gt;, compatible D-Trace probes for &lt;a href="http://rubini.us/"&gt;Rubinius&lt;/a&gt; have been developed as well.&lt;/p&gt;

&lt;h3&gt;What can you do with DTrace?&lt;/h3&gt;

&lt;p&gt;The list of uses for DTrace are endless, as it provides the means to gain answers to many questions about how your application is behaving. Some practical questions DTrace can answer include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Tracing execution flow through your application as it steps through each method/class&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Determining runtime performance analysis, working out what methods are the most expensive (excellent for 80/20 performance analysis)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Heap analysis, determining what objects are consuming the most memory&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Garbage collection impact, determining how often the garbage collector is running an impacting your applications performance&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;and much more...&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;Getting started with DTrace and Ruby&lt;/h3&gt;

&lt;p&gt;To get started with Ruby and DTrace, you'll need a compatible operating system, eg. Mac OS X Leopard, and you'll need to get the Ruby source to build MRI with Joyent's DTrace &lt;a href="http://svn.joyent.com/opensource/dtrace/ruby/patches/"&gt;patches&lt;/a&gt;. Luckily, if you're using Mac OS X Leopard, Apple has already appropriately patched their bundled version of Ruby to include DTrace patches for you, and no extra compilation is necessary. DTrace itself is also included by default under all Mac OS X Leopard operating system installs.&lt;/p&gt;

&lt;h3&gt;DTrace primer&lt;/h3&gt;

&lt;p&gt;There is a wealth of information available on the internet that I'd certainly recommend taking a look at to learn using DTrace in depth (in particular Sun's DTrace admin &lt;a href="http://www.sun.com/bigadmin/content/dtrace/"&gt;guides&lt;/a&gt;). Essentially to interact with DTrace, you write a script in a language called 'D', which defines what probes you're interested in, and what to do with the data when the probe fires. This script is then read and bytecode compiled by DTrace's command line and user land libraries, and then passed to the DTrace virtual machine running inside of the kernel to be interpreted. Probes are enabled, and appropriately fired, with data being collected according to your scripts for analysis.&lt;/p&gt;

&lt;h4&gt;Anatomy of a DTrace script&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;provider : module : function : name
/ predicate /
{
  action
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Above is generic breakdown of a DTrace script (somewhat bearing similarity to an awk script). Most parts of the script are optional as you'll see further, such as the module or function name, or even the action.&lt;/p&gt;

&lt;p&gt;Probes are grouped by &lt;em&gt;providers&lt;/em&gt;, of which there are many (io, pid, objc, profile, to name a few). &lt;em&gt;module&lt;/em&gt; and &lt;em&gt;function&lt;/em&gt;'s meaning are somewhat dependant on the provider being used. The &lt;em&gt;name&lt;/em&gt; parameter identifies the actual name of the probe that is to be fired.&lt;/p&gt;

&lt;p&gt;The predicate identifies a clause that must evaluate to true for the probe to fire and allows for conditional firing of probes.&lt;/p&gt;

&lt;p&gt;The action contains arbitrary instructions to be performed when the probe fires.&lt;/p&gt;

&lt;p&gt;To probe your application you also need root privileges on the machine you'll be running DTrace on, this is due to kernel level interaction of DTrace. &lt;/p&gt;

&lt;p&gt;Usually you'll run DTrace and pass it the name of a D script (or include the script on the command line if it's brief), either with a command to run, or a process ID of an application that's already running that should be attached to. For example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; sudo dtrace -s profile.d -c 'ruby script.rb'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; ps aux|grep ruby
crafterm 29877   0.0  0.0   590472    188 s001  R+    5:04pm   0:00.00 grep ruby
crafterm 29875   0.0  1.2   622564  25016 s001  S     5:04pm   0:00.85 ruby
$&amp;gt; sudo dtrace -s profile.d 29875
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Ruby Provider Probes&lt;/h3&gt;

&lt;p&gt;To see how many probes are available, and those that are Ruby related, we can ask DTrace to print their specifics to the console, eg:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; sudo dtrace -l | wc -l
31569
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;indicating I currently have 31569 probes available to query, this number will change depending on what applications are running at the time of running the dtrace command. &lt;/p&gt;

&lt;p&gt;Ruby specific probes can be found by:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; sudo dtrace -l | grep ruby
21427  ruby53816   libruby.1.dylib                          rb_call0 function-entry
21428  ruby53816   libruby.1.dylib                          rb_call0 function-return
21429  ruby53816   libruby.1.dylib                   garbage_collect gc-begin
21430  ruby53816   libruby.1.dylib                   garbage_collect gc-end
21431  ruby53816   libruby.1.dylib                           rb_eval line
21432  ruby53816   libruby.1.dylib                      rb_obj_alloc object-create-done
21433  ruby53816   libruby.1.dylib                      rb_obj_alloc object-create-start
21434  ruby53816   libruby.1.dylib                   garbage_collect object-free
21435  ruby53816   libruby.1.dylib                        rb_longjmp raise
21436  ruby53816   libruby.1.dylib                           rb_eval rescue
21437  ruby53816   libruby.1.dylib                 ruby_dtrace_probe ruby-probe
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see from the list in the last column of the output, probes are available between method invocations, runs of the garbage collector, creation and destruction of objects and exceptions. The last probe actually allows the application writer to fire an arbitrary ruby probe containing application specific data from ruby code. &lt;/p&gt;

&lt;p&gt;A full list of probes and arguments supplied to them is available at Joyent's Ruby provider wiki &lt;a href="https://dev.joyent.com/projects/ruby-dtrace/wiki/Ruby+DTrace+probes+and+arguments"&gt;page&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Example 1: Tracing execution flow through your application&lt;/h3&gt;

&lt;p&gt;Lets start by tracing the execution flow through a small Ruby program.&lt;/p&gt;

&lt;h4&gt;Simple Ruby Program&lt;/h4&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;class World
  def say(message)
    puts message
  end
end

world = World.new
world.say('hello')&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This small Ruby program creates an instance of the World class, sends it the &lt;em&gt;say&lt;/em&gt; message with &lt;em&gt;hello&lt;/em&gt; as a String parameter which is printed to the console.&lt;/p&gt;

&lt;h4&gt;execution-flow.d&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;ruby$target:::function-entry
{
    printf("%s:%s\n", copyinstr(arg0), copyinstr(arg1));
}

ruby$target:::function-return
{
   printf("%s:%s\n", copyinstr(arg0), copyinstr(arg1));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This particular script enables the function-entry probe on the Ruby provider, and prints the first and second arguments passed to the probe in a C-style printf command. &lt;/p&gt;

&lt;p&gt;The first and second arguments passed are provider specific, but in the Ruby provider's case for these probes they are always the class/module and method names being executed. &lt;/p&gt;

&lt;p&gt;The $target variable enables the probe on the PID of the command specified via the -c parameter to DTrace itself.&lt;/p&gt;

&lt;h4&gt;Results&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; sudo dtrace -q -F -s execution-flow.d -c "ruby hello.rb"
CPU FUNCTION
1  -&amp;gt; rb_call0                              Class:inherited
1  &amp;lt;- rb_call0                              Class:inherited
1  -&amp;gt; rb_call0                              Module:method_added
1  &amp;lt;- rb_call0                              Module:method_added
1  -&amp;gt; rb_call0                              Class:new
1    -&amp;gt; rb_call0                            Object:initialize
1    &amp;lt;- rb_call0                            Object:initialize
1  &amp;lt;- rb_call0                              Class:new
1  -&amp;gt; rb_call0                              World:say
1    -&amp;gt; rb_call0                            Object:puts
1      -&amp;gt; rb_call0                          IO:write
1      &amp;lt;- rb_call0                          IO:write
1      -&amp;gt; rb_call0                          IO:write
1      &amp;lt;- rb_call0                          IO:write
1    &amp;lt;- rb_call0                            Object:puts
1  &amp;lt;- rb_call0                              World:say
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Taking a look at the results we can almost visually 'see' how the script was parsed and executed. First Class was 'inherited', this is part of the creation of our 'World' class, then we defined World#say (invoking the Module:method_added method) to contain some operations. We then created a new instance of our class (Class:new and Object:initialize to create and construct our object), and then invoked World#say which we can see calls Object:puts and IO:write.&lt;/p&gt;

&lt;p&gt;(In this particular case, the program is small and the instructions simple, however just add &lt;em&gt;"require 'rubygems'"&lt;/em&gt; to the top of the source and re-run the DTrace script again and you'll quickly be overwhelmed with too much information - writing effective DTrace scripts is an art, but it's well worth learning to ensure you get the answers you're looking for)&lt;/p&gt;

&lt;h3&gt;Example 2: Individual Method Performance&lt;/h3&gt;

&lt;p&gt;Lets use DTrace to take another look at our application from a different perspective and see what methods are most expensive. To do this we'll use the function entry and return probes to capture a time stamp interval for each method call. &lt;/p&gt;

&lt;p&gt;We'll also use an aggregate DTrace variable to store a running average of how long each method takes so that multiple method calls are recorded together and averaged across the count of method invocations, and we'll print the results according to most expensive method execution time.&lt;/p&gt;

&lt;h4&gt;Method Performance DTrace script&lt;/h4&gt;

&lt;h4&gt;timestamps.d&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;ruby$target:::function-entry
{
  self-&amp;gt;start = timestamp;
}

ruby$target:::function-return
/self-&amp;gt;start/
{
  @[copyinstr(arg0), copyinstr(arg1)] = avg(timestamp - self-&amp;gt;start);
  self-&amp;gt;start = 0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This script introduces a few more DTrace constructs, associative arrays and aggregate functions.&lt;/p&gt;

&lt;p&gt;We enable two probes, function entry and function return on our Ruby program. When any method is entered, we capture a timestamp and store it in the 'start' variable. When any method is exited, we gather another timestamp, subtract it from the entry, and pass it to the &lt;strong&gt;avg&lt;/strong&gt; DTrace aggregate function to be averaged. &lt;/p&gt;

&lt;p&gt;The average execution time is then stored in an associative array, indexed by the module/class and method name (arg0 and arg1 respectively). Finally, we reset 'start' to zero once its no longer required. &lt;/p&gt;

&lt;p&gt;A predicate is also set on the function return probe to fire only if we have a 'start' timestamp value, which prevents us from seeing any errors or miscalculations if we attach our DTrace script to an application that is already running (since after attaching, a return probe could fire for which we have no start timestamp).&lt;/p&gt;

&lt;h4&gt;Results&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; sudo dtrace -s timestamps.d -c "ruby hello.rb"
Object                   initialize                     9185
Module                   method_added                   10021
Class                    inherited                      25323
IO                       write                          98956
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;DTrace automatically prints data collected unless you supply a custom output format (eg. by using the C-style printf DTrace function as in the method flow example above) which in this case is the associative array, indexed by class/module and method name. &lt;/p&gt;

&lt;p&gt;From these results we can see that IO#write was the slowest of the methods called, taking an average of 98956 nanaseconds to run, most likely due to its interation with the rest of the system and IO nature.&lt;/p&gt;

&lt;h3&gt;Example 3: Quantized Method Performance&lt;/h3&gt;

&lt;p&gt;Average values can often be affected by a few large values during program startup, so lets take a closer look and see what values consititue the calculation the averages above. To do this we'll use the DTrace &lt;strong&gt;quantize&lt;/strong&gt; aggregate function, which will provide us with a distribution breakdown of each individual component within the average. We'll also specifically target the IO#write method, and update our Ruby program to print 'hello' 10 times to collect some more data over a period of invocations.&lt;/p&gt;

&lt;h4&gt;timestamps-q.d&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;ruby$target:::function-entry
/copyinstr(arg0) == "IO" &amp;amp;&amp;amp; copyinstr(arg1) == "write"/
{
  self-&amp;gt;start = timestamp;
}

ruby$target:::function-return
/copyinstr(arg0) == "IO" &amp;amp;&amp;amp; copyinstr(arg1) == "write" &amp;amp;&amp;amp; self-&amp;gt;start/
{
  @[copyinstr(arg0), copyinstr(arg1)] = quantize(timestamp - self-&amp;gt;start);
  self-&amp;gt;start = 0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Results&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; sudo dtrace -s timestamps-q.d -c "ruby hello.rb"

  IO                                                  write
           value  ------------- Distribution ------------- count
            4096 |                                         0
            8192 |@@@@@@@@@@@@@@@@@@@@                     10
           16384 |@@@@@@@@@@@@@@@@                         8
           32768 |@@                                       1
           65536 |                                         0
          131072 |@@                                       1
          262144 |                                         0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we see the distribution of how long each invocation of IO#write took. There was one invocation that particuarly long, over 131k nanoseconds, with most landing between 8k and 16k nanoseconds. &lt;/p&gt;

&lt;p&gt;From here we could step further into the runtime and determine which particular IO#write call was slower than the others by inspecting the user stack inside the virtual machine, and/or by enabling probes in lower level providers.&lt;/p&gt;

&lt;h3&gt;Example 4: Memory allocation&lt;/h3&gt;

&lt;p&gt;To profile memory allocation we need to enable the &lt;em&gt;object-create-start&lt;/em&gt;, &lt;em&gt;object-create-done&lt;/em&gt;, and &lt;em&gt;object-free&lt;/em&gt; probes. Creation of objects is separated into two probes to allow you to determine exactly how long it takes to construct an object.&lt;/p&gt;

&lt;p&gt;First, lets create a simple balance script to check that objects are being allocated and deallocated correctly within the Ruby runtime. The script we'll use will create an associative array and index a counter by object type. Each time an object is created we'll increment the counter, conversely each time an object is freed we'll decrement the counter.&lt;/p&gt;

&lt;h4&gt;object-balance.d&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;ruby$target:::object-create-done { @[copyinstr(arg0)] = sum(1); }
ruby$target:::object-free        { @[copyinstr(arg0)] = sum(-1); }
&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Results&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; sudo dtrace -s object-balance.d -c "ruby hello.rb"

  NoMemoryError                                                     1
  SystemStackError                                                  1
  ThreadGroup                                                       1
  World                                                             1
  fatal                                                             1
  Object                                                            3
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Glancing over the results we can see that Ruby is creating an instance of several error classes and a thread group during the run of our application (perhaps during startup), we can also see a single instance of our &lt;em&gt;World&lt;/em&gt; class, and three other Objects that have also been allocated. &lt;/p&gt;

&lt;p&gt;Our particular hello.rb script is quite small, and probably finishes executing before the garbage collector has had a change to reclaim any unused objects. If you run this script over a large application though, you'll see a line for each Object type in the application, and essentially a reference count of how many have been created and free'd. &lt;/p&gt;

&lt;p&gt;In an ideal application, after garbarge collector has finished, all object types (except those required to keep the application running) will be listed with the value '0' alongside it indicating a corresponding deallocation for each allocation.&lt;/p&gt;

&lt;h3&gt;Example 5: Inspecting memory allocation points&lt;/h3&gt;

&lt;p&gt;The object-create-start/done probes also provide the source file and line number of where the allocation was made in Ruby script which we can use. For example if our World class came from another developer's library and we wanted to find out where it was allocated we could use the following script:&lt;/p&gt;

&lt;h4&gt;object-world-location.d&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;ruby$target:::object-create-start
/copyinstr(arg0) == "World"/
{
  printf("%s was allocated in file %s, line number %d\n", copyinstr(arg0), copyinstr(arg1), arg2);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Results&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; sudo dtrace -s object-world-location.d -c "ruby hello.rb"

  World was allocated in file hello.rb, line number 7
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which matches our source file.&lt;/p&gt;

&lt;h3&gt;Example 6: Inspecting stack traces&lt;/h3&gt;

&lt;p&gt;We also saw above that several other 'Object's are created within the C portion of the Ruby interpreter upon startup. We can also inspect where these objects were created by saving the user C stack inside the virtual machine at the point of allocation.&lt;/p&gt;

&lt;h4&gt;object-user-stack.d&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;ruby$target:::object-create-start
/copyinstr(arg0) == "Object"/
{
  @[ustack(4)] = count();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This particular script uses the DTrace &lt;em&gt;ustack&lt;/em&gt; function to access the actual runtime stack of the Ruby interpreter in userland at the point in time when the probe fired, to a depth of 4 method calls.&lt;/p&gt;

&lt;p&gt;We then use the stack as an index into an associative array and store the number of times an Object type was created at the same point in the interpreter. This example really shows how flexible associative arrays can be in DTrace, by using a full stack trace as an index.&lt;/p&gt;

&lt;h4&gt;Results&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; sudo dtrace -s object-user-stack.d -c "ruby hello.rb"

          libruby.1.dylib`rb_obj_alloc+0x90
          libruby.1.dylib`Init_Object+0x130b
          libruby.1.dylib`rb_call_inits+0x15
          libruby.1.dylib`ruby_init+0x14f
            1

          libruby.1.dylib`rb_obj_alloc+0x90
          libruby.1.dylib`Init_IO+0x1059
          libruby.1.dylib`rb_call_inits+0x6a
          libruby.1.dylib`ruby_init+0x14f
            1

          libruby.1.dylib`rb_obj_alloc+0x90
          libruby.1.dylib`Init_Hash+0x903
          libruby.1.dylib`rb_call_inits+0x51
          libruby.1.dylib`ruby_init+0x14f
            1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we can see three separate stack traces indicating a Hash, IO and Object being created as part of the ruby_init method inside the Ruby interpreter.&lt;/p&gt;

&lt;h3&gt;Summary&lt;/h3&gt;

&lt;p&gt;DTrace is a very powerful framework, allowing you to really hypothesise and ask arbitrary questions about the behaviour of your system and applications. Often, the answer to one question will lead to another, and this is very much in the sprit of DTrace. The ability to script questions and format results allows you to slice behavioural data from any perspective and depth from your application, all the way to the operating system kernel.&lt;/p&gt;

&lt;p&gt;DTrace scripts are the key to reducing complexity and understanding the true behaviour of your application at runtime, and I certainly recommend learning as much about the D script format and language as you can. Fine tuning your script to return the exact data you're after can be an art, but its well worth learning so that you can specify exactly what data you are after, and not be cluttered with too much information obscuring the information you are searching for.&lt;/p&gt;

&lt;p&gt;Collections of commonly used DTrace scripts are available as part of the &lt;a href="http://opensolaris.org/os/community/dtrace/dtracetoolkit/"&gt;DTraceToolkit&lt;/a&gt;, in particular several very useful and high quality Ruby DTrace scripts. I'd recommend taking a look at them to see how probes can be used in combination with each other, also in multi-threaded environments.&lt;/p&gt;

&lt;p&gt;In future articles I'll step further into using DTrace via &lt;a href="http://www.apple.com/macosx/developertools/instruments.html"&gt;Instruments&lt;/a&gt;, and also look at instrumenting your Rails or Merb application to collect runtime data about the performance of your web applications.&lt;/p&gt;
          &lt;img src="http://feeds.redartisan.com/~r/redartisan/~4/292818807" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://redartisan.com/2008/5/18/dtrace-ruby</feedburner:origLink></entry>
  <entry xml:base="http://redartisan.com/">
    <author>
      <name>crafterm</name>
    </author>
    <id>tag:redartisan.com,2008-05-09:92</id>
    <published>2008-05-09T00:10:00Z</published>
    <updated>2008-05-09T01:12:38Z</updated>
    <category term="Blog" />
    <link href="http://feeds.redartisan.com/~r/redartisan/~3/286462199/dtrace-melbourne-cocoaheads" rel="alternate" type="text/html" />
    <title>DTrace at Cocoaheads</title>
<content type="html">
            &lt;p&gt;Last night we had our monthly &lt;a href="http://www.melbournecocoaheads.com/"&gt;Melbourne Cocoaheads&lt;/a&gt; meetup which was great. There were several talks given including one about the &lt;a href="http://auc.uow.edu.au/"&gt;AUC&lt;/a&gt;, and I also gave a talk about &lt;a href="http://www.sun.com/bigadmin/content/dtrace/"&gt;DTrace&lt;/a&gt;, the popular dynamic tracing framework for Mac OS X Leopard and OpenSolaris.&lt;/p&gt;

&lt;div&gt;&amp;lt;object height="355" width="425" style="margin:0px"&gt;&amp;lt;param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=dtrace-cocoaheads-20080508-1210291326431928-9" /&gt;&amp;lt;param name="allowFullScreen" value="true" /&gt;&amp;lt;param name="allowScriptAccess" value="always" /&gt;&amp;lt;embed allowfullscreen="true" type="application/x-shockwave-flash" src="http://static.slideshare.net/swf/ssplayer2.swf?doc=dtrace-cocoaheads-20080508-1210291326431928-9" allowscriptaccess="always" height="355" width="425"&gt;&amp;lt;/embed&gt;&amp;lt;/object&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ve uploaded the slides from my talk to &lt;a href="http://www.slideshare.net/crafterm/dtrace-395366"&gt;slideshare&lt;/a&gt; for those interested - since most of the talk was a demo there are only a few slides included, however the links towards the end of the presentation provide some good references to more information about DTrace, the D language and using DTrace on your system. Happy DTracing! :)&lt;/p&gt;
          &lt;img src="http://feeds.redartisan.com/~r/redartisan/~4/286462199" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://redartisan.com/2008/5/9/dtrace-melbourne-cocoaheads</feedburner:origLink></entry>
  <entry xml:base="http://redartisan.com/">
    <author>
      <name>crafterm</name>
    </author>
    <id>tag:redartisan.com,2008-04-11:90</id>
    <published>2008-04-11T01:00:00Z</published>
    <updated>2008-04-11T01:11:34Z</updated>
    <category term="Blog" />
    <link href="http://feeds.redartisan.com/~r/redartisan/~3/268058467/rubycocoa-melbourne-cocoaheads" rel="alternate" type="text/html" />
    <title>Ruby Cocoa &amp; Core Image at Cocoaheads</title>
<content type="html">
            &lt;p&gt;Last night saw our first &lt;a href="http://www.melbournecocoaheads.com/"&gt;Melbourne Cocoaheads&lt;/a&gt; meet up for the year. An awesome night was had by all, there were several &lt;a href="http://www.melbournecocoaheads.com/melbourne-cocoaheads-april-meeting/"&gt;talks&lt;/a&gt; given by various people including myself about RubyCocoa &amp;amp; Core Image, XCode Organiser, Python, and the iPhone.&lt;/p&gt;

&lt;p&gt;I gave a presentation about Ruby Cocoa and some of the Core Image related research I had been working on to &lt;a href="http://redartisan.com/2007/12/12/attachment-fu-with-core-image"&gt;integrate&lt;/a&gt; it into Attachment Fu for processing file uploads in Rails applications. I’ve &lt;a href="http://www.slideshare.net/crafterm/ruby-cocoa-and-core-image/"&gt;uploaded&lt;/a&gt; the slides from my talk if anyone is interested in them.&lt;/p&gt;

&lt;div&gt;&amp;lt;object height="355" width="425" style="margin:0px"&gt;&amp;lt;param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=rubycocoa-and-core-image-1207875668487728-8" /&gt;&amp;lt;param name="allowFullScreen" value="true" /&gt;&amp;lt;param name="allowScriptAccess" value="always" /&gt;&amp;lt;embed allowfullscreen="true" type="application/x-shockwave-flash" src="http://static.slideshare.net/swf/ssplayer2.swf?doc=rubycocoa-and-core-image-1207875668487728-8" allowscriptaccess="always" height="355" width="425"&gt;&amp;lt;/embed&gt;&amp;lt;/object&gt;&lt;div&gt;&lt;a href="http://www.slideshare.net/?src=embed"&gt;&lt;/div&gt;&lt;/div&gt;
          &lt;img src="http://feeds.redartisan.com/~r/redartisan/~4/268058467" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://redartisan.com/2008/4/11/rubycocoa-melbourne-cocoaheads</feedburner:origLink></entry>
  <entry xml:base="http://redartisan.com/">
    <author>
      <name>crafterm</name>
    </author>
    <id>tag:redartisan.com,2008-03-21:88</id>
    <published>2008-03-21T10:04:00Z</published>
    <updated>2008-03-21T10:12:39Z</updated>
    <category term="Blog" />
    <link href="http://feeds.redartisan.com/~r/redartisan/~3/255435518/au-sprint-roundup" rel="alternate" type="text/html" />
    <title>.au Rubinius Sprint roundup!</title>
<content type="html">
            &lt;p&gt;&lt;img src="http://farm4.static.flickr.com/3178/2328134347_bd0831e08a.jpg?v=0" width="450" /&gt;&lt;/p&gt;

&lt;p&gt;March 8/9th saw the first Australian &lt;a href="http://rubini.us/"&gt;Rubinius&lt;/a&gt; Sprint held in Sydney, at the Shangri-La Hotel, in Sydney’s famous Rocks district! &lt;/p&gt;

&lt;p&gt;The sprint went really well, in total we had 22 attendees, including some international visitors such as including &lt;a href="http://blog.fallingsnow.net/"&gt;Evan Phoenix&lt;/a&gt;, the founder of the project and &lt;a href="http://segment7.net/"&gt;Eric Hodel&lt;/a&gt; from the United States.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://farm3.static.flickr.com/2047/2328915752_d336cedd0b.jpg?v=0" width="450" /&gt;&lt;/p&gt;

&lt;p&gt;The sprint started off with a comprehensive introduction to Rubinius by Evan, stepping through the project’s source layout and navigation, the architecture of the virtual machine, standard library and language. &lt;/p&gt;

&lt;p&gt;From there everyone selected a spec test that was failing either due to error or non-implementation and started developing patches that were submitted to Rubinius’ lighthouse bug/patch tracker.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://farm4.static.flickr.com/3018/2328095857_39159d656d.jpg?v=0" width="450" /&gt;&lt;/p&gt;

&lt;p&gt;There were many highlights over the weekend, one in particular included seeing Rubygems working inside of Rubinius and being merged into the main Rubinius git repository which is a great milestone to have been achieved.&lt;/p&gt;

&lt;p&gt;A total of ~60 patches were submitted to Lighthouse, which was an outstanding effort made by all, not to mention the fantastic ‘spinner’ spec progress indicator :)&lt;/p&gt;

&lt;p&gt;We also made several visits to some of the great local restaurants and pubs nearby, such as Red Oak, The Australian, The Glenmore, and the Lord Nelson, not to mention the world speedboat championships that were on in the background of the conference hotel.&lt;/p&gt;

&lt;p&gt;For me it was also great seeing the local community all come together to participate in such an awesome project. Great work guys! :)&lt;/p&gt;

&lt;p&gt;I’d really like to thank &lt;a href="http://dylanegan.com/"&gt;Dylan&lt;/a&gt; for helping me organise the event, and many thanks to Evan and Eric for traveling out to Australia for the sprint. &lt;/p&gt;

&lt;p&gt;A big kudos to Engine Yard for sponsoring the venue over the weekend, and to Glenn also took many more photos over the weekend which are available on &lt;a href="http://flickr.com/photos/glenndavy/sets/72157604090617600/"&gt;Flickr&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Looking forward to the next sprint!&lt;/p&gt;
          &lt;img src="http://feeds.redartisan.com/~r/redartisan/~4/255435518" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://redartisan.com/2008/3/21/au-sprint-roundup</feedburner:origLink></entry>
  <entry xml:base="http://redartisan.com/">
    <author>
      <name>crafterm</name>
    </author>
    <id>tag:redartisan.com,2008-03-20:84</id>
    <published>2008-03-20T23:55:00Z</published>
    <updated>2008-03-21T00:14:47Z</updated>
    <category term="Blog" />
    <link href="http://feeds.redartisan.com/~r/redartisan/~3/255218692/git-bisect" rel="alternate" type="text/html" />
    <title>git bisect to the rescue!</title>
<content type="html">
            &lt;p&gt;An interesting feature in &lt;a href="http://git.or.cz/"&gt;Git&lt;/a&gt; I came across the other day is the &lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-bisect.html"&gt;bisect&lt;/a&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;”Find the change that introduced a bug by binary search”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Certainly sounds intriguing, turns out it can be quite useful.&lt;/p&gt;

&lt;p&gt;The motivation behind bisect is to help you find out when a bug was introduced into the source base, by marking a known good and bad point within the source, and examining commits in between those points following a binary search algorithm (ie. eliminating half of the possible commits each successive iteration).&lt;/p&gt;

&lt;p&gt;Linux developers use it to track down issues in the kernel spread across hundreds if not thousands of commits.&lt;/p&gt;

&lt;p&gt;Lets see an example, suppose we have a project with the following (annotated) log:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;commit bdf6fe9cd7c929487ffb6830b01a105836807f50
Author: Marcus Crafter &amp;lt;crafterm@redartisan.com&amp;gt;
Date:   Fri Mar 21 00:29:38 2008 +1100

    Added change 10       (version 2.0 aka HEAD)

commit af4331699b1ecfc39f077149801d80e5d83ab5fe
Author: Marcus Crafter &amp;lt;crafterm@redartisan.com&amp;gt;
Date:   Fri Mar 21 00:29:38 2008 +1100

    Added change 9

commit 9235af336946661c9c935c6f00a0b8590447dd6e
Author: Marcus Crafter &amp;lt;crafterm@redartisan.com&amp;gt;
Date:   Fri Mar 21 00:29:38 2008 +1100

    Added change 8  

commit 25718d202ee9b16a3d661d46a9d4dac5ff80ab52
Author: Marcus Crafter &amp;lt;crafterm@redartisan.com&amp;gt;
Date:   Fri Mar 21 00:29:38 2008 +1100

    Added change 7

commit af4932de08721a333a1c0c51d130c9d006f0bf61
Author: Marcus Crafter &amp;lt;crafterm@redartisan.com&amp;gt;
Date:   Fri Mar 21 00:29:38 2008 +1100

    Added change 6      (change introduced here)

..  ..  ..  ..

commit 463a5d5bd180e6b2d0eedaeb5227aeb357ca7827
Author: Marcus Crafter &amp;lt;crafterm@redartisan.com&amp;gt;
Date:   Fri Mar 21 00:29:38 2008 +1100

    Added change 1                 (version 1.0)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The history indicates 2 releases of the software package annotated via parenthesis.&lt;/p&gt;

&lt;p&gt;Post release 2.0 lets say a defect is reported (for the reader we’ve flagged change 6 as the culprit, but lets pretend we don’t know this for the moment). The information reported is that the feature used to work in version 1.0, but it’s broken in version 2.0, but no one has any idea where.&lt;/p&gt;

&lt;p&gt;So how can git help us track down what happened?&lt;/p&gt;

&lt;p&gt;Using git bisect, we can do the following:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; git bisect start
$&amp;gt; git bisect good version_1_0
$&amp;gt; git bisect bad
Bisecting: 4 revisions left to test after this
[388ec2c43dcccb710fd9e636c3ecf28ca2b42709] Added change 5
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We’ve told git that the tag &lt;em&gt;version_1_0&lt;/em&gt; (ie. change 1) was the last known point when the issue didn’t occur, and that HEAD (ie. &lt;em&gt;version_2_0&lt;/em&gt;) still has the issue. Given this information git takes these two known boundaries, and has chosen a midway point for us to inspect - change 5, which is half way between changes 1 and 10. &lt;/p&gt;

&lt;p&gt;If the defect is present in this revision, it was introduced in this commit or beforehand (eliminating the need to check commits 6-10 to see when the issue first appeared), if the defect isn’t present, then it was introduced after (eliminating the need to check commits 1-5). Either way, we eliminate the need to check half the field of commits.&lt;/p&gt;

&lt;p&gt;We test the software at change 5 and discover that the issue isn’t present, so we tell git this particular change is good:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; git bisect good
Bisecting: 2 revisions left to test after this
[25718d202ee9b16a3d661d46a9d4dac5ff80ab52] Added change 7
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;git now fast forwards to change 7, which is midway between 5 and 10. We repeat the process again. Here things become interesting, after testing the software we find the defect has appeared - somewhere between 5 and 7, in this case a range of only 3 commits. We inform git that this point in the history is broken:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; git bisect bad
Bisecting: 0 revisions left to test after this
[af4932de08721a333a1c0c51d130c9d006f0bf61] Added change 6
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now the result is obvious. If change 6 is broken then change 6 has introduced the issue (we found out above that change 5 was good). If change 6 is good, then change 7 must have introduced the issue. Testing finds out that 6 is bad, yielding it as the commit that first exhibited the issue:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git bisect bad
af4932de08721a333a1c0c51d130c9d006f0bf61 is first bad commit
commit af4932de08721a333a1c0c51d130c9d006f0bf61
Author: Marcus Crafter &amp;lt;crafterm@redartisan.com&amp;gt;
Date:   Fri Mar 21 00:29:38 2008 +1100

    Added change 6

:100644 100644 bb009e53210caf5bd64c46c9299a1c315e393c59 17d7ba157d12c79dd6337f091491e542f49b2c14 M  README
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and git tells us some more information about it. Now we can take a closer look at the commit details and see what happened to correct it.&lt;/p&gt;

&lt;p&gt;Once we’re done we can:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; git bisect reset &amp;amp;&amp;amp; git checkout master
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to continue development since the bisect takes place on a separate branch not to interfere with any other work you were previously doing.&lt;/p&gt;

&lt;p&gt;Due to the nature of bisecting the commit space by binary search, effectively searching across large ranges of commits can really be eased.&lt;/p&gt;
          &lt;img src="http://feeds.redartisan.com/~r/redartisan/~4/255218692" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://redartisan.com/2008/3/20/git-bisect</feedburner:origLink></entry>
  <entry xml:base="http://redartisan.com/">
    <author>
      <name>crafterm</name>
    </author>
    <id>tag:redartisan.com,2008-01-31:72</id>
    <published>2008-01-31T05:36:00Z</published>
    <updated>2008-01-31T05:42:24Z</updated>
    <category term="Blog" />
    <link href="http://feeds.redartisan.com/~r/redartisan/~3/226331900/rubinius-sprint" rel="alternate" type="text/html" />
    <title>Rubinius Sprint in Sydney, Australia</title>
<content type="html">
            &lt;p&gt;&lt;a href="http://dylanegan.com/"&gt;Dylan&lt;/a&gt; and I would like to announce that we’ll be running a Rubinius Sprint in Sydney, Australia, on the 8th/9th March 2008!&lt;/p&gt;

&lt;p&gt;The Rubinius Sprint/Workshop is a weekend dedicated to learning and developing Rubinius, the next generation Ruby virtual machine. The spring is aimed at developers of all levels, the only requirement is that you have a keen interest to be involved with Rubinius and want to learn more. No particular experience with Rubinius is necessary however it would be beneficial if you’ve spent a bit of time prior to the sprint familiarizing yourself with the basics of Rubinius itself.&lt;/p&gt;

&lt;p&gt;Everyone is invited to attend, registration details, etc, are all available at:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://engineyard.eventwax.com/rubinius-sprint"&gt;http://engineyard.eventwax.com/rubinius-sprint&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks to our awesome sponsor EngineYard, attending the event will be free (you’ll need to cover your own accommodation and food).&lt;/p&gt;

&lt;p&gt;Places are limited to please register quick if you’d like to come.&lt;/p&gt;

&lt;p&gt;Looking forward to seeing you all there!&lt;/p&gt;
          &lt;img src="http://feeds.redartisan.com/~r/redartisan/~4/226331900" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://redartisan.com/2008/1/31/rubinius-sprint</feedburner:origLink></entry>
  <entry xml:base="http://redartisan.com/">
    <author>
      <name>crafterm</name>
    </author>
    <id>tag:redartisan.com,2008-01-12:57</id>
    <published>2008-01-12T12:55:00Z</published>
    <updated>2008-05-22T03:54:47Z</updated>
    <category term="Blog" />
    <link href="http://feeds.redartisan.com/~r/redartisan/~3/215495330/rubycocoa-screen-capture" rel="alternate" type="text/html" />
    <title>Screen Capture via Ruby Cocoa!</title>
<content type="html">
            &lt;p&gt;&lt;img src="http://redartisan.com/assets/2008/1/12/snap1.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;During the week a good friend of mine laid down the challenge to work out how to programatically create a screenshot of your Mac OSX desktop. The following article steps through the process of performing this, adding some charm to the operation to create a full desktop snapshot tool using Ruby Cocoa.&lt;/p&gt;

&lt;p&gt;Before stepping into the code, I’ll first present a small extension module that all code snippets rely upon. It’s essentially a small extension to the OSX::CIImage class to simplify loading and saving of image files, and conversions between Core Image and Quartz Image objects (which we’ll need later).&lt;/p&gt;

&lt;h4&gt;extensions.rb&lt;/h4&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;module OSX
  class CIImage      
    def save(target, format = OSX::NSJPEGFileType, properties = nil)
      bitmapRep = OSX::NSBitmapImageRep.alloc.initWithCIImage(self)
      blob = bitmapRep.representationUsingType_properties(format, properties)
      blob.writeToFile_atomically(target, false)
    end

    def cgimage
      OSX::NSBitmapImageRep.alloc.initWithCIImage(self).CGImage()
    end

    def self.from(filepath)
      raise Errno::ENOENT, &amp;quot;No such file or directory - #{filepath}&amp;quot; unless File.exists?(filepath)
      OSX::CIImage.imageWithContentsOfURL(OSX::NSURL.fileURLWithPath(filepath))
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Capturing the Desktop&lt;/h3&gt;

&lt;p&gt;With our extensions code in place, we can use the new CGWindow API, recently added to Mac OSX 10.5, to snapshot our desktop:&lt;/p&gt;

&lt;h4&gt;capture-plain.rb&lt;/h4&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;require 'osx/cocoa'
require 'extensions'

class Screen
  def self.capture
    screenshot = OSX::CGWindowListCreateImage(OSX::CGRectInfinite, OSX::KCGWindowListOptionOnScreenOnly, OSX::KCGNullWindowID, OSX::KCGWindowImageDefault)
    OSX::CIImage.imageWithCGImage(screenshot)
  end
end

Screen.capture.save('desktop.jpg')&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;An example screen capture is at the top of this article.&lt;/p&gt;

&lt;p&gt;This works really well and is only a few lines of code. It’s quite fast, in fact the Apple documentation mentions &lt;em&gt;”For capturing pixels, the CGWindow API should demonstrate performance that is equal or better than the techniques used by the OpenGLScreenSnapshot and OpenGLScreenCapture samples”&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;The only thing is that the user has no feedback that an actual screenshot was taken, other than the creation of the target image file.&lt;/p&gt;

&lt;p&gt;So, lets build upon this and add some feedback.&lt;/p&gt;

&lt;h3&gt;Capturing the Desktop with a Fade operation&lt;/h3&gt;

&lt;p&gt;What we’ll do to make it obvious that a screenshot is being taken, is fade the desktop out to a black colour, take the screenshot of the original desktop content, and fade the desktop back to it’s original state. &lt;/p&gt;

&lt;p&gt;The effect is similar to what OSX does while changing screen resolutions when you attach an external display or a projector to your Mac.&lt;/p&gt;

&lt;p&gt;Implementation wise, we’ll add a &lt;strong&gt;fade&lt;/strong&gt; operation to our Screen class, that will accept a block of code to perform in between fading the display out and back in again. The relevant Cocoa operations are documented in the Quartz Display Services &lt;a href="http://developer.apple.com/documentation/GraphicsImaging/Conceptual/QuartzDisplayServicesConceptual/Articles/FadeEffects.html#//apple_ref/doc/uid/TP40004232"&gt;guide&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Essentially we need to invoke &lt;strong&gt;CGAcquireDisplayFadeReservation()&lt;/strong&gt; to obtain a fade reservation token, after which we can invoke &lt;strong&gt;CGDisplayFade()&lt;/strong&gt; to fade the display to a solid colour and back. Once we’re done fading, we can release the fade reservation token with &lt;strong&gt;CGReleaseDisplayFadeReservation()&lt;/strong&gt; (or allow it to time out).&lt;/p&gt;

&lt;h4&gt;capture-with-fade.rb&lt;/h4&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;require 'osx/cocoa'
require 'extensions'

class Screen

  def self.capture
    fade do
      screenshot = OSX::CGWindowListCreateImage(OSX::CGRectInfinite, OSX::KCGWindowListOptionOnScreenOnly, OSX::KCGNullWindowID, OSX::KCGWindowImageDefault)
      OSX::CIImage.imageWithCGImage(screenshot)
    end
  end

  private

    def self.fade
      err, token = OSX::CGAcquireDisplayFadeReservation(OSX::KCGMaxDisplayReservationInterval)

      if err == OSX::KCGErrorSuccess
        begin
          OSX::CGDisplayFade(token, 0.3, OSX::KCGDisplayBlendNormal, OSX::KCGDisplayBlendSolidColor, 0, 0, 0, true)
          return yield if block_given?
        ensure
          OSX::CGDisplayFade(token, 0.3, OSX::KCGDisplayBlendSolidColor, OSX::KCGDisplayBlendNormal, 0, 0, 0, false)
          OSX::CGReleaseDisplayFadeReservation(token)
        end
      end
    end
end

Screen.capture.save('desktop.jpg')&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Capturing the Desktop with a Fade and Snap Graphic&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://www.flickr.com/photos/dsevilla/249202834/"&gt;&lt;img src="http://farm1.static.flickr.com/94/249202834_c8d25d461f.jpg?v=0" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The fade looks really nice, but since other applications can also perform the same effect, lets embed a small graphic in between the fade of a camera to really show that we’re taking a picture of the desktop.&lt;/p&gt;

&lt;p&gt;To do this, we need to capture the desktop in between the fade operation, and draw directly onto the display, without creating a window or any other graphical decorations. Capturing and drawing directly onto a display are also discussed in the Quartz documentation &lt;a href="http://developer.apple.com/documentation/GraphicsImaging/Conceptual/QuartzDisplayServicesConceptual/Articles/DisplayCapture.html"&gt;online&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Essentially, we need to use &lt;strong&gt;CGDisplayCapture(display)&lt;/strong&gt; to capture a specified display. While it’s captured we have exclusive access to the display, and no other application will interfere with it. Then, we can use &lt;strong&gt;CGDisplayGetDrawingContext(display)&lt;/strong&gt; to obtain a drawing context, and &lt;strong&gt;CGContextDrawImage()&lt;/strong&gt; to draw an image directly to the display. Once we’re done showing our picture, we can then release our capture of the display using &lt;strong&gt;CGDisplayRelease(display)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The image we’ll use is above (or grab another one you’d like to use), save is as nikon.jpg alongside the following script.&lt;/p&gt;

&lt;h4&gt;capture-with-fade-and-graphic.rb&lt;/h4&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;require 'osx/cocoa'
require 'extensions'

class Screen

  def self.capture
    fade do
      screenshot = OSX::CGWindowListCreateImage(OSX::CGRectInfinite, OSX::KCGWindowListOptionOnScreenOnly, OSX::KCGNullWindowID, OSX::KCGWindowImageDefault)
      OSX::CIImage.imageWithCGImage(screenshot)
    end
  end

  private

    def self.fade
      err, token = OSX::CGAcquireDisplayFadeReservation(OSX::KCGMaxDisplayReservationInterval)

      if err == OSX::KCGErrorSuccess
        begin
          OSX::CGDisplayFade(token, 0.3, OSX::KCGDisplayBlendNormal, OSX::KCGDisplayBlendSolidColor, 0, 0, 0, true)

          snap(token)

          return yield if block_given?
        ensure
          OSX::CGDisplayFade(token, 0.3, OSX::KCGDisplayBlendSolidColor, OSX::KCGDisplayBlendNormal, 0, 0, 0, false)
          OSX::CGReleaseDisplayFadeReservation(token)
        end
      end
    end

    def self.snap(token)
      display = OSX::CGMainDisplayID()

      if OSX::CGDisplayCapture(display) == OSX::KCGErrorSuccess
        begin
          ctx = OSX::CGDisplayGetDrawingContext(display)
          if ctx
            pic = OSX::CIImage.from('nikon.jpg')

            OSX::CGDisplayFade(token, 0.0, OSX::KCGDisplayBlendSolidColor, OSX::KCGDisplayBlendNormal, 0, 0, 0, true)

            # calculate middle of the screen for the images location
            display_width, display_height = OSX::CGDisplayPixelsWide(display), OSX::CGDisplayPixelsHigh(display)
            pic_width, pic_height = pic.extent.size.width, pic.extent.size.height
            position_x, position_y = (display_width - pic_width) / 2.0, (display_height - pic_height) / 2.0

            OSX::CGContextDrawImage(ctx, OSX::NSRectFromString(&amp;quot;#{position_x} #{position_y} #{pic_width} #{pic_height}&amp;quot;), pic.cgimage)

            sleep(0.7)

            OSX::CGDisplayFade(token, 0.0, OSX::KCGDisplayBlendNormal, OSX::KCGDisplayBlendSolidColor, 0, 0, 0, true)
          end
        ensure
          OSX::CGDisplayRelease(display)
        end
      end
    end
end

Screen.capture.save('desktop.jpg')&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Summary&lt;/h3&gt;

&lt;p&gt;First we created a simple capture class that used the new CGWindow API in Mac OSX 10.5, then we built upon that adding a fade effect around the actual screen capture. Next we drew an image directly on the display in between the fade, to make it even more obvious that we were taking a screenshot.&lt;/p&gt;

&lt;p&gt;There we have it, a really useful tool for capturing screenshots of your desktop programatically.&lt;/p&gt;

&lt;h3&gt;Special Thanks!&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Thanks to &lt;a href="http://lachstock.com.au/"&gt;Lachlan&lt;/a&gt; for the challenge mate! :)&lt;/li&gt;
&lt;li&gt;Thanks to &lt;a href="http://notahat.com/"&gt;Pete&lt;/a&gt; for your help with the Cocoa desktop fade semantics.&lt;/li&gt;
&lt;li&gt;Thanks to &lt;a href="http://www.flickr.com/photos/dsevilla/249202834/"&gt;DSevilla&lt;/a&gt; for the camera image used above.&lt;/li&gt;
&lt;/ol&gt;
          &lt;img src="http://feeds.redartisan.com/~r/redartisan/~4/215495330" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://redartisan.com/2008/1/12/rubycocoa-screen-capture</feedburner:origLink></entry>
  <entry xml:base="http://redartisan.com/">
    <author>
      <name>crafterm</name>
    </author>
    <id>tag:redartisan.com,2007-12-31:53</id>
    <published>2007-12-31T02:29:00Z</published>
    <updated>2008-05-22T03:54:13Z</updated>
    <category term="Blog" />
    <link href="http://feeds.redartisan.com/~r/redartisan/~3/208730428/core-image-effects" rel="alternate" type="text/html" />
    <title>Cool Effects with Core Image!</title>
<content type="html">
            &lt;p&gt;In a previous &lt;a href="http://redartisan.com/2007/12/12/attachment-fu-with-core-image"&gt;article&lt;/a&gt; I described how to use &lt;a href="http://developer.apple.com/macosx/coreimage.html"&gt;Core Image&lt;/a&gt; as the backend image processor for &lt;a href="http://svn.techno-weenie.net/projects/plugins/attachment_fu/README"&gt;Attachment Fu&lt;/a&gt; in your Rails applications. In that particular article we looked at supporting image scaling and thumbnails to be compatible with the other Attachment Fu backends such as &lt;a href="http://rmagick.rubyforge.org/"&gt;RMagick&lt;/a&gt; and &lt;a href="http://seattlerb.rubyforge.org/ImageScience.html"&gt;ImageScience&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With Core Image available however, we have an entire range of post processing filters available to use at our fingertips. In this article we’ll step through a few of these additional filter options that you can use to post process your images with.&lt;/p&gt;

&lt;p&gt;Here’s a few examples of what we can do with Core Image post file upload. All of the following examples use the following input image taken in Berlin while at RailsConf EU (also used in the performance measurements &lt;a href="http://redartisan.com/2007/12/16/core-image-performance"&gt;article&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/12/16/IMG_2990.jpg" /&gt;&lt;/p&gt;

&lt;h2&gt;Greyscale or Sepia&lt;/h2&gt;

&lt;p&gt;A scaled version of the source image is cool, but how about an automatic greyscale or sepia version of the image:&lt;/p&gt;

&lt;h3&gt;Greyscale&lt;/h3&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/12/31/berlin-grey.jpg" /&gt;&lt;/p&gt;

&lt;h3&gt;Sepia&lt;/h3&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/12/31/berlin-sepia.jpg" /&gt;&lt;/p&gt;

&lt;h3&gt;Code Fragment&lt;/h3&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;module RedArtisan
  module CoreImage
    module Filters
      module Color

        def greyscale(color = nil, intensity = 1.00)
          create_core_image_context(@original.extent.size.width, @original.extent.size.height)

          color = OSX::CIColor.colorWithString(&amp;quot;1.0 1.0 1.0 1.0&amp;quot;) unless color

          @original.color_monochrome :inputColor =&amp;gt; color, :inputIntensity =&amp;gt; intensity do |greyscale|
            @target = greyscale
          end
        end

        def sepia(intensity = 1.00)
          create_core_image_context(@original.extent.size.width, @original.extent.size.height)

          @original.sepia_tone :inputIntensity =&amp;gt; intensity do |sepia|
            @target = sepia
          end
        end

      end
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Exposure and Noise Control&lt;/h2&gt;

&lt;p&gt;Another option for us is to automatically adjust exposure and noise parameters upon upload to brighten images up, or remove unwanted noise from lower quality images:&lt;/p&gt;

&lt;h3&gt;1 F-Stop&lt;/h3&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/12/31/berlin-exposure-adjusted-full-stop.jpg" /&gt;&lt;/p&gt;

&lt;h3&gt;2 F-Stops&lt;/h3&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/12/31/berlin-exposure-adjusted-two-stops.jpg" /&gt;&lt;/p&gt;

&lt;h3&gt;Noise Removal&lt;/h3&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/12/31/berlin-noise-reduced.jpg" /&gt;&lt;/p&gt;

&lt;h3&gt;Code Fragment&lt;/h3&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;module RedArtisan
  module CoreImage
    module Filters
      module Quality

        def reduce_noise(level = 0.02, sharpness = 0.4)
          create_core_image_context(@original.extent.size.width, @original.extent.size.height)

          @original.noise_reduction :inputNoiseLevel =&amp;gt; level, :inputSharpness =&amp;gt; sharpness do |noise_reduced|
            @target = noise_reduced
          end
        end

        def adjust_exposure(input_ev = 0.5)
          create_core_image_context(@original.extent.size.width, @original.extent.size.height)

          @original.exposure_adjust :inputEV =&amp;gt; input_ev do |adjusted|
            @target = adjusted
          end          
        end

      end
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Watermarking&lt;/h2&gt;

&lt;p&gt;Sometimes we’d like to automatically add a watermark to our images, either with a single watermark image, or as a tiled watermark image:&lt;/p&gt;

&lt;h3&gt;Single Watermark&lt;/h3&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/12/31/berlin-watermarked.jpg" /&gt;&lt;/p&gt;

&lt;h3&gt;Tiled Watermark&lt;/h3&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/12/31/berlin-watermarked-tiled.jpg" /&gt;&lt;/p&gt;

&lt;h3&gt;Code Fragment&lt;/h3&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;module RedArtisan
  module CoreImage
    module Filters
      module Watermark

        def watermark(watermark_image, tile = false, strength = 0.1)
          create_core_image_context(@original.extent.size.width, @original.extent.size.height)

          if watermark_image.respond_to? :to_str
            watermark_image = OSX::CIImage.from(watermark_image.to_str)
          end

          if tile
            tile_transform = OSX::NSAffineTransform.transform
            tile_transform.scaleXBy_yBy 1.0, 1.0

            watermark_image.affine_tile :inputTransform =&amp;gt; tile_transform do |tiled|
              tiled.crop :inputRectangle =&amp;gt; vector(0, 0, @original.extent.size.width, @original.extent.size.height) do |tiled_watermark|
                watermark_image = tiled_watermark
              end
            end
          end

          @original.dissolve_transition :inputTargetImage =&amp;gt; watermark_image, :inputTime =&amp;gt; strength do |watermarked|
            @target = watermarked
          end
        end

      end
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Funky Effects&lt;/h2&gt;

&lt;p&gt;We can also use cool and funky effects used in applications like Photobooth, here’s an example using the edge colouring algorithm:&lt;/p&gt;

&lt;h3&gt;Edges&lt;/h3&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/12/31/berlin-edge.jpg" /&gt;&lt;/p&gt;

&lt;h3&gt;Core Fragment&lt;/h3&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;module RedArtisan
  module CoreImage
    module Filters
      module Effects

        def edges(intensity = 1.00)
          create_core_image_context(@original.extent.size.width, @original.extent.size.height)

          @original.edges :inputIntensity =&amp;gt; intensity do |edged|
            @target = edged
          end
        end

      end
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The sign artwork works particularly well with this algorithm.&lt;/p&gt;

&lt;h2&gt;Core Image Processor&lt;/h2&gt;

&lt;p&gt;All of the code above is also available as a usable image processor via &lt;a href="http://git.redartisan.com/?p=af_ci.git;a=history;f=vendor;hb=HEAD"&gt;git&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Some examples of using the processor:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;require 'red_artisan/core_image/processor'

# generate some test output images for various effects

processor = RedArtisan::CoreImage::Processor.new('berlin.jpg')

grey = processor.greyscale
grey.save 'results/berlin-grey.jpg'

sepia = processor.sepia
sepia.save 'results/berlin-sepia.jpg'

watermarked = processor.watermark('watermark_image.png')
watermarked.save 'results/berlin-watermarked.jpg'

watermarked = processor.watermark('watermark_image.png', true)
watermarked.save 'results/berlin-watermarked-tiled.jpg'

noise_reduced = processor.reduce_noise
noise_reduced.save 'results/berlin-noise-reduced.jpg'

exposure_adjusted = processor.adjust_exposure
exposure_adjusted.save 'results/berlin-exposure-adjusted-half-stop.jpg'

exposure_adjusted = processor.adjust_exposure(2.0)
exposure_adjusted.save 'results/berlin-exposure-adjusted-two-stops.jpg'

edge = processor.edges
edge.save 'results/berlin-edge.jpg'&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;The above shows us only a fraction of what can be done with the 100+ filters Core Image provides by &lt;a href="http://developer.apple.com/documentation/GraphicsImaging/Reference/CoreImageFilterReference/Reference/reference.html#//apple_ref/doc/uid/TP40004346-CH202-TPXREF101"&gt;default&lt;/a&gt;. There’s many other filters that let you create all sorts of effects with single and multiple images combined. Enjoy!&lt;/p&gt;
          &lt;img src="http://feeds.redartisan.com/~r/redartisan/~4/208730428" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://redartisan.com/2007/12/31/core-image-effects</feedburner:origLink></entry>
  <entry xml:base="http://redartisan.com/">
    <author>
      <name>crafterm</name>
    </author>
    <id>tag:redartisan.com,2007-12-16:44</id>
    <published>2007-12-16T11:42:00Z</published>
    <updated>2008-05-22T03:54:27Z</updated>
    <category term="Blog" />
    <link href="http://feeds.redartisan.com/~r/redartisan/~3/201145786/core-image-performance" rel="alternate" type="text/html" />
    <title>Core Image Performance</title>
<content type="html">
            &lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/12/16/IMG_2990.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;Following my &lt;a href="http://redartisan.com/2007/12/12/attachment-fu-with-core-image"&gt;previous&lt;/a&gt; post, a few people have asked me how well Core Image performs in comparison to &lt;a href="http://rmagick.rubyforge.org/"&gt;RMagick&lt;/a&gt; and &lt;a href="http://seattlerb.rubyforge.org/ImageScience.html"&gt;ImageScience&lt;/a&gt; when used as part of Attachment Fu. To answer these questions, I’ve spent a bit of time collecting some performance results.&lt;/p&gt;

&lt;p&gt;Please note that as with all performance testing, results will vary according to many parameters such as hardware, processing power, and even the input image content itself, as you’ll see below.&lt;/p&gt;

&lt;p&gt;Naturally Core Image &lt;em&gt;should&lt;/em&gt; be faster since it will run hardware accelerated on my MacBook Pro, so please take these results more as an indication of library characteristics rather than final timings. The tests I performed also mirrored how each library was being invoked by Attachment Fu, and beyond performance there’s also several other tangible benefits to Core Image such as deployment and access via RubyCocoa to keep in mind as well.&lt;/p&gt;

&lt;p&gt;The first test performs 5 successive resizes of a 1mb image under each library (from 1250x833 to 640x480). The input image is a complex photo (smaller version above) taken in Berlin of parts of the Berlin Wall, including a high colour range and lots of shapes and sizes:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/12/16/complex-1mb-image-resize-average.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;Both RMagick and ImageScience yield consistent results as expected. Core Image’s resize values are interesting as successive resizes are twice as fast than the first, which I speculate would include an initial Core Image to OpenGL compilation phase of the resize operation being performed.&lt;/p&gt;

&lt;p&gt;Similar characteristics can be observed with a slightly larger image size of around 2.5mb (2200x1467 to 640x480):&lt;/p&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/12/16/complex-2.5mb-image-resize-average.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;In both cases, Core Image performs really well, particularly on consecutive runs.&lt;/p&gt;

&lt;p&gt;The actual image content being resized also affects results as well - the following test uses a blank image of identical dimensions to the 1mb Berlin image (1250x833 to 640x480):&lt;/p&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/12/16/blank-image-resize-average.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;Finally, the following graph shows the results of resizing 6 versions of the Berlin image with each library, at increasing size &amp;amp; dimensions to half their original size. The results plotted for each measurement are calculated over the average of 5 resizes of each image.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/12/16/increasing-sizes-average.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;At small image sizes, we can see the difference in resize time to be essentially negligible, however as image size increase up to 500kb, the hardware acceleration of Core Image starts to shine, particularly around the 2.5mb - 5mb range and beyond where it screams along.&lt;/p&gt;

&lt;p&gt;There does seem to be a limit to performance gains, on Friday &lt;a href="http://germanforblack.com/"&gt;Ben&lt;/a&gt; and I also made a few experiments with really large image sizes (TIFF files around 90mb, resizing from 5436x4080 to 640x480), and noticed that Core Image can be slower than Image Science under these conditions:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/12/16/90mb-image-resize-average.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;At this stage I can only speculate as to why this occurs, and it deserves further inspection.&lt;/p&gt;

&lt;p&gt;Another interesting aspect to look at is the actual on disk size of the resized images. The following is a directory listing of the results after the 2.5mb image (2200x1467 resize to 640x480):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;crafterm  staff  153492 16 Dec 22:30 core_image-complex_resized.jpg
crafterm  staff  288455 16 Dec 22:30 image_science-complex_resized.jpg
crafterm  staff  356827 16 Dec 22:30 rmagick-complex_resized.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Core Image’s default compression range is quite impressive, and while I’m sure the other libraries compression factors can be fine tuned I suspect it would also affect their relative performance measurements.&lt;/p&gt;

&lt;p&gt;All measurements shown in the graphs are in seconds, and the test machine was my MacBook Pro, 15” Intel Core 2 Duo, 2.16 Ghz with an ATI Radeon X1600 video card with 128mb vram. I’d certainly be keen to see how other types of hardware perform, so please feel free to run the test code on your system and send me the resultant graphs, and I’ll add them to the project.&lt;/p&gt;

&lt;p&gt;All test code and input images (except for the 90mb example due to copyright) are available in a git repository &lt;a href="http://git.redartisan.com/?p=af_ci_extras.git;a=tree"&gt;online&lt;/a&gt;.&lt;/p&gt;
          &lt;img src="http://feeds.redartisan.com/~r/redartisan/~4/201145786" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://redartisan.com/2007/12/16/core-image-performance</feedburner:origLink></entry>
  <entry xml:base="http://redartisan.com/">
    <author>
      <name>crafterm</name>
    </author>
    <id>tag:redartisan.com,2007-12-12:40</id>
    <published>2007-12-12T23:42:00Z</published>
    <updated>2008-05-22T03:53:57Z</updated>
    <category term="Blog" />
    <link href="http://feeds.redartisan.com/~r/redartisan/~3/199452552/attachment-fu-with-core-image" rel="alternate" type="text/html" />
    <title>Attachment_fu magic with Core Image and Ruby Cocoa!</title>
<content type="html">
            &lt;p&gt;Like many of us in the Rails world, I use &lt;a href="http://svn.techno-weenie.net/projects/plugins/attachment_fu/README"&gt;attachment_fu&lt;/a&gt; to handle file uploads in my Rails applications. Attachment_fu does a great job, in particular with it’s ability to scale and generate multiple sized copies of images with various processing back ends including ImageScience, RMagick and MiniMagic, not to mention it’s flexible storage options, all from the comfort of a DSL:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;has_attachment :content_type =&amp;gt; :image, 
               :resize_to    =&amp;gt; '640x400',
               :storage      =&amp;gt; :file_system, 
               :size         =&amp;gt; 1.kilobyte .. 3.megabytes,
               :thumbnails   =&amp;gt; { :small =&amp;gt; '50x50', :medium =&amp;gt; '320x200' }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Working on under Mac OS X though, it’s often been a challenge to get these underlying libraries installed. General community consensus is that &lt;a href="http://rmagick.rubyforge.org/"&gt;RMagick&lt;/a&gt; leaks memory, and &lt;a href="http://seattlerb.rubyforge.org/ImageScience.html"&gt;ImageScience&lt;/a&gt; is built upon &lt;a href="http://freeimage.sourceforge.net/"&gt;FreeImage&lt;/a&gt; and &lt;a href="http://www.zenspider.com/ZSS/Products/RubyInline/"&gt;RubyInline&lt;/a&gt; which requires a development &lt;a href="http://developer.apple.com/tools/xcode/"&gt;environment&lt;/a&gt; to compile, install and run.&lt;/p&gt;

&lt;p&gt;As developers &lt;a href="http://www.macports.org/"&gt;MacPorts&lt;/a&gt; lets us all build and install these libraries comfortably, however the biggest beef I’ve had is that under the hood of every recent Mac OS X installation, there’s actually a great image processing library already available to us - &lt;a href="http://developer.apple.com/macosx/coreimage.html"&gt;Core Image&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Core Image&lt;/h3&gt;

&lt;p&gt;Core Image has been a part of Mac OS X since Tiger and is part of the QuartzCore framework, offering a flexible filter/pipeline based approach to manipulating images via &lt;a href="http://developer.apple.com/documentation/GraphicsImaging/Reference/CoreImageFilterReference/Reference/reference.html"&gt;transforms&lt;/a&gt;. Once of the most exciting things about Core Image though, is that it processes images using a subset of the &lt;a href="http://en.wikipedia.org/wiki/OpenGL_Shading_Language"&gt;OpenGL Shading Language&lt;/a&gt;, and when available will use the &lt;a href="http://en.wikipedia.org/wiki/Graphics_processing_unit"&gt;GPU&lt;/a&gt; to render, all in accelerated hardware near or in real time! In environments where the available GPU is not supported, Core Image automatically falls back to the CPU for processing seamlessly giving us the best of both worlds.&lt;/p&gt;

&lt;p&gt;Until recently, access to Core Image has only been available via languages such as Objective-C. However with the release of Leopard, Ruby has become an officially supported language within XCode, and in particular &lt;a href="http://rubycocoa.sourceforge.net/HomePage"&gt;RubyCocoa&lt;/a&gt; is available by default under every Leopard Mac OS X installation (in Tiger it can be installed separately).&lt;/p&gt;

&lt;p&gt;So now it’s even easier for us to take full advantage of the underlying power of these Cocoa API’s, directly from Ruby itself.&lt;/p&gt;

&lt;h3&gt;Let’s get started!&lt;/h3&gt;

&lt;p&gt;In this article, I’ll describe how to add support for using Core Image as the image processing library within attachment_fu. &lt;/p&gt;

&lt;p&gt;Once we’re finished, attachment_fu will handle all your uploads using Core Image for resizing and thumbnail generation (most likely hardware accelerated inside your Mac’s GPU), if you have Leopard it won’t require any 3rd party library to be installed to work, and it will handle any Mac OS X &lt;a href="http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Images/chapter_7_section_3.html#//apple_ref/doc/uid/TP40003290-CH208-BCIIFBJG"&gt;supported image format&lt;/a&gt;, which as of 10.5, includes RAW. &lt;/p&gt;

&lt;p&gt;It’s even more particularly enticing if you deploy your Rails application to an XServe which includes a Core Image supported GPU.&lt;/p&gt;

&lt;p&gt;To do this, we’ll need to perform the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Create&lt;/strong&gt; an image manipulation class that uses Core Image&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integrate&lt;/strong&gt; this new class into attachment_fu, by writing a new attachment_fu processor module&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optionally&lt;/strong&gt;, update attachment_fu’s automatic image processing list, or rely on using the :processor directive in our has_attachment model definitions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Create an image manipulation class that uses Core Image&lt;/h3&gt;

&lt;p&gt;Our first step is to create a new class that uses Core Image to resize and/or thumbnail a given image. To do this, we’ll need to define an API to accept the source image, some new dimensions and specify where the resized version should be rendered to.&lt;/p&gt;

&lt;p&gt;Inside of the class, we’ll use Core Image Filters to perform the actual work. &lt;/p&gt;

&lt;p&gt;Core Image Filters allow you to create a ‘pipeline’ of transforms that’s performed on a given image. Mac OS X includes many filters by default, allowing you to perform all sorts of effects on your image, but the one we’re interested in at the moment is the &lt;a href="http://developer.apple.com/documentation/GraphicsImaging/Reference/CoreImageFilterReference/Reference/reference.html#//apple_ref/doc/filter/ci/CILanczosScaleTransform"&gt;Lanczos Scale Transform filter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Lanczos Scale Transform produces a high quality, scaled version of the source image using a well defined &lt;a href="http://en.wikipedia.org/wiki/Lanczos_resampling"&gt;algorithm&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In addition to this, we’ll pre-process the image with an &lt;a href="http://developer.apple.com/documentation/GraphicsImaging/Reference/CoreImageFilterReference/Reference/reference.html#//apple_ref/doc/uid/TP30000136-DontLinkElementID_98"&gt;Affine Clamp&lt;/a&gt; filter which will make the image infinitely big by clamping the image’s edges outwards. We do this so that there’s no edge imperfections introduced due to rounding/ceiling of dimensions when scaling. After the Lanczos scaling has done it’s trick, we then crop the image to our target dimensions for rendering.&lt;/p&gt;

&lt;p&gt;Here’s an example of how we’ll use the classes API:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;p = Processor.new OSX::CIImage.from(path_to_image)
p.resize(640, 480)
p.render do |result|
  result.save('resized.jpg', OSX::NSJPEGFileType)
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Processor.resize(width, height)&lt;/strong&gt; will perform a hard resize to the given dimensions, where as &lt;strong&gt;Processor.fit(size)&lt;/strong&gt; will resize the image to a scale that fits its aspect ratio. These two methods are provided as attachment_fu includes some extra geometry processing code that lets us use RMagick style geometry stings to specify dimensions as fixed values, percentages, scales, or relative aspect ratio sizes that we’ll leverage off.&lt;/p&gt;

&lt;p&gt;Here’s the actual classes implementation&lt;/p&gt;

&lt;h3&gt;vendor/core_image/processor.rb&lt;/h3&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;require 'rubygems'
require 'osx/cocoa'
require 'active_support'

# Copyright (c) Marcus Crafter &amp;lt;crafterm@redartisan.com&amp;gt;
#
class Processor

  def initialize(original)
    @original = original
  end

  def resize(width, height)
    create_core_image_context(width, height)

    scale_x, scale_y = scale(width, height)

    @original.affine_clamp :inputTransform =&amp;gt; OSX::NSAffineTransform.transform do |clamped|
      clamped.lanczos_scale_transform :inputScale =&amp;gt; scale_x &amp;gt; scale_y ? scale_x : scale_y, :inputAspectRatio =&amp;gt; scale_x / scale_y do |scaled|
        scaled.crop :inputRectangle =&amp;gt; vector(0, 0, width, height) do |cropped|
          @target = cropped
        end
      end
    end
  end

  def fit(size)
    original_size = @original.extent.size
    scale = size.to_f / (original_size.width &amp;gt; original_size.height ? original_size.width : original_size.height)
    resize (original_size.width * scale).to_i, (original_size.height * scale).to_i
  end

  def render(&amp;amp;block)
    raise &amp;quot;unprocessed image: #{@original}&amp;quot; unless @target
    block.call @target
  end

  private

    def create_core_image_context(width, height)
        output = OSX::NSBitmapImageRep.alloc.initWithBitmapDataPlanes_pixelsWide_pixelsHigh_bitsPerSample_samplesPerPixel_hasAlpha_isPlanar_colorSpaceName_bytesPerRow_bitsPerPixel(nil, width, height, 8, 4, true, false, OSX::NSDeviceRGBColorSpace, 0, 0)
        context = OSX::NSGraphicsContext.graphicsContextWithBitmapImageRep(output)
        OSX::NSGraphicsContext.setCurrentContext(context)
        @ci_context = context.CIContext
    end

    def vector(x, y, w, h)
      OSX::CIVector.vectorWithX_Y_Z_W(x, y, w, h)
    end

    def scale(width, height)
      original_size = @original.extent.size
      return width.to_f / original_size.width.to_f, height.to_f / original_size.height.to_f
    end

end

module OSX
  class CIImage
    include OCObjWrapper

    def method_missing_with_filter_processing(sym, *args, &amp;amp;block)
      f = OSX::CIFilter.filterWithName(&amp;quot;CI#{sym.to_s.camelize}&amp;quot;)
      return method_missing_without_filter_processing(sym, *args, &amp;amp;block) unless f

      f.setDefaults if f.respond_to? :setDefaults
      f.setValue_forKey(self, 'inputImage')
      options = args.last.is_a?(Hash) ? args.last : {}
      options.each { |k, v| f.setValue_forKey(v, k.to_s) }

      block.call f.valueForKey('outputImage')
    end

    alias_method_chain :method_missing, :filter_processing

    def save(target, format, properties = nil)
      bitmapRep = OSX::NSBitmapImageRep.alloc.initWithCIImage(self)
      blob = bitmapRep.representationUsingType_properties(format, properties)
      blob.writeToFile_atomically(target, false)
    end

    def self.from(filepath)
      OSX::CIImage.imageWithContentsOfURL(OSX::NSURL.fileURLWithPath(filepath))
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The processor class uses a few Ruby idioms, in particular with the filter processing and rendering code. The filtering code leverages blocks and method_missing to provide a declarative approach to defining filters and their parameters:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;@original.affine_clamp :inputTransform =&amp;gt; OSX::NSAffineTransform.transform do |clamped|
  clamped.lanczos_scale_transform :inputScale =&amp;gt; inputScale, :inputAspectRatio =&amp;gt; ratio do |scaled|
    scaled.crop :inputRectangle =&amp;gt; vector do |cropped|
      @target = cropped
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(note that the methods affine_clamp, lanczos_scale_transform and crop don’t actually exist on OSX::CIImage, they’re applied dynamically)&lt;/p&gt;

&lt;p&gt;A few helper methods have also been added to OSX::CoreImage to ease construction and serialization. Rendered output file types can be &lt;em&gt;NSBMPFileType, NSGIFFileType, NSJPEGFileType, NSPNGFileType, or NSTIFFFileType&lt;/em&gt;. See the XCode API documentation for an &lt;a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSBitmapImageRep_Class/Reference/Reference.html"&gt;NSBitmapImageRep&lt;/a&gt; class for more information about the various properties for each type.&lt;/p&gt;

&lt;h3&gt;Integrating our core image processor into attachment_fu&lt;/h3&gt;

&lt;p&gt;Now that we have a class that can resize images using Core Image, we just need to integrate it with attachment_fu.&lt;/p&gt;

&lt;p&gt;Attachment_fu’s design is quite modular, allowing us to add a new image processor via writing a module that’s mixed in at runtime.
Essentially we need to define a module within the Technoweenie::AttachmentFu::Processors namespace, that will extend the functionality of the ‘process_attachment’ method.&lt;/p&gt;

&lt;p&gt;The common approach is to do this via alias_method_chain, which decorates the existing process_attachment method with new functionality. &lt;/p&gt;

&lt;p&gt;Here’s the new module:&lt;/p&gt;

&lt;h3&gt;technoweenie/attachment_fu/processors/core_image_processor.rb&lt;/h3&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;require 'core_image/processor'

module Technoweenie # :nodoc:
  module AttachmentFu # :nodoc:
    module Processors
      module CoreImageProcessor
        def self.included(base)
          base.send :extend, ClassMethods
          base.alias_method_chain :process_attachment, :processing
        end

        module ClassMethods
          def with_image(file, &amp;amp;block)
            block.call OSX::CIImage.from(file)
          end
        end

        protected
          def process_attachment_with_processing
            return unless process_attachment_without_processing
            with_image do |img|
              self.width  = img.extent.size.width  if respond_to?(:width)
              self.height = img.extent.size.height if respond_to?(:height)
              resize_image_or_thumbnail! img
              callback_with_args :after_resize, img
            end if image?
          end

          # Performs the actual resizing operation for a thumbnail
          def resize_image(img, size)
            processor = Processor.new(img)
            size = size.first if size.is_a?(Array) &amp;amp;&amp;amp; size.length == 1
            if size.is_a?(Fixnum) || (size.is_a?(Array) &amp;amp;&amp;amp; size.first.is_a?(Fixnum))
              if size.is_a?(Fixnum)
                processor.fit(size)
              else
                processor.resize(size[0], size[1])
              end
            else
              new_size = [img.extent.size.width, img.extent.size.height] / size.to_s
              processor.resize(new_size[0], new_size[1])
            end

            processor.render do |result|
              self.width  = result.extent.size.width  if respond_to?(:width)
              self.height = result.extent.size.height if respond_to?(:height)
              result.save self.temp_path, OSX::NSJPEGFileType
              self.size = File.size(self.temp_path)
            end
          end          
      end
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The module brings the core image based processing class we’ve written above into scope, and then proceeds to define a CoreImageProcessor module within the Technoweenie::AttachmentFu::Processors namespace. When this module is included, it then aliases process_attachment to add some new functionality, essentially the process_attachment_with_processing and resize_image methods.&lt;/p&gt;

&lt;p&gt;Most of the code in this module surrounds calling the processor class’ API with the correct resize values based on the range of possible geometry values attachment_fu allows. The ImageScience and RMagick processors look quite similar.&lt;/p&gt;

&lt;h3&gt;Update attachment_fu’s automatic image processing list&lt;/h3&gt;

&lt;p&gt;Attachment_fu includes several processors which are tried in order at startup to work out which image processing engine to use, based on what underlying libraries, etc, are available on your machine.&lt;/p&gt;

&lt;p&gt;This step is optional because we can either update this list so that our Core Image processor is part of this selection, or we can specify the processor directly when defining a has_attachment on a model:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;has_attachment :content_type =&amp;gt; :image, 
               :processor    =&amp;gt; :core_image,
               :resize_to    =&amp;gt; '640x400',
               :storage      =&amp;gt; :file_system, 
               :size         =&amp;gt; 1.kilobyte .. 3.megabytes,
               :thumbnails   =&amp;gt; { :small =&amp;gt; '50x50', :medium =&amp;gt; '320x200' }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To update the default list, open up the attachment_fu.rb source file, and update the @@default_processors class variable from:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;module Technoweenie
  module AttachmentFu
    @@default_processors = %w(ImageScience Rmagick MiniMagick)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;module Technoweenie
  module AttachmentFu
    @@default_processors = %w(CoreImage ImageScience Rmagick MiniMagick)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which will register the Core Image processor module for inclusion when attachment_fu searches for image processors.&lt;/p&gt;

&lt;h3&gt;Summary&lt;/h3&gt;

&lt;p&gt;We’ve created a class that uses Core Image to resize an image to given dimensions, using a high quality Lanczos Scale transform, via RubyCocoa. We’ve integrated it into attachment_fu by creating a new processor module that can be specified in the default image processing search list, or directly in a has_attachment definition. &lt;/p&gt;

&lt;h3&gt;I want it!&lt;/h3&gt;

&lt;p&gt;To make things easy, I’ve created a git &lt;a href="http://git.redartisan.com/?p=af_ci.git;a=summary"&gt;repository&lt;/a&gt; that includes all of the above files so you can keep up to date, and the project format is in a structure you can export directly into your attachment_fu installation. To access the source, use the following command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; git clone git://git.redartisan.com/af_ci.git
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will check out the attachment_fu core image project that you can copy across into your attachment_fu installation (or perform a nice git export of the source directly).&lt;/p&gt;

&lt;p&gt;Once you’ve installed the source files in your attachment_fu plugin, apply the supplied patch to update attachment_fu’s list of supported image processors. You’ll need to restart your Rails application to reload the plugin, after which you’ll be using Core Image to process attachments!&lt;/p&gt;

&lt;h3&gt;Future&lt;/h3&gt;

&lt;p&gt;I have several further enhancements and ideas surrounding the core image processor which I’ll talk about in further articles - if you have any improvements to the code, patches are also more than welcome. Enjoy!&lt;/p&gt;

&lt;h3&gt;[Update]&lt;/h3&gt;

&lt;p&gt;To facilitate updates to the code, I’ve imported the source into a git &lt;a href="http://git.redartisan.com/?p=af_ci.git;a=summary"&gt;repository&lt;/a&gt; rather than distribute via the tar/gz the original post referenced.&lt;/p&gt;

&lt;h3&gt;[Update II]&lt;/h3&gt;

&lt;p&gt;Now that Technoweenie has imported his sources into github, I’ve created a child &lt;a href="http://github.com/crafterm/attachment_fu/tree/master"&gt;attachment_fu&lt;/a&gt; repository that includes all of the above updates to use Core Image with Attachment Fu.&lt;/p&gt;
          &lt;img src="http://feeds.redartisan.com/~r/redartisan/~4/199452552" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://redartisan.com/2007/12/12/attachment-fu-with-core-image</feedburner:origLink></entry>
  <entry xml:base="http://redartisan.com/">
    <author>
      <name>crafterm</name>
    </author>
    <id>tag:redartisan.com,2007-11-28:39</id>
    <published>2007-11-28T00:15:00Z</published>
    <updated>2008-04-20T13:56:13Z</updated>
    <category term="Blog" />
    <link href="http://feeds.redartisan.com/~r/redartisan/~3/191779528/textmate-csv-to-yaml" rel="alternate" type="text/html" />
    <title>Extracting database content as bootstrap or fixture data</title>
<content type="html">
            &lt;p&gt;Recently I’ve been doing lots of work with databases full of existing data and often have needed to extract data out to into YAML files to use either as bootstrap data (particularly images coming from attachment_fu that need to be preloaded after deployment) or as fixtures (yep, sometimes the data is just too complex to mock).&lt;/p&gt;

&lt;p&gt;To ease the process I’ve created a script that I use inside of TextMate, which lets me convert a CSV exported file from CocoaMySQL to a YAML file, suitable for the db:bootstrap rake task or fixture data, all at the close distance of a keyboard shortcut.&lt;/p&gt;

&lt;p&gt;First, to get the data out of the database, open up CocoaMySQL, select your table and view its content, and go to ‘File -&gt; Export -&gt; Table Content Result -&gt; Text File’.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/11/28/cocoamysql-export_1.png" /&gt;&lt;/p&gt;

&lt;p&gt;Save the exported contents.&lt;/p&gt;

&lt;p&gt;Then you’ll need the following script:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;#!/usr/bin/env ruby
#
# Format CSV output of cocoamysql into a fixture file
#
# &amp;quot;id&amp;quot;,&amp;quot;name&amp;quot;,&amp;quot;mime_type&amp;quot;,&amp;quot;extensions&amp;quot;,&amp;quot;icon_url&amp;quot;
# &amp;quot;1&amp;quot;,&amp;quot;unknown&amp;quot;,&amp;quot;unknown/unknown&amp;quot;,&amp;quot;||&amp;quot;,&amp;quot;/images/icon/file_unknown.gif&amp;quot;
# &amp;quot;2&amp;quot;,&amp;quot;image/tiff&amp;quot;,&amp;quot;image/tiff&amp;quot;,&amp;quot;|tiff|tif|&amp;quot;,&amp;quot;/images/icon/blank.png&amp;quot;

require 'csv'

class String
  def unquote
    self.gsub(/^&amp;quot;|&amp;quot;$/, '')
  end
end

# first line contains the field names
line = gets
fields = line.split('&amp;quot;,&amp;quot;').collect {|f| f.unquote.chomp}

CSV::Reader.parse(STDIN) do |row|
  fixture = &amp;quot;#{row[1].downcase}_#{row[0]}:\n&amp;quot;
  fields.each_with_index do |field, i|
    fixture += &amp;quot;  #{field}: #{row[i]}\n&amp;quot;
  end

  puts fixture; puts
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which we’ll add as a new ‘Command’ inside of a TextMate bundle.&lt;/p&gt;

&lt;p&gt;To do this, open up TextMate, and select the ‘Edit Commands’ menu item&lt;/p&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/11/28/textmate-edit-commands_1.png" /&gt;&lt;/p&gt;

&lt;p&gt;Then, in a custom bundle add a new command (+ button along the bottom of the dialog) and paste the contents of the script above.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/11/28/textmate-command-editor_1.png" /&gt;&lt;/p&gt;

&lt;p&gt;Select ‘Entire Document’ as the input source, and ‘New Document’ as the output, this will ensure that you don’t overwrite your CSV file incase you require it later.&lt;/p&gt;

&lt;p&gt;Then we need to reload the bundles so that TextMate knows about your new command. To do this, select the ‘Reload Bundles’ menu item&lt;/p&gt;

&lt;p&gt;&lt;img src="http://redartisan.com/assets/2007/11/28/textmate-reload-bundles_1.png" /&gt;&lt;/p&gt;

&lt;p&gt;And we’re all set to go. Open up your CSV file, and convert it to a YAML file either via the keyboard shortcut defined in your Command (mine was ctrl-shift-cmd-F) or the menu item from your custom bundle and voila, a converted YAML document will appear which you can save directly to db/bootstrap or your fixtures directory. Enjoy.&lt;/p&gt;
          &lt;img src="http://feeds.redartisan.com/~r/redartisan/~4/191779528" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://redartisan.com/2007/11/28/textmate-csv-to-yaml</feedburner:origLink></entry>
  <entry xml:base="http://redartisan.com/">
    <author>
      <name>crafterm</name>
    </author>
    <id>tag:redartisan.com,2007-11-04:37</id>
    <published>2007-11-04T11:26:00Z</published>
    <updated>2007-11-06T00:31:49Z</updated>
    <category term="Blog" />
    <link href="http://feeds.redartisan.com/~r/redartisan/~3/179558847/railsconf-eu-presentation" rel="alternate" type="text/html" />
    <title>RailsConf Overview Slides</title>
<content type="html">
            &lt;p&gt;Arriving back in Melbourne, after having such a fantastic trip through Europe to attend RailsConf, visit clients and travel, it was great to see everyone at our local user group again at the end of last month.&lt;/p&gt;

&lt;p&gt;I gave a quick presentation covering all the fun we all had at &lt;a href="http://redartisan.com/2007/9/19/railsconf-eu"&gt;RailsConf&lt;/a&gt; while away.&lt;/p&gt;

&lt;div&gt;&amp;lt;object height="355" width="425" style="margin:0px"&gt;&amp;lt;param name="movie" value="http://s3.amazonaws.com/slideshare/ssplayer2.swf?doc=railsconf-eu-overview-1194262754577130-3" /&gt;&amp;lt;param name="allowFullScreen" value="true" /&gt;&amp;lt;param name="allowScriptAccess" value="always" /&gt;&amp;lt;embed allowfullscreen="true" type="application/x-shockwave-flash" src="http://s3.amazonaws.com/slideshare/ssplayer2.swf?doc=railsconf-eu-overview-1194262754577130-3" allowscriptaccess="always" height="355" width="425"&gt;&amp;lt;/embed&gt;&amp;lt;/object&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It was particularly cool being able to talk about the excitement and atmosphere at the conference, and also at &lt;a href="http://redartisan.com/2007/9/22/rejectconf-europe-2007"&gt;RejectConf&lt;/a&gt; which was once again a highlight of the trip.&lt;/p&gt;

&lt;p&gt;In just under three weeks we’ll be hosting &lt;a href="http://wiki.railscamp07.org/railscamp07/"&gt;RailsCamp&lt;/a&gt; in Melbourne, which I’m also looking forward to. The previous camp held in Gosford was a blast, and I’m excited to see it happening again!&lt;/p&gt;
          &lt;img src="http://feeds.redartisan.com/~r/redartisan/~4/179558847" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://redartisan.com/2007/11/4/railsconf-eu-presentation</feedburner:origLink></entry>
  <entry xml:base="http://redartisan.com/">
    <author>
      <name>crafterm</name>
    </author>
    <id>tag:redartisan.com,2007-10-11:26</id>
    <published>2007-10-11T10:10:00Z</published>
    <updated>2007-10-11T10:22:48Z</updated>
    <category term="Blog" />
    <link href="http://feeds.redartisan.com/~r/redartisan/~3/168365693/rubinius-coding" rel="alternate" type="text/html" />
    <title>Getting Started with Rubinius II: Coding!</title>
<content type="html">
            &lt;p&gt;In a &lt;a href="http://redartisan.com/2007/10/5/rubinius-getting-started"&gt;previous&lt;/a&gt; article we examined the process of checking out &lt;a href="http://rubini.us/"&gt;Rubinius&lt;/a&gt;, building it from source and discussed its directory structure. In this article, we’ll take it one step further and examine the process of implementing an example method that can be contributed back to the project as a patch for inclusion in the official Rubinius source base.&lt;/p&gt;

&lt;p&gt;If you haven’t checked out or built Rubinius please see my &lt;a href="http://redartisan.com/2007/10/5/rubinius-getting-started"&gt;previous&lt;/a&gt; post which details the preliminary steps required before we can start implementing.&lt;/p&gt;

&lt;p&gt;The feature we’ll implement is the &lt;em&gt;File.link&lt;/em&gt; method, the implementation is quite simple and only a few lines of code but it will take us through the process of adding a method to an existing class with an existing spec, and will also take us into the system call layer where we’ll interact with the underlying operating system to perform a symlink.&lt;/p&gt;

&lt;p&gt;In this case it’s not required however generally it’s a good idea to run the &lt;em&gt;rake dev:setup&lt;/em&gt; rake task before implementation to ensure that we have pristine copies of our runtime archives available. We do this because the compiler itself requires that the runtime archives work, and if we introduce a defect it’s possible to enter the situation where we cannot compile a fix.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;dev:setup&lt;/em&gt; essentially makes a backup of the runtime archives that will always be used for compilation. In our particular case the compiler doesn’t create any symlinks so this step is optional but it’s a good idea if you’re working on existing code or low level methods such as File.stat, Hash, Array, etc to do so.&lt;/p&gt;

&lt;p&gt;Normally when using git we would create a feature branch, implement our specs and changes on that branch, commit it locally and then rebase the source code off the master branch before pushing it to the main repository (this is how Rubinius committers integrate their work into the main line development). In this article we’ll omit these stages as they’re well &lt;a href="http://rubinius.lighthouseapp.com/projects/5089/using-git"&gt;documented&lt;/a&gt; on the Rubinius project pages, and here we want to focus on the changes to be made to Rubinius itself.&lt;/p&gt;

&lt;h2&gt;Specification&lt;/h2&gt;

&lt;p&gt;Back to our new feature - a spec already exists for &lt;em&gt;File.link&lt;/em&gt; and it’s in the spec/core/file/link_spec.rb file:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;require File.dirname(__FILE__) + '/../../spec_helper'

describe &amp;quot;File.link&amp;quot; do
  before do 
    @file = &amp;quot;test.txt&amp;quot;
    @link = &amp;quot;test.lnk&amp;quot;     
    File.delete(@link) if File.exists?(@link)
    File.delete(@file) if File.exists?(@file)
    File.open(@file, &amp;quot;w+&amp;quot;)
  end

  platform :not, :mswin do
    it &amp;quot;link a file with another&amp;quot; do
      File.link(@file, @link).should == 0
      File.exists?(@link).should == true
      File.identical?(@file, @link).should == true
    end

    it &amp;quot;raise an exception if the target already exists&amp;quot; do
      File.link(@file, @link)
      should_raise(Errno::EEXIST) { File.link(@file, @link) }
    end

    it &amp;quot;raise an exception if the arguments are of the wrong type or are of the incorrect number&amp;quot; do
      should_raise(ArgumentError) { File.link }
      should_raise(ArgumentError) { File.link(@file) }
    end
  end

  after do
    File.delete(@link)
    File.delete(@file)
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The core specification suite is laid out in the spec/core directory using the convention of a having a spec file per method on each class containing all behaviour for that corresponding method. Platform and bootstrap specs are in the spec/platform and spec/bootstrap directories respectively.&lt;/p&gt;

&lt;p&gt;Examining the specification above, there’s three tests that are run on all non-mswin platforms (ie. those supporting the creation of symlinks). The tests ensure that when called, File.link creates a symlink between the source and target, or raises an exception either if the target already exists or if it’s given incorrect arguments.&lt;/p&gt;

&lt;p&gt;This identifies what we need to implement.&lt;/p&gt;

&lt;p&gt;Let’s run the spec to see what’s failing:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; bin/mspec -f s spec/core/file/link_spec.rb

File.link
- link a file with another  (ERROR - 1)
- raise an exception if the target already exists (ERROR - 2)
- raise an exception if the arguments are of the wrong type or are of the incorrect number (ERROR - 3)


1)
File.link link a file with another  FAILED
No method link on an instance of Class.: 
    Object(Class)#link (method_missing) at kernel/core/object.rb:98
                        main.__script__ at spec/core/file/link_spec.rb:14
                              Proc#call at kernel/core/context.rb:262
                          SpecRunner#it at spec/mini_rspec.rb:337
                                main.it at spec/mini_rspec.rb:369
                        main.__script__ at spec/core/file/link_spec.rb:24
                          main.platform at ./spec/core/file/../../spec_helper.rb:96
                        main.__script__ at spec/core/file/link_spec.rb:30
                              Proc#call at kernel/core/context.rb:262
                    SpecRunner#describe at spec/mini_rspec.rb:347
                          main.describe at spec/mini_rspec.rb:365
                        main.__script__ at spec/core/file/link_spec.rb:3
                              main.load at kernel/core/compile.rb:78
                   main.__eval_script__ at (eval):8
                             Array#each at kernel/core/array.rb:526
                  Integer(Fixnum)#times at kernel/core/integer.rb:19
                             Array#each at kernel/core/array.rb:526
                   main.__eval_script__ at (eval):5
                CompiledMethod#activate at kernel/core/compiled_method.rb:110
                        Compile.execute at kernel/core/compile.rb:34
                        main.__script__ at kernel/loader.rb:170
..snip..
$&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From the stacktraces we can see:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;No method link on an instance of Class.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;indicates that File.link doesn’t even exist inside the current implementation of File.&lt;/p&gt;

&lt;h2&gt;Design&lt;/h2&gt;

&lt;p&gt;The corresponding source file to implement File.link is in kernel/core/file.rb:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;# depends on: io.rb

class File &amp;lt; IO
  ..snip..

  def self.new(path, mode)
    return open_with_mode(path, mode)
  end

  def self.open(path, mode=&amp;quot;r&amp;quot;)
    raise Errno::ENOENT if mode == &amp;quot;r&amp;quot; and not exists?(path)

    f = open_with_mode(path, mode)
    return f unless block_given?

    begin
      yield f
    ensure
      f.close unless f.closed?
    end
  end

  def self.exist?(path)
    out = Stat.stat(path, true)
    if out.kind_of? Stat
      return true
    else
      return false
    end
  end

  def self.file?(path)
    st = Stat.stat(path, true)
    return false unless st.kind_of? Stat
    st.kind == :file
  end

  ..snip..
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we see methods implementing various parts of the File API. The above methods show the implementation of File.new, File.open, File.exist? and File.file? (to compare MRI’s implementation of the above methods check the file.c source file in the Ruby tar.gz source archive).&lt;/p&gt;

&lt;p&gt;Lets look a first implementation of File.link. The primary behaviour of File.link is to create a hard link between two filenames. To do this we need to invoke the link(2) system call on the underlying operating system to create the link.&lt;/p&gt;

&lt;p&gt;A quick examination of the link(2) man page yields:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; man 2 link

LINK(2)             BSD System Calls Manual            LINK(2)

NAME
     link - make a hard file link

SYNOPSIS
     #include &amp;lt;unistd.h&amp;gt;

     int
     link(const char *name1, const char *name2);

DESCRIPTION
     The link() function call atomically creates the specified directory entry
     (hard link) name2 with the attributes of the underlying object pointed at
     by name1 If the link is successful: the link count of the underlying
     object is incremented; name1 and name2 share equal access and rights to
     the underlying object.

     ..snip..

RETURN VALUES
     Upon successful completion, a value of 0 is returned.  Otherwise, a value
     of -1 is returned and errno is set to indicate the error.

     ..snip..

STANDARDS
     The link() function is expected to conform to IEEE Std 1003.1-1988
     (POSIX.1).
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;According to the man page, link(2) accepts the source and target of the symlink as paramaters, and returns an integer indicating success or failure.&lt;/p&gt;

&lt;h2&gt;FFI&lt;/h2&gt;

&lt;p&gt;To invoke link(2) we need to add a new method to the &lt;em&gt;ffi&lt;/em&gt; layer inside of Rubinius. &lt;em&gt;ffi&lt;/em&gt; stands for ‘foreign function interface’, and it’s a really neat way of being able to interact with system calls on the underlying operating system without needing to write a lot of stub or native integration code.&lt;/p&gt;

&lt;p&gt;ffi bindings are compiled into the platform.rba archive, and since link(2) conforms to a POSIX standard the file we need to modify is kernel/platform/posix.rb.&lt;/p&gt;

&lt;p&gt;Opening kernel/platform/posix.rb we’ll see blocks of code such as the following inside the Platform::POSIX module:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;# file system
attach_function nil, 'access', [:string, :int], :int
attach_function nil, 'chmod',  [:string, :int], :int
attach_function nil, 'fchmod', [:int, :int], :int
attach_function nil, 'unlink', [:string], :int
attach_function nil, 'getcwd', [:string, :int], :string
attach_function nil, 'umask', [:int], :int&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This code dynamically attaches methods to the module, and specifies the parameter types and return values of each method.&lt;/p&gt;

&lt;p&gt;The general format of the ‘attach_function’ method is as follows:&lt;/p&gt;

&lt;p&gt;attach_function library, method name, [ parameters ], return value&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;library&lt;/strong&gt;, library name to load dynamically, nil otherwise&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;name&lt;/strong&gt;, name of the method to attach, this is also the name the method will be available as inside the module&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;parameters&lt;/strong&gt;, array of symbols identifying the types this method accepts as parameters&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;return value&lt;/strong&gt;, type of the return value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(attach_function can also accept several other formats of parameters, please take a closer look at kernel/platform/ffi.rb for more details)&lt;/p&gt;

&lt;p&gt;Symbols are defined for most primitive types, ie: :short, :int, :long, :string, :char, etc, which can be used in the parameter list and return value specifier.&lt;/p&gt;

&lt;p&gt;Following the examples above, link(2) can be attached to the Platform::POSIX module with one line of code:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;attach_function nil, 'link', [:string, :string], :int&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After adding this line of code to the Platform::POSIX module, we need to update the platform.rba archive to ensure it now includes knowledge of link(2) system call.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; rake build:platform
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Implementation&lt;/h2&gt;

&lt;p&gt;Now that we have access to the link(2) system call, we can invoke it via ffi from the file module.&lt;/p&gt;

&lt;p&gt;Open up kernel/core/file.rb, and in between two existing methods, enter the following code:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;def self.link(from, to)
  Platform::POSIX.link(from, to)
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As with the platform archive, we’ll need to update the core archive:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; rake build:core
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s re-run our specifications to see if it passes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; bin/mspec -f s spec/core/file/link_spec.rb

File.link
- link a file with another 
- raise an exception if the target already exists (ERROR - 1)
- raise an exception if the arguments are of the wrong type or are of the incorrect number


1)
File.link raise an exception if the target already exists FAILED
Expected EEXIST, nothing raised: 
          main.should_raise at ./spec/core/file/../../mspec_helper.rb:27
            main.__script__ at spec/core/file/link_spec.rb:21
                  Proc#call at kernel/core/context.rb:262
              SpecRunner#it at spec/mini_rspec.rb:337
                    main.it at spec/mini_rspec.rb:369
            main.__script__ at spec/core/file/link_spec.rb:24
              main.platform at ./spec/core/