Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
fail-fast: false
matrix:
os: [ ubuntu-latest, macos-latest ]
ruby: [ '2.7', '3.0', '3.1' ]
ruby: [ '3.3', '3.4' ]
runs-on: ${{ matrix.os }}

steps:
Expand All @@ -24,7 +24,7 @@ jobs:

- name: Upload artifacts
if: ${{ always() }}
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: artifacts
name: artifacts-${{ matrix.ruby }}-${{ matrix.os }}
path: artifacts/**
33 changes: 33 additions & 0 deletions .github/workflows/gem-push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Ruby Gem

on:
release:
types: [published]

jobs:
build:
name: Build + Publish
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- uses: actions/checkout@v3

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
bundler-cache: true

- name: Publish to RubyGems
run: |
mkdir -p $HOME/.gem
touch $HOME/.gem/credentials
chmod 0600 $HOME/.gem/credentials
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
gem build *.gemspec
gem push *.gem
env:
GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
138 changes: 138 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -491,3 +491,141 @@ Style/RedundantStringEscape: # (new in 1.37)
Style/RedundantEach: # (new in 1.38)
Enabled: true

Gemspec/AddRuntimeDependency: # new in 1.65
Enabled: true
Gemspec/AttributeAssignment: # new in 1.77
Enabled: true
Gemspec/DevelopmentDependencies: # new in 1.44
Enabled: false
Lint/ArrayLiteralInRegexp: # new in 1.71
Enabled: true
Lint/ConstantReassignment: # new in 1.70
Enabled: true
Lint/CopDirectiveSyntax: # new in 1.72
Enabled: true
Lint/DuplicateMatchPattern: # new in 1.50
Enabled: true
Lint/DuplicateSetElement: # new in 1.67
Enabled: true
Lint/HashNewWithKeywordArgumentsAsDefault: # new in 1.69
Enabled: true
Lint/ItWithoutArgumentsInBlock: # new in 1.59
Enabled: true
Lint/LiteralAssignmentInCondition: # new in 1.58
Enabled: true
Lint/MixedCaseRange: # new in 1.53
Enabled: true
Lint/NumericOperationWithConstantResult: # new in 1.69
Enabled: true
Lint/RedundantRegexpQuantifiers: # new in 1.53
Enabled: true
Lint/RedundantTypeConversion: # new in 1.72
Enabled: true
Lint/SharedMutableDefault: # new in 1.70
Enabled: true
Lint/SuppressedExceptionInNumberConversion: # new in 1.72
Enabled: true
Lint/UnescapedBracketInRegexp: # new in 1.68
Enabled: true
Lint/UselessConstantScoping: # new in 1.72
Enabled: true
Lint/UselessDefaultValueArgument: # new in 1.76
Enabled: true
Lint/UselessDefined: # new in 1.69
Enabled: true
Lint/UselessNumericOperation: # new in 1.66
Enabled: true
Lint/UselessOr: # new in 1.76
Enabled: true
Lint/UselessRescue: # new in 1.43
Enabled: true
Metrics/CollectionLiteralLength: # new in 1.47
Enabled: true
Naming/PredicateMethod: # new in 1.76
Enabled: true
Style/AmbiguousEndlessMethodDefinition: # new in 1.68
Enabled: true
Style/ArrayIntersect: # new in 1.40
Enabled: true
Style/BitwisePredicate: # new in 1.68
Enabled: true
Style/CollectionQuerying: # new in 1.77
Enabled: true
Style/CombinableDefined: # new in 1.68
Enabled: true
Style/ComparableBetween: # new in 1.74
Enabled: true
Style/ComparableClamp: # new in 1.44
Enabled: true
Style/ConcatArrayLiterals: # new in 1.41
Enabled: true
Style/DataInheritance: # new in 1.49
Enabled: true
Style/DigChain: # new in 1.69
Enabled: true
Style/DirEmpty: # new in 1.48
Enabled: true
Style/EmptyStringInsideInterpolation: # new in 1.76
Enabled: true
Style/ExactRegexpMatch: # new in 1.51
Enabled: true
Style/FileEmpty: # new in 1.48
Enabled: true
Style/FileNull: # new in 1.69
Enabled: true
Style/FileTouch: # new in 1.69
Enabled: true
Style/HashFetchChain: # new in 1.75
Enabled: true
Style/HashSlice: # new in 1.71
Enabled: true
Style/ItAssignment: # new in 1.70
Enabled: true
Style/ItBlockParameter: # new in 1.75
Enabled: true
Style/KeywordArgumentsMerging: # new in 1.68
Enabled: true
Style/MapIntoArray: # new in 1.63
Enabled: true
Style/MapToSet: # new in 1.42
Enabled: true
Style/MinMaxComparison: # new in 1.42
Enabled: true
Style/RedundantArrayConstructor: # new in 1.52
Enabled: true
Style/RedundantArrayFlatten: # new in 1.76
Enabled: true
Style/RedundantConstantBase: # new in 1.40
Enabled: true
Style/RedundantCurrentDirectoryInPath: # new in 1.53
Enabled: true
Style/RedundantDoubleSplatHashBraces: # new in 1.41
Enabled: true
Style/RedundantFilterChain: # new in 1.52
Enabled: true
Style/RedundantFormat: # new in 1.72
Enabled: true
Style/RedundantHeredocDelimiterQuotes: # new in 1.45
Enabled: true
Style/RedundantInterpolationUnfreeze: # new in 1.66
Enabled: true
Style/RedundantLineContinuation: # new in 1.49
Enabled: true
Style/RedundantRegexpArgument: # new in 1.53
Enabled: true
Style/RedundantRegexpConstructor: # new in 1.52
Enabled: true
Style/ReturnNilInPredicateMethodDefinition: # new in 1.53
Enabled: true
Style/SafeNavigationChainLength: # new in 1.68
Enabled: true
Style/SendWithLiteralMethodName: # new in 1.64
Enabled: true
Style/SingleLineDoEndBlock: # new in 1.57
Enabled: true
Style/SuperArguments: # new in 1.64
Enabled: true
Style/SuperWithArgsParentheses: # new in 1.58
Enabled: true
Style/YAMLFileRead: # new in 1.53
Enabled: true
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 0.2.0 (2025-07-24)

- Update to support Ruby 3.3+.
- Update Rubocop & style changes.

# 0.1.9 (2023-06-01)

- `URIs#path_escape` now attempts to convert non-UTF-8 strings to UTF-8 rather than immediately
Expand Down
58 changes: 58 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# =============================================================================
# Target: base

FROM ruby:3.3-alpine AS base

RUN apk --no-cache --update upgrade && \
apk --no-cache add \
bash \
ca-certificates \
git \
libc6-compat \
openssl \
tzdata \
xz-libs \
yaml-dev \
&& rm -rf /var/cache/apk/*

WORKDIR /opt/app

# =============================================================================
# Target: development
#

FROM base AS development

# Install system packages needed to build gems with C extensions.
RUN apk --update --no-cache add \
build-base \
coreutils \
git \
&& rm -rf /var/cache/apk/*

# The base image ships an older bundler, but we want something more recent
RUN gem install bundler -v 2.5.22

# Copy codebase to WORKDIR. Unlike application projects, for a gem project
# we need to do this before running `bundle install`, in order for the gem
# we're building to be able to "install" itself.
COPY . .

# Install gems.
RUN bundle install --path=/usr/local/bundle

# =============================================================================
# Target: production

FROM base AS production

# Copy the built codebase from the dev stage
COPY --from=development /opt/app /opt/app
COPY --from=development /usr/local/bundle /usr/local/bundle

# Sanity-check that everything was installed correctly and still runs in the
# slimmed-down production image.
RUN bundle config set deployment 'true'
RUN bundle install --local --path=/usr/local/bundle

CMD ["bundle", "exec", "rake"]
18 changes: 9 additions & 9 deletions berkeley_library-util.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ File.expand_path('lib', __dir__).tap do |lib|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
end

ruby_version = '>= 2.7'
ruby_version = '~> 3.3'

require 'berkeley_library/util/module_info'

Gem::Specification.new do |spec|
spec.name = BerkeleyLibrary::Util::ModuleInfo::NAME
spec.author = BerkeleyLibrary::Util::ModuleInfo::AUTHOR
spec.email = BerkeleyLibrary::Util::ModuleInfo::AUTHOR_EMAIL
spec.author = BerkeleyLibrary::Util::ModuleInfo::AUTHORS
spec.email = BerkeleyLibrary::Util::ModuleInfo::AUTHOR_EMAILS
spec.summary = BerkeleyLibrary::Util::ModuleInfo::SUMMARY
spec.description = BerkeleyLibrary::Util::ModuleInfo::DESCRIPTION
spec.license = BerkeleyLibrary::Util::ModuleInfo::LICENSE
Expand All @@ -21,19 +21,19 @@ Gem::Specification.new do |spec|

spec.required_ruby_version = ruby_version

spec.add_dependency 'berkeley_library-logging', '~> 0.2'
spec.add_dependency 'berkeley_library-logging', '~> 0.3'
spec.add_dependency 'rest-client', '~> 2.1'
spec.add_dependency 'typesafe_enum', '~> 0.3'

spec.add_development_dependency 'ci_reporter_rspec', '~> 1.0'
spec.add_development_dependency 'colorize', '~> 0.8'
spec.add_development_dependency 'colorize', '~> 1.0'
spec.add_development_dependency 'dotenv', '~> 2.7'
spec.add_development_dependency 'rake', '~> 13.0'
spec.add_development_dependency 'rspec', '~> 3.10'
spec.add_development_dependency 'rubocop', '= 1.39'
spec.add_development_dependency 'rubocop-rake', '= 0.6.0'
spec.add_development_dependency 'rubocop-rspec', '= 2.4.0'
spec.add_development_dependency 'ruby-prof', '~> 0.17.0'
spec.add_development_dependency 'rubocop', '~> 1.78.0'
spec.add_development_dependency 'rubocop-rake', '~> 0.7.1'
spec.add_development_dependency 'rubocop-rspec', '~> 3.6.0'
spec.add_development_dependency 'ruby-prof'
spec.add_development_dependency 'simplecov', '~> 0.21'
spec.add_development_dependency 'webmock', '~> 3.12'

Expand Down
10 changes: 10 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
services:
gem:
build:
context: .
target: development
restart: always
volumes:
# Note that this mounts the *entire* repo directory (including
# files ignored in .dockerignore when building the image)
- ./:/opt/app
2 changes: 1 addition & 1 deletion lib/berkeley_library/util/arrays.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def do_merge(shorter, longer)
shorter_unmatched = shorter[0...ix_s]
longer_unmatched = longer[0...ix_l]
all_unmatched = sort_by_first_and_flatten(shorter_unmatched, longer_unmatched)
return (all_unmatched << v) + merge(shorter[ix_s + 1..], longer[ix_l + 1..])
return (all_unmatched << v) + merge(shorter[(ix_s + 1)..], longer[(ix_l + 1)..])
end

sort_by_first_and_flatten(longer, shorter)
Expand Down
6 changes: 3 additions & 3 deletions lib/berkeley_library/util/module_info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ module BerkeleyLibrary
module Util
class ModuleInfo
NAME = 'berkeley_library-util'.freeze
AUTHOR = 'David Moles'.freeze
AUTHOR_EMAIL = 'dmoles@berkeley.edu'.freeze
AUTHORS = ['David Moles', 'maría a. matienzo'].freeze
AUTHOR_EMAILS = ['dmoles@berkeley.edu', 'matienzo@berkeley.edu'].freeze
SUMMARY = 'Miscellaneous Ruby utilities for the UC Berkeley Library'.freeze
DESCRIPTION = 'A collection of miscellaneous Ruby routines for the UC Berkeley Library.'.freeze
LICENSE = 'MIT'.freeze
VERSION = '0.1.9'.freeze
VERSION = '0.2.0'.freeze
HOMEPAGE = 'https://github.com/BerkeleyLibrary/util'.freeze
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/berkeley_library/util/strings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module Strings
def ascii_numeric?(s)
s.chars.all? do |c|
ord = c.ord
ord >= ASCII_0 && ord <= ASCII_9
ord.between?(ASCII_0, ASCII_9)
end
end

Expand Down
12 changes: 5 additions & 7 deletions lib/berkeley_library/util/uris.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,31 +109,29 @@ def safe_parse_uri(url)
nil
end

private

# TODO: extend to cover other modes - host, zone, path, password, query, fragment
# cf. https://github.com/golang/go/blob/master/src/net/url/url.go
ALLOWED_BYTES_BY_MODE = {
path_segment: [0x24, 0x26, 0x2b, 0x3a, 0x3d, 0x40] # @ & = + $
}.freeze

private

def should_escape?(b, mode)
return false if unreserved?(b)
return false if ALLOWED_BYTES_BY_MODE[mode].include?(b)

true
end

# rubocop:disable Metrics/CyclomaticComplexity
def unreserved?(byte)
return true if byte >= 0x41 && byte <= 0x5a # A-Z
return true if byte >= 0x61 && byte <= 0x7a # a-z
return true if byte >= 0x30 && byte <= 0x39 # 0-9
return true if byte.between?(0x41, 0x5a) # A-Z
return true if byte.between?(0x61, 0x7a) # a-z
return true if byte.between?(0x30, 0x39) # 0-9
return true if [0x2d, 0x2e, 0x5f, 0x7e].include?(byte) # - . _ ~

false
end
# rubocop:enable Metrics/CyclomaticComplexity
end
end
end
2 changes: 1 addition & 1 deletion rakelib/.rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
inherit_from: ../.rubocop.yml

require:
plugins:
- rubocop-rake
Loading
Loading