lunr 1.0.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Isolate CHANGED
@@ -1,8 +1,13 @@
1
- gem "configlet", "~> 1.3"
2
- gem "rsolr", "~> 0.12"
1
+ options :system => false
2
+
3
+ gem "sunspot", "~> 1.1.0"
3
4
 
4
5
  env :development do
5
- gem "fakeweb", "~> 1.3"
6
- gem "minitest", "~> 1.7"
7
- gem "will_paginate", "~> 3.0.pre2"
6
+ gem "ZenTest", "4.4.0"
7
+ gem "fakeweb", "1.3.0"
8
+ gem "hoe", "2.6.2"
9
+ gem "hoe-doofus", "1.0.0"
10
+ gem "hoe-git", "1.3.0"
11
+ gem "minitest", "1.7.1"
12
+ gem "mocha", "0.9.8"
8
13
  end
data/Manifest.txt CHANGED
@@ -5,5 +5,10 @@ Manifest.txt
5
5
  README.rdoc
6
6
  Rakefile
7
7
  lib/lunr.rb
8
- lib/lunr/error.rb
8
+ lib/lunr/errors.rb
9
+ lib/lunr/model.rb
10
+ lib/lunr/search.rb
11
+ lib/lunr/sunspot.rb
9
12
  test/test_lunr.rb
13
+ test/test_lunr_model.rb
14
+ test/test_lunr_search.rb
data/README.rdoc CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  == Description
6
6
 
7
- A simple read-only interface to Solr, built on RSolr.
7
+ A simple read-only interface to Solr, built on Sunspot.
8
8
 
9
9
  Lunr makes it easy to query and create objects from a Solr index
10
10
  without requiring all the knowledge, code, and data that was used to
@@ -14,30 +14,38 @@ If you have complex indexes with a stored fields and need to search /
14
14
  access those fields without access to the original data store, Lunr
15
15
  might be what you're looking for.
16
16
 
17
- As seen in Sunspot and similar tools, if
18
- <code>WillPaginate::Collection</code> is available it'll be wrapped
19
- around the results of any search.
20
-
21
17
  == Examples
22
18
 
23
19
  require "lunr"
24
20
 
25
- # set ENV["LUNR_URL"], or...
26
- Lunr[:url] = "http://localhost:8983/solr"
21
+ class My::SimpleTrack
22
+ include Lunr::Model
27
23
 
28
- # simplest possible, returns a hash
29
- Lunr.search "foo"
24
+ searches "Track" do
25
+ property :album, :text
26
+ property :artist, :text
27
+ property :title, :text
30
28
 
31
- # returns the result of the block for each entry
32
- Lunr.search "foo" do |raw|
33
- MyReadOnlyModelClass.new raw
34
- end
29
+ time :accepted_at
30
+ boolean :hot
31
+ string :state
32
+ end
33
+
34
+ scope do |q|
35
+ q.order_by :hot, :desc
36
+ q.order_by :accepted_at, :desc
35
37
 
36
- # pagination is part of solr, select a page with :p
37
- Lunr.search "foo", :p => params[:page]
38
+ q.with :state, "accepted"
39
+ end
38
40
 
39
- # default per page is 25, but you can set ENV["LUNR_PP"] or...
40
- Lunr.search "foo", :p => params[:page], :pp => 500
41
+ scope :hot do
42
+ with :hot, true
43
+ end
44
+
45
+ scope :state do |q, state|
46
+ q.with :state, state
47
+ end
48
+ end
41
49
 
42
50
  == Installation
43
51
 
data/Rakefile CHANGED
@@ -1,3 +1,8 @@
1
+ unless Gem.available? "isolate"
2
+ abort "Please `gem install isolate` and run rake again."
3
+ end
4
+
5
+ require "isolate/now"
1
6
  require "hoe"
2
7
 
3
8
  Hoe.plugins.delete :rubyforge
data/lib/lunr.rb CHANGED
@@ -1,57 +1,11 @@
1
- require "configlet"
2
- require "rsolr"
3
-
4
- require "lunr/error"
1
+ require "lunr/sunspot"
2
+ require "lunr/model"
3
+ require "lunr/search"
5
4
 
6
5
  module Lunr
7
- extend Configlet
8
-
9
- # Duh.
10
- VERSION = "1.0.1"
11
-
12
- config :lunr do
13
- default :pp => "25"
14
- default :url => "http://localhost:8983/solr"
15
- end
16
-
17
- def self.search query, options = {}, &block
18
- page = [1, Integer(options[:p] || 0)].max
19
- per = Integer options[:pp] || self[:pp]
20
-
21
- params = {
22
- :q => query,
23
- :rows => per,
24
- :start => per * (page - 1),
25
- }
26
-
27
- begin
28
- raw = solr.select params
29
- rescue Errno::ECONNREFUSED => e
30
- raise Lunr::Error, "Can't connect to #{self[:url]}: #{e}"
31
- end
32
-
33
- header = raw["responseHeader"]
34
- response = raw["response"]
35
6
 
36
- unless status = header["status"]
37
- raise Lunr::Error, "Bad (and cryptic) response status: #{status}"
38
- end
39
-
40
- docs = response.delete "docs"
41
- total = response.delete "numFound"
42
-
43
- docs = block_given? ? docs.map(&block) : docs
44
-
45
- if defined? WillPaginate::Collection
46
- old = docs
47
- docs = WillPaginate::Collection.new page, per, total
48
- docs.replace old
49
- end
50
-
51
- docs
52
- end
7
+ # Duh.
8
+ VERSION = "2.0.0"
53
9
 
54
- def self.solr
55
- @solr ||= RSolr.connect :url => self[:url]
56
- end
57
10
  end
11
+
@@ -0,0 +1,19 @@
1
+ module Lunr
2
+ class Error < StandardError
3
+ end
4
+
5
+ class AlreadyExecuted < Error
6
+ attr_reader :search
7
+
8
+ def initalize search
9
+ @search = search
10
+ super "Can't add more criteria, this search has already been executed!"
11
+ end
12
+ end
13
+
14
+ class BadModel < Error
15
+ def initialize klass
16
+ super "#{klass.name} doesn't include Lunr::Model!"
17
+ end
18
+ end
19
+ end
data/lib/lunr/model.rb ADDED
@@ -0,0 +1,47 @@
1
+ require "lunr/search"
2
+ require "lunr/sunspot"
3
+
4
+ module Lunr
5
+ module Model
6
+ def self.included klass
7
+ klass.extend Klass
8
+ end
9
+
10
+ attr_reader :id
11
+
12
+ module Klass
13
+ def properties
14
+ @properties ||= []
15
+ end
16
+
17
+ def scopes
18
+ @scopes ||= {}
19
+ end
20
+
21
+ def scope sym = :all, &block
22
+ scopes[sym] = block
23
+
24
+ unless sym == :all
25
+ class_eval <<-END, __FILE__, __LINE__ + 1
26
+ def self.#{sym}; search.#{sym} end
27
+ END
28
+ end
29
+ end
30
+
31
+ def search &block
32
+ Lunr::Search.new self, &block
33
+ end
34
+
35
+ alias_method :all, :search
36
+
37
+ def searches classname, &block
38
+ Sunspot::TypeField.alias self, classname
39
+ Sunspot.setup self, &block
40
+
41
+ properties.uniq.each do |prop|
42
+ attr_reader prop
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,116 @@
1
+ require "lunr/errors"
2
+ require "lunr/model"
3
+ require "lunr/sunspot"
4
+
5
+ module Lunr
6
+ class Search
7
+ include Enumerable
8
+
9
+ def each &block
10
+ execute && @results.each(&block)
11
+ end
12
+
13
+ def total
14
+ execute && @search.total
15
+ end
16
+
17
+ alias_method :size, :total
18
+
19
+ def empty?
20
+ 0 == total
21
+ end
22
+
23
+ # Acting like WillPaginate::Collection
24
+
25
+ def current_page
26
+ execute && @search.query.page
27
+ end
28
+
29
+ def per_page
30
+ execute && @search.query.per_page
31
+ end
32
+
33
+ def total_entries
34
+ total
35
+ end
36
+
37
+ def total_pages
38
+ total_entries / per_page +
39
+ (total_entries % per_page > 0 ? 1 : 0)
40
+ end
41
+
42
+ attr_reader :klass
43
+
44
+ def initialize klass, &block
45
+ raise Lunr::BadModel.new(klass) unless klass < Lunr::Model
46
+
47
+ @executed = false
48
+ @klass = klass
49
+ @search = Sunspot.new_search klass, &block
50
+
51
+ if all = @klass.scopes[:all]
52
+ scope &all
53
+ end
54
+ end
55
+
56
+ def scope &block
57
+ executable!
58
+ @search.build &block
59
+ end
60
+
61
+ def executable!
62
+ raise Lunr::AlreadyExecuted.new(self) if executed?
63
+ end
64
+
65
+ def executed?
66
+ @executed
67
+ end
68
+
69
+ # :nodoc:
70
+
71
+ def params
72
+ @search.query.to_params
73
+ end
74
+
75
+ def method_missing sym, *args
76
+ super unless scope = klass.scopes[sym]
77
+
78
+ executable!
79
+
80
+ dsl = @search.send :dsl
81
+
82
+ if args.empty?
83
+ dsl.instance_eval &scope
84
+ else
85
+ scope.call dsl, args
86
+ end
87
+
88
+ self
89
+ end
90
+
91
+ def respond_to sym, include_private = false
92
+ klass.scopes.key?(sym) || super
93
+ end
94
+
95
+ private
96
+
97
+ def execute
98
+ unless @executed
99
+ @executed = true
100
+ @search.execute
101
+
102
+ @results = @search.hits.map do |hit|
103
+ klass.new.tap do |model|
104
+ model.instance_variable_set :"@id", hit.primary_key
105
+
106
+ klass.properties.each do |prop|
107
+ model.instance_variable_set :"@#{prop}", hit.stored(prop)
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ true
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,59 @@
1
+ require "sunspot"
2
+
3
+ module Sunspot
4
+ module DSL
5
+ class Fields
6
+ def property name, type, options = {}
7
+ @setup.clazz.properties << name
8
+ send type, name, options.merge(:stored => true)
9
+ end
10
+ end
11
+ end
12
+
13
+ class Field
14
+ def stored?
15
+ @stored
16
+ end
17
+ end
18
+
19
+ module Search
20
+ class Hit
21
+ alias_method :original_initialize, :initialize
22
+
23
+ def initialize *args
24
+ original_initialize *args
25
+
26
+ if clazz = Sunspot::TypeField.aliases_inverted[@class_name]
27
+ @class_name = clazz.name
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ class Setup
34
+ def lunr_properties
35
+ @lunr_properties ||= []
36
+ end
37
+ end
38
+
39
+ class TypeField
40
+ class << self
41
+ def alias(dest_class, source_class_name)
42
+ @@inverted = nil # invalidate cache
43
+ aliases[dest_class] = source_class_name
44
+ end
45
+
46
+ def aliases
47
+ @@aliases ||= {}
48
+ end
49
+
50
+ def aliases_inverted
51
+ @@inverted ||= aliases.invert
52
+ end
53
+ end
54
+
55
+ def to_indexed clazz
56
+ self.class.aliases[clazz] || clazz.name
57
+ end
58
+ end
59
+ end
data/test/test_lunr.rb CHANGED
@@ -8,18 +8,4 @@ class TestLunr < MiniTest::Unit::TestCase
8
8
  def setup
9
9
  FakeWeb.clean_registry
10
10
  end
11
-
12
- def test_self_search
13
- stub "foo"
14
- Lunr.search "foo"
15
- end
16
-
17
- def stub query, fixture = "simple"
18
- FakeWeb.register_uri :get, url(query),
19
- :body => File.read("test/fixtures/#{fixture}")
20
- end
21
-
22
- def url query
23
- "#{Lunr[:url]}/select?wt=ruby&start=0&q=#{query}&rows=25"
24
- end
25
11
  end
@@ -0,0 +1,4 @@
1
+ require "minitest/autorun"
2
+
3
+ class TestLunrModel < MiniTest::Unit::TestCase
4
+ end
@@ -0,0 +1,42 @@
1
+ require "minitest/autorun"
2
+ require "mocha"
3
+ require "lunr/search"
4
+
5
+ class TestLunrSearch < MiniTest::Unit::TestCase
6
+ include Lunr::Model
7
+
8
+ def setup
9
+ @search = Lunr::Search.new self.class
10
+ end
11
+
12
+ def test_initialize
13
+ s = Lunr::Search.new self.class do
14
+ with :foo, "bar"
15
+ end
16
+
17
+ assert_equal TestLunrSearch, s.klass
18
+ assert_equal "type:TestLunrSearch", s.params[:fq].first
19
+ assert s.params[:fq].include?("foo_s:bar")
20
+ end
21
+
22
+ def test_scope
23
+ @search.scope { with :foo, "blergh" }
24
+ @search.scope { with :bar, "corge" }
25
+
26
+ assert @search.params[:fq].include?("foo_s:blergh")
27
+ assert @search.params[:fq].include?("bar_s:corge")
28
+ end
29
+
30
+ def test_scope_bad
31
+ @search.stubs(:executed?).returns true
32
+
33
+ assert_raises Lunr::AlreadyExecuted do
34
+ @search.scope { with :foo, "hello" }
35
+ end
36
+ end
37
+ end
38
+
39
+ Sunspot.setup TestLunrSearch do
40
+ string :bar
41
+ string :foo
42
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lunr
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 15
5
5
  prerelease: false
6
6
  segments:
7
- - 1
7
+ - 2
8
8
  - 0
9
- - 1
10
- version: 1.0.1
9
+ - 0
10
+ version: 2.0.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - John Barnette
@@ -15,38 +15,40 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-08-25 00:00:00 -07:00
18
+ date: 2010-09-01 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- name: configlet
22
+ name: sunspot
23
23
  prerelease: false
24
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
25
  none: false
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- hash: 9
29
+ hash: 19
30
30
  segments:
31
31
  - 1
32
- - 3
33
- version: "1.3"
32
+ - 1
33
+ - 0
34
+ version: 1.1.0
34
35
  type: :runtime
35
36
  version_requirements: *id001
36
37
  - !ruby/object:Gem::Dependency
37
- name: rsolr
38
+ name: ZenTest
38
39
  prerelease: false
39
40
  requirement: &id002 !ruby/object:Gem::Requirement
40
41
  none: false
41
42
  requirements:
42
- - - ~>
43
+ - - "="
43
44
  - !ruby/object:Gem::Version
44
- hash: 19
45
+ hash: 47
45
46
  segments:
47
+ - 4
48
+ - 4
46
49
  - 0
47
- - 12
48
- version: "0.12"
49
- type: :runtime
50
+ version: 4.4.0
51
+ type: :development
50
52
  version_requirements: *id002
51
53
  - !ruby/object:Gem::Dependency
52
54
  name: fakeweb
@@ -54,64 +56,114 @@ dependencies:
54
56
  requirement: &id003 !ruby/object:Gem::Requirement
55
57
  none: false
56
58
  requirements:
57
- - - ~>
59
+ - - "="
58
60
  - !ruby/object:Gem::Version
59
- hash: 9
61
+ hash: 27
60
62
  segments:
61
63
  - 1
62
64
  - 3
63
- version: "1.3"
65
+ - 0
66
+ version: 1.3.0
64
67
  type: :development
65
68
  version_requirements: *id003
66
69
  - !ruby/object:Gem::Dependency
67
- name: minitest
70
+ name: hoe
68
71
  prerelease: false
69
72
  requirement: &id004 !ruby/object:Gem::Requirement
70
73
  none: false
71
74
  requirements:
72
- - - ~>
75
+ - - "="
73
76
  - !ruby/object:Gem::Version
74
- hash: 1
77
+ hash: 19
75
78
  segments:
76
- - 1
77
- - 7
78
- version: "1.7"
79
+ - 2
80
+ - 6
81
+ - 2
82
+ version: 2.6.2
79
83
  type: :development
80
84
  version_requirements: *id004
81
85
  - !ruby/object:Gem::Dependency
82
- name: will_paginate
86
+ name: hoe-doofus
83
87
  prerelease: false
84
88
  requirement: &id005 !ruby/object:Gem::Requirement
85
89
  none: false
86
90
  requirements:
87
- - - ~>
91
+ - - "="
88
92
  - !ruby/object:Gem::Version
89
- hash: -1876988247
93
+ hash: 23
90
94
  segments:
91
- - 3
95
+ - 1
96
+ - 0
92
97
  - 0
93
- - pre2
94
- version: 3.0.pre2
98
+ version: 1.0.0
95
99
  type: :development
96
100
  version_requirements: *id005
97
101
  - !ruby/object:Gem::Dependency
98
- name: hoe
102
+ name: hoe-git
99
103
  prerelease: false
100
104
  requirement: &id006 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - "="
108
+ - !ruby/object:Gem::Version
109
+ hash: 27
110
+ segments:
111
+ - 1
112
+ - 3
113
+ - 0
114
+ version: 1.3.0
115
+ type: :development
116
+ version_requirements: *id006
117
+ - !ruby/object:Gem::Dependency
118
+ name: minitest
119
+ prerelease: false
120
+ requirement: &id007 !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - "="
124
+ - !ruby/object:Gem::Version
125
+ hash: 9
126
+ segments:
127
+ - 1
128
+ - 7
129
+ - 1
130
+ version: 1.7.1
131
+ type: :development
132
+ version_requirements: *id007
133
+ - !ruby/object:Gem::Dependency
134
+ name: mocha
135
+ prerelease: false
136
+ requirement: &id008 !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - "="
140
+ - !ruby/object:Gem::Version
141
+ hash: 43
142
+ segments:
143
+ - 0
144
+ - 9
145
+ - 8
146
+ version: 0.9.8
147
+ type: :development
148
+ version_requirements: *id008
149
+ - !ruby/object:Gem::Dependency
150
+ name: hoe
151
+ prerelease: false
152
+ requirement: &id009 !ruby/object:Gem::Requirement
101
153
  none: false
102
154
  requirements:
103
155
  - - ">="
104
156
  - !ruby/object:Gem::Version
105
- hash: 21
157
+ hash: 19
106
158
  segments:
107
159
  - 2
108
160
  - 6
109
- - 1
110
- version: 2.6.1
161
+ - 2
162
+ version: 2.6.2
111
163
  type: :development
112
- version_requirements: *id006
164
+ version_requirements: *id009
113
165
  description: |-
114
- A simple read-only interface to Solr, built on RSolr.
166
+ A simple read-only interface to Solr, built on Sunspot.
115
167
 
116
168
  Lunr makes it easy to query and create objects from a Solr index
117
169
  without requiring all the knowledge, code, and data that was used to
@@ -120,10 +172,6 @@ description: |-
120
172
  If you have complex indexes with a stored fields and need to search /
121
173
  access those fields without access to the original data store, Lunr
122
174
  might be what you're looking for.
123
-
124
- As seen in Sunspot and similar tools, if
125
- <code>WillPaginate::Collection</code> is available it'll be wrapped
126
- around the results of any search.
127
175
  email:
128
176
  - code@jbarnette.com
129
177
  executables: []
@@ -142,8 +190,13 @@ files:
142
190
  - README.rdoc
143
191
  - Rakefile
144
192
  - lib/lunr.rb
145
- - lib/lunr/error.rb
193
+ - lib/lunr/errors.rb
194
+ - lib/lunr/model.rb
195
+ - lib/lunr/search.rb
196
+ - lib/lunr/sunspot.rb
146
197
  - test/test_lunr.rb
198
+ - test/test_lunr_model.rb
199
+ - test/test_lunr_search.rb
147
200
  has_rdoc: true
148
201
  homepage: http://github.com/jbarnette/lunr
149
202
  licenses: []
@@ -178,6 +231,8 @@ rubyforge_project: lunr
178
231
  rubygems_version: 1.3.7
179
232
  signing_key:
180
233
  specification_version: 3
181
- summary: A simple read-only interface to Solr, built on RSolr
234
+ summary: A simple read-only interface to Solr, built on Sunspot
182
235
  test_files:
183
236
  - test/test_lunr.rb
237
+ - test/test_lunr_model.rb
238
+ - test/test_lunr_search.rb
data/lib/lunr/error.rb DELETED
@@ -1,4 +0,0 @@
1
- module Lunr
2
- class Error < StandardError
3
- end
4
- end