index_view 0.1.0
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.
- data/lib/index_view.rb +54 -0
- data/lib/index_view/column.rb +64 -0
- data/lib/index_view/customization_defaults.rb +28 -0
- data/lib/index_view/implementation.rb +174 -0
- data/lib/index_view/sql_conditions.rb +19 -0
- data/lib/index_view/sql_generator.rb +20 -0
- metadata +50 -0
data/lib/index_view.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/index_view/column"
|
2
|
+
require File.dirname(__FILE__) + "/index_view/sql_generator"
|
3
|
+
require File.dirname(__FILE__) + "/index_view/sql_conditions"
|
4
|
+
require File.dirname(__FILE__) + "/index_view/implementation"
|
5
|
+
require File.dirname(__FILE__) + "/index_view/customization_defaults"
|
6
|
+
|
7
|
+
module IndexView
|
8
|
+
module Version
|
9
|
+
MAJOR = 0
|
10
|
+
MINOR = 1
|
11
|
+
TINY = 0
|
12
|
+
|
13
|
+
STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
|
14
|
+
end
|
15
|
+
|
16
|
+
class InvalidSort < StandardError; end
|
17
|
+
|
18
|
+
class Base
|
19
|
+
include Implementation
|
20
|
+
include CustomizationDefaults
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def find(*args)
|
24
|
+
new({}).find(*args)
|
25
|
+
end
|
26
|
+
|
27
|
+
def all(*args)
|
28
|
+
new({}).all(*args)
|
29
|
+
end
|
30
|
+
|
31
|
+
def first(*args)
|
32
|
+
new({}).first(*args)
|
33
|
+
end
|
34
|
+
|
35
|
+
# used to define columns you want to render in the view,
|
36
|
+
# and gives you a way to customize _how_ they render
|
37
|
+
# See IndexView::Column to get an idea of the options you can pass in.
|
38
|
+
def column(*args, &block)
|
39
|
+
columns << Column.new(*args, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
# returns a collection of the IndexView::Column objects that were
|
43
|
+
# added through the +column+ method
|
44
|
+
def columns
|
45
|
+
@columns ||= []
|
46
|
+
end
|
47
|
+
|
48
|
+
def fields_for_search
|
49
|
+
searchable_columns = columns.select { |c| c.searchable? }
|
50
|
+
searchable_columns.map { |col| col.column_name }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module IndexView
|
2
|
+
class Column
|
3
|
+
class InvalidKeyError < StandardError; end
|
4
|
+
|
5
|
+
OPTION_KEYS = [:link, :sortable, :title, :searchable]
|
6
|
+
|
7
|
+
def initialize(column_name, options={ }, &link)
|
8
|
+
@column_name = column_name.to_sym
|
9
|
+
|
10
|
+
check_and_assign_values_from_keys(options, link)
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :column_name, :link
|
14
|
+
|
15
|
+
def column_value(context, object)
|
16
|
+
context.instance_exec(object, &link)
|
17
|
+
end
|
18
|
+
|
19
|
+
def column_value?
|
20
|
+
link ? true : false
|
21
|
+
end
|
22
|
+
|
23
|
+
def sortable?
|
24
|
+
@sortable ? true : false
|
25
|
+
end
|
26
|
+
|
27
|
+
def human_name
|
28
|
+
column_name.to_s.humanize
|
29
|
+
end
|
30
|
+
|
31
|
+
def title
|
32
|
+
@title ? @title : human_name
|
33
|
+
end
|
34
|
+
|
35
|
+
def searchable?
|
36
|
+
@searchable ? true : false
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def check_and_assign_values_from_keys(hash, link)
|
42
|
+
hash.each do |key, value|
|
43
|
+
key = key.to_sym
|
44
|
+
|
45
|
+
if key == :link
|
46
|
+
Kernel.warn ":link is no longer a valid key. Pass a block directly to the column method (from #{caller[5]})"
|
47
|
+
end
|
48
|
+
|
49
|
+
if OPTION_KEYS.include?(key)
|
50
|
+
assign_if_present(key, value)
|
51
|
+
else
|
52
|
+
key_names = "[#{OPTION_KEYS.map { |k| ":#{k}" }.join(", ")}]"
|
53
|
+
raise InvalidKeyError, "#{key} is not a valid key. Valid keys are #{key_names}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
assign_if_present(:link, link)
|
58
|
+
end
|
59
|
+
|
60
|
+
def assign_if_present(key, value)
|
61
|
+
instance_variable_set("@#{key}", value) if value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module IndexView
|
2
|
+
# The following methods are safe to override in descendent classes
|
3
|
+
module CustomizationDefaults
|
4
|
+
DEFAULT_PAGINATION_NUMBER = 30
|
5
|
+
|
6
|
+
def target_class
|
7
|
+
raise NotImplementedError
|
8
|
+
end
|
9
|
+
|
10
|
+
def per_page
|
11
|
+
target_class.respond_to?(:per_page) ?
|
12
|
+
target_class.per_page :
|
13
|
+
DEFAULT_PAGINATION_NUMBER
|
14
|
+
end
|
15
|
+
|
16
|
+
def default_sort_term
|
17
|
+
raise NotImplementedError, "default_sort_term must be defined"
|
18
|
+
end
|
19
|
+
|
20
|
+
def secondary_sort_term
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def default_sort_direction
|
25
|
+
Implementation::DESC
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
module IndexView
|
2
|
+
module Implementation
|
3
|
+
include SQLConditions
|
4
|
+
|
5
|
+
ASC = :ASC
|
6
|
+
DESC = :DESC
|
7
|
+
SORT_DIRECTIONS = [ASC, DESC]
|
8
|
+
|
9
|
+
attr_reader :params
|
10
|
+
|
11
|
+
# IndexView objects are initialized with the params of a request.
|
12
|
+
# See README.rdoc
|
13
|
+
def initialize(params = { })
|
14
|
+
@params = params
|
15
|
+
end
|
16
|
+
|
17
|
+
# returns a paginated set of the IndexView's +target_class+
|
18
|
+
# To customize how the objects are paginated -
|
19
|
+
# redefine +pagination_options+ in your class
|
20
|
+
def paginate
|
21
|
+
target_class.paginate(pagination_options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def find(selector, options={})
|
25
|
+
case selector
|
26
|
+
when :first, :last, :all
|
27
|
+
target_class.find(selector, find_options.merge(options))
|
28
|
+
else
|
29
|
+
target_class.find(selector)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def all(*args)
|
34
|
+
find(:all, *args)
|
35
|
+
end
|
36
|
+
|
37
|
+
def first(*args)
|
38
|
+
find(:first, *args)
|
39
|
+
end
|
40
|
+
|
41
|
+
def find_options
|
42
|
+
{
|
43
|
+
:from => table_name.to_s,
|
44
|
+
:order => sort,
|
45
|
+
:conditions => conditions_sql
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns a hash of options used to paginate your IndexView's +target_class+.
|
50
|
+
# You can overwrite this in your class to customize pagination.
|
51
|
+
def pagination_options
|
52
|
+
{
|
53
|
+
:from => table_name.to_s,
|
54
|
+
:conditions => conditions_sql,
|
55
|
+
:order => sort,
|
56
|
+
:page => @params[:page],
|
57
|
+
:per_page => per_page
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def search_term
|
62
|
+
@params[:search]
|
63
|
+
end
|
64
|
+
|
65
|
+
def search_term?
|
66
|
+
search_term && !search_term.blank? ? true : false
|
67
|
+
end
|
68
|
+
|
69
|
+
def sort
|
70
|
+
"#{sort_term} #{sort_direction}" + (!secondary_sort_term.blank? ? ", #{secondary_sort_term} #{sort_direction}" : '')
|
71
|
+
end
|
72
|
+
|
73
|
+
def sort_term
|
74
|
+
if sort = @params[:sort]
|
75
|
+
sort
|
76
|
+
else
|
77
|
+
default_sort_term.is_a?(Array) ? default_sort_term.join(", ") : default_sort_term
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def sort_direction
|
82
|
+
if SORT_DIRECTIONS.include?(given_sort_direction)
|
83
|
+
given_sort_direction
|
84
|
+
else
|
85
|
+
raise IndexView::InvalidSort, "#{given_sort_direction} is not a valid sort direction"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def opposite_sort_direction
|
90
|
+
ascending? ? DESC : ASC
|
91
|
+
end
|
92
|
+
|
93
|
+
# returns a collection of the IndexView::Column objects that were
|
94
|
+
# added through the +column+ method
|
95
|
+
def columns
|
96
|
+
self.class.columns
|
97
|
+
end
|
98
|
+
|
99
|
+
# Takes a column name and returns whether or not your index is currently sorted on that column.
|
100
|
+
def sorting?(column_name)
|
101
|
+
sort_term.to_s == column_name.to_s
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns whether or not your index is currently sorted ascended.
|
105
|
+
def ascending?
|
106
|
+
sort_direction == ASC
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns whether or not your index is currently sorted descended.
|
110
|
+
def descending?
|
111
|
+
!ascending?
|
112
|
+
end
|
113
|
+
|
114
|
+
def state?
|
115
|
+
state && !state.blank? ? true : false
|
116
|
+
end
|
117
|
+
|
118
|
+
def state
|
119
|
+
@params[:state]
|
120
|
+
end
|
121
|
+
|
122
|
+
def fields_for_search
|
123
|
+
self.class.fields_for_search
|
124
|
+
end
|
125
|
+
|
126
|
+
def table_name
|
127
|
+
target_class.table_name.to_sym
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def conditions_sql
|
133
|
+
present_conditions.join(" AND ")
|
134
|
+
end
|
135
|
+
|
136
|
+
def present_conditions
|
137
|
+
parenthesize(remove_empties(sanitize(conditions)))
|
138
|
+
end
|
139
|
+
|
140
|
+
def conditions
|
141
|
+
[search_conditions, state_conditions, *index_parameter_conditions]
|
142
|
+
end
|
143
|
+
|
144
|
+
def index_parameter_conditions
|
145
|
+
if index_params = params[:index]
|
146
|
+
index_params.reject { |k,v| v.blank? }.map { |k, v| ["#{k} = ?", v] }
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def parenthesize(collection)
|
151
|
+
collection.map { |element| "(#{element})" }
|
152
|
+
end
|
153
|
+
|
154
|
+
def remove_empties(collection)
|
155
|
+
collection.reject { |element| element.blank? }
|
156
|
+
end
|
157
|
+
|
158
|
+
def sanitize(collection)
|
159
|
+
collection.map { |element| sanitize_sql(element) }
|
160
|
+
end
|
161
|
+
|
162
|
+
def sanitize_sql(sql)
|
163
|
+
target_class.send(:sanitize_sql, sql)
|
164
|
+
end
|
165
|
+
|
166
|
+
def given_sort_direction
|
167
|
+
if direction = @params[:direction]
|
168
|
+
direction.upcase.to_sym
|
169
|
+
else
|
170
|
+
default_sort_direction
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module IndexView
|
2
|
+
module SQLConditions
|
3
|
+
include SQLGenerator
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def state_conditions
|
8
|
+
if state?
|
9
|
+
["state = ?", state]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def search_conditions
|
14
|
+
if search_term?
|
15
|
+
like_for_many_columns(search_term, *fields_for_search)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module IndexView
|
2
|
+
module SQLGenerator
|
3
|
+
def like_for_many_columns(value, *fields)
|
4
|
+
[
|
5
|
+
condition_fields_for_like_with_many_columns(value, fields),
|
6
|
+
*value_fields_for_like_with_many_columns(value, fields)
|
7
|
+
]
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def condition_fields_for_like_with_many_columns(value, fields)
|
13
|
+
fields.map { |field| "#{field} LIKE ?" }.join(" OR ")
|
14
|
+
end
|
15
|
+
|
16
|
+
def value_fields_for_like_with_many_columns(value, fields)
|
17
|
+
fields.map { "%#{value.gsub(" ", "%")}%" }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: index_view
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Scott Taylor
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-06 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: A simple way to use mysql indexes in a rails app
|
15
|
+
email: scott@railsnewbie.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/index_view/column.rb
|
21
|
+
- lib/index_view/customization_defaults.rb
|
22
|
+
- lib/index_view/implementation.rb
|
23
|
+
- lib/index_view/sql_conditions.rb
|
24
|
+
- lib/index_view/sql_generator.rb
|
25
|
+
- lib/index_view.rb
|
26
|
+
homepage: https://github.com/smtlaissezfaire/index_view
|
27
|
+
licenses: []
|
28
|
+
post_install_message:
|
29
|
+
rdoc_options: []
|
30
|
+
require_paths:
|
31
|
+
- lib
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
requirements: []
|
45
|
+
rubyforge_project:
|
46
|
+
rubygems_version: 1.8.24
|
47
|
+
signing_key:
|
48
|
+
specification_version: 3
|
49
|
+
summary: index_view rails plugin
|
50
|
+
test_files: []
|