idml 0.10.12 → 0.10.13
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/TODO.pdf/151-schema-conformance.md +48 -0
- data/lib/idml/elements/inset_spacing.rb +31 -0
- data/lib/idml/elements/properties.rb +2 -0
- data/lib/idml/elements/text_frame_preference.rb +4 -9
- data/lib/idml/elements.rb +1 -0
- data/lib/idml/render/renderers/text_frame_renderer.rb +25 -5
- data/lib/idml/schema/rnc.rb +88 -0
- data/lib/idml/schema.rb +12 -0
- data/lib/idml/version.rb +1 -1
- data/lib/idml.rb +1 -0
- data/scripts/rnc_to_lutaml.rb +13 -57
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2f2a7b73c56645a87269780fc0cab9f998f5a6bf0d167b0ce9433dba9a8019cd
|
|
4
|
+
data.tar.gz: e4bb1522273937a4c2cf5631de1927f4583f63d16f2b351f893921407d89dc88
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 83756750d549a02ff7080686509ac45acce77405db6c9d3ba0ee6dae3643622b8eb89198d28fead77047dac50bdcf9491bdab05b7e03d02e18560f1021fa5360
|
|
7
|
+
data.tar.gz: 8a9fc59030029b4342019b205f9fe7da46ae6296729d641c49c199391cd5765ffea195dfca6cde46ff0df6518f496dcf9a1b66dc5dad0b808503230be8057107
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# TODO PDF 151: Schema conformance for the Elements layer
|
|
2
|
+
|
|
3
|
+
## Status: COMPLETE — implemented 2026-08-31
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
Architecture review round four: 147 element classes held hundreds
|
|
8
|
+
of wire attributes transcribed from the RNC, but only 11 classes
|
|
9
|
+
had attribute-set specs — the project's own drift defense
|
|
10
|
+
(CLAUDE.md convention 5) covered a tenth of the surface. Any
|
|
11
|
+
hand-edit that added, dropped, or misspelled a `map_attribute`
|
|
12
|
+
passed every test.
|
|
13
|
+
|
|
14
|
+
## Solution
|
|
15
|
+
|
|
16
|
+
- **`Idml::Schema::Rnc`** (`schema/rnc.rb`): the RNC parsing
|
|
17
|
+
extracted from the generator script into a lib adapter
|
|
18
|
+
(`element_attribute_map`, `element_definition`). Two consumers
|
|
19
|
+
over one seam — `scripts/rnc_to_lutaml.rb` (now presentation
|
|
20
|
+
only) and the conformance spec.
|
|
21
|
+
- **Schema-conformance spec** (`elements_schema_conformance_spec.rb`):
|
|
22
|
+
for every Elements class — no wire attribute outside the RNC
|
|
23
|
+
universe (catches typos and inventions), and every mapped
|
|
24
|
+
destination is a declared attribute (mapping/declaration
|
|
25
|
+
consistency). Legacy non-schema classes (TableCell) carry an
|
|
26
|
+
explicit allow-list. Full equality is documented as
|
|
27
|
+
unenforceable (deliberate subsets; typedef-composed attributes).
|
|
28
|
+
|
|
29
|
+
**Bug found by the probe and fixed**: `TextFramePreference`
|
|
30
|
+
carried four invented attributes (`InsetTop/Left/Bottom/Right`)
|
|
31
|
+
that appear in no schema, no spec, and no real file — while the
|
|
32
|
+
schema-faithful inset carrier (`Properties > InsetSpacing`, spec
|
|
33
|
+
examples 31/32) was unmodeled, so real documents' text frame
|
|
34
|
+
insets were silently ignored. New `Elements::InsetSpacing`
|
|
35
|
+
(single unit → all sides; list → [top, right, bottom, left]),
|
|
36
|
+
wired into `layout_frame`; the invented attributes removed.
|
|
37
|
+
|
|
38
|
+
## Files
|
|
39
|
+
|
|
40
|
+
- `lib/idml/schema.rb`, `lib/idml/schema/rnc.rb` (new)
|
|
41
|
+
- `scripts/rnc_to_lutaml.rb`
|
|
42
|
+
- `lib/idml/elements/inset_spacing.rb` (new)
|
|
43
|
+
- `lib/idml/elements/text_frame_preference.rb`,
|
|
44
|
+
`lib/idml/elements/properties.rb`, `lib/idml/elements.rb`
|
|
45
|
+
- `lib/idml/render/renderers/text_frame_renderer.rb`,
|
|
46
|
+
`lib/idml.rb`
|
|
47
|
+
- `spec/idml/elements_schema_conformance_spec.rb` (new)
|
|
48
|
+
- `spec/idml/elements/inset_spacing_spec.rb` (new)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Idml
|
|
4
|
+
module Elements
|
|
5
|
+
# `<InsetSpacing>` inside TextFramePreference's Properties —
|
|
6
|
+
# the schema-faithful carrier of text frame insets (the
|
|
7
|
+
# spec's examples 31/32): a single `type="unit"` value applies
|
|
8
|
+
# to all sides; a `type="list"` of ListItems carries
|
|
9
|
+
# [top, right, bottom, left].
|
|
10
|
+
class InsetSpacing < Lutaml::Model::Serializable
|
|
11
|
+
attribute :type, :string
|
|
12
|
+
attribute :value, :string
|
|
13
|
+
attribute :list_item, TypedValue, collection: true
|
|
14
|
+
|
|
15
|
+
xml do
|
|
16
|
+
root "InsetSpacing"
|
|
17
|
+
map_attribute "type", to: :type
|
|
18
|
+
map_content to: :value
|
|
19
|
+
map_element "ListItem", to: :list_item
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# [top, right, bottom, left] insets; nil components when the
|
|
23
|
+
# document doesn't declare them.
|
|
24
|
+
def sides
|
|
25
|
+
return Array.new(4, value&.to_f) if list_item.empty?
|
|
26
|
+
|
|
27
|
+
(0...4).map { |i| list_item[i]&.value&.to_f }
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -18,6 +18,7 @@ module Idml
|
|
|
18
18
|
attribute :paragraph_border_color, Idml::Elements::TypedValue
|
|
19
19
|
attribute :text_wrap_offset, Idml::Elements::TypedValue
|
|
20
20
|
attribute :paragraph_border_gap_color, Idml::Elements::TypedValue
|
|
21
|
+
attribute :inset_spacing, Idml::Elements::InsetSpacing
|
|
21
22
|
|
|
22
23
|
xml do
|
|
23
24
|
root "Properties"
|
|
@@ -29,6 +30,7 @@ module Idml
|
|
|
29
30
|
map_element "ParagraphBorderColor", to: :paragraph_border_color
|
|
30
31
|
map_element "TextWrapOffset", to: :text_wrap_offset
|
|
31
32
|
map_element "ParagraphBorderGapColor", to: :paragraph_border_gap_color
|
|
33
|
+
map_element "InsetSpacing", to: :inset_spacing
|
|
32
34
|
end
|
|
33
35
|
|
|
34
36
|
def first_geometry
|
|
@@ -5,12 +5,10 @@ module Idml
|
|
|
5
5
|
# Typed model of `<TextFramePreference>`. Every
|
|
6
6
|
# attribute from `TextFramePreference_Object` in
|
|
7
7
|
# `reference-docs/schemas/package/Resources/Styles.rnc` is declared (33 attributes),
|
|
8
|
-
# generated by `scripts/rnc_to_lutaml.rb`.
|
|
8
|
+
# generated by `scripts/rnc_to_lutaml.rb`. Insets live in the
|
|
9
|
+
# Properties > InsetSpacing child (spec examples 31/32).
|
|
9
10
|
class TextFramePreference < Lutaml::Model::Serializable
|
|
10
|
-
attribute :
|
|
11
|
-
attribute :inset_left, :float
|
|
12
|
-
attribute :inset_bottom, :float
|
|
13
|
-
attribute :inset_right, :float
|
|
11
|
+
attribute :properties, Idml::Elements::Properties, collection: true
|
|
14
12
|
attribute :footnotes_enable_overrides, :boolean
|
|
15
13
|
attribute :footnotes_span_across_columns, :boolean
|
|
16
14
|
attribute :footnotes_minimum_spacing, :float
|
|
@@ -47,10 +45,7 @@ module Idml
|
|
|
47
45
|
|
|
48
46
|
xml do
|
|
49
47
|
root "TextFramePreference"
|
|
50
|
-
|
|
51
|
-
map_attribute "InsetLeft", to: :inset_left
|
|
52
|
-
map_attribute "InsetBottom", to: :inset_bottom
|
|
53
|
-
map_attribute "InsetRight", to: :inset_right
|
|
48
|
+
map_element "Properties", to: :properties
|
|
54
49
|
map_attribute "FootnotesEnableOverrides", to: :footnotes_enable_overrides
|
|
55
50
|
map_attribute "FootnotesSpanAcrossColumns", to: :footnotes_span_across_columns
|
|
56
51
|
map_attribute "FootnotesMinimumSpacing", to: :footnotes_minimum_spacing
|
data/lib/idml/elements.rb
CHANGED
|
@@ -90,6 +90,7 @@ module Idml
|
|
|
90
90
|
autoload :MasterSpreadObject, "idml/elements/master_spread_object"
|
|
91
91
|
autoload :MixedInk, "idml/elements/mixed_ink"
|
|
92
92
|
autoload :MixedInkGroup, "idml/elements/mixed_ink_group"
|
|
93
|
+
autoload :InsetSpacing, "idml/elements/inset_spacing"
|
|
93
94
|
autoload :MojikumiTable, "idml/elements/mojikumi_table"
|
|
94
95
|
autoload :MojikumiTableProperties, "idml/elements/mojikumi_table"
|
|
95
96
|
autoload :OverrideMojikumiAki, "idml/elements/mojikumi_table"
|
|
@@ -244,20 +244,40 @@ module Idml
|
|
|
244
244
|
# back to 0 when the preference is absent or doesn't declare
|
|
245
245
|
# them.
|
|
246
246
|
def self.layout_frame(frame_item, box)
|
|
247
|
-
|
|
247
|
+
top, right, bottom, left = frame_insets(
|
|
248
|
+
frame_item.text_frame_preference&.first,
|
|
249
|
+
)
|
|
248
250
|
TextEngine::Frame.new(
|
|
249
251
|
x: box[:x],
|
|
250
252
|
y: box[:y],
|
|
251
253
|
width: box[:width],
|
|
252
254
|
height: box[:height],
|
|
253
|
-
inset_top:
|
|
254
|
-
inset_bottom:
|
|
255
|
-
inset_left:
|
|
256
|
-
inset_right:
|
|
255
|
+
inset_top: top,
|
|
256
|
+
inset_bottom: bottom,
|
|
257
|
+
inset_left: left,
|
|
258
|
+
inset_right: right,
|
|
257
259
|
)
|
|
258
260
|
end
|
|
259
261
|
private_class_method :layout_frame
|
|
260
262
|
|
|
263
|
+
# Insets from Properties > InsetSpacing (spec examples
|
|
264
|
+
# 31/32): one unit value applies to all sides; a list
|
|
265
|
+
# carries [top, right, bottom, left]. Missing sides are 0.
|
|
266
|
+
def self.frame_insets(pref)
|
|
267
|
+
props = pref&.properties
|
|
268
|
+
spacing = props.first&.inset_spacing if props
|
|
269
|
+
return Array.new(4, 0.0) unless spacing
|
|
270
|
+
|
|
271
|
+
side_or_zero(spacing)
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def self.side_or_zero(spacing)
|
|
275
|
+
[0, 1, 2, 3].map do |index|
|
|
276
|
+
spacing.sides[index] || 0.0
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
private_class_method :frame_insets
|
|
280
|
+
|
|
261
281
|
# Walks the chain state's paragraphs/runs and emits one
|
|
262
282
|
# `canvas.text` per line via the Shaper → LineBreaker →
|
|
263
283
|
# Justifier → VerticalLayout pipeline. Cursor y descends
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Idml
|
|
4
|
+
module Schema
|
|
5
|
+
# Parses RelaxNG Compact element definitions into data:
|
|
6
|
+
# element name → wire attribute names. Handles the Adobe
|
|
7
|
+
# package schemas' shape (`NAME_Object = element Name { ... }`
|
|
8
|
+
# with balanced braces; attributes as `attribute X { type }`).
|
|
9
|
+
# Two consumers over this seam: the class generator script and
|
|
10
|
+
# the schema-conformance spec.
|
|
11
|
+
module Rnc
|
|
12
|
+
ELEMENT_DEF = /(\w+)\s*+=\s*+element\s*+([\w:]+)\s*+\{/
|
|
13
|
+
ATTRIBUTE_DEF = /attribute\s++(\w+)\s*+\{([^}]*)\}/
|
|
14
|
+
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
# { "Story" => [["Self", ...]], ... } for every element
|
|
18
|
+
# definition across the given RNC files. An element defined
|
|
19
|
+
# in several files keeps each definition as an alternative
|
|
20
|
+
# (array of attribute-name arrays) — a class conforms when
|
|
21
|
+
# its wire attributes equal ANY one alternative.
|
|
22
|
+
def element_attribute_map(paths)
|
|
23
|
+
definitions = Hash.new { |h, k| h[k] = [] }
|
|
24
|
+
each_element(paths) do |element_name, body|
|
|
25
|
+
definitions[element_name] << body_attributes(body)
|
|
26
|
+
end
|
|
27
|
+
definitions.to_h
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# [xml_element_name, attrs_with_types] for one named
|
|
31
|
+
# definition (`Story_Object`) in one file; nil when absent.
|
|
32
|
+
# attrs_with_types: [["Self", "xsd:string"], ...].
|
|
33
|
+
def element_definition(path, definition_name)
|
|
34
|
+
src = File.read(path)
|
|
35
|
+
prefix = /#{Regexp.escape(definition_name)}\s*=\s*element\s+/
|
|
36
|
+
pattern = /#{prefix}([\w:]+)\s*\{/
|
|
37
|
+
match = src.match(pattern)
|
|
38
|
+
return nil unless match
|
|
39
|
+
|
|
40
|
+
body = balanced_body(src, match.end(0))
|
|
41
|
+
return nil unless body
|
|
42
|
+
|
|
43
|
+
attrs_with_types = body.scan(ATTRIBUTE_DEF)
|
|
44
|
+
.map { |name, type| [name, type.strip] }
|
|
45
|
+
[match[1], attrs_with_types]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def body_attributes(body)
|
|
49
|
+
body.scan(ATTRIBUTE_DEF).map(&:first).uniq
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def each_element(paths, &block)
|
|
53
|
+
paths.each do |path|
|
|
54
|
+
scan_file(path, &block)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def scan_file(path)
|
|
59
|
+
src = File.read(path)
|
|
60
|
+
src.scan(ELEMENT_DEF) do
|
|
61
|
+
match = Regexp.last_match
|
|
62
|
+
body = balanced_body(src, match.end(0))
|
|
63
|
+
next unless body
|
|
64
|
+
|
|
65
|
+
element_name = match[2].sub(/^idPkg:/, "")
|
|
66
|
+
yield(element_name, body)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# The balanced-brace body starting just after `from` (which
|
|
71
|
+
# points past the opening brace); nil when unterminated.
|
|
72
|
+
def balanced_body(src, from)
|
|
73
|
+
depth = 1
|
|
74
|
+
i = from
|
|
75
|
+
while i < src.length && depth.positive?
|
|
76
|
+
case src[i]
|
|
77
|
+
when "{" then depth += 1
|
|
78
|
+
when "}" then depth -= 1
|
|
79
|
+
end
|
|
80
|
+
i += 1
|
|
81
|
+
end
|
|
82
|
+
return nil if depth.positive?
|
|
83
|
+
|
|
84
|
+
src[from...(i - 1)]
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
data/lib/idml/schema.rb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Idml
|
|
4
|
+
# Namespace for adapters over the committed RelaxNG Compact
|
|
5
|
+
# schemas (`reference-docs/schemas/`). The RNC files are the
|
|
6
|
+
# authoritative interface of the Elements layer — this namespace
|
|
7
|
+
# turns them into data for the generator script and the
|
|
8
|
+
# conformance spec (two consumers, one seam).
|
|
9
|
+
module Schema
|
|
10
|
+
autoload :Rnc, "#{__dir__}/schema/rnc"
|
|
11
|
+
end
|
|
12
|
+
end
|
data/lib/idml/version.rb
CHANGED
data/lib/idml.rb
CHANGED
|
@@ -18,6 +18,7 @@ module Idml
|
|
|
18
18
|
autoload :Validation, "#{__dir__}/idml/validation"
|
|
19
19
|
autoload :Composition, "#{__dir__}/idml/composition"
|
|
20
20
|
autoload :Geometry, "#{__dir__}/idml/geometry"
|
|
21
|
+
autoload :Schema, "#{__dir__}/idml/schema"
|
|
21
22
|
autoload :TextEngine, "#{__dir__}/idml/text_engine"
|
|
22
23
|
autoload :Render, "#{__dir__}/idml/render"
|
|
23
24
|
autoload :CLI, "#{__dir__}/idml/cli"
|
data/scripts/rnc_to_lutaml.rb
CHANGED
|
@@ -10,21 +10,11 @@
|
|
|
10
10
|
# Example:
|
|
11
11
|
# scripts/rnc_to_lutaml.rb reference-docs/schemas/package/Stories/Story.rnc Story_Object
|
|
12
12
|
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
# Name { Type }?` line, and prints Ruby code suitable for pasting
|
|
16
|
-
# into a Lutaml::Model::Serializable subclass.
|
|
17
|
-
#
|
|
18
|
-
# Generated output:
|
|
19
|
-
# attribute :self_attr, :string
|
|
20
|
-
# attribute :first_line_indent, :float
|
|
21
|
-
# # ... etc.
|
|
22
|
-
# xml do
|
|
23
|
-
# map_attribute "Self", to: :self_attr
|
|
24
|
-
# map_attribute "FirstLineIndent", to: :first_line_indent
|
|
25
|
-
# end
|
|
13
|
+
# RNC parsing lives in Idml::Schema::Rnc (shared with the
|
|
14
|
+
# schema-conformance spec); this script owns presentation only.
|
|
26
15
|
|
|
27
|
-
|
|
16
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
17
|
+
require "idml"
|
|
28
18
|
|
|
29
19
|
RESERVED_RUBY_NAMES = %w[self class integer float string end do begin ensure
|
|
30
20
|
rescue retry next return break yield nil true false].freeze
|
|
@@ -56,59 +46,25 @@ def ruby_attr_name(xml_name)
|
|
|
56
46
|
base
|
|
57
47
|
end
|
|
58
48
|
|
|
59
|
-
def extract_element(rnc_path, element_name)
|
|
60
|
-
src = File.read(rnc_path)
|
|
61
|
-
pattern = /#{Regexp.escape(element_name)}\s*=\s*element\s+([\w:]+)\s*\{/
|
|
62
|
-
match = src.match(pattern)
|
|
63
|
-
abort "#{element_name} not found in #{rnc_path}" unless match
|
|
64
|
-
|
|
65
|
-
xml_element_name = match[1]
|
|
66
|
-
start_pos = match.end(0)
|
|
67
|
-
|
|
68
|
-
# Walk the brace structure to find the matching close.
|
|
69
|
-
depth = 1
|
|
70
|
-
i = start_pos
|
|
71
|
-
while i < src.length && depth.positive?
|
|
72
|
-
case src[i]
|
|
73
|
-
when "{" then depth += 1
|
|
74
|
-
when "}" then depth -= 1
|
|
75
|
-
end
|
|
76
|
-
i += 1
|
|
77
|
-
end
|
|
78
|
-
body = src[start_pos...(i - 1)]
|
|
79
|
-
|
|
80
|
-
[xml_element_name, body]
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def extract_attributes(body)
|
|
84
|
-
attrs = []
|
|
85
|
-
body.scan(/^\s*attribute\s+(\w+)\s*\{\s*([^}]+)\}/) do |name, type|
|
|
86
|
-
attrs << [name, type.strip]
|
|
87
|
-
end
|
|
88
|
-
attrs
|
|
89
|
-
end
|
|
90
|
-
|
|
91
49
|
rnc_path, element_name = ARGV
|
|
92
50
|
abort "usage: #{$PROGRAM_NAME} <rnc-file> <ElementName>" unless rnc_path && element_name
|
|
93
51
|
|
|
94
|
-
xml_root,
|
|
95
|
-
|
|
52
|
+
xml_root, attrs = Idml::Schema::Rnc.element_definition(rnc_path, element_name)
|
|
53
|
+
abort "#{element_name} not found in #{rnc_path}" unless xml_root
|
|
96
54
|
|
|
97
55
|
puts "# xml root: <#{xml_root}>"
|
|
98
56
|
puts "# source: #{rnc_path} (#{element_name})"
|
|
99
57
|
puts "# #{attrs.length} attributes"
|
|
100
58
|
puts
|
|
101
|
-
puts "attribute :_placeholder_, :string # remove me"
|
|
102
|
-
puts
|
|
103
|
-
puts "xml do"
|
|
104
|
-
puts " root \"#{xml_root.sub(/^idPkg:/, '')}\""
|
|
105
|
-
attrs.each do |name, _type| # rubocop:disable Style/HashEachMethods
|
|
106
|
-
puts %( map_attribute "#{name}", to: :#{ruby_attr_name(name)}")
|
|
107
|
-
end
|
|
108
|
-
puts "end"
|
|
109
|
-
puts
|
|
110
59
|
puts "# attribute declarations:"
|
|
111
60
|
attrs.each do |name, type|
|
|
112
61
|
lutaml = lutaml_type(type.split(/\s/).first)
|
|
113
62
|
puts "attribute :#{ruby_attr_name(name)}, :#{lutaml}"
|
|
114
63
|
end
|
|
64
|
+
puts
|
|
65
|
+
puts "xml do"
|
|
66
|
+
puts %( root "#{xml_root.sub(/^idPkg:/, '')}")
|
|
67
|
+
attrs.each do |name, _type| # rubocop:disable Style/HashEachMethods
|
|
68
|
+
puts %( map_attribute "#{name}", to: :#{ruby_attr_name(name)})
|
|
69
|
+
end
|
|
70
|
+
puts "end"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: idml
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.10.
|
|
4
|
+
version: 0.10.13
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bigdecimal
|
|
@@ -215,6 +215,7 @@ files:
|
|
|
215
215
|
- TODO.pdf/149-architecture-round-two.md
|
|
216
216
|
- TODO.pdf/15-wire-spread-children.md
|
|
217
217
|
- TODO.pdf/150-architecture-round-three.md
|
|
218
|
+
- TODO.pdf/151-schema-conformance.md
|
|
218
219
|
- TODO.pdf/16-typed-model-pipeline.md
|
|
219
220
|
- TODO.pdf/17-shape-rendering.md
|
|
220
221
|
- TODO.pdf/18-text-rendering.md
|
|
@@ -352,6 +353,7 @@ files:
|
|
|
352
353
|
- lib/idml/elements/ink.rb
|
|
353
354
|
- lib/idml/elements/inner_glow_setting.rb
|
|
354
355
|
- lib/idml/elements/inner_shadow_setting.rb
|
|
356
|
+
- lib/idml/elements/inset_spacing.rb
|
|
355
357
|
- lib/idml/elements/layer.rb
|
|
356
358
|
- lib/idml/elements/link.rb
|
|
357
359
|
- lib/idml/elements/master_spread_object.rb
|
|
@@ -527,6 +529,8 @@ files:
|
|
|
527
529
|
- lib/idml/render/style_resolver.rb
|
|
528
530
|
- lib/idml/render/text_wrap_resolver.rb
|
|
529
531
|
- lib/idml/render/wrap_contour.rb
|
|
532
|
+
- lib/idml/schema.rb
|
|
533
|
+
- lib/idml/schema/rnc.rb
|
|
530
534
|
- lib/idml/text_engine.rb
|
|
531
535
|
- lib/idml/text_engine/cjk_layout.rb
|
|
532
536
|
- lib/idml/text_engine/justifier.rb
|