ortfodb 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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: []