pacer 0.9.1.1-java

Sign up to get free protection for your applications and to get access to all the features.
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