ortfodb 1.2.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d68be6f3abc3321418707238fb49360dd099acd9205f427dcd2aeba47da325cc
4
+ data.tar.gz: 1d72869648fb3efaeab1234642f1fc1126a8adef8758c6d1687ae300594e5b9a
5
+ SHA512:
6
+ metadata.gz: 6369f2be64be4fde1f479cef9cdcc85ff9f7b461998b09bb09294071676b9ee2228295b419ef384ae466c025fc7f1c16a332ab43295a5d51d992cdc51b323784
7
+ data.tar.gz: 70429cae954a86b7cc1bf2c3bbe7e005ca467958423aa45ebbfb2c88c8aa4b814bf1e7f12d0af1d91bc0f3025726647cb793f911433318ccaefe482b049d5b13
@@ -0,0 +1,251 @@
1
+ # This code may look unusually verbose for Ruby (and it is), but
2
+ # it performs some subtle and complex validation of JSON data.
3
+ #
4
+ # To parse this JSON, add 'dry-struct' and 'dry-types' gems, then do:
5
+ #
6
+ # configuration = Configuration.from_json! "{…}"
7
+ # puts configuration.technologies.repository
8
+ #
9
+ # If from_json! succeeds, the value returned matches the schema.
10
+
11
+ require 'json'
12
+ require 'dry-types'
13
+ require 'dry-struct'
14
+
15
+ module Ortfodb
16
+ module Types
17
+ include Dry.Types(default: :nominal)
18
+
19
+ Integer = Strict::Integer
20
+ Bool = Strict::Bool
21
+ Hash = Strict::Hash
22
+ String = Strict::String
23
+ end
24
+
25
+ class ExtractColors < Dry::Struct
26
+ attribute :default_files, Types.Array(Types::String)
27
+ attribute :enabled, Types::Bool
28
+ attribute :extract, Types.Array(Types::String)
29
+
30
+ def self.from_dynamic!(d)
31
+ d = Types::Hash[d]
32
+ new(
33
+ default_files: d.fetch("default files"),
34
+ enabled: d.fetch("enabled"),
35
+ extract: d.fetch("extract"),
36
+ )
37
+ end
38
+
39
+ def self.from_json!(json)
40
+ from_dynamic!(JSON.parse(json))
41
+ end
42
+
43
+ def to_dynamic
44
+ {
45
+ "default files" => default_files,
46
+ "enabled" => enabled,
47
+ "extract" => extract,
48
+ }
49
+ end
50
+
51
+ def to_json(options = nil)
52
+ JSON.generate(to_dynamic, options)
53
+ end
54
+ end
55
+
56
+ class MakeGifs < Dry::Struct
57
+ attribute :enabled, Types::Bool
58
+ attribute :file_name_template, Types::String
59
+
60
+ def self.from_dynamic!(d)
61
+ d = Types::Hash[d]
62
+ new(
63
+ enabled: d.fetch("enabled"),
64
+ file_name_template: d.fetch("file name template"),
65
+ )
66
+ end
67
+
68
+ def self.from_json!(json)
69
+ from_dynamic!(JSON.parse(json))
70
+ end
71
+
72
+ def to_dynamic
73
+ {
74
+ "enabled" => enabled,
75
+ "file name template" => file_name_template,
76
+ }
77
+ end
78
+
79
+ def to_json(options = nil)
80
+ JSON.generate(to_dynamic, options)
81
+ end
82
+ end
83
+
84
+ class MakeThumbnails < Dry::Struct
85
+ attribute :enabled, Types::Bool
86
+ attribute :file_name_template, Types::String
87
+ attribute :input_file, Types::String
88
+ attribute :sizes, Types.Array(Types::Integer)
89
+
90
+ def self.from_dynamic!(d)
91
+ d = Types::Hash[d]
92
+ new(
93
+ enabled: d.fetch("enabled"),
94
+ file_name_template: d.fetch("file name template"),
95
+ input_file: d.fetch("input file"),
96
+ sizes: d.fetch("sizes"),
97
+ )
98
+ end
99
+
100
+ def self.from_json!(json)
101
+ from_dynamic!(JSON.parse(json))
102
+ end
103
+
104
+ def to_dynamic
105
+ {
106
+ "enabled" => enabled,
107
+ "file name template" => file_name_template,
108
+ "input file" => input_file,
109
+ "sizes" => sizes,
110
+ }
111
+ end
112
+
113
+ def to_json(options = nil)
114
+ JSON.generate(to_dynamic, options)
115
+ end
116
+ end
117
+
118
+ class Media < Dry::Struct
119
+ attribute :at, Types::String
120
+
121
+ def self.from_dynamic!(d)
122
+ d = Types::Hash[d]
123
+ new(
124
+ at: d.fetch("at"),
125
+ )
126
+ end
127
+
128
+ def self.from_json!(json)
129
+ from_dynamic!(JSON.parse(json))
130
+ end
131
+
132
+ def to_dynamic
133
+ {
134
+ "at" => at,
135
+ }
136
+ end
137
+
138
+ def to_json(options = nil)
139
+ JSON.generate(to_dynamic, options)
140
+ end
141
+ end
142
+
143
+ class Tags < Dry::Struct
144
+ attribute :repository, Types::String
145
+
146
+ def self.from_dynamic!(d)
147
+ d = Types::Hash[d]
148
+ new(
149
+ repository: d.fetch("repository"),
150
+ )
151
+ end
152
+
153
+ def self.from_json!(json)
154
+ from_dynamic!(JSON.parse(json))
155
+ end
156
+
157
+ def to_dynamic
158
+ {
159
+ "repository" => repository,
160
+ }
161
+ end
162
+
163
+ def to_json(options = nil)
164
+ JSON.generate(to_dynamic, options)
165
+ end
166
+ end
167
+
168
+ class Technologies < Dry::Struct
169
+ attribute :repository, Types::String
170
+
171
+ def self.from_dynamic!(d)
172
+ d = Types::Hash[d]
173
+ new(
174
+ repository: d.fetch("repository"),
175
+ )
176
+ end
177
+
178
+ def self.from_json!(json)
179
+ from_dynamic!(JSON.parse(json))
180
+ end
181
+
182
+ def to_dynamic
183
+ {
184
+ "repository" => repository,
185
+ }
186
+ end
187
+
188
+ def to_json(options = nil)
189
+ JSON.generate(to_dynamic, options)
190
+ end
191
+ end
192
+
193
+ # Configuration represents what the ortfodb.yaml configuration file describes.
194
+ class Configuration < Dry::Struct
195
+ attribute :build_metadata_file, Types::String
196
+
197
+ # Exporter-specific configuration. Maps exporter names to their configuration.
198
+ attribute :exporters, Types::Hash.meta(of: Types::Hash.meta(of: Types::Any)).optional
199
+
200
+ attribute :extract_colors, ExtractColors
201
+ attribute :make_gifs, MakeGifs
202
+ attribute :make_thumbnails, MakeThumbnails
203
+ attribute :media, Media
204
+
205
+ # Path to the directory containing all projects. Must be absolute.
206
+ attribute :projects_at, Types::String
207
+
208
+ attribute :scattered_mode_folder, Types::String
209
+ attribute :tags, Tags
210
+ attribute :technologies, Technologies
211
+
212
+ def self.from_dynamic!(d)
213
+ d = Types::Hash[d]
214
+ new(
215
+ build_metadata_file: d.fetch("build metadata file"),
216
+ exporters: Types::Hash.optional[d["exporters"]]&.map { |k, v| [k, Types::Hash[v].map { |k, v| [k, Types::Any[v]] }.to_h] }&.to_h,
217
+ extract_colors: ExtractColors.from_dynamic!(d.fetch("extract colors")),
218
+ make_gifs: MakeGifs.from_dynamic!(d.fetch("make gifs")),
219
+ make_thumbnails: MakeThumbnails.from_dynamic!(d.fetch("make thumbnails")),
220
+ media: Media.from_dynamic!(d.fetch("media")),
221
+ projects_at: d.fetch("projects at"),
222
+ scattered_mode_folder: d.fetch("scattered mode folder"),
223
+ tags: Tags.from_dynamic!(d.fetch("tags")),
224
+ technologies: Technologies.from_dynamic!(d.fetch("technologies")),
225
+ )
226
+ end
227
+
228
+ def self.from_json!(json)
229
+ from_dynamic!(JSON.parse(json))
230
+ end
231
+
232
+ def to_dynamic
233
+ {
234
+ "build metadata file" => build_metadata_file,
235
+ "exporters" => exporters,
236
+ "extract colors" => extract_colors.to_dynamic,
237
+ "make gifs" => make_gifs.to_dynamic,
238
+ "make thumbnails" => make_thumbnails.to_dynamic,
239
+ "media" => media.to_dynamic,
240
+ "projects at" => projects_at,
241
+ "scattered mode folder" => scattered_mode_folder,
242
+ "tags" => tags.to_dynamic,
243
+ "technologies" => technologies.to_dynamic,
244
+ }
245
+ end
246
+
247
+ def to_json(options = nil)
248
+ JSON.generate(to_dynamic, options)
249
+ end
250
+ end
251
+ end
@@ -0,0 +1,439 @@
1
+ # This code may look unusually verbose for Ruby (and it is), but
2
+ # it performs some subtle and complex validation of JSON data.
3
+ #
4
+ # To parse this JSON, add 'dry-struct' and 'dry-types' gems, then do:
5
+ #
6
+ # database = Database.from_json! "{…}"
7
+ # puts database["…"].metadata.tags.first
8
+ #
9
+ # If from_json! succeeds, the value returned matches the schema.
10
+
11
+ require 'json'
12
+ require 'dry-types'
13
+ require 'dry-struct'
14
+
15
+ module Ortfodb
16
+ module Types
17
+ include Dry.Types(default: :nominal)
18
+
19
+ Integer = Strict::Integer
20
+ Bool = Strict::Bool
21
+ Hash = Strict::Hash
22
+ String = Strict::String
23
+ Double = Strict::Float | Strict::Integer
24
+ end
25
+
26
+ # MediaAttributes stores which HTML attributes should be added to the media.
27
+ class Attributes < Dry::Struct
28
+
29
+ # Controlled with attribute character > (adds)
30
+ attribute :autoplay, Types::Bool
31
+
32
+ # Controlled with attribute character = (removes)
33
+ attribute :controls, Types::Bool
34
+
35
+ # Controlled with attribute character ~ (adds)
36
+ attribute :attributes_loop, Types::Bool
37
+
38
+ # Controlled with attribute character > (adds)
39
+ attribute :muted, Types::Bool
40
+
41
+ # Controlled with attribute character = (adds)
42
+ attribute :playsinline, Types::Bool
43
+
44
+ def self.from_dynamic!(d)
45
+ d = Types::Hash[d]
46
+ new(
47
+ autoplay: d.fetch("autoplay"),
48
+ controls: d.fetch("controls"),
49
+ attributes_loop: d.fetch("loop"),
50
+ muted: d.fetch("muted"),
51
+ playsinline: d.fetch("playsinline"),
52
+ )
53
+ end
54
+
55
+ def self.from_json!(json)
56
+ from_dynamic!(JSON.parse(json))
57
+ end
58
+
59
+ def to_dynamic
60
+ {
61
+ "autoplay" => autoplay,
62
+ "controls" => controls,
63
+ "loop" => attributes_loop,
64
+ "muted" => muted,
65
+ "playsinline" => playsinline,
66
+ }
67
+ end
68
+
69
+ def to_json(options = nil)
70
+ JSON.generate(to_dynamic, options)
71
+ end
72
+ end
73
+
74
+ # ColorPalette reprensents the object in a Work's metadata.colors.
75
+ class Colors < Dry::Struct
76
+ attribute :primary, Types::String
77
+ attribute :secondary, Types::String
78
+ attribute :tertiary, Types::String
79
+
80
+ def self.from_dynamic!(d)
81
+ d = Types::Hash[d]
82
+ new(
83
+ primary: d.fetch("primary"),
84
+ secondary: d.fetch("secondary"),
85
+ tertiary: d.fetch("tertiary"),
86
+ )
87
+ end
88
+
89
+ def self.from_json!(json)
90
+ from_dynamic!(JSON.parse(json))
91
+ end
92
+
93
+ def to_dynamic
94
+ {
95
+ "primary" => primary,
96
+ "secondary" => secondary,
97
+ "tertiary" => tertiary,
98
+ }
99
+ end
100
+
101
+ def to_json(options = nil)
102
+ JSON.generate(to_dynamic, options)
103
+ end
104
+ end
105
+
106
+ # ImageDimensions represents metadata about a media as it's extracted from its file.
107
+ class Dimensions < Dry::Struct
108
+
109
+ # width / height
110
+ attribute :aspect_ratio, Types::Double
111
+
112
+ # Height in pixels
113
+ attribute :height, Types::Integer
114
+
115
+ # Width in pixels
116
+ attribute :width, Types::Integer
117
+
118
+ def self.from_dynamic!(d)
119
+ d = Types::Hash[d]
120
+ new(
121
+ aspect_ratio: d.fetch("aspectRatio"),
122
+ height: d.fetch("height"),
123
+ width: d.fetch("width"),
124
+ )
125
+ end
126
+
127
+ def self.from_json!(json)
128
+ from_dynamic!(JSON.parse(json))
129
+ end
130
+
131
+ def to_dynamic
132
+ {
133
+ "aspectRatio" => aspect_ratio,
134
+ "height" => height,
135
+ "width" => width,
136
+ }
137
+ end
138
+
139
+ def to_json(options = nil)
140
+ JSON.generate(to_dynamic, options)
141
+ end
142
+ end
143
+
144
+ class Thumbnails < Dry::Struct
145
+
146
+ def self.from_dynamic!(d)
147
+ d = Types::Hash[d]
148
+ new(
149
+ )
150
+ end
151
+
152
+ def self.from_json!(json)
153
+ from_dynamic!(JSON.parse(json))
154
+ end
155
+
156
+ def to_dynamic
157
+ {
158
+ }
159
+ end
160
+
161
+ def to_json(options = nil)
162
+ JSON.generate(to_dynamic, options)
163
+ end
164
+ end
165
+
166
+ class BlockElement < Dry::Struct
167
+ attribute :alt, Types::String
168
+
169
+ # whether the media has been analyzed
170
+ attribute :analyzed, Types::Bool
171
+
172
+ attribute :anchor, Types::String
173
+ attribute :attributes, Attributes
174
+ attribute :caption, Types::String
175
+ attribute :colors, Colors
176
+
177
+ # html
178
+ attribute :content, Types::String
179
+
180
+ attribute :content_type, Types::String
181
+ attribute :dimensions, Dimensions
182
+ attribute :dist_source, Types::String
183
+
184
+ # in seconds
185
+ attribute :duration, Types::Double
186
+
187
+ attribute :has_sound, Types::Bool
188
+ attribute :id, Types::String
189
+ attribute :index, Types::Integer
190
+ attribute :online, Types::Bool
191
+ attribute :relative_source, Types::String
192
+
193
+ # in bytes
194
+ attribute :size, Types::Integer
195
+
196
+ attribute :text, Types::String
197
+ attribute :thumbnails, Thumbnails
198
+ attribute :thumbnails_built_at, Types::String
199
+ attribute :title, Types::String
200
+ attribute :database_schema_type, Types::String
201
+ attribute :url, Types::String
202
+
203
+ def self.from_dynamic!(d)
204
+ d = Types::Hash[d]
205
+ new(
206
+ alt: d.fetch("alt"),
207
+ analyzed: d.fetch("analyzed"),
208
+ anchor: d.fetch("anchor"),
209
+ attributes: Attributes.from_dynamic!(d.fetch("attributes")),
210
+ caption: d.fetch("caption"),
211
+ colors: Colors.from_dynamic!(d.fetch("colors")),
212
+ content: d.fetch("content"),
213
+ content_type: d.fetch("contentType"),
214
+ dimensions: Dimensions.from_dynamic!(d.fetch("dimensions")),
215
+ dist_source: d.fetch("distSource"),
216
+ duration: d.fetch("duration"),
217
+ has_sound: d.fetch("hasSound"),
218
+ id: d.fetch("id"),
219
+ index: d.fetch("index"),
220
+ online: d.fetch("online"),
221
+ relative_source: d.fetch("relativeSource"),
222
+ size: d.fetch("size"),
223
+ text: d.fetch("text"),
224
+ thumbnails: Thumbnails.from_dynamic!(d.fetch("thumbnails")),
225
+ thumbnails_built_at: d.fetch("thumbnailsBuiltAt"),
226
+ title: d.fetch("title"),
227
+ database_schema_type: d.fetch("type"),
228
+ url: d.fetch("url"),
229
+ )
230
+ end
231
+
232
+ def self.from_json!(json)
233
+ from_dynamic!(JSON.parse(json))
234
+ end
235
+
236
+ def to_dynamic
237
+ {
238
+ "alt" => alt,
239
+ "analyzed" => analyzed,
240
+ "anchor" => anchor,
241
+ "attributes" => attributes.to_dynamic,
242
+ "caption" => caption,
243
+ "colors" => colors.to_dynamic,
244
+ "content" => content,
245
+ "contentType" => content_type,
246
+ "dimensions" => dimensions.to_dynamic,
247
+ "distSource" => dist_source,
248
+ "duration" => duration,
249
+ "hasSound" => has_sound,
250
+ "id" => id,
251
+ "index" => index,
252
+ "online" => online,
253
+ "relativeSource" => relative_source,
254
+ "size" => size,
255
+ "text" => text,
256
+ "thumbnails" => thumbnails.to_dynamic,
257
+ "thumbnailsBuiltAt" => thumbnails_built_at,
258
+ "title" => title,
259
+ "type" => database_schema_type,
260
+ "url" => url,
261
+ }
262
+ end
263
+
264
+ def to_json(options = nil)
265
+ JSON.generate(to_dynamic, options)
266
+ end
267
+ end
268
+
269
+ class ContentValue < Dry::Struct
270
+ attribute :blocks, Types.Array(BlockElement)
271
+ attribute :footnotes, Types::Hash.meta(of: Types::String)
272
+ attribute :layout, Types.Array(Types.Array(Types::String))
273
+ attribute :title, Types::String
274
+
275
+ def self.from_dynamic!(d)
276
+ d = Types::Hash[d]
277
+ new(
278
+ blocks: d.fetch("blocks").map { |x| BlockElement.from_dynamic!(x) },
279
+ footnotes: Types::Hash[d.fetch("footnotes")].map { |k, v| [k, Types::String[v]] }.to_h,
280
+ layout: d.fetch("layout"),
281
+ title: d.fetch("title"),
282
+ )
283
+ end
284
+
285
+ def self.from_json!(json)
286
+ from_dynamic!(JSON.parse(json))
287
+ end
288
+
289
+ def to_dynamic
290
+ {
291
+ "blocks" => blocks.map { |x| x.to_dynamic },
292
+ "footnotes" => footnotes,
293
+ "layout" => layout,
294
+ "title" => title,
295
+ }
296
+ end
297
+
298
+ def to_json(options = nil)
299
+ JSON.generate(to_dynamic, options)
300
+ end
301
+ end
302
+
303
+ class DatabaseMetadataClass < Dry::Struct
304
+
305
+ # Partial is true if the database was not fully built.
306
+ attribute :partial, Types::Bool
307
+
308
+ def self.from_dynamic!(d)
309
+ d = Types::Hash[d]
310
+ new(
311
+ partial: d.fetch("Partial"),
312
+ )
313
+ end
314
+
315
+ def self.from_json!(json)
316
+ from_dynamic!(JSON.parse(json))
317
+ end
318
+
319
+ def to_dynamic
320
+ {
321
+ "Partial" => partial,
322
+ }
323
+ end
324
+
325
+ def to_json(options = nil)
326
+ JSON.generate(to_dynamic, options)
327
+ end
328
+ end
329
+
330
+ class Metadata < Dry::Struct
331
+ attribute :additional_metadata, Types::Hash.meta(of: Types::Any)
332
+ attribute :aliases, Types.Array(Types::String)
333
+ attribute :colors, Colors
334
+ attribute :database_metadata, DatabaseMetadataClass
335
+ attribute :finished, Types::String
336
+ attribute :made_with, Types.Array(Types::String)
337
+ attribute :page_background, Types::String
338
+ attribute :private, Types::Bool
339
+ attribute :started, Types::String
340
+ attribute :tags, Types.Array(Types::String)
341
+ attribute :thumbnail, Types::String
342
+ attribute :title_style, Types::String
343
+ attribute :wip, Types::Bool
344
+
345
+ def self.from_dynamic!(d)
346
+ d = Types::Hash[d]
347
+ new(
348
+ additional_metadata: Types::Hash[d.fetch("additionalMetadata")].map { |k, v| [k, Types::Any[v]] }.to_h,
349
+ aliases: d.fetch("aliases"),
350
+ colors: Colors.from_dynamic!(d.fetch("colors")),
351
+ database_metadata: DatabaseMetadataClass.from_dynamic!(d.fetch("databaseMetadata")),
352
+ finished: d.fetch("finished"),
353
+ made_with: d.fetch("madeWith"),
354
+ page_background: d.fetch("pageBackground"),
355
+ private: d.fetch("private"),
356
+ started: d.fetch("started"),
357
+ tags: d.fetch("tags"),
358
+ thumbnail: d.fetch("thumbnail"),
359
+ title_style: d.fetch("titleStyle"),
360
+ wip: d.fetch("wip"),
361
+ )
362
+ end
363
+
364
+ def self.from_json!(json)
365
+ from_dynamic!(JSON.parse(json))
366
+ end
367
+
368
+ def to_dynamic
369
+ {
370
+ "additionalMetadata" => additional_metadata,
371
+ "aliases" => aliases,
372
+ "colors" => colors.to_dynamic,
373
+ "databaseMetadata" => database_metadata.to_dynamic,
374
+ "finished" => finished,
375
+ "madeWith" => made_with,
376
+ "pageBackground" => page_background,
377
+ "private" => private,
378
+ "started" => started,
379
+ "tags" => tags,
380
+ "thumbnail" => thumbnail,
381
+ "titleStyle" => title_style,
382
+ "wip" => wip,
383
+ }
384
+ end
385
+
386
+ def to_json(options = nil)
387
+ JSON.generate(to_dynamic, options)
388
+ end
389
+ end
390
+
391
+ # AnalyzedWork represents a complete work, with analyzed mediae.
392
+ class DatabaseValue < Dry::Struct
393
+ attribute :built_at, Types::String
394
+ attribute :content, Types::Hash.meta(of: ContentValue)
395
+ attribute :description_hash, Types::String
396
+ attribute :id, Types::String
397
+ attribute :metadata, Metadata
398
+ attribute :partial, Types::Bool
399
+
400
+ def self.from_dynamic!(d)
401
+ d = Types::Hash[d]
402
+ new(
403
+ built_at: d.fetch("builtAt"),
404
+ content: Types::Hash[d.fetch("content")].map { |k, v| [k, ContentValue.from_dynamic!(v)] }.to_h,
405
+ description_hash: d.fetch("descriptionHash"),
406
+ id: d.fetch("id"),
407
+ metadata: Metadata.from_dynamic!(d.fetch("metadata")),
408
+ partial: d.fetch("Partial"),
409
+ )
410
+ end
411
+
412
+ def self.from_json!(json)
413
+ from_dynamic!(JSON.parse(json))
414
+ end
415
+
416
+ def to_dynamic
417
+ {
418
+ "builtAt" => built_at,
419
+ "content" => content.map { |k, v| [k, v.to_dynamic] }.to_h,
420
+ "descriptionHash" => description_hash,
421
+ "id" => id,
422
+ "metadata" => metadata.to_dynamic,
423
+ "Partial" => partial,
424
+ }
425
+ end
426
+
427
+ def to_json(options = nil)
428
+ JSON.generate(to_dynamic, options)
429
+ end
430
+ end
431
+
432
+ module Ortfodb
433
+ class Database
434
+ def self.from_json!(json)
435
+ Types::Hash[JSON.parse(json, quirks_mode: true)].map { |k, v| [k, DatabaseValue.from_dynamic!(v)] }.to_h
436
+ end
437
+ end
438
+ end
439
+ end
@@ -0,0 +1,120 @@
1
+ # This code may look unusually verbose for Ruby (and it is), but
2
+ # it performs some subtle and complex validation of JSON data.
3
+ #
4
+ # To parse this JSON, add 'dry-struct' and 'dry-types' gems, then do:
5
+ #
6
+ # exporter = Exporter.from_json! "{…}"
7
+ # puts exporter.work&.first.log&.first
8
+ #
9
+ # If from_json! succeeds, the value returned matches the schema.
10
+
11
+ require 'json'
12
+ require 'dry-types'
13
+ require 'dry-struct'
14
+
15
+ module Ortfodb
16
+ module Types
17
+ include Dry.Types(default: :nominal)
18
+
19
+ Bool = Strict::Bool
20
+ Hash = Strict::Hash
21
+ String = Strict::String
22
+ end
23
+
24
+ class ExporterSchema < Dry::Struct
25
+
26
+ # Log a message. The first argument is the verb, the second is the color, the third is the
27
+ # message.
28
+ attribute :log, Types.Array(Types::String).optional
29
+
30
+ # Run a command in a shell
31
+ attribute :run, Types::String.optional
32
+
33
+ def self.from_dynamic!(d)
34
+ d = Types::Hash[d]
35
+ new(
36
+ log: d["log"],
37
+ run: d["run"],
38
+ )
39
+ end
40
+
41
+ def self.from_json!(json)
42
+ from_dynamic!(JSON.parse(json))
43
+ end
44
+
45
+ def to_dynamic
46
+ {
47
+ "log" => log,
48
+ "run" => run,
49
+ }
50
+ end
51
+
52
+ def to_json(options = nil)
53
+ JSON.generate(to_dynamic, options)
54
+ end
55
+ end
56
+
57
+ class Exporter < Dry::Struct
58
+
59
+ # Commands to run after the build finishes. Go text template that receives .Data and
60
+ # .Database, the built database.
61
+ attribute :after, Types.Array(ExporterSchema).optional
62
+
63
+ # Commands to run before the build starts. Go text template that receives .Data
64
+ attribute :before, Types.Array(ExporterSchema).optional
65
+
66
+ # Initial data
67
+ attribute :data, Types::Hash.meta(of: Types::Any).optional
68
+
69
+ # Some documentation about the exporter
70
+ attribute :description, Types::String
71
+
72
+ # The name of the exporter
73
+ attribute :exporter_name, Types::String
74
+
75
+ # List of programs that are required to be available in the PATH for the exporter to run.
76
+ attribute :requires, Types.Array(Types::String).optional
77
+
78
+ # If true, will show every command that is run
79
+ attribute :verbose, Types::Bool.optional
80
+
81
+ # Commands to run during the build, for each work. Go text template that receives .Data and
82
+ # .Work, the current work.
83
+ attribute :work, Types.Array(ExporterSchema).optional
84
+
85
+ def self.from_dynamic!(d)
86
+ d = Types::Hash[d]
87
+ new(
88
+ after: d["after"]&.map { |x| ExporterSchema.from_dynamic!(x) },
89
+ before: d["before"]&.map { |x| ExporterSchema.from_dynamic!(x) },
90
+ data: Types::Hash.optional[d["data"]]&.map { |k, v| [k, Types::Any[v]] }&.to_h,
91
+ description: d.fetch("description"),
92
+ exporter_name: d.fetch("name"),
93
+ requires: d["requires"],
94
+ verbose: d["verbose"],
95
+ work: d["work"]&.map { |x| ExporterSchema.from_dynamic!(x) },
96
+ )
97
+ end
98
+
99
+ def self.from_json!(json)
100
+ from_dynamic!(JSON.parse(json))
101
+ end
102
+
103
+ def to_dynamic
104
+ {
105
+ "after" => after&.map { |x| x.to_dynamic },
106
+ "before" => before&.map { |x| x.to_dynamic },
107
+ "data" => data,
108
+ "description" => description,
109
+ "name" => exporter_name,
110
+ "requires" => requires,
111
+ "verbose" => verbose,
112
+ "work" => work&.map { |x| x.to_dynamic },
113
+ }
114
+ end
115
+
116
+ def to_json(options = nil)
117
+ JSON.generate(to_dynamic, options)
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,105 @@
1
+ # This code may look unusually verbose for Ruby (and it is), but
2
+ # it performs some subtle and complex validation of JSON data.
3
+ #
4
+ # To parse this JSON, add 'dry-struct' and 'dry-types' gems, then do:
5
+ #
6
+ # tags = Tags.from_json! "[…]"
7
+ # puts tags.first.detect.search.first
8
+ #
9
+ # If from_json! succeeds, the value returned matches the schema.
10
+
11
+ require 'json'
12
+ require 'dry-types'
13
+ require 'dry-struct'
14
+
15
+ module Ortfodb
16
+ module Types
17
+ include Dry.Types(default: :nominal)
18
+
19
+ Hash = Strict::Hash
20
+ String = Strict::String
21
+ end
22
+
23
+ class Detect < Dry::Struct
24
+ attribute :files, Types.Array(Types::String)
25
+ attribute :made_with, Types.Array(Types::String)
26
+ attribute :search, Types.Array(Types::String)
27
+
28
+ def self.from_dynamic!(d)
29
+ d = Types::Hash[d]
30
+ new(
31
+ files: d.fetch("files"),
32
+ made_with: d.fetch("made with"),
33
+ search: d.fetch("search"),
34
+ )
35
+ end
36
+
37
+ def self.from_json!(json)
38
+ from_dynamic!(JSON.parse(json))
39
+ end
40
+
41
+ def to_dynamic
42
+ {
43
+ "files" => files,
44
+ "made with" => made_with,
45
+ "search" => search,
46
+ }
47
+ end
48
+
49
+ def to_json(options = nil)
50
+ JSON.generate(to_dynamic, options)
51
+ end
52
+ end
53
+
54
+ class Tag < Dry::Struct
55
+ attribute :aliases, Types.Array(Types::String)
56
+ attribute :description, Types::String
57
+ attribute :detect, Detect
58
+ attribute :learn_more_at, Types::String
59
+ attribute :plural, Types::String
60
+ attribute :singular, Types::String
61
+
62
+ def self.from_dynamic!(d)
63
+ d = Types::Hash[d]
64
+ new(
65
+ aliases: d.fetch("aliases"),
66
+ description: d.fetch("description"),
67
+ detect: Detect.from_dynamic!(d.fetch("detect")),
68
+ learn_more_at: d.fetch("learn more at"),
69
+ plural: d.fetch("plural"),
70
+ singular: d.fetch("singular"),
71
+ )
72
+ end
73
+
74
+ def self.from_json!(json)
75
+ from_dynamic!(JSON.parse(json))
76
+ end
77
+
78
+ def to_dynamic
79
+ {
80
+ "aliases" => aliases,
81
+ "description" => description,
82
+ "detect" => detect.to_dynamic,
83
+ "learn more at" => learn_more_at,
84
+ "plural" => plural,
85
+ "singular" => singular,
86
+ }
87
+ end
88
+
89
+ def to_json(options = nil)
90
+ JSON.generate(to_dynamic, options)
91
+ end
92
+ end
93
+
94
+ module Ortfodb
95
+ class Tags
96
+ def self.from_json!(json)
97
+ tags = JSON.parse(json, quirks_mode: true).map { |x| Tag.from_dynamic!(x) }
98
+ tags.define_singleton_method(:to_json) do
99
+ JSON.generate(self.map { |x| x.to_dynamic })
100
+ end
101
+ tags
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,89 @@
1
+ # This code may look unusually verbose for Ruby (and it is), but
2
+ # it performs some subtle and complex validation of JSON data.
3
+ #
4
+ # To parse this JSON, add 'dry-struct' and 'dry-types' gems, then do:
5
+ #
6
+ # technologies = Technologies.from_json! "[…]"
7
+ # puts technologies.first.files.first
8
+ #
9
+ # If from_json! succeeds, the value returned matches the schema.
10
+
11
+ require 'json'
12
+ require 'dry-types'
13
+ require 'dry-struct'
14
+
15
+ module Ortfodb
16
+ module Types
17
+ include Dry.Types(default: :nominal)
18
+
19
+ Hash = Strict::Hash
20
+ String = Strict::String
21
+ end
22
+
23
+ class Technology < Dry::Struct
24
+ attribute :aliases, Types.Array(Types::String)
25
+
26
+ # Autodetect contains an expression of the form 'CONTENT in PATH' where CONTENT is a
27
+ # free-form unquoted string and PATH is a filepath relative to the work folder.
28
+ # If CONTENT is found in PATH, we consider that technology to be used in the work.
29
+ attribute :autodetect, Types.Array(Types::String)
30
+
31
+ attribute :by, Types::String
32
+ attribute :description, Types::String
33
+
34
+ # Files contains a list of gitignore-style patterns. If the work contains any of the
35
+ # patterns specified, we consider that technology to be used in the work.
36
+ attribute :files, Types.Array(Types::String)
37
+
38
+ attribute :learn_more_at, Types::String
39
+ attribute :technology_name, Types::String
40
+ attribute :slug, Types::String
41
+
42
+ def self.from_dynamic!(d)
43
+ d = Types::Hash[d]
44
+ new(
45
+ aliases: d.fetch("aliases"),
46
+ autodetect: d.fetch("autodetect"),
47
+ by: d.fetch("by"),
48
+ description: d.fetch("description"),
49
+ files: d.fetch("files"),
50
+ learn_more_at: d.fetch("learn more at"),
51
+ technology_name: d.fetch("name"),
52
+ slug: d.fetch("slug"),
53
+ )
54
+ end
55
+
56
+ def self.from_json!(json)
57
+ from_dynamic!(JSON.parse(json))
58
+ end
59
+
60
+ def to_dynamic
61
+ {
62
+ "aliases" => aliases,
63
+ "autodetect" => autodetect,
64
+ "by" => by,
65
+ "description" => description,
66
+ "files" => files,
67
+ "learn more at" => learn_more_at,
68
+ "name" => technology_name,
69
+ "slug" => slug,
70
+ }
71
+ end
72
+
73
+ def to_json(options = nil)
74
+ JSON.generate(to_dynamic, options)
75
+ end
76
+ end
77
+
78
+ module Ortfodb
79
+ class Technologies
80
+ def self.from_json!(json)
81
+ technologies = JSON.parse(json, quirks_mode: true).map { |x| Technology.from_dynamic!(x) }
82
+ technologies.define_singleton_method(:to_json) do
83
+ JSON.generate(self.map { |x| x.to_dynamic })
84
+ end
85
+ technologies
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,3 @@
1
+ module Ortfodb
2
+ VERSION = "1.2.0"
3
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ortfodb
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Ewen Le Bihan
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-04-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-struct
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dry-types
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.7'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 1.7.2
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '1.7'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 1.7.2
47
+ description: Client library for working with ortfo/db databases. Generated from ortfo/db's
48
+ JSON schemas (see https://ortfo.org/db/client-libraries).
49
+ email:
50
+ - ortfo@ewen.works
51
+ executables: []
52
+ extensions: []
53
+ extra_rdoc_files: []
54
+ files:
55
+ - lib/ortfodb/configuration.rb
56
+ - lib/ortfodb/database.rb
57
+ - lib/ortfodb/exporter.rb
58
+ - lib/ortfodb/tags.rb
59
+ - lib/ortfodb/technologies.rb
60
+ - lib/ortfodb/version.rb
61
+ homepage: https://ortfo.org/db
62
+ licenses:
63
+ - MIT
64
+ metadata:
65
+ allowed_push_host: https://rubygems.org
66
+ bug_tracker_uri: https://github.com/ortfo/db/issues
67
+ changelog_uri: https://github.com/ortfo/db/blob/main/CHANGELOG.md
68
+ documentation_uri: https://ortfo.org/db
69
+ homepage_uri: https://ortfo.org/db
70
+ source_code_uri: https://github.com/ortfo/db/tree/main/packages/ruby
71
+ post_install_message:
72
+ rdoc_options: []
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: 2.0.0
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubygems_version: 3.3.25
87
+ signing_key:
88
+ specification_version: 4
89
+ summary: Client library for working with ortfo/db databases
90
+ test_files: []