Skip to content

Commit

Permalink
Merge pull request #5061 from nomadium/keyword-arguments-on-struct-new
Browse files Browse the repository at this point in the history
Add keyword_init option to Struct.new
  • Loading branch information
headius committed Mar 21, 2018
2 parents 0d9ec85 + 6746380 commit 55fa773
Showing 1 changed file with 33 additions and 0 deletions.
33 changes: 33 additions & 0 deletions core/src/main/java/org/jruby/RubyStruct.java
Expand Up @@ -32,8 +32,11 @@
***** END LICENSE BLOCK *****/
package org.jruby;

import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.ast.util.ArgsUtil;
import org.jruby.common.IRubyWarnings.ID;
import org.jruby.exceptions.RaiseException;
import org.jruby.internal.runtime.methods.DynamicMethod;
Expand Down Expand Up @@ -174,6 +177,7 @@ private IRubyObject getByName(String name) {
public static RubyClass newInstance(IRubyObject recv, IRubyObject[] args, Block block) {
String name = null;
boolean nilName = false;
boolean keywordInit = false;
Ruby runtime = recv.getRuntime();

if (args.length > 0) {
Expand All @@ -187,7 +191,14 @@ public static RubyClass newInstance(IRubyObject recv, IRubyObject[] args, Block

RubyArray member = runtime.newArray();

if (args[args.length - 1] instanceof RubyHash) {
RubyHash kwArgs = args[args.length - 1].convertToHash();
IRubyObject[] rets = ArgsUtil.extractKeywordArgs(runtime.getCurrentContext(), kwArgs, "keyword_init");
keywordInit = rets[0].isTrue();
}

for (int i = (name == null && !nilName) ? 0 : 1; i < args.length; i++) {
if (i == args.length - 1 && args[i] instanceof RubyHash) break;
member.append(runtime.newSymbol(args[i].asJavaString()));
}

Expand Down Expand Up @@ -219,11 +230,13 @@ public static RubyClass newInstance(IRubyObject recv, IRubyObject[] args, Block

newStruct.setInternalVariable("__size__", member.length());
newStruct.setInternalVariable("__member__", member);
newStruct.setInternalVariable("__keyword_init__", keywordInit ? runtime.getTrue() : runtime.getFalse());

newStruct.getSingletonClass().defineAnnotatedMethods(StructMethods.class);

// define access methods.
for (int i = (name == null && !nilName) ? 0 : 1; i < args.length; i++) {
if (i == args.length - 1 && args[i] instanceof RubyHash) break;
final String memberName = args[i].asJavaString();
// if we are storing a name as well, index is one too high for values
final int index = (name == null && !nilName) ? i : i - 1;
Expand Down Expand Up @@ -274,6 +287,13 @@ public static IRubyObject newStruct(IRubyObject recv, IRubyObject arg0, IRubyObj
public static IRubyObject members(IRubyObject recv, Block block) {
return RubyStruct.members19(recv, block);
}

@JRubyMethod
public static IRubyObject inspect(IRubyObject recv) {
IRubyObject keywordInit = RubyStruct.getInternalVariable((RubyClass)recv, "__keyword_init__");
if (!keywordInit.isTrue()) return recv.inspect();
return recv.inspect().convertToString().catString("(keyword_init: true)");
}
}

/** Create new Structure.
Expand Down Expand Up @@ -332,6 +352,19 @@ public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
modify();
checkSize(args.length);

IRubyObject keywordInit = RubyStruct.getInternalVariable(classOf(), "__keyword_init__");

if (keywordInit.isTrue()) {
if (args.length != 1 || !(args[0] instanceof RubyHash)) throw context.runtime.newArgumentError("wrong number of arguments (given " + args.length + ", expected 0)");
RubyHash kwArgs = args[0].convertToHash();
RubyArray __members__ = __member__();
String[] members = Stream.of(__members__.toJavaArray())
.map(o -> RubySymbol.objectToSymbolString(o))
.collect(Collectors.toList())
.toArray(new String[__members__.size()]);
args = ArgsUtil.extractKeywordArgs(context, kwArgs, members);
}

System.arraycopy(args, 0, values, 0, args.length);
Helpers.fillNil(values, args.length, values.length, context.runtime);

Expand Down

0 comments on commit 55fa773

Please sign in to comment.