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 CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 65909cc6d8f99929aa4c76ba6a52e23dd8b85f59
4
- data.tar.gz: 8ed82b1eab66fe78fcfc2b7b1630a8cbd2e2dcf3
5
- SHA512:
6
- metadata.gz: fd26998a2330f3b034cdad89efe07ab3a52e0125db072da03533aa0038e091240baf0af3428ddc84de5b7e7e558b9a0c5fe6b095cf9a30acee503dbd359cb27e
7
- data.tar.gz: 62a9b2a4ae2e8e5d8b28b996199b500c210f63ef53805e1c5ce491b7273832a5aed11155ff86a83dc7c4f4d5f6d66aa8a88b1db7d524dd2ca24d622c769fa0ea
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
- yeti_search = YetiSearch(active: true, name: 'Jimmy', location_in: %w[NY LA]) # or params[:search]
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 target.is_a?(Class) && target.ancestors.include?(::ActiveRecord::Base) ||
8
- target.is_a?(::ActiveRecord::Relation)
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
@@ -41,6 +41,10 @@ module Searchlight
41
41
  raise e
42
42
  end
43
43
 
44
+ def self.search_target=(value)
45
+ @search_target = value
46
+ end
47
+
44
48
  def search_methods
45
49
  public_methods.map(&:to_s).select { |m| m.start_with?('search_') }
46
50
  end
@@ -1,3 +1,3 @@
1
1
  module Searchlight
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -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) { Named::Class.new('SearchClass', Searchlight::Search).tap { |klass| klass.search_on target } }
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 eq([:where])
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 class" do
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.0.0
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-17 00:00:00.000000000 Z
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: []