From fbe1e260f965c7c8e9177de3a55bfcdb78589d83 Mon Sep 17 00:00:00 2001 From: fig Date: Tue, 3 Jan 2023 18:45:13 +0000 Subject: [PATCH 01/12] bump pry to 0.14 --- ruby_jard.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby_jard.gemspec b/ruby_jard.gemspec index 75a1e71e..3426ba33 100644 --- a/ruby_jard.gemspec +++ b/ruby_jard.gemspec @@ -33,6 +33,6 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.add_runtime_dependency 'byebug', '>= 9.1', '< 12.0' - spec.add_runtime_dependency 'pry', '~> 0.13.0' + spec.add_runtime_dependency 'pry', '~> 0.14.0' spec.add_runtime_dependency 'tty-screen', '~> 0.8.1' end From 5a79307c91e839542b089c8d0f2d91abed443b6c Mon Sep 17 00:00:00 2001 From: fig Date: Sun, 21 Sep 2025 03:04:20 +0100 Subject: [PATCH 02/12] Add bigdecimal as a runtime dependency in the gemspec --- ruby_jard.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/ruby_jard.gemspec b/ruby_jard.gemspec index 3426ba33..f36023d6 100644 --- a/ruby_jard.gemspec +++ b/ruby_jard.gemspec @@ -32,6 +32,7 @@ Gem::Specification.new do |spec| spec.executables = [] spec.require_paths = ['lib'] + spec.add_runtime_dependency 'bigdecimal', '~> 3.2', '>= 3.2.3' spec.add_runtime_dependency 'byebug', '>= 9.1', '< 12.0' spec.add_runtime_dependency 'pry', '~> 0.14.0' spec.add_runtime_dependency 'tty-screen', '~> 0.8.1' From 0993bca41dad5c5e73e848a65801024dccd68272 Mon Sep 17 00:00:00 2001 From: fig Date: Sun, 21 Sep 2025 03:04:26 +0100 Subject: [PATCH 03/12] Add mutex_m as a runtime dependency in the gemspec --- ruby_jard.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/ruby_jard.gemspec b/ruby_jard.gemspec index f36023d6..8c4e695d 100644 --- a/ruby_jard.gemspec +++ b/ruby_jard.gemspec @@ -34,6 +34,7 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'bigdecimal', '~> 3.2', '>= 3.2.3' spec.add_runtime_dependency 'byebug', '>= 9.1', '< 12.0' + spec.add_runtime_dependency 'mutex_m', '~> 0.3.0' spec.add_runtime_dependency 'pry', '~> 0.14.0' spec.add_runtime_dependency 'tty-screen', '~> 0.8.1' end From 6a4bbf7f97429f669294937036e2c00314ea5242 Mon Sep 17 00:00:00 2001 From: fig Date: Sun, 21 Sep 2025 04:44:10 +0100 Subject: [PATCH 04/12] Add CLAUDE.md documentation for development guidance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- CLAUDE.md | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..065127ec --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,74 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Ruby Jard is a terminal-based debugger for Ruby that provides a rich UI wrapping around Byebug. It offers features like highlighted source code, stacktrace visualization, variable exploration, and multi-thread debugging. + +## Development Commands + +### Testing +- `bundle exec rspec` - Run all tests +- `bundle exec rspec spec/path/to/specific_spec.rb` - Run specific test file +- `bundle exec parallel_rspec spec/` - Run tests in parallel + +### Code Quality +- `bundle exec rubocop` - Run linting +- `bundle exec rubocop -a` - Auto-fix linting issues + +### Build & Install +- `bundle install` - Install dependencies +- `rake build` - Build the gem +- `rake install` - Install the gem locally +- `rake release` - Release the gem (maintainers only) + +## Architecture Overview + +### Core Components + +**Session Management (`lib/ruby_jard/session.rb`)** +- Entry point for debugging sessions +- Manages the lifecycle of debugging contexts + +**REPL System** +- `repl_manager.rb` - Manages REPL interactions +- `repl_processor.rb` - Processes commands and input +- `repl_interceptor.rb` - Intercepts and handles debugging flow +- `repl_state.rb` - Tracks REPL state + +**Screen & Layout System** +- `screen_manager.rb` - Manages multiple debug screens +- `screen_renderer.rb` - Renders screen content +- `layout_*.rb` files - Different layout configurations (wide, narrow, tiny) +- `screens/` directory - Individual screen implementations (source, variables, backtrace, etc.) + +**Inspection System** (`lib/ruby_jard/inspectors/`) +- Modular object inspection with specialized inspectors for different data types +- `base.rb` - Base inspector class +- Type-specific inspectors for arrays, hashes, objects, strings, etc. + +**Command System** (`lib/ruby_jard/commands/`) +- Debugging commands like step, next, continue, frame navigation +- Each command is a separate class inheriting from `base_command.rb` + +### Key Design Patterns + +- **Configuration-driven**: Uses `config.rb` for user customization +- **Modular screens**: Each debug view is a separate screen class +- **Responsive layouts**: Multiple layout templates adapt to terminal size +- **Command pattern**: Debug commands are individual classes +- **Decorator pattern**: Used for colorizing and formatting output + +### Integration Points + +- **Byebug Integration**: Core debugging functionality via Byebug gem +- **Pry Integration**: REPL functionality via Pry gem +- **TTY Integration**: Terminal UI via tty-screen gem + +### Development Notes + +- The codebase uses frozen string literals throughout +- Main entry point is the `jard` method added to Kernel module +- Debugging state is managed through thread-local variables +- UI rendering is optimized for different terminal sizes and capabilities \ No newline at end of file From 16d4d21f955f98a102efa53f107560c7d1861cdf Mon Sep 17 00:00:00 2001 From: fig Date: Sun, 21 Sep 2025 04:44:34 +0100 Subject: [PATCH 05/12] Fix gem path test to use existing directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update test to find first existing gem path instead of using Gem.path.first which may not exist in Ruby 3.4.6 fresh installations. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- spec/ruby_jard/path_classifier_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ruby_jard/path_classifier_spec.rb b/spec/ruby_jard/path_classifier_spec.rb index 6531f574..a89a60f6 100644 --- a/spec/ruby_jard/path_classifier_spec.rb +++ b/spec/ruby_jard/path_classifier_spec.rb @@ -28,7 +28,7 @@ end context 'when input path is in current dir which is also gem path' do - let(:dir) { Gem.path.first } + let(:dir) { Gem.path.find { |path| Dir.exist?(path) } } it 'returns source tree' do Dir.chdir(dir) do From c36e23e1d5c6833ca151e7f0cc7da036ab725602 Mon Sep 17 00:00:00 2001 From: fig Date: Sun, 21 Sep 2025 04:44:58 +0100 Subject: [PATCH 06/12] Fix Ruby 3.4.6 compatibility in path classifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Check both rubylibdir and sitelibdir for stdlib classification since Ruby 3.4.6 moves some components like RubyGems to site_ruby - Change evaluation detection from exact string match to regex pattern to handle Ruby 3.4.6's new eval signature format 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- lib/ruby_jard/path_classifier.rb | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/lib/ruby_jard/path_classifier.rb b/lib/ruby_jard/path_classifier.rb index c78b2ff4..42c1f43f 100644 --- a/lib/ruby_jard/path_classifier.rb +++ b/lib/ruby_jard/path_classifier.rb @@ -12,7 +12,7 @@ class PathClassifier GEM_PATTERN = /(.*)-(\d+\.\d+[.\d]*[.\d]*[-.\w]*)/i.freeze STDLIB_PATTERN = /(.*)\.rb$/.freeze INTERNAL_PATTERN = /]+>/.freeze - EVALUATION_SIGNATURE = '(eval)' + EVALUATION_PATTERN = /^\(eval.*\)$/.freeze RUBY_SCRIPT_SIGNATURE = '-e' TYPES = [ @@ -80,27 +80,33 @@ def try_classify_internal(path) end def try_classify_stdlib(path) - lib_dir = RbConfig::CONFIG['rubylibdir'].to_s.strip + lib_dirs = [ + RbConfig::CONFIG['rubylibdir'], + RbConfig::CONFIG['sitelibdir'] + ].compact.map(&:strip).reject(&:empty?) - return false if lib_dir.empty? - return false unless path.start_with?(lib_dir) + lib_dirs.each do |lib_dir| + next unless path.start_with?(lib_dir) - splitted_path = - path[lib_dir.length..-1] - .split('/') - .reject(&:empty?) - lib_name = splitted_path.first - match = STDLIB_PATTERN.match(lib_name) - lib_name = match[1] if match + splitted_path = + path[lib_dir.length..-1] + .split('/') + .reject(&:empty?) + lib_name = splitted_path.first + match = STDLIB_PATTERN.match(lib_name) + lib_name = match[1] if match - [true, lib_name, splitted_path.join('/')] + return [true, lib_name, splitted_path.join('/')] + end + + false rescue NameError # RbConfig is not available false end def try_classify_evaluation(path) - path == EVALUATION_SIGNATURE + path =~ EVALUATION_PATTERN end def try_classify_ruby_script(path) From d08d8d81b329894061684bcc3c8487a50849a692 Mon Sep 17 00:00:00 2001 From: fig Date: Sun, 21 Sep 2025 05:26:30 +0100 Subject: [PATCH 07/12] Fix Ruby 3.4.6 Reline interceptor compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Allow Reline as default Readline implementation in Ruby 3.4+ - Accept forwardable.rb delegation as valid (not monkey-patched) - Add RUBYOPT=-W0 to integration tests to suppress bundler warnings 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- lib/ruby_jard/repl_interceptor.rb | 19 ++++++++++++++++--- spec/helpers/integration_helper.rb | 1 + 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/ruby_jard/repl_interceptor.rb b/lib/ruby_jard/repl_interceptor.rb index 5bbf5c3f..a5c873e2 100644 --- a/lib/ruby_jard/repl_interceptor.rb +++ b/lib/ruby_jard/repl_interceptor.rb @@ -104,9 +104,22 @@ def redirected_output def interceptable? return false unless defined?(PTY) - return false if defined?(Reline) && Readline == Reline - return false if RubyJard::Reflection.instance.call_method(::Readline, :input=).source_location != nil - return false if RubyJard::Reflection.instance.call_method(::Readline, :output=).source_location != nil + + # In Ruby 3.4+, Reline is the default Readline implementation and should work fine + if RUBY_VERSION >= '3.4.0' + # Allow forwardable delegation in Ruby 3.4+ (methods will have source_location in forwardable.rb) + input_location = RubyJard::Reflection.instance.call_method(::Readline, :input=).source_location + output_location = RubyJard::Reflection.instance.call_method(::Readline, :output=).source_location + + # Only reject if patched by non-standard sources (not forwardable.rb) + return false if input_location && !input_location[0].include?('forwardable.rb') + return false if output_location && !output_location[0].include?('forwardable.rb') + else + # Original logic for older Ruby versions + return false if defined?(Reline) && Readline == Reline + return false if RubyJard::Reflection.instance.call_method(::Readline, :input=).source_location != nil + return false if RubyJard::Reflection.instance.call_method(::Readline, :output=).source_location != nil + end true end diff --git a/spec/helpers/integration_helper.rb b/spec/helpers/integration_helper.rb index aa951667..fa885612 100644 --- a/spec/helpers/integration_helper.rb +++ b/spec/helpers/integration_helper.rb @@ -45,6 +45,7 @@ def start '-c', @dir, '-t', @target, '-n', 'main', + '-e', 'RUBYOPT=-W0', @command ) sleep 0.5 From f4081edb6014dd914cfbefe591ac10df56bff9a7 Mon Sep 17 00:00:00 2001 From: fig Date: Sun, 21 Sep 2025 06:11:46 +0100 Subject: [PATCH 08/12] Update CI configuration and version for Ruby 3.4 compatibility --- .github/workflows/rspec.yml | 4 ++-- CHANGELOG.md | 11 +++++++++++ lib/ruby_jard/version.rb | 2 +- ruby_jard.gemspec | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index 32c9d0b6..7ad57afc 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -38,7 +38,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: [2.5, 2.6, 2.7.2, head] + ruby: [2.5, 2.6, 2.7.2, 3.0, 3.1, 3.2, 3.3, 3.4, head] runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -73,7 +73,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: [2.5, 2.6, 2.7.2, head] + ruby: [2.5, 2.6, 2.7.2, 3.0, 3.1, 3.2, 3.3, 3.4, head] env: CI_PLATFORM: "macos" runs-on: macos-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 84635797..5983ea76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [0.3.2-beta1] +Ruby 3.4 compatibility release for testing. + +### Features +- Ruby 3.4 support and compatibility +- Updated CI to test against Ruby 3.0-3.4 + +### Bug fixes +- Fix Ruby 3.4.6 Reline interceptor compatibility +- Fix Ruby 3.4.6 compatibility in path classifier + ## [0.3.1] This release fixes bunch of bugs, and performance issues reported by the users after beta launch. No new features are introduced. diff --git a/lib/ruby_jard/version.rb b/lib/ruby_jard/version.rb index 7c99e1b5..206e155c 100644 --- a/lib/ruby_jard/version.rb +++ b/lib/ruby_jard/version.rb @@ -2,5 +2,5 @@ # Semantic versionn module RubyJard - VERSION = '0.3.1' + VERSION = '0.3.2.beta1' end diff --git a/ruby_jard.gemspec b/ruby_jard.gemspec index 8c4e695d..24c69f18 100644 --- a/ruby_jard.gemspec +++ b/ruby_jard.gemspec @@ -13,7 +13,7 @@ Gem::Specification.new do |spec| editors.' spec.homepage = 'https://github.com/nguyenquangminh0711/ruby_jard' spec.license = 'MIT' - spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0') + spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0', '< 3.5.0') spec.metadata['allowed_push_host'] = 'https://rubygems.org' From ecaf3ec6669b889ee07bbbe4d6911683d5a76916 Mon Sep 17 00:00:00 2001 From: fig Date: Thu, 6 Nov 2025 00:59:46 +0000 Subject: [PATCH 09/12] fix deprecations for Ruby 3.5 --- CHANGELOG.md | 5 +++++ Gemfile | 2 +- lib/ruby_jard/version.rb | 2 +- ruby_jard.gemspec | 6 ++++-- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5983ea76..81ae4ebd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ # Changelog +## [0.3.2-beta2] +Ruby 3.5 compatibility release. +- Add gem `benchmark` to gemspec +- Add gem `ostruct` to gemspec +- Update dependency `byebug` ## [0.3.2-beta1] Ruby 3.4 compatibility release for testing. diff --git a/Gemfile b/Gemfile index 1b1c841b..5a438b4d 100644 --- a/Gemfile +++ b/Gemfile @@ -9,7 +9,7 @@ if Gem.path.all? { |path| Dir[File.join(path, 'gems/jard_merge_sort*')].empty? } puts `gem install ./spec/examples/jard_merge_sort/jard_merge_sort-0.1.0.gem` end -gem 'byebug', '~> 11.1.0' +gem 'byebug', '~> 12.0' gem 'jard_merge_sort', require: false gem 'rake', '~> 12.0' gem 'rspec', '~> 3.0' diff --git a/lib/ruby_jard/version.rb b/lib/ruby_jard/version.rb index 206e155c..4b67a088 100644 --- a/lib/ruby_jard/version.rb +++ b/lib/ruby_jard/version.rb @@ -2,5 +2,5 @@ # Semantic versionn module RubyJard - VERSION = '0.3.2.beta1' + VERSION = '0.3.2.beta2' end diff --git a/ruby_jard.gemspec b/ruby_jard.gemspec index 24c69f18..e70f9e85 100644 --- a/ruby_jard.gemspec +++ b/ruby_jard.gemspec @@ -13,7 +13,7 @@ Gem::Specification.new do |spec| editors.' spec.homepage = 'https://github.com/nguyenquangminh0711/ruby_jard' spec.license = 'MIT' - spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0', '< 3.5.0') + spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0', '< 3.6.0') spec.metadata['allowed_push_host'] = 'https://rubygems.org' @@ -32,9 +32,11 @@ Gem::Specification.new do |spec| spec.executables = [] spec.require_paths = ['lib'] + spec.add_runtime_dependency 'benchmark', '~> 0.5.0' spec.add_runtime_dependency 'bigdecimal', '~> 3.2', '>= 3.2.3' - spec.add_runtime_dependency 'byebug', '>= 9.1', '< 12.0' + spec.add_runtime_dependency 'byebug', '~> 12.0' spec.add_runtime_dependency 'mutex_m', '~> 0.3.0' + spec.add_runtime_dependency 'ostruct', '~> 0.6.3' spec.add_runtime_dependency 'pry', '~> 0.14.0' spec.add_runtime_dependency 'tty-screen', '~> 0.8.1' end From e256b76cef32cdb6d53d32ec4aa530af200f5551 Mon Sep 17 00:00:00 2001 From: fig Date: Thu, 6 Nov 2025 10:51:55 +0000 Subject: [PATCH 10/12] bump rubocop version --- Gemfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 5a438b4d..60401b46 100644 --- a/Gemfile +++ b/Gemfile @@ -13,8 +13,8 @@ gem 'byebug', '~> 12.0' gem 'jard_merge_sort', require: false gem 'rake', '~> 12.0' gem 'rspec', '~> 3.0' -gem 'rubocop', '~> 0.89.1' -gem 'rubocop-rspec', '~> 1.43.1', require: false +gem 'rubocop', '~> 1.81', '>= 1.81.7' +gem 'rubocop-rspec', '~> 3.7', require: false gem 'tty-markdown', '~>0.7.0' group :test do From 999fba6c4818336a6d17a2160704194fc8a982ef Mon Sep 17 00:00:00 2001 From: fig Date: Wed, 12 Nov 2025 18:55:48 +0000 Subject: [PATCH 11/12] Update path classifier tests to use UnicodeNormalize for standard library classification The previous test subject (URI::HTTP) has been gemified. --- spec/ruby_jard/path_classifier_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/ruby_jard/path_classifier_spec.rb b/spec/ruby_jard/path_classifier_spec.rb index a89a60f6..b392b52c 100644 --- a/spec/ruby_jard/path_classifier_spec.rb +++ b/spec/ruby_jard/path_classifier_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'uri' +require 'unicode_normalize/normalize' RSpec.describe RubyJard::PathClassifier do subject(:classifier) { described_class.new } @@ -99,8 +99,8 @@ context 'when input path is a standard lib sub folder' do it 'returns stdlib, and relative path' do - expect(classifier.classify(URI::HTTP.method(:build).source_location.first)).to eq( - [:stdlib, 'uri', 'uri/http.rb'] + expect(classifier.classify(UnicodeNormalize.method(:normalize).source_location.first)).to eq( + [:stdlib, 'unicode_normalize', 'unicode_normalize/normalize.rb'] ) end end From 9e67ec7ed6820c2dd7b3d5264ba2157995afbf0c Mon Sep 17 00:00:00 2001 From: fig Date: Thu, 25 Dec 2025 15:43:17 +0000 Subject: [PATCH 12/12] Update Ruby version requirements to 3.2 in CI and gemspec --- .github/workflows/rspec.yml | 8 ++++---- .rubocop.yml | 2 +- ruby_jard.gemspec | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index 7ad57afc..ae3fe97e 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -15,7 +15,7 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: 2.5 + ruby-version: 3.2 - name: Install dependencies run: bundle install - name: Checking offenses @@ -28,7 +28,7 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: 2.5 + ruby-version: 3.2 - name: Install dependencies run: bundle install - name: Testing docs @@ -38,7 +38,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: [2.5, 2.6, 2.7.2, 3.0, 3.1, 3.2, 3.3, 3.4, head] + ruby: [3.2, 3.3, 3.4, 4.0, head] runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -73,7 +73,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: [2.5, 2.6, 2.7.2, 3.0, 3.1, 3.2, 3.3, 3.4, head] + ruby: [3.2, 3.3, 3.4, 4.0, head] env: CI_PLATFORM: "macos" runs-on: macos-latest diff --git a/.rubocop.yml b/.rubocop.yml index 6121c2f2..95efa75a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -98,6 +98,6 @@ RSpec/MultipleMemoizedHelpers: Enabled: false AllCops: - TargetRubyVersion: 2.5 + TargetRubyVersion: 3.2 Exclude: - '**/*_example.rb' diff --git a/ruby_jard.gemspec b/ruby_jard.gemspec index e70f9e85..2d73c0c1 100644 --- a/ruby_jard.gemspec +++ b/ruby_jard.gemspec @@ -13,7 +13,7 @@ Gem::Specification.new do |spec| editors.' spec.homepage = 'https://github.com/nguyenquangminh0711/ruby_jard' spec.license = 'MIT' - spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0', '< 3.6.0') + spec.required_ruby_version = Gem::Requirement.new('>= 3.2.0', '< 4.1.0') spec.metadata['allowed_push_host'] = 'https://rubygems.org'