tangle 0.8.2 → 0.11.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ee56b345a6f81de14bbc7bb9d16fbb10f9e2174b2588140a6881bd1ff31d0d5
4
- data.tar.gz: 2172244bbb6ab3a91dff9fb4e6491fadc1f56762d984edf75c7f325b1ce9bed5
3
+ metadata.gz: be7e93897d5dcfbe1b739f977740f46d2bef0a050503244e1204f9bb2a387bac
4
+ data.tar.gz: ca037f66996798b77e0fdd2b2c734a880ce5f495caac85cd84a49748daa04547
5
5
  SHA512:
6
- metadata.gz: 7bb4eeacbdf97538cef1a19738ac0260e47b56a19a6854d2de4dd735203001f7000f09239fbd3d6dcce377d8acf24a3b9647f1ddbbb2c152129b16e78de5fb16
7
- data.tar.gz: 71837d3d43769c939200f450fb823ce6e82aec754527989e93ffac3db58eac2a8a99c816c9afc648dbbf97bf101b63e78656af86e487f6d3568f40333e2fa078
6
+ metadata.gz: 2f94196947e837391f4c09b194f7d2d07e76ce7bc0215faad944eecf3c75109840f309e4b07ddd976b9466f382f7c8c0a0caffde4b68fa09c4d6fea32eb10669
7
+ data.tar.gz: 464b75f77486d466c0621bd272fdab22db7047ee58648e8af98799dfc0c1ff2da64534304c55c1bc41b7db67052801aa9ac41ec53d9b352e3d93cbae9499d958
@@ -0,0 +1,37 @@
1
+ %YAML 1.1
2
+ ---
3
+ # This workflow uses actions that are not certified by GitHub.
4
+ # They are provided by a third-party and are governed by
5
+ # separate terms of service, privacy policy, and support
6
+ # documentation.
7
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
8
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
9
+
10
+ name: Ruby
11
+
12
+ on:
13
+ push:
14
+ pull_request:
15
+ branches: [ main ]
16
+
17
+ jobs:
18
+ test:
19
+
20
+ runs-on: ubuntu-latest
21
+ strategy:
22
+ matrix:
23
+ ruby-version: ['2.6', '2.7', '3.0']
24
+
25
+ steps:
26
+ - uses: actions/checkout@v2
27
+ - name: Set up Ruby
28
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
29
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
30
+ # uses: ruby/setup-ruby@v1
31
+ uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
32
+ with:
33
+ ruby-version: ${{ matrix.ruby-version }}
34
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
35
+ - name: Run tests
36
+ run: bundle exec rake
37
+ ...
data/.gitignore CHANGED
@@ -11,3 +11,4 @@
11
11
  .rspec_status
12
12
  /Gemfile.lock
13
13
  /vendor
14
+ coverage
data/.rubocop.yml CHANGED
@@ -1,3 +1,9 @@
1
+ %YAML 1.1
2
+ ---
3
+ AllCops:
4
+ TargetRubyVersion: 2.6
5
+ NewCops: enable
6
+
1
7
  Metrics/BlockLength:
2
8
  Exclude:
3
9
  - 'spec/*_spec.rb'
@@ -6,7 +12,12 @@ Style/BlockDelimiters:
6
12
  Exclude:
7
13
  - 'spec/*_spec.rb'
8
14
 
9
- # Rubocop 0.56 causes false positives
10
- # https://github.com/bbatsov/rubocop/issues/5887
11
- Lint/SplatKeywordArguments:
12
- Enabled: false
15
+ Style/HashEachMethods:
16
+ Enabled: true
17
+
18
+ Style/HashTransformKeys:
19
+ Enabled: true
20
+
21
+ Style/HashTransformValues:
22
+ Enabled: true
23
+ ...
data/CHANGELOG.md ADDED
@@ -0,0 +1,45 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+
10
+ ## [0.11.0] - 2021-05-30
11
+
12
+ This release updates dependencies, changes the minimum Ruby version to 2.6, and adds support for Ruby version 3.
13
+
14
+ ### Added
15
+
16
+ - Ruby version 3 is now supported, and mixin initializers should not rely on keyword splat semantics for a `Hash` argument.
17
+
18
+ ### Changed
19
+
20
+ - The minimum required Ruby version is now 2.6.
21
+
22
+ - Dependencies have been updated.
23
+
24
+
25
+ ## [0.10.2] - 2019-07-05
26
+
27
+ ### Changed
28
+
29
+ - `Currify::currify`now raises a `CurrifyError` < `ArgumentError` when the method takes no arguments, instead of the curried method failing when called
30
+
31
+ - Development dependency on `bundler` is updated to `~> 2.0`.
32
+
33
+ ### Fixed
34
+
35
+ - `Graph#connected_subgraph` and `Graph#disconnected_subgraph` called an invalid method to determine connectedness of candidate vertices
36
+
37
+
38
+ ## [Older]
39
+ These releases have no change logs.
40
+
41
+
42
+ [Unreleased]: https://github.com/notCalle/ruby-tangle/compare/v0.11.0..HEAD
43
+ [0.11.0]: https://github.com/notCalle/ruby-tangle/compare/v0.10.2..v0.11.0
44
+ [0.10.2]: https://github.com/notCalle/ruby-tangle/compare/v0.10.1..v0.10.2
45
+ [Older]: https://github.com/notCalle/ruby-tangle/releases/tag/v0.10.1
data/Gemfile CHANGED
@@ -1,12 +1,6 @@
1
- source 'https://rubygems.org'
1
+ # frozen_string_literal: true
2
2
 
3
- git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
3
+ source 'https://rubygems.org'
4
4
 
5
- begin
6
- require 'git-version-bump'
7
- rescue LoadError
8
- gem 'git-version-bump', '~> 0.15'
9
- else
10
- # Specify your gem's dependencies in tangle.gemspec
11
- gemspec
12
- end
5
+ # Specify your gem's dependencies in tangle.gemspec
6
+ gemspec
data/README.md CHANGED
@@ -1,4 +1,7 @@
1
- [![Gem Version](https://badge.fury.io/rb/tangle.svg)](https://badge.fury.io/rb/tangle) [![Maintainability](https://api.codeclimate.com/v1/badges/0d92a4d05b6bb5c06dce/maintainability)](https://codeclimate.com/github/notCalle/ruby-tangle/maintainability)
1
+ [![Gem Version](https://badge.fury.io/rb/tangle.svg)](https://badge.fury.io/rb/tangle)
2
+ [![Maintainability](https://api.codeclimate.com/v1/badges/0d92a4d05b6bb5c06dce/maintainability)](https://codeclimate.com/github/notCalle/ruby-tangle/maintainability)
3
+ [![codecov](https://codecov.io/gh/notCalle/ruby-tangle/branch/master/graph/badge.svg)](https://codecov.io/gh/notCalle/ruby-tangle)
4
+ [![Ruby](https://github.com/notCalle/ruby-tangle/actions/workflows/ruby.yml/badge.svg)](https://github.com/notCalle/ruby-tangle/actions/workflows/ruby.yml)
2
5
 
3
6
  # Tangle
4
7
 
@@ -12,10 +15,12 @@ Tangle aims to untangle your graphs, by providing a set of classes for managing
12
15
  * ~~Tree~~
13
16
 
14
17
  **Feature mixins**:
15
- * Connectedness
18
+ * Filesystem directory graph
16
19
  * ~~Coloring~~
17
20
  * ~~GraphViz~~
18
21
 
22
+ See the [changelog](CHANGELOG.md) for recent changes.
23
+
19
24
  ## Installation
20
25
 
21
26
  Add this line to your application's Gemfile:
@@ -81,7 +86,7 @@ Tangle::Graph.new(mixins: [WeightedEdges])
81
86
 
82
87
  ## Contributing
83
88
 
84
- Bug reports and pull requests are welcome on GitHub at https://github.com/notCalle/tangle. Pull requests should be rebased to HEAD of `master` before submitting, and all commits must be signed with valid GPG key. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
89
+ Bug reports and pull requests are welcome on GitHub at https://github.com/notCalle/tangle. Pull requests should be rebased to HEAD of `main` before submitting, and all commits must be signed with valid GPG key. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
85
90
 
86
91
  ## License
87
92
 
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/setup'
2
4
  require 'bundler/gem_tasks'
3
5
 
@@ -20,7 +22,7 @@ task :check_version do
20
22
  raise 'Internal revision!' unless GVB.internal_revision.empty?
21
23
  end
22
24
 
23
- task test: %i[spec rubocop]
25
+ task test: %i[rubocop spec]
24
26
  task build: %i[spec]
25
27
  task release: %i[rubocop check_version]
26
28
  task default: %i[test]
data/bin/console CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'bundler/setup'
4
5
  require 'tangle'
@@ -7,8 +8,8 @@ require 'tangle'
7
8
  # with your gem easier. You can also use a different console, if you like.
8
9
 
9
10
  # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require 'pry'
11
- # Pry.start
11
+ require 'pry'
12
+ Pry.start
12
13
 
13
- require 'irb'
14
- IRB.start(__FILE__)
14
+ # require 'irb'
15
+ # IRB.start(__FILE__)
data/bin/setup CHANGED
@@ -4,6 +4,5 @@ IFS=$'\n\t'
4
4
  set -vx
5
5
 
6
6
  bundle install
7
- bundle update
8
7
 
9
8
  # Do any other automated setup that you need to do here
data/lib/tangle.rb CHANGED
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'tangle/version'
2
4
  require 'tangle/errors'
3
- require 'tangle/graph'
4
- require 'tangle/simple/graph'
5
+ require 'tangle/undirected/graph'
6
+ require 'tangle/undirected/simple/graph'
5
7
  require 'tangle/directed/graph'
6
8
  require 'tangle/directed/acyclic/graph'
7
9
 
@@ -20,8 +22,9 @@ require 'tangle/directed/acyclic/graph'
20
22
  # => Directed graph with no edge cycles
21
23
  #
22
24
  module Tangle
23
- MultiGraph = Tangle::Graph
24
- SimpleGraph = Tangle::Simple::Graph
25
+ Graph = Tangle::Undirected::Graph
26
+ MultiGraph = Tangle::Undirected::Graph
27
+ SimpleGraph = Tangle::Undirected::Simple::Graph
25
28
  DiGraph = Tangle::Directed::Graph
26
29
  DAG = Tangle::Directed::Acyclic::Graph
27
30
  end
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'currify'
4
+ require_relative 'mixin'
5
+ require_relative 'base_graph_protected'
6
+ require_relative 'base_graph_private'
7
+
8
+ module Tangle
9
+ #
10
+ # Abstract base class for (un)directed graphs
11
+ #
12
+ class BaseGraph
13
+ include Tangle::Currify
14
+ include Tangle::Mixin::Initialize
15
+ include Tangle::BaseGraphProtected
16
+ include Tangle::BaseGraphPrivate
17
+
18
+ # Initialize a new graph, preloading it with vertices and edges
19
+ #
20
+ # Graph[+vertices+] => Graph
21
+ # Graph[+vertices+, +edges+) => Graph
22
+ #
23
+ # When +vertices+ is a hash, it contains initialization kwargs as
24
+ # values and vertex names as keys. When +vertices+ is an array of
25
+ # initialization kwargs, the vertices will be be anonymous.
26
+ #
27
+ # +edges+ can contain an array of exactly two, either names of vertices
28
+ # or vertices.
29
+ #
30
+ # Any kwarg supported by Graph.new is also allowed.
31
+ #
32
+ def self.[](vertices, edges = {}, **kwargs)
33
+ graph = new(**kwargs)
34
+ vertices.each { |vertex| graph.add_vertex(vertex) }
35
+ edges.each { |from, to| graph.add_edge(from, to) }
36
+ graph
37
+ end
38
+
39
+ # Initialize a new graph, optionally preloading it with vertices and edges
40
+ #
41
+ # Graph.new() => Graph
42
+ # Graph.new(mixins: [MixinModule, ...], ...) => Graph
43
+ #
44
+ # +mixins+ is an array of modules that can be mixed into the various
45
+ # classes that makes up a graph. Initialization of a Graph, Vertex or Edge
46
+ # looks for submodules in each mixin, with the same name and extends
47
+ # any created object. Defaults to [Tangle::Mixin::Connectedness].
48
+ #
49
+ # Any subclass of Graph should also subclass Edge to manage its unique
50
+ # constraints.
51
+ #
52
+ def initialize(currify: false, mixins: [], **kwargs)
53
+ @currify = currify
54
+ initialize_vertices
55
+ initialize_edges
56
+ initialize_mixins(mixins: mixins, **kwargs)
57
+ end
58
+
59
+ # Return a subgraph, optionally filtered by a vertex selector block
60
+ #
61
+ # subgraph => Graph
62
+ # subgraph { |vertex| ... } => Graph
63
+ #
64
+ # Unless a selector is provided, the subgraph contains the entire graph.
65
+ #
66
+ def subgraph(included = nil, &selector)
67
+ result = clone
68
+ result.select_vertices!(included) unless included.nil?
69
+ result.select_vertices!(&selector) if block_given?
70
+ result
71
+ end
72
+
73
+ def clone
74
+ result = super
75
+ result.copy_vertices_and_edges(self)
76
+ result
77
+ end
78
+
79
+ def to_s
80
+ "#<#{self.class}: #{vertices.count} vertices, #{edges.count} edges>"
81
+ end
82
+ alias inspect to_s
83
+
84
+ # Fetch a vertex by its name
85
+ def fetch(name)
86
+ @vertices_by_name.fetch(name)
87
+ end
88
+
89
+ # Return a named vertex
90
+ def [](name)
91
+ @vertices_by_name[name]
92
+ end
93
+
94
+ # Return all vertices in the graph
95
+ def vertices
96
+ @vertices.keys
97
+ end
98
+
99
+ # Select vertices in the graph
100
+ def select(&selector)
101
+ @vertices.each_key.select(&selector)
102
+ end
103
+
104
+ # Add a vertex into the graph
105
+ #
106
+ # If a name: is given, or the vertex responds to :name,
107
+ # it will be registered by name in the graph
108
+ def add_vertex(vertex, name: nil)
109
+ name ||= callback(vertex, :name)
110
+ insert_vertex(vertex, name)
111
+ define_currified_methods(vertex, :vertex) if @currify
112
+ callback(vertex, :added_to_graph, self)
113
+ self
114
+ end
115
+ alias << add_vertex
116
+
117
+ # Remove a vertex from the graph
118
+ def remove_vertex(vertex)
119
+ @vertices[vertex].each do |edge|
120
+ remove_edge(edge) if edge.include?(vertex)
121
+ end
122
+ delete_vertex(vertex)
123
+ callback(vertex, :removed_from_graph, self)
124
+ end
125
+
126
+ # Get all edges.
127
+ #
128
+ # edges => Array
129
+ #
130
+ def edges(vertex = nil)
131
+ return @edges if vertex.nil?
132
+
133
+ @vertices.fetch(vertex)
134
+ end
135
+ currify :vertex, :edges
136
+
137
+ # Add a new edge to the graph
138
+ #
139
+ # add_edge(vtx1, vtx2, ...) => Edge
140
+ #
141
+ def add_edge(*vertices, **kvargs)
142
+ edge = new_edge(*vertices, mixins: @mixins, **kvargs)
143
+ insert_edge(edge)
144
+ vertices.each { |vertex| callback(vertex, :edge_added, edge) }
145
+ edge
146
+ end
147
+
148
+ # Remove an edge from the graph
149
+ def remove_edge(edge)
150
+ delete_edge(edge)
151
+ edge.each_vertex { |vertex| callback(vertex, :edge_removed, edge) }
152
+ end
153
+ end
154
+ end
@@ -1,49 +1,26 @@
1
- require 'set'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Tangle
4
- # Vertex related methods in a graph
5
- module GraphVertices
6
- # Fetch a vertex by its name
7
- def fetch(name)
8
- @vertices_by_name.fetch(name)
9
- end
10
-
11
- # Return a named vertex
12
- def [](name)
13
- @vertices_by_name[name]
14
- end
15
-
16
- # Return all vertices in the graph
17
- def vertices
18
- @vertices.keys
19
- end
20
-
21
- # Add a vertex into the graph
22
- #
23
- # If a name: is given, it will be registered by name
24
- def add_vertex(vertex, name: nil)
25
- @vertices[vertex] = Set[]
26
- @vertices_by_name[name] = vertex unless name.nil?
27
- self
28
- end
29
- alias << add_vertex
4
+ #
5
+ # Private methods of BaseGraph
6
+ #
7
+ module BaseGraphPrivate
8
+ private
30
9
 
31
- # Remove a vertex from the graph
32
- def remove_vertex(vertex)
33
- @vertices[vertex].each do |edge|
34
- remove_edge(edge) if edge.include?(vertex)
35
- end
36
- @vertices.delete(vertex)
10
+ def callback(receiver, method, *args)
11
+ receiver.send(method, *args) if receiver.respond_to?(method)
37
12
  end
38
13
 
39
- private
40
-
41
14
  # Initialize vertex related attributes
42
15
  def initialize_vertices
43
16
  @vertices = {}
44
17
  @vertices_by_name = {}
45
18
  end
46
19
 
20
+ def initialize_edges
21
+ @edges = Set[]
22
+ end
23
+
47
24
  # Yield each reachable vertex to a block, breadth first
48
25
  def each_vertex_breadth_first(start_vertex, walk_method)
49
26
  remaining = [start_vertex]