gremlin2dot 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,2 @@
1
+ gem 'rest-client', '~> 2.0'
2
+ gem 'ruby-graphviz', '~> 1.0'
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
@@ -0,0 +1,6 @@
1
+ gremlin2dot
2
+ ===========
3
+
4
+ Run a Gremlin query (e.g. against AWS Neptune), and visualise the results
5
+ using GraphViz.
6
+
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
@@ -0,0 +1,3 @@
1
+ require_relative 'gremlin2dot/data_model.rb'
2
+ require_relative 'gremlin2dot/graph_builder.rb'
3
+ require_relative 'gremlin2dot/unmangler.rb'
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: []