w3c_api 0.1.0

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 (51) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +33 -0
  3. data/README.adoc +1265 -0
  4. data/Rakefile +8 -0
  5. data/exe/w3c_api +6 -0
  6. data/lib/w3c_api/cli.rb +41 -0
  7. data/lib/w3c_api/client.rb +320 -0
  8. data/lib/w3c_api/commands/affiliation.rb +48 -0
  9. data/lib/w3c_api/commands/ecosystem.rb +57 -0
  10. data/lib/w3c_api/commands/group.rb +87 -0
  11. data/lib/w3c_api/commands/output_formatter.rb +18 -0
  12. data/lib/w3c_api/commands/participation.rb +34 -0
  13. data/lib/w3c_api/commands/series.rb +40 -0
  14. data/lib/w3c_api/commands/specification.rb +68 -0
  15. data/lib/w3c_api/commands/translation.rb +31 -0
  16. data/lib/w3c_api/commands/user.rb +77 -0
  17. data/lib/w3c_api/models/affiliation.rb +86 -0
  18. data/lib/w3c_api/models/affiliations.rb +33 -0
  19. data/lib/w3c_api/models/base.rb +39 -0
  20. data/lib/w3c_api/models/call_for_translation.rb +59 -0
  21. data/lib/w3c_api/models/call_for_translation_ref.rb +15 -0
  22. data/lib/w3c_api/models/charter.rb +110 -0
  23. data/lib/w3c_api/models/charters.rb +17 -0
  24. data/lib/w3c_api/models/collection_base.rb +79 -0
  25. data/lib/w3c_api/models/connected_account.rb +54 -0
  26. data/lib/w3c_api/models/delegate_enumerable.rb +54 -0
  27. data/lib/w3c_api/models/ecosystem.rb +72 -0
  28. data/lib/w3c_api/models/ecosystems.rb +33 -0
  29. data/lib/w3c_api/models/extension.rb +12 -0
  30. data/lib/w3c_api/models/group.rb +173 -0
  31. data/lib/w3c_api/models/groups.rb +38 -0
  32. data/lib/w3c_api/models/join_emails.rb +12 -0
  33. data/lib/w3c_api/models/link.rb +17 -0
  34. data/lib/w3c_api/models/participation.rb +109 -0
  35. data/lib/w3c_api/models/participations.rb +17 -0
  36. data/lib/w3c_api/models/serie.rb +88 -0
  37. data/lib/w3c_api/models/series.rb +41 -0
  38. data/lib/w3c_api/models/series_collection.rb +17 -0
  39. data/lib/w3c_api/models/spec_version.rb +96 -0
  40. data/lib/w3c_api/models/spec_version_ref.rb +18 -0
  41. data/lib/w3c_api/models/spec_versions.rb +17 -0
  42. data/lib/w3c_api/models/specification.rb +79 -0
  43. data/lib/w3c_api/models/specifications.rb +17 -0
  44. data/lib/w3c_api/models/translation.rb +162 -0
  45. data/lib/w3c_api/models/translations.rb +40 -0
  46. data/lib/w3c_api/models/user.rb +178 -0
  47. data/lib/w3c_api/models/users.rb +44 -0
  48. data/lib/w3c_api/models.rb +15 -0
  49. data/lib/w3c_api/version.rb +5 -0
  50. data/lib/w3c_api.rb +9 -0
  51. metadata +166 -0
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/exe/w3c_api ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'w3c_api'
5
+
6
+ W3cApi::Cli.start(ARGV)
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require_relative 'commands/specification'
5
+ require_relative 'commands/group'
6
+ require_relative 'commands/user'
7
+ require_relative 'commands/translation'
8
+ require_relative 'commands/ecosystem'
9
+ require_relative 'commands/series'
10
+ require_relative 'commands/affiliation'
11
+ require_relative 'commands/participation'
12
+
13
+ module W3cApi
14
+ # Main CLI class that registers all subcommands
15
+ class Cli < Thor
16
+ # Register subcommands
17
+ desc 'specification SUBCOMMAND ...ARGS', 'Work with W3C specifications'
18
+ subcommand 'specification', Commands::Specification
19
+
20
+ desc 'group SUBCOMMAND ...ARGS', 'Work with W3C groups'
21
+ subcommand 'group', Commands::Group
22
+
23
+ desc 'user SUBCOMMAND ...ARGS', 'Work with W3C users'
24
+ subcommand 'user', Commands::User
25
+
26
+ desc 'translation SUBCOMMAND ...ARGS', 'Work with W3C translations'
27
+ subcommand 'translation', Commands::Translation
28
+
29
+ desc 'ecosystem SUBCOMMAND ...ARGS', 'Work with W3C ecosystems'
30
+ subcommand 'ecosystem', Commands::Ecosystem
31
+
32
+ desc 'series SUBCOMMAND ...ARGS', 'Work with W3C specification series'
33
+ subcommand 'series', Commands::Series
34
+
35
+ desc 'affiliation SUBCOMMAND ...ARGS', 'Work with W3C affiliations'
36
+ subcommand 'affiliation', Commands::Affiliation
37
+
38
+ desc 'participation SUBCOMMAND ...ARGS', 'Work with W3C participations'
39
+ subcommand 'participation', Commands::Participation
40
+ end
41
+ end
@@ -0,0 +1,320 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'faraday/follow_redirects'
5
+ require 'json'
6
+
7
+ module W3cApi
8
+ class Error < StandardError; end
9
+ class NotFoundError < Error; end
10
+ class UnauthorizedError < Error; end
11
+ class BadRequestError < Error; end
12
+ class ServerError < Error; end
13
+
14
+ class Client
15
+ API_ENDPOINT = 'https://api.w3.org'
16
+
17
+ attr_reader :last_response
18
+
19
+ def initialize(options = {})
20
+ @api_endpoint = options[:api_endpoint] || API_ENDPOINT
21
+ @connection = create_connection
22
+ @params_default = { page: 1, items: 3000 }
23
+ @debug = !ENV['DEBUG_API'].nil?
24
+ end
25
+
26
+ # Specification methods
27
+
28
+ def specifications(options = {})
29
+ response = get('specifications', options.merge(@params_default))
30
+ Models::Specifications.from_response(response['_links']['specifications'])
31
+ end
32
+
33
+ def specification(shortname, options = {})
34
+ response = get("specifications/#{shortname}", options)
35
+ Models::Specification.from_response(response)
36
+ end
37
+
38
+ def specification_versions(shortname, options = {})
39
+ response = get("specifications/#{shortname}/versions", options)
40
+ Models::SpecVersions.from_response(response['_links']['version-history'])
41
+ end
42
+
43
+ def specification_version(shortname, version, options = {})
44
+ response = get("specifications/#{shortname}/versions/#{version}", options)
45
+ Models::SpecVersion.from_response(response)
46
+ end
47
+
48
+ def specifications_by_status(status, options = {})
49
+ response = get("specifications-by-status/#{status}", options.merge(@params_default))
50
+ Models::Specifications.from_response(response['_links']['specifications'])
51
+ end
52
+
53
+ def specification_supersedes(shortname, options = {})
54
+ response = get("specifications/#{shortname}/supersedes", options)
55
+ Models::Specifications.from_response(response['_links']['specifications'])
56
+ end
57
+
58
+ def specification_superseded_by(shortname, options = {})
59
+ response = get("specifications/#{shortname}/superseded", options)
60
+ Models::Specifications.from_response(response['_links']['specifications'])
61
+ end
62
+
63
+ # Series methods
64
+
65
+ def series(options = {})
66
+ response = get('specification-series', options.merge(@params_default))
67
+ Models::Series.from_response(response['_links']['specification-series'])
68
+ end
69
+
70
+ def series_by_shortname(shortname, options = {})
71
+ response = get("specification-series/#{shortname}", options)
72
+ Models::Serie.from_response(response)
73
+ end
74
+
75
+ def series_specifications(shortname, options = {})
76
+ response = get("specification-series/#{shortname}/specifications", options.merge(@params_default))
77
+ Models::Specifications.from_response(response['_links']['specifications'])
78
+ end
79
+
80
+ # Group methods
81
+
82
+ def groups(options = {})
83
+ response = get('groups', options)
84
+ Models::Groups.from_response(response['_links']['groups'])
85
+ end
86
+
87
+ def group(id, options = {})
88
+ response = get("groups/#{id}", options)
89
+ Models::Group.from_response(response)
90
+ end
91
+
92
+ def group_specifications(id, options = {})
93
+ response = get("groups/#{id}/specifications", options)
94
+ Models::Specifications.from_response(response['_links']['specifications'])
95
+ end
96
+
97
+ def group_users(id, options = {})
98
+ response = get("groups/#{id}/users", options)
99
+ Models::Users.from_response(response['_links']['users'])
100
+ end
101
+
102
+ def group_charters(id, options = {})
103
+ response = get("groups/#{id}/charters", options)
104
+ Models::Charters.from_response(response['_links']['charters'])
105
+ end
106
+
107
+ def group_chairs(id, options = {})
108
+ response = get("groups/#{id}/chairs", options)
109
+ Models::Users.from_response(response['_links']['chairs'])
110
+ rescue NotFoundError
111
+ # Return empty users collection when endpoint not found
112
+ Models::Users.from_response([])
113
+ end
114
+
115
+ def group_team_contacts(id, options = {})
116
+ response = get("groups/#{id}/teamcontacts", options)
117
+ Models::Users.from_response(response['_links']['team-contacts'])
118
+ rescue NotFoundError
119
+ # Return empty users collection when endpoint not found
120
+ Models::Users.from_response([])
121
+ end
122
+
123
+ def group_participations(id, options = {})
124
+ response = get("groups/#{id}/participations", options)
125
+ Models::Participations.from_response(response['_links']['participations'])
126
+ end
127
+
128
+ # User methods
129
+
130
+ def users(options = {})
131
+ raise ArgumentError,
132
+ 'The W3C API does not support fetching all users. You must provide a specific user ID with the user method.'
133
+ end
134
+
135
+ def user(id, options = {})
136
+ response = get("users/#{id}", options)
137
+ Models::User.from_response(response)
138
+ end
139
+
140
+ def user_specifications(id, options = {})
141
+ response = get("users/#{id}/specifications", options)
142
+ Models::Specifications.from_response(response['_links']['specifications'])
143
+ rescue NotFoundError
144
+ # Return empty specifications collection when endpoint not found
145
+ Models::Specifications.from_response([])
146
+ end
147
+
148
+ def user_groups(id, options = {})
149
+ response = get("users/#{id}/groups", options)
150
+ Models::Groups.from_response(response['_links']['groups'])
151
+ end
152
+
153
+ def user_affiliations(id, options = {})
154
+ response = get("users/#{id}/affiliations", options)
155
+ Models::Affiliations.from_response(response['_links']['affiliations'])
156
+ rescue NotFoundError
157
+ # Return empty affiliations collection when endpoint not found
158
+ Models::Affiliations.from_response([])
159
+ end
160
+
161
+ def user_participations(id, options = {})
162
+ response = get("users/#{id}/participations", options)
163
+ Models::Participations.from_response(response['_links']['participations'])
164
+ rescue NotFoundError
165
+ # Return empty participations collection when endpoint not found
166
+ Models::Participations.from_response([])
167
+ end
168
+
169
+ def user_chair_of_groups(id, options = {})
170
+ response = get("users/#{id}/chair-of-groups", options)
171
+ Models::Groups.from_response(response['_links']['groups'])
172
+ rescue NotFoundError
173
+ # Return empty groups collection when endpoint not found
174
+ Models::Groups.from_response([])
175
+ end
176
+
177
+ def user_team_contact_of_groups(id, options = {})
178
+ response = get("users/#{id}/team-contact-of-groups", options)
179
+ Models::Groups.from_response(response['_links']['groups'])
180
+ rescue NotFoundError
181
+ # Return empty groups collection when endpoint not found
182
+ Models::Groups.from_response([])
183
+ end
184
+
185
+ # Translation methods
186
+
187
+ def translations(options = {})
188
+ response = get('translations', options.merge(embed: true))
189
+ Models::Translations.from_response(response['_links']['translations'])
190
+ end
191
+
192
+ def translation(id, options = {})
193
+ response = get("translations/#{id}", options)
194
+ Models::Translation.from_response(response)
195
+ end
196
+
197
+ # Affiliation methods
198
+
199
+ def affiliations(options = {})
200
+ response = get('affiliations', options.merge(@params_default))
201
+ Models::Affiliations.from_response(response['_links']['affiliations'])
202
+ end
203
+
204
+ def affiliation(id, options = {})
205
+ response = get("affiliations/#{id}", options)
206
+ Models::Affiliation.from_response(response)
207
+ end
208
+
209
+ def affiliation_participants(id, options = {})
210
+ response = get("affiliations/#{id}/participants", options)
211
+ Models::Users.from_response(response['_links']['participants'])
212
+ end
213
+
214
+ def affiliation_participations(id, options = {})
215
+ response = get("affiliations/#{id}/participations", options)
216
+ Models::Participations.from_response(response['_links']['participations'])
217
+ end
218
+
219
+ # Ecosystem methods
220
+
221
+ def ecosystems(options = {})
222
+ response = get('ecosystems', options)
223
+ Models::Ecosystems.from_response(response['_links']['ecosystems'])
224
+ end
225
+
226
+ def ecosystem(shortname, options = {})
227
+ response = get("ecosystems/#{shortname}", options)
228
+ Models::Ecosystem.from_response(response)
229
+ end
230
+
231
+ def ecosystem_groups(shortname, options = {})
232
+ response = get("ecosystems/#{shortname}/groups", options)
233
+ Models::Groups.from_response(response['_links']['groups'])
234
+ end
235
+
236
+ def ecosystem_evangelists(shortname, options = {})
237
+ response = get("ecosystems/#{shortname}/evangelists", options)
238
+ Models::Users.from_response(response['_links']['users'])
239
+ end
240
+
241
+ def ecosystem_member_organizations(shortname, options = {})
242
+ response = get("ecosystems/#{shortname}/member-organizations", options)
243
+ Models::Affiliations.from_response(response['_links']['affiliations'])
244
+ end
245
+
246
+ # Participation methods
247
+
248
+ def participation(id, options = {})
249
+ response = get("participations/#{id}", options)
250
+ Models::Participation.from_response(response)
251
+ end
252
+
253
+ def participation_participants(id, options = {})
254
+ response = get("participations/#{id}/participants", options)
255
+ Models::Users.from_response(response['_links']['users'])
256
+ end
257
+
258
+ # Make the get method public for testing
259
+ def get(url, params = {})
260
+ @last_response = @connection.get(url, params)
261
+ handle_response(@last_response, url)
262
+ end
263
+
264
+ private
265
+
266
+ def create_connection
267
+ Faraday.new(url: @api_endpoint) do |conn|
268
+ conn.use Faraday::FollowRedirects::Middleware
269
+ conn.request :json
270
+ conn.response :json, content_type: /\bjson$/
271
+ conn.adapter Faraday.default_adapter
272
+ end
273
+ end
274
+
275
+ def handle_response(response, url)
276
+ debug_log(response, url) if @debug
277
+
278
+ case response.status
279
+ when 200..299
280
+ response.body
281
+ when 400
282
+ raise W3cApi::BadRequestError, response_message(response)
283
+ when 401
284
+ raise W3cApi::UnauthorizedError, response_message(response)
285
+ when 404
286
+ raise W3cApi::NotFoundError, response_message(response)
287
+ when 500..599
288
+ raise W3cApi::ServerError, response_message(response)
289
+ else
290
+ raise W3cApi::Error, response_message(response)
291
+ end
292
+ end
293
+
294
+ def debug_log(response, url)
295
+ puts "\n===== DEBUG: W3C API REQUEST =====".blue if defined?(Rainbow)
296
+ puts "\n===== DEBUG: W3C API REQUEST =====" unless defined?(Rainbow)
297
+ puts "URL: #{url}"
298
+ puts "Status: #{response.status}"
299
+
300
+ # Format headers as JSON
301
+ puts "\nHeaders:"
302
+ headers_hash = response.headers.to_h
303
+ puts JSON.pretty_generate(headers_hash)
304
+
305
+ puts "\nResponse body:"
306
+ if response.body.is_a?(Hash) || response.body.is_a?(Array)
307
+ puts JSON.pretty_generate(response.body)
308
+ else
309
+ puts response.body.inspect
310
+ end
311
+ puts "===== END DEBUG OUTPUT =====\n"
312
+ end
313
+
314
+ def response_message(response)
315
+ message = "Status: #{response.status}"
316
+ message += ", Error: #{response.body['error']}" if response.body.is_a?(Hash) && response.body['error']
317
+ message
318
+ end
319
+ end # End of Client class
320
+ end # End of W3c module
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require_relative 'output_formatter'
5
+ require_relative '../client'
6
+
7
+ module W3cApi
8
+ module Commands
9
+ # Thor CLI command for affiliation operations
10
+ class Affiliation < Thor
11
+ include OutputFormatter
12
+
13
+ desc 'fetch [OPTIONS]', 'Fetch affiliations'
14
+ option :id, type: :numeric, desc: 'Affiliation ID'
15
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
16
+ def fetch
17
+ client = W3cApi::Client.new
18
+
19
+ affiliations = if options[:id]
20
+ # Single affiliation
21
+ client.affiliation(options[:id])
22
+ else
23
+ client.affiliations
24
+ end
25
+
26
+ output_results(affiliations, options[:format])
27
+ end
28
+
29
+ desc 'participants', 'Fetch participants of an affiliation'
30
+ option :id, type: :numeric, required: true, desc: 'Affiliation ID'
31
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
32
+ def participants
33
+ client = W3cApi::Client.new
34
+ participants = client.affiliation_participants(options[:id])
35
+ output_results(participants, options[:format])
36
+ end
37
+
38
+ desc 'participations', 'Fetch participations of an affiliation'
39
+ option :id, type: :numeric, required: true, desc: 'Affiliation ID'
40
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
41
+ def participations
42
+ client = W3cApi::Client.new
43
+ participations = client.affiliation_participations(options[:id])
44
+ output_results(participations, options[:format])
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require_relative 'output_formatter'
5
+ require_relative '../client'
6
+
7
+ module W3cApi
8
+ module Commands
9
+ # Thor CLI command for ecosystem operations
10
+ class Ecosystem < Thor
11
+ include OutputFormatter
12
+
13
+ desc 'fetch [OPTIONS]', 'Fetch ecosystems'
14
+ option :shortname, type: :string, desc: 'Ecosystem shortname'
15
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
16
+ def fetch
17
+ client = W3cApi::Client.new
18
+
19
+ ecosystems = if options[:shortname]
20
+ # Single ecosystem
21
+ client.ecosystem(options[:shortname])
22
+ else
23
+ client.ecosystems
24
+ end
25
+
26
+ output_results(ecosystems, options[:format])
27
+ end
28
+
29
+ desc 'groups', 'Fetch groups in an ecosystem'
30
+ option :shortname, type: :string, required: true, desc: 'Ecosystem shortname'
31
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
32
+ def groups
33
+ client = W3cApi::Client.new
34
+ groups = client.ecosystem_groups(options[:shortname])
35
+ output_results(groups, options[:format])
36
+ end
37
+
38
+ desc 'evangelists', 'Fetch evangelists of an ecosystem'
39
+ option :shortname, type: :string, required: true, desc: 'Ecosystem shortname'
40
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
41
+ def evangelists
42
+ client = W3cApi::Client.new
43
+ evangelists = client.ecosystem_evangelists(options[:shortname])
44
+ output_results(evangelists, options[:format])
45
+ end
46
+
47
+ desc 'member-organizations', 'Fetch member organizations of an ecosystem'
48
+ option :shortname, type: :string, required: true, desc: 'Ecosystem shortname'
49
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
50
+ def member_organizations
51
+ client = W3cApi::Client.new
52
+ organizations = client.ecosystem_member_organizations(options[:shortname])
53
+ output_results(organizations, options[:format])
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require_relative 'output_formatter'
5
+ require_relative '../client'
6
+
7
+ module W3cApi
8
+ module Commands
9
+ # Thor CLI command for group operations
10
+ class Group < Thor
11
+ include OutputFormatter
12
+
13
+ desc 'fetch [OPTIONS]', 'Fetch groups'
14
+ option :id, type: :string, desc: 'Group ID'
15
+ option :type, type: :string, desc: 'Group type'
16
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
17
+ def fetch
18
+ client = W3cApi::Client.new
19
+
20
+ groups = if options[:id]
21
+ # Single group
22
+ client.group(options[:id])
23
+ elsif options[:type]
24
+ client.groups(type: options[:type])
25
+ else
26
+ client.groups
27
+ end
28
+
29
+ output_results(groups, options[:format])
30
+ end
31
+
32
+ desc 'users', 'Fetch users in a group'
33
+ option :id, type: :numeric, required: true, desc: 'Group ID'
34
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
35
+ def users
36
+ client = W3cApi::Client.new
37
+ users = client.group_users(options[:id])
38
+ output_results(users, options[:format])
39
+ end
40
+
41
+ desc 'specifications', 'Fetch specifications produced by a group'
42
+ option :id, type: :numeric, required: true, desc: 'Group ID'
43
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
44
+ def specifications
45
+ client = W3cApi::Client.new
46
+ specifications = client.group_specifications(options[:id])
47
+ output_results(specifications, options[:format])
48
+ end
49
+
50
+ desc 'charters', 'Fetch charters of a group'
51
+ option :id, type: :numeric, required: true, desc: 'Group ID'
52
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
53
+ def charters
54
+ client = W3cApi::Client.new
55
+ charters = client.group_charters(options[:id])
56
+ output_results(charters, options[:format])
57
+ end
58
+
59
+ desc 'chairs', 'Fetch chairs of a group'
60
+ option :id, type: :numeric, required: true, desc: 'Group ID'
61
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
62
+ def chairs
63
+ client = W3cApi::Client.new
64
+ chairs = client.group_chairs(options[:id])
65
+ output_results(chairs, options[:format])
66
+ end
67
+
68
+ desc 'team-contacts', 'Fetch team contacts of a group'
69
+ option :id, type: :numeric, required: true, desc: 'Group ID'
70
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
71
+ def team_contacts
72
+ client = W3cApi::Client.new
73
+ team_contacts = client.group_team_contacts(options[:id])
74
+ output_results(team_contacts, options[:format])
75
+ end
76
+
77
+ desc 'participations', 'Fetch participations in a group'
78
+ option :id, type: :numeric, required: true, desc: 'Group ID'
79
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
80
+ def participations
81
+ client = W3cApi::Client.new
82
+ participations = client.group_participations(options[:id])
83
+ output_results(participations, options[:format])
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module W3cApi
4
+ module Commands
5
+ module OutputFormatter
6
+ # Format and output results based on the specified format
7
+ def output_results(results, format)
8
+ case format
9
+ when 'yaml'
10
+ puts results.to_yaml
11
+ else
12
+ # Default to JSON if format is not recognized
13
+ puts results.to_json
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require_relative 'output_formatter'
5
+ require_relative '../client'
6
+
7
+ module W3cApi
8
+ module Commands
9
+ # Thor CLI command for participation operations
10
+ class Participation < Thor
11
+ include OutputFormatter
12
+
13
+ desc 'fetch', 'Fetch a participation by ID'
14
+ option :id, type: :numeric, required: true, desc: 'Participation ID'
15
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
16
+ def fetch
17
+ client = W3cApi::Client.new
18
+ participation = client.participation(options[:id])
19
+ # Wrap in a collection for consistent output
20
+ participations = Models::Participations.new(participations: [participation])
21
+ output_results(participations, options[:format])
22
+ end
23
+
24
+ desc 'participants', 'Fetch participants in a participation'
25
+ option :id, type: :numeric, required: true, desc: 'Participation ID'
26
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
27
+ def participants
28
+ client = W3cApi::Client.new
29
+ participants = client.participation_participants(options[:id])
30
+ output_results(participants, options[:format])
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require_relative 'output_formatter'
5
+ require_relative '../client'
6
+
7
+ module W3cApi
8
+ module Commands
9
+ # Thor CLI command for series operations
10
+ class Series < Thor
11
+ include OutputFormatter
12
+
13
+ desc 'fetch [OPTIONS]', 'Fetch specification series'
14
+ option :shortname, type: :string, desc: 'Series shortname'
15
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
16
+ def fetch
17
+ client = W3cApi::Client.new
18
+
19
+ series = if options[:shortname]
20
+ # Single series
21
+ client.series_by_shortname(options[:shortname])
22
+ else
23
+ # All series
24
+ client.series
25
+ end
26
+
27
+ output_results(series, options[:format])
28
+ end
29
+
30
+ desc 'specifications', 'Fetch specifications in a series'
31
+ option :shortname, type: :string, required: true, desc: 'Series shortname'
32
+ option :format, type: :string, default: 'yaml', enum: %w[json yaml], desc: 'Output format'
33
+ def specifications
34
+ client = W3cApi::Client.new
35
+ specifications = client.series_specifications(options[:shortname])
36
+ output_results(specifications, options[:format])
37
+ end
38
+ end
39
+ end
40
+ end