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,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
|