simple_solr 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -1,3 +1,2 @@
1
1
  rvm:
2
- - 1.8.7
3
2
  - 1.9.2
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,10 @@
1
+ == 0.7.0 (Sep 29, 2011)
2
+
3
+ - Only test on 1.9.2
4
+ - Use fakeweb to mock the webserver response
5
+ - Use Nokogiri to parse the response instead of relying on automatic hashing
6
+
7
+
1
8
  == 0.6.0 (Aug 18, 2011)
2
9
 
3
10
  - Return the parsed response from httparty for search results
data/Gemfile CHANGED
@@ -5,6 +5,8 @@ gemspec
5
5
  gem "rake"
6
6
  gem "activerecord"
7
7
  gem "rspec", ">= 2"
8
+ gem "nokogiri"
8
9
  gem "sqlite3"
9
10
  gem "httparty"
10
11
  gem "builder"
12
+ gem "fakeweb"
data/README.rdoc CHANGED
@@ -130,10 +130,25 @@ Use the +simple_search+ class method on your model:
130
130
 
131
131
  Document.simple_search 'apple'
132
132
 
133
- This will make a trip to Solr and return the results as a hash. That's right.
134
- The results are not correlated with your models. In fact, no processing is
135
- done at all. Simple, right? If you need to fetch model instances based on the
136
- results, that is up to you.
133
+ This will make a trip to Solr and return the results as a Nokogiri XML
134
+ Document. A slightly more convenient method to return only the matching
135
+ documents is present as well:
136
+
137
+ Document.simple_search_docs 'apple'
138
+
139
+ gives you a Nodeset which you can query further. You will need either
140
+ XPath or CSS selectors to drill down to the results you want. Given this
141
+ individual +doc+ result:
142
+
143
+ <doc><str name="title">Woezel en Pip</str></doc>
144
+
145
+ the contents of the title tag can be fetched like this:
146
+
147
+ results = Document.simple_search_docs 'apple'
148
+ results.first.at_css('str[name=title]').contents # => Woezel en Pip
149
+
150
+
151
+ === Search parameters
137
152
 
138
153
  You can add parameters, for example if you want to limit results using +fq+:
139
154
 
@@ -143,7 +158,10 @@ See the Solr documentation[http://wiki.apache.org/solr/CommonQueryParameters] fo
143
158
  of common query parameters. Just remember that the +q+ parameter will be set already,
144
159
  although it can be overriden by the parameters you provide.
145
160
 
146
- The response from Solr will look something like this:
161
+
162
+ === Response example
163
+
164
+ The raw response from Solr will look something like this:
147
165
 
148
166
  <?xml version="1.0" encoding="UTF-8"?>
149
167
  <response>
@@ -166,8 +184,7 @@ The response from Solr will look something like this:
166
184
  </lst>
167
185
  </response>
168
186
 
169
- This response will be translated into a hash by httparty. Take a look at your
170
- webserver config/response headers if that does not happen.
187
+ where every +doc+ is a matching document found in the index.
171
188
 
172
189
 
173
190
  == Working in batches
@@ -184,10 +201,15 @@ Same for deleting documents:
184
201
  document.delete_from_solr
185
202
  end
186
203
 
187
- Just remember to not touch the +id+ field since you added the model, since
204
+ Just remember to not change the +id+ field since you added the model, since
188
205
  this key is used to delete documents from Solr.
189
206
 
190
207
 
208
+ == Supported Ruby version
209
+
210
+ This gem is only tested on Ruby 1.9.2. It will probably work on other versions as well.
211
+
212
+
191
213
  == Helping out
192
214
 
193
215
  Interested in working on SimpleSolr? Please see DEVELOPMENT.rdoc.
data/lib/simple_solr.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'active_record'
2
+ require 'nokogiri'
2
3
  require 'httparty'
3
4
  require 'builder'
4
5
 
@@ -9,7 +10,6 @@ require "simple_solr/version"
9
10
 
10
11
  if defined?(ActiveRecord::Base)
11
12
  ActiveRecord::Base.send :include, SimpleSolr::Update
12
- ActiveRecord::Base.extend SimpleSolr::Search
13
13
  end
14
14
 
15
15
  module SimpleSolr
@@ -17,9 +17,5 @@ module SimpleSolr
17
17
  def configuration
18
18
  @configuration ||= SimpleSolr::Configuration.new
19
19
  end
20
-
21
- def search(query, params)
22
- SimpleSolr::Search.simple_search(query, params)
23
- end
24
20
  end
25
21
  end
@@ -5,15 +5,26 @@ module SimpleSolr
5
5
  #
6
6
  # Product.simple_search 'delicious', :fq => "category:fruit"
7
7
  #
8
- # Returns a hash with the search results:
9
- #
10
- # {
11
- # "lst" => [{"int"=>["0", "18"], "name"=>"responseHeader"},{"name"=>"highlighting"}],
12
- # "result" => {"name"=>"response", "numFound"=>"0", "start"=>"0", "maxScore"=>"0.0"}
13
- # }
8
+ # Returns a Nokogiri::XML::Document.
14
9
  def simple_search(query, params={})
15
10
  query = {:q => query}
16
- get(SimpleSolr.configuration.uri + "/select", :query => query.merge(params)).parsed_response['response']
11
+ response = get(SimpleSolr.configuration.uri + "/select", :query => query.merge(params))
12
+ Nokogiri::XML(response.body)
13
+ end
14
+
15
+ # Returns all +doc+ elements, aka matching documents, from the search results in an array.
16
+ # To dig deeper, use css selectors to find the elements you need.
17
+ #
18
+ # <doc><str name="title">Woezel en Pip</str></doc>
19
+ #
20
+ # the contents of the title tag can be fetched like this:
21
+ #
22
+ # results = Document.simple_search_docs('apple')
23
+ # results.first.at_css('str[name=title]').contents # => Woezel en Pip
24
+ #
25
+ # I told you it was close to the metal! Refer to the Nokogiro docs for more information.
26
+ def simple_search_docs(query, params={})
27
+ simple_search(query, params).css('doc')
17
28
  end
18
29
  end
19
30
  end
@@ -2,6 +2,7 @@ module SimpleSolr
2
2
  module Update
3
3
  def self.included(base)
4
4
  base.extend ClassMethods
5
+ base.extend SimpleSolr::Search
5
6
  end
6
7
 
7
8
  module ClassMethods
@@ -1,3 +1,3 @@
1
1
  module SimpleSolr
2
- VERSION = "0.6.0"
2
+ VERSION = "0.7.0"
3
3
  end
data/simple_solr.gemspec CHANGED
@@ -17,8 +17,10 @@ Gem::Specification.new do |s|
17
17
  s.require_paths = ["lib"]
18
18
 
19
19
  s.add_development_dependency "rspec", ">= 2"
20
+ s.add_development_dependency "fakeweb"
20
21
 
21
22
  s.add_runtime_dependency "activerecord"
23
+ s.add_runtime_dependency "nokogiri"
22
24
  s.add_runtime_dependency "httparty"
23
25
  s.add_runtime_dependency "builder"
24
26
  end
@@ -0,0 +1,20 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <response>
3
+ <lst name="responseHeader">
4
+ <int name="status">0</int>
5
+ <int name="QTime">3</int>
6
+ </lst>
7
+ <result name="response" numFound="1" start="0" maxScore="13.722203">
8
+ <doc>
9
+ <float name="score">13.722203</float>
10
+ <date name="date_creation">2011-01-06T23:02:33Z</date>
11
+ <str name="id">969</str>
12
+ <str name="publisher">Widgets, Inc</str>
13
+ <str name="title">Golden Delicious</str>
14
+ <str name="category">Apples</str>
15
+ </doc>
16
+ </result>
17
+ <lst name="highlighting">
18
+ <lst name="969"/>
19
+ </lst>
20
+ </response>
@@ -0,0 +1,46 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <response>
3
+ <lst name="responseHeader">
4
+ <int name="status">0</int>
5
+ <int name="QTime">3</int>
6
+ </lst>
7
+ <result name="response" numFound="1" start="0" maxScore="3.2594316">
8
+ <doc>
9
+ <float name="score">3.2594316</float>
10
+ <str name="brand_site">www.zappelin.nl</str>
11
+ <str name="brand_title">Z@ppelin</str>
12
+ <arr name="contenttype">
13
+ <str>text</str>
14
+ </arr>
15
+ <date name="date_creation">2010-12-26T23:02:48Z</date>
16
+ <date name="date_offline">2021-08-23T10:44:46Z</date>
17
+ <date name="date_online">2010-12-26T23:02:00Z</date>
18
+ <date name="date_updated">2011-01-26T16:21:56Z</date>
19
+ <str name="deeplink">http://www.zappelin.nl/series/962-woezel-en-pip</str>
20
+ <str name="id">http://www.zappelin.nl/series/962-woezel-en-pip</str>
21
+ <arr name="keywords">
22
+ <str/>
23
+ </arr>
24
+ <str name="publisher">NPO</str>
25
+ <str name="shared">true</str>
26
+ <str name="summary">&lt;p&gt;Woezel en Pip zijn de nieuwsgierige hondjes die bedacht zijn door Guusje Nederhorst.&lt;/p&gt;</str>
27
+ <arr name="thumbnails">
28
+ <str>/attachments/contents/000/002/743/uploads/thumbnail/woezel_pip.jpg</str>
29
+ </arr>
30
+ <str name="title">Woezel en Pip</str>
31
+ </doc>
32
+ </result>
33
+ <lst name="highlighting">
34
+ <lst name="http://www.zappelin.nl/series/962-woezel-en-pip">
35
+ <arr name="title">
36
+ <str>&lt;em&gt;Woezel&lt;/em&gt; en Pip </str>
37
+ </arr>
38
+ <arr name="deeplink">
39
+ <str>s/962-&lt;em&gt;woezel&lt;/em&gt;-en-pip </str>
40
+ </arr>
41
+ <arr name="summary">
42
+ <str>&lt;p&gt;&lt;em&gt;Woezel&lt;/em&gt; en Pip zijn de nieuwsgierige hondjes die bedacht zijn door Guusje Nederhorst.&lt;/p&gt; </str>
43
+ </arr>
44
+ </lst>
45
+ </lst>
46
+ </response>
@@ -1,30 +1,32 @@
1
1
  require 'spec_helper'
2
2
 
3
+ fixture = File.dirname(__FILE__) + "/../fixtures/result.xml"
4
+
5
+ FakeWeb.register_uri(:get,
6
+ "http://test.local:8983/solr/select?q=bonanza",
7
+ :body => File.read(fixture),
8
+ :content_type => "application/xml"
9
+ )
10
+
3
11
  describe SimpleSolr::Search do
4
- let(:response) { stub("response")}
5
- let(:httparty) { stub("httparty", :parsed_response => {'response' => response})}
6
-
12
+
7
13
  describe SimpleDocument do
8
- before do
9
- SimpleDocument.stub(:get).and_return(httparty)
10
- end
11
14
 
12
- it "responds to search" do
13
- SimpleDocument.should respond_to(:simple_search)
15
+ it "returns a Nokogiri::XML::Document" do
16
+ SimpleDocument.simple_search('bonanza').should be_a(Nokogiri::XML::Document)
14
17
  end
15
18
 
16
- it "gets results" do
17
- SimpleDocument.should_receive(:get).with("http://test.local:8983/solr/select", :query => {:q => 'bonanza'}).and_return(httparty)
18
- SimpleDocument.simple_search 'bonanza'
19
+ it "returns one document" do
20
+ SimpleDocument.simple_search('bonanza').css('doc').length.should eq 1
19
21
  end
20
-
21
- it "allows parameters" do
22
- SimpleDocument.should_receive(:get).with("http://test.local:8983/solr/select", :query => {:q => 'bonanza', :fq => "brand_site:www.example.com"}).and_return(httparty)
23
- SimpleDocument.simple_search 'bonanza', :fq => "brand_site:www.example.com"
22
+
23
+ it "returns one simple search result" do
24
+ SimpleDocument.simple_search_docs('bonanza').length.should eq 1
24
25
  end
25
26
 
26
- it "returns parsed response" do
27
- SimpleDocument.simple_search('bonanza').should eq(response)
27
+ it "returns title" do
28
+ SimpleDocument.simple_search_docs('bonanza').first.at_css('str[name=title]').content.should eq "Woezel en Pip"
28
29
  end
29
30
  end
31
+
30
32
  end
@@ -1,6 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe SimpleSolr::Update do
4
+ before do
5
+ SparseDocument.stub(:post) # prevent calls going out over the wire
6
+ end
7
+
4
8
  describe SparseDocument do
5
9
  it "stores just the id field" do
6
10
  SparseDocument.simple_solr_fields.should eq({:id => nil})
@@ -8,6 +12,10 @@ describe SimpleSolr::Update do
8
12
  end
9
13
 
10
14
  describe SimpleDocument do
15
+ before do
16
+ SimpleDocument.stub(:post) # prevent calls going out over the wire
17
+ end
18
+
11
19
  it "provides simple_solr class method" do
12
20
  SimpleDocument.should respond_to(:simple_solr)
13
21
  end
@@ -17,20 +25,24 @@ describe SimpleSolr::Update do
17
25
  end
18
26
 
19
27
  context "save" do
20
- let(:document) { SimpleDocument.create! :title => 'Omg Ponies' }
21
-
28
+ before do
29
+ @document = SimpleDocument.create! :title => 'Omg Ponies'
30
+ end
31
+
22
32
  it "posts to solr" do
23
- SimpleDocument.should_receive(:post).with("http://test.local:8983/solr/update?commit=true", :body => "<add><doc><field name=\"id\">#{document.id}</field><field name=\"title\">Omg Ponies</field></doc></add>")
33
+ SimpleDocument.should_receive(:post).with("http://test.local:8983/solr/update?commit=true", :body => "<add><doc><field name=\"id\">#{@document.id}</field><field name=\"title\">Omg Ponies</field></doc></add>")
34
+ @document.save
24
35
  end
25
36
  end
26
37
 
27
38
  context "destroy" do
28
- let(:document) { SimpleDocument.create! :title => 'Omg Ponies' }
39
+ before do
40
+ @document = SimpleDocument.create! :title => 'Omg Ponies'
41
+ end
29
42
 
30
43
  it "posts to solr" do
31
- SimpleDocument.should_receive(:post).with("http://test.local:8983/solr/update?commit=true", :body => "<add><doc><field name=\"id\">#{document.id}</field><field name=\"title\">Omg Ponies</field></doc></add>")
32
- SimpleDocument.should_receive(:post).with("http://test.local:8983/solr/update?commit=true", :body => "<delete><id>#{document.id}</id></delete>")
33
- document.destroy
44
+ SimpleDocument.should_receive(:post).with("http://test.local:8983/solr/update?commit=true", :body => "<delete><id>#{@document.id}</id></delete>")
45
+ @document.destroy
34
46
  end
35
47
  end
36
48
 
@@ -48,10 +60,14 @@ describe SimpleSolr::Update do
48
60
  end
49
61
 
50
62
  describe FullDocument do
51
- let(:document) { FullDocument.create :title => "Rainbows" }
63
+ before do
64
+ FullDocument.stub(:post) # prevent calls going out over the wire
65
+ @document = FullDocument.create! :title => "Rainbows", :created_at => '2011-08-18 13:32:00'.to_time
66
+ end
52
67
 
53
68
  it "posts to solr after save" do
54
- FullDocument.should_receive(:post).with("http://test.local:8983/solr?commit=true", :body => "<add><doc><field name=\"id\">full-document-#{document.id}</field><field name=\"title\">Rainbows</field><field name=\"date_creation\">#{document.created_at}</field><field name=\"shared\">false</field><field name=\"body\"></field></doc></add>")
69
+ FullDocument.should_receive(:post).with("http://test.local:8983/solr/update?commit=true", :body => "<add><doc><field name=\"id\">full-document-#{@document.id}</field><field name=\"title\">Rainbows</field><field name=\"date_creation\">#{@document.created_at}</field><field name=\"shared\">false</field><field name=\"body\"></field></doc></add>")
70
+ @document.save
55
71
  end
56
72
  end
57
73
  end
@@ -0,0 +1,3 @@
1
+ require 'fakeweb'
2
+
3
+ FakeWeb.allow_net_connect = false
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_solr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-08-18 00:00:00.000000000Z
12
+ date: 2011-09-29 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &2153333520 !ruby/object:Gem::Requirement
16
+ requirement: &2156008520 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,32 @@ dependencies:
21
21
  version: '2'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *2153333520
24
+ version_requirements: *2156008520
25
+ - !ruby/object:Gem::Dependency
26
+ name: fakeweb
27
+ requirement: &2156007520 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2156007520
25
36
  - !ruby/object:Gem::Dependency
26
37
  name: activerecord
27
- requirement: &2153333100 !ruby/object:Gem::Requirement
38
+ requirement: &2156006480 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *2156006480
47
+ - !ruby/object:Gem::Dependency
48
+ name: nokogiri
49
+ requirement: &2156005900 !ruby/object:Gem::Requirement
28
50
  none: false
29
51
  requirements:
30
52
  - - ! '>='
@@ -32,10 +54,10 @@ dependencies:
32
54
  version: '0'
33
55
  type: :runtime
34
56
  prerelease: false
35
- version_requirements: *2153333100
57
+ version_requirements: *2156005900
36
58
  - !ruby/object:Gem::Dependency
37
59
  name: httparty
38
- requirement: &2164268940 !ruby/object:Gem::Requirement
60
+ requirement: &2156004760 !ruby/object:Gem::Requirement
39
61
  none: false
40
62
  requirements:
41
63
  - - ! '>='
@@ -43,10 +65,10 @@ dependencies:
43
65
  version: '0'
44
66
  type: :runtime
45
67
  prerelease: false
46
- version_requirements: *2164268940
68
+ version_requirements: *2156004760
47
69
  - !ruby/object:Gem::Dependency
48
70
  name: builder
49
- requirement: &2164268520 !ruby/object:Gem::Requirement
71
+ requirement: &2156003620 !ruby/object:Gem::Requirement
50
72
  none: false
51
73
  requirements:
52
74
  - - ! '>='
@@ -54,7 +76,7 @@ dependencies:
54
76
  version: '0'
55
77
  type: :runtime
56
78
  prerelease: false
57
- version_requirements: *2164268520
79
+ version_requirements: *2156003620
58
80
  description: Solr client for Ruby on Rails with as few features as possible.
59
81
  email:
60
82
  - joost@spacebabies.nl
@@ -80,12 +102,15 @@ files:
80
102
  - spec/config/simple_solr.yml
81
103
  - spec/db/models.rb
82
104
  - spec/db/schema.rb
105
+ - spec/fixtures/apple.xml
106
+ - spec/fixtures/result.xml
83
107
  - spec/simple_solr/configuration_spec.rb
84
108
  - spec/simple_solr/search_spec.rb
85
109
  - spec/simple_solr/update_spec.rb
86
110
  - spec/simple_solr_spec.rb
87
111
  - spec/spec_helper.rb
88
112
  - spec/support/database.rb
113
+ - spec/support/fakeweb.rb
89
114
  - spec/support/rails.rb
90
115
  homepage: https://github.com/tilsammans/simple_solr
91
116
  licenses: []
@@ -116,10 +141,13 @@ test_files:
116
141
  - spec/config/simple_solr.yml
117
142
  - spec/db/models.rb
118
143
  - spec/db/schema.rb
144
+ - spec/fixtures/apple.xml
145
+ - spec/fixtures/result.xml
119
146
  - spec/simple_solr/configuration_spec.rb
120
147
  - spec/simple_solr/search_spec.rb
121
148
  - spec/simple_solr/update_spec.rb
122
149
  - spec/simple_solr_spec.rb
123
150
  - spec/spec_helper.rb
124
151
  - spec/support/database.rb
152
+ - spec/support/fakeweb.rb
125
153
  - spec/support/rails.rb