Channels
Displaying page 8
Posted 26 days ago at Ruby Inside

http://engineering.attinteractive.com/2010/08/code-coverage-in-ruby-1-9/ (or on Ruby Inside)

Aaron Patterson (of Nokogiri fame) has written a post for the AT&T Interactive blog about writing a code coverage tool with Ruby 1.9:

You probably didn’t know this, but code coverage is actually a miracle. Who knows how it works? Oh wait, it’s exactly opposite of what I just said. It’s not a miracle, and we can learn how it works.

I’m not going to go in to depth, but this tool works by hooking in to Ruby's virtual machine...

Aaron Patterson

It turns out that Ruby 1.9 already comes with support for code coverage monitoring. Aaron looks at how it works and improves how we interact with it a shade.

back to top

gollum: A simple, Git-powered wiki with a sweet API and local frontend.:

If your open source project needs a wiki, GitHub will leave you saying “My PRECIOUS!” After much anticipation, GitHub has finally taken the curtain down on their new git-powered wikis.

What’s new

  • Reverence images and folders in your Git project.

    Screenshot

  • Markdown support!

  • Local previewing

You’ll need to upgrade to the new wiki from within your GitHub project admin page.

As part of the rollout, they’ve also released Gollum the Ruby library that powers the new GitHub wikis. Gollumn also includes an embedded Sinatara server to preview your content.

[Source on GitHub] [Announcement blog post] [Gollum Demo]

back to top
Posted 27 days ago at The GitHub Blog

We've been hearing a lot of great feedback regarding our current wiki system. Today, we're launching the first phase in a rollout of a completely rewritten Git-backed wiki system to address these issues. Each page is a file in a directory. Each change is a commit.

Where's Markdown support?

A lot of people like Textile, but wikis are one of the few places that don't support Markdown. The new GitHub Wikis leverage our markup library to support eight formats, with context sensitive help and a toolbar.

Git-Powered History and Comparisons

Being able to see diffs of changes is another highly requested feature for wikis. Git is pretty good at this already, so we just use the existing tools for showing the history and making comparisons.

Images and Folders

You can now reference images hosted inside the Git repository.

Importing and Exporting

Each wiki is a Git repository, so you're able to push and pull them like anything else. Each wiki respects the same permissions as the source repository. Just add ".wiki" to any repository name in the URL, and you're ready to go.

View Your Content Locally

We're also releasing Gollum, the same ruby library that powers GitHub Wikis. Gollum provides a ruby API for accessing and modifying your content, and also includes a small Sinatra web server. Clone the demo wiki to see what's available, or check out the Gollum readme for more detailed information.

Our hope is that our community can help us make GitHub Wikis better, in the same way you've all helped us make GitHub Pages better through Jekyll. If other language implementations pop up, and other Git hosts start supporting Gollum Wikis, that'll be better for the Git community as a whole.

Where's the Script?

We've decided to improve the public wiki experience by hosting everything under the main github.com domain. To do this, we've had to sanitize all javascript and CSS in the wikis. You will no longer appear to be logged out when reading wikis for open source repositories.

How Can I Upgrade?

The new GitHub Wikis are still technically beta. We're encouraging our users to upgrade wikis on their own, and report any incompatibilities that come up. You're able to upgrade without disturbing the existing wiki. Once your new wiki is ready to go, you can disable the classic wiki, and we'll redirect traffic for you.

We're looking at disabling all classic wikis and forcing upgrades starting September 12th.

back to top
Favorite
Posted 27 days ago at Snax

Well, it's been a long time. But! I have four papers to add to my original distributed systems primer:

coordination

Consistency Without Concurrency Control, Mihai Letia, Nuno Preguiça, and Marc Shapiro, 2009.

Guaranteeing eventual consistency by constraining your data structure, rather than adding heavyweight distributed algorithms. FlockDB works this way.

partitioning

Scaling Online Social Networks Without Pains , Josep M. Pujol, Georgos Siganos, Vijay Erramilli, and Pablo Rodriguez, 2010.

Optimally partitioning overlapping graphs through lazy replication. Think of applying this technique at a cluster level, not just a server level.

There's a better version of this paper titled "The Little Engines That Could"; I'll update the post when it's generally available.

Feeding Frenzy: Selectively Materializing Users' Event Feeds, Adam Silberstein, Jeff Terrace, Brian F. Cooper, and Raghu Ramakrishnan, 2010.

Judicious session management and application of domain knowledge allow for optimal high-velocity mailbox updates in a memory grid. Twitter's timeline system works this way.

systems integration

Dapper, a Large-Scale Distributed Systems Tracing Infrastructure, Benjamin H. Sigelman, Luiz André Barroso, Mike Burrows, Pat Stephenson, Manoj Plakal, Donald Beaver, Saul Jaspan, and Chandan Shanbhag, 2010.

Add a transaction-tracking, sampling profiler to a reusable RPC framework and get full stack visibility without performance degradation.

Happy scaling. Make sure to read the original post if you haven't.

back to top

webshell: A console-based JavaScripty web client utility (using node.js):

If you’re like me, you probably spend a good deal of time using cURL from the console or Hurl on the web to test/inspect/debug HTTP stuffs. Wanting something a bit more robust and console-friendly Evan Haas and Sean Coates have created Webshell.

Webshell is built on Node.js (of which we’re big fans), and gives you a simple console to load and debug HTTP calls, follow 302 redirects, store history, process JSON, and more:

To run, clone the project and then fire up the shell with Node:

node shell.js 

Then you’re all set to start making HTTP requests:

webshell> GET http://google.com/
HTTP 301 http://google.com/
webshell> $_.headers
{ location: 'http://www.google.com/'
, 'content-type': 'text/html; charset=UTF-8'
, date: 'Sun, 08 Aug 2010 22:38:23 GMT'
, expires: 'Tue, 07 Sep 2010 22:38:23 GMT'
, 'cache-control': 'public, max-age=2592000'
, server: 'gws'
, 'content-length': '219'
, 'x-xss-protection': '1; mode=block'
, connection: 'close'
}
webshell> $_.headers.location
'http://www.google.com/'
webshell> $_.follow()
HTTP 302 http://www.google.com/
webshell> $_.headers.location
'http://www.google.ca/'
webshell> $_.follow()
HTTP 200 http://www.google.ca/
webshell> $_.raw.substring(0, 50)
'<!doctype html>

back to top
Posted 27 days ago at Intridea - Company Blog

This week Twitter launched the official “Tweet Button,” a button for website owners to count RT’s and let readers easily share content. Mashable was first to report on this shiny new button, but we’re the first to release a tweet-button gem for your next project.

Introducing tweet-button

A new Ruby on Rails gem/plugin to generate shiny new Twitter buttons.

image provided via Mashable.com

Usage

First, include the TweetButton module into your application helper. After that, using it is as simple as adding a single method call to your views:

<%= tweet_button %>

Bam. Done. You’ll have a sweet lookin’ Tweet button all up in your view.

Of course, you can customize it. The method takes a few options. Any default can be overridden universally.

:url - The URL to share; the default is the current URL.
:text - The text that will appear in the tweet; the default is "Check this out!"
:via - The attribution. Defaults to "tweetbutton", but you should change that.
:lang - Set the language for the tweet (no default).
:related - Related Twitter accounts (no default).
:count - The tweet count box position (values can be "none", "horizontal", or "vertical"; default is "vertical").

So, if you wanted to tweet about Hacker News, attribute it to Peter Cooper, and add some custom text, all from a tweet button with a horizontal counter, you’d do this:

<%= tweet_button(:via => "peterc", :url => "http://news.ycombinator.com", :text => "AWESOME.")

Simple enough, eh? Also, this method call will include the Twitter JavaScript into the page (it only does it once, even if you have multiple buttons on the page). To put this wherever you’d like (i.e., your header), then use the twitter_widgets_js_tag method. If you call this method, it will place the tag wherever you call it from (and only place it there; subsequent calls do nothing).

The gem also supports the custom Twitter share links. To generate one, use the custom_tweet_button (aliased to custom_tweet_link also) method:

<%= custom_tweet_button %>

This will generate a link that will link to the share page with the same default options as the standard Tweet Button generator. You can customize your custom link with text as the first argument, the same options as tweet_button (with the exception of the count parameter, which will be ignored) as the second, and HTML options as a third argument. For example:

<%= custom_tweet_button('Tweet it!', {:via => "myself"}, {:class => "tweet-sharey-thing"})

Setting universal defaults

You can set a new default for any option by setting default_tweet_button_options in your application helper. For example:

module ApplicationHelper
  include TweetButton

  TweetButton.default_tweet_button_options = {:via => "myself"}
end

Only the options you specify will be overridden; so if you only specify a new default +:via+ (which you should definitely do), then the other defaults will stay intact.

Coming Soon

Tweet Buttons can also live in an iframe, so we’ll probably be adding that very soon!

Plan on using this gem?

If you plan on using this gem, please let us know in the comments section! We’d love to check it out :-)

back to top
Posted 27 days ago at Jay Fields' Thoughts

I'll admit it, the first thing I like to do when learning a new language is fire up a REPL. However, I'm usually ready for the next step after typing in a few numbers, strings and defining a function or two.

What feels like centuries ago, Mike Clark wrote an article about using unit testing to learn a new language. Mike was ahead of his time. This blog entry should help you if you want to follow Mike's advice.

Luckily, Clojure has built in support for simple testing. (I'm currently using Clojure 1.2, you can download it from clojure.org)

Before we get started, let's make sure everything is working. Save a file with the following clojure in it and run* it with clojure.

(ns clojure.test.example
(:use clojure.test))

(run-all-tests)
If everything is okay, you should see something similar the following output.
Testing clojure.walk

Testing clojure.core

(a bunch of other namespaces tested)

Testing clojure.zip

Ran 0 tests containing 0 assertions.
0 failures, 0 errors.
If you've gotten this far, you are all set to start writing your own tests. If you are having any trouble, I suggest logging into the #clojure IRC chat room on Freenode.net

The syntax for defining tests is very simple. The following test verifies that 1 + 1 = 2. You'll want to add the test after the ns definition and before the (run-all-tests) in the file you just created.
(deftest add-1-to-1
(is (= 2 (+ 1 1))))
Running the test should produce something similar to the following output.
Testing clojure.walk

Testing clojure.test.example

(a bunch of other namespaces tested)

Ran 1 tests containing 1 assertions.
0 failures, 0 errors.
We see all of the standard clojure namespaces; however, we see our namespace (clojure.test.example) in the results as well. The output at the bottom also tells us that 1 test with 1 assertion was executed.

The following example shows testing a custom add function. (we will add additional tests from here, without ever deleting the old tests)
(defn add [x y] (+ x y))

(deftest add-x-to-y
(is (= 5 (add 2 3))))
If everything goes to plan, running your tests should now produce the following text towards the bottom of the output.
Ran 2 tests containing 2 assertions.
0 failures, 0 errors.
At this point you might want to pass in a few different numbers to verify that add works as expected.
(deftest add-x-to-y-a-few-times
(is (= 5 (add 2 3)))
(is (= 5 (add 1 4)))
(is (= 5 (add 3 2))))
Running the tests shows us our status
Ran 3 tests containing 5 assertions.
0 failures, 0 errors.
This works perfectly fine; however, clojure.test also provides are for verifying several values.

The following example tests the same conditions using are.
(deftest add-x-to-y-a-using-are
(are [x y] (= 5 (add x y))
2 3
1 4
3 2))
And, the unsurprising results.
Ran 4 tests containing 8 assertions.
That's a simple are; however, you can do whatever you need in the form. Let's grab the value out of a map as an additional example.
(deftest grab-map-values-using-are
(are [y z] (= y (:x z))
2 {:x 2}
1 {:x 1}
3 {:x 3 :y 4}))
Leaving us with
Ran 5 tests containing 11 assertions.
The is and are macros will be all that you need for 90% of all the tests you'll ever want to write. For additional assertions and more details you can check out the clojure.test documentation.

Advanced Topics (very unnecessary to get started)

I get annoyed with noise in my test results. Our results have been very noisy due to the namespace reporting. The run-all-tests function takes a regular expression (documented here). We can change our test running call to include a regular expression, as the following example shows.
(run-all-tests #"clojure.test.example")
Once we switch to providing a regular expression the results should be limited to the following output.

Testing clojure.test.example

Ran 5 tests containing 11 assertions.
0 failures, 0 errors.
This approach works fine for our current sample file; however, it seems like a better solution would be to stop reporting namespaces that do not contain any tests. The following snippet changes the report multimethod to ignore namespaces that don't contain any tests.
(defmethod report :begin-test-ns [m]
(with-test-out
(when (some #(:test (meta %)) (vals (ns-interns (:ns m))))
(println "\nTesting" (ns-name (:ns m))))))
If you're just getting started, don't worry you don't need to understand what's going on in that snippet. I've copied the original report method and made it conditional by adding the code in bold. As a result, the namespace is only printed if it contains any tests.

Now that our results are clean, let's talk about ways of getting those results.

Adding calls to the run-all-tests function isn't a big deal when working with one namespace; however, you'll need to get clever when you want to run a suite of tests. I've been told that leiningen and Maven have tasks that allow you to run all the tests. You might want to start there. I don't currently use either one, and I'm lazy. I don't want to set up either, especially since all I want to do is run all my tests.

It turns out it's very easy to add a shutdown hook in Java. So, as a simple solution, I run all my tests from the Java shutdown hook.
(.addShutdownHook
(Runtime/getRuntime)
(proxy [Thread] []
(run []
(run-all-tests))))
In general, I create a test_helper.clj with the following code.
(ns test-helper
(:use clojure.test))

(defmethod report :begin-test-ns [m]
(with-test-out
(if (some #(:test (meta %)) (vals (ns-interns (:ns m))))
(println "\nTesting" (ns-name (:ns m))))))

(.addShutdownHook
(Runtime/getRuntime)
(proxy [Thread] []
(run []
(run-all-tests))))
Once you've created a test_helper.clj you can use test-helper (just like you used clojure.test) (example below) and your tests will automatically be run on exit, and only namespaces with tests will be included in the output.

It's worth noting that some clojure.contrib namespaces seem to include tests, so in practice I end up using a regular expression that ignores all namespaces beginning with "clojure"** when running all tests. With all of those ideas combined, I find I can execute all my tests or only the tests in the current namespace very easily.

Below you can find all the code from this entry.

clojure.test.example.clj
(ns clojure.test.example
(:use clojure.test test-helper))

(deftest add-1-to-1
(is (= 2 (+ 1 1))))

(defn add [x y] (+ x y))

(deftest add-x-to-y
(is (= 5 (add 2 3))))

(deftest add-x-to-y-a-few-times
(is (= 5 (add 2 3)))
(is (= 5 (add 1 4)))
(is (= 5 (add 3 2))))

(deftest add-x-to-y-a-using-are
(are [x y] (= 5 (add x y))
2 3
1 4
3 2))

(deftest grab-map-values-using-are
(are [y z] (= y (:x z))
2 {:x 2}
1 {:x 1}
3 {:x 3 :y 4}))
test_helper.clj
(ns test-helper
(:use clojure.test))

(defmethod report :begin-test-ns [m]
(with-test-out
(if (some #(:test (meta %)) (vals (ns-interns (:ns m))))
(println "\nTesting" (ns-name (:ns m))))))

(.addShutdownHook
(Runtime/getRuntime)
(proxy [Thread] []
(run []
(run-all-tests))))

* Running a clojure file should be as easy as: java -cp /path/to/clojure.jar clojure.main -i file.to.run.clj

** (run-all-tests #"[^(clojure)].*") ; careful though, now your clojure.test.example tests will be ignored. Don't let that confuse you.

back to top
Posted 27 days ago at JustinFrench.com - notebook

After promising we’re “deliciously close to a 1.0” for about a year, this has been a long time coming.

Formtastic 1.0 is compatible with Rails 2.x. For those of you working with Rails 3, there’s a rails3 branch (aiming to be compatible with both Rails 2.x and 3.x) on Github, and we hope to ship a 1.1.0.beta gem in the next week or so from this branch.

From here on, I’d like to adhere Semantic Versioning.

If you haven’t been playing with the betas and release candidates (shame on you!), here’s a quick re-cap of what’s changed since 0.9.10:

  • Fixed that :label=>false didn’t disable the label on checkboxes & radio buttons
  • Added full support of :input_html options for hidden fields
  • Fixed that :checked_value and :unchecked_value options were being passed down into the HTML tags as attributes
  • ensure i18n < 0.4 is listed as a dependency in the gemspec
  • Added :ignore_date option to time inputs
  • Fixed some issues with the default error proc
  • Added default escaping of html entities in labels and hints
  • Added/fixed that :value_method and :label_method were being ignored for simple collections (like an Array)
  • Added some more compatibility for Mongoid and other ORMs by checking for reflection information before calling it
  • Fixed deprecation warnings in Rails 2.3.6 and newer
  • Fixed a bug where :check_boxes and :radio inputs were using the attribute name instead of the :label option
  • Fixed a conflict where i18n lookups were failing when an attribute and model have the same name
  • Fixed :radio and :check_boxes inputs so that the legend no longer includes a <label> with a for attribute pointing to an input that doesn’t exist
  • Fixed that some inputs had invalid find_options HTML attribute
  • Fixed that we were calling html_safe! when it was not always available
  • Added the ability for :input_html to now accept an option of :size => nil, to exclude the :size attribute altogether

The really exciting thing for me is that there’s been over 60 contributors to the project. Tools like Github make this easier, but real people donating their time actually makes it work.

The community is almost entirely responsible for the rails3 branch too — I started using it for the first time on a new project last month and it was so great to see how far along we are, and most importantly, how little I had to do myself to make it happen.

So, thank you all for the support, the bug reports, the patches, the testing, the polishing, the feature requests, the rants, the complaining, the praise, the promotion, the donations and the awesomeness.

back to top

html5-boilerplate: Best practices starting point project for HTML5 and mobile web apps:

While HTML5 is expanding in definition to include any whizz-bang feature in the post rounded corner web era, implementing actual HTML5 in your web app can be confusing. It’s a fast moving landscape that touches everything from traditional web apps to mobile.

Paul Irish, the Google Chrome dev relations guy who gave us the bulletproof syntax for @font-face, brings us his HTML5 Boilerplate a great tutorial/starting point for implementing a number of best practices in your desktop and mobile web applications including

  • HTML5 <!doctype> and CSS reset
  • Handheld stylesheets
  • CSS media queries for advanced mobile device targeting (even portrait or landscape layouts)
  • Paul’s Modernizr script for detecting device capabilities such as Modernizr.video.ogg

The current version is heavily documented. Paul promises a more slim, production ready version soon.

[Source on GitHub]

back to top

smoothie: Lightweight JavaScript library for smooth real-time charts in the browser:

Providing real-time, smoothly updating charts in the browser is a challenge. London-based developer Joe Walnes has tackled the problem with Smoothie Charts, a lightweight JavaScript library that uses to do just that.

Screenshot

A quick example from the project homepage:

// Randomly add a data point every 500ms
var random = new TimeSeries();
setInterval(function() {
  random.append(new Date().getTime(), Math.random() * 10000);
}, 500);

function createTimeline() {
  var chart = new SmoothieChart();
  chart.addTimeSeries(random, { strokeStyle: 'rgba(0, 255, 0, 1)', fillStyle: 'rgba(0, 255, 0, 0.2)', lineWidth: 4 });
  chart.streamTo(document.getElementById("chart"), 500);
}

[Source on GitHub] [Homepage]

back to top

placeholder: Placeholder images for your wireframes:

If you do a great deal of wireframing, then you know the tedium of creating placeholder images for adds, banners, and other fixed items. Adam and I are big fans of Placehold.it for creating placeholder images.

Placeholder from Matt Darby gives you a neat Ruby interface to the service without having to remember URL format.

sudo gem install placeholder

Now we can generate the following placeholder image: Sample placeholder image

with the following Ruby:

= Placeholder.new(:size => 400, :text => "The Changelog", :fg_color => "fff", :bg_color => "333")

[Source on GitHub]

back to top
Posted 28 days ago at RubyLearning Blog

Ruby Programming and Education: A Match Made in Heaven

Ruby programming has received much attention in the past decade or so, especially with the advent of Ruby on Rails in 2005. While the blogosphere is abuzz with the latest on Ruby, let’s ask ourselves how, exactly, Ruby programming is conducive to an educational environment.

Of course, we could go into the relevance of Ruby programming, since if you’re receiving training in an educational environment to become a computer programmer, and you don’t know Ruby, then you are increasingly being left out of the loop so to speak. However, programming languages come and go, and education isn’t about trends; it’s about ideas that maintain value because they last.

Let’s then look at the philosophy behind Ruby programming and see how it is conducive to learning. For one, Ruby is flexible. It doesn’t have the rigidity of Java or PHP. In an environment that maximizes learning, flexibility is key. And Ruby is as flexible as they come. Yukihiro Matsumoto, the first creator of Ruby, noted what he was thinking about when he first began working on the programming language: “It’s kind of funny; when I used to develop in PHP or the stuff I did in Java, I was always looking for something else.”

Another great thing about Ruby is the enhanced capacity for creativity. As many Ruby users have noted, Ruby is more closely aligned with human thought. In this way, it’s much easier to use. And precisely because it’s easier to use, it’s more versatile when it comes to being creative.

A Ruby Programming slide show explains how Ruby enables creativity. It asserts that human beings lose productivity when they are stressed by “repetitive tasks, unnecessarily complex tasks, and by resolving problems that are not within the application domain.” Since Ruby effectively rids itself of these repetitive, machine-like tasks, there is more space opened up to be creative. With students especially, creative production is the key to learning effectively.

An aspect of the learning process that is absolutely critical to educational effectiveness is fun. We usually don’t think about fun when we think about education. But think back to your own school years. If you think carefully, you’ll know that the subjects that you learned the most and retained the most were those in which you were having fun. This fun of course, stems in part from creativity. When you are being productive, you are enjoying yourself.

Unlike other programming languages, you can do a lot with Ruby even if you are just in the initial learning stages. For students, the learning process is frustrating and hampered when little mistakes get in the way of picking up on bigger concepts. Whereas using programming languages like C++ can trip up the student easily because small mistakes in code cause the entire process to malfunction, Ruby doesn’t have these little first-time learner bumps.

Of course, these are just basic ways in which Ruby is the best learning tool for those interested in computer programming, especially beginners. However, just as in education as a whole, in which basic conceptual changes to the learning process lead students to better practices in learning, so too, does Ruby offer the possibility of easy, fun, creative learning by simple virtue of how the language itself is set up to work. In the final analysis, Ruby was made for students, both young and old, beginner and more advanced.

This guest post is contributed by Kate Cunningham, who writes on the topics of online university rankings. She welcomes your questions and comments at her email Id: cn.kate1 [at] gmail.com.

Technorati Tags: Ruby, Programming

back to top
Favorite
Posted 28 days ago at ones zeros majors and minors

I really love when checkbox labels are done properly.

To see what I mean click on this checkbox's text label ("Click Me!"):

Click Me!

<input type="checkbox"> Click Me!

Nothing happened, right? Right.

Now click on this checkbox's text label:

Click Me!

<label><input type="checkbox"> Click Me!</label>

Yep, awesome. Here's another way to do it (in case your <label> and <input> tags are far apart):

Click Me!

<input type="checkbox" id="ckbx"> <label for=ckbx">Click Me!</label>

back to top

Lemonade - Generates sprites on the fly with Compass and Sass:

One of the best ways to optimize your stylesheets and improve your site performance is to use CSS sprites. A CSS sprite is the technique of stitching together many images into a larger image and managing the placement using CSS background positioning. The upside is you save many network calls for your image assets. The downside is the complexity of creating the sprite.

Enter Lemonade from Nico Hagenburger. Lemonade is a Compass plugin that creates CSS sprites on-the-fly without Photoshop or ImageMagick.

To install, just install the gem:

sudo gem install lemonade

and then add the plugin to your Compass config:

# in config.rb
require 'lemonade'

You’re then all set to start creating sprites in your Sass:

.logo {
  background: sprite-image("lemonade/lemonade-logo.png");
}
.lime {
  background: sprite-image("lemonade/lime.png");
}
.coffee {
  background: sprite-image("other-drinks/coffee.png") no-repeat;
}

which yields

.logo {
  background: url('/images/lemonade.png');
}
.lime {
  background: url('/images/lemonade.png') 0 -26px;
}
.coffee {
  background: url('/images/other-drinks.png') no-repeat;
}

Nifty. Check out some advanced features on Nico’s blog post.

Technically, a better name might have been Lymonade, but this project is refreshing just the same.

[Source on GitHub]

back to top
Posted 28 days ago at Ruby Inside

In "So You Want To Be a Ruby Dev" Kevin W Gisi presents a tongue in cheek narrative of a new Ruby developer being guided through the choices they have to make. (It's being discussed on Hacker News too - some good comments there.)

He asks a lot of questions: Which Ruby implementation to use? Which Web framework? Which Gems? Which version of Rails should you use? Which database adapter? And he caps it off with a conclusion of sorts:

Remember when Ruby and Rails was about getting stuff done? Note: New developers, Ruby is still a great place to be - even if there is an overabundance of choice at the moment.

Kevin W Gisi

I like Kevin and I saw merit in his satirical tale (for without any merit something is not satire), but right away my gut felt his conclusion was bogus. I wondered.. is there another problem here or does Ruby really suffer from an overabundance of choice?

If we're talking about the number of tools, implementations, or libraries, no. Abundance is Ruby's strength. It's the TIMTOWTDI (There Is More Than One Way To Do It) philosophy Ruby inherited from Perl, in contrast to Python's preference for only one obvious way to complete an operation. It's Ruby canon that Matz designed Ruby to be a fun programming language for himself but, also, a language flexible enough to adapt to other people's fancies and preferences. Rather than all of us reading from the same hymn sheets, we can bend, bolt onto, and monkey patch Ruby to fit our own personal or team preferences. This approach has its (much discussed) failings, but it's a philosophy nonetheless.

The overabundance is in the options we present

Still, I detected truth in Kevin's narrative. I realized, though, that it's not that Ruby is no longer about "getting stuff done" or that there's an "overabundance of choice" in libraries or tools. The problem is that Ruby's documentation, main advocacy sites, and even most sites for popular Ruby libraries (with one major exception - coming later) try too hard to demonstrate freedom, flexibility and choice from the get go without giving an opinionated, direct instructional approach for newcomers (e.g. on the official Ruby download page, the first thing you see is a link to Ruby's source code).

We need to be more specific in our READMEs and Web sites where we can and think about what a smart newcomer would want to see. We need "Getting Started" or "For Newcomers" pages that tell people exactly what to do without bending over backwards to cover edge cases or show off esoteric features. Tours that don't take diversions. Download X. Type Y. Run code Z. Instructing, rather than showing a smorgasbord of options, from which a new, confused user would choose none. Rather than offer 5 vaguely different alternatives on a "How To Install" page, give the simplest, most generic route, then discuss the alternatives for "advanced users."

Books are great at this sort of direction. Take almost any instructional Ruby book and even if it's out of date or not doing things "the accepted way", it will take a position and stick to it. Novices can follow along and make smarter judgements later. Let's bring that to our own work too, where we can (and I'm certainly aware there are people who do do this already - that's great!). I'll be going through my own libraries and future blog posts to keep an eye out for this and figure out how a newcomer might perceive them. Satish Talim's RubyLearning blog and courses have proven there's a gigantic population of people who consider themselves Ruby "newbies" reading what we write - it would be great if any of them could have a defined route to try out almost any library they stumble across.

Rails gets it right

Rails has been good at the instructional approach over the years. The "type this, type that, start a server, and bam, you've got an app" approach has been instrumental in the boom of Rails' popularity. Things like the "build a blog system in 15 minutes" screencasts were huge hits. Even complete non Rubyists could follow the same moves precisely and get the same results which they could then play around with further. Imagine if every good Ruby library had similar resources? (And if Railscasts has done a video for your library or tool and you're not making it a centerpiece of your site or README, sort that out!)

It's easy to forget that when we write about Ruby, the jargon and "do what you like" approach we frequently celebrate can seem alien to even the most intelligent newcomers who may well be used to more structured, directed "do X, then Y, just because" environments. We should provide hard and fast answers for those people, even if we run the risk of being a little wrong from time to time, without jeopardizing the richness of the number of tools, libraries, or implementations that exist.

Update 1: And I'm acutely aware now that Ruby Inside itself is not living up to the ideals professed here. I intend to resolve that. I only came up with this right now ;-)

Update 2: To be fair to Kevin, it seems he shares most of these opinions and that, perhaps, this line of thinking was his ultimate intention, judging by his tweets since he wrote the article.

back to top