grumlin 0.23.0 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +9 -9
  3. data/Gemfile.lock +1 -1
  4. data/README.md +94 -141
  5. data/Rakefile +1 -1
  6. data/bin/console +18 -3
  7. data/doc/middlewares.md +49 -10
  8. data/lib/async/channel.rb +54 -56
  9. data/lib/grumlin/benchmark/repository.rb +10 -14
  10. data/lib/grumlin/client.rb +93 -95
  11. data/lib/grumlin/config.rb +33 -33
  12. data/lib/grumlin/dummy_transaction.rb +13 -15
  13. data/lib/grumlin/edge.rb +18 -20
  14. data/lib/grumlin/expressions/cardinality.rb +5 -9
  15. data/lib/grumlin/expressions/column.rb +5 -9
  16. data/lib/grumlin/expressions/expression.rb +7 -11
  17. data/lib/grumlin/expressions/operator.rb +5 -9
  18. data/lib/grumlin/expressions/order.rb +5 -9
  19. data/lib/grumlin/expressions/p.rb +27 -31
  20. data/lib/grumlin/expressions/pop.rb +5 -9
  21. data/lib/grumlin/expressions/scope.rb +5 -9
  22. data/lib/grumlin/expressions/t.rb +5 -9
  23. data/lib/grumlin/expressions/text_p.rb +5 -9
  24. data/lib/grumlin/expressions/with_options.rb +17 -21
  25. data/lib/grumlin/features/feature_list.rb +8 -12
  26. data/lib/grumlin/features/neptune_features.rb +5 -9
  27. data/lib/grumlin/features/tinkergraph_features.rb +5 -9
  28. data/lib/grumlin/features.rb +8 -10
  29. data/lib/grumlin/middlewares/apply_shortcuts.rb +4 -8
  30. data/lib/grumlin/middlewares/build_query.rb +16 -20
  31. data/lib/grumlin/middlewares/builder.rb +15 -0
  32. data/lib/grumlin/middlewares/cast_results.rb +3 -7
  33. data/lib/grumlin/middlewares/find_blocklisted_steps.rb +14 -0
  34. data/lib/grumlin/middlewares/find_mutating_steps.rb +9 -0
  35. data/lib/grumlin/middlewares/middleware.rb +6 -10
  36. data/lib/grumlin/middlewares/run_query.rb +3 -7
  37. data/lib/grumlin/middlewares/serialize_to_bytecode.rb +5 -9
  38. data/lib/grumlin/middlewares/serialize_to_steps.rb +4 -8
  39. data/lib/grumlin/path.rb +11 -13
  40. data/lib/grumlin/property.rb +14 -16
  41. data/lib/grumlin/query_validators/blocklisted_steps_validator.rb +22 -0
  42. data/lib/grumlin/query_validators/validator.rb +36 -0
  43. data/lib/grumlin/repository/error_handling_strategy.rb +36 -40
  44. data/lib/grumlin/repository/instance_methods.rb +115 -118
  45. data/lib/grumlin/repository.rb +82 -58
  46. data/lib/grumlin/request_dispatcher.rb +55 -57
  47. data/lib/grumlin/request_error_factory.rb +53 -55
  48. data/lib/grumlin/shortcut.rb +19 -21
  49. data/lib/grumlin/shortcuts/properties.rb +12 -16
  50. data/lib/grumlin/shortcuts/storage.rb +67 -74
  51. data/lib/grumlin/shortcuts/upserts.rb +18 -22
  52. data/lib/grumlin/shortcuts.rb +23 -25
  53. data/lib/grumlin/shortcuts_applyer.rb +27 -29
  54. data/lib/grumlin/step.rb +88 -90
  55. data/lib/grumlin/step_data.rb +12 -14
  56. data/lib/grumlin/steppable.rb +23 -25
  57. data/lib/grumlin/steps.rb +52 -54
  58. data/lib/grumlin/steps_serializers/bytecode.rb +53 -56
  59. data/lib/grumlin/steps_serializers/human_readable_bytecode.rb +17 -21
  60. data/lib/grumlin/steps_serializers/serializer.rb +7 -11
  61. data/lib/grumlin/steps_serializers/string.rb +26 -30
  62. data/lib/grumlin/test/rspec/db_cleaner_context.rb +8 -12
  63. data/lib/grumlin/test/rspec/gremlin_context.rb +18 -16
  64. data/lib/grumlin/test/rspec.rb +1 -5
  65. data/lib/grumlin/transaction.rb +34 -36
  66. data/lib/grumlin/transport.rb +71 -73
  67. data/lib/grumlin/traversal_start.rb +31 -33
  68. data/lib/grumlin/traversal_strategies/options_strategy.rb +3 -7
  69. data/lib/grumlin/traverser.rb +5 -7
  70. data/lib/grumlin/typed_value.rb +11 -13
  71. data/lib/grumlin/typing.rb +70 -72
  72. data/lib/grumlin/version.rb +1 -1
  73. data/lib/grumlin/vertex.rb +14 -16
  74. data/lib/grumlin/vertex_property.rb +14 -16
  75. data/lib/grumlin/with_extension.rb +17 -19
  76. metadata +9 -6
  77. data/lib/grumlin/middlewares/frozen_builder.rb +0 -18
  78. data/lib/grumlin/sugar.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0560f7bf90bba9601628d6042ac1286076f9a8e9039b6f8e755b6f4beedb3e1a
4
- data.tar.gz: 83b7b4409198a6cbb5520b003e2dcdacfe8623b9aa8c057b0e9df1e29692a4f3
3
+ metadata.gz: e5a4223c6fde72d3f4ce23f3da0081a816f395a070d8737d9915f15b166c9721
4
+ data.tar.gz: 8c95dcb15d4f55741cc370298e1e763427858908abebaec33f945e404d3a6fa3
5
5
  SHA512:
6
- metadata.gz: f87b6a69c71ebd867f227b35e13a50c499d054c6688747465e05a41426167ee3ffea5afbfb1875ca5c49e6a0c2a97f42ea20b93f9cf32cd5966942ba844f839c
7
- data.tar.gz: 4b5262eacf5e57f4ad95e6cc5f450d924858b1e238e2bf3943b9b127da53db36c76078b22d8ba5d244aa35e5d0ddfc4db45516481bd41c58bbe2123ac262dd5f
6
+ metadata.gz: 69162f44551c45c0898ffa0c3650cee448a155d1950de5ea0a2a4b570c1b2b41612f3b97bd063f88f683af5fad3c18d4b874b96392a30334c77ab0e1fb1fd226
7
+ data.tar.gz: 1fdb7d10a84da7d8c8173e2b0edb0f5b0f913fb0418fce59bb92d28de9c2e9a1743b89eca1f0ed8495b4d0519d2068c2314e9f17f23b77a4297e080512ace082
data/.rubocop.yml CHANGED
@@ -65,10 +65,6 @@ RSpec/DescribeClass:
65
65
  RSpec/MultipleMemoizedHelpers:
66
66
  Max: 7
67
67
 
68
- Style/WordArray:
69
- Exclude:
70
- - spec/**/*_spec.rb
71
-
72
68
  Style/StringLiterals:
73
69
  Enabled: true
74
70
  EnforcedStyle: double_quotes
@@ -83,9 +79,13 @@ Style/Documentation:
83
79
  Style/MultilineBlockChain:
84
80
  Enabled: false
85
81
 
82
+ Style/SymbolArray:
83
+ EnforcedStyle: brackets
84
+
85
+ Style/WordArray:
86
+ EnforcedStyle: brackets
87
+ Exclude:
88
+ - spec/**/*_spec.rb
86
89
 
87
- # TODO:
88
- # Style/SymbolArray:
89
- # EnforcedStyle: brackets
90
- # Style/WordArray:
91
- # EnforcedStyle: brackets
90
+ Style/ClassAndModuleChildren:
91
+ EnforcedStyle: compact
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grumlin (0.23.0)
4
+ grumlin (1.0.0.rc1)
5
5
  async-pool (~> 0.3)
6
6
  async-websocket (>= 0.19, < 0.20)
7
7
  ibsciss-middleware (~> 0.4.0)
data/README.md CHANGED
@@ -82,116 +82,11 @@ Current differences between providers:
82
82
 
83
83
  **Warning**: Not all steps and expressions defined in the reference documentation are supported.
84
84
 
85
- #### Sugar
86
-
87
- Grumlin provides an easy to use module called `Grumlin::Sugar`. Once included in your class it injects some useful
88
- constants and methods turning your class into an entrypoint for traversals with pure gremlin experience.
89
-
90
- ```ruby
91
- class MyRepository
92
- include Grumlin::Sugar
93
-
94
- def nodes(property1:, property2:)
95
- g.V()
96
- .has(T.label, "node")
97
- .has(:property1, property1)
98
- .has(:property2, property2)
99
- .order.by(:property3, Order.asc).limit(10)
100
- .toList
101
- end
102
- end
103
- ```
104
-
105
- #### Shortcuts
106
-
107
- **Shortcuts** is a way to share and organize gremlin code. They let developers define their own steps consisting of
108
- sequences of standard gremlin steps, other shortcuts and even add new initially unsupported by Grumlin steps.
109
- Remember ActiveRecord scopes? Shortcuts are very similar.
110
-
111
- **Important**: if a shortcut's name matches a name of a method defined on the wrapped object, this shortcut will be
112
- be ignored because methods have higher priority.
113
-
114
- Shortcuts are designed to be used with `Grumlin::Repository` but still can be used separately, with `Grumlin::Sugar`
115
- for example.
116
-
117
- **Defining**:
118
- ```ruby
119
-
120
- # Defining shortcuts
121
- class ColorShortcut
122
- extend Grumlin::Shortcuts
123
-
124
- # Custom step
125
- shortcut :hasColor do |color|
126
- has(:color, color)
127
- end
128
- end
129
-
130
- class ChooseShortcut
131
- extend Grumlin::Shortcuts
132
-
133
- # Standard Gremlin step
134
- shortcut :choose do |*args|
135
- step(:choose, *args)
136
- end
137
- end
138
-
139
- class AllShortcuts
140
- extend Grumlin::Shortcuts
141
-
142
- # Adding shortcuts from other modules
143
- shortcuts_from ColorShortcut
144
- shortcuts_from ChooseShortcut
145
- end
146
- ```
147
-
148
- **Using with Grumlin::Sugar**:
149
- ```ruby
150
- class MyRepository
151
- include Grumlin::Sugar
152
- extend Grumlin::Shortcuts
153
-
154
- shortcuts_from AllShortcuts
155
-
156
- # Wrapping a traversal
157
- def red_triangles
158
- g(self.class.shortcuts).V.hasLabel(:triangle)
159
- .hasColor("red")
160
- .toList
161
- end
162
-
163
- # Wrapping _
164
- def something_else
165
- g(self.class.shortcuts).V.hasColor("red")
166
- .repeat(__(self.class.shortcuts))
167
- .out(:has)
168
- .hasColor("blue")
169
- .toList
170
- end
171
- end
172
- ```
173
-
174
- ##### Overriding standard steps and shortcuts
175
-
176
- Sometimes it may be useful to override standard steps. Grumlin does not allow it by default, but one
177
- is still able to override standard steps if they know what they are doing:
178
-
179
- ```ruby
180
- shortcut :addV, override: true do |label|
181
- super(label).property(:default, :value)
182
- end
183
- ```
184
-
185
- This will create a new shortcut that overrides the standard step `addV` and adds default properties to all vertices
186
- created by the repository that uses this shortcut.
187
-
188
- Shortcuts also can be overridden, but super() is not available.
189
-
190
85
  #### Grumlin::Repository
191
- `Grumlin::Repository` combines functionality of `Grumlin::Sugar` and `Grumlin::Shortcuts` as well as adds a few useful
192
- shortcuts to make gremlin code more rubyish. Can be used as a drop in replacement for `Grumlin::Sugar`. Remember that
193
- `Grumlin::Sugar` needs to be included, but `Grumlin::Repository` - extended. **Classes extending `Grumlin::Repository`
194
- or `Grumlin::Shortcuts` can be inherited**, successors don't need to extend them again and have access to shortcuts
86
+ `Grumlin::Repository` - is a starting point for all traversals. It provides easy access to `g`, `__` and usual gremlin
87
+ expressions for you class. It has support for defining your own shortcuts and is even shipped with a couple of useful
88
+ shortcuts to make gremlin code more rubyish. **Classes extending `Grumlin::Repository`
89
+ or `Grumlin::Shortcuts` can be inherited**, successors don't need to extend them again and have access to shortcuts
195
90
  defined in the ancestor.
196
91
 
197
92
  **Definition**
@@ -199,8 +94,8 @@ defined in the ancestor.
199
94
  ```ruby
200
95
  class MyRepository
201
96
  extend Grumlin::Repository
202
-
203
- # Repository supports all Grumlin::Shortcut and Grumlin::Sugar features.
97
+ # read_only! - forbids mutating queries for this repository. May be useful for separation reads and writes
98
+
204
99
  # It can add shortcuts from another repository or a shortcuts module
205
100
  shortcuts_from ChooseShortcut
206
101
 
@@ -252,13 +147,13 @@ Each `return_mode` is mapped to a particular termination step:
252
147
  - `drop_in_batches(traversal, batch_size: 10_000)`
253
148
 
254
149
  and a few methods that emulate upserts:
255
- - `upsert_vertex(label, id, create_properties: {}, update_properties: {}, on_failure: :retry, start: g, **params)`
150
+ - `upsert_vertex(label, id, create_properties: {}, update_properties: {}, on_failure: :retry, start: g, **params)`
256
151
  - `upsert_edge(label, from:, to:, create_properties: {}, update_properties: {}, on_failure: :retry, start: g, **params)`
257
152
  - `upsert_edges(edges, batch_size: 100, on_failure: :retry, start: g, **params)`
258
153
  - `upsert_vertices(edges, batch_size: 100, on_failure: :retry, start: g, **params)`
259
154
 
260
155
  All of them support 3 different modes for error handling: `:retry`, `:ignore` and `:raise`. Retry mode is implemented
261
- with [retryable](https://github.com/nfedyashev/retryable). **params will be merged to the default config for upserts
156
+ with [retryable](https://github.com/nfedyashev/retryable). **params will be merged to the default config for upserts
262
157
  and passed to `Retryable.retryable`. In case if you want to modify retryable behaviour you are to do so.
263
158
 
264
159
  If you want to use these methods inside a transaction simply pass your `gtx` as `start` parameter:
@@ -270,7 +165,7 @@ end
270
165
 
271
166
  If you don't want to define you own repository, simply use
272
167
 
273
- `Grumlin::Repository.new` returns an instance of an anonymous class extending `Grumlin::Repository`.
168
+ `Grumlin::Repository.new` returns an instance of an anonymous class extending `Grumlin::Repository`.
274
169
 
275
170
  **Usage**
276
171
 
@@ -295,6 +190,62 @@ it may be useful for debugging. Note that one needs to call a termination step m
295
190
 
296
191
  method will return profiling data of the results.
297
192
 
193
+ #### Shortcuts
194
+
195
+ **Shortcuts** is a way to share and organize gremlin code. They let developers define their own steps consisting of
196
+ sequences of standard gremlin steps, other shortcuts and even add new initially unsupported by Grumlin steps.
197
+ Remember ActiveRecord scopes? Shortcuts are very similar.
198
+
199
+ **Important**: if a shortcut's name matches a name of a method defined on the wrapped object, this shortcut will be
200
+ be ignored because methods have higher priority.
201
+
202
+ **Defining**:
203
+ ```ruby
204
+
205
+ # Defining shortcuts
206
+ class ColorShortcut
207
+ extend Grumlin::Shortcuts
208
+
209
+ # Custom step
210
+ shortcut :hasColor do |color|
211
+ has(:color, color)
212
+ end
213
+ end
214
+
215
+ class ChooseShortcut
216
+ extend Grumlin::Shortcuts
217
+
218
+ # Standard Gremlin step
219
+ shortcut :choose do |*args|
220
+ step(:choose, *args)
221
+ end
222
+ end
223
+
224
+ class AllShortcuts
225
+ extend Grumlin::Shortcuts
226
+
227
+ # Adding shortcuts from other modules
228
+ shortcuts_from ColorShortcut
229
+ shortcuts_from ChooseShortcut
230
+ end
231
+ ```
232
+
233
+ ##### Overriding standard steps and shortcuts
234
+
235
+ Sometimes it may be useful to override standard steps. Grumlin does not allow it by default, but one
236
+ is still able to override standard steps if they know what they are doing:
237
+
238
+ ```ruby
239
+ shortcut :addV, override: true do |label|
240
+ super(label).property(:default, :value)
241
+ end
242
+ ```
243
+
244
+ This will create a new shortcut that overrides the standard step `addV` and adds default properties to all vertices
245
+ created by the repository that uses this shortcut.
246
+
247
+ Shortcuts also can be overridden, but super() is not available.
248
+
298
249
  ##### Middlewares
299
250
 
300
251
  Middlewares can be used to perform certain actions before and after every query made by `Grumlin`. It can be useful for
@@ -323,41 +274,43 @@ end # commits automatically
323
274
 
324
275
  #### IRB
325
276
 
326
- An example of how to start an IRB session with support for executing gremlin queries:
327
-
328
- ```ruby
329
- Async do
330
- include Grumlin::Sugar
331
-
332
- IRB.start
333
- ensure
334
- Grumlin.close
335
- end
336
- ```
337
-
338
- Please check out [bin/console](bin/console) for full source. A similar trick may be applied to PRY.
277
+ Please check out [bin/console](bin/console) for inspiration. A similar trick may be applied to PRY.
339
278
 
340
279
  #### Rails console
341
280
 
342
281
  In order to make it possible to execute gremlin queries from the rails console you need to define
343
- a custom console class. It should look somehow like
282
+ a custom console class. It should look somewhat like
344
283
 
345
284
  ```ruby
346
- class MyRailsConsole
347
- def self.start
285
+ class Async::RailsConsole
286
+ extend Grumlin::Repository
287
+
288
+ def start
289
+ self.class.shortcuts_from Shortcuts::Content
290
+
348
291
  IRB::WorkSpace.prepend(Rails::Console::BacktraceCleaner)
349
292
  IRB::ExtendCommandBundle.include(Rails::ConsoleMethods)
350
293
 
351
- Async do
352
- include Grumlin::Sugar
294
+ IRB.setup(binding.source_location[0], argv: [])
295
+ workspace = IRB::WorkSpace.new(binding)
296
+
297
+ begin
298
+ Async do
299
+ IRB::Irb.new(workspace).run(IRB.conf)
300
+ ensure
301
+ Grumlin.close
302
+ end
303
+ rescue StandardError, Interrupt, Async::Stop, IRB::Abort
304
+ retry
305
+ end
306
+ end
353
307
 
354
- IRB.setup(binding.source_location[0], argv: [])
355
- workspace = IRB::WorkSpace.new(binding)
308
+ def inspect
309
+ 'main'
310
+ end
356
311
 
357
- IRB::Irb.new(workspace).run(IRB.conf)
358
- ensure
359
- Grumlin.close
360
- end
312
+ def to_s
313
+ inspect
361
314
  end
362
315
  end
363
316
  ```
@@ -381,13 +334,13 @@ require 'async/rspec'
381
334
  require require "grumlin/test/rspec"
382
335
  ...
383
336
  config.include_context(Async::RSpec::Reactor) # Runs async reactor
384
- config.include_context(Grumlin::Test::RSpec::GremlinContext) # Injects sugar and makes sure client is closed after every test
337
+ config.include_context(Grumlin::Test::RSpec::GremlinContext) # Injects `g`, `__` and expressions, makes sure client is closed after every test
385
338
  config.include_context(Grumlin::Test::RSpec::DBCleanerContext) # Cleans the database before every test
386
339
  ...
387
340
  ```
388
341
 
389
- It is highly recommended to use `Grumlin::Sugar` or `Grumlin::Repository` and not trying to use lower level APIs
390
- as they are subject to change.
342
+ It is highly recommended to use `Grumlin::Repository` and not trying to use lower level APIs as they are subject to
343
+ change.
391
344
 
392
345
  ## Development
393
346
 
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ require "rubocop/rake_task"
9
9
  RSpec::Core::RakeTask.new(:spec)
10
10
  RuboCop::RakeTask.new
11
11
 
12
- task default: %i[rubocop spec]
12
+ task default: [:rubocop, :spec]
13
13
 
14
14
  namespace :definitions do
15
15
  desc "Format definitions.yml"
data/bin/console CHANGED
@@ -13,10 +13,25 @@ Grumlin.configure do |config|
13
13
  config.url = ENV.fetch("GREMLIN_URL", "ws://localhost:8182/gremlin")
14
14
  end
15
15
 
16
- Async do
17
- include Grumlin::Sugar
16
+ class Repository
17
+ extend Grumlin::Repository
18
+
19
+ def start_irb
20
+ IRB.setup(nil)
21
+ IRB.conf[:PROMPT][:DEFAULT] = { PROMPT_I: "%N(main):%03n:%i> ",
22
+ PROMPT_N: "%N(main):%03n:%i> ",
23
+ PROMPT_S: "%N(main):%03n:%i%l ",
24
+ PROMPT_C: "%N(main):%03n:%i* ",
25
+ RETURN: "=> %s\n" }
26
+ workspace = IRB::WorkSpace.new(binding)
27
+ irb = IRB::Irb.new(workspace)
28
+ IRB.conf[:MAIN_CONTEXT] = irb.context
29
+ irb.eval_input
30
+ end
31
+ end
18
32
 
19
- IRB.start
33
+ Async do
34
+ Repository.new.start_irb
20
35
  ensure
21
36
  Grumlin.close
22
37
  end
data/doc/middlewares.md CHANGED
@@ -14,10 +14,11 @@ execution process:
14
14
  Normally these middlewares must never be rearranged or removed from the stack. Middlewares added after
15
15
  `Middlewares::RunQuery` will not be executed.
16
16
 
17
- # Writing a middleware for Grumlin
17
+ ## Writing a middleware for Grumlin
18
18
 
19
- This entire feature is built on top of [ibsciss-middleware](https://github.com/Ibsciss/ruby-middleware).
20
- Please refer to it's docs if you want to implement a middleware.
19
+ This entire feature is built on top of [ibsciss-middleware](https://github.com/Ibsciss/ruby-middleware) but uses a
20
+ slightly modified `Builder` which caches the chain for better performance.
21
+ Please refer to ibsciss-middleware docs if you want to implement a middleware.
21
22
 
22
23
 
23
24
  A minimal middleware that measures query execution time and puts it back to `env`:
@@ -31,13 +32,6 @@ class MeasureExecutionTime < Grumlin::Middlewares::Middleware # Middleware provi
31
32
  result
32
33
  end
33
34
  end
34
-
35
- Grumlin.configure do |cfg|
36
- cfg.url = ENV.fetch("GREMLIN_URL", "ws://localhost:8182/gremlin")
37
- cfg.provider = :tinkergraph
38
-
39
- cfg.middlewares.insert_before Grumlin::Middlewares::CastResults, MeasureExecutionTime
40
- end
41
35
  ```
42
36
 
43
37
  When placed right before `Grumlin::Middlewares::CastResults` your middleware will have access to every intermediate result
@@ -56,3 +50,48 @@ Other useful parts of `env`:
56
50
  - `env[:session_id]` - id of the session when executed inside a transaction, otherwise `nil`
57
51
  - `env[:pool]` - connection pool that will be used to interact with the server
58
52
  - `env[:need_results]` - flag stating whether the client needs the query execution results(`toList`, `next`) or not(`iterate`)
53
+
54
+ ## Adding your middleware to the stack
55
+
56
+ There are two ways of adding middlewares to your queries:
57
+ - `global` - add the middleware to every single query from every single repository
58
+ - `per repository` - add the middleware to queries performed by particular repositories
59
+
60
+ Grumlin has one global middleware stack and every repository defines it's which is by default is a
61
+ copy of the global stack. This means one can easily modify repository's stack without worrying about the global one.
62
+
63
+ When inherited a class extending `Grumlin::Repository` will copy it's middlewares to the subclass, they can also be
64
+ modified independently from the parent's middlewares.
65
+
66
+ ### Adding a middleware globally
67
+ ```ruby
68
+ Grumlin.configure do |cfg|
69
+ cfg.url = ENV.fetch("GREMLIN_URL", "ws://localhost:8182/gremlin")
70
+ cfg.provider = :tinkergraph
71
+
72
+ cfg.middlewares do |b|
73
+ b.insert_before Grumlin::Middlewares::CastResults, MeasureExecutionTime
74
+ end
75
+ end
76
+ ```
77
+
78
+ ### Adding a middleware to a repository
79
+ ```ruby
80
+ class MyRepository
81
+ # MyRepository inherits a copy of global middlewares
82
+ extend Grumlin::Repository
83
+
84
+ # SomeOtherMiddleware will be added to MyRepository's middlewares only
85
+ middlewares do |b|
86
+ b.insert_before Grumlin::Middlewares::CastResults, MeasureExecutionTime
87
+ end
88
+ end
89
+
90
+ class AnotherRepository < MyRepository
91
+ # AnotherRepository inherits parent's middlewares
92
+ middlewares do |b|
93
+ # SomeOtherMiddleware will be added to AnotherRepository's middlewares only
94
+ b.insert_before Grumlin::Middlewares::CastResults, SomeOtherMiddleware
95
+ end
96
+ end
97
+ ```
data/lib/async/channel.rb CHANGED
@@ -1,74 +1,72 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Async
4
- # Channel is a wrapper around Async::Queue that provides
5
- # a protocol and handy tools for passing data, exceptions and closing.
6
- # It is designed to be used only with one publisher and one subscriber
7
- class Channel
8
- class ChannelError < StandardError; end
9
-
10
- class ChannelClosedError < ChannelError; end
11
-
12
- def initialize
13
- @queue = Async::Queue.new
14
- @closed = false
15
- end
3
+ # Channel is a wrapper around Async::Queue that provides
4
+ # a protocol and handy tools for passing data, exceptions and closing.
5
+ # It is designed to be used only with one publisher and one subscriber
6
+ class Async::Channel
7
+ class ChannelError < StandardError; end
16
8
 
17
- def closed?
18
- @closed
19
- end
9
+ class ChannelClosedError < ChannelError; end
20
10
 
21
- def open?
22
- !@closed
23
- end
11
+ def initialize
12
+ @queue = Async::Queue.new
13
+ @closed = false
14
+ end
24
15
 
25
- # Methods for a publisher
26
- def <<(payload)
27
- raise(ChannelClosedError, "Cannot send to a closed channel") if @closed
16
+ def closed?
17
+ @closed
18
+ end
28
19
 
29
- @queue << [:payload, payload]
30
- end
20
+ def open?
21
+ !@closed
22
+ end
31
23
 
32
- def exception(exception)
33
- raise(ChannelClosedError, "Cannot send to a closed channel") if closed?
24
+ # Methods for a publisher
25
+ def <<(payload)
26
+ raise(ChannelClosedError, "Cannot send to a closed channel") if @closed
34
27
 
35
- @queue << [:exception, exception]
36
- end
28
+ @queue << [:payload, payload]
29
+ end
37
30
 
38
- def close
39
- return if closed?
31
+ def exception(exception)
32
+ raise(ChannelClosedError, "Cannot send to a closed channel") if closed?
40
33
 
41
- @queue << [:close]
42
- @closed = true
43
- end
34
+ @queue << [:exception, exception]
35
+ end
44
36
 
45
- def close!
46
- return if closed?
37
+ def close
38
+ return if closed?
47
39
 
48
- exception(ChannelClosedError.new("Channel was forcefully closed"))
49
- close
50
- end
40
+ @queue << [:close]
41
+ @closed = true
42
+ end
51
43
 
52
- # Methods for a subscriber
53
- def dequeue
54
- each do |payload| # rubocop:disable Lint/UnreachableLoop this is intended
55
- return payload
56
- end
44
+ def close!
45
+ return if closed?
46
+
47
+ exception(ChannelClosedError.new("Channel was forcefully closed"))
48
+ close
49
+ end
50
+
51
+ # Methods for a subscriber
52
+ def dequeue
53
+ each do |payload| # rubocop:disable Lint/UnreachableLoop this is intended
54
+ return payload
57
55
  end
56
+ end
58
57
 
59
- def each
60
- raise(ChannelClosedError, "Cannot receive from a closed channel") if closed?
61
-
62
- @queue.each do |type, payload|
63
- case type
64
- when :exception
65
- payload.set_backtrace(caller + (payload.backtrace || [])) # A hack to preserve full backtrace
66
- raise payload
67
- when :payload
68
- yield payload
69
- when :close
70
- break
71
- end
58
+ def each
59
+ raise(ChannelClosedError, "Cannot receive from a closed channel") if closed?
60
+
61
+ @queue.each do |type, payload|
62
+ case type
63
+ when :exception
64
+ payload.set_backtrace(caller + (payload.backtrace || [])) # A hack to preserve full backtrace
65
+ raise payload
66
+ when :payload
67
+ yield payload
68
+ when :close
69
+ break
72
70
  end
73
71
  end
74
72
  end
@@ -1,21 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Grumlin
4
- module Benchmark
5
- class Repository
6
- extend Grumlin::Repository
3
+ class Grumlin::Benchmark::Repository
4
+ extend Grumlin::Repository
7
5
 
8
- shortcut :simple_test do
9
- self.V
10
- end
6
+ shortcut :simple_test do
7
+ self.V
8
+ end
11
9
 
12
- def simple_test
13
- g.V.bytecode.serialize
14
- end
10
+ def simple_test
11
+ g.V.bytecode.serialize
12
+ end
15
13
 
16
- def simple_test_with_shortcut
17
- g.simple_test.bytecode.serialize
18
- end
19
- end
14
+ def simple_test_with_shortcut
15
+ g.simple_test.bytecode.serialize
20
16
  end
21
17
  end