acts_as_graph 0.0.1 → 0.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 85713371daed2a84ea58c068c10a373165ad9b3b
4
- data.tar.gz: 448fd7508d466a053e8568e3958326f0115bd68f
2
+ SHA256:
3
+ metadata.gz: 1e2c2c5547d606eb07ee5f497397e85b61e05937a5b4eac9f1641f5a8c5c51ea
4
+ data.tar.gz: f405e59e5356dcf1099f27a7f4b139c7fb1a776ab87109e611caa2b0ba7f152d
5
5
  SHA512:
6
- metadata.gz: da1fe3794e4b6d89fe824908f1d1767e3a45dad7206dcf1cb3b4dee9926ff253c6085e7e3067608f2a795dbee6362463a65fc8dc4cbf8346d33573fb43ff6cc5
7
- data.tar.gz: 6f2f24d36ca3530c70f9d2a3f700e93fcb6b216b6305ee4a4d8e634445273b91427da69745eaa3f12ba0d0117845ad31438ac6367576f7a133649c342fc6a021
6
+ metadata.gz: d9e53a8bbcd9da65eb69e40ad61a0a59f97aca36daf9e94aaf0141bd5aac1bf980495f9f8c5b14f336ac3968e0704d5ffe23cc57166b809ab2b6f68a7a3a4920
7
+ data.tar.gz: 8593e2dd8c8ec45c4942eac7f437a8fa6fdcd5182f4cf5c9d482990aad94872644b93aaebf92f163f31ef41fa8664dceac3a65f4bbc9cb08482da357c93e1afa
@@ -1,12 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- acts_as_graph (0.0.1)
5
- rspec
4
+ acts_as_graph (0.0.2)
6
5
 
7
6
  GEM
8
7
  remote: https://rubygems.org/
9
8
  specs:
9
+ byebug (10.0.2)
10
10
  diff-lcs (1.3)
11
11
  rspec (3.7.0)
12
12
  rspec-core (~> 3.7.0)
@@ -27,6 +27,8 @@ PLATFORMS
27
27
 
28
28
  DEPENDENCIES
29
29
  acts_as_graph!
30
+ byebug
31
+ rspec
30
32
 
31
33
  BUNDLED WITH
32
- 1.16.1
34
+ 1.17.2
@@ -9,18 +9,20 @@ Gem::Specification.new do |s|
9
9
  s.platform = Gem::Platform::RUBY
10
10
  s.authors = ['Zhichao Feng']
11
11
  s.email = ['flankerfc@gmail.com']
12
- s.homepage = 'https://github.com/flanker'
12
+ s.homepage = 'https://github.com/flanker/acts_as_graph'
13
13
  s.summary = 'A very simple acts as graph for your model'
14
14
  s.description = 'A very simple acts as graph for your model'
15
15
  s.license = 'MIT'
16
+ s.metadata = {'source_code_uri' => 'https://github.com/flanker/acts_as_graph'}
16
17
 
17
- s.required_ruby_version = '>= 2.3'
18
+ s.required_ruby_version = '>= 2.5'
18
19
  s.required_rubygems_version = '>= 1.3.6'
19
20
 
20
21
  s.files = `git ls-files`.split("\n")
21
22
  s.test_files = `git ls-files -- test/*`.split("\n")
22
23
  s.require_path = ['lib']
23
24
 
24
- s.add_runtime_dependency 'rspec'
25
+ s.add_development_dependency 'rspec'
26
+ s.add_development_dependency 'byebug'
25
27
 
26
28
  end
@@ -1,3 +1,5 @@
1
+ require 'acts_as_graph/dag'
2
+
1
3
  module ActsAsGraph
2
4
 
3
5
  def self.included base
@@ -30,31 +32,33 @@ module ActsAsGraph
30
32
  child_vertices.each do |child_vertice|
31
33
  next if vertices_found.include?(child_vertice) || child_vertice == starting_vertice
32
34
  vertices_found << child_vertice
33
- child_vertice.collect_child_vertices vertices_found, starting_vertice: starting_vertice
35
+ child_vertice.collect_child_vertices vertices_found, starting_vertice: starting_vertice if child_vertice.respond_to?(:collect_child_vertices)
34
36
  end
35
37
  end
36
38
 
37
39
  def has_circular_reference?
38
- vertices_found = []
39
- has_circular_reference_in_child_vertices? vertices_found, starting_vertice: self
40
+ child_vertices.any? do |child_vertice|
41
+ path = [self, child_vertice]
42
+ child_vertice.has_circular_reference_in_path?(path) if child_vertice.respond_to?(:has_circular_reference_in_path?)
43
+ end
40
44
  end
41
45
 
42
- def has_circular_reference_in_child_vertices? vertices_found, starting_vertice: nil
46
+ def has_circular_reference_in_path? path
43
47
  child_vertices.any? do |child_vertice|
44
- return true if vertices_found.include?(child_vertice) || child_vertice == starting_vertice
45
- vertices_found << child_vertice
46
- child_vertice.has_circular_reference_in_child_vertices? vertices_found, starting_vertice: starting_vertice
48
+ return true if path.include?(child_vertice)
49
+ next_path = path + [child_vertice]
50
+ child_vertice.has_circular_reference_in_path?(next_path) if child_vertice.respond_to?(:has_circular_reference_in_path?)
47
51
  end
48
52
  end
49
53
 
54
+ def child_vertices
55
+ self.send children_method_name
56
+ end
57
+
50
58
  private
51
59
 
52
60
  def children_method_name
53
61
  self.class.children_method_name
54
62
  end
55
63
 
56
- def child_vertices
57
- self.send children_method_name
58
- end
59
-
60
64
  end
@@ -0,0 +1,30 @@
1
+ module ActsAsGraph
2
+ class Dag
3
+
4
+ attr_reader :vertices
5
+
6
+ def initialize vertices
7
+ @vertices = vertices
8
+ end
9
+
10
+ def topological_sort
11
+ visited = []
12
+ post_order = []
13
+ vertices.each do |vertice|
14
+ dfs(vertice, visited, post_order) unless visited.include?(vertice)
15
+ end
16
+ post_order
17
+ end
18
+
19
+ private
20
+
21
+ def dfs vertice, visited, post_order
22
+ visited << vertice
23
+ vertice.child_vertices.each do |child_vertice|
24
+ dfs(child_vertice, visited, post_order) unless visited.include?(child_vertice)
25
+ end if vertice.respond_to?(:child_vertices)
26
+ post_order << vertice
27
+ end
28
+
29
+ end
30
+ end
@@ -1,3 +1,3 @@
1
1
  module ActsAsGraph
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.3'
3
3
  end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ module ActsAsGraph
4
+ RSpec.describe Dag do
5
+
6
+ class Task
7
+
8
+ include ActsAsGraph
9
+
10
+ acts_as_graph children: :depended_tasks
11
+
12
+ attr_reader :title
13
+ attr_accessor :depended_tasks
14
+
15
+ def initialize title, depended_tasks = []
16
+ @title = title
17
+ @depended_tasks = depended_tasks
18
+ end
19
+
20
+ end
21
+
22
+ it 'sorts as topological order' do
23
+ task_1 = Task.new 'task_1'
24
+ task_2 = Task.new 'task_2'
25
+ task_3 = Task.new 'task_3'
26
+ task_4 = Task.new 'task_4'
27
+ task_5 = Task.new 'task_5'
28
+ task_6 = Task.new 'task_6'
29
+ task_7 = Task.new 'task_7'
30
+ task_8 = Task.new 'task_8'
31
+
32
+ task_2.depended_tasks = [task_1]
33
+ task_3.depended_tasks = [task_2]
34
+ task_4.depended_tasks = [task_2]
35
+ task_6.depended_tasks = [task_5]
36
+ task_7.depended_tasks = [task_3, task_4]
37
+ task_8.depended_tasks = [task_2, task_3]
38
+
39
+ dag = Dag.new [task_8, task_7, task_6, task_5, task_4, task_3, task_2, task_1]
40
+
41
+ result = dag.topological_sort
42
+ expect(result.length).to eq(8)
43
+ expect(result).to match_array([task_1, task_2, task_3, task_8, task_4, task_7, task_5, task_6])
44
+ end
45
+
46
+ end
47
+ end
@@ -18,6 +18,15 @@ RSpec.describe ActsAsGraph do
18
18
 
19
19
  end
20
20
 
21
+ class Job
22
+
23
+ attr_reader :title
24
+
25
+ def initialize title
26
+ @title = title
27
+ end
28
+ end
29
+
21
30
  context '#descendant_depended_tasks' do
22
31
 
23
32
  it 'should get all descendant tasks' do
@@ -57,13 +66,24 @@ RSpec.describe ActsAsGraph do
57
66
  expect(descendant_depended_tasks.length).to eq(5)
58
67
  expect(descendant_depended_tasks).to match_array([task_2, task_3, task_4, task_5, task_6])
59
68
  end
69
+
70
+ it 'supports other type of object as a child' do
71
+ task_1 = Task.new 'task_1'
72
+ task_2 = Task.new 'task_2'
73
+ job_1 = Job.new 'job_1'
74
+ task_1.depended_tasks = [task_2, job_1]
75
+
76
+ descendant_depended_tasks = task_1.descendant_depended_tasks
77
+ expect(descendant_depended_tasks.length).to eq(2)
78
+ expect(descendant_depended_tasks).to match_array([task_2, job_1])
79
+ end
60
80
  end
61
81
 
62
82
  context '#has_circular_reference?' do
63
83
 
64
84
  it 'works if there is no circular reference' do
65
85
  task_1 = Task.new 'task_1'
66
- task_2 = Task.new 'task_2'
86
+ task_2 = Task.new 'task_2', [task_1]
67
87
  task_3 = Task.new 'task_3', [task_1, task_2]
68
88
 
69
89
  expect(task_3.has_circular_reference?).to be false
@@ -83,6 +103,23 @@ RSpec.describe ActsAsGraph do
83
103
  expect(task_3.has_circular_reference?).to be true
84
104
  end
85
105
 
106
+ it 'works if the circular reference has longer path' do
107
+ task_1 = Task.new 'task_1'
108
+ task_2 = Task.new 'task_2'
109
+ task_3 = Task.new 'task_3'
110
+ task_4 = Task.new 'task_4'
111
+
112
+ task_1.depended_tasks = [task_2]
113
+ task_2.depended_tasks = [task_3]
114
+ task_3.depended_tasks = [task_4]
115
+ task_4.depended_tasks = [task_1]
116
+
117
+ expect(task_1.has_circular_reference?).to be true
118
+ expect(task_2.has_circular_reference?).to be true
119
+ expect(task_3.has_circular_reference?).to be true
120
+ expect(task_4.has_circular_reference?).to be true
121
+ end
122
+
86
123
  it 'works if there are two vertices reference with each other' do
87
124
  task_1 = Task.new 'task_1'
88
125
  task_2 = Task.new 'task_2'
@@ -96,6 +133,29 @@ RSpec.describe ActsAsGraph do
96
133
  expect(task_2.has_circular_reference?).to be true
97
134
  expect(task_3.has_circular_reference?).to be true
98
135
  end
136
+
137
+ it 'works in complex case' do
138
+ task_1 = Task.new 'task_1'
139
+ task_2 = Task.new 'task_2'
140
+ task_3 = Task.new 'task_3'
141
+ task_4 = Task.new 'task_4'
142
+
143
+ task_2.depended_tasks = [task_1]
144
+ task_3.depended_tasks = [task_1, task_2]
145
+ task_4.depended_tasks = [task_2, task_3]
146
+
147
+ # expect(task_2.has_circular_reference?).to be false
148
+ # expect(task_3.has_circular_reference?).to be false
149
+ expect(task_4.has_circular_reference?).to be false
150
+ end
151
+
152
+ it 'supports other type of object as a child' do
153
+ task_1 = Task.new 'task_1'
154
+ job_1 = Job.new 'job_1'
155
+ task_1.depended_tasks = [job_1]
156
+
157
+ expect(task_1.has_circular_reference?).to be false
158
+ end
99
159
  end
100
160
 
101
161
  end
@@ -1,5 +1,6 @@
1
1
  require 'bundler/setup'
2
2
  require 'acts_as_graph'
3
+ require 'byebug'
3
4
 
4
5
  RSpec.configure do |config|
5
6
  # Enable flags like --only-failures and --next-failure
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_graph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zhichao Feng
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-10 00:00:00.000000000 Z
11
+ date: 2020-11-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -17,7 +17,21 @@ dependencies:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
- type: :runtime
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: byebug
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
@@ -38,14 +52,17 @@ files:
38
52
  - Rakefile
39
53
  - acts_as_graph.gemspec
40
54
  - lib/acts_as_graph.rb
55
+ - lib/acts_as_graph/dag.rb
41
56
  - lib/acts_as_graph/version.rb
57
+ - spec/acts_as_graph/dag_spec.rb
42
58
  - spec/acts_as_graph_spec.rb
43
59
  - spec/spec_helper.rb
44
- homepage: https://github.com/flanker
60
+ homepage: https://github.com/flanker/acts_as_graph
45
61
  licenses:
46
62
  - MIT
47
- metadata: {}
48
- post_install_message:
63
+ metadata:
64
+ source_code_uri: https://github.com/flanker/acts_as_graph
65
+ post_install_message:
49
66
  rdoc_options: []
50
67
  require_paths:
51
68
  - lib
@@ -53,16 +70,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
53
70
  requirements:
54
71
  - - ">="
55
72
  - !ruby/object:Gem::Version
56
- version: '2.3'
73
+ version: '2.5'
57
74
  required_rubygems_version: !ruby/object:Gem::Requirement
58
75
  requirements:
59
76
  - - ">="
60
77
  - !ruby/object:Gem::Version
61
78
  version: 1.3.6
62
79
  requirements: []
63
- rubyforge_project:
64
- rubygems_version: 2.6.14
65
- signing_key:
80
+ rubygems_version: 3.0.3
81
+ signing_key:
66
82
  specification_version: 4
67
83
  summary: A very simple acts as graph for your model
68
84
  test_files: []