w3c_api 0.1.1 → 0.1.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: e5227c6f6b71312ce390dadc6053628d111cc387d1477e43ab7aa2473200e611
4
- data.tar.gz: a6b3afb0ee859b549234c9fe0c55c64896c14d0d2ddc31d20d19040d2859772a
3
+ metadata.gz: 0c0510c0782d6254f3b44a3a7beedd38e75347803c4c1bd24caca60a154210db
4
+ data.tar.gz: 1be78e42272c5b5b6b67eb02193605a0845f68ac2c85cb2fb3a59217d67973ef
5
5
  SHA512:
6
- metadata.gz: d9a9ffeb9cf9b32c35015b22f89c8d152e508098b14365b964ae12c21712371f1bd8c9793e634444a5e96539887d709b59a08540e65c80b72c357efa3e95fa22
7
- data.tar.gz: cd5575a30e2c307de3fa1b679de2f10fb9c07ff340b9f76e76d3aa030ff68be73623f24b29bcb0dfde2926f0a31f6ba584e580ac1521c19b8f6bb210f6f33475
6
+ metadata.gz: d043016ab770ef2df85493e3589f72acc960e6e5db4bd34dfdfbbdf09d1bb87a490a0d0bf0d624e1f536a0271d67382ed118e2ee093bd3e95b572e19d9decd71
7
+ data.tar.gz: ad8b105ca1cbff73c29ea76cfa757288f056c683f13b583c7066620883e641ab1b6340f998117db55b41416083df146a5b50bb5f799cb0cc5148fe6e3e74cbef
data/.rubocop.yml ADDED
@@ -0,0 +1 @@
1
+ inherit_from: .rubocop_todo.yml
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,40 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2025-07-03 16:44:51 UTC using RuboCop version 1.77.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 2
10
+ # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
11
+ Metrics/AbcSize:
12
+ Max: 32
13
+
14
+ # Offense count: 35
15
+ # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
16
+ # AllowedMethods: refine
17
+ Metrics/BlockLength:
18
+ Max: 373
19
+
20
+ # Offense count: 1
21
+ # Configuration parameters: CountComments, CountAsOne.
22
+ Metrics/ClassLength:
23
+ Max: 225
24
+
25
+ # Offense count: 2
26
+ # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
27
+ Metrics/MethodLength:
28
+ Max: 184
29
+
30
+ # Offense count: 30
31
+ # Configuration parameters: AllowedConstants.
32
+ Style/Documentation:
33
+ Enabled: false
34
+
35
+ # Offense count: 7
36
+ # This cop supports safe autocorrection (--autocorrect).
37
+ # Configuration parameters: AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
38
+ # URISchemes: http, https
39
+ Layout/LineLength:
40
+ Max: 457
data/README.adoc CHANGED
@@ -11,27 +11,27 @@ A Ruby client implementation for the W3C web API with a CLI interface.
11
11
  This gem provides:
12
12
 
13
13
  * A complete client for the W3C API (oft-used endpoints implemented)
14
-
15
14
  * Data models created with
16
15
  https://github.com/lutaml/lutaml-hal[lutaml-hal] and
17
16
  https://github.com/lutaml/lutaml-model[lutaml-model]
18
17
  for all W3C API resources
19
-
20
- * HAL (Hypertext Application Language) implementation for recursive resource traversal
21
-
18
+ * HAL (Hypertext Application Language) implementation for recursive resource
19
+ traversal
22
20
  * A command-line interface using Thor following GitHub CLI patterns
23
21
 
24
22
  The endpoint supported is at https://api.w3.org.
25
23
 
26
24
  This gem is developed against the W3C API documented at https://api.w3.org/doc.
27
25
 
28
-
29
26
  == Illustrative example usage
30
27
 
31
28
  This is an example demonstrating the power of this library as inherited
32
29
  from `lutaml-hal`, showing multiple levels of automatic link resolution.
33
30
 
31
+ [example]
32
+ ====
34
33
  .Calling the Ruby API with multiple levels of link resolution
34
+
35
35
  [source,ruby]
36
36
  ----
37
37
  > require 'w3c_api'
@@ -100,7 +100,7 @@ from `lutaml-hal`, showing multiple levels of automatic link resolution.
100
100
  # @pages=1,
101
101
  # @total=1>
102
102
  ----
103
-
103
+ ====
104
104
 
105
105
  == Ruby API
106
106
 
@@ -121,6 +121,38 @@ versions = client.specification_versions('webrtc')
121
121
  version = client.specification_version('webrtc', '20241008')
122
122
  specs_by_status = client.specifications_by_status('Recommendation')
123
123
 
124
+ # Get predecessor and successor versions
125
+ predecessors = client.specification_version_predecessors('webrtc', '20241008')
126
+ successors = client.specification_version_successors('webrtc', '20241008')
127
+
128
+ # All client methods support comprehensive options including:
129
+
130
+ # Pagination options
131
+ specifications = client.specifications(page: 2, items: 50)
132
+ groups = client.groups(page: 1, items: 10)
133
+
134
+ # HTTP client options
135
+ user = client.user('hash', timeout: 30, headers: { 'User-Agent' => 'MyApp/1.0' })
136
+ spec = client.specification('html5', read_timeout: 45, open_timeout: 10)
137
+
138
+ # Query parameters for filtering and sorting
139
+ rec_specs = client.specifications_by_status('REC', sort: 'date', order: 'desc')
140
+ active_groups = client.groups(type: 'working-group', status: 'active')
141
+
142
+ # Combining multiple options
143
+ options = {
144
+ page: 1,
145
+ per_page: 25,
146
+ headers: { 'Accept-Language' => 'en-US' },
147
+ timeout: 60,
148
+ sort: 'name'
149
+ }
150
+ specs = client.specifications(options)
151
+
152
+ # Backward compatibility - existing code continues to work
153
+ specifications = client.specifications # No options
154
+ specification = client.specification('webrtc') # Required params only
155
+
124
156
  # Work with linked resources directly
125
157
  spec = client.specification('webrtc')
126
158
  spec_versions = spec.links.versions
@@ -170,6 +202,155 @@ ecosystems = client.ecosystems
170
202
  ecosystem = client.ecosystem('data')
171
203
  ----
172
204
 
205
+ === Pagination
206
+
207
+ All index endpoints support pagination with the following parameters:
208
+
209
+ * `page` - The page number to retrieve (default: 1)
210
+ * `items` - The number of items per page (default: 100)
211
+
212
+ ==== Basic pagination
213
+
214
+ [source,ruby]
215
+ ----
216
+ # Get first page with default limit (100 items)
217
+ specifications = client.specifications
218
+
219
+ # Get specific page with custom limit
220
+ specifications = client.specifications(page: 2, items: 25)
221
+
222
+ # Get first page with smaller limit
223
+ groups = client.groups(page: 1, items: 10)
224
+ ----
225
+
226
+ ==== Navigation links
227
+
228
+ All paginated responses include navigation links that can be used to traverse
229
+ pages:
230
+
231
+ [source,ruby]
232
+ ----
233
+ # Get first page
234
+ specs_page1 = client.specifications(page: 1, items: 10)
235
+
236
+ # Access navigation links
237
+ links = specs_page1.links
238
+
239
+ # Check available navigation options
240
+ puts "Has next page: #{!links.next.nil?}"
241
+ puts "Has previous page: #{!links.prev.nil?}"
242
+
243
+ # Navigate to next page using the link
244
+ if links.next
245
+ next_page = links.next.realize
246
+ puts "Next page number: #{next_page.page}"
247
+ puts "Items on next page: #{next_page.links.specifications.length}"
248
+ end
249
+
250
+ # Navigate to first/last pages
251
+ first_page = links.first.realize if links.first
252
+ last_page = links.last.realize if links.last
253
+ ----
254
+
255
+ ==== Pagination information
256
+
257
+ Each paginated response includes metadata about the pagination state:
258
+
259
+ [source,ruby]
260
+ ----
261
+ specs = client.specifications(page: 2, items: 25)
262
+
263
+ puts "Current page: #{specs.page}" # 2
264
+ puts "Items per page: #{specs.limit}" # 25
265
+ puts "Total items: #{specs.total}" # e.g., 1643
266
+ puts "Total pages: #{specs.pages}" # e.g., 66
267
+ ----
268
+
269
+ ==== Iterating through all pages
270
+
271
+ [source,ruby]
272
+ ----
273
+ # Method 1: Using navigation links
274
+ current_page = client.specifications(page: 1, items: 50)
275
+ all_specifications = []
276
+
277
+ loop do
278
+ all_specifications.concat(current_page.links.specifications)
279
+
280
+ break unless current_page.links.next
281
+
282
+ current_page = current_page.links.next.realize
283
+ end
284
+
285
+ puts "Total specifications collected: #{all_specifications.length}"
286
+
287
+ # Method 2: Manual page iteration
288
+ page = 1
289
+ all_specifications = []
290
+
291
+ loop do
292
+ current_page = client.specifications(page: page, items: 50)
293
+ specifications = current_page.links.specifications
294
+
295
+ break if specifications.empty?
296
+
297
+ all_specifications.concat(specifications)
298
+ page += 1
299
+ end
300
+ ----
301
+
302
+ ==== Pagination for nested resources
303
+
304
+ Nested resources also support pagination:
305
+
306
+ [source,ruby]
307
+ ----
308
+ # Get a group
309
+ group = client.group(109735)
310
+
311
+ # Get paginated specifications for this group
312
+ specs = group.specifications(page: 1, items: 10)
313
+
314
+ # Navigate through pages
315
+ if specs.links.next
316
+ next_specs = specs.links.next.realize
317
+ end
318
+
319
+ # Other nested resources with pagination
320
+ users = group.users(page: 1, items: 20)
321
+ chairs = group.chairs(page: 1, items: 5)
322
+ participations = group.participations(page: 1, items: 15)
323
+
324
+ # Affiliation nested resources
325
+ affiliation = client.affiliation(35662)
326
+ participants = affiliation.participants(page: 1, items: 10)
327
+ participations = affiliation.participations(page: 1, items: 10)
328
+ ----
329
+
330
+ ==== Supported endpoints
331
+
332
+ All the following endpoints support pagination:
333
+
334
+ * `client.specifications(page:, items:)`
335
+ * `client.groups(page:, items:)`
336
+ * `client.affiliations(page:, items:)`
337
+ * `client.series(page:, items:)`
338
+ * `client.translations(page:, items:)`
339
+ * `client.ecosystems(page:, items:)`
340
+ * `group.specifications(page:, items:)`
341
+ * `group.users(page:, items:)`
342
+ * `group.chairs(page:, items:)`
343
+ * `group.team_contacts(page:, items:)`
344
+ * `group.participations(page:, items:)`
345
+ * `affiliation.participants(page:, items:)`
346
+ * `affiliation.participations(page:, items:)`
347
+ * `participation.participants(page:, items:)`
348
+ * `user.groups(page:, items:)`
349
+ * `user.specifications(page:, items:)`
350
+ * `user.affiliations(page:, items:)`
351
+ * `user.participations(page:, items:)`
352
+ * And many more nested resource endpoints
353
+
173
354
  === Models
174
355
 
175
356
  ==== General
@@ -247,8 +428,8 @@ W3C API provides a command-line interface (CLI) for various operations.
247
428
 
248
429
  The main executable is `w3c_api`.
249
430
 
250
- By default, the output is in YAML format. You can specify the output format using the
251
- `--format` option, which accepts `json` or `yaml`.
431
+ By default, the output is in YAML format. You can specify the output format
432
+ using the `--format` option, which accepts `json` or `yaml`.
252
433
 
253
434
  [source,shell]
254
435
  ----
@@ -535,9 +716,12 @@ specifications:
535
716
  This command provides access to W3C users.
536
717
 
537
718
  [IMPORTANT]
538
- .User ID Formats
719
+ .User ID formats
539
720
  ====
540
- The W3C API uses both numeric IDs (e.g., `128112`) and string IDs (e.g., `f1ovb5rydm8s0go04oco0cgk0sow44w`) for users. All user-related commands support both formats. The format depends on how the user is referenced in API responses.
721
+ The W3C API uses both numeric IDs (e.g., `128112`) and string IDs (e.g.,
722
+ `f1ovb5rydm8s0go04oco0cgk0sow44w`) for users. All user-related commands
723
+ support both formats. The format depends on how the user is referenced in API
724
+ responses.
541
725
  ====
542
726
 
543
727
  ==== Get
@@ -742,7 +926,7 @@ participations:
742
926
  ----
743
927
  ====
744
928
 
745
- ==== Chair of Groups
929
+ ==== Chair of groups
746
930
 
747
931
  Getting groups a user chairs.
748
932
 
data/Rakefile CHANGED
@@ -1,8 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
8
- task default: :spec
8
+ require 'rubocop/rake_task'
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -7,185 +7,134 @@ require_relative 'hal'
7
7
 
8
8
  module W3cApi
9
9
  class Client
10
- def specifications(options = {})
11
- Hal.instance.register.fetch(:specification_index)
10
+ # Specification methods
11
+ def specifications(options = nil)
12
+ fetch_resource(:specification_index, **(options || {}))
12
13
  end
13
14
 
14
15
  def specification(shortname, options = {})
15
- Hal.instance.register.fetch(:specification_resource, shortname: shortname)
16
+ fetch_resource(:specification_resource, shortname: shortname, **options)
16
17
  end
17
18
 
18
19
  def specification_versions(shortname, options = {})
19
- Hal.instance.register.fetch(:specification_resource_version_index, shortname: shortname)
20
+ fetch_resource(:specification_resource_version_index,
21
+ shortname: shortname, **options)
20
22
  end
21
23
 
22
24
  def specification_version(shortname, version, options = {})
23
- Hal.instance.register.fetch(:specification_resource_version_resource, shortname: shortname, version: version)
25
+ fetch_resource(:specification_resource_version_resource,
26
+ shortname: shortname, version: version, **options)
24
27
  end
25
28
 
26
29
  def specifications_by_status(status, options = {})
27
- Hal.instance.register.fetch(:specification_by_status_index, status: status)
30
+ fetch_resource(:specification_by_status_index, status: status, **options)
28
31
  end
29
32
 
30
- def specification_supersedes(shortname, options = {})
31
- Hal.instance.register.fetch(:specification_supersedes_index, shortname: shortname)
32
- end
33
-
34
- def specification_superseded_by(shortname, options = {})
35
- Hal.instance.register.fetch(:specification_superseded_by_index, shortname: shortname)
36
- end
37
-
38
- # New methods for editors and deliverers
39
-
40
- def specification_editors(shortname, options = {})
41
- Hal.instance.register.fetch(:specification_editors_index, shortname: shortname)
42
- end
43
-
44
- def specification_deliverers(shortname, options = {})
45
- Hal.instance.register.fetch(:specification_deliverers_index, shortname: shortname)
33
+ %w[supersedes superseded_by editors deliverers].each do |method_suffix|
34
+ define_method("specification_#{method_suffix}") do |shortname, options = {}|
35
+ fetch_resource(:"specification_#{method_suffix}_index",
36
+ shortname: shortname, **options)
37
+ end
46
38
  end
47
39
 
48
40
  # Series methods
49
-
50
41
  def series(options = {})
51
- Hal.instance.register.fetch(:serie_index)
42
+ fetch_resource(:serie_index, **options)
52
43
  end
53
44
 
54
45
  def series_by_shortname(shortname, options = {})
55
- Hal.instance.register.fetch(:serie_resource, shortname: shortname)
46
+ fetch_resource(:serie_resource, shortname: shortname, **options)
56
47
  end
57
48
 
58
49
  def series_specifications(shortname, options = {})
59
- Hal.instance.register.fetch(:serie_specification_resource, shortname: shortname)
50
+ fetch_resource(:serie_specification_resource,
51
+ shortname: shortname, **options)
60
52
  end
61
53
 
62
54
  # Group methods
63
-
64
55
  def groups(options = {})
65
- Hal.instance.register.fetch(:group_index)
56
+ fetch_resource(:group_index, **options)
66
57
  end
67
58
 
68
59
  def group(id, options = {})
69
- Hal.instance.register.fetch(:group_resource, id: id)
70
- end
71
-
72
- def group_specifications(id, options = {})
73
- Hal.instance.register.fetch(:group_specifications_index, id: id)
60
+ fetch_resource(:group_resource, id: id, **options)
74
61
  end
75
62
 
76
- def group_users(id, options = {})
77
- Hal.instance.register.fetch(:group_users_index, id: id)
78
- end
79
-
80
- def group_charters(id, options = {})
81
- Hal.instance.register.fetch(:group_charters_index, id: id)
82
- end
83
-
84
- def group_chairs(id, options = {})
85
- Hal.instance.register.fetch(:group_chairs_index, id: id)
86
- end
87
-
88
- def group_team_contacts(id, options = {})
89
- Hal.instance.register.fetch(:group_team_contacts_index, id: id)
90
- end
91
-
92
- def group_participations(id, options = {})
93
- Hal.instance.register.fetch(:group_participations_index, id: id)
63
+ %w[specifications users charters chairs team_contacts participations].each do |resource|
64
+ define_method("group_#{resource}") do |id, options = {}|
65
+ fetch_resource(:"group_#{resource}_index", id: id, **options)
66
+ end
94
67
  end
95
68
 
96
69
  # User methods
97
-
98
- # def users(options = {})
99
- # raise ArgumentError,
100
- # 'The W3C API does not support fetching all users. You must provide a specific user ID with the user method.'
101
- # end
102
-
103
70
  def user(hash, options = {})
104
- Hal.instance.register.fetch(:user_resource, hash: hash)
105
- end
106
-
107
- def user_groups(hash, options = {})
108
- Hal.instance.register.fetch(:user_groups_index, hash: hash)
109
- end
110
-
111
- def user_affiliations(hash, options = {})
112
- Hal.instance.register.fetch(:user_affiliations_index, hash: hash)
71
+ fetch_resource(:user_resource, hash: hash, **options)
113
72
  end
114
73
 
115
- def user_participations(hash, options = {})
116
- Hal.instance.register.fetch(:user_participations_index, hash: hash)
117
- end
118
-
119
- def user_chair_of_groups(hash, options = {})
120
- Hal.instance.register.fetch(:user_chair_of_groups_index, hash: hash)
121
- end
122
-
123
- def user_team_contact_of_groups(hash, options = {})
124
- Hal.instance.register.fetch(:user_team_contact_of_groups_index, hash: hash)
125
- end
126
-
127
- def user_specifications(hash, options = {})
128
- Hal.instance.register.fetch(:user_specifications_index, hash: hash)
74
+ %w[groups affiliations participations chair_of_groups
75
+ team_contact_of_groups specifications].each do |resource|
76
+ define_method("user_#{resource}") do |hash, options = {}|
77
+ fetch_resource(:"user_#{resource}_index", hash: hash, **options)
78
+ end
129
79
  end
130
80
 
131
81
  # Translation methods
132
-
133
82
  def translations(options = {})
134
- Hal.instance.register.fetch(:translation_index)
83
+ fetch_resource(:translation_index, **options)
135
84
  end
136
85
 
137
86
  def translation(id, options = {})
138
- Hal.instance.register.fetch(:translation_resource, id: id)
87
+ fetch_resource(:translation_resource, id: id, **options)
139
88
  end
140
89
 
141
90
  # Affiliation methods
142
-
143
91
  def affiliations(options = {})
144
- Hal.instance.register.fetch(:affiliation_index)
92
+ fetch_resource(:affiliation_index, **options)
145
93
  end
146
94
 
147
95
  def affiliation(id, options = {})
148
- Hal.instance.register.fetch(:affiliation_resource, id: id)
96
+ fetch_resource(:affiliation_resource, id: id, **options)
149
97
  end
150
98
 
151
- def affiliation_participants(id, options = {})
152
- Hal.instance.register.fetch(:affiliation_participants_index, id: id)
153
- end
154
-
155
- def affiliation_participations(id, options = {})
156
- Hal.instance.register.fetch(:affiliation_participations_index, id: id)
99
+ %w[participants participations].each do |resource|
100
+ define_method("affiliation_#{resource}") do |id, options = {}|
101
+ fetch_resource(:"affiliation_#{resource}_index", id: id, **options)
102
+ end
157
103
  end
158
104
 
159
105
  # Ecosystem methods
160
-
161
106
  def ecosystems(options = {})
162
- Hal.instance.register.fetch(:ecosystem_index)
107
+ fetch_resource(:ecosystem_index, **options)
163
108
  end
164
109
 
165
110
  def ecosystem(id, options = {})
166
- Hal.instance.register.fetch(:ecosystem_resource, id: id)
111
+ fetch_resource(:ecosystem_resource, id: id, **options)
167
112
  end
168
113
 
169
- def ecosystem_groups(shortname, options = {})
170
- Hal.instance.register.fetch(:ecosystem_groups_index, shortname: shortname)
171
- end
172
-
173
- def ecosystem_evangelists(shortname, options = {})
174
- Hal.instance.register.fetch(:ecosystem_evangelists_index, shortname: shortname)
175
- end
176
-
177
- def ecosystem_member_organizations(shortname, options = {})
178
- Hal.instance.register.fetch(:ecosystem_member_organizations_index, shortname: shortname)
114
+ %w[groups evangelists member_organizations].each do |resource|
115
+ define_method("ecosystem_#{resource}") do |shortname, options = {}|
116
+ fetch_resource(:"ecosystem_#{resource}_index",
117
+ shortname: shortname, **options)
118
+ end
179
119
  end
180
120
 
181
121
  # Participation methods
182
-
183
122
  def participation(id, options = {})
184
- Hal.instance.register.fetch(:participation_resource, id: id)
123
+ fetch_resource(:participation_resource, id: id, **options)
185
124
  end
186
125
 
187
126
  def participation_participants(id, options = {})
188
- Hal.instance.register.fetch(:participation_participants_index, id: id)
127
+ fetch_resource(:participation_participants_index, id: id, **options)
128
+ end
129
+
130
+ private
131
+
132
+ def fetch_resource(resource_key, **params)
133
+ if params.any?
134
+ Hal.instance.register.fetch(resource_key, **params)
135
+ else
136
+ Hal.instance.register.fetch(resource_key)
137
+ end
189
138
  end
190
139
  end
191
140
  end
data/lib/w3c_api/hal.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'singleton'
2
4
  require_relative 'models'
3
5
 
@@ -5,124 +7,236 @@ module W3cApi
5
7
  class Hal
6
8
  include Singleton
7
9
 
10
+ API_URL = 'https://api.w3.org/'
11
+
8
12
  def initialize
9
13
  setup
10
14
  end
11
15
 
12
16
  def client
13
- @client ||= Lutaml::Hal::Client.new(api_url: 'https://api.w3.org/')
17
+ @client ||= Lutaml::Hal::Client.new(api_url: API_URL)
14
18
  end
15
19
 
16
20
  def register
17
21
  return @register if @register
18
22
 
19
23
  @register = Lutaml::Hal::ModelRegister.new(name: :w3c_api, client: client)
20
- Lutaml::Hal::GlobalRegister.instance.register(:w3c_api, @register)
24
+ Lutaml::Hal::GlobalRegister.instance.register(
25
+ :w3c_api, @register
26
+ )
21
27
  @register
22
28
  end
23
29
 
24
- def setup
25
- register.add_endpoint(id: :affiliation_index, type: :index, url: '/affiliations', model: Models::AffiliationIndex)
26
- register.add_endpoint(id: :affiliation_resource, type: :resource, url: '/affiliations/{id}',
27
- model: Models::Affiliation)
28
- register.add_endpoint(id: :affiliation_participants_index, type: :index, url: '/affiliations/{id}/participants',
29
- model: Models::ParticipantIndex)
30
- register.add_endpoint(id: :affiliation_participations_index, type: :index, url: '/affiliations/{id}/participations',
31
- model: Models::ParticipationIndex)
32
-
33
- # register.add_endpoint(id: :charter_resource, type: :resource, url: '/charters/{id}', model: Models::Charter)
34
-
35
- register.add_endpoint(id: :ecosystem_index, type: :index, url: '/ecosystems', model: Models::EcosystemIndex)
36
- register.add_endpoint(id: :ecosystem_resource, type: :resource, url: '/ecosystems/{id}', model: Models::Ecosystem)
37
- register.add_endpoint(id: :ecosystem_evangelists_index, type: :index, url: '/ecosystems/{shortname}/evangelists',
38
- model: Models::EvangelistIndex)
39
- register.add_endpoint(id: :ecosystem_groups_index, type: :index, url: '/ecosystems/{shortname}/groups',
40
- model: Models::GroupIndex)
41
- register.add_endpoint(id: :ecosystem_member_organizations_index, type: :index, url: '/ecosystems/{shortname}/member-organizations',
42
- model: Models::AffiliationIndex)
43
-
44
- register.add_endpoint(id: :group_index, type: :index, url: '/groups', model: Models::GroupIndex)
45
- register.add_endpoint(id: :group_resource, type: :resource, url: '/groups/{id}', model: Models::Group)
46
- register.add_endpoint(id: :group_specifications_index, type: :index, url: '/groups/{id}/specifications',
47
- model: Models::SpecificationIndex)
48
- register.add_endpoint(id: :group_charters_index, type: :index, url: '/groups/{id}/charters',
49
- model: Models::CharterIndex)
50
- register.add_endpoint(id: :group_users_index, type: :index, url: '/groups/{id}/users',
51
- model: Models::UserIndex)
52
- register.add_endpoint(id: :group_chairs_index, type: :index, url: '/groups/{id}/chairs',
53
- model: Models::ChairIndex)
54
- register.add_endpoint(id: :group_team_contacts_index, type: :index, url: '/groups/{id}/teamcontacts',
55
- model: Models::TeamContactIndex)
56
- register.add_endpoint(id: :group_participations_index, type: :index, url: '/groups/{id}/participations',
57
- model: Models::ParticipationIndex)
58
-
59
- # register.add_endpoint(id: :participation_index, type: :index, url: '/participations', model: Models::ParticipationIndex)
60
- register.add_endpoint(id: :participation_resource, type: :resource, url: '/participations/{id}',
61
- model: Models::Participation)
62
- register.add_endpoint(id: :participation_participants_index, type: :index, url: '/participations/{id}/participants',
63
- model: Models::ParticipantIndex)
64
-
65
- register.add_endpoint(id: :serie_index, type: :index, url: '/specification-series', model: Models::SerieIndex)
66
- register.add_endpoint(id: :serie_resource, type: :resource, url: '/specification-series/{shortname}',
67
- model: Models::Serie)
68
-
69
- register.add_endpoint(id: :serie_specification_resource, type: :index,
70
- url: '/specification-series/{shortname}/specifications', model: Models::SpecificationIndex)
71
-
72
- register.add_endpoint(id: :specification_index, type: :index, url: '/specifications',
73
- model: Models::SpecificationIndex)
74
- register.add_endpoint(id: :specification_resource, type: :resource, url: '/specifications/{shortname}',
75
- model: Models::Specification)
76
- register.add_endpoint(id: :specification_resource_version_index, type: :index, url: '/specifications/{shortname}/versions',
77
- model: Models::SpecVersionIndex)
30
+ private
78
31
 
32
+ # Common pagination query parameters
33
+ PAGINATION_PARAMS = { 'page' => '{page}',
34
+ 'items' => '{items}' }.freeze
35
+
36
+ # Helper method to add index endpoints with pagination
37
+ def add_index_endpoint(id, url, model, query_params = PAGINATION_PARAMS)
79
38
  register.add_endpoint(
80
- id: :specification_resource_version_resource,
81
- type: :resource,
82
- url: '/specifications/{shortname}/versions/{version}',
83
- model: Models::SpecVersion
84
- )
85
- register.add_endpoint(
86
- id: :specification_version_predecessors_index,
39
+ id: id,
87
40
  type: :index,
88
- url: '/specifications/{shortname}/versions/{version}/predecessors',
89
- model: Models::SpecVersionIndex
41
+ url: url,
42
+ model: model,
43
+ query_params: query_params
90
44
  )
91
- register.add_endpoint(
92
- id: :specification_version_successors_index,
93
- type: :index,
94
- url: '/specifications/{shortname}/versions/{version}/successors',
95
- model: Models::SpecVersionIndex
45
+ end
46
+
47
+ # Helper method to add resource endpoints
48
+ def add_resource_endpoint(id, url, model)
49
+ register.add_endpoint(id: id, type: :resource, url: url, model: model)
50
+ end
51
+
52
+ # Helper method to add nested index endpoints for a parent resource
53
+ def add_nested_index_endpoints(parent, parent_id_param, nested_configs)
54
+ nested_configs.each do |config|
55
+ # Convert plural parent to singular for endpoint naming
56
+ singular_parent = parent.end_with?('s') ? parent[0..-2] : parent
57
+ id = "#{singular_parent}_#{config[:name]}_index".to_sym
58
+ url = "/#{parent}/#{parent_id_param}/#{config[:path]}"
59
+ add_index_endpoint(id, url, config[:model])
60
+ end
61
+ end
62
+
63
+ def setup
64
+ # Affiliation endpoints
65
+ add_index_endpoint(
66
+ :affiliation_index,
67
+ '/affiliations',
68
+ Models::AffiliationIndex
96
69
  )
97
- register.add_endpoint(
98
- id: :specification_by_status_index,
99
- type: :index,
100
- url: '/specifications-by-status/{status}',
101
- model: Models::SpecificationIndex
70
+ add_resource_endpoint(
71
+ :affiliation_resource,
72
+ '/affiliations/{id}',
73
+ Models::Affiliation
102
74
  )
103
- register.add_endpoint(
104
- id: :specification_supersedes_index,
105
- type: :index,
106
- url: '/specifications/{shortname}/supersedes',
107
- model: Models::SpecificationIndex
75
+ add_index_endpoint(
76
+ :affiliation_participants_index,
77
+ '/affiliations/{id}/participants',
78
+ Models::ParticipantIndex
108
79
  )
109
- register.add_endpoint(
110
- id: :specification_superseded_by_index,
111
- type: :index,
112
- url: '/specifications/{shortname}/superseded',
113
- model: Models::SpecificationIndex
80
+ add_index_endpoint(
81
+ :affiliation_participations_index,
82
+ '/affiliations/{id}/participations',
83
+ Models::ParticipationIndex
114
84
  )
115
- register.add_endpoint(
116
- id: :specification_version_editors_index,
117
- type: :index,
118
- url: '/specifications/{shortname}/version/{version}/editors',
119
- model: Models::UserIndex
85
+
86
+ # register.add_endpoint(
87
+ # id: :charter_resource,
88
+ # type: :resource,
89
+ # url: '/charters/{id}',
90
+ # model: Models::Charter
91
+ # )
92
+
93
+ # Ecosystem endpoints
94
+ add_index_endpoint(
95
+ :ecosystem_index,
96
+ '/ecosystems',
97
+ Models::EcosystemIndex
120
98
  )
121
- register.add_endpoint(
122
- id: :specification_version_deliverers_index,
123
- type: :index,
124
- url: '/specifications/{shortname}/version/{version}/deliverers',
125
- model: Models::UserIndex
99
+ add_resource_endpoint(
100
+ :ecosystem_resource,
101
+ '/ecosystems/{id}',
102
+ Models::Ecosystem
103
+ )
104
+ add_index_endpoint(
105
+ :ecosystem_evangelists_index,
106
+ '/ecosystems/{shortname}/evangelists',
107
+ Models::EvangelistIndex
108
+ )
109
+ add_index_endpoint(
110
+ :ecosystem_groups_index,
111
+ '/ecosystems/{shortname}/groups',
112
+ Models::GroupIndex
113
+ )
114
+ add_index_endpoint(
115
+ :ecosystem_member_organizations_index,
116
+ '/ecosystems/{shortname}/member-organizations',
117
+ Models::AffiliationIndex
118
+ )
119
+
120
+ # Group endpoints
121
+ add_index_endpoint(
122
+ :group_index,
123
+ '/groups',
124
+ Models::GroupIndex
125
+ )
126
+ add_resource_endpoint(
127
+ :group_resource,
128
+ '/groups/{id}',
129
+ Models::Group
130
+ )
131
+ add_nested_index_endpoints(
132
+ 'groups',
133
+ '{id}', [
134
+ { name: 'specifications', path: 'specifications',
135
+ model: Models::SpecificationIndex },
136
+ { name: 'charters', path: 'charters',
137
+ model: Models::CharterIndex },
138
+ { name: 'users', path: 'users',
139
+ model: Models::UserIndex },
140
+ { name: 'chairs', path: 'chairs',
141
+ model: Models::ChairIndex },
142
+ { name: 'team_contacts', path: 'teamcontacts',
143
+ model: Models::TeamContactIndex },
144
+ { name: 'participations', path: 'participations',
145
+ model: Models::ParticipationIndex }
146
+ ]
147
+ )
148
+
149
+ # Participation endpoints
150
+ # register.add_endpoint(
151
+ # id: :participation_index,
152
+ # type: :index,
153
+ # url: '/participations',
154
+ # model: Models::ParticipationIndex
155
+ # )
156
+
157
+ add_resource_endpoint(
158
+ :participation_resource,
159
+ '/participations/{id}',
160
+ Models::Participation
161
+ )
162
+ add_index_endpoint(
163
+ :participation_participants_index,
164
+ '/participations/{id}/participants',
165
+ Models::ParticipantIndex
166
+ )
167
+
168
+ # Serie endpoints
169
+ add_index_endpoint(
170
+ :serie_index,
171
+ '/specification-series',
172
+ Models::SerieIndex
173
+ )
174
+ add_resource_endpoint(
175
+ :serie_resource,
176
+ '/specification-series/{shortname}',
177
+ Models::Serie
178
+ )
179
+ add_index_endpoint(
180
+ :serie_specification_resource,
181
+ '/specification-series/{shortname}/specifications',
182
+ Models::SpecificationIndex
183
+ )
184
+
185
+ # Specification endpoints
186
+ add_index_endpoint(
187
+ :specification_index,
188
+ '/specifications',
189
+ Models::SpecificationIndex
190
+ )
191
+ add_resource_endpoint(
192
+ :specification_resource,
193
+ '/specifications/{shortname}',
194
+ Models::Specification
195
+ )
196
+ add_index_endpoint(
197
+ :specification_resource_version_index,
198
+ '/specifications/{shortname}/versions',
199
+ Models::SpecVersionIndex
200
+ )
201
+ add_resource_endpoint(
202
+ :specification_resource_version_resource,
203
+ '/specifications/{shortname}/versions/{version}',
204
+ Models::SpecVersion
205
+ )
206
+ add_index_endpoint(
207
+ :specification_version_predecessors_index,
208
+ '/specifications/{shortname}/versions/{version}/predecessors',
209
+ Models::SpecVersionIndex
210
+ )
211
+ add_index_endpoint(
212
+ :specification_version_successors_index,
213
+ '/specifications/{shortname}/versions/{version}/successors',
214
+ Models::SpecVersionIndex
215
+ )
216
+ add_index_endpoint(
217
+ :specification_by_status_index,
218
+ '/specifications-by-status/{status}',
219
+ Models::SpecificationIndex
220
+ )
221
+ add_index_endpoint(
222
+ :specification_supersedes_index,
223
+ '/specifications/{shortname}/supersedes',
224
+ Models::SpecificationIndex
225
+ )
226
+ add_index_endpoint(
227
+ :specification_superseded_by_index,
228
+ '/specifications/{shortname}/superseded',
229
+ Models::SpecificationIndex
230
+ )
231
+ add_index_endpoint(
232
+ :specification_version_editors_index,
233
+ '/specifications/{shortname}/version/{version}/editors',
234
+ Models::UserIndex
235
+ )
236
+ add_index_endpoint(
237
+ :specification_version_deliverers_index,
238
+ '/specifications/{shortname}/version/{version}/deliverers',
239
+ Models::UserIndex
126
240
  )
127
241
 
128
242
  # TODO: Why is this endpoint needed? There already is /specifications/{shortname}...
@@ -133,32 +247,48 @@ module W3cApi
133
247
  # model: Models::SpecificationIndex
134
248
  # )
135
249
 
136
- register.add_endpoint(id: :translation_index, type: :index, url: '/translations', model: Models::TranslationIndex)
137
- register.add_endpoint(id: :translation_resource, type: :resource, url: '/translations/{id}',
138
- model: Models::Translation)
250
+ # Translation endpoints
251
+ add_index_endpoint(
252
+ :translation_index,
253
+ '/translations',
254
+ Models::TranslationIndex
255
+ )
256
+ add_resource_endpoint(
257
+ :translation_resource,
258
+ '/translations/{id}',
259
+ Models::Translation
260
+ )
139
261
 
262
+ # User endpoints
140
263
  # NOTE: This endpoint doesn't exist, just here for reference.
141
- # register.add_endpoint(id: :user_index, type: :index, url: '/users', model: Models::UserIndex)
142
-
143
- register.add_endpoint(id: :user_groups_index, type: :index, url: '/users/{hash}/groups',
144
- model: Models::GroupIndex)
145
-
146
- register.add_endpoint(id: :user_resource, type: :resource, url: '/users/{hash}', model: Models::User)
147
-
148
- register.add_endpoint(id: :user_affiliations_index, type: :index, url: '/users/{hash}/affiliations',
149
- model: Models::AffiliationIndex)
150
-
151
- register.add_endpoint(id: :user_participations_index, type: :index, url: '/users/{hash}/participations',
152
- model: Models::ParticipationIndex)
153
-
154
- register.add_endpoint(id: :user_chair_of_groups_index, type: :index, url: '/users/{hash}/chair-of-groups',
155
- model: Models::GroupIndex)
156
-
157
- register.add_endpoint(id: :user_team_contact_of_groups_index, type: :index, url: '/users/{hash}/team-contact-of-groups',
158
- model: Models::GroupIndex)
159
-
160
- register.add_endpoint(id: :user_specifications_index, type: :index, url: '/users/{hash}/specifications',
161
- model: Models::SpecificationIndex)
264
+ # register.add_endpoint(
265
+ # id: :user_index,
266
+ # type: :index,
267
+ # url: '/users',
268
+ # model: Models::UserIndex
269
+ # )
270
+ add_resource_endpoint(
271
+ :user_resource,
272
+ '/users/{hash}',
273
+ Models::User
274
+ )
275
+ add_nested_index_endpoints(
276
+ 'users',
277
+ '{hash}', [
278
+ { name: 'groups', path: 'groups',
279
+ model: Models::GroupIndex },
280
+ { name: 'affiliations', path: 'affiliations',
281
+ model: Models::AffiliationIndex },
282
+ { name: 'participations', path: 'participations',
283
+ model: Models::ParticipationIndex },
284
+ { name: 'chair_of_groups', path: 'chair-of-groups',
285
+ model: Models::GroupIndex },
286
+ { name: 'team_contact_of_groups', path: 'team-contact-of-groups',
287
+ model: Models::GroupIndex },
288
+ { name: 'specifications', path: 'specifications',
289
+ model: Models::SpecificationIndex }
290
+ ]
291
+ )
162
292
  end
163
293
  end
164
294
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'lutaml/hal'
2
4
  # {
3
5
  # "created": "2021-03-12T22:06:06+00:00",
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'specification_index'
4
+
5
+ module W3cApi
6
+ module Models
7
+ # Manual GroupLinkSet class to fix collection issue
8
+ class GroupLinkSet < Lutaml::Hal::LinkSet
9
+ # Define the specifications attribute with collection: true
10
+ # This is needed because the Group model's specifications link
11
+ # realizes to a SpecificationIndex which contains a collection
12
+ attribute :specifications, SpecificationIndexLink, collection: true
13
+
14
+ key_value do
15
+ map 'specifications', to: :specifications
16
+ end
17
+ end
18
+
19
+ # Define the link class for SpecificationIndex
20
+ class SpecificationIndexLink < Lutaml::Hal::Link
21
+ attribute :type, :string, default: 'SpecificationIndex'
22
+ end
23
+ end
24
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'lutaml/model'
2
4
 
3
5
  # "photos": [
@@ -5,9 +5,10 @@ require_relative 'spec_version'
5
5
  module W3cApi
6
6
  module Models
7
7
  class SpecVersionIndex < Lutaml::Hal::Page
8
+ hal_link :versions, key: 'versions', realize_class: 'SpecVersion', collection: true
8
9
  hal_link :spec_versions, key: 'version-history', realize_class: 'SpecVersion', collection: true
9
- hal_link :predecessor_version, key: 'predecessor-version', realize_class: 'SpecVersionIndex', collection: true
10
- hal_link :successor_version, key: 'successor-version', realize_class: 'SpecVersionIndex', collection: true
10
+ hal_link :predecessor_version, key: 'predecessor-version', realize_class: 'SpecVersion', collection: true
11
+ hal_link :successor_version, key: 'successor-version', realize_class: 'SpecVersion', collection: true
11
12
  end
12
13
  end
13
14
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'specification'
4
+
3
5
  module W3cApi
4
6
  module Models
5
7
  # SpecificationIndex class that models `/specifications`
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'lutaml/hal'
2
4
 
3
5
  # "testimonials": {
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'translation'
4
+
3
5
  # {
4
6
  # "page"=>1,
5
7
  # "limit"=>100,
@@ -9,7 +11,7 @@
9
11
  # "translations"=>[
10
12
  # {
11
13
  # "href"=>"https://api.w3.org/translations/2",
12
- # "title"=>"Vidéo: introduction à laccessibilité web et aux standards du W3C",
14
+ # "title"=>"Vidéo : introduction à l'accessibilité web et aux standards du W3C",
13
15
  # "language"=>"fr"
14
16
  # },
15
17
  # {
@@ -19,6 +19,7 @@ require_relative 'models/evangelist_index'
19
19
  require_relative 'models/extension'
20
20
  require_relative 'models/group'
21
21
  require_relative 'models/group_index'
22
+ require_relative 'models/group_link_set'
22
23
  require_relative 'models/join_emails'
23
24
  require_relative 'models/participant_index'
24
25
  require_relative 'models/participation'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module W3cApi
4
- VERSION = '0.1.1'
4
+ VERSION = '0.1.2'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: w3c_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -42,16 +42,16 @@ dependencies:
42
42
  name: lutaml-hal
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 0.1.6
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
- version: '0'
54
+ version: 0.1.6
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: lutaml-model
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -102,6 +102,8 @@ executables:
102
102
  extensions: []
103
103
  extra_rdoc_files: []
104
104
  files:
105
+ - ".rubocop.yml"
106
+ - ".rubocop_todo.yml"
105
107
  - LICENSE.md
106
108
  - README.adoc
107
109
  - Rakefile
@@ -134,6 +136,7 @@ files:
134
136
  - lib/w3c_api/models/extension.rb
135
137
  - lib/w3c_api/models/group.rb
136
138
  - lib/w3c_api/models/group_index.rb
139
+ - lib/w3c_api/models/group_link_set.rb
137
140
  - lib/w3c_api/models/join_emails.rb
138
141
  - lib/w3c_api/models/participant_index.rb
139
142
  - lib/w3c_api/models/participation.rb