Custom 404 error page with Rails 4

Posted 24 days back at The Pug Automatic

This is what I did to get a custom 404 error page on Rails 4, without replacing the default 500 and 422 error pages.

There are other solutions where you just use the router as the exceptions app, but then you have to handle those other errors as well.

It’s very much based on this Gist by Turadg Aleahmad, but with some cleanup and fixes.

Code changes

Remove the default public/404.html to avoid any collisions.

Modify these files like so:

<figure class="code"><figcaption>config/application.rb</figcaption>
# …

module NameOfMyApp
  class Application < Rails::Application
    # …

    require Rails.root.join("lib/custom_public_exceptions")
    config.exceptions_app = CustomPublicExceptions.new(Rails.public_path)
  end
end
</figure> <figure class="code"><figcaption>config/routes.rb</figcaption>
Rails.application.routes.draw do
  match "/404" => "errors#error404", via: [ :get, :post, :patch, :delete ]

  # …
end
</figure>

Add these files:

<figure class="code"><figcaption>lib/custom_public_exceptions.rb</figcaption>
class CustomPublicExceptions < ActionDispatch::PublicExceptions
  def call(env)
    status = env["PATH_INFO"][1..-1]

    if status == "404"
      Rails.application.routes.call(env)
    else
      super
    end
  end
end
</figure> <figure class="code"><figcaption>app/controllers/errors_controller.rb</figcaption>
class ErrorsController < ApplicationController
  def error404
    render status: :not_found
  end
end
</figure> <figure class="code"><figcaption>app/views/errors/error404.erb</figcaption>
<p>Sorry! No such page!</p>
</figure>

Verify in development

To see the page in development, just visit /404.

If you see the default Rails 404 page, you probably forgot to remove public/404.html.

If you want to make sure it actually works, change config/environments/development.rb to say

<figure class="code">
# Do not commit!
config.consider_all_requests_local = false
</figure>

instead of true.

Just don’t keep that value, since you’ll get less helpful errors in development, and you’ll also disable the /rails/info/properties page with debug info.

Tests

I haven’t been able to figure out a way to do production-style error handling in a single test, so I settled for this:

<figure class="code"><figcaption>spec/features/errors_spec.rb</figcaption>
require "rails_helper"

describe "404 page" do
  it "is customized" do
    # Haven't been able to get the "show instead of exceptions" thing working in tests, but this at least makes sure the page can render correctly.
    visit "/404"
    expect(page.status_code).to eq 404
    expect(page).to have_content("Sorry!")
  end
end
</figure>

UNION with Active Record

Posted 24 days back at The Pug Automatic

I wanted to do a UNION query in Active Record, combining the results of two subqueries.

This is how I did it in Rails 4.1.5 with Postgres:

<figure class="code">
items = category.items
query1 = items.some_scope
query2 = items.other_scope

# Get a real category_id instead of "$1" in the generated SQL.
sql = Item.connection.unprepared_statement {
  "((#{query1.to_sql}) UNION (#{query2.to_sql})) AS items"
}

Item.from(sql).order("we_can_add_an_order_if_we_like ASC")
</figure>

The generated query will be something like

<figure class="code">
SELECT items.*
  FROM ((SELECT ) UNION (SELECT )) AS items
  ORDER BY we_can_add_an_order_if_we_like ASC;
</figure>

This is of course not guaranteed to be fast just because it’s raw SQL.

Consider UNION vs. UNION ALL, benchmark as needed, and use multiple queries or Ruby code if that’s faster or more readable in your situation.

Maintenance Friday 29th at 10pm EST

Posted 25 days back at entp hoth blog - Home

We will have a routine maintenance for Lighthouse this Friday 29th at 10pm EST. It should last about 30 mins, hopefully less.

Go enjoy your friday night!

Cheers.

Episode #492 - August 27, 2014

Posted 26 days back at Ruby5

In today's episode we cover the new Rails 4.2beta, JSON API Resources, Country Select 2.0, Harpoon, Poodr course learning, and Feature Focus all while riding in our Roles Royce.

Listen to this episode on Ruby5

Sponsored by Top Ruby Jobs

If you're looking for a top 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.
Top Ruby Jobs

Rails 4.2beta1 Released

The Rails core team has just released Rails 4.2beta1 on August 20th. This includes a lot of new features such as the ActiveJob interface, ActionMailer#deliver_later method, Adequate Record and the Rails Web console.
Rails 4.2beta1 Released

Royce

The Royce gem, by Martin Nash is a new library to add roles on your ActiveRecord models.
Royce

Introducing JSON API Resources

JSON API Resources is a framework by Dan and Larry Gebhardt for developing a server that complies with the JSON API Specification. JSON API Resources requires little more than a definition of your resources including their attributes and relationships to make them compliant with the near 1.0 JSON API release.
Introducing JSON API Resources

Country Select Gem 2.0

Adam Anderson reached out to let us know about the country_select gem just hitting 2.0. A lot of libraries depend on this library, like simple_form and formtastic. This new release includes a number of breaking changes to increase i18n compatibility. You’ll want to stick with version 1 until you’re ready to do an upgrade, there’s some differences around how countries are stored.
Country Select Gem 2.0

Deploying Static Sites to S3 with Harpoon

Harpoon is a simple static site deployment tool by Ryan Quinn. It has a lot of the same features you're used to with Capistrano.
Deploying Static Sites to S3 with Harpoon

I Spent 3 Days with Sandi Metz, here’s what I learned

Jack Hoy attended one of Sandi Metz 3 day long POODR Ruby courses, and he wrote up a great blog post about some of the core principles he took away from the course.
I Spent 3 Days with Sandi Metz, here’s what I learned

Code School Groupon Feature Focus

On Thursday last week Code School released the 5th episode in the Feature Focus series. In the 5th episode we implement geolocation features seen on Groupon.com and then go on location at Groupon HQ in Chicago to get feedback on our implementation.
Code School Groupon Feature Focus

Sponsored by Ruby5

Ruby5 is released Tuesday and Friday mornings. To stay informed about and active with this podcast, we encourage you to do one of the following:

Thank You for Listening to Ruby5

The Case for Buying Technical Books

Posted 27 days back at Jay Fields Thoughts

In the past few months I've seen more than a few articles encouraging programmers to write books. Each article provides at least a bit of good advice, and proceeds to conclude with the same idea:
You should write a book to build your brand.
I find this conclusion accurate and extremely disappointing. If the overwhelming reason to write a book is brand building, then the pool of potential authors is restricted to people who would benefit from brand building (and people who don't value their time).
How Did We Get Here?
The Internet, obviously. Practically everyone knows how to download any movie, song, or book at no cost. Opinions on "illegal downloading" range from opposition to pride. I'm not particularly interested in discussing those opinions; however, I believe it's worth observing the impact of the combination of ability and desire to acquire content without compensating the creator.
“Books aren't written - they're rewritten...” -- Michael Crichton
If you've never written a book, you may not be aware of colossal effort it takes to write a mediocre book. When it's all said and done, it can take well over an hour of effort per page. Great books, such as Java Concurrency in Practice, require an even greater level of attention to detail, and cost even more time to create. Brian Goetz estimates that it took them approximately 2,400 hours to create JCiP. If we also knew their royalty structure and the number of copies sold, we'd be able to calculate the hourly rate for writing a high quality book.
It turns out, one of the recent articles encouraging writing gives you royalty numbers and a hint on how many copies a quality book might sell.
Royalties for print should start at 18% of net revenues to the publisher. (Expect that figure to be around $10-20, so you're only making a few dollars on each sale.)
...
Selling 10 thousand copies of a print tech book these days is a solid success and should be compensated accordingly. -- Obie Fernandez
Let's assume JCiP was more than a solid success and sold 20K copies (doubling Obie's "solid success" benchmark). Assuming they negotiated royalties well, that would mean making $40,000 - thus the hourly rate for writing JCiP would be under $17 per hour.
Clearly I've made a few assumptions, but I believe all of them are based on sound logic. As long as you work 8 hours a day, 5 days a week, for 50 weeks and write a modern classic, you'll make around $34,000 per year. Anecdotal evidence among my author friends who've yet to write a modern classic is worse: the hourly rate is less than minimum wage.
The royalty structures combined with lessening sales create an environment where writing a book for (royalty) profit isn't a reasonable use of your time. As a result, the majority of today's authors are either consultants or unknown programmers. Established, non-consultant programmers gain little from the brand building aspect of writing a book, and likely make far more than $34,000 a year at their full-time jobs - why would they take on a poorly paying second job?
Around 2005 it became fairly easy to download, for free, practically any book. It might be coincidence that 10 of 13 of these Must-Read books were written prior to 2005. Despite the possibility, I don't believe it's a coincidence. Rather, I believe that at one time it paid to create a best selling technical book, and people with various backgrounds took up the challenge.
Nice Assumption Filled History Lesson, What's Your Point?
My point is fairly simple. If you're, like I am, tired of having to choose between books written decades ago and books written by those with at least a slightly ulterior motive, buy some books. Does your company have a book buying policy? If you aren't spending your entire book budget, why not? It costs you nothing to buy a book and give it to a teammate, and every royalty penny reminds an author that someone cares about all of those hours writing and rewriting.
Even if your company doesn't have a book budget, ask yourself if you'd rather your next book about Java be written by a consultant you've never heard of or Java's language architect. The average technical book costs little compared to life's other expenses, and buying a technical book is investing in your profession twice. You stand to gain knowledge both from today's book purchase and a potential future book written by the same author - a future book that may never be written given the current financial incentives.
If you're a CTO, Director or Manager, why aren't you constantly buying books for the developers you work with? They could probably use your advice on which books will best guide their careers.
Makes Sense, What Should I Buy?
There are several good books now available on leanpub - where the authors are paid significantly higher royalties. If you want to support authors you should always start there. From there I would own at least a copy of Chad's (previously referenced) Must-Read books. I'd also buy Chad's Passionate Programmer. Finally, you can't go wrong working your way through this list: Clojure Bookshelf.

Baseimage-docker 0.9.13 released

Posted about 1 month back at Phusion Corporate Blog

Baseimage-docker is a special Docker image that is configured for correct use within Docker containers. It is Ubuntu, plus modifications for Docker-friendliness. You can use it as a base for your own Docker images. Learn more at the Github repository and the website, which explain in detail what the problems are with the stock Ubuntu base image, and why you should use baseimage-docker.

Changes in this release

  • Fixed my_init not properly exiting with a non-zero exit status when Ctrl-C is pressed.
  • The GID of the docker_env group has been changed from 1000 to 8377, in order to avoid GID conflicts with any groups that you might want to introduce inside the container.
  • The syslog-ng socket is now deleted before starting the syslog-ng daemon, to avoid the daemon from failing to start due to garbage on the filesystem. Thanks to Kingdon Barrett. Closes GH-129.
  • Typo fixes by Arkadi Shishlov.

Using baseimage-docker

Please learn more at the README.

The post Baseimage-docker 0.9.13 released appeared first on Phusion Corporate Blog.

Baseimage-docker 0.9.13 released

Posted about 1 month back at Phusion Corporate Blog

Baseimage-docker is a special Docker image that is configured for correct use within Docker containers. It is Ubuntu, plus modifications for Docker-friendliness. You can use it as a base for your own Docker images. Learn more at the Github repository and the website, which explain in detail what the problems are with the stock Ubuntu base image, and why you should use baseimage-docker.

Changes in this release

  • Fixed my_init not properly exiting with a non-zero exit status when Ctrl-C is pressed.
  • The GID of the docker_env group has been changed from 1000 to 8377, in order to avoid GID conflicts with any groups that you might want to introduce inside the container.
  • The syslog-ng socket is now deleted before starting the syslog-ng daemon, to avoid the daemon from failing to start due to garbage on the filesystem. Thanks to Kingdon Barrett. Closes GH-129.
  • Typo fixes by Arkadi Shishlov.

Using baseimage-docker

Please learn more at the README.

The post Baseimage-docker 0.9.13 released appeared first on Phusion Corporate Blog.

Phusion Passenger 4.0.49 released

Posted about 1 month back at Phusion Corporate Blog


Phusion Passenger is a fast and robust web server and application server for Ruby, Python, Node.js and Meteor. Passenger takes a lot of complexity out of deploying web apps, and adds powerful enterprise-grade features that are useful in production. High-profile companies such as Apple, New York Times, AirBnB, Juniper, American Express, etc are already using it, as well as over 350.000 websites.

Phusion Passenger is under constant maintenance and development. Version 4.0.49 is a bugfix release.

Phusion Passenger also has an Enterprise version which comes with a wide array of additional features. By buying Phusion Passenger Enterprise you will directly sponsor the development of the open source version.

Recent changes

  • Upgraded the preferred Nginx version to 1.6.1.
  • Fixed a crash that may be triggered by the passenger_max_requests feature.
  • Introduced the spawn_failed hook, which is called when an application process fails to spawn. You could use this hook to setup an error notification system. Closes GH-1252.
  • Fonts, RSS and XML are now gzip-compressed by default in Phusion Passenger Standalone. Thanks to Jacob Elder. Closes GH-1254.
  • Fixed some user and group information lookup issues. Closes GH-1253.
  • Fixed some request handling crashes. Closes GH-1250.
  • Fixed some compilation problems on Gentoo. Closes GH-1261.
  • Fixed some compilation problems on Solaris. Closes GH-1260.

Installing or upgrading to 4.0.49

OS X OS X Debian Debian Ubuntu Ubuntu
Heroku Heroku Ruby gem Ruby gem Tarball Tarball

Final

Fork us on Github!Phusion Passenger’s core is open source. Please fork or watch us on Github. :)

<iframe src="http://ghbtns.com/github-btn.html?user=phusion&amp;repo=passenger&amp;type=watch&amp;size=large&amp;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="170" height="30"></iframe><iframe src="http://ghbtns.com/github-btn.html?user=phusion&amp;repo=passenger&amp;type=fork&amp;size=large&amp;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="170" height="30"></iframe><iframe src="http://ghbtns.com/github-btn.html?user=phusion&amp;type=follow&amp;size=large&amp;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="190" height="30"></iframe>

If you would like to stay up to date with Phusion news, please fill in your name and email address below and sign up for our newsletter. We won’t spam you, we promise.



Phusion Passenger 4.0.49 released

Posted about 1 month back at Phusion Corporate Blog


Phusion Passenger is a fast and robust web server and application server for Ruby, Python, Node.js and Meteor. Passenger takes a lot of complexity out of deploying web apps, and adds powerful enterprise-grade features that are useful in production. High-profile companies such as Apple, New York Times, AirBnB, Juniper, American Express, etc are already using it, as well as over 350.000 websites.

Phusion Passenger is under constant maintenance and development. Version 4.0.49 is a bugfix release.

Phusion Passenger also has an Enterprise version which comes with a wide array of additional features. By buying Phusion Passenger Enterprise you will directly sponsor the development of the open source version.

Recent changes

  • Upgraded the preferred Nginx version to 1.6.1.
  • Fixed a crash that may be triggered by the passenger_max_requests feature.
  • Introduced the spawn_failed hook, which is called when an application process fails to spawn. You could use this hook to setup an error notification system. Closes GH-1252.
  • Fonts, RSS and XML are now gzip-compressed by default in Phusion Passenger Standalone. Thanks to Jacob Elder. Closes GH-1254.
  • Fixed some user and group information lookup issues. Closes GH-1253.
  • Fixed some request handling crashes. Closes GH-1250.
  • Fixed some compilation problems on Gentoo. Closes GH-1261.
  • Fixed some compilation problems on Solaris. Closes GH-1260.

Installing or upgrading to 4.0.49

OS X OS X Debian Debian Ubuntu Ubuntu
Heroku Heroku Ruby gem Ruby gem Tarball Tarball

Final

Fork us on Github!Phusion Passenger’s core is open source. Please fork or watch us on Github. :)

<iframe src="http://ghbtns.com/github-btn.html?user=phusion&amp;repo=passenger&amp;type=watch&amp;size=large&amp;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="170" height="30"></iframe><iframe src="http://ghbtns.com/github-btn.html?user=phusion&amp;repo=passenger&amp;type=fork&amp;size=large&amp;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="170" height="30"></iframe><iframe src="http://ghbtns.com/github-btn.html?user=phusion&amp;type=follow&amp;size=large&amp;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="190" height="30"></iframe>

If you would like to stay up to date with Phusion news, please fill in your name and email address below and sign up for our newsletter. We won’t spam you, we promise.



Episode #491 - August 22nd, 2014

Posted about 1 month back at Ruby5

Semaphore is now free for open source projects, URL extraction with PostRank-URI, STI with JSON fields, a different approach to email validation, transit-rails, and the Pixel Perfect Precision Handbook all in this episode of the Ruby5!

Listen to this episode on Ruby5

Sponsored by New Relic

New Relic is _the_ all-in-one web performance analytics product. It lets you manage and monitor web application performance, from the browser down to the line of code. With Real User Monitoring, New Relic users can see browser response times by geographical location of the user, or by browser type.
This episode is sponsored by New Relic

Semaphore Free for OSS

The Semaphore CI service now has a free plan for open source projects!
Semaphore Free for OSS

PostRank URI

Need to parse URLs out of random text or just normalize them? The new postrank-uri gem makes takes all the pain out of it!
PostRank URI

Renewed Life for STI

Have you been avoiding STI all these years, too? The folks at NetGuru are making a case for it again by leveraging the JSON data type in Postgres.
Renewed Life for STI

Email Validation

Email validation discussions usually revolve around format, but what about verifying the MX DNS records of the domain? This blog post explains a very different approach.
Email Validation

transit-rails

Tired of jumping through hoops to use transit format in your Rails app? The transit-rails gem makes it easy!
transit-rails

Pixel Perfect Precision Handbook

If you're baffled by how good design happens, read PPP's free PDF!
Pixel Perfect Precision Handbook

Episode #490 - August 19th, 2014

Posted about 1 month back at Ruby5

We talk about Rails 4.0.9 and 4.1.5, flatten records, introduce Http::Exceptions, manage configurations, and update Devise.

Listen to this episode on Ruby5

Sponsored by Top Ruby Jobs

If you're looking for a top 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.
Top Ruby Jobs

Rails 4.0.9 and 4.1.5

Two new updates to Rails were just released yesterday, Rails 4.0.9 and 4.1.5. These releases affect Rails 4.0 and newer and primarily address issues with insecure parameter handling and the ActiveRecord create_with method.
Rails 4.0.9 and 4.1.5

FlattenRecord

Alvin Ng wrote in to let us know about his latest gem, called FlattenRecord. FlattenRecord’s purpose is to give you a more reasonable way to denormalize or flatten ActiveRecord objects in your application.
FlattenRecord

Introducing Http::Exceptions

Http::Exceptions provides an easy way to rescue exceptions that get thrown by your HTTP library and a way to raise exceptions on unexpected HTTP status codes.
Introducing Http::Exceptions

Configurations

If you’re a gem author, you may be interested in a new configuration management library aptly named, configurations. It aims to remove the redundancy of writing those configuration blocks and their support in your Ruby gems while providing some interesting content- and type-checks to the developer-defined configuration values.
Configurations

RailsApps Update for Devise 3.3

Devise 3.3 was recently released. The Devise CHANGELOG lists several minor enhancements and bug fixes. Perhaps a more significant change is new wording for the error messages when a user’s email address or password is incorrect. Take a look at the changed locale file if you’d like to see the new error messages.
RailsApps Update for Devise 3.3

Sponsored by Ruby5

Ruby5 is released Tuesday and Friday mornings. To stay informed about and active with this podcast, we encourage you to do one of the following:

Thank You for Listening to Ruby5

Paid Private Repos for Hound

Posted about 1 month back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

In April, we announced Hound, a hosted service that comments on Ruby style guide violations in your GitHub pull requests. Since then, about 2,000 users have signed up for Hound. We have been hard at work across 127 commits making Hound faster and more reliable. Recently, Hound has been reviewing about 7,000 GitHub pull requests across about 300 GitHub repos each week.

What people are telling us

We have heard from users that their teams are quickly getting on board with Hound. By their nature, formatting issues are quick fixes. By its nature, Hound is in your face. So far, the combination seems effective for actually making positive change in the repo.

Some people are treating Hound as CI in the sense of catching the final 5% of style issues they may have missed locally. These folks may even have RuboCop running locally in their text editor.

Others rely more heavily on a “human memory + Hound” approach, preferring to configure plugins such as Syntastic to focus only on syntax issues, which keeps Vim running fast.

Another group includes style checkers / linters in their test suites. We hope to convince them that style violations should not fail the build, that a system like Hound commenting during code review is the right balance of machine-based feedback and humans making final decisions.

Pricing

As we promised in the launch announcement, we are now charging for private repos. Private personal repos are $9 per month per repo. Private organization repos are $24 per month per repo.

There are no limits on number of users, pull requests, or Hound comments. Public repos are free.

We believe this pricing strategy is low cost compared to the benefits Hound provides. It is tedious, error-prone, and time-consuming for humans to do the menial work of style-checking. Saving even one developer 15-30 minutes each month during code review would make Hound worth paying for.

Based on feedback from users, though, we think we’re saving teams more time than 15-30 minutes each month. By keeping codebases formatted consistently, Hound lowers the cognitive overhead while we read code and lets us focus on higher-level concerns.

Enable Hound on your private repo

Enable Hound on a private repo by clicking the toggle button next to the repo name. When you submit the credit card form, you will be charged for the first month. We will then charge you once a month from the time it was enabled. When you disable a repo, we will stop charging you for it.

Existing private repos

As a thank you to early users, current Hound-enabled private repos will remain free until September 19, 2014. To keep using Hound after that date, please disable and re-enable Hound on your private repos. If you do nothing, you will not be charged and we will automatically disable Hound on uncharged private repos on September 19, 2014.

What’s next?

We are charging for Hound in order to run it sustainably, improve it, make it review other languages such as CoffeeScript, and maintain it. We hope you love it as much as we do.

Thank you for supporting Hound!

Scott's dog wearing a sombrero

Building Ralph with SVG

Posted about 1 month back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

SVG (Scalable Vector Graphic) is a graphic format, similar to PNG or JPEG, that’s great for icons, charts and supporting high-DPI displays. They’re vector-based, so you won’t lose visual fidelity or see any pixelation, no matter what size your graphic is. Because it’s written in XML, you can mark it up just like HTML and modify it with other languages like Javascript or CSS.

Let’s build a robot

SVGs are typically made up of objects, like shapes and paths. Let’s start by building something simple like Ralph’s head. Here’s our full logo in SVG for reference:

Open your favorite text editor and create a new file. Start with an empty <svg> element and define its XML namespace:

<svg xmlns="http://www.w3.org/2000/svg">
</svg>

To start creating a graphic, we can add a simple rectangle by specifying a height, width and fill color.

<svg xmlns="http://www.w3.org/2000/svg">
  <rect height="60" width="100" fill="#B32317" />
</svg>

Save that file, open it in a web browser, and you should see something like this:

We can round the corners of the rectangle with rx and ry attributes. These attribute should always be the same if you want a circular corner.

...
<rect height="60" width="100" rx="10" ry="10" fill="#B32317" />
...

Just like the <rect> element, SVG has a <circle> element. We’ll use that for the eyes.

...
<circle cx="26" cy="26" r="10" fill="#000000"></circle>
<circle cx="74" cy="26" r="10" fill="#000000"></circle>
...

As you can see, circles and rectangles have different attributes. The cx and cy attributes are the x and y coordinates of the center of the circle, respectively. The coordinate system has the origin at the top/left with the x-axis pointing to the right and the y-axis pointing down. The r attribute is the radius of the circle.

To keep your code more organized, SVG has a <g> element, similar to HTML’s <div>, that you can use for grouping. These elements are a great place to add classes for styling or manipulating later.

While we’re at it, let’s change the fill attribute on the circles to #FFFFFF so they will show up on the red rectangle better.

<svg xmlns="http://www.w3.org/2000/svg">
  <g class="head">
    <rect height="60" width="100" rx="10" ry="10" fill="#B32317" />
    <g class="eyes">
      <circle cx="26" cy="26" r="10" fill="#FFFFFF"></circle>
      <circle cx="74" cy="26" r="10" fill="#FFFFFF"></circle>
    </g>
  </g>
</svg>

Starting to look more familiar…

Add a couple more circles, and we’ve got ourselves a robot head:

...
<circle cx="26" cy="26" r="7" fill="#B32317"></circle>
<circle cx="74" cy="26" r="7" fill="#B32317"></circle>
...

Working with SVG in the real world

Hand writing SVGs like this rarely makes sense. Exporting an SVG you’ve already made in a vector graphics application is much quicker. An example workflow using Sketch, an OS X-only vector graphics app:

  • Select the shape or group you want to export as SVG.

  • Click “Make Exportable” in the lower right corner.

  • Find “SVG” in the dropdown and click “Export”.

Although Sketch doesn’t give you insight into the code it produces, it exports relatively clean SVG files. Next, you take the outputted code and paste it into the page you’re working on. Here is an example:

Here’s a gist of that code, so you can see what it will look like when you’ve exported a more complex shape. Now that you can export SVGs from an application and have a basic understanding of how the attributes work, you can start to modify them with Javascript or CSS.

Episode #489 - August 15th, 2014

Posted about 1 month back at Ruby5

Dokkufy, Rails Helpers, JRuby, Xiki and DHH code review

Listen to this episode on Ruby5

Sponsored by NewRelic

NewRelic recently announced that they joind the Cloud Security Alliance to Promote SaaS Security
NewRelic

Your mini-Heroku with Dokku and Dokkufy

Cristiano Betta has released the Dokkufy gem
Your mini-Heroku with Dokku and Dokkufy

Rails Misapprehensions: Replace Helpers With View Models!

Nick Sutterer says Cells view models are better then Rails Helpers
Rails Misapprehensions: Replace Helpers With View Models!

JRuby: The Hard Parts

Charles Nutter has shared a slide deck entitled JRuby: The Hard Parts
JRuby: The Hard Parts

Xiki Kickstarter

Xiki is most then a shell, its the simplest way to create interactive interfaces with text in and text out
Xiki Kickstarter

Basecamp: Search

Gregg Pollack and Carlos Souza have released a Feature Focus video as they walk you through their creation of a Basecamp search functionality.
Basecamp: Search

Write a Vim Plugin with TDD

Posted about 1 month back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

My colleague Chris Toomey and I are writing a Vim plugin called vim-spec-runner that runs RSpec and JavaScript tests. We’re test-driving it and learned a lot.

Vimrunner

We’re using the excellent vimrunner Ruby gem. It provides a Ruby interface to run arbitrary commands in Vim by hooking into Vim’s client-server architecture. If Vim was compiled with +clientserver, you can launch a Vim process that acts as a command server, with a client that sends commands to it. Vimrunner launches a Vim server and then sends your commands to it.

We discovered that terminal Vim doesn’t work with vimrunner, but MacVim works perfectly. Vimrunner will pick up MacVim if it’s installed, so all you have to do is brew install macvim. If you’re using Linux/BSD, it might work out of the box, but we haven’t tried it.

Here’s how to use Vimrunner to sort a file:

VimRunner.start do |vim|
  vim.edit "file.txt"
  vim.command "%sort"
end

Vimrunner also comes with some neat RSpec helpers. You can look at vim-spec-runner’s full spec_helper, but here are the important bits:

require "vimrunner"
require "vimrunner/rspec"

ROOT = File.expand_path("../..", __FILE__)

Vimrunner::RSpec.configure do |config|
  config.reuse_server = true

  config.start_vim do
    vim = Vimrunner.start
    vim.add_plugin(File.join(ROOT, "plugin"), "spec-runner.vim")
    vim
  end
end

First, we require vimrunner and vimrunner/rspec, for RSpec support. Then we set the ROOT constant to the directory containing the plugin directory. We then configure Vimrunner’s RSpec integration:

  • config.reuse_server = true: Use the same Vim instance for every spec.
  • config.start_vim: This block is used whenever Vimrunner needs a new Vim instance. We’re using it to always add our plugin to the vim instance.

Customizing RSpec

We use RSpec’s custom matchers quite a bit in our specs. They reduce the amount of code we have to write and make our tests much more readable.

Here’s an example:

it "does not create a mapping if one already exists" do
  using_vim_without_plugin do |clean_vim|
    clean_vim.edit "my_spec.rb"
    clean_vim.command "nnoremap <Leader>x <Plug>RunCurrentSpecFile"
    load_plugin(clean_vim)

    expect(clean_vim).to have_no_normal_map_from("<Leader>a")
  end
end

using_vim_without_plugin and load_plugin are both plain Ruby methods defined in our main spec file. Here’s the have_no_normal_map_from matcher:

RSpec::Matchers.define :have_no_normal_map_from do |expected_keys|
  match do |vim_instance|
    mapping_output(vim_instance, expected_keys) == 'No mapping found'
  end

  failure_message_for_should do |vim_instance|
    "expected no map for '#{expected_keys}' but it maps to something"
  end

  def mapping_output(vim_instance, expected_keys)
    vim_instance.command "nmap #{expected_keys}"
  end
end

The outer block variable, expected_keys, is what we pass to expect, while the block variable for match is what we pass to the have_no_normal_map_from method.

We define failure_message_for_should so that if there is a mapping, we get a useful, human-formatted error message.

Travis CI

It took some work, but we got our plugin running on Travis CI. Vimrunner needs a Vim that was compiled with +clientserver, so we install the vim-gnome Ubuntu package. Vimrunner also needs an X server, so we use xvfb to start up a headless X environment. Here’s the result:

before_install:
  - "sudo apt-get update"
  - "sudo apt-get install vim-gnome"
  - "vim --version"
install: bundle
script: xvfb-run bundle exec rspec --format documentation

We use the --format documentation option to RSpec so we can see exactly which test failed on Travis. You can see our full .travis.yml file here and a sample test run here.

What’s next?

Try out vim-spec-runner! If you want to add tests to your own Vim plugin, check out the full spec file.