scoped_search 2.3.7 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,28 @@
1
+ language: ruby
2
+ script: bundle exec rake
3
+ before_script:
4
+ - psql -c 'create database scoped_search_test;' -U postgres
5
+ - mysql -e 'create database scoped_search_test;'
6
+ rvm:
7
+ - 1.8.7
8
+ - 1.9.2
9
+ - 1.9.3
10
+ - ruby-head
11
+ - ree
12
+ - jruby-18mode
13
+ - jruby-19mode
14
+ - jruby-head
15
+ gemfile:
16
+ - Gemfile.activerecord2
17
+ - Gemfile.activerecord3
18
+ matrix:
19
+ allow_failures:
20
+ - rvm: ruby-head
21
+ - rvm: jruby-head
22
+ exclude:
23
+ - rvm: jruby-18mode
24
+ gemfile: Gemfile.activerecord2
25
+ - rvm: jruby-19mode
26
+ gemfile: Gemfile.activerecord2
27
+ - rvm: jruby-head
28
+ gemfile: Gemfile.activerecord2
data/Gemfile CHANGED
@@ -1,15 +1,16 @@
1
1
  source :rubygems
2
2
  gemspec
3
3
 
4
- # ScopedSearch is always tested on a sqlite3 memory database.
5
- # Uncomment the following gems to test scoped search on other RDBMSs.
6
- # You can specify the databasde connection details in spec/database.yml
4
+ gem 'activerecord'
7
5
 
8
- gem 'mysql2', '~> 0.2.6' # preferred over 'mysql'
9
- #gem 'mysql'
10
- # gem 'postgresql'
6
+ platforms :jruby do
7
+ gem 'activerecord-jdbcsqlite3-adapter'
8
+ gem 'activerecord-jdbcmysql-adapter'
9
+ gem 'activerecord-jdbcpostgresql-adapter'
10
+ end
11
11
 
12
- # # JDBC connections
13
- # gem 'activerecord-jdbcsqlite3-adapter'
14
- # gem 'activerecord-jdbcmysql-adapter'
15
- # gem 'activerecord-jdbcpostgresql-adapter'
12
+ platforms :ruby do
13
+ gem 'sqlite3'
14
+ gem 'mysql2'
15
+ gem 'pg'
16
+ end
@@ -0,0 +1,16 @@
1
+ source :rubygems
2
+ gemspec
3
+
4
+ gem 'activerecord', '~> 2'
5
+
6
+ platforms :jruby do
7
+ gem 'activerecord-jdbcsqlite3-adapter'
8
+ gem 'activerecord-jdbcmysql-adapter'
9
+ gem 'activerecord-jdbcpostgresql-adapter'
10
+ end
11
+
12
+ platforms :ruby do
13
+ gem 'sqlite3'
14
+ gem 'mysql2', '~> 0.2.6'
15
+ gem 'pg'
16
+ end
@@ -0,0 +1,16 @@
1
+ source :rubygems
2
+ gemspec
3
+
4
+ gem 'activerecord', '~> 3'
5
+
6
+ platforms :jruby do
7
+ gem 'activerecord-jdbcsqlite3-adapter'
8
+ gem 'activerecord-jdbcmysql-adapter'
9
+ gem 'activerecord-jdbcpostgresql-adapter'
10
+ end
11
+
12
+ platforms :ruby do
13
+ gem 'sqlite3'
14
+ gem 'mysql2', '~> 0.3.11'
15
+ gem 'pg'
16
+ end
data/README.rdoc CHANGED
@@ -124,6 +124,8 @@ For more info, see the the project wiki: http://github.com/wvanbergen/scoped_sea
124
124
 
125
125
  == License
126
126
 
127
- This plugin is released under the MIT license. Please contact weshays
128
- (http://github.com/weshays) or wvanbergen (http://github.com/wvanbergen) for any
129
- questions.
127
+ This plugin is released under the MIT license (see LICENSE).
128
+
129
+ This plugin was originally developed for Floorplanner.com by Willem van Bergen
130
+ (https://github.com/wvanbergen) with help from Wes Hays (https://github.com/weshays).
131
+ The current maintainer is Amos Benari (https://github.com/abenari).
data/lib/scoped_search.rb CHANGED
@@ -14,7 +14,7 @@ module ScopedSearch
14
14
 
15
15
  # The current scoped_search version. Do not change thisvalue by hand,
16
16
  # because it will be updated automatically by the gem release script.
17
- VERSION = "2.3.7"
17
+ VERSION = "2.4.0"
18
18
 
19
19
  # The ClassMethods module will be included into the ActiveRecord::Base class
20
20
  # to add the <tt>ActiveRecord::Base.scoped_search</tt> method and the
@@ -168,9 +168,12 @@ module ScopedSearch
168
168
  return ["#{name}."] if !val || !val.is_a?(String) || !(val.include?('.'))
169
169
  val = val.sub(/.*\./,'')
170
170
 
171
- table = field.key_klass.connection.quote_table_name(field.key_klass.table_name)
172
- field_name = "#{table}.#{field.key_field}"
173
- opts = value_conditions(field_name, val).merge(:limit => 20, :select => field_name, :group => field_name )
171
+ connection = definition.klass.connection
172
+ quoted_table = field.key_klass.connection.quote_table_name(field.key_klass.table_name)
173
+ quoted_field = field.key_klass.connection.quote_column_name(field.key_field)
174
+ field_name = "#{quoted_table}.#{quoted_field}"
175
+ select_clause = "DISTINCT #{field_name}"
176
+ opts = value_conditions(field_name, val).merge(:select => select_clause, :limit => 20)
174
177
 
175
178
  field.key_klass.all(opts).map(&field.key_field).compact.map{ |f| "#{name}.#{f} "}
176
179
  end
@@ -15,12 +15,49 @@ module ScopedSearch
15
15
  # class, so you should not create instances of this class yourself.
16
16
  class Field
17
17
 
18
- attr_reader :definition, :field, :only_explicit, :relation, :key_relation,
18
+ attr_reader :definition, :field, :only_explicit, :relation, :key_relation, :full_text_search,
19
19
  :key_field, :complete_value, :offset, :word_size, :ext_method, :operators
20
20
 
21
+ # Initializes a Field instance given the definition passed to the
22
+ # scoped_search call on the ActiveRecord-based model class.
23
+ def initialize(definition, options = {})
24
+ @definition = definition
25
+ @definition.profile = options[:profile] if options[:profile]
26
+ @definition.default_order ||= default_order(options)
27
+
28
+ case options
29
+ when Symbol, String
30
+ @field = field.to_sym
31
+ when Hash
32
+ @field = options.delete(:on)
33
+
34
+ # Set attributes from options hash
35
+ @complete_value = options[:complete_value]
36
+ @relation = options[:in]
37
+ @key_relation = options[:in_key]
38
+ @key_field = options[:on_key]
39
+ @offset = options[:offset]
40
+ @word_size = options[:word_size] || 1
41
+ @ext_method = options[:ext_method]
42
+ @operators = options[:operators]
43
+ @only_explicit = !!options[:only_explicit]
44
+ @full_text_search = options[:full_text_search]
45
+ @default_operator = options[:default_operator] if options.has_key?(:default_operator)
46
+ end
47
+
48
+ # Store this field is the field array
49
+ definition.fields[@field] ||= self unless options[:rename]
50
+ definition.fields[options[:rename].to_sym] ||= self if options[:rename]
51
+ definition.unique_fields << self
52
+
53
+ # Store definition for alias / aliases as well
54
+ definition.fields[options[:alias].to_sym] ||= self if options[:alias]
55
+ options[:aliases].each { |al| definition.fields[al.to_sym] ||= self } if options[:aliases]
56
+ end
57
+
21
58
  # The ActiveRecord-based class that belongs to this field.
22
59
  def klass
23
- if relation
60
+ @klass ||= if relation
24
61
  related = definition.klass.reflections[relation]
25
62
  raise ScopedSearch::QueryNotSupported, "relation '#{relation}' not one of #{definition.klass.reflections.keys.join(', ')} " if related.nil?
26
63
  related.klass
@@ -28,9 +65,10 @@ module ScopedSearch
28
65
  definition.klass
29
66
  end
30
67
  end
68
+
31
69
  # The ActiveRecord-based class that belongs the key field in a key-value pair.
32
70
  def key_klass
33
- if key_relation
71
+ @key_klass ||= if key_relation
34
72
  definition.klass.reflections[key_relation].klass
35
73
  elsif relation
36
74
  definition.klass.reflections[relation].klass
@@ -41,12 +79,18 @@ module ScopedSearch
41
79
 
42
80
  # Returns the ActiveRecord column definition that corresponds to this field.
43
81
  def column
44
- klass.columns_hash[field.to_s]
82
+ @column ||= begin
83
+ if klass.columns_hash.has_key?(field.to_s)
84
+ klass.columns_hash[field.to_s]
85
+ else
86
+ raise ActiveRecord::UnknownAttributeError, "#{klass.inspect} doesn't have column #{field.inspect}."
87
+ end
88
+ end
45
89
  end
46
90
 
47
91
  # Returns the column type of this field.
48
92
  def type
49
- column.type
93
+ @type ||= column.type
50
94
  end
51
95
 
52
96
  # Returns true if this field is a datetime-like column
@@ -95,41 +139,6 @@ module ScopedSearch
95
139
  order = (options[:default_order].to_s.downcase.include?('desc')) ? "DESC" : "ASC"
96
140
  return "#{field_name} #{order}"
97
141
  end
98
- # Initializes a Field instance given the definition passed to the
99
- # scoped_search call on the ActiveRecord-based model class.
100
- def initialize(definition, options = {})
101
- @definition = definition
102
- @definition.profile = options[:profile] if options[:profile]
103
- @definition.default_order ||= default_order(options)
104
-
105
- case options
106
- when Symbol, String
107
- @field = field.to_sym
108
- when Hash
109
- @field = options.delete(:on)
110
-
111
- # Set attributes from options hash
112
- @complete_value = options[:complete_value]
113
- @relation = options[:in]
114
- @key_relation = options[:in_key]
115
- @key_field = options[:on_key]
116
- @offset = options[:offset]
117
- @word_size = options[:word_size] || 1
118
- @ext_method = options[:ext_method]
119
- @operators = options[:operators]
120
- @only_explicit = !!options[:only_explicit]
121
- @default_operator = options[:default_operator] if options.has_key?(:default_operator)
122
- end
123
-
124
- # Store this field is the field array
125
- definition.fields[@field] ||= self unless options[:rename]
126
- definition.fields[options[:rename].to_sym] ||= self if options[:rename]
127
- definition.unique_fields << self
128
-
129
- # Store definition for alias / aliases as well
130
- definition.fields[options[:alias].to_sym] ||= self if options[:alias]
131
- options[:aliases].each { |al| definition.fields[al.to_sym] ||= self } if options[:aliases]
132
- end
133
142
  end
134
143
 
135
144
  attr_reader :klass
@@ -185,13 +194,15 @@ module ScopedSearch
185
194
  end
186
195
 
187
196
  NUMERICAL_REGXP = /^\-?\d+(\.\d+)?$/
197
+ INTEGER_REGXP = /^\-?\d+$/
188
198
 
189
199
  # Returns a list of appropriate fields to search in given a search keyword and operator.
190
200
  def default_fields_for(value, operator = nil)
191
201
 
192
202
  column_types = []
193
203
  column_types += [:string, :text] if [nil, :like, :unlike, :ne, :eq].include?(operator)
194
- column_types += [:integer, :double, :float, :decimal] if value =~ NUMERICAL_REGXP
204
+ column_types += [:double, :float, :decimal] if value =~ NUMERICAL_REGXP
205
+ column_types += [:integer] if value =~ INTEGER_REGXP
195
206
  column_types += [:datetime, :date, :timestamp] if (parse_temporal(value))
196
207
 
197
208
  default_fields.select { |field| column_types.include?(field.type) && !field.set? }
@@ -236,8 +247,7 @@ module ScopedSearch
236
247
  search_scope = search_scope.where(find_options[:conditions]) if find_options[:conditions]
237
248
  search_scope = search_scope.includes(find_options[:include]) if find_options[:include]
238
249
  search_scope = search_scope.joins(find_options[:joins]) if find_options[:joins]
239
- search_scope = search_scope.order(find_options[:order]) if find_options[:order]
240
- search_scope = search_scope.group(find_options[:group]) if find_options[:group]
250
+ search_scope = search_scope.reorder(find_options[:order]) if find_options[:order]
241
251
  search_scope
242
252
  })
243
253
  else
@@ -247,15 +257,14 @@ module ScopedSearch
247
257
  raise "Currently, only ActiveRecord 2.1 or higher is supported!"
248
258
  end
249
259
  end
250
- end
251
- end
252
260
 
253
- # Registers the complete_for method within the class that is used for searching.
254
- def register_complete_for! # :nodoc
255
- @klass.class_eval do
256
- def self.complete_for (query, options = {})
257
- search_options = ScopedSearch::AutoCompleteBuilder.auto_complete(@scoped_search , query, options)
258
- search_options
261
+ # Registers the complete_for method within the class that is used for searching.
262
+ def register_complete_for! # :nodoc
263
+ @klass.class_eval do
264
+ def self.complete_for(query, options = {})
265
+ ScopedSearch::AutoCompleteBuilder.auto_complete(@scoped_search , query, options)
266
+ end
267
+ end
259
268
  end
260
269
  end
261
- end
270
+ end
@@ -81,7 +81,6 @@ module ScopedSearch
81
81
  find_attributes[:include] = includes.uniq unless includes.empty?
82
82
  find_attributes[:joins] = joins.uniq unless joins.empty?
83
83
  find_attributes[:order] = order unless order.nil?
84
- find_attributes[:group] = options[:group] unless options[:group].nil?
85
84
 
86
85
  # p find_attributes # Uncomment for debugging
87
86
  return find_attributes
@@ -89,13 +88,13 @@ module ScopedSearch
89
88
 
90
89
  def order_by(order, &block)
91
90
  order ||= definition.default_order
92
- if order
93
- field = definition.field_by_name(order.to_s.split(' ')[0])
94
- raise ScopedSearch::QueryNotSupported, "the field '#{order.to_s.split(' ')[0]}' in the order statement is not valid field for search" unless field
95
- sql = field.to_sql(&block)
96
- direction = (order.to_s.downcase.include?('desc')) ? " DESC" : " ASC"
97
- order = sql + direction
98
- end
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
94
+ sql = field.to_sql(&block)
95
+ direction = (order.to_s.downcase.include?('desc')) ? " DESC" : " ASC"
96
+ order = sql + direction
97
+
99
98
  return order
100
99
  end
101
100
 
@@ -461,10 +460,25 @@ module ScopedSearch
461
460
  # <tt>ILIKE operator</tt> instead of <tt>LIKE</tt>.
462
461
  class PostgreSQLAdapter < ScopedSearch::QueryBuilder
463
462
 
464
- # Switches out the default LIKE operator for ILIKE in the default
465
- # <tt>sql_operator</tt> method.
463
+ # Switches out the default query generation of the <tt>sql_test</tt>
464
+ # method if full text searching is enabled and a text search is being
465
+ # performed.
466
+ def sql_test(field, operator, value, lhs, &block)
467
+ if [:like, :unlike].include?(operator) and field.full_text_search
468
+ yield(:parameter, value)
469
+ negation = (operator == :unlike) ? "NOT " : ""
470
+ locale = (field.full_text_search == true) ? 'english' : field.full_text_search
471
+ return "#{negation}to_tsvector('#{locale}', #{field.to_sql(operator, &block)}) #{self.sql_operator(operator, field)} to_tsquery('#{locale}', ?)"
472
+ else
473
+ super
474
+ end
475
+ end
476
+
477
+ # Switches out the default LIKE operator in the default <tt>sql_operator</tt>
478
+ # method for ILIKE or @@ if full text searching is enabled.
466
479
  def sql_operator(operator, field)
467
480
  raise ScopedSearch::QueryNotSupported, "the operator '#{operator}' is not supported for field type '#{field.type}'" if [:like, :unlike].include?(operator) and !field.textual?
481
+ return '@@' if [:like, :unlike].include?(operator) and field.full_text_search
468
482
  case operator
469
483
  when :like then 'ILIKE'
470
484
  when :unlike then 'NOT ILIKE'
@@ -476,6 +490,12 @@ module ScopedSearch
476
490
  def to_not_sql(rhs, definition, &block)
477
491
  "NOT COALESCE(#{rhs.to_sql(self, definition, &block)}, false)"
478
492
  end
493
+
494
+ def order_by(order, &block)
495
+ sql = super(order, &block)
496
+ sql += sql.include?('DESC') ? ' NULLS LAST ' : ' NULLS FIRST ' if sql
497
+ sql
498
+ end
479
499
  end
480
500
 
481
501
  # The Oracle adapter also requires some tweaks to make the case insensitive LIKE work.
@@ -3,8 +3,8 @@ Gem::Specification.new do |s|
3
3
 
4
4
  # Do not change the version and date fields by hand. This will be done
5
5
  # automatically by the gem release script.
6
- s.version = "2.3.7"
7
- s.date = "2012-04-30"
6
+ s.version = "2.4.0"
7
+ s.date = "2012-09-11"
8
8
 
9
9
  s.summary = "Easily search you ActiveRecord models with a simple query language using a named scope."
10
10
  s.description = <<-EOS
@@ -20,21 +20,19 @@ Gem::Specification.new do |s|
20
20
  it may not be the best choice if it is going to be used on very large datasets or by a large user base.
21
21
  EOS
22
22
 
23
- s.authors = ['Willem van Bergen', 'Wes Hays']
24
- s.email = ['willem@railsdoctors.com', 'weshays@gbdev.com']
23
+ s.authors = ['Amos Benari', 'Willem van Bergen', 'Wes Hays']
24
+ s.email = ['abenari@redhat.com', 'willem@railsdoctors.com', 'weshays@gbdev.com']
25
25
  s.homepage = 'http://github.com/wvanbergen/scoped_search/wiki'
26
26
 
27
27
  s.add_runtime_dependency('activerecord', '>= 2.1.0')
28
28
  s.add_development_dependency('rspec', '~> 2.0')
29
29
  s.add_development_dependency('rake')
30
-
31
- s.add_development_dependency('sqlite3-ruby')
32
30
 
33
31
  s.rdoc_options << '--title' << s.name << '--main' << 'README.rdoc' << '--line-numbers' << '--inline-source'
34
32
  s.extra_rdoc_files = ['README.rdoc']
35
33
 
36
34
  # Do not change the files and test_files fields by hand. This will be done
37
35
  # automatically by the gem release script.
38
- s.files = %w(.gitignore .infinity_test Gemfile LICENSE README.rdoc Rakefile init.rb lib/scoped_search.rb lib/scoped_search/auto_complete_builder.rb lib/scoped_search/definition.rb lib/scoped_search/query_builder.rb lib/scoped_search/query_language.rb lib/scoped_search/query_language/ast.rb lib/scoped_search/query_language/parser.rb lib/scoped_search/query_language/tokenizer.rb lib/scoped_search/rails_helper.rb scoped_search.gemspec spec/database.yml spec/integration/api_spec.rb spec/integration/auto_complete_spec.rb spec/integration/key_value_querying_spec.rb spec/integration/ordinal_querying_spec.rb spec/integration/profile_querying_spec.rb spec/integration/relation_querying_spec.rb spec/integration/set_query_spec.rb spec/integration/string_querying_spec.rb spec/lib/database.rb spec/lib/matchers.rb spec/lib/mocks.rb spec/spec_helper.rb spec/unit/ast_spec.rb spec/unit/auto_complete_builder_spec.rb spec/unit/definition_spec.rb spec/unit/parser_spec.rb spec/unit/query_builder_spec.rb spec/unit/tokenizer_spec.rb tasks/github-gem.rake)
36
+ s.files = %w(.gitignore .infinity_test .travis.yml Gemfile Gemfile.activerecord2 Gemfile.activerecord3 LICENSE README.rdoc Rakefile init.rb lib/scoped_search.rb lib/scoped_search/auto_complete_builder.rb lib/scoped_search/definition.rb lib/scoped_search/query_builder.rb lib/scoped_search/query_language.rb lib/scoped_search/query_language/ast.rb lib/scoped_search/query_language/parser.rb lib/scoped_search/query_language/tokenizer.rb lib/scoped_search/rails_helper.rb scoped_search.gemspec spec/database.jruby.yml spec/database.ruby.yml spec/integration/api_spec.rb spec/integration/auto_complete_spec.rb spec/integration/key_value_querying_spec.rb spec/integration/ordinal_querying_spec.rb spec/integration/profile_querying_spec.rb spec/integration/relation_querying_spec.rb spec/integration/set_query_spec.rb spec/integration/string_querying_spec.rb spec/lib/database.rb spec/lib/matchers.rb spec/lib/mocks.rb spec/spec_helper.rb spec/unit/ast_spec.rb spec/unit/auto_complete_builder_spec.rb spec/unit/definition_spec.rb spec/unit/parser_spec.rb spec/unit/query_builder_spec.rb spec/unit/tokenizer_spec.rb tasks/github-gem.rake)
39
37
  s.test_files = %w(spec/integration/api_spec.rb spec/integration/auto_complete_spec.rb spec/integration/key_value_querying_spec.rb spec/integration/ordinal_querying_spec.rb spec/integration/profile_querying_spec.rb spec/integration/relation_querying_spec.rb spec/integration/set_query_spec.rb spec/integration/string_querying_spec.rb spec/unit/ast_spec.rb spec/unit/auto_complete_builder_spec.rb spec/unit/definition_spec.rb spec/unit/parser_spec.rb spec/unit/query_builder_spec.rb spec/unit/tokenizer_spec.rb)
40
38
  end
@@ -0,0 +1,15 @@
1
+ sqlite:
2
+ adapter: "jdbcsqlite3"
3
+ database: ":memory:"
4
+
5
+ mysql:
6
+ adapter: "jdbcmysql"
7
+ host: "localhost"
8
+ username: "root"
9
+ database: "scoped_search_test"
10
+
11
+ postgresql:
12
+ adapter: "jdbcpostgresql"
13
+ host: "localhost"
14
+ username: "postgres"
15
+ database: "scoped_search_test"
@@ -0,0 +1,15 @@
1
+ sqlite:
2
+ adapter: "sqlite3"
3
+ database: ":memory:"
4
+
5
+ mysql:
6
+ adapter: "mysql2"
7
+ host: "localhost"
8
+ username: "root"
9
+ database: "scoped_search_test"
10
+
11
+ postgresql:
12
+ adapter: "postgresql"
13
+ host: "localhost"
14
+ username: "postgres"
15
+ database: "scoped_search_test"
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  describe ScopedSearch, "API" do
4
4
 
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  # These specs will run on all databases that are defined in the spec/database.yml file.
4
4
  # Comment out any databases that you do not have available for testing purposes if needed.
@@ -9,31 +9,48 @@ 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
- ## The related class
13
- ActiveRecord::Migration.drop_table(:bars) rescue nil
14
- ActiveRecord::Migration.create_table(:bars) { |t| t.string :related; t.integer :foo_id }
15
- class ::Bar < ActiveRecord::Base; belongs_to :foo; end
12
+ ActiveRecord::Migration.create_table(:bars, :force => true) do |t|
13
+ t.integer :foo_id
14
+ t.string :related
15
+ end
16
16
 
17
- ::Foo = ScopedSearch::RSpec::Database.create_model(:string => :string, :another => :string, :explicit => :string, :int => :integer, :date => :date, :unindexed => :integer) do |klass|
18
- klass.has_many :bars
19
-
20
- klass.scoped_search :on => [:string, :int, :date]
21
- klass.scoped_search :on => :another, :default_operator => :eq, :alias => :alias
22
- klass.scoped_search :on => :explicit, :only_explicit => true, :complete_value => true
23
- klass.scoped_search :on => :related, :in => :bars, :rename => 'bars.related'.to_sym
17
+ ActiveRecord::Migration.create_table(:foos, :force => true) do |t|
18
+ t.string :string
19
+ t.string :another
20
+ t.string :explicit
21
+ t.integer :int
22
+ t.date :date
23
+ t.integer :unindexed
24
+ end
25
+
26
+ class ::Bar < ActiveRecord::Base
27
+ belongs_to :foo
28
+ end
29
+
30
+ class ::Foo < ActiveRecord::Base
31
+ has_many :bars
24
32
 
33
+ scoped_search :on => [:string, :int, :date]
34
+ scoped_search :on => :another, :default_operator => :eq, :alias => :alias
35
+ scoped_search :on => :explicit, :only_explicit => true, :complete_value => true
36
+ scoped_search :on => :related, :in => :bars, :rename => 'bars.related'.to_sym
25
37
  end
26
38
 
27
- @foo_1 = Foo.create!(:string => 'foo', :another => 'temp 1', :explicit => 'baz', :int => 9 , :date => 'February 8, 20011' , :unindexed => 10)
28
- Foo.create!(:string => 'bar', :another => 'temp 2', :explicit => 'baz', :int => 9 , :date => 'February 10, 20011', :unindexed => 10)
39
+ @foo_1 = Foo.create!(:string => 'foo', :another => 'temp 1', :explicit => 'baz', :int => 9 , :date => 'February 8, 2011' , :unindexed => 10)
40
+ Foo.create!(:string => 'bar', :another => 'temp 2', :explicit => 'baz', :int => 9 , :date => 'February 10, 2011', :unindexed => 10)
29
41
  Foo.create!(:string => 'baz', :another => nil, :explicit => nil , :int => nil, :date => nil , :unindexed => nil)
30
42
 
31
43
  Bar.create!(:related => 'lala', :foo => @foo_1)
32
- Bar.create!(:related => 'another lala', :foo => @foo_1)
44
+ Bar.create!(:related => 'another lala', :foo => @foo_1)
33
45
  end
34
46
 
35
47
  after(:all) do
36
- ScopedSearch::RSpec::Database.drop_model(Foo)
48
+ ActiveRecord::Migration.drop_table(:foos)
49
+ ActiveRecord::Migration.drop_table(:bars)
50
+
51
+ Object.send :remove_const, :Foo
52
+ Object.send :remove_const, :Bar
53
+
37
54
  ScopedSearch::RSpec::Database.close_connection
38
55
  end
39
56
 
@@ -136,7 +153,7 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
136
153
  end
137
154
  end
138
155
 
139
- context 'exceptional search strings' do
156
+ context 'exceptional search strings' do
140
157
 
141
158
  it "query that starts with 'or'" do
142
159
  Foo.complete_for('or ').should have(9).items
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  # These specs will run on all databases that are defined in the spec/database.yml file.
4
4
  # Comment out any databases that you do not have available for testing purposes if needed.
@@ -20,72 +20,73 @@ require "#{File.dirname(__FILE__)}/../spec_helper"
20
20
  ActiveRecord::Migration.create_table(:keys) { |t| t.string :name }
21
21
  class ::Key < ActiveRecord::Base; has_many :facts; end
22
22
 
23
- ActiveRecord::Migration.create_table(:facts) { |t| t.string :value; t.integer :key_id; t.integer :bar_id }
24
- class ::Fact < ActiveRecord::Base; belongs_to :key; belongs_to :bar; end
23
+ ActiveRecord::Migration.create_table(:facts) { |t| t.string :value; t.integer :key_id; t.integer :key_value_id }
24
+ class ::Fact < ActiveRecord::Base; belongs_to :key; belongs_to :key_value; end
25
25
 
26
26
  # The class that will run the queries
27
- ::Bar = ScopedSearch::RSpec::Database.create_model(:name => :string) do |klass|
28
- klass.has_many :facts
29
- klass.has_many :keys, :through => :facts
30
- klass.scoped_search :in => :facts, :on => :value, :rename => :facts, :in_key => :keys, :on_key => :name, :complete_value => true
27
+ ActiveRecord::Migration.create_table(:key_values) { |t| t.string :name }
28
+ class ::KeyValue < ActiveRecord::Base
29
+ has_many :facts
30
+ has_many :keys, :through => :facts
31
+
32
+ scoped_search :in => :facts, :on => :value, :rename => :facts, :in_key => :keys, :on_key => :name, :complete_value => true
31
33
  end
32
34
 
33
35
  @key1 = Key.create!(:name => 'color')
34
36
  @key2 = Key.create!(:name => 'size')
35
37
 
38
+ @kv1 = KeyValue.create!(:name => 'bar')
39
+ @kv2 = KeyValue.create!(:name => 'barbary')
36
40
 
37
- @bar1 = Bar.create!(:name => 'bar')
38
- @bar2 = Bar.create!(:name => 'barbary')
39
-
40
- Fact.create!(:value => 'green', :key => @key1, :bar => @bar1)
41
- Fact.create!(:value => 'gold' , :key => @key1, :bar => @bar2)
42
- Fact.create!(:value => '5' , :key => @key2, :bar => @bar1)
41
+ Fact.create!(:value => 'green', :key => @key1, :key_value => @kv1)
42
+ Fact.create!(:value => 'gold' , :key => @key1, :key_value => @kv2)
43
+ Fact.create!(:value => '5' , :key => @key2, :key_value => @kv1)
43
44
 
44
45
  end
45
46
 
46
47
  after(:all) do
47
- ScopedSearch::RSpec::Database.drop_model(Bar)
48
+ ScopedSearch::RSpec::Database.drop_model(KeyValue)
48
49
  ScopedSearch::RSpec::Database.drop_model(Fact)
49
50
  ScopedSearch::RSpec::Database.drop_model(Key)
50
51
  Object.send :remove_const, :Fact
51
52
  Object.send :remove_const, :Key
52
- Object.send :remove_const, :Bar
53
+ Object.send :remove_const, :KeyValue
53
54
  end
54
55
 
55
56
  it "should find all bars with a fact name color and fact value green" do
56
- Bar.search_for('facts.color = green').should have(1).items
57
+ KeyValue.search_for('facts.color = green').should have(1).items
57
58
  end
58
59
 
59
60
  it "should find all bars with a fact name color and fact value gold" do
60
- Bar.search_for('facts.color = gold').first.name.should eql('barbary')
61
+ KeyValue.search_for('facts.color = gold').first.name.should eql('barbary')
61
62
  end
62
63
 
63
64
  it "should find all bars with a fact name size and fact value 5" do
64
- Bar.search_for('facts.size = 5').should have(1).items
65
+ KeyValue.search_for('facts.size = 5').should have(1).items
65
66
  end
66
67
 
67
68
  it "should find all bars with a fact color green and fact size 5" do
68
- Bar.search_for('facts.color = green and facts.size = 5').should have(1).items
69
+ KeyValue.search_for('facts.color = green and facts.size = 5').should have(1).items
69
70
  end
70
71
 
71
72
  it "should find all bars with a fact color gold or green" do
72
- Bar.search_for('facts.color = gold or facts.color = green').should have(2).items
73
+ KeyValue.search_for('facts.color = gold or facts.color = green').should have(2).items
73
74
  end
74
75
 
75
76
  it "should find all bars that has size value" do
76
- Bar.search_for('has facts.size').should have(1).items
77
+ KeyValue.search_for('has facts.size').should have(1).items
77
78
  end
78
79
 
79
80
  it "should find all bars that has color value" do
80
- Bar.search_for('has facts.color').should have(2).items
81
+ KeyValue.search_for('has facts.color').should have(2).items
81
82
  end
82
83
 
83
84
  it "should complete facts names" do
84
- Bar.complete_for('facts.').should have(2).items
85
+ KeyValue.complete_for('facts.').should have(2).items
85
86
  end
86
87
 
87
88
  it "should complete values for fact name = color" do
88
- Bar.complete_for('facts.color = ').should have(2).items
89
+ KeyValue.complete_for('facts.color = ').should have(2).items
89
90
  end
90
91
 
91
92
  end
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  # These specs will run on all databases that are defined in the spec/database.yml file.
4
4
  # Comment out any databases that you do not have available for testing purposes if needed.
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  # These specs will run on all databases that are defined in the spec/database.yml file.
4
4
  # Comment out any databases that you do not have available for testing purposes if needed.
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  # These specs will run on all databases that are defined in the spec/database.yml file.
4
4
  # Comment out any databases that you do not have available for testing purposes if needed.
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  # These specs will run on all databases that are defined in the spec/database.yml file.
4
4
  # Comment out any databases that you do not have available for testing purposes if needed.
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  # These specs will run on all databases that are defined in the spec/database.yml file.
4
4
  # Comment out any databases that you do not have available for testing purposes if needed.
@@ -192,6 +192,7 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
192
192
  @class.search_for('null? explicit').should have(1).items
193
193
  end
194
194
  end
195
+
195
196
  context 'using order' do
196
197
  it "sort by string ASC" do
197
198
  @class.search_for('',:order => 'string ASC').first.string.should eql('bar')
@@ -205,8 +206,14 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
205
206
  @class.search_for('').first.string.should eql('bar')
206
207
  end
207
208
 
208
- it "group by explicit" do
209
- @class.search_for('',:group => 'explicit').should have(2).items
209
+ it "resetting order when selecting distinct values" do
210
+ distinct_search = if ActiveRecord::VERSION::MAJOR == 2
211
+ @class.search_for('', :order => '').all(:select => 'DISTINCT(explicit)')
212
+ else
213
+ @class.search_for('', :order => '').select(:explicit).uniq
214
+ end
215
+
216
+ Set.new(distinct_search.map(&:explicit)).should == Set['baz', nil]
210
217
  end
211
218
  end
212
219
  end
data/spec/lib/database.rb CHANGED
@@ -12,12 +12,22 @@ module ScopedSearch::RSpec::Database
12
12
  end
13
13
 
14
14
  def self.test_databases_configuration
15
- file = File.expand_path("../database.yml", File.dirname(__FILE__))
16
- @database_connections ||= YAML.load(ERB.new(File.read(file)).result)
15
+ file = if RUBY_PLATFORM == 'java'
16
+ File.expand_path("../database.jruby.yml", File.dirname(__FILE__))
17
+ else
18
+ File.expand_path("../database.ruby.yml", File.dirname(__FILE__))
19
+ end
20
+
21
+ @database_connections ||= YAML.load(File.read(file))
17
22
  end
18
23
 
19
24
  def self.test_databases
20
- test_databases_configuration.keys.sort
25
+ database_names = test_databases_configuration.keys.sort
26
+ if ENV['EXCLUDE_DATABASE'].present?
27
+ exclude_databases = ENV['EXCLUDE_DATABASE'].split(',')
28
+ database_names -= exclude_databases
29
+ end
30
+ return database_names
21
31
  end
22
32
 
23
33
  def self.establish_named_connection(name)
@@ -34,7 +44,7 @@ module ScopedSearch::RSpec::Database
34
44
  end
35
45
 
36
46
  def self.create_model(fields)
37
- table_name = "model_#{rand}".gsub(/\./, '')
47
+ table_name = "model_#{rand}".gsub(/\W/, '')
38
48
  ActiveRecord::Migration.create_table(table_name) do |t|
39
49
  fields.each do |name, field_type|
40
50
  options = (field_type == :decimal) ? { :scale => 2, :precision => 10 } : {}
@@ -42,8 +52,8 @@ module ScopedSearch::RSpec::Database
42
52
  end
43
53
  end
44
54
 
45
- klass = Class.new(ActiveRecord::Base)
46
- klass.set_table_name(table_name)
55
+ klass = ScopedSearch::RSpec::Database.const_set(table_name.classify, Class.new(ActiveRecord::Base))
56
+ klass.table_name = table_name
47
57
  yield(klass) if block_given?
48
58
  return klass
49
59
  end
data/spec/lib/mocks.rb CHANGED
@@ -10,6 +10,7 @@ module ScopedSearch::RSpec::Mocks
10
10
  ar_mock.stub!(:scope).with(:search_for, anything)
11
11
  ar_mock.stub!(:connection).and_return(mock_database_connection)
12
12
  ar_mock.stub!(:ancestors).and_return([ActiveRecord::Base])
13
+ ar_mock.stub!(:columns_hash).and_return({'existing' => mock('column')})
13
14
  return ar_mock
14
15
  end
15
16
 
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  describe ScopedSearch::QueryLanguage::AST do
4
4
 
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  describe ScopedSearch::AutoCompleteBuilder do
4
4
 
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  describe ScopedSearch::Definition do
4
4
 
@@ -8,6 +8,21 @@ describe ScopedSearch::Definition do
8
8
  @definition.stub!(:setup_adapter)
9
9
  end
10
10
 
11
+ describe ScopedSearch::Definition::Field do
12
+ describe '#column' do
13
+ it "should raise an exception when using an unknown field" do
14
+ lambda {
15
+ @definition.define(:on => 'nonexisting').column
16
+ }.should raise_error(ActiveRecord::UnknownAttributeError)
17
+ end
18
+
19
+ it "should not raise an exception when using an unknown field" do
20
+ lambda {
21
+ @definition.define(:on => 'existing').column
22
+ }.should_not raise_error(ActiveRecord::UnknownAttributeError)
23
+ end
24
+ end
25
+ end
11
26
 
12
27
  describe '#initialize' do
13
28
 
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  describe ScopedSearch::QueryLanguage::Parser do
4
4
 
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  describe ScopedSearch::QueryBuilder do
4
4
 
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  describe ScopedSearch::QueryLanguage::Tokenizer do
4
4
 
@@ -13,8 +13,8 @@ module GithubGem
13
13
 
14
14
  # Detects the main include file of this project using heuristics
15
15
  def self.detect_main_include
16
- if detect_gemspec_file =~ /^(\.*)\.gemspec$/ && File.exist?("lib/#{$1}.rb")
17
- "lib/#{$1}.rb"
16
+ if File.exist?(File.expand_path("../lib/#{File.basename(detect_gemspec_file, '.gemspec').gsub(/-/, '/')}.rb", detect_gemspec_file))
17
+ "lib/#{File.basename(detect_gemspec_file, '.gemspec').gsub(/-/, '/')}.rb"
18
18
  elsif FileList['lib/*.rb'].length == 1
19
19
  FileList['lib/*.rb'].first
20
20
  else
@@ -24,6 +24,8 @@ module GithubGem
24
24
 
25
25
  class RakeTasks
26
26
 
27
+ include Rake::DSL if Rake.const_defined?('DSL')
28
+
27
29
  attr_reader :gemspec, :modified_files
28
30
  attr_accessor :gemspec_file, :task_namespace, :main_include, :root_dir, :spec_pattern, :test_pattern, :remote, :remote_branch, :local_branch
29
31
 
@@ -342,7 +344,7 @@ module GithubGem
342
344
  require 'net/https'
343
345
  require 'uri'
344
346
 
345
- uri = URI.parse('https://github.com/wvanbergen/github-gem/raw/master/tasks/github-gem.rake')
347
+ uri = URI.parse('https://raw.github.com/wvanbergen/github-gem/master/tasks/github-gem.rake')
346
348
  http = Net::HTTP.new(uri.host, uri.port)
347
349
  http.use_ssl = true
348
350
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
metadata CHANGED
@@ -1,97 +1,77 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: scoped_search
3
- version: !ruby/object:Gem::Version
4
- hash: 13
5
- prerelease: false
6
- segments:
7
- - 2
8
- - 3
9
- - 7
10
- version: 2.3.7
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.4.0
5
+ prerelease:
11
6
  platform: ruby
12
- authors:
7
+ authors:
8
+ - Amos Benari
13
9
  - Willem van Bergen
14
10
  - Wes Hays
15
11
  autorequire:
16
12
  bindir: bin
17
13
  cert_chain: []
18
-
19
- date: 2012-04-30 00:00:00 +03:00
20
- default_executable:
21
- dependencies:
22
- - !ruby/object:Gem::Dependency
23
- requirement: &id001 !ruby/object:Gem::Requirement
14
+ date: 2012-09-11 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: activerecord
18
+ requirement: &70188989608520 !ruby/object:Gem::Requirement
24
19
  none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- hash: 11
29
- segments:
30
- - 2
31
- - 1
32
- - 0
20
+ requirements:
21
+ - - ! '>='
22
+ - !ruby/object:Gem::Version
33
23
  version: 2.1.0
34
24
  type: :runtime
35
- name: activerecord
36
25
  prerelease: false
37
- version_requirements: *id001
38
- - !ruby/object:Gem::Dependency
39
- requirement: &id002 !ruby/object:Gem::Requirement
26
+ version_requirements: *70188989608520
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: &70188989607800 !ruby/object:Gem::Requirement
40
30
  none: false
41
- requirements:
31
+ requirements:
42
32
  - - ~>
43
- - !ruby/object:Gem::Version
44
- hash: 3
45
- segments:
46
- - 2
47
- - 0
48
- version: "2.0"
33
+ - !ruby/object:Gem::Version
34
+ version: '2.0'
49
35
  type: :development
50
- name: rspec
51
36
  prerelease: false
52
- version_requirements: *id002
53
- - !ruby/object:Gem::Dependency
54
- requirement: &id003 !ruby/object:Gem::Requirement
55
- none: false
56
- requirements:
57
- - - ">="
58
- - !ruby/object:Gem::Version
59
- hash: 3
60
- segments:
61
- - 0
62
- version: "0"
63
- type: :development
37
+ version_requirements: *70188989607800
38
+ - !ruby/object:Gem::Dependency
64
39
  name: rake
65
- prerelease: false
66
- version_requirements: *id003
67
- - !ruby/object:Gem::Dependency
68
- requirement: &id004 !ruby/object:Gem::Requirement
40
+ requirement: &70188989607000 !ruby/object:Gem::Requirement
69
41
  none: false
70
- requirements:
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- hash: 3
74
- segments:
75
- - 0
76
- version: "0"
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
77
46
  type: :development
78
- name: sqlite3-ruby
79
47
  prerelease: false
80
- version_requirements: *id004
81
- description: " Scoped search makes it easy to search your ActiveRecord-based models.\n \n It will create a named scope :search_for that can be called with a query string. It will build an SQL query using\n the provided query string and a definition that specifies on what fields to search. Because the functionality is\n built on named_scope, the result of the search_for call can be used like any other named_scope, so it can be\n chained with another scope or combined with will_paginate.\n \n Because it uses standard SQL, it does not require any setup, indexers or daemons. This makes scoped_search\n suitable to quickly add basic search functionality to your application with little hassle. On the other hand,\n it may not be the best choice if it is going to be used on very large datasets or by a large user base.\n"
82
- email:
48
+ version_requirements: *70188989607000
49
+ description: ! " Scoped search makes it easy to search your ActiveRecord-based
50
+ models.\n \n It will create a named scope :search_for that can be called with
51
+ a query string. It will build an SQL query using\n the provided query string
52
+ and a definition that specifies on what fields to search. Because the functionality
53
+ is\n built on named_scope, the result of the search_for call can be used like
54
+ any other named_scope, so it can be\n chained with another scope or combined
55
+ with will_paginate.\n \n Because it uses standard SQL, it does not require
56
+ any setup, indexers or daemons. This makes scoped_search\n suitable to quickly
57
+ add basic search functionality to your application with little hassle. On the other
58
+ hand,\n it may not be the best choice if it is going to be used on very large
59
+ datasets or by a large user base.\n"
60
+ email:
61
+ - abenari@redhat.com
83
62
  - willem@railsdoctors.com
84
63
  - weshays@gbdev.com
85
64
  executables: []
86
-
87
65
  extensions: []
88
-
89
- extra_rdoc_files:
66
+ extra_rdoc_files:
90
67
  - README.rdoc
91
- files:
68
+ files:
92
69
  - .gitignore
93
70
  - .infinity_test
71
+ - .travis.yml
94
72
  - Gemfile
73
+ - Gemfile.activerecord2
74
+ - Gemfile.activerecord3
95
75
  - LICENSE
96
76
  - README.rdoc
97
77
  - Rakefile
@@ -106,7 +86,8 @@ files:
106
86
  - lib/scoped_search/query_language/tokenizer.rb
107
87
  - lib/scoped_search/rails_helper.rb
108
88
  - scoped_search.gemspec
109
- - spec/database.yml
89
+ - spec/database.jruby.yml
90
+ - spec/database.ruby.yml
110
91
  - spec/integration/api_spec.rb
111
92
  - spec/integration/auto_complete_spec.rb
112
93
  - spec/integration/key_value_querying_spec.rb
@@ -126,46 +107,38 @@ files:
126
107
  - spec/unit/query_builder_spec.rb
127
108
  - spec/unit/tokenizer_spec.rb
128
109
  - tasks/github-gem.rake
129
- has_rdoc: true
130
110
  homepage: http://github.com/wvanbergen/scoped_search/wiki
131
111
  licenses: []
132
-
133
112
  post_install_message:
134
- rdoc_options:
113
+ rdoc_options:
135
114
  - --title
136
115
  - scoped_search
137
116
  - --main
138
117
  - README.rdoc
139
118
  - --line-numbers
140
119
  - --inline-source
141
- require_paths:
120
+ require_paths:
142
121
  - lib
143
- required_ruby_version: !ruby/object:Gem::Requirement
122
+ required_ruby_version: !ruby/object:Gem::Requirement
144
123
  none: false
145
- requirements:
146
- - - ">="
147
- - !ruby/object:Gem::Version
148
- hash: 3
149
- segments:
150
- - 0
151
- version: "0"
152
- required_rubygems_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ! '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
129
  none: false
154
- requirements:
155
- - - ">="
156
- - !ruby/object:Gem::Version
157
- hash: 3
158
- segments:
159
- - 0
160
- version: "0"
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
161
134
  requirements: []
162
-
163
135
  rubyforge_project:
164
- rubygems_version: 1.3.7
136
+ rubygems_version: 1.8.16
165
137
  signing_key:
166
138
  specification_version: 3
167
- summary: Easily search you ActiveRecord models with a simple query language using a named scope.
168
- test_files:
139
+ summary: Easily search you ActiveRecord models with a simple query language using
140
+ a named scope.
141
+ test_files:
169
142
  - spec/integration/api_spec.rb
170
143
  - spec/integration/auto_complete_spec.rb
171
144
  - spec/integration/key_value_querying_spec.rb