diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml
index 6e63b88..a5e52a4 100644
--- a/.github/workflows/ruby.yml
+++ b/.github/workflows/ruby.yml
@@ -7,7 +7,7 @@
#
# Created: 15th August 2026
-# Updated: 15th August 2026
+# Updated: 19th August 2026
#
name: Ruby
@@ -70,13 +70,20 @@ jobs:
uses: actions/checkout@v4
- name: Remove Gemfile.lock
+ shell: bash
run: rm -f Gemfile.lock
- name: Set up Ruby v${{ matrix.ruby-version }}
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
- bundler-cache: true # runs 'bundle install' and caches installed gems automatically
+ # Bundler 4 honours Gemfile `lockfile false`, so no Gemfile.lock
+ # is written. bundler-cache cats that file after `bundle lock`
+ # and fails on Windows 3.2+ (setup-ruby installs Bundler ~> 4).
+ bundler-cache: false
+
+ - name: Install gems
+ run: bundle install
- name: Show Ruby version
run: ruby -v
@@ -87,7 +94,7 @@ jobs:
- name: Gem build and install smoke
shell: bash
run: |
- gem build cmpfs.gemspec
+ gem build cmpfs-ruby.gemspec
gem install --local cmpfs-ruby-*.gem
ruby -e "require 'cmpfs/version'; abort('VERSION missing') unless defined?(CmpFS::VERSION); puts CmpFS::VERSION"
@@ -102,13 +109,17 @@ jobs:
uses: actions/checkout@v4
- name: Remove Gemfile.lock
+ shell: bash
run: rm -f Gemfile.lock
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
- ruby-version: '3.3'
- bundler-cache: true
+ ruby-version: '3.4'
+ bundler-cache: false
+
+ - name: Install gems
+ run: bundle install
- name: Show Ruby version
run: ruby -v
diff --git a/.gitignore b/.gitignore
index 0d510c3..14b3203 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,10 +2,13 @@
/.bzr/
/.bundle/
+/.bzr/
/.config/
/.svn/
+/.vscode/
/.yardoc/
+/_build/
/_yardoc/
/InstalledFiles/
@@ -23,8 +26,10 @@
/tmp/
/vendor/bundle/
+
# directories (by pattern)
+
# files (by name)
.DS_Store
@@ -32,8 +37,11 @@
.ruby-version
.rvmrc
+Gemfile.lock
+
/spec/examples.txt
+
# files (by pattern)
*~
diff --git a/CHANGES.md b/CHANGES.md
index 457beeb..66909b9 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,6 +1,18 @@
# cmpfs.Ruby - Changes
+## 0.2.5 - 19th August 2026
+
+* renamed **cmpfs.gemspec** to **cmpfs-ruby.gemspec** so the filename stem matches `spec.name`;
+* **cmpfs-ruby.gemspec**: `spec.summary` matches the README tagline; packaged **AUTHORS**, **CHANGES**, **CONTRIBUTING**, **EXAMPLES**, **FAQ**, **INSTALL**, **NEWS**, **SECURITY**, and **TODO**; **Gemfile.lock** and **.ruby-version** excluded from `spec.files`;
+* stop tracking **Gemfile.lock**; **Gemfile** sets `lockfile false` when Bundler supports it; CI uses `bundler-cache: false` because Bundler 4 then writes no lockfile and **ruby/setup-ruby** cache cats **Gemfile.lock**;
+* CI **Warnings** job now runs on Ruby **3.4**; `gem build cmpfs-ruby.gemspec`;
+* updated **run_all_unit_tests.sh** (from https://github.com/synesissoftware/misc-dev-scripts) to skip **tput** when **$TERM** is unset or stdout is not a TTY;
+* reordered **README.md** (tagline before badges; TOC after badges), added Language / License / Last Commit badges and **Dependencies** (Efferent / Afferent);
+* **EXAMPLES.md** example links are repo-relative (`./examples/…`);
+* library source **Home:** URLs now use `https`;
+
+
## 0.2.4 - 15th August 2026
* added `# frozen_string_literal: true` to all **lib/** sources;
diff --git a/EXAMPLES.md b/EXAMPLES.md
index e4f3fdb..0696942 100644
--- a/EXAMPLES.md
+++ b/EXAMPLES.md
@@ -1,9 +1,9 @@
# cmpfs.Ruby - Examples
-| Name | Source & Description | Summary |
-| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
-| **compare_two_binary_files** | [examples/compare_two_binary_files.rb](/examples/compare_two_binary_files.rb)
[examples/compare_two_binary_files.md](/examples/compare_two_binary_files.md) | Compares two files for binary equality via `compare_binary` |
-| **compare_two_text_files** | [examples/compare_two_text_files.rb](/examples/compare_two_text_files.rb)
[examples/compare_two_text_files.md](/examples/compare_two_text_files.md) | Compares two files for text equality via `compare_text` (skip blank lines; trim) |
+|Name|Source & Description|Summary|
+|---|---|---|
+|**compare_two_binary_files**|[examples/compare_two_binary_files.rb](./examples/compare_two_binary_files.rb)
[examples/compare_two_binary_files.md](./examples/compare_two_binary_files.md)|Compares two files for binary equality via `compare_binary`|
+|**compare_two_text_files**|[examples/compare_two_text_files.rb](./examples/compare_two_text_files.rb)
[examples/compare_two_text_files.md](./examples/compare_two_text_files.md)|Compares two files for text equality via `compare_text` (skip blank lines; trim)|
diff --git a/Gemfile b/Gemfile
index 29f6d2e..79965e8 100644
--- a/Gemfile
+++ b/Gemfile
@@ -2,6 +2,13 @@
source "https://rubygems.org"
+# Suppress lockfile on Bundler 4+ (gem: do not pin the graph). No-op on
+# Bundler that lacks the DSL (Ruby 2.x CI). Do not combine with
+# ruby/setup-ruby `bundler-cache: true` — that action cats Gemfile.lock
+# after `bundle lock` and fails when no file is written (Windows 3.2+,
+# where setup-ruby installs Bundler ~> 4).
+lockfile false if respond_to?(:lockfile)
+
gemspec
# rake 13 requires Ruby >= 2.3
diff --git a/Gemfile.lock b/Gemfile.lock
deleted file mode 100644
index 8d6765f..0000000
--- a/Gemfile.lock
+++ /dev/null
@@ -1,20 +0,0 @@
-PATH
- remote: .
- specs:
- cmpfs-ruby (0.2.3)
-
-GEM
- remote: https://rubygems.org/
- specs:
- xqsr3 (0.39.5)
-
-PLATFORMS
- arm64-darwin-25
- ruby
-
-DEPENDENCIES
- cmpfs-ruby!
- xqsr3 (~> 0.39, >= 0.39.1)
-
-BUNDLED WITH
- 2.6.9
diff --git a/NEWS.md b/NEWS.md
index af22b41..a1998bc 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,7 @@
| Date | News Item |
| ---------------- | ---------------------------------------------------------------------------------------- |
+| 19th August 2026 | [**cmpfs.Ruby** 0.2.5](https://github.com/synesissoftware/cmpfs.Ruby/releases/tag/0.2.5) |
| 15th August 2026 | [**cmpfs.Ruby** 0.2.4](https://github.com/synesissoftware/cmpfs.Ruby/releases/tag/0.2.4) |
| 4th April 2024 | [**cmpfs.Ruby** 0.2.3](https://github.com/synesissoftware/cmpfs.Ruby/releases/tag/0.2.3) |
| 4th April 2024 | **cmpfs.Ruby** 0.2.2.1 released |
diff --git a/README.md b/README.md
index 4fe1341..21abef8 100644
--- a/README.md
+++ b/README.md
@@ -2,15 +2,13 @@
**Com**pare **F**ile-**S**ystem entities, for **Ruby**
+
+[](https://opensource.org/licenses/BSD-3-Clause)
[](https://badge.fury.io/rb/cmpfs-ruby)
+[](https://github.com/synesissoftware/cmpfs.Ruby/commits/master)
[](https://github.com/synesissoftware/cmpfs.Ruby/actions/workflows/ruby.yml)
-## Introduction
-
-Provides platform-independent facilities for comparing file contents, for both binary and text files
-
-
## Table of Contents
- [Introduction](#introduction)
@@ -21,13 +19,38 @@ Provides platform-independent facilities for comparing file contents, for both b
- [Where to get help](#where-to-get-help)
- [Contribution guidelines](#contribution-guidelines)
- [Dependencies](#dependencies)
+ - [Efferent (fan-out)](#efferent-fan-out)
+ - [Runtime Dependencies (aka "Normal Dependencies")](#runtime-dependencies-aka-normal-dependencies)
+ - [Development Dependencies](#development-dependencies)
+ - [Afferent (fan-in)](#afferent-fan-in)
+ - [Runtime dependents](#runtime-dependents)
+ - [Development dependents](#development-dependents)
- [Related projects](#related-projects)
- [License](#license)
+## Introduction
+
+**cmpfs.Ruby** provides platform-independent facilities for comparing file contents, for both binary and text files.
+
+It has **no dependencies** on any other non-standard library.
+
+
## Installation
-Install using `gem install cmpfs-ruby` or add it to your `Gemfile`.
+Install via **gem** as in:
+
+```
+gem install cmpfs-ruby
+```
+
+or add it to your `Gemfile`.
+
+Use via **require**, as in:
+
+```Ruby
+require 'cmpfs'
+```
## Components
@@ -46,6 +69,8 @@ all of which are obtained when `extend`ing or `include`ing the `CmpFS` module.
## Examples
+Examples are provided in the ```examples``` directory, along with a markdown description for each. A detailed list TOC of them is provided in [EXAMPLES.md](./EXAMPLES.md).
+
**examples/compare_two_binary_files.rb**:
```Ruby
#! /usr/bin/env ruby
@@ -143,6 +168,7 @@ $stdout.puts "files are #{compare_text(lhs_path, rhs_path, skip_blank_lines: tru
## Project Information
+
### Where to get help
[GitHub Page](https://github.com/synesissoftware/cmpfs.Ruby "GitHub Page")
@@ -156,6 +182,38 @@ Defect reports, feature requests, and pull requests are welcome on https://githu
### Dependencies
+#### Efferent (fan-out)
+
+Libraries upon which **cmpfs.Ruby** depends:
+
+
+##### Runtime Dependencies (aka "Normal Dependencies")
+
+* \;
+
+
+##### Development Dependencies
+
+* [**rake**](https://rubygems.org/gems/rake);
+* [**test-unit**](https://rubygems.org/gems/test-unit);
+* [**xqsr3**](https://github.com/synesissoftware/xqsr3);
+
+
+#### Afferent (fan-in)
+
+Projects that depend on **cmpfs.Ruby**:
+
+
+##### Runtime dependents
+
+* \;
+
+
+##### Development dependents
+
+* \;
+
+
### Related projects
* C/C++ **cmpfs** — same product idea (binary/text file and stream comparison); recovery into freelibs is planned beside this gem (not yet published as a sibling tree here);
@@ -167,4 +225,3 @@ Defect reports, feature requests, and pull requests are welcome on https://githu
-
diff --git a/TODO.md b/TODO.md
index 94d7dbe..c90fa18 100644
--- a/TODO.md
+++ b/TODO.md
@@ -3,7 +3,8 @@
## Functional improvements
-* \
+* [ ] quiet assigned-but-unused variable warnings in **lib/cmpfs/compare/text/internal_.rb** (`lhs_ix`, `rhs_ix`, `lhs_nr`, `rhs_nr`; Ruby 3.4 `-W` / CI **Warnings** job);
+* [ ] quiet the ambiguous `/` regexp warning in **test/unit/tc_version.rb** (Ruby 3.4 `-W` / CI **Warnings** job);
## Performance improvements
@@ -13,7 +14,11 @@
## Packaging improvements
-* [ ] Rename gemspec so the filename stem matches `spec.name` (`cmpfs.gemspec` → **cmpfs-ruby.gemspec**);
+* [x] ~~~updated **run_all_unit_tests.sh** (from **misc-dev-scripts**) to skip `tput` when `$TERM` is unset or stdout is not a TTY~~~;
+* [x] ~~~**Gemfile** `lockfile false`; stop tracking **Gemfile.lock**; CI `bundler-cache: false`~~~;
+* [x] ~~~gemspec polish: README tagline as `spec.summary`, package docs, exclude **Gemfile.lock** / **.ruby-version**; renamed **cmpfs.gemspec** → **cmpfs-ruby.gemspec**~~~;
+* [x] ~~~README canonical structure (tagline before badges; **Dependencies**; CI badge → **ruby.yml**)~~~;
+* [x] ~~~after the packaging/boilerplate/CI baseline: bump **VERSION** and align **CHANGES**/**NEWS**~~~;
diff --git a/cmpfs.gemspec b/cmpfs-ruby.gemspec
similarity index 70%
rename from cmpfs.gemspec
rename to cmpfs-ruby.gemspec
index 5f3b3bc..6dd0a07 100644
--- a/cmpfs.gemspec
+++ b/cmpfs-ruby.gemspec
@@ -1,12 +1,12 @@
-# ######################################################################### #
-# File: cmpfs.gemspec
+# ######################################################################## #
+# File: cmpfs-ruby.gemspec
#
# Purpose: Gemspec for cmpfs.Ruby library
#
# Created: 1st March 2019
-# Updated: 15th August 2026
+# Updated: 19th August 2026
#
-# ######################################################################### #
+# ######################################################################## #
$:.unshift File.join(File.dirname(__FILE__), 'lib')
@@ -17,8 +17,8 @@ require 'cmpfs/version'
Gem::Specification.new do |spec|
spec.name = 'cmpfs-ruby'
+ spec.summary = 'Compare File-System entities, for Ruby'
spec.version = CmpFS::VERSION
- spec.summary = 'CmpFS.Ruby'
spec.description = <= 1.9.3' ]
@@ -44,7 +43,27 @@ END_DESC
'source_code_uri' => 'https://github.com/synesissoftware/cmpfs.Ruby',
}
- spec.add_development_dependency "xqsr3", [ '>= 0.39.5', '< 1.0' ]
+ spec.files = Dir[
+ 'Rakefile',
+ '{bin,examples,lib,man,spec,test}/**/*',
+ 'AUTHORS*',
+ 'CHANGES*',
+ 'CONTRIBUTING*',
+ 'EXAMPLES*',
+ 'FAQ*',
+ 'INSTALL*',
+ 'LICENSE*',
+ 'NEWS*',
+ 'README*',
+ 'SECURITY*',
+ 'TODO*',
+ ] & `git ls-files -z`.split("\0")
+ spec.files -= [
+ '.ruby-version',
+ 'Gemfile.lock',
+ ]
+
+ spec.add_development_dependency 'xqsr3', [ '>= 0.39.5', '< 1.0' ]
end
diff --git a/lib/cmpfs.rb b/lib/cmpfs.rb
index 83b0648..68c6f36 100644
--- a/lib/cmpfs.rb
+++ b/lib/cmpfs.rb
@@ -5,9 +5,9 @@
# Purpose: Primary require for cmpfs.Ruby library
#
# Created: 1st March 2019
-# Updated: 15th August 2026
+# Updated: 19th August 2026
#
-# Home: http://github.com/synesissoftware/cmpfs.Ruby
+# Home: https://github.com/synesissoftware/cmpfs.Ruby
#
# Author: Matthew Wilson
#
diff --git a/lib/cmpfs/compare.rb b/lib/cmpfs/compare.rb
index b41b3f7..13ae5d2 100644
--- a/lib/cmpfs/compare.rb
+++ b/lib/cmpfs/compare.rb
@@ -5,9 +5,9 @@
# Purpose: Version for cmpfs.Ruby library
#
# Created: 1st March 2019
-# Updated: 15th August 2026
+# Updated: 19th August 2026
#
-# Home: http://github.com/synesissoftware/cmpfs.Ruby
+# Home: https://github.com/synesissoftware/cmpfs.Ruby
#
# Author: Matthew Wilson
#
diff --git a/lib/cmpfs/version.rb b/lib/cmpfs/version.rb
index ee6f778..e62913c 100644
--- a/lib/cmpfs/version.rb
+++ b/lib/cmpfs/version.rb
@@ -5,9 +5,9 @@
# Purpose: Version for cmpfs.Ruby library
#
# Created: 1st March 2019
-# Updated: 15th August 2026
+# Updated: 19th August 2026
#
-# Home: http://github.com/synesissoftware/cmpfs.Ruby
+# Home: https://github.com/synesissoftware/cmpfs.Ruby
#
# Author: Matthew Wilson
#
@@ -51,7 +51,7 @@
module CmpFS
# Current version of the cmpfs.Ruby library
- VERSION = '0.2.4'
+ VERSION = '0.2.5'
private
VERSION_PARTS_ = VERSION.split(/[.]/).collect { |n| n.to_i } # :nodoc:
diff --git a/run_all_unit_tests.sh b/run_all_unit_tests.sh
index 6aea55b..0a05634 100755
--- a/run_all_unit_tests.sh
+++ b/run_all_unit_tests.sh
@@ -8,7 +8,7 @@
# executing each rbenv version
#
# Created: 9th June 2011
-# Updated: 12th August 2026
+# Updated: 19th August 2026
#
# Copyright (c) Matthew Wilson, 2011-2026
# All rights reserved
@@ -58,18 +58,20 @@ Basename="$(basename "$Source")"
# colours
-if command -v tput > /dev/null; then
+SisClr_Blue=${FG_BLUE:-}
+SisClr_Red=${FG_RED:-}
+SisClr_Bold=${FD_BOLD:-}
+SisClr_None=${FD_NONE:-}
- SisClr_Blue=${FG_BLUE:-$(tput setaf 4)}
- SisClr_Red=${FG_RED:-$(tput setaf 1)}
- SisClr_Bold=${FD_BOLD:-$(tput bold)}
- SisClr_None=${FD_NONE:-$(tput sgr0)}
-else
+if [ -n "${TERM:-}" ] && [ -t 1 ] && command -v tput >/dev/null 2>&1; then
+
+ if tput sgr0 >/dev/null 2>&1; then
- SisClr_Blue=
- SisClr_Red=
- SisClr_Bold=
- SisClr_None=
+ SisClr_Blue=${FG_BLUE:-$(tput setaf 4)}
+ SisClr_Red=${FG_RED:-$(tput setaf 1)}
+ SisClr_Bold=${FD_BOLD:-$(tput bold)}
+ SisClr_None=${FD_NONE:-$(tput sgr0)}
+ fi
fi
@@ -115,19 +117,19 @@ if [ ! -z "$RunRbEnvAllVersions" ]; then
if ! command -v rbenv > /dev/null; then
- >&2 echo "$0: ${SisClr_Red}${SisClr_Bold}rbenv${SisClr_None} not detected"
+ >&2 echo "$0: ${SisClr_Red}${SisClr_Bold}rbenv${SisClr_None} not detected"
- exit 1
+ exit 1
fi
exclusions=()
if [ -e "$ProjectDir/.ruby-version-exclusions" ]; then
- exclusion_lines=`cat "$ProjectDir/.ruby-version-exclusions"`
- for line in $exclusion_lines; do
+ exclusion_lines=`cat "$ProjectDir/.ruby-version-exclusions"`
+ for line in $exclusion_lines; do
- exclusions+=("$line")
- done
+ exclusions+=("$line")
+ done
fi
echo "executing command line '${SisClr_Blue}${SisClr_Bold}$0 ${ForwardArgs[*]}${SisClr_None}' with all Ruby versions ..."
@@ -138,11 +140,20 @@ if [ ! -z "$RunRbEnvAllVersions" ]; then
current=$(tr -d '[:space:]' < "$ProjectDir/.ruby-version")
fi
+ if ! version_output=$(rbenv versions --bare); then
+
+ >&2 echo "$0: ${SisClr_Red}${SisClr_Bold}failed to enumerate Ruby versions via rbenv${SisClr_None}"
+ exit 1
+ fi
+
versions=()
- while IFS= read -r line; do
+ if [ -n "$version_output" ]; then
- versions+=("$line")
- done < <(rbenv versions --bare)
+ while IFS= read -r line; do
+
+ versions+=("$line")
+ done <<< "$version_output"
+ fi
echo "versions: ${SisClr_Blue}${SisClr_Bold}${versions[*]}${SisClr_None}; skipped versions: ${SisClr_Blue}${SisClr_Bold}${exclusions[*]}${SisClr_None}; current version: ${SisClr_Blue}${SisClr_Bold}${current:-(none)}${SisClr_None}"
@@ -151,32 +162,32 @@ if [ ! -z "$RunRbEnvAllVersions" ]; then
for version in "${versions[@]}"
do
- echo
+ echo
- skip=
+ skip=
- for exclusion in "${exclusions[@]}"; do
+ for exclusion in "${exclusions[@]}"; do
- if [[ "$exclusion" == "$version" ]]; then
+ if [[ "$exclusion" == "$version" ]]; then
- skip=1
- fi
- done
+ skip=1
+ fi
+ done
- if [ "$skip" != "" ]; then
+ if [ "$skip" != "" ]; then
- echo "skipping Ruby version ${SisClr_Blue}${SisClr_Bold}$version${SisClr_None}:"
- else
+ echo "skipping Ruby version ${SisClr_Blue}${SisClr_Bold}$version${SisClr_None}:"
+ else
- echo "processing Ruby version ${SisClr_Blue}${SisClr_Bold}$version${SisClr_None}:"
+ echo "processing Ruby version ${SisClr_Blue}${SisClr_Bold}$version${SisClr_None}:"
- echo -e "\texecuting command line 'RBENV_VERSION=$version $0 ${ForwardArgs[*]}' with Ruby version $version ..."
+ echo -e "\texecuting command line 'RBENV_VERSION=$version $0 ${ForwardArgs[*]}' with Ruby version $version ..."
- if ! RBENV_VERSION="$version" "$0" "${ForwardArgs[@]}"; then
+ if ! RBENV_VERSION="$version" "$0" "${ForwardArgs[@]}"; then
- result=1
+ result=1
+ fi
fi
- fi
done
exit $result
@@ -275,13 +286,24 @@ else
result=0
+ test_files=$(mktemp "${TMPDIR:-/tmp}/run_all_unit_tests.XXXXXX") || {
+ >&2 echo "$0: ${SisClr_Red}${SisClr_Bold}failed to create temporary file for test discovery${SisClr_None}"
+ exit 1
+ }
+ trap 'rm -f "$test_files"' EXIT
+
+ if ! find "$ProjectDir" -name 'tc_*.rb' -print0 > "$test_files"; then
+ >&2 echo "$0: ${SisClr_Red}${SisClr_Bold}failed to discover test files${SisClr_None}"
+ exit 1
+ fi
+
while IFS= read -r -d '' testfile; do
if ! ruby $DebugFlag $WarningsFlag "$testfile"; then
result=1
fi
- done < <(find "$ProjectDir" -name 'tc_*.rb' -print0)
+ done < "$test_files"
exit $result
fi