Module: Dms

Defined in:
lib/dms/parser.rb,
lib/dms.rb,
lib/dms/tier1.rb,
lib/dms/types.rb,
lib/dms/emitter.rb

Overview

DMS parser - port of the Python/Rust reference, optimized for Ruby.

Hand-written recursive-descent + stateful lexer. Errors carry (line, column, message). Tables are insertion-ordered Hashes.

Hot-path strategy: positions are byte offsets into a UTF-8 source. Inline scanners use String#getbyte (returns Integer or nil) which is allocation-free, vs. String#[] which copies a 1-char String per call. DMS structural characters (‘:’, ‘+’, ‘-’, ‘n’, digits, ASCII keys) are all ASCII, so byte-level checks are exact for the common cases. Multi-byte content only matters in string bodies (handled via byteslice + force_encoding) and for non-ASCII bare-key chars (label- class check has a UTF-8 multi-byte fallback).

Defined Under Namespace

Modules: Tier1 Classes: AttachedComment, Comment, DecodeError, Document, Emitter, EncodeError, HeredocModifierCall, LocalDate, LocalDateTime, LocalTime, OffsetDateTime, OriginalLiteral, Parser, StringForm, UnorderedHash

Constant Summary collapse

VERSION =
"0.3.0"
SUPPORTS_LITE_MODE =

Capability flag — this port ships lite-mode decode + lite-mode encode_lite. See SPEC §Decoding modes — full and lite.

true
SUPPORTS_IGNORE_ORDER =

Capability flag — this port ships unordered-table decode mode. See SPEC §Unordered tables.

true
ParseError =

Deprecated alias. Use ‘Dms::DecodeError`. Referencing this constant emits a one-shot warning via `deprecate_constant`.

DecodeError
INDENT_STR =
"  "

Class Method Summary collapse

Class Method Details

._contains_unordered_table?(v) ⇒ Boolean

Recursive walk: returns true iff ‘v` (or any descendant) is an `UnorderedHash`. Used by `encode` to enforce the SPEC contract that full-mode round-trip refuses unordered documents.

Returns:

  • (Boolean)


30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/dms/emitter.rb', line 30

def self._contains_unordered_table?(v)
  case v
  when UnorderedHash
    true
  when Hash
    v.each_value { |vv| return true if _contains_unordered_table?(vv) }
    false
  when Array
    v.each { |vv| return true if _contains_unordered_table?(vv) }
    false
  else
    false
  end
end

._warn_deprecated(old, new_name) ⇒ Object



113
114
115
116
117
118
119
# File 'lib/dms.rb', line 113

def self._warn_deprecated(old, new_name)
  return if @_deprecation_warned[old]
  @_deprecation_warned[old] = true
  warn "[DEPRECATION] `Dms.#{old}` is deprecated and will be removed " \
       "in the next release. Use `Dms.#{new_name}` instead.",
       uplevel: 2
end

.decode(src) ⇒ Object

Decode a DMS source string and return the body value tree.



37
38
39
# File 'lib/dms.rb', line 37

def self.decode(src)
  Parser.parse_document(src).body
end

.decode_document(src) ⇒ Object

Decode a DMS source string and return the full Document (body, meta, comments, original_forms).



43
44
45
# File 'lib/dms.rb', line 43

def self.decode_document(src)
  Parser.parse_document(src)
end

.decode_document_unordered(src) ⇒ Object

Unordered full-mode decode (SPEC §“Unordered tables”). Body tables are built as ‘Dms::UnorderedHash` (a Hash subclass) with keys shuffled at end-of-build so callers cannot rely on insertion order. Front matter remains insertion-ordered.

‘Dms.encode` (full-mode round-trip) refuses Documents containing unordered tables — use `Dms.encode_lite` for canonical emit.



64
65
66
# File 'lib/dms.rb', line 64

def self.decode_document_unordered(src)
  Parser.parse_document_unordered(src)
end

.decode_front_matter(src) ⇒ Object

Front-matter-only decode (SPEC §Front-matter-only decode). Scans leading trivia + ‘+++` + contents + `+++` and stops; the body is not tokenized. Returns the front-matter Hash (empty when the FM block is empty), or nil when the document has no FM at all. In-FM diagnostics are byte-identical to a full decode and raise `Dms::DecodeError`. Required at tier 0 — there is no capability flag for this entry point.



82
83
84
# File 'lib/dms.rb', line 82

def self.decode_front_matter(src)
  Parser.parse_front_matter_only(src)
end

.decode_lite(src) ⇒ Object

Lite-mode decode: same data tree, no comment AST, no original_forms. Not suitable for ‘encode` round-trip. SPEC §Decoding modes — full and lite.



49
50
51
# File 'lib/dms.rb', line 49

def self.decode_lite(src)
  Parser.parse_lite_document(src).body
end

.decode_lite_document(src) ⇒ Object



53
54
55
# File 'lib/dms.rb', line 53

def self.decode_lite_document(src)
  Parser.parse_lite_document(src)
end

.decode_lite_document_unordered(src) ⇒ Object

Unordered lite-mode decode. The fastest read-only path: no comment AST, no original_forms, body tables built as ‘Dms::UnorderedHash` with shuffled key order. SPEC §“Unordered tables”.



71
72
73
# File 'lib/dms.rb', line 71

def self.decode_lite_document_unordered(src)
  Parser.parse_lite_document_unordered(src)
end

.encode(doc) ⇒ Object

Encode a parsed Document back to DMS source (SPEC §encode). Refuses Documents containing ‘Dms::UnorderedHash` — use `encode_lite` for canonical emit of unordered Documents.



89
90
91
# File 'lib/dms.rb', line 89

def self.encode(doc)
  Emitter._encode_full(doc)
end

.encode_lite(doc) ⇒ Object

Canonical-form emit. Drops comments and original_forms. Accepts both full-mode and lite-mode Documents. SPEC §encode.



95
96
97
# File 'lib/dms.rb', line 95

def self.encode_lite(doc)
  Emitter._encode_lite(doc)
end

.parse(src) ⇒ Object



121
122
123
124
# File 'lib/dms.rb', line 121

def self.parse(src)
  _warn_deprecated(:parse, :decode)
  decode(src)
end

.parse_document(src) ⇒ Object



126
127
128
129
# File 'lib/dms.rb', line 126

def self.parse_document(src)
  _warn_deprecated(:parse_document, :decode_document)
  decode_document(src)
end

.parse_document_unordered(src) ⇒ Object



141
142
143
144
# File 'lib/dms.rb', line 141

def self.parse_document_unordered(src)
  _warn_deprecated(:parse_document_unordered, :decode_document_unordered)
  decode_document_unordered(src)
end

.parse_lite(src) ⇒ Object



131
132
133
134
# File 'lib/dms.rb', line 131

def self.parse_lite(src)
  _warn_deprecated(:parse_lite, :decode_lite)
  decode_lite(src)
end

.parse_lite_document(src) ⇒ Object



136
137
138
139
# File 'lib/dms.rb', line 136

def self.parse_lite_document(src)
  _warn_deprecated(:parse_lite_document, :decode_lite_document)
  decode_lite_document(src)
end

.parse_lite_document_unordered(src) ⇒ Object



146
147
148
149
150
# File 'lib/dms.rb', line 146

def self.parse_lite_document_unordered(src)
  _warn_deprecated(:parse_lite_document_unordered,
                   :decode_lite_document_unordered)
  decode_lite_document_unordered(src)
end

.supports_ignore_orderObject

Capability flag (SPEC §“Unordered tables”). True iff this port ships ‘decode_document_unordered` / `decode_lite_document_unordered` with spec-correct semantics. Callers probe before opting in.



102
103
104
# File 'lib/dms.rb', line 102

def self.supports_ignore_order
  true
end

.to_dms(doc) ⇒ Object



152
153
154
155
# File 'lib/dms.rb', line 152

def self.to_dms(doc)
  _warn_deprecated(:to_dms, :encode)
  encode(doc)
end

.to_dms_lite(doc) ⇒ Object



157
158
159
160
# File 'lib/dms.rb', line 157

def self.to_dms_lite(doc)
  _warn_deprecated(:to_dms_lite, :encode_lite)
  encode_lite(doc)
end