gremlin2dot 0.1.0
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.
- checksums.yaml +7 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +28 -0
- data/README.md +6 -0
- data/bin/gremlin2dot +84 -0
- data/lib/gremlin2dot/data_model.rb +60 -0
- data/lib/gremlin2dot/graph_builder.rb +54 -0
- data/lib/gremlin2dot/unmangler.rb +67 -0
- data/lib/gremlin2dot.rb +3 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 329541aa877df7ee19cd655d44becf877b32739d76b41dfd1b5a97b3aad1f619
|
4
|
+
data.tar.gz: 074615b05287eda09c507586b86891bf30d1f34cf113e6b031ae7906550fe60c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 51e50cc7cd8e90042a07beb665665073f9aa626056c52b40865eb92b1fbdd1e1c57a8dfaa3bf0eec7ea77fe68caf4c260b711e2f6e94a5096b8336145f1f64b6
|
7
|
+
data.tar.gz: 77e8a9450f43d4b50a0540c18695991b7b4a319b7a9efb0d23bd987c71034572518c04679f7347de8e4e7ded6b50da315b9e204f887f8536b99c9c13e36b729f
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
GEM
|
2
|
+
specs:
|
3
|
+
domain_name (0.5.20180417)
|
4
|
+
unf (>= 0.0.5, < 1.0.0)
|
5
|
+
http-cookie (1.0.3)
|
6
|
+
domain_name (~> 0.5)
|
7
|
+
mime-types (3.1)
|
8
|
+
mime-types-data (~> 3.2015)
|
9
|
+
mime-types-data (3.2016.0521)
|
10
|
+
netrc (0.11.0)
|
11
|
+
rest-client (2.0.2)
|
12
|
+
http-cookie (>= 1.0.2, < 2.0)
|
13
|
+
mime-types (>= 1.16, < 4.0)
|
14
|
+
netrc (~> 0.8)
|
15
|
+
ruby-graphviz (1.2.2)
|
16
|
+
unf (0.1.4)
|
17
|
+
unf_ext
|
18
|
+
unf_ext (0.0.7.5)
|
19
|
+
|
20
|
+
PLATFORMS
|
21
|
+
ruby
|
22
|
+
|
23
|
+
DEPENDENCIES
|
24
|
+
rest-client (~> 2.0)
|
25
|
+
ruby-graphviz (~> 1.0)
|
26
|
+
|
27
|
+
BUNDLED WITH
|
28
|
+
1.16.1
|
data/README.md
ADDED
data/bin/gremlin2dot
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# vi: set ts=2 sw=2 :
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
def error(message)
|
7
|
+
$stderr.puts message
|
8
|
+
exit 2
|
9
|
+
end
|
10
|
+
|
11
|
+
endpoint = nil
|
12
|
+
query = nil
|
13
|
+
use_stdin = false
|
14
|
+
|
15
|
+
json_file = nil
|
16
|
+
|
17
|
+
canon_file = nil
|
18
|
+
dot_file = nil
|
19
|
+
png_file = nil
|
20
|
+
svg_file = nil
|
21
|
+
|
22
|
+
opts = OptionParser.new
|
23
|
+
opts.on('-e', '--endpoint URL', 'The URL of the Gremlin endpoint') {|v| endpoint = v }
|
24
|
+
opts.on('-q', '--query QUERY', 'The Gremlin query to run') {|v| query = v }
|
25
|
+
opts.on('--stdin', 'Read Gremlin results as JSON from standard input') { use_stdin = true }
|
26
|
+
opts.on('--save-json FILE', 'Save the JSON to FILE') {|v| json_file = v }
|
27
|
+
opts.on('--canon FILE', 'Write the results as canonical DOT to FILE') {|v| canon_file = v }
|
28
|
+
opts.on('--dot FILE', 'Write the results as placed DOT to FILE') {|v| dot_file = v }
|
29
|
+
opts.on('--png FILE', 'Write the results as PNG to FILE') {|v| png_file = v }
|
30
|
+
opts.on('--svg FILE', 'Write the results as SVG to FILE') {|v| svg_file = v }
|
31
|
+
opts.order!
|
32
|
+
|
33
|
+
if !canon_file and !dot_file and !png_file and !svg_file
|
34
|
+
canon_file = "/dev/stdout"
|
35
|
+
end
|
36
|
+
|
37
|
+
if endpoint.nil? != query.nil?
|
38
|
+
error "Either specify both --endpoint and --query, or specify --stdin 1"
|
39
|
+
end
|
40
|
+
|
41
|
+
if use_stdin != endpoint.nil?
|
42
|
+
error "Either specify both --endpoint and --query, or specify --stdin 2"
|
43
|
+
end
|
44
|
+
|
45
|
+
require 'json'
|
46
|
+
require 'gremlin2dot'
|
47
|
+
require 'ruby-graphviz'
|
48
|
+
|
49
|
+
json_text = if use_stdin
|
50
|
+
$stdin.read
|
51
|
+
else
|
52
|
+
require 'rest-client'
|
53
|
+
RestClient.post(
|
54
|
+
endpoint,
|
55
|
+
{ gremlin: query }.to_json,
|
56
|
+
{ content_type: :json, accept: :json },
|
57
|
+
).body
|
58
|
+
end
|
59
|
+
|
60
|
+
if json_file
|
61
|
+
IO.write(json_file, json_text)
|
62
|
+
end
|
63
|
+
|
64
|
+
query_results = JSON.parse(json_text)
|
65
|
+
unmangled_data = Gremlin2Dot::Unmangler.new.unmangle(query_results)
|
66
|
+
g = Gremlin2Dot::GraphBuilder.build(unmangled_data)
|
67
|
+
|
68
|
+
if canon_file
|
69
|
+
g.output(canon: canon_file)
|
70
|
+
end
|
71
|
+
|
72
|
+
if dot_file
|
73
|
+
g.output(dot: dot_file)
|
74
|
+
end
|
75
|
+
|
76
|
+
if png_file
|
77
|
+
g.output(png: png_file)
|
78
|
+
end
|
79
|
+
|
80
|
+
if svg_file
|
81
|
+
g.output(svg: svg_file)
|
82
|
+
end
|
83
|
+
|
84
|
+
exit
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Gremlin2Dot
|
2
|
+
|
3
|
+
class Edge < Hash
|
4
|
+
def id ; self['id'] ; end
|
5
|
+
def label ; self['label'] ; end
|
6
|
+
def inVLabel ; self['inVLabel'] ; end
|
7
|
+
def outVLabel ; self['outVLabel'] ; end
|
8
|
+
def inV ; self['inV'] ; end
|
9
|
+
def outV ; self['outV'] ; end
|
10
|
+
def properties ; self['properties'] || {} ; end
|
11
|
+
def inspect ; "#<#{self.class.name} #{super}>" ; end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Vertex < Hash
|
15
|
+
def id ; self['id'] ; end
|
16
|
+
def label ; self['label'] ; end
|
17
|
+
def properties ; self['properties'] || {} ; end
|
18
|
+
def inspect ; "#<#{self.class.name} #{super}>" ; end
|
19
|
+
end
|
20
|
+
|
21
|
+
class VertexProperty < Hash
|
22
|
+
def id ; self['id'] ; end
|
23
|
+
def label ; self['label'] ; end
|
24
|
+
def value ; self['value'] ; end
|
25
|
+
|
26
|
+
def inspect
|
27
|
+
value.inspect
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
value.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
def pretty_print(*args)
|
35
|
+
value.pretty_print *args
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Property < Hash
|
40
|
+
def key ; self['key'] ; end
|
41
|
+
def value ; self['value'] ; end
|
42
|
+
|
43
|
+
def inspect
|
44
|
+
value.inspect
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_s
|
48
|
+
value.to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
def pretty_print(*args)
|
52
|
+
value.pretty_print *args
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class Tree
|
57
|
+
attr_accessor :key, :items
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Gremlin2Dot
|
4
|
+
|
5
|
+
class GraphBuilder
|
6
|
+
|
7
|
+
def self.build(results)
|
8
|
+
self.new().build(results)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@seen = Set.new
|
13
|
+
@g = GraphViz.new("G")
|
14
|
+
end
|
15
|
+
|
16
|
+
def build(unmangled_data)
|
17
|
+
trees = unmangled_data['result']['data']
|
18
|
+
|
19
|
+
trees.each do |t0|
|
20
|
+
t0.each do |t1|
|
21
|
+
add_thing t1
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
@g
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_thing(thing)
|
29
|
+
case thing
|
30
|
+
when Vertex
|
31
|
+
node = thing
|
32
|
+
unless @seen.include? node.id
|
33
|
+
label = node.label + node.properties.entries.sort_by(&:first).map {|k, v| "\n#{k}=#{v.first}" }.join("")
|
34
|
+
@g.add_nodes(node.id, label: label)
|
35
|
+
@seen << node.id
|
36
|
+
end
|
37
|
+
when Edge
|
38
|
+
edge = thing
|
39
|
+
unless @seen.include? edge.id
|
40
|
+
label = edge.label + edge.properties.entries.sort_by(&:first).map {|k, v| "\n#{k}=#{v}" }.join("")
|
41
|
+
@g.add_edges(edge.outV, edge.inV, label: label)
|
42
|
+
@seen << edge.id
|
43
|
+
end
|
44
|
+
when Tree
|
45
|
+
add_thing thing.key
|
46
|
+
thing.items.each {|child| add_thing child}
|
47
|
+
else
|
48
|
+
$stderr.puts "Not adding #{thing.class} to the graph"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Gremlin2Dot
|
2
|
+
|
3
|
+
class Unmangler
|
4
|
+
|
5
|
+
def unmangle(d)
|
6
|
+
if d.kind_of?(Hash) and d.has_key?('@type') and d.has_key?('@value') and d.keys.count == 2
|
7
|
+
case d['@type']
|
8
|
+
when 'g:Map'
|
9
|
+
h = Hash.new
|
10
|
+
raise unless d['@value'].empty?
|
11
|
+
h
|
12
|
+
when 'g:List'
|
13
|
+
unmangle d['@value']
|
14
|
+
when 'g:Tree'
|
15
|
+
# array of hashes, where each hash has 'key'=Vertex/Edge, 'value' = ...
|
16
|
+
# Array of Hash with 'key' and 'value', where ...
|
17
|
+
# – key is a Vertex
|
18
|
+
# – value is a Hash of @type/@value
|
19
|
+
|
20
|
+
d['@value'].map do |item|
|
21
|
+
t = Tree.new
|
22
|
+
t.key = unmangle item['key']
|
23
|
+
t.items = unmangle item['value']
|
24
|
+
t
|
25
|
+
end
|
26
|
+
when 'g:Edge'
|
27
|
+
unmangle_object(d, Edge)
|
28
|
+
when 'g:Vertex'
|
29
|
+
unmangle_object(d, Vertex)
|
30
|
+
when 'g:VertexProperty'
|
31
|
+
unmangle_object(d, VertexProperty)
|
32
|
+
# discard the id
|
33
|
+
# unmangle d['@value']['value']
|
34
|
+
when 'g:Property'
|
35
|
+
unmangle_object(d, Property)
|
36
|
+
# discard the key
|
37
|
+
# unmangle d['@value']['value']
|
38
|
+
when 'g:Int32'
|
39
|
+
d['@value']
|
40
|
+
when 'g:Double'
|
41
|
+
d['@value']
|
42
|
+
when 'g:Date'
|
43
|
+
Time.at(d['@value'] / 1000.0)
|
44
|
+
else
|
45
|
+
$stderr.puts 'Ignoring unknown type ' + d['@type'] + " with value #{d['@value'].inspect[0..200]}..."
|
46
|
+
unmangle d['@value']
|
47
|
+
end
|
48
|
+
elsif d.kind_of? Hash
|
49
|
+
d.entries.map {|k, v| [k, unmangle(v)]}.to_h
|
50
|
+
elsif d.kind_of? Array
|
51
|
+
d.map {|v| unmangle v}
|
52
|
+
else
|
53
|
+
d
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def unmangle_object(d, klass)
|
58
|
+
o = klass.new
|
59
|
+
d['@value'].entries.each do |k, v|
|
60
|
+
o[k] = unmangle v
|
61
|
+
end
|
62
|
+
o
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
data/lib/gremlin2dot.rb
ADDED
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gremlin2dot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rachel Evans
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-06-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rest-client
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: ruby-graphviz
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.5'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.5'
|
55
|
+
description: "\n"
|
56
|
+
email:
|
57
|
+
- rachel@rachelevans.org
|
58
|
+
executables:
|
59
|
+
- gremlin2dot
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- Gemfile
|
64
|
+
- Gemfile.lock
|
65
|
+
- README.md
|
66
|
+
- bin/gremlin2dot
|
67
|
+
- lib/gremlin2dot.rb
|
68
|
+
- lib/gremlin2dot/data_model.rb
|
69
|
+
- lib/gremlin2dot/graph_builder.rb
|
70
|
+
- lib/gremlin2dot/unmangler.rb
|
71
|
+
homepage: http://rve.org.uk/gems/gremlin2dot
|
72
|
+
licenses:
|
73
|
+
- Apache-2.0
|
74
|
+
metadata: {}
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
requirements: []
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 2.7.6
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: Run a gremlin query, and visualise using GraphViz
|
95
|
+
test_files: []
|