grumlin 0.19.5 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 80bbea20c7a9e194618b59cc128ae8e783af4d342ddd9ca56039f08013218a81
4
- data.tar.gz: baf7565f084501e8b4488bf5d7d8e09a5c786b91181dda46919b0668662ecfd0
3
+ metadata.gz: 0ab9e228cb2cd8ecc761136dab0e92a42aae268708aecf5784aac670a4404ecb
4
+ data.tar.gz: 984d2323e97056291370c37dadc2cf90d694f27caa753053a110165985dc067b
5
5
  SHA512:
6
- metadata.gz: 3c2760d46e3bada592f71da13bbbec31a970cde6c112a57d06f435eb673ba213573d98e82e65080c5453f521c27c27f6037472cd1db65046dfa31432f879d3e1
7
- data.tar.gz: e6a073136f3ebeaaf1cac78a6c6886a2e7a91beeaf18a61d340e18ab968018859861de64fc01a04f7ba708fea9ab8859706b6edb5f27c9432a2116717d323c55
6
+ metadata.gz: 27a73c8e77850b99e030c129f8df2e30fc6933ad4da29e5a205b7812c64c88f24d7aceb2128af6687fc4bf35056509421989d2cae5a51c5db6f53c18f735fe97
7
+ data.tar.gz: adf371f27c60f2c0e70feaafcfede32dc64beef09b098bf35f01270b37049ee5ce76a68c184bf80abe33c7069ca8b947bbd54ecdcab42fd461a8bb09c270b1b1
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  --color
2
+ --require dead_end
2
3
  --require spec_helper
data/Gemfile CHANGED
@@ -13,6 +13,7 @@ gem "overcommit"
13
13
  gem "rake"
14
14
 
15
15
  gem "async-rspec"
16
+ gem "dead_end"
16
17
  gem "factory_bot"
17
18
  gem "rspec"
18
19
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grumlin (0.19.5)
4
+ grumlin (0.20.0)
5
5
  async-pool (~> 0.3)
6
6
  async-websocket (~> 0.19)
7
7
  oj (~> 3.13)
@@ -17,7 +17,7 @@ GEM
17
17
  minitest (>= 5.1)
18
18
  tzinfo (~> 2.0)
19
19
  ast (2.4.2)
20
- async (1.30.2)
20
+ async (1.30.3)
21
21
  console (~> 1.10)
22
22
  nio4r (~> 2.3)
23
23
  timers (~> 4.1)
@@ -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.14)
75
+ oj (3.13.16)
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
@@ -143,6 +143,20 @@ class MyRepository
143
143
  end
144
144
  ```
145
145
 
146
+ ##### Overriding standard steps
147
+
148
+ Sometimes it may be useful to override standard steps. Grumlin does not allow it by default, but one
149
+ is still able to override standard steps if they know what they are doing:
150
+
151
+ ```ruby
152
+ shortcut :addV, override: true do |label|
153
+ super(label).property(:default, :value)
154
+ end
155
+ ```
156
+
157
+ This will create a new shortcut that overrides the standard step `addV` and adds default properties to all vertices
158
+ created by the repository that uses this shortcut.
159
+
146
160
  #### Grumlin::Repository
147
161
  `Grumlin::Repository` combines functionality of `Grumlin::Sugar` and `Grumlin::Shortcuts` as well as adds a few useful
148
162
  shortcuts to make gremlin code more rubyish. Can be used as a drop in replacement for `Grumlin::Sugar`. Remember that
@@ -167,6 +181,23 @@ class MyRepository
167
181
  hasAll(T.label => :triangle, color: color)
168
182
  end
169
183
 
184
+ # `default_vertex_properties` and `default_edge_properties`
185
+ # override `addV` and `addE` according and inject hashes returned from passed
186
+ # as properties for newly created vertices and edges.
187
+ # In case if a repository is inherited, newly defined default properties will be merged to
188
+ # default properties defined in the parent repository.
189
+ default_vertex_properties do |_label|
190
+ {
191
+ created_at: Time.now.to_i
192
+ }
193
+ end
194
+
195
+ default_edge_properties do |_label|
196
+ {
197
+ created_at: Time.now.to_i
198
+ }
199
+ end
200
+
170
201
  # g and __ are already aware of shortcuts
171
202
  query(:triangles_with_color, return_mode: :list) do |color| # :list is the default return mode, also possible: :none, :single, :traversal
172
203
  g.V.hasLabel(:triangle)
data/bin/console CHANGED
@@ -7,6 +7,8 @@ require "grumlin"
7
7
  require "irb"
8
8
  require "irb/completion"
9
9
 
10
+ require "dead_end"
11
+
10
12
  Grumlin.configure do |config|
11
13
  config.url = ENV.fetch("GREMLIN_URL", "ws://localhost:8182/gremlin")
12
14
  end
@@ -1,3 +1,7 @@
1
1
  FROM tinkerpop/gremlin-server
2
2
 
3
+ RUN rm -rf /opt/gremlin-server/ext/tinkergraph-gremlin
4
+
5
+ ADD tinkergraph-gremlin /opt/gremlin-server/ext/tinkergraph-gremlin
6
+
3
7
  ADD tinkergraph-empty.properties /opt/gremlin-server/conf/
data/grumlin.gemspec CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.metadata["homepage_uri"] = spec.homepage
22
22
  spec.metadata["source_code_uri"] = "https://github.com/zhulik/grumlin"
23
23
  spec.metadata["changelog_uri"] = "https://github.com/zhulik/grumlin/blob/master/CHANGELOG.md"
24
+ spec.metadata["rubygems_mfa_required"] = "true"
24
25
 
25
26
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
27
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
@@ -32,7 +33,4 @@ Gem::Specification.new do |spec|
32
33
  spec.add_dependency "oj", "~> 3.13"
33
34
  spec.add_dependency "retryable", "~> 3.0"
34
35
  spec.add_dependency "zeitwerk", "~> 2.6"
35
- spec.metadata = {
36
- "rubygems_mfa_required" => "true"
37
- }
38
36
  end
data/lib/definitions.yml CHANGED
@@ -8,9 +8,11 @@ steps:
8
8
  - aggregate
9
9
  - and
10
10
  - as
11
+ - barrier
11
12
  - both
12
13
  - bothE
13
14
  - by
15
+ - cap
14
16
  - choose
15
17
  - coalesce
16
18
  - constant
@@ -19,6 +21,7 @@ steps:
19
21
  - drop
20
22
  - elementMap
21
23
  - emit
24
+ - filter
22
25
  - fold
23
26
  - from
24
27
  - group
@@ -37,6 +40,9 @@ steps:
37
40
  - label
38
41
  - limit
39
42
  - map
43
+ - match
44
+ - max
45
+ - min
40
46
  - none
41
47
  - not
42
48
  - option
@@ -77,9 +83,13 @@ steps:
77
83
  - withSack
78
84
  - withSideEffect
79
85
  expressions:
86
+ cardinality:
87
+ - list
88
+ - set
89
+ - single
80
90
  column:
81
- - keys
82
- - values
91
+ - keys
92
+ - values
83
93
  operator:
84
94
  - addAll
85
95
  - and
@@ -1,32 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
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
4
+ class Action < Steppable
5
+ attr_reader :name, :args, :params, :next_step, :configuration_steps, :previous_step, :shortcut
8
6
 
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)
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
- @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)
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
- @shortcuts == other.shortcuts
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
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grumlin
4
+ module Expressions
5
+ module Cardinality
6
+ SUPPORTED_STEPS = Grumlin.definitions.dig(:expressions, :cardinality).map(&:to_sym).freeze
7
+
8
+ class << self
9
+ extend Expression
10
+
11
+ define_steps(SUPPORTED_STEPS, "Cardinality")
12
+ end
13
+ end
14
+ end
15
+ end
@@ -16,7 +16,7 @@ module Grumlin
16
16
 
17
17
  class << self
18
18
  # TODO: support more predicates
19
- %i[eq neq].each do |predicate|
19
+ %i[eq gt lt neq].each do |predicate|
20
20
  define_method predicate do |*args|
21
21
  Predicate.new("P", predicate, value: args[0])
22
22
  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
- def __
18
- @__ ||= TraversalStart.new(self.class.shortcuts)
19
- end
19
+ def_delegators :shortcuts, :g, :__
20
20
 
21
- def g
22
- @g ||= TraversalStart.new(self.class.shortcuts)
21
+ def shortcuts
22
+ self.class.shortcuts
23
23
  end
24
24
 
25
25
  def drop_vertex(id)
@@ -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 self.class.empty_result?(t)
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.key?(return_mode)
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.key?(request[:requestId])
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.key?(request_id)
76
+ @requests.include?(request_id)
77
77
  end
78
78
 
79
79
  def clear
@@ -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,105 @@
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
+ # not lazy shortcuts are allowed to be overridden
35
+ if known?(name) && @storage[name] != shortcut && shortcut.lazy?
36
+ raise ArgumentError,
37
+ "shortcut '#{name}' already exists"
38
+ end
39
+
40
+ @storage[name] = shortcut
41
+
42
+ ac = action_class
43
+
44
+ shortcut_methods_module.define_method(name) do |*args, **params|
45
+ next ac.new(name, args: args, params: params, previous_step: self)
46
+ end
47
+ extend_traversal_classes(shortcut) unless shortcut.lazy?
48
+ end
49
+
50
+ def add_from(other)
51
+ other.storage.each do |name, shortcut|
52
+ add(name, shortcut)
53
+ end
54
+ end
55
+
56
+ def g
57
+ __
58
+ end
59
+
60
+ def __
61
+ @__ ||= traversal_start_class.new
62
+ end
63
+
64
+ def traversal_start_class
65
+ @traversal_start_class ||= shortcut_aware_class(TraversalStart)
66
+ end
67
+
68
+ def action_class
69
+ @action_class ||= shortcut_aware_class(Action)
70
+ end
71
+
72
+ protected
73
+
74
+ attr_reader :storage
75
+
76
+ private
77
+
78
+ def shortcut_methods_module
79
+ @shortcut_methods_module ||= begin
80
+ shorts = self
81
+ Module.new do
82
+ define_method :shortcuts do
83
+ shorts
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ def shortcut_aware_class(base)
90
+ methods = shortcut_methods_module
91
+ Class.new(base) do
92
+ include methods
93
+ end
94
+ end
95
+
96
+ def extend_traversal_classes(shortcut)
97
+ m = Module.new do
98
+ define_method(shortcut.name, &shortcut.block)
99
+ end
100
+ action_class.include(m)
101
+ traversal_start_class.include(m)
102
+ end
103
+ end
104
+ end
105
+ 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( # TODO: extract upsert pattern to a shortcut
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
@@ -11,33 +11,26 @@ module Grumlin
11
11
  subclass.shortcuts_from(self)
12
12
  end
13
13
 
14
- def shortcut(name, shortcut = nil, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
14
+ def shortcut(name, shortcut = nil, override: false, lazy: true, &block)
15
15
  name = name.to_sym
16
- # TODO: blocklist of names to avoid conflicts with standard methods?
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 (shortcut.nil? && block.nil?) || (shortcut && block)
23
- raise ArgumentError, "either shortcut or block must be passed"
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 ||= Shortcut.new(name, &block)
23
+ raise ArgumentError, "either shortcut or block must be passed" if [shortcut, block].count(&:nil?) != 1
27
24
 
28
- raise ArgumentError, "shortcut '#{name}' already exists" if shortcuts.key?(name) && shortcuts[name] != shortcut
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.each do |name, shortcut|
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 unless steps.uses_shortcuts?
7
+ return steps if !steps.is_a?(Steps) || !steps.uses_shortcuts?
8
8
 
9
9
  shortcuts = steps.shortcuts
10
10
 
11
- configuration_steps = process_steps(steps.configuration_steps, shortcuts)
12
- regular_steps = process_steps(steps.steps, shortcuts)
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
- (configuration_steps + regular_steps).each do |step|
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 do |arg|
26
- arg.is_a?(Steps) ? ShortcutsApplyer.call(arg) : arg
27
- end
27
+ args = step.args.map { |arg| call(arg) }
28
28
 
29
- if shortcuts.include?(step.name)
30
- t = TraversalStart.new(shortcuts)
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
- new_steps = ShortcutsApplyer.call(Steps.from(action))
35
- result.concat(new_steps.configuration_steps)
36
- result.concat(new_steps.steps)
37
- else
38
- result << StepData.new(step.name, args: args, params: step.params)
39
- end
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,32 @@
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 RuntimerError,
17
+ "steppable must not be initialized directly, use Grumlin::Shortcuts::Storage#g or #__ instead"
18
+ end
19
+
20
+ ALL_STEPS.each do |step|
21
+ define_method step do |*args, **params|
22
+ shortcuts.action_class.new(step, args: args, params: params, previous_step: self)
23
+ end
24
+ end
25
+
26
+ def step(name, *args, **params)
27
+ shortcuts.action_class.new(name, args: args, params: params, previous_step: self)
28
+ end
29
+
30
+ def_delegator :shortcuts, :__
31
+ end
32
+ 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.include?(step.name) || step.args.any? do |arg|
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
- def __(shortcuts = {})
10
- Grumlin::TraversalStart.new(shortcuts) # TODO: allow only regular and start steps
11
- end
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,39 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
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
-
4
+ class TraversalStart < Steppable
37
5
  def to_s(*)
38
6
  self.class.to_s
39
7
  end
@@ -41,11 +9,5 @@ module Grumlin
41
9
  def inspect
42
10
  self.class.inspect
43
11
  end
44
-
45
- private
46
-
47
- def respond_to_missing?(name, _include_private = false)
48
- @shortcuts.key?(name)
49
- end
50
12
  end
51
13
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Grumlin
4
- VERSION = "0.19.5"
4
+ VERSION = "0.20.0"
5
5
  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.19.5
4
+ version: 0.20.0
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-06-14 00:00:00.000000000 Z
11
+ date: 2022-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async-pool
@@ -108,6 +108,8 @@ files:
108
108
  - docker-compose.yml
109
109
  - gremlin_server/Dockerfile
110
110
  - gremlin_server/tinkergraph-empty.properties
111
+ - gremlin_server/tinkergraph-gremlin/lib/tinkergraph-gremlin-3.5.3.jar
112
+ - gremlin_server/tinkergraph-gremlin/plugin/tinkergraph-gremlin-3.5.3.jar
111
113
  - grumlin.gemspec
112
114
  - lib/async/channel.rb
113
115
  - lib/definitions.yml
@@ -116,6 +118,7 @@ files:
116
118
  - lib/grumlin/benchmark/repository.rb
117
119
  - lib/grumlin/client.rb
118
120
  - lib/grumlin/edge.rb
121
+ - lib/grumlin/expressions/cardinality.rb
119
122
  - lib/grumlin/expressions/column.rb
120
123
  - lib/grumlin/expressions/expression.rb
121
124
  - lib/grumlin/expressions/operator.rb
@@ -135,9 +138,11 @@ files:
135
138
  - lib/grumlin/shortcut.rb
136
139
  - lib/grumlin/shortcuts.rb
137
140
  - lib/grumlin/shortcuts/properties.rb
141
+ - lib/grumlin/shortcuts/storage.rb
138
142
  - lib/grumlin/shortcuts/upserts.rb
139
143
  - lib/grumlin/shortcuts_applyer.rb
140
144
  - lib/grumlin/step_data.rb
145
+ - lib/grumlin/steppable.rb
141
146
  - lib/grumlin/steps.rb
142
147
  - lib/grumlin/steps_serializers/bytecode.rb
143
148
  - lib/grumlin/steps_serializers/human_readable_bytecode.rb
@@ -159,6 +164,9 @@ homepage: https://github.com/zhulik/grumlin
159
164
  licenses:
160
165
  - MIT
161
166
  metadata:
167
+ homepage_uri: https://github.com/zhulik/grumlin
168
+ source_code_uri: https://github.com/zhulik/grumlin
169
+ changelog_uri: https://github.com/zhulik/grumlin/blob/master/CHANGELOG.md
162
170
  rubygems_mfa_required: 'true'
163
171
  post_install_message:
164
172
  rdoc_options: []