Skip to content

Commit 09e9ecb

Browse files
authored
Merge pull request jruby#9225 from headius/struct_empty_kwargs
Expand Data initialize empty kwargs fix to Struct
2 parents 4db0c8a + 0526ca3 commit 09e9ecb

7 files changed

Lines changed: 53 additions & 2 deletions

File tree

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import static org.jruby.runtime.ThreadContext.CALL_KEYWORD_EMPTY;
4444
import static org.jruby.runtime.ThreadContext.clearCallInfo;
4545
import static org.jruby.runtime.ThreadContext.hasKeywords;
46+
import static org.jruby.runtime.ThreadContext.hasNonemptyKeywords;
4647
import static org.jruby.runtime.ThreadContext.resetCallInfo;
4748
import static org.jruby.runtime.invokedynamic.MethodNames.HASH;
4849
import static org.jruby.util.RubyStringBuilder.str;
@@ -310,7 +311,7 @@ public static IRubyObject rbNew(ThreadContext context, IRubyObject self, IRubyOb
310311

311312
RubyHash init;
312313
int callInfo = resetCallInfo(context);
313-
if (hasKeywords(callInfo) && (callInfo & CALL_KEYWORD_EMPTY) == 0) {
314+
if (hasNonemptyKeywords(callInfo)) {
314315
if (!(hashOrElt instanceof RubyHash)) {
315316
throw argumentError(context, 1, 0, 0);
316317
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import static org.jruby.runtime.Helpers.invokedynamic;
7272
import static org.jruby.runtime.ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR;
7373
import static org.jruby.runtime.ThreadContext.hasKeywords;
74+
import static org.jruby.runtime.ThreadContext.hasNonemptyKeywords;
7475
import static org.jruby.runtime.Visibility.PRIVATE;
7576
import static org.jruby.runtime.invokedynamic.MethodNames.HASH;
7677
import static org.jruby.RubyEnumerator.SizeFn;
@@ -531,7 +532,7 @@ public IRubyObject initialize(ThreadContext context) {
531532

532533
@JRubyMethod(visibility = PRIVATE)
533534
public IRubyObject initialize(ThreadContext context, IRubyObject arg0) {
534-
boolean keywords = hasKeywords(ThreadContext.resetCallInfo(context));
535+
boolean keywords = hasNonemptyKeywords(ThreadContext.resetCallInfo(context));
535536

536537
if (keywords) {
537538
return setupStructValuesFromHash(context, (RubyHash) arg0);

core/src/main/java/org/jruby/runtime/ThreadContext.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,14 @@ public static boolean hasKeywords(int callInfo) {
15881588
return (callInfo & CALL_KEYWORD) != 0;
15891589
}
15901590

1591+
public static boolean hasNonemptyKeywords(int callInfo) {
1592+
return (callInfo & CALL_KEYWORD) != 0 && !keywordsEmpty(callInfo);
1593+
}
1594+
1595+
public static boolean keywordsEmpty(int callInfo) {
1596+
return (callInfo & CALL_KEYWORD_EMPTY) != 0;
1597+
}
1598+
15911599
@Deprecated(since = "9.3.0.0")
15921600
public IRubyObject setBackRef(IRubyObject match) {
15931601
if (match.isNil()) return clearBackRef();

spec/ruby/core/data/fixtures/classes.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
module DataSpecs
22
if Data.respond_to?(:define)
33
Measure = Data.define(:amount, :unit)
4+
Single = Data.define(:value)
45

56
class MeasureWithOverriddenName < Measure
67
def self.name
78
"A"
89
end
910
end
1011

12+
class SingleWithOverriddenName < Single
13+
def self.name
14+
"A"
15+
end
16+
end
17+
1118
class DataSubclass < Data; end
1219

1320
MeasureSubclass = Class.new(Measure) do

spec/ruby/core/data/initialize_spec.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@
3737
data.unit.should == "km"
3838
end
3939

40+
it "accepts positional arguments with empty keyword arguments" do
41+
data = DataSpecs::Single.new(42, **{})
42+
43+
data.value.should == 42
44+
45+
data = DataSpecs::Measure.new(42, "km", **{})
46+
47+
data.amount.should == 42
48+
data.unit.should == "km"
49+
end
50+
4051
it "raises ArgumentError if no arguments are given" do
4152
-> {
4253
DataSpecs::Measure.new
@@ -111,6 +122,17 @@ def initialize(*, **)
111122
ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}]
112123
end
113124

125+
it "accepts positional arguments with empty keyword arguments" do
126+
data = DataSpecs::SingleWithOverriddenName.new(42, **{})
127+
128+
data.value.should == 42
129+
130+
data = DataSpecs::MeasureWithOverriddenName.new(42, "km", **{})
131+
132+
data.amount.should == 42
133+
data.unit.should == "km"
134+
end
135+
114136
# See https://github.com/ruby/psych/pull/765
115137
it "can be deserialized by calling Data.instance_method(:initialize)" do
116138
d1 = DataSpecs::Area.new(width: 2, height: 3)

spec/ruby/core/struct/fixtures/classes.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module StructClasses
33
class Apple < Struct; end
44

55
Ruby = Struct.new(:version, :platform)
6+
Single = Struct.new(:value)
67

78
Car = Struct.new(:make, :model, :year)
89

spec/ruby/core/struct/initialize_spec.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,15 @@
4848
positional_args.version.should == keyword_args.version
4949
positional_args.platform.should == keyword_args.platform
5050
end
51+
52+
it "accepts positional arguments with empty keyword arguments" do
53+
data = StructClasses::Single.new(42, **{})
54+
55+
data.value.should == 42
56+
57+
data = StructClasses::Ruby.new("3.2", "OS", **{})
58+
59+
data.version.should == "3.2"
60+
data.platform.should == "OS"
61+
end
5162
end

0 commit comments

Comments
 (0)