Saturday, March 24, 2007

Rails: ActiveRecord Unit Testing part II

Back in December I wrote about unit testing ActiveRecord models. Following that post, we started using that pattern to unit test our models. It quickly became obvious that the ActiveRecord::ConnectionAdapters::Column.new("digits", nil, "string", false) statements were largely static and we wrapped this behavior in a fluent interface.

This worked, but some developers on the team didn't like the (arguably) unnecessary additional syntax. These developers argued that since none of our Unit Tests hit the database we should simply override the new method and handle stubbing the columns method.

You can argue that adding magic to the new method could be confusing, but our team has the standard that no unit test can hit the database. Therefore, everyone is very aware that, despite the standard syntax, we are injecting our own column handling mechanism.

The code to make this work is fairly straightforward. The usual alias method gotchas apply so I chose to use an alternative. Adding the following code will allow you to create disconnected models in your unit tests simply by calling new.
class << ActiveRecord::Base

new_method = instance_method :initialize
define_method :initialize do |*attributes|
attributes = attributes.empty? ? nil : attributes.first
self.stubs(:columns).returns(no_db_columns(attributes))
new_method.bind(self).call attributes
end

def no_db_columns attributes
return [] if attributes.nil?
attributes.keys.collect do |attribute|
sql_type = case attributes[attribute].class
when " " then "integer"
when "Float" then "float"
when "Time" then "time"
when "Date" then "date"
when "String" then "string"
when "Object" then "boolean"
end
ActiveRecord::ConnectionAdapters::Column.new(attribute.to_s, nil, sql_type, false)
end
end

end

Friday, March 23, 2007

Ruby: === operator

Recently I was looking at creating a patch for Mocha that would allow you to specify a class as an argument. The feature was added to allow you to specify that an argument can be any instance of the class specified.
object.expects(:do_this).with(Fixnum, true, 99)
object.do_this(2, true, 99) # satisfies the expectation
To support this new feature I looked into the === method.

The === method of Object is defined as:
Case Equality—For class Object, effectively the same as calling #==, but typically overridden by descendents to provide meaningful semantics in case statements.
There's no mystery here, use === like ==. However, the === method of Module provides the behavior I'm looking for.
Case Equality—Returns true if anObject is an instance of mod or one of mod‘s descendents. Of limited use for modules, but can be used in case statements to classify objects by class.
The documentation can be tested easily to ensure the behavior I'm looking for.
Fixnum === 2 #=> true
An important thing to note is that 2 and Fixnum are not commutative.
2 === Fixnum #=> false
So, using the === method I was able create the following patch that provides the behavior I was looking for.
Index: trunk/test/unit/expectation_test.rb
===================================================================
--- trunk/test/unit/expectation_test.rb (revision 109)
+++ trunk/test/unit/expectation_test.rb (working copy)
@@ -30,6 +30,16 @@
assert expectation.match?(:expected_method, 1, 2, 3)
end

+ def test_should_match_calls_to_same_method_with_expected_parameter_values_or_class
+ expectation = new_expectation.with(1, Fixnum, Object)
+ assert expectation.match?(:expected_method, 1, 2, 3)
+ end
+
+ def test_should_match_calls_to_same_method_with_expected_parameter_values_or_class
+ expectation = new_expectation.with(1, Fixnum, Object)
+ assert expectation.match?(:expected_method, 1, Fixnum, 3)
+ end
+
def test_should_match_calls_to_same_method_with_parameters_constrained_as_expected
expectation = new_expectation.with() {|x, y, z| x + y == z}
assert expectation.match?(:expected_method, 1, 2, 3)
Index: trunk/lib/mocha/expectation.rb
===================================================================
--- trunk/lib/mocha/expectation.rb (revision 109)
+++ trunk/lib/mocha/expectation.rb (working copy)
@@ -22,9 +22,6 @@
class InvalidExpectation < Exception; end

class AlwaysEqual
- def ==(other)
- true
- end
end

attr_reader :method_name, :backtrace
@@ -43,7 +40,15 @@
end
def match?(method_name, *arguments)
- (@method_name == method_name) and (@parameter_block ? @parameter_block.call(*arguments) : (@parameters == arguments))
+ return false unless @method_name == method_name
+ return @parameter_block.call(*arguments) unless @parameter_block.nil?
+ return true if @parameters.is_a? AlwaysEqual
+ return false unless @parameters.size == arguments.size
+ @parameters.inject([0, true]) do |result, arg|
+ result[1] &&= (arguments[result.first].is_a?(Module) ? arg == arguments[result.first] : arg === arguments[result.first])
+ result[0] += 1
+ result
+ end.last
end
# :startdoc:

Should Rails include Mocha?

I like the way the Rails integration tests currently depend on Mocha.
# integration_test.rb
...
begin # rescue LoadError
require 'mocha'
...
rescue LoadError
$stderr.puts "Skipping integration tests. `gem install mocha` and try again."
end
In fact, I stole the idea and changed it up a bit for sqldsl.
unless File.directory? File.dirname(__FILE__) + '/../vendor/mocha-0.4.0/'
raise "mocha 4.0 is required to run the test suite. create the 'vendor' directory as
a sibling of test and 'gem unpack mocha' in 'vendor'"
end
$:.unshift File.dirname(__FILE__) + '/../vendor/mocha-0.4.0/lib/'
require File.dirname(__FILE__) + '/../vendor/mocha-0.4.0/lib/mocha'
However, now I'm wondering if Rails should depend on, and include Mocha.

I've previously written that I think xUnit frameworks should include Mocks. Since Rails bakes in testing, I believe it should provide you with the full array of testing tools, including Mocks.

Thoughts?

Thursday, March 22, 2007

Rails: ActiveRecord Serialize method

On my current project we have a model with a few attributes that are instances. Generally, this is handled with a relationship (e.g. belongs_to). However, these attributes are not ActiveRecord::Base subclass instances. ActiveRecord handles this situation by providing the ActiveRecord::Base.serialize class method.

As a contrived example, imagine a UserAccount class that has a AuthorizationConfirmation instance as an attribute.
class CreateModels < ActiveRecord::Migration
def self.up
create_table :user_accounts do |t|
t.column :authorization_confirmation, :string
end
end

def self.down
drop_table :user_accounts
end
end

class UserAccount < ActiveRecord::Base
serialize :authorization_confirmation, AuthorizationConfirmation
end

class AuthorizationConfirmation
attr_accessor :fingerprint, :key
end
As you can see in the above example, the UserAccount class has the attribute authorization_confirmation. The value stored in authorization_confirmation is expected to be an instance of the AuthorizationConfirmation class.

A simple test proves the expected behavior.
require File.expand_path(File.dirname(__FILE__) + "/../test_helper")

class UserAccountTest < Test::Unit::TestCase
def test_authorization_confirmation_is_serialized_and_deserialized
account = UserAccount.new
account.authorization_confirmation = AuthorizationConfirmation.new
account.authorization_confirmation.fingerprint = "Xc1sseE"
account.authorization_confirmation.key = "gEteEQ"
account.save
retrieved = UserAccount.find account.id
assert_equal "Xc1sseE", retrieved.authorization_confirmation.fingerprint
assert_equal "gEteEQ", retrieved.authorization_confirmation.key
end
end
The test proves that the instance of AuthorizationConfirmation is saved and retrieved as expected.

A quick peek in the database shows the instance as yaml.
 id | authorization_confirmation                           
----+------+-------------------------------------------------------------------------------
6 | --- !ruby/object:AuthorizationConfirmation
fingerprint: Xc1sseE
key: gEteEQ
NOTE: At the time of this writing any attribute that is serialized cannot be nil. Ticket 7293 should resolve this problem.

Saturday, March 17, 2007

Ruby: sqldsl 1.4.0 released

This morning I released the 1.4.0 version of sqldsl. This release is mostly in response to the suggestions that sqldsl has recently gotten from the Ruby Community. The new version can be retrieved via "gem install sqldsl" as soon as the file propagates. For now, it can be downloaded from the download page.

Breaking Changes:
Table and column aliasing is now done with an 'as' method instead of using hashes. This change was necessary since column order is important and hashes are unordered.
irb> Select[:column1.as(:book), 1.as(:total), 'foo'.as(:constant)].to_sql
=> "select column1 as book, 1 as total, 'foo' as constant"

irb> Select.all.from[:table1.as(:aliased_table_name)].to_sql
=> "select * from table1 aliased_table_name"
Equality in the where clause has been changed from a single equals to double equals. I personally preferred the single equals; however, it broke in scenarios where columns were not prefixed by table names. The previous solution did not work because ruby assigned a local variable instead of raising a method_missing and allowing the ReceiveAny class to handle the assignment.

The new syntax is the same, except it uses == instead of =.
Select[:column1].from[:table1].where do
column1 == 99
end.to_sql
=> "select column1 from table1 where column1 = 99"
New Feature:
Inner Joins are now also supported
Select.all.from[:t1.as(:a)].inner_join[:t2.as(:b)].on do
a.id == b.id
end.inner_join[:t3.as(:c)].on do
b.id2 == c.id
end.to_sql
=> "select * from t1 a inner join t2 b on a.id = b.id inner join t3 c on b.id2 = c.id"
Bug Fix:
Or conditions are surrounded by parenthesis.
Select[:column1].from[:table1].where do
column1.equal 0
end.or do
column1 > 100
end.to_sql
=> "select column1 from table1 where column1 = 0 or (column1 > 100)"

Friday, March 16, 2007

Rails: Presenter Pattern

The default architecture for Ruby on Rails, Model View Controller, can begin to break down as Controllers become bloated and logic begins to creep into view templates. The Presenter pattern addresses this problem by adding another layer of abstraction: a class representation of the state of the view.

Presenter was inspired by the various GUI patterns documented by Martin Fowler.

How It Works
The Presenter pattern addresses bloated controllers and views containing logic in concert by creating a class representation of the state of the view. An architecture that uses the Presenter pattern provides view specific data as attributes of an instance of the Presenter. The Presenter's state is an aggregation of model and user entered data.

When To Use It
As non-trivial applications grow Controllers can approach sizes that compromise maintainability. Complex controller actions may require instantiation of multiple objects and take on the responsibility of aggregating data from various objects. A Presenter can encapsulate this aggregation behavior and leave the controller with more focused responsibilities. This also allows for testing of aggregation or calculation behavior without a dependency on setting up a Controller to a testable state.

Since views are templates they can also contain behavior. The most common behavior you encounter in a view is formatting; however, since the view is a template you will occasionally see computations or worse. Because this logic is stored in a template it can be problematic to test. Presenters address this problem by pulling all formatting, computation, and any additional behavior into a class that can be easily tested.

Presenters do add an additional layer, and thus more complexity. A presenter is not likely to be a automatic decision or standard. Presenters are generally introduced when actions are required to act upon various models or the data in the database needs to be manipulated in various ways before it is displayed in the view.

Example
The example used to demonstrate a usage of the Presenter pattern is a page that allows you to enter your address information, personal information, and user credentials.



To get to our example page (and the following page) we'll need to add a few routes to routes.rb.
ActionController::Routing::Routes.draw do |map|
map.with_options :controller => 'order' do |route|
route.complete "complete", :action => "complete"
route.thank_you "thank_you", :action => "thank_you"
end
...
end
The example relies on three different models: address, user_account, user_credential. The migration for creating these tables is straightforward.
class CreateModels < ActiveRecord::Migration
def self.up
create_table :user_accounts do |t|
t.column :name, :string
end
create_table :addresses do |t|
t.column :line_1, :string
t.column :line_2, :string
t.column :city, :string
t.column :state, :string
t.column :zip_code, :string
end
create_table :user_credentials do |t|
t.column :username, :string
t.column :password, :string
end
end

def self.down
drop_table :user_accounts
drop_table :addresses
drop_table :user_credentials
end
end
The models need not contain any behavior for our example.
class Address < ActiveRecord::Base
end

class UserAccount < ActiveRecord::Base
end

class UserCredential < ActiveRecord::Base
end
The template for our example view is also straightforward, and this is one of the large benefits for using a presenter.
<% form_for :presenter do |form| %>
<table>
<tr><td colspan="2">Billing Information:</td></tr>
<tr>
<td>Name</td>
<td><%= form.text_field :name %></td>
</tr>
<tr>
<td>Address Line 1</td>
<td><%= form.text_field :line_1 %></td>
</tr>
<tr>
<td>Address Line 2</td>
<td><%= form.text_field :line_2 %></td>
</tr>
<tr>
<td>City</td>
<td><%= form.text_field :city %></td>
</tr>
<tr>
<td>State</td>
<td><%= form.text_field :state %></td>
</tr>
<tr>
<td>Zip Code</td>
<td><%= form.text_field :zip_code %></td>
</tr>
<tr><td colspan="2">Account Information:</td></tr>
<tr>
<td>Username</td>
<td><%= form.text_field :username %></td>
</tr>
<tr>
<td>Password</td>
<td><%= form.text_field :password %></td>
</tr>
</table>
<%= submit_tag "Complete Order" %>
<% end %>
And, the last example before we dive into the Presenter will be the controller. The controller is also simple, thus maintainable, due to the usage of the Presenter.
class OrderController < ApplicationController
def complete
@presenter = CompletePresenter.new(params[:presenter])
redirect_to thank_you_url if request.post? && @presenter.save
end

def thank_you
end
end
Finally, the CompletePresenter aggregates all the data for the view.
class CompletePresenter < Presenter
def_delegators :user_account, :name, :name=
def_delegators :address, :line_1, :line_2, :city, :state, :zip_code
:line_1=, :line_2=, :city=, :state=, :zip_code=
def_delegators :user_credentials, :username, :password, :username=, :password=

def user_account
@user_account ||= UserAccount.new
end

def address
@address ||= Address.new
end

def user_credentials
@credentials ||= UserCredential.new
end

def save
user_account.save && address.save && user_credentials.save
end
end
The CompletePresenter does inherit from Presenter, but only to get Forwardable behavior and a constructor that allows you to create an instance with attributes set from a hash.
class Presenter
extend Forwardable

def initialize(params)
params.each_pair do |attribute, value|
self.send :"#{attribute}=", value
end unless params.nil?
end
end
By using the presenter an easily testable layer has been created. This additional layer can coordinate with the models that this view is responsible for. The added layer also allows the models to be tested independent of any controller behavior. The presenter also provides the ability for extension where other solutions prove inadequate. For example, in a real scenario, the models would also likely contain validations. The presenter provides a layer that can validate the various models and merge their errors collections to provide one error collection that the view can work with.

Used appropriately, Presenters greatly benefit an application's architecture and maintainability

Monday, March 12, 2007

Ruby: LocalJumpError workaround

I was recently working on some code very similar to the following distilled example.
class Foo

attr_accessor :some_val

def self.method_with_additional_behavior(method_name, &block)
define_method method_name do
# do some stuff before calling block
instance_eval &block
# do some stuff after calling block
end
end

method_with_additional_behavior :foo do
return 0 if self.some_val.nil?
some_val * 2
end
end

Foo.new.foo
Executing the above code gives the following error.
LocalJumpError: unexpected return
The error occurs because the return statement attempts to return from the method_with_additional_behavior. There are a few ways to solve this, but I also had some constraints that influenced my decision.

In my codebase the method_with_additional_behavior is defined in a superclass, and the subclasses use this method to create methods with additional behavior. I (believe I) could have forced them to use lambda and gotten around the problem, but that wouldn't be very friendly. I could also define another method, such as "__#{method_name}__", and call the underscored method from the desired method, but that would have left my classes with an additional method that should never be called in isolation.

I solved the problem by defining a method, storing that method in a local variable and then overriding the newly defined method with my additional behavior and a call to the method stored in the local variable.
class Foo

attr_accessor :some_val

def self.method_with_additional_behavior(method_name, &block)
define_method method_name, &block
new_method = instance_method(method_name)
define_method method_name do
# do some stuff before calling block
new_method.bind(self).call
# do some stuff after calling block
end
end

method_with_additional_behavior :foo do
return 0 if self.some_val.nil?
some_val * 2
end
end

Foo.new.foo #=> 0

Friday, March 09, 2007

Ruby: Why sqldsl?

I recently wrote about introducing sqldsl into my current project. This led to a few conversations on what are the pros and cons of using sqldsl.

Cons:
  • Additional characters required in simple statements.
    "select column1 from table1 
    where name = '#{person_name}'"

    # becomes

    Select[:column1].from[:table1].where do
    name = person_name
    end
  • Another library creates a larger barrier to entry when dealing with a foreign code base.
Pros:
  • Objects know how to quote themselves.
    1.to_sql                     #=> "1"
    "foo".to_sql #=> "'foo'"
    :column.to_sql #=> "column"
    [1, 'foo', :column].to_sql #=> "1, 'foo', column"
  • Syntax Highlighting
  • Better than string concatenation to generate SQL statements.
    "escaped_values = hash.values.collect { |value| sql_escape value }
    insert into #{hash.keys.join(", ")} values #{escaped_values.join(", ")}"

    # becomes

    Insert.into[hash.keys.to_sql].values[hash.values.to_sql]
  • Much better support for conditional statement building.
    "select column1 from table1, table2
    where table1.column1 = table2.table1_id
    #{"and table1.column2 >= #{quantity}" if quantity > 0}"

    # becomes

    Select[:column1].from[:table1, :table2].where do
    table1.column1 = table2.table1_id
    table1.column2 >= quantity if quantity > 0
    end
  • Fail without requiring a database trip for referencing tables in the where statement that do not appear in the table list.
    Select[:column1].from[table1].where do
    table1.column1 = table2.column1
    end #=> Raises an error stating that table2 does not exist in the from clause.
  • Open for extension where necessary. For example, ActiveRecord::Base.execute could be changed to take a block.
    class ActiveRecord::Base
    alias original_execute execute
    def execute(arg, &block)
    original_execute block.call.to_sql(connection)
    end
    end
    If this change were made, the sqldsl library could use the connection to create vendor specific sql. This allows for things like changing sql to be prepared statement compatible when the oracle adapter supports this in the future. The point is, as long as your sql is nothing more than a string it is not able to be easily modified. However, an object representation of your sql could be evaluated in various contexts to produce different results.

Ruby: instance_eval and class_eval method definitions

In yesterday's entry on Cleaning up Controller Tests you can find the following code.
# example 1
...
test_class.class_eval do
define_method :setup do
...
end
end
test_class.class_eval &block
...
An earlier version of this code only used one call to the class_eval method.
# example 2
...
test_class.class_eval do
define_method :setup do
...
end
instance_eval &block
end
...
Example 2 works when your controller tests contain only test methods.
# example 3
controller_tests do
test "should add the params" do
assert_equal 4, Math.add(2,2)
end

test "should multiply the params" do
assert_equal 9, Math.multiply(3,3)
end
end
However, Example 2 stops working if your test class contains any helper methods.
# example 4
controller_tests do
test "should not save if first name is nil" do
person = valid_person
person.first_name = nil
assert_equal false, person.save
end

def valid_person
Person.new(...)
end
end
So, what's the difference between example 1 and example 2? The context in which the block is evaluated.

The above examples are from actual code, but the essence of the issue can be captured in a much simpler example.
# example 5
Foo = Class.new
Foo.class_eval do
def bar
"bar"
end
end
Foo.instance_eval do
def baz
"baz"
end
end
Foo.bar #=> undefined method ‘bar’ for Foo:Class
Foo.new.bar #=> "bar"
Foo.baz #=> "baz"
Foo.new.baz #=> undefined method ‘baz’ for #<Foo:0x7dce8>
As you can see in example 5, using def in an instance_eval is different from using def in a class_eval method call.

Example 5 shows that using def in a class_eval defines an instance method on the receiver (Foo in our example). However, using def in an instance_eval defines an instance method on the singleton class of the receiver (the singleton class of Foo in our example).

This explains why example 3 does not work: the valid_person method was being defined on the singleton class of the controller test class and not as an instance method of the controller test class.

As I previously stated, using def in an instance_eval defines an instance method on the singleton class of the receiver. This also explains how using def in an instance_eval when the receiver is an instance of a class defines a method on that instance.
# example 6
Foo = Class.new
foo = Foo.new
foo.instance_eval do
def instance_bar
"instance_bar"
end
end
foo.instance_bar #=> "instance_bar"
I've already explained where methods are stored in the various examples; however, the following example serves to prove my assertion.
# example 7
class Object
def singleton_class
class << self; self; end
end
end

Foo = Class.new
Foo.class_eval do
def instance_method_of_Foo; end
end
Foo.instance_eval do
def instance_method_of_Foos_singleton_class; end
end

Foo.instance_methods(false).inspect
#=> ["instance_method_of_Foo"]
Foo.singleton_class.instance_methods(false).inspect
#=> ["instance_method_of_Foos_singleton_class", "new", "superclass", "allocate"]

foo = Foo.new
foo.instance_eval do
def instance_method_of_foos_singleton_class; end
end

foo.singleton_class.instance_methods(false).inspect
#=> ["instance_method_of_Foo", "instance_method_of_foos_singleton_class"]
How does define_method fit into this picture?
# example 8
Foo = Class.new
Foo.class_eval do
define_method :instance_method_of_Foo do end
end
Foo.instance_eval do
define_method :another_instance_method_of_Foo do end
end

Foo.instance_methods(false).inspect
#=> ["another_instance_method_of_Foo", "instance_method_of_Foo"]
As you can see from example 8 define_method always defines an instance method on the target (Foo in our example). This makes sense because define_method is being call on the implicit self, which evaluates to the receiver (Foo) in our example.
# example 9
Foo.class_eval do
self #=> Foo
end

Foo.instance_eval do
self #=> Foo
end
By combining examples 5 and 8 I can create the following code that should no longer be surprising.
class Object
def singleton_class
class << self; self; end
end
end

Foo = Class.new
Foo.instance_eval do
def an_instance_method_of_the_singleton_class
end

define_method :an_instance_method do
end
end

Foo.instance_methods(false).inspect
#=> ["an_instance_method"]
Foo.singleton_class.instance_methods(false).inspect
#=> ["an_instance_method_of_the_singleton_class", "new", "superclass", "allocate"]
Thanks to Ali Aghareza, Pat Farley, and Zak Tamsen for collaborating with me on this.

Conferences: Presenting at GoRuCo

I'm happy to announce that I will be presenting at Gotham Ruby Conference 2007. The conference is already sold out, but you still have time to add your name to the waiting list.

The topic I will be covering is Business Natural Language Ruby Systems.
A Business Natural Language is a Domain Specific Language where subject matter experts use natural language to represent business logic....

Blog: New Url

My blog has moved to a new location.

For Viewing: http://blog.jayfields.com
RSS: http://blog.jayfields.com/rss.xml
Atom: http://blog.jayfields.com/atom.xml

Please update your links or subscriptions.

Thursday, March 08, 2007

Rails: Clean up Controller Tests

Traditional Rails Controller tests begin with code very similar to the following code.
require File.dirname(__FILE__) + '/../test_helper'

# Re-raise errors caught by the controller.
class SomeController; def rescue_action(e) raise e end; end

class SomeControllerTest < Test::Unit::TestCase

def setup
@controller = SomeController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
If you use generators you may not notice or care about all this boiler plate code; however, if you generally create your files from scratch you may be interested in the following method that I add to Object (in my test_helper.rb).
class Object
def controller_tests(&block)
full_path_file_name = eval "__FILE__", block.binding
test_name = File.basename(full_path_file_name, ".rb")
controller_name = test_name.chomp("_test")
require controller_name

controller = controller_name.camelize.constantize
controller.class_eval do
def rescue_action(e)
raise e
end
end

test_class = eval "module Functionals; class #{test_name.camelize} < Test::Unit::TestCase; self; end; end"
test_class.class_eval do
define_method :setup do
@controller = controller.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
end
test_class.class_eval &block
end
end
The above code does basically the same thing, but it allows me to define my controller tests in a much cleaner way.
require File.dirname(__FILE__) + '/../test_helper'

controller_tests do
test "should display order number index" do
get :index
...
end

test "should create new order on new" do
get :new
...
end
end
This change also provides the benefit of automatic test class renames when the test file name changes.

Friday, March 02, 2007

Ruby: sqldsl new version

I recently put sqldsl to work on my current project. Part of putting it into our codebase was extending it to support some additional syntax. The new syntax support was extracted and put into the 1.2.2 release of sqldsl.

The 1.2.2 release adds a few minor features and a significant change.

Significant:
The where block now allows you to specify conditions using traditional ruby syntax.
Select[:column1].from[:table1, :table2].where do
table1.column1 >= 1
table1.column2 <= 20
table1.column3 = table2.column1
table1.column4 = 'foo'
end
This change creates very nice looking code in the where block, but I'm not entirely sure it's a step in the right direction. While it looks great in the above example it also allows you to use variables, which can be confusing.
some_val = 1
Select[:column1].from[:table1].where do
column1 = some_val
end.to_sql #=> "select column1 from table1 where column1 = 1
In the above example column1 and some_val look very similar, but create very different output in the generated sql string. The alternative is to use the existing equal syntax.
Select[:column1].from[:table1].where do
equal :column1, some_val
end
In the previous example it is very clear that column1 is a column and some_val is a variable. The problem with this solution is that it begins to fall down when you consider <=, >=, etc. To support conditions with these operators we would have needed to implement the following (arguably ugly) syntax.
Select[:column1].from[:table1].where do
less_than_equal :column1, some_val
end
When faced with this decision we opted for the example that simply allowed ruby syntax.

Minor:
The not_null method was added to the options available in where conditions.
Select[:column1].from[:table1].where do
not_null :column2
end.to_sql #=> "select column1 from table1 where column2 is not null"
The is_not_in method was added to String, Numeric, and Symbol.
Select[:column1].from[:table1].where do
:column1.is_not_in do
Select[:column1].from[:table2]
end
end.to_sql #=> "select column1 from table1 where column1 not in (select column1 from table2)"
Table and column aliasing was also added in this release.
Select[:column1 => :total].from[:table1 => :results].to_sql #=> "select column1 as total from table1 as results"
sqldsl 1.2.2 is available via a gem install.
> gem install sqldsl