tangle 0.8.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ee56b345a6f81de14bbc7bb9d16fbb10f9e2174b2588140a6881bd1ff31d0d5
4
- data.tar.gz: 2172244bbb6ab3a91dff9fb4e6491fadc1f56762d984edf75c7f325b1ce9bed5
3
+ metadata.gz: 49ee5268eb1851a1087ba45efac9f00794a248dfce75aadab846f6617d91620e
4
+ data.tar.gz: cc4d0d76f99b86c5494758311637bcb4610555afb58118e059833f62992ef492
5
5
  SHA512:
6
- metadata.gz: 7bb4eeacbdf97538cef1a19738ac0260e47b56a19a6854d2de4dd735203001f7000f09239fbd3d6dcce377d8acf24a3b9647f1ddbbb2c152129b16e78de5fb16
7
- data.tar.gz: 71837d3d43769c939200f450fb823ce6e82aec754527989e93ffac3db58eac2a8a99c816c9afc648dbbf97bf101b63e78656af86e487f6d3568f40333e2fa078
6
+ metadata.gz: c785bb5d7b83a53db61c03ffff2b6a26c17659eb9f79868e4882c884d0e97339b8748d32778bd2e73bb5293b5dd3a9a9adfef22ff38ab9e0f2c1c660dc0dd09c
7
+ data.tar.gz: f042503d2a4d65f6f9ed4cce56e6ba94623ef6e57e73b306a690edce5d2276aa01a7e211d83a2d2aec096a85def0923e4c8da350eb417a37101217764c84c18e
@@ -62,14 +62,10 @@ module Tangle
62
62
  #
63
63
  # Unless a selector is provided, the subgraph contains the entire graph.
64
64
  #
65
- def subgraph(included = nil)
66
- included ||= vertices
65
+ def subgraph(included = nil, &selector)
67
66
  result = clone
68
- vertices.each do |vertex|
69
- result.remove_vertex(vertex) unless included.include?(vertex)
70
- next unless block_given?
71
- result.remove_vertex(vertex) unless yield(vertex)
72
- end
67
+ result.select_vertices!(included) unless included.nil?
68
+ result.select_vertices!(&selector) if block_given?
73
69
  result
74
70
  end
75
71
 
@@ -77,5 +73,11 @@ module Tangle
77
73
  "#<#{self.class}: #{vertices.count} vertices, #{edges.count} edges>"
78
74
  end
79
75
  alias inspect to_s
76
+
77
+ private
78
+
79
+ def callback(receiver, method, *args)
80
+ receiver.send(method, *args) if receiver.respond_to?(method)
81
+ end
80
82
  end
81
83
  end
@@ -17,15 +17,16 @@ module Tangle
17
17
  # add_edge(vtx1, vtx2, ...) => Edge
18
18
  #
19
19
  def add_edge(*vertices, **kvargs)
20
- insert_edge(self.class::Edge.new(*vertices, mixins: @mixins, **kvargs))
20
+ edge = self.class::Edge.new(*vertices, mixins: @mixins, **kvargs)
21
+ insert_edge(edge)
22
+ vertices.each { |vertex| callback(vertex, :edge_added, edge) }
23
+ edge
21
24
  end
22
25
 
23
26
  # Remove an edge from the graph
24
27
  def remove_edge(edge)
25
- edge.each_vertex do |vertex|
26
- @vertices.fetch(vertex).delete(edge)
27
- end
28
- @edges.delete(edge)
28
+ delete_edge(edge)
29
+ edge.each_vertex { |vertex| callback(vertex, :edge_removed, edge) }
29
30
  end
30
31
 
31
32
  protected
@@ -34,10 +35,12 @@ module Tangle
34
35
  #
35
36
  def insert_edge(edge)
36
37
  @edges << edge
37
- edge.each_vertex do |vertex|
38
- @vertices.fetch(vertex) << edge
39
- end
40
- edge
38
+ edge.each_vertex { |vertex| @vertices.fetch(vertex) << edge }
39
+ end
40
+
41
+ def delete_edge(edge)
42
+ edge.each_vertex { |vertex| @vertices.fetch(vertex).delete(edge) }
43
+ @edges.delete(edge)
41
44
  end
42
45
 
43
46
  private
@@ -18,12 +18,19 @@ module Tangle
18
18
  @vertices.keys
19
19
  end
20
20
 
21
+ # Select vertices in the graph
22
+ def select(&selector)
23
+ @vertices.each_key.select(&selector)
24
+ end
25
+
21
26
  # Add a vertex into the graph
22
27
  #
23
- # If a name: is given, it will be registered by name
28
+ # If a name: is given, or the vertex responds to :name,
29
+ # it will be registered by name in the graph
24
30
  def add_vertex(vertex, name: nil)
25
- @vertices[vertex] = Set[]
26
- @vertices_by_name[name] = vertex unless name.nil?
31
+ name ||= callback(vertex, :name)
32
+ insert_vertex(vertex, name)
33
+ callback(vertex, :added_to_graph, self)
27
34
  self
28
35
  end
29
36
  alias << add_vertex
@@ -33,7 +40,31 @@ module Tangle
33
40
  @vertices[vertex].each do |edge|
34
41
  remove_edge(edge) if edge.include?(vertex)
35
42
  end
43
+ delete_vertex(vertex)
44
+ callback(vertex, :removed_from_graph, self)
45
+ end
46
+
47
+ protected
48
+
49
+ def select_vertices!(selected = nil)
50
+ vertices.each do |vertex|
51
+ delete_vertex(vertex) if block_given? && !yield(vertex)
52
+ next if selected.nil?
53
+ delete_vertex(vertex) unless selected.any? { |vtx| vtx.eql?(vertex) }
54
+ end
55
+ end
56
+
57
+ def insert_vertex(vertex, name = nil)
58
+ @vertices[vertex] = Set[]
59
+ @vertices_by_name[name] = vertex unless name.nil?
60
+ end
61
+
62
+ def delete_vertex(vertex)
63
+ @vertices[vertex].each do |edge|
64
+ delete_edge(edge) if edge.include?(vertex)
65
+ end
36
66
  @vertices.delete(vertex)
67
+ @vertices_by_name.delete_if { |_, vtx| vtx.eql?(vertex) }
37
68
  end
38
69
 
39
70
  private
@@ -7,17 +7,23 @@ module Tangle
7
7
  # options are:
8
8
  # root: root directory for the structure (mandatory)
9
9
  # loaders: list of object loader lambdas (mandatory)
10
+ # ->(graph, **) { ... } => finished?
10
11
  # follow_links: bool for following symlinks to directories
11
12
  # (default false)
12
13
  #
13
- # A loader lambda will be called like
14
- # ->(graph, path, parent_path) { ... }
14
+ # A loader lambda is called with the graph as only positional
15
+ # argument, and a number of keyword arguments:
15
16
  #
16
- # The lambdas are called in order until one returns true
17
+ # path: Path of current filesystem object
18
+ # parent: Path of filesystem parent object
19
+ # lstat: File.lstat for path
20
+ # stat: File.stat for path, if lstat.symlink?
21
+ #
22
+ # The lambdas are called in order until one returns true.
17
23
  #
18
24
  # Example:
19
- # loader = lambda do |g, path, parent|
20
- # vertex = File::Stat.new(path)
25
+ # loader = lambda do |g, path:, parent:, lstat:, **|
26
+ # vertex = kwargs[:lstat]
21
27
  # g.add_vertex(vertex, name: path)
22
28
  # g.add_edge(g[parent], vertex) unless parent.nil?
23
29
  # end
@@ -38,17 +44,28 @@ module Tangle
38
44
  end
39
45
 
40
46
  def load_directory_graph(path, parent = nil)
41
- @directory_loaders.any? do |loader|
42
- loader.to_proc.call(self, path, parent)
43
- end
44
-
45
- return if File.symlink?(path) && !@follow_directory_links
46
- return unless File.directory?(path)
47
+ return unless load_directory_object(path, parent)
47
48
 
48
49
  Dir.each_child(path) do |file|
49
50
  load_directory_graph(File.join(path, file), path)
50
51
  end
51
52
  end
53
+
54
+ # Load a filesystem object into the graph, returning
55
+ # +true+ if the object was a directory (or link to one,
56
+ # and we're following links).
57
+ def load_directory_object(path, parent = nil)
58
+ stat = lstat = File.lstat(path)
59
+ stat = File.stat(path) if lstat.symlink?
60
+
61
+ @directory_loaders.any? do |loader|
62
+ loader.to_proc.call(self, path: path, parent: parent,
63
+ lstat: lstat, stat: stat)
64
+ end
65
+
66
+ return if lstat.symlink? && !@follow_directory_links
67
+ stat.directory?
68
+ end
52
69
  end
53
70
  end
54
71
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tangle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Calle Englund
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-05-15 00:00:00.000000000 Z
11
+ date: 2018-05-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: git-version-bump