tangle 0.8.2 → 0.11.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: 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]