graphable 0.0.5 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/graphable.gemspec +2 -2
- data/lib/graphable.rb +31 -5
- data/lib/graphable/edge_creator.rb +35 -22
- data/lib/graphable/index_creator.rb +7 -5
- data/lib/graphable/node_creator.rb +7 -4
- data/lib/graphable/version.rb +1 -1
- metadata +19 -7
data/graphable.gemspec
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
require File.expand_path('../lib/graphable/version', __FILE__)
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
|
-
gem.authors = ["Joe Fredette"]
|
6
|
-
gem.email = ["jfredett@gmail.com"]
|
5
|
+
gem.authors = ["Joe Fredette", "Andrew Ross"]
|
6
|
+
gem.email = ["jfredett@gmail.com", "andrewslavinross@gmail.com"]
|
7
7
|
gem.description = %q{A library for extracting static graph representations of data from rails-y databases}
|
8
8
|
gem.summary = %q{A library for extracting static graph representations of data from rails-y databases}
|
9
9
|
gem.homepage = "http://www.github.com/jfredett/graphable"
|
data/lib/graphable.rb
CHANGED
@@ -10,7 +10,7 @@ module Graphable
|
|
10
10
|
|
11
11
|
included do
|
12
12
|
Graphable.register NodeCreator.new(self)
|
13
|
-
|
13
|
+
graph_indexes :id
|
14
14
|
end
|
15
15
|
|
16
16
|
def self.register(registrant)
|
@@ -26,7 +26,7 @@ module Graphable
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.build!
|
29
|
-
puts "Building Graph"
|
29
|
+
puts "Building Graph..."
|
30
30
|
registry.select { |f| f.is_a? NodeCreator }.map(&:call)
|
31
31
|
registry.select { |f| f.is_a? IndexCreator }.map(&:call)
|
32
32
|
registry.select { |f| f.is_a? EdgeCreator }.map(&:call)
|
@@ -41,6 +41,18 @@ module Graphable
|
|
41
41
|
@completed_indicies ||= {}
|
42
42
|
end
|
43
43
|
|
44
|
+
def self.object_access_methods
|
45
|
+
@object_access_methods ||= {}
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.objects_of(klass)
|
49
|
+
klass.send(object_access_methods[klass] || 'all')
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.register_object_access_method(klass, method)
|
53
|
+
object_access_methods[klass] = method
|
54
|
+
end
|
55
|
+
|
44
56
|
def self.completed_index(klass, method)
|
45
57
|
completed_indicies[[klass, method]] = true
|
46
58
|
end
|
@@ -49,23 +61,33 @@ module Graphable
|
|
49
61
|
completed_indicies[[klass,method]]
|
50
62
|
end
|
51
63
|
|
64
|
+
def self.completed_edges
|
65
|
+
@completed_edges ||= {}
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.completed_edge(source, target, name)
|
69
|
+
completed_edges[[source,target,name]] = true
|
70
|
+
end
|
52
71
|
|
72
|
+
def self.has_completed_edge?(source, target, name)
|
73
|
+
completed_edges[[source,target,name]]
|
74
|
+
end
|
53
75
|
|
54
76
|
module InstanceMethods
|
55
77
|
def to_node
|
56
78
|
attributes.to_hash.tap do |hash|
|
57
|
-
hash.each { |k,
|
79
|
+
hash.each { |k, v| hash.delete(k) if v.nil? || k.to_s =~ /_id$/ } #remove FKs and nil values
|
58
80
|
hash[:type] = self.class.name
|
59
81
|
end
|
60
82
|
end
|
61
83
|
end
|
62
84
|
|
63
85
|
module ClassMethods
|
64
|
-
def
|
86
|
+
def graph_index_name
|
65
87
|
"#{name.downcase.pluralize}_index"
|
66
88
|
end
|
67
89
|
|
68
|
-
def
|
90
|
+
def graph_indexes(*methods)
|
69
91
|
methods.each do |method|
|
70
92
|
Graphable.register IndexCreator.new(self, method)
|
71
93
|
end
|
@@ -83,6 +105,10 @@ module Graphable
|
|
83
105
|
raise "Invalid Edge type, must be :through or :via"
|
84
106
|
end
|
85
107
|
end
|
108
|
+
|
109
|
+
def graph_with(method)
|
110
|
+
Graphable.register_object_access_method(self, method)
|
111
|
+
end
|
86
112
|
end
|
87
113
|
|
88
114
|
end
|
@@ -35,11 +35,11 @@ module Graphable
|
|
35
35
|
# anyway.
|
36
36
|
metadata.reject! { |_,v| v.nil? }
|
37
37
|
|
38
|
-
|
38
|
+
Graphable.neo.create_relationship(@name, source_node, target_node, metadata)
|
39
39
|
end
|
40
40
|
|
41
41
|
def sources
|
42
|
-
@source
|
42
|
+
Graphable.objects_of(@source)
|
43
43
|
end
|
44
44
|
|
45
45
|
def target_name
|
@@ -49,21 +49,26 @@ module Graphable
|
|
49
49
|
|
50
50
|
class ThroughEdgeCreator < EdgeCreator
|
51
51
|
def call
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
52
|
+
return if Graphable.has_completed_edge?(@source, @target, @name)
|
53
|
+
|
54
|
+
puts "Building #{@name} edges for #{@source.name} -> #{@target.name}"
|
55
|
+
sources.each_slice(250) do |slice|
|
56
|
+
Graphable.neo.batch(*slice.map { |obj|
|
57
|
+
source_node = load_node(obj)
|
58
|
+
relationships = []
|
59
|
+
intermediates_for(obj).each do |intermediate_target|
|
60
|
+
metadata = {}
|
58
61
|
metadata = @metadata_proc.call(intermediate_target) if @metadata_proc
|
59
62
|
metadata = intermediate_target.send(:edge_metadata) if intermediate_target.respond_to?(:edge_metadata)
|
60
|
-
|
61
63
|
target_node = load_node(intermediate_target.send(target_name)) rescue binding.pry
|
62
|
-
|
63
|
-
|
64
|
+
next unless source_node && target_node
|
65
|
+
relationships << [:create_relationship, @name, source_node, target_node, metadata || {}]
|
64
66
|
end
|
65
|
-
|
67
|
+
relationships
|
68
|
+
}.flatten(1))
|
66
69
|
end
|
70
|
+
|
71
|
+
Graphable.completed_edge(@source, @target, @name)
|
67
72
|
end
|
68
73
|
|
69
74
|
def targets_for(source)
|
@@ -79,17 +84,25 @@ module Graphable
|
|
79
84
|
|
80
85
|
class ViaEdgeCreator < EdgeCreator
|
81
86
|
def call
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
87
|
+
return if Graphable.has_completed_edge?(@source, @target, @name)
|
88
|
+
|
89
|
+
puts "Building #{@name} edges for #{@source.name} -> #{@target.name}"
|
90
|
+
sources.each_slice(250) do |slice|
|
91
|
+
Graphable.neo.batch(*slice.map { |obj|
|
92
|
+
source_node = load_node(obj)
|
93
|
+
relationships = []
|
94
|
+
targets_for(obj).each do |target|
|
95
|
+
metadata = {}
|
96
|
+
metadata = @metadata_proc.call(target) if @metadata_proc
|
97
|
+
target_node = load_node(target) rescue binding.pry
|
98
|
+
next unless source_node && target_node
|
99
|
+
relationships << [:create_relationship, @name, source_node, target_node, metadata]
|
100
|
+
end
|
101
|
+
relationships
|
102
|
+
}.flatten(1))
|
92
103
|
end
|
104
|
+
|
105
|
+
Graphable.completed_edge(@source, @target, @name)
|
93
106
|
end
|
94
107
|
|
95
108
|
def targets_for(source)
|
@@ -3,7 +3,7 @@ module Graphable
|
|
3
3
|
extend Forwardable
|
4
4
|
|
5
5
|
attr_reader :klass
|
6
|
-
delegate [:name, :
|
6
|
+
delegate [:name, :graph_index_name] => :@klass
|
7
7
|
|
8
8
|
def initialize(klass, method)
|
9
9
|
@klass = klass
|
@@ -13,11 +13,13 @@ module Graphable
|
|
13
13
|
def call
|
14
14
|
return if Graphable.has_indexed?(@klass, @method)
|
15
15
|
|
16
|
-
puts "Building index for #{name}"
|
17
|
-
Graphable.neo.create_node_index(
|
16
|
+
puts "Building #{@method} index for #{name}"
|
17
|
+
Graphable.neo.create_node_index(graph_index_name, 'exact') # fulltext
|
18
18
|
|
19
|
-
|
20
|
-
Graphable.neo.
|
19
|
+
Graphable.objects_of(@klass).each_slice(250) do |slice|
|
20
|
+
Graphable.neo.batch(*slice.map do |obj|
|
21
|
+
[:add_node_to_index, graph_index_name, @method, obj.send(@method), Graphable.index_cache[obj]]
|
22
|
+
end)
|
21
23
|
end
|
22
24
|
|
23
25
|
Graphable.completed_index(@klass, @method)
|
@@ -5,7 +5,7 @@ module Graphable
|
|
5
5
|
extend Forwardable
|
6
6
|
|
7
7
|
attr_reader :klass
|
8
|
-
delegate [:name
|
8
|
+
delegate [:name] => :@klass
|
9
9
|
|
10
10
|
def initialize(klass)
|
11
11
|
@klass = klass
|
@@ -13,9 +13,12 @@ module Graphable
|
|
13
13
|
|
14
14
|
def call
|
15
15
|
puts "Building nodes for #{name}"
|
16
|
-
|
17
|
-
slice.
|
18
|
-
|
16
|
+
Graphable.objects_of(@klass).each_slice(250) do |slice|
|
17
|
+
nodes = Graphable.neo.batch(*slice.map do |obj|
|
18
|
+
[:create_node, obj.to_node]
|
19
|
+
end)
|
20
|
+
slice.zip(nodes).each do |object, node|
|
21
|
+
Graphable.index_cache[object] = node["body"]
|
19
22
|
end
|
20
23
|
end
|
21
24
|
end
|
data/lib/graphable/version.rb
CHANGED
metadata
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Joe Fredette
|
9
|
+
- Andrew Ross
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date: 2012-
|
13
|
+
date: 2012-08-15 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: activesupport
|
16
|
-
requirement:
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
17
18
|
none: false
|
18
19
|
requirements:
|
19
20
|
- - ~>
|
@@ -21,10 +22,15 @@ dependencies:
|
|
21
22
|
version: '3.1'
|
22
23
|
type: :runtime
|
23
24
|
prerelease: false
|
24
|
-
version_requirements:
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '3.1'
|
25
31
|
- !ruby/object:Gem::Dependency
|
26
32
|
name: neography
|
27
|
-
requirement:
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
28
34
|
none: false
|
29
35
|
requirements:
|
30
36
|
- - ! '>='
|
@@ -32,11 +38,17 @@ dependencies:
|
|
32
38
|
version: '0'
|
33
39
|
type: :runtime
|
34
40
|
prerelease: false
|
35
|
-
version_requirements:
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
36
47
|
description: A library for extracting static graph representations of data from rails-y
|
37
48
|
databases
|
38
49
|
email:
|
39
50
|
- jfredett@gmail.com
|
51
|
+
- andrewslavinross@gmail.com
|
40
52
|
executables: []
|
41
53
|
extensions: []
|
42
54
|
extra_rdoc_files: []
|
@@ -72,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
72
84
|
version: '0'
|
73
85
|
requirements: []
|
74
86
|
rubyforge_project:
|
75
|
-
rubygems_version: 1.8.
|
87
|
+
rubygems_version: 1.8.18
|
76
88
|
signing_key:
|
77
89
|
specification_version: 3
|
78
90
|
summary: A library for extracting static graph representations of data from rails-y
|