module Shoulda # :nodoc:
  module Matchers
    module ActiveRecord # :nodoc:
      module AssociationMatchers
        class ModelReflector
          delegate :associated_class, :through?, :join_table,
            :association_relation, to: :reflection

          def initialize(subject, name)
            @subject = subject
            @name = name
          end

          def reflection
            @reflection ||= reflect_on_association(name)
          end

          def reflect_on_association(name)
            reflection = model_class.reflect_on_association(name)

            if reflection
              ModelReflection.new(reflection)
            end
          end

          def model_class
            subject.class
          end

          def build_relation_with_clause(name, value)
            case name
              when :conditions then associated_class.where(value)
              when :order      then associated_class.order(value)
              else                  raise ArgumentError, "Unknown clause '#{name}'"
            end
          end

          def extract_relation_clause_from(relation, name)
            case name
              when :conditions then relation.where_values_hash
              when :order      then relation.order_values.join(', ')
              else                  raise ArgumentError, "Unknown clause '#{name}'"
            end
          end

          private

          attr_reader :subject, :name
        end
      end
    end
  end
end

module Shoulda # :nodoc:
  module Matchers
    module ActiveRecord # :nodoc:
      module AssociationMatchers
        class ModelReflector
          delegate :associated_class, :through?, :join_table,
            :association_relation, to: :reflection

          def initialize(subject, name)
            @subject = subject
            @name = name
          end

          def reflection
            @reflection ||= reflect_on_association(name)
          end

          def reflect_on_association(name)
            reflection = model_class.reflect_on_association(name)

            if reflection
              ModelReflection.new(reflection)
            end
          end

          def model_class
            subject.class
          end

          def build_relation_with_clause(name, value)
            case name
              when :conditions then associated_class.where(value)
              when :order      then associated_class.order(value)
              else                  raise ArgumentError, "Unknown clause '#{name}'"
            end
          end

          def extract_relation_clause_from(relation, name)
            case name
            when :conditions
              relation.where_values_hash
            when :order
              relation.order_values.map { |value| value_as_sql(value) }.join(', ')
            else
              raise ArgumentError, "Unknown clause '#{name}'"
            end
          end

          private

          attr_reader :subject, :name

          def value_as_sql(value)
            if value.respond_to?(:to_sql)
              value.to_sql
            else
              value
            end
          end
        end
      end
    end
  end
end

Make `order` option Rails 4.0.1-compatible
Make `order` option Rails 4.0.1-compatible

The way that we figure out whether the value which is passed to `order`
is the same as the `order` that the association was defined with is by
creating an ActiveRecord::Relation object from the given `order` and
comparing it with the Relation stored under the association.
Specifically, every time you call `order` on a Relation, it appends the
value you've given to an internal `order_values` array, so we actually
access this array and compare the two between the two Relation objects.

Currently we assume that this `order_values` array is an array of
strings, so it's very easy to compare. That was valid pre-Rails 4.0.1,
but it looks like as per [these][1] [commits][2], it's now possible for
`order_values` to be an array of Arel nodes. So, to make a proper
comparison, we have to convert any Arel nodes to strings by calling
 #to_sql on them.

[1]: https://github.com/rails/rails/commit/d345ed4
[2]: https://github.com/rails/rails/commit/f83c9b10b4c92b0d8deacb30d6fdfa2b1252d6dd
