package org.jruby.javasupport.ext;
import org.jruby.*;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import static org.jruby.javasupport.JavaUtil.convertJavaToUsableRubyObject;
import static org.jruby.javasupport.JavaUtil.unwrapJavaObject;
public abstract class JavaUtilRegex {
public static void define(final Ruby runtime) {
JavaExtensions.put(runtime, java.util.regex.Pattern.class, (proxyClass) -> Pattern.define(runtime, (RubyClass) proxyClass));
JavaExtensions.put(runtime, java.util.regex.Matcher.class, (proxyClass) -> Matcher.define(runtime, (RubyClass) proxyClass));
}
@JRubyClass(name = "Java::JavaUtilRegex::Pattern")
public static class Pattern {
static RubyClass define(final Ruby runtime, final RubyClass proxy) {
proxy.defineAnnotatedMethods(Pattern.class);
return proxy;
}
@JRubyMethod(name = "=~", required = 1)
public static IRubyObject op_match(final ThreadContext context, final IRubyObject self, IRubyObject str) {
final java.util.regex.Matcher matcher = matcher(self, str);
return matcher.find() ? context.runtime.newFixnum(matcher.start()) : context.nil;
}
@JRubyMethod(name = "match", required = 1)
public static IRubyObject match(final ThreadContext context, final IRubyObject self, IRubyObject str) {
final java.util.regex.Matcher matcher = matcher(self, str);
if ( ! matcher.find() ) return context.nil;
final RubyObject matcherProxy = (RubyObject) convertJavaToUsableRubyObject(context.runtime, matcher);
matcherProxy.setInternalVariable("str", str);
return matcherProxy;
}
@JRubyMethod(name = "===", required = 1)
public static IRubyObject eqq(final ThreadContext context, final IRubyObject self, IRubyObject str) {
return RubyBoolean.newBoolean(context, matcher(self, str).find() );
}
@JRubyMethod(name = "casefold?")
public static IRubyObject casefold_p(final ThreadContext context, final IRubyObject self) {
final java.util.regex.Pattern regex = unwrapJavaObject(self);
boolean i = ( regex.flags() & java.util.regex.Pattern.CASE_INSENSITIVE ) != 0;
return RubyBoolean.newBoolean(context, i);
}
private static java.util.regex.Matcher matcher(final IRubyObject self, final IRubyObject str) {
final java.util.regex.Pattern regex = unwrapJavaObject(self);
return regex.matcher((CharSequence) str.toJava(CharSequence.class));
}
}
@JRubyClass(name = "Java::JavaUtilRegex::Matcher")
public static class Matcher {
static RubyClass define(final Ruby runtime, final RubyClass proxy) {
proxy.defineAnnotatedMethods(Matcher.class);
return (RubyClass) proxy;
}
@JRubyMethod
public static IRubyObject regexp(final ThreadContext context, final IRubyObject self) {
final java.util.regex.Matcher matcher = unwrapJavaObject(self);
return convertJavaToUsableRubyObject(context.runtime, matcher.pattern());
}
@JRubyMethod
public static IRubyObject begin(final ThreadContext context, final IRubyObject self, final IRubyObject idx) {
final java.util.regex.Matcher matcher = unwrapJavaObject(self);
if ( idx instanceof RubySymbol ) {
return context.runtime.newFixnum( matcher.start(idx.toString()) );
}
final int group = idx.convertToInteger().getIntValue();
return context.runtime.newFixnum( matcher.start(group) );
}
@JRubyMethod
public static IRubyObject end(final ThreadContext context, final IRubyObject self, final IRubyObject idx) {
final java.util.regex.Matcher matcher = unwrapJavaObject(self);
if ( idx instanceof RubySymbol ) {
return context.runtime.newFixnum( matcher.end(idx.toString()) );
}
final int group = idx.convertToInteger().getIntValue();
return context.runtime.newFixnum(matcher.end(group));
}
@JRubyMethod
public static IRubyObject offset(final ThreadContext context, final IRubyObject self, final IRubyObject idx) {
final java.util.regex.Matcher matcher = unwrapJavaObject(self);
final IRubyObject beg; final IRubyObject end;
if ( idx instanceof RubySymbol ) {
beg = context.runtime.newFixnum( matcher.start(idx.toString()) );
end = context.runtime.newFixnum( matcher.end(idx.toString()) );
}
else {
final int group = idx.convertToInteger().getIntValue();
beg = context.runtime.newFixnum( matcher.start(group) );
end = context.runtime.newFixnum( matcher.end(group) );
}
return RubyArray.newArray(context.runtime, beg, end);
}
@JRubyMethod(name = { "length", "size" })
public static RubyFixnum size(final ThreadContext context, final IRubyObject self) {
final java.util.regex.Matcher matcher = unwrapJavaObject(self);
return context.runtime.newFixnum(matcher.groupCount() + 1);
}
@JRubyMethod
public static RubyString string(final ThreadContext context, final IRubyObject self) {
return str(context, self);
}
private static RubyString str(final ThreadContext context, final IRubyObject self) {
final IRubyObject str = (IRubyObject) self.getInternalVariables().getInternalVariable("str");
return str.convertToString();
}
@JRubyMethod
public static IRubyObject pre_match(final ThreadContext context, final IRubyObject self) {
final java.util.regex.Matcher matcher = unwrapJavaObject(self);
return str(context, self).substr(context.runtime, 0, matcher.start(0));
}
@JRubyMethod
public static IRubyObject post_match(final ThreadContext context, final IRubyObject self) {
final java.util.regex.Matcher matcher = unwrapJavaObject(self);
final RubyString str = str(context, self);
final int offset = matcher.end(0);
return str.substr(context.runtime, offset, str.size() - offset);
}
@JRubyMethod
public static RubyArray to_a(final ThreadContext context, final IRubyObject self) {
return RubyArray.newArrayMayCopy(context.runtime, groups(context, self, 0));
}
@JRubyMethod
public static RubyArray captures(final ThreadContext context, final IRubyObject self) {
return RubyArray.newArrayMayCopy(context.runtime, groups(context, self, 1));
}
private static IRubyObject[] groups(final ThreadContext context, final IRubyObject self, final int off) {
final Ruby runtime = context.runtime;
final java.util.regex.Matcher matcher = unwrapJavaObject(self);
final IRubyObject[] arr = new IRubyObject[ matcher.groupCount() - off + 1 ];
for ( int i = 0; i < arr.length; i++ ) {
if ( matcher.start(i + off) == -1 ) {
arr[i] = context.nil;
}
else {
arr[i] = runtime.newString(matcher.group(i + off));
}
}
return arr;
}
@JRubyMethod(name = "[]", required = 1)
public static IRubyObject aref(final ThreadContext context, final IRubyObject self, final IRubyObject idx) {
final java.util.regex.Matcher matcher = unwrapJavaObject(self);
if ( idx instanceof RubySymbol || idx instanceof RubyString ) {
return context.runtime.newString( matcher.group(idx.toString()) );
}
if ( idx instanceof RubyInteger ) {
final int group = ((RubyInteger) idx).getIntValue();
return context.runtime.newString( matcher.group(group) );
}
return to_a(context, self).aref(idx);
}
@JRubyMethod(name = "[]", required = 2)
public static IRubyObject aref(final ThreadContext context, final IRubyObject self,
final IRubyObject arg0, final IRubyObject arg1) {
return to_a(context, self).aref(arg0, arg1);
}
@JRubyMethod(rest = true)
public static IRubyObject values_at(final ThreadContext context, final IRubyObject self, final IRubyObject[] args) {
return to_a(context, self).values_at(args);
}
}
}