pacer 0.9.1.1-java
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +8 -0
- data/.document +5 -0
- data/.gitignore +26 -0
- data/.rspec +1 -0
- data/.rvmrc +0 -0
- data/CONTRIBUTORS +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +24 -0
- data/README.md +187 -0
- data/Rakefile +49 -0
- data/autotest/discover.rb +1 -0
- data/bin/autospec +16 -0
- data/bin/autotest +16 -0
- data/bin/rake +16 -0
- data/bin/rcov +16 -0
- data/bin/rspec +16 -0
- data/bin/yard +16 -0
- data/bin/yardoc +16 -0
- data/lib/pacer/blueprints/extensions.rb +77 -0
- data/lib/pacer/blueprints/multi_graph.rb +121 -0
- data/lib/pacer/blueprints/ruby_graph.rb +199 -0
- data/lib/pacer/blueprints/tg.rb +100 -0
- data/lib/pacer/blueprints.rb +4 -0
- data/lib/pacer/core/graph/edges_route.rb +92 -0
- data/lib/pacer/core/graph/element_route.rb +171 -0
- data/lib/pacer/core/graph/graph_index_route.rb +48 -0
- data/lib/pacer/core/graph/graph_route.rb +55 -0
- data/lib/pacer/core/graph/mixed_route.rb +96 -0
- data/lib/pacer/core/graph/vertices_route.rb +220 -0
- data/lib/pacer/core/graph.rb +13 -0
- data/lib/pacer/core/route.rb +502 -0
- data/lib/pacer/core/side_effect.rb +11 -0
- data/lib/pacer/core.rb +8 -0
- data/lib/pacer/exceptions.rb +11 -0
- data/lib/pacer/extensions/block_filter_element.rb +22 -0
- data/lib/pacer/extensions.rb +6 -0
- data/lib/pacer/filter/block_filter.rb +31 -0
- data/lib/pacer/filter/collection_filter.rb +109 -0
- data/lib/pacer/filter/empty_filter.rb +70 -0
- data/lib/pacer/filter/future_filter.rb +68 -0
- data/lib/pacer/filter/index_filter.rb +30 -0
- data/lib/pacer/filter/loop_filter.rb +95 -0
- data/lib/pacer/filter/object_filter.rb +55 -0
- data/lib/pacer/filter/property_filter/edge_filters.rb +93 -0
- data/lib/pacer/filter/property_filter/filters.rb +269 -0
- data/lib/pacer/filter/property_filter.rb +111 -0
- data/lib/pacer/filter/random_filter.rb +13 -0
- data/lib/pacer/filter/range_filter.rb +104 -0
- data/lib/pacer/filter/uniq_filter.rb +12 -0
- data/lib/pacer/filter/where_filter/node_visitor.rb +280 -0
- data/lib/pacer/filter/where_filter.rb +47 -0
- data/lib/pacer/filter.rb +17 -0
- data/lib/pacer/function_resolver.rb +43 -0
- data/lib/pacer/graph/edge_mixin.rb +127 -0
- data/lib/pacer/graph/element_mixin.rb +202 -0
- data/lib/pacer/graph/graph_indices_mixin.rb +93 -0
- data/lib/pacer/graph/graph_mixin.rb +361 -0
- data/lib/pacer/graph/graph_transactions_mixin.rb +207 -0
- data/lib/pacer/graph/index_mixin.rb +30 -0
- data/lib/pacer/graph/vertex_mixin.rb +119 -0
- data/lib/pacer/graph.rb +14 -0
- data/lib/pacer/pipe/blackbox_pipeline.rb +48 -0
- data/lib/pacer/pipe/block_filter_pipe.rb +38 -0
- data/lib/pacer/pipe/collection_filter_pipe.rb +10 -0
- data/lib/pacer/pipe/cross_product_transform_pipe.rb +48 -0
- data/lib/pacer/pipe/enumerable_pipe.rb +30 -0
- data/lib/pacer/pipe/expandable_pipe.rb +63 -0
- data/lib/pacer/pipe/id_collection_filter_pipe.rb +33 -0
- data/lib/pacer/pipe/is_empty_pipe.rb +30 -0
- data/lib/pacer/pipe/is_unique_pipe.rb +61 -0
- data/lib/pacer/pipe/label_collection_filter_pipe.rb +21 -0
- data/lib/pacer/pipe/label_prefix_pipe.rb +21 -0
- data/lib/pacer/pipe/loop_pipe.rb +86 -0
- data/lib/pacer/pipe/map_pipe.rb +36 -0
- data/lib/pacer/pipe/never_pipe.rb +9 -0
- data/lib/pacer/pipe/process_pipe.rb +37 -0
- data/lib/pacer/pipe/property_comparison_pipe.rb +40 -0
- data/lib/pacer/pipe/ruby_pipe.rb +25 -0
- data/lib/pacer/pipe/simple_visitor_pipe.rb +43 -0
- data/lib/pacer/pipe/stream_sort_pipe.rb +84 -0
- data/lib/pacer/pipe/stream_uniq_pipe.rb +33 -0
- data/lib/pacer/pipe/type_filter_pipe.rb +22 -0
- data/lib/pacer/pipe/unary_transform_pipe.rb +59 -0
- data/lib/pacer/pipe/variable_store_iterator_wrapper.rb +26 -0
- data/lib/pacer/pipe/visitor_pipe.rb +67 -0
- data/lib/pacer/pipes.rb +61 -0
- data/lib/pacer/route/mixin/bulk_operations.rb +52 -0
- data/lib/pacer/route/mixin/route_operations.rb +107 -0
- data/lib/pacer/route/mixin/variable_route_module.rb +26 -0
- data/lib/pacer/route/mixins.rb +3 -0
- data/lib/pacer/route.rb +228 -0
- data/lib/pacer/routes.rb +6 -0
- data/lib/pacer/side_effect/aggregate.rb +31 -0
- data/lib/pacer/side_effect/counted.rb +30 -0
- data/lib/pacer/side_effect/group_count.rb +44 -0
- data/lib/pacer/side_effect/is_unique.rb +32 -0
- data/lib/pacer/side_effect/section.rb +25 -0
- data/lib/pacer/side_effect/visitor.rb +37 -0
- data/lib/pacer/side_effect.rb +11 -0
- data/lib/pacer/support/array_list.rb +28 -0
- data/lib/pacer/support/enumerable.rb +100 -0
- data/lib/pacer/support/hash.rb +9 -0
- data/lib/pacer/support/iterator_mixins.rb +110 -0
- data/lib/pacer/support/native_exception.rb +22 -0
- data/lib/pacer/support/proc.rb +16 -0
- data/lib/pacer/support.rb +10 -0
- data/lib/pacer/transform/cap.rb +50 -0
- data/lib/pacer/transform/gather.rb +9 -0
- data/lib/pacer/transform/has_count_cap.rb +41 -0
- data/lib/pacer/transform/join.rb +181 -0
- data/lib/pacer/transform/map.rb +23 -0
- data/lib/pacer/transform/path.rb +50 -0
- data/lib/pacer/transform/process.rb +23 -0
- data/lib/pacer/transform/scatter.rb +23 -0
- data/lib/pacer/transform/sort_section.rb +103 -0
- data/lib/pacer/transform/stream_sort.rb +21 -0
- data/lib/pacer/transform/stream_uniq.rb +21 -0
- data/lib/pacer/transform.rb +16 -0
- data/lib/pacer/utils/graph_analysis.rb +112 -0
- data/lib/pacer/utils/trie.rb +93 -0
- data/lib/pacer/utils/tsort.rb +65 -0
- data/lib/pacer/utils/y_files.rb +127 -0
- data/lib/pacer/utils.rb +10 -0
- data/lib/pacer/version.rb +13 -0
- data/lib/pacer/wrappers/edge_wrapper.rb +51 -0
- data/lib/pacer/wrappers/element_wrapper.rb +78 -0
- data/lib/pacer/wrappers/new_element.rb +106 -0
- data/lib/pacer/wrappers/vertex_wrapper.rb +51 -0
- data/lib/pacer/wrappers.rb +19 -0
- data/lib/pacer-0.9.1.1-standalone.jar +0 -0
- data/lib/pacer.rb +290 -0
- data/pacer.gemspec +30 -0
- data/pom/standalone.xml +22 -0
- data/pom.xml +124 -0
- data/samples/grateful-dead.xml +26380 -0
- data/samples/grateful_dead.rb +63 -0
- data/samples/profile.rb +15 -0
- data/spec/data/grateful-dead.xml +26380 -0
- data/spec/data/pacer.graphml +319 -0
- data/spec/pacer/blueprints/dex_spec.rb +172 -0
- data/spec/pacer/blueprints/neo4j_spec.rb +177 -0
- data/spec/pacer/blueprints/tg_spec.rb +128 -0
- data/spec/pacer/core/graph/edges_route_spec.rb +52 -0
- data/spec/pacer/core/graph/element_route_spec.rb +46 -0
- data/spec/pacer/core/graph/graph_route_spec.rb +94 -0
- data/spec/pacer/core/graph/vertices_route_spec.rb +169 -0
- data/spec/pacer/core/route_spec.rb +197 -0
- data/spec/pacer/filter/collection_filter_spec.rb +19 -0
- data/spec/pacer/filter/empty_filter_spec.rb +29 -0
- data/spec/pacer/filter/future_filter_spec.rb +97 -0
- data/spec/pacer/filter/loop_filter_spec.rb +31 -0
- data/spec/pacer/filter/property_filter_spec.rb +111 -0
- data/spec/pacer/filter/random_filter_spec.rb +17 -0
- data/spec/pacer/filter/uniq_filter_spec.rb +18 -0
- data/spec/pacer/filter/where_filter_spec.rb +93 -0
- data/spec/pacer/graph/edge_mixin_spec.rb +116 -0
- data/spec/pacer/graph/element_mixin_spec.rb +297 -0
- data/spec/pacer/graph/graph_mixin_spec.rb +538 -0
- data/spec/pacer/graph/index_mixin_spec.rb +0 -0
- data/spec/pacer/graph/vertex_mixin_spec.rb +192 -0
- data/spec/pacer/pipe/block_filter_pipe_spec.rb +0 -0
- data/spec/pacer/pipe/labels_filter_pipe_spec.rb +0 -0
- data/spec/pacer/pipe/ruby_pipe_spec.rb +0 -0
- data/spec/pacer/pipe/type_filter_pipe_spec.rb +0 -0
- data/spec/pacer/route/mixin/base_spec.rb +419 -0
- data/spec/pacer/route/mixin/bulk_operations_spec.rb +30 -0
- data/spec/pacer/route/mixin/route_operations_spec.rb +127 -0
- data/spec/pacer/support/array_list_spec.rb +0 -0
- data/spec/pacer/support/enumerable_spec.rb +115 -0
- data/spec/pacer/transform/join_spec.rb +138 -0
- data/spec/pacer/transform/path_spec.rb +54 -0
- data/spec/pacer/utils/tsort_spec.rb +89 -0
- data/spec/pacer/wrapper/edge_wrapper_spec.rb +33 -0
- data/spec/pacer/wrapper/element_wrapper_spec.rb +169 -0
- data/spec/pacer/wrapper/vertex_wrapper_spec.rb +33 -0
- data/spec/pacer_spec.rb +0 -0
- data/spec/spec_helper.rb +91 -0
- data/spec/support/contexts.rb +14 -0
- data/spec/support/graph_runner.rb +142 -0
- data/spec/support/matchers.rb +19 -0
- data/spec/support/use_transactions.rb +31 -0
- data/spec/tackle/simple_mixin.rb +21 -0
- data/spec/tackle/tinkerpop_graph_mixins.rb +60 -0
- 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
|
data/lib/pacer/core.rb
ADDED
@@ -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,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
|