expressir 2.4.16 → 2.4.17

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: ca7a970fe2d30edcb570639ddd4c178b2edf7bdee839844df7946fdb1e842d1b
4
- data.tar.gz: a5a5b1c703de8027892d77792fbc957155101b8875fe1aa080feefec9d278ac7
3
+ metadata.gz: 6fb8953f2f2e9d76be3693148c8951ae36f562bbaf8214a8bc510b68888700d2
4
+ data.tar.gz: dfbcc336cc1a580501ca69632d6e6bb348e196be470cbc712a637131ffe1993c
5
5
  SHA512:
6
- metadata.gz: '0950891e9ddb51792aaf69c1c82af9224ae6126b5ff77dd481e48105b2e39215dd23a1d1c3e30d060be4ef2988132b4aec47cf306903dc9081a05e73c5e6f42d'
7
- data.tar.gz: 976131ab90fedb6e659129ca1f0aa6a3e8a8d5df40cb00950dc8b6b237789dcc4d896df03c35532e3afac6483e2f3674983bb0bc092adbf0534ed355d155a507
6
+ metadata.gz: 2e5259fb143ac5419ab85b8a97e8ab50a3a809826f799b8cd74242a673599c5cac0bd21cfe1dc33af562c16a806afc95f9f43f75f8eba43e18b68377104d5406
7
+ data.tar.gz: 0d2520a7a817f1c8d72a6f768887e803c91a6070f3cf8d4230bde9e66dcb6a1580ff7ee39ac6e9c886106cde64db14e175db57e81be0b798ea8f45af57bfaaa7
@@ -0,0 +1,211 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "liquid"
4
+
5
+ module Expressir
6
+ module Express
7
+ # Lazy read path over a compiled-set artifact (M2 slice 2,
8
+ # TODO.parity-ee/19): schemas hydrate individually, on first touch,
9
+ # instead of the whole repository at once. Metanorma schema-doc
10
+ # rendering touches one schema per page — the lazy repository makes
11
+ # that pay: one hydration per page, not one per schema in the set.
12
+ #
13
+ # Duck-types the read surface of Model::Repository used by
14
+ # rendering (schemas, files, each, size, children). Anything beyond
15
+ # the read surface should wait for eager hydration via
16
+ # #to_eager (returns a real Model::Repository).
17
+ class LazyRepository
18
+ attr_reader :set_path
19
+
20
+ # @param set_path [String] compiled-set artifact path
21
+ # @param read_paths [Hash{String => String}] wire path => source path
22
+ def initialize(set_path, read_paths = {})
23
+ @set_path = set_path
24
+ @set = Core.lazy_set(set_path)
25
+ @read_paths = read_paths
26
+ @wire_paths = @set.wire_paths
27
+ @mutex = Mutex.new
28
+ @file_cache = {}
29
+ @hydration_count = 0
30
+ end
31
+
32
+ # Wire paths in artifact order — no hydration.
33
+ # @return [Array<String>]
34
+ def wire_paths
35
+ @wire_paths.dup
36
+ end
37
+
38
+ # Files in artifact order, each wrapped so it hydrates on first
39
+ # use. The file is the hydration grain: an artifact stores wire
40
+ # JSON per source file.
41
+ # @return [Array<LazyFile>]
42
+ def files
43
+ @wire_paths.map { |wire_path| file_by_wire_path(wire_path) }
44
+ end
45
+
46
+ # Hydrated (or hydrating) file for one wire path.
47
+ def file_by_wire_path(wire_path)
48
+ @mutex.synchronize do
49
+ @file_cache[wire_path] ||= LazyFile.new(wire_path) do
50
+ hydrate(wire_path)
51
+ end
52
+ end
53
+ end
54
+
55
+ # Schemas across all files. EAGER by definition: it hydrates
56
+ # every file. Lazy callers iterate #files, or render through
57
+ # #to_liquid, which keeps per-file hydration lazy.
58
+ # @return [Array<Declarations::Schema>]
59
+ def schemas
60
+ files.map(&:__target__).flat_map(&:schemas).compact
61
+ end
62
+
63
+ # Liquid binding for metanorma (M2): returns a Drop whose
64
+ # `schemas` is a lazy per-file list — each entry hydrates only
65
+ # its own file when the template touches it. Schema count per
66
+ # file is unknown until hydration, so the Drop presents one
67
+ # entry per FILE; single-schema files (the corpus norm) render
68
+ # identically to the eager path.
69
+ def to_liquid
70
+ LazyRepositoryDrop.new(self)
71
+ end
72
+
73
+ # How many files have actually been hydrated (observability for
74
+ # the laziness contract).
75
+ def hydration_count
76
+ @hydration_count
77
+ end
78
+
79
+ # Hydrate everything and return a real Model::Repository — the
80
+ # escape hatch for callers needing the full read surface.
81
+ def to_eager
82
+ repo = Model::Repository.new
83
+ repo.files = files.map(&:__target__)
84
+ repo
85
+ end
86
+
87
+ def each(&)
88
+ files.each(&)
89
+ end
90
+
91
+ def size
92
+ @wire_paths.size
93
+ end
94
+
95
+ def children
96
+ schemas
97
+ end
98
+
99
+ # The read path on disk for a wire path (may be nil when the
100
+ # caller did not supply source paths).
101
+ def read_path_for(wire_path)
102
+ @read_paths[wire_path]
103
+ end
104
+
105
+ def matches_sources?
106
+ @set.matches_sources(@read_paths.dup) == true
107
+ end
108
+
109
+ private
110
+
111
+ def hydrate(wire_path)
112
+ @mutex.synchronize do
113
+ _wire, model = @set.hydrate_one(wire_path)
114
+ @hydration_count += 1
115
+ model
116
+ end
117
+ end
118
+ end
119
+
120
+ # Liquid::Drop over a LazyRepository: `schemas` enumerates lazy
121
+ # per-file entries; touching an entry hydrates that file and
122
+ # presents its schemas (single-schema files present the schema
123
+ # itself, matching the eager Drop's element contract).
124
+ class LazyRepositoryDrop < ::Liquid::Drop
125
+ def initialize(repo)
126
+ @repo = repo
127
+ super()
128
+ end
129
+
130
+ def schemas
131
+ @repo.files.map do |file|
132
+ LazyFileDrop.new(file)
133
+ end
134
+ end
135
+
136
+ def size
137
+ @repo.size
138
+ end
139
+ end
140
+
141
+ # Per-file lazy drop: hydrates on first access, then presents the
142
+ # file's single schema directly (or the schema list for
143
+ # multi-schema files).
144
+ class LazyFileDrop < ::Liquid::Drop
145
+ def initialize(file)
146
+ @file = file
147
+ super()
148
+ end
149
+
150
+ def __file__
151
+ @file.__target__
152
+ end
153
+
154
+ def method_missing(name, *, &)
155
+ schemas = __file__.schemas
156
+ if schemas.size == 1
157
+ schemas.first.public_send(name, *, &)
158
+ else
159
+ __file__.public_send(name, *, &)
160
+ end
161
+ end
162
+
163
+ def respond_to_missing?(name, include_private = false)
164
+ __file__.respond_to?(name, include_private) ||
165
+ __file__.schemas.first.respond_to?(name, include_private)
166
+ end
167
+ end
168
+
169
+ # Stands in for a Model::ExpFile until first method access, then
170
+ # hydrates through the block and forwards everything.
171
+ class LazyFile
172
+ def initialize(wire_path, &hydrator)
173
+ @wire_path = wire_path
174
+ @hydrator = hydrator
175
+ @mutex = Mutex.new
176
+ @target = nil
177
+ end
178
+
179
+ attr_reader :wire_path
180
+
181
+ # The real Schema, hydrating on first call.
182
+ def __target__
183
+ @mutex.synchronize do
184
+ @__target__ ||= @hydrator.call
185
+ end
186
+ end
187
+
188
+ def method_missing(name, *, &)
189
+ __target__.public_send(name, *, &)
190
+ end
191
+
192
+ def respond_to_missing?(name, include_private = false)
193
+ __target__.respond_to?(name, include_private)
194
+ end
195
+
196
+ # Identity through the wrapper: rendering compares and groups by
197
+ # class/is_a?, which the real file answers.
198
+ def is_a?(klass)
199
+ super || __target__.is_a?(klass)
200
+ end
201
+
202
+ def instance_of?(klass)
203
+ __target__.instance_of?(klass)
204
+ end
205
+
206
+ def class
207
+ __target__.class
208
+ end
209
+ end
210
+ end
211
+ end
@@ -44,6 +44,7 @@ module Expressir
44
44
  "#{__dir__}/express/schema_plain_source_formatter"
45
45
  autoload :SchemaSourceFormatter, "#{__dir__}/express/schema_source_formatter"
46
46
  autoload :ScopeResolver, "#{__dir__}/express/scope_resolver"
47
+ autoload :LazyRepository, "#{__dir__}/express/lazy_repository"
47
48
  autoload :SmrlXml, "#{__dir__}/express/smrl_xml"
48
49
  autoload :Xsd, "#{__dir__}/express/xsd"
49
50
  autoload :SourceFormatter, "#{__dir__}/express/source_formatter"
@@ -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.16".freeze
6
+ VERSION = "2.4.17".freeze
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: expressir
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.16
4
+ version: 2.4.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -506,6 +506,7 @@ files:
506
506
  - lib/expressir/express/grammar/parser.rb
507
507
  - lib/expressir/express/hyperlink_formatter.rb
508
508
  - lib/expressir/express/interface_dot.rb
509
+ - lib/expressir/express/lazy_repository.rb
509
510
  - lib/expressir/express/line_map.rb
510
511
  - lib/expressir/express/listing.rb
511
512
  - lib/expressir/express/model_traversal.rb