grumlin 0.15.3 → 0.16.0
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 +10 -0
- data/Gemfile.lock +2 -2
- data/README.md +4 -0
- data/Rakefile +21 -3
- data/lib/definitions.yml +114 -0
- data/lib/grumlin/action.rb +124 -0
- data/lib/grumlin/client.rb +2 -2
- data/lib/grumlin/expressions/operator.rb +1 -1
- data/lib/grumlin/expressions/order.rb +1 -1
- data/lib/grumlin/expressions/p.rb +12 -17
- data/lib/grumlin/expressions/pop.rb +1 -1
- data/lib/grumlin/expressions/scope.rb +1 -1
- data/lib/grumlin/expressions/t.rb +1 -1
- data/lib/grumlin/expressions/text_p.rb +15 -0
- data/lib/grumlin/expressions/with_options.rb +17 -14
- 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 +15 -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/version.rb +1 -1
- data/lib/grumlin.rb +6 -4
- metadata +14 -8
- data/lib/grumlin/anonymous_step.rb +0 -49
- data/lib/grumlin/bytecode.rb +0 -70
- data/lib/grumlin/expressions/u.rb +0 -19
- data/lib/grumlin/shortcut_proxy.rb +0 -53
- data/lib/grumlin/step.rb +0 -43
- data/lib/grumlin/traversal.rb +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a18e5e39768c0142eb219751991d67cb8512dd6d8cbeaa42494be193d44b694
|
4
|
+
data.tar.gz: 3c6833ffce68c409d78a656a892a81801b7820b9ea793dc60600e69c96315f76
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c48059b03c81f68ff26802268f150c8d8af5476659e8f730de3c64c90f45896cdfa08dfd3bcc2db85240c34ef601b26317cbde269f3f834d6e3dd9f27a99f3e
|
7
|
+
data.tar.gz: 8033907ed22e1aa349b39ce3f247977242221d28aeea2f34c721e2bc6ec807f0a08dd21e450ef183fb989dac04534dc4fedbc1358e805ce5c8c57b59ab18b968
|
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,13 @@
|
|
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
|
+
|
6
|
+
## [0.15.4] - 2022-01-20
|
7
|
+
|
8
|
+
- Move step and expression definitions to a yaml file for better diffs
|
9
|
+
- Add `definitions:format` rake task
|
10
|
+
|
1
11
|
## [0.15.3] - 2022-01-18
|
2
12
|
|
3
13
|
- Fix passing nils as step arguments. Even if they are not supported by the server, they should not be omitted.
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
grumlin (0.
|
4
|
+
grumlin (0.16.0)
|
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/README.md
CHANGED
@@ -258,6 +258,10 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
258
258
|
the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version,
|
259
259
|
push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
260
260
|
|
261
|
+
### Adding new steps and expressions
|
262
|
+
To add a new step or an expression simple put it to the corresponding list in [definitions.yml](lib/definitions.yml)
|
263
|
+
and run `rake definitions:format`. You don't need to properly sort the lists manually, the rake task will do it for you.
|
264
|
+
|
261
265
|
## Contributing
|
262
266
|
|
263
267
|
Bug reports and pull requests are welcome on GitHub at https://github.com/zhulik/grumlin. This project is intended to
|
data/Rakefile
CHANGED
@@ -1,12 +1,30 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "yaml"
|
4
|
+
|
3
5
|
require "bundler/gem_tasks"
|
4
6
|
require "rspec/core/rake_task"
|
7
|
+
require "rubocop/rake_task"
|
5
8
|
|
6
9
|
RSpec::Core::RakeTask.new(:spec)
|
10
|
+
RuboCop::RakeTask.new
|
7
11
|
|
8
|
-
|
12
|
+
task default: %i[rubocop spec]
|
9
13
|
|
10
|
-
|
14
|
+
namespace :definitions do
|
15
|
+
desc "Format definitions.yml"
|
16
|
+
task :format do
|
17
|
+
path = File.join(__dir__, "lib", "definitions.yml")
|
18
|
+
definitions = YAML.safe_load(File.read(path))
|
19
|
+
|
20
|
+
definitions.each_value do |kind|
|
21
|
+
kind.each do |name, list|
|
22
|
+
next if name == "with_options"
|
23
|
+
|
24
|
+
list.sort!
|
25
|
+
end
|
26
|
+
end
|
11
27
|
|
12
|
-
|
28
|
+
File.write(path, YAML.dump(definitions))
|
29
|
+
end
|
30
|
+
end
|
data/lib/definitions.yml
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
---
|
2
|
+
steps:
|
3
|
+
regular:
|
4
|
+
- E
|
5
|
+
- V
|
6
|
+
- addE
|
7
|
+
- addV
|
8
|
+
- aggregate
|
9
|
+
- and
|
10
|
+
- as
|
11
|
+
- both
|
12
|
+
- bothE
|
13
|
+
- by
|
14
|
+
- choose
|
15
|
+
- coalesce
|
16
|
+
- constant
|
17
|
+
- count
|
18
|
+
- dedup
|
19
|
+
- drop
|
20
|
+
- elementMap
|
21
|
+
- emit
|
22
|
+
- fold
|
23
|
+
- from
|
24
|
+
- group
|
25
|
+
- groupCount
|
26
|
+
- has
|
27
|
+
- hasId
|
28
|
+
- hasLabel
|
29
|
+
- hasNot
|
30
|
+
- id
|
31
|
+
- identity
|
32
|
+
- in
|
33
|
+
- inE
|
34
|
+
- inV
|
35
|
+
- inject
|
36
|
+
- is
|
37
|
+
- label
|
38
|
+
- limit
|
39
|
+
- map
|
40
|
+
- none
|
41
|
+
- not
|
42
|
+
- option
|
43
|
+
- or
|
44
|
+
- order
|
45
|
+
- out
|
46
|
+
- outE
|
47
|
+
- outV
|
48
|
+
- path
|
49
|
+
- project
|
50
|
+
- properties
|
51
|
+
- property
|
52
|
+
- range
|
53
|
+
- repeat
|
54
|
+
- sack
|
55
|
+
- select
|
56
|
+
- sideEffect
|
57
|
+
- skip
|
58
|
+
- sum
|
59
|
+
- tail
|
60
|
+
- timeLimit
|
61
|
+
- to
|
62
|
+
- unfold
|
63
|
+
- union
|
64
|
+
- until
|
65
|
+
- valueMap
|
66
|
+
- values
|
67
|
+
- where
|
68
|
+
- with
|
69
|
+
start:
|
70
|
+
- E
|
71
|
+
- V
|
72
|
+
- addE
|
73
|
+
- addV
|
74
|
+
- inject
|
75
|
+
configuration:
|
76
|
+
- withSack
|
77
|
+
- withSideEffect
|
78
|
+
expressions:
|
79
|
+
operator:
|
80
|
+
- addAll
|
81
|
+
- and
|
82
|
+
- assign
|
83
|
+
- div
|
84
|
+
- max
|
85
|
+
- min
|
86
|
+
- minus
|
87
|
+
- mult
|
88
|
+
- or
|
89
|
+
- sum
|
90
|
+
order:
|
91
|
+
- asc
|
92
|
+
- desc
|
93
|
+
- shuffle
|
94
|
+
pop:
|
95
|
+
- all
|
96
|
+
- first
|
97
|
+
- last
|
98
|
+
- mixed
|
99
|
+
scope:
|
100
|
+
- local
|
101
|
+
t:
|
102
|
+
- id
|
103
|
+
- label
|
104
|
+
with_options:
|
105
|
+
tokens: "~tinkerpop.valueMap.tokens"
|
106
|
+
none: 0
|
107
|
+
ids: 1
|
108
|
+
labels: 2
|
109
|
+
keys: 4
|
110
|
+
values: 8
|
111
|
+
all: 15
|
112
|
+
indexer: "~tinkerpop.index.indexer"
|
113
|
+
list: 0
|
114
|
+
map: 1
|
@@ -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,27 +2,30 @@
|
|
2
2
|
|
3
3
|
module Grumlin
|
4
4
|
module Expressions
|
5
|
-
|
6
|
-
WITH_OPTIONS =
|
7
|
-
tokens: "~tinkerpop.valueMap.tokens",
|
8
|
-
none: 0,
|
9
|
-
ids: 1,
|
10
|
-
labels: 2,
|
11
|
-
keys: 4,
|
12
|
-
values: 8,
|
13
|
-
all: 15,
|
14
|
-
indexer: "~tinkerpop.index.indexer",
|
15
|
-
list: 0,
|
16
|
-
map: 1
|
17
|
-
}.freeze
|
5
|
+
class WithOptions
|
6
|
+
WITH_OPTIONS = Grumlin.definitions.dig(:expressions, :with_options).freeze
|
18
7
|
|
19
8
|
class << self
|
20
9
|
WITH_OPTIONS.each do |k, v|
|
21
10
|
define_method k do
|
22
|
-
|
11
|
+
name = "@#{k}"
|
12
|
+
return instance_variable_get(name) if instance_variable_defined?(name)
|
13
|
+
|
14
|
+
instance_variable_set(name, WithOptions.new(k, v))
|
23
15
|
end
|
24
16
|
end
|
25
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
|
26
29
|
end
|
27
30
|
end
|
28
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,19 +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
|
-
|
17
|
+
if Grumlin::Action::REGULAR_STEPS.include?(name)
|
18
|
+
raise ArgumentError,
|
19
|
+
"cannot use names of standard gremlin steps"
|
20
|
+
end
|
21
|
+
|
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)
|
25
27
|
|
26
|
-
raise ArgumentError, "shortcut '#{name}' already exists" if shortcuts.key?(name) && shortcuts[name] !=
|
28
|
+
raise ArgumentError, "shortcut '#{name}' already exists" if shortcuts.key?(name) && shortcuts[name] != shortcut
|
27
29
|
|
28
|
-
shortcuts[name] =
|
30
|
+
shortcuts[name] = shortcut
|
29
31
|
end
|
30
32
|
|
31
33
|
def shortcuts_from(other_shortcuts)
|
32
|
-
other_shortcuts.shortcuts.each do |name,
|
33
|
-
shortcut(name,
|
34
|
+
other_shortcuts.shortcuts.each do |name, shortcut|
|
35
|
+
shortcut(name, shortcut)
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|