Love, Software, and Squeals of Delight

March 23rd, 2009 by comment

Dock

Software does more than crunch your numbers or take your picture: it can make you angry or bring you joy. And those are the things that we, as developers, have to tune in to if we want to make our products stand out.

Skitch is one of a handful of products I’ve used recently that remind me what makes a product successful. Utility is important, of course, but the love and emotional connection it engenders in its users is where it’s going to live or die.

Let’s start backwards, with the logo, since it’s the first thing you see. Their logo says nothing about their product’s functionality. There’s no initial, no recognizable signifier (thanks for sparing us the paintbrush), or even an abstract swoop. It’s, um, a heart.

And not just any heart, but a hot-pink, shimmering, pumping, overflowing, disco heart.

They’re not saying, “You might like us”. Or even, “As you can see by the ‘S‘, we’re Skitch”. They’re saying, “This is LOVE, baby!”. You and me!!! (How they’re managing to do that without coming across like Mr. Roper, though, is a mystery that is beyond the scope of this post.)

Now, this Love they offer, it’s not too intense. It’s not Valentines Day Red. It’s not a pushy “when are you going to commit” heart, a dreaded “we have to talk” heart, or even an “I’m complicated, but deep” kind of heart. Just hey, hearts, baby, I’m an extrovert, let’s groove on the dance floor and take some snaps!!!

I focus on this because right there in their identity they align themselves not with Software, but with Love and Play — a great gap to bridge. If the product sucked, it would be one thing. But it doesn’t. It makes bold choices and executes them well. They’re going for the whole tamale, not hiding behind industry-speak, and not afraid of a little heart and soul.

So, they have a lot to live up to. Moving beyond the logo, what does Skitch do that works and how can we learn from that?

It’s makes it easy to get started.
I haven’t taken the time to figure out all the features — in fact, I was too ADD to even watch the whole 3 minute video. But I didn’t need to. The critical 2 or 3 features are easy enough to get right away. Once someone commits, they’ll go deeper, but don’t make them wait, fiddle, or read a manual first. Make your learning curve the equivalent of 140 characters or less.

It does the things you’d want it to do.
This may sound simple, but it’s worth repeating. I wanted to take screenshots, write on them in fun fonts with arrows, then upload them to the web. Bingo. No matter how fun an imagined feature is, the trick is matching it to the intuitive use of your product. If people wouldn’t naturally want to do that thing, drop it. It doesn’t matter how slick it is.

It cuts out the middle steps.
In Skitch, you don’t have to select layers, like in Photoshop, to move items that are separate, such as text and arrows. You don’t have to explicitly save the picture on your desktop and then FTP it to the web — the app does it for you in one click. The designers have figured out your starting and ending points, then cut out all the excess steps in between. Spend time here, trimming the middle.

It makes it fun.
It understands that an application is not just about utility: you’re not just tediously trying to upload a picture to a website or share it with a friend — you’re having a moment in your life. Make that moment simple, and when you achieve that, make it fun.

It makes common actions unexpectedly pleasurable to use.
There are tons of patterns we use all the time when interacting with web and desktop applications. For instance, copy and paste. Copy and paste is great and I love doing it, but the folks at Skitch saved me a couple keystrokes by giving me a fun copy button on the image detail page. It wasn’t necessary per se, but it genuinely improved my user experience. So, don’t try to think about new things you could add: find out what the most integral interactions with your product are. Improve those.

Squeals of Delight
That’s what I did when I first used that copy button. That’s what I did when I clicked “webpost”, heard a whoosh, and saw that my screenshot was now on my very own Skitch web page. Go for the squeals: it means, this feels JUST RIGHT. If someone is squealing with delight (for Love or Software!) they are going to come back.

It’s not all paradise and apples of course.

There are confusing and frustrating interactions, just like in any product. These stand out more, ironically, because they raised the bar so high. So Skitchers, as you move forward, solve these problems for me :)

1. How do I get back to my home skitch page from a specific image page? You don’t really mean for me to click on the back button or delete the rest of the URL in the address bar after furrowing my brow looking for the obvious home link, do you?

2. Uploading. From my Skitch app window, I can’t click “webpost” right away because it first shows me “share”. Only after clicking on the “share” is “webpost” exposed. Since clicking “share” triggers a browser window populated with the Share link that steals focus, I have to tab back to Skitch to webpost. Annoying.

Overall, It was great to look at Skitch because it’s so well done. I think it’s worth taking a product apart to see why it works and how we can use those lessons in our own applications.

And finally, Full Disclosure: I have nothing to do with Skitch.

I just heart them.

ˆ Back to top

Don't go splurging at the widget store

February 15th, 2009 by comment

It is easy for clients, I have noticed, to mistakenly conflate adding widgets, effects and acronyms — Sliders, Sorters, Expanding-Menus, Oh My! — with implementing an idea. The client talks excitedly, rattling off a Rube Goldberg chain of widget-to-widget interactions, their voices rising, the importance of each and every widget in the chain perceived critical to the achievement of the Internet Holy Grail: Angel Investment. Or at least, a really slick site.

Don’t get me wrong. I think everyone is in favor of a well-placed widget.

They can be so smooth and beautiful that you gasp. They can glow yellow for just the correct duration before fading to white (“where has that beautiful apparition gone?”, you wonder, before drunkenly clicking again. And again. And again.). They can add an item to a list almost magically: never was it so fun to have so many things To Do. They can save you clicks, keep you in one place, slide items into carts with almost illicit ease.

In short, they can make things so simple that a tear comes to your eye, and you rush off, hat in hand, in the quest of The Holy Spinner to deliver your payload.

The Holy Spinner

But stop.

What are you looking for? Forget the elevator pitch, as it can be intoxicating: the sound of your voice, people nodding enthusiastically, the doors shut blocking their escape (especially if you are stuck between floors). Instead, do the quiet room test. You alone. Your idea. Naked. A convergence of souls.

“What do you need, Idea”, you ask, “in order to fully manifest your glorious Idea-ness?”

If your idea is quiet, do not rush to speak for it. If your idea speaks but is simple, do not scoff. Do not dress your idea up in Widget Drag, so it looks like a teenager searching for their identity at the Web 2.0 Store. If your idea does not need a Yellow Fade or slider, that is OK. If you remove the slider and yellow fade and find there is no idea underneath, that’s OK, too. Go for a walk. Another idea will come.

Think about building a UI like listening to the ones that you love. You observe them. You listen to their likes and dislikes so your gifts will please them, not reflect your tastes. It’s not about the shiny present: it’s about the connection, the need anticipated and met, a little bit of the edge taken off. Brush cleared, the path made simpler.

If you’re tempted to drive up to your date in the red corvette of ideas — or wow your user with the accordian navigation ’cause it like, opens and closes! — remember that you might be saying more about yourself than anything else.

And then ask yourself: Do you need that rainbow-colored slider on your site?

ˆ Back to top

Good programmers aren't lazy

February 8th, 2009 by comment

It goes something like this. A really good programmer, who obviously does not have a lazy cell in his or her brain (the body is another matter entirely!) declares, “I program because I’m too lazy to do the same thing again and again!”.

Variations abound, all coming back to the idea that “laziness” == an aversion to repetition.

Really?

It’s a fallacy, like the skinny girl standing in front of you declaring, “I’m so fat!”. It’s a cry for attention that points out the obvious opposite, and generates a protest, spoken or not. “No, you’re not! You’re (skinny|smart|efficient)!”

Some of the worst code I’ve ever written has been when I’m in genuine lazy mode. Laziness makes you not mind if you copy and paste a function 40 times without abstracting it. Laziness lets you avoid figuring out how to do something better, because you really don’t want to think about it. Laziness lets you put off finding a solution, copy code without understanding it, hard-code values in your applications, or stuff inline css in your html tags ‘just for now’.

Laziness is the ability to tolerate boredom and inefficiency. Good programmers lack that tolerance.

For programmers who still hide behind that phrase, it’s time to drop it. Try something else, like “I am unable to be bored”, “I cannot tolerate repetition”, or “my skin itches and I start squawking when I see DreamWeaver-generated JavaScript”.

Simplicity and elegance are hard. Striving for them is many things, but not lazy.

ˆ Back to top

Using YUI DataTable with Rails

February 7th, 2009 by comment

I am currently working on an Rails app that integrates the YUI dataTable, and in going through the tutorials I noticed they are all assume a PHP back-end. I also saw a number of people asking how to get this to work with a Rails controller, so I thought I’d write up my experience in the hopes that it helps someone else. For basic info about setting up the dataTable, refer to the YUI site, linked above. I’m also going to try to clarify a few things that I found a bit obscure.

To create a dataTable you have to define a few basic ingredients:

  1. A dataSource. This defines where the info in the table comes from, and what format it is returned in. I’m using JSON.
  2. A schema that you define. This is a part of the dataSource and is essentially a map to your data. The schema tells the table where to find the field values.
  3. An array of column definitions. You supply the name and “key” of each column and any additional information, such as whether it is editable (and if so, which editor to use) and how to format the data inside the column if you don’t want to just spit it out directly.

Let’s start with a dataSource. In this example, we’re making a table of tasks, so I want to hit my tasks controller to return the data. Standard Rails controller action. In the code snippet below,

  1. in line 1, I supply a URL (note that the url ends in .json, and in my controller I have a responds_to block which constructs my json response).
  2. In line 2, I’m telling the dataSource — hey, you’re gonna get some JSON.
  3. And line 3, is where we define the responseSchema, which has two critical parts: the resultsList and the fields.
  var dataSource = new YAHOO.util.XHRDataSource("/projects/13/elements/21/tasks.json");
  dataSource.responseType = YAHOO.util.XHRDataSource.TYPE_JSON;
  dataSource.responseSchema = {
   resultsList: "Resources.data",
   fields: [
      {key:"task.id"},
      {key:"task.status"},
      {key:"task.percent_complete"},
      {key:"task.description"},
      {key:"task.due_date", parser:date}
      ]
  }

Let me be clear since I got hung up on this a bit. You as the application developer are responsible for two things. One, constructing your response — in other words, you can build your JSON response any way you want, with any keys, values and hierarchical structure that make sense (though it will help you to think it through and standardize it, Satyam has some good info on that here). And two, telling your dataSource how to navigate your response: i.e. — where do find what the data you’re looking for (the needle) in the response (the haystack of JSON)? This is the schema, the map of your data.
Controller code that creates my custom JSON:

# tasks_controller.rb
def index
 respond_to do |format|
      format.json{
         tasks = []
         @tasks.each do |task|
           task_container = {}
           task_container  = task
           task_container['editable_by_user'] = permission.edit? # some metadata I use
           task_container['deletable_by_user'] = permission.delete?
           task_container['resource_name'] = "task"
           tasks << task_container
        end
        data = {"Resources" => {"data" => tasks}}
        render :json => data.to_json
      }
  end
end

And just for fun, here’s a look at the JSON my controller gives me back when I hit this url ‘/projects/13/elements/21/tasks.json’.
The JSON:

{"Resources": {"data": [{"task": {"status": "not_started", "started_on": null, "updated_at": "2009-02-07T22
:03:18Z", "project_id": 13, "percent_complete": null, "high_priority": null, "element_id": 32, "deletable_by_user"
: true, "completed_on": null, "editable_by_user": true, "element_title": "looking good", "id": 50, "created_by_id"
: 7, "resource_name": "task", "description": "Pass the stimulus bill", "assignments": [], "due_date"
: "", "users": [], "resource_url": "/projects/13/elements/32/tasks/50", "due": null, "created_at": "2009-02-07T22
:03:18Z"}}, {"task": {"status": "not_started", "started_on": null, "updated_at": "2009-02-07T22:03:39Z"
, "project_id": 13, "percent_complete": null, "high_priority": null, "element_id": 32, "deletable_by_user"
: true, "completed_on": null, "editable_by_user": true, "element_title": "looking good", "id": 51, "created_by_id"
: 7, "resource_name": "task", "description": "Negotiate without pre-conditions", "assignments": [], "due_date"
: "", "users": [], "resource_url": "/projects/13/elements/32/tasks/51", "due": null, "created_at": "2009-02-07T22
:03:39Z"}}]}}

So that’s it! I’ve defined this JSON array and built it, then returned it from the controller when I get a .json request.

Now that you’ve seen the response, take another look at the responseSchema (you created above) and the two properties that you set:

  1. ResultsList. Notice it is set to “Resources.data”, which are the JSON keys I used. It uses dot-syntax to point to array of tasks in my json.
  2. Fields. Again using dot syntax, and having the ResultsList array to navigate through, it can pull the specific values it wants from the list; so ‘task.status’, ‘task.started_on’, etc., will retrieve those values from the response.

Make sense?

You are now one step away from being able to see your table. So, create your column definitions, an array of data about each column in the table. This is also where you can specify formatting and editing information (not covered in this article).

var columnDefinitions = [
  {key:"task.status",formatter:"formatPriority", sortable:true},
  {key:"task.percent_complete", label:"Percent Complete", sortable:true},
  {key:"task.description", label:"Description"},
  {key:"task.due_date", label:"Due Date", editable:true,sortable: "true",formatter:YAHOO.widget.DataTable.formatDate, editor: new YAHOO.widget.DateCellEditor({resource:'task', updateParams:"task[due]"})}
  ];

Notice that each column definition has a key: this key must be accessible in your JSON, AND it must be defined as a field.

And then you create your table. The first argument is the id of a div on the page to which the table will be attached, the last is an optional configuration hash (pagination, anyone?).

var dataTable = new YAHOO.widget.DataTable("project_tasks", columnDefinitions, dataSource, optionalConfigurationHash);

I hope this is helpful to get you started with the YUI dataTable on Rails. I may do further posts on XHR editing of individual cells in a dataTable using Rails.

ˆ Back to top

An Attachment Walked Into A Bar. Was That U, Fu?

August 22nd, 2007 by comment

I recently spent some time working on a Rails application that needed to have various kinds of attachments, such as PDFs and images, for various types of resources, such as Programs and Questions. The app in question lets you create programs and questionnaires for the purpose of granting continuing medical education (CME) credits to doctors — so they’re apprised of the bleeding edge techniques for sawing off your arm or tying your tooth to a doorknob. Not that this matters for the piece, but context — like sugar or salt — makes things go down easier.

If you can picture an office of harried administrators dealing with ever-changing AMA requirements — “This brochure needs to go with this program!”, “This xray picture needs to go with Question 7″, “This program needs to sing ‘Missing You’ while showing you diagrams of a root canal”.. (OK, maybe not the second item), you’ll see why I wanted to build a system that could expand easily. I did not want to find myself in the position of trying to look tough while shamefacedly muttering, “I’m sorry, PDFs can only go with *Programs*, as you initially specified” and watching these not-so-gentle administrative souls stare at me with fully warranted incredulity. Blaming the client is like [fill-in-the-blank]: weirdly fun for about 10 minutes before the hangover sets in.

This project turned into a tour of attachment_fu, single table inheritance, polymorphism and functional testing of uploads. Thanks to input from friends, blogs and the usual Internet suspects, I got it up and running in its first form and decided to write it up. Hopefully what I’ve learned can help someone else. “Link-outs”, the reclusive programmer’s form of the “Shout Out” (aka a list of great resources), can be found at the bottom of the article.

Goal

To implement a system that would allow for many types of files to be uploaded and attached to many types of resources.

Requirements

  1. Many types of assets (image, pdf, etc.)
  2. Assets belong to many types of resources (program, question, etc)
  3. Assets upload to the file system
  4. Assets validate in the context of their parent resource [you upload the pdf in the program form; the image in the question form, etc]
  5. All functional tests pass for uploads

Design

Rather than have database tables for each attachment type (PDFs and images, then eventually MP3s) I made one table called Assets. Listening to my requirements, a friend suggested setting up my Assets model using polymorphism and single table inheritance and that I look into attachment_fu for the uploads. For this exercise I will only be focusing on the PDF upload. Readers can extrapolate from there for image or other media types. This article does not address image resizing, or anything related to uploading images. There are some great links at the bottom that deal with these topics in depth.

Modeling the domain:

Assets (the table) has a field called type that is be [PDF, Image (etc)]; a field called resource_type which is the name of the class it belongs to, [Program, Question, etc.] and resource_id which is the id of the resource it belongs to.

The Asset class will inherit from ActiveRecord. PDF and Image (and any future file types we add to the system) inherit from Asset. Line items from Assets (the table) will look like this (leaving out the other fields for now)

type   | resource_type | resource_id

Pdf      | Program         | 82
Image  | Question         | 79

For my assets, I created the following models:
asset.rb, image.rb and pdf.rb. The latter two inherit from Asset.

# [Asset.rb]
class Asset < ActiveRecord::Base
  belongs_to :resource, :polymorphic=>true
end

# [Pdf.rb]
class Pdf < Asset
  belongs_to :program
  has_attachment  :content_type=>'application/pdf',
                         :storage=>:file_system,
                         :path_prefix=>'public/uploads/pdfs/',
                         :size => 1.megabyte..3.megabytes
  validates_presence_of   :content_type, :filename

   def validate
     if filename &&  /pdf$/.match(filename).nil?
         errors.add(:filename, "must be a PDF ")
     end
  end

end

Because I am using attachment_fu, I need to have a set of basic fields in my table that will handle image and file uploads. The migration I created looks like this:


t.column :parent_id,  :integer     # for the thumbnails of resized images, required for plugin
t.column :type, :string               # for STI on this table (curent types are image, PDF)
t.column :resource_type, :string  # for polymorphism on this table (current types are Program, Question)
t.column :resource_id, :integer    # for polymorphism, (program_id, question_id, etc)
t.column :content_type, :string    # Fields here [content_type] and below all attachment_fu requirements
t.column :filename, :string
t.column :thumbnail, :string
t.column :size, :integer
t.column :width, :integer
t.column :height, :integer

To create the relationship for my parent models (question and program) I set up the polymorphic relationship like so:

# [program.rb]
class Program < ActiveRecord::Base
   has_many    :pdfs, :as=>:resource,  :dependent => :destroy
end

# [question.rb]
class Question < ActiveRecord::Base
  has_many      :images, :as=>:resource, :dependent => :destroy
end

Note the difference between delete and destroy. Destroy will remove the entry from the database and the file from the filesystem. Delete will only delete the database entry.

Once this is set up, you can test it in the console and see the magic of Rails at work. Through the column names and relationships we've built, entries in Assets are automatically created. It's one of the things that's great about Rails. It doesn't simply describe different modeling patterns: it implements them if you set up your code correctly. It's a beautiful thing.

Uploading

Without moving files to the server, the system is not complete. So, onto attachment_fu. The attachment_fu tutorials I found online all made the assumption that the attachment you are uploading is an entity of its own, in its own form: a mugshot, for instance. My case was different: I needed to embed the attachment in the forms for their parent resources (pdf in the program form; image in the question form, etc) rather than independently. So I needed to validate a form for more than one model. In my _form.rhtml partial for program I have the pdf field like so:

# [views/program/_form.rhtml]

< label for="program_notes" >Notes
<%= f.text_area :notes %> # ... more fields ... < label for="program_status" >Add Brochure? [PDF Files only]< /label > <%= file_field("pdf", "uploaded_data") %>

This means that both a pdf object and a program object are being passed back to the program controller. Since we know that a program has_many pdfs, we can use program.pdfs.build in order to create -- then validate and ultimately save -- pdf objects.

Validating in context of parent resource:

I needed to check for errors with my program fields and my pdf field. This snippet is what I ended up with. The second line, validate_and_build_pdf is just a result of refactoring: it allows the validation methods to be run if you select a file through the upload file field (so if you try to upload a gif, the validation in Pdf.rb will squak) -- but not if you just leave that field empty.

#[programs_controller.rb]
def create
  @program = Program.new(params[:program])
   validate_and_build_pdf(params[:pdf],params[:pdf][:uploaded_data])
   if @program.save
      flash[:notice] = 'Program was successfully created.'
      redirect_to :action => 'list' and return
   else
      render :action => 'new'
   end
end

# this method stops program from saving the asset if the field is blank,
# and returns type-errors if relevant (files not PDF)
def validate_and_build_pdf(fileParams,file)
  if Asset.is_valid_file?(file)
     @pdf = @program.pdfs.build(fileParams)
  end
end

The reason for the Asset.is_valid_file? method was the same: if no file was uploaded an entry was still being made in the assets table due to the polymorphic relationship. So I had to make sure I was dealing with an actual fileobject, not an empty field. Since this would be used across the application for all types of file uploads, I made this a class method of Asset.

[Asset.rb]
# Checks that the object is one of the following types before running validation on it
def self.is_valid_file?(fileObj)
  if fileObj.is_a?(Tempfile)|| fileObj.is_a?(StringIO)
     || (defined?(ActionController::TestUploadedFile) && fileObj.instance_of?(ActionController::TestUploadedFile))
     true
  else
     false
  end
end

You may be wondering what's up with the ActionController::TestUploadedFile condition -- it's because when you run functional tests of uploaded assets, that is what they are -- they are not instances of fileObj.

Once it's determined that you're dealing with a valid file and you hit custom validation methods (such as informing the user that the file needs to be a pdf), you can include them with your program error messages so you only get one messages box at the top of your form, not two:

<%= error_messages_for :program, :pdf %>

Pass Functional Tests

This part is where you test all your uploads from your functional tests. To test uploaded files, you need to put files in your fixtures/files directory then build your tests.

# [programs_controller_test.rb]
def test_create_with_pdf
  fdata = fixture_file_upload('/files/semi.pdf', 'application/pdf')
  num_programs = Program.count
  post :create,   :multipart => true,
  :pdf=>{"uploaded_data"=>fdata},
  :program => {:name=>"Newest Created Program",
                    :is_ongoing=>1,
                    :status=>"Edit"}
  assert_response :redirect
  assert_redirected_to :action => 'list'
  assert_equal num_programs + 1, Program.count
end

I had a gotcha here -- I realized that I has to have the pdf array separate from the program array (since in the form it’s field_for pdf). I fixed it by submitting two objects, program and pdf, to the controller, seen above.

Finally, running the functional testing leaves files on the file system and they should be deleted at the end of all tests. So I added a destroy method in the teardown, which removes them.

def teardown
  Pdf.find(:all).each { |p| p.destroy }
end

Failing Upload Tests
Just to check that only Pdfs can be uploaded for programs, I added a handful of other file types to my directory and created an array of invalid file types in my setup:

# [programs_controller_test.rb]
def setup
 # other stuff....
 @invalid_files = [['lipsum.doc',"application/doc"],['lipsum.rtf',"application/rtf"],
             ['lipsum.txt',"text/plain"],['squiggle.gif','image/gif' ],
             ['squiggle.jpg','image/jpg' ], ['squiggle.png','image/png' ],
             ['squiggle.psd',"image/x-photoshop"],['squiggle.zip', 'application/zip']
             ]
end

and created a test to check these uploads will fail:

  def test_create_with_invalid_file_types
    @invalid_files.each do |name, type|
      fdata = fixture_file_upload('/files/' + name, type)
      post :create,   :multipart => true,
                      :pdf=>{"uploaded_data"=>fdata},
                      :program => {:name=>"Newerest Created Program",
                             :is_ongoing=>1,
                             :status=>"Edit",
                             :start_date=>Time.now.tomorrow,
                             :end_date=>''}
      assert_response 200
    end
  end

This gave me peace of mind that my files are being uploaded, only the right types are accepted, and all is good in the land of PDFs and Programs. And voila, we are done and on to the next task.


Link Outs

Here's a listing of various online resources on the topics covered in this post. This should be enough for a good start. Happy Uploading!

ˆ Back to top

Sprites in the Machine: Selenium Remote Control on Windows

June 15th, 2007 by comment

The first time I was played with Selenium (the IDE) was a jaw-droppping moment. It was as if little sprites had taken over my computer and were gleefully doing my job. Sitting back and watching a form being filled in, a button selected, links linked — it was an incredible, mafia-man type experience: things were just getting done, and fast. The little guy rushed through my tasks in seconds, cheerfully, leaving green check-marks in his midst, while I sat back and kind of stared, the way you’re supposed to stare at a national monument. These days there are too many hot-dog stands and camera-d tourists at national monuments to merit my awe, but it’s safe to say that my little browser sprite was stepping up to the plate nicely. One could get used to this, I thought. Me, the sprite, and Firefox: what could be wrong in the world?

This didn’t last (amazing how quickly one gets spoiled). The problem with Selenium IDE is that the tests only play back in Firefox. I love Firefox, but the whole gist of my job is that the stuff we do needs to work in all browsers, on all machines (ok, most on most, but you get the idea). At any rate, I went looking for how I could extend the power of Selenium so I could test my web apps cross browser.

There are two approaches: Selenium on Rails (not covered in this article but you can find info here), and Selenium RC (Remote Control). After poking around a bit it seemed that RC was the solution for me. I was testing old apps, not Rails ones, so the Rails solution was overkill — and I had heard a general buzz that RC is a more robust, ‘best-practice’ solution. Whether that’s commonly held wisdom I can’t say (and if anyone wants to do a comparison, I’d love to hear), but it fit my requirements so I dove in.

If you’re not familiar with what Selenium RC lets you do, here: it lets you write tests in most languages (java, perl, python, ruby, php (NOTE: at the time of my testing I could not locate 0.9.1, with php support. It may be available now)) and then run them from the command line. Assuming the selenium server is running (see steps below), a proxy browser is fired up and your script is executed. In short, a browser opens and is interacted with. Each test is run and you’re fed a success or error message. It’s the same process you see when you run tests back using the IDE: your application being lovingly and quickly manhandled by invisible testing men (though based on the current online discussions I should probably make it clear that the gender of the magic sprites is unknown and irrelevant — and that they do not want to have sex with you, even if they are running in heels :) )!

To the docs

The openqa docs are great resources. My one caveat is I would suggest a larger font and a clearer navigation scheme. It’s all there though, and it works, so read carefully, try the examples, and be patient.

From here on out I’m going to transcribe the steps I took to get up and running. This is the order I did things, so hopefully this is helpful as a list of steps and guidelines:

STEPS To set up Selenium RC on Windows

  1. Read the openQA tutorial:
  2. Download selenium RC here: [NOTE: 0.9.1 says it has php but I couldn't find it anywhere. I got 0.9.0]
  3. Extract it using winzip
  4. Put in your c dir (or wherever you keep programs), like so: c:\selenium-remote-control-0.9.0.. I renamed it to selenium, so mine reads c:\selenium. NOTE: make sure you have right java version by typing java –version in your cmd shell. You must have at least 1.5 (1.4???)]. If you don’t, upgrade your java.
  5. Put selenium.rb in your ruby lib dir so it will be accessible to ruby using require ‘selenium’. If you don’t do this you’ll have to run your scripts from w/in the same directory as selenium.rb: you don’t wanna do that. For me I put it in C:\ruby\lib\ruby\1.8\selenium.rb
  6. Start Server. You need to run from cmd line from WITHIN your selenium\server dir [ in my case c:\selenium\server] or feed it the path. [NOTE jar is Java Archive: To run an application packaged as a JAR java -jar app.jar]
java -jar selenium-server.jar --interactive.

At this point you can execute commands on the command line or you can execute a standalone script. There are commands in the tutorial that you can follow along with. To do the latter (execute a program), simply navigate to a test (there’s one in ruby/samples called selenium.rb ) and run it. The one that shipped with my ruby opens google and searches for the string “Hello World”.

C:ruby\\samples>ruby selenium.rb

Once this was done, it was time to start working on a real app. I had an 4 y/o php app in a frameset that I decided to use for testing. Motivation: if I got this stuff working, I would never have to manually slog through all the test cases on that app again. Motivation enough!

Making your tests

You can do this one of two ways: Read the API and manually code your tests in your language of choice (I was using Ruby), or, create your test cases by recording your actions in Selenium IDE (in Firefox) and then save as a .rb script. [File-->export tests as...]. The latter is the much more efficient solution: it’s quicker (do instead of write), and it’s a quicker way to learn the API. Not sure what the method for selecting a frameset is? Just select the frameset in the IDE, export, and the script will come out with that method written right in. It’s @selenium.select_frame “framename” btw.

The way I proceeded was to create (record) an individual test for each action. Because it’s a web app and not a unit test, each test has lots of smaller steps in it that create the overall story of what you are doing. Some of my examples are: create_program, create_test_one_question_no_domains, add_evaluation_to_test, add_test_to_program, etc. The same sorts of things we’d give in a list to QA. You can tell what they are by the titles, which is a common-sense way to keep things clear: descriptive naming is the name of the game. When done, I could run each test from my command line, like so:

ruby create_program.rb

and the browser would open and go through all the steps to, in the case above, create a new program in my application. However, this was repetitive: each individual test used the same setup method and only ran itself. So, I created a master suite called createProgramAndTestSuite.rb. I pasted my individual tests as methods into this class, so that in running the suite I’d be executing all the individual actions (tests) necessary to test this part of the app. Now, one line could run my 16 tests at once:

ruby createProgramAndTestSuite.rb

And, bingo: all my previously individual tests: create_program, create_test_one_question_no_domains, add_evaluation_to_test, etc. were all run in one fell swoop.

The other beauty of consolidation it allows you to take advantage of the setup method. The setup method is run before each test so you can start each individual test where it needs to start — rather than backing up to login or some equivalent “setup” (hence the name) actions. You get most of this for free: tests exported from Selenium IDE come with auto-generated setup and teardown methods that you can leave or modify. Also, note that you can customize your variable names and script conventions in the IDE by going to Options->format and choosing the language you’re working with. Putting all my tests in one suite allowed me to DRY up my repetitive setup actions in one place.

My final setup for the suite looks something like this — I added a bunch of stuff to log me in, select the main frame and gets me ready for each individual action.

def setup
@verification_errors = []
if $selenium
@selenium = $selenium
else
@selenium = Selenium::SeleneseInterpreter.new("localhost", 4444, "*firefox", "http://urlofapp.com/", 10000);
@selenium.start
@selenium.open "http://urlofapp.com/admin/admin.php"
@selenium.type "staff_email", "secret@email.com"
@selenium.type "level_passwd", "magic_password"
@selenium.click("login")
@selenium.select_window "main"
@selenium.wait_for_page_to_load "30000"
# more stuff
end
end

the teardown (again run after each test) is the default from the IDE (I did not change this).

def teardown
@selenium.stop unless $selenium
assert_equal [], @verification_errors
end

And my test methods are pretty straightforward — here’s a few lines just to give you an idea of what it looks like:

def test_create_new_program
@selenium.click "link=Programs"
@selenium.wait_for_page_to_load "30000"
@selenium.click "link=create program"
# more stuff
end

def test_create_test_one_question_no_domains
@selenium.click "link=Questionnaires"
@selenium.wait_for_page_to_load "30000"
@selenium.click "link=create questionnaire"
@selenium.wait_for_page_to_load "30000"
@selenium.click "submit"
@selenium.wait_for_page_to_load "30000"
@selenium.type "test_name", "Selenium: Test
# more stuff
end

Testing is verbose and simple. You write a lot, but, like with most tests, I found I relied on a few basic calls again and again. The typical browser work-horses are going to be select, type, click, wait, etc. I found I had to use wait_for_page_to_load a lot. But there’s an API in the contextual menu if you have the IDE installed (right click when you’re recording tests and you’ll see the showAllAvailableCommands submenu that you can insert into your recording tests). Or, you can check out the Selenium API online.

As a result of executing (and recording) all the actions once in the IDE and doing some copy-pasting and rearranging, in a few days you can have a library of test suites for your application, and voila! your app is not only running itself, but, more importantly, testing itself. You no longer have to run these by hand, you can spot errors more quickly, you can test simultaneously on multiple platforms, and you can easily pinpoint, and fix, failures. It’s a beautiful thing.

Of course, there are lots of complicated browser interactions, especially nowadays, that are not easy (or possible) to test in Selenium. Apps using drag-and-drop, for instance. And if you get into RJS or other types of javascript browser effects that we associate with “web 2.0″, you’ll need to look elsewhere. Actually, if folks know resources or have experiences in this domain, please post to the comments so we can build a resource. But, outside of these cases, Selenium RC is great for running acceptance tests. It’s easy to set up, well integrated, and, most importantly, highly addictive.

Happy testing!

ˆ Back to top

DIY Binary Hands, base-CAT, and counting to 10 (or is it 2)?

April 19th, 2007 by comment

Some time ago, I was learning binary operators and struggling to understand the base-2 system of counting. It felt very foreign to me. My friend Zack explained that the reason we use base-10 is really related to the fact we have 10 digits on our hands: i.e., it’s easy and comes naturally. Most people don’t even think of it: it’s just how counting “works”. But, base-10 or “decimal” is not the only counting system, and not the best for every usage (for instance, in computers the binary system makes the most sense because it’s easy to implement electronically). Nor is it the only counting we can do with our hands! In this post we’ll make our very own pair of binary hands that can count, not only to 10, but to 1023… Here goes.

Before getting to the fun part (making hands at home!) it’s worth mentioning that the main difficulty in learning binary is that while describing binary one is often compelled to compare the number to decimal, because we think in decimal so naturally that it seems like it’s the only “real” way of explaining a quantity. This leads us to conflate the representation of the quantity (say, 2 [decimal]) with the fact of the quantity (say, a pair of cats) and treat them as if they are one and the same. When in fact, a numeric description is just that: a description of a quantity. And depending on the base used, one of many possible descriptions of the same quantity. This was a problem for me and is for others, often leading to long transliteration exercises such as: 10[binary] == 2[decimal] followed by a string of powers and multiplications explaining why. What gets lost in the shuffle is the fact of the pure quantity of the measured, which is independent of the base describing it. In this post, I’ll append the string [binary] to digits in base-2, and the string [decimal] to digits in base-10, to make reading easier.

Now, just so you don’t feel cheated, here is that string of powers and multiplications I mentioned above (and again, read wikipedia for a full explanation). So, in binary, the digits “10″ don’t equal the quantity of ten[decimal]: they equal (in decimal): two. This is because:

(1 x 2^1) + (0 x 2^0).
In other words, 2 + 0. Or, two[decimal].

In decimal, the digits “10″ equals ten because it works out to:

(1 x 10^1) + (0 x 10^0).
Or,  10 + 0. Ten [decimal].

Now, here is the same digit-al representation but getting at the underlying quantity of the represented. What do we have here? A pair of cats, eating dinner.

base cat

How many cats is that? You could say there are 10[binary] cats eating dinner. Or 2[decimal] cats eating dinner. But, as William Shakespeare famously said, “A cat in any other base will still eat dinner”.

The fun part:
Despite the fact that it’s relatively simple to get on paper… and when you start using base-cat, it’s almost graspable, it can be hard to reach the “aha!” moment where counting in binary makes natural sense. It’s like cursing in french: you want it to come out easily as cursing in, say, cartoon:

"*#$&!!" == "merde"

The point is, no matter how you say it, you’re still having a bad day! It’s just that, as some bases are more suited to building computers than others, some languages are more suited to inclusion in PowerPoint presentations than others. Speaking of french translation, bad days, and DIY, can you translate “vas te faire encule” to binary? Once you start playing with the hands, I’m sure you can! (hint: it’s 132[decimal], represented in 10 bits, and it’s not work-safe!:)).

Anyway, working towards that moment of enlightenment, we went through the binary finger exercises (a fun java applet is here), which were new to me at the time. To better concretize the system for myself, I took a pen and marked up my knuckles and the pads of my fingers so I could see both the decimal numbers and the binary numbers, as well as their relationship (up, or “on” is represented by 1: down, or “off”, by 0).

I’m a hands-on learner, pun partially intended: the more I can see or demonstrate a concept in human-space, the better I understand it. But, since I was planning to wash my hands before I had fully mastered the new counting, I decided to make permanent versions, to keep and refer to always.

Here’s how you can do this at home: (What am I learning again?)

Materials Needed

1. Hands, 2, preferably yours.

2. Cardstock

3. Pen

4. Scissors

5. Refrigerator magnets (optional)

6. Refrigerator (optional, but really nice to have)

Steps:

1. Trace the outline of both your hands on the cardstock, fingers spread like you’re making a thanksgiving turkey.

2. Cut them out.

3. Place the hands, palms-up, on the table in front of you. On the base-pads of the “fingers”, counting in base-2, start from “1″ at the base of your right thumb. You will get up to 512[decimal] by your left thumb. 1,2,4,8,16,32,64,128, 256,512

4. On the front-tip of each finger, draw a 1

5. Fold the fingers down, and draw a 0 on the knuckle of each bent finger. When the finger is folded, it should obscure the digit on the palm of your hand so that all you see is the 0.

To count:

You can count to any number, up to 1023[decimal] — which is a lot of cats! — by raising and folding your fingers. Notice that each finger represents 2 raised to the next power, which is what base-2 (or base-anything) means. You will be able to see the binary representation of each number from the configuration of 1s (raised fingers) and 0s (folded fingers).

When a finger is raised, and you can see the number on your palm, that bit is “on”, represented by the visible number 1. When a number is obscured, it is “off” and you do not count it: what you see instead is the 0 of your folded knuckle. The number (in decimal) that you reach will be the sum of the visible digits on the palm of your hand.

So, for instance, to get to 1023[decimal], which is the highest you can count with 10 fingers, you’d have all 10 fingers raised so you can see all the digits, like so:


e.g., 1+2+4+8+16+32+64+128+256+512 = 1023[decimal]

Likewise, to get to 0, fold all your fingers: it’s that simple. Of course, there is no need for 10 bits to encode the value of 0 — we’re fine with 1 bit. But, since in this example we’re using our hands and can’t very well lop off our other 9 fingers, it makes sense to just keep them folded. In short, [0+0+0+0+0+0+0+0+0+0+0=0].

Using the combination of refrigerator magnets or just bare or paper hands, challenge yourself to count to any number between 1 and 1023[decimal]. Represent household quanties of items in binary. Fold and raise the appropriate fingers so the visible sum adds up to the number you’re thinking of or looking at, and then read the binary representation of the number in the 1s and 0s of your fingertips and knuckles.

A few other examples

How about 61[decimal]? [32 + 16 + 8 + 4 + 1 = 61].


Or, 449[decimal]:[256 + 128 + 64 + 1 = 449]

You’ll see in the final picture, a yellow rabbit came on the scene. It is a little-known fact that yellow rabbits excel at counting in base-2.

In closing

What I think is the most interesting about this is thinking of what other “real world” implementations you can come up with to represent otherwise abstract principles. When you can start to translate concepts into your own space it allows you to “get” them in a way you might not just reading about them on paper.

I’d love to see other examples of this — how high could you count if your feet were involved? What would base-8 hands look like? What are particularly obtuse concepts you’ve mastered that could be extrapolated using paper, scissors, refrigerator magnets and household pets? Sharing welcomed — and happy counting!

ˆ Back to top

Getting started with YUI's Connection Manager in Rails and PHP; or "All Happy Families Are Not Alike"

February 28th, 2007 by comment

This post is geared towards folks who haven’t done the A part of AJAX before (And I mean the first A, as in Asychronous); are new to Yahoo’s implementation of the XMLHttpRequest object (The Yahoo! Connection Manager) and would like added information on how that works; or bothThis is not meant to supplant the excellent yui! tutorials which you should read in detail for thorough explanations and examples. What I am adding here are a few examples of using this in the Rails framework and some thoughts on the callback object and scope.

Your “AJAX” goals are simple: you want to communicate with your server, get a response back that you can use (or not), do something with that response (or not), and move on. As this is asynchronous, you want to do this without reloading your web page. Or, as a client once said to me, referring to certain animated gifs in the upper right-hand corner of certain browsers, without “making the world spin”. To this end, Yahoo! has supplied us one line of code:

var transaction =
YAHOO.util.Connect.asyncRequest(
method, uri, callback, postData);

or, same line with some data plugged in:

var transaction =
YAHOO.util.Connect.asyncRequest(
'POST',   'php/post.php', callback,"id=1&old_id=2");

When I was making the switch from synchronous to a-, it helped me to visualize a standard web form to see how form elements and attributes are translated to an AJAX request. It’s pretty obvious, but if you need an “aha!” moment, the above line is akin to the html form printed below (though unless you’re one of those people whose definition of interactivity is “The Monologue”, do refrain from creating forms with 2 hard-coded hidden inputs and nothing else! :) ).

<form method="post" action="php/post.php">
<input type="hidden" name="id" value="1" />
<input type="hidden" name="old_id" value="2" />
<input type="submit">
</form>

So, excluding a reference to the callback for the moment (which is not addressed in this example), that form maps to the Connection Manager call quite simply: method, action (uri), data. Let’s look at the arguments required:

method: the method of the server request (POST, GET and others also available).

uri: the uri that’s receiving and processing the data you send (in our example, “php/post.php”). YUI’s examples use php, but, if you’re using the Connection Manager in a Rails app, it’s easy to adapt: your argument uri might read “/projects/update which would pass the data to the update method in projects_controller.rb, which would then be able to access the data through the params array, like so:

def update
@project = Project.find(params[:id])
end

In php you’d probably do some type of db query [assume input cleanup and some type of database abstraction layer, such as PEAR/DB_DataObject, here]

$project = DB_DataObject::factory('Projects');
$project->get($_POST['id']);

Callback: a reference to the callback object you are supplying. This is how everything is handled. More on that in a minute.

postData: the data itself in standard query-string format (“new=1&old=2″). NOTE: if you’re doing a GET transaction, your 4th argument would be false and your second argument would include the url and query string, like so:

“php/post.php?new=1&old=2".

So, what’s this callback?. In a synchronous transaction, you have the luxury of redrawing the page to process your data (and yes, nothing says luxury like a nice, slow, page reload…). In an asynchronous transaction you need to essentially “sneak” your data back into the page without reloading it. This is where your callback object comes in. It helps you get your data “in the door”, so to speak, so your page or application can change in a way that feels seamless to the user but often returns a visible result (changing a div, displaying some text, etc.) and if not a visible result at least a meaningful one (setting the value of a hidden form element, for example). Your callback is responsible for executing actions based on the data retrieved (or the failure to retrieve data) from the uri. In a standard synchronous form this action might be “generate an HTML table that displays your database results”. Or, “Print a message saying there are no results”. Of course, you can do anything you want with your data, that’s just an example of a fairly common scenario.

Once you’ve sent your data to the uri for processing, you need to wait for your response — without, of course, appearing to wait (save for the ubiquitous web 2.0 spinner you know you’re dying to try!). And, of course you want to know if your transaction failed. If you don’t watch for these things — “success” and “failure” in technical terms — you’re not going to be able to make an appropriate decision about what to do next in your app. So you feed your AJAX request a callback object: an object that defines functions for what to do in the cases of success and failure. In simplest terms, we’ve got

var callback = {
success: handleSuccess,
failure: handleFailure
};

where “handleSuccess” and “handleFailure” are user-defined functions that take the http response object and do stuff with it.

handleSuccess = function(o){
// cheer! (or process data returned from the server)
}

handleFailure = function(o){
// cry, vow to try again! (or display failure message)
}

There’s also the ability to pass scope, timeouts, and additional arguments to the callback object. To do so you’d read the great tutorials at the links above and add the lines below, of course changing the values to values meaningful in your application.

scope: Ajaxobject,
timeout: 5000,
args: ['arg1', 'arg2']

The handlers. handleSuccess and handleFailure both take an object o, which is the http response object. There’s a detailed list of all the properties of o on the yui page (Not to be confused with the Story of O, which I will not link to as it is beyond the scope of this article, you dirty rascals, you…). The property you’ll likely use most often is o.responseText, which is the server’s response as a string. This is what you pass back from good old ‘php/post.php’, and getting it is simple: echo. What? echo. What? echo..o..o… ok, sorry, moving on. For instance, if we wanted to capture the update_date in our successHandler to print to our page and we’re using php, we’d write something like this:

echo $project->update_date;

and if we’re in Rails? something like this:

render_text @project.update_date

If you need more data than a string — an array or collection of objects passed back from the server, you’ll find that’s simple, too: call the ruby method to_json() on your array instead. This essentially serializes your object so it can survive the journey to the Client. Once there, you can access the data using JavaScript’s magic wand: eval(). It’s great. So if you had an array of users connected to a project (and your database relationships are set up correctly), you could write

render_text @project.users.to_json

in php, assume you’ve got your $users array, and use print_r

print_r($users);

The in your JavaScript successHandler use eval(), like so:

var users =  eval(o.responseText)

and bingo: in two lines you’re happily in your JavaScript parsing your users array like you would any other JavaScript array. You have connected your server to your DOM and no one is the wiser for it.

All this is great. We have our AJAX call and our callback object and are ready to go. But, suppose you don’t want to rewrite the AJAX call all over your app? The Yahoo folks have a great example of a ‘“hypothetical ajax object” (mysteriously named “AjaxObject”) that encapsulates success, failure, and process methods and calls a callback object that defines AjaxObject as it’s scope. Encapsulating your AJAX request so you can call it from wherever you want in your scripts in a DRY fashion makes your code cleaner and easier to manage. Yahoo! does this well in their example: in my usage I changed it up a little bit to meet my needs.

To quote the great Chicago writer Leo Tolstoy from his famous novel Anna Karenina Does Lake Michigan, ‘“Happy families are all alike; every unhappy family is unhappy in its own way”. I’ve learned that when working on an app, the opposite is true: success cases call for a range of actions: failures can more easily handled (log, display error, abort). Based on this, I’ve adapted the yui AjaxObject example to accept a postAction, successHandler, and object (used to define scope). This allows you to call AjaxObject from other objects, pass specific success handlers, and pass this (a reference to your current object) so you can access it in your successHandler from within the calling object. The AjaxObject builds the callback using those arguments. Like so:

var AjaxObject = {

handleFailure:function(o){
// Fail gracefully
},

/**
* Wrapper for AJAX calls using YUI connector
*
* @param postAction {String} URL to post to
* @param callBackSuccess {String} Success handler
* @param postData {String} Data to post
* @param obj {Object} Object that handler has scope in
*
*/
startRequest:function(postAction, callBackSuccess, postData, obj) {

var callback = {
success:callBackSuccess,
failure:this.handleFailure,
scope:obj
}
// ASSUME you've shortened your yui connection mgr to $C
$C('POST', postAction, callback, postData);
}

};

Then you can call AjaxObject from within a class, like so, and pass it a class method as it’s success-handler:

var Project = function Project(){
// initialize project however you like
this.foo = "bar";
...
// CREATE in db and return id
AjaxObject.startRequest('/project/create',
this._generateDbId, postData, this);

}   // Success handler  Project.prototype._generateDbId = function(o){
if(o.responseText !== undefined){
this._setDbid(Number(o.responseText));
// DO other stuff..
}
}

This way your AJAX calls are in one place, you can use them in the scope of the calling object and define as many success handlers as success cases (or pass false); and fail in one standard way (gracefully, of course). Of course, this can be adapted to pass failure cases in too, or however you like. This was a way I found helpful in my work, and I hope it’s helpful to you as well. And thanks again to the folks at Yahoo! for providing so much great stuff to work with in the first place.

ˆ Back to top

A brief look at Yahoo! Event Utility [addListener]

February 13th, 2007 by comment

I’ve been getting familiar with the Event Utility in the Yahoo library , and it’s a great way to handle and manage javascript events in a clean centralized way. It also smooths out the differences between browser event handling so you no longer need lines like this in your event functions:

e  = e ? window.event;

If you’re unfamiliar with events, it might help to read the article on quirksmode, as well as the yui page.

This library has lots of great methods for event listening, creating custom events, passing objects to event handler functions (a great feature), stopping default event behavior, and attaching listeners to all elements of a particular class rather than cluttering up your code with hundreds of individual listener calls. It’s all encapsulated in neat, well-documented code and a clear API.

One current simple example. I’m building a project where there’s a text input field on stage that serves as a quick “editor”: the user types a number into the field that corresponds with an object on the stage, and then they hit ENTER. [Result: they land in the object in an open editor, saving them mouse-action on the stage and allowing for easy keyboard access to dispersed elements]. We’re not actually submitting a form and since the text area is embedded in another form we just want to listen for the ENTER key but disable form submission, which automatically happens on enter. We also need to make sure that if the user double-clicks within the text area, the usual dblclick behavior (which creates a new object) is disabled. So we want this editor to listen for two events: keydown and dblclick; as well as stop the default behavior of the enter key (submitting the form).

Instead of something like this [pseudo-but-close code]:

< input type="text" id="editor"
onkeydown="javascript:edit();return false"
ondblclick="javascript:return false;" />

We can simply write

< input type="text" id="editor" />

And then in script tags in a centralized location,

$E = YAHOO.util.Event;
$E.addListener('editor', 'keydown', edit);
$E.addListener('editor', 'dblclick', interceptAction);

The first argument is name of the id of the element in question (or an element object itself); the second is the javascript event to listen for; and the third is the name of your function. There's an optional 4th argument, obj, which is an arbitrary object you can pass to your handler. If you do this, define your handler with two arguments: (e,obj).

Then define your functions:

/* handler to open your editor */
var edit = function(e){
// GRAB enter key
if( e.keyCode == 13){
// PREVENT form from submitting on enter
//[the default behavior of the enter key]
$E.preventDefault(e);
// DO things here
openInlineEditor();
}
}
/* handler to prevent default actions */
var interceptAction= function(e) {
// STOP the event from propagating to other listeners
$E.stopPropagation(e);
}

This is just the tip of the iceberg. I recommend reading up on this and looking at their examples and related articles linked on the page. It's made my event handling easier and more fun.

ˆ Back to top

< DirectoryMatch > and regular expressions

October 5th, 2006 by comment

I learned something new in Apache today that I thought I’d share with the group. You may already know this but always good to write stuff down.

I’m maintaining an application on a virtual host that uses a vhost.conf file to set php settings (such as auto_prepend_file, open_basedir, and include_path) for the application (rather than using individual .htaccess files). Initially we were setting the same settings for the entire application, and so we could use the Directory container in the vhost.conf file like this:

< Directory
/path/to/public/directory >

php_value auto_prepend_file /path/to/
global/configuration/config.php

< /Directory>

And then that file would be automatically prepended to every file in the app, so stuff like database settings were always available. But we’re integrating a second module that will need it’s own configuration files so I was trying to find a way to have the initial include work recursively for every directory *except* the new integrated directory. In short, I wanted: /path/to/public/directory/EXCEPT_FOR_NEW_DIRECTORY.

I learned that to do that you have to use < DirectoryMatch > and feed it a regular expression. You could also feed a regular expression to < Directory > but < DirectoryMatch > is intended for that purpose. It was a little more complicated than I’d thought to write the regex, since you can’t just write a regex that excludes an entire word — those end up searching for each character in the word, so if your word is [myword] your regex works on m,y,w,o,r,d — which is not what you want. I found an example that will check for the first three letters of a word (since I knew that would be enough for me, and b/c it was getting long) and tailored that to my purposes. I also found one for negative lookbacks, but that was more complex than I needed.

So I ended up doing this:

< DirectoryMatch
"/usr/local/psa/home/vhosts/mecme.org/httpdocs/
(cm[^e]|c[^m]e|c[^m][^e]|[^c]me|
[^c]m[^e]|[^c][^m]e|[^c][^m][^e])(w*)" >

-- do stuff

< / DirectoryMatch>

And then I had another simple < Directory > container for the included module.

***

Later it was pointed out to me that “if it’s only some options you don’t want you could subtract them:”

< Directory
/usr/local/psa/home/vhosts/mecme.org/httpdocs >

Options Indexes

< /Directory >

< Directory
/usr/local/psa/home/vhosts/
mecme.org/httpdocs/different_dir >

Options -Indexes +ExecCGI

< /Directory>

I don’t know a ton about apache configuration, so I went with my first method, which was working. If anyone can chime in and further explain the latter example with the subtraction, that’d be great.

ˆ Back to top

cheap research papers