bootic_client 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e21ff6db54eead797a8ca1206880db8f32fd7bb2
4
- data.tar.gz: 6cd1e6710e2a4b19edf284c749094217242c53ff
3
+ metadata.gz: 44cb025e788fcf5db4f335c6714b051a970e9647
4
+ data.tar.gz: 6871584b9fc940f4117e8c841f4ac1b85588121a
5
5
  SHA512:
6
- metadata.gz: ee764305af03d550c8f6263df35b5ad0c656053dd7dffe57bfbc11713af78869e20eaf57d5cbc05574c00df947c7bf533cfc8a2276cf80a9f97106d14541ee19
7
- data.tar.gz: 9faa674657d2ad7f08155366cce46fd8af5d7c740cfcb607d43c2d9b3f0e1877c0e4c917691c95bdec8996151271dba0ed9db9765fb623a1ea5fe3974caa4e57
6
+ metadata.gz: 8d2f579c6dca54966104b03b8518a5e9b32910b4195e62c2d84fa01ead10a5c16ae5465f4ea00349e8679c30b0beb0077a8f1392c0cf0e7adb47500b2f3b73dd
7
+ data.tar.gz: f03e36499a5275ae7a999f2be58ce05ce76d54eccb79a57fdf3388fec72b2d11f38c1e1eaa5412d5277f4bafaa485cdccba3a5dceeb25895d3daa4347787b185
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  group :test do
7
- gem 'byebug'
7
+ gem 'byebug' if RUBY_VERSION.to_i >= 2
8
8
  gem 'vcr', '~> 2.4'
9
- gem 'webmock', '>= 1.9'
10
- end
9
+ gem 'webmock', '>= 1.20'
10
+ end
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  [![Build Status](https://travis-ci.org/bootic/bootic_client.rb.svg?branch=master)](https://travis-ci.org/bootic/bootic_client.rb)
2
2
  [![Gem Version](https://badge.fury.io/rb/bootic_client.svg)](http://badge.fury.io/rb/bootic_client)
3
3
 
4
- ## WORK IN PROGRESS
5
4
 
6
5
  # BooticClient
7
6
 
@@ -53,13 +52,41 @@ if root.has?(:all_products)
53
52
  puts product.price
54
53
  end
55
54
 
56
- if all_product.has?(:next)
55
+ # Iterate through pages of products
56
+ # See "iterating" section below for a more elegant option
57
+ if all_products.has?(:next)
57
58
  next_page = all_products.next
58
59
  next_page.each{...}
59
60
  end
60
61
  end
61
62
  ```
62
63
 
64
+ ### Iterating
65
+
66
+ Entities representing lists of things ([products](https://developers.bootic.net/rels/products/), [orders](https://developers.bootic.net/rels/orders/), etc) are fully [enumerable](http://ruby-doc.org/core-2.2.0/Enumerable.html).
67
+
68
+ ```ruby
69
+ # These will only iterate this page's worth of products
70
+ all_products.each{|pr| puts pr.title}
71
+ all_products.map(&:title)
72
+ all_products.reduce(0){|sum, pr| sum + pr.price}
73
+ ```
74
+
75
+ These lists might be part of a paginated data set. If you want to iterate items across pages and make sure you consume the full set, use `#full_set`.
76
+
77
+ ```ruby
78
+ # These will iterate all necessary pages
79
+ all_products.full_set.each{|pr| puts pr.title }
80
+ all_products.full_set.map(&:title)
81
+ all_products.full_set.first(500)
82
+ ```
83
+
84
+ You can check whether an entity is iterable with:
85
+
86
+ ```ruby
87
+ all_products.respond_to?(:each)
88
+ ```
89
+
63
90
  ## Strategies
64
91
 
65
92
  The Bootic Client supports different authentication strategies depending on the use case.
@@ -106,7 +133,6 @@ if shop.can?(:create_product)
106
133
  title: 'A shiny new product',
107
134
  price: 122332,
108
135
  status: "visible",
109
- collecton_names: ["Featured products", "Homepage"],
110
136
  variants: [
111
137
  {
112
138
  title: 'First variant',
@@ -114,6 +140,10 @@ if shop.can?(:create_product)
114
140
  available_if_no_stock: 1,
115
141
  stock: 12
116
142
  }
143
+ ],
144
+ collections: [
145
+ {title: "A new collection"},
146
+ {id: 1234}
117
147
  ]
118
148
  )
119
149
 
@@ -21,9 +21,9 @@ Gem::Specification.new do |spec|
21
21
  spec.add_dependency "faraday", '~> 0.9'
22
22
  spec.add_dependency "uri_template", '~> 0.7'
23
23
  spec.add_dependency "faraday_middleware", '~> 0.9'
24
- spec.add_dependency "faraday-http-cache", '~> 0.4'
24
+ spec.add_dependency "faraday-http-cache", '0.4.2'
25
25
  spec.add_dependency "net-http-persistent", '~> 2.9'
26
- spec.add_dependency "oauth2"
26
+ spec.add_dependency "oauth2", "~> 1"
27
27
 
28
28
  spec.add_development_dependency "bundler", "~> 1.3"
29
29
  spec.add_development_dependency "rake"
@@ -2,6 +2,26 @@ require "bootic_client/relation"
2
2
  require 'ostruct'
3
3
 
4
4
  module BooticClient
5
+ module EnumerableEntity
6
+ include Enumerable
7
+
8
+ def each(&block)
9
+ self[:items].each &block
10
+ end
11
+
12
+ def full_set
13
+ page = self
14
+
15
+ Enumerator.new do |yielder|
16
+ loop do
17
+ page.each{|item| yielder.yield item }
18
+ raise StopIteration unless page.has_rel?(:next)
19
+ page = page.next
20
+ end
21
+ end
22
+ end
23
+ end
24
+
5
25
  class Entity
6
26
 
7
27
  CURIE_EXP = /(.+):(.+)/.freeze
@@ -13,10 +33,15 @@ module BooticClient
13
33
  def initialize(attrs, client, top = self)
14
34
  @attrs, @client, @top = attrs, client, top
15
35
  build!
36
+ self.extend EnumerableEntity if iterable?
37
+ end
38
+
39
+ def to_hash
40
+ @attrs
16
41
  end
17
42
 
18
43
  def [](key)
19
- properties[key.to_sym]
44
+ properties[key.to_sym] || entities[key.to_sym]
20
45
  end
21
46
 
22
47
  def has?(prop_name)
@@ -84,10 +109,6 @@ module BooticClient
84
109
  rels.has_key? prop_name.to_sym
85
110
  end
86
111
 
87
- def each(&block)
88
- iterable? ? entities[:items].each(&block) : [self].each(&block)
89
- end
90
-
91
112
  def rels
92
113
  @rels ||= (
93
114
  links = attrs.fetch('_links', {})
@@ -126,4 +147,4 @@ module BooticClient
126
147
  end
127
148
  end
128
149
  end
129
- end
150
+ end
@@ -19,6 +19,10 @@ module BooticClient
19
19
  request_and_wrap :get, config.api_root, Entity
20
20
  end
21
21
 
22
+ def from_hash(hash, wrapper_class = Entity)
23
+ wrapper_class.new hash, self
24
+ end
25
+
22
26
  def request_and_wrap(request_method, href, wrapper_class, payload = {})
23
27
  begin
24
28
  wrapper_class.new client.send(request_method, href, payload).body, self
@@ -1,3 +1,3 @@
1
1
  module BooticClient
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
@@ -144,5 +144,14 @@ describe 'BooticClient::Strategies::Authorized' do
144
144
  expect(shops.title).to eql('All shops')
145
145
  end
146
146
  end
147
+
148
+ describe '#from_hash' do
149
+ it 'builds and returns an entity' do
150
+ entity = client.from_hash('name' => 'foo', '_links' => {'delete' => {'href' => '/foo/bar'}})
151
+ expect(entity).to be_kind_of(BooticClient::Entity)
152
+ expect(entity.name).to eql('foo')
153
+ expect(entity.can?(:delete)).to be true
154
+ end
155
+ end
147
156
  end
148
157
  end
data/spec/client_spec.rb CHANGED
@@ -11,7 +11,12 @@ describe BooticClient::Client do
11
11
  {'Accept' => 'application/json', 'Authorization' => "Bearer xxx"}
12
12
  }
13
13
  let(:response_headers) {
14
- {'Content-Type' => 'application/json', 'Last-Modified' => 'Sat, 07 Jun 2014 12:10:33 GMT'}
14
+ {
15
+ 'Content-Type' => 'application/json',
16
+ 'Last-Modified' => 'Sat, 07 Jun 2014 12:10:33 GMT',
17
+ 'ETag' => '0937dafce10db7b7d405667f9576d26d',
18
+ 'Cache-Control' => 'max-age=0, private, must-revalidate'
19
+ }
15
20
  }
16
21
  let(:root_data) {
17
22
  {
@@ -57,6 +62,24 @@ describe BooticClient::Client do
57
62
  end
58
63
  end
59
64
  end
65
+
66
+ context 'and then cached by ETag' do
67
+ before do
68
+ @cached_request = stub_request(:get, root_url)
69
+ .with(headers: {'If-None-Match' => response_headers['ETag']})
70
+ .to_return(status: 304, body: '', headers: response_headers)
71
+ end
72
+
73
+ it 'returns cached response' do
74
+ r = client.get(root_url)
75
+ expect(@cached_request).to have_been_requested
76
+
77
+ expect(r.status).to eql(200)
78
+ r.body.tap do |b|
79
+ expect(b['_links']['shops']).to eql({'href' => 'https://api.bootic.net/v1/products'})
80
+ end
81
+ end
82
+ end
60
83
  end
61
84
 
62
85
  context 'errors' do
data/spec/entity_spec.rb CHANGED
@@ -67,6 +67,10 @@ describe BooticClient::Entity do
67
67
  expect(entity.page).to eql(1)
68
68
  end
69
69
 
70
+ it 'has hash access to properties' do
71
+ expect(entity[:total_items]).to eql(10)
72
+ end
73
+
70
74
  it 'wraps object properties as entities' do
71
75
  expect(entity.an_object.name).to eql('Foobar')
72
76
  expect(entity.an_object.age).to eql(22)
@@ -82,6 +86,12 @@ describe BooticClient::Entity do
82
86
  expect(entity.has?(:foobar)).to eql(false)
83
87
  end
84
88
 
89
+ describe '#to_hash' do
90
+ it 'returns original data' do
91
+ expect(entity.to_hash).to eql(list_payload)
92
+ end
93
+ end
94
+
85
95
  describe 'embedded entities' do
86
96
 
87
97
  it 'has a #entities object' do
@@ -97,6 +107,10 @@ describe BooticClient::Entity do
97
107
  end
98
108
  end
99
109
 
110
+ it 'has hash access to properties' do
111
+ expect(entity[:total_items]).to eql(10)
112
+ end
113
+
100
114
  it 'recursively builds embedded entities' do
101
115
  product = entity.items.first
102
116
  product.shop.tap do |shop|
@@ -158,17 +172,48 @@ describe BooticClient::Entity do
158
172
  end
159
173
 
160
174
  describe 'iterating' do
161
- it 'iterates items if it is a list' do
175
+ it 'is an enumerable if it is a list' do
162
176
  prods = []
163
177
  entity.each{|pr| prods << pr}
164
178
  expect(prods).to match_array(entity.items)
179
+ expect(entity.map{|pr| pr}).to match_array(entity.items)
180
+ expect(entity.reduce(0){|sum,e| sum + e.price.to_i}).to eql(24687)
181
+ expect(entity.each).to be_kind_of(Enumerator)
165
182
  end
166
183
 
167
- it 'iterates itself if not a list' do
184
+ it 'is not treated as an array if not a list' do
168
185
  ent = BooticClient::Entity.new({'foo' => 'bar'}, client)
169
- ents = []
170
- ent.each{|e| ents << e}
171
- expect(ents).to match_array([ent])
186
+ expect(ent).not_to respond_to(:each)
187
+ end
188
+ end
189
+
190
+ describe '#full_set' do
191
+ let(:page_2_data) {
192
+ {
193
+ 'total_items' => 10,
194
+ 'per_page' => 3,
195
+ 'page' => 2,
196
+ '_links' => {
197
+ 'self' => {'href' => '/foo?page=2'},
198
+ 'next' => { 'href' => '/foo?page=3'}
199
+ },
200
+ "_embedded" => {
201
+ 'items' => [
202
+ {"title" => "Item 3"},
203
+ {"title" => "Item 4"},
204
+ {"title" => "Item 5"}
205
+ ]
206
+ }
207
+ }
208
+ }
209
+ let(:page_2) { BooticClient::Entity.new(page_2_data, client) }
210
+
211
+ it 'lazily enumerates entries across pages, making as little requests as possible' do
212
+ expect(client).to receive(:request_and_wrap).with(:get, '/foo?page=2', BooticClient::Entity, {}).and_return page_2
213
+ expect(client).to_not receive(:request_and_wrap).with(:get, '/foo?page=3', BooticClient::Entity, {})
214
+ results = entity.full_set.first(4)
215
+ titles = results.map(&:title)
216
+ expect(titles).to match_array(['iPhone 4', 'iPhone 5', 'Item 3', 'Item 4'])
172
217
  end
173
218
  end
174
219
  end
metadata CHANGED
@@ -1,167 +1,167 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bootic_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ismael Celis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-27 00:00:00.000000000 Z
11
+ date: 2015-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0.9'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.9'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: uri_template
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0.7'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.7'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: faraday_middleware
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0.9'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0.9'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: faraday-http-cache
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: '0.4'
61
+ version: 0.4.2
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ~>
66
+ - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: '0.4'
68
+ version: 0.4.2
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: net-http-persistent
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
75
  version: '2.9'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '2.9'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: oauth2
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: '1'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '>='
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: '1'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: bundler
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ~>
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
103
  version: '1.3'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ~>
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '1.3'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rake
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - '>='
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
117
  version: '0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - '>='
122
+ - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rspec
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - '>='
129
+ - - ">="
130
130
  - !ruby/object:Gem::Version
131
131
  version: '0'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - '>='
136
+ - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: jwt
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - '>='
143
+ - - ">="
144
144
  - !ruby/object:Gem::Version
145
145
  version: '0'
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - '>='
150
+ - - ">="
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: dalli
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
- - - '>='
157
+ - - ">="
158
158
  - !ruby/object:Gem::Version
159
159
  version: '0'
160
160
  type: :development
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
- - - '>='
164
+ - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
167
  description: Official Ruby client for the Bootic API
@@ -171,9 +171,9 @@ executables: []
171
171
  extensions: []
172
172
  extra_rdoc_files: []
173
173
  files:
174
- - .gitignore
175
- - .rspec
176
- - .travis.yml
174
+ - ".gitignore"
175
+ - ".rspec"
176
+ - ".travis.yml"
177
177
  - Gemfile
178
178
  - LICENSE.txt
179
179
  - README.md
@@ -207,17 +207,17 @@ require_paths:
207
207
  - lib
208
208
  required_ruby_version: !ruby/object:Gem::Requirement
209
209
  requirements:
210
- - - '>='
210
+ - - ">="
211
211
  - !ruby/object:Gem::Version
212
212
  version: '0'
213
213
  required_rubygems_version: !ruby/object:Gem::Requirement
214
214
  requirements:
215
- - - '>='
215
+ - - ">="
216
216
  - !ruby/object:Gem::Version
217
217
  version: '0'
218
218
  requirements: []
219
219
  rubyforge_project:
220
- rubygems_version: 2.0.3
220
+ rubygems_version: 2.4.5
221
221
  signing_key:
222
222
  specification_version: 4
223
223
  summary: Official Ruby client for the Bootic API