grumlin 0.19.7 → 0.20.2
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/.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:
|