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 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: []