jade-lang 0.12.1 → 0.12.2

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: 1b6d2de0940d8842121c48456180fa3cbc04345d0bf991c31f8e008019c4e017
4
- data.tar.gz: 425323f1b3c92b1d817b088a3973b86c94f7743fe185197cb5d60c680281184f
3
+ metadata.gz: fd36bbcd9dc0af93f281ebf187acafe5eb8b19d9cb868375a4261a2c8346e3c8
4
+ data.tar.gz: 631ba0267189d7d59bf014fe44fb07bec65d657bc0f87ba809bee8bfd577c503
5
5
  SHA512:
6
- metadata.gz: 0da5c33762fdac3b212474c72925c1d47c48b915f7b4a6877a6328b3c07ac15430e0f97c5647d714886d498c94850a1a448100ae29cfd73d7f97abc3bfc2248c
7
- data.tar.gz: ee26d40ebaa14f0587675692a83d977f6e7eae0ba80c342929847636c9c5509778fa7e19977974deb2421bf7cab0e17a066cafd4188f121d6165347cd1a4b3b4
6
+ metadata.gz: 7343d1d44fc2eab19f07360d5d87369c3707e005b51493a58911c07ef52e6c6832e270a54741e325d0ccbdbd65d7ea5f7b6b744fa21bea6bcc68c7d14d235534
7
+ data.tar.gz: 31c9091262b1472f3e51a5797bf1b6ab13359693b774f2912b62d3a53e185124260a6c493cff2d1a5cf7f712b87367ce3fcd346da1577e568d349519441331ae
data/CHANGELOG.md CHANGED
@@ -6,6 +6,21 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.12.2] - 2026-09-24
10
+
11
+ ### Fixed
12
+
13
+ - **A hoisted dictionary is built on first use, not while the module loads.**
14
+ One can hold the result of calling a module function, and that function's
15
+ own body can name another dictionary — emitted as constants in the order
16
+ they were written, the second was still undefined while the first was being
17
+ built, and requiring the module raised `uninitialized constant DICT_6`.
18
+ Whether it happened depended on the order the dictionaries were discovered
19
+ in, so adding an unrelated function could break a module that compiled
20
+ yesterday. They are memoised singleton methods now, cleared on each load so
21
+ a reloaded module does not keep dictionaries closing over classes the
22
+ reload replaced.
23
+
9
24
  ## [0.12.1] - 2026-09-21
10
25
 
11
26
  Both of these make code compile that should have compiled, so they ride a
@@ -56,6 +56,20 @@ module Jade
56
56
  @dict_consts = prev
57
57
  end
58
58
 
59
+ # The module the dictionary methods are defined on, so a reference from
60
+ # inside `Internal` still finds them.
61
+ def dict_owner
62
+ @dict_owner
63
+ end
64
+
65
+ def with_dict_owner(owner)
66
+ prev = @dict_owner
67
+ @dict_owner = owner
68
+ yield
69
+ ensure
70
+ @dict_owner = prev
71
+ end
72
+
59
73
  # When set, references with this name emit as `self` (and field accesses
60
74
  # on them as bare method calls). Used to rewrite operator-impl lambda
61
75
  # bodies — `(a, b) -> { a.amount == b.amount }` becomes
@@ -140,7 +140,8 @@ module Jade
140
140
  table = Codegen.dict_consts or return source
141
141
  return source if Codegen.dict_env.values.any? { source.include?(it) }
142
142
 
143
- table[source] ||= "DICT_#{table.size}"
143
+ table[source] ||= "dict_#{table.size}"
144
+ "::#{Codegen.dict_owner}.#{table[source]}"
144
145
  end
145
146
 
146
147
  # Polymorphic fn referenced as a value (not called). Wraps the fn with
data/lib/jade/codegen.rb CHANGED
@@ -109,10 +109,12 @@ module Jade
109
109
  outer, inner, wrappers =
110
110
  with_substitution(registry.get(name).env.substitution) do
111
111
  with_dict_consts(dict_consts) do
112
- with_boundary_cache(boundary_cache) do
113
- with_dispatched_methods(collect_dispatched_methods(body, registry)) do
114
- with_hoisted_records do
115
- partition_module_body(body.expressions, registry, name.count('.'))
112
+ with_dict_owner(to_qualified(name)) do
113
+ with_boundary_cache(boundary_cache) do
114
+ with_dispatched_methods(collect_dispatched_methods(body, registry)) do
115
+ with_hoisted_records do
116
+ partition_module_body(body.expressions, registry, name.count('.'))
117
+ end
116
118
  end
117
119
  end
118
120
  end
@@ -365,9 +367,25 @@ module Jade
365
367
  # weighed against its specialized form, say), and a discarded one can
366
368
  # still have claimed a constant. Keep the ones that survived, and the
367
369
  # ones those refer to.
370
+ # Memoised methods rather than constants: a dictionary can hold the
371
+ # result of calling a module function, and that function's own body can
372
+ # name another dictionary. Constants are evaluated in the order they are
373
+ # written, so that dependency could reach forward to one not defined
374
+ # yet; a method body runs when it is first called, by which time every
375
+ # definition exists.
368
376
  def referenced_dicts(table, body)
369
377
  reachable_dicts(table, body.join(Pretty.newline))
370
- .map { |source, const| "#{const} = #{source}.freeze" }
378
+ .map { |source, const| dict_method(const, source) }
379
+ end
380
+
381
+ # The nil assignment runs on every load, so a reloaded module rebuilds
382
+ # its dictionaries rather than keeping ones that close over the classes
383
+ # the reload just replaced.
384
+ def dict_method(const, source)
385
+ [
386
+ "@#{const} = nil",
387
+ Pretty.block("def self.#{const}", "@#{const} ||= #{source}.freeze"),
388
+ ].join(Pretty.newline(2))
371
389
  end
372
390
 
373
391
  # A kept dictionary can name another one, so widen the search text
data/lib/jade/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Jade
2
- VERSION = '0.12.1'
2
+ VERSION = '0.12.2'
3
3
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jade-lang
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.1
4
+ version: 0.12.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Agustin Cornu
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-09-21 00:00:00.000000000 Z
10
+ date: 2026-09-24 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: base64