andromeda_cms 0.1.1-aarch64-linux → 0.2.0-aarch64-linux
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 +4 -4
- data/CHANGELOG.md +49 -0
- data/README.md +2 -0
- data/lib/andromeda/assets.rb +22 -0
- data/lib/andromeda/check.rb +3 -1
- data/lib/andromeda/entry.rb +25 -4
- data/lib/andromeda/pipeline.rb +35 -7
- data/lib/andromeda/references.rb +72 -0
- data/lib/andromeda/schema.rb +9 -1
- data/lib/andromeda/version.rb +1 -1
- data/lib/andromeda_cms.rb +1 -0
- data/lib/generators/andromeda/install/install_generator.rb +5 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2f503f2e0323c9c9f1e60ec590e71a478e9c3b89165784228219ee59a72036df
|
|
4
|
+
data.tar.gz: 6c68eb084c18fdc56ad761af82334d02658516dc70913d8b56fe4663287fc365
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4472d7d23beb4f422c2d2410b5643f31bceb44acd18156161d72e0aa293f39483c201390af7abd526f3b6ba5f13d25b724fc8f454fb72538b8c0ffd14f4ca913
|
|
7
|
+
data.tar.gz: 1bc41d2dd539523d725129f7bd69942c5c2654395115fa1607df134a0778e8539666ec985575f1059df541e2519f19f210e1ade428d041877e790b567a0dbb15
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,53 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.0] - 2026-09-29
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- The reader for an `:array` attribute declared `of: :reference` now resolves
|
|
13
|
+
each element to its entry, the way a single `:reference` reader already
|
|
14
|
+
did: `post.tags` returns the tag entries, in frontmatter order, and raises
|
|
15
|
+
`Andromeda::EntryNotFound` for an id with no entry. It used to return the
|
|
16
|
+
`Andromeda::Reference` pointers, which are still in `post.data[:tags]`.
|
|
17
|
+
- `andromeda:build` and `andromeda:check` now fail on content that used to
|
|
18
|
+
pass and then broke when served. Run `andromeda:check` before upgrading a
|
|
19
|
+
deploy to see what needs fixing:
|
|
20
|
+
- a `:reference`, alone or in an array, whose id has no entry in the target
|
|
21
|
+
collection, or that names a collection nobody registered;
|
|
22
|
+
- an image in the body written as a bare path (`blog/posts/x.png`) that
|
|
23
|
+
Propshaft's load path cannot find. These used to fall back to a plain
|
|
24
|
+
`/assets/...` URL and 404 in production. Without Propshaft the path is
|
|
25
|
+
still used as written.
|
|
26
|
+
- Declaring `:array` with `of: :reference` and no `collection:`, or with
|
|
27
|
+
`of: :enum` and no `values:`, now raises `ArgumentError` at definition time.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- An `:array` of `:reference` built its elements without the declared
|
|
32
|
+
`collection:`, so each `Andromeda::Reference` had a `nil` collection. The
|
|
33
|
+
first process worked; the next one to read `.andromeda/` failed with
|
|
34
|
+
`NoMethodError: undefined method 'to_sym' for nil`. `of: :enum` lost its
|
|
35
|
+
`values:` the same way and raised `NoMethodError` on any value.
|
|
36
|
+
- An image in the body written as `./` or `../` with no file behind it was
|
|
37
|
+
treated as an asset pipeline path and rendered as a broken `/assets/./...`
|
|
38
|
+
URL. It now fails the build, as the documentation says, and so does a
|
|
39
|
+
relative path that leaves the project.
|
|
40
|
+
- `andromeda:install` appended its ignore lines to the last line of a
|
|
41
|
+
`.gitignore` or `.dockerignore` that did not end with a newline, breaking
|
|
42
|
+
both that entry and `/.andromeda/`.
|
|
43
|
+
|
|
44
|
+
## [0.1.2] - 2026-09-27
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- `Entry#body` returned `nil` in production. Entries there are read from the
|
|
49
|
+
built index, which leaves bodies out, so anything using the raw Markdown --
|
|
50
|
+
a reading-time estimate, a Markdown export -- failed with `NoMethodError`.
|
|
51
|
+
The build now stores each entry's body in its own file (not the index), and
|
|
52
|
+
`Entry#body` reads it from there when needed, the same way `html` works.
|
|
53
|
+
Existing builds pick this up on the next `andromeda:build`.
|
|
54
|
+
|
|
8
55
|
## [0.1.1] - 2026-09-27
|
|
9
56
|
|
|
10
57
|
### Fixed
|
|
@@ -38,5 +85,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
38
85
|
- Generators: `andromeda:install`, `andromeda:collection`,
|
|
39
86
|
`andromeda:component` and `andromeda:import_astro`.
|
|
40
87
|
|
|
88
|
+
[0.2.0]: https://github.com/AndromedaCMS/andromeda_cms/releases/tag/v0.2.0
|
|
89
|
+
[0.1.2]: https://github.com/AndromedaCMS/andromeda_cms/releases/tag/v0.1.2
|
|
41
90
|
[0.1.1]: https://github.com/AndromedaCMS/andromeda_cms/releases/tag/v0.1.1
|
|
42
91
|
[0.1.0]: https://github.com/AndromedaCMS/andromeda_cms/releases/tag/v0.1.0
|
data/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Astro-compatible content collections for Ruby on Rails.
|
|
4
4
|
|
|
5
|
+
https://github.com/user-attachments/assets/7bde3b4f-7bdb-49f9-9646-cd981846a451
|
|
6
|
+
|
|
5
7
|
[Documentation](https://www.andromedacms.dev/docs) · [Changelog](CHANGELOG.md)
|
|
6
8
|
|
|
7
9
|
Copy the `.md` and `.mdx` files from an [Astro](https://astro.build) project
|
data/lib/andromeda/assets.rb
CHANGED
|
@@ -72,6 +72,28 @@ module Andromeda
|
|
|
72
72
|
File.join("/assets", logical_path)
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
+
# Whether the asset pipeline can serve `logical_path`. `url_for` falls
|
|
76
|
+
# back to a plain /assets path for anything it cannot find, so without
|
|
77
|
+
# this check a typo only shows up as a 404 in production.
|
|
78
|
+
#
|
|
79
|
+
# @return [Boolean, nil] nil when there is no Propshaft load path to ask
|
|
80
|
+
# (no asset pipeline, or Sprockets), so callers can skip the check.
|
|
81
|
+
def exists?(logical_path)
|
|
82
|
+
load_path = pipeline_load_path
|
|
83
|
+
return nil if load_path.nil?
|
|
84
|
+
|
|
85
|
+
!load_path.find(logical_path).nil?
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def pipeline_load_path
|
|
89
|
+
return nil unless defined?(::Rails) && ::Rails.respond_to?(:application) && ::Rails.application
|
|
90
|
+
|
|
91
|
+
assets = ::Rails.application.assets
|
|
92
|
+
assets.respond_to?(:load_path) && assets.load_path.respond_to?(:find) ? assets.load_path : nil
|
|
93
|
+
rescue StandardError
|
|
94
|
+
nil
|
|
95
|
+
end
|
|
96
|
+
|
|
75
97
|
def logical_path(source, content_root:)
|
|
76
98
|
source = File.expand_path(source)
|
|
77
99
|
root = File.expand_path(content_root)
|
data/lib/andromeda/check.rb
CHANGED
|
@@ -15,18 +15,20 @@ module Andromeda
|
|
|
15
15
|
# @return [Array<String>] human-readable problems; empty when content is healthy.
|
|
16
16
|
def run(entry_classes = Andromeda::Pipeline.default_entry_classes)
|
|
17
17
|
problems = []
|
|
18
|
+
loaded = {}
|
|
18
19
|
|
|
19
20
|
entry_classes.each do |entry_class|
|
|
20
21
|
entries = load_entries(entry_class, problems)
|
|
21
22
|
next if entries.nil?
|
|
22
23
|
|
|
24
|
+
loaded[entry_class] = entries
|
|
23
25
|
entries.each do |entry|
|
|
24
26
|
problems.concat(frontmatter_style_problems(entry))
|
|
25
27
|
problems.concat(conversion_problems(entry))
|
|
26
28
|
end
|
|
27
29
|
end
|
|
28
30
|
|
|
29
|
-
problems
|
|
31
|
+
problems.concat(Andromeda::References.problems(loaded))
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
def load_entries(entry_class, problems)
|
data/lib/andromeda/entry.rb
CHANGED
|
@@ -58,7 +58,8 @@ module Andromeda
|
|
|
58
58
|
# stored `Andromeda::Reference` to the actual target entry (lazily,
|
|
59
59
|
# via the registry) rather than returning the pointer itself --
|
|
60
60
|
# `post.data[:author]` still holds the raw Reference for callers that
|
|
61
|
-
# want it.
|
|
61
|
+
# want it. An `:array` of `:reference` resolves each element the same
|
|
62
|
+
# way, so `post.tags` returns the tag entries.
|
|
62
63
|
#
|
|
63
64
|
# @see Andromeda::Schema#attribute for the full parameter list.
|
|
64
65
|
def attribute(name, type, **options)
|
|
@@ -67,6 +68,8 @@ module Andromeda
|
|
|
67
68
|
|
|
68
69
|
if type == :reference
|
|
69
70
|
define_method(attr_name) { resolve_reference(attr_name) }
|
|
71
|
+
elsif type == :array && options[:of] == :reference
|
|
72
|
+
define_method(attr_name) { resolve_references(attr_name) }
|
|
70
73
|
else
|
|
71
74
|
define_method(attr_name) { data[attr_name] }
|
|
72
75
|
end
|
|
@@ -230,9 +233,6 @@ module Andromeda
|
|
|
230
233
|
# @return [Hash] Symbol-keyed validated frontmatter (may also carry
|
|
231
234
|
# String keys for unrecognized frontmatter -- see Schema::Result).
|
|
232
235
|
attr_reader :data
|
|
233
|
-
# @return [String] raw Markdown/MDX body, frontmatter stripped but with
|
|
234
|
-
# original line numbers preserved (Andromeda::Frontmatter#parse).
|
|
235
|
-
attr_reader :body
|
|
236
236
|
# @return [String] absolute path to the source file.
|
|
237
237
|
attr_reader :file_path
|
|
238
238
|
# @return [String] SHA-256 of the whole source file, for cache keys.
|
|
@@ -262,6 +262,20 @@ module Andromeda
|
|
|
262
262
|
converted[:html]
|
|
263
263
|
end
|
|
264
264
|
|
|
265
|
+
# The raw Markdown/MDX body, frontmatter stripped but with original line
|
|
266
|
+
# numbers preserved (Andromeda::Frontmatter#parse). Entries loaded from
|
|
267
|
+
# source carry it already; in production they come from the index, which
|
|
268
|
+
# leaves bodies out, so it is read from the entry's built file the same
|
|
269
|
+
# way `html` is.
|
|
270
|
+
#
|
|
271
|
+
# @return [String, nil] nil only for a build made before bodies were
|
|
272
|
+
# stored (andromeda_cms < 0.1.2); rebuilding fixes it.
|
|
273
|
+
# @raise [Andromeda::BuildMissing] in production, if this entry has
|
|
274
|
+
# never been built.
|
|
275
|
+
def body
|
|
276
|
+
@body || converted[:body]
|
|
277
|
+
end
|
|
278
|
+
|
|
265
279
|
# @return [Array<Hash>] `{depth:, slug:, text:}` per heading, in
|
|
266
280
|
# document order (Andromeda::Renderer::Result#headings).
|
|
267
281
|
# @raise [Andromeda::BuildMissing] in production, if this entry has
|
|
@@ -302,5 +316,12 @@ module Andromeda
|
|
|
302
316
|
# referencing an entry never forces every other collection to load.
|
|
303
317
|
Andromeda.get_entry(reference.collection, reference.id)
|
|
304
318
|
end
|
|
319
|
+
|
|
320
|
+
# @param attr_name [Symbol] an `:array` attribute declared `of: :reference`.
|
|
321
|
+
# @return [Array<Andromeda::Entry>] in the order the frontmatter lists them.
|
|
322
|
+
# @raise [Andromeda::EntryNotFound] for the first id with no entry.
|
|
323
|
+
def resolve_references(attr_name)
|
|
324
|
+
Array(data[attr_name]).map { |reference| Andromeda.get_entry(reference.collection, reference.id) }
|
|
325
|
+
end
|
|
305
326
|
end
|
|
306
327
|
end
|
data/lib/andromeda/pipeline.rb
CHANGED
|
@@ -22,7 +22,11 @@ module Andromeda
|
|
|
22
22
|
# components, syntax errors) -- collected rather than raised
|
|
23
23
|
# individually, so a build reports everything in one pass (same
|
|
24
24
|
# principle as Andromeda::LoaderError).
|
|
25
|
-
|
|
25
|
+
#
|
|
26
|
+
# `entries` holds what was read from source (nil when the collection
|
|
27
|
+
# failed to load), so `.build_all` can check references across
|
|
28
|
+
# collections without reading every file a second time.
|
|
29
|
+
BuildResult = Struct.new(:collection, :converted, :errors, :entries, keyword_init: true) do
|
|
26
30
|
def success? = errors.empty?
|
|
27
31
|
end
|
|
28
32
|
|
|
@@ -49,7 +53,7 @@ module Andromeda
|
|
|
49
53
|
# `data`/`body`/`digest`/`file_path` all come straight from the
|
|
50
54
|
# source file, not from a previous build).
|
|
51
55
|
# @return [Hash] the stored payload (Symbol-keyed: `id`, `collection`,
|
|
52
|
-
# `data`, `html`, `headings`, `digest`, `file_path`).
|
|
56
|
+
# `data`, `html`, `headings`, `body`, `digest`, `file_path`).
|
|
53
57
|
# @raise [Andromeda::SyntaxError, Andromeda::ParserError,
|
|
54
58
|
# Andromeda::Renderer::MissingComponentError] on a bad file; callers
|
|
55
59
|
# that want every problem across a whole collection reported together
|
|
@@ -69,6 +73,10 @@ module Andromeda
|
|
|
69
73
|
data: publish_data_images(entry),
|
|
70
74
|
html: result.html,
|
|
71
75
|
headings: result.headings,
|
|
76
|
+
# Kept so `Entry#body` works in production, where entries come from
|
|
77
|
+
# the index and the source file is never read. The index itself
|
|
78
|
+
# leaves it out (Store#index_summary), so listings stay small.
|
|
79
|
+
body: entry.body,
|
|
72
80
|
digest: entry.digest,
|
|
73
81
|
render_key: render_key,
|
|
74
82
|
file_path: entry.file_path
|
|
@@ -190,7 +198,7 @@ module Andromeda
|
|
|
190
198
|
end
|
|
191
199
|
|
|
192
200
|
@store.replace_collection!(entry_class.collection_name, payloads)
|
|
193
|
-
BuildResult.new(collection: entry_class.collection_name, converted: payloads.size, errors: errors)
|
|
201
|
+
BuildResult.new(collection: entry_class.collection_name, converted: payloads.size, errors: errors, entries: entries)
|
|
194
202
|
end
|
|
195
203
|
|
|
196
204
|
# Converts every registered collection, reporting every problem found
|
|
@@ -205,10 +213,13 @@ module Andromeda
|
|
|
205
213
|
# `Andromeda::Store.new`'s own `Andromeda.config.build_path` default.
|
|
206
214
|
# @return [Array<BuildResult>] one per collection, on success.
|
|
207
215
|
# @raise [Andromeda::BuildError] listing every problem found, across
|
|
208
|
-
# every collection, if any entry failed to convert
|
|
216
|
+
# every collection, if any entry failed to convert or references an
|
|
217
|
+
# entry that does not exist.
|
|
209
218
|
def self.build_all(entry_classes = default_entry_classes, store: Andromeda::Store.new)
|
|
210
219
|
results = entry_classes.map { |entry_class| new(store: store).build_collection(entry_class) }
|
|
211
220
|
errors = results.flat_map(&:errors)
|
|
221
|
+
loaded = entry_classes.zip(results).filter_map { |entry_class, result| [entry_class, result.entries] if result.entries }
|
|
222
|
+
errors.concat(Andromeda::References.problems(loaded.to_h))
|
|
212
223
|
raise Andromeda::BuildError, errors unless errors.empty?
|
|
213
224
|
|
|
214
225
|
results
|
|
@@ -266,7 +277,7 @@ module Andromeda
|
|
|
266
277
|
content_root = File.dirname(entry.file_path)
|
|
267
278
|
base_dir = Andromeda::Registry[entry.collection]&.base_dir || content_root
|
|
268
279
|
|
|
269
|
-
lambda do |url,
|
|
280
|
+
lambda do |url, node|
|
|
270
281
|
# Absolute URLs point at something already being served -- a file in
|
|
271
282
|
# `public/`, another host, or an inline data URI -- so they are left
|
|
272
283
|
# exactly as the author wrote them.
|
|
@@ -278,10 +289,27 @@ module Andromeda
|
|
|
278
289
|
next Andromeda::Assets.marker_for(logical) if logical
|
|
279
290
|
end
|
|
280
291
|
|
|
281
|
-
#
|
|
292
|
+
# `./` and `../` can only mean "relative to this file", so falling
|
|
293
|
+
# back to the asset pipeline would just turn a typo into a silent 404.
|
|
294
|
+
# Containment is checked first so a crafted path never learns whether
|
|
295
|
+
# something outside the project exists.
|
|
296
|
+
start = (node && node[:position] || {})[:start] || {}
|
|
297
|
+
location = start[:line] ? "#{start[:line]}:#{start[:column]}: " : ""
|
|
298
|
+
if url.start_with?("./", "../")
|
|
299
|
+
inside = Andromeda::Assets.logical_path(source, content_root: base_dir)
|
|
300
|
+
reason = inside ? "does not exist" : "resolves outside the project"
|
|
301
|
+
raise Andromeda::Error, "#{location}image #{url.inspect} #{reason}"
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# A bare path is not a file next to the content: treat it as a logical asset path so
|
|
282
305
|
# images the application already ships (`app/assets/images/logo.png`,
|
|
283
306
|
# written as `logo.png`) resolve through the asset pipeline and get
|
|
284
|
-
# their digest, instead of 404ing in production.
|
|
307
|
+
# their digest, instead of 404ing in production. Without Propshaft
|
|
308
|
+
# there is nothing to ask, so the path is trusted as written.
|
|
309
|
+
if Andromeda::Assets.exists?(url) == false
|
|
310
|
+
raise Andromeda::Error, "#{location}image #{url.inspect} is not in the asset pipeline"
|
|
311
|
+
end
|
|
312
|
+
|
|
285
313
|
Andromeda::Assets.marker_for(url)
|
|
286
314
|
end
|
|
287
315
|
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "set"
|
|
4
|
+
|
|
5
|
+
module Andromeda
|
|
6
|
+
# Checks that every `:reference` attribute -- on its own or as the
|
|
7
|
+
# elements of an `:array` -- names an entry that actually exists.
|
|
8
|
+
#
|
|
9
|
+
# Entries resolve references lazily (Entry#resolve_reference), so without
|
|
10
|
+
# this a typo in an id only surfaces when a page asks for the target. It
|
|
11
|
+
# needs every target collection loaded, which is why only the whole-site
|
|
12
|
+
# build (Pipeline.build_all) and Andromeda::Check run it.
|
|
13
|
+
module References
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
# @param entries_by_class [Hash{Class => Array<Andromeda::Entry>}]
|
|
17
|
+
# entries already loaded, reused as reference targets. A target
|
|
18
|
+
# collection missing from here is loaded from source.
|
|
19
|
+
# @return [Array<String>] human-readable problems; empty when every
|
|
20
|
+
# reference resolves.
|
|
21
|
+
def problems(entries_by_class)
|
|
22
|
+
ids = Hash.new { |cache, name| cache[name] = ids_for(name, entries_by_class) }
|
|
23
|
+
|
|
24
|
+
entries_by_class.flat_map do |entry_class, entries|
|
|
25
|
+
attributes = reference_attributes(entry_class)
|
|
26
|
+
next [] if attributes.empty?
|
|
27
|
+
|
|
28
|
+
entries.flat_map do |entry|
|
|
29
|
+
attributes.flat_map do |attr|
|
|
30
|
+
references_in(entry.data[attr.name]).filter_map do |reference|
|
|
31
|
+
problem_for(reference, ids[reference.collection])&.then do |message|
|
|
32
|
+
"[#{entry_class.collection_name}] #{entry.file_path}: #{attr.name}: #{message}"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def reference_attributes(entry_class)
|
|
41
|
+
entry_class.schema.attributes.values.select do |attr|
|
|
42
|
+
attr.type == :reference || (attr.type == :array && attr.of == :reference)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# `Array(value)` would splat a single Reference (a Struct) into its
|
|
47
|
+
# fields, so the two shapes are told apart explicitly.
|
|
48
|
+
def references_in(value)
|
|
49
|
+
(value.is_a?(Array) ? value : [value]).grep(Andromeda::Reference)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def problem_for(reference, known)
|
|
53
|
+
return "unknown collection #{reference.collection.inspect}" if known == :unknown
|
|
54
|
+
# The target collection failed to load; that failure is reported on
|
|
55
|
+
# its own, and every reference into it would only repeat it.
|
|
56
|
+
return nil if known.nil?
|
|
57
|
+
return nil if known.include?(reference.id.to_s)
|
|
58
|
+
|
|
59
|
+
"no #{reference.collection.inspect} entry with id #{reference.id.to_s.inspect}"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def ids_for(name, entries_by_class)
|
|
63
|
+
entry_class = Andromeda::Registry[name]
|
|
64
|
+
return :unknown if entry_class.nil?
|
|
65
|
+
|
|
66
|
+
entries = entries_by_class.fetch(entry_class) { entry_class.source_entries }
|
|
67
|
+
entries.map(&:id).to_set
|
|
68
|
+
rescue Andromeda::LoaderError
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
data/lib/andromeda/schema.rb
CHANGED
|
@@ -108,6 +108,12 @@ module Andromeda
|
|
|
108
108
|
end
|
|
109
109
|
raise ArgumentError, "#{name}: :enum requires values:" if type == :enum && (values.nil? || values.empty?)
|
|
110
110
|
raise ArgumentError, "#{name}: :reference requires collection:" if type == :reference && collection.nil?
|
|
111
|
+
if type == :array && of == :reference && collection.nil?
|
|
112
|
+
raise ArgumentError, "#{name}: :array of :reference requires collection:"
|
|
113
|
+
end
|
|
114
|
+
if type == :array && of == :enum && (values.nil? || values.empty?)
|
|
115
|
+
raise ArgumentError, "#{name}: :array of :enum requires values:"
|
|
116
|
+
end
|
|
111
117
|
if type == :array && of && !TYPES.include?(of)
|
|
112
118
|
raise ArgumentError, "#{name}: unknown element type #{of.inspect} for of:"
|
|
113
119
|
end
|
|
@@ -291,7 +297,9 @@ module Andromeda
|
|
|
291
297
|
return [nil, "#{value.inspect} is not an array"] unless value.is_a?(Array)
|
|
292
298
|
return [value, nil] unless attr.of
|
|
293
299
|
|
|
294
|
-
|
|
300
|
+
# `values:` and `collection:` describe the elements, not the array, so
|
|
301
|
+
# they have to travel with the element type.
|
|
302
|
+
element_attr = Attribute.new(name: attr.name, type: attr.of, values: attr.values, collection: attr.collection)
|
|
295
303
|
errors = []
|
|
296
304
|
elements = value.each_with_index.map do |element, index|
|
|
297
305
|
coerced, error = coerce(element_attr, element, entry_path: entry_path, content_root: content_root)
|
data/lib/andromeda/version.rb
CHANGED
data/lib/andromeda_cms.rb
CHANGED
|
@@ -19,6 +19,7 @@ require_relative "andromeda/loader"
|
|
|
19
19
|
require_relative "andromeda/entry"
|
|
20
20
|
require_relative "andromeda/store"
|
|
21
21
|
require_relative "andromeda/pipeline"
|
|
22
|
+
require_relative "andromeda/references"
|
|
22
23
|
|
|
23
24
|
module Andromeda
|
|
24
25
|
# The native extension is built per Ruby minor version, so prefer the
|
|
@@ -70,7 +70,11 @@ module Andromeda
|
|
|
70
70
|
return
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
# Without this, a file whose last line has no newline gets the first
|
|
74
|
+
# ignore line glued onto it, breaking both entries.
|
|
75
|
+
content = File.read(path)
|
|
76
|
+
separator = content.empty? || content.end_with?("\n") ? "" : "\n"
|
|
77
|
+
append_to_file filename, "#{separator}#{missing.join("\n")}\n"
|
|
74
78
|
end
|
|
75
79
|
end
|
|
76
80
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: andromeda_cms
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- LIMHAUS Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: railties
|
|
@@ -98,6 +98,7 @@ files:
|
|
|
98
98
|
- lib/andromeda/parser.rb
|
|
99
99
|
- lib/andromeda/pipeline.rb
|
|
100
100
|
- lib/andromeda/railtie.rb
|
|
101
|
+
- lib/andromeda/references.rb
|
|
101
102
|
- lib/andromeda/registry.rb
|
|
102
103
|
- lib/andromeda/relation.rb
|
|
103
104
|
- lib/andromeda/renderer.rb
|