Jenkins AnsiColor 0.2.1 w/ Support for Conceal Codes Draft Hidden Sticky

Posted Friday, 03 February 2012 | Post Comment |

I just released AnsiColor 0.2.0 that now supports the ANSI conceal code. Conceal code 0x8 is a hacky way to hide data inside text using ANSI sequences. Jenkins uses it to annotate output with something that looks like ha:<long base64 string>. You can see this implemented in ConsoleNote.java. The previous version of AnsiColor produced garbage by stripping the conceal sequence, therefore revealing the content inside the conceal block (issue #3). Fixed in this commit. Also updated Jansi to 1.7 – Jansi makes this plugin possible.

Update your Jenkins.

 

CarrierWave: DelayJob-Processing of Selected Versions, Revisited Draft Hidden Sticky

Posted Tuesday, 31 January 2012 | Post Comment |

I’ve written about delay-processing certain image versions in this article. We’ve made some progress since with a much more robust implementation. Check out this new post on the Art.sy Engineering blog.

 

Testing w/ Analytical Gem and RSpec Draft Hidden Sticky

Posted Monday, 30 January 2012 | Post Comment |

We use the Analytical gem to include various thirdparty Javascripts in our Rails application. Our test environment was configured with dummy values in config/analytical.yml.

  1. production:
  2.   google:
  3.     key: <%= ENV['GOOGLE_UA'] %>
  4.   kiss_metrics:
  5.     js_url_key: <%= ENV['KISS_METRICS_URL_KEY'] %>
  6.  
  7. test:
  8.   google:
  9.     key: 'UA-12345'
  10.   kiss_metrics:
  11.     js_url_key: 12345
  12.  
  13. development:

We wrote a few simple tests to make sure the analytical code is being included properly. For example, we can check whether Google Analytics is included on the splash page.

  1. context "google analytics" do
  2.   it "should appear on the splash page" do
  3.     visit "/"
  4.     within :css, "script[type='text/javascript']:contains('.google-analytics.com/')" do
  5.       page.should have_content("UA-12345")
  6.     end
  7.   end
  8. end

Or, more complicated, test whether a user ID is sent to Kissmetrics.

  1. context "kiss-metrics analytics" do
  2.   it "should appear on the splash page" do
  3.     visit "/"
  4.     within :css, "script[type='text/javascript']:contains('kissmetrics.com/')" do
  5.       page.should have_content("12345")
  6.     end
  7.   end
  8.   context "logged-in user" do
  9.     before(:each) do
  10.       login_as @user
  11.       visit "/"
  12.     end
  13.     it "should appear on the search page" do
  14.       within :css, "script[type='text/javascript']:contains('kissmetrics.com/')" do
  15.         page.should have_content("12345")
  16.       end
  17.     end
  18.     it "should include user id" do
  19.       within :css, "script[type='text/javascript']:contains(\"identify\")" do
  20.         page.should have_content("[\"identify\", \"#{@user.id}\"]);")
  21.       end
  22.     end
  23.   end
  24. end

The drawback of this approach is that the Analytical code is included with every other test that doesn’t need it. With every Capybara test that runs in a browser, this hits DNS, then makes an HTTP request to Google and Kissmetrics. We cannot stub that with VCR or another gem because we’re using a real browser. But we can selectively enable Analytics without a configuration file by emptying the :test block in config/analytical.yml by configuring it before any test that needs it.

  1. before :each do
  2.     @analytical_options = ApplicationController.analytical_options.dup
  3.     ApplicationController.analytical_options = @analytical_options.merge({
  4.         :modules => [ :google, :kiss_metrics ],
  5.         :google => { :key => "UA-12345" },
  6.         :kiss_metrics => { :js_url_key => 12345 }
  7.     })
  8. end
  9. after :each do
  10.     ApplicationController.analytical_options = @analytical_options
  11. end

It helps to be open-source. Looking at the internals of Analytical, its options are processed inside each controller on load, then merged with request options on every request before anything is rendered. The code above updates the configuration between those two steps. Note that since we’re modifying a static we have to make sure to cleanup after ourselves.

 

Grape API Mounted on RACK w/ Static Pages Draft Hidden Sticky

Posted Monday, 30 January 2012 | Post Comment |

tl;dr – the source is here

Here’s how I mount a Grape API on Rack and also serve static pages. Most useful for building a service with documentation.

Setup bundler with the required gems. I am using the next version of Grape (frontier branch and the next version of rack-contrib which contains Rack::TryStatic that we’re going to want to use).

  1. source "http://rubygems.org"
  2.  
  3. gem "rack", "1.3.5"
  4. gem "rack-contrib", :git => "https://github.com/rack/rack-contrib.git", :require => "rack/contrib"
  5. gem "grape", :git => "http://github.com/intridea/grape.git", :branch => "frontier"

Static content goes to a new public folder, for example public/index.html.

Our application will need to boot with all these gems, we’ll do it Rails-style by starting with a config/boot.rb file. It brings in Bundler.

  1. require 'rubygems'
  2. require 'bundler/setup'

Lets define our Acme Grape API that will have a system resource that answers ping requests with “pong”. This goes into api/api.rb.

  1. module Acme
  2.   class API < Grape::API
  3.     version 'v1', :using => :header, :vendor => 'acme', :format => :json    
  4.     resource :system do
  5.       desc "Returns pong."
  6.       get :ping do
  7.         "pong"
  8.       end
  9.     end
  10.   end
  11. end

The application requires Bundler, all the gems in Gemfile and our API. Lets define it in config/application.rb.

  1. require File.expand_path('../boot', __FILE__)
  2.  
  3. Bundler.require :default, ENV['RACK_ENV']
  4.  
  5. require File.expand_path('../../api/api', __FILE__)

Note the odd File.expand_path construct, borrowed from Rails, - it translates a relative path to the current file into an absolute path, there’re allowing us to run the application from any directory – useful for hosting where you never know who boots the application.

Continuing to borrow from Rails, we will want different environments (development, production, etc.), so it’s a good idea to keep things organized. Setup the environment in config/environment.rb and then load the application.

  1. ENV['RACK_ENV'] ||= :test
  2.  
  3. require File.expand_path('../application', __FILE__)

Finally, we need to “rackup” this whole thing in config.ru. We will use Rack::TryStatic to serve static pages when available and pass through to the Acme API otherwise.

  1. require File.expand_path('../config/environment', __FILE__)
  2.  
  3. use Rack::TryStatic,
  4.   :root => File.expand_path('../public', __FILE__),
  5.   :urls => %w[/], :try => ['.html', 'index.html', '/index.html']
  6.  
  7. run Acme::API

Run the application with bundle exec rackup.

image

Full source on Github.

 

How Art.sy uses Github to Build Art.sy Draft Hidden Sticky

Posted Sunday, 29 January 2012 | Post Comment |

I *heart* Github and its magical green merge button. The entire fork/pull/merge workflow has been singlehandedly responsible for a massive amount of open-source contributions by making it so easy! I wrote a quick post on how Art.sy uses Github to build Art.sy on the new Art.sy Engineering Blog, here.

image

 

Octopress: Setting up a Blog and Contributing to an Existing One Draft Hidden Sticky

Posted Tuesday, 17 January 2012 | Post Comment |

Octopress documentation can be quite confusing. It took me a while to understand what the heck Octopress is doing to branches and remote origins. It’s actually pretty simple, so I am going to try to un-confuse you. I will also show you a better way to contribute to an existing blog and explain what’s happening in those Rake tasks.

We are going to deploy a blog to Github pages, so we need a project, such as username.github.com. Go to Github to create one. Use your username instead of “username”.

Next, fetch Octopress and install it locally. This gets the files from its main repository and applies a default theme.

  1. $ git clone git://github.com/imathis/octopress.git octopress
  2.  
  3. Cloning into octopress...
  4. remote: Counting objects: 6046, done.
  5. remote: Compressing objects: 100% (2420/2420), done.
  6. remote: Total 6046 (delta 3448), reused 5549 (delta 3097)
  7. Receiving objects: 100% (6046/6046), 1.26 MiB | 426 KiB/s, done.
  8. Resolving deltas: 100% (3448/3448), done.
  9.  
  10. $ cd octopress
  11. Using /home/dblock/.rvm/gems/ruby-1.9.2-p290
  12.  
  13. octopress$ bundle install
  14. Fetching source index for http://rubygems.org/
  15. ...
  16. Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
  17.  
  18. octopress$ rake install
  19. ## Copying classic theme into ./source and ./sass

Octopress comes with some handy Rake tasks to get you started. To deploy to Github pages run rake setup_github_pages. When prompted, enter the GIT URL to your new repository, such as git@github.com:username/username.github.com.git.

  1. octopress$ rake setup_github_pages
  2. Enter the read/write url for your repository: git@github.com:username/username.github.com.git
  3.  
  4. Added remote git@github.com:username/username.github.com.git as origin
  5. Set origin as default remote
  6. Master branch renamed to 'source' for committing your blog source files
  7. Initialized empty Git repository in /home/username/source/octopress/_deploy/.git/
  8. [master (root-commit) 2a4e9e7] Octopress init
  9. 1 files changed, 1 insertions(+), 0 deletions(-)
  10. create mode 100644 index.html
  11.  
  12. ---
  13. ## Now you can deploy to http://username.github.com with `rake deploy` ##

So what the heck happened here? It pointed our clone to our new repository. It also created a _deploy directory with another git repository that is going to contain everything that is being deployed. The remote in that directory is the same as the one in our octopress directory, but the checked out branch is master. Btw, we’re now on the source branch.

  1. octopress$ git remote -v
  2. octopress    git://github.com/imathis/octopress.git (fetch)
  3. octopress    git://github.com/imathis/octopress.git (push)
  4. origin    git@github.com:username/username.github.com.git (fetch)
  5. origin    git@github.com:username/username.github.com.git (push)
  6.  
  7. octopress$ git branch
  8. * source
  9.  
  10. octopress$ cd _deploy/
  11. octopress/_deploy$ git remote -v
  12. origin    git@github.com:username/username.github.com.git (fetch)
  13. origin    git@github.com:username/username.github.com.git (push)
  14.  
  15. octopress/_deploy$ git branch
  16. * master
  17.  
  18. octopress/_deploy$ cd ..
  19.  
  20. octopress$

Now is a good time to read Blogging Basics. You should edit _config.yml with your blog name, etc. Lets create an article and deploy it.

  1. octopress$ rake new_post["New Post"]
  2. Creating new post: source/_posts/2012-01-17-new-post.markdown

Edit the generated file and add some text at the bottom.

Generate the blog.

  1. octopress$ rake generate
  2. ## Generating Site with Jekyll
  3. directory source/stylesheets/
  4.    create source/stylesheets/screen.css
  5. Configuration from /home/dblock/source/o/octopress/_config.yml
  6. Building site: source -> public
  7. Successfully generated site: source -> public

You can also preview it with rake preview.

Before we deploy the blog, save the source and push it to Github. Note that we’re pushing our source branch.

  1. octopress$ git add .
  2.  
  3. octopress$ git commit -m "Initial blog post."
  4. ...
  5.  
  6. octopress$ git push origin source
  7. Counting objects: 3927, done.
  8. Compressing objects: 100% (1412/1412), done.
  9. Writing objects: 100% (3927/3927), 910.08 KiB, done.
  10. Total 3927 (delta 2257), reused 3848 (delta 2203)
  11. To git@github.com:username/username.github.com.git
  12. * [new branch]      source -> source

You’ll have to repeat the above every time you make changes, to save them.

Deploy the blog. What this does it rake everything inside _deploy and push it onto the master branch.

  1. octopress$ rake deploy
  2.  
  3. ## Pushing generated _deploy website
  4. Counting objects: 84, done.
  5. Compressing objects: 100% (74/74), done.
  6. Writing objects: 100% (84/84), 180.40 KiB, done.
  7. Total 84 (delta 2), reused 0 (delta 0)
  8. To git@github.com:username/username.github.com.git
  9. * [new branch]      master -> master

If you go to http://username.github.com you should see your blog with the blog post once Github has regenerated the pages – usually a minute or two. And on https://github.com/username/username.github.com you should be able to see the generated files on master along with a source branch with the blog source.

You’ll have to do this every time you want to deploy your changes.

So how does one start contributing to an existing Octopress blog (or yourself from a new computer)? What we want is the same setup as above, but not from scratch.

  1. $ git clone git@github.com:username/username.github.com.git
  2. $ cd username.github.com
  3. username.github.com$ git checkout source
  4. username.github.com$ mkdir _deploy
  5. username.github.com$ cd _deploy
  6. username.github.com/_deploy$ git init
  7. username.github.com/_deploy$ git remote add origin git@github.com:username/username.github.com.git
  8. username.github.com/_deploy$ git pull origin master
  9. username.github.com/_deploy$ cd ..
  10. username.github.com$

You’re all set. Create posts and stuff. Happy blogging with Octopress.

 

Octopress: Blogging Evolution Draft Hidden Sticky

Posted Tuesday, 17 January 2012 | Post Comment |

In 93’ I wrote a Guestbook CGI in C++. Then in 94’ I made my first blogging system. I honestly don’t remember what technology it used, but I think it was some hairy PHP with a ton of issues. Data must have been stored in text files or something like that. The technology has since evolved and got hours of work poured into it. This blog’s code is here. But don’t use it. It all works, but it’s proprietary and riddled with legacy. I would have done something very different today. So …

I wanted something modern, fresh, nerdy and open-source for the new Art.sy Engineering blog. Last week I played with Octopress. It was confusing at first, but now feels completely natural and clean. Octopress is fully integrated with Git and Github pages, so we love it. Check it out. Bookmark it. Subscribe to its RSS.

image

There’s also an awesome first post by @mmcnierney14 on responsive layout with CSS3 and a collection of our open-source projects.

 

Paginating w/ Mongoid 2.4.0, MongoMapper and Kaminari Draft Hidden Sticky

Posted Sunday, 15 January 2012 | Post Comment |

I’ve upgraded our project from Mongoid 2.0.2 to 2.4.0. It took me a few days since our specs raised a couple of real issues. If you’re doing the same, take Mongoid from the tip of 2.4.0-Stable.

If you remember, 2.0.2 dropped pagination support and a helpful Kaminari gem took over (details here). Once again the upgrade had a surprise, the number of items on the current page was wrong, displaying the entire count of a collection. I thought this was a bug in Mongoid and created #1584. Turns out that the behavior of count on a Mongoid::Criteria is now aligned with the Ruby driver, which takes a curious boolean skip_and_limit parameter that basically says whether to take limit and skip options into account (doc here). So calling Foo.limit(1).count may return 10 if there’re 10 Foos. The fix is to call Foo.limit(1).count(true). I am going to guess this was a bug in the Mongo driver and the additional of a boolean was a clever fix hack?

Kaminari needed to pass the boolean, which meant adding a current_page_count to the Kamiari collection wrapper, pulled in #194. Next version (probably 0.14.0) will have the fix. In the meantime, I am not super happy with my implementation:

  • It’s not possible to know whether count takes a parameter, method(:count).arity doesn’t provide enough indication for optional parameters, so the code relies on a ArgumentError.
  • MongoMapper needed the same fix, but is lacking a way to pass count to the driver. The current implementation calls to_a, which can’t be good when you just want a count.
 

Warning: Toplevel Constant XYZ Referenced Admin:XYZ Draft Hidden Sticky

Posted Saturday, 07 January 2012 | Post Comment |

I posted this to a Ruby forum a while ago.

I got controllers in a namespace and controllers outside of the namespace. For example, I have a PagesController and a Admin::PagesController. When I run rspec from the top, tests pass and I get the following warning: spec/controllers/admin/pages_controller_spec.rb:4: warning: toplevel constant PagesController referenced by Admin::PagesController. This makes no sense. I do have a PagesController and an Admin::PagesController and specs for both that are declared properly.

This was only happening under Spork, so I posted a similar question to the sporkgem list.

I also found a workaround, to require the Admin controllers first in spec/spec_helper.rb.

  1. Dir[File.expand_path("app/controllers/admin/*.rb")].each do |file|
  2.   require file
  3. end

Finally, @tilsammans figured it out. It’s the same problem as what I have: an Admin namespace and an Admin class.

It was because I also had a class Admin, as well as a namespace Admin. Since Admin was a class (a model) it inherited from Object which made the top-level ApplicationController available inside the Admin namespace. The reply by Andrew White on http://groups.google.com/group/rubyonrails-core/browse_thread/thread/bab5e87ee10d2ecb lead me to find the right answer. In the end I renamed Admin to AdminUser and everything fell into place.

This is rather counterintuitive and one would think Ruby should somehow handle this situation, but it at least makes technical sense.

 

Fabricating Spec Failures Draft Hidden Sticky

Posted Friday, 06 January 2012 | Post Comment |

I love fabricators. We use the awesome fabrication gem that lets you do some pretty neat things in Rails specs.

For example, we have a page that lists users in alphabetical order. The retrieval is implemented in a controller.

  1. def index
  2.   @users = User.asc(:name)
  3. end

The fabricator for a User generates a global sequence to give each user a unique name.

  1. Fabricator(:user) do
  2.   name { Fabricate.sequence(:name) { |i| "Joe #{i}" } }
  3. end

To test the above-mentioned controller, we would fabricate a couple users and ensure that they are returned in the correct order.

  1. it "returns users in alphabetical order"
  2.     user1 = Fabricate :user
  3.     user2 = Fabricate :user
  4.     get :index
  5.     assigns(:users).should eq [ user1, user2 ]
  6. end

What could possibly go wrong here?

I made a beginner mistake that just looks like someone else’s fault (specs fail depending on which order you run them). To get a failed test we fabricate 8 users before this spec is run. The next two users that are fabricated are Joe 9 and Joe 10. When sorted alphabetically Joe 10 comes before Joe 9, duh. It’s a good lesson in not relying on external behavior for tests – in this case we should not rely on knowing how names are generated in a fabricator to test that the users are sorted by name. Instead, we should assign names explicitly.

  1. it "returns users in alphabetical order"
  2.     user1 = Fabricate :user, name: "A"
  3.     user2 = Fabricate :user, name: "B"
  4.     get :index
  5.     assigns(:users).should eq [ user1, user2 ]
  6. end
 
< | 1  2  3  4  5  6  7  8  9  10  11  ... >