Generating Multiple RSpec Files from a Design Document

Ruby, Software Tweaking, Test Driven Development, YAML — Tags: , , , , — Ardekantur @ 10:55 pm

Taking queues from Adam Wiggin’s first commit to his Rush project, simply a design document and some specs, and Err the Blog’s post about BDD and generating specs from YAML, I’ve written a small Rake task that will take a single file design document in YAML and separate it out into the components you specify. For example:

spec/design.yml

Website Integration:
    - should be able to log in from the front page and land at your profile
 
OpenID module:
    - should accept an OpenID URL
    - should return an error message if the URL cannot be reached
 
User:
    - should have a valid user name
    - should return an error if creating a duplicate user name is attempted

And then:

rake design

Takes the section headers, and flattens them as the filenames. So this particular design creates three different files, website_integration_spec.rb, openid_module_spec.rb, and user_spec.rb. They’ll look like this:

spec/user_spec.rb

require File.dirname(__FILE__) + '/spec_helper'
 
describe 'User' do
 
  it 'should have a valid user name'
  it 'should return an error if creating a duplicate user name is attempted'
 
end

And just like that, you have your specs, ready to go!

Here it is:

Please note that it will destroy those files if they already exist, replacing them! I really don’t care if you lose your existing specs! Back them up if you want to try this! You have been warned! This is more of a technique for a brand new project, anyway.

Also, please note that I’ve embedded the rake task as a GitHub Gist paste, so feel free to fork it and modify it. I’d be interested in seeing cleaner, more interesting implementations of my 30-second hack. Additionally, please choose view raw if you want to copy it, seeing as how GitHub seems to bork on a newline character in the code snippet.

Phusion, Rack, Sinatra, and sub-domains

I’ve spent the past couple of hours futzing around with Sinatra and Rack being hooked up to the latest Phusion Passenger, and I’ve come across a bizarre problem. Let’s see what I can illustrate.

I have a Slicehost VPS, and I threw a DynDNS address at it because I didn’t feel like registering a domain name for something that was essentially supposed to be a playground. I set it up so that subdomains would also get redirected to my slice, since I didn’t want Phusion interfering with some PHP, Trac, and SVN stuff I also have running on it. My configuration basically looks like this:

/etc/apache2/sites-available/phusion-passenger

<VirtualHost *:80>
        ServerAdmin webmaster@localhost
        ServerName  projects.example.com
        DocumentRoot /var/projects
        <Directory /var/projects>
                Options -Indexes
        </Directory>
        RackBaseURI /sinatra_test
</VirtualHost>

Then I set up /webapps/sinatra_test, along with the latest version of Sinatra, as outlined on the “Bleeding Edge” section of the Sinatra website. The Phusion Passenger documentation provides instructions on the proper way to format your Rack directories, which includes a tmp directory, a public directory, and a config.ru. Add my actual Sinatra application, and I have a setup that looks like this:

root@slice:/webapps/sinatra_test# ls -l
total 16
-rw-r--r-- 1 www-data www-data  326 Jul 27 15:19 config.ru
-rw-r--r-- 1 www-data www-data  235 Jul 27 15:44 myapp.rb
drwxr-xr-x 2 www-data www-data 4096 Jul 27 05:54 public
lrwxrwxrwx 1 www-data www-data   10 Jul 27 06:13 sinatra -> ../sinatra
drwxr-xr-x 2 www-data www-data 4096 Jul 27 15:46 tmp

All good to go, right? You’d think. There’s some bizarre things going on with Phusion, or Rack, or Sinatra, in terms of discerning correct actions and mapping them to URL endpoints.

My Sinatra application:

myapp.rb

  $:.unshift File.dirname(__FILE__) + '/sinatra/lib'
  require 'sinatra'
 
  get '' do
    "Rootless test"
  end
 
  get '/' do
    "Root test"
  end
 
  get '/other' do
    "Other application part"
  end
 
  get '/other/' do
    "This is a different endpoint"
  end

As well as the config.ru I’m using for it:

config.ru

  $:.unshift File.dirname(__FILE__) + '/sinatra/lib'
  require 'sinatra'
 
  Sinatra::Application.default_options.merge!(
    :run => false,
    :env => :development,
    :raise_errors => true,
    :app_file => 'myapp.rb'
  )
 
  log = File.new("sinatra.log", "a")
  STDOUT.reopen(log)
  STDERR.reopen(log)
 
  require 'myapp'
  run Sinatra.application

And this is what I get when I play with curl.

~ $ curl http://projects.example.com/sinatra_test/other
Other application part

~ $ curl http://projects.example.com/sinatra_test/other/
This is a different endpoint

~ $ curl http://projects.example.com/sinatra_test
Rootless test

~ $ curl http://projects.example.com/sinatra_test/
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /sinatra_test/
on this server.</p>
...

What’s going on? other and other/ are considered different endpoints, which makes sense, I imagine. I’m not an HTTP wizard. Even if the root of the sinatra_test directory and the same root with an ending slash are considered different endpoints, then why wouldn’t I be able to access the latter? Especially with it defined explicitly in my Sinatra application? Even more, especially since if this was a distinction, as in the case of other and other/, but isn’t working the same way for the root URL?

Curioser and curioser. I have no idea if the problem is with Sinatra, Rack, Phusion, or my Apache configuration, and I’ve played around with omitting or specifying explicitly an ending forward slash for the DocumentRoot and RackBaseURI. Some of you may point out that I’ve specified -Indexes for the VirtualHost configuration, but if that isn’t specified, then navigating to http://projects.example.com/sinatra_test/ generates an empty directory listing, since it is pointing to my empty public folder.

So that’s where I am. Any insight would be appreciated, but I’ll keep hacking at it.

EDIT Well, there’s some relief for me - disabling mod_autoindex in Apache does the trick. I’m still not sure how I feel about the two endpoints — one with trailing slash and one with — being distinct, but at least there’s a viable solution. If you don’t have a reason to use mod_autoindex, disable it, and it will stop the interference. If you do need it, I’m not entirely sure what you would do.

Tasko/TaskPaper + Ruby = Awesome

This is the first release of an evolving library that interacts with the online todo-list thingie Tasko. If you’ve never heard of it, or its brother-in-spirit TaskPaper, you’re in for a treat.

Plain text files, converted to To Do lists with simple formatting rules. Lines that end with a colon are project names. Lines with a hyphen starting them are tasks. Use tags on lines to categorize them. @today, @home, whatever. Tag a line @done to cross it out. Simple!

Taskpaper Screen

So now we have Taskomaly, which works on your local machine, interacts with task lists, and can upload them to Tasko using its API. Tasko provides both an API key and a user ID when you register. You need both of these things. Register, then go to your settings page to retrieve them. I suggest placing them in a file in YAML format, like so:

  user: 9999
  key: d9cca721a735dac4efe709e0f3518373

Then, off to irb!

  t = Taskomaly::From '~/.tasks.yml'

Now, get the information you want. Your papers! Make a change, then save them back to the website.

  t.request :papers # ['Paper One', 'Paper Two']
  p = t.papers.first
 
  puts p.name # 'Paper One'
  puts p.body # duh
 
  p.body["@today"] = "@tomorrow"
  p.save # true if groovy, false if failed

This is the first real project I’ve put a huge emphasis on TDD, guided along by the simple principles espoused by Adam Wiggins during his work with the rush shell.

So, yeah. That’s that. Work (and specs) are coming along soon to help you with individual projects inside task papers, searching and using tags, and all kinds of other fun stuff.

EDIT Jesus I forgot to put a link to the project. Here it is. On GitHub. Duh.

On the Edge of Camping: OpenID and Perl Ports

Interesting Links, Projects I Support, Ruby — Tags: , , , — Ardekantur @ 7:56 am

Your favorite ruby web microframework, Camping, has some interesting new developments:

OpenID

That’s right, the framework only 4k large now has basic support for authenticating against OpenID servers. This functionality requires the OpenID gem, but other than that, it looks very simple and easy to implement. You can see the mailing list post that started it all here.

Squatting: A Perl Microframework based on Camping

This may not be entirely relevant edge Camping news, but it is interesting nonetheless. Coder beppu has managed to piece together a Perl microframework that takes the basic simplicity espoused in Camping. If you’re a Perlite at heart or were interested in looking into the language, this might be a good jumping off point. You can read the mailing list post announcement and check it out yourself.

Thoughts about Rails and the Enterprise

Observations, Ruby, Ruby on Rails — Tags: , , — Ardekantur @ 1:09 pm

I know, I know. I said the E word. But bear with me. I’m working with some code right now that, while well-written for the most part, still is written in ASP.NET, and makes me wonder if its levels of intricacies can be managed in Rails. Some of the particular obstacles that would require tackling are:

  • A modular architecture. We provide our product in separate pieces, but they all use the same basic data model on the backend. Having a nice, clean way to install new modules for a client on a dime, and have it integrate with the rest of the web application, would be wonderful. Logins would have to across modules. All workable, but difficult. Is a plugin the best way to modularize part of a Rails application? Is a gem?

  • Batch data insertion. Our clients receive products in bulk, and a form that allows them to insert multiple rows at once, on one web form, while still being RESTFUL, sounds complicated. I’m sure it’s possible, but I’d have to think through it to make sure.

  • Integration with the desktop. Some of our web application’s functionality is relegated to the desktop, where GUI applications keep track of things for us. This is looking more and more possible with Ruby and QT bindings.

So those are my thoughts.

EDIT: And some more thoughts.

  • Auditing. Being able to see every single change that anybody made to an some database objects is an absolute must. Full and complete accounting practices should be available without any extra work on the programmer’s part.

  • Reports. Right now I think we have about 84 separate Crystal Reports files. I’ve been looking at Ruport but it’s hard to tell whether or not it would fit all of our needs.

Next Page »
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.
(c) 2008 Ardekantur | powered by WordPress with Barecity