w3c_api 0.1.0 → 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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/.rubocop_todo.yml +40 -0
  4. data/LICENSE.md +1 -1
  5. data/README.adoc +1032 -439
  6. data/Rakefile +7 -3
  7. data/lib/w3c_api/cli.rb +20 -20
  8. data/lib/w3c_api/client.rb +57 -237
  9. data/lib/w3c_api/commands/affiliation.rb +33 -33
  10. data/lib/w3c_api/commands/ecosystem.rb +47 -47
  11. data/lib/w3c_api/commands/group.rb +68 -68
  12. data/lib/w3c_api/commands/output_formatter.rb +11 -11
  13. data/lib/w3c_api/commands/participation.rb +20 -22
  14. data/lib/w3c_api/commands/series.rb +26 -26
  15. data/lib/w3c_api/commands/specification.rb +77 -52
  16. data/lib/w3c_api/commands/translation.rb +18 -18
  17. data/lib/w3c_api/commands/user.rb +60 -60
  18. data/lib/w3c_api/hal.rb +294 -0
  19. data/lib/w3c_api/models/account.rb +46 -0
  20. data/lib/w3c_api/models/affiliation.rb +54 -65
  21. data/lib/w3c_api/models/affiliation_index.rb +11 -0
  22. data/lib/w3c_api/models/call_for_translation.rb +15 -39
  23. data/lib/w3c_api/models/chair_index.rb +11 -0
  24. data/lib/w3c_api/models/charter.rb +48 -89
  25. data/lib/w3c_api/models/charter_index.rb +11 -0
  26. data/lib/w3c_api/models/connected_account.rb +21 -30
  27. data/lib/w3c_api/models/ecosystem.rb +20 -42
  28. data/lib/w3c_api/models/{ecosystems.rb → ecosystem_index.rb} +4 -10
  29. data/lib/w3c_api/models/evangelist_index.rb +11 -0
  30. data/lib/w3c_api/models/extension.rb +5 -7
  31. data/lib/w3c_api/models/group.rb +63 -142
  32. data/lib/w3c_api/models/group_index.rb +12 -0
  33. data/lib/w3c_api/models/group_link_set.rb +24 -0
  34. data/lib/w3c_api/models/join_emails.rb +5 -7
  35. data/lib/w3c_api/models/participant_index.rb +11 -0
  36. data/lib/w3c_api/models/participation.rb +31 -90
  37. data/lib/w3c_api/models/participation_index.rb +11 -0
  38. data/lib/w3c_api/models/photo.rb +28 -0
  39. data/lib/w3c_api/models/serie.rb +21 -51
  40. data/lib/w3c_api/models/{series.rb → serie_index.rb} +22 -13
  41. data/lib/w3c_api/models/spec_version.rb +69 -83
  42. data/lib/w3c_api/models/spec_version_index.rb +14 -0
  43. data/lib/w3c_api/models/spec_version_ref.rb +11 -13
  44. data/lib/w3c_api/models/specification.rb +54 -66
  45. data/lib/w3c_api/models/specification_index.rb +12 -0
  46. data/lib/w3c_api/models/team_contact_index.rb +11 -0
  47. data/lib/w3c_api/models/testimonial.rb +19 -0
  48. data/lib/w3c_api/models/translation.rb +33 -72
  49. data/lib/w3c_api/models/{translations.rb → translation_index.rb} +5 -11
  50. data/lib/w3c_api/models/user.rb +95 -165
  51. data/lib/w3c_api/models/user_index.rb +11 -0
  52. data/lib/w3c_api/models.rb +36 -12
  53. data/lib/w3c_api/version.rb +1 -1
  54. data/lib/w3c_api.rb +3 -2
  55. metadata +38 -19
  56. data/lib/w3c_api/models/affiliations.rb +0 -33
  57. data/lib/w3c_api/models/base.rb +0 -39
  58. data/lib/w3c_api/models/call_for_translation_ref.rb +0 -15
  59. data/lib/w3c_api/models/charters.rb +0 -17
  60. data/lib/w3c_api/models/collection_base.rb +0 -79
  61. data/lib/w3c_api/models/delegate_enumerable.rb +0 -54
  62. data/lib/w3c_api/models/groups.rb +0 -38
  63. data/lib/w3c_api/models/link.rb +0 -17
  64. data/lib/w3c_api/models/participations.rb +0 -17
  65. data/lib/w3c_api/models/series_collection.rb +0 -17
  66. data/lib/w3c_api/models/spec_versions.rb +0 -17
  67. data/lib/w3c_api/models/specifications.rb +0 -17
  68. data/lib/w3c_api/models/users.rb +0 -44
@@ -0,0 +1,294 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+ require_relative 'models'
5
+
6
+ module W3cApi
7
+ class Hal
8
+ include Singleton
9
+
10
+ API_URL = 'https://api.w3.org/'
11
+
12
+ def initialize
13
+ setup
14
+ end
15
+
16
+ def client
17
+ @client ||= Lutaml::Hal::Client.new(api_url: API_URL)
18
+ end
19
+
20
+ def register
21
+ return @register if @register
22
+
23
+ @register = Lutaml::Hal::ModelRegister.new(name: :w3c_api, client: client)
24
+ Lutaml::Hal::GlobalRegister.instance.register(
25
+ :w3c_api, @register
26
+ )
27
+ @register
28
+ end
29
+
30
+ private
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)
38
+ register.add_endpoint(
39
+ id: id,
40
+ type: :index,
41
+ url: url,
42
+ model: model,
43
+ query_params: query_params
44
+ )
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
69
+ )
70
+ add_resource_endpoint(
71
+ :affiliation_resource,
72
+ '/affiliations/{id}',
73
+ Models::Affiliation
74
+ )
75
+ add_index_endpoint(
76
+ :affiliation_participants_index,
77
+ '/affiliations/{id}/participants',
78
+ Models::ParticipantIndex
79
+ )
80
+ add_index_endpoint(
81
+ :affiliation_participations_index,
82
+ '/affiliations/{id}/participations',
83
+ Models::ParticipationIndex
84
+ )
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
98
+ )
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
240
+ )
241
+
242
+ # TODO: Why is this endpoint needed? There already is /specifications/{shortname}...
243
+ # register.add_endpoint(
244
+ # id: :specification_by_shortname_index,
245
+ # type: :index,
246
+ # url: '/specifications-by-shortname/{shortname}',
247
+ # model: Models::SpecificationIndex
248
+ # )
249
+
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
+ )
261
+
262
+ # User endpoints
263
+ # NOTE: This endpoint doesn't exist, just here for reference.
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
+ )
292
+ end
293
+ end
294
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lutaml/hal'
4
+ # {
5
+ # "created": "2021-03-12T22:06:06+00:00",
6
+ # "service": "github",
7
+ # "identifier": "57469",
8
+ # "nickname": "jenstrickland",
9
+ # "profile-picture": "https://avatars.githubusercontent.com/u/57469?v=4",
10
+ # "href": "https://github.com/jenstrickland",
11
+ # "_links": {
12
+ # "user": {
13
+ # "href": "https://api.w3.org/users/f1ovb5rydm8s0go04oco0cgk0sow44w"
14
+ # }
15
+ # }
16
+ # }
17
+
18
+ module W3cApi
19
+ module Models
20
+ # User model representing a W3C user/participant
21
+ class Account < Lutaml::Hal::Resource
22
+ attribute :created, :date_time
23
+ attribute :updated, :date_time
24
+ attribute :identifier, :string
25
+ attribute :nickname, :string
26
+ attribute :service, :string
27
+ attribute :profile_picture, :string
28
+ attribute :href, :string
29
+
30
+ hal_link :user, key: 'user', realize_class: 'User'
31
+
32
+ key_value do
33
+ %i[
34
+ created
35
+ updated
36
+ identifier
37
+ nickname
38
+ service
39
+ profile_picture
40
+ ].each do |key|
41
+ map key.to_s.tr('_', '-'), to: key
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,27 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
- require_relative 'link'
5
-
6
- # Example affiliation response:
3
+ # https://api.w3.org/affiliations/35662
7
4
  # {
8
- # "id"=>48830,
9
- # "name"=>"Postmedia",
10
- # "discr"=>"organization",
11
- # "is-member"=>false,
12
- # "is-member-association"=>false,
13
- # "is-partner-member"=>false,
14
- # "_links"=>{
15
- # "self"=>{
16
- # "href"=>"https://api.w3.org/affiliations/48830"
17
- # },
18
- # "participants"=>{
19
- # "href"=>"https://api.w3.org/affiliations/48830/participants"
5
+ # "id": 35662,
6
+ # "name": "Google LLC",
7
+ # "discr": "organization",
8
+ # "testimonials": {
9
+ # "en": "Google's mission is to organize the world’s information and make it universally accessible and useful."
20
10
  # },
21
- # "participations"=>{
22
- # "href"=>"https://api.w3.org/affiliations/48830/participations"
11
+ # "is-member": true,
12
+ # "is-member-association": false,
13
+ # "is-partner-member": false,
14
+ # "_links": {
15
+ # "homepage": {
16
+ # "href": "http://www.google.com/"
17
+ # },
18
+ # "self": {
19
+ # "href": "https://api.w3.org/affiliations/35662"
20
+ # },
21
+ # "participants": {
22
+ # "href": "https://api.w3.org/affiliations/35662/participants"
23
+ # },
24
+ # "participations": {
25
+ # "href": "https://api.w3.org/affiliations/35662/participations"
26
+ # },
27
+ # "logo": {
28
+ # "href": "https://www.w3.org/thumbnails/250/logos/organizations/35662.png?x-version=1"
29
+ # }
23
30
  # }
24
- # }
25
31
  # }
26
32
 
27
33
  # Fetch index response:
@@ -30,57 +36,40 @@ require_relative 'link'
30
36
  # "title"=>"Framkom (Forskningsaktiebolaget Medie-och Kommunikationsteknik)"
31
37
  # },
32
38
 
39
+ require_relative 'testimonial'
33
40
 
34
41
  module W3cApi
35
- module Models
36
- class AffiliationLinks < Lutaml::Model::Serializable
37
- attribute :self, Link
38
- attribute :participants, Link
39
- attribute :participations, Link
40
- end
41
-
42
- class Affiliation < Base
43
- attribute :id, :integer
44
- attribute :name, :string
45
- attribute :href, :string
46
- attribute :title, :string
47
- attribute :descr, :string
48
- attribute :is_member, :boolean
49
- attribute :is_member_association, :boolean
50
- attribute :is_partner_member, :boolean
51
- attribute :_links, AffiliationLinks
52
-
53
- # Get participants of this affiliation
54
- def participants(client = nil)
55
- return nil unless client && _links&.participants
56
-
57
- client.affiliation_participants(id)
58
- end
59
-
60
- # Get participations of this affiliation
61
- def participations(client = nil)
62
- return nil unless client && _links&.participations
63
-
64
- client.affiliation_participations(id)
65
- end
42
+ module Models
43
+ class Affiliation < Lutaml::Hal::Resource
44
+ attribute :id, :integer
45
+ attribute :name, :string
46
+ attribute :href, :string
47
+ attribute :title, :string
48
+ attribute :discr, :string
49
+ attribute :testimonials, Testimonial
50
+ attribute :is_member, :boolean
51
+ attribute :is_member_association, :boolean
52
+ attribute :is_partner_member, :boolean
66
53
 
67
- def self.from_response(response)
68
- transformed_response = transform_keys(response)
54
+ hal_link :self, key: 'self', realize_class: 'Affiliation'
55
+ hal_link :homepage, key: 'homepage', realize_class: 'String'
56
+ hal_link :participants, key: 'participants', realize_class: 'Participant'
57
+ hal_link :participations, key: 'participations', realize_class: 'Participation'
58
+ hal_link :logo, key: 'logo', realize_class: 'String'
69
59
 
70
- affiliation = new
71
- transformed_response.each do |key, value|
72
- case key
73
- when :_links
74
- links = value.each_with_object({}) do |(link_name, link_data), acc|
75
- acc[link_name] = Link.new(href: link_data[:href], title: link_data[:title])
76
- end
77
- affiliation._links = AffiliationLinks.new(links)
78
- else
79
- affiliation.send("#{key}=", value) if affiliation.respond_to?("#{key}=")
80
- end
81
- end
82
- affiliation
60
+ key_value do
61
+ %i[
62
+ id
63
+ name
64
+ discr
65
+ testimonials
66
+ is_member
67
+ is_member_association
68
+ is_partner_member
69
+ ].each do |key|
70
+ map key.to_s.tr('_', '-'), to: key
83
71
  end
84
72
  end
85
73
  end
74
+ end
86
75
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'affiliation'
4
+
5
+ module W3cApi
6
+ module Models
7
+ class AffiliationIndex < Lutaml::Hal::Page
8
+ hal_link :affiliations, key: 'affiliations', realize_class: 'Affiliation', collection: true
9
+ end
10
+ end
11
+ end
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
- require_relative 'link'
5
- require_relative 'spec_version_ref'
6
-
7
3
  # {
8
4
  # "uri": "https://www.w3.org/WAI/videos/standards-and-benefits/"
9
5
  # "title": "Video Introduction to Web Accessibility and W3C Standards"
@@ -18,42 +14,22 @@ require_relative 'spec_version_ref'
18
14
  # }
19
15
 
20
16
  module W3cApi
21
- module Models
22
- class CallForTranslationLinks < Lutaml::Model::Serializable
23
- attribute :self, Link
24
- attribute :translations, Link
25
- end
26
-
27
- class CallForTranslation < Base
28
- attribute :uri, :string
29
- attribute :title, :string
30
- attribute :spec_version, SpecVersionRef
31
- attribute :_links, CallForTranslationLinks
32
-
33
- # Get translations for this call for translation
34
- def translations(client = nil)
35
- return nil unless client && _links&.translations
36
-
37
- client.call_for_translation_translations(uri)
38
- end
39
-
40
- def self.from_response(response)
41
- transformed_response = transform_keys(response)
42
-
43
- cft = new
44
- transformed_response.each do |key, value|
45
- case key
46
- when :_links
47
- links = value.each_with_object({}) do |(link_name, link_data), acc|
48
- acc[link_name] = Link.new(href: link_data[:href], title: link_data[:title])
49
- end
50
- cft._links = CallForTranslationLinks.new(links)
51
- else
52
- cft.send("#{key}=", value) if cft.respond_to?("#{key}=")
53
- end
54
- end
55
- cft
17
+ module Models
18
+ class CallForTranslation < Lutaml::Hal::Resource
19
+ attribute :uri, :string
20
+ attribute :title, :string
21
+
22
+ hal_link :self, key: 'self', realize_class: 'CallForTranslation'
23
+ hal_link :translations, key: 'translations', realize_class: 'TranslationIndex'
24
+
25
+ key_value do
26
+ %i[
27
+ uri
28
+ title
29
+ ].each do |key|
30
+ map key.to_s.tr('_', '-'), to: key
56
31
  end
57
32
  end
58
33
  end
34
+ end
59
35
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'user'
4
+
5
+ module W3cApi
6
+ module Models
7
+ class ChairIndex < Lutaml::Hal::Page
8
+ hal_link :chairs, key: 'chairs', realize_class: 'User', collection: true
9
+ end
10
+ end
11
+ end