Skip to content

Commit 330e2e0

Browse files
authored
Merge pull request jruby#9335 from kares/deconstruct-keys-10
[fix] MatchData#deconstruct_keys: include non-participating captures
2 parents 71fbf42 + a00e7d7 commit 330e2e0

2 files changed

Lines changed: 34 additions & 3 deletions

File tree

core/src/main/java/org/jruby/RubyMatchData.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,7 @@ public IRubyObject deconstruct_keys(ThreadContext context, IRubyObject what) {
951951

952952
for (int b : entry.getBackRefs()) {
953953
IRubyObject value = RubyRegexp.nth_match(context, b, this);
954-
if (value.isTrue()) hash.op_aset(context, key, value);
954+
hash.op_aset(context, key, value);
955955
}
956956
});
957957
} else if (what instanceof RubyArray arr) {
@@ -967,8 +967,6 @@ public IRubyObject deconstruct_keys(ThreadContext context, IRubyObject what) {
967967
if (index == -1) break;
968968

969969
IRubyObject value = RubyRegexp.nth_match(context, index, this);
970-
if (!value.isTrue()) break;
971-
972970
hash.op_aset(context, requestedKey, value);
973971
}
974972
} else {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
require 'rspec'
2+
3+
# Regression test for MatchData#deconstruct_keys with non-participating
4+
# named captures.
5+
#
6+
# When a named capture group doesn't participate in the match (e.g.
7+
# an optional group like (?<b>world)?), deconstruct_keys should include
8+
# the key with a nil value, not omit it entirely.
9+
10+
describe "MatchData#deconstruct_keys with non-participating captures" do
11+
let(:match) { "hello".match(/(?<a>hello)(?<b>world)?/) }
12+
13+
it "includes non-participating captures as nil for nil argument" do
14+
result = match.deconstruct_keys(nil)
15+
expect(result).to eq({ a: "hello", b: nil })
16+
end
17+
18+
it "includes non-participating captures as nil for explicit keys" do
19+
result = match.deconstruct_keys([:a, :b])
20+
expect(result).to eq({ a: "hello", b: nil })
21+
end
22+
23+
it "does not stop iterating at non-participating captures" do
24+
m = "hello!".match(/(?<a>hello)(?<b>world)?(?<c>!)/)
25+
result = m.deconstruct_keys([:b, :c, :a])
26+
expect(result).to eq({ b: nil, c: "!", a: "hello" })
27+
end
28+
29+
it "preserves key order from argument" do
30+
result = match.deconstruct_keys([:b, :a])
31+
expect(result.keys).to eq([:b, :a])
32+
end
33+
end

0 commit comments

Comments
 (0)