////
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
////
[[style-guide]]
== Style Guide

Gremlin is a data flow language where each new step concatenation alters the stream accordingly. This aspect of the
language allows users to easily "build-up" a traversal (literally) step-by-step until the expected results are
returned. For instance:

[gremlin-groovy,modern]
----
g.V(1)
g.V(1).out('knows')
g.V(1).out('knows').out('created')
g.V(1).out('knows').out('created').groupCount()
g.V(1).out('knows').out('created').groupCount().by('name')
----

A drawback of building up a traversal is that users tend to create long, single line traversal that are hard to read.
For simple traversals, a single line is fine. For complex traversals, there are few formatting patterns that should be followed
which will yield cleaner, easier to understand traversals. For instance, the last traversal above would be written:

[gremlin-groovy,modern]
----
g.V(1).out('knows').out('created').
  groupCount().by('name')
----

Lets look at a complex traversal and analyze each line according to the recommended formatting rule is subscribes to.

[gremlin-groovy,modern]
----
g.V().out('knows').out('created').  <1>
  group().by('lang').by().          <2>
    select('java').unfold().        <3>
  in('created').hasLabel('person'). <4>
  order().                          <5>
    by(inE().count(),desc).         <6>
    by('age',asc).
  dedup().limit(10).values('name')  <7>
----


<1> A sequence of `ins().outs().filters().etc()` on a single line until it gets too long.
<2> When a barrier (reducer, aggregator, etc.) is used, put it on a new line.
<3> When a next line component is an "add on" to the previous line component, 2 space indent.
The `select()`-step in this context is "almost like" a `by()`-modulator as its projecting data out of the `group()`.
The `unfold()`-step is a data formatting necessity that should not be made too prominent.
<4> Back to a series of `ins().outs().filters().etc()` on a single line.
<5> `order()` is a barrier step and thus, should be on a new line.
<6> If there is only one `by()`-modulator (or a series of short ones), keep it on one line, else each `by()` is a new line.
<7> Back to a series `ins().outs().filters().etc()`.

=== Style Guide Rules

A generalization of the specifics above are presented below.

* Always use 2 space indent.
* No newline should ever have the same indent as the line starting with the traversal source `g`.
* Barrier steps should form line breaks unless they are simple (e.g. `sum()`).
* Complex `by()`-modulators form indented "paragraphs."
* Standard filters, maps, flatMaps remain on the same line until they get too long.

Given the diversity of traversals and the complexities introduced by lambdas (for example), these rules will not always
lead to optimal representations. However, by in large, the style rules above will help make 90% of traversals look great.
