Skip to main content

Mobomo webinars-now on demand! | learn more.

I really like using MongoDB and Mongoid, but a while back I ran into some shortcomings with querying timestamps. The problem was that I wanted to query only part of a timestamp, such as the day, week or year. So for example, let's say we need to find all users that signed up on a Wednesday.

In SQL there are date functions that let you to parse dates inside your query (although they seem to vary between engines). So in Postgres, you could do something like this:

select * from users where extract(dow from created_at) = 3; 

Note: Wednesday is the 3rd day of the week.

But MongoDB doesn’t have any native support for parsing a date/time inside the query. The best you can do is compare ranges, like this example using Mongoid:

User.where(:created_at.gte => "2012-05-30", :created_at.lt => "2012-05-31") 

Great, that finds us all users created last Wednesday. But what about all users created on any Wednesday, say in 2012? That would typically require building a query with different ranges for every Wednesday in 2012. Talk about tedious and repetitive. I think it’s safe to say that when faced with such a task most developers will end up just looping over each user, comparing the dates in Ruby.

User.scoped.select { |u| u.created_at.wday == 3 && u.created_at.year == 2012 } 

Eeek! This might work with small collections, but once you have a bunch of users it’s sub-optimal.

So I know I just said there were no native date functions in Mongo. But recently I was excited to find a solution that kind of works. It turns out that date/time types in Mongo get stored as UTC datetimes, which are basically just javascript dates stored in BSON. So it’s possible to drop down into javascript in your query using $where. With Mongoid it might look something like this:

User.where("return this.created_at.getDay() == 2 && this.created_at.getFullYear() == 2012") 

Note: in Javascript the day of week starts with 0 instead of 1. So Wednesdays are 2.

Now things seem to be looking up for us. But alas, the MongoDB documentation for $where warns of major performance issues. This makes sense because what’s really happening here is each user record is still getting accessed and each date is still getting parsed with javascript. Furthermore, we can’t index our search. So this solution is probably only marginally better than looping over each record in Ruby.

What I really wanted was a way to query by just day of week, or month, or hour, minute, second, etc. And I decided the best way to accomplish that would be to parse each timestamp before it gets saved, and then store all the additional timestamp metadata along with the record. That way I could query timestamp parts just like any other field, with no parsing. And as an added bonus, it should be even faster than using the native date functions with SQL!

So I started thinking of all the fields I would want to store, and I came up with the following list:

  • year
  • month
  • day
  • wday
  • hour
  • min
  • sec
  • zone
  • offset

But that’s a lot of fields cluttering up our model, especially if we’re storing two different timestamps like a created_at and updated_at. Well fortunately this is one area where MongoDB really shines. We can simply nest all this metadata under each timestamp field as BSON. And since we’re using Mongoid, we can also override the serialize and deserialize methods to make the interface behave just like a regular time field. So this is where the idea for the mongoid-metastamp gem came from. Here’s a simple usage example:

class MyEvent   include Mongoid::Document   field :timestamp, type: Mongoid::Metastamp::Time end  event = MyEvent.new event.timestamp = "2012-05-30 10:00" 

Now, calling a timestamp field returns a regular time:

event.timestamp => Wed, 30 May 2012 10:00:00 UTC +00:00 

But you can also access all the other timestamp metadata like this:

event['timestamp'] => {"time"=>2012-05-30 10:00:00 UTC, "year"=>2012, "month"=>5, "day"=>30, "wday"=>3, "hour"=>10, "min"=>0, "sec"=>0, "zone"=>"UTC", "offset"=>0} 

Now at last, we can performantly search for all Wednesday events in 2012:

hump_days = MyEvent.where("timestamp.wday" => 3, "timestamp.year" => 2012) 

If you were paying close attention you may have also noticed that zone is included in the metadata. That's because Mongoid Metastamp has some powerful features that allow you to store and query timestamps relative to the local time they were created in. But I’ll have to write more about that in a follow up post.

Categories
Author

Twitter popularized the term "firehose API", to mean a realtime stream of data sent through a persistent connection. But even if you're not a realtime service, streaming APIs are great for pushing data from the backend to clients. They reduce resource usage because the server can decide when it's a good time to send a incremental chunk of data. They can also improve the responsiveness of your user experience. The same HTTP API can be reused to power multiple different apps. For example, you could write your web frontend with a Javascript frameworks like Backbone.js, but reuse the same API to power a native iOS application. Follow the jump to read about how streaming APIs work, and how you can write one with Rack::Stream.

TL;DR

Rack::Stream is rack middleware that lets you write streaming API endpoints that understand HTTP, WebSockets, and EventSource. It comes with a DSL and can be used alongside other rackable web frameworks such as Sinatra and Grape.

What's Streaming HTTP?

Normally, when an HTTP request is made, the server closes the connection when it's done processing the request. For streaming HTTP, also known as Comet, the main difference is that the server doesn't close the connection and can continue sending data to the client at a later time.

normal http

streaming http

To prevent the connection from closing, rack-stream uses Thin's 'async.callback' to defer closing the connection until either the server decides to close the connection, or the client disconnects.

Rack::Stream

Rack::Stream is rack middleware that lets you write streaming HTTP endpoints that can understand multiple protocols. Multiple protocols means that you can write an API endpoint that works with curl, but that same endpoint would also works with WebSockets in the browser. The simplest streaming API you can make is:

# config.ru # run with `thin start -p 9292` require 'rack-stream'  class App   def call(env)     [200, {'Content-Type' => 'text/plain'}, ["Hello", " ", "World"]]   end end  use Rack::Stream run App 

If you ran this basic rack app, you could then use curl to stream it's response:

> curl -i -N http://localhost:9292/  HTTP/1.1 200 OK Content-Type: text/plain Transfer-Encoding: chunked Connection: close Server: thin 1.3.1 codename Triple Espresso  Hello World 

This isn't very exciting, but you'll notice that the Transfer-Encoding for the response is set to chunked. By default, rack-stream will take any downstream application's response bodies and stream them over in chunks. You can read more about chunked transfer encoding on Wikipedia.

Let's spice it up a bit and build an actual firehose. This next application will keep sending data to the client until the client disconnects:

require 'rack-stream'  class Firehose   include Rack::Stream::DSL    def call(env)     EM.add_periodic_timer(0.1) {       chunk "nChunky Monkey"     }     [200, {'Content-Type' => 'text/plain'}, ['Hello']]   end end  use Rack::Stream run Firehose 

The first thing to notice is the Firehose rack endpoint includes Rack::Stream::DSL. This are convenience methods that allow you to access env['rack.stream'], which is injected into env whenever you use Rack::Stream. When a request comes in, the #call method schedules a timer that runs every 0.1 seconds and uses the #chunk method to stream data. If you run curl, you would see:

> curl -i -N http://localhost:9292/  HTTP/1.1 200 OK Transfer-Encoding: chunked Connection: close Server: thin 1.3.1 codename Triple Espresso  Hello Chunky Monkey Chunky Monkey Chunky Monkey # ... more monkeys 

rack-stream also allows you to register callbacks for manipulating response chunks, and controlling when something is sent with different callbacks. Here's a more advanced example with callbacks added:

require 'rack-stream'  class Firehose   include Rack::Stream::DSL    def call(env)     after_open do       chunk "nChunky Monkey"       close  # start closing the connection     end      before_chunk do |chunks|       chunks.map(&:upcase)  # manipulate chunks     end      before_close do       chunk "nGoodbye!"  # send something before we close     end      [200, {'Content-Type' => 'text/plain'}, ['Hello']]   end end  use Rack::Stream run Firehose 

If you ran curl now, you would see:

> curl -i -N http://localhost:9292/  HTTP/1.1 200 OK Transfer-Encoding: chunked Connection: close Server: thin 1.3.1 codename Triple Espresso  HELLO CHUNKY MONKEY GOODBYE! 

For details about the callbacks, see the project page.

Up until this point, I've only used curl to demonstrate hitting the rack endpoint, but one of the big benefits of rack-stream is that it'll automatically recognize WebSocket and EventSource requests and stream through those as well. For example, you could write an html file that accesses that same endpoint:

<html> <body>   <script type='text/javascript'>     var socket       = new WebSocket('ws://localhost:9292/');     socket.onopen    = function()  {alert("socket opened")};     socket.onmessage = function(m) {alert(m.data)};     socket.onclose   = function()  {alert("socket closed")};   </script> </body> </html> 

Whether you access the endpoint with curl, ajax, or WebSockets, your backend API logic doesn't have to change.

For the last example, I'll show a basic chat application using Grape and Rails. The full runnable source is included in the examples/rails directory.

require 'grape' require 'rack/stream' require 'redis' require 'redis/connection/synchrony'  class API < Grape::API   default_format :txt    helpers do     include Rack::Stream::DSL      def redis       @redis ||= Redis.new     end      def build_message(text)       redis.rpush 'messages', text       redis.ltrim 'messages', 0, 50       redis.publish 'messages', text       text     end   end    resources :messages do     get do       after_open do         # subscribe after_open b/c this runs until the connection is closed         redis.subscribe 'messages' do |on|           on.message do |channel, msg|             chunk msg           end         end       end        status 200       header 'Content-Type', 'application/json'       chunk *redis.lrange('messages', 0, 50)       ""     end      post do       status 201       build_message(params[:text])     end   end end 

This example uses redis pubsub to push out messages that are created from #post. Thanks to em-synchrony, requests are not blocked when no messages are being sent. It's important do the redis subscribe after the connection has been opened. Otherwise, the initial response won't be sent.

What about socket.io?

socket.io is great because it provides many transport fallbacks to give maximum compatibility with many different browsers, but its pubsub interface is too low level for capturing common app semantics. The application developer doesn't have nice REST features like HTTP verbs, resource URIs, parameter and response encoding, and request headers.

The goal of rack-stream is to provide clean REST-like semantics when you're developing, but allow you to swap out different transport protocols. Currently, it supports normal HTTP, WebSockets, and EventSource. But the goal is to support more protocols over time and allow custom protocols. This architecture allows socket.io to become another protocol handler that can be plugged into rack-stream. If you wanted to use Pusher as a protocol, that could also be written as a handler for rack-stream.

Summary

rack-stream aims to be a thin abstraction that lets Ruby developers write streaming APIs with their preferred frameworks. I plan to broaden support and test against common use cases and popular frameworks like Sinatra and Rails. If you have any questions or comments, feel free to submit an issue or leave a comment below!

Categories
Author

Hey RailsConf goers! You won't want to miss Jerry Cheung, co-author of (the just-released) MacRuby in Action book and Senior Engineer at Intridea present "Evented Ruby vs Node.js" Tuesday afternoon!

While Node.js is the hot new kid on the block, evented libraries like EventMachine for Ruby and Twisted for Python have existed for a long time. When does it make sense to use one over the other? What are the advantages and disadvantages to using node over ruby? In this talk, you will learn how to get the same power of concurrency enjoyed by Node.js while continuing to write in the language you know and love. Topics covered will include pubsub with redis or faye, building evented rack applications, and running evented applications alongside existing Rails apps.

Jerry will be in Salon K at 2:30 pm tomorrow.

Keep it weird, Austin Rails!

Categories
Author

This post is a part of Polishing Rubies, an end-to-end guide to Ruby open source development.

« Back to Part 3: Tools for Testing

Can you believe it? It's actually time to start writing the code for your gem! Now, in this part of the guide you'll be more "on your own" than up to this point. I don't know what kind of open source library you're writing, whether it's an extension to an existing library, a simple utility, or a complex, sprawling project that will change the face of development forever. What I do know, however, is that there are some common things that you may want to do that have community best practices attached.

File Structure, Naming, and Requirement

While it may not seem vital, how you name your files and where you put them can be a critical component of your library's ease of use for developers. This is particularly true because on a GitHub repository page one can simply press t and start typing a filename, then look at the code for that file by pressing return. This is the way that many people will try to take a quick peek at the internals of your gem, so by creating sane, easily guessable filenames you are making it simple for others to read your code.

In general, you will have one class per file and one folder per module namespace, so for instance:

  • MyGem becomes lib/my-gem.rb (this is a special case, see part 2)
  • MyGem::Widget becomes lib/my_gem/widget.rb
  • MyGem::Widgets::FooBar becomes lib/my_gem/widgets/foo_bar.rb

There are, however, a few corner cases in which each class may not have its own file. One is a private class that is meant to be used only internally and only in the scope of another class. Another are the exception classes for your library. We will cover exception classes in the next section.

When a developer wants to use your library, they should be able to do so (in almost all cases) by making a single require statement that is identical to the gem name. That means that in the root file you need to make any additional require statements necessary for your gem to function. So if I have a MyGem module, a MyGem::Widget class, and a MyGem::Widgets::FooBar class, the lib/my-gem.rb file in my gem might look like this:

require 'external_library' # require any external dependencies  module MyGem # it is best to declare the base module at the top end  require 'my_gem/version' # created by Bundler require 'my_gem/widget' require 'my_gem/widgets/foo_bar' 

By requiring all of the files necessary for your gem to run in the base file you make it easier for developers to use your library. Some gems, however, may be made up of multiple parts that could be used independently of each other. ActiveSupport, for example, provides a large number of useful utilities that, while they function together, can also function separately.

If I add require 'active_support' to my code I load all of ActiveSupport. While this may be what I want in some cases (like inside a Rails application) in other cases I may just want a specific piece of ActiveSupport. Luckily, ActiveSupport is designed to handle this well. If I, for instance, add require 'active_support/core_ext' I will only be loading the Ruby core extensions that are a part of ActiveSupport.

How can you make this work in your library? It's quite simple: your base file should, when required, require all the other parts of your library. However, each part of your library should, at its top, require any other parts or external dependencies so that it may be included without the user having previously required the base file. Let's take a look at an example:

# in lib/my-gem.rb  require 'my_gem/widget' require 'my_gem/widgets/foo_bar' reuqire 'my_gem/widgets/baz'  # in lib/my_gem/widget.rb  require 'external_library'  module MyGem   class Widget   end end  # in lib/my_gem/widgets/foo_bar  require 'my_gem/widget'  module MyGem   module Widgets     class FooBar < MyGem::Widget     end   end end 

Each of the files in the above example can be required independently, giving developers the flexibility to use only a subset of your library's functionality if needed. Remember that require statements will only load the code from a file once, so it is safe to require the same file multiple times.

Exception Classes

As a library author you are creating a black box: you tell developers how to send messages to the box, the box sends messages back, but a well-designed library does not expose internal implementation details to its end users. In service of creating a properly bounded library, your application should only raise errors that you allow it to raise.

Sometimes you will be able to use existing error classes. For instance, if you might raise an ArgumentError if invalid parameters are passed to a method in your library or a NotImplementedError if you are building some kind of abstract interface. Many times, however, you will want to create one or more custom exception classes to provide insight into what happened when things go wrong.

Exception classes usually end up in one of two places in a library: either in the base file (lib/my-gem.rb) or, if there are more than one or two error classes, all together in a file such as lib/my_gem/errors.rb. It is entirely possible to create a custom exception class in a single line:

module MyGem   class Error < StandardError; end end 

This allows you to raise out an error that can be caught by users of your library when exceptions occur:

raise MyGem::Error, "This is the error message." 

If you wish to create more than one custom exception class, it is a good practice to have a single base MyGem::Error class and several subclasses underneath it. This way, users of your library can rescue from any exception it might generate simply with rescue MyGem::Error.

One other thing you might want to do is store some additional information along with an error; for instance, in an API client library if you receive a non-success status code you may want to include the HTTP response so that more information can be obtained:

module MyGem   class Error < StandardError; end   class ResponseError < MyGem::Error     attr_reader :response      def initialize(response, message)       @response = response       super(message)     end   end end  # Elsewhere...  raise MyGem::ResponseError.new(response, "Invalid response from HTTP client.") 

Because you are providing library code you will usually want to wrap any internal exceptional scenarios with your own exception class. For instance, if there is a method that you call from another library that will sometimes raise exceptions, you should rescue from those exception classes and wrap it into your own:

module MyGem   class SomeClass     def some_method       ExternalLibrary.dangerous_method_call     rescue ExternalLibrary::Error => e       raise MyGem::Error, "Some dangerous method call didn't work."     end   end end 

Proper exception handling makes your library well-encapsulated and easy to use and also helps your users to report issues when they occur.

Library Configuration

Oftentimes in a library there is various "root-level" configuration that may need to be performed. There are lots of different ways to handle such configuration (including a number of gems that you can depend upon to do the heavy-lifting) but, with a little bit of elbow grease, you can write your own configuration class that is robust without being cumbersome.

To begin, let's create a new file lib/my_gem/configuration.rb that will contain our configuration class. Now let's fill it up:

module MyGem   class Configuration     attr_accessor :option1, :option2      def initialize(config = {})       config.each_pair do |key, value|         self.send("#{key}=", value)       end     end   end end 

This gets us started with two configuration options (:option1 and :option2) and can be used like so:

config = MyGem::Configuration.new(option1: 'foo', option2: 'bar') config.option1 # => 'foo' config.option1 = 'baz' config.option1 # => 'baz' 

As you can see, this gives us the beginnings of what we might want from library configuration: there are a few different options, we can read and write each option individually and we can also initialize their values with a hash. So what might we want next? Well, it's usually best to explicitly define default options we might have:

module MyGem   class Configuration     DEFAULT_CONFIGURATION = {       option1: 'foo',        option2: nil     }      attr_accessor :option1, :option2      def initialize(attributes = {})       DEFAULT_CONFIGURATION.merge(attributes).each_pair do |attribute, value|         self.send("#{attribute}=", value)       end     end   end end 

That was easy enough: our default options are set as a constant beneath our Configuration class, and we then merge in the options that are passed to the constructor to bootstrap our configuration. Note also that in this example :option2 is defaulted to nil. Each option should be given an explicit default value so that developers who are reading your code know all of the options that are available.

Next up we will make our Configuration class friendly to people who want to use block-style declarative configuration:

module MyGem   class Configuration     DEFAULT_CONFIGURATION = {       option1: 'foo',        option2: nil     }      attr_accessor :option1, :option2      def initialize(attributes = {}, &block)       configure(DEFAULT_CONFIGURATION.merge(attributes), &block)     end      def configure(attributes = {})       attributes.each_pair do |attribute, value|         self.send("#{attribute}=", value)       end        yield self if block_given?        self     end   end end 

As you can see we've added a #configure method that takes a hash and sets configuration values or takes a block and yields itself. We also added block-yielding capabilities to the constructor. This allows us to set configuration like so:

c = MyGem::Configuration.new do |config|   config.option1 = 'baz' end  c.option1 # => 'baz'  c.configure do |config|   config.option1 = 'wonk' end  c.option1 # => 'wonk' 

Look familiar? Many gems utilize this block-yielding method of configuration; it's a community pattern and one that is nice and easy to implement. Now that we've built a simple configuration class, we need to hook it into our root module. So let's open up lib/my_gem.rb and add the following:

module MyGem   def self.config     @config ||= Configuration.new   end    def self.configure(attributes = {}, &block)     config.configure attributes, &block   end end 

By memoizing an instance of the configuration class at MyGem.config, we have a single persistent configuration object for our gem. We can now configure our library exactly like many others:

MyGem.configure do |config|   config.option1 = 'bar' end  MyGem.config.option1 # => 'bar' 

Because we support both block-yielding and hashes, we also make it easy for people to use, for instance, a YAML configuration file and pass the relevant configuration in that way.

Keep it Clean

The most important aspect of writing library code is just to write the best code you can write! Every best practice and code style that you've heard of is doubly important when you're writing code meant to be read and used by an entire community of developers. That being said, no library ever ships with perfect code. It's often better to do your best and get something out the door than to hold off and hold off while you tweak things ad infinitum. You can always fix it in the next version!

Categories
Author

This post is a part of Polishing Rubies, an end-to-end guide to Ruby open source development.

« Back to Part 2: Creating a Gem

A good toolchain is important for any development project. It makes the lives of developers easier by abstracting away or automating repetitive tasks. You should always spend some time at the outset of a project making sure you're using all of the best tools available. On an open source project this is 10 times more important.

Instead of building a toolchain that will be used by your company or small team, you're building a toolchain that will potentially be used by dozens, hundreds, or even thousands of other developers. An annoyance that costs five minutes, multiplied by all those developers, equals hours and hours of lost potential productivity. Now that we've bootstrapped the directory structure of our gem, it's time to get our toolchain up and running so that development for you (and all of your contributors some day) is as painless and fast as possible.

Test Setup

Having tests for your gem is fundamentally important. If you have no tests, you have no way to vet incoming pull requests, check for regressions between versions, or really have any control over the quality of your project. Luckily, the Ruby community has a strong testing culture so there are great tools to use and widespread adoption of testing practices.

I'm going to walk through how to set your gem up for testing via RSpec. In general the Ruby community nearly universally uses either RSpec or the built-in Test::Unit as its framework of choice. I would love to cover Test::Unit as well, but I don't have enough of a grasp on best practices to be able to tell you how to do that here. If you would like to contribute such a section to this guide, by all means please fork it on GitHub and I'll be happy to update the content.

The first step to using RSpec in your tests is to add it to your project's gemspec:

gem.add_development_dependency 'rspec', '~> 2.9' 

This tells RubyGems that RSpec is a necessary library for developers who are going to try to contribute to your gem. Once you've added the dependency, run bundle to update your dependencies with Bundler. Note that because Bundler is capable of reading dependencies from a gemspec you don't need to manually specify them in your Gemfile.

With RSpec, it's a good practice to specify the most recent minor version (the second number in the MAJOR.MINOR.PATCH versioning system) for your dependency. This way if RSpec updates to a new major version that breaks existing functionality, you can review any breakages and fix them with a new release of your gem rather than having unstable tests in the wild.

Now that you have RSpec in your project's bundle, you should run bundle exec rspec --init. This is a simple generator that will bootstrap your project's RSpec setup. The output should look something like this:

create   spec/spec_helper.rb create   .rspec 

The .rspec file is an options file that lets you specify the default command-line options (such as output format and color) that will be used by RSpec's runner in your project. If you've written tests before, you should be familiar with spec/spec_helper.rb as a central place to bootstrap your test suite and add any dependent library requires, etc.

Because we're writing a gem we will want to set up our spec_helper.rb file to work with our gem's structure. Alter the file to look like this:

$:.unshift File.dirname(__FILE__) + '/../lib' require 'my-gem'  RSpec.configure do |config|   config.treat_symbols_as_metadata_keys_with_true_values = true   config.run_all_when_everything_filtered = true   config.filter_run :focus end 

The first line adds our gem's lib directory to Ruby's load path. This means that when we say something like require 'some-file' Ruby will automatically look in our gem's lib directory to see if that file exists. The second line, require 'my-gem', is the same line that your end users will type when they want to start using your gem. This allows us to write tests from the perspective of someone who has installed the gem and required it, either manually or automatically through a tool like Bundler.

Now that we have our spec_helper all set up, let's go ahead and create our first spec. Create a file spec/my_gem_spec.rb (replace my_gem with your gem's name) and put this in it:

require 'spec_helper'  describe MyGem do   it 'requires additional testing' end 

Now simply run the rspec command in your project's root directory. You should see output that looks like this:

Run options: include {:focus=>true}  All examples were filtered out; ignoring {:focus=>true} *  Pending:   MyGem requires additional testing     # Not yet implemented     # ./spec/my_gem_spec.rb:4  Finished in 0.00015 seconds 1 example, 0 failures, 1 pending 

Congratulations! You've got your gem's test suite up and running.

Testing With Rake

Another standard practice amongst all Ruby projects (apps and gems alike) is to make it possible to run the tests for a project via a Rake task. This is remarkably easy; all you need to do is open up the Rakefile in your project's directory and add the following to the bottom of your Rakefile:

require 'rspec/core/rake_task' RSpec::Core::RakeTask.new task :default => :spec 

This does two things: first, it creates a new RSpec rake task that, by default, can be run by typing rake spec at your project's root. Second, we assign the :default task to be :spec. This means that in your project's root you can simply run rake and all of the tests for your project will run. This is a convention in the Ruby community and a good practice for all projects.

To verify everything we've done we can simply run rake -T which is a command to list the available Rake tasks. You should see something like this:

rake build    # Build my-gem-0.0.1.gem into the pkg directory rake install  # Build and install my-gem-0.0.1.gem into system gems rake release  # Create tag v0.0.1 and build and push my-gem-0.0.1.gem to Ru... rake spec     # Run RSpec code examples 

As you can see, we have four tasks available. Three of them are provided to us by Bundler for packaging and releasing our gem, and one of them is provided by RSpec for testing our gem.

Autotesting With Guard

Guard is a gem that allows you to observe your project's files for change and perform actions based on that change. The first thing you will need to do is add Guard (and its helpers for Bundler and RSpec) to the end of your Gemfile:

gem 'guard' gem 'guard-rspec' gem 'guard-bundler' 

Note that, differently from RSpec, I prefer to add Guard and its related gems to my project's Gemfile, not its gemspec. This choice comes down to personal preference, but while RSpec is required for someone to do development on my gem, Guard is really more of a nice to have and so I relax the dependency somewhat. The effect is the same for contributors: simply running bundle in the project's directory will install all of the dependencies from the gemspec and the Gemfile. Speaking of which, you should now run bundle in your project root to install Guard if it isn't already.

Now we need to initialize Guard and configure it for our project. Luckily, Guard comes with its own command line helpers:

guard init guard init bundler guard init rspec 

Guard works similarly to Bundler and Rake by creating a Guardfile in your project's root directory. These commands automatically add example configuration for each guard type to the Guardfile (after guard init creates the file to begin with). While I'm going to tell you explicitly what to put in your Guardfile, the init commands can really help jog your memory if you're trying to do it from scratch. Let's modify our Guardfile to look like this:

guard 'bundler' do   watch('Gemfile')   watch(/^.+.gemspec/) end  guard 'rspec', :version => 2 do   watch(%r{^spec/.+_spec.rb$})   watch(%r{^lib/(.+).rb$})     { |m| "spec/#{m[1]}_spec.rb" }   watch('spec/spec_helper.rb')  { "spec" } end 

Guard works by watching certain files in your project and then performing actions when those files change. The first guard tells us to watch for the Gemfile and the gemspec to change, and re-bundle the application when that happens. The second guard tells us to watch all of our RSpec test files, our spec_helper, and the corresponding library files for each of our RSpec tests. This means that when you change a file, Guard can automatically re-run the tests for that specific file only.

Now that your Guardfile is properly configured, you can just run bundle exec guard from your project's root directory. This will get Guard up and running and you will now automatically run tests and re-bundle as you build your gem. Running Guard makes the development feedback loop as tight and automatic as possible.

Continuous Integration

Continuous Integration is the process of automatically running the tests for a project when new code is pushed to the central repository. Luckily, a team of developers has built Travis CI that provides free continuous integration for open source projects of all types.

Why do you need continuous integration for an open source project?

  • Travis allows you to test your code across multiple versions of Ruby. Even if you don't personally develop on older versions of Ruby or alternative implementations such as JRuby or Rubinius, Travis can run your tests on these Rubies and notify you of any build failures.
  • Travis gives you the confidence to merge pull requests from the web. If someone submits a pull request you can merge it into your repository knowing that if it breaks your test build Travis will let you know. In the future, Travis will even support testing pull requests before you merge them.

In addition to the benefits provided by Travis is it exceptionally easy to implement. Here's how:

  1. Go to http://travis-ci.org and sign in with your GitHub account. Travis needs access to your GitHub info to be able to set up the automatic build process for each repository.
  2. Hover over your name once logged in and go to your profile. This lists out your open source repositories; from here you can simply "switch on" CI for each project.
  3. Set up a .travis.yml file in your project.

We haven't yet created a GitHub repository for our project, so steps 1 and 2 will actually come a bit later. However, we can set up the configuration file so that when we're ready to push to GitHub we will get continuous integration immediately. To set up Travis for your project you need to create one more configuration file in your repository. Make a file called .travis.yml (the leading dot is not a typo) and add this to it:

rvm:   - 1.9.3   - 1.9.2   - jruby   - rbx script: "bundle exec rake" 

As you can see, the configuration is very straightforward. The rvm key allows us to specify the different versions of Ruby we want to test against. The script key tells Travis what command to run for the build. Any command that exits with a non-zero status code (a Unix standard for a command that had errors) will automatically fail the build in Travis. In our case we're going to run bundle exec rake which, as explained above, has been aliased to running our RSpec tests via Rake.

Once you've added your Travis configuration file, it's time to create another commit:

git add . git commit -m "Adds RSpec, Rake testing, Guard, and Travis." 

All right! Now we've not only created a gem but we've added robust tools for testing that will give us and other contributors the power to develop quickly and in a test-driven manner. We've also set up continuous integration to let us test against many different versions of Ruby, even if we don't have them installed! We're well on our way to building a gem. Stay tuned for the next installment!

Continue to Part 4: Writing Library Code »

Categories
Author

This post is a part of Polishing Rubies, an end-to-end guide to Ruby open source development.

« Back to Part 1: Introduction

Creating Your Gem

Eureka! You've thought of a new idea for an open source library. Perhaps you already have some code tucked away in your application that you're extracting into a library, or perhaps you're starting from scratch. Either way, your next step is going to be setting up a gem folder to which you can then add code, tests, and documentation. As we saw previously, RubyGems are simply folders that follow certain patterns. You can build one from scratch quite easily, but luckily we have some tools that make it even easier.

A Gem By Any Other Name...

Of course when you create your gem you're going to have to have something to call it. Naming may not seem very important as a first step, but the gem name ends up in folder names, file names, and Ruby code, so you usually want to come up with a name first. So how do you pick one?

Developers have created RubyGems with an incredibly wide range of names, from the straightforward to the absurd, from the clever to the downright crass. Depending on what you're building, however, there might be a convention to follow in your name. Here is an incomplete list of gem naming conventions:

  • Your gem's name should be all lowercase with dash delimiters between words. Typically, the root module or class for your gem should be inferrable by class-casing your gem name. For example, if I wanted to call my library "Awesome Sauce" the gem name would be awesome-sauce and the root class/module would be AwesomeSauce.
  • If you are building a gem that adapts an existing library (such as a C library for parsing JSON) the common pattern is simply to name your gem libraryname-ruby (e.g. yajl-ruby for the YAJL JSON library).
  • If you are building a library that adapts another library for a framework (such as RSpec testing for Rails), the convention is to name it libraryname-rails (e.g. rspec-rails).
  • Some libraries are somewhat like frameworks in their own right and allow for an open "constellation" of associated gems. These will usually suggest a naming pattern, but the common one is frameworkname-libraryname (for example, the Facebook strategy gem for the OmniAuth authentication framework is called omniauth-facebook).
  • If you are building a Ruby library to access, for example, a specific service's web API, the gem is usually just named after the service (though in some cases follows the service-ruby pattern). You should be pretty confident about your long-term maintenance of a gem like this, as you will be claiming that gem name for all eternity. It would be unfortunate if the twitter gem fell into disrepair and was no longer a good way to access Twitter's API.

Ultimately a gem name is a lot like a brand name. Whether it's fair or not, a bad gem name can damage the popularity and success of a library just like a good one can make it more memorable and successful. When in doubt, try to include a keyword from your problem domain in the gem name (for example "auth" for an authentication library or "test" for a test framework). Avoid hard-to-spell words and elaborate metaphors (the typhoeus library has always been particularly hard to remember). Keep it short and simple, but ultimately, it's your library, and if you want to name it something funny or clever that's entirely your prerogative.

Before you settle on a name, you will need to make sure that it isn't already taken. The simplest way to do this is simply to visit http://rubygems.org/gems/{YOUR_GEM_NAME} in your browser. If you see a page that says "Page not found." then that gem is available.

Tooling Up

Polishing Rubies is meant to be a guide that is both pragmatic and encourages best practices. To that end, whenever possible we will not be "doing it from scratch." When you're building an open source library you're building for multiple audiences: yourself, end users, and contributors. Using the right tools is important for all of the audiences, but is most important to encourage contribution.

When it comes to making contributors happy, you want to be using a toolchain that is as comfortable as possible to make it extremely easy for someone to check out your code and start working with it. We'll cover that a bit more later on.

Here a quick list of the tools that we'll be using throughout this guide to help us make a gem that follows community best practices:

  • GitHub: where you will be hosting the source code, issue reporting and wiki documentation for your gem
  • Bundler: directory bootstrapping, dependency, and release management
  • Travis: free, amazing continuous integration for open source projects
  • Guard: development process automation tool
  • RSpec: our test framework (my personal choice, but the built-in Test::Unit libraries included with Ruby are a perfectly acceptable alternative)
  • Rubydoc.info: automatic documentation generation for RubyGems. Always a handy place to link from your project's README
  • Gemnasium: tracks dependencies to make sure your library is always compatible with the latest versions of the libraries you use

We'll talk about the use of each of these tools as needed throughout the guide, but this can serve as a handy reference to the things that most (if not all) gems will eventually end up using. Right now we're only going to worry about using Bundler.

Spinning Up a Gem

All right, now that all of the introductory material is out of the way, it's time to actually spin up your gem. This guide will be written assuming that you are using a POSIX-based shell system (such as Mac OS X or Linux) and that you have already installed Ruby 1.9.2 or later on your machine.

First make sure that you have Bundler installed on your system. Bundler contains a command-line helper called bundle gem that automatically generates a basic gem skeleton for us. To install Bundler you need to run this command in a terminal window:

gem install bundler 

Once you've installed Bundler, you should change directories to the location that you want to create your gem folder (for me, that location is ~/code/gems). Once there you will create the gem like so:

bundle gem my-gem 

Where my-gem is your gem's name. Note that if you are building a command line tool you should add the -b flag to this command (bundle gem my-gem -b). You should see output that looks something like this:

      create  my-gem/Gemfile       create  my-gem/Rakefile       create  my-gem/.gitignore       create  my-gem/my-gem.gemspec       create  my-gem/lib/my-gem.rb       create  my-gem/lib/my-gem/version.rb Initializating git repo in /Users/mbleigh/code/gems/my-gem 

Bundler has just generated a skeleton for your gem. You should recognize many of the files from our earlier discussion of the general structure of a gem. Some of the nice things that Bundler has done for us include:

  • .gitignore: There are certain files that you will not want to have to your git repository. Bundler automatically excludes the most common of these.
  • version.rb: Bundler creates my-gem/lib/my-gem/version.rb automatically. This file is used as a single place to track the current version of your library. By default, Bundler sets the version to 0.0.1.
  • Rakefile: The Rakefile created by Bundler is already set up with Bundler's gem helpers. These helpers allow you to release a new version of your gem (including creating a release tag in git and pushing the compiled gem to rubygems.org) with a single command.

Now that we've used Bundler to help us build our basic directory structure, we need to dig in and do a little housekeeping before we're ready to set up our development toolchain and start working.

Gemspec: Metadata for Your Library

Bundler has automatically created the gemspec file that serves as a manifest of metadata about your gem. However, you will need to edit this file to add specific information before your gem will be properly set up. Your gemspec should look something like this:

# -*- encoding: utf-8 -*- require File.expand_path('../lib/my-gem/version', __FILE__)  Gem::Specification.new do |gem|   gem.authors       = ["Michael Bleigh"]   gem.email         = ["michael@intridea.com"]   gem.description   = %q{TODO: Write a gem description}   gem.summary       = %q{TODO: Write a gem summary}   gem.homepage      = ""    gem.executables   = `git ls-files -- bin/*`.split("n").map{ |f| File.basename(f) }   gem.files         = `git ls-files`.split("n")   gem.test_files    = `git ls-files -- {test,spec,features}/*`.split("n")   gem.name          = "my-gem"   gem.require_paths = ["lib"]   gem.version       = My::Gem::VERSION end 

Most of these fields are fairly straightforward. Authors lets you provide one or more names of the authors of the library, email is the contact email for each of the authors. The executables, files, and test_files fields each represent lists of files to include in the packaged gem. When a gem is built, only these files will be included. By default Bundler uses some handy command-line magic with git to programmatically determine the file lists. For most circumstances, you shouldn't need to change these lines.

At this point you need to make a few changes to this file to follow best practices:

  1. gem.description: you should write a single-sentence description of your gem in this field. Note that %q{} is an alternative way to declare a string in Ruby. Bundler uses this by default so that you can use double and single quotes within the description without needing to escape them. Your maximum length should be no more than around 140 characters (like a tweet!).
  2. gem.summary: you can just copy and paste the gem description into this field for now.
  3. gem.homepage: this should generally be set to the location of your repo on GitHub unless you have created a specific website for your library.

The last step of your initial setup is to ensure that the constant and folder names generated by Bundler matches the constant and folder names you want to use for your library. Sometimes Bundler gets this right, and sometimes it doesn't. For example, in the above gemspec the referenced version is My::Gem::VERSION when I would actually want it to be MyGem::VERSION. To change this, I need to modify the constant in three places:

  1. The version reference in the gemspec
  2. The lib/my-gem.rb file
  3. The lib/my-gem/version.rb file

Unless your library is going to be very small, you will usually want your base constant (for example MyGem) to be a module, not a class. This allows you to easily namespace all of the different classes and components of your gem in a simple and sane way.

Underscores and Dashes

RubyGems have an unfortunate conflict of common patterns: gem names are almost always delimited with dashes while folder and file names are almost always delimited with underscores. This is partially to make for inferrable mappings from file names to class names (a pattern that is actively utilized by Rails to automatically load constants based on their file names). So if I have a constant called MyGem::VERSION it should be located in lib/my_gem/version.rb even though my gem's name is my-gem.

When Bundler generates your gem (if you have dashes in the name) it creates a folder inside the lib directory of the same name. I would recommend modifying this to use underscores in place of dashes. To do this, you will need to do the following:

  1. Rename the directory (e.g. mv lib/my-gem lib/my_gem).
  2. Alter the first line require in lib/my-gem.rb to use the underscored directory name.
  3. Alter the require in the gemspec file to use the underscored directory name.

If all of this weren't confusing enough, there is another pattern in Ruby that the only file that should be added to the root load path (the first level of your gem's lib) should be named identically to the gem. So lib/my-gem.rb is the one and only place that you should allow dashes in your filenames.

Following such needlessly complicated naming schemes may feel like a waste of time, but it most certainly isn't. By following the community conventions you:

  1. Make your library easier to "guess" how to use because developers can use common idioms to which they have become accustomed.
  2. Make your library auto-requireable by Bundler (which looks for the my-gem.rb file and requires it automatically in frameworks such as Rails)
  3. Make your library easier for contributors to join by providing familiar patterns and locations for code

Library Dependencies

As with a man, no gem is an island (well, ok, very few gems are islands). Nearly all gems are going to have dependencies upon other libraries that they require in order to function. These dependencies are explicitly declared in the gemspec so that when a gem is installed, all of the gems that are needed to run that gem can automatically be installed with it.

There are two types of gem dependencies, runtime dependencies and development dependencies. Runtime dependencies are libraries that your gem needs in order to function. For example, if you built a Rails extension, you would need to add Rails to the runtime dependencies of your project. Development dependencies, on the other hand, are gems that are only needed by people who are going to contribute to the code of the gem. Gems are, by default, installed only with the runtime dependencies. This avoids cluttering up an environment with development dependencies if they aren't needed.

Adding dependencies to your gemspec is extremely simple; all you need to do is add a line to the file for each dependency:

# -*- encoding: utf-8 -*- require File.expand_path('../lib/my-gem/version', __FILE__)  Gem::Specification.new do |gem|   # ...    gem.add_dependency 'rails'   gem.add_development_dependency 'rspec', '~> 2.7' end 

In addition to specifying the gem name of a dependency, you can also specify a version of the gem to get even more specific. Versioning is an important topic and one that we will cover later. For now, it's OK if you just add your dependencies without specifying the version. RubyGems will default to the latest version if no specific version is required.

Now you've created the basic structure of your gem. You understand the gemspec manifest file, a little bit about the structure of the app, and the somewhat-confusing-but-it-makes-sense-eventually-trust-me file naming conventions for Ruby libraries. You've also hopefully added the gem dependencies that you already know about (don't worry, you can always add more later). There's only one more thing to do: commit your code! It's great to have your first commit at this point because you haven't actually added any specific code and this serves as a baseline. So git add . and git commit -m "Initial Import" and you're on your way to building a first-class Ruby library!

Next time, we'll get our new gem set up with all of the bells and whistles you need to make open source development hum.

Categories
Author

Welcome to the inaugural post of Polishing Rubies! In this blog post series I will be walking through the process of building and maintaining open source libraries in Ruby from the ground up.

The What and Why of Gems

Building an open source library can be a daunting task if you've never done it before. How should I structure the project? What do I need to include in terms of documentation? What tools can I use to make my library friendly for others to contribute?

We'll get to all of that. But before we do, I think it's worthwhile to examine the RubyGems system, how it works, and what exactly makes up a gem. Once you understand all of that, the idea of creating a gem will be neither confusing nor mysterious but rather just another tool in your arsenal to be used to help make your projects cleaner, more modular, as well as to help you contribute to the open source community.

This post series assumes that you have already installed Ruby on your development machine. You can visit the Ruby language download page if you need help getting started with Ruby.

RubyGems: A Package Management System for Ruby

All programming languages have support for libraries. Libraries are collections of reusable code that are usually grouped around a common purpose. There can be libraries for just about anything, from advanced processing of strings to higher level math functions to entire encapsulated applications.

While all programming languages have libraries, not all programming languages have a system to deliver those libraries as simple and elegant as RubyGems. RubyGems is an internet-aware package management system that allows for the download and installation of new libraries through the simple gem install command. RubyGems is a part of the Ruby programming language. If you have Ruby (version 1.9.2 or later), you have RubyGems.

Bundler: Tracking Your Project's RubyGems

A companion tool to RubyGems that has become indispensable for Ruby development is Bundler. Bundler is a way to manage all of the various gem dependencies for a Ruby project simply and in a single place. Bundler is itself a RubyGem and can be installed at a command line with gem install bundler.

With Bundler you can specify all of the dependencies of your application (the libraries that your application needs to function) in a single manifest file called a Gemfile. Bundler will automatically find compatible versions of the libraries you specify, and you can additionally include libraries that are checked out via git or are local to your filesystem.

Bundler is not mandatory for creating RubyGems, but it provides extremely helpful tools for library authors to automate certain processes. You will learn more about using Bundler when we create our first gem.

So What is A Gem, Anyway?

A RubyGem is essentially a specially structured folder that contains the source code, description, documentation, and tests of a Ruby library. Gems can sometimes contain command-line executables as well. The file structure of a Ruby usually looks like this:

   my-gem   ??? bin           ?   ??? my-gem    ??? lib           ?   ??? my-gem.rb    ?   ??? my-gem       ?       ??? version.rb   ??? spec (or test)   ?   ??? spec_helper.rb    ?   ??? my-gem_spec.rb   ??? my-gem.gemspec   ??? Gemfile      ??? Rakefile  

Let's go through the different parts individually to make sure we know what they all are:

  • bin: This directory will contain any command-line executables that a gem has defined. For instance, the Bundler gem contains a bundler executable in this directory.
  • lib: This directory houses all of your library code. The convention is that you should only define a single file at the "root" level of your lib directory. That file should be named exactly the same as your gem. All other files should go into a subdirectory in the lib directory named after your gem (the lib/my-gem directory in the example above).
  • spec or test: This directory houses all of the automated tests for your gem. Nearly all open source gems have automated tests as testing ensures both maximum quality and maximum reliability for code that is being worked on by many parties such as an open source project.
  • my-gem.gemspec: Every gem needs a gemspec file that is effectively all of the metadata that RubyGems needs to know about your library. We will dig into the gemspec in a later post.
  • Gemfile: This is the manifest file used by Bundler to keep track of the project's dependencies. This is primarily present to make it easy for other developers to check out and work on the source code of a library.
  • Rakefile: Rake is a library that allows developers to define simple "tasks" that can be performed via the rake command at the command line. Most gems have rake tasks for running specs, generating documentation, and performing release-time chores.

And really, that's pretty much it! If you're feeling a little bit overwhelmed by this list, don't worry: we will cover the needs and uses of each of these files in depth as we build our gem throughout this series. I just wanted to give you a clear overview up front of what really goes into a gem. Remember: a gem is just a folder that follows some conventions and rules, nothing more.

Why Would I Want To Create A Gem?

So now you know what a gem is but you may be wondering: why would I want to create an open source gem? There are many, many reasons why individuals and companies alike build open source projects, but here are some common benefits of open source development:

  1. By encapsulating reusable code in a packaged library, you are able to reuse that code in multiple applications without rewriting the same thing over and over.
  2. Individuals who release open source libraries build a reputation in the community. Most of the "well-known" Ruby developers became so by giving back to the community in the form of useful open source libraries.
  3. Companies who promote open source development are more likely to attract the very best programmers, as the very best programmers in the Ruby communities tend to be deeply involved in the open source community.
  4. When you release open source libraries, other people do some of the work for you! When the community can fix bugs and make improvements to common libraries it helps everyone get more done faster.

Again, there are far too many reasons to list here as to why you might want to release open source libraries. You might find some more answers in Intridea's own Open Source Citizenry blog post series.

In my next post I'll be covering the creation of the basic structure of a gem as well as getting it well-situated for automated testing, documentation, and other common needs. If you have any questions, comments, inaccuracies, or suggestions please do comment below or fork this post on GitHub. I want this to be a clear and accurate guide that can serve as a great starting point for anyone who wants to get involved in the Ruby open source world. Until next time, keep polishing those gems!

Continue to Part 2: Creating Your Gem »

Categories
Author

I've got 99 problems but a redirect ain't one

What do you get when you discover you setup a route incorrectly ages ago? Why, a redirect of course! And a blog post with some handy redirect code that you might find useful one day!

The Situation

Our blog posts were routed like so:

  match '/:year/:month/:day/:id' => "posts#show", :as => "blog_post",         :requirements => { :year => /d{4}/, :month => /d{2}/, :day => /d{1,2}/ } 

Which technically works just fine... except that the URL of a post ends up as this:

When I'd really rather have the URL as this:

If I had just setup my routes for the first time today I would simply change it to this (to include 'blog' in the url):

  match '/blog/:year/:month/:day/:id' => "posts#show", :as => "blog_post",         :requirements => { :year => /d{4}/, :month => /d{2}/, :day => /d{1,2}/ } 

But since posts had been routed that way for quite some time, I needed to add a redirect to ensure that older links to posts that were floating around in the ether would still work.

So then I was all like, "Sweet! @merbist mentioned that redirects can be done in the routes in Rails 3! Easy Peasy!"

Thus, I added some code to the routes file that looked like this:

match '/:year/:month/:day/:id', :to => redirect('/blog/:year/:month/:day/:id'), :as => "blog_post",        :requirements => { :year => /d{4}/, :month => /d{2}/, :day => /d{1,2}/ } 

And then Rails was all like, "Oh no she didn't!"

NoMethodError in PostsController#show  undefined method `published_on' for nil:NilClass Rails.root: /Users/renaebair/workspace/intridea/newsite  Application Trace | Framework Trace | Full Trace app/helpers/blogs_helper.rb:23:in post_link' app/controllers/posts_controller.rb:23:inshow' Request  Parameters:  {"requirements"=>{"year"=>/d{4}/, "month"=>/d{2}/, "day"=>/d{1, 2}/}, "year"=>":year", "month"=>":month", "day"=>":day", "id"=>":id"} 

And then I was all like, "Must not have the syntax down. No problem, Google can help!"

And after several dead ends and poor implementations I had to step back.

The Solution

Finally, with my coder ego sulking at subterranean depths, I pulled together the humility to ask for help; I pinged Michael Bleigh, who is a very busy guy but never ignores a coder's plea for help.

In less than 30 seconds he sent me a working solution, which I now present to you:

  match '/:year/:month/:day/:id',          :to => lambda{|env|            Rack::Response.new(['301 Permanently Moved'], 301, {'Location' => "/blog#{env['PATH_INFO']}"}).to_a         }, :as => "old_blog_post", :requirements => { :year => /d{4}/, :month => /d{2}/, :day => /d{1,2}/ } 

As you can see, he embedded a Rack reponse in the route using a lambda. This is important because the route file is only loaded once , right when the app starts up. Putting the redirect code in the lambda ensures that the Rack response will be evaluated anytime that route is matched. When it's matched the Rack response throws a 301, indicating the page has a new home and redirects to the new home. It's important to use a 301 code "Permanently Moved" because otherwise you'll lose a ton of link "juice" (eww). Click here for more HTTP status code definitions.

And there you have it - a juicy snippet of code for all your redirect woes!

Categories
Author

You've heard of Pry right? It's a full-featured alternative to the classic IRB shell that we use in Ruby, and it's awesomesauce. If you've ever felt like you wanted a crowbar to pry open your code during runtime... well, Pry is your answer.

Pry is essentially a REPL (read–eval–print loop) tool that you can use to examine and debug your code. One of the best features is that local variables are available to Pry, saving you from recreating them as you normally would in an IRB session.

Installing Pry

I like to install pry into the global gemset since it's a tool even when I'm outside of a Rails project

rvm use @global gem install pry 

Replacing IRB with Pry

In your application initialization, add the following to replace IRB with pry by default. For example, Rails would add this code to config/initializers/pry.rb

begin   require "pry"   IRB = pry rescue   # do nothing if pry fails to load end 

Replacing ruby-debug with Pry

Between different versions of Ruby, installing and requiring ruby-debug can lead to annoying problems. 1.8.7 uses ruby-debug, 1.9.2 requires ruby-debug19, and 1.9.3 blows up when you try to use ruby-debug19. ruby-debug also depends on the linecache gem, which sometimes requires extra work to use with rvm and sometimes fails in environments when the native extensions fail to build.

Instead, skip all that headache with Pry! Anywhere you would use a 'debugger' statement, just call:

binding.pry 

'binding' is a reference to the current local context. Enter 'exit' when you're finished with debugging, and the code will resume executing

Additional features

Pry has a ton of other productivity boosters built in. You can drop into a shell temporarily, browse docs without leaving your shell, edit and reload code, and send code snippets up to gist.

There's a ton of documentation for Pry and a growing community around it; if you're interested in jumping in be sure to start at their Github page for links to tutorials, screencasts, FAQs and a Wiki!

Disclaimer: We love Pry so much we were compelled to donate funds to the project. And write this blog post about it. If you like it, you can support them too!

Categories
Author

I've been doing a bit more Ruby and Ruby on Rails coding lately by virtue of silently commandeering the Intridea.com codebase. shhhh, it can be our secret.

Riding the Pipeline of Assets

Last month I upgraded the site from Rails 2.3 to Rails 3.1; getting up and running on the asset pipeline was a much larger project than I imagined, and while I had plans for a supremely awesome post on all the details of the upgrade, I spent less time taking notes on all the cute little steps and more time... LOST IN TIME AND SPACE with all the.... complications. #ahem

This week I got the site running on Rails 3.2, which thankfully was pretty easy. The instructions on RubyonRails.org were succinct and helpful. I did run into a few minor hiccups but overall it was a breeze. The biggest problem I ran into was one involving Rack 1.4.1 and cookies. For a view of the crime scene, check the gist.

A quick search on StackOverflow told me a lot of others were having this issue as well, but a simple act of clearing cookies fixed their problem. It wasn't so easy in my case. In the end I had to rollback to Rack 1.4.0, but I've got my fingers crossed for a fix in some future release.

i to the P

With Rails upgrades out of the way, I am focusing on smaller enhancements here and there as time permits. This week I added a helper file for our blog categories. These categories are generated dynamically based on the popularity/density of tags in blog posts (thanks to Michael Bleigh's Acts As Taggable On gem), but I wanted to capitalize the category names and appropriately not capitalize the "i" in words like "iPhone" and "iPad" and consequently capitalize the second letter in those specific words. It's not rocket science, but if you are upper-casing words in your app and want to create exceptions for Apple products, here's some code for you:

module TagHelper   def tag_title(tag)     name = tag.name.downcase     iProduct = %w(iphone ipad)     if iProduct.include?(name)       apple_product_titlize(name)     else       name.capitalize     end   end    def apple_product_titlize(name)     name[0] + name[1].capitalize + name[2..-1]   end end 

This method is called by a bit of Ruby in our view:

<% @categories.each do |tag| %>   <li><%= link_to "#{tag_title(tag)} (#{tag.count})", "/tag/#{tag.name}" %></li> <% end %> 

The Before & After

Updates? Yeah, we do that

So there you have it - a long overdue update on intridea.com upgrades and a snippet of code to help you manage the "i" pandemic.

Happy coding!

Categories
Author
Subscribe to Ruby