filterer 0.4.3 → 1.0.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/filterer.rb +0 -1
- data/lib/filterer/active_record.rb +24 -0
- data/lib/filterer/base.rb +119 -83
- data/lib/filterer/engine.rb +4 -0
- data/lib/filterer/version.rb +1 -1
- metadata +33 -7
- data/app/helpers/filterer/pagination_helper.rb +0 -54
- data/lib/filterer/paginator.rb +0 -51
- data/lib/tasks/filterer_tasks.rake +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b44892d5a150d19bef25b69c217cf1fa0fa76cb7
|
4
|
+
data.tar.gz: c8f02087f8d7ee437e936f841d23f9c2200f0462
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3afe610c8e745b68f336a32078246cf94987a44803d8452384987acdd52886bfc4573ae33f146b12a1286e80deb901b487c15d37e8a671f4a302cd572e02f701
|
7
|
+
data.tar.gz: 79ca8ab44c8d266eed187033a2fb22f4554695af64489a75afccbcdeaba78f77d1d8322ed769ca94444607db864e9abbc0176130a0d40f47296f02d804ea0810
|
data/lib/filterer.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
module Filterer
|
2
|
+
module ActiveRecord
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
def self.filter(params = {}, opts = {})
|
7
|
+
filterer_class(opts[:filterer_class]).
|
8
|
+
filter(params, { starting_query: all }.merge(opts))
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.filterer_class(override)
|
12
|
+
if override
|
13
|
+
override.constantize
|
14
|
+
else
|
15
|
+
const_get("#{name}Filterer")
|
16
|
+
end
|
17
|
+
rescue
|
18
|
+
fail "Looked for #{name}Filterer and couldn't find one!"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
ActiveRecord::Base.send(:include, Filterer::ActiveRecord)
|
data/lib/filterer/base.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
module Filterer
|
2
2
|
class Base
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
attr_accessor :results,
|
4
|
+
:meta,
|
5
|
+
:sort,
|
6
|
+
:params,
|
7
|
+
:opts
|
6
8
|
|
7
9
|
class_attribute :sort_options
|
8
10
|
self.sort_options = []
|
@@ -10,21 +12,22 @@ module Filterer
|
|
10
12
|
class_attribute :per_page
|
11
13
|
self.per_page = 20
|
12
14
|
|
13
|
-
class_attribute :
|
14
|
-
self.
|
15
|
+
class_attribute :allow_per_page_override
|
16
|
+
self.allow_per_page_override = false
|
15
17
|
|
16
18
|
class_attribute :per_page_max
|
17
19
|
self.per_page_max = 1000
|
18
20
|
|
19
21
|
class << self
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
# Macro for adding sort options
|
23
|
+
def sort_option(key, string_or_proc = nil, opts = {})
|
24
|
+
if string_or_proc.is_a?(Hash)
|
25
|
+
opts, string_or_proc = string_or_proc.clone, nil
|
23
26
|
end
|
24
27
|
|
25
|
-
if !
|
28
|
+
if !string_or_proc
|
26
29
|
if key.is_a?(String)
|
27
|
-
|
30
|
+
string_or_proc = key
|
28
31
|
else
|
29
32
|
raise 'Please provide a query string or a proc.'
|
30
33
|
end
|
@@ -34,120 +37,128 @@ module Filterer
|
|
34
37
|
raise "Default sort option can't have a Regexp key."
|
35
38
|
end
|
36
39
|
|
37
|
-
if
|
40
|
+
if string_or_proc.is_a?(Proc) && opts[:tiebreaker]
|
38
41
|
raise "Tiebreaker can't be a proc."
|
39
42
|
end
|
40
43
|
|
41
44
|
self.sort_options += [{
|
42
45
|
key: key,
|
43
|
-
|
46
|
+
string_or_proc: string_or_proc,
|
44
47
|
opts: opts
|
45
48
|
}]
|
46
49
|
end
|
47
50
|
|
48
|
-
|
49
|
-
|
51
|
+
# Public API
|
52
|
+
# @return [ActiveRecord::Association]
|
53
|
+
def filter(*args)
|
54
|
+
new(*args).results
|
50
55
|
end
|
56
|
+
end
|
51
57
|
|
52
|
-
|
53
|
-
|
54
|
-
|
58
|
+
def initialize(params = {}, opts = {})
|
59
|
+
self.params = defaults.merge(params).with_indifferent_access
|
60
|
+
self.opts = opts
|
61
|
+
self.results = opts[:starting_query] || starting_query
|
62
|
+
self.results = apply_default_filters || results
|
63
|
+
add_params_to_query
|
64
|
+
order_results unless opts[:skip_ordering]
|
65
|
+
paginate_results unless opts[:skip_pagination]
|
66
|
+
extend_active_record_relation
|
55
67
|
end
|
56
68
|
|
57
69
|
def defaults
|
58
70
|
{}
|
59
71
|
end
|
60
72
|
|
61
|
-
def
|
62
|
-
|
63
|
-
setup_meta
|
64
|
-
find_results
|
73
|
+
def starting_query
|
74
|
+
raise 'You must override this method!'
|
65
75
|
end
|
66
76
|
|
67
|
-
def
|
68
|
-
|
77
|
+
def direction
|
78
|
+
params[:direction].try(:downcase) == 'desc' ? 'desc' : 'asc'
|
69
79
|
end
|
70
80
|
|
71
|
-
def
|
72
|
-
@
|
73
|
-
|
74
|
-
|
75
|
-
|
81
|
+
def sort
|
82
|
+
@sort ||= begin
|
83
|
+
if params[:sort] && find_sort_option_from_param(params[:sort])
|
84
|
+
params[:sort]
|
85
|
+
else
|
86
|
+
default_sort_option.try(:[], :key)
|
87
|
+
end
|
88
|
+
end
|
76
89
|
end
|
77
90
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
91
|
+
private
|
92
|
+
|
93
|
+
def paginate_results
|
94
|
+
if per_page && paginator
|
95
|
+
send("paginate_results_with_#{paginator}")
|
83
96
|
end
|
84
97
|
end
|
85
98
|
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
return if @opts[:meta_only]
|
99
|
+
def paginator
|
100
|
+
if defined?(Kaminari)
|
101
|
+
:kaminari
|
102
|
+
elsif defined?(WillPaginate)
|
103
|
+
:will_paginate
|
104
|
+
end
|
105
|
+
end
|
94
106
|
|
95
|
-
|
96
|
-
|
107
|
+
def paginate_results_with_kaminari
|
108
|
+
self.results = results.page(current_page).per(per_page)
|
109
|
+
end
|
97
110
|
|
98
|
-
|
99
|
-
|
111
|
+
def paginate_results_with_will_paginate
|
112
|
+
self.results = results.paginate(page: current_page, per_page: per_page)
|
100
113
|
end
|
101
114
|
|
102
|
-
def
|
103
|
-
|
104
|
-
@meta[:last_page] = [(@meta[:total].to_f / @meta[:per_page]).ceil, 1].max
|
105
|
-
@meta[:page] = [@meta[:last_page], @meta[:page]].min
|
115
|
+
def apply_default_filters
|
116
|
+
results
|
106
117
|
end
|
107
118
|
|
108
119
|
def add_params_to_query
|
109
|
-
|
110
|
-
.select { |k, v| v.present? }
|
111
|
-
.each do |k, v|
|
112
|
-
|
120
|
+
present_params.each do |k, v|
|
113
121
|
method_name = "param_#{k}"
|
114
|
-
|
122
|
+
|
123
|
+
if respond_to?(method_name)
|
124
|
+
self.results = send(method_name, v)
|
125
|
+
end
|
115
126
|
end
|
116
127
|
end
|
117
128
|
|
118
|
-
def
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
if !get_sort_option(@sort)
|
123
|
-
@results = @results.order default_sort_sql
|
124
|
-
elsif get_sort_option(@sort)[:query_string_or_proc].is_a?(String)
|
125
|
-
@results = @results.order basic_sort_sql
|
126
|
-
elsif get_sort_option(@sort)[:query_string_or_proc].is_a?(Proc)
|
127
|
-
apply_sort_proc
|
129
|
+
def present_params
|
130
|
+
params.select do |_k, v|
|
131
|
+
v.present?
|
128
132
|
end
|
129
133
|
end
|
130
134
|
|
131
|
-
def
|
132
|
-
|
135
|
+
def order_results
|
136
|
+
self.results = if !sort_option
|
137
|
+
results.order(default_sort_sql)
|
138
|
+
elsif sort_option[:string_or_proc].is_a?(String)
|
139
|
+
results.order(basic_sort_sql)
|
140
|
+
elsif sort_option[:string_or_proc].is_a?(Proc)
|
141
|
+
apply_sort_proc
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def per_page
|
146
|
+
if self.class.allow_per_page_override && params[:per_page].present?
|
147
|
+
[params[:per_page], per_page_max].min
|
148
|
+
else
|
149
|
+
self.class.per_page
|
150
|
+
end
|
133
151
|
end
|
134
152
|
|
135
|
-
def
|
136
|
-
|
137
|
-
#{get_sort_option(@sort)[:query_string_or_proc]}
|
138
|
-
#{@direction}
|
139
|
-
#{get_sort_option(@sort)[:opts][:nulls_last] ? 'NULLS LAST' : ''}
|
140
|
-
#{tiebreaker_sort_string ? ',' + tiebreaker_sort_string : ''}
|
141
|
-
}.squish
|
153
|
+
def current_page
|
154
|
+
[params[:page].to_i, 1].max
|
142
155
|
end
|
143
156
|
|
144
|
-
def
|
145
|
-
|
146
|
-
matches = sort_key.is_a?(Regexp) && @sort.match(sort_key)
|
147
|
-
@results = get_sort_option(@sort)[:query_string_or_proc].call(@results, matches, self)
|
157
|
+
def sort_option
|
158
|
+
@sort_option ||= find_sort_option_from_param(sort)
|
148
159
|
end
|
149
160
|
|
150
|
-
def
|
161
|
+
def find_sort_option_from_param(x)
|
151
162
|
self.class.sort_options.detect do |sort_option|
|
152
163
|
if sort_option[:key].is_a?(Regexp)
|
153
164
|
x.match(sort_option[:key])
|
@@ -157,20 +168,45 @@ module Filterer
|
|
157
168
|
end
|
158
169
|
end
|
159
170
|
|
160
|
-
def
|
171
|
+
def default_sort_sql
|
172
|
+
"#{results.model.table_name}.id asc"
|
173
|
+
end
|
174
|
+
|
175
|
+
def basic_sort_sql
|
176
|
+
%{
|
177
|
+
#{sort_option[:string_or_proc]}
|
178
|
+
#{direction}
|
179
|
+
#{sort_option[:opts][:nulls_last] ? 'NULLS LAST' : ''}
|
180
|
+
#{tiebreaker_sort_string ? ', ' + tiebreaker_sort_string : ''}
|
181
|
+
}.squish
|
182
|
+
end
|
183
|
+
|
184
|
+
def apply_sort_proc
|
185
|
+
sort_key = sort_option[:key]
|
186
|
+
matches = sort_key.is_a?(Regexp) && params[:sort].match(sort_key)
|
187
|
+
sort_option[:string_or_proc].call(results, matches, self)
|
188
|
+
end
|
189
|
+
|
190
|
+
def default_sort_option
|
161
191
|
self.class.sort_options.detect do |sort_option|
|
162
192
|
sort_option[:opts][:default]
|
163
|
-
end
|
193
|
+
end
|
164
194
|
end
|
165
195
|
|
166
196
|
def tiebreaker_sort_string
|
167
197
|
self.class.sort_options.detect do |sort_option|
|
168
198
|
sort_option[:opts][:tiebreaker]
|
169
|
-
end.try(:[], :
|
199
|
+
end.try(:[], :string_or_proc)
|
170
200
|
end
|
171
201
|
|
172
|
-
def
|
173
|
-
|
202
|
+
def extend_active_record_relation
|
203
|
+
results.instance_variable_set(:@filterer, self)
|
204
|
+
|
205
|
+
results.extending! do
|
206
|
+
def filterer
|
207
|
+
@filterer
|
208
|
+
end
|
209
|
+
end
|
174
210
|
end
|
175
211
|
end
|
176
212
|
end
|
data/lib/filterer/engine.rb
CHANGED
data/lib/filterer/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: filterer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.beta.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Becker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-06-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 4.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: benchmark-ips
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: capybara
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,6 +108,20 @@ dependencies:
|
|
94
108
|
- - ">="
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
97
125
|
- !ruby/object:Gem::Dependency
|
98
126
|
name: rspec-rails
|
99
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -145,11 +173,10 @@ extensions: []
|
|
145
173
|
extra_rdoc_files: []
|
146
174
|
files:
|
147
175
|
- Rakefile
|
148
|
-
- app/helpers/filterer/pagination_helper.rb
|
149
176
|
- lib/filterer.rb
|
177
|
+
- lib/filterer/active_record.rb
|
150
178
|
- lib/filterer/base.rb
|
151
179
|
- lib/filterer/engine.rb
|
152
|
-
- lib/filterer/paginator.rb
|
153
180
|
- lib/filterer/version.rb
|
154
181
|
- lib/generators/filterer/filterer_generator.rb
|
155
182
|
- lib/generators/filterer/templates/filter.rb
|
@@ -157,7 +184,6 @@ files:
|
|
157
184
|
- lib/generators/rspec/templates/filter_spec.rb
|
158
185
|
- lib/generators/test_unit/filterer_generator.rb
|
159
186
|
- lib/generators/test_unit/templates/filter_test.rb
|
160
|
-
- lib/tasks/filterer_tasks.rake
|
161
187
|
homepage: https://github.com/dobtco/filterer
|
162
188
|
licenses:
|
163
189
|
- MIT
|
@@ -173,9 +199,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
173
199
|
version: '0'
|
174
200
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
175
201
|
requirements:
|
176
|
-
- - "
|
202
|
+
- - ">"
|
177
203
|
- !ruby/object:Gem::Version
|
178
|
-
version:
|
204
|
+
version: 1.3.1
|
179
205
|
requirements: []
|
180
206
|
rubyforge_project:
|
181
207
|
rubygems_version: 2.2.2
|
@@ -1,54 +0,0 @@
|
|
1
|
-
module Filterer
|
2
|
-
module PaginationHelper
|
3
|
-
|
4
|
-
RIGHT_ARROW = '›'.html_safe
|
5
|
-
LEFT_ARROW = '‹'.html_safe
|
6
|
-
|
7
|
-
def render_filterer_pagination(filterer)
|
8
|
-
content_tag(:div, class: 'pagination-wrapper') do
|
9
|
-
content_tag(:ul, class: 'unstyled') do
|
10
|
-
render_filterer_previous_link(filterer) +
|
11
|
-
filterer.paginator.pages.map { |p| render_filterer_page_link(filterer, p) }.join('').html_safe +
|
12
|
-
render_filterer_next_link(filterer)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
def calculate_filterer_pagination_url(page)
|
19
|
-
url_for(params.merge(page: page))
|
20
|
-
end
|
21
|
-
|
22
|
-
def render_filterer_previous_link(filterer)
|
23
|
-
content_tag(:li, class: filterer.meta[:page] == 1 ? "disabled" : '') do
|
24
|
-
if filterer.meta[:page] == 1
|
25
|
-
content_tag(:span) { LEFT_ARROW }
|
26
|
-
else
|
27
|
-
content_tag(:a, class: 'pagination-previous',
|
28
|
-
href: calculate_filterer_pagination_url(filterer.meta[:page] - 1)) { LEFT_ARROW }
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def render_filterer_next_link(filterer)
|
34
|
-
content_tag(:li, class: filterer.meta[:page] == filterer.meta[:last_page] ? "disabled" : '') do
|
35
|
-
if filterer.meta[:page] == filterer.meta[:last_page]
|
36
|
-
content_tag(:span) { RIGHT_ARROW }
|
37
|
-
else
|
38
|
-
content_tag(:a, class: 'pagination-next', href: calculate_filterer_pagination_url(filterer.meta[:page] + 1)) { RIGHT_ARROW }
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def render_filterer_page_link(filterer, p)
|
44
|
-
if p == 'break'
|
45
|
-
"<li><span>…</span></li>"
|
46
|
-
else
|
47
|
-
content_tag(:li, class: p == filterer.meta[:page] ? 'active' : '') do
|
48
|
-
content_tag(:a, href: calculate_filterer_pagination_url(p)) { p.to_s }
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
end
|
data/lib/filterer/paginator.rb
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
module Filterer
|
2
|
-
class Paginator
|
3
|
-
|
4
|
-
attr_reader :pages
|
5
|
-
|
6
|
-
def initialize(filterer)
|
7
|
-
@filterer = filterer
|
8
|
-
return @pages = [1] if @filterer.meta[:last_page] == 1
|
9
|
-
push_default_pages
|
10
|
-
calculate_additional_pages
|
11
|
-
add_breaks
|
12
|
-
end
|
13
|
-
|
14
|
-
def push_default_pages
|
15
|
-
@pages = [1, 2]
|
16
|
-
push_page(@filterer.meta[:last_page], @filterer.meta[:last_page] - 1)
|
17
|
-
end
|
18
|
-
|
19
|
-
def calculate_additional_pages
|
20
|
-
offset = 0
|
21
|
-
current_page = @filterer.meta[:page]
|
22
|
-
|
23
|
-
while @pages.length < 11 && ( (current_page - offset >= 1) || (current_page + offset <= @filterer.meta[:last_page]) ) do
|
24
|
-
push_page(current_page - offset, current_page + offset)
|
25
|
-
offset += 1
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def add_breaks
|
30
|
-
pages_without_breaks = @pages.sort
|
31
|
-
pages_with_breaks = []
|
32
|
-
|
33
|
-
pages_without_breaks.each_with_index do |p, i|
|
34
|
-
if pages_without_breaks[i - 1] && (p - pages_without_breaks[i - 1] > 1)
|
35
|
-
pages_with_breaks.push 'break'
|
36
|
-
end
|
37
|
-
|
38
|
-
pages_with_breaks.push p
|
39
|
-
end
|
40
|
-
|
41
|
-
@pages = pages_with_breaks
|
42
|
-
end
|
43
|
-
|
44
|
-
def push_page(*args)
|
45
|
-
args.each do |page|
|
46
|
-
@pages.push(page) unless @pages.include?(page) || (page > @filterer.meta[:last_page]) || (page < 1)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
end
|