Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion core/src/main/java/org/jruby/RubyData.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import static org.jruby.runtime.ThreadContext.CALL_KEYWORD_EMPTY;
import static org.jruby.runtime.ThreadContext.clearCallInfo;
import static org.jruby.runtime.ThreadContext.hasKeywords;
import static org.jruby.runtime.ThreadContext.hasNonemptyKeywords;
import static org.jruby.runtime.ThreadContext.resetCallInfo;
import static org.jruby.runtime.invokedynamic.MethodNames.HASH;
import static org.jruby.util.RubyStringBuilder.str;
Expand Down Expand Up @@ -310,7 +311,7 @@ public static IRubyObject rbNew(ThreadContext context, IRubyObject self, IRubyOb

RubyHash init;
int callInfo = resetCallInfo(context);
if (hasKeywords(callInfo) && (callInfo & CALL_KEYWORD_EMPTY) == 0) {
if (hasNonemptyKeywords(callInfo)) {
if (!(hashOrElt instanceof RubyHash)) {
throw argumentError(context, 1, 0, 0);
}
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/org/jruby/RubyStruct.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
import static org.jruby.runtime.Helpers.invokedynamic;
import static org.jruby.runtime.ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR;
import static org.jruby.runtime.ThreadContext.hasKeywords;
import static org.jruby.runtime.ThreadContext.hasNonemptyKeywords;
import static org.jruby.runtime.Visibility.PRIVATE;
import static org.jruby.runtime.invokedynamic.MethodNames.HASH;
import static org.jruby.RubyEnumerator.SizeFn;
Expand Down Expand Up @@ -531,7 +532,7 @@ public IRubyObject initialize(ThreadContext context) {

@JRubyMethod(visibility = PRIVATE)
public IRubyObject initialize(ThreadContext context, IRubyObject arg0) {
boolean keywords = hasKeywords(ThreadContext.resetCallInfo(context));
boolean keywords = hasNonemptyKeywords(ThreadContext.resetCallInfo(context));

if (keywords) {
return setupStructValuesFromHash(context, (RubyHash) arg0);
Expand Down
8 changes: 8 additions & 0 deletions core/src/main/java/org/jruby/runtime/ThreadContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -1588,6 +1588,14 @@ public static boolean hasKeywords(int callInfo) {
return (callInfo & CALL_KEYWORD) != 0;
}

public static boolean hasNonemptyKeywords(int callInfo) {
return (callInfo & CALL_KEYWORD) != 0 && !keywordsEmpty(callInfo);
}

public static boolean keywordsEmpty(int callInfo) {
return (callInfo & CALL_KEYWORD_EMPTY) != 0;
}

@Deprecated(since = "9.3.0.0")
public IRubyObject setBackRef(IRubyObject match) {
if (match.isNil()) return clearBackRef();
Expand Down
7 changes: 7 additions & 0 deletions spec/ruby/core/data/fixtures/classes.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
module DataSpecs
if Data.respond_to?(:define)
Measure = Data.define(:amount, :unit)
Single = Data.define(:value)

class MeasureWithOverriddenName < Measure
def self.name
"A"
end
end

class SingleWithOverriddenName < Single
def self.name
"A"
end
end

class DataSubclass < Data; end

MeasureSubclass = Class.new(Measure) do
Expand Down
22 changes: 22 additions & 0 deletions spec/ruby/core/data/initialize_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@
data.unit.should == "km"
end

it "accepts positional arguments with empty keyword arguments" do
data = DataSpecs::Single.new(42, **{})

data.value.should == 42

data = DataSpecs::Measure.new(42, "km", **{})

data.amount.should == 42
data.unit.should == "km"
end

it "raises ArgumentError if no arguments are given" do
-> {
DataSpecs::Measure.new
Expand Down Expand Up @@ -111,6 +122,17 @@ def initialize(*, **)
ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}]
end

it "accepts positional arguments with empty keyword arguments" do
data = DataSpecs::SingleWithOverriddenName.new(42, **{})

data.value.should == 42

data = DataSpecs::MeasureWithOverriddenName.new(42, "km", **{})

data.amount.should == 42
data.unit.should == "km"
end

# See https://github.com/ruby/psych/pull/765
it "can be deserialized by calling Data.instance_method(:initialize)" do
d1 = DataSpecs::Area.new(width: 2, height: 3)
Expand Down
1 change: 1 addition & 0 deletions spec/ruby/core/struct/fixtures/classes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module StructClasses
class Apple < Struct; end

Ruby = Struct.new(:version, :platform)
Single = Struct.new(:value)

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

Expand Down
11 changes: 11 additions & 0 deletions spec/ruby/core/struct/initialize_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,15 @@
positional_args.version.should == keyword_args.version
positional_args.platform.should == keyword_args.platform
end

it "accepts positional arguments with empty keyword arguments" do
data = StructClasses::Single.new(42, **{})

data.value.should == 42

data = StructClasses::Ruby.new("3.2", "OS", **{})

data.version.should == "3.2"
data.platform.should == "OS"
end
end