dockyard/pg_array_parser

View on GitHub
ext/pg_array_parser/PgArrayParserEngine.java

Summary

Maintainability
B
4 hrs
Test Coverage
package pgarrayparser;

import org.jruby.*;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

@JRubyClass(name = "PgArrayParser::PgArrayParserEngine")
public class PgArrayParserEngine extends RubyObject {

    public PgArrayParserEngine(final Ruby runtime, RubyClass rubyClass) {
        super(runtime, rubyClass);
    }

    @JRubyMethod(name = "parse_pg_array")
    public RubyArray parse_pg_array( ThreadContext context, IRubyObject value) {
        String content = value.asJavaString();
        return parseData(context, content, 0);
    }

    private static RubyArray parseData( ThreadContext context, String content, int index)
    {
        RubyArray items = RubyArray.newArray(context.getRuntime());

        for( int x = index; x < content.length(); x++ ) {

            char token = content.charAt(x);

            switch (token) {
                case '{':
                    x = parseArrayContents( context, items, content, x + 1 );
                    break;
                case '}':
                    return items;
            }

        }

        return items;
    }

    private static int parseArrayContents( ThreadContext context, RubyArray items, String content, int index ) {

        StringBuilder currentItem = new StringBuilder();
        boolean isEscaping = false;
        boolean isQuoted = false;
        boolean wasQuoted = false;

        int x = index;

        for(; x < content.length(); x++ ) {

            char token = content.charAt(x);

            if ( isEscaping ) {
                currentItem.append( token );
                isEscaping = false;
            } else {
                if ( isQuoted ) {
                    switch (token) {
                        case '"':
                            isQuoted = false;
                            wasQuoted = true;
                            break;
                        case '\\':
                            isEscaping = true;
                            break;
                        default:
                            currentItem.append(token);
                    }
                } else {
                    switch (token) {
                        case '\\':
                            isEscaping = true;
                            break;
                        case ',':
                            addItem(context, items, currentItem, wasQuoted);
                            currentItem = new StringBuilder();
                            wasQuoted = false;
                            break;
                        case '"':
                            isQuoted = true;
                            break;
                        case '{':
                            RubyArray internalItems = RubyArray.newArray(context.getRuntime());
                            x = parseArrayContents( context, internalItems, content, x + 1 );
                            items.add(internalItems);
                            break;
                        case '}':
                            addItem(context, items, currentItem, wasQuoted);
                            return x;
                        default:
                            currentItem.append(token);
                    }
                }
            }

        }

        return x;
    }

    private static void addItem( ThreadContext context, RubyArray items, StringBuilder builder, boolean quoted ) {
        String value = builder.toString();

        if ( !quoted && value.length() == 0 ) {
            return;
        }

        if ( !quoted && "NULL".equalsIgnoreCase( value ) ) {
            items.add(context.getRuntime().getNil());
        } else {
            items.add(RubyString.newString( context.getRuntime(), value ));
        }
    }

}