README.md in grumlin-0.12.5 vs README.md in grumlin-0.13.0

- old
+ new

@@ -12,11 +12,11 @@ **Important**: Grumlin is based on the [async stack](https://github.com/socketry/async) and utilizes [async-websocket](https://github.com/socketry/async-websocket). Code using grumlin must be executed in an async event loop. -**Warning:** Grumlin is in development, but ready for simple use cases +**Warning**: Grumlin is in development, but ready for simple use cases ## Table of contents - [Install](#install) - [Usage](#usage) - [Development](#development) @@ -49,16 +49,16 @@ end ``` ### Traversing graphs -**Warning:** Not all steps and tools described in the standard are supported +**Warning**: Not all steps and tools described in the standard are supported #### Sugar Grumlin provides an easy to use module called `Grumlin::Sugar`. Once included in your class it injects some useful -constants and methods turning your class into an entrypoint for traversals. +constants and methods turning your class into an entrypoint for traversals with pure gremlin experience. ```ruby class MyRepository include Grumlin::Sugar @@ -67,9 +67,112 @@ .has(T.label, "node") .has(:property1, property1) .has(:property2, property2) .order.by(:property3, Order.asc).limit(10) .toList + end +end +``` + +#### Shortcuts + +**Shortcuts** is a way to share and organize gremlin code. They let developers define their own steps consisting of +sequences of standard gremlin steps, other shortcuts and even add new initially unsupported by Grumlin steps. +Remember ActiveRecord scopes? Shortcuts are very similar. `Grumlin::Shortcuts#with_shortcuts` wraps a given object into +a proxy object that simply proxies all methods existing in the wrapped object to it and handles shortcuts. + +**Important**: if a shortcut's name matches a name of a method defined on the wrapped object, this shortcut will be +be ignored because methods have higher priority. You cannot override supported by Grumlin steps with shortcuts, +`Grumlin::Shortcuts.shortcut` will raise an `ArgumentError`. Please carefully choose names for your shortcuts. + +Shortcuts are designed to be used with `Grumlin::Repository` but still can be used separately, with `Grumlin::Sugar` +for example. + +**Defining**: +```ruby + +# Defining shortcuts +class ColorShortcut + extend Grumlin::Shortcuts + + # Custom step + shortcut :hasColor do |color| + has(:color, color) + end +end + +class ChooseShortcut + extend Grumlin::Shortcuts + + # Standard Gremlin step + shortcut :choose do |*args| + step(:choose, *args) + end +end + +class AllShortcuts + extend Grumlin::Shortcuts + + # Adding shortcuts from other modules + shortcuts_from ColorShortcut + shortcuts_from ChooseShortcut +end +``` + +**Using with Grumlin::Sugar**: +```ruby +class MyRepository + include Grumlin::Sugar + extend Grumlin::Shortcuts + + shortcuts_from AllShortcuts + + # Wrapping a traversal + def red_triangles + with_shortcuts(g).V.hasLabel(:triangle) + .hasColor("red") + .toList + end + + # Wrapping _ + def something_else + with_shortcuts(g).V.hasColor("red") + .repeat(with_shortcuts(__) + .out(:has) + .hasColor("blue")).toList + end +end +``` + +#### Grumlin::Repository +`Grumlin::Repository` combines functionality of `Grumlin::Sugar` and `Grumlin::Shortcuts` as well as adds a few useful +shortcuts to make gremlin code more rubyish. Can be used as a drop in replacement for `Grumlin::Sugar`. Remember that +`Grumlin::Sugar` needs to be included, but `Grumlin::Repository` - extended. **Classes extending `Grumlin::Repository` +or `Grumlin::Shortcuts` can be inherited**, successors don't need to extend them again and have access to shortcuts +defined in the ancestor. + +**Using**: + +```ruby +class MyRepository + extend Grumlin::Repository + + # Repository supports all Grumlin::Shortcut and Grumlin::Sugar features. + # It can add shortcuts from another repository or a shortcuts module + shortcuts_from ChooseShortcut + + shortcut :red_triangles do |color| + # hasAll unwraps a hash of properties into a chain of `has` steps: + # hasAll(name1: :value, name2: :value) == has(:name1, :value).has(:name2, :value) + # the `props` shortcut does exactly the same but with `property` steps. + hasAll(T.label => :triangle, color: color) + end + + # g and __ are already aware of shortcuts + def red_triangles + g.V.hasLabel(:triangle) + .hasColor("red") + .toList end end ``` #### IRB