haveapi 0.29.0 → 0.29.2

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: b5fea26ee9dde153cf44881ba46fe548ebe63077029d787e9b8e82ac19295d27
4
- data.tar.gz: 9314173d105633354963d996f0d8f4ceb70d5ec30c22684ced53052d694d9463
3
+ metadata.gz: 3de67ba481b9c0e88a56b07403e1979e24558ee8f52f3c1eb9d720faa442a62b
4
+ data.tar.gz: 1d3d0d435612eceeba75ec9973082f7eeca6fd8f7c5010197cb324edd606c843
5
5
  SHA512:
6
- metadata.gz: 6b1fb3f7ea1140e86091161f740399c258540036c5dccd04e2c9c6c632d0ef8f5e9cd4ab3cf9ecfec7f2952f109b50716fd255bb22fd385efea4c2ea47df6999
7
- data.tar.gz: e68a162dc87376dccfc8b5db1cc190aae4e1a47ff18029f21325b7dc2dc063aa522af594cedf0bec2a2f7d0c00d1df4f75151405a83e32821f7289ad4a14775b
6
+ metadata.gz: 40fcf28b778528046eab97d60034de89210b41c3e7977f12d622c0b8248bc89c231663eb355b5284693db781a3f25887c719ec6ca76effbfb604a10a914762e2
7
+ data.tar.gz: 7cd757b4ff23dfdd3dbe5efd732ceb23c6adb1bc763ed117de84687ee5c23652a7e71332e7f8762b94eca198b5b5cdbd76a2cf2f5698b876b9032343b98e1fab
data/README.md CHANGED
@@ -328,6 +328,27 @@ cs:
328
328
  label: "Hostname"
329
329
  ```
330
330
 
331
+ Choice labels declared through the `choices`/`include` validator use the same
332
+ parameter metadata path with `choices.<value>.label` appended. If choices were
333
+ declared as a value-to-label map, the declared label is used as the English
334
+ fallback. If choices were declared as an array, untranslated self-description
335
+ keeps the array form; a locale that supplies labels is returned as the existing
336
+ HaveAPI `{value: label}` map form.
337
+
338
+ ```yaml
339
+ cs:
340
+ my_api:
341
+ resources:
342
+ vps:
343
+ attributes:
344
+ state:
345
+ choices:
346
+ running:
347
+ label: "bezi"
348
+ stopped:
349
+ label: "vypnuto"
350
+ ```
351
+
331
352
  Metadata parameters fall back through resource and global metadata keys:
332
353
 
333
354
  ```yaml
data/haveapi.gemspec CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
15
15
  s.required_ruby_version = ">= #{File.read('../../.ruby-version').strip}"
16
16
 
17
17
  s.add_dependency 'activesupport', '>= 7.1'
18
- s.add_dependency 'haveapi-client', '~> 0.29.0'
18
+ s.add_dependency 'haveapi-client', '~> 0.29.2'
19
19
  s.add_dependency 'i18n', '>= 1.6', '< 2'
20
20
  s.add_dependency 'json'
21
21
  s.add_dependency 'mail'
@@ -14,7 +14,7 @@ module HaveAPI::Parameters
14
14
  keys:,
15
15
  value:
16
16
  }
17
- end
17
+ end + choice_i18n_catalog_items(context, i18n_path)
18
18
  end
19
19
 
20
20
  private
@@ -27,6 +27,17 @@ module HaveAPI::Parameters
27
27
  localized_metadata(context, i18n_path, :description, @desc)
28
28
  end
29
29
 
30
+ def localized_validators(context, i18n_path, validators)
31
+ include_validator = validators[:include]
32
+ return validators unless include_validator && include_validator.has_key?(:values)
33
+
34
+ values = include_validator.fetch(:values)
35
+ localized_values = localized_choice_values(context, i18n_path, values)
36
+ return validators if localized_values.equal?(values)
37
+
38
+ validators.merge(include: include_validator.merge(values: localized_values))
39
+ end
40
+
30
41
  def localized_metadata(context, i18n_path, kind, fallback)
31
42
  keys = metadata_i18n_keys(context, i18n_path, kind, fallback)
32
43
  default = HaveAPI.localize(fallback)
@@ -61,6 +72,74 @@ module HaveAPI::Parameters
61
72
  [exact_key, *metadata_i18n_default_keys(context, i18n_path, kind, scope)].uniq
62
73
  end
63
74
 
75
+ def localized_choice_values(context, i18n_path, values)
76
+ case values
77
+ when ::Hash
78
+ values.to_h do |value, label|
79
+ [
80
+ value,
81
+ localized_metadata(context, i18n_path, choice_i18n_kind(value), label)
82
+ ]
83
+ end
84
+ when ::Array
85
+ localized = values.to_h do |value|
86
+ label = localized_metadata(
87
+ context,
88
+ i18n_path,
89
+ choice_i18n_kind(value),
90
+ value.to_s
91
+ )
92
+ [value, label]
93
+ end
94
+
95
+ localized.any? { |value, label| label.to_s != value.to_s } ? localized : values
96
+ else
97
+ values
98
+ end
99
+ end
100
+
101
+ def choice_i18n_catalog_items(context, i18n_path)
102
+ values = choice_i18n_values
103
+ return [] unless values
104
+
105
+ choice_i18n_fallbacks(values).filter_map do |value, fallback|
106
+ keys = metadata_i18n_keys(context, i18n_path, choice_i18n_kind(value), fallback)
107
+ label = HaveAPI.localize(fallback).to_s.strip
108
+
109
+ next if keys.empty? || label.empty?
110
+
111
+ {
112
+ param: HaveAPI::Params.i18n_segment(@name),
113
+ kind: metadata_i18n_key_suffix(choice_i18n_kind(value)),
114
+ keys:,
115
+ value: label
116
+ }
117
+ end
118
+ end
119
+
120
+ def choice_i18n_values
121
+ metadata_i18n_choice_values
122
+ end
123
+
124
+ def metadata_i18n_choice_values
125
+ nil
126
+ end
127
+
128
+ def choice_i18n_fallbacks(values)
129
+ case values
130
+ when ::Hash
131
+ values
132
+ when ::Array
133
+ values.to_h { |value| [value, value.to_s] }
134
+ else
135
+ {}
136
+ end
137
+ end
138
+
139
+ def choice_i18n_kind(value)
140
+ "choices.#{HaveAPI::Params.i18n_segment(value)}.label"
141
+ end
142
+
64
143
  def metadata_i18n_fallback(kind)
65
144
  case kind
66
145
  when :label
@@ -78,8 +157,6 @@ module HaveAPI::Parameters
78
157
  @label_key
79
158
  when :description
80
159
  @desc_key
81
- else
82
- raise ArgumentError, "unsupported parameter metadata kind #{kind.inspect}"
83
160
  end
84
161
  end
85
162
 
@@ -62,7 +62,7 @@ module HaveAPI::Parameters
62
62
  label: localized_label(context, i18n_path),
63
63
  description: localized_description(context, i18n_path),
64
64
  type: @type ? @type.to_s : String.to_s,
65
- validators: @validators ? @validators.describe : {},
65
+ validators: @validators ? localized_validators(context, i18n_path, @validators.describe) : {},
66
66
  default: @default,
67
67
  protected: @protected || false
68
68
  }
@@ -167,6 +167,10 @@ module HaveAPI::Parameters
167
167
  @type == Custom
168
168
  end
169
169
 
170
+ def metadata_i18n_choice_values
171
+ @validators&.describe&.dig(:include, :values)
172
+ end
173
+
170
174
  def normalize_custom_keys(value)
171
175
  case value
172
176
  when ::Hash
@@ -1,4 +1,4 @@
1
1
  module HaveAPI
2
2
  PROTOCOL_VERSION = '2.0'.freeze
3
- VERSION = '0.29.0'.freeze
3
+ VERSION = '0.29.2'.freeze
4
4
  end
data/spec/i18n_spec.rb CHANGED
@@ -48,6 +48,14 @@ describe HaveAPI::I18n do
48
48
  string :global_attr_label,
49
49
  label: 'Global attribute fallback',
50
50
  desc: 'Global attribute description fallback'
51
+ string :status, choices: %i[enabled disabled]
52
+ string :priority,
53
+ choices: {
54
+ values: {
55
+ low: 'Low priority',
56
+ high: 'High priority'
57
+ }
58
+ }
51
59
  string :code, length: {
52
60
  min: 3,
53
61
  message: HaveAPI.message('haveapi.validators.length.min', min: 3)
@@ -146,6 +154,14 @@ describe HaveAPI::I18n do
146
154
  expect(length[:message]).to eq('délka musí být v rozsahu <3, 5>')
147
155
  end
148
156
 
157
+ it 'keeps untranslated array choices unchanged in OPTIONS responses' do
158
+ header 'Accept', 'application/json'
159
+ options '/v1/things', method: 'POST'
160
+
161
+ choices = api_response[:input][:parameters][:status][:validators][:include]
162
+ expect(choices[:values]).to eq(%w[enabled disabled])
163
+ end
164
+
149
165
  it 'localizes API metadata in OPTIONS responses' do
150
166
  previous_available = ::I18n.available_locales
151
167
  ::I18n.available_locales = (previous_available + %i[en cs]).uniq
@@ -218,6 +234,18 @@ describe HaveAPI::I18n do
218
234
  global_attr_label: {
219
235
  label: 'Přesný globální popisek',
220
236
  description: 'Přesný globální popis'
237
+ },
238
+ status: {
239
+ choices: {
240
+ enabled: { label: 'Zapnuto' },
241
+ disabled: { label: 'Vypnuto' }
242
+ }
243
+ },
244
+ priority: {
245
+ choices: {
246
+ low: { label: 'Nízká priorita' },
247
+ high: { label: 'Vysoká priorita' }
248
+ }
221
249
  }
222
250
  },
223
251
  output: {
@@ -325,6 +353,14 @@ describe HaveAPI::I18n do
325
353
  label: 'Přesný globální popisek',
326
354
  description: 'Přesný globální popis'
327
355
  )
356
+ expect(input_params[:status][:validators][:include][:values]).to eq(
357
+ enabled: 'Zapnuto',
358
+ disabled: 'Vypnuto'
359
+ )
360
+ expect(input_params[:priority][:validators][:include][:values]).to eq(
361
+ low: 'Nízká priorita',
362
+ high: 'Vysoká priorita'
363
+ )
328
364
  expect(input_params[:count]).to include(
329
365
  label: 'Count',
330
366
  description: nil
data/spec/params_spec.rb CHANGED
@@ -258,6 +258,8 @@ describe HaveAPI::Params do
258
258
  p = described_class.new(:input, ParamsSpec::MyResource::Index)
259
259
  p.add_block(proc do
260
260
  string :hostname, label: 'Hostname', desc: 'VPS hostname'
261
+ string :state, choices: %i[queued running]
262
+ string :priority, choices: { values: { low: 'Low priority' } }
261
263
  string :framework,
262
264
  label: HaveAPI.message('haveapi.parameters.metadata.no.label')
263
265
  end)
@@ -274,6 +276,22 @@ describe HaveAPI::Params do
274
276
  params_spec.attributes.hostname.label
275
277
  ])
276
278
  expect(items.none? { |item| item[:param] == 'framework' }).to be true
279
+
280
+ choice = items.detect do |item|
281
+ item[:param] == 'state' && item[:kind] == 'choices.queued.label'
282
+ end
283
+ expect(choice[:value]).to eq('queued')
284
+ expect(choice[:keys]).to eq(%w[
285
+ params_spec.resources.my_resource.actions.index.input.state.choices.queued.label
286
+ params_spec.resources.my_resource.input.state.choices.queued.label
287
+ params_spec.resources.my_resource.attributes.state.choices.queued.label
288
+ params_spec.attributes.state.choices.queued.label
289
+ ])
290
+
291
+ choice = items.detect do |item|
292
+ item[:param] == 'priority' && item[:kind] == 'choices.low.label'
293
+ end
294
+ expect(choice[:value]).to eq('Low priority')
277
295
  end
278
296
 
279
297
  it 'does not parse meta resource path segments as metadata paths' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haveapi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.29.0
4
+ version: 0.29.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jakub Skokan
@@ -29,14 +29,14 @@ dependencies:
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: 0.29.0
32
+ version: 0.29.2
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: 0.29.0
39
+ version: 0.29.2
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: i18n
42
42
  requirement: !ruby/object:Gem::Requirement