interscript 3.3.0 → 3.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f7222468ba9bbd27444aea9c8fe0f7e3378b053a500d9f03c925a4c2a39cc9f1
4
- data.tar.gz: b6c1e37c348f2bb42d4358ca83fa332f83a29b41b9ff88241a1e171b20c4225c
3
+ metadata.gz: c07cde4f6168fc8fefa3ea522ffa3ecf809801492861a18fc6456deb0baa36bb
4
+ data.tar.gz: 9cea9f897db3900314f2c41209d75e19c6a91aae513d2ae4b7c74a5cdd10ccdf
5
5
  SHA512:
6
- metadata.gz: a0cf0d2d1f75e3dd9b30b2282eae24b58572c002ae5fde9cac4b26debe7bb457f97b83193c965a8936e92f8c9e673c5fad36c051804accd3f0fd708679b60efe
7
- data.tar.gz: bcb8654fb9af857a41e469d284c825d07ada2c62c9c21732c7d510b07a3186afcd7bdc37a631048d98bd30e967f768c359020189e8d5cb974f56fff5781e8775
6
+ metadata.gz: 9fe0d7425cc3890e0e70ca12c2482b98280b27c7d3700b1092c9c3f78db24fd1984da7f8d18d41934f267f25181c8b12a10831c3c6f0c74e35785bae6481a20a
7
+ data.tar.gz: f4302ba9d6722cb9f96e2e766b08a09e0b02cb5387da7aab5f06b6fb4ac6cd3670f92828d20c7bbf033abb43f1fd7a477bdf44f236ab1e7a5dd6a4e50289fa10
data/README.md CHANGED
@@ -33,6 +33,32 @@ Interscript.transliterate("odni-rus-Cyrl-Latn-2015", "привет")
33
33
  # => "privet"
34
34
  ----
35
35
 
36
+ == Workflow extension (ISC-WF-1)
37
+
38
+ Maps can reuse rule blocks and condition rows on a language. A
39
+ `ruleset` is spliced at a `use` position (recursively, across
40
+ declared dependencies); `use ... override { ... }` replaces rows on
41
+ byte-exact from-equality; a `languages` declaration plus `when`
42
+ guards let the caller select a language per call — guards are inert
43
+ without a selection:
44
+
45
+ [source,ruby]
46
+ ----
47
+ # alalc-tha and bgnpcgn-tha share their leading-vowel machinery
48
+ # through libs/thai-latn.isc — one ruleset, per-map overrides
49
+ Interscript.transliterate("bgnpcgn-tha-Thai-Latn-2002", "กรุงเทพ")
50
+
51
+ # language conditioning: select one of the map's declared languages;
52
+ # guards are inert when no (or an undeclared) language is passed
53
+ Interscript.transliterate("some-map-id", "...", {}, language: "kur")
54
+ ----
55
+
56
+ The constructs are additive: maps that don't use them transliterate
57
+ identically. The corpus adoption so far is the Thai leading-vowel
58
+ shared ruleset (W1/W2); W3 conditioning is exercised by the
59
+ conformance fixtures. Normative text: interscript/maps
60
+ `docs/isc-wf-1.md`.
61
+
36
62
  == Neural models (Interscript::ML)
37
63
 
38
64
  The gem embeds the IMF v1 model runtime — resolve a model id through
data/interscript.gemspec CHANGED
@@ -33,7 +33,7 @@ Gem::Specification.new do |spec|
33
33
  spec.require_paths = ["lib"]
34
34
 
35
35
  spec.add_dependency "thor"
36
- spec.add_dependency "interscript-maps", "~> 2.5"
36
+ spec.add_dependency "interscript-maps", "~> 3.0"
37
37
  spec.add_dependency "text"
38
38
  spec.add_dependency "parsanol", ">= 1.3.61", "< 2"
39
39
  end
@@ -5,7 +5,7 @@ class Interscript::Interpreter < Interscript::Compiler
5
5
  self
6
6
  end
7
7
 
8
- def call(str, stage = :main, each: false, &block)
8
+ def call(str, stage = :main, each: false, language: nil, &block)
9
9
  stage = @map.stages[stage]
10
10
  if each
11
11
  e = Enumerator.new do |yielder|
@@ -22,7 +22,7 @@ class Interscript::Interpreter < Interscript::Compiler
22
22
  # standard:disable Style/GlobalVars (deliberate $DEBUG / -d-flag debug idiom)
23
23
  $select_nth_string = true
24
24
  # standard:enable Style/GlobalVars
25
- result = Stage.new(@map, str).execute_rule(stage)
25
+ result = Stage.new(@map, str, language: language).execute_rule(stage)
26
26
  # standard:disable Style/GlobalVars (deliberate $DEBUG / -d-flag debug idiom)
27
27
  $select_nth_string = false
28
28
  # standard:enable Style/GlobalVars
@@ -68,20 +68,72 @@ class Interscript::Interpreter < Interscript::Compiler
68
68
  e
69
69
  end
70
70
  else
71
- Stage.new(@map, str).execute_rule(stage)
71
+ Stage.new(@map, str, language: language).execute_rule(stage)
72
72
  end
73
73
  end
74
74
 
75
+ # ISC-WF-1 W3: effective language for a run. A selection outside the
76
+ # map's `languages` declaration (or any selection on a map without a
77
+ # declaration) means every `when` guard is inert (spec §5.1).
78
+ def self.select_language(map, language)
79
+ return nil if language.nil?
80
+
81
+ declared = map.languages
82
+ return nil unless declared.is_a?(Interscript::Node::LanguagesDecl) &&
83
+ declared.include?(language.to_sym)
84
+
85
+ language.to_sym
86
+ end
87
+
75
88
  class Stage
76
- def initialize(map, str)
89
+ attr_reader :language
90
+
91
+ def initialize(map, str, language: nil)
77
92
  @str = str
78
93
  @map = map
94
+ @language = Interscript::Interpreter.select_language(map, language)
95
+ end
96
+
97
+ # ISC-WF-1 W3 guard applicability. Unguarded rules always apply; a
98
+ # guarded rule applies only under a selected language that its `when`
99
+ # list contains. Inert rules are absent from the pass (spec §5.1).
100
+ def guard_applies? rule
101
+ return true unless Interscript::Node::Rule::Sub === rule && rule.when_languages
102
+ return false unless @language
103
+
104
+ rule.when_languages.include?(@language)
105
+ end
106
+
107
+ # ISC-WF-1 W3: the effective rule set of a parallel pass = unguarded
108
+ # rules ∪ guard-applicable rules; where an unguarded rule and a
109
+ # guard-applicable rule share the same from-string, the
110
+ # guard-applicable rule wins (spec §5.2). Passes without any guard
111
+ # return the group untouched — zero change for pre-WF1 maps. Filtered
112
+ # variants are memoized per selected language on the group so the
113
+ # compiled-tree cache below stays per-language.
114
+ def resolve_parallel_guards r
115
+ return r unless r.children.any? { |c| Interscript::Node::Rule::Sub === c && c.when_languages }
116
+
117
+ r.wf1_variants ||= {}
118
+ r.wf1_variants[@language] ||= begin
119
+ applicable = r.children.select { |c| guard_applies?(c) }
120
+ guarded_froms = applicable
121
+ .select { |c| Interscript::Node::Rule::Sub === c && c.when_languages }
122
+ .map { |c| c.from.inspect }
123
+ filtered = Interscript::Node::Group::Parallel.new
124
+ filtered.children = applicable.reject do |c|
125
+ Interscript::Node::Rule::Sub === c && !c.when_languages &&
126
+ guarded_froms.include?(c.from.inspect)
127
+ end
128
+ filtered
129
+ end
79
130
  end
80
131
 
81
132
  def execute_rule r
82
133
  return if r.reverse_run == true
83
134
  case r
84
135
  when Interscript::Node::Group::Parallel
136
+ r = resolve_parallel_guards(r)
85
137
  if r.cached_tree
86
138
  @str = Interscript::Stdlib.parallel_replace_tree(@str, r.cached_tree)
87
139
  elsif r.subs_regexp && r.subs_replacements
@@ -135,9 +187,12 @@ class Interscript::Interpreter < Interscript::Compiler
135
187
  end
136
188
  when Interscript::Node::Group
137
189
  r.children.each do |t|
190
+ # ISC-WF-1 W3: in sequence, an inert guarded rule is skipped.
191
+ next unless guard_applies?(t)
138
192
  execute_rule(t)
139
193
  end
140
194
  when Interscript::Node::Rule::Sub
195
+ return @str unless guard_applies?(r)
141
196
  @str = if r.to == :upcase
142
197
  @str.gsub(Regexp.new(build_regexp(r)), &:upcase)
143
198
  elsif r.to == :downcase
@@ -151,10 +206,10 @@ class Interscript::Interpreter < Interscript::Compiler
151
206
  if r.stage.map
152
207
  doc = @map.dep_aliases[r.stage.map].document
153
208
  stage = doc.imported_stages[r.stage.name]
154
- @str = Stage.new(doc, @str).execute_rule(stage)
209
+ @str = Stage.new(doc, @str, language: @language).execute_rule(stage)
155
210
  else
156
211
  stage = @map.imported_stages[r.stage.name]
157
- @str = Stage.new(@map, @str).execute_rule(stage)
212
+ @str = Stage.new(@map, @str, language: @language).execute_rule(stage)
158
213
  end
159
214
  end
160
215
 
@@ -37,6 +37,8 @@ module Interscript
37
37
  tests_arr = []
38
38
  stages_arr = []
39
39
  dependencies_arr = []
40
+ rulesets_arr = []
41
+ languages_arr = []
40
42
 
41
43
  body.each do |item|
42
44
  if item[:metadata]
@@ -45,6 +47,12 @@ module Interscript
45
47
  aliases_arr.concat(extract_aliases(item[:aliases]))
46
48
  elsif item[:tests]
47
49
  tests_arr.concat(extract_tests(item[:tests]))
50
+ elsif item[:languages]
51
+ # ISC-WF-1 W3: map-declared languages.
52
+ languages_arr.concat(Array(item[:languages]).map { |l| ident(l) })
53
+ elsif item[:ruleset]
54
+ # ISC-WF-1 W1: named ruleset declaration.
55
+ rulesets_arr << extract_ruleset(item)
48
56
  elsif item[:stage]
49
57
  stages_arr << extract_stage(item)
50
58
  elsif item[:target]
@@ -52,7 +60,7 @@ module Interscript
52
60
  end
53
61
  end
54
62
 
55
- {
63
+ doc = {
56
64
  schemaVersion: SCHEMA_VERSION,
57
65
  filename: @filename,
58
66
  systemCode: code,
@@ -63,6 +71,11 @@ module Interscript
63
71
  stages: stages_arr,
64
72
  dependencies: dependencies_arr
65
73
  }
74
+ # ISC-WF-1 keys are present only when the map uses the constructs —
75
+ # documents of maps that don't keep their exact pre-WF1 shape.
76
+ doc[:languages] = languages_arr if languages_arr.any?
77
+ doc[:rulesets] = rulesets_arr if rulesets_arr.any?
78
+ doc
66
79
  end
67
80
 
68
81
  private
@@ -254,6 +267,15 @@ module Interscript
254
267
  {name: name, body: body}
255
268
  end
256
269
 
270
+ # ISC-WF-1 W1: a named ruleset declaration — same body shape as a
271
+ # stage, addressed by name through `use` expansion.
272
+ def extract_ruleset(item)
273
+ node = item[:ruleset]
274
+ name = ident(item[:ruleset_name])
275
+ body = Array(node).flat_map { |n| extract_stage_items(n) }
276
+ {name: name, body: body}
277
+ end
278
+
257
279
  def extract_stage_items(n)
258
280
  return [] unless n.is_a?(Hash)
259
281
  if n[:sequence]
@@ -279,6 +301,10 @@ module Interscript
279
301
  [{kind: :run, dependency: nil, stage: ident(n[:run_stage_only][:stage])}]
280
302
  elsif n[:bare_rule]
281
303
  [{kind: :bare_rule, rule: extract_rule(n[:bare_rule])}]
304
+ elsif n[:use]
305
+ # ISC-WF-1 W1/W2: `use <ident>` or `use <alias>.<ident>` with an
306
+ # optional override block.
307
+ [extract_use(n[:use])]
282
308
  elsif n[:comment]
283
309
  []
284
310
  elsif n[:noop]
@@ -288,6 +314,19 @@ module Interscript
288
314
  end
289
315
  end
290
316
 
317
+ # `use <name>` (same-map ruleset) or `use <dep>.<name>` (dependency-
318
+ # declared ruleset), plus the optional override rows (W2).
319
+ def extract_use(u)
320
+ dep = u[:qualified_name] ? ident(u[:use_alias]) : nil
321
+ name = ident(u[:qualified_name] || u[:use_alias])
322
+ item = {kind: :use, ruleset: name, dependency: dep}
323
+ overrides = Array(u[:use_overrides])
324
+ .select { |r| r.is_a?(Hash) && r.key?(:from) }
325
+ .map { |r| extract_rule(r) }
326
+ item[:overrides] = overrides if overrides.any?
327
+ item
328
+ end
329
+
291
330
  # Filter out noop rules (from: None, to: None) created by empty
292
331
  # parallel/sequence blocks that contain only comments or whitespace.
293
332
  def filter_noop(rules)
@@ -302,11 +341,17 @@ module Interscript
302
341
  from_val = r.is_a?(Hash) ? r[:from] : nil
303
342
  to_val = r.is_a?(Hash) ? r[:to] : nil
304
343
  constraints_val = r.is_a?(Hash) ? r[:constraints] : nil
305
- {
344
+ rule = {
306
345
  from: from_val ? materialize(from_val) : Items::None.new,
307
346
  to: to_val ? materialize(to_val) : Items::None.new,
308
347
  constraints: extract_constraints(constraints_val)
309
348
  }
349
+ # ISC-WF-1 W3: a `when` guard folds to the list of language names.
350
+ # The rule hash never goes through Transform as a whole (from/to/
351
+ # constraints are materialized individually), so the guard fragment
352
+ # gets its own apply.
353
+ rule[:when_languages] = @transform.apply(when: r[:when]) if r.is_a?(Hash) && r[:when]
354
+ rule
310
355
  end
311
356
 
312
357
  def extract_constraints(arr)
@@ -125,7 +125,14 @@ module Interscript
125
125
  str("line_end") | str("word_boundary") |
126
126
  str("downcase") | str("upcase") | str("title_case") |
127
127
  str("capture") | str("maybe") | str("some") | str("ref") |
128
- str("any_character")
128
+ str("any_character") |
129
+ # ISC-WF-1: ruleset / use / override / languages / when join
130
+ # the keyword table (spec §2). Prefix matching follows the
131
+ # existing table behavior; quoted-string forms remain the
132
+ # pass-through escape hatch. Verified against the 404-map
133
+ # corpus: no bare identifier starts with any of these words.
134
+ str("ruleset") | str("use") | str("override") |
135
+ str("languages") | str("when")
129
136
  end
130
137
 
131
138
  # Concatenation: one or more atoms. The continuation pattern
@@ -17,11 +17,44 @@ module Interscript
17
17
  braced(stage_item.repeat(0)).as(:stage)
18
18
  end
19
19
 
20
+ # ISC-WF-1 W1: a named, reusable block of stage items. Declared at
21
+ # map top level anywhere a stage may appear; never executes on its
22
+ # own (only `use` expansion reaches the runtime).
23
+ rule(:ruleset_block) do
24
+ str("ruleset") >> whitespace >>
25
+ identifier.as(:ruleset_name) >> whitespace? >>
26
+ braced(stage_item.repeat(0)).as(:ruleset)
27
+ end
28
+
29
+ # ISC-WF-1 W1/W2: `use <ident>` (same-map ruleset) or
30
+ # `use <alias>.<ident>` (dependency-declared ruleset), with an
31
+ # optional override block of full replacement rows (child-wins on
32
+ # exact from-equality).
33
+ rule(:use_directive) do
34
+ (str("use") >> whitespace >>
35
+ identifier.as(:use_alias) >>
36
+ (str(".") >> identifier.as(:qualified_name)).maybe >>
37
+ (whitespace >> str("override") >> whitespace? >>
38
+ braced(rule_line.repeat(0)).as(:use_overrides)).maybe
39
+ ).as(:use)
40
+ end
41
+
42
+ # ISC-WF-1 W3: `when <ident> (","|ws <ident>)*` — a language guard
43
+ # on a sub rule. Inert unless the caller selects a language the
44
+ # map declares (spec §5.1). Identifiers are keyword-guarded so the
45
+ # repeat stops at the next rule instead of swallowing it.
46
+ rule(:when_guard) do
47
+ (whitespace >> str("when") >> whitespace >>
48
+ keyword.absent? >> identifier.as(:when_lang) >>
49
+ ((comma | whitespace) >> (keyword.absent? >> identifier.as(:when_lang))).repeat
50
+ ).as(:when)
51
+ end
52
+
20
53
  rule(:stage_item) do
21
54
  whitespace? >>
22
55
  (sequence_block | parallel_block | run_rule | separate_directive |
23
56
  string_case_directive | compose_directive | rababa_directive |
24
- bare_rule | comment_item) >>
57
+ use_directive | bare_rule | comment_item) >>
25
58
  whitespace?
26
59
  end
27
60
 
@@ -105,7 +138,8 @@ module Interscript
105
138
  str("sub") >> whitespace >>
106
139
  item_atom.as(:from) >> whitespace >>
107
140
  item_atom.as(:to) >>
108
- constraints
141
+ constraints >>
142
+ when_guard.maybe
109
143
  end
110
144
 
111
145
  rule(:block_rule) do
@@ -114,6 +148,7 @@ module Interscript
114
148
  str("from") >> whitespace >> item.as(:from) >> whitespace? >>
115
149
  str("to") >> whitespace >> item.as(:to) >>
116
150
  (whitespace >> constraint).repeat.as(:constraints) >>
151
+ when_guard.maybe >>
117
152
  whitespace? >> str("}")
118
153
  end
119
154
 
@@ -10,12 +10,23 @@ module Interscript
10
10
  module System
11
11
  include Parsanol
12
12
 
13
+ # ISC-WF-1 W3: the languages a map serves, declared once per map
14
+ # inside the system block alongside metadata (spec §5.1). List
15
+ # identifiers are keyword-guarded so the repeat stops at the next
16
+ # block item (`stage`, `ruleset`, …) instead of swallowing it.
17
+ rule(:languages_decl) do
18
+ str("languages") >> whitespace >>
19
+ (keyword.absent? >> identifier.as(:language) >>
20
+ ((comma | whitespace) >> (keyword.absent? >> identifier.as(:language))).repeat
21
+ ).as(:languages)
22
+ end
23
+
13
24
  # A block-item is any of the top-level constructs that may appear
14
25
  # inside `system "<code>" { ... }`.
15
26
  rule(:block_item) do
16
27
  whitespace? >>
17
- (metadata_block | aliases_block | tests_block |
18
- stage_block | dependency_decl) >>
28
+ (metadata_block | aliases_block | tests_block | languages_decl |
29
+ ruleset_block | stage_block | dependency_decl) >>
19
30
  whitespace?
20
31
  end
21
32
 
@@ -28,7 +28,7 @@ grammar InterscriptIsc version "0.1.0" {
28
28
  ident_rest = %x41-5A / %x61-7A / %x30-39 / %x5F
29
29
  identifier = (ident_first 0*ident_rest) as identifier
30
30
 
31
- keyword = "parallel" / "sequence" / "stage" / "compose" / "separate" / "system" / "metadata" / "aliases" / "tests" / "notes" / "description" / "any_character" / "authority" / "dependency" / "run" / "sub" / "before" / "after" / "not_before" / "not_after" / "any" / "none" / "boundary" / "line_start" / "line_end" / "word_boundary" / "downcase" / "upcase" / "title_case" / "capture" / "maybe" / "some" / "ref" / "name"
31
+ keyword = "parallel" / "sequence" / "stage" / "compose" / "separate" / "system" / "metadata" / "aliases" / "tests" / "notes" / "description" / "any_character" / "authority" / "dependency" / "run" / "sub" / "before" / "after" / "not_before" / "not_after" / "any" / "none" / "boundary" / "line_start" / "line_end" / "word_boundary" / "downcase" / "upcase" / "title_case" / "capture" / "maybe" / "some" / "ref" / "name" / "ruleset" / "use" / "override" / "languages" / "when"
32
32
 
33
33
  # -- string literals ----------------------------------------------------
34
34
 
@@ -143,9 +143,12 @@ grammar InterscriptIsc version "0.1.0" {
143
143
  constraint = constraint_after / constraint_before / constraint_not_before / constraint_not_after
144
144
  constraints = *(whitespace constraint)
145
145
 
146
- compact_rule = "sub" whitespace (item_atom as from) whitespace (item_atom as to) ((*(whitespace constraint)) as constraints)
146
+ compact_rule = "sub" whitespace (item_atom as from) whitespace (item_atom as to) ((*(whitespace constraint)) as constraints) [(when_guard)]
147
147
 
148
- block_rule = "sub" [ws] "{" [ws] "from" whitespace (item as from) [ws] "to" whitespace (item as to) ((*(whitespace constraint)) as constraints) [ws] "}"
148
+ block_rule = "sub" [ws] "{" [ws] "from" whitespace (item as from) [ws] "to" whitespace (item as to) ((*(whitespace constraint)) as constraints) [(when_guard)] [ws] "}"
149
+
150
+ when_lang = (!(keyword) identifier) as when_lang
151
+ when_guard = (whitespace "when" whitespace (when_lang) *(((comma_ws / whitespace) (when_lang)))) as when
149
152
 
150
153
  rule = block_rule / compact_rule
151
154
 
@@ -172,12 +175,21 @@ grammar InterscriptIsc version "0.1.0" {
172
175
  run_rule = "run" whitespace ((run_dep) / run_stage_only)
173
176
 
174
177
  bare_rule = (rule) as bare_rule
175
- stage_item = [ws] (sequence_block / parallel_block / run_rule / separate_directive / string_case_directive / compose_directive / rababa_directive / bare_rule / comment_item) [ws]
178
+
179
+ use_alias = (identifier) as use_alias
180
+ use_qualified = "." (identifier as qualified_name)
181
+ use_overrides_part = whitespace "override" [ws] "{" [ws] ((*(rule_line)) as use_overrides) [ws] "}"
182
+ use_directive = (("use" whitespace (use_alias) [(use_qualified)] [(use_overrides_part)]) as use)
183
+
184
+ stage_item = [ws] (sequence_block / parallel_block / run_rule / separate_directive / string_case_directive / compose_directive / rababa_directive / use_directive / bare_rule / comment_item) [ws]
176
185
  stage_items = *(stage_item)
177
186
  stage_name_paren = "(" (identifier as stage_name) ")"
178
187
  stage_name_ws = whitespace (identifier as stage_name)
179
188
  stage_block = "stage" (stage_name_paren / stage_name_ws) [ws] "{" [ws] (stage_items as stage) [ws] "}"
180
189
 
190
+ ruleset_name_ws = whitespace (identifier as ruleset_name)
191
+ ruleset_block = "ruleset" (ruleset_name_ws) [ws] "{" [ws] (stage_items as ruleset) [ws] "}"
192
+
181
193
  # -- tests ---------------------------------------------------------------
182
194
 
183
195
  test_note = whitespace "note" whitespace (quoted_string as note)
@@ -187,7 +199,10 @@ grammar InterscriptIsc version "0.1.0" {
187
199
 
188
200
  # -- system --------------------------------------------------------------
189
201
 
190
- block_item = [whitespace] (metadata_block / aliases_block / tests_block / stage_block / dependency_decl) [whitespace]
202
+ language_ident = (!(keyword) identifier) as language
203
+ languages_decl = ("languages" whitespace ((language_ident *(((comma_ws / whitespace) (language_ident))))) as languages)
204
+
205
+ block_item = [whitespace] (metadata_block / aliases_block / tests_block / languages_decl / ruleset_block / stage_block / dependency_decl) [whitespace]
191
206
  body_items = *(block_item)
192
207
  system_block = "system" whitespace ((quoted_string) as system_code) [whitespace] "{" [ws] ((*(block_item)) as body) [ws] "}" [whitespace]
193
208
  isc_source = [whitespace] ((system_block) as system) [whitespace]
@@ -4,6 +4,7 @@ require "lutaml/model"
4
4
  require "interscript/isc/model/test"
5
5
  require "interscript/isc/model/alias"
6
6
  require "interscript/isc/model/stage"
7
+ require "interscript/isc/model/ruleset"
7
8
  require "interscript/isc/model/dependency"
8
9
 
9
10
  module Interscript
@@ -15,6 +16,8 @@ module Interscript
15
16
  attribute :tests, Test, collection: true
16
17
  attribute :aliases, Alias, collection: true
17
18
  attribute :stages, Stage, collection: true
19
+ attribute :rulesets, Ruleset, collection: true
20
+ attribute :languages, :string, collection: true
18
21
  attribute :dependencies, Dependency, collection: true
19
22
 
20
23
  yaml do
@@ -23,6 +26,8 @@ module Interscript
23
26
  map "tests", to: :tests
24
27
  map "aliases", to: :aliases
25
28
  map "stages", to: :stages
29
+ map "rulesets", to: :rulesets
30
+ map "languages", to: :languages
26
31
  map "dependencies", to: :dependencies
27
32
  end
28
33
  end
@@ -11,11 +11,13 @@ module Interscript
11
11
  attribute :from, Item
12
12
  attribute :to, Item
13
13
  attribute :constraints, Constraint, collection: true
14
+ attribute :when_languages, :string, collection: true
14
15
 
15
16
  yaml do
16
17
  map "from", to: :from
17
18
  map "to", to: :to
18
19
  map "constraints", to: :constraints
20
+ map "when_languages", to: :when_languages
19
21
  end
20
22
  end
21
23
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+ require "interscript/isc/model/stage_item"
5
+
6
+ module Interscript
7
+ module Isc
8
+ module Model
9
+ # ISC-WF-1 W1: a named, reusable block of stage items (spec §3).
10
+ class Ruleset < Lutaml::Model::Serializable
11
+ attribute :name, :string
12
+ attribute :body, StageItem, collection: true
13
+
14
+ yaml do
15
+ map "name", to: :name
16
+ map "body", to: :body
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -8,7 +8,8 @@ module Interscript
8
8
  module Isc
9
9
  module Model
10
10
  # A single item in a stage body. Discriminated by `kind`:
11
- # parallel, sequence, bare_rule, run, separate, compose, string_case
11
+ # parallel, sequence, bare_rule, run, use, separate, compose,
12
+ # string_case
12
13
  class StageItem < Lutaml::Model::Serializable
13
14
  attribute :kind, :string
14
15
  attribute :rules, Rule, collection: true
@@ -17,6 +18,11 @@ module Interscript
17
18
  attribute :stage, :string
18
19
  attribute :separator, Item
19
20
  attribute :op, :string
21
+ # ISC-WF-1 W1/W2: the referenced ruleset and the per-site
22
+ # override rows; `dependency` carries the alias for qualified
23
+ # references (`use alias.<ruleset>`).
24
+ attribute :ruleset, :string
25
+ attribute :overrides, Rule, collection: true
20
26
 
21
27
  yaml do
22
28
  map "kind", to: :kind
@@ -26,6 +32,8 @@ module Interscript
26
32
  map "stage", to: :stage
27
33
  map "separator", to: :separator
28
34
  map "op", to: :op
35
+ map "ruleset", to: :ruleset
36
+ map "overrides", to: :overrides
29
37
  end
30
38
  end
31
39
  end
@@ -10,6 +10,7 @@ module Interscript
10
10
  autoload :Rule, "interscript/isc/model/rule"
11
11
  autoload :StageItem, "interscript/isc/model/stage_item"
12
12
  autoload :Stage, "interscript/isc/model/stage"
13
+ autoload :Ruleset, "interscript/isc/model/ruleset"
13
14
  autoload :Alias, "interscript/isc/model/alias"
14
15
  autoload :Test, "interscript/isc/model/test"
15
16
  autoload :Dependency, "interscript/isc/model/dependency"