expressir 2.4.28 → 2.4.30

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: 45dd9d5d13614ca549340d534defb9a674a5fca35a9f3b16f5ef345b73e263eb
4
- data.tar.gz: f5a14e8e4cb49ebebe7823d9015de7296459735b3f8ea06edc3494e072b0877f
3
+ metadata.gz: 422611b8889e4e8c78ca3a4c2482b3988dcda82d3035d813c462b7c77f3eac50
4
+ data.tar.gz: cd132662d82929629aa50ad7b7ad0dd238cd744af87e3ec0cda519b8ab949575
5
5
  SHA512:
6
- metadata.gz: d46d905d2f0ca978c614cba3574a398fa38809f38296930115905b9e97cf1e223e8b0882c1c7431e026dc97015579f7e820f067173da4645ede0be33a00c6842
7
- data.tar.gz: bc103128faa28cbaafdb27a61117431c9b17d77913b4dcc038db64638b815f19be7e90c4366ca45ef378196f360445296244cd40c435997038280d776de94dd1
6
+ metadata.gz: fad716d2795853e70bc21eda9dec8baf15406d6a9afe9cba82bd138f672d8c852876664cde22c9ef10331d4b514769195c11cd5e3d7e5fec0409bb3589777f7a
7
+ data.tar.gz: e23c2fd8555d20aac0972817f6af0e6b242602a4deca1df7e1e2dfcbee22200f771a4b12afd48340b2efa648bedaed9505244cc343eec7a7935578602092c435
@@ -26,4 +26,9 @@ sc = Expressir::Express::Parser.from_exp(src).schemas.first.subtype_constraints.
26
26
  abort "FAIL: subtype constraint ABSTRACT body (#462)" unless sc&.abstract == true
27
27
  puts "#462 form: ok"
28
28
 
29
+ # The platform gems force-build the Rust compiled-set writer; a leg that
30
+ # shipped a non-loadable expressir_core would otherwise pass this smoke.
31
+ abort "FAIL: core_set_available is false" unless Expressir::Express::Parser.core_set_available?
32
+ puts "compiled-set core: ok"
33
+
29
34
  puts "SMOKE OK"
@@ -52,12 +52,14 @@ jobs:
52
52
  EXPRESSIR_CORE_FORCE: "1"
53
53
  with:
54
54
  platform: ${{ matrix.ruby-platform }}
55
- # Dock images provision cross rubies for 3.2-3.4 only; a 4.0
56
- # leg silently falls back to the dock's host toolchain and
57
- # fails linking (or worse, links against the wrong ruby).
58
- # Ruby 4.0 users on these platforms get the pure-Ruby parser
59
- # fallback until the images ship 4.0 cross rubies.
60
- ruby-versions: "3.2,3.3,3.4"
55
+ # Must include the dock image's HOST ruby (4.0): when the
56
+ # running ruby is absent from this list, rake-compiler adds an
57
+ # extra leg for it built from the host toolchain's RbConfig,
58
+ # and rb-sys correctly refuses to generate bindings against a
59
+ # different target_os. Current rb-sys-dock images ship cross
60
+ # rubies for 3.2-4.0 (parsanol-ruby's identical cross-gem
61
+ # setup builds a working x86_64-mingw-ucrt ruby-4.0.2 leg).
62
+ ruby-versions: "3.2,3.3,3.4,4.0"
61
63
 
62
64
  - uses: actions/upload-artifact@v4
63
65
  with:
@@ -170,19 +172,33 @@ jobs:
170
172
  release:
171
173
  name: Release gems to rubygems
172
174
  needs: [native, smoke-linux, smoke-linux-arm, smoke-macos-arm, smoke-macos-intel, smoke-windows, source]
173
- if: startsWith(github.ref, 'refs/tags/v')
175
+ # workflow_dispatch lets a fix publish the already-tagged version when
176
+ # the tag's own run failed after the builds (reruns reuse the tag's
177
+ # workflow copy, so fixes cannot reach them any other way).
178
+ if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
174
179
  runs-on: ubuntu-22.04
175
- environment: release
180
+ # No environment: the rubygems.org trusted publisher for native-gems.yml
181
+ # is registered without one; an environment claim would fail the match.
182
+ permissions:
183
+ id-token: write
176
184
  steps:
177
185
  - uses: actions/download-artifact@v4
178
186
  with:
179
187
  path: pkg/
180
188
  pattern: cross-gem-*
181
189
  merge-multiple: true
190
+ - uses: actions/download-artifact@v4
191
+ with:
192
+ path: pkg/
193
+ name: source-gem
194
+ # OIDC trusted publishing - the repo has no rubygems API-key secret;
195
+ # release.yml publishes through the same exchange.
196
+ - uses: rubygems/configure-rubygems-credentials@v2.1.0
182
197
  - name: Push to rubygems
183
- env:
184
- GEM_HOST_API_KEY: ${{ secrets.LUTAML_CI_RUBYGEMS_API_KEY }}
185
198
  run: |
186
199
  for gem in pkg/expressir-*.gem; do
187
- gem push "$gem"
200
+ # Idempotent: a gem already on rubygems (e.g. the source gem
201
+ # shipped by release.yml ahead of the platform run) is a skip,
202
+ # not a failure.
203
+ gem push "$gem" || echo "::warning::$(basename "$gem") already published or rejected; continuing"
188
204
  done
data/expressir.gemspec CHANGED
@@ -24,6 +24,11 @@ Gem::Specification.new do |spec|
24
24
  spec.metadata["rubygems_mfa_required"] = "true"
25
25
 
26
26
  spec.required_ruby_version = Gem::Requirement.new(">= 3.2.0")
27
+ # Source gem builds on the ruby platform; declaring it keeps
28
+ # rake-compiler's `gem` task from rebuilding the extension for the
29
+ # host ruby during cross builds (rb-sys then sees a windows
30
+ # CARGO_BUILD_TARGET with linux headers and refuses).
31
+ spec.platform = Gem::Platform::RUBY
27
32
 
28
33
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
29
34
  `git ls-files -z`.split("\x0").reject do |f|
@@ -37,18 +42,18 @@ Gem::Specification.new do |spec|
37
42
  spec.extensions = ["ext/expressir_core/extconf.rb"]
38
43
  spec.add_dependency "rb_sys", "~> 0.9.130"
39
44
 
40
- spec.add_dependency "base64"
45
+ spec.add_dependency "base64", ">= 0.1.0"
41
46
  spec.add_dependency "benchmark"
42
47
  spec.add_dependency "benchmark-ips"
43
48
  spec.add_dependency "csv"
44
- spec.add_dependency "liquid"
49
+ spec.add_dependency "liquid", "~> 5"
45
50
  spec.add_dependency "lutaml-model", "~> 0.8.76"
46
51
  spec.add_dependency "moxml"
47
- spec.add_dependency "nokogiri"
52
+ spec.add_dependency "nokogiri", "~> 1.19"
48
53
  spec.add_dependency "paint"
49
- spec.add_dependency "parsanol", "~> 1.3.9", ">= 1.3.9"
54
+ spec.add_dependency "parsanol", "~> 1.3.9", ">= 1.3.89"
50
55
  spec.add_dependency "ruby-progressbar", "~> 1.11"
51
- spec.add_dependency "rubyzip"
56
+ spec.add_dependency "rubyzip", "~> 3.7"
52
57
  spec.add_dependency "table_tennis"
53
58
  spec.add_dependency "thor", "~> 1.0"
54
59
  # Native YAML/JSON engine (lutaml-model opt-in by bundle contents)
@@ -21,7 +21,7 @@ module Expressir
21
21
  autoload :Changes, "#{__dir__}/commands/changes"
22
22
  autoload :ChangesValidate, "#{__dir__}/commands/changes_validate"
23
23
  autoload :ChangesImportEengine, "#{__dir__}/commands/changes_import_eengine"
24
- autoload :Version, "#{__dir__}/commands/version"
24
+ autoload :Version, "#{__dir__}/commands/version_command"
25
25
  autoload :Package, "#{__dir__}/commands/package"
26
26
  autoload :Manifest, "#{__dir__}/commands/manifest"
27
27
  autoload :MappingValidate, "#{__dir__}/commands/mapping_validate"
@@ -7,16 +7,34 @@ module Expressir
7
7
  # Ruby bridge to the expressir-core Rust crate (parse + model
8
8
  # extraction). Available when the native extension is built;
9
9
  # callers fall back to the pure-Ruby parser otherwise.
10
+ #
11
+ # Windows is excluded along with parsanol's native engine
12
+ # (Grammar::Parser.native_available?): the core embeds the
13
+ # parsanol-rs parse stack, whose x64-mingw build deadlocks the
14
+ # same way at first parse (expressir#487) - the compiled
15
+ # extension is present, so the gate is explicit rather than a
16
+ # LoadError consequence.
10
17
  module Core
11
- NATIVE_AVAILABLE = begin
18
+ NATIVE_AVAILABLE = !Gem.win_platform? && begin
12
19
  require "expressir/expressir_core"
13
20
  true
14
21
  rescue LoadError
15
22
  begin
16
- require_relative "../../../ext/expressir_core/expressir_core"
23
+ # Platform gems carry the fat-binary layout
24
+ # (lib/expressir/<major.minor>/expressir_core.so); rubygems
25
+ # does not resolve versioned dirs under a nested require path,
26
+ # so the version segment is explicit - same contract as
27
+ # parsanol's loader.
28
+ ruby_version = RUBY_VERSION.split(".").take(2).join(".")
29
+ require "expressir/#{ruby_version}/expressir_core"
17
30
  true
18
31
  rescue LoadError
19
- false
32
+ begin
33
+ require_relative "../../../ext/expressir_core/expressir_core"
34
+ true
35
+ rescue LoadError
36
+ false
37
+ end
20
38
  end
21
39
  end
22
40
 
@@ -27,6 +27,22 @@ module Expressir
27
27
  # Files above this use parse_fresh which has no packrat cache
28
28
  LARGE_FILE_THRESHOLD = 1024 * 1024 # 1 MB
29
29
 
30
+ # Whitespace rides the engine's injected trivia (parsanol-ruby
31
+ # #180's source-preserving mode, 1.3.82+): each unit records
32
+ # verbatim under :space and attaches to the next Named capture.
33
+ # Remarks stay OUT of the skip rule — they are product data,
34
+ # captured by the tailRemark/embeddedRemark rules and attached
35
+ # by RemarkScanner; tail remarks attach backward, the engine's
36
+ # next-capture channel is the wrong direction for them.
37
+ rule(:trivia) { match[" \r\n\t\f"].repeat(1) }
38
+ # exempt (parsanol#195, shipped 1.3.89): token rules whose bodies
39
+ # manage their own internals — injection before a char-class tail
40
+ # repetition absorbs the following token across whitespace
41
+ # ("RULE r FOR" parsed as one simpleId). simpleId additionally
42
+ # matches as a single quantified Re, which needs no exemption;
43
+ # the two mechanisms agree and stay for defense in depth.
44
+ skip(:trivia, whitespace: :space, exempt: %i[simpleId digits])
45
+
30
46
  # Get cached parser instance (thread-safe)
31
47
  # Reusing the parser avoids the overhead of reinitializing all rule definitions
32
48
  def self.cached_parser
@@ -46,6 +62,15 @@ module Expressir
46
62
 
47
63
  # Check if native parsing is available
48
64
  def self.native_available?
65
+ # parsanol 1.3.54+ x64-mingw builds deadlock inside the native
66
+ # parse at runtime: the library loads (early examples run) but
67
+ # the first parse never returns (expressir#487 — every windows
68
+ # rake run since 2026-09-29 hit the 6h limit; the control at
69
+ # green-era leptris/moxml/yeptris still hangs, parsanol 1.3.53
70
+ # was green). The pure-Ruby engine is correct, so windows falls
71
+ # back to it until parsanol fixes the mingw build.
72
+ return false if Gem.win_platform?
73
+
49
74
  return @native_available unless @native_available.nil?
50
75
 
51
76
  @native_available = begin
@@ -604,7 +629,13 @@ module Expressir
604
629
  (unaryOp >> simpleFactorExpression).as(:simpleFactorUnaryExpression)
605
630
  end
606
631
  rule(:simpleId) do
607
- anyKeyword.absent? >> cts((match["a-zA-Z_"] >> match["a-zA-Z0-9_"].repeat).as(:str)).as(:simpleId)
632
+ # One quantified Re, not lead >> tail-repeat: under skip
633
+ # injection the DSL interleaves trivia before the tail
634
+ # repetition, so a two-atom ident would absorb the following
635
+ # whitespace-separated identifier ("RULE r FOR (e)" parses
636
+ # "r FOR" as one simpleId). A quantified Re consumes the
637
+ # whole identifier in a single step — parsanol GH-69.
638
+ anyKeyword.absent? >> cts(match("[a-zA-Z_][a-zA-Z0-9_]*").as(:str)).as(:simpleId)
608
639
  end
609
640
  rule(:simpleStringLiteral) do
610
641
  cts((str("'") >> (str("'").absent? >> any).repeat >> str("'")).as(:str)).as(:simpleStringLiteral)
@@ -3,6 +3,6 @@ module Expressir
3
3
  # autoload it (Ruby autoload only works for module/class constants, not
4
4
  # for string constants like `Expressir::VERSION`).
5
5
  module Version
6
- VERSION = "2.4.28".freeze
6
+ VERSION = "2.4.30".freeze
7
7
  end
8
8
  end
data/rakelib/native.rake CHANGED
@@ -7,43 +7,16 @@
7
7
  # artifact in lib/expressir/, which core.rb's first require finds.
8
8
  begin
9
9
  require "rb_sys/extensiontask"
10
- require "rb_sys/toolchain_info"
11
10
 
12
11
  gemspec = Gem::Specification.load("expressir.gemspec")
13
12
 
14
13
  RbSys::ExtensionTask.new("expressir_core", gemspec) do |ext|
15
14
  ext.lib_dir = "lib/expressir"
16
-
17
- ext.cross_compiling do |spec|
18
- next if spec.platform == Gem::Platform::RUBY
19
-
20
- plat = spec.platform.to_s
21
- triple = begin
22
- RbSys::ToolchainInfo::DATA.fetch(plat).fetch("rust-target")
23
- rescue KeyError
24
- { "arm-linux-musl" => "arm-unknown-linux-musleabihf" }.fetch(plat)
25
- end
26
-
27
- # rb-sys's cargo build already ran for the cross target; stage the
28
- # artifact from the tree (rake-compiler stages callback-added files).
29
- # rb_sys uses a per-package target dir unless the crate is a
30
- # workspace member (then the root target/ holds artifacts) — glob
31
- # both layouts.
32
- art = Dir["target/#{triple}/release/expressir_core.{so,dylib,dll}",
33
- "target/#{triple}/release/libexpressir_core.{so,dylib}",
34
- "ext/expressir_core/target/#{triple}/release/expressir_core.{so,dylib,dll}",
35
- "ext/expressir_core/target/#{triple}/release/libexpressir_core.{so,dylib}"].first
36
- raise "binding artifact not found for #{plat} (#{triple})" unless art
37
-
38
- # core.rb requires "expressir/expressir_core", so the staged file
39
- # must sit at the canonical Ruby extension path/name — cargo's
40
- # lib- prefixed or .dll/.dylib-suffixed names are renamed to
41
- # expressir_core.so (Ruby's require accepts .so on every target:
42
- # DLEXT on linux/windows, DLEXT2 on darwin).
43
- dest = "lib/expressir/expressir_core.so"
44
- cp art, dest
45
- spec.files << dest
46
- end
15
+ # rb-sys stages the cross-built artifact itself; a manual cp into
16
+ # lib_dir here would claim the file rake-compiler's own
17
+ # copy:expressir_core:<host-platform> task owns, and the cross gem's
18
+ # dependency chain would then force a host-ruby build (rb-sys
19
+ # refuses windows bindings from linux headers).
47
20
  end
48
21
  rescue LoadError
49
22
  # rake-compiler/rb_sys not installed (consumer checkouts); the native
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: expressir
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.28
4
+ version: 2.4.30
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-09-30 00:00:00.000000000 Z
11
+ date: 2026-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rb_sys
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 0.1.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 0.1.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: benchmark
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -84,16 +84,16 @@ dependencies:
84
84
  name: liquid
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: '5'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: '5'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: lutaml-model
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -126,16 +126,16 @@ dependencies:
126
126
  name: nokogiri
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - ">="
129
+ - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: '0'
131
+ version: '1.19'
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - ">="
136
+ - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: '0'
138
+ version: '1.19'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: paint
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -159,7 +159,7 @@ dependencies:
159
159
  version: 1.3.9
160
160
  - - ">="
161
161
  - !ruby/object:Gem::Version
162
- version: 1.3.9
162
+ version: 1.3.89
163
163
  type: :runtime
164
164
  prerelease: false
165
165
  version_requirements: !ruby/object:Gem::Requirement
@@ -169,7 +169,7 @@ dependencies:
169
169
  version: 1.3.9
170
170
  - - ">="
171
171
  - !ruby/object:Gem::Version
172
- version: 1.3.9
172
+ version: 1.3.89
173
173
  - !ruby/object:Gem::Dependency
174
174
  name: ruby-progressbar
175
175
  requirement: !ruby/object:Gem::Requirement
@@ -188,16 +188,16 @@ dependencies:
188
188
  name: rubyzip
189
189
  requirement: !ruby/object:Gem::Requirement
190
190
  requirements:
191
- - - ">="
191
+ - - "~>"
192
192
  - !ruby/object:Gem::Version
193
- version: '0'
193
+ version: '3.7'
194
194
  type: :runtime
195
195
  prerelease: false
196
196
  version_requirements: !ruby/object:Gem::Requirement
197
197
  requirements:
198
- - - ">="
198
+ - - "~>"
199
199
  - !ruby/object:Gem::Version
200
- version: '0'
200
+ version: '3.7'
201
201
  - !ruby/object:Gem::Dependency
202
202
  name: table_tennis
203
203
  requirement: !ruby/object:Gem::Requirement
@@ -463,7 +463,7 @@ files:
463
463
  - lib/expressir/commands/validate.rb
464
464
  - lib/expressir/commands/validate_ascii.rb
465
465
  - lib/expressir/commands/validate_load.rb
466
- - lib/expressir/commands/version.rb
466
+ - lib/expressir/commands/version_command.rb
467
467
  - lib/expressir/commands/xsd.rb
468
468
  - lib/expressir/config.rb
469
469
  - lib/expressir/coverage.rb