capsium 0.1.2 → 0.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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +34 -7
  4. data/CHANGELOG.md +58 -0
  5. data/Gemfile +6 -0
  6. data/LICENSE +21 -0
  7. data/README.adoc +177 -135
  8. data/Rakefile +8 -1
  9. data/bin/console +1 -1
  10. data/capsium.gemspec +11 -19
  11. data/exe/capsium +1 -1
  12. data/lib/capsium/cli/convert.rb +18 -0
  13. data/lib/capsium/cli/package.rb +86 -0
  14. data/lib/capsium/cli/reactor.rb +25 -0
  15. data/lib/capsium/cli.rb +3 -96
  16. data/lib/capsium/converters/jekyll.rb +5 -7
  17. data/lib/capsium/converters.rb +7 -0
  18. data/lib/capsium/package/dataset.rb +67 -34
  19. data/lib/capsium/package/manifest.rb +33 -22
  20. data/lib/capsium/package/manifest_config.rb +52 -7
  21. data/lib/capsium/package/metadata.rb +4 -8
  22. data/lib/capsium/package/metadata_config.rb +97 -9
  23. data/lib/capsium/package/routes.rb +39 -41
  24. data/lib/capsium/package/routes_config.rb +120 -44
  25. data/lib/capsium/package/security.rb +123 -0
  26. data/lib/capsium/package/security_config.rb +60 -0
  27. data/lib/capsium/package/storage.rb +20 -45
  28. data/lib/capsium/package/storage_config.rb +100 -3
  29. data/lib/capsium/package/validator.rb +149 -0
  30. data/lib/capsium/package.rb +68 -66
  31. data/lib/capsium/packager.rb +42 -6
  32. data/lib/capsium/reactor/introspection.rb +88 -0
  33. data/lib/capsium/reactor.rb +89 -41
  34. data/lib/capsium/version.rb +1 -1
  35. data/lib/capsium.rb +7 -9
  36. data/sig/capsium/package/dataset.rbs +28 -0
  37. data/sig/capsium/package/manifest.rbs +34 -0
  38. data/sig/capsium/package/manifest_config.rbs +38 -0
  39. data/sig/capsium/package/metadata.rbs +26 -0
  40. data/sig/capsium/package/metadata_config.rbs +49 -0
  41. data/sig/capsium/package/routes.rbs +37 -0
  42. data/sig/capsium/package/routes_config.rbs +74 -0
  43. data/sig/capsium/package/security.rbs +65 -0
  44. data/sig/capsium/package/security_config.rbs +57 -0
  45. data/sig/capsium/package/storage.rbs +28 -0
  46. data/sig/capsium/package/storage_config.rbs +61 -0
  47. data/sig/capsium/package/validator.rbs +29 -0
  48. data/sig/capsium/package.rbs +53 -0
  49. data/sig/capsium/packager.rbs +23 -0
  50. data/sig/capsium/reactor/introspection.rbs +31 -0
  51. data/sig/capsium/reactor.rbs +30 -0
  52. data/sig/capsium.rbs +3 -1
  53. metadata +52 -183
  54. data/lib/capsium/package/dataset_config.rb +0 -28
  55. data/lib/capsium/protector.rb +0 -103
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2b954beb33b36d3300f8ff418f643a9afbbf688fad4e8333b195ccb76b38b41
4
- data.tar.gz: b2ef9e049b70ce3eb111ef0c136befaaf7a2f6a4d233ed9fb41a9d27d9c39e2c
3
+ metadata.gz: 9746224c88e5a4a3b2aabe9609af2348235d6efe09dcd37fa71c710f08594829
4
+ data.tar.gz: fcbf1c6857f12bede912bb25d32dc83ddb84cd97757425dcf642af9e785e9478
5
5
  SHA512:
6
- metadata.gz: e3c75b5ab47ef3b7fe5a8f20571a300c15b960951c032d9c8d01e3eff295a237c294288613449ed090c73e38df718986f412573deeafd0f33acd7a43ead76c41
7
- data.tar.gz: 8bdb432b2b7efb4987d211608e8cb13828e2bf49d49cf921c3d9a7f7cc74f5a775ed6454e5bfd3e91a539a36fa0beb28395ff7910682d9d791f8c44db3eebe26
6
+ metadata.gz: fce42689914eda35768a2dfa4dfa74b5c00e8b760ddb50cb6b44b810a20b1423e0a31392eaefff1270408c6ed83d4b56c10a895a54f609ff71afd117b6950194
7
+ data.tar.gz: a45f5ea52966810c8ab183f0ec3407287eb7c87b34f82555242372d08b944edea2c372fdabe836f5e8ef0ff7ee793bed10fcc0a6ca21e486acd2466f7fbb1b93
data/.gitignore CHANGED
@@ -6,6 +6,7 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /Gemfile.lock
9
10
 
10
11
  # rspec failure tracking
11
12
  .rspec_status
data/.rubocop.yml CHANGED
@@ -1,12 +1,39 @@
1
- inherit_from:
2
- - https://raw.githubusercontent.com/riboseinc/oss-guides/master/ci/rubocop.yml
3
-
4
- # local repo-specific modifications
5
- # ...
1
+ plugins:
2
+ - rubocop-performance
6
3
 
7
4
  AllCops:
8
- TargetRubyVersion: 2.6
5
+ TargetRubyVersion: 3.2
9
6
  NewCops: enable
7
+ SuggestExtensions: false
10
8
  Exclude:
11
- - 'lib/sts/mapper.rb'
12
9
  - 'vendor/**/*'
10
+
11
+ Layout/LineLength:
12
+ Max: 100
13
+
14
+ # Project convention: double-quoted string literals.
15
+ Style/StringLiterals:
16
+ EnforcedStyle: double_quotes
17
+
18
+ # Classes are intentionally undocumented for now; API docs land with a
19
+ # later phase together with the RBS signatures.
20
+ Style/Documentation:
21
+ Enabled: false
22
+
23
+ # RSpec example groups and the gemspec are block-heavy by nature.
24
+ Metrics/BlockLength:
25
+ Exclude:
26
+ - 'spec/**/*'
27
+ - 'capsium.gemspec'
28
+
29
+ Metrics/ClassLength:
30
+ Max: 120
31
+
32
+ Metrics/MethodLength:
33
+ Max: 25
34
+
35
+ Metrics/AbcSize:
36
+ Max: 30
37
+
38
+ Metrics/CyclomaticComplexity:
39
+ Max: 8
data/CHANGELOG.md ADDED
@@ -0,0 +1,58 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0
4
+
5
+ ### Changed
6
+
7
+ - Migrated all package configuration models from shale to lutaml-model.
8
+ - All configuration files now follow the canonical schemas
9
+ (ARCHITECTURE.md sections 2-6):
10
+ - `metadata.json`: `dependencies` is an object of `guid -> semver range`;
11
+ `name`/`version`/`description`/`guid`/`uuid` are the required fields.
12
+ - `manifest.json`: a `resources` object keyed by package-relative path
13
+ (`type`, `visibility`, optional `version`).
14
+ - `routes.json`: optional top-level `index` plus a `routes` array with
15
+ discriminated kinds (`resource` / `dataset` / handler).
16
+ - `storage.json`: `storage.dataSets` object; dataset `source` and
17
+ `schemaFile` are package-relative paths.
18
+ - Legacy (pre-0.2) configuration files are accepted on read and normalized
19
+ to the canonical forms; writers emit only the canonical forms.
20
+ - Manifest and routes auto-generation is deterministic (sorted); HTML files
21
+ get dual routes, the index HTML gets `/`, datasets get
22
+ `/api/v1/data/<id>`.
23
+ - The reactor serves dataset routes as JSON, sets `Cache-Control: public,
24
+ max-age=31536000` on static resources (configurable), responds 501 to
25
+ handler routes, and rejects packages that fail integrity verification.
26
+ - The CLI exits nonzero on errors.
27
+
28
+ ### Added
29
+
30
+ - `security.json` with SHA-256 checksums over every package file, generated
31
+ at pack time; verified automatically on load (`Package#verify_integrity`,
32
+ `Capsium::Package::Security::IntegrityError` on mismatch).
33
+ - `capsium package validate <path|cap>`: per-check validation report
34
+ (metadata formats, on-disk existence of manifest resources, route targets
35
+ and dataset sources, dataset JSON-schema validation, checksums, external
36
+ http(s) references in content), exit status 1 on any failure.
37
+ - `capsium package unpack <cap> [-o dir]`.
38
+ - `Capsium::Package::Validator` and `Capsium::Package::Security`.
39
+ - Reactor introspection HTTP API (ARCHITECTURE.md section 7):
40
+ `GET /api/v1/introspect/metadata`, `/routes`, `/content-hashes` and
41
+ `/content-validity`, served as JSON by `Capsium::Reactor::Introspection`.
42
+ `content-hashes` is the SHA-256 of the `.cap` blob, or of the canonical
43
+ JSON serialization of the content checksums for directory sources;
44
+ `content-validity` re-verifies integrity live.
45
+ - Zip-slip protection on `.cap` extraction: entries escaping the
46
+ destination (absolute paths, drive letters, `..` segments) raise
47
+ `Capsium::Packager::UnsafeEntryError`.
48
+ - RBS signatures for the public API (`sig/`), kept green by the
49
+ `rbs:validate` rake task (part of the default rake task).
50
+ - `Capsium::Package#cap_file_path`.
51
+
52
+ ### Removed
53
+
54
+ - `Capsium::Protector` (bit-rotted, insecure; encryption/signing is
55
+ deferred to a later phase).
56
+ - shale dependency (replaced by lutaml-model); base64 dependency.
57
+ - Unused constants `Package::PACKAGING_FILE`, `Package::SIGNATURE_FILE`,
58
+ `Package::ENCRYPTED_PACKAGING_FILE`, `Routes::DEFAULT_INDEX_TARGET`.
data/Gemfile CHANGED
@@ -4,3 +4,9 @@ source "https://rubygems.org"
4
4
 
5
5
  # Specify your gem's dependencies in capsium.gemspec
6
6
  gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+ gem "rbs", "~> 4.0"
10
+ gem "rspec", "~> 3.11"
11
+ gem "rubocop", "~> 1.88"
12
+ gem "rubocop-performance", "~> 1.26"
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Ribose Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.adoc CHANGED
@@ -9,27 +9,14 @@ content packages with ease.
9
9
  This gem provides a structured way to handle content, data, and metadata for
10
10
  various applications.
11
11
 
12
-
13
- == Testing out how it works
14
-
15
- Download the mn-samples-iso built site: https://github.com/metanorma/mn-samples-iso/actions/runs/8862815829/artifacts/1453746303[mn-samples-iso-Linux].
16
-
17
- Then run these commands:
12
+ == Test it out!
18
13
 
19
14
  [source,bash]
20
15
  ----
21
- $ unzip mn-samples-iso-Linux.zip
22
- $ cd mn-samples-iso-Linux
23
- $ mkdir content
24
- $ mv index.html documents.xml documents content
25
- $ echo '{"name": "mn-samples-iso","version":"0.1.0"}' > metadata.json
26
- $ cd ..
27
- $ bundle exec capsium package pack -f mn-samples-iso-Linux
28
- Package created: mn-samples-iso-0.1.0.cap
29
- $ bundle exec capsium reactor serve mn-samples-iso-0.1.0.cap
30
- Starting server on http://localhost:8864
31
- [2024-06-05 14:56:41] INFO WEBrick::HTTPServer#start: pid=8234 port=8864
32
- ...
16
+ $ wget https://github.com/capsiums/cap-story/releases/download/v0.9.0/story_of_claire-0.9.0.cap
17
+ $ capsium reactor serve story_of_claire-0.9.0.cap
18
+ $ open http://localhost:8864
19
+ # => Read the story!
33
20
  ----
34
21
 
35
22
  == Installation
@@ -57,184 +44,231 @@ gem install capsium
57
44
 
58
45
  == What is a Capsium package?
59
46
 
60
- A Capsium package is a structured collection of content, data, metadata, and routing information. It is designed to encapsulate all resources needed for a particular application or service in a well-organized format. A package typically includes:
47
+ A Capsium package is a structured collection of content, data, metadata, and
48
+ routing information, distributed as a single `.cap` file (a ZIP archive, MIME
49
+ `application/vnd.capsium.package`). The canonical layout:
61
50
 
62
- * **Content**: Static files like HTML, CSS, and JavaScript.
63
- * **Data**: Structured data files, such as YAML or JSON.
64
- * **Metadata**: Descriptive information about the package, such as its name, version, and dependencies.
65
- * **Routes**: Mapping of URLs to content or data endpoints.
66
- * **Storage**: Definitions for datasets and their sources, formats, and schemas.
51
+ [source]
52
+ ----
53
+ metadata.json # REQUIRED, hand-authored
54
+ manifest.json # auto-generated at load/pack time when absent
55
+ routes.json # auto-generated when absent
56
+ storage.json # optional (only when datasets exist)
57
+ security.json # generated at pack time (SHA-256 checksums)
58
+ content/ # served content root (URL space mirrors paths below it)
59
+ data/ # datasets (optional)
60
+ ----
61
+
62
+ Paths inside the configuration files are package-relative POSIX paths.
63
+
64
+ * **metadata.json**: name (kebab-case), version (semver), description, guid
65
+ (URI) and uuid are required; author, license, repository, dependencies
66
+ (an object of `guid -> semver range`) are optional.
67
+ * **manifest.json**: an object keyed by package-relative resource path, e.g.
68
+ `"content/index.html": { "type": "text/html", "visibility": "exported" }`.
69
+ Generated by scanning `content/` (MIME types via marcel) when absent.
70
+ * **routes.json**: an optional top-level `index` plus a `routes` array. Route
71
+ kinds: `{path, resource}` for static files, `{path, dataset}` for datasets
72
+ (served under `/api/v1/data/<id>`). HTML files get two routes (basename and
73
+ full filename); the index HTML additionally gets `/`.
74
+ * **storage.json**: dataset definitions under `storage.dataSets`, either
75
+ schema-backed files (`source`, `schemaFile`, `schemaType: json-schema`)
76
+ or SQLite (`databaseFile`, `table`).
77
+ * **security.json**: `security.integrityChecks.checksums` holds a SHA-256 hex
78
+ digest for every file in the package except `security.json` itself.
79
+
80
+ Legacy (pre-0.2) configuration files are still accepted on read and
81
+ normalized to the canonical forms; writers emit only the canonical forms.
67
82
 
68
83
  == What is a Capsium reactor?
69
84
 
70
- A Capsium reactor is a runtime environment that serves Capsium packages. It reads the package configuration and starts a server that can handle HTTP requests according to the routes defined in the package. The reactor ensures that the content and data within the package are served correctly, allowing for easy integration and deployment of packaged applications.
85
+ A Capsium reactor is a runtime environment that serves Capsium packages. It
86
+ reads the package configuration and starts a server that can handle HTTP
87
+ requests according to the routes defined in the package. The reactor verifies
88
+ the package against `security.json` when present and rejects tampered
89
+ packages. Dataset routes are served as JSON; static resources are served with
90
+ `Cache-Control: public, max-age=31536000` (configurable). While serving, the
91
+ reactor also answers the introspection endpoints described below.
71
92
 
72
93
  == CLI: Package
73
94
 
74
- To pack a package, you need to define the content, data, metadata, routes, and storage configurations. Once defined, you can use the Capsium command-line interface (CLI) to create and manage your packages.
95
+ Capsium provides a CLI to help you pack and manage your packages.
75
96
 
76
- Capsium provides a CLI to help you pack and manage your packages. Here are some common commands:
97
+ === Packing a package
77
98
 
78
99
  [source,bash]
79
100
  ----
80
- # TODO: Create a new package
81
- # Full command
82
- capsium package new my_package
83
- # Shorthand
84
- capsium package my_package
85
-
86
- # TODO: Add content to the package
87
- capsium package add content example.html example.css example.js
101
+ capsium package pack [--force/-f] path-to-package
102
+ ----
88
103
 
89
- # TODO: Add data to the package
90
- capsium package add data animals.yaml
104
+ This command generates `manifest.json`/`routes.json` when absent, writes
105
+ `security.json` with SHA-256 checksums of every package file, and packs the
106
+ directory into `{package-name}-{package-version}.cap` (name and version from
107
+ `metadata.json`).
91
108
 
92
- # TODO: Add metadata to the package
93
- capsium package add metadata name=sample_package version=0.1.0
109
+ .Sample `pack` command
110
+ ====
111
+ [source,bash]
112
+ ----
113
+ capsium package pack -f spec/fixtures/bare-package
114
+ ----
115
+ ====
94
116
 
95
- # TODO: Define routes for the package
96
- capsium package add route /=example.html /index=index.html /api/v1/data/animals={type:dataset,name:animals}
117
+ === Unpacking a package
97
118
 
98
- # TODO: Define storage for the package
99
- capsium package add storage datasets=[{name:animals,source:data/animals.yaml,format:yaml,schema:data/animals_schema.yaml}]
119
+ [source,bash]
120
+ ----
121
+ capsium package unpack bare-package-0.1.0.cap [-o/--output my_bare_package]
100
122
  ----
101
123
 
102
- === Packing a package
124
+ When `-o` is omitted, the package is unpacked into a directory named after
125
+ the `.cap` file.
103
126
 
104
- To pack an existing Capsium package directory, use the following command:
127
+ Extraction is zip-slip safe: entries whose names would escape the
128
+ destination (absolute paths, drive letters, `..` segments) are rejected
129
+ with `Capsium::Packager::UnsafeEntryError`.
130
+
131
+ === Validating a package
105
132
 
106
133
  [source,bash]
107
134
  ----
108
- capsium package pack [--force/-f] path-to-package
135
+ capsium package validate path-to-package-or-cap
109
136
  ----
110
137
 
111
- This command will pack your package into a single file with the
112
- filename:
138
+ Runs a per-check report and exits with status 1 on any failure:
113
139
 
114
- * `{package-name}-{package-version}.cap`
115
- * where the name and version both come from `{package-path}/metadata.json`
140
+ * metadata: required fields present and well-formed (kebab-case name, semver
141
+ version, URI guid, UUID)
142
+ * manifest: every resource exists on disk
143
+ * routes: route targets exist; dataset routes live under `/api/v1/data/`;
144
+ the index resolves to an existing HTML file
145
+ * storage: dataset sources (and schemas) exist; dataset data passes
146
+ JSON-schema validation
147
+ * security: checksums match when `security.json` is present
148
+ * content: no external `http(s)` references in `content/` files
149
+
150
+ === Inspecting a package
116
151
 
117
- .Sample `pack` command
118
- ====
119
152
  [source,bash]
120
153
  ----
121
- capsium package pack -f spec/fixtures/bare_package
154
+ capsium package info|manifest|routes|metadata|storage path-to-package
122
155
  ----
123
- ====
124
-
125
-
126
156
 
127
157
  == CLI: Reactor
128
158
 
129
159
  === Starting a reactor on your package
130
160
 
131
- To start a Capsium reactor on your package, use the following command:
132
-
133
161
  [source,bash]
134
162
  ----
135
- capsium reactor serve my_package.cap
163
+ capsium reactor serve my_package.cap [--port 8864]
136
164
  ----
137
165
 
166
+ The reactor takes a local package directory or `.cap` file; serving
167
+ directly from a URL is not supported.
168
+
169
+ === Reactor introspection API
170
+
171
+ While serving, the reactor answers the Monitoring HTTP API
172
+ (ARCHITECTURE.md section 7) as `application/json`:
173
+
174
+ [source]
175
+ ----
176
+ GET /api/v1/introspect/metadata # => {"packages": [{"name", "version", "author", "description"}]}
177
+ GET /api/v1/introspect/routes # => {"routes": [{"package", "routes": [{"method", "path"}]}]}
178
+ GET /api/v1/introspect/content-hashes # => {"contentHashes": [{"package", "hash"}]}
179
+ GET /api/v1/introspect/content-validity # => {"contentValidity": [{"package", "valid", "lastChecked", "reason"?}]}
180
+ ----
181
+
182
+ Non-GET methods on these paths are answered `405 Method Not Allowed`.
183
+
184
+ `content-hashes` is the SHA-256 of the `.cap` blob when the package was
185
+ served from one. For a directory source there is no blob, so the hash
186
+ covers the canonical (sorted-key) JSON serialization of the package
187
+ content checksums — the same data `security.json` integrityChecks carry.
188
+
189
+ `content-validity` re-verifies the package against `security.json` on
190
+ every request and reports the outcome with a UTC `lastChecked`
191
+ timestamp; `reason` lists the integrity errors when `valid` is false.
138
192
 
139
193
  == Programmatically managing packages
140
194
 
141
- You can also create, load, and use packages programmatically within your Ruby application.
195
+ The public API below ships with RBS signatures in `sig/`
196
+ (`bundle exec rbs -I sig validate`).
142
197
 
143
- === Creating packages
198
+ === Loading packages
144
199
 
145
200
  [source,ruby]
146
201
  ----
147
202
  require 'capsium'
148
203
 
149
- package = Capsium::Package.new(
150
- name: 'sample_package',
151
- version: '0.1.0',
152
- content: {
153
- 'example.html' => 'text/html',
154
- 'example.css' => 'text/css',
155
- 'example.js' => 'application/javascript'
156
- },
157
- data: {
158
- 'animals.yaml' => {
159
- 'animals' => [
160
- { 'name' => 'Lion', 'type' => 'Mammal', 'habitat' => 'Savannah' },
161
- { 'name' => 'Eagle', 'type' => 'Bird', 'habitat' => 'Mountains' },
162
- { 'name' => 'Shark', 'type' => 'Fish', 'habitat' => 'Ocean' }
163
- ]
164
- }
165
- },
166
- metadata: {
167
- 'name' => 'sample_package',
168
- 'version' => '0.1.0',
169
- 'dependencies' => []
170
- },
171
- routes: {
172
- '/' => 'example.html',
173
- '/index' => 'index.html',
174
- '/index.html' => 'index.html',
175
- '/example.css' => 'example.css',
176
- '/example.js' => 'example.js',
177
- '/api/v1/data/animals' => { 'type' => 'dataset', 'name' => 'animals' }
178
- },
179
- storage: {
180
- 'datasets' => [
181
- {
182
- 'name' => 'animals',
183
- 'source' => 'data/animals.yaml',
184
- 'format' => 'yaml',
185
- 'schema' => 'data/animals_schema.yaml'
186
- }
187
- ]
188
- }
189
- )
190
-
191
- # Save the package to a file
192
- File.write('my_package.json', package.to_json(pretty: true))
204
+ # Read a package directory or a .cap file
205
+ package = Capsium::Package.new(path)
193
206
  ----
194
207
 
195
- === Loading packages
208
+ When `security.json` is present, the package is verified on load and
209
+ `Capsium::Package::Security::IntegrityError` is raised on mismatch.
196
210
 
197
- To load an existing package from a JSON file, you can use the `Capsium::Package.new(path)` method:
211
+ === Using packages in your program
198
212
 
199
213
  [source,ruby]
200
214
  ----
201
- require 'capsium'
215
+ # Accessing package metadata
216
+ puts "Package Name: #{package.metadata.name}"
217
+ puts "Package Version: #{package.metadata.version}"
202
218
 
203
- # Read the package file or folder
204
- package = Capsium::Package.new(path)
219
+ # Accessing manifest resources
220
+ package.manifest.resources.each do |path, resource|
221
+ puts "Resource: #{path}, Type: #{resource.type}"
222
+ end
205
223
 
206
- # Inspect the loaded package
207
- puts package.inspect
208
- ----
224
+ # Accessing routes
225
+ route = package.routes.resolve('/')
226
+ puts route.resource
209
227
 
210
- === Using packages in your program
228
+ # Accessing datasets
229
+ animals = package.storage.dataset('animals')
230
+ puts animals.data.inspect
231
+
232
+ # Verifying integrity (returns a list of typed errors, empty when valid)
233
+ errors = package.verify_integrity
234
+ ----
211
235
 
212
- Once you have created or loaded a package, you can use it within your Ruby application to access its content, data, and other properties.
236
+ === Packing and unpacking programmatically
213
237
 
214
238
  [source,ruby]
215
239
  ----
216
- # Accessing package metadata
217
- puts "Package Name: #{package.metadata['name']}"
218
- puts "Package Version: #{package.metadata['version']}"
240
+ packager = Capsium::Packager.new
241
+ cap_file = packager.pack(package, force: true)
242
+ packager.unpack(cap_file, 'output-directory')
243
+ ----
219
244
 
220
- # Accessing content
221
- package.content.each do |filename, content_type|
222
- puts "Content File: #{filename}, Content Type: #{content_type}"
223
- end
245
+ == Building the mn-samples-iso cap package
224
246
 
225
- # Accessing data
226
- animals_data = package.data['animals.yaml']
227
- puts "Animals Data: #{animals_data.inspect}"
247
+ Download the mn-samples-iso built site: https://github.com/metanorma/mn-samples-iso/actions/runs/8862815829/artifacts/1453746303[mn-samples-iso-Linux].
228
248
 
229
- # Accessing routes
230
- package.routes.each do |route, destination|
231
- puts "Route: #{route}, Destination: #{destination}"
232
- end
249
+ Then run these commands:
233
250
 
234
- # Accessing storage definitions
235
- package.storage['datasets'].each do |dataset|
236
- puts "Dataset Name: #{dataset['name']}, Source: #{dataset['source']}, Format: #{dataset['format']}"
237
- end
251
+ [source,bash]
252
+ ----
253
+ $ unzip mn-samples-iso-Linux.zip
254
+ $ cd mn-samples-iso-Linux
255
+ $ mkdir content
256
+ $ mv index.html documents.xml documents content
257
+ $ cat > metadata.json <<'JSON'
258
+ {
259
+ "name": "mn-samples-iso",
260
+ "version": "0.1.0",
261
+ "description": "Metanorma ISO sample documents",
262
+ "guid": "https://github.com/metanorma/mn-samples-iso",
263
+ "uuid": "123e4567-e89b-12d3-a456-426614174000"
264
+ }
265
+ JSON
266
+ $ cd ..
267
+ $ bundle exec capsium package pack -f mn-samples-iso-Linux
268
+ Package created: mn-samples-iso-0.1.0.cap
269
+ $ bundle exec capsium reactor serve mn-samples-iso-0.1.0.cap
270
+ Starting server on http://localhost:8864
271
+ ...
238
272
  ----
239
273
 
240
274
  == Contributing
@@ -247,7 +281,16 @@ To run the tests, use the following command:
247
281
 
248
282
  [source,bash]
249
283
  ----
250
- rspec
284
+ bundle exec rspec
285
+ ----
286
+
287
+ The linter and the RBS signature validation are part of the default rake
288
+ task (`bundle exec rake`), or run them individually:
289
+
290
+ [source,bash]
291
+ ----
292
+ bundle exec rubocop
293
+ bundle exec rbs -I sig validate
251
294
  ----
252
295
 
253
296
  == License
@@ -255,4 +298,3 @@ rspec
255
298
  Copyright Ribose.
256
299
 
257
300
  Capsium is released under the MIT License. See the LICENSE file for more details.
258
-
data/Rakefile CHANGED
@@ -9,4 +9,11 @@ require "rubocop/rake_task"
9
9
 
10
10
  RuboCop::RakeTask.new
11
11
 
12
- task default: %i[spec rubocop]
12
+ namespace :rbs do
13
+ desc "Validate the RBS signatures (sig/)"
14
+ task :validate do
15
+ sh "bundle exec rbs -I sig validate"
16
+ end
17
+ end
18
+
19
+ task default: %i[spec rubocop rbs:validate]
data/bin/console CHANGED
@@ -2,7 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "bundler/setup"
5
- require "capsium"
5
+ require File.expand_path("../lib/capsium", __dir__)
6
6
 
7
7
  # You can add fixtures and/or initialization code here to make experimenting
8
8
  # with your gem easier. You can also use a different console, if you like.
data/capsium.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "lib/capsium/version"
3
+ require File.expand_path("lib/capsium/version", __dir__)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "capsium"
@@ -8,14 +8,19 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["Ribose Inc."]
9
9
  spec.email = ["open.source@ribose.com"]
10
10
 
11
- spec.summary = "Capsium"
12
- spec.description = "Capsium"
11
+ spec.summary = "Packager and reactor for Capsium packages (.cap)"
12
+ spec.description = "Capsium facilitates the creation, management and " \
13
+ "deployment of content packages with ease. This gem " \
14
+ "provides a structured way to handle content, data, " \
15
+ "and metadata for various applications: it packages " \
16
+ "them into .cap files and serves them over HTTP."
13
17
  spec.homepage = "https://github.com/capsiums/capsium"
14
18
  spec.license = "MIT"
15
19
 
16
20
  spec.metadata["homepage_uri"] = spec.homepage
17
21
  spec.metadata["source_code_uri"] = spec.homepage
18
22
  spec.metadata["changelog_uri"] = "https://github.com/capsiums/capsium/releases"
23
+ spec.metadata["rubygems_mfa_required"] = "true"
19
24
 
20
25
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
21
26
  `git ls-files -z`
@@ -26,30 +31,17 @@ Gem::Specification.new do |spec|
26
31
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
32
  spec.require_paths = ["lib"]
28
33
 
29
- spec.required_ruby_version = ">= 2.7.0"
34
+ spec.required_ruby_version = ">= 3.2.0"
30
35
 
31
- spec.add_dependency "cssminify"
32
36
  spec.add_dependency "csv"
33
- spec.add_dependency "htmlcompressor"
34
- spec.add_dependency "html-proofer"
35
- spec.add_dependency "jekyll"
36
37
  spec.add_dependency "json"
37
38
  spec.add_dependency "json-schema"
38
39
  spec.add_dependency "listen"
40
+ spec.add_dependency "lutaml-model", ">= 0.8", "< 1.0"
39
41
  spec.add_dependency "marcel"
40
- spec.add_dependency "rubyzip", "~> 2.3.2"
41
- spec.add_dependency "scss_lint"
42
- spec.add_dependency "shale"
42
+ spec.add_dependency "rubyzip", ">= 2.3.2", "< 4.0"
43
43
  spec.add_dependency "sqlite3"
44
44
  spec.add_dependency "thor"
45
- spec.add_dependency "uglifier"
46
45
  spec.add_dependency "webrick"
47
46
  spec.add_dependency "yaml"
48
-
49
- spec.add_development_dependency "pry"
50
- spec.add_development_dependency "rack-test"
51
- spec.add_development_dependency "rake", "~> 13.0"
52
- spec.add_development_dependency "rspec", "~> 3.11"
53
- spec.add_development_dependency "rubocop", "~> 1.58"
54
- spec.add_development_dependency "rubocop-performance"
55
47
  end
data/exe/capsium CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "capsium/cli"
4
+ require File.expand_path("../lib/capsium", __dir__)
5
5
 
6
6
  Capsium::Cli.start(ARGV)