pacer 0.9.1.1-java

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.
Files changed (184) hide show
  1. data/.autotest +8 -0
  2. data/.document +5 -0
  3. data/.gitignore +26 -0
  4. data/.rspec +1 -0
  5. data/.rvmrc +0 -0
  6. data/CONTRIBUTORS +5 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.txt +24 -0
  9. data/README.md +187 -0
  10. data/Rakefile +49 -0
  11. data/autotest/discover.rb +1 -0
  12. data/bin/autospec +16 -0
  13. data/bin/autotest +16 -0
  14. data/bin/rake +16 -0
  15. data/bin/rcov +16 -0
  16. data/bin/rspec +16 -0
  17. data/bin/yard +16 -0
  18. data/bin/yardoc +16 -0
  19. data/lib/pacer/blueprints/extensions.rb +77 -0
  20. data/lib/pacer/blueprints/multi_graph.rb +121 -0
  21. data/lib/pacer/blueprints/ruby_graph.rb +199 -0
  22. data/lib/pacer/blueprints/tg.rb +100 -0
  23. data/lib/pacer/blueprints.rb +4 -0
  24. data/lib/pacer/core/graph/edges_route.rb +92 -0
  25. data/lib/pacer/core/graph/element_route.rb +171 -0
  26. data/lib/pacer/core/graph/graph_index_route.rb +48 -0
  27. data/lib/pacer/core/graph/graph_route.rb +55 -0
  28. data/lib/pacer/core/graph/mixed_route.rb +96 -0
  29. data/lib/pacer/core/graph/vertices_route.rb +220 -0
  30. data/lib/pacer/core/graph.rb +13 -0
  31. data/lib/pacer/core/route.rb +502 -0
  32. data/lib/pacer/core/side_effect.rb +11 -0
  33. data/lib/pacer/core.rb +8 -0
  34. data/lib/pacer/exceptions.rb +11 -0
  35. data/lib/pacer/extensions/block_filter_element.rb +22 -0
  36. data/lib/pacer/extensions.rb +6 -0
  37. data/lib/pacer/filter/block_filter.rb +31 -0
  38. data/lib/pacer/filter/collection_filter.rb +109 -0
  39. data/lib/pacer/filter/empty_filter.rb +70 -0
  40. data/lib/pacer/filter/future_filter.rb +68 -0
  41. data/lib/pacer/filter/index_filter.rb +30 -0
  42. data/lib/pacer/filter/loop_filter.rb +95 -0
  43. data/lib/pacer/filter/object_filter.rb +55 -0
  44. data/lib/pacer/filter/property_filter/edge_filters.rb +93 -0
  45. data/lib/pacer/filter/property_filter/filters.rb +269 -0
  46. data/lib/pacer/filter/property_filter.rb +111 -0
  47. data/lib/pacer/filter/random_filter.rb +13 -0
  48. data/lib/pacer/filter/range_filter.rb +104 -0
  49. data/lib/pacer/filter/uniq_filter.rb +12 -0
  50. data/lib/pacer/filter/where_filter/node_visitor.rb +280 -0
  51. data/lib/pacer/filter/where_filter.rb +47 -0
  52. data/lib/pacer/filter.rb +17 -0
  53. data/lib/pacer/function_resolver.rb +43 -0
  54. data/lib/pacer/graph/edge_mixin.rb +127 -0
  55. data/lib/pacer/graph/element_mixin.rb +202 -0
  56. data/lib/pacer/graph/graph_indices_mixin.rb +93 -0
  57. data/lib/pacer/graph/graph_mixin.rb +361 -0
  58. data/lib/pacer/graph/graph_transactions_mixin.rb +207 -0
  59. data/lib/pacer/graph/index_mixin.rb +30 -0
  60. data/lib/pacer/graph/vertex_mixin.rb +119 -0
  61. data/lib/pacer/graph.rb +14 -0
  62. data/lib/pacer/pipe/blackbox_pipeline.rb +48 -0
  63. data/lib/pacer/pipe/block_filter_pipe.rb +38 -0
  64. data/lib/pacer/pipe/collection_filter_pipe.rb +10 -0
  65. data/lib/pacer/pipe/cross_product_transform_pipe.rb +48 -0
  66. data/lib/pacer/pipe/enumerable_pipe.rb +30 -0
  67. data/lib/pacer/pipe/expandable_pipe.rb +63 -0
  68. data/lib/pacer/pipe/id_collection_filter_pipe.rb +33 -0
  69. data/lib/pacer/pipe/is_empty_pipe.rb +30 -0
  70. data/lib/pacer/pipe/is_unique_pipe.rb +61 -0
  71. data/lib/pacer/pipe/label_collection_filter_pipe.rb +21 -0
  72. data/lib/pacer/pipe/label_prefix_pipe.rb +21 -0
  73. data/lib/pacer/pipe/loop_pipe.rb +86 -0
  74. data/lib/pacer/pipe/map_pipe.rb +36 -0
  75. data/lib/pacer/pipe/never_pipe.rb +9 -0
  76. data/lib/pacer/pipe/process_pipe.rb +37 -0
  77. data/lib/pacer/pipe/property_comparison_pipe.rb +40 -0
  78. data/lib/pacer/pipe/ruby_pipe.rb +25 -0
  79. data/lib/pacer/pipe/simple_visitor_pipe.rb +43 -0
  80. data/lib/pacer/pipe/stream_sort_pipe.rb +84 -0
  81. data/lib/pacer/pipe/stream_uniq_pipe.rb +33 -0
  82. data/lib/pacer/pipe/type_filter_pipe.rb +22 -0
  83. data/lib/pacer/pipe/unary_transform_pipe.rb +59 -0
  84. data/lib/pacer/pipe/variable_store_iterator_wrapper.rb +26 -0
  85. data/lib/pacer/pipe/visitor_pipe.rb +67 -0
  86. data/lib/pacer/pipes.rb +61 -0
  87. data/lib/pacer/route/mixin/bulk_operations.rb +52 -0
  88. data/lib/pacer/route/mixin/route_operations.rb +107 -0
  89. data/lib/pacer/route/mixin/variable_route_module.rb +26 -0
  90. data/lib/pacer/route/mixins.rb +3 -0
  91. data/lib/pacer/route.rb +228 -0
  92. data/lib/pacer/routes.rb +6 -0
  93. data/lib/pacer/side_effect/aggregate.rb +31 -0
  94. data/lib/pacer/side_effect/counted.rb +30 -0
  95. data/lib/pacer/side_effect/group_count.rb +44 -0
  96. data/lib/pacer/side_effect/is_unique.rb +32 -0
  97. data/lib/pacer/side_effect/section.rb +25 -0
  98. data/lib/pacer/side_effect/visitor.rb +37 -0
  99. data/lib/pacer/side_effect.rb +11 -0
  100. data/lib/pacer/support/array_list.rb +28 -0
  101. data/lib/pacer/support/enumerable.rb +100 -0
  102. data/lib/pacer/support/hash.rb +9 -0
  103. data/lib/pacer/support/iterator_mixins.rb +110 -0
  104. data/lib/pacer/support/native_exception.rb +22 -0
  105. data/lib/pacer/support/proc.rb +16 -0
  106. data/lib/pacer/support.rb +10 -0
  107. data/lib/pacer/transform/cap.rb +50 -0
  108. data/lib/pacer/transform/gather.rb +9 -0
  109. data/lib/pacer/transform/has_count_cap.rb +41 -0
  110. data/lib/pacer/transform/join.rb +181 -0
  111. data/lib/pacer/transform/map.rb +23 -0
  112. data/lib/pacer/transform/path.rb +50 -0
  113. data/lib/pacer/transform/process.rb +23 -0
  114. data/lib/pacer/transform/scatter.rb +23 -0
  115. data/lib/pacer/transform/sort_section.rb +103 -0
  116. data/lib/pacer/transform/stream_sort.rb +21 -0
  117. data/lib/pacer/transform/stream_uniq.rb +21 -0
  118. data/lib/pacer/transform.rb +16 -0
  119. data/lib/pacer/utils/graph_analysis.rb +112 -0
  120. data/lib/pacer/utils/trie.rb +93 -0
  121. data/lib/pacer/utils/tsort.rb +65 -0
  122. data/lib/pacer/utils/y_files.rb +127 -0
  123. data/lib/pacer/utils.rb +10 -0
  124. data/lib/pacer/version.rb +13 -0
  125. data/lib/pacer/wrappers/edge_wrapper.rb +51 -0
  126. data/lib/pacer/wrappers/element_wrapper.rb +78 -0
  127. data/lib/pacer/wrappers/new_element.rb +106 -0
  128. data/lib/pacer/wrappers/vertex_wrapper.rb +51 -0
  129. data/lib/pacer/wrappers.rb +19 -0
  130. data/lib/pacer-0.9.1.1-standalone.jar +0 -0
  131. data/lib/pacer.rb +290 -0
  132. data/pacer.gemspec +30 -0
  133. data/pom/standalone.xml +22 -0
  134. data/pom.xml +124 -0
  135. data/samples/grateful-dead.xml +26380 -0
  136. data/samples/grateful_dead.rb +63 -0
  137. data/samples/profile.rb +15 -0
  138. data/spec/data/grateful-dead.xml +26380 -0
  139. data/spec/data/pacer.graphml +319 -0
  140. data/spec/pacer/blueprints/dex_spec.rb +172 -0
  141. data/spec/pacer/blueprints/neo4j_spec.rb +177 -0
  142. data/spec/pacer/blueprints/tg_spec.rb +128 -0
  143. data/spec/pacer/core/graph/edges_route_spec.rb +52 -0
  144. data/spec/pacer/core/graph/element_route_spec.rb +46 -0
  145. data/spec/pacer/core/graph/graph_route_spec.rb +94 -0
  146. data/spec/pacer/core/graph/vertices_route_spec.rb +169 -0
  147. data/spec/pacer/core/route_spec.rb +197 -0
  148. data/spec/pacer/filter/collection_filter_spec.rb +19 -0
  149. data/spec/pacer/filter/empty_filter_spec.rb +29 -0
  150. data/spec/pacer/filter/future_filter_spec.rb +97 -0
  151. data/spec/pacer/filter/loop_filter_spec.rb +31 -0
  152. data/spec/pacer/filter/property_filter_spec.rb +111 -0
  153. data/spec/pacer/filter/random_filter_spec.rb +17 -0
  154. data/spec/pacer/filter/uniq_filter_spec.rb +18 -0
  155. data/spec/pacer/filter/where_filter_spec.rb +93 -0
  156. data/spec/pacer/graph/edge_mixin_spec.rb +116 -0
  157. data/spec/pacer/graph/element_mixin_spec.rb +297 -0
  158. data/spec/pacer/graph/graph_mixin_spec.rb +538 -0
  159. data/spec/pacer/graph/index_mixin_spec.rb +0 -0
  160. data/spec/pacer/graph/vertex_mixin_spec.rb +192 -0
  161. data/spec/pacer/pipe/block_filter_pipe_spec.rb +0 -0
  162. data/spec/pacer/pipe/labels_filter_pipe_spec.rb +0 -0
  163. data/spec/pacer/pipe/ruby_pipe_spec.rb +0 -0
  164. data/spec/pacer/pipe/type_filter_pipe_spec.rb +0 -0
  165. data/spec/pacer/route/mixin/base_spec.rb +419 -0
  166. data/spec/pacer/route/mixin/bulk_operations_spec.rb +30 -0
  167. data/spec/pacer/route/mixin/route_operations_spec.rb +127 -0
  168. data/spec/pacer/support/array_list_spec.rb +0 -0
  169. data/spec/pacer/support/enumerable_spec.rb +115 -0
  170. data/spec/pacer/transform/join_spec.rb +138 -0
  171. data/spec/pacer/transform/path_spec.rb +54 -0
  172. data/spec/pacer/utils/tsort_spec.rb +89 -0
  173. data/spec/pacer/wrapper/edge_wrapper_spec.rb +33 -0
  174. data/spec/pacer/wrapper/element_wrapper_spec.rb +169 -0
  175. data/spec/pacer/wrapper/vertex_wrapper_spec.rb +33 -0
  176. data/spec/pacer_spec.rb +0 -0
  177. data/spec/spec_helper.rb +91 -0
  178. data/spec/support/contexts.rb +14 -0
  179. data/spec/support/graph_runner.rb +142 -0
  180. data/spec/support/matchers.rb +19 -0
  181. data/spec/support/use_transactions.rb +31 -0
  182. data/spec/tackle/simple_mixin.rb +21 -0
  183. data/spec/tackle/tinkerpop_graph_mixins.rb +60 -0
  184. metadata +364 -0
@@ -0,0 +1,502 @@
1
+ require 'set'
2
+ module Pacer
3
+ module Core
4
+
5
+ # The basic internal logic for routes and core route shared methods are
6
+ # defined here. Many of these methods are designed to be specialized by
7
+ # other modules included after Core::Route is included.
8
+ module Route
9
+ class << self
10
+ protected
11
+ def included(target)
12
+ target.send :include, Enumerable
13
+ end
14
+ end
15
+
16
+ # Replace the generated class name of this route with a specific
17
+ # one by setting route_name.
18
+ attr_accessor :route_name
19
+ attr_accessor :info
20
+
21
+ # Specify which pipe class will be instantiated when an iterator is created.
22
+ attr_accessor :pipe_class
23
+
24
+ # If true, elements won't be printed to STDOUT when #inspect is
25
+ # called on this route.
26
+ # @return [true, false]
27
+ attr_accessor :hide_elements
28
+
29
+ # Set which graph this route will operate on.
30
+ #
31
+ # @todo move this to graph routes.
32
+ attr_writer :graph
33
+
34
+ # Return which graph this route operates on.
35
+ #
36
+ # @todo move this to graph routes.
37
+ #
38
+ # @return [GraphMixin]
39
+ def graph
40
+ @graph = nil unless defined? @graph
41
+ @graph ||= (@back || @source).graph rescue nil
42
+ end
43
+
44
+ # Returns true if the given graph is the one this route operates on.
45
+ def from_graph?(g)
46
+ graph.equals g
47
+ end
48
+
49
+ # The arguments passed to the pipe constructor.
50
+ #
51
+ # @overload pipe_args
52
+ # @overload pipe_args=(args)
53
+ # @param [Object] args
54
+ # @overload pipe_args=(args)
55
+ # @param [[Object]] args
56
+ #
57
+ # @return [[Object]] array of arguments
58
+ attr_reader :pipe_args
59
+
60
+ def pipe_args=(args)
61
+ if args.is_a? Array
62
+ @pipe_args = args
63
+ else
64
+ @pipe_args = [args]
65
+ end
66
+ end
67
+
68
+ # Return true if this route is at the beginning of the route definition.
69
+ def root?
70
+ !@source.nil? or @back.nil?
71
+ end
72
+
73
+ # Prevents the route from being evaluated when it is inspected. Useful
74
+ # for computationally expensive or one-time routes.
75
+ #
76
+ # @todo rename this method
77
+ #
78
+ # @return [self]
79
+ def route
80
+ @hide_elements = true
81
+ self
82
+ end
83
+
84
+ # Returns the hash of variables used during the previous evaluation of
85
+ # the route.
86
+ #
87
+ # The contents of vars is expected to be in a state relevant to the
88
+ # latest route being evaluated and is primarily meant for internal use,
89
+ # but YMMV.
90
+ #
91
+ # @todo It would maybe be better if the vars were tied to the
92
+ # thread context or preferably to the actual pipe instance in
93
+ # use. The current implementation of vars is not threadsafe if
94
+ # the same route is being used in multiple threads concurrently.
95
+ #
96
+ # @return [Hash]
97
+ def vars
98
+ if @back
99
+ @back.vars
100
+ else
101
+ @vars ||= {}
102
+ end
103
+ end
104
+
105
+ # Iterates over each element or object resulting from traversing the
106
+ # route up to this point.
107
+ #
108
+ # @yield [item] if a block is given
109
+ # @return [Enumerator] if no block is given
110
+ def each
111
+ iter = iterator
112
+ configure_iterator(iter)
113
+ if block_given?
114
+ while true
115
+ yield iter.next
116
+ end
117
+ else
118
+ iter
119
+ end
120
+ rescue java.util.NoSuchElementException
121
+ self
122
+ end
123
+
124
+ # Returns a single use pipe iterator based on this route.
125
+ #
126
+ # @yield [java.util.Iterator] the pipe. Very useful because this method will catch the pipe's java.util.NoSuchElementException when iteration is finished.
127
+ # @return [java.util.Iterator] the pipe.
128
+ def pipe
129
+ iterator = each
130
+ yield iterator if block_given?
131
+ iterator
132
+ rescue java.util.NoSuchElementException
133
+ iterator
134
+ end
135
+
136
+ # Returns a string representation of the route definition. If there are
137
+ # less than Graph#inspect_limit matches, it will also output all matching
138
+ # elements formatted in columns up to a maximum character width of
139
+ # Graph#columns. If this output behaviour is undesired, it may be turned
140
+ # off by calling #route on the current route.
141
+ #
142
+ # @return [String]
143
+ def inspect(limit = nil)
144
+ if Pacer.hide_route_elements or hide_elements or source_iterator.nil?
145
+ "#<#{inspect_strings.join(' -> ')}>"
146
+ else
147
+ Pacer.hide_route_elements do
148
+ count = 0
149
+ limit ||= Pacer.inspect_limit
150
+ results = collect do |v|
151
+ count += 1
152
+ return route.inspect if count > limit
153
+ v.inspect
154
+ end
155
+ if count > 0
156
+ lens = results.collect { |r| r.length }
157
+ max = lens.max
158
+ cols = (Pacer.columns / (max + 1).to_f).floor
159
+ cols = 1 if cols < 1
160
+ if cols == 1
161
+ template_part = ['%s']
162
+ else
163
+ template_part = ["%-#{max}s"]
164
+ end
165
+ template = (template_part * cols).join(' ')
166
+ results.each_slice(cols) do |row|
167
+ template = (template_part * row.count).join(' ') if row.count < cols
168
+ puts template % row
169
+ end
170
+ end
171
+ puts "Total: #{ count }"
172
+ "#<#{inspect_strings.join(' -> ')}>"
173
+ end
174
+ end
175
+ end
176
+
177
+ # Returns true if the other route is defined the same as the current route.
178
+ #
179
+ # Note that block filters will prevent matches even with identically
180
+ # defined routes unless the routes are actually the same object.
181
+ # @return [true, false]
182
+ def ==(other)
183
+ other.class == self.class and
184
+ other.function == function and
185
+ other.element_type == element_type and
186
+ other.back == back and
187
+ other.source == source
188
+ end
189
+
190
+ # Returns true if this route currently has no elements.
191
+ def empty?
192
+ none?
193
+ end
194
+
195
+ # Add an extension to the route.
196
+ #
197
+ # If the extension has a Route module inside it, this route will
198
+ # be extended with the extension's Route module.
199
+ #
200
+ # If the extension has a Vertex or Edge module inside it, any vertices
201
+ # or edges emitted from this route will be extended with with the
202
+ # extension as well.
203
+ #
204
+ # @see VertexMixin#add_extensions
205
+ # @see EdgeMixin#add_extensions
206
+ #
207
+ # @return [self]
208
+ def add_extension(mod, add_to_list = true)
209
+ return self unless mod.respond_to?(:const_defined?)
210
+ is_extension = false
211
+ if mod.const_defined? :Route
212
+ is_extension = true
213
+ extend mod::Route
214
+ end
215
+ if add_to_list and (is_extension or mod.const_defined? :Vertex or mod.const_defined? :Edge)
216
+ @extensions << mod
217
+ end
218
+ self
219
+ end
220
+
221
+ def set_wrapper(wrapper)
222
+ if wrapper.respond_to? :extensions
223
+ wrapper.extensions.each do |ext|
224
+ add_extension ext, false
225
+ end
226
+ end
227
+ @wrapper = wrapper
228
+ self
229
+ end
230
+ alias wrapper= set_wrapper
231
+
232
+ def wrapper
233
+ @wrapper
234
+ end
235
+
236
+ # Add extensions to this route.
237
+ #
238
+ # @see #add_extension
239
+ def extensions=(exts)
240
+ add_extensions Set[*exts]
241
+ end
242
+
243
+ # Get the set of extensions currently on this route.
244
+ #
245
+ # The order of extensions for custom defined wrappers are
246
+ # guaranteed. If a wrapper is iterated with additional extensions,
247
+ # a new wrapper will be created dynamically with the original
248
+ # extensions in order followed by any additional extensions in
249
+ # undefined order.
250
+ #
251
+ # If a wrapper is present, returns an Array. Otherwise a Set.
252
+ #
253
+ # @return [Enumerable[extension]]
254
+ def extensions
255
+ if wrapper
256
+ wrapper.extensions + @extensions.to_a
257
+ else
258
+ @extensions
259
+ end
260
+ end
261
+
262
+ # If any objects in the given array are modules that contain a Route
263
+ # submodule, extend this route with the Route module.
264
+ # @see #add_extension
265
+ # @return [self]
266
+ def add_extensions(exts)
267
+ modules = exts.select { |obj| obj.is_a? Module or obj.is_a? Class }
268
+ modules.each do |mod|
269
+ add_extension(mod)
270
+ end
271
+ self
272
+ end
273
+
274
+ def no_extensions
275
+ chain_route(:extensions => nil, :wrapper => nil)
276
+ end
277
+
278
+ # Change the source of this route.
279
+ #
280
+ # @note all routes derived from any route in the chain will be
281
+ # affected so use with caution.
282
+ #
283
+ # @param [Enumerable, Enumerator] src the data source.
284
+ def set_pipe_source(src)
285
+ if @back
286
+ @back.set_pipe_source src
287
+ else
288
+ self.source = src
289
+ end
290
+ end
291
+
292
+ protected
293
+
294
+ # Set the previous route in the chain.
295
+ def back=(back)
296
+ if back.is_a? Route and not back.is_a? GraphMixin
297
+ @back = back
298
+ else
299
+ @source = back
300
+ end
301
+ end
302
+
303
+ # Return the route which is attached to the given route.
304
+ def route_after(route)
305
+ if route == self
306
+ nil
307
+ elsif @back
308
+ if @back == route
309
+ self
310
+ elsif @back.is_a? Route
311
+ @back.route_after(route)
312
+ end
313
+ end
314
+ end
315
+
316
+ # Overridden to extend the iterator to apply mixins
317
+ # or wrap elements
318
+ def configure_iterator(iter)
319
+ end
320
+
321
+ def get_section_route(name)
322
+ if respond_to? :section_name and section_name == name
323
+ self
324
+ elsif @back
325
+ @back.get_section_route(name)
326
+ else
327
+ raise ArgumentError, "Section #{ name } not found"
328
+ end
329
+ end
330
+
331
+ # Returns a HashSet of element ids from the collection, but
332
+ # only if all elements in the collection have an element_id.
333
+
334
+ # This should not normally need to be set. It can be used to inject a route
335
+ # into another route during iterator generation.
336
+ def source=(source)
337
+ @back = nil
338
+ @source = source
339
+ end
340
+
341
+ # Get the actual source of data for this route.
342
+ #
343
+ # @return [java.util.Iterator]
344
+ def source_iterator
345
+ if @source
346
+ iterator_from_source(@source)
347
+ elsif @back
348
+ @back.send(:source_iterator)
349
+ end
350
+ end
351
+
352
+ # Get the first and last pipes in the pipeline before the current
353
+ # route's pipes are added.
354
+ # @see #build_pipeline
355
+ # @return [[com.tinkerpop.pipes.Pipe, com.tinkerpop.pipes.Pipe], nil]
356
+ def pipe_source
357
+ if @source
358
+ nil
359
+ elsif @back
360
+ @back.send(:build_pipeline)
361
+ end
362
+ end
363
+
364
+ # Return an iterator for a variety of source object types.
365
+ def iterator_from_source(src)
366
+ if src.is_a? Pacer::GraphMixin
367
+ al = java.util.ArrayList.new
368
+ al << src
369
+ al.iterator
370
+ elsif src.is_a? Pacer::Wrappers::ElementWrapper
371
+ Pacer::Pipes::EnumerablePipe.new src.element
372
+ elsif src.is_a? Proc
373
+ iterator_from_source(src.call)
374
+ elsif src.is_a? Iterator
375
+ src
376
+ elsif src
377
+ Pacer::Pipes::EnumerablePipe.new src
378
+ end
379
+ end
380
+
381
+ # Return an iterator for this route loading data from all previous routes
382
+ # in the chain.
383
+ def iterator
384
+ start, end_pipe = build_pipeline
385
+ if start
386
+ src = source_iterator
387
+ Pacer.debug_source = src if Pacer.debug_pipes
388
+ start.setStarts src
389
+ end_pipe
390
+ elsif end_pipe
391
+ raise "End pipe without start pipe"
392
+ else
393
+ pipe = Pacer::Pipes::IdentityPipe.new
394
+ pipe.setStarts source_iterator
395
+ pipe
396
+ end
397
+ end
398
+
399
+ # This is the default implementation of the method used to create
400
+ # the specialized pipe for each route instance. It is overridden
401
+ # in most function modules to produce the pipe needed to perform
402
+ # that function.
403
+ #
404
+ # @see Filter modules in this namespace override this method
405
+ # @see Transform modules in this namespace override this method
406
+ # @see SideEffect modules in this namespace override this method
407
+ #
408
+ # @param [com.tinkerpop.pipes.Pipe] the pipe emitting the source
409
+ # data for this pipe
410
+ # @return [com.tinkerpop.pipes.Pipe] the pipe that emits the
411
+ # resulting data from this step
412
+ def attach_pipe(end_pipe)
413
+ if pipe_class
414
+ if pipe_args
415
+ begin
416
+ pipe = pipe_class.new(*pipe_args)
417
+ rescue ArgumentError
418
+ raise ArgumentError, "Invalid args for pipe: #{ pipe_class.inspect }.new(*#{pipe_args.inspect})"
419
+ end
420
+ else
421
+ begin
422
+ pipe = pipe_class.new
423
+ rescue ArgumentError
424
+ raise ArgumentError, "Invalid args for pipe: #{ pipe_class.inspect }.new()"
425
+ end
426
+ end
427
+ pipe.setStarts end_pipe if end_pipe
428
+ pipe
429
+ else
430
+ end_pipe
431
+ end
432
+ rescue NativeException => e
433
+ if e.cause.name == 'java.lang.InstantiationException'
434
+ raise Exception, "Unable to instantiate abstract class #{ pipe_class }"
435
+ else
436
+ raise
437
+ end
438
+ end
439
+
440
+ # Walks back along the chain of routes to build the series of Pipe
441
+ # objects that represent this route.
442
+ #
443
+ # @return [[com.tinkerpop.pipes.Pipe, com.tinkerpop.pipes.Pipe]]
444
+ # start and end pipe in the pipeline. The start pipe gets the
445
+ # source applied to it, the end pipe produces the result when its
446
+ # next method is called.
447
+ def build_pipeline
448
+ start, end_pipe = pipe_source
449
+ pipe = attach_pipe(end_pipe)
450
+ Pacer.debug_pipes << { :name => inspect_class_name, :start => start, :end => pipe } if Pacer.debug_pipes
451
+ [start || pipe, pipe]
452
+ end
453
+
454
+ # Returns an array of strings representing each route object in the
455
+ # chain.
456
+ # @return [[String]]
457
+ def inspect_strings
458
+ ins = []
459
+ ins += @back.inspect_strings unless root?
460
+
461
+ ins << inspect_string
462
+ ins
463
+ end
464
+
465
+ # Returns the string representing just this route instance.
466
+ # @return [String]
467
+ def inspect_string
468
+ return route_name if route_name
469
+ if pipe_class
470
+ ps = pipe_class.name
471
+ if ps =~ /FilterPipe$/
472
+ ps = ps.split('::').last.sub(/FilterPipe/, '')
473
+ if pipe_args
474
+ pipeargs = pipe_args.collect do |arg|
475
+ if arg.is_a? Enumerable and arg.count > 10
476
+ "[...#{ arg.count } items...]"
477
+ else
478
+ arg.to_s
479
+ end
480
+ end
481
+ ps = "#{ps}(#{pipeargs.join(', ')})" if pipeargs.any?
482
+ end
483
+ elsif pipe_args
484
+ ps = pipe_args.join(', ')
485
+ end
486
+ end
487
+ s = inspect_class_name
488
+ s = "#{s}(#{ ps })" if ps and ps != ''
489
+ s
490
+ end
491
+
492
+ # Return the class name of the current route.
493
+ # @return [String]
494
+ def inspect_class_name
495
+ s = "#{self.class.name.split('::').last.sub(/Route$/, '')}"
496
+ s = "#{s} #{ info }" if info
497
+ s
498
+ end
499
+
500
+ end
501
+ end
502
+ end
@@ -0,0 +1,11 @@
1
+ module Pacer
2
+ module Core
3
+ module SideEffect
4
+ # Get the side effect produced by the most recently created pipe.
5
+ # @return [Object]
6
+ def side_effect
7
+ @pipe.getSideEffect
8
+ end
9
+ end
10
+ end
11
+ end
data/lib/pacer/core.rb ADDED
@@ -0,0 +1,8 @@
1
+ module Pacer
2
+ module Core
3
+ end
4
+ end
5
+
6
+ require 'pacer/core/route'
7
+ require 'pacer/core/graph'
8
+ require 'pacer/core/side_effect'
@@ -0,0 +1,11 @@
1
+ module Pacer
2
+ class ElementNotFound < StandardError
3
+ end
4
+
5
+ class ElementExists < StandardError
6
+ end
7
+
8
+ class UnsupportedOperation < StandardError
9
+ end
10
+ end
11
+
@@ -0,0 +1,22 @@
1
+ module Pacer
2
+ module Extensions
3
+ module BlockFilterElement
4
+ module Route
5
+ def back=(back)
6
+ @back = back
7
+ end
8
+
9
+ # The previous route element.
10
+ def back
11
+ @back
12
+ end
13
+
14
+ # The vars hash contains variables that were set earlier in the processing
15
+ # of the route. Vars may also be set within the block.
16
+ def vars
17
+ @back.vars
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,6 @@
1
+ module Pacer
2
+ module Extensions
3
+ end
4
+ end
5
+
6
+ require 'pacer/extensions/block_filter_element'
@@ -0,0 +1,31 @@
1
+ module Pacer
2
+ module Routes
3
+ module RouteOperations
4
+ def select(&block)
5
+ chain_route :filter => :block, :block => block, :route_name => 'Select'
6
+ end
7
+
8
+ def reject(&block)
9
+ chain_route :filter => :block, :block => block, :invert => true, :route_name => 'Reject'
10
+ end
11
+ end
12
+ end
13
+
14
+ module Filter
15
+ module BlockFilter
16
+ attr_accessor :block, :invert
17
+
18
+ def ==(other)
19
+ super and invert == other.invert and block == other.block
20
+ end
21
+
22
+ protected
23
+
24
+ def attach_pipe(end_pipe)
25
+ pipe = Pacer::Pipes::BlockFilterPipe.new(self, block, invert)
26
+ pipe.set_starts end_pipe if end_pipe
27
+ pipe
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,109 @@
1
+ module Pacer
2
+ module Core
3
+ module Route
4
+ def except(excluded)
5
+ if excluded.is_a? Symbol
6
+ chain_route :filter => :collection, :except_var => excluded
7
+ else
8
+ chain_route :filter => :collection, :except => excluded
9
+ end
10
+ end
11
+
12
+ def -(other)
13
+ chain_route :filter => :collection, :except => other
14
+ end
15
+
16
+ def only(included)
17
+ if included.is_a? Symbol
18
+ chain_route :filter => :collection, :only_var => included
19
+ else
20
+ chain_route :filter => :collection, :only => included
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ module Filter
27
+ module CollectionFilter
28
+ import java.util.HashSet
29
+
30
+ attr_reader :var, :comparison, :ids, :objects
31
+
32
+ def except=(collection)
33
+ self.collection = collection
34
+ @comparison = Pacer::Pipes::NOT_EQUAL
35
+ end
36
+
37
+ def except_var=(var)
38
+ @var = var
39
+ @comparison = Pacer::Pipes::NOT_EQUAL
40
+ end
41
+
42
+ def only=(collection)
43
+ self.collection = collection
44
+ @comparison = Pacer::Pipes::EQUAL
45
+ end
46
+
47
+ def only_var=(var)
48
+ @var = var
49
+ @comparison = Pacer::Pipes::EQUAL
50
+ end
51
+
52
+ protected
53
+
54
+ def collection=(collection)
55
+ collection = [collection] unless collection.is_a? Enumerable
56
+ @ids = nil
57
+ if collection.is_a? HashSet
58
+ @objects = collection
59
+ elsif element_type != Object
60
+ @ids = element_id_hashset(collection)
61
+ @objects = collection.to_hashset unless ids
62
+ else
63
+ @objects = collection.to_hashset
64
+ end
65
+ end
66
+
67
+ def element_id_hashset(collection)
68
+ if collection.is_a? Pacer::Core::Graph::ElementRoute
69
+ collection.element_ids.to_hashset
70
+ else
71
+ collection.to_hashset(:element_id) rescue nil
72
+ end
73
+ end
74
+
75
+ def attach_pipe(end_pipe)
76
+ if var
77
+ pipe = Pacer::Pipes::CollectionFilterPipe.new(vars[var], comparison)
78
+ elsif ids
79
+ pipe = Pacer::Pipes::IdCollectionFilterPipe.new(ids, comparison)
80
+ else
81
+ pipe = Pacer::Pipes::CollectionFilterPipe.new(objects, comparison)
82
+ end
83
+ pipe.set_starts(end_pipe) if end_pipe
84
+ pipe
85
+ end
86
+
87
+ def collection_count
88
+ @collection.count
89
+ end
90
+
91
+ def inspect_class_name
92
+ if @comparison == Pacer::Pipes::NOT_EQUAL
93
+ 'Except'
94
+ else
95
+ 'Only'
96
+ end
97
+ end
98
+
99
+ def inspect_string
100
+ if var
101
+ "#{ inspect_class_name }(#{ var.inspect })"
102
+ else
103
+ c = (ids || objects)
104
+ "#{ inspect_class_name }(#{c.count} elements)"
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end