lhs 3.3.6 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +19 -2
- data/lib/lhs/collection.rb +6 -5
- data/lib/lhs/concerns/item/destroy.rb +1 -2
- data/lib/lhs/concerns/item/save.rb +1 -1
- data/lib/lhs/concerns/item/update.rb +2 -3
- data/lib/lhs/concerns/item/validation.rb +1 -1
- data/lib/lhs/concerns/record/all.rb +16 -11
- data/lib/lhs/concerns/record/batch.rb +4 -4
- data/lib/lhs/concerns/record/configuration.rb +34 -0
- data/lib/lhs/concerns/record/create.rb +2 -2
- data/lib/lhs/concerns/record/endpoints.rb +1 -1
- data/lib/lhs/concerns/record/find.rb +2 -2
- data/lib/lhs/concerns/record/find_by.rb +1 -1
- data/lib/lhs/concerns/record/where.rb +1 -1
- data/lib/lhs/data.rb +8 -6
- data/lib/lhs/endpoint.rb +1 -1
- data/lib/lhs/proxy.rb +1 -2
- data/lib/lhs/record.rb +1 -0
- data/lib/lhs/version.rb +1 -1
- data/spec/collection/configurable_spec.rb +44 -0
- data/spec/data/collection_spec.rb +7 -1
- data/spec/data/raw_spec.rb +2 -5
- data/spec/data/select_spec.rb +7 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c6ba978add2aba0196bb5d98ecb6e114445db064
|
4
|
+
data.tar.gz: be48ebe2badd12166f55dac56e6579bef5fbed77
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e96f1f2d0baa2658854f73222e50a7569ccc5afd4075614eaadb99f656afbe041f839ca7332f358a41e7e3fad18d5f30e1b90724ba4dac5dd9969ca42ceab61a
|
7
|
+
data.tar.gz: 960bce0293960b60fd428d80d272038db342001416ab93cd00f5715e3a7eb1ee96d1f7d28456dbbc89163e2f3e81e6611060bb596be8040c060086794a0cf0ab
|
data/README.md
CHANGED
@@ -368,7 +368,24 @@ Feedback.where(limit: 50, offset: 51)
|
|
368
368
|
`limit` provides amount of items per page.
|
369
369
|
`offset` provides how many items where skipped to start the current page.
|
370
370
|
|
371
|
-
|
371
|
+
### Configure the name of the keys for offset, limit, total and name of items
|
372
|
+
|
373
|
+
Endpoints provide different interfaces to deal with paginated resources.
|
374
|
+
They differ for example for the key that is used for providing the current page items, the total amount of items, the current page size etc.
|
375
|
+
In order to have `LHS::Record` deal with those different interfaces you can configure it:
|
376
|
+
|
377
|
+
```ruby
|
378
|
+
class Search < LHS::Record
|
379
|
+
configuration items: :docs, limit: :size, offset: :start, total: :totalResults
|
380
|
+
endpoint ':search/:type'
|
381
|
+
end
|
382
|
+
```
|
383
|
+
`items` key used to determine items of the current page.
|
384
|
+
`limit` key used to work with page limits.
|
385
|
+
`offset` key used to paginate multiple pages.
|
386
|
+
`total` key used to determine the total amount of items.
|
387
|
+
|
388
|
+
### Partial Kaminari support
|
372
389
|
|
373
390
|
LHS implements an interface that makes it partially working with Kaminari.
|
374
391
|
|
@@ -384,7 +401,7 @@ For example, you can use kaminari to render paginations based on LHS Records:
|
|
384
401
|
= paginate @items
|
385
402
|
```
|
386
403
|
|
387
|
-
|
404
|
+
### form_for Helper
|
388
405
|
Rails `form_for` view-helper can be used in combination with instances of LHS::Record to autogenerate forms:
|
389
406
|
```
|
390
407
|
<%= form_for(@instance, url: '/create') do |f| %>
|
data/lib/lhs/collection.rb
CHANGED
@@ -7,17 +7,18 @@ class LHS::Collection < LHS::Proxy
|
|
7
7
|
include InternalCollection
|
8
8
|
|
9
9
|
delegate :select, to: :_collection
|
10
|
+
delegate :_record, to: :_data
|
10
11
|
|
11
12
|
def total
|
12
|
-
_data._raw[
|
13
|
+
_data._raw[_record.total_key]
|
13
14
|
end
|
14
15
|
|
15
16
|
def limit
|
16
|
-
_data._raw[
|
17
|
+
_data._raw[_record.limit_key]
|
17
18
|
end
|
18
19
|
|
19
20
|
def offset
|
20
|
-
_data._raw[
|
21
|
+
_data._raw[_record.offset_key]
|
21
22
|
end
|
22
23
|
|
23
24
|
def href
|
@@ -26,8 +27,8 @@ class LHS::Collection < LHS::Proxy
|
|
26
27
|
|
27
28
|
def _collection
|
28
29
|
raw = _data._raw if _data._raw.is_a?(Array)
|
29
|
-
raw ||= _data._raw[
|
30
|
-
Collection.new(raw, _data,
|
30
|
+
raw ||= _data._raw[_record.items_key]
|
31
|
+
Collection.new(raw, _data, _record)
|
31
32
|
end
|
32
33
|
|
33
34
|
delegate :_raw, to: :_data
|
@@ -7,8 +7,7 @@ class LHS::Item < LHS::Proxy
|
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
9
|
def destroy
|
10
|
-
|
11
|
-
_data._request = record.request(method: :delete, url: href)._request
|
10
|
+
_data._request = _data.class.request(method: :delete, url: href)._request
|
12
11
|
_data
|
13
12
|
end
|
14
13
|
end
|
@@ -14,9 +14,8 @@ class LHS::Item < LHS::Proxy
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def update!(params)
|
17
|
-
|
18
|
-
_data.
|
19
|
-
response_data = record.request(
|
17
|
+
_data.merge_raw!(LHS::Data.new(params, _data.parent, _data.class))
|
18
|
+
response_data = _data.class.request(
|
20
19
|
method: :post,
|
21
20
|
url: href,
|
22
21
|
body: _data.to_json,
|
@@ -30,7 +30,7 @@ class LHS::Item < LHS::Proxy
|
|
30
30
|
private
|
31
31
|
|
32
32
|
def validation_endpoint
|
33
|
-
endpoint = _data.
|
33
|
+
endpoint = _data._record.find_endpoint(_data._raw)
|
34
34
|
endpoint ||= LHS::Endpoint.for_url(_data.href) if _data.href
|
35
35
|
validates = endpoint.options && endpoint.options.fetch(:validates, false)
|
36
36
|
fail 'Endpoint does not support validations!' unless validates
|
@@ -5,6 +5,8 @@ class LHS::Record
|
|
5
5
|
module All
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
|
+
DEFAULT_LIMIT = 100
|
9
|
+
|
8
10
|
module ClassMethods
|
9
11
|
# Should be an edge case but sometimes all objects from a certain resource
|
10
12
|
# are required. In this case we load the first page with the default max limit,
|
@@ -12,12 +14,10 @@ class LHS::Record
|
|
12
14
|
# for the following pages and concatenate all the results in order to return
|
13
15
|
# all the objects for a given resource.
|
14
16
|
def all(params = {})
|
15
|
-
|
16
|
-
|
17
|
-
data
|
18
|
-
|
19
|
-
request_all_the_rest(data, all, params) if data._raw.is_a?(Hash) && data._raw[:total]
|
20
|
-
data._record_class.new(LHS::Data.new(all, nil, self))
|
17
|
+
limit = params[limit_key] || DEFAULT_LIMIT
|
18
|
+
data = request(params: params.merge(limit_key => limit))
|
19
|
+
request_all_the_rest(data, params) if data._raw.is_a?(Hash) && data._raw[total_key]
|
20
|
+
data._record.new(LHS::Data.new(data, nil, self))
|
21
21
|
end
|
22
22
|
|
23
23
|
private
|
@@ -26,18 +26,23 @@ class LHS::Record
|
|
26
26
|
if data._raw.is_a?(Array)
|
27
27
|
data._raw
|
28
28
|
else
|
29
|
-
data._raw[
|
29
|
+
data._raw[items_key]
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
def request_all_the_rest(data,
|
34
|
-
total_left = data._raw[
|
35
|
-
limit = data._raw[
|
33
|
+
def request_all_the_rest(data, params)
|
34
|
+
total_left = data._raw[total_key] - data.count
|
35
|
+
limit = data._raw[limit_key] || data.count
|
36
36
|
if limit > 0
|
37
37
|
requests = total_left / limit
|
38
38
|
requests.times do |i|
|
39
39
|
offset = limit * (i + 1) + 1
|
40
|
-
|
40
|
+
data._raw[items_key].concat all_items_from request(
|
41
|
+
params: params.merge(
|
42
|
+
data._record.limit_key => limit,
|
43
|
+
data._record.offset_key => offset
|
44
|
+
)
|
45
|
+
)
|
41
46
|
end
|
42
47
|
end
|
43
48
|
end
|
@@ -8,10 +8,10 @@ class LHS::Record
|
|
8
8
|
module ClassMethods
|
9
9
|
# Process single entries fetched in batches
|
10
10
|
def find_each(options = {})
|
11
|
-
find_in_batches(options) do |
|
12
|
-
|
13
|
-
item = LHS::Item.new(
|
14
|
-
yield new(LHS::Data.new(item,
|
11
|
+
find_in_batches(options) do |records|
|
12
|
+
records.each do |record|
|
13
|
+
item = LHS::Item.new(record)
|
14
|
+
yield new(LHS::Data.new(item, records._data, self))
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
3
|
+
class LHS::Record
|
4
|
+
|
5
|
+
# Allows configuring endpoints
|
6
|
+
# like which keys are used for the items, offset, total etc.
|
7
|
+
module Configuration
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
mattr_accessor :configuration
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def configuration(args)
|
14
|
+
@configuration ||= args.freeze || {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def items_key
|
18
|
+
@configuration.try(:[], :items) || :items
|
19
|
+
end
|
20
|
+
|
21
|
+
def limit_key
|
22
|
+
@configuration.try(:[], :limit) || :limit
|
23
|
+
end
|
24
|
+
|
25
|
+
def total_key
|
26
|
+
@configuration.try(:[], :total) || :total
|
27
|
+
end
|
28
|
+
|
29
|
+
def offset_key
|
30
|
+
@configuration.try(:[], :offset) || :offset
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -13,13 +13,13 @@ class LHS::Record
|
|
13
13
|
data = LHS::Data.new(json, nil, self, e.response.request)
|
14
14
|
item = LHS::Item.new(data)
|
15
15
|
item.errors = LHS::Errors.new(e.response)
|
16
|
-
data.
|
16
|
+
data._record.new(LHS::Data.new(item, data))
|
17
17
|
end
|
18
18
|
|
19
19
|
def create!(data = {})
|
20
20
|
url = compute_url!(data)
|
21
21
|
data = request(url: url, method: :post, body: data.to_json, headers: { 'Content-Type' => 'application/json' })
|
22
|
-
data.
|
22
|
+
data._record.new(data)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
@@ -31,7 +31,7 @@ class LHS::Record
|
|
31
31
|
|
32
32
|
def for_url(url)
|
33
33
|
return unless url
|
34
|
-
_template, record = LHS::Record::Endpoints.all.detect do |template,
|
34
|
+
_template, record = LHS::Record::Endpoints.all.detect do |template, _|
|
35
35
|
LHC::Endpoint.match?(url, template)
|
36
36
|
end
|
37
37
|
record
|
data/lib/lhs/data.rb
CHANGED
@@ -5,14 +5,16 @@ Dir[File.dirname(__FILE__) + '/concerns/data/*.rb'].each { |file| require file }
|
|
5
5
|
class LHS::Data
|
6
6
|
include Json
|
7
7
|
|
8
|
+
delegate :instance_methods, :items_key, :limit_key, :total_key, :offset_key, to: :class
|
9
|
+
|
8
10
|
# prevent clashing with attributes of underlying data
|
9
|
-
attr_accessor :_proxy, :_raw, :_parent, :
|
11
|
+
attr_accessor :_proxy, :_raw, :_parent, :_record, :_request
|
10
12
|
|
11
13
|
def initialize(input, parent = nil, record = nil, request = nil)
|
12
14
|
self._raw = raw_from_input(input)
|
13
|
-
self._proxy = proxy_from_input(input)
|
14
|
-
self._record_class = record
|
15
15
|
self._parent = parent
|
16
|
+
self._record = record
|
17
|
+
self._proxy = proxy_from_input(input)
|
16
18
|
self._request = request
|
17
19
|
end
|
18
20
|
|
@@ -30,7 +32,7 @@ class LHS::Data
|
|
30
32
|
end
|
31
33
|
|
32
34
|
def class
|
33
|
-
_root.
|
35
|
+
_root._record
|
34
36
|
end
|
35
37
|
|
36
38
|
# enforce internal data structure to have deep symbolized keys
|
@@ -50,14 +52,14 @@ class LHS::Data
|
|
50
52
|
end
|
51
53
|
|
52
54
|
def respond_to_missing?(name, include_all = false)
|
53
|
-
(root_item? &&
|
55
|
+
(root_item? && instance_methods.include?(name)) ||
|
54
56
|
_proxy.respond_to?(name, include_all)
|
55
57
|
end
|
56
58
|
|
57
59
|
private
|
58
60
|
|
59
61
|
def collection_proxy?(input)
|
60
|
-
!! (input.is_a?(Hash) && input[
|
62
|
+
!! (input.is_a?(Hash) && input[items_key]) || input.is_a?(Array) || _raw.is_a?(Array)
|
61
63
|
end
|
62
64
|
|
63
65
|
def root_item
|
data/lib/lhs/endpoint.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
class LHS::Endpoint
|
3
3
|
|
4
4
|
def self.for_url(url)
|
5
|
-
template, record = LHS::Record::Endpoints.all.detect do |template,
|
5
|
+
template, record = LHS::Record::Endpoints.all.detect do |template, _record|
|
6
6
|
LHC::Endpoint.match?(url, template)
|
7
7
|
end
|
8
8
|
record.endpoints.detect { |endpoint| endpoint.url == template } if record
|
data/lib/lhs/proxy.rb
CHANGED
@@ -17,8 +17,7 @@ class LHS::Proxy
|
|
17
17
|
|
18
18
|
def reload!
|
19
19
|
fail 'No href found' unless _data.href
|
20
|
-
|
21
|
-
data = record.request(url: _data.href, method: :get)
|
20
|
+
data = _data.class.request(url: _data.href, method: :get)
|
22
21
|
_data.merge_raw!(data)
|
23
22
|
self._loaded = true
|
24
23
|
self
|
data/lib/lhs/record.rb
CHANGED
data/lib/lhs/version.rb
CHANGED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe LHS::Collection do
|
4
|
+
let(:search) { 'http://local.ch/search' }
|
5
|
+
let(:limit) { 10 }
|
6
|
+
let(:total) { 20 }
|
7
|
+
let(:offset) { 0 }
|
8
|
+
let(:first_response_data) do
|
9
|
+
{
|
10
|
+
docs: (1..10).to_a,
|
11
|
+
start: offset,
|
12
|
+
size: limit,
|
13
|
+
totalResults: total
|
14
|
+
}
|
15
|
+
end
|
16
|
+
let(:second_response_data) do
|
17
|
+
{
|
18
|
+
docs: (11..20).to_a,
|
19
|
+
start: offset,
|
20
|
+
size: limit,
|
21
|
+
totalResults: total
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
before(:each) do
|
26
|
+
LHC.config.placeholder('search', search)
|
27
|
+
class Search < LHS::Record
|
28
|
+
configuration items: :docs, limit: :size, offset: :start, total: :totalResults
|
29
|
+
endpoint ':search/:type'
|
30
|
+
end
|
31
|
+
stub_request(:get, "http://local.ch/search/phonebook?size=10").to_return(body: first_response_data.to_json)
|
32
|
+
stub_request(:get, "http://local.ch/search/phonebook?size=10&start=11").to_return(body: second_response_data.to_json)
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'lets you configure how to deal with collections' do
|
36
|
+
it 'initalises and gives access to collections according to configuration' do
|
37
|
+
results = Search.all(type: :phonebook, size: 10)
|
38
|
+
expect(results.count).to eq total
|
39
|
+
expect(results.total).to eq total
|
40
|
+
expect(results.limit).to eq limit
|
41
|
+
expect(results.offset).to eq offset
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/spec/data/raw_spec.rb
CHANGED
@@ -10,15 +10,12 @@ describe LHS::Data do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
let(:data_from_raw) do
|
13
|
-
LHS::Data.new(
|
14
|
-
href: 'http://www.local.ch/v2/stuff',
|
15
|
-
id: '123123123'
|
16
|
-
)
|
13
|
+
LHS::Data.new({ href: 'http://www.local.ch/v2/stuff', id: '123123123' }, nil, Record)
|
17
14
|
end
|
18
15
|
|
19
16
|
let(:data_from_item) do
|
20
17
|
raw = { href: 'http://www.local.ch/v2/stuff' }
|
21
|
-
item = LHS::Item.new(LHS::Data.new(raw))
|
18
|
+
item = LHS::Item.new(LHS::Data.new(raw, nil, Record))
|
22
19
|
LHS::Data.new(item)
|
23
20
|
end
|
24
21
|
|
data/spec/data/select_spec.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lhs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- https://github.com/local-ch/lhs/graphs/contributors
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-03-
|
11
|
+
date: 2016-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: lhc
|
@@ -186,6 +186,7 @@ files:
|
|
186
186
|
- lib/lhs/concerns/item/validation.rb
|
187
187
|
- lib/lhs/concerns/record/all.rb
|
188
188
|
- lib/lhs/concerns/record/batch.rb
|
189
|
+
- lib/lhs/concerns/record/configuration.rb
|
189
190
|
- lib/lhs/concerns/record/create.rb
|
190
191
|
- lib/lhs/concerns/record/endpoints.rb
|
191
192
|
- lib/lhs/concerns/record/find.rb
|
@@ -207,6 +208,7 @@ files:
|
|
207
208
|
- script/ci/build.sh
|
208
209
|
- spec/.DS_Store
|
209
210
|
- spec/collection/collection_items_spec.rb
|
211
|
+
- spec/collection/configurable_spec.rb
|
210
212
|
- spec/collection/delegate_spec.rb
|
211
213
|
- spec/collection/enumerable_spec.rb
|
212
214
|
- spec/collection/meta_data_spec.rb
|
@@ -331,6 +333,7 @@ summary: Rails gem providing an easy, active-record-like interface to use http b
|
|
331
333
|
services
|
332
334
|
test_files:
|
333
335
|
- spec/collection/collection_items_spec.rb
|
336
|
+
- spec/collection/configurable_spec.rb
|
334
337
|
- spec/collection/delegate_spec.rb
|
335
338
|
- spec/collection/enumerable_spec.rb
|
336
339
|
- spec/collection/meta_data_spec.rb
|