Logo

Capitalism and Meaning

about 1 year ago | Amy Grandov: Technology for Social Innovation

I’m a Target kind of person. Walmart – not so much.

I got some insight into why people connect emotionally to a brand, whether it’s a retailer, iPod or Harley Davidson, by listening to a podcast called Conscious Capitalism, from the Social Innovation Conversations Network (from Stanford University Graduate School of Business).

A panel of business and design leaders discussed how understanding and connecting to a consumer’s world view and belief system through design will be increasingly important to business success. The panelists were also concerned about how this could lead to more sustainable and socially responsible businesses in an age of surplus and consumerism.

Its worth a listen to hear these guys speak. Incidentally, the panel includes Brandon Schauer from Adaptive Path, who is well known in UX circles. He was also the instructor for a Design Strategy class I took.

The discussion left me pondering whether internal IT systems could – and should - connect to users on an emotional level. To deliver maximum value, should we be going beyond functional requirements to understand what our users value and believe in? Is this even ethical?

Younger generations of users may simply expect this from their technology. For systems that people are not compelled to use, like knowledge bases and collaborative sites, perhaps designers would benefit from tapping into value systems around sharing, helping, connecting, learning, etc.

I am also wondering if we should see our internal systems as services and experiences rather than discrete products. What would we do differently if we considered the holistic experience our applications deliver, including support and ongoing maintenance.

As usual, I have more new questions than new answers.

Listen to the podcast here: http://sic.conversationsnetwork.org/shows/detail3892.html

The auto_complete plugin modified for repeated fields

about 1 year ago | Pat Shaughnessy: Pat Shaughnessy - Home

This version of auto_complete will support text fields that are repeated more than once on a complex form. It allows you to call text_field_with_auto_complete inside of fields_for or form_for.

Code: http://github.com/patshaughnessy/auto_complete

Install:

script/plugins install git://github.com/patshaughnessy/auto_complete.git

More information:

Note: my changes were previously in a separate plugin called “repeated_auto_complete,” but now I’ve merged the changes into this forked repository of auto_complete.

Sample app for auto complete on a complex form

about 1 year ago | Pat Shaughnessy: Pat Shaughnessy - Home

In his “Complex Forms” series (part 1, part 2 and part 3) Ryan Bates does a fantastic job explaining how to create a complex form containing a series of parent/child text fields while still using simple, clean code. Ryan also pushed the sample application from the screen cast onto github, here: http://github.com/ryanb/complex-form-examples

Here’s what Ryan’s sample complex form looks like:

One problem I ran into while using Ryan’s suggestions on a complex form I was writing was how to get auto complete behavior to work properly using the auto_complete plugin for fields that are repeated, like the “task” field here. As I explained in a previous blog post, this causes a lot of problems for the auto_complete plugin since the <input id=””> attributes are no longer unique, breaking the javascript used for auto complete. I was able to solve the problem by modifying the auto_complete plugin to generate unique <input id=””> attributes, among other things.

Here I want to take some time to show how to use my modified auto_complete plugin, using the same sample application from Ryan’s screencast. To get started, let’s clone the git repository for the sample app - this command refers to my fork of Ryan's complex-form-examples repository: http://github.com/patshaughnessy/complex-form-examples

$ git clone git://github.com/patshaughnessy/complex-form-examples.git
Initialized empty Git repository in /Users/pat/rails-apps/complex-form-examples/.git/
remote: Counting objects: 192, done.
remote: Compressing objects: 100% (122/122), done.
remote: Total 192 (delta 71), reused 159 (delta 58)
Receiving objects: 100% (192/192), 86.19 KiB | 68 KiB/s, done.
Resolving deltas: 100% (71/71), done.

Ryan had saved various versions of the sample app in different git branches, so to avoid confusion I’ve saved my auto complete related changes in a branch called “auto_complete.” So next you should switch to that branch:

$ git checkout origin/auto_complete
Note: moving to "origin/auto_complete" which isn't a local branch
If you want to create a new branch from this checkout, you may do so
(now or later) by using -b with the checkout command again. Example:
  git checkout -b <new_branch_name>
HEAD is now at 4f3e908... Sample app code changes for auto_complete

Now you will see my changes in Ryans’ code, except for one more detail: I saved my version of the auto_complete plugin in this git repository as a submodule. To get the plugin’s code for this sample app you need to run these commands:

$ git submodule init
Submodule 'vendor/plugins/auto_complete' (git://github.com/patshaughnessy/auto_complete.git) registered for path 'vendor/plugins/auto_complete'
$ git submodule update
Initialized empty Git repository in /Users/pat/rails-apps/complex-form-examples/vendor/plugins/auto_complete/.git/
remote: Counting objects: 22, done.
remote: Compressing objects: 100% (21/21), done.
remote: Total 22 (delta 5), reused 0 (delta 0)
Receiving objects: 100% (22/22), 7.65 KiB, done.
Resolving deltas: 100% (5/5), done.
Submodule path 'vendor/plugins/auto_complete': checked out '0814a25a754a235c5cf6f7a258fa405059a5ca6f'

(Note that normally to install the plugin in your app you would just run “script/plugin install git://github.com/patshaughnessy/auto_complete.git” – the submodule is only present in this sample app.) Now to setup and run the application you just need to:

  1. Enter your MySQL details in config/database.yml
  2. Run rake db:migrate
  3. Run script/server to launch the app

If you enter a few records you should be able to see the auto complete drop down, even for the repeated field:

Let’s review the changes I’ve made to Ryan’s code aside from adding my modified version of auto_complete to vendor/plugins. First, I added the standard auto_complete handlers to projects_controller.rb for both the project and task fields:

class ProjectsController < ApplicationController
  auto_complete_for :project, :name
  auto_complete_for :task, :name
…

Next I modified the project text field to use auto complete (in views/projects/_form.html.erb):

<p>
  <%= f.label :name, "Project:" %>
  <%= text_field_with_auto_complete :project, :name, {}, {:method => :get } %>
</p>

These two changes enable auto complete for the single project text field, just the same way you would with any text field and the standard auto_complete plugin. However, to get auto complete to work with the repeated tasks field, we need to use changes I’ve made to auto_complete. First, in helpers/projects_helper.rb change the “fields_for_task” method to use my new auto_complete_fields_for method, like this:

def fields_for_task(task, &block)
  new_or_existing = task.new_record? ? 'new' : 'existing'
  prefix = "project[#{new_or_existing}_task_attributes][]"
  auto_complete_fields_for(prefix, task, &block)
end

This causes my code in auto_complete to provide a custom form builder object, which we can use in the view as follows (views/projects/_task.html.erb):

<% fields_for_task task do |f| -%>
  <%= error_messages_for :task, :object => task %>
  <%= f.label :name, "Task:" %>
  <%= f.text_field_with_auto_complete :task, :name, {}, {:method => :get } %>
  <%= link_to_function "remove", "$(this).up('.task').remove()" %>
<% end -%>

Here I’ve called “text_field_with_auto_complete” as a method on the “f” form builder object yielded by fields_for_task. This will cause the auto complete script and HTML to be generated with unique <input id=””> attributes, allowing the auto complete behavior to work properly.

One other change I made was also to helpers/projects_helper.rb:

def add_task_link(name)
  link_to_remote "Add a task", :url => {
                                 :controller => "projects",
                                 :action => "add_task_script"
                               }
end

Here I’ve changed Ryan’s “link_to_function” call to “link_to_remote.” As Ryan explains in part 2 of his complex forms screen cast, link_to_function avoids an AJAX call to the server to obtain the HTML for each new task <input> tag, avoiding unnecessary load on the server since all of the task fields are the same. However, with my changes to auto_complete the HTML generated for the task field contains random numbers which are different for each copy of the field… meaning that we do need a separate call to the server to obtain the task field HTML and script. To handle the call from link_to_remote, I’ve added a new file, views/projects/add_task_script.rjs:

page.insert_html :bottom, :tasks, :partial => 'task', :object => Task.new

… which works essentially the same way as described by Ryan, but is called each time the user clicks “Add a task.”

The last change I made to the sample app is in routes.rb; these changes are required to allow the controller to map the Ajax requests, and to insure that these requests use GET, and not POST HTTP requests:

map.connect 'projects/auto_complete_for_project_name',
            :controller => 'projects',
            :action => 'auto_complete_for_project_name'
map.connect 'projects/auto_complete_for_task_name',
            :controller => 'projects',
            :action => 'auto_complete_for_task_name'
map.connect 'projects/add_task_script',
            :controller => 'projects',
            :action => 'add_task_script'
map.resources :projects,
              :collection => {
                :auto_complete_for_project_name => :get,
                :auto_complete_for_task_name => :get
              }

This certainly seems very ugly, and probably could be simplified! But for now, we need this code to avoid problems with CRSF protection; see http://www.ruby-forum.com/topic/128970.

Sample app for auto complete on a complex form

about 1 year ago | Pat Shaughnessy: Pat Shaughnessy - Home

Update June 2009: I just added support to my version of auto_complete to support Rails 2.3 nested attributes; for more details see: http://patshaughnessy.net/repeated_auto_complete. This sample app will still work since the git submodule commands below refer to the old version of my auto_complete plugin; I’ll try to write another sample app or tutorial in the next week or two illustrating how to use Rails 2.3 to build this same app… in a much simpler way! If you download my version of auto_complete now from github, please refer to my description of the usage changes.

 

In his “Complex Forms” series (part 1, part 2 and part 3) Ryan Bates does a fantastic job explaining how to create a complex form containing a series of parent/child text fields while still using simple, clean code. Ryan also pushed the sample application from the screen cast onto github, here: http://github.com/ryanb/complex-form-examples

Here’s what Ryan’s sample complex form looks like:

One problem I ran into while using Ryan’s suggestions on a complex form I was writing was how to get auto complete behavior to work properly using the auto_complete plugin for fields that are repeated, like the “task” field here. As I explained in a previous blog post, this causes a lot of problems for the auto_complete plugin since the <input id=””> attributes are no longer unique, breaking the javascript used for auto complete. I was able to solve the problem by modifying the auto_complete plugin to generate unique <input id=””> attributes, among other things.

Here I want to take some time to show how to use my modified auto_complete plugin, using the same sample application from Ryan’s screencast. To get started, let’s clone the git repository for the sample app - this command refers to my fork of Ryan's complex-form-examples repository: http://github.com/patshaughnessy/complex-form-examples

$ git clone git://github.com/patshaughnessy/complex-form-examples.git
Initialized empty Git repository in /Users/pat/rails-apps/complex-form-examples/.git/
remote: Counting objects: 192, done.
remote: Compressing objects: 100% (122/122), done.
remote: Total 192 (delta 71), reused 159 (delta 58)
Receiving objects: 100% (192/192), 86.19 KiB | 68 KiB/s, done.
Resolving deltas: 100% (71/71), done.

Ryan had saved various versions of the sample app in different git branches, so to avoid confusion I’ve saved my auto complete related changes in a branch called “auto_complete.” So next you should switch to that branch:

$ cd complex-form-examples
$ git checkout origin/auto_complete
Note: moving to "origin/auto_complete" which isn't a local branch
If you want to create a new branch from this checkout, you may do so
(now or later) by using -b with the checkout command again. Example:
  git checkout -b <new_branch_name>
HEAD is now at 4f3e908... Sample app code changes for auto_complete

Now you will see my changes in Ryans’ code, except for one more detail: I saved my version of the auto_complete plugin in this git repository as a submodule. To get the plugin’s code for this sample app you need to run these commands:

$ git submodule init
Submodule 'vendor/plugins/auto_complete' (git://github.com/patshaughnessy/auto_complete.git) registered for path 'vendor/plugins/auto_complete'
$ git submodule update
Initialized empty Git repository in /Users/pat/rails-apps/complex-form-examples/vendor/plugins/auto_complete/.git/
remote: Counting objects: 22, done.
remote: Compressing objects: 100% (21/21), done.
remote: Total 22 (delta 5), reused 0 (delta 0)
Receiving objects: 100% (22/22), 7.65 KiB, done.
Resolving deltas: 100% (5/5), done.
Submodule path 'vendor/plugins/auto_complete': checked out '0814a25a754a235c5cf6f7a258fa405059a5ca6f'

(Note that normally to install the plugin in your app you would just run “script/plugin install git://github.com/patshaughnessy/auto_complete.git” – the submodule is only present in this sample app.) Now to setup and run the application you just need to:

  1. Enter your MySQL details in config/database.yml
  2. Run rake db:migrate
  3. Run script/server to launch the app

If you enter a few records you should be able to see the auto complete drop down, even for the repeated field:

Let’s review the changes I’ve made to Ryan’s code aside from adding my modified version of auto_complete to vendor/plugins. First, I added the standard auto_complete handlers to projects_controller.rb for both the project and task fields:

class ProjectsController < ApplicationController
  auto_complete_for :project, :name
  auto_complete_for :task, :name
…

Next I modified the project text field to use auto complete (in views/projects/_form.html.erb):

<p>
  <%= f.label :name, "Project:" %>
  <%= text_field_with_auto_complete :project, :name, {}, {:method => :get } %>
</p>

These two changes enable auto complete for the single project text field, just the same way you would with any text field and the standard auto_complete plugin. However, to get auto complete to work with the repeated tasks field, we need to use changes I’ve made to auto_complete. First, in helpers/projects_helper.rb change the “fields_for_task” method to use my new auto_complete_fields_for method, like this:

def fields_for_task(task, &block)
  new_or_existing = task.new_record? ? 'new' : 'existing'
  prefix = "project[#{new_or_existing}_task_attributes][]"
  auto_complete_fields_for(prefix, task, &block)
end

This causes my code in auto_complete to provide a custom form builder object, which we can use in the view as follows (views/projects/_task.html.erb):

<% fields_for_task task do |f| -%>
  <%= error_messages_for :task, :object => task %>
  <%= f.label :name, "Task:" %>
  <%= f.text_field_with_auto_complete :task, :name, {}, {:method => :get } %>
  <%= link_to_function "remove", "$(this).up('.task').remove()" %>
<% end -%>

Here I’ve called “text_field_with_auto_complete” as a method on the “f” form builder object yielded by fields_for_task. This will cause the auto complete script and HTML to be generated with unique <input id=””> attributes, allowing the auto complete behavior to work properly.

One other change I made was also to helpers/projects_helper.rb:

def add_task_link(name)
  link_to_remote "Add a task", :url => {
                                 :controller => "projects",
                                 :action => "add_task_script"
                               }
end

Here I’ve changed Ryan’s “link_to_function” call to “link_to_remote.” As Ryan explains in part 2 of his complex forms screen cast, link_to_function avoids an AJAX call to the server to obtain the HTML for each new task <input> tag, avoiding unnecessary load on the server since all of the task fields are the same. However, with my changes to auto_complete the HTML generated for the task field contains random numbers which are different for each copy of the field… meaning that we do need a separate call to the server to obtain the task field HTML and script. To handle the call from link_to_remote, I’ve added a new file, views/projects/add_task_script.rjs:

page.insert_html :bottom, :tasks, :partial => 'task', :object => Task.new

… which works essentially the same way as described by Ryan, but is called each time the user clicks “Add a task.”

The last change I made to the sample app is in routes.rb; these changes are required to allow the controller to map the Ajax requests, and to insure that these requests use GET, and not POST HTTP requests:

map.connect 'projects/auto_complete_for_project_name',
            :controller => 'projects',
            :action => 'auto_complete_for_project_name'
map.connect 'projects/auto_complete_for_task_name',
            :controller => 'projects',
            :action => 'auto_complete_for_task_name'
map.connect 'projects/add_task_script',
            :controller => 'projects',
            :action => 'add_task_script'
map.resources :projects,
              :collection => {
                :auto_complete_for_project_name => :get,
                :auto_complete_for_task_name => :get
              }

This certainly seems very ugly, and probably could be simplified! But for now, we need this code to avoid problems with CRSF protection; see http://www.ruby-forum.com/topic/128970.

Repeated_auto_complete changes merged into auto_complete

about 1 year ago | Pat Shaughnessy: Pat Shaughnessy - Home

In October I described how the auto_complete plugin doesn’t work when text fields are repeated more than once on a complex form. I went on to write a plugin called “repeated_auto_complete&rdquo; which modified the way the standard auto_complete plugin works and fixed this problem by adding random numbers to <input id=""> attributes among other changes.

Since it’s much cleaner to have a single auto_complete plugin rather than two separate plugins, I’ve merged my changes to auto_complete into the original version, and pushed them to github as a new fork: http://github.com/patshaughnessy/auto_complete

To install and use my modified version of auto_complete first remove the standard auto_complete plugin from your app if necessary, and install with:

script/plugin install git://github.com/patshaughnessy/auto_complete.git

To use auto complete in a complex form, you write “auto_complete_fields_for” or “auto_complete_form_for” in your view, and then call text_field_with_auto_complete on the form builder object, as follows:

<% for person in @group.people %>
  <% auto_complete_fields_for "group[person_attributes][]", person do |form| %>
    Person <%= person_form.label :name %><br />
    <%= form.text_field_with_auto_complete :person, :name, {},
                                           {:method => :get}  %>
  <% end %>
<% end %>

To understand my changes to the plugin, let’s first look at how the original auto_complete works. If you add this line to your view:

<%= text_field_with_auto_complete :project, :name, {}, {:method => :get } %>

…then you get HTML and script that looks like this (style sheet omitted):

<input id="project_name" name="project[name]" size="30" type="text" />
<div class="auto_complete" id="project_name_auto_complete"></div>
<script type="text/javascript">
//<![CDATA[
var project_name_auto_completer = new Ajax.Autocompleter('project_name',
'project_name_auto_complete', '/projects/auto_complete_for_project_name',
{method:'get'})
//]]>
</script>

The original text_field_with_auto_complete method looked like this:

def text_field_with_auto_complete(object, method, tag_options = {},
                                  completion_options = {})
    (completion_options[:skip_style] ? "" : auto_complete_stylesheet) +
    text_field(object, method, tag_options) +
    content_tag("div", "", :id => "#{object}_#{method}_auto_complete",
                :class => "auto_complete") +
    auto_complete_field(
        "#{object}_#{method}",
        { 
          :url => { :action => "auto_complete_for_#{object}_#{method}" }
        }.update(completion_options))
  end

You can see that it calls “text_field” in ActionView::Helpers::FormHelper to generate the actual <input> tag for the form, in addition to generating the HTML and script needed for the auto completion behavior.

What I wanted to achieve in the modified plugin was to allow the view to contain code like this:

<% auto_complete_fields_for task do |f| %>
  <%= f.label :name, "Task:" %>
  <%= f.text_field_with_auto_complete :task, :name, {}, {:method => :get } %>
<% end %>

To make this work, we need a new version of text_field_with_auto_complete that calls text_field from ActionView::Helpers::FormBuilder, and not ActionView::Helpers::FormHelper, generating an <input> tag similar to what this call would generate:

<% fields_for task do |f| %>
  <%= f.text_field :name %>
<% end %>

To do this, I first refactored the original text_field_with_auto_complete in auto_complete_macros_helper.rb:

def text_field_with_auto_complete(object, method, tag_options = {},
                                  completion_options = {})
  auto_complete_field_with_style_and_script(object, method, tag_options,
                                            completion_options) do
    text_field(object, method, tag_options)
  end
end

def auto_complete_field_with_style_and_script(object, method,
                                              tag_options = {},
                                              completion_options = {})
  (completion_options[:skip_style] ? "" : auto_complete_stylesheet) +
  yield +
  content_tag("div", "", :id => "#{object}_#{method}_auto_complete",
              :class => "auto_complete") +
  auto_complete_field(
    "#{object}_#{method}",
    {
      :url => { :action => "auto_complete_for_#{object}_#{method}" } 
    }.update(completion_options))
end

Here I’ve introduced a new utility function called “auto_complete_field_with_style_and_script” that generates the same Javascript and style sheet for the view as before, but instead calls a block to generate the actual text field. Then I changed text_field_with_auto_complete to call this, providing a block to make the call to “text_field” in ActionView::Helpers::FormHelper with the proper names and options.

Now my new form builder class in auto_complete_form_helper.rb contains a version of text_field_with_auto_complete that looks like this:

def text_field_with_auto_complete(object,
                                  method,
                                  tag_options = {},
                                  completion_options = {})
  unique_object_name = "#{object}_#{Object.new.object_id.abs}"
  completion_options_for_original_name =
    {
      :url => { :action => "auto_complete_for_#{object}_#{method}"},
      :param_name => "#{object}[#{method}]"
    }.update(completion_options)
  @template.auto_complete_field_with_style_and_script(
        unique_object_name,
        method,
        tag_options,
        completion_options_for_original_name
  ) do
    text_field(method,
               {
                 :id => "#{unique_object_name}_#{method}"
               }.update(tag_options))
  end
end

Here the call to auto_complete_field_with_style_and_script passes a block that calls the other text_field from ActionView::Helpers::FormBuilder (note the “object” parameter is not present as above).

To allow the text field to be repeated on a complex form, I insure the object’s name is unique by adding a random number to it (“unique_object_name”). This unique name is then passed into both auto_complete_field_with_style_and_script and text_field, insuring that the <input> and related Javascript all work without problems, even if the text field is repeated more than once on the same form.

The last important detail here is that the completion options passed into auto_complete_field_with_style_and_script are generated using the original, unchanged (non-unque) object name, so that the Ajax calls to the server are made using the original name. This means no changes are required on the server side, and the same single line of code in your controller still works as usual:

auto_complete_for :task, :name

Next time I’ll post a sample application that uses this new plugin, and explain what changes you will need to make to your own application for auto_complete in a complex form.

Repeated_auto_complete changes merged into auto_complete

about 1 year ago | Pat Shaughnessy: Pat Shaughnessy - Home

Update June 2009: I just added support to my version of auto_complete to support Rails 2.3 nested attributes; for more details see: http://patshaughnessy.net/repeated_auto_complete. The basic ideas below still apply, but my implementation of auto_complete has changed, and I’ve also simplified the usage.

 

In October I described how the auto_complete plugin doesn’t work when text fields are repeated more than once on a complex form. I went on to write a plugin called “repeated_auto_complete&rdquo; which modified the way the standard auto_complete plugin works and fixed this problem by adding random numbers to <input id=""> attributes among other changes.

Since it’s much cleaner to have a single auto_complete plugin rather than two separate plugins, I’ve merged my changes to auto_complete into the original version, and pushed them to github as a new fork: http://github.com/patshaughnessy/auto_complete

To install and use my modified version of auto_complete first remove the standard auto_complete plugin from your app if necessary, and install with:

script/plugin install git://github.com/patshaughnessy/auto_complete.git

To use auto complete in a complex form, you write “auto_complete_fields_for” or “auto_complete_form_for” in your view, and then call text_field_with_auto_complete on the form builder object, as follows:

<% for person in @group.people %>
  <% auto_complete_fields_for "group[person_attributes][]", person do |form| %>
    Person <%= person_form.label :name %><br />
    <%= form.text_field_with_auto_complete :person, :name, {},
                                           {:method => :get}  %>
  <% end %>
<% end %>

To understand my changes to the plugin, let’s first look at how the original auto_complete works. If you add this line to your view:

<%= text_field_with_auto_complete :project, :name, {}, {:method => :get } %>

…then you get HTML and script that looks like this (style sheet omitted):

<input id="project_name" name="project[name]" size="30" type="text" />
<div class="auto_complete" id="project_name_auto_complete"></div>
<script type="text/javascript">
//<![CDATA[
var project_name_auto_completer = new Ajax.Autocompleter('project_name',
'project_name_auto_complete', '/projects/auto_complete_for_project_name',
{method:'get'})
//]]>
</script>

The original text_field_with_auto_complete method looked like this:

def text_field_with_auto_complete(object, method, tag_options = {},
                                  completion_options = {})
    (completion_options[:skip_style] ? "" : auto_complete_stylesheet) +
    text_field(object, method, tag_options) +
    content_tag("div", "", :id => "#{object}_#{method}_auto_complete",
                :class => "auto_complete") +
    auto_complete_field(
        "#{object}_#{method}",
        { 
          :url => { :action => "auto_complete_for_#{object}_#{method}" }
        }.update(completion_options))
  end

You can see that it calls “text_field” in ActionView::Helpers::FormHelper to generate the actual <input> tag for the form, in addition to generating the HTML and script needed for the auto completion behavior.

What I wanted to achieve in the modified plugin was to allow the view to contain code like this:

<% auto_complete_fields_for task do |f| %>
  <%= f.label :name, "Task:" %>
  <%= f.text_field_with_auto_complete :task, :name, {}, {:method => :get } %>
<% end %>

To make this work, we need a new version of text_field_with_auto_complete that calls text_field from ActionView::Helpers::FormBuilder, and not ActionView::Helpers::FormHelper, generating an <input> tag similar to what this call would generate:

<% fields_for task do |f| %>
  <%= f.text_field :name %>
<% end %>

To do this, I first refactored the original text_field_with_auto_complete in auto_complete_macros_helper.rb:

def text_field_with_auto_complete(object, method, tag_options = {},
                                  completion_options = {})
  auto_complete_field_with_style_and_script(object, method, tag_options,
                                            completion_options) do
    text_field(object, method, tag_options)
  end
end

def auto_complete_field_with_style_and_script(object, method,
                                              tag_options = {},
                                              completion_options = {})
  (completion_options[:skip_style] ? "" : auto_complete_stylesheet) +
  yield +
  content_tag("div", "", :id => "#{object}_#{method}_auto_complete",
              :class => "auto_complete") +
  auto_complete_field(
    "#{object}_#{method}",
    {
      :url => { :action => "auto_complete_for_#{object}_#{method}" } 
    }.update(completion_options))
end

Here I’ve introduced a new utility function called “auto_complete_field_with_style_and_script” that generates the same Javascript and style sheet for the view as before, but instead calls a block to generate the actual text field. Then I changed text_field_with_auto_complete to call this, providing a block to make the call to “text_field” in ActionView::Helpers::FormHelper with the proper names and options.

Now my new form builder class in auto_complete_form_helper.rb contains a version of text_field_with_auto_complete that looks like this:

def text_field_with_auto_complete(object,
                                  method,
                                  tag_options = {},
                                  completion_options = {})
  unique_object_name = "#{object}_#{Object.new.object_id.abs}"
  completion_options_for_original_name =
    {
      :url => { :action => "auto_complete_for_#{object}_#{method}"},
      :param_name => "#{object}[#{method}]"
    }.update(completion_options)
  @template.auto_complete_field_with_style_and_script(
        unique_object_name,
        method,
        tag_options,
        completion_options_for_original_name
  ) do
    text_field(method,
               {
                 :id => "#{unique_object_name}_#{method}"
               }.update(tag_options))
  end
end

Here the call to auto_complete_field_with_style_and_script passes a block that calls the other text_field from ActionView::Helpers::FormBuilder (note the “object” parameter is not present as above).

To allow the text field to be repeated on a complex form, I insure the object’s name is unique by adding a random number to it (“unique_object_name”). This unique name is then passed into both auto_complete_field_with_style_and_script and text_field, insuring that the <input> and related Javascript all work without problems, even if the text field is repeated more than once on the same form.

The last important detail here is that the completion options passed into auto_complete_field_with_style_and_script are generated using the original, unchanged (non-unque) object name, so that the Ajax calls to the server are made using the original name. This means no changes are required on the server side, and the same single line of code in your controller still works as usual:

auto_complete_for :task, :name

Next time I’ll post a sample application that uses this new plugin, and explain what changes you will need to make to your own application for auto_complete in a complex form.

Electric Bandages?

about 1 year ago | Erika Santos: Santos on Technology and Life


Bandage plus voltage. 


Tata Indicom gets a Second Life!

about 1 year ago | Rajesh Rathod: Uncommon "Common Sense"!

I distinctively remember just when I had to prepare a presentation on 'Sustainable Assets Management (SAM) and I was learning about Dow Jones Sustainability Index (DJSI), a new broke out - "TCS makes it to the Dow Jones Sustainability Index". What a coincidence!

Well, history repeats itself... sometimes...

Now that I am about to complete my project on Second Life, another news broke out last week - "
Tata Indicom gets a Second Life". Well, this makes Tata Teleservices Ltd the first Indian telecom company to establish it's presence in Second Life.

"the first telecom operator to have a presence in the virtual world with a mass media campaign; the first to offer a virtual talent hunt, which will invite participation from people all over the world; and the first to have its brand ambassadors, in their virtual avatars, engage with visitors from the Indian subcontinent in an interactive forum. "

As part of the initiative, Tata Indicom will create and own an 'island' in the virtual world of Second Life. Users can visit this island, participate in the talent hunt, get a deeper understanding of the company's products and offerings and enjoy the softer properties on the island, including games, songs and other interactive programs.

Lloyd Mathias, chief marketing officer, TTSL, says, "With the exciting Second Life initiative, we continue with our tradition of launching many industry firsts. The digital world is evolving at a fantastic pace – cutting across geographical and cultural barriers – and we firmly believe that the virtual world has a huge outreach potential for businesses. “As a company at the cutting edge of technology, TTSL always scouts for relevant and innovative technologies and opportunities. We feel our association with Second Life will redefine the concept of outreach and take digital interactivity to the next level, for it will allow Tata Indicom to engage with the growing digital audience in a manner that is relevant to them."

Second Life is an Internet enabled virtual world in which users can create their virtual identities to interact with the virtual identities of other users. Members of Second Life can participate in individual or group activities and create and trade items like virtual property and services. Members have to pay for the space they purchase on Second Life. Second Life is developed by the US based Linden Lab.

Now here are some interesting figures regarding the virtual world. According to Gartner Inc., by 2011, 80 per cent of active Internet users will interact with virtual worlds; by 2010, 20 per cent of global Tier I retailers will have a marketing presence in online games and virtual worlds. As far as Second Life is concerned, it has 15 million registered users and around 1.5 million active/unique users.

Long live Second Life:-)







The stuff of life.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

The cover of the latest issue of Gourmet features a drool-worthy pile of freshly baked rolls - salty topknots, yeasty fantails, sesame-encrusted whole wheat...you name it, it's there. I could practically smell the yeasty goodness rising off of the page. How could I resist trying out at least one of the recipes?

So, last Sunday, before I headed out to do my laundry, I whipped up the dough for a batch of buttermilk fantail rolls (using the buttermilk I'd picked up on my Saturday outing). I picked the fantails because they seemed like the easiest for a novice bread-maker like myself (and because they were so gosh-darned purty).

They really were remarkably easy to make - you let the yeast ferment a bit with some warm water and sugar (I used some of the turbinado sugar I keep on hand for my coffee), add in the butter, flour, buttermilk and salt, and then knead the resulting dough for a few minutes before setting it aside to rise.

After about two hours or so, you punch down the dough and roll it out in two batches, slice the dough into strips, stack 'em, and cut crosswise to make the fantail shapes. Slap those babies into buttered muffin cups, let them do the second rise, and then bake. Enjoy the smell of baking bread for the next twenty minutes, then take your pan out. Brush them with butter straight out of the oven, and ten minutes later, you've got rolls.

My oven is a bit tricky, and I probably need to adjust the cooking temperature down just a bit, so they bake a bit more slowly and end up tinged golden and brown rather than brown and darker brown - but they still tasted dang good with the salad I had for dinner (and with lunch the next day).

Welcome

about 1 year ago | Amy Grandov: Technology for Social Innovation

Inspiration can come from anywhere, and sometimes from unexpected places. As an IT professional in the private sector, I am continually inspired by social entrepreneurs and others who are using technology in innovative and exciting ways to solve tough social problems.

In my opinion, social innovation is where the rubber meets the road for technology. Will a new technology change the world? Empower people in new ways? Build virtual bridges to connect people and resources? Lessen suffering and lift people out of poverty? Now that's some raw material for an amazing business case!

As technology gets cheaper, moves globally, and enters into more corners of every day lives, there are opportunities to try a fresh approach to old challenges. Many of the more successful social sector organizations have learned from the private sector in recent years, evolving to become more results-oriented, entrepreneurial, and tech saavy. In turn, the private sector can learn from the social sector, as well as contribute and provide support. And when budgets are tight, who better to learn from then the people who are experts on maximizing their impact on a shoestring and mobilizing volunteers.

In this blog, I'll be sharing my thoughts on the subject of social innovation and posting links to groups that I see advancing social goals in innovative or unexpected ways through technology. Occassionally, I stumble across a group or idea that's just plain cool, and I may blogg off topic now and again.

I welcome your comments and feedback!

Like the corners of my mind.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

See that, right there? That's a dish of baeckeoffe and a green salad, from my trip to Strasbourg in 2006. Louisa's making baeckeoffe tonight, and now I'm nostalgic. I can almost taste the tender, brothy potatoes and the knuckly portions of beef, all braised in slightly sweet Alsatian wine. Sigh.

Social Software Adoption: Why Law Firms Get It Wrong (and How to Get It Right)

about 1 year ago | Michael Idinopulos: Transparent Office

I had a great conversation recently with Headshift's Penny Edwards and Jon Mell. We were talking about social software adoption patterns in law firms--a topic over which a lot of digital ink has been spilled lately. Our conversation helped me...

Repeated_auto_complete merged into auto_complete fork

about 1 year ago | Pat Shaughnessy: Pat Shaughnessy - Home

FYI I merged the repeated_auto_complete plugin code into a refactored version of the original auto_complete. This means you don't have to install two separate plugins, just one:

script/plugin install git://github.com/patshaughnessy/auto_complete.git

See: http://github.com/patshaughnessy/auto_complete/tree/master.

I'll write up the detailed changes here tomorrow, as well as post a link to a sample app illustrating how to use auto_complete in a complex form.

First Projector-Phones

about 1 year ago | Erika Santos: Santos on Technology and Life

Samsung's The Show: Built-in projector, 3.2-inch OLED screen, digital TV tuner, five-megapixel camera. There are also suspicions that the phone will allow users to to tune in and record digital TV broadcasts, and make video calls. Will premier in Korea.








Logic Bolt: Packaged with a built-in projector, PowerPoint, Excel and Word. Future versions promise to have the entire Windows Mobile Software pack and full video-conferencing capabilities. Expected to be available at T-Mobile for $100 with a two-year contract.





Watch out BlackBerry.

Mildew on Clothes? Twitter can help!

about 1 year ago | Erika Santos: Santos on Technology and Life


Ryan Rose, The TiVo senior programmer from San Jose, hacked his 25-year-old washing machine to send a message to Twitter whenever his laudry is done.

After some attention from various blogs and news articles, Rose's washing machine has 407 followers on Twitter -- meaning 407 people hear about it every time he does laundry.

After reading the article on this machine, a few things flashed across my mind:

1) Don't judge an appliance by its appearance

2) I want my washer and oven to do the same

3) Alan Kay's quote: "The easiest way to predict the future is to invent it."


Walk-through of hack: http://www.youtube.com/watch?v=wkMXpKmRXvU
Wash Status:
http://twitter.com/pimpy3wash

Source information courtesy of LATimes.com
Image courtesy of eddy1210 on YouTube

Technology and the Economic Stimulus Plan

about 1 year ago | Erika Santos: Santos on Technology and Life


The economic stimulus plan presented by House Democrats this month calls for $37 billion of high-tech spending in the following areas: computerizing medical records, creating smarted technical grids and spending high-speed Internet access in rural and undeserved areas.

Obama's transition team asserted that the investment in those three areas could produce more than 900,000 jobs in the first year alone. These jobs, according to John Irons from the Economic Policy Institute, would range from the implementation to the adoption of these technologies locally, spanning a spectrum of skills and income levels, in addition to not being outsourced offshore.

Advocates say that the appeal goes beyond the stimulus, building a platform for productivity gains and long-term growth. The high-tech investments can be the equivalent of federal financing for highways in the 1950s, they say, which fostered the growth of businesses such as automakers and retail chains.

Critics argue that while these projects are worthy of the long term, they should not be part of the recovery plan. The problem is that not every investment in the technology field fits the standard of the initiatives that are to be included in the plan. The standard, according to Blair Levin, former technology advisor to Obama's transition team, is that the initiative be “timely, targeted and temporary,” while also creating jobs.

Stanford economist, Robert E. Hall says that the government should not pour money into those areas, as competent suppliers would be in short supply and get increased incomes, benefiting mostly individuals companies, rather than the economy as a whole.
Substantial investment in technology is clearly necessary to keep the USA competitive. But do you think it belongs in the recovery plan?

Source information courtesy of NYT.com
Image courtesy of MashGet on Flickr

















Girl time.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

My friend Miya invited me to hit the Greenmarket with her on Saturday - her husband Jordan is a med student and was on call starting at 7 AM, so she was up and ready to get moving bright and early. Since I hadn't been to the market since before Christmas (and since I don't see Miya nearly often enough), I took her up on it.

We met up at Barnes & Noble around 11:45 (I was running a shameful 15 minutes late - sorry, Miya!) and made a fairly quick tour of the wintertime stands - lots of apples (probably mealy, sadly), gorgeous eggs at Knoll's Crest (I bought half a dozen brown), onions, celery root, jewel-like jams - and dairy. I bought a quart of fresh buttermilk (more on its fate soon) at the Tonje Farms stand, and, eventually, we found ourselves in front of Ronnybrook.

Normally, I pick up some farmer's cheese at Ronnybrook, or maybe a coffee milk for the road. But on Saturday, they were serving hot chocolate with fresh whipped cream. (Right next to a stack of sweet compound butters, such as cinammon toast butter, yum.) The whipped cream was ivory in color - full of rich, delicious butterfat, and the hot chocolate was all-American, as much milky as chocolatey. So good.

For lunch, we hit Republic, a noodle bar on Union Square East. More on our delicious Japanese eggplant and various adventures in noodles in a forthcoming post!

Three reasons to bet on 'Android'

about 1 year ago | Lalatendu Das: Interpretations of Technorealism

The humongous success of ‘iPhone’ has done enough to redefine the utility of ‘Smartphones’. While enterprise and consumers alike are betting big on future of mobile computing, it’s natural to expect fierce competition in the mobile software platform space. While veterans like Palm OS, Windows Mobile, Symbian and Blackberry have already cornered a good deal of the mobile software market, the new generation platforms such as Android, iPhone (Cocoa), Brew and host of other Linux based platforms are beginning to challenge the old order. As enterprises moving towards mobile application development, the big question remains, which platform to bet on..

 Here are 3 reasons why I would bet on Android over other worthy competitors

1.      Open Handset Alliance – Android is backed by the heavyweights of the industry such as Google, Sony Ericsson, Motorola, Samsung, China Mobile and NTT Docomo..to name a few. The backing of Open Handset Alliance (OHA) will certainly raise the entry barrier for any future competition

2.      Technical advantages – Open source, programming Java on Eclipse plugin (iPhone needs Objective C!!! on XCode IDE), can be developed on win/mac/Linux, runs natively (Blackberry needs special JVM). Along with the OS, you get host of other mobile applications such as an email client, SMS program, calendar and map applications..as bonus!   

3.      Positioning of Android – Shrewd marketing strategists as they are, Google is positioning Android in two parallel markets. With it’s leverage in OHA, there is a constant push for Android adoption by big players in both mobile handset manufacturing as well as mobile Operators. At the same time, as open source platform, it’s targeting consumer ‘first’. Eventually, when Android phones come to enterprise, it would come as consumer-purchased rather than enterprise-issued. On a related note, Google might extend Android to be a desktop OS..if and when such an event happens, the possibilities of cross platform application development would be huge..

All said and done, Android phones are yet to be launched in large scale (Currently being used exclusively on T-Mobile G1). The real test would come with it's application on more high-end phones in the hands of highly demanding consumers. However, as things stand, the future looks promising for Android.

Whitehouse.gov runs on ASP.Net

about 1 year ago | Rohan Daxini: Rohan Daxini

I found some information about http://www.whitehouse.gov/ web site and it turns out that this site runs on ASP.NET. Some interesting characteristics:

- web server is IIS 6.0
- ASP.NET version is 2.0.50727
- they use jQuery 1.2.6 but jQuery scripts are not hosted in Google global script hosting service,
- pages are GZIP compressed and they seem to use pretty high compression level
- JPG files are highly compressed to make page load faster.

Further details on website code --> http://dotnetperls.com/Content/whitehouse-gov-Site.aspx

Sweet Indulgence

about 1 year ago | Erika Santos: Santos on Technology and Life


Optoma has developed an enticing new toy that I would have loved to have back in my traveling days as a consultant. Pk-101 is a 4 oz, 0.6 by 2 inches projector that can be hooked up to any media device.

The other day, when I was struggling to get the projector to work in one of our conference rooms, I just longed for the day when a standard laptop would have its own projector. But PK-101 has given me new aspirations. What I really want is to run presentations from a web app in my mobile device. Now, THAT's mobility.

Image courtesy of CNN.com.

Articles on Trekking - Vasota-Nageshwar, Fansad-Korlai, Ankaai-Tankaai

about 1 year ago | Niranjan Sarade: InLoveWithNature

Here are my few articles about trekking and nature ! I have written those in my Mother Language, i.e. Marathi ! :-)

http://trekshitiz.com/articles/Article_Index.htm

Ruby on Rails - Metric_fu integration with cruisecontrol.rb

about 1 year ago | Niranjan Sarade: InLoveWithNature



You can integrate metric_fu with cruisecontrol ! It is very simple and straightforward !
http://metric-fu.rubyforge.org/

Metric_fu is a set of rake tasks to generate metrics reports. It uses Saikuro ( Cyclomatic complexity), Flog (Cyclomatic complexity) , Rcov (Unit test coverage), Churn ( Finds how many times your files have been changed), Subversion, Git, and Rails built-in stats (LOC, Methods, Test LOC, Code LOC, etc.) task to create a series of reports.

There was issue with stats report not rendering properly in the browser. Fixed that issue with modifying stats rake task inside metric_fu.
Modified file :- jscruggs-metric_fu-0.8.0\lib\tasks\stats.rake

Training with a Budget of $0.

about 1 year ago | Erika Santos: Santos on Technology and Life




Times are tough. Budgets are trim. Specially when it comes to training.



So I decided to increase my skillset inhouse. Having been a Product Owner on different SCRUM teams for about a year, I've come to truly trust the process. And now, it's time for more of it.

My idea is to be coached by a colleague on becoming a SCRUM Master (SM) while coaching a colleague on becoming a Product Owner (PO). Meanwhile, I've also joined a work initiative that allows me to be a SM in a project in which we will develop a tool internal to our department (low risk).

The skills of a PO and a SM are distinct, but of course, complementary. So regardless of what path I take in the upcoming year, I am certain that I will be a greater contributor to my teams for better understanding the SM role.

If anyone out there is also interested in learning more about being a SM, below is some information I found very helpful.

Courtesy of Pete Behrens
SM Key Responsibilities:
  1. Facilitating effective meetings (not necessarily running them, but ensuring that they are focused on the right things, and that team members are engaged)
  2. Coaching (in action, by doing)
  3. Agile Leadership (getting team to self organize)
  4. Organizational Development (removing impediments, exerting influence, navigating through bureaucracy)
SM Traits:
  • Understanding of SCRUM rich enough to be able to educate others about it
  • Making project/activities 'about the team'
  • Facilitating- Engaging team members in decision making

Suggested Reading:
  • Artful Making by Robert Austin and Lee Devin
  • Managing for Excellence by David L. Bradford and Allan R. Cohen

Image courtesy of weddingssc1 on Flickr.

Don't do this if you want them to say "I do."

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

February's issue of Gourmet has a useful and ultimately hilarious article about making romantic gestures - proposals of marriage or otherwise - in restaurants. It starts off as a what not to do list, and ends up with some great stories of proposals gone horribly, horribly awry - and some that went well, too!

Classic, tongue-in-cheek example of why Gourmet is one of my favorite food mags.

UPDATE: I found the article - click away!

Image courtesy of rmrayner on Flickr. Some people lust after diamond solitaires; I prefer sapphires.

Ducks Quack, Eagles Fly

about 1 year ago | Rajesh Rathod: Uncommon "Common Sense"!

I have read this more than a couple of times and found it so meaningful every time... Knowing that you may have already read this, I still thought of sharing it for the benefits of those who may have missed it...


***** Ducks Quack , Eagles Fly *****

No one can make you serve customers well.

That's because great service is a choice.

Harvey Mackay, tells a wonderful story about a cab driver that proved this point.

He was waiting in line for a ride at the airport. When a cab pulled up, the first thing Harvey noticed was that the taxi was polished to a bright shine. Smartly dressed in a white shirt, black tie, and freshly pressed black slacks, the cab driver jumped out and rounded the car to open the back passenger door for Harvey.

He handed my friend a laminated card and said:
"I'm Wally, your driver. While I'm loading your bags in the trunk I'd like you to read my mission statement."

Taken aback, Harvey read the card.. It said:
Wally's Mission Statement: To get my customers to their destination in the quickest, safest and cheapest way possible in a friendly environment.

This blew Harvey away. Especially when he noticed that the inside of the cab matched the outside. Spotlessly clean!

As he slid behind the wheel, Wally said, "Would you like a cup of coffee? I have a thermos of regular and one of decaf."

My friend said jokingly, "No, I'd prefer a soft drink."

Wally smiled and said, "No problem. I have a cooler up front with regular and Diet Coke, water and orange juice."

Almost stuttering, Harvey said, "I'll take a Diet Coke."

Handing him his drink, Wally said, "If you'd like something to read, I have The Wall Street Journal, Time, Sports Illustrated and USA Today."

As they were pulling away, Wally handed my friend another laminated card. "These are the stations I get and the music they play, if you'd like to listen to the radio."

And as if that weren't enough, Wally told Harvey that he had the air conditioning on and asked if the temperature was comfortable for him. Then he advised Harvey of the best route to his destination for that time of day. He also let him know that he'd be happy to chat and tell him about some of the sights or, if Harvey preferred, to leave him with his own thoughts.

"Tell me, Wally," my amazed friend asked the driver, "have you always served customers like this?"

Wally smiled into the rear view mirror. "No, not always. In fact, it's only been in the last two years. My first five years driving, I spent most of my time complaining like all the rest of the cabbies do. Then I heard the personal growth guru, Wayne Dyer, on the radio one day.

He had just written a book called You'll See It When You Believe It. Dyer said that if you get up in the morning expecting to have a bad day, you'll rarely disappoint yourself. He said, 'Stop complaining! Differentiate yourself from your competition. Don't be a duck. Be an eagle.. Ducks quack and complain. Eagles soar above the crowd.'"

"That hit me right between the eyes," said Wally. "Dyer was really talking about me. I was always quacking and complaining, so I decided to change my attitude and become an eagle. I looked around at the other cabs and their drivers. The cabs were dirty, the drivers were unfriendly, and the customers were unhappy. So I decided to make some changes. I put in a few at a time. When my customers responded well, I did more."

"I take it that has paid off for you," Harvey said.

"It sure has," Wally replied. "My first year as an eagle, I doubled my income from the previous year. This year I'll probably quadruple it. You were lucky to get me today. I don't sit at cabstands anymore. My customers call me for appointments on my cell phone or leave a message on my answering machine. If I can't pick them up myself, I get a reliable cabbie friend to do it and I take a piece of the action."

Wally was phenomenal. He was running a limo service out of a Yellow Cab. I've probably told that story to more than fifty cab drivers over the years, and only two took the idea and ran with it. Whenever I go to their cities, I give them a call. The rest of the drivers quacked like ducks and told me all the reasons they couldn't do any of what I was suggesting.

Wally the Cab Driver made a different choice. He decided to stop quacking like ducks and start soaring like eagles.

How about us???

You can use .NET 3.5 with Visual Studio 2005

about 1 year ago | Rohan Daxini: Rohan Daxini

Myth and Misconceptions
It seems that the recent release of Visual Studio 2008 and .NET framework 3.5 is causing lots of confusion. The .NET framework does not have any built-in dependency on Visual Studio. NET 3.5 continues to exploit version 2.0 of the CLR. Visual Studio 2005 is perfectly happy to compile your code against .NET 3.5 assemblies. They are just assemblies. Most of the assemblies in .NET 3.5 are identical to those in .NET 3.0. There are some new assemblies with new features.

The wonderful new LinQ technologies introduced in .Net 3.5 rely on explicit compiler-level support, and therefore require LinQ aware compilers in Visual Studio. The new version of Visual Studio i.e. VS 2008 provides these compilers, allowing developers to take advantage of the new monadic syntax. In addition, Visual Studio 2008 has several new features designed to make it easier to exploit NET 3.5 features such as Ajax and the foundation libraries (WCF, WF and WPF).

Thus .NET 3.5 is perfectly suitable to run on VS 2005 as well. Microsoft has long since split the versioning of the framework from the versioning of the run-time environment.

Why is this explanaition on versioning important?
Well, not everyone is ready to upgrade to Visual Studio 2008. Ofcourse the expense involved in upgrading is a point of decision. Apart from that people dont fall into misconception of various versioning dependencies with the IDE's which is not the case here.

What are the issues if we use .NET 3.5 with VS 2005 ?
Visual Studio 2005 does not have access to various new project and file templates and tools that support the new version of the framework. Developers may need to do more coding in Visual Studio 2005 than would be necessary in Visual Studio 2008.

How to access improvements in .NET 3.5 using VS 2005
As an example, consider the new integration between WF and WCF, provided in the new System.WorkflowServices assembly. The integration is provided via the new WorkflowServiceHost class and a couple of new activities. Visual Studio 2008 has new template support for building workflow services, and comes with a very useful new WCF test harness. However, exploiting this new functionality in Visual Studio 2005 is trivial. Create a WF workflow library, add a reference to System.WorkflowServices and add the new activities to your tool box. Finally, use the WCF Service template to add a service class to your project and you are just about in the same position as you would be in Visual Studio 2008 if you used the new Workflow Service project template. You'll need to write a couple of lines of code to use WorkflowServiceHost to host your service, of course.


The making of four lunches.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

Kitchen Lust: Vintage glassware.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

If I had more cabinet space, one of the first things I'd invest in would be a collection of vintage glassware. Wine glasses, water goblets, champagne coupes (the ones above are available right now on Etsy) - you name it, I'd take it off your hands.

My ultimate goal? A motley yet curated collection that wouldn't look out of place on the best Parisian flea market tables.

Want to do what I can't? Go ahead and search Etsy and eBay, and don't tell me what you find. I'll just be too jealous.

A resolution I'm hoping to keep.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

Buying lunch in midtown Manhattan is really, really expensive. The cheapest lunches, which can be had from street carts, are usually about $5.00. If you want something with vegetables - say, a salad - you're talking more like $10 or $11. Multiply that by five days a week, fifty weeks a year, and we're talking $3,000. THREE GRAND!

So, I have resolved to bring my lunch to work with me at least three times per week. On Fridays, my office provides a free lunch at the (pretty darn decent) cafeteria, and I figure leaving myself one day a week of purchased lunch is probably the most realistic goal.

I've kicked things off this weekend, cooking a bunch of dishes that will keep well in the fridge over the course of the week. I also bought three high-end Tupperware-type thingies with supposedly leak-proof seals.

This week's menu: roasted tomato soup, coq au vin, roasted shrimp with orzo, celery remoulade, and cabbage salad. Might also throw in some brussels sprouts at some point, too. I mean, just because I'm brown bagging it doesn't mean I need to eat cold cuts and carrot sticks all week, right?

Free theatre = excuse to spend money on dinner.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

In case you weren't one of the 100 people I invited on Facebook, or the other 50 I invited via email, I thought it important to let you know that the event of the season is taking place this weekend on the Upper West Side.

That's right - Babel Theatre Project's second annual readings festival, entitled Groundwork, kicks off on January 24th. Six plays in two days, all TOTALLY FREE. (Details on the plays can be found on Babel's website.) Since you're getting two full afternoons of free theatre, I'm thinking you can probably also hit one of these neighborhood spots for dinner, right?

Using transactions in a separate database with Drupal PHPUnit tests

about 1 year ago | Pat Shaughnessy: Pat Shaughnessy - Home

This month I’ve been experimenting with using testing ideas from Ruby on Rails while developing a Drupal module. To read more, see:

If you want to try this out yourself, follow these instructions:

  1. Edit settings.php and use an array of two values for $db_url:

    $db_url["default"] = 'mysql://user:password@localhost/drupal;
    $db_url["test"] = 'mysql://user:password@localhost/drupal_test';
  2. Create a new test database in MySQL:

    CREATE DATABASE drupal_test DEFAULT CHARACTER SET utf8
                                COLLATE utf8_unicode_ci;
  3. Download and save phpunit_setup.inc somewhere in your Drupal application; for example in the “includes” folder.
  4. Include phpunit_setup.inc at the top of each of your PHPUnit test classes. See one of the two articles above for example PHPUnit tests.
  5. Execute your PHPUnit test class from the root folder of your Drupal app:

    $ cd /path/to/your/drupal-site
    $ phpunit YourClass modules/your_module/YourClassFileName.php 
    PHPUnit 3.2.21 by Sebastian Bergmann.
    ..
    Time: 0 seconds
    OK (2 tests)

For more information about how to run PHPUnit with Drupal, see: Writing your first PHPUnit test in Drupal.

Using transactions in a separate database with Drupal PHPUnit tests

about 1 year ago | Pat Shaughnessy: Pat Shaughnessy - Home

Update April 2009:
I’ve started working with Mark Bennett on phpunit_setup.inc and moved it up to a github repository. Mark has adapted it to work with Drupal 5, and we’re working on a number of other related ideas as well. I’ll post updates here about our progress.

This month I’ve been experimenting with using testing ideas from Ruby on Rails while developing a Drupal module. To read more, see:

If you want to try this out yourself, follow these instructions:

  1. Edit settings.php and use an array of two values for $db_url:

    $db_url["default"] = 'mysql://user:password@localhost/drupal;
    $db_url["test"] = 'mysql://user:password@localhost/drupal_test';
  2. Create a new test database in MySQL:

    CREATE DATABASE drupal_test DEFAULT CHARACTER SET utf8
                                COLLATE utf8_unicode_ci;
  3. Download and save phpunit_setup.inc somewhere in your Drupal application; for example in the “includes” folder.
  4. Include phpunit_setup.inc at the top of each of your PHPUnit test classes. See one of the two articles above for example PHPUnit tests.
  5. Execute your PHPUnit test class from the root folder of your Drupal app:

    $ cd /path/to/your/drupal-site
    $ phpunit YourClass modules/your_module/YourClassFileName.php 
    PHPUnit 3.2.21 by Sebastian Bergmann.
    ..
    Time: 0 seconds
    OK (2 tests)

For more information about how to run PHPUnit with Drupal, see: Writing your first PHPUnit test in Drupal.

Using MySQL transactions with Drupal unit tests

about 1 year ago | Pat Shaughnessy: Pat Shaughnessy - Home

Last time I wrote about how to use an entirely separate MySQL database to hold test data for Drupal unit tests, similar to the approach that the Ruby on Rails framework uses for test data. In this post I’ll look at another Rails innovation that can be applied equally well to unit testing with Drupal: running each unit test in a separate database transaction.

First let’s take a quick look at what database transactions are, and how we would use them while running unit tests. In a nutshell, a database transaction is just a way to group a series of SQL operations together and insuring that they are all run together as a single unit – either all of them are executed, or none of them. Let’s take an example. Here are some of the SQL statements Drupal executes when you save a new node in the database:

BEGIN
INSERT INTO node_revisions (nid, uid, title, body, teaser, log, timestamp...
INSERT INTO node (vid, type, language, title, uid, status, created, changed...
UPDATE node_revisions SET nid = 2 WHERE vid = 2
COMMIT

Normally Drupal does not use transactions, but I've inserted the “BEGIN” and “COMMIT” commands here as an example: the transaction starts with the BEGIN command, and ends with the COMMIT command. When MySQL receives the COMMIT command, it allows other database clients (future Drupal HTTP requests, or possibly future command line unit tests) to see the new inserted and updated node data. However, if the transaction were rolled back like this:

BEGIN
INSERT INTO node_revisions (nid, uid, title, body, teaser, log, timestamp...
INSERT INTO node (vid, type, language, title, uid, status, created, changed...
UPDATE node_revisions SET nid = 2 WHERE vid = 2
ROLLBACK

… then none of the changes would be made to the node and node_revisions tables. Instead when MySQL receives the ROLLBACK command it will discard the changes and these tables will appear the same way they did before the transaction started. Therefore, by running each unit test in a separate transaction and rolling it back at the end of each test, we can insure that any changes made to the database by that test are discarded… before the next test is run. Below I’ll explain how to actually do this with PHPUnit and Drupal.

But first let me quickly mention another huge benefit to using transactions with unit test suites: test performance. To learn more about why your tests will run a lot faster using MySQL transactions, read this great article by Mike Clark from the period when Rails 1.0 was released, way back in 2005. What Mike wrote about Rails in 2005 is still true today for Drupal: your unit tests will run faster because fewer SQL statements are required. You won’t need to execute DELETE SQL statements to remove the data after each test since rolling back each transaction accomplishes the same thing.

Now let’s get it to work with Drupal… first let me add a second unit test to my simple PHPUnit test class from last time:

<?php
require_once './includes/phpunit_setup.inc';
class TestDataExampleTest2 extends PHPUnit_Framework_TestCase
{  
  public function create_test_blog_post()
  {
    $node = new stdClass();
    $node->title = "This is a blog post";
    $node->body = "This is the body of the post";
    $node->type = "Story";
    $node->promote = 1;
    node_save($node);
    return $node;
  }
  public function test_there_is_one_post()
  {
    $this->create_test_blog_post();
    $this->assertEquals(1, db_result(db_query("SELECT COUNT(*) FROM {NODE}")));
  }
  public function test_there_are_two_posts()
  {
    $this->create_test_blog_post();
    $this->create_test_blog_post();
    $this->assertEquals(2, db_result(db_query("SELECT COUNT(*) FROM {NODE}")));
  }
}
?>

In this example, I use the phpunit_setup.inc file I wrote in my last post to clear out and setup a new Drupal schema each time I run the tests. Even though I have a clean test database each time I run PHPUnit, without using transactions one of these two unit tests will fail since each one creates its own test data, and assumes no other test data exist in the node table:

$ phpunit TestDataExampleTest2
          modules/test_data_module/TestDataExampleTest2.php 
PHPUnit 3.2.21 by Sebastian Bergmann.
.F
Time: 0 seconds
There was 1 failure:
1) test_there_are_two_posts(TestDataExampleTest2)
Failed asserting that <string:3> matches expected value <integer:2>.
/Users/pat/htdocs/drupal4/modules/test_data_module/TestDataExampleTest2.php:24
FAILURES!
Tests: 2, Failures: 1.

Here the second test fails since the blog post created in the first test is still present in the database. The simplest way to start a new database transaction before each test is run, and to rollback after each test is completed, is with the PHPUnit setup/teardown methods as follows:

public function setup()
{
  db_query("BEGIN");
}
public function teardown()
{
  db_query("ROLLBACK");
}

If you add these functions to the “TestDataExampleTest2” class above both tests should now pass since the ROLLBACK call will delete the nodes created by each test each time teardown is called…

$ phpunit TestDataExampleTest2
          modules/test_data_module/TestDataExampleTest2.php 
PHPUnit 3.2.21 by Sebastian Bergmann.
.F
…
FAILURES!
Tests: 2, Failures: 1.

Wait… what happened? It failed!

The problem is that MySQL does not support transactions using the MyISAM database engine, which is what Drupal uses by default. What we need to do is to convert all of the Drupal MySQL tables to use the InnoDB database engine instead. Unfortunately, there are many implications to using InnoDB vs. MyISAM in Drupal or with any MySQL based application. See "MySQL InnoDB: performance gains as well as some pitfalls" to read more. Specifically, there can be performance issues and degradation when using InnoDB incorrectly, or depending on the type of application you have. Drupal was actually designed and developed with MyISAM in mind, and not InnoDB, although there is some chance this might change for Drupal 7 someday.

Despite all of this, using InnoDB in a test database is a great idea since you will get all of the benefits of isolating tests from each other without having to worry about how InnoDB will effect your production site’s performance. In fact, the performance of your tests will actually be dramatically improved, as Mike Clark explained.

With all of this in mind, I wrote some code to convert the newly created Drupal tables in the test database from MyISAM to InnoDB right after we clear out and reload the test database. Here’s how it works; this code is from phpunit_setup.inc, which I included at the top of my PHPUnit test file:

function enable_mysql_transactions()
{
  convert_test_tables_to_innodb();
  db_query("SET AUTOCOMMIT = 0");  
}
function convert_test_tables_to_innodb()
{
  each_table('convert_to_innodb');  
} 
function each_table($table_callback)
{
  global $db_url;
  $url = parse_url($db_url['test']);
  $database = substr($url['path'], 1);
  $result = db_query("SELECT table_name FROM information_schema.tables
                      WHERE table_schema = '$database'");
  while ($table = db_result($result)) {
    $table_callback($table);
  }
}
function convert_to_innodb($table)
{
  db_query("ALTER TABLE $table ENGINE = INNODB");
}

This iterates over the Drupal tables in the test database and executes ALTER TABLE … ENGINE = INNODB on each one. The SET AUTOCOMMIT=0 command is used to prevent SQL statements from being committed immediately after they are executed, and to allow the InnoDB transactions to work properly.

To repeat and summarize how to employ and separate MySQL test database and transactions in your PHPUnit tests for Drupal, just follow these steps:

  1. Edit settings.php and use an array of two values for $db_url:

    $db_url["default"] = 'mysql://user:password@localhost/drupal;
    $db_url["test"] = 'mysql://user:password@localhost/drupal_test';
  2. Create a new test database in MySQL:

    CREATE DATABASE drupal_test DEFAULT CHARACTER SET utf8
                                COLLATE utf8_unicode_ci;
  3. Download and save phpunit_setup.inc somewhere in your Drupal application; for example in the “includes” folder.
  4. Include phpunit_setup.inc at the top of each of your PHPUnit test classes.
  5. Execute your PHPUnit test class from the root folder of your Drupal app:

    $ cd /path/to/your/drupal-site
    $ phpunit YourClass modules/your_module/YourClassFileName.php 
    PHPUnit 3.2.21 by Sebastian Bergmann.
    ..
    Time: 0 seconds
    OK (2 tests)

Here’s my finished test class:

<?php
require_once './includes/phpunit_setup.inc';
class TestDataExampleTest2 extends PHPUnit_Framework_TestCase
{  
  public function setup()
  {
    db_query("BEGIN");
  }
  public function teardown()
  {
    db_query("ROLLBACK");
  }
  public function create_test_blog_post()
  {
    $node = new stdClass();
    $node->title = "This is a blog post";
    $node->body = "This is the body of the post";
    $node->type = "Story";
    $node->promote = 1;
    node_save($node);
    return $node;
  }
  public function test_there_is_one_post()
  {
    $this->create_test_blog_post();
    $this->assertEquals(1, db_result(db_query("SELECT COUNT(*) FROM {NODE}")));
  }
  public function test_there_are_two_posts()
  {
    $this->create_test_blog_post();
    $this->create_test_blog_post();
    $this->assertEquals(2, db_result(db_query("SELECT COUNT(*) FROM {NODE}")));
  }
}
?>

Using MySQL transactions with Drupal unit tests

about 1 year ago | Pat Shaughnessy: Pat Shaughnessy - Home

Last time I wrote about how to use an entirely separate MySQL database to hold test data for Drupal unit tests, similar to the approach that the Ruby on Rails framework uses for test data. In this post I’ll look at another Rails innovation that can be applied equally well to unit testing with Drupal: running each unit test in a separate database transaction.

First let’s take a quick look at what database transactions are, and how we would use them while running unit tests. In a nutshell, a database transaction is just a way to group a series of SQL operations together and insuring that they are all run together as a single unit – either all of them are executed, or none of them. Let’s take an example. Here are some of the SQL statements Drupal executes when you save a new node in the database:

BEGIN
INSERT INTO node_revisions (nid, uid, title, body, teaser, log, timestamp...
INSERT INTO node (vid, type, language, title, uid, status, created, changed...
UPDATE node_revisions SET nid = 2 WHERE vid = 2
COMMIT

Normally Drupal does not use transactions, but I've inserted the “BEGIN” and “COMMIT” commands here as an example: the transaction starts with the BEGIN command, and ends with the COMMIT command. When MySQL receives the COMMIT command, it allows other database clients (future Drupal HTTP requests, or possibly future command line unit tests) to see the new inserted and updated node data. However, if the transaction were rolled back like this:

BEGIN
INSERT INTO node_revisions (nid, uid, title, body, teaser, log, timestamp...
INSERT INTO node (vid, type, language, title, uid, status, created, changed...
UPDATE node_revisions SET nid = 2 WHERE vid = 2
ROLLBACK

… then none of the changes would be made to the node and node_revisions tables. Instead when MySQL receives the ROLLBACK command it will discard the changes and these tables will appear the same way they did before the transaction started. Therefore, by running each unit test in a separate transaction and rolling it back at the end of each test, we can insure that any changes made to the database by that test are discarded… before the next test is run. Below I’ll explain how to actually do this with PHPUnit and Drupal.

But first let me quickly mention another huge benefit to using transactions with unit test suites: test performance. To learn more about why your tests will run a lot faster using MySQL transactions, read this great article by Mike Clark from the period when Rails 1.0 was released, way back in 2005. What Mike wrote about Rails in 2005 is still true today for Drupal: your unit tests will run faster because fewer SQL statements are required. You won’t need to execute DELETE SQL statements to remove the data after each test since rolling back each transaction accomplishes the same thing.

Now let’s get it to work with Drupal… first let me add a second unit test to my simple PHPUnit test class from last time:

<?php
require_once './includes/phpunit_setup.inc';
class TestDataExampleTest2 extends PHPUnit_Framework_TestCase
{  
  public function create_test_blog_post()
  {
    $node = new stdClass();
    $node->title = "This is a blog post";
    $node->body = "This is the body of the post";
    $node->type = "Story";
    $node->promote = 1;
    node_save($node);
    return $node;
  }
  public function test_there_is_one_post()
  {
    $this->create_test_blog_post();
    $this->assertEquals(1, db_result(db_query("SELECT COUNT(*) FROM {NODE}")));
  }
  public function test_there_are_two_posts()
  {
    $this->create_test_blog_post();
    $this->create_test_blog_post();
    $this->assertEquals(2, db_result(db_query("SELECT COUNT(*) FROM {NODE}")));
  }
}
?>

In this example, I use the phpunit_setup.inc file I wrote in my last post to clear out and setup a new Drupal schema each time I run the tests. Even though I have a clean test database each time I run PHPUnit, without using transactions one of these two unit tests will fail since each one creates its own test data, and assumes no other test data exist in the node table:

$ phpunit TestDataExampleTest2
          modules/test_data_module/TestDataExampleTest2.php 
PHPUnit 3.2.21 by Sebastian Bergmann.
.F
Time: 0 seconds
There was 1 failure:
1) test_there_are_two_posts(TestDataExampleTest2)
Failed asserting that <string:3> matches expected value <integer:2>.
/Users/pat/htdocs/drupal4/modules/test_data_module/TestDataExampleTest2.php:24
FAILURES!
Tests: 2, Failures: 1.

Here the second test fails since the blog post created in the first test is still present in the database. The simplest way to start a new database transaction before each test is run, and to rollback after each test is completed, is with the PHPUnit setup/teardown methods as follows:

public function setup()
{
  db_query("BEGIN");
}
public function teardown()
{
  db_query("ROLLBACK");
}

If you add these functions to the “TestDataExampleTest2” class above both tests should now pass since the ROLLBACK call will delete the nodes created by each test each time teardown is called…

$ phpunit TestDataExampleTest2
          modules/test_data_module/TestDataExampleTest2.php 
PHPUnit 3.2.21 by Sebastian Bergmann.
.F
…
FAILURES!
Tests: 2, Failures: 1.

Wait… what happened? It failed!

The problem is that MySQL does not support transactions using the MyISAM database engine, which is what Drupal uses by default. What we need to do is to convert all of the Drupal MySQL tables to use the InnoDB database engine instead. Unfortunately, there are many implications to using InnoDB vs. MyISAM in Drupal or with any MySQL based application. See "MySQL InnoDB: performance gains as well as some pitfalls" to read more. Specifically, there can be performance issues and degradation when using InnoDB incorrectly, or depending on the type of application you have. Drupal was actually designed and developed with MyISAM in mind, and not InnoDB, although there is some chance this might change for Drupal 7 someday.

Despite all of this, using InnoDB in a test database is a great idea since you will get all of the benefits of isolating tests from each other without having to worry about how InnoDB will effect your production site’s performance. In fact, the performance of your tests will actually be dramatically improved, as Mike Clark explained.

With all of this in mind, I wrote some code to convert the newly created Drupal tables in the test database from MyISAM to InnoDB right after we clear out and reload the test database. Here’s how it works; this code is from phpunit_setup.inc, which I included at the top of my PHPUnit test file:

function enable_mysql_transactions()
{
  convert_test_tables_to_innodb();
  db_query("SET AUTOCOMMIT = 0");  
}
function convert_test_tables_to_innodb()
{
  each_table('convert_to_innodb');  
} 
function each_table($table_callback)
{
  global $db_url;
  $url = parse_url($db_url['test']);
  $database = substr($url['path'], 1);
  $result = db_query("SELECT table_name FROM information_schema.tables
                      WHERE table_schema = '$database'");
  while ($table = db_result($result)) {
    $table_callback($table);
  }
}
function convert_to_innodb($table)
{
  db_query("ALTER TABLE $table ENGINE = INNODB");
}

This iterates over the Drupal tables in the test database and executes ALTER TABLE … ENGINE = INNODB on each one. The SET AUTOCOMMIT=0 command is used to prevent SQL statements from being committed immediately after they are executed, and to allow the InnoDB transactions to work properly.

To repeat and summarize how to employ and separate MySQL test database and transactions in your PHPUnit tests for Drupal, just follow these steps:

  1. Edit settings.php and use an array of two values for $db_url:

    $db_url["default"] = 'mysql://user:password@localhost/drupal;
    $db_url["test"] = 'mysql://user:password@localhost/drupal_test';
  2. Create a new test database in MySQL:

    CREATE DATABASE drupal_test DEFAULT CHARACTER SET utf8
                                COLLATE utf8_unicode_ci;
  3. Download and save phpunit_setup.inc somewhere in your Drupal application; for example in the “includes” folder.
  4. Include phpunit_setup.inc at the top of each of your PHPUnit test classes.
  5. Execute your PHPUnit test class from the root folder of your Drupal app:

    $ cd /path/to/your/drupal-site
    $ phpunit YourClass modules/your_module/YourClassFileName.php 
    PHPUnit 3.2.21 by Sebastian Bergmann.
    ..
    Time: 0 seconds
    OK (2 tests)

Here’s my finished test class:

<?php
require_once './includes/phpunit_setup.inc';
class TestDataExampleTest2 extends PHPUnit_Framework_TestCase
{  
  public function setup()
  {
    db_query("BEGIN");
  }
  public function teardown()
  {
    db_query("ROLLBACK");
  }
  public function create_test_blog_post()
  {
    $node = new stdClass();
    $node->title = "This is a blog post";
    $node->body = "This is the body of the post";
    $node->type = "Story";
    $node->promote = 1;
    node_save($node);
    return $node;
  }
  public function test_there_is_one_post()
  {
    $this->create_test_blog_post();
    $this->assertEquals(1, db_result(db_query("SELECT COUNT(*) FROM {NODE}")));
  }
  public function test_there_are_two_posts()
  {
    $this->create_test_blog_post();
    $this->create_test_blog_post();
    $this->assertEquals(2, db_result(db_query("SELECT COUNT(*) FROM {NODE}")));
  }
}
?>

Using the right DB increased test coverage 10 times !!!

about 1 year ago | Riju Kansal: Riju's Thoughts Captured...

I have not worked on any web application which doesn' t connect to database. If we intend to write our application thru our tests or even vice versa, it becomes quite necessary that the DB we are using gives a great deal of support to the fact.
What support?
- Quickness
- ease of rebuilding
- smooth to handle with a programming language

I worked on an application recently which had no unit tests. When I joined the team I spoke to the team about benefits of tests - both unit and acceptance. The project had good amount automated acceptance tests though.

We tried the idea of in-memory DB - HSQLDB. This is a light weight database made in Java language. Using ANT (with hibernate) we created tasks like -
- generateSchema
- createDatabase
- populateDatabase
- deleteDatabase
Using these tasks we had great control over the DB. Moreover the DB being light and in-memory made writing tests very quick. We even configured it in Cruise Control.
Initially before we started with HSQLDB 10 days back, our test coverage was 3% and now it is 30%, growing exponentially.

Sometimes, size does matter.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

On Saturday night, my apartment was really. Effing. Cold. My windows don't have the best insulation - something that doesn't usually matter, since I can't adjust my own heat and it's usually cranked up way high. But, on Saturday night (after three days of temperatures at or below 20 degrees) it mattered.

To ward off the chill, I decided to bake a batch of madeleines. I hauled the stand mixer out of the pantry and whipped the eggs and sugar till they were thick and glossy - almost like a yolky meringue. Then I gently folded in the vanilla, the silky, sifted flour and the melted butter.

At this point, I needed to make a decision - big, cakey madeleines, or small madeleines, with crisp-crumbly crusts? Being a big fan of the crisp and crumbly, I went for the small.

Aside from being totally adorable, miniature madeleines are perfect for serving with coffee, and they're also a great snack. Smaller than bite-sized, they have a greater crust-to-cake ratio and therefore taste even more strongly of rich, caramelized sugar than their standard-sized counterparts.

An excellent dessert, and pretty good for breakfast today, too. Yum.

A spot of brekkie.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

Scrambled eggs with scallions (a bit of mustard whisked in before cooking makes them a touch richer), toasted English muffin with butter, and coffee. Kate Winslet's charming Inside the Actor's Studio on the TV, and a snowy Upper East Side wonderland out the window.

Not a bad morning, all in all.

Hunkering down.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

If you're not on the East Coast of the States today, you may not know this - but it is really freaking cold out this week. Today, the temperature in Manhattan has hovered around 15 degrees Fahrenheit (it was 9 when I woke up this morning), and it's not going to warm up significantly for at least a few days. Oh, and - we're expecting snow tomorrow and Monday.

So what's a girl to do when it's too cold to leave the apartment? Well, first that girl has to come to terms with the fact that she has no food in the house, and is indeed going to have to trek to the grocery store. Then, she starts planning a menu, and not just because having the oven on helps warm up the house.

On deck for me this weekend? Roasted tomato soup, to take to work for lunch this week. Roast chicken and a riff on Ina's roasted shrimp and orzo dish, ditto. Madeleines, for fun. Gougeres, for my friend Cristin's freezer (she's addicted to the ones at Ouest). And a couple of salads - celery remoulade and Mark Bittman's wintry slaw.

Not a bad agenda, I should think. I'm hoping to post a few recipes as the days pass here in the arctic north, so stay tuned!

Power of MOTIVATION

about 1 year ago | Nikhil Rao: Nix Talk

A group of frogs were traveling through the woods, and two of them
fell into a deep pit. When the other frogs saw how deep the pit
was, they told the two frogs that they were as good as dead. The
two frogs ignored the comments and tried to jump up out of the pit
with all their might. The other frogs kept telling them to stop,
that they were as good as dead. Finally, one of the frogs took
heed to what the other frogs were saying and gave up. He fell down
and died.

The other frog continued to jump as hard as he could. Once again,
the crowd of frogs yelled at him to stop the pain and just die. He
jumped even harder and finally made it out. When he got out, the
other frogs said, "Did you not hear us?" The frog explained to
them that he was deaf. He thought they were encouraging him the
entire time.

This story teaches two lessons:

1. There is power of life and death in the tongue. An encouraging
word to someone who is down can lift them up and help them make it
through the day.

2. A destructive word to someone who is down can be what it takes
to kill them.

Be careful of what you say. Speak life to those who cross your
path. The power of words... it is sometimes hard to understand
that an encouraging word can go such a long way. Anyone can speak
words that tend to rob another of the spirit to continue in
difficult times. Special is the individual who will take the time
to encourage another.

The power of really good software

about 1 year ago | Mark Mintz: Mark Mintz

I am doing some research into SugarCRM and I am absolutely amazed how simple it is to install, configure and use. SugarCRM is an open source CRM package and according to their website:

SugarCRM is rethinking how technology can help companies manage customer relationships. Sugar, the market leading commercial open source CRM application, delivers a feature-rich set of business processes that enhance marketing effectiveness, drive sales performance, improve customer satisfaction and provide executive insight into business performance. Supported by deep collaboration and administration capabilities that adapt to how your company operates, Sugar is delighting customers of all sizes across a broad range of industries.
The need that we are looking for SugarCRM (or any other similar application) to fulfill is to track interactions with a set of people. This is obviously a very small subset of what SugarCRM can do. As a result, the goal of my initial evaluation was to see how easy it would be to get a simplified version of the application in front of key stakeholders and get some feedback on whether we thought it was worth proceeding. In less than 1 hour, I was able to download the entire application stack (Apache, MySQL and the SugarCRM application) and get the application up and running locally on my workstation. Of the hour I spent, these simple steps took about 10 minutes, of which approximately 5 minutes of that was spent waiting for the software to download. In the remaining 50 minutes I was able to login, get a pretty good feel for how the application functions and actually configure the screens and tabs users see and add and remove fields on screens. None of my time was spent reading documentation or user manuals. Instead I was immediately adding value: making changes, testing them out and then making some more changes. Configuration changes are simple drag and drop exercises and saving and deploying changes is as simple as pressing the "Save and Deploy" button. Understanding how to use the application was just as easy and within minutes I was adding data and navigating around the application with ease. All in all, the experience was an absolute pleasure and I believe that after that 1 hour of work I have a good enough sample that I can share with stakeholders to figure out how to proceed. What a great example of software done right!! And the best part....it's FREE!

Using a test database with Drupal unit tests

about 1 year ago | Pat Shaughnessy: Pat Shaughnessy - Home

In my last few posts I used Test Driven Development (TDD) to write a very simple Drupal module and showed how TDD helped to keep my custom code decoupled from the Drupal framework. This time I want to take a closer look at the biggest headache I ran into while using TDD with Drupal: handling the test data. When I started to write unit tests for my example module I ran into trouble creating test data inside each test, since I found that PHPUnit stopped executing the test each time there was a failing assertion, meaning that test data weren’t cleaned up after a test failure. I was able to avoid this problem by creating and deleting the test data before and after each test was run using the setup/teardown methods from PHPUnit. But this solution brings along different problems with it:

  • In setup() I need to create all of the test data that every test will use since it is called every time, which becomes a performance problem as the number of tests increases.
  • Teardown() still won’t be called if there are any PHP syntax errors in my test or production code, which happens a lot if I’m really using TDD.
  • There’s no way to create different test data for different tests
  • Worst of all, any existing data in my Drupal database might cause the tests to fail, and vice-versa: the test data might interfere with my development work.

We need a better approach for handling test data. Rather than reinventing the wheel, let’s take a look at the Ruby on Rails framework for some inspiration and see if we can emulate the way Rails handles test data using PHP and Drupal. How does Rails handle test data? First of all, each Rails application has multiple, different databases setup: one for development, one for production, and a third for testing at a minimum. Every time you run a unit test in Rails, the test database is manipulated as follows:

  • Rails deletes the existing contents of the test database, if any.
  • Rails loads your test database with an empty copy of your application’s database schema (tables, columns, indices, etc.).
  • Finally Rails runs each of the unit tests targeting this empty test database, by default each test within a separate database transaction (more on this in my next post).

How can we do this with Drupal? If you take a close look at the SimpleTest module, you’ll see that it uses some tricks to create a test copy of the Drupal schema using the “database prefix” feature of Drupal. While this works fine, I decided to see if I could directly follow the Rails pattern of having a completely separate MySQL database to use for testing. Let’s use PHPUnit directly on Drupal from the command line again as I did before. Here’s a very simple PHPUnit test:

<?php
require_once './includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
class TestDataExampleTest extends PHPUnit_Framework_TestCase
{  
  public function create_test_blog_post()
  {
    $node = new stdClass();
    $node->title = "This is a blog post";
    $node->body = "This is the body of the post";
    $node->type = "Story";
    $node->promote = 1;
    node_save($node);
    return $node;
  }
  public function test_there_is_one_post()
  {
    $this->create_test_blog_post();
    $this->assertEquals(1, db_result(db_query("SELECT COUNT(*) FROM {NODE}")));
  }
}
?>

As I explained in December, we have to run the unit test from the Drupal root folder as follows (replace “modules/test_data_module/TestDataExampleTest.php” with the path to the test file):

$ cd /path/to/my-drupal-site
$ phpunit TestDataExampleTest modules/test_data_module/TestDataExampleTest.php

The “test_there_is_one_post” unit test will create a test blog post record in the node table, and then count the number of nodes in the database and assert that there is exactly one. Obviously this will fail if there are any existing node records in my Drupal database, or if I even just run the test more than once:

$ phpunit TestDataExampleTest modules/test_data_module/TestDataExampleTest.php
PHPUnit 3.2.21 by Sebastian Bergmann.
F
Time: 0 seconds
There was 1 failure:
1) test_there_is_one_post(TestDataExampleTest)
Failed asserting that <string:6> matches expected value <integer:1>.
/Users/pat/htdocs/drupal4/TestDataExampleTest.php:19
FAILURES!
Tests: 1, Failures: 1.

This failure is actually good: this test is intentionally dependent on the contents of the test database. Later if we can get this test to pass then we know we have properly initialized the contents of the database without resorting to the setup/teardown solution from last time.

Let’s get started by creating a real test database using the MySQL command line:

mysql> CREATE DATABASE drupal_test DEFAULT CHARACTER SET utf8
       COLLATE utf8_unicode_ci;
Query OK, 1 row affected (0.00 sec)

Now, how can we get Drupal to use this database instead of the normal one? Let’s try converting the $db_url value in settings.php into an array, like this:

$db_url["default"] = 'mysql://user:password@localhost/drupal;
$db_url["test"] = 'mysql://user:password@localhost/drupal_test';

Here I’ve renamed the original $db_url variable to $db_url[“default”], and created a new entry for the test database. Now Drupal can run against either the original database, or the test database as we wish.

The next step is to load the test database with an empty copy of the Drupal database schema. In the Rails world, there are Ruby functions that export the development database schema, and then reload it into the test database. In Drupal, the database schema is created automatically by PHP functions when you install the application for the first time. The SimpleTest module also does the same thing before running its tests. Looking at code in install.php from the Drupal installation process, and also in drupal_web_test_case.php from SimpleTest I came up with this solution:

function create_test_drupal_schema()
{
  include_once './includes/install.inc';
  drupal_install_system();
  drupal_install_modules(drupal_verify_profile('default', 'en'));
  $task = 'profile';
  default_profile_tasks($task, '');
  menu_rebuild();
  actions_synchronize();
  _drupal_flush_css_js();

  variable_set('user_mail_status_activated_notify', FALSE);
  $account = user_load(1);
  $merge_data = array('name' => 'admin', 'pass' => 'test', 'roles' => array(),
                     'status' => 1);
  user_save($account, $merge_data);  
}

Here drupal_install_system() and drupal_install_modules() will create most of the empty tables we need just the way they do when you install Drupal. The other calls I took from DrupalWebTestCase->setup() in SimpleTest to create some initial data Drupal requires to function properly, like the menu for example. The last few lines I wrote to setup the admin user properly, and to avoid sending emails to the admin during this process.

The last piece of the puzzle is to find a way to clear out the test database before each test run. To do that, I wrote this code to iterate over all of the tables in the test database and drop them:

function drop_test_tables()
{
  each_table('drop');
}
function each_table($table_callback)
{
  global $db_url;
  $url = parse_url($db_url['test']);
  $database = substr($url['path'], 1);
  $result = db_query("SELECT table_name FROM information_schema.tables
                      WHERE table_schema = '$database'");
  while ($table = db_result($result)) {
    $table_callback($table);
  }
}
function drop($table)
{
  db_query("DROP TABLE $table");
}

To put it all together we just need to call db_set_active(“test”) and call all of this code before our test runs:

db_set_active("test");
drop_test_tables();
create_test_drupal_schema();

Here db_set_active(“test”) tells Drupal we want to use the test database instead of the actual database. After switching to the test database we drop any existing tables that may exist there, and then create a new, empty Drupal schema.

To avoid cluttering my PHPUnit test file, and to be able to reuse this code in many PHPUnit tests, I moved the test database setup into a new include file called: phpunit_setup.inc. I also added some validation code to phpunit_setup.inc to perform a sanity check so you don’t accidentally drop all of the tables in your main Drupal database, and to make it easier to avoid mistakes with $db_url in settings.php. The code requires that "test" be present in the test database name. I also added code to enable database transactions in the test database, which I will discuss in my next post.

To try this out on your system, just download phpunit_setup.inc and then include it at the top of your PHPUnit test file, like this:

<?php
require_once './includes/phpunit_setup.inc';
class TestDataExampleTest extends PHPUnit_Framework_TestCase
{  
  public function create_test_blog_post()
  {
    $node = new stdClass();
    $node->title = "This is a blog post";
    $node->body = "This is the body of the post";
    $node->type = "Story";
    $node->promote = 1;
    node_save($node);
    return $node;
  }
  public function test_there_is_one_post()
  {
    $this->create_test_blog_post();
    $this->assertEquals(1, db_result(db_query("SELECT COUNT(*) FROM {NODE}")));
  }
}
?>

The require_once statement above assumes you downloaded phpunit_setup.inc into the includes folder. If you put it somewhere else, just update require_once as necessary. Now the test passes every time:

$ cd /path/to/my-drupal-site
$ phpunit TestDataExampleTest modules/test_data_module/TestDataExampleTest.php
PHPUnit 3.2.21 by Sebastian Bergmann.
.
Time: 0 seconds
OK (1 test)

One important detail I’ve glossed over here is that the test only passes because it is the only test I’m running at all in this database. If there were a second test with it’s own test data and assumptions about what data were present, then there would be failures depending on what data each test expected, and which test ran first. Next time, I’ll show how Rails solved this problem using database transactions and show how to use them with Drupal unit tests.

Using a test database with Drupal unit tests

about 1 year ago | Pat Shaughnessy: Pat Shaughnessy - Home

In my last few posts I used Test Driven Development (TDD) to write a very simple Drupal module and showed how TDD helped to keep my custom code decoupled from the Drupal framework. This time I want to take a closer look at the biggest headache I ran into while using TDD with Drupal: handling the test data. When I started to write unit tests for my example module I ran into trouble creating test data inside each test, since I found that PHPUnit stopped executing the test each time there was a failing assertion, meaning that test data weren’t cleaned up after a test failure. I was able to avoid this problem by creating and deleting the test data before and after each test was run using the setup/teardown methods from PHPUnit. But this solution brings along different problems with it:

  • In setup() I need to create all of the test data that every test will use since it is called every time, which becomes a performance problem as the number of tests increases.
  • Teardown() still won’t be called if there are any PHP syntax errors in my test or production code, which happens a lot if I’m really using TDD.
  • There’s no way to create different test data for different tests
  • Worst of all, any existing data in my Drupal database might cause the tests to fail, and vice-versa: the test data might interfere with my development work.

We need a better approach for handling test data. Rather than reinventing the wheel, let’s take a look at the Ruby on Rails framework for some inspiration and see if we can emulate the way Rails handles test data using PHP and Drupal. How does Rails handle test data? First of all, each Rails application has multiple, different databases setup: one for development, one for production, and a third for testing at a minimum. Every time you run a unit test in Rails, the test database is manipulated as follows:

  • Rails deletes the existing contents of the test database, if any.
  • Rails loads your test database with an empty copy of your application’s database schema (tables, columns, indices, etc.).
  • Finally Rails runs each of the unit tests targeting this empty test database, by default each test within a separate database transaction (more on this in my next post).

How can we do this with Drupal? If you take a close look at the SimpleTest module, you’ll see that it uses some tricks to create a test copy of the Drupal schema using the “database prefix” feature of Drupal. While this works fine, I decided to see if I could directly follow the Rails pattern of having a completely separate MySQL database to use for testing. Let’s use PHPUnit directly on Drupal from the command line again as I did before. Here’s a very simple PHPUnit test:

<?php
require_once './includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
class TestDataExampleTest extends PHPUnit_Framework_TestCase
{  
  public function create_test_blog_post()
  {
    $node = new stdClass();
    $node->title = "This is a blog post";
    $node->body = "This is the body of the post";
    $node->type = "Story";
    $node->promote = 1;
    node_save($node);
    return $node;
  }
  public function test_there_is_one_post()
  {
    $this->create_test_blog_post();
    $this->assertEquals(1, db_result(db_query("SELECT COUNT(*) FROM {NODE}")));
  }
}
?>

As I explained in December, we have to run the unit test from the Drupal root folder as follows (replace “modules/test_data_module/TestDataExampleTest.php” with the path to the test file):

$ cd /path/to/my-drupal-site
$ phpunit TestDataExampleTest modules/test_data_module/TestDataExampleTest.php

The “test_there_is_one_post” unit test will create a test blog post record in the node table, and then count the number of nodes in the database and assert that there is exactly one. Obviously this will fail if there are any existing node records in my Drupal database, or if I even just run the test more than once:

$ phpunit TestDataExampleTest modules/test_data_module/TestDataExampleTest.php
PHPUnit 3.2.21 by Sebastian Bergmann.
F
Time: 0 seconds
There was 1 failure:
1) test_there_is_one_post(TestDataExampleTest)
Failed asserting that <string:6> matches expected value <integer:1>.
/Users/pat/htdocs/drupal4/TestDataExampleTest.php:19
FAILURES!
Tests: 1, Failures: 1.

This failure is actually good: this test is intentionally dependent on the contents of the test database. Later if we can get this test to pass then we know we have properly initialized the contents of the database without resorting to the setup/teardown solution from last time.

Let’s get started by creating a real test database using the MySQL command line:

mysql> CREATE DATABASE drupal_test DEFAULT CHARACTER SET utf8
       COLLATE utf8_unicode_ci;
Query OK, 1 row affected (0.00 sec)

Now, how can we get Drupal to use this database instead of the normal one? Let’s try converting the $db_url value in settings.php into an array, like this:

$db_url["default"] = 'mysql://user:password@localhost/drupal;
$db_url["test"] = 'mysql://user:password@localhost/drupal_test';

Here I’ve renamed the original $db_url variable to $db_url[“default”], and created a new entry for the test database. Now Drupal can run against either the original database, or the test database as we wish.

The next step is to load the test database with an empty copy of the Drupal database schema. In the Rails world, there are Ruby functions that export the development database schema, and then reload it into the test database. In Drupal, the database schema is created automatically by PHP functions when you install the application for the first time. The SimpleTest module also does the same thing before running its tests. Looking at code in install.php from the Drupal installation process, and also in drupal_web_test_case.php from SimpleTest I came up with this solution:

function create_test_drupal_schema()
{
  include_once './includes/install.inc';
  drupal_install_system();
  drupal_install_modules(drupal_verify_profile('default', 'en'));
  $task = 'profile';
  default_profile_tasks($task, '');
  menu_rebuild();
  actions_synchronize();
  _drupal_flush_css_js();

  variable_set('user_mail_status_activated_notify', FALSE);
  $account = user_load(1);
  $merge_data = array('name' => 'admin', 'pass' => 'test', 'roles' => array(),
                     'status' => 1);
  user_save($account, $merge_data);  
}

Here drupal_install_system() and drupal_install_modules() will create most of the empty tables we need just the way they do when you install Drupal. The other calls I took from DrupalWebTestCase->setup() in SimpleTest to create some initial data Drupal requires to function properly, like the menu for example. The last few lines I wrote to setup the admin user properly, and to avoid sending emails to the admin during this process.

The last piece of the puzzle is to find a way to clear out the test database before each test run. To do that, I wrote this code to iterate over all of the tables in the test database and drop them:

function drop_test_tables()
{
  each_table('drop');
}
function each_table($table_callback)
{
  global $db_url;
  $url = parse_url($db_url['test']);
  $database = substr($url['path'], 1);
  $result = db_query("SELECT table_name FROM information_schema.tables
                      WHERE table_schema = '$database'");
  while ($table = db_result($result)) {
    $table_callback($table);
  }
}
function drop($table)
{
  db_query("DROP TABLE $table");
}

To put it all together we just need to call db_set_active(“test”) and call all of this code before our test runs:

db_set_active("test");
drop_test_tables();
create_test_drupal_schema();

Here db_set_active(“test”) tells Drupal we want to use the test database instead of the actual database. After switching to the test database we drop any existing tables that may exist there, and then create a new, empty Drupal schema.

To avoid cluttering my PHPUnit test file, and to be able to reuse this code in many PHPUnit tests, I moved the test database setup into a new include file called: phpunit_setup.inc. I also added some validation code to phpunit_setup.inc to perform a sanity check so you don’t accidentally drop all of the tables in your main Drupal database, and to make it easier to avoid mistakes with $db_url in settings.php. The code requires that "test" be present in the test database name. I also added code to enable database transactions in the test database, which I will discuss in my next post.

To try this out on your system, just download phpunit_setup.inc and then include it at the top of your PHPUnit test file, like this:

<?php
require_once './includes/phpunit_setup.inc';
class TestDataExampleTest extends PHPUnit_Framework_TestCase
{  
  public function create_test_blog_post()
  {
    $node = new stdClass();
    $node->title = "This is a blog post";
    $node->body = "This is the body of the post";
    $node->type = "Story";
    $node->promote = 1;
    node_save($node);
    return $node;
  }
  public function test_there_is_one_post()
  {
    $this->create_test_blog_post();
    $this->assertEquals(1, db_result(db_query("SELECT COUNT(*) FROM {NODE}")));
  }
}
?>

The require_once statement above assumes you downloaded phpunit_setup.inc into the includes folder. If you put it somewhere else, just update require_once as necessary. Now the test passes every time:

$ cd /path/to/my-drupal-site
$ phpunit TestDataExampleTest modules/test_data_module/TestDataExampleTest.php
PHPUnit 3.2.21 by Sebastian Bergmann.
.
Time: 0 seconds
OK (1 test)

One important detail I’ve glossed over here is that the test only passes because it is the only test I’m running at all in this database. If there were a second test with it’s own test data and assumptions about what data were present, then there would be failures depending on what data each test expected, and which test ran first. Next time, I’ll show how Rails solved this problem using database transactions and show how to use them with Drupal unit tests.

Impact of the economy on PMs

about 1 year ago | Mark Mintz: Mark Mintz

Josh Nankivel at PMStudent.com created a survey that asks participants

What impacts on project management (in particular) have you seen from the state of the economy?
A slightly revised version of my initial response below:
In the world of software development within enterprise IT, with less money available for projects, teams are asked to do the same or more with less....less money, less people, less tools, etc. The PMs who will be the most successful in this climate are the ones who do more than just manage. Those that can lead, inspire and motivate, those that can innovate, those that can break down barriers and remove impediments, those that can teach and mentor and make others better, those that can pitch in and code or test or prioritize requirements or help solve problems when necessary, those who can get stuff done by building empowered and enabled high performing teams will succeed.....come to think of it, these are the people who will also be most successful when the economy is strong!

Interview questions for software developers

about 1 year ago | Mark Mintz: Mark Mintz

Jurgen Appelo, CIO at ISM eCompany and author of the NOOP.NL blog, posted a list of 100 interview questions for software developers. The list includes questions grouped by knowledge areas like Requirements, Project Management, Testing as well as Functional Design, Technical Design, Construction, Data Structures and Algorithms so it should apply to PMs, BAs, Scrum Masters and Product Owners as well as Developers and Architects.

Going through the questions and thinking about how I would answer the questions was an interesting exercise that I would recommend for others. Some of my favorite questions:

  1. How do you treat changing requirements? Are they good or bad? Why?
  2. What do you do with requirements that are incomplete or incomprehensible?
  3. Can you name the responsibilities of the user, the customer and the developer in the requirements process?
  4. How can you reduce the user's perception of waiting when some functions take a lot of time?
  5. Which tools are essential to you for testing the quality of your code?
  6. What measures have you taken to make your software products more easily maintainable?
  7. What can you do reduce the chance that a customer finds things that he doesn't like during acceptance testing?
  8. How many of the three variables scope, time and cost can be fixed by the customer?

Refactoring as a learning exercise

about 1 year ago | Mark Mintz: Mark Mintz

Over the last several months I have been trying to add a new tool to my tool belt by learning Ruby, Ruby on Rails and RSpec. After completing some tutorials and other basic programming tasks I was looking for something else to further develop my skills. Not having any great ideas for new applications I turned to our SVN repository and the code base for an application that I was functionally familiar with. My goal was to look through the code base, understand what was going on and see if there was anything that I could refactor. I figured this would be a good way to learn from real world code. This code base is for a new, greenfield project and was developed with good RSpec coverage so it was a good candidate because the code was likely in good condition and it would really challenge me by stretching my Ruby and Rails skills. As I dug around I found some things that were of interest and possible candidates for refactoring:

  1. In trying to understand what one area of the code was doing I looked first to the RSpec tests. After reading the tests and then the code the tests were testing I realized that the tests were created at a higher level and as a result it was somewhat hard to infer the behavior of the code under test
  2. In that same area of the code several Model classes had quite a bit of hand written SQL code. Portions of the SQL was dynamically generated and as a result it was somewhat difficult to understand what was actually going on. I knew functionally what this area of the code was supposed to be doing but it was not totally clear from reading the code what it was actually doing
This was the opportunity I was looking for...could I figure out what was going on, refactor the code to better leverage ActiveRecord without having to write custom SQL and get the proper results at the end? Having a goal and learning opportunity in place here is what I did:

I started by writing my own RSpec tests at a lower level of detail. The existing tests tested higher level methods that called several lower level methods, did some calculations and returned a result. The new tests I wrote started by testing the lower level methods individually. This had two benefits: (1) I could get a better understanding of what each of the lower level methods were doing and (2) I could refactor each method individually and have tests that would ensure I was not breaking anything at the lowest level of detail. This was by far the slowest part of the exercise because I needed to work through much of the handwritten SQL to be able to understand what was expected from these methods so that I could write the tests. After several hours of walking through the code and testing out SQL's against the development database I had what I thought was a decent handle on what was going on so I created my first test and verified that I was able to get it to pass with the existing code. My next step was to then figure out how I could replace the hand written SQL with ActiveRecord API calls and retain the same functionality. The first place I started was with the ActiveRecord find_by Dynamic attribute-based finders. The first challenge I faced was that the handwritten SQL's had several joins that I needed to deal with. To be able to deal with these joins I added some associations to the appropriate model classes and began to dive into getting the right :group, :include and :conditions options to return what I needed. This was an amazing learning exercise in Rails and the power it possesses. Finally, after several more hours of trying different things on IRB I got something that seemed like it could work. During my research however, I bumped into the ActiveRecord Calculations module. Considering that the main goal of the SQL's I was trying to refactor was to sum column data I thought perhaps the sum method would be an even better option. After several passes through IRB with the sum method I found what I was looking for and lucky me, my first test passed. From this point on it was more of the same with 5 or 6 additional methods until I got to a point where all of the hadwritten SQL was replaced by ActiveRecord API calls and I had a set of RSpecs that tested each method individually, including the higher level method that calls all of the lower level methods. Having made it this far and feeling pretty good about the results, I identified some next steps to keep the learning going:
  1. complete the same exercise for the remaining model classes where similar hand written SQLs exist
  2. look for areas where I can extract duplicate code across all of those models into single, re-usable methods or classes
  3. work on refactoring the RSpecs to improve their performance. Currently they feel a bit slow due to, what I suspect, are the many database interactions that are happening
So for those of you that have actually read this far down, here is what I learned:
  1. Refactoring is a great way to learn about a programming language. If you are new to a language try finding some existing code, write some tests for it to get an understanding of what it is doing and then refactor the code while getting the tests to pass.
  2. Using TDD or BDD makes learning about a programming language easier
  3. ActiveRecord is a powerful tool that gives you a great way to interact with a database without having to write SQL

Internet Connection monitoring script for the GNOME panel

about 1 year ago | Amar Phadke: Amar Phadke's weblog

I was having issues with my Internet connection lately. My connection used to drop after using it for a while and the router used to lose the IP address. I decided to write a simple script that would sit on the GNOME panel and tell me the current state of my Internet connection. I found a [...]

An anticipatory moment of silence, please.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

The word on the street is that Gourmet Magazine, helmed since 1999 by the truly remarkable Ruth Reichl, may be on its way out. Since 2004, their ad pages have dropped from 1,364 to 955; Conde Nast may be feeling overextended in the food mag department, given their simultaneous investements in Bon Appetit and Epicurious.com.

The choice of Bon Appetit over Gourmet may be the best fiscal choice, but is not, in my opinion, the right one. Under Reichl's direction, Gourmet has become slightly too aspirational (some of the serving pieces featured cost a week's salary), but it's also highlighted little-known travel destinations (Strasbourg, the Auvergne, Laos, western China), and championed delicious foods made with quality ingredients.

Reichl brought in superlative food photographer Romulo Yanes, whose pictures routinely rise above traditional "food porn," as well as the coolest roadies ever, Jane & Michael Stern. She also nabbed David Foster Wallace, who penned a hotly discussed essay entitled Consider The Lobster for the August 2004 issue.

Reichl not only writes the only editor's letter worth reading every single month; she has also transformed Gourmet from a housewife's staid bible to a sophisticated cook's fantasy fodder.

If Ruth Reichl is anything, she's a survivor. If Gourmet does close up shop, she'll take on a new challenge, and it will be a thrill to see what she does next.

But I'll still be a little bit sad.

Hello, my name is Meg, and I'm a caffeine addict.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

Dear Caffeine,

I love you.

I love the way my morning coffee gives me a burst of energy. I love that a cup of espresso settles my stomach after a meal, and I love that a Diet Coke settles my stomach after a night of profligate cocktailing.

I love the smell of brewing coffee, and I love the aroma of a strong English Breakfast or Earl Grey tea. I love that a cafe au lait is substantial enough to be an afternoon snack, and that a cappuccino can serve as breakfast.

I love that you are always there for me - through every late night, early morning, and long-ass meeting, you're there, holding my hand, keeping me sane and awake. So, thank you.

And, one more time (because when you mean it, you can't say it often enough): I love you.

XOXO,
Meg

Paris in Poladroid.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

My new toy makes stuff look old.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

Feeling nostalgic? Check out the Poladroid project. This free software turns your digital photos into sentimental Polaroid-esque images. SO fun and addictive.

Many thanks to stylish, inspiring blogger Katy Elliott for the heads-up on this one. After all, who needs to go do laundry when I could just sit here and play with this all day long?

TDD keeps your PHP code separate from Drupal

about 1 year ago | Pat Shaughnessy: Pat Shaughnessy - Home

Many Drupal projects that I’ve been involved with during the past few years have all suffered from different variations on the same problem: the custom PHP code added by me and the development team I was in has ended up being highly coupled with the Drupal framework. At best, our code was hard to understand without knowing a lot about Drupal internals and could never run on its own outside of Drupal. At worst, our code changes were made right inside Drupal core functions and needed to be identified, reimplemented and merged into every newer version of Drupal whenever we decided to upgrade.

In hindsight, I believe that we could have avoided all of these problems if we had only used Test Driven Development (TDD). Using TDD has a lot of benefits for any software project which I won’t go into here (see Wikipedia or Bob Martin's explanation for more information) but I believe the biggest benefit of using TDD specifically on a Drupal development project is that it makes it easy to write PHP code that is not highly coupled with Drupal, is easy to distinguish from Drupal’s core modules, and can even run on its own outside of Drupal entirely.

The same is probably true while developing inside any application development framework.

To explore this topic in detail and find out whether I was right about this, in December I started experimenting with Drupal and TDD. After I wrote my first Drupal PHPUnit test, I started to write a simple example module using TDD, showing how the test first thought process can work with PHP and Drupal. Below I’ll take a look at the finished example module to see whether the module’s code is any less coupled to Drupal, and whether it’s any easier to identify and maintain.

But first let’s take a closer look at the 3 types of PHP code any Drupal web site will contain:

  1. Drupal Code: This is the PHP code you download from drupal.org: files such as node.module, common.include, index.php, etc. You can assume it all works properly, was tested by the Drupal community and is used in thousands of other web sites successfully.
  2. Custom Code: This is code you write to actually implement the special behavior your business or community needs in its web site. You need to write and maintain this, and you need to test that it works properly since no one else will use it.
  3. Connection Code: This is code you have to write to connect your custom code to Drupal. Unfortunately, there’s no way to magically drop your business logic into a Drupal site and see it appear in a web page, ready for users. You need to know something about how Drupal actually works, and you need to connect your Custom Code with the Drupal Code properly.

A good way to understand better the difference between Drupal, Custom and Connection code is to imagine that next year you decide to upgrade your site from Drupal 6.x to Drupal 7, or that you decide to rebuild your site with Ruby on Rails or some other new technology. What you would have to do is:

  • Discard the Drupal Code, and replace it with the new framework.
  • Discard your Connection Code, and write the necessary new code required to connect to the new framework.
  • Take your Custom Code with you, possibly retaining the PHP unchanged for Drupal 7, or else rewriting it using Ruby or some other language.

Clearly you need to know which code is which or else you’ll discard code you really need! TDD can make this easy; the reason why is that using PHPUnit forces you to structure your Custom Code so that it can run outside of Drupal from the command line. Knowing that your Custom Code can run outside of Drupal inside of a unit test suite guarantees that you will be able to take the code with you and later connect it to another framework.

Let’s see how my example module turned out; see one of my previous posts for more background on what this module does and how to set it up. Here’s the finished code:

What I’ve done since my last post while finishing up this simple example is to separate the Custom Code and Connection Code into two separate files. First, here’s my finished Custom Code:

<?php
function tdd_search_for_titles($query, $ascending, $from, $count) {
  $titles = array();
  if ($query != NULL) {
    $sql = "SELECT title FROM {node} WHERE title LIKE '%%%s%%'";
    if ($ascending) {
      $sql .= ' ORDER BY title';
    }
    else {
      $sql .= ' ORDER BY title DESC';
    }
    if ($from || $count) {
      $result = db_query_range($sql, $query, $from, $count);
    }
    else {
      $result = db_query($sql, $query);
    }
    while ($node = db_fetch_object($result)) {
      $titles[] = $node->title;
    }
  }
  return $titles;
}
?>

This probably could be refactored even more into 2 or 3 simpler methods, but the question here is whether this is Custom Code, or Connection Code. I know this is my Custom Code because:

  • This is the code that actually implements the behavior I am trying to achieve. In this simple example the code is searching for nodes by words in their titles.
  • This code is not at all coupled to the Drupal framework. This function is easy to understand for any PHP developer, even someone who knows nothing about Drupal. The only minor exception here is that it uses 3 simple utility Drupal functions: db_query(), db_query_range() and db_fetch_object(). However, these are self-explanatory; If I were a purist, I could have used the mysql_query() function instead, and have eliminated all of my dependencies on Drupal entirely. The code also assumes the presence of the node table and the title column within it, but the same code would work on any database table containing web pages and their titles with only trivial changes. The point is that the code is easy to understand and would be easy to migrate to another framework.
  • This code can run outside the Drupal framework. I know this is the case since I do this when I run PHPUnit on my tests in TddTests.php:
    $ cd ~/htdocs/drupal3
    $ phpunit TddTests modules/tdd/TddTests.php 
    PHPUnit 3.2.21 by Sebastian Bergmann.
    ............
    Time: 0 seconds
    OK (12 tests)

The test code, which I won’t repeat here, is also an essential part of my Custom Code, since it is the only way I have to prove that my function is working properly. It also documents my code’s the desired behavior, and finally will allow me to validate that the code is working if I ever move it to a newer version of Drupal or to some other technology. Also, if you take a look at TddTests.php, you’ll see that the test code is also not highly coupled to Drupal. There are a few references to node_save() and drupal_bootstrap() for example, but most of the test code is pure PHPUnit and has nothing to do with Drupal.

Let’s take a look at my Connection Code, which is in the tdd.module file. I won’t repeat all of it here in this page, but if you look at tdd.module you can see the code does not have these 3 qualities:

  • This code has nothing to do with the behavior I’m trying to implement. It simply provides URL parameters from the user’s request to tdd_search_for_titles(), and displays the results from tdd_search_for_titles() in a web page. It also handles the complexity around the Drupal Form API.
  • This code is very coupled to the Drupal framework. For someone who doesn’t understand Drupal internals tdd.module is very hard to understand – even for developers with years of PHP experience.
  • This code could never run outside of the Drupal framework. This is because it uses functions such as drupal_get_form() and theme() that would be impossible - and pointless - to implement outside of Drupal. More importantly, the functions in tdd.module are called by Drupal at certain times during its processing; none of this would make any sense outside of Drupal.

Here’s the only interesting snippet from my Connection Code:

...
$sortAscending = true;
if (isset($_GET['sort']) && $_GET['sort'] == 'desc') {
  $sortAscending = false;
}
$titles = tdd_search_for_titles($keys, $sortAscending, 0, 10);
$rows = array();
foreach ($titles as $title) {
  $rows[] = array($title);
}
...

This is the actual location in the code where we “connect” from Drupal to my Custom Code, and vice-versa. This few lines are actually passing (connecting) the request parameters onto my Custom Code, and later saving the results in $titles which is parsed and returned to Drupal in the required format.

In my next post I’ll try using TDD again to write a more complex and interesting Drupal module: one that will display monthly archive links - e.g. January 2009 (23) - for a Drupal blog, similar to what you would see in a standard WordPress or B2Evolution blog site.

TDD keeps your PHP code separate from Drupal

about 1 year ago | Pat Shaughnessy: Pat Shaughnessy - Home

Many Drupal projects that I’ve been involved with during the past few years have all suffered from different variations on the same problem: the custom PHP code added by me and the development team I was in has ended up being highly coupled with the Drupal framework. At best, our code was hard to understand without knowing a lot about Drupal internals and could never run on its own outside of Drupal. At worst, our code changes were made right inside Drupal core functions and needed to be identified, reimplemented and merged into every newer version of Drupal whenever we decided to upgrade.

In hindsight, I believe that we could have avoided all of these problems if we had only used Test Driven Development (TDD). Using TDD has a lot of benefits for any software project which I won’t go into here (see Wikipedia or Bob Martin's explanation for more information) but I believe the biggest benefit of using TDD specifically on a Drupal development project is that it makes it easy to write PHP code that is not highly coupled with Drupal, is easy to distinguish from Drupal’s core modules, and can even run on its own outside of Drupal entirely.

The same is probably true while developing inside any application development framework.

To explore this topic in detail and find out whether I was right about this, in December I started experimenting with Drupal and TDD. After I wrote my first Drupal PHPUnit test, I started to write a simple example module using TDD, showing how the test first thought process can work with PHP and Drupal. Below I’ll take a look at the finished example module to see whether the module’s code is any less coupled to Drupal, and whether it’s any easier to identify and maintain.

But first let’s take a closer look at the 3 types of PHP code any Drupal web site will contain:

  1. Drupal Code: This is the PHP code you download from drupal.org: files such as node.module, common.include, index.php, etc. You can assume it all works properly, was tested by the Drupal community and is used in thousands of other web sites successfully.
  2. Custom Code: This is code you write to actually implement the special behavior your business or community needs in its web site. You need to write and maintain this, and you need to test that it works properly since no one else will use it.
  3. Connection Code: This is code you have to write to connect your custom code to Drupal. Unfortunately, there’s no way to magically drop your business logic into a Drupal site and see it appear in a web page, ready for users. You need to know something about how Drupal actually works, and you need to connect your Custom Code with the Drupal Code properly.

A good way to understand better the difference between Drupal, Custom and Connection code is to imagine that next year you decide to upgrade your site from Drupal 6.x to Drupal 7, or that you decide to rebuild your site with Ruby on Rails or some other new technology. What you would have to do is:

  • Discard the Drupal Code, and replace it with the new framework.
  • Discard your Connection Code, and write the necessary new code required to connect to the new framework.
  • Take your Custom Code with you, possibly retaining the PHP unchanged for Drupal 7, or else rewriting it using Ruby or some other language.

Clearly you need to know which code is which or else you’ll discard code you really need! TDD can make this easy; the reason why is that using PHPUnit forces you to structure your Custom Code so that it can run outside of Drupal from the command line. Knowing that your Custom Code can run outside of Drupal inside of a unit test suite guarantees that you will be able to take the code with you and later connect it to another framework.

Let’s see how my example module turned out; see one of my previous posts for more background on what this module does and how to set it up. Here’s the finished code:

What I’ve done since my last post while finishing up this simple example is to separate the Custom Code and Connection Code into two separate files. First, here’s my finished Custom Code:

<?php
function tdd_search_for_titles($query, $ascending, $from, $count) {
  $titles = array();
  if ($query != NULL) {
    $sql = "SELECT title FROM {node} WHERE title LIKE '%%%s%%'";
    if ($ascending) {
      $sql .= ' ORDER BY title';
    }
    else {
      $sql .= ' ORDER BY title DESC';
    }
    if ($from || $count) {
      $result = db_query_range($sql, $query, $from, $count);
    }
    else {
      $result = db_query($sql, $query);
    }
    while ($node = db_fetch_object($result)) {
      $titles[] = $node->title;
    }
  }
  return $titles;
}
?>

This probably could be refactored even more into 2 or 3 simpler methods, but the question here is whether this is Custom Code, or Connection Code. I know this is my Custom Code because:

  • This is the code that actually implements the behavior I am trying to achieve. In this simple example the code is searching for nodes by words in their titles.
  • This code is not at all coupled to the Drupal framework. This function is easy to understand for any PHP developer, even someone who knows nothing about Drupal. The only minor exception here is that it uses 3 simple utility Drupal functions: db_query(), db_query_range() and db_fetch_object(). However, these are self-explanatory; If I were a purist, I could have used the mysql_query() function instead, and have eliminated all of my dependencies on Drupal entirely. The code also assumes the presence of the node table and the title column within it, but the same code would work on any database table containing web pages and their titles with only trivial changes. The point is that the code is easy to understand and would be easy to migrate to another framework.
  • This code can run outside the Drupal framework. I know this is the case since I do this when I run PHPUnit on my tests in TddTests.php:
    $ cd ~/htdocs/drupal3
    $ phpunit TddTests modules/tdd/TddTests.php 
    PHPUnit 3.2.21 by Sebastian Bergmann.
    ............
    Time: 0 seconds
    OK (12 tests)

The test code, which I won’t repeat here, is also an essential part of my Custom Code, since it is the only way I have to prove that my function is working properly. It also documents my code’s the desired behavior, and finally will allow me to validate that the code is working if I ever move it to a newer version of Drupal or to some other technology. Also, if you take a look at TddTests.php, you’ll see that the test code is also not highly coupled to Drupal. There are a few references to node_save() and drupal_bootstrap() for example, but most of the test code is pure PHPUnit and has nothing to do with Drupal.

Let’s take a look at my Connection Code, which is in the tdd.module file. I won’t repeat all of it here in this page, but if you look at tdd.module you can see the code does not have these 3 qualities:

  • This code has nothing to do with the behavior I’m trying to implement. It simply provides URL parameters from the user’s request to tdd_search_for_titles(), and displays the results from tdd_search_for_titles() in a web page. It also handles the complexity around the Drupal Form API.
  • This code is very coupled to the Drupal framework. For someone who doesn’t understand Drupal internals tdd.module is very hard to understand – even for developers with years of PHP experience.
  • This code could never run outside of the Drupal framework. This is because it uses functions such as drupal_get_form() and theme() that would be impossible - and pointless - to implement outside of Drupal. More importantly, the functions in tdd.module are called by Drupal at certain times during its processing; none of this would make any sense outside of Drupal.

Here’s the only interesting snippet from my Connection Code:

...
$sortAscending = true;
if (isset($_GET['sort']) && $_GET['sort'] == 'desc') {
  $sortAscending = false;
}
$titles = tdd_search_for_titles($keys, $sortAscending, 0, 10);
$rows = array();
foreach ($titles as $title) {
  $rows[] = array($title);
}
...

This is the actual location in the code where we “connect” from Drupal to my Custom Code, and vice-versa. This few lines are actually passing (connecting) the request parameters onto my Custom Code, and later saving the results in $titles which is parsed and returned to Drupal in the required format.

In my next post I’ll try using TDD again to write a more complex and interesting Drupal module: one that will display monthly archive links - e.g. January 2009 (23) - for a Drupal blog, similar to what you would see in a standard WordPress or B2Evolution blog site.

How I refine a test spec while writing getting it to green

about 1 year ago | Alex Rothenberg: Common Sense Software

In most of the examples I've read on TDD they show the Red-Green-Refactor cycle as


  1. Write a failing test

  2. Write just enough code to make the test pass

  3. Refactor

  4. Repeat



I absolutely do believe in this cycle and live it every day however I think there's a small detail that differs from what I do. When I move from step 1 to step 2, I keep my test window open and will switch back and forth between the test and code windows and refining the test while writing the code that makes the test pass. Its only as I write the code that I realize what calls I need to mock out in the test which also adds additional expectations to my test. I'm sure this is how most people work but I've never seen it written up so I'm going to try going through an example here.

Let's say I have a social networking application with a page showing friend requests where you can accept or reject each request. Something like this


Friend Requests:

Accept request from Pat?
Accept request from Gourav?



Now I'm ready to implement an action in the Friend Controller that receives a posted form with a list of friend requests to accept and reject. I might first go into my friends_controller_spec.rb and write something like


describe FriendController do
it 'should approve one friend requests' do
post :update_requests, :approved_requests => ['123']
response.should be_redirect
response.should redirect_to(:back)
flash[:notice].should == "Friend requests approved."
end
end


Now I have a failing test so I start implementing the code


class FriendController < ApplicationController
def update_requests
FriendRequest.approve(params[:approve_requests])
flash[:notice] = "User access changes saved."
redirect_to :back
end
end


I'm done but my test is still failing...why? I haven't added the approve method to my FriendRequest model yet. I could go ahead and implement that method to get this test to pass but I don't want to do that because then this test would be testing more than just one unit. This is a unit test for the update_requests method of my FriendController and should be isolated from bugs in the rest of my application. Time to go back to the spec and add a mock to isolate this spec from the model and impose another expectation on my spec (that the method be called with the correct argument).


describe FriendController do
it 'should approve one friend requests' do
FriendRequest.expects(:approve).with(['123'])
request.env['HTTP_REFERER'] = "http://some.site.com"

post :update_requests, :approved_requests => ['123']
response.should be_redirect
response.should redirect_to(:back)
flash[:notice].should == "Friend requests approved."
end
end


Now my spec passes and I can do my refactoring then go back to the beginning and write my next expectation.

The point of this example is that when I first wrote the spec I hadn't yet thought about how I would implement update_requests so did not yet know that I would need to mock FriendRequest.approve. I do this all the time and typically find myself go back and forth between the code and spec many times with the spec telling me what code I need to write and the code telling me how to refine the spec.

One last point (and a teaser for a future post). You have probably noticed that although my spec passes if I try to run the application it will not work because I still haven't written the FriendRequest.approve method. In a future post I hope to discuss how to interleave integration testing into this process to ensure that the classes we're writing in isolation also integrate so that the application satisfies its business function.

How I refine a test spec while writing getting it to green

about 1 year ago | Alex Rothenberg: Common Sense Software

In most of the examples I've read on TDD they show the Red-Green-Refactor cycle as


  1. Write a failing test

  2. Write just enough code to make the test pass

  3. Refactor

  4. Repeat



I absolutely do believe in this cycle and live it every day however I think there's a small detail that differs from what I do. When I move from step 1 to step 2, I keep my test window open and will switch back and forth between the test and code windows and refining the test while writing the code that makes the test pass. Its only as I write the code that I realize what calls I need to mock out in the test which also adds additional expectations to my test. I'm sure this is how most people work but I've never seen it written up so I'm going to try going through an example here.

Let's say I have a social networking application with a page showing friend requests where you can accept or reject each request. Something like this


Friend Requests:

Accept request from Pat?
Accept request from Gourav?



Now I'm ready to implement an action in the Friend Controller that receives a posted form with a list of friend requests to accept and reject. I might first go into my friends_controller_spec.rb and write something like


describe FriendController do
it 'should approve one friend requests' do
post :update_requests, :approved_requests => ['123']
response.should be_redirect
response.should redirect_to(:back)
flash[:notice].should == "Friend requests approved."
end
end


Now I have a failing test so I start implementing the code


class FriendController < ApplicationController
def update_requests
FriendRequest.approve(params[:approve_requests])
flash[:notice] = "User access changes saved."
redirect_to :back
end
end


I'm done but my test is still failing...why? I haven't added the approve method to my FriendRequest model yet. I could go ahead and implement that method to get this test to pass but I don't want to do that because then this test would be testing more than just one unit. This is a unit test for the update_requests method of my FriendController and should be isolated from bugs in the rest of my application. Time to go back to the spec and add a mock to isolate this spec from the model and impose another expectation on my spec (that the method be called with the correct argument).


describe FriendController do
it 'should approve one friend requests' do
FriendRequest.expects(:approve).with(['123'])
request.env['HTTP_REFERER'] = "http://some.site.com"

post :update_requests, :approved_requests => ['123']
response.should be_redirect
response.should redirect_to(:back)
flash[:notice].should == "Friend requests approved."
end
end


Now my spec passes and I can do my refactoring then go back to the beginning and write my next expectation.

The point of this example is that when I first wrote the spec I hadn't yet thought about how I would implement update_requests so did not yet know that I would need to mock FriendRequest.approve. I do this all the time and typically find myself go back and forth between the code and spec many times with the spec telling me what code I need to write and the code telling me how to refine the spec.

One last point (and a teaser for a future post). You have probably noticed that although my spec passes if I try to run the application it will not work because I still haven't written the FriendRequest.approve method. In a future post I hope to discuss how to interleave integration testing into this process to ensure that the classes we're writing in isolation also integrate so that the application satisfies its business function.

:-))

about 1 year ago | Surbhi Bhati: Clean Desk, Jammed drawers

When you are born,

Your world is so small

Mother’s lap & father’s shoulder

Is all you know of.

And then you grow up

Startled that the business of life is very mean

And before you realize

You are turned into a machine.

While you make money, drink, dance

and chill out

all you hear is noises

and Voices die out.

You don’t even know how long you’ve been pretending

Being a person, you never thought of

So why not once be your innocent self

And damn the showing of

We always portray what we wanna be

We never cherish what we actually are

We become a person of other’s want

And our true self stands far

So being yourself is not that bad

It’s mighty hard I agree

but it may well turn you on

and stand on top and bounce and flee!!!

Need your help

about 1 year ago | Biju Bhaskar: Thoughts on enterprise application development...

As I mentioned earlier, I'm participating at Wharton this week in an intensive workshop on the development of web-based products and services. My classmates and I have developed some interesting new websites. We're very interested in having some potential users take a look at these sites and provide us with some reactions. Today is our friends and family sneak preview. Please take a look at http://www.wwwharton.com.

These are proof-of-concept prototypes intended to gauge your reactions. That information will be extremely helpful in deciding whether or not to pursue the opportunities and how to improve the approaches. While your actively providing feedback is certainly welcome, simply visiting the site gives us valuable statistical information as well.

Thanks very much.

Need your help

about 1 year ago | Biju Bhaskar: Thoughts on enterprise application development...

As I mentioned earlier, I'm participating at Wharton this week in an intensive workshop on the development of web-based products and services. My classmates and I have developed some interesting new websites. We're very interested in having some potential users take a look at these sites and provide us with some reactions. Today is our friends and family sneak preview. Please take a look at http://www.wwwharton.com.

These are proof-of-concept prototypes intended to gauge your reactions. That information will be extremely helpful in deciding whether or not to pursue the opportunities and how to improve the approaches. While your actively providing feedback is certainly welcome, simply visiting the site gives us valuable statistical information as well.

Thanks very much.

When the weather outside is frightful...

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

Now that we're firmly entrenched in winter, it seems the right time for choucroute.

Lucy Vanel - she of the amazing, gorgeous, inspiring blog Lucy's Kitchen Notebook - agrees. Her latest post features a sublimely easy recipe for the Alsatian classic. If you'd like a bit more guidance, have a gander at these recipes.

Either way, go out, get some meat and sauerkraut, pick up a couple of bottles of Alsatian wine (I've had it from a reliable source that Gewurtztraminer is the best grape you can get), and settle in for a long winter's feast.

Mouthwatering photo courtesy of Lucy's Kitchen Notebook.

Lightweight Javascript Table Sorter using Prototype

about 1 year ago | Amit Kumar: RubyizednRailified

The Javascript tablesorter is built on top of Prototype library. The library gives the dynamic feature of row formatting, maintain the sort order of the table on dynamic addition/deletion of a row, default sort order when the page loads, keep one or more columns unsortable, make multiple tables sortable on the same page etc.


Usage:

* The table should have an id attribute
* It should have thead > tr > th as headers.
* It should have tbody > tr > td as body.
* thead > tr > th[class="integer"] will make the column int sort
* thead > tr > th[class="date"] will make the column date sort
* thead > tr > th[class="float"] will make the column float sort
* thead > tr > th[class=""] will make the column string sort
* thead > tr > th[class="nosort"] will make the column unsortable
* thead > tr > th[class="sort-asc"] will make the column default sort on page load
* sorterId = TableSortObserver.sortableTables[table_id];
sorterId.resort(sorterId.sortIndex, sorterId.sortOrder);
This will resort the table after dynamic addition/deletion of a row. It will retain the last sort column.

Initialize:

* TableSortObserver.bindEventsToTableRow(table_id)

The TableSortObserver retains all the sortable tables registered on the page. The sorter has been tesetd on IE 5/6, FF 2/3, Chrome, Safari.

Update: Source code on github

Flex + Rails = Flexible Rails -> Rich Internet Applications

about 1 year ago | Amit Kumar: RubyizednRailified

The wave started in 2007 when Simeon Bateman presented Building Rich Internet Applications with Flex and Ruby on Rails @ Rails Euro Conf. Both Rails and Flex are two great tools to quickly develop nice looking and compelling applications.

For those who don't know Rails -> Type Ruby on Rails on google and the result will overwhelm you :)

Quick introduction to Flex:

* Flex is cross platform development framework for creating RIAs, Desktop applications
* It is component based. Coding is done in MXML (Macromedia XML), ActionScript 3 (Object Oriented, Strongly type)
* Flex Builder and SDK are used for design and code view
* Flex 3 framework is Open Source
* Compiles in swf file which runs in Flash Player ref in HTML page
* Support RESTful API

A typical communication that happens between Rails and Flex component:



Worldwide ubiquity of Adobe Flash Player 9 Sept-08 -> 89.4%.

Recently published book by Peter Armstrong (Manning Publication co.), explains the seamless integration through RESTful APIs. Another one is talks about why Flex is better than using Javascript and CSS.

In our project we were looking for a component to bulk upload documents (always painful). Flex gave the power to bulk upload documents and integration with Rails was pretty straightforward. browse() and upload() method of FileReference class does the whole magic.

Wanna Test the Flex Component ?
For geeks who like to test every piece of code they write Flex 3 provides FlexUnit, a unit testing framework for Flex and ActionScript 3.0 which mimics JUnit and comes with graphical test runner.

The beautiful flex component:



Wanna try the power of Rails combined with the flexibility of Flex ??

Code to come shortly

Social Software in Government: Headed for Mainstream

about 1 year ago | Michael Idinopulos: Transparent Office

Since Alan Lepofsky and I spoke last month at Social Media for Government, I've been having a lot of conversations with beltway folks. There's a ton of interest in social media in government. It all started back in 2006 when...

Blog list for developers

about 1 year ago | Mark Mintz: Mark Mintz

For those looking for good blogs to keep you up to date on software development check out the Top 100 Blogs for Developers (Q4 2008). According to the author...

...the list is meant to cover software development in a broad sense, which includes project management, process improvement, agile development, requirements, design, coding and testing.
There's even an OPML version of the list to make subscribing to these blogs as easy as importing the list into your favorite RSS reader!!

SAP PMO Lead - My new role

about 1 year ago | Bhargav Gandhi: AGILE SOFTWARE DEVELOPMENT

Project Management Office(PMO) is a new experience for me. This is managerial role. It deals with the consolidated and corporate view of "SAP as a platform" across my organization.

My respsonsibilites are

  1. Managing corporate level SAP initiatives
  2. Help/guide different verticals with their SAP related needs
  3. Interact and co-ordinate with the SAP India/SAP AG.
There are some benefits associated with this role:
  1. I get to interact with lots of people across the organization. This results in the increased visibility
  2. Involvment in the pre-sales and proposals stage
  3. Management experience in the field of IT

Web Server’s virtual directory and network drive

about 1 year ago | Amar Phadke: Amar Phadke's weblog

I encountered a problem today trying to create an Apache Tomcat virtual directory that pointed to a mapped network drive. Found out that this was due to the fact that Tomcat was running as a Service with a local account. It was not able to see the network drive since that used to get mapped with [...]

Shake Shack, take two.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

On Tuesday, I got a treat. My friends Lori and Liam came to visit me in New York. They live out in Connecticut and only make it into Manhattan a couple of times a year, so to have a full day in the city with them was tons of fun. Of course, I had a challenge in front of me: how to feed them in an appropriately memorable manner, given they only visit me once in a while?

Well, since we'd decided to make a pilgrimage to the Museum of Natural History (I wanted Liam to see the blue whale, who has entranced me since I was his age, and Liam wanted to visit the Horse exhibit), I thought it was the perfect opportunity to make my first visit to the new Upper West Side outpost of Shake Shack.

I began visiting the original Shack way back when it was just an over-the-top hot dog cart in Madison Square Park, and have made regular visits to the permanent Shack since it opened in 2004. When word came out that a new Shake Shack was opening uptown, I figured it would be a fortress of screaming children and aggressive Upper West Side stroller moms. It is.

But it's also got the same delicious food and friendly service you'll find downtown. There's not enough seating to go around (we snagged a table for two for the three of us, and Lori ate standing up, good woman), but you almost don't care. The burgers are flavorful, the pickles are thick-cut and refreshing, and the buns are squishy and soft without being tasteless.

Golden fries and thick shakes (the chocolate is particularly good) round things out. All in all, we were three satisfied customers on our walk over to the museum.

And the whale is as cool as ever.

Happy New Year!

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

When I drink a great champagne, my soul is happy.
- Ferran Adria