mwmitchell-rsolr-ext 0.5.8 → 0.5.9

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.
data/README.rdoc CHANGED
@@ -1,7 +1,7 @@
1
1
  =RSolr::Ext
2
2
  A set of helper methods/modules to assist in building Solr queries and handling responses when using the RSolr library.
3
3
 
4
- NOTE: The API for RSolr::Ext is pre 1.0. Things are be changing!
4
+ NOTE: The API for RSolr::Ext is pre 1.0. Things are changing quickly...
5
5
 
6
6
  ==Request Example
7
7
  std = RSolr::Ext::Request::Standard.new
@@ -22,17 +22,21 @@ NOTE: The API for RSolr::Ext is pre 1.0. Things are be changing!
22
22
 
23
23
  ==Response Example
24
24
  rsolr = RSolr.connect
25
+
25
26
  raw_response = rsolr.select(:q=>'*:*)
26
27
  r = RSolr::Ext::Response::Standard.new(raw_response)
27
28
 
28
- r.header[:params]
29
- r.response[:docs]
30
- r.response[:docs].previous_page
31
-
29
+ r.ok?
30
+ r.params
31
+ r.docs
32
+ r.docs.previous_page
33
+ r.docs.next_page
34
+ r.facets
35
+
32
36
  ===Doc Pagination
33
37
  After creating a RSolr::Ext::Response object, pass-in the response.docs to the will_paginate view helper:
34
38
  rsolr = RSolr.connect
35
39
  raw_response = rsolr.select(:q=>'*:*)
36
40
  @response = RSolr::Ext::Response::Standard.new(raw_response)
37
41
  # in view:
38
- <%= will_paginate @response.response[:docs] %>
42
+ <%= will_paginate @response.docs %>
data/lib/rsolr-ext.rb CHANGED
@@ -15,7 +15,7 @@ module RSolr
15
15
 
16
16
  module Ext
17
17
 
18
- VERSION = '0.5.8'
18
+ VERSION = '0.5.9'
19
19
 
20
20
  autoload :Request, 'rsolr-ext/request.rb'
21
21
  autoload :Response, 'rsolr-ext/response.rb'
@@ -23,7 +23,7 @@ module RSolr::Ext::Request::Queryable
23
23
  def build_query(value, quote_string=false)
24
24
  case value
25
25
  when String,Symbol
26
- return quote_string ? quote(value.to_s) : value.to_s
26
+ quote_string ? quote(value.to_s) : value.to_s
27
27
  when Array
28
28
  value.collect do |v|
29
29
  build_query(v, quote_string)
@@ -1,8 +1,7 @@
1
1
  module RSolr::Ext::Response
2
2
 
3
- autoload :Facetable, 'rsolr-ext/response/facetable'
4
- autoload :Pageable, 'rsolr-ext/response/pageable'
5
- autoload :DocExt, 'rsolr-ext/response/doc_ext'
3
+ autoload :Facets, 'rsolr-ext/response/facets'
4
+ autoload :Docs, 'rsolr-ext/response/docs'
6
5
 
7
6
  class Base < Mash
8
7
 
@@ -10,6 +9,10 @@ module RSolr::Ext::Response
10
9
  self[:responseHeader]
11
10
  end
12
11
 
12
+ def params
13
+ header[:params]
14
+ end
15
+
13
16
  def ok?
14
17
  header[:status] == 0
15
18
  end
@@ -19,32 +22,16 @@ module RSolr::Ext::Response
19
22
  #
20
23
  class Standard < Base
21
24
 
22
- include Facetable
23
-
24
- def initialize(*a)
25
- super(*a)
26
- activate_pagination!
25
+ def initialize(*args)
26
+ super(*args)
27
+ extend Docs
28
+ extend Facets
27
29
  end
28
30
 
29
31
  def response
30
32
  self[:response]
31
33
  end
32
34
 
33
- def docs
34
- response[:docs]
35
- end
36
-
37
- private
38
-
39
- def activate_pagination!
40
- d = self[:response][:docs]
41
- d.each{|dhash| dhash.extend DocExt }
42
- d.extend Pageable
43
- d.start = self[:responseHeader][:params][:start].to_s.to_i
44
- d.per_page = self[:responseHeader][:params][:rows].to_s.to_i
45
- d.total = self[:response][:numFound]
46
- end
47
-
48
35
  end
49
36
 
50
37
  class Dismax < Standard
@@ -58,10 +45,14 @@ module RSolr::Ext::Response
58
45
  # An optional rule can be used for "grepping" field names:
59
46
  # field_list(/_facet$/)
60
47
  def field_list(rule=nil)
61
- self[:fields].select do |k,v|
48
+ fields.select do |k,v|
62
49
  rule ? k =~ rule : true
63
50
  end.collect{|k,v|k}
64
51
  end
52
+
53
+ def fields
54
+ self[:fields]
55
+ end
65
56
 
66
57
  end# end Luke
67
58
 
@@ -0,0 +1,96 @@
1
+ module RSolr::Ext::Response::Docs
2
+
3
+ module Accessable
4
+
5
+ # Helper method to check if value/multi-values exist for a given key.
6
+ # The value can be a string, or a RegExp
7
+ # Multiple "values" can be given; only one needs to match.
8
+ #
9
+ # Example:
10
+ # doc.has?(:location_facet)
11
+ # doc.has?(:location_facet, 'Clemons')
12
+ # doc.has?(:id, 'h009', /^u/i)
13
+ def has?(k, *values)
14
+ return if self[k].nil?
15
+ return true if self.key?(k) and values.empty?
16
+ target = self[k]
17
+ if target.is_a?(Array)
18
+ values.each do |val|
19
+ return target.any?{|tv| val.is_a?(Regexp) ? (tv =~ val) : (tv==val)}
20
+ end
21
+ else
22
+ return values.any? {|val| val.is_a?(Regexp) ? (target =~ val) : (target == val)}
23
+ end
24
+ end
25
+
26
+ # helper
27
+ # key is the name of the field
28
+ # opts is a hash with the following valid keys:
29
+ # - :sep - a string used for joining multivalued field values
30
+ # - :default - a value to return when the key doesn't exist
31
+ # if :sep is nil and the field is a multivalued field, the array is returned
32
+ def get(key, opts={:sep=>', ', :default=>nil})
33
+ if self.key? key
34
+ val = self[key]
35
+ (val.is_a?(Array) and opts[:sep]) ? val.join(opts[:sep]) : val
36
+ else
37
+ opts[:default]
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ module Pageable
44
+
45
+ attr_accessor :start, :per_page, :total
46
+
47
+ # Returns the current page calculated from 'rows' and 'start'
48
+ # WillPaginate hook
49
+ def current_page
50
+ return 1 if start < 1
51
+ per_page_normalized = per_page < 1 ? 1 : per_page
52
+ @current_page ||= (start / per_page_normalized).ceil + 1
53
+ end
54
+
55
+ # Calcuates the total pages from 'numFound' and 'rows'
56
+ # WillPaginate hook
57
+ def total_pages
58
+ @total_pages ||= per_page > 0 ? (total / per_page.to_f).ceil : 1
59
+ end
60
+
61
+ # returns the previous page number or 1
62
+ # WillPaginate hook
63
+ def previous_page
64
+ @previous_page ||= (current_page > 1) ? current_page - 1 : 1
65
+ end
66
+
67
+ # returns the next page number or the last
68
+ # WillPaginate hook
69
+ def next_page
70
+ @next_page ||= (current_page == total_pages) ? total_pages : current_page+1
71
+ end
72
+
73
+ def has_next?
74
+ current_page < total_pages
75
+ end
76
+
77
+ def has_previous?
78
+ current_page > 1
79
+ end
80
+
81
+ end
82
+
83
+ def self.extended(base)
84
+ d = base.response[:docs]
85
+ d.extend Pageable
86
+ d.each{|item|item.extend Accessable}
87
+ d.start = base.header[:params][:start].to_s.to_i
88
+ d.per_page = base.header[:params][:rows].to_s.to_i
89
+ d.total = base.response[:numFound].to_s.to_i
90
+ end
91
+
92
+ def docs
93
+ response[:docs]
94
+ end
95
+
96
+ end
@@ -1,7 +1,7 @@
1
- module RSolr::Ext::Response::Facetable
1
+ module RSolr::Ext::Response::Facets
2
2
 
3
3
  # represents a facet value; which is a field value and its hit count
4
- class FacetValue
4
+ class FacetItem
5
5
  attr_reader :value,:hits
6
6
  def initialize(value,hits)
7
7
  @value,@hits=value,hits
@@ -9,12 +9,12 @@ module RSolr::Ext::Response::Facetable
9
9
  end
10
10
 
11
11
  # represents a facet; which is a field and its values
12
- class Facet
13
- attr_reader :field
14
- attr_accessor :values
15
- def initialize(field)
16
- @field=field
17
- @values=[]
12
+ class FacetField
13
+ attr_reader :name
14
+ attr_accessor :items
15
+ def initialize(name)
16
+ @name=name
17
+ @items=[]
18
18
  end
19
19
  end
20
20
 
@@ -25,25 +25,33 @@ module RSolr::Ext::Response::Facetable
25
25
  def facets
26
26
  # memoize!
27
27
  @facets ||= (
28
- facet_fields.inject([]) do |acc,(facet_field_name,values_and_hits_list)|
29
- acc << facet = Facet.new(facet_field_name)
28
+ all = facet_fields.collect do |(facet_field_name,values_and_hits_list)|
29
+ facet = FacetField.new(facet_field_name)
30
30
  # the values_and_hits_list is an array where a value is immediately followed by it's hit count
31
31
  # so we shift off an item (the value)
32
32
  while value = values_and_hits_list.shift
33
33
  # and then shift off the next to get the hit value
34
- facet.values << FacetValue.new(value, values_and_hits_list.shift)
34
+ facet.items << FacetItem.new(value, values_and_hits_list.shift)
35
35
  # repeat until there are no more pairs in the values_and_hits_list array
36
36
  end
37
- acc
37
+ facet
38
38
  end
39
+ #all.extend RSolr::Ext::Response::Docs::Pageable
40
+ #all.start = header['params']['facet.offset'].to_s.to_i
41
+ #all.per_page = header['params']['facet.limit'].to_s.to_i - 1
42
+ #all.total = -1
43
+ ## override the has_next? method -- when paging through facets,
44
+ ## it's not possible to know how many "pages" there are
45
+ #all.instance_eval "def has_next?; #{all.size == all.per_page+1} end"
46
+ all
39
47
  )
40
48
  end
41
-
49
+
42
50
  # pass in a facet field name and get back a Facet instance
43
51
  def facet_by_field_name(name)
44
52
  @facets_by_field_name ||= {}
45
53
  @facets_by_field_name[name] ||= (
46
- facets.detect{|facet|facet.field.to_s == name.to_s}
54
+ facets.detect{|facet|facet.name.to_s == name.to_s}
47
55
  )
48
56
  end
49
57
 
data/rsolr-ext.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "rsolr-ext"
3
- s.version = "0.5.8"
4
- s.date = "2009-03-18"
3
+ s.version = "0.5.9"
4
+ s.date = "2009-03-20"
5
5
  s.summary = "An extension lib for RSolr"
6
6
  s.email = "goodieboy@gmail.com"
7
7
  s.homepage = "http://github.com/mwmitchell/rsolr_ext"
@@ -18,10 +18,8 @@ Gem::Specification.new do |s|
18
18
  "lib/rsolr-ext/request/queryable.rb",
19
19
  "lib/rsolr-ext/request.rb",
20
20
 
21
- "lib/rsolr-ext/response/doc_ext.rb",
22
- "lib/rsolr-ext/response/facet_paginator.rb",
23
- "lib/rsolr-ext/response/facetable.rb",
24
- "lib/rsolr-ext/response/pageable.rb",
21
+ "lib/rsolr-ext/response/docs.rb",
22
+ "lib/rsolr-ext/response/facets.rb",
25
23
  "lib/rsolr-ext/response.rb",
26
24
 
27
25
  "lib/rsolr-ext.rb",
data/test/helper.rb CHANGED
@@ -1,21 +1,3 @@
1
1
  def mock_query_response
2
- %({'responseHeader'=>{
3
- 'status'=>0,'QTime'=>43,'params'=>{
4
- 'q'=>'*:*','wt'=>'ruby','echoParams'=>'EXPLICIT'
5
- }
6
- },
7
- 'response'=>{
8
- 'numFound'=>26,'start'=>0,'docs'=>[
9
- {'id'=>'SP2514N','inStock'=>true,'manu'=>'Samsung Electronics Co. Ltd.','name'=>'Samsung SpinPoint P120 SP2514N - hard drive - 250 GB - ATA-133','popularity'=>6,'price'=>92.0,'sku'=>'SP2514N','timestamp'=>'2008-11-21T17:21:55.601Z','cat'=>['electronics','hard drive'],'spell'=>['Samsung SpinPoint P120 SP2514N - hard drive - 250 GB - ATA-133'],'features'=>['7200RPM, 8MB cache, IDE Ultra ATA-133','NoiseGuard, SilentSeek technology, Fluid Dynamic Bearing (FDB) motor']},
10
- {'id'=>'6H500F0','inStock'=>true,'manu'=>'Maxtor Corp.','name'=>'Maxtor DiamondMax 11 - hard drive - 500 GB - SATA-300','popularity'=>6,'price'=>350.0,'sku'=>'6H500F0','timestamp'=>'2008-11-21T17:21:55.617Z','cat'=>['electronics','hard drive'],'spell'=>['Maxtor DiamondMax 11 - hard drive - 500 GB - SATA-300'],'features'=>['SATA 3.0Gb/s, NCQ','8.5ms seek','16MB cache']},
11
- {'id'=>'F8V7067-APL-KIT','inStock'=>false,'manu'=>'Belkin','name'=>'Belkin Mobile Power Cord for iPod w/ Dock','popularity'=>1,'price'=>19.95,'sku'=>'F8V7067-APL-KIT','timestamp'=>'2008-11-21T17:21:55.652Z','weight'=>4.0,'cat'=>['electronics','connector'],'spell'=>['Belkin Mobile Power Cord for iPod w/ Dock'],'features'=>['car power adapter, white']},
12
- {'id'=>'IW-02','inStock'=>false,'manu'=>'Belkin','name'=>'iPod & iPod Mini USB 2.0 Cable','popularity'=>1,'price'=>11.5,'sku'=>'IW-02','timestamp'=>'2008-11-21T17:21:55.657Z','weight'=>2.0,'cat'=>['electronics','connector'],'spell'=>['iPod & iPod Mini USB 2.0 Cable'],'features'=>['car power adapter for iPod, white']},
13
- {'id'=>'MA147LL/A','inStock'=>true,'includes'=>'earbud headphones, USB cable','manu'=>'Apple Computer Inc.','name'=>'Apple 60 GB iPod with Video Playback Black','popularity'=>10,'price'=>399.0,'sku'=>'MA147LL/A','timestamp'=>'2008-11-21T17:21:55.681Z','weight'=>5.5,'cat'=>['electronics','music'],'spell'=>['Apple 60 GB iPod with Video Playback Black'],'features'=>['iTunes, Podcasts, Audiobooks','Stores up to 15,000 songs, 25,000 photos, or 150 hours of video','2.5-inch, 320x240 color TFT LCD display with LED backlight','Up to 20 hours of battery life','Plays AAC, MP3, WAV, AIFF, Audible, Apple Lossless, H.264 video','Notes, Calendar, Phone book, Hold button, Date display, Photo wallet, Built-in games, JPEG photo playback, Upgradeable firmware, USB 2.0 compatibility, Playback speed control, Rechargeable capability, Battery level indication']},
14
- {'id'=>'TWINX2048-3200PRO','inStock'=>true,'manu'=>'Corsair Microsystems Inc.','name'=>'CORSAIR XMS 2GB (2 x 1GB) 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) Dual Channel Kit System Memory - Retail','popularity'=>5,'price'=>185.0,'sku'=>'TWINX2048-3200PRO','timestamp'=>'2008-11-21T17:21:55.706Z','cat'=>['electronics','memory'],'spell'=>['CORSAIR XMS 2GB (2 x 1GB) 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) Dual Channel Kit System Memory - Retail'],'features'=>['CAS latency 2, 2-3-3-6 timing, 2.75v, unbuffered, heat-spreader']},
15
- {'id'=>'VS1GB400C3','inStock'=>true,'manu'=>'Corsair Microsystems Inc.','name'=>'CORSAIR ValueSelect 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - Retail','popularity'=>7,'price'=>74.99,'sku'=>'VS1GB400C3','timestamp'=>'2008-11-21T17:21:55.71Z','cat'=>['electronics','memory'],'spell'=>['CORSAIR ValueSelect 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - Retail']},
16
- {'id'=>'VDBDB1A16','inStock'=>true,'manu'=>'A-DATA Technology Inc.','name'=>'A-DATA V-Series 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - OEM','popularity'=>5,'sku'=>'VDBDB1A16','timestamp'=>'2008-11-21T17:21:55.712Z','cat'=>['electronics','memory'],'spell'=>['A-DATA V-Series 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - OEM'],'features'=>['CAS latency 3, 2.7v']},
17
- {'id'=>'3007WFP','inStock'=>true,'includes'=>'USB cable','manu'=>'Dell, Inc.','name'=>'Dell Widescreen UltraSharp 3007WFP','popularity'=>6,'price'=>2199.0,'sku'=>'3007WFP','timestamp'=>'2008-11-21T17:21:55.724Z','weight'=>401.6,'cat'=>['electronics','monitor'],'spell'=>['Dell Widescreen UltraSharp 3007WFP'],'features'=>['30" TFT active matrix LCD, 2560 x 1600, .25mm dot pitch, 700:1 contrast']},
18
- {'id'=>'VA902B','inStock'=>true,'manu'=>'ViewSonic Corp.','name'=>'ViewSonic VA902B - flat panel display - TFT - 19"','popularity'=>6,'price'=>279.95,'sku'=>'VA902B','timestamp'=>'2008-11-21T17:21:55.734Z','weight'=>190.4,'cat'=>['electronics','monitor'],'spell'=>['ViewSonic VA902B - flat panel display - TFT - 19"'],'features'=>['19" TFT active matrix LCD, 8ms response time, 1280 x 1024 native resolution']}]
19
- }
20
- })
2
+ %({'responseHeader'=>{'status'=>0,'QTime'=>5,'params'=>{'facet.limit'=>'10','wt'=>'ruby','rows'=>'11','facet'=>'true','facet.field'=>['manu','cat'],'echoParams'=>'EXPLICIT','q'=>'*:*','facet.sort'=>'true'}},'response'=>{'numFound'=>26,'start'=>0,'docs'=>[{'id'=>'SP2514N','inStock'=>true,'manu'=>'Samsung Electronics Co. Ltd.','name'=>'Samsung SpinPoint P120 SP2514N - hard drive - 250 GB - ATA-133','popularity'=>6,'price'=>92.0,'sku'=>'SP2514N','timestamp'=>'2009-03-20T14:42:49.795Z','cat'=>['electronics','hard drive'],'spell'=>['Samsung SpinPoint P120 SP2514N - hard drive - 250 GB - ATA-133'],'features'=>['7200RPM, 8MB cache, IDE Ultra ATA-133','NoiseGuard, SilentSeek technology, Fluid Dynamic Bearing (FDB) motor']},{'id'=>'6H500F0','inStock'=>true,'manu'=>'Maxtor Corp.','name'=>'Maxtor DiamondMax 11 - hard drive - 500 GB - SATA-300','popularity'=>6,'price'=>350.0,'sku'=>'6H500F0','timestamp'=>'2009-03-20T14:42:49.877Z','cat'=>['electronics','hard drive'],'spell'=>['Maxtor DiamondMax 11 - hard drive - 500 GB - SATA-300'],'features'=>['SATA 3.0Gb/s, NCQ','8.5ms seek','16MB cache']},{'id'=>'F8V7067-APL-KIT','inStock'=>false,'manu'=>'Belkin','name'=>'Belkin Mobile Power Cord for iPod w/ Dock','popularity'=>1,'price'=>19.95,'sku'=>'F8V7067-APL-KIT','timestamp'=>'2009-03-20T14:42:49.937Z','weight'=>4.0,'cat'=>['electronics','connector'],'spell'=>['Belkin Mobile Power Cord for iPod w/ Dock'],'features'=>['car power adapter, white']},{'id'=>'IW-02','inStock'=>false,'manu'=>'Belkin','name'=>'iPod & iPod Mini USB 2.0 Cable','popularity'=>1,'price'=>11.5,'sku'=>'IW-02','timestamp'=>'2009-03-20T14:42:49.944Z','weight'=>2.0,'cat'=>['electronics','connector'],'spell'=>['iPod & iPod Mini USB 2.0 Cable'],'features'=>['car power adapter for iPod, white']},{'id'=>'MA147LL/A','inStock'=>true,'includes'=>'earbud headphones, USB cable','manu'=>'Apple Computer Inc.','name'=>'Apple 60 GB iPod with Video Playback Black','popularity'=>10,'price'=>399.0,'sku'=>'MA147LL/A','timestamp'=>'2009-03-20T14:42:49.962Z','weight'=>5.5,'cat'=>['electronics','music'],'spell'=>['Apple 60 GB iPod with Video Playback Black'],'features'=>['iTunes, Podcasts, Audiobooks','Stores up to 15,000 songs, 25,000 photos, or 150 hours of video','2.5-inch, 320x240 color TFT LCD display with LED backlight','Up to 20 hours of battery life','Plays AAC, MP3, WAV, AIFF, Audible, Apple Lossless, H.264 video','Notes, Calendar, Phone book, Hold button, Date display, Photo wallet, Built-in games, JPEG photo playback, Upgradeable firmware, USB 2.0 compatibility, Playback speed control, Rechargeable capability, Battery level indication']},{'id'=>'TWINX2048-3200PRO','inStock'=>true,'manu'=>'Corsair Microsystems Inc.','name'=>'CORSAIR XMS 2GB (2 x 1GB) 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) Dual Channel Kit System Memory - Retail','popularity'=>5,'price'=>185.0,'sku'=>'TWINX2048-3200PRO','timestamp'=>'2009-03-20T14:42:49.99Z','cat'=>['electronics','memory'],'spell'=>['CORSAIR XMS 2GB (2 x 1GB) 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) Dual Channel Kit System Memory - Retail'],'features'=>['CAS latency 2, 2-3-3-6 timing, 2.75v, unbuffered, heat-spreader']},{'id'=>'VS1GB400C3','inStock'=>true,'manu'=>'Corsair Microsystems Inc.','name'=>'CORSAIR ValueSelect 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - Retail','popularity'=>7,'price'=>74.99,'sku'=>'VS1GB400C3','timestamp'=>'2009-03-20T14:42:50Z','cat'=>['electronics','memory'],'spell'=>['CORSAIR ValueSelect 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - Retail']},{'id'=>'VDBDB1A16','inStock'=>true,'manu'=>'A-DATA Technology Inc.','name'=>'A-DATA V-Series 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - OEM','popularity'=>5,'sku'=>'VDBDB1A16','timestamp'=>'2009-03-20T14:42:50.004Z','cat'=>['electronics','memory'],'spell'=>['A-DATA V-Series 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - OEM'],'features'=>['CAS latency 3, 2.7v']},{'id'=>'3007WFP','inStock'=>true,'includes'=>'USB cable','manu'=>'Dell, Inc.','name'=>'Dell Widescreen UltraSharp 3007WFP','popularity'=>6,'price'=>2199.0,'sku'=>'3007WFP','timestamp'=>'2009-03-20T14:42:50.017Z','weight'=>401.6,'cat'=>['electronics','monitor'],'spell'=>['Dell Widescreen UltraSharp 3007WFP'],'features'=>['30" TFT active matrix LCD, 2560 x 1600, .25mm dot pitch, 700:1 contrast']},{'id'=>'VA902B','inStock'=>true,'manu'=>'ViewSonic Corp.','name'=>'ViewSonic VA902B - flat panel display - TFT - 19"','popularity'=>6,'price'=>279.95,'sku'=>'VA902B','timestamp'=>'2009-03-20T14:42:50.034Z','weight'=>190.4,'cat'=>['electronics','monitor'],'spell'=>['ViewSonic VA902B - flat panel display - TFT - 19"'],'features'=>['19" TFT active matrix LCD, 8ms response time, 1280 x 1024 native resolution']},{'id'=>'0579B002','inStock'=>true,'manu'=>'Canon Inc.','name'=>'Canon PIXMA MP500 All-In-One Photo Printer','popularity'=>6,'price'=>179.99,'sku'=>'0579B002','timestamp'=>'2009-03-20T14:42:50.062Z','weight'=>352.0,'cat'=>['electronics','multifunction printer','printer','scanner','copier'],'spell'=>['Canon PIXMA MP500 All-In-One Photo Printer'],'features'=>['Multifunction ink-jet color photo printer','Flatbed scanner, optical scan resolution of 1,200 x 2,400 dpi','2.5" color LCD preview screen','Duplex Copying','Printing speed up to 29ppm black, 19ppm color','Hi-Speed USB','memory card: CompactFlash, Micro Drive, SmartMedia, Memory Stick, Memory Stick Pro, SD Card, and MultiMediaCard']}]},'facet_counts'=>{'facet_queries'=>{},'facet_fields'=>{'manu'=>['inc',8,'apach',2,'belkin',2,'canon',2,'comput',2,'corp',2,'corsair',2,'foundat',2,'microsystem',2,'softwar',2],'cat'=>['electronics',14,'memory',3,'card',2,'connector',2,'drive',2,'graphics',2,'hard',2,'monitor',2,'search',2,'software',2]},'facet_dates'=>{}}})
21
3
  end
@@ -16,13 +16,13 @@ class RSolrExtResponseTest < Test::Unit::TestCase
16
16
  r = RSolr::Ext::Response::Standard.new(raw_response)
17
17
  assert r.respond_to?(:response)
18
18
  assert r.ok?
19
- assert_equal 10, r[:response][:docs].size
20
- assert_equal 'EXPLICIT', r[:responseHeader][:params][:echoParams]
21
- assert_equal 1, r[:response][:docs].previous_page
22
- assert_equal 1, r[:response][:docs].next_page
19
+ assert_equal 11, r.docs.size
20
+ assert_equal 'EXPLICIT', r.params[:echoParams]
21
+ assert_equal 1, r.docs.previous_page
22
+ assert_equal 2, r.docs.next_page
23
23
  #
24
- assert r[:response][:docs].kind_of?(RSolr::Ext::Response::Pageable)
25
- assert r.kind_of?(RSolr::Ext::Response::Facetable)
24
+ assert r.kind_of?(RSolr::Ext::Response::Docs)
25
+ assert r.kind_of?(RSolr::Ext::Response::Facets)
26
26
  end
27
27
 
28
28
  test 'standard response doc ext methods' do
@@ -38,4 +38,68 @@ class RSolrExtResponseTest < Test::Unit::TestCase
38
38
  assert_equal 'def', doc.get(:xyz, :default=>'def')
39
39
  end
40
40
 
41
+ test 'Response::Standard facets' do
42
+ raw_response = eval(mock_query_response)
43
+ r = RSolr::Ext::Response::Standard.new(raw_response)
44
+ assert_equal 2, r.facets.size
45
+
46
+ field_names = r.facets.collect{|facet|facet.name}
47
+ assert field_names.include?('cat')
48
+ assert field_names.include?('manu')
49
+
50
+ first_facet = r.facets.first
51
+ assert_equal 'cat', first_facet.name
52
+ assert_equal 10, first_facet.items.size
53
+
54
+ expected = first_facet.items.collect do |item|
55
+ item.value + ' - ' + item.hits.to_s
56
+ end.join(', ')
57
+ assert_equal "electronics - 14, memory - 3, card - 2, connector - 2, drive - 2, graphics - 2, hard - 2, monitor - 2, search - 2, software - 2", expected
58
+
59
+ r.facets.each do |facet|
60
+ assert facet.respond_to?(:name)
61
+ facet.items.each do |item|
62
+ assert item.respond_to?(:value)
63
+ assert item.respond_to?(:hits)
64
+ end
65
+ end
66
+
67
+ end
68
+
69
+ test 'response::standard facet_by_field_name' do
70
+ raw_response = eval(mock_query_response)
71
+ r = RSolr::Ext::Response::Standard.new(raw_response)
72
+ facet = r.facet_by_field_name('cat')
73
+ assert_equal 'cat', facet.name
74
+ end
75
+
76
+ =begin
77
+
78
+ # pagination for facets has been commented out in the response/facets module.
79
+ # ...need to think more about how this can be handled
80
+
81
+ test 'response::standard facets.paginate' do
82
+ raw_response = eval(mock_query_response)
83
+ raw_response['responseHeader']['params']['facet.offset'] = 1
84
+ raw_response['responseHeader']['params']['facet.limit'] = 2
85
+
86
+ r = RSolr::Ext::Response::Standard.new(raw_response)
87
+
88
+ assert_equal 2, r.facets.current_page
89
+
90
+ # always 1 less than facet.limit
91
+ assert_equal 1, r.facets.per_page
92
+
93
+ assert_equal 3, r.facets.next_page
94
+
95
+ assert_equal 1, r.facets.previous_page
96
+
97
+ # can't know how many pages there are with facets.... so we set it to -1
98
+ assert_equal -1, r.facets.total_pages
99
+
100
+ assert r.facets.has_next?
101
+ assert r.facets.has_previous?
102
+ end
103
+ =end
104
+
41
105
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mwmitchell-rsolr-ext
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.8
4
+ version: 0.5.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Mitchell
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-03-18 00:00:00 -07:00
12
+ date: 2009-03-20 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -28,10 +28,8 @@ files:
28
28
  - lib/rsolr-ext/mapable.rb
29
29
  - lib/rsolr-ext/request/queryable.rb
30
30
  - lib/rsolr-ext/request.rb
31
- - lib/rsolr-ext/response/doc_ext.rb
32
- - lib/rsolr-ext/response/facet_paginator.rb
33
- - lib/rsolr-ext/response/facetable.rb
34
- - lib/rsolr-ext/response/pageable.rb
31
+ - lib/rsolr-ext/response/docs.rb
32
+ - lib/rsolr-ext/response/facets.rb
35
33
  - lib/rsolr-ext/response.rb
36
34
  - lib/rsolr-ext.rb
37
35
  - LICENSE
@@ -1,38 +0,0 @@
1
- # module for adding helper methods to each solr response[:docs] object
2
- module RSolr::Ext::Response::DocExt
3
-
4
- # Helper method to check if value/multi-values exist for a given key.
5
- # The value can be a string, or a RegExp
6
- # Example:
7
- # doc.has?(:location_facet)
8
- # doc.has?(:location_facet, 'Clemons')
9
- # doc.has?(:id, 'h009', /^u/i)
10
- def has?(k, *values)
11
- return if self[k].nil?
12
- return true if self.key?(k) and values.empty?
13
- target = self[k]
14
- if target.is_a?(Array)
15
- values.each do |val|
16
- return target.any?{|tv| val.is_a?(Regexp) ? (tv =~ val) : (tv==val)}
17
- end
18
- else
19
- return values.any? {|val| val.is_a?(Regexp) ? (target =~ val) : (target == val)}
20
- end
21
- end
22
-
23
- # helper
24
- # key is the name of the field
25
- # opts is a hash with the following valid keys:
26
- # - :sep - a string used for joining multivalued field values
27
- # - :default - a value to return when the key doesn't exist
28
- # if :sep is nil and the field is a multivalued field, the array is returned
29
- def get(key, opts={:sep=>', ', :default=>nil})
30
- if self.key? key
31
- val = self[key]
32
- (val.is_a?(Array) and opts[:sep]) ? val.join(opts[:sep]) : val
33
- else
34
- opts[:default]
35
- end
36
- end
37
-
38
- end
@@ -1,24 +0,0 @@
1
- class RSolr::Ext::Response::FacetPaginator
2
-
3
- attr_reader :total, :items, :previous_offset, :next_offset
4
-
5
- def initialize(all_facet_values, offset, limit)
6
- offset = offset.to_s.to_i
7
- limit = limit.to_s.to_i
8
- total = all_facet_values.size
9
- @items = all_facet_values.slice(0, limit-1)
10
- @has_next = total == limit
11
- @has_previous = offset > 0
12
- @next_offset = offset + (limit-1)
13
- @previous_offset = offset - (limit-1)
14
- end
15
-
16
- def has_next?
17
- @has_next
18
- end
19
-
20
- def has_previous?
21
- @has_previous
22
- end
23
-
24
- end
@@ -1,30 +0,0 @@
1
- module RSolr::Ext::Response::Pageable
2
-
3
- attr_accessor :start, :per_page, :total
4
-
5
- # Returns the current page calculated from 'rows' and 'start'
6
- # WillPaginate hook
7
- def current_page
8
- return 1 if start < 1
9
- @current_page ||= (start / per_page).ceil + 1
10
- end
11
-
12
- # Calcuates the total pages from 'numFound' and 'rows'
13
- # WillPaginate hook
14
- def total_pages
15
- @total_pages ||= per_page > 0 ? (total / per_page.to_f).ceil : 1
16
- end
17
-
18
- # returns the previous page number or 1
19
- # WillPaginate hook
20
- def previous_page
21
- @previous_page ||= (current_page > 1) ? current_page - 1 : 1
22
- end
23
-
24
- # returns the next page number or the last
25
- # WillPaginate hook
26
- def next_page
27
- @next_page ||= (current_page < total_pages) ? current_page + 1 : total_pages
28
- end
29
-
30
- end