scoped_search 2.6.5 → 2.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3bb6838588ce385873a180ec0e875deedde5fcde
4
- data.tar.gz: efbe17ef6dd34eadea7ac3251b3fbf5225e4e2c5
3
+ metadata.gz: 7053f29622ce510229c05ba561ce8a1e275942cf
4
+ data.tar.gz: e28a7d2541cc4e586b2bcbde23ea4742fa7a5671
5
5
  SHA512:
6
- metadata.gz: aa3ed52f60b294fba0ef10b2299882e820d985b26dd03dfdcb0c91b93fb2445c5fe21817e80a4d452eb5f169f68626f4a672e7abb8f7e542a94516a794bcd979
7
- data.tar.gz: c43a5e3d499f854bf01ae594387650bf46deaf4e4770ed44047949b2fcd0ca46bcd8ab8312970430fbe58ff9bebea86125a5862c9e840bde4821c94d960bfb05
6
+ metadata.gz: 7e3fac5a915408137d1ae6eb7194ddb43f75501407e13dd7203da779dc8e23fc011b0f55f2b7a1b6c461fb799e3afd376881bd001d6cc7276443d96ce8f2e7cd
7
+ data.tar.gz: 7b8643f0e611d089409b34f87f0102ef856ec9079d2f07e0ce1458ded6402f1d7c08d251ab4d609c29489e4eb5d5a673390e99948ce429eea663c3ef1638c85b
data/.gitignore CHANGED
@@ -8,5 +8,5 @@ scoped_search-*.gem
8
8
  /files
9
9
  /spec/database.yml
10
10
  .bundle/
11
- Gemfile.lock
11
+ Gemfile*.lock
12
12
  .idea/
data/.travis.yml CHANGED
@@ -5,28 +5,26 @@ before_script:
5
5
  - mysql -e 'create database scoped_search_test;'
6
6
  rvm:
7
7
  - 1.8.7
8
- - 1.9.2
9
8
  - 1.9.3
10
9
  - 2.0.0
10
+ - 2.1.1
11
11
  - ruby-head
12
- - ree
13
12
  - jruby-18mode
14
13
  - jruby-19mode
15
14
  - jruby-head
16
15
  gemfile:
17
16
  - Gemfile.activerecord2
18
17
  - Gemfile.activerecord3
18
+ - Gemfile.activerecord4
19
19
  matrix:
20
20
  include:
21
- - rvm: 1.9.3
22
- gemfile: Gemfile.activerecord4
23
- - rvm: 2.0.0
24
- gemfile: Gemfile.activerecord4
25
21
  allow_failures:
26
22
  - rvm: ruby-head
27
23
  - rvm: jruby-head
28
- - rvm: jruby-18mode
29
- - rvm: jruby-19mode
24
+ - rvm: 2.0.0
25
+ gemfile: Gemfile.activerecord2
26
+ - rvm: 2.1.1
27
+ gemfile: Gemfile.activerecord2
30
28
  exclude:
31
29
  - rvm: jruby-18mode
32
30
  gemfile: Gemfile.activerecord2
@@ -34,6 +32,7 @@ matrix:
34
32
  gemfile: Gemfile.activerecord2
35
33
  - rvm: jruby-head
36
34
  gemfile: Gemfile.activerecord2
37
- - rvm: jruby-head
38
- gemfile: Gemfile.activerecord2
39
- - rvm: ree
35
+ - rvm: 1.8.7
36
+ gemfile: Gemfile.activerecord4
37
+ - rvm: jruby-18mode
38
+ gemfile: Gemfile.activerecord4
data/lib/scoped_search.rb CHANGED
@@ -17,19 +17,23 @@ module ScopedSearch
17
17
  # <tt>ActiveRecord::Base.search_for</tt> named scope.
18
18
  module ClassMethods
19
19
 
20
+ def self.extended(base)
21
+ base.class_attribute :scoped_search_definition
22
+ end
23
+
20
24
  # Export the scoped_search method fo defining the search options.
21
25
  # This method will create a definition instance for the class if it does not yet exist,
22
26
  # and use the object as block argument and retun value.
23
27
  def scoped_search(*definitions)
24
- @scoped_search ||= ScopedSearch::Definition.new(self)
28
+ self.scoped_search_definition ||= ScopedSearch::Definition.new(self)
25
29
  definitions.each do |definition|
26
30
  if definition[:on].kind_of?(Array)
27
- definition[:on].each { |field| @scoped_search.define(definition.merge(:on => field)) }
31
+ definition[:on].each { |field| self.scoped_search_definition.define(definition.merge(:on => field)) }
28
32
  else
29
- @scoped_search.define(definition)
33
+ self.scoped_search_definition.define(definition)
30
34
  end
31
35
  end
32
- return @scoped_search
36
+ return self.scoped_search_definition
33
37
  end
34
38
  end
35
39
 
@@ -137,13 +137,13 @@ module ScopedSearch
137
137
  q.chomp!(quoted[1]) if quoted
138
138
  end
139
139
 
140
- # for doted field names compact the suggestions list to be one suggestion
140
+ # for dotted field names compact the suggestions list to be one suggestion
141
141
  # unless the user has typed the relation name entirely or the suggestion list
142
142
  # is short.
143
- if (suggestions.size > 10 && (tokens.empty? || !(tokens.last.to_s.include?('.')) ) && !(is_value))
144
- suggestions = suggestions.map {|s|
145
- (s.to_s.split('.')[0].end_with?(tokens.last)) ? s.to_s : s.to_s.split('.')[0]
146
- }
143
+ if (suggestions.size > 10 && (tokens.empty? || !tokens.last.to_s.include?('.')) && !is_value)
144
+ suggestions = suggestions.map do |s|
145
+ s.to_s.split('.')[0].end_with?(tokens.last.to_s) ? s.to_s : s.to_s.split('.')[0]
146
+ end
147
147
  end
148
148
 
149
149
  suggestions.uniq.map {|m| "#{q} #{m}"}
@@ -158,7 +158,7 @@ module ScopedSearch
158
158
  if (f[1].key_field)
159
159
  keywords += complete_key(f[0], f[1], tokens.last)
160
160
  else
161
- keywords << f[0].to_s+' '
161
+ keywords << f[0].to_s + ' '
162
162
  end
163
163
  end
164
164
  keywords.sort
@@ -182,11 +182,11 @@ module ScopedSearch
182
182
  # this method auto-completes values of fields that have a :complete_value marker
183
183
  def complete_value
184
184
  if last_token_is(COMPARISON_OPERATORS)
185
- token = tokens[tokens.size-2]
185
+ token = tokens[tokens.size - 2]
186
186
  val = ''
187
187
  else
188
- token = tokens[tokens.size-3]
189
- val = tokens[tokens.size-1]
188
+ token = tokens[tokens.size - 3]
189
+ val = tokens[tokens.size - 1]
190
190
  end
191
191
 
192
192
  field = definition.field_by_name(token)
@@ -234,13 +234,14 @@ module ScopedSearch
234
234
 
235
235
  # Registers the search_for named scope within the class that is used for searching.
236
236
  def register_named_scope! # :nodoc
237
+ definition = self
237
238
  if @klass.ancestors.include?(ActiveRecord::Base)
238
239
  case ActiveRecord::VERSION::MAJOR
239
240
  when 2
240
- @klass.named_scope(:search_for, lambda { |*args| ScopedSearch::QueryBuilder.build_query(self, args[0], args[1]) })
241
+ @klass.named_scope(:search_for, lambda { |*args| ScopedSearch::QueryBuilder.build_query(definition, args[0], args[1]) })
241
242
  when 3
242
243
  @klass.scope(:search_for, lambda { |*args|
243
- find_options = ScopedSearch::QueryBuilder.build_query(self, args[0], args[1])
244
+ find_options = ScopedSearch::QueryBuilder.build_query(definition, args[0], args[1])
244
245
  search_scope = @klass.scoped
245
246
  search_scope = search_scope.where(find_options[:conditions]) if find_options[:conditions]
246
247
  search_scope = search_scope.includes(find_options[:include]) if find_options[:include]
@@ -250,7 +251,7 @@ module ScopedSearch
250
251
  })
251
252
  when 4
252
253
  @klass.scope(:search_for, lambda { |*args|
253
- find_options = ScopedSearch::QueryBuilder.build_query(self, args[0], args[1])
254
+ find_options = ScopedSearch::QueryBuilder.build_query(definition, args[0], args[1])
254
255
  search_scope = @klass.all
255
256
  search_scope = search_scope.where(find_options[:conditions]) if find_options[:conditions]
256
257
  search_scope = search_scope.includes(find_options[:include]) if find_options[:include]
@@ -269,11 +270,13 @@ module ScopedSearch
269
270
 
270
271
  # Registers the complete_for method within the class that is used for searching.
271
272
  def register_complete_for! # :nodoc
272
- @klass.class_eval do
273
- def self.complete_for(query, options = {})
274
- ScopedSearch::AutoCompleteBuilder.auto_complete(@scoped_search , query, options)
275
- end
276
- end
273
+ @klass.extend(ScopedSearch::AutoCompleteClassMethods)
274
+ end
275
+ end
276
+
277
+ module AutoCompleteClassMethods
278
+ def complete_for(query, options = {})
279
+ ScopedSearch::AutoCompleteBuilder.auto_complete(scoped_search_definition, query, options)
277
280
  end
278
281
  end
279
282
  end
@@ -89,19 +89,20 @@ module ScopedSearch
89
89
  def order_by(order, &block)
90
90
  order ||= definition.default_order
91
91
  return nil if order.blank?
92
- field = definition.field_by_name(order.to_s.split(' ')[0])
93
- raise ScopedSearch::QueryNotSupported, "the field '#{order.to_s.split(' ')[0]}' in the order statement is not valid field for search" unless field
92
+ field_name, direction_name = order.to_s.split(/\s+/, 2)
93
+ field = definition.field_by_name(field_name)
94
+ raise ScopedSearch::QueryNotSupported, "the field '#{field_name}' in the order statement is not valid field for search" unless field
94
95
  sql = field.to_sql(&block)
95
- direction = (order.to_s.downcase.include?('desc')) ? " DESC" : " ASC"
96
+ direction = (!direction_name.nil? && direction_name.downcase.eql?('desc')) ? " DESC" : " ASC"
96
97
  order = sql + direction
97
98
 
98
99
  return order
99
100
  end
100
101
 
101
102
  # A hash that maps the operators of the query language with the corresponding SQL operator.
102
- SQL_OPERATORS = { :eq =>'=', :ne => '<>', :like => 'LIKE', :unlike => 'NOT LIKE',
103
- :gt => '>', :lt =>'<', :lte => '<=', :gte => '>=',
104
- :in => 'IN',:notin => 'NOT IN' }
103
+ SQL_OPERATORS = { :eq => '=', :ne => '<>', :like => 'LIKE', :unlike => 'NOT LIKE',
104
+ :gt => '>', :lt =>'<', :lte => '<=', :gte => '>=',
105
+ :in => 'IN', :notin => 'NOT IN' }
105
106
 
106
107
  # Return the SQL operator to use given an operator symbol and field definition.
107
108
  #
@@ -223,13 +224,14 @@ module ScopedSearch
223
224
  elsif field.definition.klass.reflections[field.relation].try(:macro) == :has_many
224
225
  value = value.to_i if field.offset
225
226
  yield(:parameter, value)
226
- primary_key = "#{field.definition.klass.quoted_table_name}.#{field.definition.klass.primary_key}"
227
+ connection = field.definition.klass.connection
228
+ primary_key = "#{connection.quote_table_name(field.definition.klass.table_name)}.#{connection.quote_column_name(field.definition.klass.primary_key)}"
227
229
  if field.definition.klass.reflections[field.relation].options.has_key?(:through)
228
230
  join = has_many_through_join(field)
229
231
  return "#{primary_key} IN (SELECT #{primary_key} FROM #{join} WHERE #{field.to_sql(operator, &block)} #{self.sql_operator(operator, field)} ? )"
230
232
  else
231
- foreign_key = field.reflection_keys(field.definition.klass.reflections[field.relation])[1]
232
- return "#{primary_key} IN (SELECT #{foreign_key} FROM #{field.klass.quoted_table_name} WHERE #{field.to_sql(operator, &block)} #{self.sql_operator(operator, field)} ? )"
233
+ foreign_key = connection.quote_column_name(field.reflection_keys(field.definition.klass.reflections[field.relation])[1])
234
+ return "#{primary_key} IN (SELECT #{foreign_key} FROM #{connection.quote_table_name(field.klass.table_name)} WHERE #{field.to_sql(operator, &block)} #{self.sql_operator(operator, field)} ? )"
233
235
  end
234
236
  else
235
237
  value = value.to_i if field.offset
@@ -241,23 +243,27 @@ module ScopedSearch
241
243
  def has_many_through_join(field)
242
244
  many_class = field.definition.klass
243
245
  through = many_class.reflections[field.relation].options[:through]
244
- #table names
246
+ connection = many_class.connection
247
+
248
+ # table names
245
249
  endpoint_table_name = field.klass.table_name
246
250
  many_table_name = many_class.table_name
247
251
  middle_table_name = many_class.reflections[through].klass.table_name
248
- #primary and foreign keys + optional condition for the many to middle join
252
+
253
+ # primary and foreign keys + optional condition for the many to middle join
249
254
  pk1, fk1 = field.reflection_keys(many_class.reflections[through])
250
255
  condition1 = field.reflection_conditions(field.klass.reflections[many_table_name.to_sym])
251
- #primary and foreign keys + optional condition for the endpoint to middle join
256
+
257
+ # primary and foreign keys + optional condition for the endpoint to middle join
252
258
  pk2, fk2 = field.reflection_keys(field.klass.reflections[middle_table_name.to_sym])
253
259
  condition2 = field.reflection_conditions(many_class.reflections[field.relation])
254
260
 
255
261
  <<-SQL
256
- #{many_table_name}
257
- INNER JOIN #{middle_table_name}
258
- ON #{many_table_name}.#{pk1} = #{middle_table_name}.#{fk1} #{condition1}
259
- INNER JOIN #{endpoint_table_name}
260
- ON #{middle_table_name}.#{fk2} = #{endpoint_table_name}.#{pk2} #{condition2}
262
+ #{connection.quote_table_name(many_table_name)}
263
+ INNER JOIN #{connection.quote_table_name(middle_table_name)}
264
+ ON #{connection.quote_table_name(many_table_name)}.#{connection.quote_column_name(pk1)} = #{connection.quote_table_name(middle_table_name)}.#{connection.quote_column_name(fk1)} #{condition1}
265
+ INNER JOIN #{connection.quote_table_name(endpoint_table_name)}
266
+ ON #{connection.quote_table_name(middle_table_name)}.#{connection.quote_column_name(fk2)} = #{connection.quote_table_name(endpoint_table_name)}.#{connection.quote_column_name(pk2)} #{condition2}
261
267
  SQL
262
268
  end
263
269
 
@@ -277,13 +283,13 @@ module ScopedSearch
277
283
  if key_relation
278
284
  yield(:joins, construct_join_sql(key_relation, num) )
279
285
  yield(:keycondition, "#{key_klass.table_name}_#{num}.#{connection.quote_column_name(key_field.to_s)} = ?")
280
- klass_table_name = relation ? "#{klass.table_name}_#{num}" : connection.quote_table_name(klass.table_name)
281
- return "#{klass_table_name}.#{connection.quote_column_name(field.to_s)}"
286
+ klass_table_name = relation ? "#{klass.table_name}_#{num}" : klass.table_name
287
+ return "#{connection.quote_table_name(klass_table_name)}.#{connection.quote_column_name(field.to_s)}"
282
288
  elsif key_field
283
289
  yield(:joins, construct_simple_join_sql(num))
284
290
  yield(:keycondition, "#{key_klass.table_name}_#{num}.#{connection.quote_column_name(key_field.to_s)} = ?")
285
- klass_table_name = relation ? "#{klass.table_name}_#{num}" : connection.quote_table_name(klass.table_name)
286
- return "#{klass_table_name}.#{connection.quote_column_name(field.to_s)}"
291
+ klass_table_name = relation ? "#{klass.table_name}_#{num}" : klass.table_name
292
+ return "#{connection.quote_table_name(klass_table_name)}.#{connection.quote_column_name(field.to_s)}"
287
293
  elsif relation
288
294
  yield(:include, relation)
289
295
  end
@@ -340,7 +346,7 @@ module ScopedSearch
340
346
  main_table = definition.klass.table_name
341
347
  main_table_pk, value_table_fk_main = reflection_keys(definition.klass.reflections[relation])
342
348
 
343
- join_sql = "\n INNER JOIN #{connection.quote_table_name(key_value_table)} #{key_value_table}_#{num} ON (#{connection.quote_table_name(main_table)}.#{main_table_pk} = #{key_value_table}_#{num}.#{value_table_fk_main})"
349
+ join_sql = "\n INNER JOIN #{connection.quote_table_name(key_value_table)} #{key_value_table}_#{num} ON (#{connection.quote_table_name(main_table)}.#{connection.quote_column_name(main_table_pk)} = #{key_value_table}_#{num}.#{connection.quote_column_name(value_table_fk_main)})"
344
350
  return join_sql
345
351
  end
346
352
 
@@ -7,11 +7,13 @@ module ScopedSearch
7
7
  #
8
8
  # sort @search, :by => :username
9
9
  # sort @search, :by => :created_at, :as => "Created"
10
+ # sort @search, :by => :created_at, :default => "DESC"
10
11
  #
11
12
  # This helper accepts the following options:
12
13
  #
13
14
  # * <tt>:by</tt> - the name of the named scope. This helper will prepend this value with "ascend_by_" and "descend_by_"
14
15
  # * <tt>:as</tt> - the text used in the link, defaults to whatever is passed to :by
16
+ # * <tt>:default</tt> - default sorting order, DESC or ASC
15
17
  def sort(field, options = {}, html_options = {})
16
18
 
17
19
  unless options[:as]
@@ -21,14 +23,20 @@ module ScopedSearch
21
23
 
22
24
  ascend = "#{field} ASC"
23
25
  descend = "#{field} DESC"
24
-
25
- ascending = params[:order] == ascend
26
- new_sort = ascending ? descend : ascend
27
26
  selected = [ascend, descend].include?(params[:order])
28
27
 
28
+ case params[:order]
29
+ when ascend
30
+ new_sort = descend
31
+ when descend
32
+ new_sort = ascend
33
+ else
34
+ new_sort = ["ASC", "DESC"].include?(options[:default]) ? "#{field} #{options[:default]}" : ascend
35
+ end
36
+
29
37
  if selected
30
38
  css_classes = html_options[:class] ? html_options[:class].split(" ") : []
31
- if ascending
39
+ if new_sort == ascend
32
40
  options[:as] = "&#9650;&nbsp;#{options[:as]}"
33
41
  css_classes << "ascending"
34
42
  else
@@ -1,3 +1,3 @@
1
1
  module ScopedSearch
2
- VERSION = "2.6.5"
2
+ VERSION = "2.7.0"
3
3
  end
@@ -1,15 +1,15 @@
1
1
  sqlite:
2
- adapter: "jdbcsqlite3"
2
+ adapter: jdbcsqlite3
3
3
  database: ":memory:"
4
4
 
5
5
  mysql:
6
- adapter: "jdbcmysql"
7
- host: "localhost"
8
- username: "root"
9
- database: "scoped_search_test"
6
+ adapter: jdbcmysql
7
+ host: localhost
8
+ username: root
9
+ database: scoped_search_test
10
10
 
11
11
  postgresql:
12
- adapter: "jdbcpostgresql"
13
- host: "localhost"
14
- username: "postgres"
15
- database: "scoped_search_test"
12
+ adapter: jdbcpostgresql
13
+ host: localhost
14
+ username: postgres
15
+ database: scoped_search_test
@@ -1,16 +1,18 @@
1
1
  sqlite:
2
- adapter: "sqlite3"
2
+ adapter: sqlite3
3
3
  database: ":memory:"
4
4
 
5
- # mysql:
6
- # adapter: "mysql2"
7
- # host: "127.0.0.1"
8
- # port: 13306
9
- # username: "root"
10
- # database: "scoped_search_test"
5
+ mysql:
6
+ adapter: mysql2
7
+ host: localhost
8
+ port: 3306
9
+ username: root
10
+ database: scoped_search_test
11
+ encoding: utf8
11
12
 
12
- # postgresql:
13
- # adapter: "postgresql"
14
- # host: "127.0.0.1"
15
- # port: 5432
16
- # database: "scoped_search_test"
13
+ postgresql:
14
+ adapter: postgresql
15
+ host: localhost
16
+ username: postgres
17
+ port: 5432
18
+ database: scoped_search_test
@@ -38,6 +38,9 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
38
38
  scoped_search :on => :related, :in => :bars, :rename => 'bars.related'.to_sym
39
39
  end
40
40
 
41
+ class ::Infoo < ::Foo
42
+ end
43
+
41
44
  @foo_1 = Foo.create!(:string => 'foo', :another => 'temp 1', :explicit => 'baz', :int => 9 , :date => 'February 8, 2011' , :unindexed => 10)
42
45
  Foo.create!(:string => 'bar', :another => 'temp 2', :explicit => 'baz', :int => 9 , :date => 'February 10, 2011', :unindexed => 10)
43
46
  Foo.create!(:string => 'baz', :another => nil, :explicit => nil , :int => nil, :date => nil , :unindexed => nil)
@@ -52,6 +55,7 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
52
55
 
53
56
  Object.send :remove_const, :Foo
54
57
  Object.send :remove_const, :Bar
58
+ Object.send :remove_const, :Infoo
55
59
 
56
60
  ScopedSearch::RSpec::Database.close_connection
57
61
  end
@@ -104,7 +108,12 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
104
108
  it "should not contain deprecated field in autocompleter" do
105
109
  Foo.complete_for(' ').should_not contain(" deprecated")
106
110
  end
111
+ end
107
112
 
113
+ context 'inherited auto completer' do
114
+ it "should complete the field name" do
115
+ Infoo.complete_for('str').should =~ ([' string '])
116
+ end
108
117
  end
109
118
 
110
119
  context 'using an aliased field' do
@@ -14,6 +14,26 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
14
14
  ScopedSearch::RSpec::Database.close_connection
15
15
  end
16
16
 
17
+ context 'querying a subclass' do
18
+ before do
19
+ ActiveRecord::Migration.create_table(:supers) { |t| t.string :name }
20
+ class Super < ActiveRecord::Base
21
+ scoped_search :on => :name
22
+ end
23
+ class Sub < Super; end
24
+
25
+ @super_record = Super.create!(:name => 'test')
26
+ end
27
+
28
+ after do
29
+ ScopedSearch::RSpec::Database.drop_model(Super)
30
+ end
31
+
32
+ it "should find records when searching the subclass" do
33
+ Sub.search_for('test').should have(1).item
34
+ end
35
+ end
36
+
17
37
  context 'querying a :belongs_to relation' do
18
38
 
19
39
  before do
@@ -9,15 +9,21 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
9
9
  before(:all) do
10
10
  ScopedSearch::RSpec::Database.establish_named_connection(db)
11
11
 
12
- @class = ScopedSearch::RSpec::Database.create_model(:string => :string, :another => :string, :explicit => :string) do |klass|
12
+ @class = ScopedSearch::RSpec::Database.create_model(
13
+ :string => :string,
14
+ :another => :string,
15
+ :explicit => :string,
16
+ :description => :string
17
+ ) do |klass|
13
18
  klass.scoped_search :on => :string
14
19
  klass.scoped_search :on => :another, :default_operator => :eq, :alias => :alias, :default_order => :desc
15
20
  klass.scoped_search :on => :explicit, :only_explicit => true
21
+ klass.scoped_search :on => :description
16
22
  end
17
23
 
18
- @class.create!(:string => 'foo', :another => 'temp 1', :explicit => 'baz')
19
- @class.create!(:string => 'bar', :another => 'temp 2', :explicit => 'baz')
20
- @class.create!(:string => 'baz', :another => nil, :explicit => nil)
24
+ @class.create!(:string => 'foo', :another => 'temp 1', :explicit => 'baz', :description => '1 - one')
25
+ @class.create!(:string => 'bar', :another => 'temp 2', :explicit => 'baz', :description => '2 - two')
26
+ @class.create!(:string => 'baz', :another => nil, :explicit => nil, :description => '3 - three')
21
27
  end
22
28
 
23
29
  after(:all) do
@@ -202,7 +208,15 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
202
208
  @class.search_for('',:order => 'string DESC').first.string.should eql('foo')
203
209
  end
204
210
 
205
- it "default order by another DESC" do
211
+ it "sort by description ASC" do
212
+ @class.search_for('',:order => 'description ASC').first.description.should eql('1 - one')
213
+ end
214
+
215
+ it "sort by description DESC" do
216
+ @class.search_for('',:order => 'description DESC').first.description.should eql('3 - three')
217
+ end
218
+
219
+ it "default order by another DESC" do
206
220
  @class.search_for('').first.string.should eql('bar')
207
221
  end
208
222
 
@@ -212,6 +226,10 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
212
226
 
213
227
  Set.new(distinct_search.map(&:explicit)).should == Set['baz', nil]
214
228
  end
229
+
230
+ it 'should order using symbol' do
231
+ @class.search_for('',:order => :string).first.string.should eql('bar')
232
+ end
215
233
  end
216
234
  end
217
235
  end
@@ -0,0 +1,73 @@
1
+ require "spec_helper"
2
+ require "scoped_search/rails_helper"
3
+
4
+ module ActionViewHelperStubs
5
+ def html_escape(str)
6
+ str
7
+ end
8
+
9
+ def tag_options(options)
10
+ ""
11
+ end
12
+ end
13
+
14
+ describe ScopedSearch::RailsHelper do
15
+ include ScopedSearch::RailsHelper
16
+ include ActionViewHelperStubs
17
+
18
+ let(:params) { HashWithIndifferentAccess.new(:controller => "resources", :action => "search") }
19
+
20
+ it "should generate a link with the order param set" do
21
+ should_receive(:url_for).with(
22
+ "controller" => "resources",
23
+ "action" => "search",
24
+ "order" => "field ASC"
25
+ ).and_return("/example")
26
+
27
+ sort("field")
28
+ end
29
+
30
+ it "should generate a link with order param set to alternative default sorting order" do
31
+ should_receive(:url_for).with(
32
+ "controller" => "resources",
33
+ "action" => "search",
34
+ "order" => "field DESC"
35
+ ).and_return("/example")
36
+
37
+ sort("field", :default => "DESC")
38
+ end
39
+
40
+ it "should generate a link with the order param inverted" do
41
+ should_receive(:url_for).with(
42
+ "controller" => "resources",
43
+ "action" => "search",
44
+ "order" => "field DESC"
45
+ ).and_return("/example")
46
+
47
+ params[:order] = "field ASC"
48
+ sort("field")
49
+ end
50
+
51
+ it "should generate a link with other parameters retained" do
52
+ should_receive(:url_for).with(
53
+ "controller" => "resources",
54
+ "action" => "search",
55
+ "walrus" => "unicorns",
56
+ "order" => "field ASC"
57
+ ).and_return("/example")
58
+
59
+ params[:walrus] = "unicorns"
60
+ sort("field")
61
+ end
62
+
63
+ it "should replace the current sorting order" do
64
+ should_receive(:url_for).with(
65
+ "controller" => "resources",
66
+ "action" => "search",
67
+ "order" => "other ASC"
68
+ ).and_return("/example")
69
+
70
+ params[:order] = "field ASC"
71
+ sort("other")
72
+ end
73
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scoped_search
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.5
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amos Benari
@@ -10,48 +10,48 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-03-10 00:00:00.000000000 Z
13
+ date: 2014-03-22 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  requirements:
19
- - - '>='
19
+ - - ">="
20
20
  - !ruby/object:Gem::Version
21
21
  version: 2.1.0
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
- - - '>='
26
+ - - ">="
27
27
  - !ruby/object:Gem::Version
28
28
  version: 2.1.0
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: rspec
31
31
  requirement: !ruby/object:Gem::Requirement
32
32
  requirements:
33
- - - ~>
33
+ - - "~>"
34
34
  - !ruby/object:Gem::Version
35
35
  version: '2.0'
36
36
  type: :development
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
39
39
  requirements:
40
- - - ~>
40
+ - - "~>"
41
41
  - !ruby/object:Gem::Version
42
42
  version: '2.0'
43
43
  - !ruby/object:Gem::Dependency
44
44
  name: rake
45
45
  requirement: !ruby/object:Gem::Requirement
46
46
  requirements:
47
- - - '>='
47
+ - - ">="
48
48
  - !ruby/object:Gem::Version
49
49
  version: '0'
50
50
  type: :development
51
51
  prerelease: false
52
52
  version_requirements: !ruby/object:Gem::Requirement
53
53
  requirements:
54
- - - '>='
54
+ - - ">="
55
55
  - !ruby/object:Gem::Version
56
56
  version: '0'
57
57
  description: " Scoped search makes it easy to search your ActiveRecord-based models.\n
@@ -74,8 +74,8 @@ extensions: []
74
74
  extra_rdoc_files:
75
75
  - README.rdoc
76
76
  files:
77
- - .gitignore
78
- - .travis.yml
77
+ - ".gitignore"
78
+ - ".travis.yml"
79
79
  - Gemfile
80
80
  - Gemfile.activerecord2
81
81
  - Gemfile.activerecord3
@@ -120,33 +120,34 @@ files:
120
120
  - spec/unit/definition_spec.rb
121
121
  - spec/unit/parser_spec.rb
122
122
  - spec/unit/query_builder_spec.rb
123
+ - spec/unit/rails_helper_spec.rb
123
124
  - spec/unit/tokenizer_spec.rb
124
125
  homepage: https://github.com/wvanbergen/scoped_search/wiki
125
126
  licenses: []
126
127
  metadata: {}
127
128
  post_install_message:
128
129
  rdoc_options:
129
- - --title
130
+ - "--title"
130
131
  - scoped_search
131
- - --main
132
+ - "--main"
132
133
  - README.rdoc
133
- - --line-numbers
134
- - --inline-source
134
+ - "--line-numbers"
135
+ - "--inline-source"
135
136
  require_paths:
136
137
  - lib
137
138
  required_ruby_version: !ruby/object:Gem::Requirement
138
139
  requirements:
139
- - - '>='
140
+ - - ">="
140
141
  - !ruby/object:Gem::Version
141
142
  version: '0'
142
143
  required_rubygems_version: !ruby/object:Gem::Requirement
143
144
  requirements:
144
- - - '>='
145
+ - - ">="
145
146
  - !ruby/object:Gem::Version
146
147
  version: '0'
147
148
  requirements: []
148
149
  rubyforge_project:
149
- rubygems_version: 2.0.3
150
+ rubygems_version: 2.2.2
150
151
  signing_key:
151
152
  specification_version: 4
152
153
  summary: Easily search you ActiveRecord models with a simple query language using
@@ -171,4 +172,5 @@ test_files:
171
172
  - spec/unit/definition_spec.rb
172
173
  - spec/unit/parser_spec.rb
173
174
  - spec/unit/query_builder_spec.rb
175
+ - spec/unit/rails_helper_spec.rb
174
176
  - spec/unit/tokenizer_spec.rb