graphable 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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"
@@ -10,7 +10,7 @@ module Graphable
10
10
 
11
11
  included do
12
12
  Graphable.register NodeCreator.new(self)
13
- indexes :id
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, _| hash.delete(k) if k.to_s =~ /_id$/ } #remove FKs
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 index_name
86
+ def graph_index_name
65
87
  "#{name.downcase.pluralize}_index"
66
88
  end
67
89
 
68
- def indexes(*methods)
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
- Neography::Relationship.create(@name, source_node, target_node, metadata)
38
+ Graphable.neo.create_relationship(@name, source_node, target_node, metadata)
39
39
  end
40
40
 
41
41
  def sources
42
- @source.all
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
- puts "Building edges for #{@source.name} -> #{@target.name}"
53
- sources.each_slice(100) do |slice|
54
- slice.each do |source|
55
- source_node = load_node(source)
56
-
57
- intermediates_for(source).each do |intermediate_target|
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
- build_relationship(source_node, target_node, metadata || {})
64
+ next unless source_node && target_node
65
+ relationships << [:create_relationship, @name, source_node, target_node, metadata || {}]
64
66
  end
65
- end
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
- puts "Building edges for #{@source.name} -> #{@target.name}"
83
- sources.each do |source|
84
- source_node = load_node(source)
85
-
86
- targets_for(source).each do |target|
87
- metadata = @metadata_proc.call(target) if @metadata_proc
88
-
89
- target_node = load_node(target) rescue binding.pry
90
- build_relationship(source_node, target_node, metadata || {})
91
- end
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, :all, :index_name] => :@klass
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(index_name, 'fulltext')
16
+ puts "Building #{@method} index for #{name}"
17
+ Graphable.neo.create_node_index(graph_index_name, 'exact') # fulltext
18
18
 
19
- all.to_a.each do |object|
20
- Graphable.neo.add_node_to_index(index_name, @method, object.send(@method), Graphable.index_cache[object])
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, :all] => :@klass
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
- all.each_slice(100) do |slice|
17
- slice.each do |object|
18
- Graphable.index_cache[object] = Neography::Node.create(object.to_node)
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
@@ -1,3 +1,3 @@
1
1
  module Graphable
2
- VERSION = "0.0.5"
2
+ VERSION = "0.1.0"
3
3
  end
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.5
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-04-04 00:00:00.000000000 Z
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: &2156110660 !ruby/object:Gem::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: *2156110660
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: &2156109400 !ruby/object:Gem::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: *2156109400
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.17
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