index_view 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []