ransack 0.5.3 → 0.5.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +7 -0
- data/Gemfile +31 -6
- data/lib/ransack/context.rb +1 -5
- data/lib/ransack/nodes/condition.rb +6 -5
- data/lib/ransack/nodes/value.rb +5 -3
- data/lib/ransack/predicate.rb +3 -2
- data/lib/ransack/version.rb +1 -1
- data/spec/ransack/adapters/active_record/base_spec.rb +32 -13
- data/spec/ransack/adapters/active_record/context_spec.rb +20 -4
- data/spec/ransack/configuration_spec.rb +20 -0
- data/spec/ransack/predicate_spec.rb +31 -1
- data/spec/ransack/search_spec.rb +11 -8
- data/spec/spec_helper.rb +13 -0
- data/spec/support/schema.rb +1 -0
- metadata +20 -17
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -1,14 +1,39 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
gemspec
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
gem 'rake'
|
5
|
+
|
6
|
+
rails = ENV['RAILS'] || 'master'
|
7
|
+
arel = ENV['AREL'] || 'master'
|
8
|
+
|
9
|
+
arel_opts = case arel
|
10
|
+
when /\// # A path
|
11
|
+
{:path => arel}
|
12
|
+
when /^v/ # A tagged version
|
13
|
+
{:git => 'git://github.com/rails/arel.git', :tag => arel}
|
14
|
+
else
|
15
|
+
{:git => 'git://github.com/rails/arel.git', :branch => arel}
|
16
|
+
end
|
17
|
+
|
18
|
+
gem 'arel', arel_opts
|
19
|
+
|
20
|
+
case rails
|
21
|
+
when /\// # A path
|
22
|
+
gem 'activesupport', :path => "#{rails}/activesupport"
|
23
|
+
gem 'activemodel', :path => "#{rails}/activemodel"
|
24
|
+
gem 'activerecord', :path => "#{rails}/activerecord"
|
25
|
+
gem 'actionpack', :path => "#{rails}/activerecord"
|
26
|
+
when /^v/ # A tagged version
|
27
|
+
git 'git://github.com/rails/rails.git', :tag => rails do
|
28
|
+
gem 'activesupport'
|
29
|
+
gem 'activemodel'
|
30
|
+
gem 'activerecord'
|
31
|
+
gem 'actionpack'
|
32
|
+
end
|
8
33
|
else
|
9
|
-
|
10
|
-
git 'git://github.com/rails/rails.git' do
|
34
|
+
git 'git://github.com/rails/rails.git', :branch => rails do
|
11
35
|
gem 'activesupport'
|
36
|
+
gem 'activemodel'
|
12
37
|
gem 'activerecord'
|
13
38
|
gem 'actionpack'
|
14
39
|
end
|
data/lib/ransack/context.rb
CHANGED
@@ -25,10 +25,6 @@ module Ransack
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
def can_accept?(object)
|
29
|
-
method_defined? DISPATCH[object.class]
|
30
|
-
end
|
31
|
-
|
32
28
|
end
|
33
29
|
|
34
30
|
def initialize(object)
|
@@ -99,7 +95,7 @@ module Ransack
|
|
99
95
|
end
|
100
96
|
|
101
97
|
def unpolymorphize_association(str)
|
102
|
-
if (match = str.match(/_of_(.+?)_type$/))
|
98
|
+
if (match = str.match(/_of_(.+?)_type$/))
|
103
99
|
[match.pre_match, Kernel.const_get(match.captures.first)]
|
104
100
|
else
|
105
101
|
[str, nil]
|
@@ -16,7 +16,7 @@ module Ransack
|
|
16
16
|
:a => attributes,
|
17
17
|
:p => predicate.name,
|
18
18
|
:m => combinator,
|
19
|
-
:v => [values]
|
19
|
+
:v => %w(in not_in).include?(predicate.arel_predicate) ? Array(values) : [values]
|
20
20
|
)
|
21
21
|
# TODO: Figure out what to do with multiple types of attributes, if anything.
|
22
22
|
# Tempted to go with "garbage in, garbage out" on this one
|
@@ -41,7 +41,7 @@ module Ransack
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def valid_arity?
|
44
|
-
values.size <= 1 || predicate.
|
44
|
+
values.size <= 1 || predicate.wants_array
|
45
45
|
end
|
46
46
|
|
47
47
|
def attributes
|
@@ -113,7 +113,7 @@ module Ransack
|
|
113
113
|
end
|
114
114
|
|
115
115
|
def value
|
116
|
-
predicate.
|
116
|
+
predicate.wants_array ? values.map {|v| v.cast(default_type)} : values.first.cast(default_type)
|
117
117
|
end
|
118
118
|
|
119
119
|
def build(params)
|
@@ -180,7 +180,7 @@ module Ransack
|
|
180
180
|
end
|
181
181
|
|
182
182
|
def validated_values
|
183
|
-
values.select {|v| predicate.validator
|
183
|
+
values.select {|v| predicate.validator.call(v.value)}
|
184
184
|
end
|
185
185
|
|
186
186
|
def casted_values_for_attribute(attr)
|
@@ -188,11 +188,12 @@ module Ransack
|
|
188
188
|
end
|
189
189
|
|
190
190
|
def formatted_values_for_attribute(attr)
|
191
|
-
casted_values_for_attribute(attr).map do |val|
|
191
|
+
formatted = casted_values_for_attribute(attr).map do |val|
|
192
192
|
val = attr.ransacker.formatter.call(val) if attr.ransacker && attr.ransacker.formatter
|
193
193
|
val = predicate.format(val)
|
194
194
|
val
|
195
195
|
end
|
196
|
+
predicate.wants_array ? formatted : formatted.first
|
196
197
|
end
|
197
198
|
|
198
199
|
def default_type
|
data/lib/ransack/nodes/value.rb
CHANGED
@@ -65,10 +65,12 @@ module Ransack
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def cast_to_boolean(val)
|
68
|
-
if
|
69
|
-
|
68
|
+
if Constants::TRUE_VALUES.include?(val)
|
69
|
+
true
|
70
|
+
elsif Constants::FALSE_VALUES.include?(val)
|
71
|
+
false
|
70
72
|
else
|
71
|
-
|
73
|
+
nil
|
72
74
|
end
|
73
75
|
end
|
74
76
|
|
data/lib/ransack/predicate.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Ransack
|
2
2
|
class Predicate
|
3
|
-
attr_reader :name, :arel_predicate, :type, :formatter, :validator, :compound
|
3
|
+
attr_reader :name, :arel_predicate, :type, :formatter, :validator, :compound, :wants_array
|
4
4
|
|
5
5
|
class << self
|
6
6
|
|
@@ -39,8 +39,9 @@ module Ransack
|
|
39
39
|
@arel_predicate = opts[:arel_predicate]
|
40
40
|
@type = opts[:type]
|
41
41
|
@formatter = opts[:formatter]
|
42
|
-
@validator = opts[:validator] || lambda { |v| v.
|
42
|
+
@validator = opts[:validator] || lambda { |v| v.respond_to?(:empty?) ? !v.empty? : !v.nil? }
|
43
43
|
@compound = opts[:compound]
|
44
|
+
@wants_array = @compound || ['in', 'not_in'].include?(@arel_predicate)
|
44
45
|
end
|
45
46
|
|
46
47
|
def eql?(other)
|
data/lib/ransack/version.rb
CHANGED
@@ -5,33 +5,36 @@ module Ransack
|
|
5
5
|
module ActiveRecord
|
6
6
|
describe Base do
|
7
7
|
|
8
|
-
|
9
|
-
::ActiveRecord::Base.should respond_to :ransack
|
10
|
-
end
|
8
|
+
subject { ::ActiveRecord::Base }
|
11
9
|
|
12
|
-
it
|
13
|
-
|
14
|
-
end
|
10
|
+
it { should respond_to :ransack }
|
11
|
+
it { should respond_to :search }
|
15
12
|
|
16
13
|
describe '#search' do
|
17
|
-
|
18
|
-
@s = Person.search
|
19
|
-
end
|
14
|
+
subject { Person.search }
|
20
15
|
|
21
|
-
it
|
22
|
-
|
23
|
-
|
16
|
+
it { should be_a Search }
|
17
|
+
it 'has a Relation as its object' do
|
18
|
+
subject.object.should be_an ::ActiveRecord::Relation
|
24
19
|
end
|
25
20
|
end
|
26
21
|
|
27
22
|
describe '#ransacker' do
|
23
|
+
# in schema.rb, class Person:
|
24
|
+
# ransacker :reversed_name, :formatter => proc {|v| v.reverse} do |parent|
|
25
|
+
# parent.table[:name]
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# ransacker :doubled_name do |parent|
|
29
|
+
# Arel::Nodes::InfixOperation.new('||', parent.table[:name], parent.table[:name])
|
30
|
+
# end
|
28
31
|
it 'creates ransack attributes' do
|
29
32
|
s = Person.search(:reversed_name_eq => 'htimS cirA')
|
30
33
|
s.result.should have(1).person
|
31
34
|
s.result.first.should eq Person.find_by_name('Aric Smith')
|
32
35
|
end
|
33
36
|
|
34
|
-
it '
|
37
|
+
it 'can be accessed through associations' do
|
35
38
|
s = Person.search(:children_reversed_name_eq => 'htimS cirA')
|
36
39
|
s.result.to_sql.should match /"children_people"."name" = 'Aric Smith'/
|
37
40
|
end
|
@@ -42,6 +45,22 @@ module Ransack
|
|
42
45
|
end if defined?(Arel::Nodes::InfixOperation)
|
43
46
|
end
|
44
47
|
|
48
|
+
describe '#ransackable_attributes' do
|
49
|
+
subject { Person.ransackable_attributes }
|
50
|
+
|
51
|
+
it { should include 'name' }
|
52
|
+
it { should include 'reversed_name' }
|
53
|
+
it { should include 'doubled_name' }
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#ransackable_associations' do
|
57
|
+
subject { Person.ransackable_associations }
|
58
|
+
|
59
|
+
it { should include 'parent' }
|
60
|
+
it { should include 'children' }
|
61
|
+
it { should include 'articles' }
|
62
|
+
end
|
63
|
+
|
45
64
|
end
|
46
65
|
end
|
47
66
|
end
|
@@ -4,19 +4,35 @@ module Ransack
|
|
4
4
|
module Adapters
|
5
5
|
module ActiveRecord
|
6
6
|
describe Context do
|
7
|
-
|
8
|
-
|
7
|
+
subject { Context.new(Person) }
|
8
|
+
|
9
|
+
describe '#evaluate' do
|
10
|
+
it 'evaluates search obects' do
|
11
|
+
search = Search.new(Person, :name_eq => 'Joe Blow')
|
12
|
+
result = subject.evaluate(search)
|
13
|
+
|
14
|
+
result.should be_an ::ActiveRecord::Relation
|
15
|
+
result.to_sql.should match /"name" = 'Joe Blow'/
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'SELECTs DISTINCT when :distinct => true' do
|
19
|
+
search = Search.new(Person, :name_eq => 'Joe Blow')
|
20
|
+
result = subject.evaluate(search, :distinct => true)
|
21
|
+
|
22
|
+
result.should be_an ::ActiveRecord::Relation
|
23
|
+
result.to_sql.should match /SELECT DISTINCT/
|
24
|
+
end
|
9
25
|
end
|
10
26
|
|
11
27
|
it 'contextualizes strings to attributes' do
|
12
|
-
attribute =
|
28
|
+
attribute = subject.contextualize 'children_children_parent_name'
|
13
29
|
attribute.should be_a Arel::Attributes::Attribute
|
14
30
|
attribute.name.to_s.should eq 'name'
|
15
31
|
attribute.relation.table_alias.should eq 'parents_people'
|
16
32
|
end
|
17
33
|
|
18
34
|
it 'builds new associations if not yet built' do
|
19
|
-
attribute =
|
35
|
+
attribute = subject.contextualize 'children_articles_title'
|
20
36
|
attribute.should be_a Arel::Attributes::Attribute
|
21
37
|
attribute.name.to_s.should eq 'title'
|
22
38
|
attribute.relation.name.should eq 'articles'
|
@@ -7,5 +7,25 @@ module Ransack
|
|
7
7
|
config.should eq Ransack
|
8
8
|
end
|
9
9
|
end
|
10
|
+
|
11
|
+
it 'adds predicates' do
|
12
|
+
Ransack.configure do |config|
|
13
|
+
config.add_predicate :test_predicate
|
14
|
+
end
|
15
|
+
|
16
|
+
Ransack.predicates.should have_key 'test_predicate'
|
17
|
+
Ransack.predicates.should have_key 'test_predicate_any'
|
18
|
+
Ransack.predicates.should have_key 'test_predicate_all'
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'avoids creating compound predicates if :compounds => false' do
|
22
|
+
Ransack.configure do |config|
|
23
|
+
config.add_predicate :test_predicate_without_compound, :compounds => false
|
24
|
+
end
|
25
|
+
|
26
|
+
Ransack.predicates.should have_key 'test_predicate_without_compound'
|
27
|
+
Ransack.predicates.should_not have_key 'test_predicate_without_compound_any'
|
28
|
+
Ransack.predicates.should_not have_key 'test_predicate_without_compound_all'
|
29
|
+
end
|
10
30
|
end
|
11
31
|
end
|
@@ -7,6 +7,23 @@ module Ransack
|
|
7
7
|
@s = Search.new(Person)
|
8
8
|
end
|
9
9
|
|
10
|
+
describe 'eq' do
|
11
|
+
it 'generates an equality condition for boolean true' do
|
12
|
+
@s.awesome_eq = true
|
13
|
+
@s.result.to_sql.should match /"people"."awesome" = 't'/
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'generates an equality condition for boolean false' do
|
17
|
+
@s.awesome_eq = false
|
18
|
+
@s.result.to_sql.should match /"people"."awesome" = 'f'/
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'does not generate a condition for nil' do
|
22
|
+
@s.awesome_eq = nil
|
23
|
+
@s.result.to_sql.should_not match /WHERE/
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
10
27
|
describe 'cont' do
|
11
28
|
it 'generates a LIKE query with value surrounded by %' do
|
12
29
|
@s.name_cont = 'ric'
|
@@ -21,5 +38,18 @@ module Ransack
|
|
21
38
|
end
|
22
39
|
end
|
23
40
|
|
41
|
+
describe 'null' do
|
42
|
+
it 'generates a value IS NULL query' do
|
43
|
+
@s.name_null = true
|
44
|
+
@s.result.to_sql.should match /"people"."name" IS NULL/
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'not_null' do
|
49
|
+
it 'generates a value IS NOT NULL query' do
|
50
|
+
@s.name_not_null = true
|
51
|
+
@s.result.to_sql.should match /"people"."name" IS NOT NULL/
|
52
|
+
end
|
53
|
+
end
|
24
54
|
end
|
25
|
-
end
|
55
|
+
end
|
data/spec/ransack/search_spec.rb
CHANGED
@@ -126,7 +126,12 @@ module Ransack
|
|
126
126
|
)
|
127
127
|
search.result.should be_an ActiveRecord::Relation
|
128
128
|
where = search.result.where_values.first
|
129
|
-
|
129
|
+
sql = where.to_sql
|
130
|
+
first, second = sql.split(/ AND /)
|
131
|
+
first.should match /"people"."name" = 'Ernie'/
|
132
|
+
first.should match /"children_people"."name" = 'Ernie'/
|
133
|
+
second.should match /"people"."name" = 'Bert'/
|
134
|
+
second.should match /"children_people"."name" = 'Bert'/
|
130
135
|
end
|
131
136
|
|
132
137
|
it 'returns distinct records when passed :distinct => true' do
|
@@ -175,13 +180,11 @@ module Ransack
|
|
175
180
|
}
|
176
181
|
}
|
177
182
|
@s.sorts.should have(2).items
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
sort2.name.should eq 'name'
|
184
|
-
sort2.dir.should eq 'asc'
|
183
|
+
@s.sorts.should be_all {|s| Nodes::Sort === s}
|
184
|
+
id_sort = @s.sorts.detect {|s| s.name == 'id'}
|
185
|
+
name_sort = @s.sorts.detect {|s| s.name == 'name'}
|
186
|
+
id_sort.dir.should eq 'desc'
|
187
|
+
name_sort.dir.should eq 'asc'
|
185
188
|
end
|
186
189
|
end
|
187
190
|
|
data/spec/spec_helper.rb
CHANGED
@@ -25,4 +25,17 @@ RSpec.configure do |config|
|
|
25
25
|
config.before(:each) { Sham.reset(:before_each) }
|
26
26
|
|
27
27
|
config.include RansackHelper
|
28
|
+
end
|
29
|
+
|
30
|
+
RSpec::Matchers.define :be_like do |expected|
|
31
|
+
match do |actual|
|
32
|
+
actual.gsub(/^\s+|\s+$/, '').gsub(/\s+/, ' ').strip ==
|
33
|
+
expected.gsub(/^\s+|\s+$/, '').gsub(/\s+/, ' ').strip
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
RSpec::Matchers.define :have_attribute_method do |expected|
|
38
|
+
match do |actual|
|
39
|
+
actual.attribute_method?(expected)
|
40
|
+
end
|
28
41
|
end
|
data/spec/support/schema.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ransack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,12 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-07-24 00:00:00.000000000 -04:00
|
13
|
+
default_executable:
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: activerecord
|
16
|
-
requirement: &
|
17
|
+
requirement: &70355886036760 !ruby/object:Gem::Requirement
|
17
18
|
none: false
|
18
19
|
requirements:
|
19
20
|
- - ~>
|
@@ -21,10 +22,10 @@ dependencies:
|
|
21
22
|
version: '3.0'
|
22
23
|
type: :runtime
|
23
24
|
prerelease: false
|
24
|
-
version_requirements: *
|
25
|
+
version_requirements: *70355886036760
|
25
26
|
- !ruby/object:Gem::Dependency
|
26
27
|
name: activesupport
|
27
|
-
requirement: &
|
28
|
+
requirement: &70355886036220 !ruby/object:Gem::Requirement
|
28
29
|
none: false
|
29
30
|
requirements:
|
30
31
|
- - ~>
|
@@ -32,10 +33,10 @@ dependencies:
|
|
32
33
|
version: '3.0'
|
33
34
|
type: :runtime
|
34
35
|
prerelease: false
|
35
|
-
version_requirements: *
|
36
|
+
version_requirements: *70355886036220
|
36
37
|
- !ruby/object:Gem::Dependency
|
37
38
|
name: actionpack
|
38
|
-
requirement: &
|
39
|
+
requirement: &70355886035700 !ruby/object:Gem::Requirement
|
39
40
|
none: false
|
40
41
|
requirements:
|
41
42
|
- - ~>
|
@@ -43,10 +44,10 @@ dependencies:
|
|
43
44
|
version: '3.0'
|
44
45
|
type: :runtime
|
45
46
|
prerelease: false
|
46
|
-
version_requirements: *
|
47
|
+
version_requirements: *70355886035700
|
47
48
|
- !ruby/object:Gem::Dependency
|
48
49
|
name: rspec
|
49
|
-
requirement: &
|
50
|
+
requirement: &70355886035200 !ruby/object:Gem::Requirement
|
50
51
|
none: false
|
51
52
|
requirements:
|
52
53
|
- - ~>
|
@@ -54,10 +55,10 @@ dependencies:
|
|
54
55
|
version: 2.6.0
|
55
56
|
type: :development
|
56
57
|
prerelease: false
|
57
|
-
version_requirements: *
|
58
|
+
version_requirements: *70355886035200
|
58
59
|
- !ruby/object:Gem::Dependency
|
59
60
|
name: machinist
|
60
|
-
requirement: &
|
61
|
+
requirement: &70355886034700 !ruby/object:Gem::Requirement
|
61
62
|
none: false
|
62
63
|
requirements:
|
63
64
|
- - ~>
|
@@ -65,10 +66,10 @@ dependencies:
|
|
65
66
|
version: 1.0.6
|
66
67
|
type: :development
|
67
68
|
prerelease: false
|
68
|
-
version_requirements: *
|
69
|
+
version_requirements: *70355886034700
|
69
70
|
- !ruby/object:Gem::Dependency
|
70
71
|
name: faker
|
71
|
-
requirement: &
|
72
|
+
requirement: &70355886034140 !ruby/object:Gem::Requirement
|
72
73
|
none: false
|
73
74
|
requirements:
|
74
75
|
- - ~>
|
@@ -76,10 +77,10 @@ dependencies:
|
|
76
77
|
version: 0.9.5
|
77
78
|
type: :development
|
78
79
|
prerelease: false
|
79
|
-
version_requirements: *
|
80
|
+
version_requirements: *70355886034140
|
80
81
|
- !ruby/object:Gem::Dependency
|
81
82
|
name: sqlite3
|
82
|
-
requirement: &
|
83
|
+
requirement: &70355886033680 !ruby/object:Gem::Requirement
|
83
84
|
none: false
|
84
85
|
requirements:
|
85
86
|
- - ~>
|
@@ -87,7 +88,7 @@ dependencies:
|
|
87
88
|
version: 1.3.3
|
88
89
|
type: :development
|
89
90
|
prerelease: false
|
90
|
-
version_requirements: *
|
91
|
+
version_requirements: *70355886033680
|
91
92
|
description: Ransack is the successor to the MetaSearch gem. It improves and expands
|
92
93
|
upon MetaSearch's functionality, but does not have a 100%-compatible API.
|
93
94
|
email:
|
@@ -97,6 +98,7 @@ extensions: []
|
|
97
98
|
extra_rdoc_files: []
|
98
99
|
files:
|
99
100
|
- .gitignore
|
101
|
+
- .travis.yml
|
100
102
|
- Gemfile
|
101
103
|
- LICENSE
|
102
104
|
- README.md
|
@@ -153,6 +155,7 @@ files:
|
|
153
155
|
- spec/spec_helper.rb
|
154
156
|
- spec/support/en.yml
|
155
157
|
- spec/support/schema.rb
|
158
|
+
has_rdoc: true
|
156
159
|
homepage: http://metautonomo.us/projects/ransack
|
157
160
|
licenses: []
|
158
161
|
post_install_message:
|
@@ -173,7 +176,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
173
176
|
version: '0'
|
174
177
|
requirements: []
|
175
178
|
rubyforge_project: ransack
|
176
|
-
rubygems_version: 1.
|
179
|
+
rubygems_version: 1.6.2
|
177
180
|
signing_key:
|
178
181
|
specification_version: 3
|
179
182
|
summary: Object-based searching for ActiveRecord (currently).
|