Decoupling Data from Presentation

Posted 3 days back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

I’m really happy to see a resurgence in an understanding that writing integration tests that use classes and DOM structure to perform assertions within these tests is typically a bad idea. The DOM structure constantly changes but the data displayed (the stuff we want to assert is present on a page) typically doesn’t.

Why write tests against some markup that a designer may change, sometimes often if he’s iterating over a design? It’ll end up causing everyone headaches and frustration.

How can we mark up our documents without performing assertions against a deep nesting of classes and elements while ensuring our data is displayed properly?

Data attributes.

The browsers I care about support HTML5, so why not start using some of its capabilities to clean up some integration tests?

Imagine this scenario:

Scenario: See the site description on the homepage
  When I am on the homepage
  Then I should see the site description

Simple, straightforward, and each step is a similar level of abstraction.

Now imagine this markup:

<section class="primary-content">
  <header>
    

Welcome to the site!

Insert a witty tagline here

</header>

This product will make your life 100 times better.

</section>

I could write a step like this:

Then "I should see the site description" do
  page.should have_selector("section.primary-content p.description",
                            text: "This product will make your life 100 times better.")
end

This step is asserting that there’s a section element with a class of primary-content who has a child paragraph tag with a class of description that contains the correct text. Classes change. Structure changes. This is begging to be rewritten.

<section data-role="primary-content">
  <header>
    

Welcome to the site!

Insert a witty tagline here

</header>

This product will make your life 100 times better.

</section> Then "I should see the site description" do page.should have_selector("[data-role='primary-content'] [data-role='description']", text: "This product will make your life 100 times better.") end

Now, the step is asserting that there’s an element with a role of description within an element with a role of primary-content that contains the correct text.

XHTML introduced a role attribute, but it’s not present currently in HTML5. Luckily, data attributes are even more flexible and we can use any conventions we like. data-role and data-state are two of my favorites.

Interested in how to write awesome Cucumber steps? Head to my Intro to Test-Driven Rails workshop on March 26th and March 27th where we’ll cover this and other awesome topics on writing great tests!

Presentation: Mobile HTML5

Posted 3 days back at InfoQ Personalized Feed for unregistered user - Register to upgrade!

Scott Davis explains how to prepare a website for mobile devices from small tweaks –smaller screen sizes, portrait/landscape- to using HTML5’s local storage, application cache, and remote data. By Scott Davis

Interview: All things Hadoop

Posted 3 days back at InfoQ Personalized Feed for unregistered user - Register to upgrade!

In this interview Ted Dunning talk about Hadoop, its current usage and its future. He explains the reasons for Hadoop's success and make recommendations on how to start using it. By Ted Dunning

Customising ActiveRecord's attribute formatting on inspect

Posted 4 days back at blah blah woof woof articles

We all know that you can change how a Ruby object is represented textually through the inspect method. ActiveRecord::Base provides a useful out-of-the-box implementation of inspect that allows you to see the content of all of a record’s attributes:

>> Gig.last
=> #<Gig id: 123, name: "ICELAB presents Ruby: A Rock Opera in 1.9.3 Thrilli...", starts_at: "2012-03-03 09:30:00", capacity: 750, available_ticket_numbers: nil, sold_ticket_numbers: nil, created_at: "2012-01-19 06:47:02", updated_at: "2012-01-19 06:47:02">

What you might not know is that ActiveRecord provides a hook for you to customise how each of these attributes is formatted in this inspect output. Let’s see how it is used in ActiveRecord::Base#inspect:

# Returns the contents of the record as a nicely formatted string.
def inspect
  attributes_as_nice_string = self.class.column_names.collect { |name|
    if has_attribute?(name) || new_record?
      "#{name}: #{attribute_for_inspect(name)}"
    end
  }.compact.join(", ")
  "#<#{self.class} #{attributes_as_nice_string}>"
end

You’ll see that it iterates over each of the attributes and passes them through attribute_for_inspect(name). This is also a public method that truncates a string if it is longer than 50 characters, shows dates in their DB-native UTC format, the otherwise just calls inspect on whatever the attribute value is.

Why would you want to customise this? We have an ActiveRecord with a few columns where we are serializing large arrays to the database

class Gig < ActiveRecord::Base
  serialize :available_ticket_numbers
  serialize :sold_ticket_numbers
end

This can lead to some very messy console output:

>> Gig.last
=> #<Gig id: 123, name: "ICELAB presents Ruby: A Rock Opera in 1.9.3 Thrilli...", starts_at: "2012-03-03 09:30:00", capacity: 750, available_ticket_numbers: nil, sold_ticket_numbers: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", "112", "113", "114", "115", "116", "117", "118", "119", "120", "121", "122", "123", "124", "125", "126", "127", "128", "129", "130", "131", "132", "133", "134", "135", "136", "137", "138", "139", "140", "141", "142", "143", "144", "145", "146", "147", "148", "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", "160", "161", "162", "163", "164", "165", "166", "167", "168", "169", "170", "171", "172", "173", "174", "175", "176", "177", "178", "179", "180", "181", "182", "183", "184", "185", "186", "187", "188", "189", "190", "191", "192", "193", "194", "195", "196", "197", "198", "199", "200", "201", "202", "203", "204", "205", "206", "207", "208", "209", "210", "211", "212", "213", "214", "215", "216", "217", "218", "219", "220", "221", "222", "223", "224", "225", "226", "227", "228", "229", "230", "231", "232", "233", "234", "235", "236", "237", "238", "239", "240", "241", "242", "243", "244", "245", "246", "247", "248", "249", "250", "251", "252", "253", "254", "255", "256", "257", "258", "259", "260", "261", "262", "263", "264", "265", "266", "267", "268", "269", "270", "271", "272", "273", "274", "275", "276", "277", "278", "279", "280", "281", "282", "283", "284", "285", "286", "287", "288", "289", "290", "291", "292", "293", "294", "295", "296", "297", "298", "299", "300", "301", "302", "303", "304", "305", "306", "307", "308", "309", "310", "311", "312", "313", "314", "315", "316", "317", "318", "319", "320", "321", "322", "323", "324", "325", "326", "327", "328", "329", "330", "331", "332", "333", "334", "335", "336", "337", "338", "339", "340", "341", "342", "343", "344", "345", "346", "347", "348", "349", "350", "351", "352", "353", "354", "355", "356", "357", "358", "359", "360", "361", "362", "363", "364", "365", "366", "367", "368", "369", "370", "371", "372", "373", "374", "375", "376", "377", "378", "379", "380", "381", "382", "383", "384", "385", "386", "387", "388", "389", "390", "391", "392", "393", "394", "395", "396", "397", "398", "399", "400", "401", "402", "403", "404", "405", "406", "407", "408", "409", "410", "411", "412", "413", "414", "415", "416", "417", "418", "419", "420", "421", "422", "423", "424", "425", "426", "427", "428", "429", "430", "431", "432", "433", "434", "435", "436", "437", "438", "439", "440", "441", "442", "443", "444", "445", "446", "447", "448", "449", "450", "451", "452", "453", "454", "455", "456", "457", "458", "459", "460", "461", "462", "463", "464", "465", "466", "467", "468", "469", "470", "471", "472", "473", "474", "475", "476", "477", "478", "479", "480", "481", "482", "483", "484", "485", "486", "487", "488", "489", "490", "491", "492", "493", "494", "495", "496", "497", "498", "499", "500", "501", "502", "503", "504", "505", "506", "507", "508", "509", "510", "511", "512", "513", "514", "515", "516", "517", "518", "519", "520", "521", "522", "523", "524", "525", "526", "527", "528", "529", "530", "531", "532", "533", "534", "535", "536", "537", "538", "539", "540", "541", "542", "543", "544", "545", "546", "547", "548", "549", "550", "551", "552", "553", "554", "555", "556", "557", "558", "559", "560", "561", "562", "563", "564", "565", "566", "567", "568", "569", "570", "571", "572", "573", "574", "575", "576", "577", "578", "579", "580", "581", "582", "583", "584", "585", "586", "587", "588", "589", "590", "591", "592", "593", "594", "595", "596", "597", "598", "599", "600", "601", "602", "603", "604", "605", "606", "607", "608", "609", "610", "611", "612", "613", "614", "615", "616", "617", "618", "619", "620", "621", "622", "623", "624", "625", "626", "627", "628", "629", "630", "631", "632", "633", "634", "635", "636", "637", "638", "639", "640", "641", "642", "643", "644", "645", "646", "647", "648", "649", "650", "651", "652", "653", "654", "655", "656", "657", "658", "659", "660", "661", "662", "663", "664", "665", "666", "667", "668", "669", "670", "671", "672", "673", "674", "675", "676", "677", "678", "679", "680", "681", "682", "683", "684", "685", "686", "687", "688", "689", "690", "691", "692", "693", "694", "695", "696", "697", "698", "699", "700", "701", "702", "703", "704", "705", "706", "707", "708", "709", "710", "711", "712", "713", "714", "715", "716", "717", "718", "719", "720", "721", "722", "723", "724", "725", "726", "727", "728", "729", "730", "731", "732", "733", "734", "735", "736", "737", "738", "739", "740", "741", "742", "743", "744", "745", "746", "747", "748", "749", "750", created_at: "2012-01-19 06:47:02", updated_at: "2012-01-19 06:47:02">

That’s a lot of noise. Most of the time, it just gets in the way when we’re trying to work with our records. If we ever wanted to inspect the content of such an attribute, we could just address it directly.

To clean this up in one shot across our entire application, we can override attribute_for_inspect. Put this in a file in lib/ somwhere and require it from your config/application.rb:

module ActiveRecord
  class Base
    alias_method :attribute_for_inspect_before_extension, :attribute_for_inspect
    def attribute_for_inspect(attr_name)
      value = read_attribute(attr_name)

      if value.kind_of?(Array) && value.length > 4
        (value[0..1] + ["... #{value.length - 4} elements ..."] + value[-2..-1]).inspect
      else
        attribute_for_inspect_before_extension(attr_name)
      end
    end
  end
end

This checks for any array attributes and gives them a shortened output if they contain more than five elements:

>> Gig.last
=> #<Gig id: 123, name: "ICELAB presents Ruby: A Rock Opera in 1.9.3 Thrilli...", starts_at: "2012-03-03 09:30:00", capacity: 750, available_ticket_numbers: nil, sold_ticket_numbers: ["1", "2", "... 746 elements ...", "749", "750"], created_at: "2012-01-19 06:47:02", updated_at: "2012-01-19 06:47:02">

Much neater. We get tidier inspect output without having to override ActiveRecord’s otherwise useful inspect altogether. Depending on your app, I’d imagine you could extend it in many different ways to clean up your time on the console.

PostgreSQL and Neo4J Are Making Their Way into the Cloud

Posted 4 days back at InfoQ Personalized Feed for unregistered user - Register to upgrade!

PostgreSQL and Neo4J, a relational and a graph database respectively, are among the latest data stores taking the route to the cloud. By Abel Avram

Rails 3.2.1

Posted 5 days back at The Ruby Show

Jason and Peter talk about the new Rails 3.2.0 and 3.2.1 releases, upcoming conferences, project updates, and more.

net-http-persistent 2.4

Posted 5 days back at Segment7

net-http-persistent version 2.4 has been released!

Manages persistent connections using Net::HTTP plus a speed fix for Ruby 1.8. It’s thread-safe too!

Using persistent HTTP connections can dramatically increase the speed of HTTP. Creating a new HTTP connection for every request involves an extra TCP round-trip and causes TCP congestion avoidance negotiation to start over.

Net::HTTP supports persistent connections with some API methods but does not handle reconnection gracefully. Net::HTTP::Persistent supports reconnection and retry according to RFC 2616.

2.4 / 2012-01-31

  • Minor Enhancement

    • net-http-persistent now complains if OpenSSL::SSL::VERIFY_PEER is equal to OpenSSL::SSL::VERIFY_NONE. If you have a platform that is broken this way you must define the constant:

      I_KNOW_THAT_OPENSSL_VERIFY_PEER_EQUALS_VERIFY_NONE_IS_WRONG = nil

      at the top level of your application to disable the warning.

  • Bug fix

    • Fix persisting SSL sessions through HTTP proxies. Mechanize issue #178 by Robert Poor, net-http-persistent issues #10, #11.

Automating Fixture Instantiation in Mocha using Async

Posted 5 days back at A Programmer's Perspective

My latest Node.JS project has been entirely test-driven and I always strive to write very simple & concise tests. Convoluted code in a test will be far less likely to be maintained. So when test driving my latest model, I (…)

Read the rest of this entry »

Episode #242 - January 31, 2012

Posted 5 days back at Ruby5

In 3.2.1, we Devise a way to run Ruby 1.9.2 on Heroku, by using a 30% Faster Kookaburra that we Resqued during a recent trip Cross-Country - it's all in this episode of Ruby5.

Listen to this episode on Ruby5

This episode is sponsored by Top Ruby Jobs
If you're looking for a Ruby job or for top Ruby talent, then you should check out Top Ruby Jobs. Top Ruby Jobs is a website dedicated to the best jobs available in the Ruby community.

Devise 2.0 has been released
Over the weekend, Devise 2.0 was released. This new version only supports Rails 3.1+, but adds support for email reconfirmation, better support for Rails Engines, and more. There's a wiki page available to help with the upgrade, as well.

Running Ruby 1.9.3 on Heroku’s Cedar stack
Late last week, Daniel Kehoe created a tutorial on getting Rails 3.2 running on Heroku, with additional detail about how to get it running on Ruby 1.9.3. This seems like extremely useful information, so we thought we'd share it.

Acceptance and Integration Testing with Kookaburra
Last week Sam Livingston-Gray sent in an email letting us know about a testing library called Kookaburra, which is a framework for implementing the window driver pattern to keep your acceptance tests maintainable. If your acceptance tests are becoming brittle or unmaintainable, maybe this is worth a look.

30% faster boot time in Ruby 1.9.3-p0 in one line
Burke Libbey has put together several performance-oriented patches, from Sokolov Yura and Samuel Cochran, for Ruby 1.9.3-p0 into a single Gist which can be installed with just one line of code. After the gist patches have been applied, people are reporting significantly faster Rails boot times. The gist contains install instructions for rvm and rbenv.

Rails 3.2.1 has been released
Late last week, Rails 3.2.1 was released to address a few regression issues introduced in 3.2.0 and add more documentation to new or changed features. Otherwise, this release shouldn't introduce anything new, and therefore, is bug free. ;)

Separate Your Resque Workers with simple_resque
Mike Subelsky recently released simple_resque, which is a gem that allows you to split your application’s Resque workers apart from your web application code. This could allow you to separate your asynchronous workers onto different machines and better grow your application.

CSS Cross-Country
Just this morning, Code School released CSS Cross-Country, which is a foundation course in CSS, covering floats, specificity, display types, positioning, sprites, pseudo classes, and more.

Peekaboo

Posted 5 days back at Mike Clark

Peekaboo

I've been studying this wild bobcat for the past few months. This weekend he hopped up on this rock to play a bit of peekaboo with me.

(Comments: Flickr)

Undo-Redo Frameworks For WPF and Silverlight

Posted 5 days back at InfoQ Personalized Feed for unregistered user - Register to upgrade!

Undo and Redo are commands that are commonly expected by end users and, when well implemented, can improve an application's usability significantly. At least two libraries exist that can help WPF and Silverlight developers for this purpose - a recently announced Undo-Redo framework from Infragistics (CTP) and an open source library called Undo. By Roopesh Shenoy

The Wefunder Petition

Posted 6 days back at zerosum dirt(nap) - Home

Kickstarter is awesome for funding creative projects. It’s one of my favorite startups at the moment, and it’s important. I lurves it. But I wish I could use something like it to invest in actual companies – both the tech startup variety that my friends work tirelessly on as well as the hyper local variety that make those special tapas that my neighbors are raving about.

Soon, new laws may allow us to do just that.

To raise awareness of these initiatives, a few friends and I tossed together the Wefunder petition to support HR2930 and Brown’s Democratizing Access to Capital Act (S.1791) that’s currently being debated in the US Senate. Please go sign it (click the “learn more” link on the site for more background information and links).

These changes could have huge impacts for both entrepreneurs and investors, allowing bold new ideas to surface and creating a ton of important jobs and opportunities. I know that sounds like marketing speak, but it’s true. This matters.

We’ll be going to DC next week to talk to Senator Brown’s people and see what else we can do to push this forward. We’ve also been fortunate enough to get some great coverage for our efforts at BoingBoing and ReadWriteWeb.

Now go sign it already and help us send a message. And thanks!

Bitmap Marking GC for Ruby Improves Memory Usage

Posted 6 days back at InfoQ Personalized Feed for unregistered user - Register to upgrade!

The successor of Ruby 1.9.3 will replace the current Lazy Sweep Garbage Collector with a Bitmap Marking GC, which will significantly reduce Ruby's memory usage for parallel programs, similar to Ruby Enterprise Edition's copy-on-write-friendly GC. We talked with Narihiro Nakamura who implemented both the current Lazy Sweep and the Bitmap Marking GC. By Mirko Stocker

Mini book: Good Relationships

Posted 7 days back at InfoQ Personalized Feed for unregistered user - Register to upgrade!

With Spring Data, the ever popular Spring Framework has cultivated a new patch of ground, bringing Big Data and NOSQL technology like Neo4j to enterprise developers. This guide introduces you to Spring Data Neo4j, using the fast, powerful and scalable graph database Neo4j to enjoy the benefits of having good relationships in your data. By Michael Hunger

#320 Jbuilder

Posted 7 days back at Railscasts

Jbuilder provides a DSL for generating JSON. It includes a template engine which allows you to create complex responses with helpers and conditions.