grumlin 0.15.4 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +10 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +2 -2
- data/lib/definitions.yml +5 -0
- data/lib/grumlin/action.rb +124 -0
- data/lib/grumlin/client.rb +2 -2
- data/lib/grumlin/expressions/p.rb +12 -17
- data/lib/grumlin/expressions/text_p.rb +15 -0
- data/lib/grumlin/expressions/with_options.rb +16 -2
- data/lib/grumlin/repository.rb +2 -2
- data/lib/grumlin/shortcut.rb +27 -0
- data/lib/grumlin/shortcuts/properties.rb +6 -2
- data/lib/grumlin/shortcuts.rb +12 -13
- data/lib/grumlin/shortcuts_applyer.rb +48 -0
- data/lib/grumlin/step_data.rb +18 -0
- data/lib/grumlin/steps.rb +77 -0
- data/lib/grumlin/steps_serializers/bytecode.rb +65 -0
- data/lib/grumlin/steps_serializers/human_readable_bytecode.rb +36 -0
- data/lib/grumlin/steps_serializers/serializer.rb +16 -0
- data/lib/grumlin/steps_serializers/string.rb +42 -0
- data/lib/grumlin/sugar.rb +4 -4
- data/lib/grumlin/traversal_start.rb +51 -0
- data/lib/grumlin/typed_value.rb +0 -15
- data/lib/grumlin/typing.rb +2 -0
- data/lib/grumlin/version.rb +1 -1
- metadata +13 -8
- data/lib/grumlin/anonymous_step.rb +0 -45
- data/lib/grumlin/bytecode.rb +0 -70
- data/lib/grumlin/expressions/u.rb +0 -16
- data/lib/grumlin/shortcut_proxy.rb +0 -53
- data/lib/grumlin/step.rb +0 -43
- data/lib/grumlin/traversal.rb +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce713ebd08c676dfe38124e0286963ea18ee8d5d51f678096fd5f2ae8c28c51c
|
4
|
+
data.tar.gz: 6cd25c9ac701a2276fdb470b55b4ebaf123323521c6cd8d4d87365b68d604426
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 81b5b522b5d183240d27cb36285f448e4918386cd267ea84fcffb2cc763d156d272844a4ffab2e00999d5c5be129930d905220506e07702ff150c49ac7388d1b
|
7
|
+
data.tar.gz: f4d56b0a66d91f8f454964a8d42de46fa0b6b85595c48e67e09875e01bfdb96eb131e0c6cb5ec395ebeb7dda59c45ff67c445f88e75a12a03436689d9ba14279
|
data/.rubocop.yml
CHANGED
@@ -60,6 +60,9 @@ RSpec/MultipleExpectations:
|
|
60
60
|
RSpec/DescribeClass:
|
61
61
|
Enabled: false
|
62
62
|
|
63
|
+
RSpec/MultipleMemoizedHelpers:
|
64
|
+
Max: 7
|
65
|
+
|
63
66
|
Style/WordArray:
|
64
67
|
Exclude:
|
65
68
|
- spec/**/*_spec.rb
|
@@ -77,3 +80,10 @@ Style/Documentation:
|
|
77
80
|
|
78
81
|
Style/MultilineBlockChain:
|
79
82
|
Enabled: false
|
83
|
+
|
84
|
+
|
85
|
+
# TODO:
|
86
|
+
# Style/SymbolArray:
|
87
|
+
# EnforcedStyle: brackets
|
88
|
+
# Style/WordArray:
|
89
|
+
# EnforcedStyle: brackets
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
## [0.16.0] - 2022-03-11
|
2
|
+
|
3
|
+
- Query building is rewritten from scratch. No public APIs were changed. [Details](https://github.com/babbel/grumlin/pull/64)
|
4
|
+
- Add support for [TextP](https://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/process/traversal/TextP.html)
|
5
|
+
|
1
6
|
## [0.15.4] - 2022-01-20
|
2
7
|
|
3
8
|
- Move step and expression definitions to a yaml file for better diffs
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
grumlin (0.
|
4
|
+
grumlin (0.16.1)
|
5
5
|
async-pool (~> 0.3)
|
6
6
|
async-websocket (~> 0.19)
|
7
7
|
oj (~> 3.12)
|
@@ -28,7 +28,7 @@ GEM
|
|
28
28
|
protocol-http (~> 0.22.0)
|
29
29
|
protocol-http1 (~> 0.14.0)
|
30
30
|
protocol-http2 (~> 0.14.0)
|
31
|
-
async-io (1.
|
31
|
+
async-io (1.33.0)
|
32
32
|
async
|
33
33
|
async-pool (0.3.9)
|
34
34
|
async (>= 1.25)
|
data/lib/definitions.yml
CHANGED
@@ -32,17 +32,21 @@ steps:
|
|
32
32
|
- in
|
33
33
|
- inE
|
34
34
|
- inV
|
35
|
+
- inject
|
35
36
|
- is
|
36
37
|
- label
|
37
38
|
- limit
|
38
39
|
- map
|
40
|
+
- none
|
39
41
|
- not
|
42
|
+
- option
|
40
43
|
- or
|
41
44
|
- order
|
42
45
|
- out
|
43
46
|
- outE
|
44
47
|
- outV
|
45
48
|
- path
|
49
|
+
- profile
|
46
50
|
- project
|
47
51
|
- properties
|
48
52
|
- property
|
@@ -68,6 +72,7 @@ steps:
|
|
68
72
|
- V
|
69
73
|
- addE
|
70
74
|
- addV
|
75
|
+
- inject
|
71
76
|
configuration:
|
72
77
|
- withSack
|
73
78
|
- withSideEffect
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grumlin
|
4
|
+
class Action
|
5
|
+
START_STEPS = Grumlin.definitions.dig(:steps, :start).map(&:to_sym).freeze
|
6
|
+
CONFIGURATION_STEPS = Grumlin.definitions.dig(:steps, :configuration).map(&:to_sym).freeze
|
7
|
+
REGULAR_STEPS = Grumlin.definitions.dig(:steps, :regular).map(&:to_sym).freeze
|
8
|
+
|
9
|
+
ALL_STEPS = START_STEPS + CONFIGURATION_STEPS + REGULAR_STEPS
|
10
|
+
|
11
|
+
attr_reader :name, :args, :params, :shortcuts, :next_step, :configuration_steps, :previous_step
|
12
|
+
|
13
|
+
def initialize(name, args: [], params: {}, previous_step: nil, shortcuts: {}, pool: Grumlin.default_pool)
|
14
|
+
@name = name.to_sym
|
15
|
+
@args = args # TODO: add recursive validation: only json types or Action
|
16
|
+
@params = params # TODO: add recursive validation: only json types
|
17
|
+
@previous_step = previous_step
|
18
|
+
@shortcuts = shortcuts
|
19
|
+
@pool = pool
|
20
|
+
end
|
21
|
+
|
22
|
+
ALL_STEPS.each do |step|
|
23
|
+
define_method step do |*args, **params|
|
24
|
+
step(step, *args, **params)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def step(name, *args, **params)
|
29
|
+
Action.new(name, args: args, params: params, previous_step: self, shortcuts: @shortcuts, pool: @pool)
|
30
|
+
end
|
31
|
+
|
32
|
+
def configuration_step?
|
33
|
+
CONFIGURATION_STEPS.include?(@name)
|
34
|
+
end
|
35
|
+
|
36
|
+
def start_step?
|
37
|
+
START_STEPS.include?(@name)
|
38
|
+
end
|
39
|
+
|
40
|
+
def regular_step?
|
41
|
+
REGULAR_STEPS.include?(@name)
|
42
|
+
end
|
43
|
+
|
44
|
+
def supported_step?
|
45
|
+
ALL_STEPS.include?(@name)
|
46
|
+
end
|
47
|
+
|
48
|
+
def shortcut?
|
49
|
+
@shortcuts.key?(@name)
|
50
|
+
end
|
51
|
+
|
52
|
+
def arguments
|
53
|
+
@arguments ||= [*@args].tap do |args|
|
54
|
+
args << @params if @params.any?
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def method_missing(name, *args, **params)
|
59
|
+
return step(name, *args, **params) if @shortcuts.key?(name)
|
60
|
+
|
61
|
+
super
|
62
|
+
end
|
63
|
+
|
64
|
+
def ==(other)
|
65
|
+
self.class == other.class &&
|
66
|
+
@name == other.name &&
|
67
|
+
@args == other.args &&
|
68
|
+
@params == other.params &&
|
69
|
+
@previous_step == other.previous_step &&
|
70
|
+
@shortcuts == other.shortcuts
|
71
|
+
end
|
72
|
+
|
73
|
+
def steps
|
74
|
+
@steps ||= Steps.from(self)
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_s(**params)
|
78
|
+
StepsSerializers::String.new(steps, **params).serialize
|
79
|
+
end
|
80
|
+
|
81
|
+
# TODO: add human readable mode
|
82
|
+
def inspect
|
83
|
+
conf_steps, regular_steps = StepsSerializers::HumanReadableBytecode.new(steps).serialize
|
84
|
+
"#{conf_steps.any? ? conf_steps : nil}#{regular_steps}"
|
85
|
+
end
|
86
|
+
|
87
|
+
def bytecode(no_return: false)
|
88
|
+
StepsSerializers::Bytecode.new(steps, no_return: no_return)
|
89
|
+
end
|
90
|
+
|
91
|
+
def next
|
92
|
+
to_enum.next
|
93
|
+
end
|
94
|
+
|
95
|
+
def hasNext # rubocop:disable Naming/MethodName
|
96
|
+
to_enum.peek
|
97
|
+
true
|
98
|
+
rescue StopIteration
|
99
|
+
false
|
100
|
+
end
|
101
|
+
|
102
|
+
def to_enum
|
103
|
+
@to_enum ||= toList.to_enum
|
104
|
+
end
|
105
|
+
|
106
|
+
def toList
|
107
|
+
@pool.acquire do |client|
|
108
|
+
client.write(bytecode)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def iterate
|
113
|
+
@pool.acquire do |client|
|
114
|
+
client.write(bytecode(no_return: true))
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def respond_to_missing?(name, _include_private = false)
|
121
|
+
@shortcuts.key?(name)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
data/lib/grumlin/client.rb
CHANGED
@@ -97,7 +97,7 @@ module Grumlin
|
|
97
97
|
def write(bytecode)
|
98
98
|
raise NotConnectedError unless connected?
|
99
99
|
|
100
|
-
request = to_query(bytecode
|
100
|
+
request = to_query(bytecode)
|
101
101
|
channel = @request_dispatcher.add_request(request)
|
102
102
|
@transport.write(request)
|
103
103
|
|
@@ -130,7 +130,7 @@ module Grumlin
|
|
130
130
|
op: "bytecode",
|
131
131
|
processor: "traversal",
|
132
132
|
args: {
|
133
|
-
gremlin: bytecode,
|
133
|
+
gremlin: { :@type => "g:Bytecode", :@value => bytecode.serialize },
|
134
134
|
aliases: { g: :g }
|
135
135
|
}
|
136
136
|
}
|
@@ -2,28 +2,23 @@
|
|
2
2
|
|
3
3
|
module Grumlin
|
4
4
|
module Expressions
|
5
|
-
|
6
|
-
class
|
7
|
-
|
8
|
-
def initialize(name, args:, arg_type: nil)
|
9
|
-
super(type: "P")
|
10
|
-
@name = name
|
11
|
-
@args = args
|
12
|
-
@arg_type = arg_type
|
13
|
-
end
|
5
|
+
class P
|
6
|
+
class Predicate
|
7
|
+
attr_reader :namespace, :name, :value, :type
|
14
8
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
9
|
+
def initialize(namespace, name, value:, type: nil)
|
10
|
+
@namespace = namespace
|
11
|
+
@name = name
|
12
|
+
@value = value
|
13
|
+
@type = type
|
21
14
|
end
|
15
|
+
end
|
22
16
|
|
17
|
+
class << self
|
23
18
|
# TODO: support more predicates
|
24
19
|
%i[eq neq].each do |predicate|
|
25
20
|
define_method predicate do |*args|
|
26
|
-
Predicate.new(predicate,
|
21
|
+
Predicate.new("P", predicate, value: args[0])
|
27
22
|
end
|
28
23
|
end
|
29
24
|
|
@@ -36,7 +31,7 @@ module Grumlin
|
|
36
31
|
else
|
37
32
|
args.to_a
|
38
33
|
end
|
39
|
-
Predicate.new(predicate,
|
34
|
+
Predicate.new("P", predicate, value: args, type: "List")
|
40
35
|
end
|
41
36
|
end
|
42
37
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grumlin
|
4
|
+
module Expressions
|
5
|
+
class TextP < P
|
6
|
+
class << self
|
7
|
+
%i[containing endingWith notContaining notEndingWith notStartingWith startingWith].each do |predicate|
|
8
|
+
define_method predicate do |*args|
|
9
|
+
P::Predicate.new("TextP", predicate, value: args[0])
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -2,16 +2,30 @@
|
|
2
2
|
|
3
3
|
module Grumlin
|
4
4
|
module Expressions
|
5
|
-
|
5
|
+
class WithOptions
|
6
6
|
WITH_OPTIONS = Grumlin.definitions.dig(:expressions, :with_options).freeze
|
7
7
|
|
8
8
|
class << self
|
9
9
|
WITH_OPTIONS.each do |k, v|
|
10
10
|
define_method k do
|
11
|
-
|
11
|
+
name = "@#{k}"
|
12
|
+
return instance_variable_get(name) if instance_variable_defined?(name)
|
13
|
+
|
14
|
+
instance_variable_set(name, WithOptions.new(k, v))
|
12
15
|
end
|
13
16
|
end
|
14
17
|
end
|
18
|
+
|
19
|
+
attr_reader :name, :value
|
20
|
+
|
21
|
+
def initialize(name, value)
|
22
|
+
@name = name
|
23
|
+
@value = value
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
"WithOptions.#{@name}"
|
28
|
+
end
|
15
29
|
end
|
16
30
|
end
|
17
31
|
end
|
data/lib/grumlin/repository.rb
CHANGED
@@ -4,11 +4,11 @@ module Grumlin
|
|
4
4
|
module Repository
|
5
5
|
module InstanceMethods
|
6
6
|
def __
|
7
|
-
|
7
|
+
TraversalStart.new(self.class.shortcuts)
|
8
8
|
end
|
9
9
|
|
10
10
|
def g
|
11
|
-
|
11
|
+
TraversalStart.new(self.class.shortcuts)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grumlin
|
4
|
+
class Shortcut
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
attr_reader :name, :block
|
8
|
+
|
9
|
+
def_delegator :@block, :arity
|
10
|
+
def_delegator :@block, :source_location
|
11
|
+
|
12
|
+
def initialize(name, &block)
|
13
|
+
@name = name
|
14
|
+
@block = block
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(other)
|
18
|
+
@name == other.name && @block == other.block
|
19
|
+
end
|
20
|
+
|
21
|
+
# TODO: to_s, inspect, preview
|
22
|
+
|
23
|
+
def apply(object, *args, **params)
|
24
|
+
object.instance_exec(*args, **params, &@block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -5,13 +5,17 @@ module Grumlin
|
|
5
5
|
module Properties
|
6
6
|
extend Grumlin::Shortcuts
|
7
7
|
|
8
|
-
shortcut :props do
|
8
|
+
shortcut :props do |props|
|
9
|
+
next if props.nil? # TODO: fixme, add proper support for **params
|
10
|
+
|
9
11
|
props.reduce(self) do |tt, (prop, value)|
|
10
12
|
tt.property(prop, value)
|
11
13
|
end
|
12
14
|
end
|
13
15
|
|
14
|
-
shortcut :hasAll do
|
16
|
+
shortcut :hasAll do |props|
|
17
|
+
next if props.nil? # TODO: fixme, add proper support for **params
|
18
|
+
|
15
19
|
props.reduce(self) do |tt, (prop, value)|
|
16
20
|
tt.has(prop, value)
|
17
21
|
end
|
data/lib/grumlin/shortcuts.rb
CHANGED
@@ -2,14 +2,7 @@
|
|
2
2
|
|
3
3
|
module Grumlin
|
4
4
|
module Shortcuts
|
5
|
-
module InstanceMethods
|
6
|
-
def with_shortcuts(obj)
|
7
|
-
ShortcutProxy.new(obj, self.class.shortcuts, parent: self)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
5
|
def self.extended(base)
|
12
|
-
base.include(InstanceMethods)
|
13
6
|
base.include(Grumlin::Expressions)
|
14
7
|
end
|
15
8
|
|
@@ -18,22 +11,28 @@ module Grumlin
|
|
18
11
|
subclass.shortcuts_from(self)
|
19
12
|
end
|
20
13
|
|
21
|
-
def shortcut(name, &block)
|
14
|
+
def shortcut(name, shortcut = nil, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
22
15
|
name = name.to_sym
|
23
16
|
# TODO: blocklist of names to avoid conflicts with standard methods?
|
24
|
-
if Grumlin::
|
17
|
+
if Grumlin::Action::REGULAR_STEPS.include?(name)
|
25
18
|
raise ArgumentError,
|
26
19
|
"cannot use names of standard gremlin steps"
|
27
20
|
end
|
28
21
|
|
29
|
-
|
22
|
+
if (shortcut.nil? && block.nil?) || (shortcut && block)
|
23
|
+
raise ArgumentError, "either shortcut or block must be passed"
|
24
|
+
end
|
25
|
+
|
26
|
+
shortcut ||= Shortcut.new(name, &block)
|
27
|
+
|
28
|
+
raise ArgumentError, "shortcut '#{name}' already exists" if shortcuts.key?(name) && shortcuts[name] != shortcut
|
30
29
|
|
31
|
-
shortcuts[name] =
|
30
|
+
shortcuts[name] = shortcut
|
32
31
|
end
|
33
32
|
|
34
33
|
def shortcuts_from(other_shortcuts)
|
35
|
-
other_shortcuts.shortcuts.each do |name,
|
36
|
-
shortcut(name,
|
34
|
+
other_shortcuts.shortcuts.each do |name, shortcut|
|
35
|
+
shortcut(name, shortcut)
|
37
36
|
end
|
38
37
|
end
|
39
38
|
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grumlin
|
4
|
+
class ShortcutsApplyer
|
5
|
+
class << self
|
6
|
+
def call(steps)
|
7
|
+
new.call(steps)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(steps)
|
12
|
+
return steps unless steps.uses_shortcuts?
|
13
|
+
|
14
|
+
shortcuts = steps.shortcuts
|
15
|
+
|
16
|
+
configuration_steps = process_steps(steps.configuration_steps, shortcuts)
|
17
|
+
regular_steps = process_steps(steps.steps, shortcuts)
|
18
|
+
|
19
|
+
Steps.new(shortcuts).tap do |processed_steps|
|
20
|
+
(configuration_steps + regular_steps).each do |step|
|
21
|
+
processed_steps.add(step.name, step.arguments)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def process_steps(steps, shortcuts) # rubocop:disable Metrics/AbcSize
|
29
|
+
steps.each_with_object([]) do |step, result|
|
30
|
+
arguments = step.arguments.map do |arg|
|
31
|
+
arg.is_a?(Steps) ? ShortcutsApplyer.call(arg) : arg
|
32
|
+
end
|
33
|
+
|
34
|
+
if shortcuts.include?(step.name)
|
35
|
+
t = TraversalStart.new(shortcuts)
|
36
|
+
action = shortcuts[step.name].apply(t, *arguments)
|
37
|
+
next if action.nil? || action == t # Shortcut did not add any steps
|
38
|
+
|
39
|
+
new_steps = ShortcutsApplyer.call(Steps.from(action))
|
40
|
+
result.concat(new_steps.configuration_steps)
|
41
|
+
result.concat(new_steps.steps)
|
42
|
+
else
|
43
|
+
result << StepData.new(step.name, arguments)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grumlin
|
4
|
+
class StepData
|
5
|
+
attr_reader :name, :arguments
|
6
|
+
|
7
|
+
def initialize(name, arguments)
|
8
|
+
@name = name
|
9
|
+
@arguments = arguments
|
10
|
+
end
|
11
|
+
|
12
|
+
def ==(other)
|
13
|
+
self.class == other.class &&
|
14
|
+
@name == other.name &&
|
15
|
+
@arguments == other.arguments
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grumlin
|
4
|
+
class Steps
|
5
|
+
CONFIGURATION_STEPS = Action::CONFIGURATION_STEPS
|
6
|
+
ALL_STEPS = Action::ALL_STEPS
|
7
|
+
|
8
|
+
def self.from(action)
|
9
|
+
raise ArgumentError, "expected: #{Action}, given: #{action.class}" unless action.is_a?(Action)
|
10
|
+
|
11
|
+
shortcuts = action.shortcuts
|
12
|
+
actions = []
|
13
|
+
|
14
|
+
until action.nil?
|
15
|
+
actions.unshift(action)
|
16
|
+
action = action.previous_step
|
17
|
+
end
|
18
|
+
|
19
|
+
new(shortcuts).tap do |chain|
|
20
|
+
actions.each do |act|
|
21
|
+
chain.add(act.name, act.arguments)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :configuration_steps, :steps, :shortcuts
|
27
|
+
|
28
|
+
def initialize(shortcuts, configuration_steps: [], steps: [])
|
29
|
+
@shortcuts = shortcuts
|
30
|
+
@configuration_steps = configuration_steps
|
31
|
+
@steps = steps
|
32
|
+
end
|
33
|
+
|
34
|
+
def add(name, arguments)
|
35
|
+
return add_configuration_step(name, arguments) if CONFIGURATION_STEPS.include?(name)
|
36
|
+
|
37
|
+
StepData.new(name, cast_arguments(arguments)).tap do |step|
|
38
|
+
@steps << step
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def uses_shortcuts?
|
43
|
+
shortcuts?(@configuration_steps) || shortcuts?(@steps)
|
44
|
+
end
|
45
|
+
|
46
|
+
def ==(other)
|
47
|
+
self.class == other.class &&
|
48
|
+
@shortcuts == other.shortcuts &&
|
49
|
+
@configuration_steps == other.configuration_steps &&
|
50
|
+
@steps == other.steps
|
51
|
+
end
|
52
|
+
|
53
|
+
# TODO: add #bytecode, to_s, inspect
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def shortcuts?(steps_ary)
|
58
|
+
steps_ary.any? do |step|
|
59
|
+
@shortcuts.include?(step.name) || step.arguments.any? do |arg|
|
60
|
+
arg.is_a?(Steps) ? arg.uses_shortcuts? : false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def add_configuration_step(name, arguments)
|
66
|
+
raise ArgumentError, "cannot use configuration steps after start step was used" unless @steps.empty?
|
67
|
+
|
68
|
+
StepData.new(name, cast_arguments(arguments)).tap do |step|
|
69
|
+
@configuration_steps << step
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def cast_arguments(arguments)
|
74
|
+
arguments.map { |arg| arg.is_a?(Action) ? Steps.from(arg) : arg }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grumlin
|
4
|
+
module StepsSerializers
|
5
|
+
class Bytecode < Serializer
|
6
|
+
# constructor params: no_return: true|false, default false
|
7
|
+
# TODO: add pretty
|
8
|
+
|
9
|
+
NONE_STEP = StepData.new("none", [])
|
10
|
+
|
11
|
+
def serialize
|
12
|
+
steps = ShortcutsApplyer.call(@steps)
|
13
|
+
no_return = @params[:no_return] || false
|
14
|
+
|
15
|
+
{
|
16
|
+
step: (steps.steps + (no_return ? [NONE_STEP] : [])).map { |s| serialize_step(s) }
|
17
|
+
}.tap do |v|
|
18
|
+
v.merge!(source: steps.configuration_steps.map { |s| serialize_step(s) }) if steps.configuration_steps.any?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def serialize_step(step)
|
25
|
+
[step.name, *step.arguments.map { |arg| serialize_arg(arg) }]
|
26
|
+
end
|
27
|
+
|
28
|
+
def serialize_arg(arg)
|
29
|
+
return serialize_typed_value(arg) if arg.is_a?(TypedValue)
|
30
|
+
return serialize_predicate(arg) if arg.is_a?(Expressions::P::Predicate)
|
31
|
+
return arg.value if arg.is_a?(Expressions::WithOptions)
|
32
|
+
|
33
|
+
return arg unless arg.is_a?(Steps)
|
34
|
+
|
35
|
+
{ :@type => "g:Bytecode", :@value => Bytecode.new(arg, **@params.merge(no_return: false)).serialize }
|
36
|
+
end
|
37
|
+
|
38
|
+
def serialize_typed_value(value)
|
39
|
+
return value.value if value.type.nil?
|
40
|
+
|
41
|
+
{
|
42
|
+
"@type": "g:#{value.type}",
|
43
|
+
"@value": value.value
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def serialize_predicate(value)
|
48
|
+
{
|
49
|
+
"@type": "g:#{value.namespace}",
|
50
|
+
"@value": {
|
51
|
+
predicate: value.name,
|
52
|
+
value: if value.type.nil?
|
53
|
+
value.value
|
54
|
+
else
|
55
|
+
{
|
56
|
+
"@type": "g:#{value.type}",
|
57
|
+
"@value": value.value
|
58
|
+
}
|
59
|
+
end
|
60
|
+
}
|
61
|
+
}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grumlin
|
4
|
+
module StepsSerializers
|
5
|
+
class HumanReadableBytecode < Serializer
|
6
|
+
def serialize
|
7
|
+
steps = ShortcutsApplyer.call(@steps)
|
8
|
+
[serialize_steps(steps.configuration_steps), serialize_steps(steps.steps)]
|
9
|
+
end
|
10
|
+
|
11
|
+
def serialize_steps(steps)
|
12
|
+
steps.map { |s| serialize_step(s) }
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def serialize_step(step)
|
18
|
+
[step.name, *step.arguments.map { |arg| serialize_arg(arg) }]
|
19
|
+
end
|
20
|
+
|
21
|
+
def serialize_arg(arg)
|
22
|
+
return arg.to_s if arg.is_a?(TypedValue)
|
23
|
+
return serialize_predicate(arg) if arg.is_a?(Expressions::P::Predicate)
|
24
|
+
return arg.value if arg.is_a?(Expressions::WithOptions)
|
25
|
+
|
26
|
+
return arg unless arg.is_a?(Steps)
|
27
|
+
|
28
|
+
HumanReadableBytecode.new(arg, **@params.merge(no_return: false)).serialize[1]
|
29
|
+
end
|
30
|
+
|
31
|
+
def serialize_predicate(arg)
|
32
|
+
"#{arg.name}(#{arg.value})"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grumlin
|
4
|
+
module StepsSerializers
|
5
|
+
class String < Serializer
|
6
|
+
# constructor params: apply_shortcuts: true|false, default: false
|
7
|
+
# constructor params: anonymous: true|false, default: false
|
8
|
+
# TODO: add pretty
|
9
|
+
|
10
|
+
def serialize
|
11
|
+
steps = @params[:apply_shortcuts] ? ShortcutsApplyer.call(@steps) : @steps
|
12
|
+
|
13
|
+
configuration_steps = serialize_steps(steps.configuration_steps)
|
14
|
+
regular_steps = serialize_steps(steps.steps)
|
15
|
+
|
16
|
+
"#{prefix}.#{(configuration_steps + regular_steps).join(".")}"
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def prefix
|
22
|
+
@prefix ||= @params[:anonymous] ? "__" : "g"
|
23
|
+
end
|
24
|
+
|
25
|
+
def serialize_arg(arg)
|
26
|
+
return "\"#{arg}\"" if arg.is_a?(::String) || arg.is_a?(Symbol)
|
27
|
+
return "#{arg.type}.#{arg.value}" if arg.is_a?(Grumlin::TypedValue)
|
28
|
+
return arg.to_s if arg.is_a?(Grumlin::Expressions::WithOptions)
|
29
|
+
|
30
|
+
return arg unless arg.is_a?(Steps)
|
31
|
+
|
32
|
+
StepsSerializers::String.new(arg, anonymous: true, **@params).serialize
|
33
|
+
end
|
34
|
+
|
35
|
+
def serialize_steps(steps)
|
36
|
+
steps.map do |step|
|
37
|
+
"#{step.name}(#{step.arguments.map { |a| serialize_arg(a) }.join(", ")})"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/grumlin/sugar.rb
CHANGED
@@ -6,12 +6,12 @@ module Grumlin
|
|
6
6
|
base.include(Grumlin::Expressions)
|
7
7
|
end
|
8
8
|
|
9
|
-
def __
|
10
|
-
Grumlin::
|
9
|
+
def __(shortcuts = {})
|
10
|
+
Grumlin::TraversalStart.new(shortcuts) # TODO: allow only regular and start steps
|
11
11
|
end
|
12
12
|
|
13
|
-
def g
|
14
|
-
Grumlin::
|
13
|
+
def g(shortcuts = {})
|
14
|
+
Grumlin::TraversalStart.new(shortcuts)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grumlin
|
4
|
+
class TraversalStart
|
5
|
+
START_STEPS = Grumlin.definitions.dig(:steps, :start).map(&:to_sym).freeze
|
6
|
+
REGULAR_STEPS = Grumlin.definitions.dig(:steps, :regular).map(&:to_sym).freeze
|
7
|
+
CONFIGURATION_STEPS = Grumlin.definitions.dig(:steps, :configuration).map(&:to_sym).freeze
|
8
|
+
|
9
|
+
ALL_STEPS = START_STEPS + CONFIGURATION_STEPS + REGULAR_STEPS
|
10
|
+
|
11
|
+
ALL_STEPS.each do |step|
|
12
|
+
define_method step do |*args, **params|
|
13
|
+
step(step, *args, **params)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :shortcuts
|
18
|
+
|
19
|
+
def initialize(shortcuts)
|
20
|
+
@shortcuts = shortcuts
|
21
|
+
end
|
22
|
+
|
23
|
+
def step(name, *args, **params)
|
24
|
+
Action.new(name, args: args, params: params, shortcuts: @shortcuts)
|
25
|
+
end
|
26
|
+
|
27
|
+
def method_missing(name, *args, **params)
|
28
|
+
return step(name, *args, **params) if @shortcuts.key?(name)
|
29
|
+
|
30
|
+
super
|
31
|
+
end
|
32
|
+
|
33
|
+
def __
|
34
|
+
TraversalStart.new(@shortcuts) # TODO: allow only regular and start steps
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s(*)
|
38
|
+
self.class.to_s
|
39
|
+
end
|
40
|
+
|
41
|
+
def inspect
|
42
|
+
self.class.inspect
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def respond_to_missing?(name, _include_private = false)
|
48
|
+
@shortcuts.key?(name)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/grumlin/typed_value.rb
CHANGED
@@ -9,17 +9,6 @@ module Grumlin
|
|
9
9
|
@value = value
|
10
10
|
end
|
11
11
|
|
12
|
-
def to_bytecode
|
13
|
-
@to_bytecode ||= if type.nil?
|
14
|
-
value
|
15
|
-
else
|
16
|
-
{
|
17
|
-
"@type": "g:#{type}",
|
18
|
-
"@value": value
|
19
|
-
}
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
12
|
def inspect
|
24
13
|
"<#{type}.#{value}>"
|
25
14
|
end
|
@@ -27,9 +16,5 @@ module Grumlin
|
|
27
16
|
def to_s
|
28
17
|
inspect
|
29
18
|
end
|
30
|
-
|
31
|
-
def to_readable_bytecode
|
32
|
-
inspect
|
33
|
-
end
|
34
19
|
end
|
35
20
|
end
|
data/lib/grumlin/typing.rb
CHANGED
@@ -16,6 +16,8 @@ module Grumlin
|
|
16
16
|
"g:Double" => ->(value) { cast_double(value) },
|
17
17
|
"g:Direction" => ->(value) { value },
|
18
18
|
# "g:VertexProperty"=> ->(value) { value }, # TODO: implement me
|
19
|
+
"g:TraversalMetrics" => ->(value) { cast_map(value[:@value]) },
|
20
|
+
"g:Metrics" => ->(value) { cast_map(value[:@value]) },
|
19
21
|
"g:T" => ->(value) { value.to_sym }
|
20
22
|
}.freeze
|
21
23
|
|
data/lib/grumlin/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grumlin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gleb Sinyavskiy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async-pool
|
@@ -98,8 +98,7 @@ files:
|
|
98
98
|
- lib/async/channel.rb
|
99
99
|
- lib/definitions.yml
|
100
100
|
- lib/grumlin.rb
|
101
|
-
- lib/grumlin/
|
102
|
-
- lib/grumlin/bytecode.rb
|
101
|
+
- lib/grumlin/action.rb
|
103
102
|
- lib/grumlin/client.rb
|
104
103
|
- lib/grumlin/edge.rb
|
105
104
|
- lib/grumlin/expressions/expression.rb
|
@@ -109,22 +108,28 @@ files:
|
|
109
108
|
- lib/grumlin/expressions/pop.rb
|
110
109
|
- lib/grumlin/expressions/scope.rb
|
111
110
|
- lib/grumlin/expressions/t.rb
|
112
|
-
- lib/grumlin/expressions/
|
111
|
+
- lib/grumlin/expressions/text_p.rb
|
113
112
|
- lib/grumlin/expressions/with_options.rb
|
114
113
|
- lib/grumlin/path.rb
|
115
114
|
- lib/grumlin/property.rb
|
116
115
|
- lib/grumlin/repository.rb
|
117
116
|
- lib/grumlin/request_dispatcher.rb
|
118
|
-
- lib/grumlin/
|
117
|
+
- lib/grumlin/shortcut.rb
|
119
118
|
- lib/grumlin/shortcuts.rb
|
120
119
|
- lib/grumlin/shortcuts/properties.rb
|
121
|
-
- lib/grumlin/
|
120
|
+
- lib/grumlin/shortcuts_applyer.rb
|
121
|
+
- lib/grumlin/step_data.rb
|
122
|
+
- lib/grumlin/steps.rb
|
123
|
+
- lib/grumlin/steps_serializers/bytecode.rb
|
124
|
+
- lib/grumlin/steps_serializers/human_readable_bytecode.rb
|
125
|
+
- lib/grumlin/steps_serializers/serializer.rb
|
126
|
+
- lib/grumlin/steps_serializers/string.rb
|
122
127
|
- lib/grumlin/sugar.rb
|
123
128
|
- lib/grumlin/test/rspec.rb
|
124
129
|
- lib/grumlin/test/rspec/db_cleaner_context.rb
|
125
130
|
- lib/grumlin/test/rspec/gremlin_context.rb
|
126
131
|
- lib/grumlin/transport.rb
|
127
|
-
- lib/grumlin/
|
132
|
+
- lib/grumlin/traversal_start.rb
|
128
133
|
- lib/grumlin/traverser.rb
|
129
134
|
- lib/grumlin/typed_value.rb
|
130
135
|
- lib/grumlin/typing.rb
|
@@ -1,45 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Grumlin
|
4
|
-
class AnonymousStep
|
5
|
-
attr_reader :name, :previous_step, :configuration_steps
|
6
|
-
|
7
|
-
SUPPORTED_STEPS = Grumlin.definitions.dig(:steps, :regular).map(&:to_sym).freeze
|
8
|
-
|
9
|
-
def initialize(name, *args, configuration_steps: [], previous_step: nil, **params)
|
10
|
-
@name = name
|
11
|
-
@previous_step = previous_step
|
12
|
-
@args = args
|
13
|
-
@params = params
|
14
|
-
@configuration_steps = configuration_steps
|
15
|
-
end
|
16
|
-
|
17
|
-
SUPPORTED_STEPS.each do |step|
|
18
|
-
define_method(step) do |*args, **params|
|
19
|
-
step(step, *args, **params)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def step(name, *args, **params)
|
24
|
-
self.class.new(name, *args, previous_step: self, configuration_steps: configuration_steps, **params)
|
25
|
-
end
|
26
|
-
|
27
|
-
def inspect
|
28
|
-
bytecode.inspect
|
29
|
-
end
|
30
|
-
|
31
|
-
def to_s
|
32
|
-
inspect
|
33
|
-
end
|
34
|
-
|
35
|
-
def bytecode(no_return: false)
|
36
|
-
@bytecode ||= Bytecode.new(self, no_return: no_return)
|
37
|
-
end
|
38
|
-
|
39
|
-
def args
|
40
|
-
[*@args].tap do |args|
|
41
|
-
args << @params if @params.any?
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
data/lib/grumlin/bytecode.rb
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Grumlin
|
4
|
-
# Incapsulates logic of converting step chains and step arguments to queries that can be sent to the server
|
5
|
-
# and to human readable strings.
|
6
|
-
class Bytecode < TypedValue
|
7
|
-
class NoneStep
|
8
|
-
def to_bytecode
|
9
|
-
["none"]
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
NONE_STEP = NoneStep.new
|
14
|
-
|
15
|
-
def initialize(step, no_return: false)
|
16
|
-
super(type: "Bytecode")
|
17
|
-
@step = step
|
18
|
-
@no_return = no_return
|
19
|
-
end
|
20
|
-
|
21
|
-
def inspect
|
22
|
-
configuration_steps = @step.configuration_steps.map do |s|
|
23
|
-
serialize_arg(s, serialization_method: :to_readable_bytecode)
|
24
|
-
end
|
25
|
-
"#{configuration_steps.any? ? configuration_steps : nil}#{to_readable_bytecode}"
|
26
|
-
end
|
27
|
-
|
28
|
-
def to_s
|
29
|
-
inspect
|
30
|
-
end
|
31
|
-
|
32
|
-
def to_readable_bytecode
|
33
|
-
@to_readable_bytecode ||= steps.map { |s| serialize_arg(s, serialization_method: :to_readable_bytecode) }
|
34
|
-
end
|
35
|
-
|
36
|
-
def value
|
37
|
-
@value ||= { step: (steps + (@no_return ? [NONE_STEP] : [])).map { |s| serialize_arg(s) } }.tap do |v|
|
38
|
-
v.merge!(source: @step.configuration_steps.map { |s| serialize_arg(s) }) if @step.configuration_steps.any?
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
# Serializes step or a step argument to either an executable query or a human readable string representation
|
45
|
-
# depending on the `serialization_method` parameter. It should be either `:to_readable_bytecode` for human readable
|
46
|
-
# representation or `:to_bytecode` for query.
|
47
|
-
def serialize_arg(arg, serialization_method: :to_bytecode)
|
48
|
-
return arg.public_send(serialization_method) if arg.respond_to?(serialization_method)
|
49
|
-
return arg unless arg.is_a?(AnonymousStep)
|
50
|
-
|
51
|
-
arg.args.each.with_object([arg.name.to_s]) do |a, res|
|
52
|
-
res << if a.respond_to?(:bytecode)
|
53
|
-
a.bytecode.public_send(serialization_method)
|
54
|
-
else
|
55
|
-
serialize_arg(a, serialization_method: serialization_method)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def steps
|
61
|
-
@steps ||= [].tap do |result|
|
62
|
-
step = @step
|
63
|
-
until step.nil?
|
64
|
-
result.unshift(step)
|
65
|
-
step = step.previous_step
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Grumlin
|
4
|
-
module Expressions
|
5
|
-
# The module is called U because Underscore and implements __
|
6
|
-
module U
|
7
|
-
class << self
|
8
|
-
Grumlin::AnonymousStep::SUPPORTED_STEPS.each do |step|
|
9
|
-
define_method step do |*args, **params|
|
10
|
-
AnonymousStep.new(step, *args, **params)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Grumlin
|
4
|
-
class ShortcutProxy
|
5
|
-
extend Forwardable
|
6
|
-
|
7
|
-
attr_reader :object, :shortcuts
|
8
|
-
|
9
|
-
# shortcuts: {"name": ->(arg) {}}
|
10
|
-
def initialize(object, shortcuts, parent: nil)
|
11
|
-
@object = object
|
12
|
-
@shortcuts = shortcuts
|
13
|
-
@parent = parent
|
14
|
-
end
|
15
|
-
|
16
|
-
def method_missing(name, *args, **params)
|
17
|
-
return @parent.public_send(name, *args, **params) if %i[__ g].include?(name) && !@parent.nil?
|
18
|
-
|
19
|
-
return wrap_result(@object.public_send(name, *args, **params)) if @object.respond_to?(name)
|
20
|
-
|
21
|
-
return wrap_result(instance_exec(*args, **params, &@shortcuts[name])) if @shortcuts.key?(name)
|
22
|
-
|
23
|
-
super
|
24
|
-
end
|
25
|
-
|
26
|
-
# For some reason the interpreter thinks it's private
|
27
|
-
public def respond_to_missing?(name, include_private = false) # rubocop:disable Style/AccessModifierDeclarations
|
28
|
-
name = name.to_sym
|
29
|
-
|
30
|
-
(%i[__ g].include?(name) &&
|
31
|
-
@parent.respond_to?(name)) ||
|
32
|
-
@object.respond_to?(name) ||
|
33
|
-
@shortcuts.key?(name) ||
|
34
|
-
super
|
35
|
-
end
|
36
|
-
|
37
|
-
def_delegator :@object, :to_s
|
38
|
-
|
39
|
-
def inspect
|
40
|
-
@object.inspect
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
def wrap_result(result)
|
46
|
-
if result.is_a?(AnonymousStep) || result.is_a?(Traversal)
|
47
|
-
return self.class.new(result, @shortcuts, parent: @parent)
|
48
|
-
end
|
49
|
-
|
50
|
-
result
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
data/lib/grumlin/step.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Grumlin
|
4
|
-
class Step < AnonymousStep
|
5
|
-
attr_reader :client
|
6
|
-
|
7
|
-
def initialize(pool, name, *args, configuration_steps: [], previous_step: nil, **params)
|
8
|
-
super(name, *args, previous_step: previous_step, configuration_steps: configuration_steps, **params)
|
9
|
-
@pool = pool
|
10
|
-
end
|
11
|
-
|
12
|
-
def next
|
13
|
-
to_enum.next
|
14
|
-
end
|
15
|
-
|
16
|
-
def hasNext # rubocop:disable Naming/MethodName
|
17
|
-
to_enum.peek
|
18
|
-
true
|
19
|
-
rescue StopIteration
|
20
|
-
false
|
21
|
-
end
|
22
|
-
|
23
|
-
def to_enum
|
24
|
-
@to_enum ||= toList.to_enum
|
25
|
-
end
|
26
|
-
|
27
|
-
def toList
|
28
|
-
@pool.acquire do |client|
|
29
|
-
client.write(bytecode)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def iterate
|
34
|
-
@pool.acquire do |client|
|
35
|
-
client.write(bytecode(no_return: true))
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def step(step_name, *args, **params)
|
40
|
-
self.class.new(@pool, step_name, *args, previous_step: self, configuration_steps: @configuration_steps, **params)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
data/lib/grumlin/traversal.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Grumlin
|
4
|
-
class Traversal
|
5
|
-
SUPPORTED_STEPS = Grumlin.definitions.dig(:steps, :start).map(&:to_sym).freeze
|
6
|
-
|
7
|
-
CONFIGURATION_STEPS = Grumlin.definitions.dig(:steps, :configuration).map(&:to_sym).freeze
|
8
|
-
|
9
|
-
attr_reader :configuration_steps
|
10
|
-
|
11
|
-
def initialize(pool = Grumlin.default_pool, configuration_steps: [])
|
12
|
-
@pool = pool
|
13
|
-
@configuration_steps = configuration_steps
|
14
|
-
end
|
15
|
-
|
16
|
-
def inspect
|
17
|
-
"#<#{self.class}>"
|
18
|
-
end
|
19
|
-
|
20
|
-
def to_s
|
21
|
-
inspect
|
22
|
-
end
|
23
|
-
|
24
|
-
CONFIGURATION_STEPS.each do |step|
|
25
|
-
define_method step do |*args, **params|
|
26
|
-
self.class.new(@pool, configuration_steps: @configuration_steps + [AnonymousStep.new(step, *args, **params)])
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
SUPPORTED_STEPS.each do |step|
|
31
|
-
define_method step do |*args, **params|
|
32
|
-
Step.new(@pool, step, *args, configuration_steps: @configuration_steps, **params)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|