dag_link_calculator 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 +7 -0
- data/.codeclimate.yml +28 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.rubocop.yml +1156 -0
- data/.ruby-version +1 -0
- data/.travis.yml +8 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Guardfile +43 -0
- data/LICENSE.txt +21 -0
- data/README.md +220 -0
- data/Rakefile +6 -0
- data/bin/_guard-core +17 -0
- data/bin/console +14 -0
- data/bin/guard +17 -0
- data/bin/rake +17 -0
- data/bin/rspec +17 -0
- data/bin/setup +8 -0
- data/dag_link_calculator.gemspec +34 -0
- data/lib/dag_link_calculator.rb +17 -0
- data/lib/dag_link_calculator/calculator.rb +79 -0
- data/lib/dag_link_calculator/cycle_exception.rb +4 -0
- data/lib/dag_link_calculator/direct_link.rb +40 -0
- data/lib/dag_link_calculator/node_link.rb +20 -0
- data/lib/dag_link_calculator/node_route.rb +23 -0
- data/lib/dag_link_calculator/version.rb +3 -0
- metadata +133 -0
data/bin/rspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
#
|
4
|
+
# This file was generated by Bundler.
|
5
|
+
#
|
6
|
+
# The application 'rspec' is installed as part of a gem, and
|
7
|
+
# this file is here to facilitate running it.
|
8
|
+
#
|
9
|
+
|
10
|
+
require "pathname"
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
12
|
+
Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
require "rubygems"
|
15
|
+
require "bundler/setup"
|
16
|
+
|
17
|
+
load Gem.bin_path("rspec-core", "rspec")
|
data/bin/setup
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dag_link_calculator/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'dag_link_calculator'
|
8
|
+
spec.version = DagLinkCalculator::VERSION
|
9
|
+
spec.authors = ['Eduardo Turiño']
|
10
|
+
spec.email = ['eturino@eturino.com']
|
11
|
+
spec.required_ruby_version = '>= 2.1'
|
12
|
+
|
13
|
+
spec.summary = <<-TXT.gsub(/[\s]*/, ' ')
|
14
|
+
Given a list of parent-child relationships, it will return a list of links ancestor-descendant, with count
|
15
|
+
TXT
|
16
|
+
spec.description = <<-TXT.gsub(/[\s]*/, ' ')
|
17
|
+
Given a list of parent-child relationships, it will return a list of links ancestor-descendant, with count.
|
18
|
+
Can be used to restore a list of links in `act-as-dag`, providing that the direct links are correct.
|
19
|
+
TXT
|
20
|
+
spec.homepage = 'https://github.com/artirix/dag_link_calculator'
|
21
|
+
spec.license = 'MIT'
|
22
|
+
|
23
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
24
|
+
f.match(%r{^(test|spec|features)/})
|
25
|
+
end
|
26
|
+
spec.bindir = 'exe'
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ['lib']
|
29
|
+
|
30
|
+
spec.add_development_dependency 'bundler', '~> 1.14'
|
31
|
+
spec.add_development_dependency 'guard-rspec', '~> 4.7'
|
32
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
33
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
34
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'dag_link_calculator/version'
|
2
|
+
require 'dag_link_calculator/cycle_exception'
|
3
|
+
require 'dag_link_calculator/node_link'
|
4
|
+
require 'dag_link_calculator/direct_link'
|
5
|
+
require 'dag_link_calculator/node_route'
|
6
|
+
require 'dag_link_calculator/calculator'
|
7
|
+
|
8
|
+
module DagLinkCalculator
|
9
|
+
def self.from_direct_links_structs(direct_links_structs)
|
10
|
+
Calculator.new(direct_links_structs)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.from_direct_links_hashes(direct_links_hashes)
|
14
|
+
direct_links_structs = direct_links_hashes.map { |h| DirectLink.from_hash(h) }
|
15
|
+
from_direct_links_structs(direct_links_structs)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module DagLinkCalculator
|
2
|
+
class Calculator
|
3
|
+
attr_reader :direct_links_structs
|
4
|
+
|
5
|
+
def initialize(direct_links_structs)
|
6
|
+
@direct_links_structs = direct_links_structs
|
7
|
+
end
|
8
|
+
|
9
|
+
def all_links_hashes
|
10
|
+
@all_links_hashes ||= build_all_links_hashes
|
11
|
+
end
|
12
|
+
|
13
|
+
def all_links_structs
|
14
|
+
@all_links_structs ||= build_all_links_structs
|
15
|
+
end
|
16
|
+
|
17
|
+
def all_routes_structs
|
18
|
+
@all_routes_structs ||= build_all_routes_structs
|
19
|
+
end
|
20
|
+
|
21
|
+
def parents_map
|
22
|
+
@parent_map ||= build_parents_map
|
23
|
+
end
|
24
|
+
|
25
|
+
def parents_of(descendant_id)
|
26
|
+
parents_map[descendant_id] || []
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def build_all_links_hashes
|
32
|
+
all_links_structs.map(&:to_hash)
|
33
|
+
end
|
34
|
+
|
35
|
+
def build_all_links_structs
|
36
|
+
grouped = all_routes_structs.group_by { |node_route| [node_route.descendant_id, node_route.ancestor_id] }
|
37
|
+
grouped.map do |(descendant_id, ancestor_id), list|
|
38
|
+
count = list.size
|
39
|
+
direct = list.any?(&:direct?)
|
40
|
+
NodeLink.new(ancestor_id, descendant_id, direct, count)
|
41
|
+
end.sort
|
42
|
+
end
|
43
|
+
|
44
|
+
def build_all_routes_structs
|
45
|
+
parents_map.keys.map do |descendant_id|
|
46
|
+
routes_for_node descendant_id
|
47
|
+
end.flatten.sort
|
48
|
+
end
|
49
|
+
|
50
|
+
def build_parents_map
|
51
|
+
direct_links_structs
|
52
|
+
.group_by(&:descendant_id)
|
53
|
+
.map { |k, list| [k, list.map(&:ancestor_id)] }
|
54
|
+
.to_h
|
55
|
+
end
|
56
|
+
|
57
|
+
def routes_for_node(node_id, recursive_ids_list = [])
|
58
|
+
@routes_map ||= {}
|
59
|
+
@routes_map[node_id] ||= build_routes_for_node node_id, recursive_ids_list
|
60
|
+
end
|
61
|
+
|
62
|
+
def build_routes_for_node(node_id, recursive_ids_list)
|
63
|
+
raise CycleException if recursive_ids_list.include? node_id
|
64
|
+
recursive_ids_list << node_id
|
65
|
+
|
66
|
+
parents_of(node_id).map do |parent_id|
|
67
|
+
[NodeRoute.new([node_id, parent_id])].concat(build_parent_routes_for(node_id, parent_id, recursive_ids_list))
|
68
|
+
end.flatten
|
69
|
+
end
|
70
|
+
|
71
|
+
def build_parent_routes_for(node_id, parent_id, recursive_ids_list)
|
72
|
+
routes_for_node(parent_id, recursive_ids_list).map do |r|
|
73
|
+
NodeRoute.new([node_id].concat(r.nodes))
|
74
|
+
end
|
75
|
+
rescue CycleException
|
76
|
+
raise CycleException, "nodes #{parent_id.inspect} and #{node_id.inspect} are ancestor and descendant of each other: cycle detected!"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module DagLinkCalculator
|
2
|
+
ANCESTOR_KEYS = [:ancestor_id, :ancestor, :parent_id, :parent].freeze
|
3
|
+
DESCENDANT_KEYS = [:descendant_id, :descendant, :child_id, :child].freeze
|
4
|
+
|
5
|
+
DirectLink = Struct.new(:ancestor_id, :descendant_id) do
|
6
|
+
def self.from_hash(hash)
|
7
|
+
ancestor_id = fetch_from hash, ANCESTOR_KEYS
|
8
|
+
descendant_id = fetch_from hash, DESCENDANT_KEYS
|
9
|
+
new(ancestor_id, descendant_id)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.fetch_from(hash, keys)
|
13
|
+
keys.each do |k|
|
14
|
+
return hash[k] if hash[k]
|
15
|
+
end
|
16
|
+
|
17
|
+
raise KeyError, "none of these keys found in the given hash: #{keys}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def direct
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def direct?
|
25
|
+
direct
|
26
|
+
end
|
27
|
+
|
28
|
+
def count
|
29
|
+
1
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_link
|
33
|
+
NodeLink.new(ancestor_id, descendant_id, direct?, count)
|
34
|
+
end
|
35
|
+
|
36
|
+
def <=>(other)
|
37
|
+
[ancestor_id, descendant_id] <=> [other.ancestor_id, other.descendant_id]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module DagLinkCalculator
|
2
|
+
NodeLink = Struct.new(:ancestor_id, :descendant_id, :direct, :count) do
|
3
|
+
def direct?
|
4
|
+
direct
|
5
|
+
end
|
6
|
+
|
7
|
+
def <=>(other)
|
8
|
+
[ancestor_id, descendant_id] <=> [other.ancestor_id, other.descendant_id]
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_hash
|
12
|
+
{
|
13
|
+
ancestor_id: ancestor_id,
|
14
|
+
descendant_id: descendant_id,
|
15
|
+
direct: direct,
|
16
|
+
count: count,
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module DagLinkCalculator
|
2
|
+
NodeRoute = Struct.new(:nodes) do
|
3
|
+
def size
|
4
|
+
nodes.size
|
5
|
+
end
|
6
|
+
|
7
|
+
def direct?
|
8
|
+
size == 2
|
9
|
+
end
|
10
|
+
|
11
|
+
def descendant_id
|
12
|
+
nodes.first
|
13
|
+
end
|
14
|
+
|
15
|
+
def ancestor_id
|
16
|
+
nodes.last
|
17
|
+
end
|
18
|
+
|
19
|
+
def <=>(other)
|
20
|
+
nodes <=> other.nodes
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dag_link_calculator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Eduardo Turiño
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-04-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.14'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: guard-rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.7'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
description: " G i v e n a l i s t o f p a r e n t - c h i l d r e l a t i o
|
70
|
+
n s h i p s , i t w i l l r e t u r n a l i s t o f l i n k s a n c e s
|
71
|
+
t o r - d e s c e n d a n t , w i t h c o u n t . C a n b e u s e d t o r
|
72
|
+
e s t o r e a l i s t o f l i n k s i n ` a c t - a s - d a g ` , p r o v
|
73
|
+
i d i n g t h a t t h e d i r e c t l i n k s a r e c o r r e c t . "
|
74
|
+
email:
|
75
|
+
- eturino@eturino.com
|
76
|
+
executables: []
|
77
|
+
extensions: []
|
78
|
+
extra_rdoc_files: []
|
79
|
+
files:
|
80
|
+
- ".codeclimate.yml"
|
81
|
+
- ".coveralls.yml"
|
82
|
+
- ".gitignore"
|
83
|
+
- ".rspec"
|
84
|
+
- ".rubocop.yml"
|
85
|
+
- ".ruby-version"
|
86
|
+
- ".travis.yml"
|
87
|
+
- CODE_OF_CONDUCT.md
|
88
|
+
- Gemfile
|
89
|
+
- Guardfile
|
90
|
+
- LICENSE.txt
|
91
|
+
- README.md
|
92
|
+
- Rakefile
|
93
|
+
- bin/_guard-core
|
94
|
+
- bin/console
|
95
|
+
- bin/guard
|
96
|
+
- bin/rake
|
97
|
+
- bin/rspec
|
98
|
+
- bin/setup
|
99
|
+
- dag_link_calculator.gemspec
|
100
|
+
- lib/dag_link_calculator.rb
|
101
|
+
- lib/dag_link_calculator/calculator.rb
|
102
|
+
- lib/dag_link_calculator/cycle_exception.rb
|
103
|
+
- lib/dag_link_calculator/direct_link.rb
|
104
|
+
- lib/dag_link_calculator/node_link.rb
|
105
|
+
- lib/dag_link_calculator/node_route.rb
|
106
|
+
- lib/dag_link_calculator/version.rb
|
107
|
+
homepage: https://github.com/artirix/dag_link_calculator
|
108
|
+
licenses:
|
109
|
+
- MIT
|
110
|
+
metadata: {}
|
111
|
+
post_install_message:
|
112
|
+
rdoc_options: []
|
113
|
+
require_paths:
|
114
|
+
- lib
|
115
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '2.1'
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
requirements: []
|
126
|
+
rubyforge_project:
|
127
|
+
rubygems_version: 2.6.11
|
128
|
+
signing_key:
|
129
|
+
specification_version: 4
|
130
|
+
summary: G i v e n a l i s t o f p a r e n t - c h i l d r e l a t i o n s h
|
131
|
+
i p s , i t w i l l r e t u r n a l i s t o f l i n k s a n c e s t o r
|
132
|
+
- d e s c e n d a n t , w i t h c o u n t
|
133
|
+
test_files: []
|