[ 
https://issues.apache.org/jira/browse/TINKERPOP-1278?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15260825#comment-15260825
 ] 

Marko A. Rodriguez commented on TINKERPOP-1278:
-----------------------------------------------

I decided to test the idea. Check it out:

Assume this is {{PythonVariantConverter}}.

{code}
public class VariantConverter {

    public String source(final String source) {
        return source;
    }

    public String concat() {
        return ".";
    }

    public String step(final String stepName, final Object... args) {
        if (args.length == 0)
            return stepName + "()";
        else
            return stepName + "(" + stringify(args) + ")";
    }

    private static String stringify(final Object... args) {
        String temp = "";
        for (final Object object : args) {
            if (object instanceof String) {
                temp = temp + "\"${object}\",";
            }
        }
        return temp.substring(0, temp.length() - 1);
    }
}
{code}

{code}
class VariantTraversal implements GraphTraversal {

    private static GremlinGroovyScriptEngine scriptEngine = new 
GremlinGroovyScriptEngine();

    private String variantString;
    private String traversalSourceName;
    private TraversalSource traversalSource;
    private VariantConverter converter = new VariantConverter();
    private Traversal traversal;

    static {
        VariantTraversal.metaClass.invokeMethod = { String name, args ->
            if (name.equals("hasNext") || name.equals("next"))
                return delegate.metaClass.getMetaMethod(name, 
*args).invoke(delegate, args);
            variantString = variantString + converter.concat() + 
converter.step(name, args);
            return delegate;
        }
    }

    public VariantTraversal(final String traversalSourceName, final 
TraversalSource traversalSource) {
        this.traversalSourceName = traversalSourceName;
        this.traversalSource = traversalSource;
        this.variantString = traversalSourceName;
    }

    @Override
    public String toString() {
        return this.variantString;
    }

    @Override
    boolean hasNext() {
        if (null == this.traversal)
            this.compile();
        return this.traversal.hasNext();
    }

    @Override
    Object next() {
        if (null == this.traversal)
            this.compile();
        return this.traversal.next();
    }

    private void compile() {
        SimpleBindings bindings = new SimpleBindings();
        bindings.put(this.traversalSourceName, this.traversalSource);
        this.traversal = (Traversal) scriptEngine.eval(this.variantString, 
bindings);
    }
}
{code}

{code}
class VariantTraversalTest {
    @Test
    public void playTest() {
        final Graph graph = EmptyGraph.instance();
        final Traversal traversal = new VariantTraversal("g", 
graph.traversal()).V().out("created").groupCount().by("name");
        println traversal;
        println traversal.hasNext();
        println traversal.next();
        println traversal.hasNext();
    }
}
{code}

The output of the test above is (note its an {{EmptyGraph}}):

{code}
g.V().out("created").groupCount().by("name")
true
[:]
false
{code}

There it is! ... All the language variant needs to do is implement their own 
{{VariantConverter}}... Groovy and introspection and ScriptEngine, etc. will 
take care of the rest.

> Support at least 3 Gremlin language variants.
> ---------------------------------------------
>
>                 Key: TINKERPOP-1278
>                 URL: https://issues.apache.org/jira/browse/TINKERPOP-1278
>             Project: TinkerPop
>          Issue Type: Improvement
>    Affects Versions: 3.2.0-incubating
>            Reporter: Marko A. Rodriguez
>
> As discussed on dev@...
> Apache TinkerPop should provide, out-of-the-box, at least 3 Gremlin language 
> variants. It would be cool if these were:
> * Python (Mark Henderson)
> * PHP ([~PommeVerte])
> * Ruby (?[~okram])
> I think each of these should be generated using the reflection-model 
> presented in 
> http://tinkerpop.apache.org/docs/3.2.1-SNAPSHOT/tutorials/gremlin-language-variants/.
>  Moreover, on every {{mvn clean install}}, the code for these variants is 
> generated.
> Given the desire to separate language variants from language drivers, I think 
> that a language driver for each variant above should be "plugable." Moreover, 
> we should provide one driver implementation for each -- simple GremlinServer 
> REST.
> {code}
> gremlin-variants/
>   gremlin-ruby/
>     gremlin_ruby.rb
>     gremlin_ruby_rest_driver.rb
>   gremlin-php/
>     Gremlin_PHP.php
>     Gremlin_PHP_REST_Driver.php
>   gremlin-python/
>     gremlin-python.py
>     gremlin-python-rest-driver.py
> {code}
> Next, each variant implementation should be testable. This is PAINFUL if we 
> have to implement each {{g_V_out_repeatXasXaXX}} test case in 
> {{ProcessXXXSuite}}. Perhaps some RegEx transducer magic could be used to 
> convert all those tests from Gremlin-Java to the respective host language? 
> However, even if we do that, we still have the problem of how to test the 
> returned results. 
> I think what we should test the returned results using the JVM. For instance, 
> JRuby, Jython, JPHP (does it exist?). If we do this, we will save ourselves a 
> massive headache. All we have to do is create a {{GraphProvider}} that uses 
> {{TinkerGraph}} and whose {{TraversalSource}} is some sort of wrapper around 
> reflection-generated Ruby (e.g.).
> {code}
> g.V.out_e("knows") // returns a Ruby iterator
> {code}
> That Ruby iterator should be converted to a Java iterator and then the 
> {{ProcessXXXSuite}} can verify the results.
> With this, most everything is reflectively constructed.
> {code}
> gremlin_ruby.rb             // generated via Java reflection
> gremlin_ruby_rest_driver.rb // manually coded
> match_test.rb               // generated via RegEx transducer
> has_test.rb                 // generated via RegEx transducer
> ...
> RubyGraphProvider.java        // manually coded
> RubyProcessStandardSuite.java // manually coded
> RubyProcessComputerSuite.java // manually coded
> {code}
> Thus, the testing data flow would be:
> {code}
> MatchTest.Traversals.java --transducer-> match_test.rb
> match-test.rb --REST--> GremlinServer
> GremlinServer --GraphSON-->match-test.rb
> GraphSON --JRuby/GraphSONReader-->Java objects
> Java objects --JRuby-->MatchTest.java 
> {code}



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to