solr4r 0.0.5 → 0.0.6

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/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