gt:             wc = "where(" + dblQuote(path) + " => " + rhs + ")";
context: package org.intermine.api.query.codegen;
  
  /*
   * Copyright (C) 2002-2016 FlyMine
   *
   * This code may be freely distributed and modified under the
   * terms of the GNU Lesser General Public Licence.  This should
   * be distributed with the code.  See the LICENSE file for more
   * information or http://www.gnu.org/copyleft/lesser.html.
   *
   */
  
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Map.Entry;
  
  import org.apache.commons.lang.StringUtils;
  import org.intermine.metadata.ConstraintOp;
  import org.intermine.pathquery.OrderDirection;
  import org.intermine.pathquery.OrderElement;
  import org.intermine.pathquery.OuterJoinStatus;
  import org.intermine.pathquery.PathConstraint;
  import org.intermine.pathquery.PathConstraintSubclass;
  import org.intermine.pathquery.PathConstraintAttribute;
  import org.intermine.pathquery.PathConstraintBag;
  import org.intermine.pathquery.PathConstraintLookup;
  import org.intermine.pathquery.PathConstraintLoop;
  import org.intermine.pathquery.PathConstraintMultiValue;
  import org.intermine.pathquery.PathException;
  import org.intermine.pathquery.PathQuery;
  import org.intermine.template.SwitchOffAbility;
  import org.intermine.template.TemplateQuery;
  import org.intermine.metadata.TypeUtil;
  
  /**
   * @author Alex
   */
  public class WebserviceRubyCodeGenerator implements WebserviceCodeGenerator
  {
  
      protected static final String INVALID_QUERY           = "Invalid query: ";
      protected static final String NULL_QUERY              = "Invalid query. Query can not be null.";
  
      protected static final String INDENT                  = "    ";
      protected static final String SPACE                   = " ";
      protected static final String LEFT_BRACE              = "{";
      protected static final String RIGHT_BRACE             = "}";
  
      private String endl = System.getProperty("line.separator");
  
      protected static final String TEMPLATE_BAG_CONSTRAINT = "This template contains a list "
              + "constraint, which is currently not supported.";
  
  
      private void appendBoilerPlate(StringBuffer sb, WebserviceCodeGenInfo info) {
  
          sb.append("#!/usr/bin/env ruby" + endl + endl);
          sb.append("# This is an automatically generated script to run your query" + endl);
          sb.append("# to use it you will require the intermine ruby client." + endl);
          sb.append("# To install the client, run the following command from a terminal:" + endl);
          sb.append("#" + endl);
          sb.append("#     sudo gem install intermine" + endl);
          sb.append("#" + endl);
          sb.append("# For further documentation you can visit:" + endl);
          sb.append("#          http://intermine.org/docs/ruby-docs/" + endl);
          sb.append("#     and: http://intermine.org/docs/ruby-bio-docs/" + endl);
          sb.append("#" + endl);
          sb.append("# The following two lines will be needed in every script:" + endl);
          sb.append("require \"rubygems\"" + endl);
          sb.append("require \"intermine/service\"" + endl);
          sb.append("service = Service.new(\"" + info.getServiceBaseURL() + "\"");
          if (!info.isPublic()) {
              sb.append(", \"YOUR-API-KEY\"");
          }
          sb.append(")" +  endl + endl);
      }
  
      @Override
      public String generate(WebserviceCodeGenInfo wsCodeGeninfo) {
  
          endl = wsCodeGeninfo.getLineBreak();
  
          PathQuery query = wsCodeGeninfo.getQuery();
  
          // query is null
          if (query == null) {
              return NULL_QUERY;
          }
  
          StringBuffer sb = new StringBuffer();
          appendBoilerPlate(sb, wsCodeGeninfo);
  
          try {
              if (query.getClass().toString().endsWith("TemplateQuery")) {
                  appendTemplate(sb, (TemplateQuery) query);
              } else {
                  appendPathQuery(sb, query);
              }
          } catch (InvalidQueryException e) {
              return INVALID_QUERY + e.getMessage();
          }
  
          return sb.toString();
      }
  
      private class PresentedList<T>
      {
  
          StringBuffer presented = new StringBuffer();
  
          public PresentedList(Collection<T> things) {
              for (Iterator<T> i = things.iterator(); i.hasNext();) {
                  addElement(i.next());
              }
          }
  
          public void addElement(T elem) {
              if (presented.length() > 0) {
                  presented.append(", ");
              }
              presented.append("\"" + elem.toString() + "\"");
          }
  
          @Override
          public String toString() {
              return "[" + presented.toString() + "]";
          }
      }
  
      private static Collection<String> deheadify(Collection<String> withHeads) {
          List<String> deheadeds = new ArrayList<String>();
          for (String x: withHeads) {
              deheadeds.add(decapitate(x));
          }
          return deheadeds;
      }
  
      private static String decapitate(String x) {
          return x.substring(x.indexOf('.') + 1);
      }
  
      private static String dblQuote(String x) {
          return "\"" + x + "\"";
      }
  
      private class RubyWhereClause
      {
  
          PathConstraint pc;
          String wc;
  
          public RubyWhereClause(PathConstraint pc) throws InvalidQueryException {
              this.pc = pc;
              parse();
          }
  
          public RubyWhereClause(String path, String type) throws InvalidQueryException {
              this.pc = new PathConstraintSubclass(path, type);
              parse();
          }
  
          @SuppressWarnings({ "unchecked", "rawtypes" })
          private void parse() throws InvalidQueryException {
              String className = TypeUtil.unqualifiedName(pc.getClass().toString());
              String path = pc.getPath();
              ConstraintOp op = pc.getOp();
  
              String subk = (op == null) ? null : op.toString().toLowerCase().replace(' ', '_');
              String subv = null;
              String rhs = null;
  
              if ("PathConstraintSubclass".equals(className)) {
                  // can not test from webapp
                  subv = dblQuote(((PathConstraintSubclass) pc).getType());
                  subk = "sub_class";
              } else if ("PathConstraintLoop".equals(className)) {
                  if (op.equals(ConstraintOp.EQUALS)) {
                      subk = "is";
                  } else {
                      subk = "is_not";
                  }
                  subv = dblQuote(((PathConstraintLoop) pc).getLoopPath());
              } else if ("PathConstraintMultiValue".equals(className)) {
                  subv = new PresentedList(((PathConstraintMultiValue) pc).getValues()).toString();
              } else if ("PathConstraintBag".equals(className)) {
                  subv = dblQuote(((PathConstraintBag) pc).getBag());
              } else if ("PathConstraintLookup".equals(className)) {
                  String extraValue = ((PathConstraintLookup) pc).getExtraValue();
                  if (StringUtils.isBlank(extraValue)) {
                      subv = dblQuote(((PathConstraintLookup) pc).getValue());
                  } else {
                      subv = dblQuote(((PathConstraintLookup) pc).getValue()
                              + "\", => :with => " + extraValue);
                  }
              } else if ("PathConstraintAttribute".equals(className)) {
                  String val = dblQuote(((PathConstraintAttribute) pc).getValue());
                  if (op.equals(ConstraintOp.EQUALS)) {
                      rhs = val;
                  } else {
                      subv = val;
                  }
              } else if ("PathConstraintNull".equals(className)) {
                  if (op.equals(ConstraintOp.IS_NULL))  {
                      rhs = "nil";
                  } else if (op.equals(ConstraintOp.IS_NOT_NULL)) {
                      subk = "!=";
                      subv = "nil";
                  } else {
                      throw new InvalidQueryException("Unknown null-constraint op (" + op + ")");
                  }
              } else {
                  throw new InvalidQueryException("Unknown constraint class (" + className + ")");
              }
              if (rhs == null) {
                  rhs = "{"
                        + ((subk.startsWith("!") || subk.startsWith("="))
                                ? dblQuote(subk) : ":" + subk)
                        + " => "
                        + subv
                        + "}";
              }
  