searchlight 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +14 -6
- data/CHANGELOG.md +4 -0
- data/README.md +4 -2
- data/lib/searchlight/adapters/active_record.rb +25 -4
- data/lib/searchlight/search.rb +4 -0
- data/lib/searchlight/version.rb +1 -1
- data/spec/searchlight/adapters/active_record_spec.rb +39 -7
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MjNmMzE5OWE2YzM4N2ZjMDU4YWNmNGZmZTk5NzM2NGQxNWRjYzNjYw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
Y2IzNWVmNzUyOTU4NjYxYjU2YmRiNWIzZDBjZmE0YTgyMzZlMTgyNw==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MjE2ZTMxMDM4OTQ0NDlmNjk5MWY4ODBlMmJkNDAwZDMzZjg4Njc1NDJmZWIz
|
10
|
+
Y2UzNTIxMzg2M2E1Mzk4OGM1MzdhNmYwOGFlOGM1MDg1ZmU0MWJjNDRmYWY5
|
11
|
+
Y2IxOTM2YzU1OTRjZWU4MjhkM2FlZjQxZGU3YTU1YTcwMjc0MjI=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MGQ0ZDg1YmMyZmJjYjcxNmY0ODU3MGNkNDY5YmY4NzkyOGJjMDExZThjNzk0
|
14
|
+
YjRlZDc0ODRiNTI4ZDgyNjFjNzEzOWU4ZTNjOGVlZjY5M2Y3YmI1NGYzM2My
|
15
|
+
ZGIwNTBlNzg4ZDM3ZWY4NTZmNDU0NjJiNWQ2ZTY3ODNiN2RkNmU=
|
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.1.0
|
6
|
+
|
7
|
+
ActiveRecord adapter ensures that searches return a relation, even if no options are given
|
8
|
+
|
5
9
|
## v1.0.0
|
6
10
|
|
7
11
|
- If no search target is given, search class attempts to guess based on its own name
|
data/README.md
CHANGED
@@ -14,7 +14,7 @@ The basic idea of Searchlight is to build a search by chaining method calls that
|
|
14
14
|
For example, if you have a Searchlight search class called `YetiSearch`, and you instantiate it like this:
|
15
15
|
|
16
16
|
```ruby
|
17
|
-
|
17
|
+
search = YetiSearch.new(active: true, name: 'Jimmy', location_in: %w[NY LA]) # or params[:search]
|
18
18
|
```
|
19
19
|
|
20
20
|
... calling `results` on the instance will build a search by chaining calls to `search_active`, `search_name`, and `search_location`.
|
@@ -108,7 +108,7 @@ For each search option, Searchlight defines two accessors: one for a value, and
|
|
108
108
|
For example, if your class `searches :awesomeness` and gets instantiated like:
|
109
109
|
|
110
110
|
```ruby
|
111
|
-
search = MySearchClass(awesomeness: 'Xtreme')
|
111
|
+
search = MySearchClass.new(awesomeness: 'Xtreme')
|
112
112
|
```
|
113
113
|
|
114
114
|
... your search methods can use:
|
@@ -292,6 +292,8 @@ For each of your search options, the module will have the simplest possible sear
|
|
292
292
|
|
293
293
|
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.
|
294
294
|
|
295
|
+
The adapter also ensures that searches return a relation, even if no options are given.
|
296
|
+
|
295
297
|
### ActionView
|
296
298
|
|
297
299
|
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`.
|
@@ -4,10 +4,8 @@ module Searchlight
|
|
4
4
|
|
5
5
|
def search_on(target)
|
6
6
|
super
|
7
|
-
if
|
8
|
-
|
9
|
-
extend Search
|
10
|
-
end
|
7
|
+
extend Search if is_active_record?(target)
|
8
|
+
convert_to_relation if is_active_record_class?(target)
|
11
9
|
end
|
12
10
|
|
13
11
|
module Search
|
@@ -32,6 +30,29 @@ module Searchlight
|
|
32
30
|
end
|
33
31
|
end
|
34
32
|
|
33
|
+
protected
|
34
|
+
|
35
|
+
def is_active_record?(target)
|
36
|
+
is_active_record_class?(target) || is_active_record_relation?(target)
|
37
|
+
end
|
38
|
+
|
39
|
+
def is_active_record_class?(target)
|
40
|
+
target.is_a?(Class) && target.ancestors.include?(::ActiveRecord::Base)
|
41
|
+
end
|
42
|
+
|
43
|
+
def is_active_record_relation?(target)
|
44
|
+
target.is_a?(::ActiveRecord::Relation)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Ensure that searches without options still return enumerable results
|
48
|
+
def convert_to_relation
|
49
|
+
self.search_target = (active_record_version >= 4) ? search_target.all : search_target.scoped
|
50
|
+
end
|
51
|
+
|
52
|
+
def active_record_version
|
53
|
+
::ActiveRecord::VERSION::MAJOR.to_i
|
54
|
+
end
|
55
|
+
|
35
56
|
end
|
36
57
|
end
|
37
58
|
end
|
data/lib/searchlight/search.rb
CHANGED
data/lib/searchlight/version.rb
CHANGED
@@ -7,15 +7,21 @@ describe 'Searchlight::Adapters::ActiveRecord', adapter: true do
|
|
7
7
|
require 'active_record'
|
8
8
|
end
|
9
9
|
|
10
|
-
let(:search_class) {
|
10
|
+
let(:search_class) {
|
11
|
+
Named::Class.new('SearchClass', Searchlight::Search).tap { |klass|
|
12
|
+
klass.instance_eval(&ar_version_faker)
|
13
|
+
klass.search_on target
|
14
|
+
}
|
15
|
+
}
|
16
|
+
let(:ar_version_faker) { lambda {|klass| nil } } # no-op
|
11
17
|
let(:search_instance) { search_class.new(elephants: 'yes, please') }
|
12
18
|
|
13
|
-
before :each do
|
14
|
-
search_class.searches :elephants
|
15
|
-
end
|
16
|
-
|
17
19
|
shared_examples "search classes with an ActiveRecord target" do
|
18
20
|
|
21
|
+
before :each do
|
22
|
+
search_class.searches :elephants
|
23
|
+
end
|
24
|
+
|
19
25
|
it "adds search methods to the search class" do
|
20
26
|
expect(search_class.new).to respond_to(:search_elephants)
|
21
27
|
end
|
@@ -26,7 +32,7 @@ describe 'Searchlight::Adapters::ActiveRecord', adapter: true do
|
|
26
32
|
|
27
33
|
it "defines search methods that call where on the search target" do
|
28
34
|
search_instance.results
|
29
|
-
expect(search_instance.search.called_methods).to
|
35
|
+
expect(search_instance.search.called_methods).to include(:where)
|
30
36
|
end
|
31
37
|
|
32
38
|
it "sets arguments properly in the defined method" do
|
@@ -40,11 +46,37 @@ describe 'Searchlight::Adapters::ActiveRecord', adapter: true do
|
|
40
46
|
|
41
47
|
let(:target) { MockActiveRecord }
|
42
48
|
|
49
|
+
describe "converting to an ActiveRecord::Relation" do
|
50
|
+
|
51
|
+
context "for ActiveRecord <= 3" do
|
52
|
+
|
53
|
+
let(:ar_version_faker) { lambda { |klass| klass.stub(:active_record_version).and_return(3) } }
|
54
|
+
|
55
|
+
it "calls 'scoped'" do
|
56
|
+
target.should_receive(:scoped)
|
57
|
+
search_class
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
context "for ActiveRecord >= 4" do
|
63
|
+
|
64
|
+
let(:ar_version_faker) { lambda { |klass| klass.stub(:active_record_version).and_return(4) } }
|
65
|
+
|
66
|
+
it "calls 'all'" do
|
67
|
+
target.should_receive(:all)
|
68
|
+
search_class
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
43
75
|
it_behaves_like "search classes with an ActiveRecord target"
|
44
76
|
|
45
77
|
end
|
46
78
|
|
47
|
-
context "when the search target is an ActiveRecord
|
79
|
+
context "when the search target is an ActiveRecord relation" do
|
48
80
|
|
49
81
|
let(:target) { MockActiveRecord.joins(:dudes_named_milford).tap { |r| r.called_methods.clear } }
|
50
82
|
|
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.1.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-05-
|
12
|
+
date: 2013-05-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: named
|
@@ -57,28 +57,28 @@ dependencies:
|
|
57
57
|
name: rake
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
|
-
- - '>='
|
60
|
+
- - ! '>='
|
61
61
|
- !ruby/object:Gem::Version
|
62
62
|
version: '0'
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
|
-
- - '>='
|
67
|
+
- - ! '>='
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '0'
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: rails
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
|
-
- - '>='
|
74
|
+
- - ! '>='
|
75
75
|
- !ruby/object:Gem::Version
|
76
76
|
version: '3'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- - '>='
|
81
|
+
- - ! '>='
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '3'
|
84
84
|
- !ruby/object:Gem::Dependency
|
@@ -154,12 +154,12 @@ require_paths:
|
|
154
154
|
- lib
|
155
155
|
required_ruby_version: !ruby/object:Gem::Requirement
|
156
156
|
requirements:
|
157
|
-
- - '>='
|
157
|
+
- - ! '>='
|
158
158
|
- !ruby/object:Gem::Version
|
159
159
|
version: '0'
|
160
160
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
161
|
requirements:
|
162
|
-
- - '>='
|
162
|
+
- - ! '>='
|
163
163
|
- !ruby/object:Gem::Version
|
164
164
|
version: '0'
|
165
165
|
requirements: []
|