Skip to main content

Mobomo webinars-now on demand! | learn more.

After kicking off the month of March in Austin at SXSW with Patti and Bobby and then at MountainWest RubyConf with Ted for some UXDD goodness, we're heading to, well... our backyard.

That's right, we're supporting RubyNation for the third year in a row, and this time Pete Jackson will be presenting "Geospace your Rails Apps" to a sold out crowd of more than 250 Ruby enthusiasts.

The 2 track/2 day conference kicks off this Friday at the Sheraton in Reston, Virginia. Pete takes the stage at 3:40 pm on Friday afternoon:

Intridea co-founder Dave Naffis will be there too, talking shop with folks and taking in the sights.

Five years running, RubyNation brings Ruby luminaries to the DC community, energizing the local Ruby scene with poignant speakers, networking opportunities, and thoughtful, intellectual debate. We're thrilled to support this event and the greater DC/MD/VA Ruby community.

If you want to track down Dave or Pete at the conference this week be sure to ping them on Twitter or harass them in the hallways between tracks!

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

Ted O'Meara departs today for Salt Lake City, Utah where he'll spend the next few days immersed in the ever-evolving community of Ruby and Ruby on Rails developers. He's headed for destination: MountainWest RubyConf.

Ted came to Intridea two years ago as a designer and in just a short time he's proven to be a dextrous and pioneering leader. Not only has he become an accomplished project manager, he also plunged into the development world in an effort to become a more knowledgable and powerful designer. He did it. He crossed the streams.

While total protonic reversal was not a direct consequence of Ted's actions, he did actually learn a thing or two about the gaps between developers and designers and how small divergences in processes between the two groups effects the products they build. He'll be sharing his insights and solutions at MWRC this Friday.

In his talk, "UXDD (User Experience Driven Development): Build for your users, not your tests", Ted will propose practical and technological solutions to ways developers can increase the overall quality of their applications by aligning and testing their work against the user interface and flow.

In a candid example of why this is important, Ted posits the following user story:

Given that John has 30 pies
When he eats 3 of them a day
And he eats them for 10 days
Then he should not be hungry

And then adds "...but he might have gained 50lbs."

Throughout a project's lifecycle there may be several additions or changes to the overall user flow and back-end architecture. Following the principles of test-driven and behavior-driven development head-down might cause you to miss glaring errors in functionality for the user. So go see Ted's presentation this Friday at 4:30 pm for a Complete and Perfect Solution™ - he'll fix all your problems, ever. Just don't tell him I said so.

Categories
Author

*Welcome to End of the Office, our new blog post series detailing the motivation that has led us to dedicate ourselves to retaining a fully distributed workforce rather than consolidating in a single office as so many companies do. In the coming weeks you will see posts from a number of Intrideans explaining the various benefits of distributed teams as well as the perils and pitfalls of traditional office settings.*

Arrive at the office. Log in to computer. Check email. Morning standup meeting. Check bug tracker. Someone asks me a question. Break off a development branch. Code for five minutes. Conversation starts happening two desks over; overhear topic I know about, join conversation. Check email again. Get pulled into a production bugfix, stash my five minutes of code. Switch branches. Deal with bugfix, back to work. Nevermind, it's already time for lunch.

If you think that having all of your employees together in an office will be a boon for productivity because they will have ready access to each other, think again. If you feel the need to have everyone in the same place so that you can keep an eye on them and make sure they're doing work, solve your trust issues or improve your hiring process. If you want your employees to be happy and productive, set them free from synchronous obligations.

One of the greatest gains from a truly distributed team is the natural de-emphasizing of synchronous activity. When the natural communication channels of a business are email, corporate chat, instant messaging, and [microblogging](http://www.socialspring.com/about#stream) the employees are freed up to prioritize their attention rather than having it overridden by the burdens face-to-face meetings (or a phone calls).

### Makers and Managers

Most companies include two classes of employee: makers and managers. Makers are responsible for producing output; in a web development shop, the makers are developers and designers. Conventional wisdom places the role of managers as overseeing the makers. In a successful distributed team, managers do the opposite: they oversee everything *except* the makers so that the makers can achieve the focus necessary to complete business objectives.

This requires, more than anything, faith in the self-direction of your employees. A fully distributed team can only be built through extremely careful hiring. Each employee must be able to function and make small decisions without "running it up the flagpole." If your team has to "sync up" for every minor task assignment your makers will lose the productivity flow from being asynchronous.

If you have external stakeholders in a project, you should do everything you can to block them from having direct contact with the makers. Clients and customers don't understand that interrupting a maker mid-stream is going to completely wreck productivity, nor should they have to. Instead, project managers, client liasons, and other roles should be fully utilized as buffers between the people who do the talking and the people who do the making.

### Fluid Schedule

Another aspect of a fully asynchronous workflow is having a fluid work schedule. Few jobs truly require any kind of synchronous time commitment. Makers need to be able to find their own rhythm of productivity, something that is simple to do with an asynchronous team and nearly impossible to do with a synchronous one.

I find that I work best in three "chunks" of time during the day: a chunk in the morning, the afternoon, and the evening. Ideally these chunks are punctuated by two to three hour breaks during which I can take care of non-work related errands, eat meals, etc. When I'm forced to work on a different schedule than my natural rhythm I find myself waning in productivity but unable to do anything about it. For some people the "nine to five" schedule might fall perfectly in line with their rhythm. Others might prefer to do an intense single block of work in the evening. There is an infinite spectrum of ideal schedules and all can be accomodated in an asynchronous team.

### Asynchronous Tools

The adoption of tools that encourage and support asynchronous work is key to the success of an asynchronous team. Task management systems should ideally include either robust notification systems or other ways to "catch up" on a time period of activity quickly. Communication systems, similarly, should ideally have a way of denoting the "last read" items so that everything new can be consumed quickly and easily without manual scanning.

Synchronous activities such as phone calls, meetings, or even instant message sessions should be quickly distilled into asynchronous tools after the fact. Ideally there should be **no part** of your project that requires synchronous communication to move forward. This means less understanding-by-conversation and more well-written documentation around the project. If you have to have a conversation to understand something, also write the key points of the conversation down so that in the future someone can understand the same thing asynchronously.

### An Asynchronous Office?

Some people like having offices. Some people like working in offices. The existence and utilization of an office is not *necessarily* an automatic blocker to an asynchronous workflow. I would argue, however, that offices encourage synchronous work by default while distributed teams encourage asynchronous work by default.

If you are in an office but want to adopt an asynchronous work style, you will have to institute a policy discouraging the kinds of small, distracting communication that interrupt workflow. Employees should each have private space and focus that is protected from interruption as much as possible. Even if you're all in the same building, use the asynchronous tools as your primary means of communication. Make sure that knowledge is documented, not conversational.

Put simply, adopt an asynchronous workflow and you will see each of your makers operating at his or her maximum capacity.

Categories
Author

Faraday is a Ruby HTTP client which allow developers to customize its behavior with middlewares. If you're familiar with Rack, then you'll love Faraday. Rather than re-im
plement yet another HTTP client, Faraday has adapters for popular libraries like Net::HTTP, excon, patron, and em-http. On top of having a consistent interface between different adapters, Faraday also allows you to manipulate request and responses before and after a request is executed. This tutorial gives an introduction of common use cases built into Faraday, and also explains how to extend Faraday with custom middleware. The code is well tested and easy to follow, so I recommend browsing the source code to find extra options and features not covered in this tutorial.

Basics

Out of the box, Faraday functions like a normal HTTP client with a easy to use interface.

Faraday.get 'http://example.com' 

Alternatively, you can initialize a Faraday::Connection instance:

conn = Faraday.new
  response = conn.get 'http://example.com'
  response.status
  response.body
conn.post 'http://example.com', :some_param => 'Some Value'
conn.put  'http://example.com', :other_param => 'Other Value'
conn.delete 'http://example.com/foo' # head, patch, and options all work similarly

Parameters can be set inline as the 2nd hash argument. To specify headers, add optional hash after the parameters argument or set them through an accessor:

conn.get 'http://example.com', {}, {'Accept' => 'vnd.github-v3+json'}
conn.params  = {'tesla' => 'coil'}
conn.headers = {'Accept' => 'vnd.github-v3+json'} 

If you have a restful resource you're accessing with a common base url, you can pass in a :url parameter that'll be prefixed to all other calls. Other request options can also be set here.

conn = Faraday.new(:url => 'http://example.com/comments')
conn.get '/index'
# GET http://example.com/comments/index 

All HTTP verb methods can take an optional block that will yield a Faraday::Request object:

conn.get '/' do |request|
  request.params['limit'] = 100
  request.headers['Content-Type'] = 'application/json'
  request.body = "{some: body}"
end 

File upload

payload = { :name => 'Maguro' }
# uploading a file:
payload = { :profile_pic => Faraday::UploadIO.new('avatar.jpg', 'image/jpeg') }
# "Multipart" middleware detects files and encodes with "multipart/form-data":
conn.put '/profile', payload 

Authentication

Basic and Token authentication are handled by Faraday::Request::BasicAuthentication and Faraday::Request::TokenAuthentication respectively. These can be added as middleware manually or through the helper methods.

conn.basic_auth('pita', 'ch1ps')
conn.token_auth('pitach1ps-token') 

Proxies

To specify an HTTP proxy:

Faraday.new(:proxy => 'http://proxy.example.com:80')
Faraday.new(:proxy => {
   :uri      => 'http://proxy.example.com',
   :user     => 'foo',
   :password => 'bar'
}) 

SSL

See the Setting up SSL certificates wiki page.

conn = Faraday.new('https://encrypted.google.com', :ssl => {
   :ca_path => "/usr/lib/ssl/certs"
})
conn.get '/search?q=asdf' 

Faraday Middleware

Like a Rack app, a Faraday::Connection object has a list of middlewares. Faraday middlewares are passed an env hash that has request and response information. Middlewares can manipulate this information before and after a request is executed.

To make this more concrete, let's take a look at a new Faraday::Connection:

conn = Faraday.new
conn.builder  > #<Faraday::Builder:0x00000131239308
     @handlers=[Faraday::Request::UrlEncoded, Faraday::Adapter::NetHttp]> 

Faraday::Builder is analogus to Rack::Builder. The newly initialized Faraday::Connection object has a middleware Faraday::Request::UrlEncoded in front of an adapter Faraday::Adapter::NetHttp. When a connection object executes a request, it creates a shared env hash, wraps the outer middlewares around each inner middleware, and executes the call method. Also like a Rack application, the adapter at the end of the builder chain is what actually executes the request.

Middlewares can be grouped into 3 types: request middlewares, response middlewares, and adapters. The distinction between the three is cosmetic. The following two initializers are equivalent:

Faraday.new do |builder|
builder.request  :retry
  builder.request  :basic_authentication, 'login', 'pass'
  builder.response :logger
  builder.adapter  :net_http
end
Faraday.new do |builder|
  builder.use Faraday::Request::Retry
  builder.use Faraday::Request::BasicAuthentication, 'login', 'pass'
  builder.use Faraday::Response::Logger
  builder.use Faraday::Adapter::NetHttp
end 

Using a Different HTTP Adapter

If you wanted to use a different HTTP adapter, you can plug one in. For example, to use a EventMachine friendly client, you can switch to the EMHttp adapter:

conn = Faraday.new do |builder|
  builder.use Faraday::Adapter::EMHttp
  # alternative syntax that looks up registered adapters from lib/faraday/adapter.rb
  builder.adapter :em_http
end 

Currently, the supported adapters are Net::HTTP, EM::HTTP, Excon, and Patron.

Advanced Middleware Usage

The order in which middleware is stacked is important. Like with Rack, the first middleware on the list wraps all others, while the last middleware is the innermost one, so that's usually the adapter.

conn = Faraday.new(:url => 'http://sushi.com') do |builder|
  # POST/PUT params encoders:
  builder.request  :multipart
  builder.request  :url_encoded
  builder.adapter  :net_http
end 

This request middleware setup affects POST/PUT requests in the following way:

  1. Request::Multipart checks for files in the payload, otherwise leaves everything untouched;
  2. Request::UrlEncoded encodes as "application/x-www-form-urlencoded" if not already encoded or of another type

Swapping middleware means giving the other priority. Specifying the "Content-Type" for the request is explicitly stating which middleware should process it.

Examples:

payload = { :name => 'Maguro' }
# uploading a file:
payload = { :profile_pic => Faraday::UploadIO.new('avatar.jpg', 'image/jpeg') }
# "Multipart" middleware detects files and encodes with "multipart/form-data":
conn.put '/profile', payload 

Modifying the Middleware Stack

Each Faraday::Connection instance has a Faraday::Builder instance that can be used to manipulate the middlewares stack.

conn = Faraday.new
conn.builder.swap(1, Faraday::Adapter::EMHttp)
# replace adapter
conn.builder.insert(0, MyCustomMiddleware)
# add middleware to beginning
conn.builder.delete(MyCustomMiddleware) 

For a full list of actions, take a look at the Faraday::Builder documentation.

Writing Middleware

Middleware are classes that respond to call. They wrap the request/response cycle. When it's time to execute a middleware, it's called with an env hash that has information about the request and response. The general interface for a middleware is:

class MyCustomMiddleware   def call(env) 
    # do something with the request 
    @app.call(env).on_complete do |env| 
      # do something with the response 
      # env[:response] is now filled in 
    end 
  end 
end 

It's important to do all processing of the response only in the on_complete block. This enables middleware to work in parallel mode where requests are asynchronous.

env is a hash with symbol keys that contains info about the request and response.

:method           - a symbolized request method (:get, :post, :put, :delete, :option, :patch) 
:body             - the request body that will eventually be converted to a string. 
:url              - URI instance for the current request. 
:status           - HTTP response status code 
:request_headers  - hash of HTTP Headers to be sent to the server 
:response_headers - Hash of HTTP headers from the server 
:parallel_manager - sent if the connection is in parallel mode
:request          - Hash of options for configuring the request. 
  :timeout        - open/read timeout Integer in seconds 
  :open_timeout   - read timeout Integer in seconds 
  :proxy          - Hash of proxy options 
    :uri            - Proxy Server URI 
    :user           - Proxy server username 
    :password       - Proxy server password 
:response      - Faraday::Response instance. Available only after `on_complete` 
:ssl           - Hash of options for configuring SSL requests. 
  :ca_path       - path to directory with certificates 
  :ca_file       - path to certificate file 

Testing Middleware

Faraday::Adapter::Test is an HTTP adapter middleware that lets you to fake responses.

# It's possible to define stubbed request outside a test adapter block. 
stubs = Faraday::Adapter::Test::Stubs.new do |stub| 
  stub.get('/tamago') { [200, {}, 'egg'] } 
end 
# You can pass stubbed request to the test adapter or define them in a block 
# or a combination of the two. 
test = Faraday.new do |builder| 
  builder.adapter :test, stubs do |stub| 
    stub.get('/ebi') {[ 200, {}, 'shrimp' ]} 
  end 
end 
# It's also possible to stub additional requests after the connection has 
# been initialized. This is useful for testing. 
stubs.get('/uni') {[ 200, {}, 'urchin' ]} 
resp = test.get '/tamago' 
resp.body # => 'egg' 
resp = test.get '/ebi' 
resp.body # => 'shrimp' 
resp = test.get '/uni' 
resp.body # => 'urchin' 
resp = test.get '/else' # => raises "no such stub" 
error 
# If you like, you can treat your stubs as mocks by verifying that all of 
# the stubbed calls were made. NOTE that this feature is still fairly 
# experimental: It will not verify the order or count of any stub, only that 
# it was called once during the course of the test. stubs.verify_stubbed_calls 

Useful Middleware

Categories
Tags
Author

Votifi, a mobile-based political polling and analytics company, is a finalist in the fourth annual South by Southwest (SXSW) Accelerator at the 2012 SXSW Festival in Austin, Texas. Launched in June 2011, Votifi is an innovative platform that promotes engagement on political issues across social and demographic divides. The app is a personal, virtual, mobile soapbox for political engagement.

Votifi launched its iPhone application at SXSW. The app provides political information and a platform to amplify the voice of the mobile voter. Mobomo developed the Votifi app was developed by MOBOMO.COM of Bethesda, Maryland and its founder Barg Upender. The MOBOMO team lead by Brian Lacey has worked diligently to ensure a successful and timely SXSW launch.

Categories
Tags
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

In the previous SASS recipe post we discussed using loops to create complex series of CSS classes. This week we explore more helper functions tucked away at the SASS Helper Reference

Lighten and Darken

Sometimes when creating accent colors it can be useful to handle it programmatically. lighten() and darken() accept a color and a percentage to increase or decrease that color.

lighten(#000, 20%) => #333333 darken(#ccc, %44) => #5c5c5c 

Lightness

When passed a color, either hexademic prefixed with # or a standard color string, return that color's lightness as a percentage between 0% and 100%. Be sure to pass your color with the # prefix of you'll get a syntax error.

lightness(#ccc) => 80% lightness(#d17b7f) => 65.098% lightness(abcabc) => 'SyntaxError: "abcabc" is not a color for `lightness'' 

Putting it to use

So now we've got a lightness percentage, what can we do with it? How about automatically adjusting colors based on the background color of a button, like so:

=btn-color($gradientStart, $gradientEnd, $innerShadow)   +vertical-gradient($gradientStart, $gradientEnd)     @if lightness($gradientStart) > lightness(#aaaaaa)     color: #4a4a4a     +text-shadow(0 1px 0 rgba(#fff, .4))   @else     color: #fafafa     +text-shadow(0 -1px 0 rgba(#000, .75))     &:active, &.active     box-shadow: 0 1px 5px $innerShadow inset 

If the lightness of top gradient color ($gradientStart) is lighter than the lightness of a pretty light color (#aaaaaa), then we make our text color dark (#4a4a4a) and give it a white text shadow. If $gradientStart is darker than #aaaaaa, make the text color dark (#fafafa) and give it a light text shadow.

These sorts of things will certainly require tweaking, but the end result are styles that intelligently take care of themselves. Combining our last SASS recipe with these techniques will yield concise yet powerful stylesheets that can be modified solely by editing a list of colors.

Continued tinkering

Be sure to look through the HSL functions of the SASS reference to see all sorts of awesome things you have available. Things like adjusting hue, saturation, converting colors to grayscale, and even getting a color's compliment are all possible through SASS.

Acknowledgments

Again my thanks go to Ian for his inspiring code which taught me these cool techniques.

Categories
Tags
Author

When you use Rails built-in helpers for page, action, and fragment caching, the cached data is stored into an instance of ActiveSupport::Cache::Store. But while the interface for using the cache stores are the same, each cache store implementation has different performance characteristics and are suited for different jobs. In this post, I'll cover what cache stores are available with Rails by default, how to tune them, and how to write your own custom cache store.

Grabbing the Code

If you want to follow along in the code, I recommend cloning the Rails repository. The cache related code I'm covering all live within activesupport/lib/cache.rb and activesupport/lib/cache folder. The corresponding tests live in activesupport/test/caching_test.rb.

Introducing the Abstract Store

All cache store implementations inherit from an abstract store named ActiveSupport::Cache::Store. This class defines the public interface that's used by Rails to do caching. The three basic operations are read, write, and delete. Here's a simple example you can run in irb:

require 'activesupport' cache = ActiveSupport::Cache.lookup_cache(:memory_store) cache.read('foo') => nil cache.write('foo', 'bar') cache.read('foo') => 'bar' cache.delete('foo') cache.read('foo') => nil 

After requiring activesupport, we ask for an instance of a MemoryStore (we'll cover the different store types later in this post). The interface for read, write, and delete are self explanatory. You can also customize the behavior of these actions.

Store Implementations

The concrete store implementations are well documented, so I'll introduce them briefly here and leave the details to the documentation.

  • MemoryStore - a cache store that stores data in a plain-old Ruby hash. As an added feature, it keeps track of cache access and cache size, and will prune the cache when it hits a customizable max size.

  • FileStore - a cache store that stores data on the filesystem. It also caches multiple read calls within the same block in memory to decrease I/O.

  • MemCacheStore - the big daddy of cache stores. Backed by memcached, this store allows you to specify multiple memcached servers and load balances between them.

  • NullStore - Interesting cache store that does nothing. That's right, if you look at its implementation, it's just a bunch of empty methods. It's perfect for use as a mock cache store for testing, or as a template for writing your own cache store.

Rails Initialization

By default, Rails 3 will initialize a FileStore that you can reference through Rails.cache. This cache is used internally by Rails to cache classes, pages, actions, and fragments. If you want to change which cache store is used, you can configure it in your application.rb

# use a MemoryStore cache with a max size of 512 megabytes config.cache_store = [:memory_store, {:size => 536870912}] 

In production mode, Rails will also insert Rack::Cache to the top of the middleware stack and use Rails.cache as its storage. Note that even though Rack::Cache's heap storage does not bound the size of its cache, if you use ActiveSupport's MemoryStore, the least recently used entries will be pruned from the cache when it hits your specified limit. So if you set correct cache headers, Rack::Cache will pick them and cache your responses.

Writing A Custom Cache Store

The default cache stores are a perfect fit for most situations, but if you do need to write a custom cache store, rest assured that it's easy to do.

The three main methods to override are:

# Read an entry from the cache implementation. Subclasses must implement this method. def read_entry(key, options) # :nodoc:   raise NotImplementedError.new end  # Write an entry to the cache implementation. Subclasses must implement this method. def write_entry(key, entry, options) # :nodoc:   raise NotImplementedError.new end  # Delete an entry from the cache implementation. Subclasses must implement this method. def delete_entry(key, options) # :nodoc:   raise NotImplementedError.new end 

These methods are then used by the public interface methods. There are a few methods you can optionally implement, but your cache will work with just the three listed above.

For a client project, I wrote a write-through cache store called CascadeCache that chains multiple cache stores together. For example, here's one possible configuration:

config.cache_store = [:cascade_store, {   :stores => [     [:memory_store, :size => 5.megabytes],     [:memcache_store, 'somehost:11211']   ] }] 

The behavior of this cache store is to return the first hit from the list of caches. This allows the app to have a small low-latency MemoryStore in front of a MemCacheStore. If something can't be found in the MemoryCache, then we fall back to MemCache. When writing to the cache, entries are written through to both underlying cache stores. The primary reason for doing this wasn't because MemCache store was slow, but as an extra backup cache in case MemCache became temporarily unavailable (actually happened in production).

I'm hoping CascadeCache makes it upstream into ActiveSupport, but in the meantime, I've packaged it up as a separate gem. For another example of a custom cache implementation, check out redis-store. It includes an ActiveSupport compatible cache.

Caching is a tricky beast. On top of deciding what to cache and when to expire, the underlying cache store can affect your app's performance. Choose the cache store that best fits your needs, use a hybrid CascadeCache, or write your own. Good luck and happy tuning!

Categories
Author

SXSW kicks off this week, and you'll find Intrideans Patti and Bobby in Austin for the tech event of the year!

Be sure to hit the Rockstars or Roadies: Who's the Better Employee panel at 3:30 on Sunday, March 11th to hear leaders from successful companies talk about their experiences building teams of productive, happy, and talented employees. Patti will be sharing her own expertise on working with Rockstars and Roadies, alongside Corey Reid of Freshbooks, Daniel Ha of Disqus, Heather Gold of Subvert, and Joe Stump of SimpleGeo.

Even if you can't make the panel be sure to hit up @pattichan and @bobbymartines via Twitter during the festival - they're looking forward to connecting with anyone who enjoys talking about tech as much as they do!

Categories
Author
Subscribe to