grumlin 0.15.2 → 0.15.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a7027bddd19689f2886286b1bcd099c7c8dbf764502f77b5469434cd243387e5
4
- data.tar.gz: b5a3e1e1db75e2a7378f77246c9b3bbbc066d5b32c575d15c88d38917d4658be
3
+ metadata.gz: 195f614a2cbebbe43f6dd2aedb3aeb54891c4377f50f85f21f44ee3325c87f58
4
+ data.tar.gz: 0f0a3c0b5aa8f03fb4d613c406b08497685ee9fb4cbea2e8a0b99385f749ebf3
5
5
  SHA512:
6
- metadata.gz: b116b30db9eeaf3255793843caa191b6942de7c16a5765b00aa0b803c5e7ae7a1e35d4da4372fd9e2ebe485555f9b895b0fb527cbb37ff89636824197e3a9821
7
- data.tar.gz: 11647d93fe2b33814a5356607bca81f2d30edf3992cbae4c52a2191cc34db8632e65bd672ac61030ed27a3c7a7387316d0522188b53e83cef63af2171d5a8494
6
+ metadata.gz: 21a7d91e9ce0a9e143f4bba9bb15d4bd31f6337f72500038bf09cd471ab05535d9d3ade4cfba6d6b6d779e09600b6352ed83b3e4bd70aeadd1417e51ba663937
7
+ data.tar.gz: 9cd14a8f18b856eca87d3b51b48c3f3c0d8d454b76fae92466bd7aee370019bbbb0b398236187acfcfed2322520aa4a3aa68a0e6bfb8b02a073e27f0db3cf525
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
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## [0.15.4] - 2022-01-20
2
+
3
+ - Move step and expression definitions to a yaml file for better diffs
4
+ - Add `definitions:format` rake task
5
+
6
+ ## [0.15.3] - 2022-01-18
7
+
8
+ - Fix passing nils as step arguments. Even if they are not supported by the server, they should not be omitted.
9
+
1
10
  ## [0.15.2] - 2022-01-17
2
11
 
3
12
  - New steps: `map` and `identity`
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grumlin (0.15.2)
4
+ grumlin (0.15.6)
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.32.2)
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
- require "rubocop/rake_task"
12
+ task default: %i[rubocop spec]
9
13
 
10
- RuboCop::RakeTask.new
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
- task default: %i[spec rubocop]
28
+ File.write(path, YAML.dump(definitions))
29
+ end
30
+ end
@@ -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
@@ -4,11 +4,7 @@ module Grumlin
4
4
  class AnonymousStep
5
5
  attr_reader :name, :previous_step, :configuration_steps
6
6
 
7
- # TODO: add other steps
8
- SUPPORTED_STEPS = %i[E V addE addV aggregate and as both bothE by choose coalesce count dedup drop elementMap emit
9
- fold from group groupCount has hasId hasLabel hasNot id identity in inE inV is label limit
10
- map not or order out outE path project properties property range repeat sack select sideEffect
11
- skip sum tail to unfold union until valueMap values where with].freeze
7
+ SUPPORTED_STEPS = Grumlin.definitions.dig(:steps, :regular).map(&:to_sym).freeze
12
8
 
13
9
  def initialize(name, *args, configuration_steps: [], previous_step: nil, **params)
14
10
  @name = name
@@ -41,7 +37,9 @@ module Grumlin
41
37
  end
42
38
 
43
39
  def args
44
- [*@args, @params.any? ? @params : nil].compact
40
+ [*@args].tap do |args|
41
+ args << @params if @params.any?
42
+ end
45
43
  end
46
44
  end
47
45
  end
@@ -3,7 +3,7 @@
3
3
  module Grumlin
4
4
  module Expressions
5
5
  module Operator
6
- SUPPORTED_STEPS = %i[addAll and assign div max min minus mult or sum].freeze
6
+ SUPPORTED_STEPS = Grumlin.definitions.dig(:expressions, :operator).map(&:to_sym).freeze
7
7
 
8
8
  class << self
9
9
  extend Expression
@@ -3,7 +3,7 @@
3
3
  module Grumlin
4
4
  module Expressions
5
5
  module Order
6
- SUPPORTED_STEPS = %i[asc desc shuffle].freeze
6
+ SUPPORTED_STEPS = Grumlin.definitions.dig(:expressions, :order).map(&:to_sym).freeze
7
7
 
8
8
  class << self
9
9
  extend Expression
@@ -3,7 +3,7 @@
3
3
  module Grumlin
4
4
  module Expressions
5
5
  module Pop
6
- SUPPORTED_STEPS = %i[all first last mixed].freeze
6
+ SUPPORTED_STEPS = Grumlin.definitions.dig(:expressions, :pop).map(&:to_sym).freeze
7
7
 
8
8
  class << self
9
9
  extend Expression
@@ -3,7 +3,7 @@
3
3
  module Grumlin
4
4
  module Expressions
5
5
  module Scope
6
- SUPPORTED_STEPS = %i[local].freeze
6
+ SUPPORTED_STEPS = Grumlin.definitions.dig(:expressions, :scope).map(&:to_sym).freeze
7
7
 
8
8
  class << self
9
9
  extend Expression
@@ -3,7 +3,7 @@
3
3
  module Grumlin
4
4
  module Expressions
5
5
  module T
6
- SUPPORTED_STEPS = %i[id label].freeze
6
+ SUPPORTED_STEPS = Grumlin.definitions.dig(:expressions, :t).map(&:to_sym).freeze
7
7
 
8
8
  class << self
9
9
  extend Expression
@@ -2,13 +2,10 @@
2
2
 
3
3
  module Grumlin
4
4
  module Expressions
5
+ # The module is called U because Underscore and implements __
5
6
  module U
6
- # TODO: add other start steps
7
- SUPPORTED_STEPS = %i[V addV coalesce constant count drop fold has hasLabel hasNot id identity in inE inV is label
8
- out outE outV project repeat select timeLimit unfold valueMap values].freeze
9
-
10
7
  class << self
11
- SUPPORTED_STEPS.each do |step|
8
+ Grumlin::AnonymousStep::SUPPORTED_STEPS.each do |step|
12
9
  define_method step do |*args, **params|
13
10
  AnonymousStep.new(step, *args, **params)
14
11
  end
@@ -3,18 +3,7 @@
3
3
  module Grumlin
4
4
  module Expressions
5
5
  module WithOptions
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
6
+ WITH_OPTIONS = Grumlin.definitions.dig(:expressions, :with_options).freeze
18
7
 
19
8
  class << self
20
9
  WITH_OPTIONS.each do |k, v|
@@ -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
@@ -18,7 +18,7 @@ module Grumlin
18
18
 
19
19
  return wrap_result(@object.public_send(name, *args, **params)) if @object.respond_to?(name)
20
20
 
21
- return wrap_result(instance_exec(*args, **params, &@shortcuts[name])) if @shortcuts.key?(name)
21
+ return wrap_result(@shortcuts[name].apply(self, *args, **params)) if @shortcuts.key?(name)
22
22
 
23
23
  super
24
24
  end
@@ -18,19 +18,28 @@ module Grumlin
18
18
  subclass.shortcuts_from(self)
19
19
  end
20
20
 
21
- def shortcut(name, &block)
21
+ def shortcut(name, shortcut = nil, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
22
22
  name = name.to_sym
23
23
  # TODO: blocklist of names to avoid conflicts with standard methods?
24
- raise ArgumentError, "cannot use names of standard gremlin steps" if Grumlin.supported_steps.include?(name)
24
+ if Grumlin::AnonymousStep::SUPPORTED_STEPS.include?(name)
25
+ raise ArgumentError,
26
+ "cannot use names of standard gremlin steps"
27
+ end
28
+
29
+ if (shortcut.nil? && block.nil?) || (shortcut && block)
30
+ raise ArgumentError, "either shortcut or block must be passed"
31
+ end
32
+
33
+ shortcut ||= Shortcut.new(name, &block)
25
34
 
26
- raise ArgumentError, "shortcut '#{name}' already exists" if shortcuts.key?(name) && shortcuts[name] != block
35
+ raise ArgumentError, "shortcut '#{name}' already exists" if shortcuts.key?(name) && shortcuts[name] != shortcut
27
36
 
28
- shortcuts[name] = block
37
+ shortcuts[name] = shortcut
29
38
  end
30
39
 
31
40
  def shortcuts_from(other_shortcuts)
32
- other_shortcuts.shortcuts.each do |name, block|
33
- shortcut(name, &block)
41
+ other_shortcuts.shortcuts.each do |name, shortcut|
42
+ shortcut(name, shortcut)
34
43
  end
35
44
  end
36
45
 
@@ -2,10 +2,9 @@
2
2
 
3
3
  module Grumlin
4
4
  class Traversal
5
- # TODO: add other start steps
6
- SUPPORTED_STEPS = %i[E V addE addV].freeze
5
+ SUPPORTED_STEPS = Grumlin.definitions.dig(:steps, :start).map(&:to_sym).freeze
7
6
 
8
- CONFIGURATION_STEPS = %i[withSack withSideEffect].freeze
7
+ CONFIGURATION_STEPS = Grumlin.definitions.dig(:steps, :configuration).map(&:to_sym).freeze
9
8
 
10
9
  attr_reader :configuration_steps
11
10
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Grumlin
4
- VERSION = "0.15.2"
4
+ VERSION = "0.15.6"
5
5
  end
data/lib/grumlin.rb CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  require "securerandom"
4
4
  require "oj"
5
+ require "yaml"
5
6
 
7
+ # TODO: use Oj directly
6
8
  Oj.mimic_JSON
7
9
  Oj.add_to_json
8
10
 
@@ -108,10 +110,6 @@ module Grumlin
108
110
  end
109
111
  end
110
112
 
111
- def self.supported_steps
112
- @supported_steps ||= (Grumlin::AnonymousStep::SUPPORTED_STEPS + Grumlin::Expressions::U::SUPPORTED_STEPS).sort.uniq
113
- end
114
-
115
113
  @pool_mutex = Mutex.new
116
114
 
117
115
  class << self
@@ -145,6 +143,10 @@ module Grumlin
145
143
  Thread.current.thread_variable_set(:grumlin_default_pool, nil)
146
144
  end
147
145
  end
146
+
147
+ def definitions
148
+ @definitions ||= YAML.safe_load(File.read(File.join(__dir__, "definitions.yml")), symbolize_names: true)
149
+ end
148
150
  end
149
151
  end
150
152
 
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.15.2
4
+ version: 0.15.6
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-01-17 00:00:00.000000000 Z
11
+ date: 2022-03-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async-pool
@@ -96,6 +96,7 @@ files:
96
96
  - gremlin_server/tinkergraph-empty.properties
97
97
  - grumlin.gemspec
98
98
  - lib/async/channel.rb
99
+ - lib/definitions.yml
99
100
  - lib/grumlin.rb
100
101
  - lib/grumlin/anonymous_step.rb
101
102
  - lib/grumlin/bytecode.rb
@@ -114,6 +115,7 @@ files:
114
115
  - lib/grumlin/property.rb
115
116
  - lib/grumlin/repository.rb
116
117
  - lib/grumlin/request_dispatcher.rb
118
+ - lib/grumlin/shortcut.rb
117
119
  - lib/grumlin/shortcut_proxy.rb
118
120
  - lib/grumlin/shortcuts.rb
119
121
  - lib/grumlin/shortcuts/properties.rb