javax0.jamal.ruby.RubyProperty Maven / Gradle / Ivy
package javax0.jamal.ruby;
import javax0.jamal.api.BadSyntax;
import javax0.jamal.api.InnerScopeDependent;
import javax0.jamal.api.Input;
import javax0.jamal.api.Macro;
import javax0.jamal.api.Processor;
import javax0.jamal.tools.InputHandler;
import org.jruby.Ruby;
import org.jruby.RubyComplex;
import org.jruby.RubyFixnum;
import org.jruby.RubyFloat;
import org.jruby.RubyRational;
import org.jruby.RubyString;
import org.jruby.RubySymbol;
import java.util.Optional;
import java.util.function.Function;
import java.util.regex.Pattern;
public class RubyProperty implements Macro, InnerScopeDependent {
@Override
public String evaluate(Input in, Processor processor) throws BadSyntax {
final var shell = Shell.getShell(in, processor);
InputHandler.skipWhiteSpaces(in);
final var id = InputHandler.fetchId(in);
InputHandler.skipWhiteSpaces(in);
if (in.length() == 0) {
return "" + shell.property(id);
}
if (InputHandler.firstCharIs(in, '=')) {
InputHandler.skip(in, 1);
} else {
throw new BadSyntax("There must be a '=' after the name of the Ruby property to assign a value to it.");
}
InputHandler.skipWhiteSpaces(in);
shell.property(id, cast(in.toString(), shell.shell.getProvider().getRuntime()));
return "";
}
private static Object cast(String s, Ruby ruby) throws BadSyntax {
try {
return
cast(s, "to_sym", k -> RubySymbol.newSymbol(ruby, k)).orElseGet(() ->
cast(s, "to_r", k -> toRational(ruby, k)).orElseGet(() ->
cast(s, "to_f", k -> RubyFloat.newFloat(ruby, Double.parseDouble(k))).orElseGet(() ->
cast(s, "to_i", k -> RubyFixnum.newFixnum(ruby, Long.parseLong(k))).orElseGet(() ->
cast(s, "to_c", k -> toComplex(ruby, k)).orElseGet(() ->
cast(s, "to_c/i", k -> toComplexInt(ruby, k)).orElseGet(() ->
cast(s, "to_s", k -> RubyString.newString(ruby, k)).orElseGet(
() -> RubyString.newString(ruby, s)
)
)
)
)
)
)
);
} catch (Exception e) {
throw new BadSyntax("There was an error during casting the value '" + s + "'", e);
}
}
private static RubyRational toRational(Ruby ruby, final String s) {
final var parts = s.split("/", -1);
if (parts.length != 2) {
throw new IllegalArgumentException("Ruby rational has to be 'number / number' format and '" + s + "' is not.");
}
return RubyRational.newRational(ruby, Long.parseLong(parts[0].trim()), Long.parseLong(parts[1].trim()));
}
private static final String FLOAT_REGEX = "[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?";
private static final String INT_REGEX = "[-+]?[0-9]*";
private static final Pattern FLOAT_PATTERN = Pattern.compile("(" + FLOAT_REGEX + ")\\s*\\+\\s*(" + FLOAT_REGEX + ")\\s*i");
private static final Pattern INT_PATTERN = Pattern.compile("(" + INT_REGEX + ")\\s*\\+\\s*(" + INT_REGEX + ")\\s*i");
private static RubyComplex toComplex(Ruby ruby, final String s) {
final var matcher = FLOAT_PATTERN.matcher(s);
if (!matcher.matches()) {
throw new IllegalArgumentException("Ruby complex has to be 'R+Ci' format and '" + s + "' is not.");
}
return RubyComplex.newComplexRaw(ruby, RubyFloat.newFloat(ruby, Double.parseDouble(matcher.group(1))),
RubyFloat.newFloat(ruby, Double.parseDouble(matcher.group(2))));
}
private static RubyComplex toComplexInt(Ruby ruby, final String s) {
final var matcher = INT_PATTERN.matcher(s);
if (!matcher.matches()) {
throw new IllegalArgumentException("Ruby complex has to be 'R+Ci' format and '" + s + "' is not.");
}
return RubyComplex.newComplexRaw(ruby, RubyFixnum.newFixnum(ruby, Long.parseLong(matcher.group(1))),
RubyFixnum.newFixnum(ruby, Long.parseLong(matcher.group(2))));
}
private static Optional
© 2015 - 2024 Weber Informatics LLC | Privacy Policy