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.
- 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,112 @@
|
|
|
1
|
+
module Pacer
|
|
2
|
+
module Utils
|
|
3
|
+
module GraphAnalysis
|
|
4
|
+
|
|
5
|
+
class << self
|
|
6
|
+
# Returns a TinkerGraph representing the number of each type of node and how
|
|
7
|
+
# many edges (by label) point to each other type of node.
|
|
8
|
+
def structure(graph, type_field = :type)
|
|
9
|
+
result = Pacer.tg
|
|
10
|
+
result.vertex_name = proc do |v|
|
|
11
|
+
if v[:element_type] == 'vertex'
|
|
12
|
+
"vertex '#{v[:type]}' (#{v[:count]})"
|
|
13
|
+
elsif v[:element_type] == 'edge'
|
|
14
|
+
"edge :#{v[:label]} (#{v[:count]})"
|
|
15
|
+
elsif v[:element_type] == 'property keys'
|
|
16
|
+
"properties #{v[:number]} keys (#{v[:count]})"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
graph.v[type_field].fast_group_count.to_h.each do |type, count|
|
|
20
|
+
result.create_vertex :element_type => 'vertex', :type_field => type_field, :type => type, :count => count
|
|
21
|
+
end
|
|
22
|
+
graph.e.labels.fast_group_count.to_h.each do |label, count|
|
|
23
|
+
result.create_vertex :element_type => 'edge', :label => label, :count => count
|
|
24
|
+
end
|
|
25
|
+
result.v(:element_type => 'vertex').each do |type_node|
|
|
26
|
+
puts "vertices of type #{ type_node[:type] }: #{ type_node[:count] }"
|
|
27
|
+
graph.v(self, :type => type_node[:type]).property_variations result, type_node
|
|
28
|
+
end
|
|
29
|
+
result.v(:element_type => 'edge').each do |edge_node|
|
|
30
|
+
puts "edges with label #{ edge_node[:label] }: #{ edge_node[:count] }"
|
|
31
|
+
edge_route = graph.e(self, edge_node[:label])
|
|
32
|
+
edge_route.property_variations result, edge_node
|
|
33
|
+
end
|
|
34
|
+
result.v.each do |type_node|
|
|
35
|
+
begin
|
|
36
|
+
edges = graph.v(type_field => type_node[:type]).out_e
|
|
37
|
+
edge_types = edges.group_count do |e|
|
|
38
|
+
[e.label, e.in_vertex[type_field]]
|
|
39
|
+
end
|
|
40
|
+
edge_types.each do |(label, type), count|
|
|
41
|
+
puts "edges labelled #{ label } from #{ type_node[:type] } to #{ type }: #{ count }"
|
|
42
|
+
type_node.add_edges_to(label, result.v(:type => type), :count => count)
|
|
43
|
+
end
|
|
44
|
+
rescue => e
|
|
45
|
+
puts e.message
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
result
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
module Route
|
|
53
|
+
def property_variations(result, node)
|
|
54
|
+
prop_keys = group_count { |v| v.properties.keys.sort }
|
|
55
|
+
prop_keys.each do |keys, count|
|
|
56
|
+
prop_key = result.v(:element_type => 'property keys').detect { |v| v[:keys] == keys }
|
|
57
|
+
unless prop_key
|
|
58
|
+
prop_key = result.create_vertex :element_type => 'property keys', :keys => keys, :number => keys.count, :count => 0
|
|
59
|
+
end
|
|
60
|
+
prop_key[:count] += count
|
|
61
|
+
puts " #{ count } with #{ keys.count } properties: #{ keys.inspect }"
|
|
62
|
+
node.add_edges_to :properties, prop_key, :count => count
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
module Vertices
|
|
68
|
+
def self.route_conditions
|
|
69
|
+
{ :element_type => 'vertex' }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
module Route
|
|
73
|
+
def out_edge_types
|
|
74
|
+
all_edges = graph.v(Edges)
|
|
75
|
+
out_e.labels.uniq.inject(all_edges) do |route, label|
|
|
76
|
+
route.branch { |b| b.filter(:label => label) }
|
|
77
|
+
end.v.v(Edges)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def in_edge_types
|
|
81
|
+
all_edges = graph.v(Edges)
|
|
82
|
+
in_e.labels.uniq.inject(all_edges) do |route, label|
|
|
83
|
+
route.branch { |b| b.filter(:label => label) }
|
|
84
|
+
end.v.v(Edges)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def property_variations
|
|
88
|
+
out_e(:properties).in_v(Properties)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
module Edges
|
|
94
|
+
def self.route_conditions
|
|
95
|
+
{ :element_type => 'edge' }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
module Route
|
|
99
|
+
def property_variations
|
|
100
|
+
out_e(:properties).in_v(Properties)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
module Properties
|
|
106
|
+
def self.route_conditions
|
|
107
|
+
{ :element_type => 'property keys' }
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
module Pacer::Utils
|
|
2
|
+
module Trie
|
|
3
|
+
class << self
|
|
4
|
+
def trie(graph, name)
|
|
5
|
+
t = graph.v(self, :name => name).first
|
|
6
|
+
if t
|
|
7
|
+
t
|
|
8
|
+
else
|
|
9
|
+
graph.create_vertex self, :type => 'Trie', :name => name
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def route_conditions
|
|
14
|
+
{ :type => 'Trie' }
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
module Vertex
|
|
19
|
+
def find_word(word)
|
|
20
|
+
find word.scan(/./)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def find(array)
|
|
24
|
+
found = find_partial(array)
|
|
25
|
+
if found.length == array.length
|
|
26
|
+
result = found.last.in_vertex.add_extensions [Trie]
|
|
27
|
+
result.graph = graph
|
|
28
|
+
result
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def find_partial(array)
|
|
33
|
+
return [] if array.empty?
|
|
34
|
+
strings = array.map &:to_s
|
|
35
|
+
max_depth = array.length - 1
|
|
36
|
+
found = []
|
|
37
|
+
v.out_e(strings.first).loop { |e| e.in_v.out_e }.while do |e, depth|
|
|
38
|
+
if e.label == "trie:#{strings[depth]}" and depth <= max_depth
|
|
39
|
+
found << e
|
|
40
|
+
:loop
|
|
41
|
+
end
|
|
42
|
+
end.to_a
|
|
43
|
+
found
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def add_word(word)
|
|
47
|
+
add word.scan(/./)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def add(array)
|
|
51
|
+
found = find_partial(array)
|
|
52
|
+
if found.length == array.length
|
|
53
|
+
result = found.last.in_vertex
|
|
54
|
+
else
|
|
55
|
+
found[array.length] ||= nil
|
|
56
|
+
result = array.zip(found).inject(self) do |vertex, (part, edge)|
|
|
57
|
+
if edge
|
|
58
|
+
edge.in_vertex
|
|
59
|
+
else
|
|
60
|
+
new_vertex = graph.create_vertex :type => 'Trie'
|
|
61
|
+
graph.create_edge nil, vertex, new_vertex, "trie:#{part.to_s}"
|
|
62
|
+
new_vertex
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
result[:end] = true
|
|
67
|
+
result.graph = graph
|
|
68
|
+
result.add_extensions [Trie]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def path
|
|
72
|
+
result = []
|
|
73
|
+
v.in_e.chain_route(:pipe_class => Pacer::Pipes::LabelPrefixPipe, :pipe_args => 'trie:').loop do |e|
|
|
74
|
+
e.out_v.in_e.chain_route(:pipe_class => Pacer::Pipes::LabelPrefixPipe, :pipe_args => 'trie:')
|
|
75
|
+
end.while do |e, d|
|
|
76
|
+
if e.out_vertex[:type] == 'Trie'
|
|
77
|
+
:emit
|
|
78
|
+
else
|
|
79
|
+
:loop
|
|
80
|
+
end
|
|
81
|
+
end.paths.to_a.first.reverse.to_route(:element_type => :mixed, :graph => graph)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def array
|
|
85
|
+
path.e.labels.map { |label| label[/^trie:(.*)$/, 1] }.to_a
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def word
|
|
89
|
+
array.join
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require 'tsort'
|
|
2
|
+
|
|
3
|
+
module Pacer
|
|
4
|
+
module Utils
|
|
5
|
+
# Include this module in your traversal to use ruby's built-in TSort
|
|
6
|
+
# utility to sort your vertices according to the direction of the
|
|
7
|
+
# edges that connect them.
|
|
8
|
+
module TSort
|
|
9
|
+
module Route
|
|
10
|
+
include ::TSort
|
|
11
|
+
|
|
12
|
+
attr_accessor :tsort_anon_mod
|
|
13
|
+
|
|
14
|
+
# NOTE: this is a great example of dynamically injecting a custom method
|
|
15
|
+
# into a route.
|
|
16
|
+
def dependencies(&block)
|
|
17
|
+
anon_mod = Module.new
|
|
18
|
+
anon_mod.const_set :Route, TSort::Route
|
|
19
|
+
anon_mod.const_set :Vertex, Module.new
|
|
20
|
+
anon_mod::Vertex.const_set :DependenciesBlock, block
|
|
21
|
+
anon_mod::Vertex.instance_eval do
|
|
22
|
+
def self.included(target)
|
|
23
|
+
target.const_set :DependenciesBlock, self::DependenciesBlock
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
route = v(*(extensions - [TSort] + [anon_mod]))
|
|
27
|
+
route.tsort_anon_mod = anon_mod
|
|
28
|
+
route
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def tsort_each_node
|
|
32
|
+
v.each do |vertex|
|
|
33
|
+
yield vertex
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def tsort_each_child(node)
|
|
38
|
+
node.tsort_dependencies(tsort_anon_mod).each do |vertex|
|
|
39
|
+
yield vertex
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def tsort
|
|
44
|
+
super.to_route(:graph => graph,
|
|
45
|
+
:element_type => :vertex,
|
|
46
|
+
:extensions => (extensions - [TSort, tsort_anon_mod]))
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
module Vertex
|
|
51
|
+
def tsort_each_node
|
|
52
|
+
yield self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def tsort_dependencies(tsort_anon_mod = nil)
|
|
56
|
+
if self.class.const_defined? :DependenciesBlock
|
|
57
|
+
self.class::DependenciesBlock.call(self).add_extension(tsort_anon_mod)
|
|
58
|
+
else
|
|
59
|
+
self.in
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
require 'nokogiri'
|
|
2
|
+
require 'set'
|
|
3
|
+
|
|
4
|
+
module Pacer
|
|
5
|
+
module Utils
|
|
6
|
+
|
|
7
|
+
# Exports a graph to GraphML with some yworks.com graphml formatting extensions.
|
|
8
|
+
class YFilesExport
|
|
9
|
+
|
|
10
|
+
# a proc that takes a vertex and returns a label string
|
|
11
|
+
attr_accessor :vertex_label
|
|
12
|
+
# a proc that takes a vertex and returns a color in hex format: "#aaee00"
|
|
13
|
+
attr_accessor :vertex_fill
|
|
14
|
+
# a proc that takes a vertex and returns a hash of properties to be exported
|
|
15
|
+
attr_accessor :vertex_properties
|
|
16
|
+
|
|
17
|
+
# a proc that takes an edge and returns a label string
|
|
18
|
+
attr_accessor :edge_label
|
|
19
|
+
# a proc that takes an edge and returns a color in hex format: "#aaee00"
|
|
20
|
+
attr_accessor :edge_color
|
|
21
|
+
# a proc that takes an edge and returns a hash of properties to be exported
|
|
22
|
+
attr_accessor :edge_properties
|
|
23
|
+
|
|
24
|
+
def initialize
|
|
25
|
+
self.vertex_label = proc { |v| v[:name] }
|
|
26
|
+
self.edge_label = proc { |e| e.label }
|
|
27
|
+
self.vertex_properties = self.edge_properties = proc { |x| x.properties }
|
|
28
|
+
self.vertex_fill = proc { |v| "#FFCC00" }
|
|
29
|
+
self.edge_color = proc { |e| "#000000" }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Export the given graph to the given path in an extended .graphml format.
|
|
33
|
+
def export(graph, path)
|
|
34
|
+
x = xml(graph)
|
|
35
|
+
File.open(File.expand_path(path), 'w') do |f|
|
|
36
|
+
f.puts x.to_xml
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Returns the xml builder used to construct the xml for the given graph.
|
|
41
|
+
def xml(graph)
|
|
42
|
+
node_keys = Set[]
|
|
43
|
+
edge_keys = Set[]
|
|
44
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
|
45
|
+
xml.graphml('xmlns' => "http://graphml.graphdrawing.org/xmlns",
|
|
46
|
+
'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
|
|
47
|
+
'xmlns:y' => "http://www.yworks.com/xml/graphml",
|
|
48
|
+
'xsi:schemaLocation' => "http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd") do
|
|
49
|
+
xml.key 'for' => "node", 'id' => "y.nodegraphics", 'yfiles.type' => "nodegraphics"
|
|
50
|
+
xml.key 'attr.name' => "description", 'attr.type' => "string", 'for' => "node", 'id' => "d2"
|
|
51
|
+
xml.key 'for' => "edge", 'id' => "y.edgegraphics", 'yfiles.type' => "edgegraphics"
|
|
52
|
+
graph.v.each do |v|
|
|
53
|
+
xml.node :id => v.element_id do
|
|
54
|
+
xml.data :key => 'y.nodegraphics' do
|
|
55
|
+
xml['y'].ShapeNode do
|
|
56
|
+
#xml['y'].Geometry 'height' => "30.0", 'width' => "30.0", 'x' => "15.0", 'y' => "0.0"
|
|
57
|
+
xml['y'].Fill 'color' => vertex_fill.call(v), 'transparent' => "false"
|
|
58
|
+
xml['y'].BorderStyle 'color' => "#000000", 'type' => "line", 'width' => "1.0"
|
|
59
|
+
xml['y'].NodeLabel('alignment' => "center",
|
|
60
|
+
'autoSizePolicy' => "content",
|
|
61
|
+
'fontFamily' => "Dialog",
|
|
62
|
+
'fontSize' => "12",
|
|
63
|
+
'fontStyle' => "plain",
|
|
64
|
+
'hasBackgroundColor' => "false",
|
|
65
|
+
'hasLineColor' => "false",
|
|
66
|
+
#'height' => "4.0",
|
|
67
|
+
'modelName' => "internal",
|
|
68
|
+
'modelPosition' => "c",
|
|
69
|
+
'textColor' => "#000000",
|
|
70
|
+
'visible' => "true"
|
|
71
|
+
#'width' => "4.0",
|
|
72
|
+
#'x' => "13.0",
|
|
73
|
+
#'y' => "13.0"
|
|
74
|
+
) { xml.text vertex_label.call(v) }
|
|
75
|
+
xml['y'].Shape 'type' => "rectangle"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
vertex_properties.call(v).each do |name, value|
|
|
79
|
+
node_keys << name
|
|
80
|
+
xml.data(:key => name) { xml.text value }
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
graph.e.each do |e|
|
|
85
|
+
xml.edge :id => e.element_id, :source => e.out_vertex.element_id, :target => e.in_vertex.element_id, :label => e.label do
|
|
86
|
+
xml.data :key => 'y.edgegraphics' do
|
|
87
|
+
xml['y'].PolyLineEdge do
|
|
88
|
+
xml['y'].LineStyle 'color' => edge_color.call(e), 'type' => 'line', 'width' => '1.0'
|
|
89
|
+
xml['y'].Arrows 'source' => 'none', 'target' => 'standard'
|
|
90
|
+
xml['y'].EdgeLabel('alignment' => "center",
|
|
91
|
+
#'distance' => "2.0",
|
|
92
|
+
'fontFamily' => "Dialog",
|
|
93
|
+
'fontSize' => "12",
|
|
94
|
+
'fontStyle' => "plain",
|
|
95
|
+
'hasBackgroundColor' => "false",
|
|
96
|
+
'hasLineColor' => "false",
|
|
97
|
+
#'height' => "18.1328125",
|
|
98
|
+
'modelName' => "side_slider",
|
|
99
|
+
#'preferredPlacement' => "right",
|
|
100
|
+
#'ratio' => "0.43751239324621083",
|
|
101
|
+
'textColor' => "#000000",
|
|
102
|
+
'visible' => "true"
|
|
103
|
+
#'width' => "28.87890625",
|
|
104
|
+
#'x' => "49.62109375",
|
|
105
|
+
#'y' => "-27.201349990172957"
|
|
106
|
+
) { xml.text edge_label.call(e) }
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
edge_properties.call(e).each do |name, value|
|
|
110
|
+
edge_keys << name
|
|
111
|
+
xml.data(:key => name) { xml.text value }
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
node_keys.each do |key|
|
|
117
|
+
xml.key :id => key, :for => 'node', 'attr.name' => key, 'attr.type' => 'string'
|
|
118
|
+
end
|
|
119
|
+
edge_keys.each do |key|
|
|
120
|
+
xml.key :id => key, :for => 'edge', 'attr.name' => key, 'attr.type' => 'string'
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
data/lib/pacer/utils.rb
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module Pacer
|
|
2
|
+
module Utils
|
|
3
|
+
autoload :YFilesExport, 'pacer/utils/y_files'
|
|
4
|
+
autoload :GraphAnalysis, 'pacer/utils/graph_analysis'
|
|
5
|
+
autoload :TSort, 'pacer/utils/tsort'
|
|
6
|
+
autoload :Trie, 'pacer/utils/trie'
|
|
7
|
+
import com.tinkerpop.blueprints.pgm.util.AutomaticIndexHelper
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module Pacer::Wrappers
|
|
2
|
+
class EdgeWrapper < ElementWrapper
|
|
3
|
+
include Pacer::Edge
|
|
4
|
+
include Pacer::Core::Graph::EdgesRoute
|
|
5
|
+
include Pacer::ElementMixin
|
|
6
|
+
include Pacer::EdgeMixin
|
|
7
|
+
|
|
8
|
+
def_delegators :@element,
|
|
9
|
+
:getId, :getLabel, :getPropertyKeys, :getProperty, :setProperty, :removeProperty,
|
|
10
|
+
:getInVertex, :getOutVertex,
|
|
11
|
+
:getRawEdge,
|
|
12
|
+
:graph, :graph=, :<=>, :==
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
def wrapper_for(exts)
|
|
16
|
+
@wrappers = {} unless defined? @wrappers
|
|
17
|
+
@wrappers[exts.to_set] ||= build_edge_wrapper(exts)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def clear_cache
|
|
21
|
+
@wrappers = {}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
protected
|
|
25
|
+
|
|
26
|
+
def build_edge_wrapper(exts)
|
|
27
|
+
build_extension_wrapper(exts, [:Route, :Edge], EdgeWrapper)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# This method must be defined here rather than in the superclass in order
|
|
32
|
+
# to correctly override the method in an included module
|
|
33
|
+
def extensions
|
|
34
|
+
self.class.extensions
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# This method must be defined here rather than in the superclass in order
|
|
38
|
+
# to correctly override the method in an included module
|
|
39
|
+
def element
|
|
40
|
+
@element
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def add_extensions(exts)
|
|
44
|
+
if exts.any?
|
|
45
|
+
self.class.wrap(element, extensions + exts.to_a)
|
|
46
|
+
else
|
|
47
|
+
self
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module Pacer::Wrappers
|
|
2
|
+
class ElementWrapper
|
|
3
|
+
include Pacer::Element
|
|
4
|
+
extend Forwardable
|
|
5
|
+
include Comparable
|
|
6
|
+
|
|
7
|
+
class << self
|
|
8
|
+
def wrap(element, exts)
|
|
9
|
+
wrapper_for(exts).new(element.element)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def extensions
|
|
13
|
+
@extensions ||= []
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def clear_cache
|
|
17
|
+
Pacer.send :remove_const, :Wrap if Pacer.const_defined? :Wrap
|
|
18
|
+
VertexWrapper.clear_cache
|
|
19
|
+
EdgeWrapper.clear_cache
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def route_conditions
|
|
23
|
+
return @route_conditions if defined? @route_conditions
|
|
24
|
+
@route_conditions = extensions.inject({}) do |h, ext|
|
|
25
|
+
if ext.respond_to? :route_conditions
|
|
26
|
+
h.merge! ext.route_conditions
|
|
27
|
+
else
|
|
28
|
+
h
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
@route_conditions
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
protected
|
|
35
|
+
|
|
36
|
+
def build_extension_wrapper(exts, mod_names, superclass)
|
|
37
|
+
sc_name = superclass.to_s.split(/::/).last
|
|
38
|
+
exts = exts.uniq unless exts.is_a? Set
|
|
39
|
+
classname = "#{sc_name}#{exts.map { |m| m.to_s }.join('')}".gsub(/::/, '_').gsub(/\W/, '')
|
|
40
|
+
eval "module ::Pacer; module Wrap; class #{classname.to_s} < #{sc_name}; end; end; end"
|
|
41
|
+
wrapper = Pacer::Wrap.const_get classname
|
|
42
|
+
exts.each do |obj|
|
|
43
|
+
if obj.is_a? Module or obj.is_a? Class
|
|
44
|
+
mod_names.each do |mod_name|
|
|
45
|
+
if obj.const_defined? mod_name
|
|
46
|
+
wrapper.send :include, obj.const_get(mod_name)
|
|
47
|
+
wrapper.extensions << obj unless wrapper.extensions.include? obj
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
wrapper
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def initialize(element)
|
|
57
|
+
@element = element
|
|
58
|
+
after_initialize
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def element_id
|
|
62
|
+
@element.get_id
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def hash
|
|
66
|
+
@element.hash
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def eql?(other)
|
|
70
|
+
@element.eql?(other)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
protected
|
|
74
|
+
|
|
75
|
+
def after_initialize
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
module Pacer::Wrappers
|
|
2
|
+
class NewElement
|
|
3
|
+
include Pacer::Element
|
|
4
|
+
|
|
5
|
+
def initialize
|
|
6
|
+
@properties = {}
|
|
7
|
+
@out_edges = []
|
|
8
|
+
@in_edges = []
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def getId
|
|
12
|
+
nil
|
|
13
|
+
end
|
|
14
|
+
alias get_id getId
|
|
15
|
+
|
|
16
|
+
def getPropertyKeys
|
|
17
|
+
@properties.keys
|
|
18
|
+
end
|
|
19
|
+
alias property_keys getPropertyKeys
|
|
20
|
+
|
|
21
|
+
def getProperty(prop)
|
|
22
|
+
@properties[prop]
|
|
23
|
+
end
|
|
24
|
+
alias get_property getProperty
|
|
25
|
+
|
|
26
|
+
def setProperty(prop, value)
|
|
27
|
+
@properties[prop] = value
|
|
28
|
+
end
|
|
29
|
+
alias set_property setProperty
|
|
30
|
+
|
|
31
|
+
def removeProperty(prop)
|
|
32
|
+
@properties.delete prop
|
|
33
|
+
end
|
|
34
|
+
alias remove_property removeProperty
|
|
35
|
+
|
|
36
|
+
def graph
|
|
37
|
+
@graph
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def graph=(graph)
|
|
41
|
+
@graph = graph
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def <=>(other)
|
|
45
|
+
object_id <=> other.object_id
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def ==(other)
|
|
49
|
+
equal? other
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class NewVertex < NewElement
|
|
54
|
+
include Pacer::Vertex
|
|
55
|
+
|
|
56
|
+
def getOutEdges(*args)
|
|
57
|
+
@out_edges
|
|
58
|
+
end
|
|
59
|
+
alias out_edges getOutEdges
|
|
60
|
+
alias get_out_edges getOutEdges
|
|
61
|
+
|
|
62
|
+
def getInEdges(*args)
|
|
63
|
+
@in_edges
|
|
64
|
+
end
|
|
65
|
+
alias in_edges getInEdges
|
|
66
|
+
alias get_in_edges getInEdges
|
|
67
|
+
|
|
68
|
+
def getRawVertex
|
|
69
|
+
self
|
|
70
|
+
end
|
|
71
|
+
alias raw_vertex getRawVertex
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
class NewEdge < NewElement
|
|
75
|
+
include Pacer::Edge
|
|
76
|
+
|
|
77
|
+
def getInVertex
|
|
78
|
+
@in_vertex
|
|
79
|
+
end
|
|
80
|
+
alias in_vertex getInVertex
|
|
81
|
+
alias inVertex getInVertex
|
|
82
|
+
|
|
83
|
+
def getOutVertex
|
|
84
|
+
@out_vertex
|
|
85
|
+
end
|
|
86
|
+
alias out_vertex getOutVertex
|
|
87
|
+
alias outVertex getOutVertex
|
|
88
|
+
|
|
89
|
+
def getLabel
|
|
90
|
+
@label
|
|
91
|
+
end
|
|
92
|
+
alias get_label getLabel
|
|
93
|
+
alias label getLabel
|
|
94
|
+
|
|
95
|
+
def setLabel(label)
|
|
96
|
+
@label = label
|
|
97
|
+
end
|
|
98
|
+
alias set_label setLabel
|
|
99
|
+
alias label= setLabel
|
|
100
|
+
|
|
101
|
+
def getRawEdge
|
|
102
|
+
self
|
|
103
|
+
end
|
|
104
|
+
alias raw_edge getRawEdge
|
|
105
|
+
end
|
|
106
|
+
end
|