Skip to content

Commit c971c6c

Browse files
authored
Merge pull request #2 from mlibrary/ruby-3.x
Support for ruby 3.x; use standardrb
2 parents bd87706 + 180866d commit c971c6c

18 files changed

+282
-263
lines changed

.github/workflows/tests.yml

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Run Tests
2+
3+
on: push
4+
5+
jobs:
6+
test:
7+
runs-on: ubuntu-latest
8+
name: Ruby ${{ matrix.ruby }}
9+
strategy:
10+
matrix:
11+
ruby: [2.7, 3.0, 3.1, 3.2]
12+
steps:
13+
- uses: actions/checkout@v3
14+
- name: Set up Ruby
15+
uses: ruby/setup-ruby@v1
16+
with:
17+
ruby-version: ${{ matrix.ruby }}
18+
bundler-cache: true
19+
- name: Run linter for Ruby
20+
run: bundle exec standardrb
21+
- name: Run tests
22+
run: bundle exec rspec
23+
- name: Report to Coveralls
24+
uses: coverallsapp/[email protected]
25+
with:
26+
github-token: ${{ secrets.github_token }}

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ doc
1010

1111
# bundler
1212
.bundle
13+
vendor/
1314

1415
# jeweler generated
1516
pkg

Gemfile

+5-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ source "https://rubygems.org"
33
# Specify your gem's dependencies in test.gemspec
44
gemspec
55

6-
7-
gem 'rcov', :platform => :mri_18
8-
gem 'simplecov', :platforms => [:mri_19, :mri_20]
9-
gem 'simplecov-rcov', :platforms => [:mri_19, :mri_20]
6+
group :development, :test do
7+
gem "simplecov"
8+
gem "standardrb"
9+
gem "simplecov-lcov"
10+
end

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
[![Tests](https://github.com/mlibrary/pairtree/actions/workflows/tests.yaml/badge.svg)](https://github.com/mlibrary/pairtree/actions/workflows/tests.yaml)
2+
[![Coverage Status](https://coveralls.io/repos/github/mlibrary/pairtree/badge.svg?branch=main)](https://coveralls.io/github/mlibrary/pairtree?branch=main)
3+
[![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
4+
15
# (r)pairtree
26

37
Ruby implementation of the [Pairtree](https://wiki.ucop.edu/display/Curation/PairTree) specification from the California Digital Library.

Rakefile

+18-19
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,44 @@
1-
require 'rubygems'
2-
require 'bundler'
1+
require "rubygems"
2+
require "bundler"
33
begin
44
Bundler.setup(:default, :development)
55
rescue Bundler::BundlerError => e
6-
$stderr.puts e.message
7-
$stderr.puts "Run `bundle install` to install missing gems"
6+
warn e.message
7+
warn "Run `bundle install` to install missing gems"
88
exit e.status_code
99
end
1010

1111
Bundler::GemHelper.install_tasks
1212

13-
require 'rake'
14-
require 'rspec'
15-
require 'rspec/core/rake_task'
13+
require "rake"
14+
require "rspec"
15+
require "rspec/core/rake_task"
1616

17-
desc 'Default: run specs.'
18-
task :default => :spec
17+
desc "Default: run specs."
18+
task default: :spec
1919

2020
RSpec::Core::RakeTask.new do |t|
21-
if ENV['COVERAGE'] and RUBY_VERSION =~ /^1.8/
21+
if ENV["COVERAGE"] && RUBY_VERSION =~ (/^1.8/)
2222
t.rcov = true
23-
t.rcov_opts = ['--exclude', 'spec', '--exclude', 'gems']
23+
t.rcov_opts = ["--exclude", "spec", "--exclude", "gems"]
2424
end
2525
end
2626

2727
# Use yard to build docs
2828
begin
29-
require 'yard'
30-
require 'yard/rake/yardoc_task'
31-
project_root = File.expand_path(File.dirname(__FILE__))
32-
doc_destination = File.join(project_root, 'doc')
29+
require "yard"
30+
require "yard/rake/yardoc_task"
31+
project_root = __dir__
32+
doc_destination = File.join(project_root, "doc")
3333

3434
YARD::Rake::YardocTask.new(:doc) do |yt|
35-
yt.files = Dir.glob(File.join(project_root, 'lib', '**', '*.rb')) +
36-
[ File.join(project_root, 'README.md') ]
37-
yt.options = ['--output-dir', doc_destination, '--readme', 'README.md']
35+
yt.files = Dir.glob(File.join(project_root, "lib", "**", "*.rb")) +
36+
[File.join(project_root, "README.md")]
37+
yt.options = ["--output-dir", doc_destination, "--readme", "README.md"]
3838
end
3939
rescue LoadError
4040
desc "Generate YARD Documentation"
4141
task :doc do
4242
abort "Please install the YARD gem to generate rdoc."
4343
end
4444
end
45-

lib/pairtree.rb

+33-28
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1-
require 'pairtree/identifier'
2-
require 'pairtree/path'
3-
require 'pairtree/obj'
4-
require 'pairtree/root'
1+
require "pairtree/identifier"
2+
require "pairtree/path"
3+
require "pairtree/obj"
4+
require "pairtree/root"
55

6-
require 'fileutils'
6+
require "fileutils"
77

88
module Pairtree
9-
class IdentifierError < Exception; end
10-
class PathError < Exception; end
11-
class VersionMismatch < Exception; end
9+
class IdentifierError < RuntimeError; end
10+
11+
class PathError < RuntimeError; end
12+
13+
class VersionMismatch < RuntimeError; end
1214

1315
SPEC_VERSION = 0.1
14-
16+
1517
##
1618
# Instantiate a pairtree at a given path location
1719
# @param [String] path The path in which the pairtree resides
@@ -20,34 +22,34 @@ class VersionMismatch < Exception; end
2022
# @option args [String] :version (Pairtree::SPEC_VERSION) the version of the pairtree spec that this tree conforms to
2123
# @option args [Boolean] :create (false) if true, create the pairtree and its directory structure if it doesn't already exist
2224
def self.at path, args = {}
23-
args = { :prefix => nil, :version => nil, :create => false }.merge(args)
25+
args = {prefix: nil, version: nil, create: false}.merge(args)
2426
args[:version] ||= SPEC_VERSION
2527
args[:version] = args[:version].to_f
26-
27-
root_path = File.join(path, 'pairtree_root')
28-
prefix_file = File.join(path, 'pairtree_prefix')
28+
29+
root_path = File.join(path, "pairtree_root")
30+
prefix_file = File.join(path, "pairtree_prefix")
2931
version_file = File.join(path, pairtree_version_filename(args[:version]))
30-
existing_version_file = Dir[File.join(path, "pairtree_version*")].sort.last
31-
32+
existing_version_file = Dir[File.join(path, "pairtree_version*")].max
33+
3234
if args.delete(:create)
33-
if File.exists?(path) and not File.directory?(path)
35+
if File.exist?(path) && !File.directory?(path)
3436
raise PathError, "#{path} exists, but is not a valid pairtree root"
3537
end
3638
FileUtils.mkdir_p(root_path)
3739

38-
unless File.exists? prefix_file
39-
File.open(prefix_file, 'w') { |f| f.write(args[:prefix].to_s) }
40+
unless File.exist? prefix_file
41+
File.write(prefix_file, args[:prefix].to_s)
4042
end
41-
43+
4244
if existing_version_file
4345
if existing_version_file != version_file
44-
stored_version = existing_version_file.scan(/([0-9]+)_([0-9]+)/).flatten.join('.').to_f
46+
stored_version = existing_version_file.scan(/([0-9]+)_([0-9]+)/).flatten.join(".").to_f
4547
raise VersionMismatch, "Version #{args[:version]} specified, but #{stored_version} found."
4648
end
4749
else
4850
args[:version] ||= SPEC_VERSION
4951
version_file = File.join(path, pairtree_version_filename(args[:version]))
50-
File.open(version_file, 'w') { |f| f.write %{This directory conforms to Pairtree Version #{args[:version]}. Updated spec: http://www.cdlib.org/inside/diglib/pairtree/pairtreespec.html} }
52+
File.write(version_file, %(This directory conforms to Pairtree Version #{args[:version]}. Updated spec: http://www.cdlib.org/inside/diglib/pairtree/pairtreespec.html))
5153
existing_version_file = version_file
5254
end
5355
else
@@ -57,22 +59,25 @@ def self.at path, args = {}
5759
end
5860

5961
stored_prefix = File.read(prefix_file)
60-
unless args[:prefix].nil? or args[:prefix].to_s == stored_prefix
62+
unless args[:prefix].nil? || (args[:prefix].to_s == stored_prefix)
6163
raise IdentifierError, "Specified prefix #{args[:prefix].inspect} does not match stored prefix #{stored_prefix.inspect}"
6264
end
6365
args[:prefix] = stored_prefix
6466

65-
stored_version = existing_version_file.scan(/([0-9]+)_([0-9]+)/).flatten.join('.').to_f
67+
stored_version = existing_version_file.scan(/([0-9]+)_([0-9]+)/).flatten.join(".").to_f
6668
args[:version] ||= stored_version
6769
unless args[:version] == stored_version
6870
raise VersionMismatch, "Version #{args[:version]} specified, but #{stored_version} found."
6971
end
70-
71-
Pairtree::Root.new(File.join(path, 'pairtree_root'), args)
72+
73+
Pairtree::Root.new(File.join(path, "pairtree_root"), args)
7274
end
7375

74-
private
75-
def self.pairtree_version_filename(version)
76-
"pairtree_version#{version.to_s.gsub(/\./,'_')}"
76+
class << self
77+
private
78+
79+
def pairtree_version_filename(version)
80+
"pairtree_version#{version.to_s.tr(".", "_")}"
81+
end
7782
end
7883
end

lib/pairtree/identifier.rb

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# encoding: utf-8
21
module Pairtree
32
class Identifier
43
ENCODE_REGEX = Regexp.compile("[\"*+,<=>?\\\\^|]|[^\x21-\x7e]", nil)
@@ -8,29 +7,29 @@ class Identifier
87
# Encode special characters within an identifier
98
# @param [String] id The identifier
109
def self.encode id
11-
id.gsub(ENCODE_REGEX) { |c| char2hex(c) }.tr('/:.', '=+,')
10+
id.gsub(ENCODE_REGEX) { |c| char2hex(c) }.tr("/:.", "=+,")
1211
end
1312

1413
##
1514
# Decode special characters within an identifier
1615
# @param [String] id The identifier
1716
def self.decode id
18-
input = id.tr('=+,', '/:.').bytes.to_a
17+
input = id.tr("=+,", "/:.").bytes.to_a
1918
intermediate = []
2019
while input.first
2120
if input.first == 94
2221
h = []
2322
input.shift
2423
h << input.shift
2524
h << input.shift
26-
intermediate << h.pack('c*').hex
25+
intermediate << h.pack("c*").hex
2726
else
2827
intermediate << input.shift
2928
end
3029
end
31-
result = intermediate.pack('c*')
30+
result = intermediate.pack("c*")
3231
if result.respond_to? :force_encoding
33-
result.force_encoding('UTF-8')
32+
result.force_encoding("UTF-8")
3433
end
3534
result
3635
end
@@ -39,14 +38,14 @@ def self.decode id
3938
# Convert a character to its pairtree hexidecimal representation
4039
# @param [Char] c The character to convert
4140
def self.char2hex c
42-
c.unpack('H*')[0].scan(/../).map { |x| "^#{x}"}.join('')
41+
c.unpack1("H*").scan(/../).map { |x| "^#{x}" }.join("")
4342
end
4443

4544
##
4645
# Convert a pairtree hexidecimal string to its character representation
4746
# @param [String] h The hexidecimal string to convert
4847
def self.hex2char h
49-
'' << h.delete('^').hex
48+
"" << h.delete("^").hex
5049
end
5150
end
5251
end

lib/pairtree/obj.rb

+20-21
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,51 @@
1-
module Pairtree
1+
module Pairtree
22
class Obj < ::Dir
3-
4-
FILE_METHODS = [:atime, :open, :read, :file?, :directory?, :exist?, :exists?, :file?, :ftype, :lstat,
3+
FILE_METHODS = [:atime, :open, :read, :file?, :directory?, :exist?, :exists?, :file?, :ftype, :lstat,
54
:mtime, :readable?, :size, :stat, :truncate, :writable?, :zero?]
65
FILE_METHODS.each do |file_method|
7-
define_method file_method do |fname,*args,&block|
8-
File.send(file_method, File.join(self.path, fname), *args, &block)
6+
define_method file_method do |fname, *args, &block|
7+
File.send(file_method, File.join(path, fname), *args, &block)
98
end
109
end
1110

1211
def delete *args
13-
File.delete(*(prepend_filenames(args)))
12+
File.delete(*prepend_filenames(args))
1413
end
1514
alias_method :unlink, :delete
1615

1716
def link *args
18-
File.link(*(prepend_filenames(args)))
17+
File.link(*prepend_filenames(args))
1918
end
2019

2120
def rename *args
22-
File.rename(*(prepend_filenames(args)))
21+
File.rename(*prepend_filenames(args))
2322
end
24-
23+
2524
def utime atime, mtime, *args
26-
File.utime(atime, mtime, *(prepend_filenames(args)))
25+
File.utime(atime, mtime, *prepend_filenames(args))
2726
end
28-
27+
2928
def entries
30-
super - ['.','..']
29+
super - [".", ".."]
3130
end
32-
31+
3332
def each &block
34-
super { |entry| yield(entry) unless entry =~ /^\.{1,2}$/ }
33+
super { |entry| yield(entry) unless /^\.{1,2}$/.match?(entry) }
3534
end
36-
35+
3736
def glob(string, flags = 0)
38-
result = Dir.glob(File.join(self.path, string), flags) - ['.','..']
39-
result.collect { |f| f.sub(%r{^#{self.path}/},'') }
37+
result = Dir.glob(File.join(path, string), flags) - [".", ".."]
38+
result.collect { |f| f.sub(%r{^#{path}/}, "") }
4039
end
41-
40+
4241
def [](string)
4342
glob(string, 0)
4443
end
45-
44+
4645
private
46+
4747
def prepend_filenames(files)
48-
files.collect { |fname| File.join(self.path, fname) }
48+
files.collect { |fname| File.join(path, fname) }
4949
end
50-
5150
end
5251
end

0 commit comments

Comments
 (0)