haveapi-client 0.29.5 → 0.29.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
  SHA256:
3
- metadata.gz: d2bd2997fa01f67713bf17e28740a8a24363f40daf8a3707868495bd2edbb863
4
- data.tar.gz: ecbfda7acc42a0d0e782de2f80f6cdd0c3d92b1fcbecbcfa307ead6939e8d2ad
3
+ metadata.gz: b2a413b63db6d6f00c9664d93b6a2bb7d6958f7cbe5375206173ad1449b35123
4
+ data.tar.gz: ea5a9393d531ee3503b6ce0274926aae67d9419c8c98d3c85ed2b1fe83d23499
5
5
  SHA512:
6
- metadata.gz: 3fa58eb4ff7603855c2214cbc26e2116128c65cf0720043601bd913dd004a721d43b6290fcc58e0c5b36d41f47b08dc8326bb7b59267de3652f3b6824104cf18
7
- data.tar.gz: da464e8a0826c3bfebf2a6e622fa3e9fa45d1574f38e5c0b91b56142a023feedff5c57b090e1f6144cbed8e838717cb1f90d39e96475c93fd01a945fa8dfcfb8
6
+ metadata.gz: 947f1336247d07ad353055d7fc5cc68708b4a698927a789b80e91878526dc04b33a9ab2a1ab509e4c8ba2846bcde5cb9710a18b05e61f243c2c82d311b93cc68
7
+ data.tar.gz: 8bf5a0cae801ca319dcb18fd441a3b03d3fad11de8eda64b483a078886f72d9fbbe81187aada825b6abcf4e81e2d788b9777ed96faab76439eaaa28310df18ae
data/README.md CHANGED
@@ -120,6 +120,14 @@ client-side validation errors:
120
120
  api = HaveAPI::Client::Client.new('https://your.api.tld', language: 'cs')
121
121
  ```
122
122
 
123
+ Change the request language on an existing client with `set_opts`. Read the
124
+ configured value through `opts`:
125
+
126
+ ```ruby
127
+ api.set_opts(language: 'en')
128
+ p api.opts[:language]
129
+ ```
130
+
123
131
  The value is sent in `Accept-Language` by default. Use `language_header` when
124
132
  the API is configured with a custom language header. Set the language before
125
133
  the client fetches the API description so translated validator descriptions
@@ -90,24 +90,8 @@ class HaveAPI::Client::Client
90
90
  # @param opts [Hash] options
91
91
  def set_opts(opts)
92
92
  @opts.update(opts)
93
- self.language = opts[:language] if opts.has_key?(:language)
94
- self.language_header = opts[:language_header] if opts.has_key?(:language_header)
95
- end
96
-
97
- def language
98
- @api.language
99
- end
100
-
101
- def language=(value)
102
- @api.language = value
103
- end
104
-
105
- def language_header
106
- @api.language_header
107
- end
108
-
109
- def language_header=(value)
110
- @api.language_header = value
93
+ @api.language = opts[:language] if opts.has_key?(:language)
94
+ @api.language_header = opts[:language_header] if opts.has_key?(:language_header)
111
95
  end
112
96
 
113
97
  def client_message(key, **values)
@@ -205,10 +205,17 @@ module HaveAPI::Client
205
205
  def find_association(res_desc, res_val)
206
206
  return nil unless res_val
207
207
 
208
- tmp = @client
208
+ resource = @client
209
+ path = []
209
210
 
210
- res_desc[:resource].each do |r|
211
- tmp = tmp.method(r).call
211
+ res_desc[:resource].each do |name|
212
+ path << name
213
+
214
+ begin
215
+ resource = resource.resources.fetch(name.to_sym)
216
+ rescue KeyError
217
+ raise ProtocolError, "associated resource '#{path.join('.')}' not found"
218
+ end
212
219
  end
213
220
 
214
221
  # FIXME: read _meta namespace from description
@@ -217,8 +224,8 @@ module HaveAPI::Client
217
224
  ResourceInstance.new(
218
225
  @client,
219
226
  @api,
220
- tmp,
221
- action: tmp.actions[:show],
227
+ resource,
228
+ action: resource.actions[:show],
222
229
  resolved: meta[:resolved],
223
230
  response: meta[:resolved] ? res_val : nil,
224
231
  meta: meta
@@ -1,6 +1,6 @@
1
1
  module HaveAPI
2
2
  module Client
3
3
  PROTOCOL_VERSION = '2.0'.freeze
4
- VERSION = '0.29.5'.freeze
4
+ VERSION = '0.29.6'.freeze
5
5
  end
6
6
  end
@@ -80,6 +80,10 @@ RSpec.describe HaveAPI::Client::Client do
80
80
  actions: {},
81
81
  resources: {}
82
82
  },
83
+ language: {
84
+ actions: {},
85
+ resources: {}
86
+ },
83
87
  users: {
84
88
  actions: {},
85
89
  resources: {}
@@ -94,8 +98,9 @@ RSpec.describe HaveAPI::Client::Client do
94
98
  expect(client.method(:setup).owner).to eq(described_class)
95
99
  expect(client.authenticate(:token, token: 'secret-token')).to eq(:authenticated)
96
100
  expect(api.authenticate_calls).to eq(2)
101
+ expect(client.language).to be_a(HaveAPI::Client::Resource)
97
102
  expect(client.users).to be_a(HaveAPI::Client::Resource)
98
- expect(client.resources.keys).to contain_exactly(:authenticate, :setup, :users)
103
+ expect(client.resources.keys).to contain_exactly(:authenticate, :setup, :language, :users)
99
104
  end
100
105
 
101
106
  it 'does not let actions or nested resources replace resource methods' do
data/spec/i18n_spec.rb CHANGED
@@ -24,6 +24,18 @@ RSpec.describe HaveAPI::Client::Client do
24
24
  expect(client.communicator.language_headers).to eq('X-Language' => 'cs-CZ')
25
25
  end
26
26
 
27
+ it 'updates and reports language options through the option interface' do
28
+ client = described_class.new(TEST_SERVER.base_url)
29
+
30
+ client.set_opts(language: 'cs-CZ', language_header: 'X-Language')
31
+
32
+ expect(client.opts(:language, :language_header)).to eq(
33
+ language: 'cs-CZ',
34
+ language_header: 'X-Language'
35
+ )
36
+ expect(client.communicator.language_headers).to eq('X-Language' => 'cs-CZ')
37
+ end
38
+
27
39
  it 'localizes local validation errors' do
28
40
  client = described_class.new(TEST_SERVER.base_url, language: 'cs')
29
41
 
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ class ResourceAssociationTestCommunicator
6
+ attr_reader :calls
7
+
8
+ def initialize(resolved:, association_path: ['language'])
9
+ @resolved = resolved
10
+ @association_path = association_path
11
+ @calls = []
12
+ end
13
+
14
+ def describe_api(_version)
15
+ {
16
+ resources: {
17
+ language: resource_description(
18
+ show: action_description(
19
+ namespace: 'language',
20
+ path: '/v1/languages/{language_id}',
21
+ parameters: {
22
+ id: { type: 'Integer' },
23
+ code: { type: 'String' }
24
+ }
25
+ )
26
+ ),
27
+ user: resource_description(
28
+ current: action_description(
29
+ namespace: 'user',
30
+ path: '/v1/users/current',
31
+ parameters: {
32
+ id: { type: 'Integer' },
33
+ language: {
34
+ type: 'Resource',
35
+ resource: @association_path,
36
+ value_id: 'id',
37
+ value_label: 'code'
38
+ }
39
+ }
40
+ )
41
+ )
42
+ }
43
+ }
44
+ end
45
+
46
+ def call(action, _params)
47
+ @calls << action.name
48
+
49
+ case action.name
50
+ when :current
51
+ response(
52
+ user: {
53
+ id: 1,
54
+ language: {
55
+ id: 1,
56
+ code: 'cs',
57
+ _meta: {
58
+ resolved: @resolved,
59
+ path_params: [1]
60
+ }
61
+ }
62
+ }
63
+ )
64
+ when :show
65
+ response(
66
+ language: {
67
+ id: 1,
68
+ code: 'cs'
69
+ }
70
+ )
71
+ else
72
+ raise "unexpected action #{action.name}"
73
+ end
74
+ end
75
+
76
+ def url
77
+ 'https://api.example'
78
+ end
79
+
80
+ protected
81
+
82
+ def resource_description(actions)
83
+ {
84
+ actions: actions.transform_values { |v| v },
85
+ resources: {}
86
+ }
87
+ end
88
+
89
+ def action_description(namespace:, path:, parameters:)
90
+ {
91
+ auth: false,
92
+ description: 'test action',
93
+ aliases: [],
94
+ blocking: false,
95
+ input: {
96
+ parameters: {},
97
+ layout: 'object',
98
+ namespace: namespace
99
+ },
100
+ output: {
101
+ parameters: parameters,
102
+ layout: 'object',
103
+ namespace: namespace
104
+ },
105
+ meta: {
106
+ object: nil,
107
+ global: nil
108
+ },
109
+ examples: [],
110
+ scope: "#{namespace}#show",
111
+ path: path,
112
+ method: 'GET',
113
+ help: "#{path}?method=GET"
114
+ }
115
+ end
116
+
117
+ def response(values)
118
+ {
119
+ status: true,
120
+ response: values.merge(_meta: {}),
121
+ message: nil,
122
+ errors: nil
123
+ }
124
+ end
125
+ end
126
+
127
+ RSpec.describe HaveAPI::Client::ResourceInstance do
128
+ def client_for(...)
129
+ communicator = ResourceAssociationTestCommunicator.new(...)
130
+ client = HaveAPI::Client::Client.new(
131
+ 'https://api.example',
132
+ communicator: communicator
133
+ )
134
+
135
+ [client, communicator]
136
+ end
137
+
138
+ it 'materializes a resolved association through the resource registry' do
139
+ client, communicator = client_for(resolved: true)
140
+
141
+ user = client.user.current
142
+
143
+ expect(user.language_id).to eq(1)
144
+ expect(user.language.code).to eq('cs')
145
+ expect(communicator.calls).to eq([:current])
146
+ end
147
+
148
+ it 'resolves a lazy association through the resource registry' do
149
+ client, communicator = client_for(resolved: false)
150
+
151
+ user = client.user.current
152
+
153
+ expect(user.language.code).to eq('cs')
154
+ expect(communicator.calls).to eq(%i[current show])
155
+ end
156
+
157
+ it 'reports an invalid associated resource path as a protocol error' do
158
+ client, = client_for(resolved: true, association_path: ['missing'])
159
+
160
+ expect { client.user.current }
161
+ .to raise_error(
162
+ HaveAPI::Client::ProtocolError,
163
+ "associated resource 'missing' not found"
164
+ )
165
+ end
166
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haveapi-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.29.5
4
+ version: 0.29.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jakub Skokan
@@ -162,6 +162,7 @@ files:
162
162
  - spec/integration/client_spec.rb
163
163
  - spec/integration/typed_input_spec.rb
164
164
  - spec/load_spec.rb
165
+ - spec/resource_instance_association_spec.rb
165
166
  - spec/spec_helper.rb
166
167
  - spec/support/test_server.rb
167
168
  - spec/validators/inclusion_spec.rb