solr4r 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/lib/solr4r/client.rb CHANGED
@@ -7,7 +7,7 @@
7
7
  # #
8
8
  # Copyright (C) 2014-2015 Jens Wille #
9
9
  # #
10
- # Mir is free software: you can redistribute it and/or modify it under the #
10
+ # solr4r is free software: you can redistribute it and/or modify it under the #
11
11
  # terms of the GNU Affero General Public License as published by the Free #
12
12
  # Software Foundation, either version 3 of the License, or (at your option) #
13
13
  # any later version. #
@@ -30,178 +30,143 @@ module Solr4R
30
30
  include Logging
31
31
 
32
32
  DEFAULT_HOST = 'localhost'
33
- DEFAULT_PATH = 'solr'
34
33
  DEFAULT_PORT = 8983
34
+ DEFAULT_PATH = 'solr'
35
+ DEFAULT_CORE = 'collection1'
35
36
 
36
- DEFAULT_PARAMS = {
37
- wt: :json
38
- }
39
-
40
- DEFAULT_BATCH_SIZE = 1000
41
-
42
- DEFAULT_ENDPOINTS = %w[select query spell suggest terms] <<
43
- ['ping', path: 'admin/ping', method: :head] <<
44
- ['dump', path: 'debug/dump']
45
-
46
- DEFAULT_SELECT_PATH = 'select'
47
-
48
- DEFAULT_UPDATE_PATH = 'update'
49
-
50
- DEFAULT_MLT_PATH = 'mlt'
51
-
52
- SYSTEM_INFO_PATH = 'admin/info/system'
53
-
54
- MATCH_ALL_QUERY = '*:*'
55
-
56
- def initialize(options = {})
57
- uri, options = options, {} unless options.is_a?(Hash)
58
-
59
- self.options = options
60
-
61
- uri ||= options.fetch(:uri, default_uri)
62
-
63
- self.logger = options.fetch(:logger, default_logger)
37
+ DEFAULT_PARAMS = { wt: :json }
64
38
 
65
- self.builder = options.fetch(:builder) {
66
- forward_logger(Builder.new) }
39
+ class << self
67
40
 
68
- self.request = options.fetch(:request) {
69
- forward_logger(Request.new(self, uri)) }
41
+ def default_uri(options = {})
42
+ 'http://%s:%d/%s/%s' % [
43
+ options.fetch(:host, DEFAULT_HOST),
44
+ options.fetch(:port, DEFAULT_PORT),
45
+ options.fetch(:path, DEFAULT_PATH),
46
+ options.fetch(:core, DEFAULT_CORE)
47
+ ]
48
+ end
70
49
 
71
- self.default_params = options.fetch(:default_params, DEFAULT_PARAMS)
50
+ def query_string(query, escape = true)
51
+ case query
52
+ when nil
53
+ # ignore
54
+ when String
55
+ escape(query, escape) unless query.empty?
56
+ when Array
57
+ if query.last.is_a?(Hash)
58
+ lp, qs = query_from_hash((query = query.dup).pop, escape)
59
+ query << qs if qs
60
+ end
61
+
62
+ query_with_params(lp, query_string(query.join(' '), escape))
63
+ when Hash
64
+ query_with_params(*query_from_hash(query, escape))
65
+ else
66
+ type_error(query)
67
+ end
68
+ end
72
69
 
73
- register_endpoints(options.fetch(:endpoints, DEFAULT_ENDPOINTS))
74
- end
70
+ def local_params_string(local_params, hash = {}, escape = true)
71
+ case local_params = expand_local_params(local_params, hash)
72
+ when nil
73
+ # ignore
74
+ when String
75
+ escape("{!#{local_params}}", escape) unless local_params.empty?
76
+ when Array
77
+ local_params_string(local_params.join(' '), {}, escape)
78
+ when Hash
79
+ local_params_string(local_params.map { |key, value|
80
+ "#{key}=#{value =~ /\s/ ? %Q{"#{value}"} : value}" }, {}, escape)
81
+ else
82
+ type_error(local_params)
83
+ end
84
+ end
75
85
 
76
- attr_accessor :options, :builder, :request, :default_params
86
+ def escape(string, escape = true)
87
+ escape ? string.gsub('&', '%26') : string
88
+ end
77
89
 
78
- def register_endpoints(endpoints)
79
- endpoints.each { |args| register_endpoint(*args) } if endpoints
80
- self
81
- end
90
+ private
82
91
 
83
- def register_endpoint(path, options = {})
84
- name, path = path, options.fetch(:path, path)
92
+ def query_from_hash(query, escape)
93
+ local_params = query.key?(lp = :_) &&
94
+ local_params_string((query = query.dup).delete(lp), {}, escape)
85
95
 
86
- if error = invalid_endpoint?(name.to_s)
87
- raise ArgumentError, "invalid endpoint: #{name} (#{error})"
88
- else
89
- define_singleton_method(name) { |_params = {}, _options = {}, &block|
90
- send_request(path, options.merge(_options.merge(
91
- params: options.fetch(:params, {}).merge(_params))), &block)
92
- }
96
+ [local_params, query_string(query.flat_map { |key, values|
97
+ Array(values).map { |value| "#{key}:#{value}" } }, escape)]
93
98
  end
94
99
 
95
- self
96
- end
97
-
98
- def json(path, params = {}, options = {}, &block)
99
- get(path, params.merge(wt: :json), options, &block).result
100
- end
101
-
102
- def get(path, params = {}, options = {}, &block)
103
- send_request(path, options.merge(method: :get, params: params), &block)
104
- end
100
+ def query_with_params(local_params, query_string)
101
+ local_params ? local_params + query_string : query_string
102
+ end
105
103
 
106
- def post(path, data = nil, options = {}, &block)
107
- send_request(path, options.merge(method: :post, data: data), &block)
108
- end
104
+ def expand_local_params(local_params, hash)
105
+ case type = hash[:type]
106
+ when nil
107
+ local_params
108
+ when String, Symbol
109
+ type_error(local_params, :Array) unless local_params.is_a?(Array)
110
+
111
+ local_params.each { |param| hash[param] = "$#{type}.#{param}" }
112
+ hash
113
+ else
114
+ type_error(type, %w[String Symbol])
115
+ end
116
+ end
109
117
 
110
- def head(path, params = {}, options = {}, &block)
111
- send_request(path, options.merge(method: :head, params: params), &block)
112
- end
118
+ def type_error(obj, types = %w[String Array Hash])
119
+ types = Array(types).join(' or ')
120
+ raise TypeError, "#{types} expected, got #{obj.class}", caller(1)
121
+ end
113
122
 
114
- def update(data, options = {}, path = DEFAULT_UPDATE_PATH, &block)
115
- options = amend_options(options, :headers, 'Content-Type' => 'text/xml')
116
- post(path, data, options, &block)
117
123
  end
118
124
 
119
- # See Builder#add.
120
- def add(doc, attributes = {}, options = {}, &block)
121
- update(builder.add(doc, attributes), options, &block)
122
- end
125
+ def initialize(options = {})
126
+ uri, options = options, {} unless options.is_a?(Hash)
123
127
 
124
- def add_batch(docs, attributes = {}, options = {}, batch_size = DEFAULT_BATCH_SIZE, &block)
125
- failed = []
128
+ self.options, self.default_params =
129
+ options, options.fetch(:default_params, DEFAULT_PARAMS)
126
130
 
127
- docs.each_slice(batch_size) { |batch|
128
- unless add(batch, attributes, options, &block).success?
129
- failed.concat(batch_size == 1 ? batch : add_batch(
130
- batch, attributes, options, batch_size / 10, &block))
131
- end
132
- }
131
+ self.logger = options.fetch(:logger) { default_logger }
133
132
 
134
- failed
135
- end
133
+ self.builder = options.fetch(:builder) { forward_logger(Builder.new) }
136
134
 
137
- # See Builder#commit.
138
- def commit(attributes = {}, options = {}, &block)
139
- update(builder.commit(attributes), options, &block)
140
- end
135
+ self.request = options.fetch(:request) { forward_logger(Request.new(
136
+ self, uri || options.fetch(:uri) { default_uri })) }
141
137
 
142
- # See Builder#optimize.
143
- def optimize(attributes = {}, options = {}, &block)
144
- update(builder.optimize(attributes), options, &block)
138
+ self.endpoints = forward_logger(Endpoints.new(self))
145
139
  end
146
140
 
147
- # See Builder#rollback.
148
- def rollback(options = {}, &block)
149
- update(builder.rollback, options, &block)
150
- end
141
+ attr_accessor :options, :builder, :request, :default_params, :endpoints
151
142
 
152
- # See Builder#delete.
153
- def delete(hash, options = {}, &block)
154
- update(builder.delete(hash), options, &block)
155
- end
143
+ alias_method :ep, :endpoints
156
144
 
157
- # See #delete.
158
- def delete_by_id(id, options = {}, &block)
159
- delete({ id: id }, options, &block)
160
- end
145
+ def json(path,
146
+ params = {}, options = {}, &block)
161
147
 
162
- # See #delete.
163
- def delete_by_query(query, options = {}, &block)
164
- delete({ query: query }, options, &block)
148
+ get(path, params.merge(wt: :json), options, &block).result
165
149
  end
166
150
 
167
- # See #delete_by_query.
168
- def delete_all!(options = {}, &block)
169
- delete_by_query(MATCH_ALL_QUERY, options, &block)
170
- end
151
+ def get(path,
152
+ params = {}, options = {}, &block)
171
153
 
172
- def count(params = {}, options = {}, path = DEFAULT_SELECT_PATH, &block)
173
- params = params.merge(rows: 0)
174
- params[:q] ||= MATCH_ALL_QUERY
175
- get(path, params, options, &block)
154
+ send_request(path, options.merge(
155
+ method: :get, params: params), &block)
176
156
  end
177
157
 
178
- def json_query(params = {}, options = {}, path = DEFAULT_SELECT_PATH, &block)
179
- json(path, params.merge(q: query_string(params[:q])), options, &block)
180
- end
158
+ def post(path, data = nil,
159
+ params = {}, options = {}, &block)
181
160
 
182
- def more_like_this(params = {}, options = {}, path = DEFAULT_MLT_PATH, &block)
183
- json_query(params, options, path, &block)
161
+ send_request(path, options.merge(
162
+ method: :post, params: params, data: data), &block)
184
163
  end
185
164
 
186
- def query_string(query)
187
- case query
188
- when nil
189
- # ignore
190
- when String
191
- query.gsub('&', '%26')
192
- when Array, Hash
193
- query.flat_map { |key, values|
194
- Array(values).map { |value|
195
- query_string("#{key}:#{value}")
196
- }
197
- }.join(' ')
198
- else
199
- query_string(query.to_s)
200
- end
201
- end
165
+ def head(path,
166
+ params = {}, options = {}, &block)
202
167
 
203
- def solr_version(type = :spec)
204
- json(SYSTEM_INFO_PATH) % "lucene/solr-#{type}-version"
168
+ send_request(path, options.merge(
169
+ method: :head, params: params), &block)
205
170
  end
206
171
 
207
172
  def inspect
@@ -213,27 +178,26 @@ module Solr4R
213
178
  private
214
179
 
215
180
  def default_uri
216
- 'http://%s:%d/%s' % [
217
- options.fetch(:host, DEFAULT_HOST),
218
- options.fetch(:port, DEFAULT_PORT),
219
- options.fetch(:path, DEFAULT_PATH)
220
- ]
181
+ self.class.default_uri(options)
221
182
  end
222
183
 
223
- def amend_options(options, key, value)
184
+ def amend_options_hash(options, key, value)
224
185
  options.merge(key => value.merge(options.fetch(key, {})))
225
186
  end
226
187
 
227
- def send_request(path, options, &block)
228
- request.execute(path,
229
- amend_options(options, :params, default_params), &block)
188
+ def amend_options_array(options, key, *value)
189
+ options.merge(key => Array(options[key]).dup.concat(value))
230
190
  end
231
191
 
232
- def invalid_endpoint?(name)
233
- 'method already defined' if respond_to?(name) || (
234
- respond_to?(name, true) && !DEFAULT_ENDPOINTS.flatten.include?(name))
192
+ def send_request(path, options, &block)
193
+ request.execute(path, amend_options_hash(
194
+ options, :params, default_params), &block)
235
195
  end
236
196
 
237
197
  end
238
198
 
239
199
  end
200
+
201
+ require_relative 'client/update'
202
+ require_relative 'client/query'
203
+ require_relative 'client/admin'
@@ -7,7 +7,7 @@
7
7
  # #
8
8
  # Copyright (C) 2014-2015 Jens Wille #
9
9
  # #
10
- # Mir is free software: you can redistribute it and/or modify it under the #
10
+ # solr4r is free software: you can redistribute it and/or modify it under the #
11
11
  # terms of the GNU Affero General Public License as published by the Free #
12
12
  # Software Foundation, either version 3 of the License, or (at your option) #
13
13
  # any later version. #
@@ -31,12 +31,6 @@ module Solr4R
31
31
 
32
32
  extend Forwardable
33
33
 
34
- UNIQUE_KEY = 'id'
35
-
36
- MLT_DEFAULT_FL = '*,score'
37
-
38
- MLT_DEFAULT_ROWS = 5
39
-
40
34
  def initialize(result, hash)
41
35
  @result, @hash = result, hash
42
36
  end
@@ -45,20 +39,26 @@ module Solr4R
45
39
 
46
40
  def_delegators :result, :client
47
41
 
48
- def_delegators :to_hash, :[], :each, :to_json
42
+ def_delegators :to_hash, :[], :each, :fetch, :to_json
49
43
 
50
44
  def to_hash
51
45
  @hash
52
46
  end
53
47
 
54
- def more_like_this(fl = nil, params = {}, *args, &block)
55
- client.more_like_this(params.merge(
56
- q: { id: self[UNIQUE_KEY] },
57
- fl: params.fetch(:fl, MLT_DEFAULT_FL),
58
- rows: params.fetch(:rows, MLT_DEFAULT_ROWS),
59
- 'mlt.fl' => Array(fl).join(',')), *args, &block)
48
+ def id
49
+ fetch('id')
50
+ end
51
+
52
+ def more_like_this_h(*args, &block)
53
+ client.more_like_this_h(id, *args, &block)
54
+ end
55
+
56
+ def more_like_this_q(*args, &block)
57
+ client.more_like_this_q(id, *args, &block)
60
58
  end
61
59
 
60
+ alias_method :more_like_this, :more_like_this_q
61
+
62
62
  end
63
63
 
64
64
  end
@@ -0,0 +1,86 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ ###############################################################################
5
+ # #
6
+ # solr4r -- A Ruby client for Apache Solr #
7
+ # #
8
+ # Copyright (C) 2014-2015 Jens Wille #
9
+ # #
10
+ # solr4r is free software: you can redistribute it and/or modify it under the #
11
+ # terms of the GNU Affero General Public License as published by the Free #
12
+ # Software Foundation, either version 3 of the License, or (at your option) #
13
+ # any later version. #
14
+ # #
15
+ # solr4r is distributed in the hope that it will be useful, but WITHOUT ANY #
16
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
17
+ # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for #
18
+ # more details. #
19
+ # #
20
+ # You should have received a copy of the GNU Affero General Public License #
21
+ # along with solr4r. If not, see <http://www.gnu.org/licenses/>. #
22
+ # #
23
+ ###############################################################################
24
+ #++
25
+
26
+ module Solr4R
27
+
28
+ class Endpoints
29
+
30
+ include Logging
31
+
32
+ DEFAULT_ENDPOINTS = %w[select query export spell suggest terms debug/dump]
33
+
34
+ def initialize(client)
35
+ @client, @endpoints = client, []
36
+ register(client.options.fetch(:endpoints, DEFAULT_ENDPOINTS))
37
+ end
38
+
39
+ attr_reader :client
40
+
41
+ def register(path, options = {})
42
+ case path
43
+ when nil
44
+ # ignore
45
+ when String
46
+ name, path = File.basename(path), options.fetch(:path, path).to_s
47
+
48
+ error = invalid_endpoint?(name) and
49
+ raise ArgumentError, "invalid endpoint: #{name} (#{error})"
50
+
51
+ @endpoints << [name, path]
52
+
53
+ define_singleton_method(name) { |_params = {}, _options = {}, &block|
54
+ client.send(:send_request, path, options.merge(_options.merge(
55
+ params: options.fetch(:params, {}).merge(_params))), &block)
56
+ }
57
+ when Symbol
58
+ register(path.to_s, options)
59
+ when Array
60
+ path.each { |args| register(*args) }
61
+ when Hash
62
+ path.each { |name, opts| register(name,
63
+ opts.is_a?(Hash) ? opts : { path: opts }) }
64
+ else
65
+ Client.send(:type_error, path, %w[String Symbol Array Hash])
66
+ end
67
+
68
+ self
69
+ end
70
+
71
+ def inspect
72
+ '#<%s:0x%x [%s]>' % [self.class, object_id, @endpoints.map { |name, path|
73
+ name == path ? name : "#{name}=#{path}" }.join(', ')]
74
+ end
75
+
76
+ private
77
+
78
+ def invalid_endpoint?(name)
79
+ 'method already defined' if respond_to?(name) || (
80
+ respond_to?(name, true) &&
81
+ DEFAULT_ENDPOINTS.all? { |ep,| ep.to_s != name })
82
+ end
83
+
84
+ end
85
+
86
+ end
@@ -5,9 +5,9 @@
5
5
  # #
6
6
  # solr4r -- A Ruby client for Apache Solr #
7
7
  # #
8
- # Copyright (C) 2014 Jens Wille #
8
+ # Copyright (C) 2014-2015 Jens Wille #
9
9
  # #
10
- # Mir is free software: you can redistribute it and/or modify it under the #
10
+ # solr4r is free software: you can redistribute it and/or modify it under the #
11
11
  # terms of the GNU Affero General Public License as published by the Free #
12
12
  # Software Foundation, either version 3 of the License, or (at your option) #
13
13
  # any later version. #
@@ -24,12 +24,14 @@
24
24
  #++
25
25
 
26
26
  require 'logger'
27
- require 'nuggets/module/lazy_attr'
27
+ require 'nuggets/module/lazy_attr_mixin'
28
28
 
29
29
  module Solr4R
30
30
 
31
31
  module Logging
32
32
 
33
+ extend Nuggets::Module::LazyAttrMixin
34
+
33
35
  DEFAULT_LOG_DEVICE = $stderr
34
36
  DEFAULT_LOG_LEVEL = Logger::WARN
35
37
  DEFAULT_LOG_NAME = "Solr4R/#{VERSION}"
@@ -7,7 +7,7 @@
7
7
  # #
8
8
  # Copyright (C) 2014-2015 Jens Wille #
9
9
  # #
10
- # Mir is free software: you can redistribute it and/or modify it under the #
10
+ # solr4r is free software: you can redistribute it and/or modify it under the #
11
11
  # terms of the GNU Affero General Public License as published by the Free #
12
12
  # Software Foundation, either version 3 of the License, or (at your option) #
13
13
  # any later version. #
@@ -25,7 +25,6 @@
25
25
 
26
26
  require 'net/https'
27
27
 
28
- require_relative 'request_extension'
29
28
  require_relative 'uri_extension'
30
29
 
31
30
  module Solr4R
@@ -45,6 +44,8 @@ module Solr4R
45
44
 
46
45
  attr_reader :client
47
46
 
47
+ attr_accessor :base_uri, :http_options, :http, :last_response
48
+
48
49
  def start
49
50
  self.http = Net::HTTP.start(base_uri.hostname, base_uri.port,
50
51
  { use_ssl: base_uri.scheme == 'https' }.merge(http_options))
@@ -69,18 +70,7 @@ module Solr4R
69
70
  req = prepare_request(path, options, &block)
70
71
  res = http.request(req)
71
72
 
72
- self.last_response = Response.new(self,
73
- request_body: req.body,
74
- request_headers: req.to_hash,
75
- request_method: req.method.downcase.to_sym,
76
- request_params: req.params,
77
- request_url: req.uri.to_s,
78
-
79
- response_body: res.body,
80
- response_charset: res.type_params['charset'],
81
- response_code: res.code.to_i,
82
- response_headers: res.to_hash
83
- )
73
+ self.last_response = Response.new(self, req, res)
84
74
  end
85
75
 
86
76
  def request_line
@@ -93,15 +83,11 @@ module Solr4R
93
83
 
94
84
  private
95
85
 
96
- attr_accessor :base_uri, :http_options, :http, :last_response
97
-
98
86
  def prepare_request(path, options)
99
87
  uri = make_uri(path, options.fetch(:params, {}))
88
+ req = make_request(uri, options.fetch(:method, DEFAULT_METHOD))
100
89
 
101
- req = make_request(uri,
102
- options.fetch(:method, DEFAULT_METHOD),
103
- options.fetch(:data, {}))
104
-
90
+ set_data(req, options.fetch(:data, {})) if req.request_body_permitted?
105
91
  set_headers(req, options.fetch(:headers, {}))
106
92
 
107
93
  yield req if block_given?
@@ -113,31 +99,17 @@ module Solr4R
113
99
  base_uri.merge(path).extend(RequestUriExtension).with_params(params)
114
100
  end
115
101
 
116
- def make_request(uri, method, data)
117
- case method
118
- when :get, :head
119
- req = request_for(method, uri)
120
- when :post
121
- req = request_for(method, uri)
122
- set_data(req, data)
123
- else
124
- raise ArgumentError, "method not supported: #{method}"
125
- end
126
-
102
+ def make_request(uri, method)
103
+ req = Net::HTTP.const_get(method.to_s.capitalize).new(uri)
104
+ req.uri.extend(RequestUriExtension).params = uri.params
127
105
  req
128
106
  end
129
107
 
130
- def request_for(method, uri)
131
- Net::HTTP.const_get(method.to_s.capitalize)
132
- .extend(HTTPRequestExtension).from_uri(uri)
133
- end
134
-
135
108
  def set_headers(req, headers)
136
109
  req['User-Agent'] = DEFAULT_USER_AGENT
137
110
 
138
111
  headers.each { |key, value|
139
- Array(value).each { |val| req.add_field(key, val) }
140
- }
112
+ Array(value).each { |val| req.add_field(key, val) } }
141
113
  end
142
114
 
143
115
  def set_data(req, data)
@@ -7,7 +7,7 @@
7
7
  # #
8
8
  # Copyright (C) 2014-2015 Jens Wille #
9
9
  # #
10
- # Mir is free software: you can redistribute it and/or modify it under the #
10
+ # solr4r is free software: you can redistribute it and/or modify it under the #
11
11
  # terms of the GNU Affero General Public License as published by the Free #
12
12
  # Software Foundation, either version 3 of the License, or (at your option) #
13
13
  # any later version. #
@@ -34,18 +34,29 @@ module Solr4R
34
34
 
35
35
  DEFAULT_CHARSET = 'UTF-8'
36
36
 
37
- EVALUATE_METHODS = [:get, :post]
37
+ def initialize(request, req = nil, res = nil)
38
+ @request, @evaluate = request, req.response_body_permitted?
38
39
 
39
- def initialize(request, options)
40
- @request = request
41
- options.each { |key, value| send("#{key}=", value) }
42
- @evaluate = EVALUATE_METHODS.include?(request_method)
40
+ if req
41
+ self.request_body = req.body
42
+ self.request_headers = req.to_hash
43
+ self.request_method = req.method.downcase.to_sym
44
+ self.request_params = req.uri.params
45
+ self.request_url = req.uri.to_s
46
+ end
47
+
48
+ if res
49
+ self.response_body = res.body
50
+ self.response_headers = res.to_hash
51
+ self.response_charset = res.type_params['charset']
52
+ self.response_code = res.code.to_i
53
+ end
43
54
  end
44
55
 
45
56
  attr_reader :request
46
57
 
47
- attr_accessor :response_body, :response_charset, :response_code, :response_headers,
48
- :request_body, :request_method, :request_params, :request_url, :request_headers
58
+ attr_accessor :response_body, :response_headers, :response_charset, :response_code,
59
+ :request_body, :request_headers, :request_method, :request_params, :request_url
49
60
 
50
61
  def_delegators :request, :client
51
62
 
data/lib/solr4r/result.rb CHANGED
@@ -7,7 +7,7 @@
7
7
  # #
8
8
  # Copyright (C) 2014-2015 Jens Wille #
9
9
  # #
10
- # Mir is free software: you can redistribute it and/or modify it under the #
10
+ # solr4r is free software: you can redistribute it and/or modify it under the #
11
11
  # terms of the GNU Affero General Public License as published by the Free #
12
12
  # Software Foundation, either version 3 of the License, or (at your option) #
13
13
  # any later version. #
@@ -55,7 +55,7 @@ module Solr4R
55
55
 
56
56
  def_delegators :response, :client
57
57
 
58
- def_delegators :to_hash, :fetch, :deep_fetch, :%
58
+ def_delegators :to_hash, :%, :deep_fetch, :fetch
59
59
 
60
60
  def to_hash
61
61
  @hash