Fix/add specs, remove duplicate base.rb for edge and 3.0

This commit is contained in:
Ernie Miller 2011-06-04 18:01:12 -04:00
parent 747b414110
commit cec4e3d64f
12 changed files with 198 additions and 50 deletions

View File

@ -1,18 +1,17 @@
require 'ransack/adapters/active_record/base'
ActiveRecord::Base.extend Ransack::Adapters::ActiveRecord::Base
case ActiveRecord::VERSION::STRING
when /^3\.0\./
require 'ransack/adapters/active_record/3.0/base'
require 'ransack/adapters/active_record/3.0/join_dependency'
require 'ransack/adapters/active_record/3.0/join_association'
require 'ransack/adapters/active_record/3.0/context'
ActiveRecord::Base.extend Ransack::Adapters::ActiveRecord::Base
ActiveRecord::Associations::ClassMethods::JoinDependency.send :include, Ransack::Adapters::ActiveRecord::JoinDependency
else
require 'ransack/adapters/active_record/base'
require 'ransack/adapters/active_record/join_dependency'
require 'ransack/adapters/active_record/join_association'
require 'ransack/adapters/active_record/context'
ActiveRecord::Base.extend Ransack::Adapters::ActiveRecord::Base
ActiveRecord::Associations::JoinDependency.send :include, Ransack::Adapters::ActiveRecord::JoinDependency
end

View File

@ -1,33 +0,0 @@
module Ransack
module Adapters
module ActiveRecord
module Base
def self.extended(base)
alias :search :ransack unless base.method_defined? :search
base.instance_eval do
class_attribute :_ransackers
self._ransackers ||= {}
end
end
def ransack(params = {}, options = {})
Search.new(self, params, options)
end
def ransacker(name, opts = {}, &block)
Ransacker.new(self, name, opts, &block)
end
def ransackable_attributes(auth_object)
column_names + _ransackers.keys
end
def ransackable_associations(auth_object)
reflect_on_all_associations.map {|a| a.name.to_s}
end
end
end
end
end

View File

@ -20,4 +20,147 @@ class ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinBase
:engine => active_record.arel_engine,
:columns => active_record.columns)
end
end
module Arel
class Table
alias :table_name :name
def [] name
::Arel::Attribute.new self, name.to_sym
end
end
module Nodes
class Node
def not
Nodes::Not.new self
end
end
remove_const :And
class And < Arel::Nodes::Node
attr_reader :children
def initialize children, right = nil
unless Array === children
children = [children, right]
end
@children = children
end
def left
children.first
end
def right
children[1]
end
end
class NamedFunction < Arel::Nodes::Function
attr_accessor :name, :distinct
include Arel::Predications
def initialize name, expr, aliaz = nil
super(expr, aliaz)
@name = name
@distinct = false
end
end
class InfixOperation < Binary
include Arel::Expressions
include Arel::Predications
attr_reader :operator
def initialize operator, left, right
super(left, right)
@operator = operator
end
end
class Multiplication < InfixOperation
def initialize left, right
super(:*, left, right)
end
end
class Division < InfixOperation
def initialize left, right
super(:/, left, right)
end
end
class Addition < InfixOperation
def initialize left, right
super(:+, left, right)
end
end
class Subtraction < InfixOperation
def initialize left, right
super(:-, left, right)
end
end
end
module Visitors
class ToSql
def column_for attr
name = attr.name.to_s
table = attr.relation.table_name
column_cache[table][name]
end
def column_cache
@column_cache ||= Hash.new do |hash, key|
hash[key] = Hash[
@engine.connection.columns(key, "#{key} Columns").map do |c|
[c.name, c]
end
]
end
end
def visit_Arel_Nodes_InfixOperation o
"#{visit o.left} #{o.operator} #{visit o.right}"
end
def visit_Arel_Nodes_NamedFunction o
"#{o.name}(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x|
visit x
}.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
end
def visit_Arel_Nodes_And o
o.children.map { |x| visit x }.join ' AND '
end
def visit_Arel_Nodes_Not o
"NOT (#{visit o.expr})"
end
def visit_Arel_Nodes_Values o
"VALUES (#{o.expressions.zip(o.columns).map { |value, attr|
if Nodes::SqlLiteral === value
visit_Arel_Nodes_SqlLiteral value
else
quote(value, attr && column_for(attr))
end
}.join ', '})"
end
end
end
module Predications
def as other
Nodes::As.new self, Nodes::SqlLiteral.new(other)
end
end
end

View File

@ -19,12 +19,11 @@ module Ransack
Ransacker.new(self, name, opts, &block)
end
# TODO: Let's actually do some authorization. Whitelist-only.
def ransackable_attributes(auth_object)
def ransackable_attributes(auth_object = nil)
column_names + _ransackers.keys
end
def ransackable_associations(auth_object)
def ransackable_associations(auth_object = nil)
reflect_on_all_associations.map {|a| a.name.to_s}
end

View File

@ -7,7 +7,7 @@ module Ransack
mattr_accessor :predicates
self.predicates = {}
def self.predicate_keys
def predicate_keys
predicates.keys.sort {|a,b| b.length <=> a.length}
end

View File

@ -28,7 +28,7 @@ module Ransack
def extract_attributes_and_predicate(key)
str = key.dup
name = Ransack::Configuration.predicate_keys.detect {|p| str.sub!(/_#{p}$/, '')}
name = Ransack.predicate_keys.detect {|p| str.sub!(/_#{p}$/, '')}
predicate = Predicate.named(name)
raise ArgumentError, "No valid predicate for #{key}" unless predicate
attributes = str.split(/_and_|_or_/)

View File

@ -198,7 +198,7 @@ module Ransack
def strip_predicate_and_index(str)
string = str.split(/\(/).first
Ransack::Configuration.predicate_keys.detect {|p| string.sub!(/_#{p}$/, '')}
Ransack.predicate_keys.detect {|p| string.sub!(/_#{p}$/, '')}
string
end

View File

@ -18,7 +18,7 @@ module Ransack
original_name = key.to_s
base_class = context.klass
base_ancestors = base_class.ancestors.select { |x| x.respond_to?(:model_name) }
predicate = Ransack::Configuration.predicate_keys.detect {|p| original_name.match(/_#{p}$/)}
predicate = Ransack.predicate_keys.detect {|p| original_name.match(/_#{p}$/)}
attributes_str = original_name.sub(/_#{predicate}$/, '')
attribute_names = attributes_str.split(/_and_|_or_/)
combinator = attributes_str.match(/_and_/) ? :and : :or

View File

@ -2,9 +2,9 @@ require 'spec_helper'
module Ransack
describe Configuration do
it 'yields self on configure' do
Ransack.configure do
self.should eq Ransack::Configuration
it 'yields Ransack on configure' do
Ransack.configure do |config|
config.should eq Ransack
end
end
end

View File

@ -32,9 +32,43 @@ module Ransack
it 'selects previously-entered time values with datetime_select' do
@s.created_at_eq = [2011, 1, 2, 3, 4, 5]
html = @f.datetime_select :created_at_eq
[2011, 1, 2, 3, 4, 5].each do |val|
html.should match /<option selected="selected" value="#{val}">#{val}<\/option>/o
html = @f.datetime_select :created_at_eq, :use_month_numbers => true, :include_seconds => true
%w(2011 1 2 03 04 05).each do |val|
html.should match /<option selected="selected" value="#{val}">#{val}<\/option>/
end
end
it 'localizes labels' do
html = @f.label :name_cont
html.should match /Full Name contains/
end
it 'localizes submit' do
html = @f.submit
html.should match /"Search"/
end
it 'returns ransackable attributes for attribute_select' do
html = @f.attribute_select
html.split(/\n/).should have(Person.ransackable_attributes.size + 1).lines
Person.ransackable_attributes.each do |attribute|
html.should match /<option value="#{attribute}">/
end
end
it 'returns ransackable attributes for associations in attribute_select with associations' do
attributes = Person.ransackable_attributes + Article.ransackable_attributes.map {|a| "articles_#{a}"}
html = @f.attribute_select :associations => ['articles']
html.split(/\n/).should have(attributes.size).lines
attributes.each do |attribute|
html.should match /<option value="#{attribute}">/
end
end
it 'returns option groups for base and associations in attribute_select with associations' do
html = @f.attribute_select :associations => ['articles']
[Person, Article].each do |model|
html.should match /<optgroup label="#{model}">/
end
end

View File

@ -4,6 +4,7 @@ require 'faker'
require 'ransack'
Time.zone = 'Eastern Time (US & Canada)'
I18n.load_path += Dir[File.join(File.dirname(__FILE__), 'support', '*.yml')]
Dir[File.expand_path('../{helpers,support,blueprints}/*.rb', __FILE__)].each do |f|
require f

5
spec/support/en.yml Normal file
View File

@ -0,0 +1,5 @@
en:
ransack:
attributes:
person:
name: Full Name