searchlight 1.2.4 → 1.3.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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +2 -1
- data/README.md +8 -6
- data/gemfiles/Gemfile.rails-3.2.x +7 -0
- data/gemfiles/Gemfile.rails-4.0.x +8 -0
- data/lib/searchlight.rb +1 -0
- data/lib/searchlight/adapters/mongoid.rb +60 -0
- data/lib/searchlight/version.rb +1 -1
- data/searchlight.gemspec +0 -1
- data/spec/searchlight/adapters/action_view_spec.rb +5 -3
- data/spec/searchlight/adapters/mongoid_spec.rb +86 -0
- data/spec/spec_helper.rb +9 -4
- data/spec/support/mock_model.rb +0 -12
- data/spec/support/mock_models/active_record.rb +23 -0
- data/spec/support/mock_models/mongoid.rb +19 -0
- metadata +11 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5654905b697feb05239ed5b783d46e6a282eaa4
|
4
|
+
data.tar.gz: 7b9622f4a6d5d9f7cdcc2429941fc08f36e6c491
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64e8e55512aac81f5bed20ac97152a012211cdfdcb25906f62cb62b52e0a8970eb8111f991b85120f382e57771cea3f23e64edf4d4bcb0673b8983dc12a91f26
|
7
|
+
data.tar.gz: 491c812aa4973a4cfca1b2948f435a647ab1c59da69ea40414073bd93d780d4619afe5a5c10bebfee1a5509bf8915693abd7723b5e5080db29ef2c7bc5cde29b
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
Searchlight does its best to use [semantic versioning](http://semver.org).
|
4
4
|
|
5
|
+
## v1.3.0
|
6
|
+
|
7
|
+
New Mongoid adapter, thanks to [iliabylich](https://github.com/iliabylich).
|
8
|
+
|
5
9
|
## v1.2.4
|
6
10
|
|
7
11
|
- `options` method only returns those that map to search methods (not `attr_accessor` type values)
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -10,6 +10,10 @@ Searchlight can work with any ORM or object that can build a query using chained
|
|
10
10
|
[](https://coveralls.io/r/nathanl/searchlight?branch=master)
|
11
11
|
[](https://gemnasium.com/nathanl/searchlight)
|
12
12
|
|
13
|
+
## Getting Started
|
14
|
+
|
15
|
+
An [introductory video](https://vimeo.com/69179161), [the demo app it uses](http://bookfinder-searchlight-demo.herokuapp.com) and [the code for that app](https://github.com/nathanl/bookfinder) are available to help you get started.
|
16
|
+
|
13
17
|
## Overview
|
14
18
|
|
15
19
|
The basic idea of Searchlight is to build a search by chaining method calls that you define. It calls **public** methods on the object you specify, based on the options you pass.
|
@@ -284,13 +288,13 @@ end
|
|
284
288
|
```
|
285
289
|
## Adapters
|
286
290
|
|
287
|
-
Currently, Searchlight has adapters for ActiveRecord and
|
291
|
+
Currently, Searchlight has adapters for ActiveRecord, ActionView, and Mongoid. We'd love to get pull requests for others. :)
|
288
292
|
|
289
|
-
### ActiveRecord
|
293
|
+
### ActiveRecord and Mongoid
|
290
294
|
|
291
|
-
When you call `search_on` in your Searchlight class, Searchlight checks whether the search target comes from ActiveRecord, and, if so, mixes a module into your class.
|
295
|
+
When you call `search_on` in your Searchlight class, Searchlight checks whether the search target comes from ActiveRecord or Mongoid, and, if so, mixes a module into your class.
|
292
296
|
|
293
|
-
For each of your search options, the module will have the simplest possible search method defined. For example, if your class `searches :name`, the module will have this method:
|
297
|
+
For each of your search options, the module will have the simplest possible search method defined. For example, if your class `searches :name`, the ActiveRecord module will have this method:
|
294
298
|
|
295
299
|
```ruby
|
296
300
|
def search_name
|
@@ -300,8 +304,6 @@ For each of your search options, the module will have the simplest possible sear
|
|
300
304
|
|
301
305
|
Since that method is in a parent module, you can easily override it by defining your own method. You can also call `super` in the method you define.
|
302
306
|
|
303
|
-
The adapter also ensures that searches return a relation, even if no options are given.
|
304
|
-
|
305
307
|
### ActionView
|
306
308
|
|
307
309
|
Similarly, Searchlight adds ActionView-friendly methods to your classes if it sees that `ActionView` is a defined constant. See the code for details, but the upshot is that you can use a search with `form_for`.
|
data/lib/searchlight.rb
CHANGED
@@ -8,4 +8,5 @@ end
|
|
8
8
|
require 'searchlight/dsl'
|
9
9
|
require 'searchlight/search'
|
10
10
|
require 'searchlight/adapters/active_record' if defined?(::ActiveRecord)
|
11
|
+
require 'searchlight/adapters/mongoid' if defined?(::Mongoid)
|
11
12
|
require 'searchlight/adapters/action_view' if defined?(::ActionView)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Searchlight
|
2
|
+
module Adapters
|
3
|
+
module Mongoid
|
4
|
+
|
5
|
+
def search_on(target)
|
6
|
+
super
|
7
|
+
extend Search if mongoid?(target)
|
8
|
+
end
|
9
|
+
|
10
|
+
module Search
|
11
|
+
|
12
|
+
def searches(*attributes_names)
|
13
|
+
super
|
14
|
+
|
15
|
+
attributes_names.map do |attribute_name|
|
16
|
+
method_name = "search_#{attribute_name}"
|
17
|
+
if field?(attribute_name)
|
18
|
+
define_method method_name do
|
19
|
+
search.where(attribute_name.to_s => public_send(attribute_name))
|
20
|
+
end
|
21
|
+
else
|
22
|
+
define_method method_name do
|
23
|
+
raise Searchlight::Adapters::Mongoid::UndefinedColumn,
|
24
|
+
"Class `#{self.class.model_class}` has no field `#{attribute_name}`; please define `search_#{attribute_name}` on `#{self.class}` to clarify what you intend to search for"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def field?(attributes_name)
|
31
|
+
model_class.fields.has_key? attributes_name.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
def model_class
|
35
|
+
search_target.is_a?(::Mongoid::Criteria) ? search_target.klass : search_target
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def mongoid?(target)
|
43
|
+
mongoid_document?(target) || mongoid_criteria?(target)
|
44
|
+
end
|
45
|
+
|
46
|
+
def mongoid_document?(target)
|
47
|
+
defined?(::Mongoid::Document) && target.include?(::Mongoid::Document)
|
48
|
+
end
|
49
|
+
|
50
|
+
def mongoid_criteria?(target)
|
51
|
+
defined?(::Mongoid::Criteria) && target.is_a?(::Mongoid::Criteria)
|
52
|
+
end
|
53
|
+
|
54
|
+
UndefinedColumn = Class.new(StandardError)
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Searchlight::Search.extend(Searchlight::Adapters::Mongoid)
|
data/lib/searchlight/version.rb
CHANGED
data/searchlight.gemspec
CHANGED
@@ -23,7 +23,6 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_development_dependency "rspec", "~> 2.13"
|
24
24
|
spec.add_development_dependency "bundler", "~> 1.3"
|
25
25
|
spec.add_development_dependency "rake"
|
26
|
-
spec.add_development_dependency "rails", ">= 3"
|
27
26
|
spec.add_development_dependency "capybara", "~> 2.0"
|
28
27
|
spec.add_development_dependency "simplecov", "~> 0.7"
|
29
28
|
end
|
@@ -2,14 +2,16 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe 'Searchlight::Adapters::ActionView', type: :feature, adapter: true do
|
4
4
|
|
5
|
+
let(:view) { ::ActionView::Base.new }
|
6
|
+
let(:search) { AccountSearch.new(paid_amount: 15) }
|
7
|
+
|
5
8
|
before :all do
|
6
9
|
require 'searchlight/adapters/action_view'
|
7
10
|
require 'action_view'
|
11
|
+
require 'active_model'
|
12
|
+
require 'active_support/core_ext'
|
8
13
|
end
|
9
14
|
|
10
|
-
let(:view) { ::ActionView::Base.new }
|
11
|
-
let(:search) { AccountSearch.new(paid_amount: 15) }
|
12
|
-
|
13
15
|
before :each do
|
14
16
|
view.stub(:protect_against_forgery?).and_return(false)
|
15
17
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Searchlight::Adapters::Mongoid', adapter: true do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
require 'mongoid'
|
7
|
+
require 'searchlight/adapters/mongoid'
|
8
|
+
end
|
9
|
+
|
10
|
+
after :all do
|
11
|
+
Object.send(:remove_const, :Mongoid)
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:search_class) {
|
15
|
+
Named::Class.new('SearchClass', Searchlight::Search).tap { |klass| klass.search_on target }
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:search_instance) { search_class.new(elephants: 'yes, please') }
|
19
|
+
|
20
|
+
shared_examples "search classes with an Mongoid target" do
|
21
|
+
|
22
|
+
context "when the base model has a field matching the search term" do
|
23
|
+
|
24
|
+
before do
|
25
|
+
MockMongoid.stub(:fields).and_return('elephants' => 'column info...')
|
26
|
+
search_class.searches :elephants
|
27
|
+
end
|
28
|
+
|
29
|
+
it "adds search methods to the search class" do
|
30
|
+
expect(search_class.new).to respond_to(:search_elephants)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "defines search methods that call `where` on the search target" do
|
34
|
+
search_instance.results
|
35
|
+
expect(search_instance.search.called_methods).to include(:where)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "sets arguments properly in the defined method" do
|
39
|
+
search_instance.search.should_receive(:where).with('elephants' => 'yes, please')
|
40
|
+
search_instance.search_elephants
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when the base model has no field matching the search term" do
|
46
|
+
|
47
|
+
before do
|
48
|
+
MockMongoid.stub(fields: {})
|
49
|
+
search_class.searches :elephants
|
50
|
+
end
|
51
|
+
|
52
|
+
it "adds search methods to the search class" do
|
53
|
+
expect(search_class.new).to respond_to(:search_elephants)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "defines search methods to raise an exception" do
|
57
|
+
expect { search_instance.results }.to raise_error(
|
58
|
+
Searchlight::Adapters::Mongoid::UndefinedColumn
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
context "when the search target is a class with Mongoid::Document module" do
|
67
|
+
|
68
|
+
let(:target) { MockMongoid }
|
69
|
+
|
70
|
+
it_behaves_like "search classes with an Mongoid target"
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
context "when the search target is Mongoid::Criteria class" do
|
75
|
+
|
76
|
+
let(:target) { MockMongoidCriteria.new([]) }
|
77
|
+
|
78
|
+
before do
|
79
|
+
target.stub(klass: MockMongoid)
|
80
|
+
end
|
81
|
+
|
82
|
+
it_behaves_like "search classes with an Mongoid target"
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
require 'capybara/rspec'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
if ENV["TRAVIS"]
|
3
|
+
require 'coveralls'
|
4
|
+
Coveralls.wear!
|
5
|
+
else
|
6
|
+
require 'simplecov'
|
7
|
+
SimpleCov.start { add_filter "/spec" }
|
8
|
+
end
|
6
9
|
require 'searchlight'
|
7
10
|
$LOAD_PATH << '.'
|
8
11
|
require 'support/mock_model'
|
12
|
+
require 'support/mock_models/active_record'
|
13
|
+
require 'support/mock_models/mongoid'
|
9
14
|
require 'support/account_search'
|
10
15
|
require 'support/spiffy_account_search'
|
11
16
|
|
data/spec/support/mock_model.rb
CHANGED
@@ -3,18 +3,6 @@ class MockModel
|
|
3
3
|
def self.method_missing(method, *args, &block)
|
4
4
|
MockRelation.new(method)
|
5
5
|
end
|
6
|
-
|
7
|
-
end
|
8
|
-
|
9
|
-
class MockActiveRecord < MockModel
|
10
|
-
|
11
|
-
def self.ancestors
|
12
|
-
super + [::ActiveRecord::Base]
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.is_a?(thing)
|
16
|
-
thing == ::ActiveRecord::Base ? true : super
|
17
|
-
end
|
18
6
|
|
19
7
|
end
|
20
8
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class MockActiveRecord < MockModel
|
2
|
+
|
3
|
+
def self.ancestors
|
4
|
+
super + [::ActiveRecord::Base]
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.is_a?(thing)
|
8
|
+
thing == ::ActiveRecord::Base ? true : super
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
class MockActiveRecordRelation < MockRelation
|
14
|
+
|
15
|
+
def is_a?(thing)
|
16
|
+
thing == ::ActiveRecord::Relation ? true : super
|
17
|
+
end
|
18
|
+
|
19
|
+
def engine
|
20
|
+
MockActiveRecord
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class MockMongoid < MockModel
|
2
|
+
|
3
|
+
def self.include?(thing)
|
4
|
+
thing == ::Mongoid::Document ? true : super
|
5
|
+
end
|
6
|
+
|
7
|
+
end
|
8
|
+
|
9
|
+
class MockMongoidCriteria < MockRelation
|
10
|
+
|
11
|
+
def is_a?(thing)
|
12
|
+
thing == ::Mongoid::Criteria ? true : super
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.include?(thing)
|
16
|
+
thing == ::Mongoid::Document ? false : super
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: searchlight
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathan Long
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-07-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: named
|
@@ -67,20 +67,6 @@ dependencies:
|
|
67
67
|
- - '>='
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '0'
|
70
|
-
- !ruby/object:Gem::Dependency
|
71
|
-
name: rails
|
72
|
-
requirement: !ruby/object:Gem::Requirement
|
73
|
-
requirements:
|
74
|
-
- - '>='
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
version: '3'
|
77
|
-
type: :development
|
78
|
-
prerelease: false
|
79
|
-
version_requirements: !ruby/object:Gem::Requirement
|
80
|
-
requirements:
|
81
|
-
- - '>='
|
82
|
-
- !ruby/object:Gem::Version
|
83
|
-
version: '3'
|
84
70
|
- !ruby/object:Gem::Dependency
|
85
71
|
name: capybara
|
86
72
|
requirement: !ruby/object:Gem::Requirement
|
@@ -129,20 +115,26 @@ files:
|
|
129
115
|
- README.md
|
130
116
|
- Rakefile
|
131
117
|
- TODO.md
|
118
|
+
- gemfiles/Gemfile.rails-3.2.x
|
119
|
+
- gemfiles/Gemfile.rails-4.0.x
|
132
120
|
- lib/searchlight.rb
|
133
121
|
- lib/searchlight/adapters/action_view.rb
|
134
122
|
- lib/searchlight/adapters/active_record.rb
|
123
|
+
- lib/searchlight/adapters/mongoid.rb
|
135
124
|
- lib/searchlight/dsl.rb
|
136
125
|
- lib/searchlight/search.rb
|
137
126
|
- lib/searchlight/version.rb
|
138
127
|
- searchlight.gemspec
|
139
128
|
- spec/searchlight/adapters/action_view_spec.rb
|
140
129
|
- spec/searchlight/adapters/active_record_spec.rb
|
130
|
+
- spec/searchlight/adapters/mongoid_spec.rb
|
141
131
|
- spec/searchlight/search_spec.rb
|
142
132
|
- spec/searchlight_spec.rb
|
143
133
|
- spec/spec_helper.rb
|
144
134
|
- spec/support/account_search.rb
|
145
135
|
- spec/support/mock_model.rb
|
136
|
+
- spec/support/mock_models/active_record.rb
|
137
|
+
- spec/support/mock_models/mongoid.rb
|
146
138
|
- spec/support/spiffy_account_search.rb
|
147
139
|
homepage: https://github.com/nathanl/searchlight
|
148
140
|
licenses:
|
@@ -172,9 +164,12 @@ summary: Searchlight helps you build searches from options via Ruby methods that
|
|
172
164
|
test_files:
|
173
165
|
- spec/searchlight/adapters/action_view_spec.rb
|
174
166
|
- spec/searchlight/adapters/active_record_spec.rb
|
167
|
+
- spec/searchlight/adapters/mongoid_spec.rb
|
175
168
|
- spec/searchlight/search_spec.rb
|
176
169
|
- spec/searchlight_spec.rb
|
177
170
|
- spec/spec_helper.rb
|
178
171
|
- spec/support/account_search.rb
|
179
172
|
- spec/support/mock_model.rb
|
173
|
+
- spec/support/mock_models/active_record.rb
|
174
|
+
- spec/support/mock_models/mongoid.rb
|
180
175
|
- spec/support/spiffy_account_search.rb
|