grumlin 0.19.7 → 0.20.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +4 -2
- data/README.md +34 -2
- data/bin/console +2 -0
- data/gremlin_server/Dockerfile +2 -0
- data/lib/definitions.yml +1 -0
- data/lib/grumlin/action.rb +7 -38
- data/lib/grumlin/repository/instance_methods.rb +10 -10
- data/lib/grumlin/repository.rb +14 -6
- data/lib/grumlin/request_dispatcher.rb +2 -2
- data/lib/grumlin/shortcut.rb +6 -1
- data/lib/grumlin/shortcuts/storage.rb +99 -0
- data/lib/grumlin/shortcuts/upserts.rb +3 -3
- data/lib/grumlin/shortcuts.rb +9 -16
- data/lib/grumlin/shortcuts_applyer.rb +15 -17
- data/lib/grumlin/steppable.rb +31 -0
- data/lib/grumlin/steps.rb +2 -2
- data/lib/grumlin/sugar.rb +4 -6
- data/lib/grumlin/traversal_start.rb +2 -38
- data/lib/grumlin/traversal_strategies/options_strategy.rb +11 -0
- data/lib/grumlin/version.rb +1 -1
- data/lib/grumlin/with_extension.rb +28 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e2a547fb7cbcfe53c2fab5486236b4d1021b8c4fe487307003571b24ea9e04d8
|
4
|
+
data.tar.gz: b1f73d016d9779f63a0d19c2c02afc5b975544a479aa9e9a1f5424edfde2911f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e8c6fa1bea702a974a9c0b22ec7c3f914ccceaf7c12f4bc8b5f8ce94eace7edd6dce4e47f318189e3e1b7af8c5e8ace6b00479283823274e3badfe25b6b0b07
|
7
|
+
data.tar.gz: cbb5bbfd192542785f041157232097ed01fe0d1444c20fc7c5606c1873229a7d7577183b8919f475085b5e7bf6700fae6cc987e0024fe6263cfab61f44ce898c
|
data/.rspec
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
grumlin (0.
|
4
|
+
grumlin (0.20.2)
|
5
5
|
async-pool (~> 0.3)
|
6
6
|
async-websocket (~> 0.19)
|
7
7
|
oj (~> 3.13)
|
@@ -48,6 +48,7 @@ GEM
|
|
48
48
|
concurrent-ruby (1.1.10)
|
49
49
|
console (1.15.3)
|
50
50
|
fiber-local
|
51
|
+
dead_end (4.0.0)
|
51
52
|
diff-lcs (1.5.0)
|
52
53
|
docile (1.4.0)
|
53
54
|
e2mmap (0.1.0)
|
@@ -71,7 +72,7 @@ GEM
|
|
71
72
|
racc (~> 1.4)
|
72
73
|
nokogiri (1.13.6-x86_64-linux)
|
73
74
|
racc (~> 1.4)
|
74
|
-
oj (3.13.
|
75
|
+
oj (3.13.17)
|
75
76
|
overcommit (0.59.1)
|
76
77
|
childprocess (>= 0.6.3, < 5)
|
77
78
|
iniparse (~> 1.4)
|
@@ -172,6 +173,7 @@ PLATFORMS
|
|
172
173
|
DEPENDENCIES
|
173
174
|
async-rspec
|
174
175
|
benchmark-ips
|
176
|
+
dead_end
|
175
177
|
factory_bot
|
176
178
|
grumlin!
|
177
179
|
memory_profiler
|
data/README.md
CHANGED
@@ -80,8 +80,7 @@ sequences of standard gremlin steps, other shortcuts and even add new initially
|
|
80
80
|
Remember ActiveRecord scopes? Shortcuts are very similar.
|
81
81
|
|
82
82
|
**Important**: if a shortcut's name matches a name of a method defined on the wrapped object, this shortcut will be
|
83
|
-
be ignored because methods have higher priority.
|
84
|
-
`Grumlin::Shortcuts.shortcut` will raise an `ArgumentError`. Please carefully choose names for your shortcuts.
|
83
|
+
be ignored because methods have higher priority.
|
85
84
|
|
86
85
|
Shortcuts are designed to be used with `Grumlin::Repository` but still can be used separately, with `Grumlin::Sugar`
|
87
86
|
for example.
|
@@ -143,6 +142,22 @@ class MyRepository
|
|
143
142
|
end
|
144
143
|
```
|
145
144
|
|
145
|
+
##### Overriding standard steps and shortcuts
|
146
|
+
|
147
|
+
Sometimes it may be useful to override standard steps. Grumlin does not allow it by default, but one
|
148
|
+
is still able to override standard steps if they know what they are doing:
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
shortcut :addV, override: true do |label|
|
152
|
+
super(label).property(:default, :value)
|
153
|
+
end
|
154
|
+
```
|
155
|
+
|
156
|
+
This will create a new shortcut that overrides the standard step `addV` and adds default properties to all vertices
|
157
|
+
created by the repository that uses this shortcut.
|
158
|
+
|
159
|
+
Shortcuts also can be overridden, but super() is not available.
|
160
|
+
|
146
161
|
#### Grumlin::Repository
|
147
162
|
`Grumlin::Repository` combines functionality of `Grumlin::Sugar` and `Grumlin::Shortcuts` as well as adds a few useful
|
148
163
|
shortcuts to make gremlin code more rubyish. Can be used as a drop in replacement for `Grumlin::Sugar`. Remember that
|
@@ -167,6 +182,23 @@ class MyRepository
|
|
167
182
|
hasAll(T.label => :triangle, color: color)
|
168
183
|
end
|
169
184
|
|
185
|
+
# `default_vertex_properties` and `default_edge_properties`
|
186
|
+
# override `addV` and `addE` according and inject hashes returned from passed
|
187
|
+
# as properties for newly created vertices and edges.
|
188
|
+
# In case if a repository is inherited, newly defined default properties will be merged to
|
189
|
+
# default properties defined in the parent repository.
|
190
|
+
default_vertex_properties do |_label|
|
191
|
+
{
|
192
|
+
created_at: Time.now.to_i
|
193
|
+
}
|
194
|
+
end
|
195
|
+
|
196
|
+
default_edge_properties do |_label|
|
197
|
+
{
|
198
|
+
created_at: Time.now.to_i
|
199
|
+
}
|
200
|
+
end
|
201
|
+
|
170
202
|
# g and __ are already aware of shortcuts
|
171
203
|
query(:triangles_with_color, return_mode: :list) do |color| # :list is the default return mode, also possible: :none, :single, :traversal
|
172
204
|
g.V.hasLabel(:triangle)
|
data/bin/console
CHANGED
data/gremlin_server/Dockerfile
CHANGED
data/lib/definitions.yml
CHANGED
data/lib/grumlin/action.rb
CHANGED
@@ -1,32 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Grumlin
|
4
|
-
class Action
|
5
|
-
|
6
|
-
CONFIGURATION_STEPS = Grumlin.definitions.dig(:steps, :configuration).map(&:to_sym).freeze
|
7
|
-
REGULAR_STEPS = Grumlin.definitions.dig(:steps, :regular).map(&:to_sym).freeze
|
4
|
+
class Action < Steppable
|
5
|
+
attr_reader :name, :args, :params, :next_step, :configuration_steps, :previous_step, :shortcut
|
8
6
|
|
9
|
-
|
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)
|
7
|
+
def initialize(name, args: [], params: {}, previous_step: nil, pool: nil)
|
8
|
+
super()
|
14
9
|
@name = name.to_sym
|
15
10
|
@args = args # TODO: add recursive validation: only json types or Action
|
16
11
|
@params = params # TODO: add recursive validation: only json types
|
17
12
|
@previous_step = previous_step
|
18
|
-
@
|
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)
|
13
|
+
@shortcut = shortcuts[@name]
|
14
|
+
@pool = pool || Grumlin.default_pool
|
30
15
|
end
|
31
16
|
|
32
17
|
def configuration_step?
|
@@ -45,23 +30,13 @@ module Grumlin
|
|
45
30
|
ALL_STEPS.include?(@name)
|
46
31
|
end
|
47
32
|
|
48
|
-
def shortcut?
|
49
|
-
@shortcuts.key?(@name)
|
50
|
-
end
|
51
|
-
|
52
|
-
def method_missing(name, *args, **params)
|
53
|
-
return step(name, *args, **params) if @shortcuts.key?(name)
|
54
|
-
|
55
|
-
super
|
56
|
-
end
|
57
|
-
|
58
33
|
def ==(other)
|
59
34
|
self.class == other.class &&
|
60
35
|
@name == other.name &&
|
61
36
|
@args == other.args &&
|
62
37
|
@params == other.params &&
|
63
38
|
@previous_step == other.previous_step &&
|
64
|
-
|
39
|
+
shortcuts == other.shortcuts
|
65
40
|
end
|
66
41
|
|
67
42
|
def steps
|
@@ -108,11 +83,5 @@ module Grumlin
|
|
108
83
|
client.write(bytecode(no_return: true))
|
109
84
|
end
|
110
85
|
end
|
111
|
-
|
112
|
-
private
|
113
|
-
|
114
|
-
def respond_to_missing?(name, _include_private = false)
|
115
|
-
@shortcuts.key?(name)
|
116
|
-
end
|
117
86
|
end
|
118
87
|
end
|
@@ -5,6 +5,8 @@ module Grumlin
|
|
5
5
|
module InstanceMethods
|
6
6
|
include Grumlin::Expressions
|
7
7
|
|
8
|
+
extend Forwardable
|
9
|
+
|
8
10
|
UPSERT_RETRY_PARAMS = {
|
9
11
|
on: [Grumlin::AlreadyExistsError, Grumlin::ConcurrentInsertFailedError],
|
10
12
|
sleep_method: ->(n) { Async::Task.current.sleep(n) },
|
@@ -14,12 +16,10 @@ module Grumlin
|
|
14
16
|
|
15
17
|
DEFAULT_ERROR_HANDLING_STRATEGY = ErrorHandlingStrategy.new(mode: :retry, **UPSERT_RETRY_PARAMS)
|
16
18
|
|
17
|
-
|
18
|
-
@__ ||= TraversalStart.new(self.class.shortcuts)
|
19
|
-
end
|
19
|
+
def_delegators :shortcuts, :g, :__
|
20
20
|
|
21
|
-
def
|
22
|
-
|
21
|
+
def shortcuts
|
22
|
+
self.class.shortcuts
|
23
23
|
end
|
24
24
|
|
25
25
|
def drop_vertex(id)
|
@@ -56,7 +56,7 @@ module Grumlin
|
|
56
56
|
with_upsert_error_handling(on_failure, params) do
|
57
57
|
create_properties, update_properties = cleanup_properties(create_properties, update_properties)
|
58
58
|
|
59
|
-
g.upsertV(label, id, create_properties, update_properties).next
|
59
|
+
g.upsertV(label, id, create_properties, update_properties).id.next
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -70,7 +70,7 @@ module Grumlin
|
|
70
70
|
create_properties, update_properties = cleanup_properties(create_properties, update_properties)
|
71
71
|
|
72
72
|
t.upsertV(label, id, create_properties, update_properties)
|
73
|
-
end.iterate
|
73
|
+
end.id.iterate
|
74
74
|
end
|
75
75
|
end
|
76
76
|
end
|
@@ -80,12 +80,12 @@ module Grumlin
|
|
80
80
|
def upsert_edge(label, from:, to:, create_properties: {}, update_properties: {}, on_failure: :retry, **params) # rubocop:disable Metrics/ParameterLists
|
81
81
|
with_upsert_error_handling(on_failure, params) do
|
82
82
|
create_properties, update_properties = cleanup_properties(create_properties, update_properties, T.label)
|
83
|
-
g.upsertE(label, from, to, create_properties, update_properties).next
|
83
|
+
g.upsertE(label, from, to, create_properties, update_properties).id.next
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
87
|
# edges:
|
88
|
-
# [["label", "
|
88
|
+
# [["label", "from", "to", {create: :properties}, {update: properties}]]
|
89
89
|
# params can override Retryable config from UPSERT_RETRY_PARAMS
|
90
90
|
def upsert_edges(edges, batch_size: 100, on_failure: :retry, **params)
|
91
91
|
edges.each_slice(batch_size) do |slice|
|
@@ -94,7 +94,7 @@ module Grumlin
|
|
94
94
|
create_properties, update_properties = cleanup_properties(create_properties, update_properties, T.label)
|
95
95
|
|
96
96
|
t.upsertE(label, from, to, create_properties, update_properties)
|
97
|
-
end.iterate
|
97
|
+
end.id.iterate
|
98
98
|
end
|
99
99
|
end
|
100
100
|
end
|
data/lib/grumlin/repository.rb
CHANGED
@@ -23,7 +23,7 @@ module Grumlin
|
|
23
23
|
|
24
24
|
define_method name do |*args, query_params: {}, **params, &block|
|
25
25
|
t = instance_exec(*args, **params, &query_block)
|
26
|
-
return t if
|
26
|
+
return t if t.nil? || (t.respond_to?(:empty?) && t.empty?)
|
27
27
|
|
28
28
|
unless t.is_a?(Grumlin::Action)
|
29
29
|
raise WrongQueryResult,
|
@@ -45,8 +45,20 @@ module Grumlin
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
+
def default_vertex_properties(&block)
|
49
|
+
shortcut :addV, override: true do |*args|
|
50
|
+
super(*args).props(**block.call(*args)) # rubocop:disable Performance/RedundantBlockCall
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def default_edge_properties(&block)
|
55
|
+
shortcut :addE, override: true do |*args|
|
56
|
+
super(*args).props(**block.call(*args)) # rubocop:disable Performance/RedundantBlockCall
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
48
60
|
def validate_return_mode!(return_mode)
|
49
|
-
return return_mode if RETURN_MODES.
|
61
|
+
return return_mode if RETURN_MODES.include?(return_mode)
|
50
62
|
|
51
63
|
raise ArgumentError, "unsupported return mode #{return_mode}. Supported modes: #{RETURN_MODES.keys}"
|
52
64
|
end
|
@@ -60,9 +72,5 @@ module Grumlin
|
|
60
72
|
raise ArgumentError,
|
61
73
|
"postprocess_with must be a String, Symbol or a callable object, given: #{postprocess_with.class}"
|
62
74
|
end
|
63
|
-
|
64
|
-
def empty_result?(result)
|
65
|
-
result.nil? || (result.respond_to?(:empty?) && result.empty?)
|
66
|
-
end
|
67
75
|
end
|
68
76
|
end
|
@@ -38,7 +38,7 @@ module Grumlin
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def add_request(request)
|
41
|
-
raise RequestAlreadyAddedError if @requests.
|
41
|
+
raise RequestAlreadyAddedError if @requests.include?(request[:requestId])
|
42
42
|
|
43
43
|
Async::Channel.new.tap do |channel|
|
44
44
|
@requests[request[:requestId]] = { request: request, result: [], channel: channel }
|
@@ -73,7 +73,7 @@ module Grumlin
|
|
73
73
|
end
|
74
74
|
|
75
75
|
def ongoing_request?(request_id)
|
76
|
-
@requests.
|
76
|
+
@requests.include?(request_id)
|
77
77
|
end
|
78
78
|
|
79
79
|
def clear
|
data/lib/grumlin/shortcut.rb
CHANGED
@@ -9,8 +9,9 @@ module Grumlin
|
|
9
9
|
def_delegator :@block, :arity
|
10
10
|
def_delegator :@block, :source_location
|
11
11
|
|
12
|
-
def initialize(name, &block)
|
12
|
+
def initialize(name, lazy: true, &block)
|
13
13
|
@name = name
|
14
|
+
@lazy = lazy
|
14
15
|
@block = block
|
15
16
|
end
|
16
17
|
|
@@ -18,6 +19,10 @@ module Grumlin
|
|
18
19
|
@name == other.name && @block == other.block
|
19
20
|
end
|
20
21
|
|
22
|
+
def lazy?
|
23
|
+
@lazy
|
24
|
+
end
|
25
|
+
|
21
26
|
# TODO: to_s, inspect, preview
|
22
27
|
|
23
28
|
def apply(object, *args, **params)
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grumlin
|
4
|
+
module Shortcuts
|
5
|
+
class Storage
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def [](other)
|
10
|
+
new(other)
|
11
|
+
end
|
12
|
+
|
13
|
+
def empty
|
14
|
+
@empty ||= new
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(storage = {})
|
19
|
+
@storage = storage
|
20
|
+
storage.each do |n, s|
|
21
|
+
add(n, s)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def_delegator :@storage, :[]
|
26
|
+
def_delegator :@storage, :include?, :known?
|
27
|
+
def_delegator :@storage, :keys, :names
|
28
|
+
|
29
|
+
def ==(other)
|
30
|
+
@storage == other.storage
|
31
|
+
end
|
32
|
+
|
33
|
+
def add(name, shortcut)
|
34
|
+
@storage[name] = shortcut
|
35
|
+
|
36
|
+
ac = action_class
|
37
|
+
|
38
|
+
shortcut_methods_module.define_method(name) do |*args, **params|
|
39
|
+
next ac.new(name, args: args, params: params, previous_step: self)
|
40
|
+
end
|
41
|
+
extend_traversal_classes(shortcut) unless shortcut.lazy?
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_from(other)
|
45
|
+
other.storage.each do |name, shortcut|
|
46
|
+
add(name, shortcut)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def g
|
51
|
+
__
|
52
|
+
end
|
53
|
+
|
54
|
+
def __
|
55
|
+
@__ ||= traversal_start_class.new
|
56
|
+
end
|
57
|
+
|
58
|
+
def traversal_start_class
|
59
|
+
@traversal_start_class ||= shortcut_aware_class(TraversalStart)
|
60
|
+
end
|
61
|
+
|
62
|
+
def action_class
|
63
|
+
@action_class ||= shortcut_aware_class(Action)
|
64
|
+
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
|
68
|
+
attr_reader :storage
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def shortcut_methods_module
|
73
|
+
@shortcut_methods_module ||= begin
|
74
|
+
shorts = self
|
75
|
+
Module.new do
|
76
|
+
define_method :shortcuts do
|
77
|
+
shorts
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def shortcut_aware_class(base)
|
84
|
+
methods = shortcut_methods_module
|
85
|
+
Class.new(base) do
|
86
|
+
include methods
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def extend_traversal_classes(shortcut)
|
91
|
+
m = Module.new do
|
92
|
+
define_method(shortcut.name, &shortcut.block)
|
93
|
+
end
|
94
|
+
action_class.include(m)
|
95
|
+
traversal_start_class.include(m)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -5,16 +5,16 @@ module Grumlin
|
|
5
5
|
module Upserts
|
6
6
|
extend Grumlin::Shortcuts
|
7
7
|
|
8
|
-
shortcut :upsertV do |label, id, create_properties, update_properties|
|
8
|
+
shortcut :upsertV do |label, id, create_properties = {}, update_properties = {}|
|
9
9
|
self.V(id)
|
10
10
|
.fold
|
11
|
-
.coalesce(
|
11
|
+
.coalesce(
|
12
12
|
__.unfold,
|
13
13
|
__.addV(label).props(**create_properties.merge(T.id => id))
|
14
14
|
).props(**update_properties)
|
15
15
|
end
|
16
16
|
|
17
|
-
shortcut :upsertE do |label, from, to, create_properties, update_properties|
|
17
|
+
shortcut :upsertE do |label, from, to, create_properties = {}, update_properties = {}|
|
18
18
|
self.V(from)
|
19
19
|
.outE(label).where(__.inV.hasId(to))
|
20
20
|
.fold
|
data/lib/grumlin/shortcuts.rb
CHANGED
@@ -11,33 +11,26 @@ module Grumlin
|
|
11
11
|
subclass.shortcuts_from(self)
|
12
12
|
end
|
13
13
|
|
14
|
-
def shortcut(name, shortcut = nil,
|
14
|
+
def shortcut(name, shortcut = nil, override: false, lazy: true, &block)
|
15
15
|
name = name.to_sym
|
16
|
-
|
17
|
-
if Grumlin::Action::REGULAR_STEPS.include?(name)
|
18
|
-
raise ArgumentError,
|
19
|
-
"cannot use names of standard gremlin steps"
|
20
|
-
end
|
16
|
+
lazy = false if override
|
21
17
|
|
22
|
-
if
|
23
|
-
raise ArgumentError,
|
18
|
+
if Grumlin::Action::REGULAR_STEPS.include?(name) && !override
|
19
|
+
raise ArgumentError,
|
20
|
+
"overriding standard gremlin steps is not allowed, if you know what you're doing, pass `override: true`"
|
24
21
|
end
|
25
22
|
|
26
|
-
shortcut
|
23
|
+
raise ArgumentError, "either shortcut or block must be passed" if [shortcut, block].count(&:nil?) != 1
|
27
24
|
|
28
|
-
|
29
|
-
|
30
|
-
shortcuts[name] = shortcut
|
25
|
+
shortcuts.add(name, shortcut || Shortcut.new(name, lazy: lazy, &block))
|
31
26
|
end
|
32
27
|
|
33
28
|
def shortcuts_from(other_shortcuts)
|
34
|
-
other_shortcuts.shortcuts
|
35
|
-
shortcut(name, shortcut)
|
36
|
-
end
|
29
|
+
shortcuts.add_from(other_shortcuts.shortcuts)
|
37
30
|
end
|
38
31
|
|
39
32
|
def shortcuts
|
40
|
-
@shortcuts ||=
|
33
|
+
@shortcuts ||= Storage.new
|
41
34
|
end
|
42
35
|
end
|
43
36
|
end
|
@@ -4,15 +4,17 @@ module Grumlin
|
|
4
4
|
class ShortcutsApplyer
|
5
5
|
class << self
|
6
6
|
def call(steps)
|
7
|
-
return steps
|
7
|
+
return steps if !steps.is_a?(Steps) || !steps.uses_shortcuts?
|
8
8
|
|
9
9
|
shortcuts = steps.shortcuts
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
steps = [
|
12
|
+
*process_steps(steps.configuration_steps, shortcuts),
|
13
|
+
*process_steps(steps.steps, shortcuts)
|
14
|
+
]
|
13
15
|
|
14
16
|
Steps.new(shortcuts).tap do |processed_steps|
|
15
|
-
|
17
|
+
steps.each do |step|
|
16
18
|
processed_steps.add(step.name, args: step.args, params: step.params)
|
17
19
|
end
|
18
20
|
end
|
@@ -22,21 +24,17 @@ module Grumlin
|
|
22
24
|
|
23
25
|
def process_steps(steps, shortcuts) # rubocop:disable Metrics/AbcSize
|
24
26
|
steps.each_with_object([]) do |step, result|
|
25
|
-
args = step.args.map
|
26
|
-
arg.is_a?(Steps) ? ShortcutsApplyer.call(arg) : arg
|
27
|
-
end
|
27
|
+
args = step.args.map { |arg| call(arg) }
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
action = shortcuts[step.name].apply(t, *args, **step.params)
|
32
|
-
next if action.nil? || action == t # Shortcut did not add any steps
|
29
|
+
shortcut = shortcuts[step.name]
|
30
|
+
next result << StepData.new(step.name, args: args, params: step.params) unless shortcut&.lazy?
|
33
31
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
32
|
+
t = shortcuts.__
|
33
|
+
action = shortcut.apply(t, *args, **step.params)
|
34
|
+
next if action.nil? || action == t # Shortcut did not add any steps
|
35
|
+
|
36
|
+
new_steps = call(Steps.from(action))
|
37
|
+
result.concat(new_steps.configuration_steps, new_steps.steps)
|
40
38
|
end
|
41
39
|
end
|
42
40
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grumlin
|
4
|
+
class Steppable
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
START_STEPS = Grumlin.definitions.dig(:steps, :start).map(&:to_sym).freeze
|
8
|
+
REGULAR_STEPS = Grumlin.definitions.dig(:steps, :regular).map(&:to_sym).freeze
|
9
|
+
CONFIGURATION_STEPS = Grumlin.definitions.dig(:steps, :configuration).map(&:to_sym).freeze
|
10
|
+
|
11
|
+
ALL_STEPS = START_STEPS + CONFIGURATION_STEPS + REGULAR_STEPS
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
return if respond_to?(:shortcuts)
|
15
|
+
|
16
|
+
raise "steppable must not be initialized directly, use Grumlin::Shortcuts::Storage#g or #__ instead"
|
17
|
+
end
|
18
|
+
|
19
|
+
ALL_STEPS.each do |step|
|
20
|
+
define_method step do |*args, **params|
|
21
|
+
shortcuts.action_class.new(step, args: args, params: params, previous_step: self)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def step(name, *args, **params)
|
26
|
+
shortcuts.action_class.new(name, args: args, params: params, previous_step: self)
|
27
|
+
end
|
28
|
+
|
29
|
+
def_delegator :shortcuts, :__
|
30
|
+
end
|
31
|
+
end
|
data/lib/grumlin/steps.rb
CHANGED
@@ -11,7 +11,7 @@ module Grumlin
|
|
11
11
|
shortcuts = action.shortcuts
|
12
12
|
actions = []
|
13
13
|
|
14
|
-
until action.nil?
|
14
|
+
until action.nil? || action.is_a?(TraversalStart)
|
15
15
|
actions.unshift(action)
|
16
16
|
action = action.previous_step
|
17
17
|
end
|
@@ -56,7 +56,7 @@ module Grumlin
|
|
56
56
|
|
57
57
|
def shortcuts?(steps_ary)
|
58
58
|
steps_ary.any? do |step|
|
59
|
-
@shortcuts.
|
59
|
+
@shortcuts.known?(step.name) || step.args.any? do |arg|
|
60
60
|
arg.is_a?(Steps) ? arg.uses_shortcuts? : false
|
61
61
|
end
|
62
62
|
end
|
data/lib/grumlin/sugar.rb
CHANGED
@@ -6,12 +6,10 @@ module Grumlin
|
|
6
6
|
base.include(Grumlin::Expressions)
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
def g(shortcuts = {})
|
14
|
-
Grumlin::TraversalStart.new(shortcuts)
|
9
|
+
%i[__ g].each do |name|
|
10
|
+
define_method name do |cuts = Shortcuts::Storage.empty|
|
11
|
+
cuts.send(name)
|
12
|
+
end
|
15
13
|
end
|
16
14
|
end
|
17
15
|
end
|
@@ -1,38 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Grumlin
|
4
|
-
class TraversalStart
|
5
|
-
|
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
|
4
|
+
class TraversalStart < Steppable
|
5
|
+
include WithExtension
|
36
6
|
|
37
7
|
def to_s(*)
|
38
8
|
self.class.to_s
|
@@ -41,11 +11,5 @@ module Grumlin
|
|
41
11
|
def inspect
|
42
12
|
self.class.inspect
|
43
13
|
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
def respond_to_missing?(name, _include_private = false)
|
48
|
-
@shortcuts.key?(name)
|
49
|
-
end
|
50
14
|
end
|
51
15
|
end
|
data/lib/grumlin/version.rb
CHANGED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grumlin
|
4
|
+
module WithExtension
|
5
|
+
def with(name, value)
|
6
|
+
prev = self
|
7
|
+
strategy = if is_a?(with_action_class)
|
8
|
+
prev = previous_step
|
9
|
+
TraversalStrategies::OptionsStrategy.new(args.first.value.merge(name => value))
|
10
|
+
else
|
11
|
+
TraversalStrategies::OptionsStrategy.new({ name => value })
|
12
|
+
end
|
13
|
+
with_action_class.new(:withStrategies, args: [strategy], previous_step: prev)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def with_action_class
|
19
|
+
@with_action_class ||= Class.new(shortcuts.action_class) do
|
20
|
+
include WithExtension
|
21
|
+
|
22
|
+
def with_action_class
|
23
|
+
self.class
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
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.20.2
|
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-07-
|
11
|
+
date: 2022-07-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async-pool
|
@@ -138,9 +138,11 @@ files:
|
|
138
138
|
- lib/grumlin/shortcut.rb
|
139
139
|
- lib/grumlin/shortcuts.rb
|
140
140
|
- lib/grumlin/shortcuts/properties.rb
|
141
|
+
- lib/grumlin/shortcuts/storage.rb
|
141
142
|
- lib/grumlin/shortcuts/upserts.rb
|
142
143
|
- lib/grumlin/shortcuts_applyer.rb
|
143
144
|
- lib/grumlin/step_data.rb
|
145
|
+
- lib/grumlin/steppable.rb
|
144
146
|
- lib/grumlin/steps.rb
|
145
147
|
- lib/grumlin/steps_serializers/bytecode.rb
|
146
148
|
- lib/grumlin/steps_serializers/human_readable_bytecode.rb
|
@@ -152,11 +154,13 @@ files:
|
|
152
154
|
- lib/grumlin/test/rspec/gremlin_context.rb
|
153
155
|
- lib/grumlin/transport.rb
|
154
156
|
- lib/grumlin/traversal_start.rb
|
157
|
+
- lib/grumlin/traversal_strategies/options_strategy.rb
|
155
158
|
- lib/grumlin/traverser.rb
|
156
159
|
- lib/grumlin/typed_value.rb
|
157
160
|
- lib/grumlin/typing.rb
|
158
161
|
- lib/grumlin/version.rb
|
159
162
|
- lib/grumlin/vertex.rb
|
163
|
+
- lib/grumlin/with_extension.rb
|
160
164
|
- lib/tasks/benchmark.rake
|
161
165
|
homepage: https://github.com/zhulik/grumlin
|
162
166
|
licenses:
|