<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -17,7 +17,7 @@ module SortableTable
             define_sort_order(acceptable_columns, mappings)
           end
           
-          def pop_hash_from_list(*args)
+          def pop_hash_from_list(args)
             if args.last.is_a?(Hash)
               args.pop
             else
@@ -27,7 +27,7 @@ module SortableTable
           
           def join_array_and_hash_values(array, hash)
             array.collect { |each| each.to_s } + 
-              hash.values.collect { |each| each.to_s }
+              hash.keys.collect { |each| each.to_s }
           end
           
           def define_sort_order(acceptable_columns, mappings)
@@ -89,7 +89,5 @@ module SortableTable
 
       end
     end
-  end  
+  end
 end
-
-</diff>
      <filename>lib/sortable_table/app/controllers/application_controller.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,28 @@
 module SortableTable
   module Shoulda
 
+    class Attribute
+      def initialize(attr)
+        @attr = attr
+      end
+
+      def complex?
+        @attr.is_a?(Hash)
+      end
+
+      def name
+        complex? ? @attr.keys.first : @attr
+      end
+
+      def values
+        @attr.values.flatten
+      end
+
+      def to_s
+        name.to_s
+      end
+    end
+
     def should_sort_by(attribute, options = {}, &amp;block)
       collection       = get_collection_name(options[:collection])
       model_under_test = get_model_under_test(attribute, options[:model_name])
@@ -8,6 +30,8 @@ module SortableTable
       block  = block || default_sorting_block(model_under_test, attribute)
       action = options[:action] || default_sorting_action
 
+      attribute = Attribute.new(attribute)
+
       %w(ascending descending).each do |direction|
         should &quot;sort by #{attribute.to_s} #{direction}&quot; do
           # sanity checks
@@ -15,10 +39,10 @@ module SortableTable
           assert_db_records_exist_for(model_under_test)
 
           # exercise
-          action.bind(self).call(attribute.to_s, direction)
+          action.bind(self).call(attribute.name.to_s, direction)
 
           # sanity check
-          assert_collection_can_be_tested_for_sorting(collection, attribute)
+          assert_collection_can_be_tested_for_sorting(collection, attribute, &amp;block)
 
           # verification
           assert_collection_is_sorted(collection, direction, &amp;block)
@@ -75,34 +99,14 @@ module SortableTable
     end
 
     def get_model_under_test(attribute, override)
-      if override
-        model_name = override
-      else
-        model_name = if attribute_includes_table?(attribute)
-          get_model_from_attribute(attribute)
-        else
-          get_model_under_test_from_test_name
-        end
-      end
-      model_name.singularize.camelize.constantize
+      model_name = override || get_model_under_test_from_test_name
+      model_name.classify.constantize
     end
     
     def get_model_under_test_from_test_name
       model_name_from_test_name = self.name.gsub(/ControllerTest/, '')
       remove_namespacing(model_name_from_test_name)
     end
-    
-    def attribute_includes_table?(attribute)
-      attribute.to_s.include?(&quot;.&quot;)
-    end
-    
-    def get_model_from_attribute(attribute)
-      if attribute.is_a?(Hash)
-        attribute.values.first.split(&quot;.&quot;).first
-      else
-        attribute.split(&quot;.&quot;).first
-      end
-    end
 
     def remove_namespacing(string)
       while string.include?('/')
@@ -145,15 +149,15 @@ module SortableTable
         &quot;need at least 2 #{model_under_test} records in the db to test sorting&quot;
     end
     
-    def assert_collection_can_be_tested_for_sorting(collection, attribute)
+    def assert_collection_can_be_tested_for_sorting(collection, attribute, &amp;block)
       assert_not_nil assigns(collection), 
         &quot;assigns(:#{collection}) is nil&quot;
       assert assigns(collection).size &gt;= 2, 
         &quot;cannot test sorting without at least 2 sortable objects. &quot; &lt;&lt;
         &quot;assigns(:#{collection}) is #{assigns(collection).inspect}&quot;
-      values = assigns(collection).collect(&amp;attribute).uniq
+      values = assigns(collection).collect(&amp;block).uniq
       assert values.size &gt;= 2,
-             &quot;need at least 2 distinct #{attribute} values to test sorting\n&quot; &lt;&lt;
+             &quot;need at least 2 distinct #{attribute.name} values to test sorting\n&quot; &lt;&lt;
              &quot;found values: #{values.inspect}&quot;
     end
     
@@ -167,10 +171,26 @@ module SortableTable
     end
 
     def assert_attribute_defined(attribute, model_under_test)
-      column = model_under_test.
+      if attribute.complex?
+        attribute.values.each do |attr|
+          if attr.include?('.')
+            model, attr = attr.split('.')
+            model = model.classify.constantize
+            assert_db_column_exists(attr, model)
+          else
+            assert_db_column_exists(attr, model_under_test)
+          end
+        end
+      else
+        assert_db_column_exists(attribute, model_under_test)
+      end
+    end
+
+    def assert_db_column_exists(attribute, model)
+      column = model.
         columns.
         detect {|column| column.name == attribute.to_s }
-      assert_not_nil column, &quot;No such column: #{model_under_test}##{attribute}&quot;
+      assert_not_nil column, &quot;No such column: #{model}##{attribute}&quot;
     end
   end
 end</diff>
      <filename>shoulda_macros/sortable_table.rb</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,7 @@ class Admin::UsersController &lt; ApplicationController
                       :age_and_name =&gt; [&quot;age&quot;, &quot;users.name&quot;]
 
   def index
-    @users = User.find :all, :order =&gt; sort_order
+    @users = User.find :all, :include =&gt; :group, :order =&gt; sort_order
   end
 
 end</diff>
      <filename>test/rails_root/app/controllers/admin/users_controller.rb</filename>
    </modified>
    <modified>
      <diff>@@ -4,13 +4,13 @@ class UsersController &lt; ApplicationController
                       :age_and_name =&gt; [&quot;age&quot;, &quot;users.name&quot;]
 
   def index
-    @users = User.find :all, :order =&gt; sort_order(&quot;ascending&quot;)
+    @users = User.find :all, :include =&gt; :group, :order =&gt; sort_order(&quot;ascending&quot;)
   end
-  
+
   def show
     @users = User.find :all, :order =&gt; sort_order
   end
-  
+
   def members
     @members = User.find :all, :order =&gt; sort_order
   end</diff>
      <filename>test/rails_root/app/controllers/users_controller.rb</filename>
    </modified>
    <modified>
      <diff>@@ -25,7 +25,8 @@ Rails::Initializer.run do |config|
   
   config.gem 'mocha',
              :version =&gt; '&gt;= 0.9.3'
-  config.gem 'quietbacktrace',
+  config.gem 'thoughtbot-quietbacktrace',
+             :lib =&gt; 'quietbacktrace',
              :version =&gt; '&gt;= 0.1.1'
   config.gem 'thoughtbot-factory_girl',
              :lib =&gt; 'factory_girl',</diff>
      <filename>test/rails_root/config/environment.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,3 +1,5 @@
+UNSORTED_NUMBERS = [1, 6, 2, 5, 4, 8, 10, 9, 3, 7]
+
 Factory.define :user do |user|
   user.email { Factory.next :email }
   user.name  { Factory.next :name }
@@ -6,17 +8,25 @@ Factory.define :user do |user|
 end
 
 Factory.define :group do |group|
-  group.name { Factory.next :name }
+  group.name { Factory.next(:unsorted_name) }
+end
+
+Factory.sequence :email do |n|
+  &quot;email#{n}@example.com&quot;
+end
+
+Factory.sequence :name do |n|
+  &quot;name#{n}&quot;
 end
 
-Factory.sequence :email do |each| 
-  &quot;email#{each}@example.com&quot;
+Factory.sequence :unsorted_number do |n|
+  UNSORTED_NUMBERS[n % UNSORTED_NUMBERS.size]
 end
 
-Factory.sequence :name do |each| 
-  &quot;name#{each}&quot;
+Factory.sequence :age do |n|
+  20 + Factory.next(:unsorted_number)
 end
 
-Factory.sequence :age do |each| 
-  each
+Factory.sequence :unsorted_name do |n|
+  &quot;name#{Factory.next(:unsorted_number)}#{n}&quot;
 end</diff>
      <filename>test/rails_root/test/factories/user_factory.rb</filename>
    </modified>
    <modified>
      <diff>@@ -9,8 +9,13 @@ class Admin::UsersControllerTest &lt; ActionController::TestCase
 
     should_sort_by_attributes :name, :email
 
-    # TODO: this was unimplemented
-    # should_sort_by_attributes :group =&gt; &quot;groups.name&quot;
+    should_sort_by :group =&gt; 'groups.name' do |user|
+      user.group.name
+    end
+
+    should_sort_by :age_and_name =&gt; [&quot;age&quot;, &quot;users.name&quot;] do |user|
+      &quot;#{user.age}#{user.name}&quot;
+    end
 
     context &quot;GET to #index&quot; do
       setup { get :index }
@@ -19,4 +24,3 @@ class Admin::UsersControllerTest &lt; ActionController::TestCase
   end
 
 end
-</diff>
      <filename>test/rails_root/test/functional/admin/users_controller_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -14,17 +14,19 @@ class UsersControllerTest &lt; ActionController::TestCase
 
     should_sort_by_attributes :name, :admin
 
-    # TODO: this was unimplemented
-    # should_sort_by_attributes :group =&gt; &quot;groups.name&quot;
+    should_sort_by :group =&gt; 'groups.name' do |user|
+      user.group.name
+    end
+
+    should_sort_by :age_and_name =&gt; [&quot;age&quot;, &quot;users.name&quot;] do |user|
+      &quot;#{user.age}#{user.name}&quot;
+    end
 
     # block form to test an action other than :index
-    should_sort_by_attributes :age do |sort, order|
+    should_sort_by_attributes :email do |sort, order|
       get :show, :sort =&gt; sort, :order =&gt; order
     end
 
-    # TODO:
-    # should_sort_by :age_and_name =&gt; [&quot;age&quot;, &quot;users.name&quot;]
-
     context &quot;with a non-standard collection name&quot; do
       action = lambda { |sort, order| get :members, :sort =&gt; sort, :order =&gt; order }
       should_sort_by :name, { :collection =&gt; &quot;members&quot;, 
@@ -78,4 +80,3 @@ class UsersControllerTest &lt; ActionController::TestCase
   end
 
 end
-</diff>
      <filename>test/rails_root/test/functional/users_controller_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>f919126f665528c38cc8c2a32dd1e6500f8054cf</id>
    </parent>
  </parents>
  <author>
    <name>Jason Morrison</name>
    <email>jasonmorrison@jason-morrisons-macbook.local</email>
  </author>
  <url>http://github.com/JackDanger/sortable_table/commit/67104346e9a6b90aa7395eed0339c45f9343cc16</url>
  <id>67104346e9a6b90aa7395eed0339c45f9343cc16</id>
  <committed-date>2009-02-27T13:06:51-08:00</committed-date>
  <authored-date>2009-02-27T13:06:51-08:00</authored-date>
  <message>Supporting complex attributes in sortable_attributes (merging patch from Eugene Bolshakov)</message>
  <tree>17fbc131225bf6796aaf286769fb031e28e7f364</tree>
  <committer>
    <name>Jason Morrison</name>
    <email>jasonmorrison@jason-morrisons-macbook.local</email>
  </committer>
</commit>
