├── .ruby-version ├── .gitattributes ├── .envrc ├── .bundle └── config ├── bin └── console ├── lib ├── irb-power_assert.rb └── irb │ ├── power_assert │ └── version.rb │ ├── power_assert.rb │ └── cmd │ └── pa.rb ├── .vscode ├── extensions.json └── settings.json ├── .editorconfig ├── gemfiles └── oldest │ └── Gemfile ├── .github ├── workflows │ ├── dependency-review.yml │ ├── lint.yml │ ├── update-nixpkgs-and-versions-in-ci.yml │ ├── ci-nix.yml │ ├── ci-ruby.yml │ ├── merge-bot-pr.yml │ └── release.yml ├── renovate.json └── dependabot.yml ├── dprint.json ├── Gemfile ├── flake.lock ├── LICENSE.txt ├── CONTRIBUTING.md ├── flake.nix ├── Rakefile ├── irb-power_assert.gemspec ├── .gitignore ├── test ├── helper.rb └── test_irb_power_assert.rb ├── README.md └── .rubocop.yml /.ruby-version: -------------------------------------------------------------------------------- 1 | 3.4.8 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | .envrc linguist-vendored 2 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | use flake 4 | -------------------------------------------------------------------------------- /.bundle/config: -------------------------------------------------------------------------------- 1 | --- 2 | BUNDLE_PATH: "vendor/bundle" 3 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'bundler/setup' 4 | require_relative '../lib/irb/power_assert' 5 | 6 | IRB.start(__FILE__) 7 | -------------------------------------------------------------------------------- /lib/irb-power_assert.rb: -------------------------------------------------------------------------------- 1 | # coding: us-ascii 2 | # frozen_string_literal: true 3 | # Copyright (C) 2021 Kenichi Kamiya 4 | 5 | require_relative 'irb/power_assert' 6 | -------------------------------------------------------------------------------- /lib/irb/power_assert/version.rb: -------------------------------------------------------------------------------- 1 | # coding: us-ascii 2 | # frozen_string_literal: true 3 | 4 | module IRB 5 | module PowerAssert 6 | VERSION = '0.4.0' 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "editorconfig.editorconfig", 4 | "github.vscode-github-actions", 5 | "rubocop.vscode-rubocop", 6 | "tekumara.typos-vscode", 7 | "dprint.dprint" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /gemfiles/oldest/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec(path: Pathname(__dir__).parent.parent) 4 | 5 | group :test do 6 | gem 'rake', '13.2.1' 7 | gem 'test-unit', '3.6.7' 8 | gem 'test-unit-ruby-core', '1.0' 9 | gem 'warning', '1.5.0' 10 | 11 | gem 'irb', '1.14.0' 12 | gem 'power_assert', '2.0.3' 13 | end 14 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.defaultFormatter": "dprint.dprint", 4 | "[ruby]": { 5 | "editor.defaultFormatter": "rubocop.vscode-rubocop" 6 | }, 7 | "[nix]": { 8 | "editor.defaultFormatter": "jnoortheen.nix-ide" 9 | }, 10 | "nix.enableLanguageServer": true, 11 | "nix.serverPath": "nixd" 12 | } 13 | -------------------------------------------------------------------------------- /lib/irb/power_assert.rb: -------------------------------------------------------------------------------- 1 | # coding: us-ascii 2 | # frozen_string_literal: true 3 | # Copyright (C) 2021 Kenichi Kamiya 4 | 5 | require 'irb' 6 | require 'power_assert' 7 | require_relative 'power_assert/version' 8 | 9 | module PowerAssert 10 | INTERNAL_LIB_DIRS[IRB::PowerAssert] = File.dirname(File.dirname(caller_locations(1, 1).first.path)) 11 | end 12 | 13 | require_relative 'cmd/pa' 14 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | name: 💂➕ 2 | on: 3 | pull_request: 4 | paths: 5 | - '.github/workflows/dependency-review.yml' 6 | - 'Gemfile' 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | dependency-review: 13 | runs-on: ubuntu-24.04 14 | steps: 15 | - name: 'Checkout Repository' 16 | uses: actions/checkout@v6 17 | - name: 'Dependency Review' 18 | uses: actions/dependency-review-action@v4 19 | -------------------------------------------------------------------------------- /dprint.json: -------------------------------------------------------------------------------- 1 | { 2 | "json": { 3 | }, 4 | "markdown": { 5 | }, 6 | "yaml": { 7 | "quotes": "preferSingle", 8 | "trimTrailingWhitespaces": false 9 | }, 10 | "excludes": [ 11 | ".git", 12 | "**/*lock.json", 13 | "doc", 14 | "vendor" 15 | ], 16 | "plugins": [ 17 | "https://plugins.dprint.dev/json-0.21.0.wasm", 18 | "https://plugins.dprint.dev/markdown-0.20.0.wasm", 19 | "https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.1.wasm" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "dependencyDashboard": true, 4 | "enabledManagers": [ 5 | "nix", 6 | "custom.regex" 7 | ], 8 | "extends": [ 9 | "github>kachick/renovate-config-dprint#1.3.0", 10 | "github>kachick/renovate-config-dprint:self" 11 | ], 12 | "labels": [ 13 | "dependencies", 14 | "renovate" 15 | ], 16 | "nix": { 17 | "enabled": false 18 | }, 19 | "ignoreDeps": [ 20 | "crate-ci/typos" 21 | ], 22 | "schedule": [ 23 | "on Tuesday" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | group :development, :test do 6 | gem 'rake', '~> 13.3.1' 7 | end 8 | 9 | group :development do 10 | # Don't relax rubocop family versions with `~> the_version`, rubocop often introduce breaking changes in patch versions. See ruby-ulid#722 11 | gem 'rubocop', '1.82.0', require: false 12 | gem 'rubocop-rake', '0.7.1', require: false 13 | end 14 | 15 | group :test do 16 | gem 'test-unit', '~> 3.7.3' 17 | gem 'test-unit-ruby-core', '~> 1.0' 18 | gem 'warning', '~> 1.5.0' 19 | 20 | gem 'irb', '1.16.0' 21 | gem 'power_assert', '3.0.1' 22 | end 23 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 1766070988, 6 | "narHash": "sha256-G/WVghka6c4bAzMhTwT2vjLccg/awmHkdKSd2JrycLc=", 7 | "owner": "NixOS", 8 | "repo": "nixpkgs", 9 | "rev": "c6245e83d836d0433170a16eb185cefe0572f8b8", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "NixOS", 14 | "ref": "nixos-unstable", 15 | "repo": "nixpkgs", 16 | "type": "github" 17 | } 18 | }, 19 | "root": { 20 | "inputs": { 21 | "nixpkgs": "nixpkgs" 22 | } 23 | } 24 | }, 25 | "root": "root", 26 | "version": 7 27 | } 28 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'github-actions' 4 | directory: '/' 5 | schedule: 6 | interval: 'monthly' 7 | ignore: 8 | - dependency-name: 'crate-ci/typos' 9 | - package-ecosystem: 'bundler' 10 | # Don't icnlude '/gemfiles/oldest', the gemspec is not parsible by dependabot and using hardlink will broken the require_relative in gemspec 11 | directory: '/' 12 | schedule: 13 | interval: 'weekly' 14 | versioning-strategy: increase 15 | groups: 16 | rubocop-dependencies: 17 | patterns: 18 | - '*rubocop*' 19 | ignore: 20 | - dependency-name: 'rubocop' 21 | versions: 22 | # https://github.com/rubocop/rubocop/pull/14067#issuecomment-2820741234 23 | - '1.75.3' 24 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: 👕 2 | on: 3 | push: 4 | branches: 5 | - 'main' 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | jobs: 10 | dprint: 11 | timeout-minutes: 15 12 | runs-on: ubuntu-24.04 13 | steps: 14 | - uses: actions/checkout@v6 15 | - uses: dprint/check@v2.3 16 | with: 17 | dprint-version: '0.50.2' # selfup {"extract":"\\d[^']+","replacer":["bash","-c","dprint --version | cut -d ' ' -f 2"]} 18 | 19 | typos: 20 | timeout-minutes: 15 21 | runs-on: ubuntu-24.04 22 | steps: 23 | - uses: actions/checkout@v6 24 | - uses: crate-ci/typos@v1.40.0 # selfup {"extract":"\\d\\.\\d+\\.\\d+","replacer":["bash","-c","typos --version | cut -d ' ' -f 2"]} 25 | with: 26 | files: | 27 | . 28 | .github 29 | .vscode 30 | -------------------------------------------------------------------------------- /.github/workflows/update-nixpkgs-and-versions-in-ci.yml: -------------------------------------------------------------------------------- 1 | name: 🤖🆙❄️ 2 | on: 3 | pull_request: 4 | paths: 5 | - '.github/workflows/update-nixpkgs-and-versions-in-ci.yml' 6 | schedule: 7 | # Every Monday 10:17 JST 8 | # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule 9 | - cron: '17 1 * * 1' 10 | workflow_dispatch: 11 | 12 | jobs: 13 | update-nixpkgs: 14 | uses: kachick/selfup/.github/workflows/reusable-bump-flake-lock-and-selfup.yml@v1.3.0 15 | with: 16 | app_id: ${{ vars.APP_ID }} 17 | dry-run: ${{ github.event_name == 'pull_request' }} 18 | pr-title: 'Bump flake.lock and related dependencies' 19 | optional-run: | 20 | nix develop --command ruby -e 'puts RUBY_VERSION' > .ruby-version 21 | # https://stackoverflow.com/q/34807971 22 | git update-index -q --really-refresh 23 | git diff-index --quiet HEAD || git commit -m 'Update .ruby-version' .ruby-version 24 | secrets: 25 | APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} 26 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Kenichi Kamiya 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to develop 2 | 3 | ## Setup whole environment 4 | 5 | If only changing Ruby code, this step is unnecessary 6 | 7 | 1. Install [Nix](https://nixos.org/) package manager and enable [Flakes](https://wiki.nixos.org/wiki/Flakes)\ 8 | Or use Nix installed containers. For example, look at [this repo](https://github.com/kachick/containers) 9 | 2. Run dev shell as one of the following 10 | - with [direnv](https://github.com/direnv/direnv): `direnv allow` 11 | - nix only: `nix develop` 12 | 3. You can use development tools 13 | 14 | ```console 15 | > nix develop 16 | (prepared bash) 17 | > dprint --version 18 | ... 19 | ``` 20 | 21 | ## How to release 22 | 23 | 1. Push tags as `v0.4.2` 24 | 2. Wait for complete the GitHub Actions 25 | 3. Run following commands 26 | ```bash 27 | cd "$(mktemp --directory)" 28 | curl -L https://github.com/kachick/irb-power_assert/releases/latest/download/irb-power_assert.gem > irb-power_assert.gem 29 | sha256sum irb-power_assert.gem # Make sure it has same hash as GitHub Action printed 30 | 31 | gem push irb-power_assert.gem --otp [CHECK_MFTA_TOOL] 32 | ``` 33 | 4. Check https://rubygems.org/gems/irb-power_assert 34 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 4 | }; 5 | 6 | outputs = 7 | { 8 | nixpkgs, 9 | ... 10 | }: 11 | let 12 | inherit (nixpkgs) lib; 13 | forAllSystems = lib.genAttrs lib.systems.flakeExposed; 14 | in 15 | { 16 | formatter = forAllSystems (system: nixpkgs.legacyPackages.${system}.nixfmt-tree); 17 | devShells = forAllSystems ( 18 | system: 19 | let 20 | pkgs = nixpkgs.legacyPackages.${system}; 21 | in 22 | { 23 | # Require CC to build io-console 24 | default = pkgs.mkShell { 25 | buildInputs = with pkgs; [ 26 | bashInteractive 27 | findutils # xargs 28 | nixfmt-rfc-style 29 | nixd 30 | 31 | ruby_3_4 32 | # Required to build psych via irb dependency 33 | # https://github.com/kachick/irb-power_assert/issues/116 34 | # https://github.com/ruby/irb/pull/648 35 | libyaml 36 | 37 | tree 38 | 39 | dprint 40 | typos 41 | ]; 42 | }; 43 | } 44 | ); 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler/gem_tasks' 4 | 5 | require 'rake/testtask' 6 | 7 | begin 8 | require 'rubocop/rake_task' 9 | rescue LoadError 10 | puts 'can not use rubocop in this environment' 11 | else 12 | RuboCop::RakeTask.new 13 | end 14 | 15 | task default: [:test_behaviors] 16 | 17 | task test_behaviors: [:test] 18 | 19 | desc 'Simulate CI results in local machine as possible' 20 | multitask simulate_ci: [:test_behaviors, :rubocop] 21 | 22 | Rake::TestTask.new(:test) do |tt| 23 | tt.pattern = 'test/**/test_*.rb' 24 | tt.warning = true 25 | end 26 | 27 | desc 'Prevent miss packaging!' 28 | task :view_packaging_files do 29 | sh 'rm -rf ./pkg' 30 | sh 'rake build' 31 | cd 'pkg' do 32 | sh 'gem unpack *.gem' 33 | sh 'tree -I *\.gem' 34 | end 35 | sh 'rm -rf ./pkg' 36 | end 37 | 38 | desc 'Print dependencies' 39 | task :deps do 40 | sh('ruby --version') 41 | sh('dprint --version') 42 | sh('tree --version') 43 | sh('typos --version') 44 | sh('nix --version') 45 | sh('nixfmt --version') 46 | end 47 | 48 | desc 'Linters except ruby' 49 | task :linters do 50 | sh('dprint check') 51 | sh('typos . .github .vscode') 52 | sh(%q!git ls-files '*.nix' | xargs nixfmt --check!) 53 | end 54 | -------------------------------------------------------------------------------- /lib/irb/cmd/pa.rb: -------------------------------------------------------------------------------- 1 | # coding: us-ascii 2 | # frozen_string_literal: true 3 | 4 | require 'power_assert' 5 | require 'power_assert/colorize' 6 | 7 | module IRB 8 | class PaCommand < IRB::Command::Base 9 | description 'Show inspections for each result.' 10 | category 'Misc' 11 | help_message 'Print PowerAssert inspection for the given expression.' 12 | 13 | def usage 14 | <<~'EOD' 15 | `pa` command will work for expressions that includes method calling. 16 | e.g. `pa (2 * 3 * 7).abs == 1010102.to_s.to_i(2)` 17 | EOD 18 | end 19 | 20 | def execute(expression) 21 | if expression == '' 22 | # Avoid warn and raise here, warn does not appear in irb and exception sounds like a IRB bug 23 | puts usage 24 | return 25 | end 26 | 27 | result = nil 28 | inspection = nil 29 | ::PowerAssert.start(expression, source_binding: irb_context.workspace.binding) do |pa| 30 | result = pa.yield 31 | inspection = pa.message_proc.call 32 | end 33 | 34 | if inspection == '' 35 | puts usage 36 | else 37 | puts inspection, "\n" 38 | end 39 | 40 | puts "=> #{result.inspect}" 41 | end 42 | end 43 | 44 | Command.register(:pa, PaCommand) 45 | end 46 | -------------------------------------------------------------------------------- /irb-power_assert.gemspec: -------------------------------------------------------------------------------- 1 | # coding: us-ascii 2 | # frozen_string_literal: true 3 | 4 | lib_name = 'irb-power_assert' 5 | 6 | require_relative './lib/irb/power_assert/version' 7 | repository_url = "https://github.com/kachick/#{lib_name}" 8 | 9 | Gem::Specification.new do |gem| 10 | gem.summary = %q{power_assert in irb} 11 | gem.description = %q{Use power_assert inspection in irb} 12 | gem.homepage = repository_url 13 | gem.license = 'MIT' 14 | gem.name = lib_name 15 | gem.version = IRB::PowerAssert::VERSION 16 | 17 | gem.metadata = { 18 | 'source_code_uri' => repository_url, 19 | 'bug_tracker_uri' => "#{repository_url}/issues", 20 | 'rubygems_mfa_required' => 'true', 21 | } 22 | 23 | gem.add_dependency 'irb', '>= 1.14.0', '< 2.0' 24 | gem.add_dependency 'power_assert', '>= 2.0.3', '< 4.0' 25 | 26 | gem.required_ruby_version = '>= 3.3' 27 | 28 | # common 29 | 30 | gem.authors = ['Kenichi Kamiya'] 31 | gem.email = ['kachick1+ruby@gmail.com'] 32 | might_be_parsing_by_tool_as_dependabot = `git ls-files`.lines.empty? 33 | files = Dir['README*', '*LICENSE*', 'lib/**/*', 'sig/**/*'].uniq 34 | if !might_be_parsing_by_tool_as_dependabot && files.grep(%r!\A(?:lib|sig)/!).size < 4 35 | raise "obvious mistaken in packaging files: #{files.inspect}" 36 | end 37 | gem.files = files 38 | gem.require_paths = ['lib'] 39 | end 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | /.config 4 | /coverage/ 5 | /InstalledFiles 6 | /pkg/ 7 | /spec/reports/ 8 | /spec/examples.txt 9 | /test/tmp/ 10 | /test/version_tmp/ 11 | /tmp/ 12 | 13 | # Used by dotenv library to load environment variables. 14 | # .env 15 | 16 | # Ignore Byebug command history file. 17 | .byebug_history 18 | 19 | ## Specific to RubyMotion: 20 | .dat* 21 | .repl_history 22 | build/ 23 | *.bridgesupport 24 | build-iPhoneOS/ 25 | build-iPhoneSimulator/ 26 | 27 | ## Specific to RubyMotion (use of CocoaPods): 28 | # 29 | # We recommend against adding the Pods directory to your .gitignore. However 30 | # you should judge for yourself, the pros and cons are mentioned at: 31 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 32 | # 33 | # vendor/Pods/ 34 | 35 | ## Documentation cache and generated files: 36 | /.yardoc/ 37 | /_yardoc/ 38 | /doc/ 39 | /rdoc/ 40 | 41 | ## Environment normalization: 42 | /.bundle/* 43 | !.bundle/config 44 | /vendor/ 45 | 46 | # for a library or gem, you might want to ignore these files since the code is 47 | # intended to run in multiple environments; otherwise, check them in: 48 | # Gemfile.lock 49 | # .ruby-version 50 | # .ruby-gemset 51 | 52 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 53 | .rvmrc 54 | 55 | # Used by RuboCop. Remote config files pulled in from inherit_from directive. 56 | # .rubocop-https?--* 57 | 58 | *.lock 59 | !flake.lock 60 | .direnv/ 61 | 62 | .DS_Store 63 | 64 | .irb_history 65 | -------------------------------------------------------------------------------- /.github/workflows/ci-nix.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/NixOS/nixos-artwork/blob/35ebbbf01c3119005ed180726c388a01d4d1100c/logo/README.md#L5 2 | name: ❄️ 3 | on: 4 | push: 5 | branches: [main] 6 | paths: 7 | - '.github/workflows/ci-nix.yml' 8 | - '**.nix' 9 | - 'flake.*' 10 | - '.ruby-version' 11 | pull_request: 12 | paths: 13 | - '.github/workflows/ci-nix.yml' 14 | - '**.nix' 15 | - 'flake.*' 16 | - '.ruby-version' 17 | schedule: 18 | # Every 10:42 JST 19 | # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule 20 | - cron: '42 1 * * *' 21 | workflow_dispatch: 22 | 23 | jobs: 24 | tasks: 25 | runs-on: ubuntu-24.04 26 | timeout-minutes: 30 27 | steps: 28 | - uses: actions/checkout@v6 29 | - uses: cachix/install-nix-action@0b0e072294b088b73964f1d72dfdac0951439dbd # v31.8.4 30 | with: 31 | extra_nix_config: | 32 | sandbox = true 33 | accept-flake-config = true 34 | - run: nix flake check 35 | - run: nix develop --command echo 'This step should be done before any other "nix develop" steps because of measuring Nix build time' 36 | - run: nix develop --command bundle install 37 | - name: Log current versions 38 | run: nix develop --command bundle exec rake deps 39 | - name: Test with external dependencies 40 | run: nix develop --command bundle exec rake linters 41 | - name: Test with Ruby 42 | run: nix develop --command bundle exec rake 43 | -------------------------------------------------------------------------------- /test/helper.rb: -------------------------------------------------------------------------------- 1 | # coding: us-ascii 2 | # frozen_string_literal: true 3 | 4 | require 'stringio' 5 | require 'warning' 6 | require 'prettyprint' 7 | 8 | # https://test-unit.github.io/test-unit/en/ 9 | require 'test/unit' 10 | 11 | # https://github.com/ruby/test-unit-ruby-core 12 | require 'envutil' 13 | # Test::Unit::TestCase.include Test::Unit::CoreAssertions 14 | 15 | Warning[:deprecated] = true 16 | Warning[:experimental] = true 17 | 18 | Gem.path.each do |path| 19 | Warning.ignore(//, path) 20 | end 21 | 22 | # https://github.com/kachick/irb-power_assert/issues/176 23 | # https://github.com/ruby/ruby/blob/e5b585ba908d371c67d97988795a5e40ec2f9e93/lib/prettyprint.rb#L184 24 | Warning.ignore(/literal string will be frozen in the future/, PrettyPrint.instance_method(:text).source_location.first) 25 | 26 | Warning.process do |_warning| 27 | :raise 28 | end 29 | 30 | require_relative '../lib/irb-power_assert' 31 | 32 | module TestIRBPowerAssertHelpers 33 | class TestInputMethod < ::IRB::InputMethod 34 | attr_reader :list, :line_no 35 | 36 | def initialize(list = []) 37 | super() 38 | @line_no = 0 39 | @list = list 40 | end 41 | 42 | def gets 43 | @list[@line_no]&.tap { @line_no += 1 } 44 | end 45 | 46 | def eof? 47 | @line_no >= @list.size 48 | end 49 | 50 | def encoding 51 | Encoding.default_external 52 | end 53 | 54 | def reset 55 | @line_no = 0 56 | end 57 | end 58 | 59 | def save_encodings 60 | @default_encoding = [Encoding.default_external, Encoding.default_internal] 61 | @stdio_encodings = [STDIN, STDOUT, STDERR].map { |io| [io.external_encoding, io.internal_encoding] } 62 | end 63 | 64 | def restore_encodings 65 | EnvUtil.suppress_warning do 66 | Encoding.default_external, Encoding.default_internal = *@default_encoding 67 | [STDIN, STDOUT, STDERR].zip(@stdio_encodings) do |io, encs| 68 | io.set_encoding(*encs) 69 | end 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /.github/workflows/ci-ruby.yml: -------------------------------------------------------------------------------- 1 | name: 💎 2 | on: 3 | push: 4 | tags: 5 | - 'v*.*.*' 6 | branches: 7 | - main 8 | paths: 9 | - '.github/workflows/ci-ruby.yml' 10 | - '.ruby-version' 11 | - '**.gemspec' 12 | - '**Gemfile' 13 | - 'Rakefile' 14 | - '**.rb' 15 | pull_request: 16 | paths: 17 | - '.github/workflows/ci-ruby.yml' 18 | - '.ruby-version' 19 | - '**.gemspec' 20 | - '**Gemfile' 21 | - 'Rakefile' 22 | - '**.rb' 23 | schedule: 24 | # Every 10:42 JST 25 | # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule 26 | - cron: '42 1 * * *' 27 | workflow_dispatch: 28 | 29 | jobs: 30 | test: 31 | strategy: 32 | fail-fast: false 33 | matrix: 34 | os: [ubuntu-24.04] 35 | # Due to https://github.com/actions/runner/issues/849, we have to use quotes for '3.0' 36 | ruby: ['head', '3.4', '3.3'] 37 | gemfile: ['Gemfile', 'gemfiles/oldest/Gemfile'] 38 | runs-on: ${{ matrix.os }} 39 | env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps 40 | BUNDLE_GEMFILE: '${{ github.workspace }}/${{ matrix.gemfile }}' 41 | # https://github.com/kachick/irb-power_assert/blob/104834846baf5caa1e8536a11c43acdd56fc849c/CONTRIBUTING.md#adding-dependencies-for-this-gem 42 | BUNDLE_WITHOUT: development 43 | steps: 44 | - uses: actions/checkout@v6 45 | - uses: ruby/setup-ruby@v1 46 | with: 47 | ruby-version: ${{ matrix.ruby }} 48 | # Enabling is the recommended way, but it cannot detect runner changes in early stage. 49 | # So disable it is better for test job, do not mind in other jobs 50 | bundler-cache: false # runs 'bundle install' and caches installed gems automatically 51 | - run: bundle install 52 | - run: bundle exec rake test 53 | 54 | rubocop: 55 | runs-on: 'ubuntu-24.04' 56 | steps: 57 | - uses: actions/checkout@v6 58 | - uses: ruby/setup-ruby@v1 59 | with: 60 | bundler-cache: true 61 | - run: bundle exec rake rubocop 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # irb-power_assert 2 | 3 | [![Build Status](https://github.com/kachick/irb-power_assert/actions/workflows/ci-ruby.yml/badge.svg?branch=main)](https://github.com/kachick/irb-power_assert/actions/workflows/ci-ruby.yml?query=branch%3Amain+) 4 | [![Gem Version](https://badge.fury.io/rb/irb-power_assert.svg)](http://badge.fury.io/rb/irb-power_assert) 5 | 6 | Use power_assert inspection in irb 7 | 8 | ## Usage 9 | 10 | Tested only in ruby-head and the last 2 stable versions\ 11 | So require Ruby 3.3 or higher 12 | 13 | ```console 14 | $ gem install irb-power_assert 15 | ...installed 16 | ``` 17 | 18 | ```console 19 | $ irb -r irb-power_assert 20 | # enabled this gem 21 | ``` 22 | 23 | Or specify in your `~/.irbrc` as below 24 | 25 | ```ruby 26 | require 'irb/power_assert' 27 | ``` 28 | 29 | ```console 30 | $ irb 31 | irb(main):004> help pa 32 | Print PowerAssert inspection for the given expression. 33 | ``` 34 | 35 | Then you can use `pa` as an IRB command. 36 | 37 | ```ruby 38 | irb(main):001:0> pa "0".class == "3".to_i.times.map {|i| i + 1 }.class 39 | "0".class == "3".to_i.times.map {|i| i + 1 }.class 40 | | | | | | | 41 | | | | | | Array 42 | | | | | [1, 2, 3] 43 | | | | # 44 | | | 3 45 | | false 46 | String 47 | 48 | => false 49 | ``` 50 | 51 | No hack is needed in your irbrc 52 | 53 | ## Thanks! 54 | 55 | [ruby/power_assert](https://github.com/ruby/power_assert) is a recent my favorites.\ 56 | (the author is [@k-tsj](https://github.com/k-tsj), thank you!) 57 | 58 | It is super helpful in complex testing. 59 | 60 | I just would get irb version of 61 | [yui-knk/pry-power_assert](https://github.com/yui-knk/pry-power_assert). 62 | 63 | Latest IRB is much helpful to [create own command](https://github.com/ruby/irb/pull/886) 64 | 65 | Honor should be bestowed upon them. 66 | 67 | ## References 68 | 69 | - [power-assert-js/power-assert](https://github.com/power-assert-js/power-assert) 70 | - [Power Assert in Ruby](https://speakerdeck.com/k_tsj/power-assert-in-ruby) 71 | - [pry-power_assert implementation](https://github.com/yui-knk/pry-power_assert/blob/2d10ee3df8efaf9c448f31d51bff8033a1792739/lib/pry-power_assert.rb#L26-L35) 72 | -------------------------------------------------------------------------------- /.github/workflows/merge-bot-pr.yml: -------------------------------------------------------------------------------- 1 | name: 🤖👌🤖 2 | on: pull_request 3 | 4 | permissions: 5 | contents: write 6 | pull-requests: write 7 | # checks: read # For private repositories 8 | # actions: read # For private repositories 9 | 10 | jobs: 11 | dependabot: 12 | runs-on: ubuntu-24.04 13 | if: ${{ github.actor == 'dependabot[bot]' }} 14 | steps: 15 | - name: Dependabot metadata 16 | id: metadata 17 | uses: dependabot/fetch-metadata@v2.4.0 18 | - name: Wait other jobs 19 | if: ${{ steps.metadata.outputs.update-type != 'version-update:semver-major' }} 20 | uses: kachick/wait-other-jobs@v3 21 | with: 22 | skip-same-workflow: 'true' 23 | skip-list: | 24 | [ 25 | { 26 | "workflowFile": "ci-ruby.yml", 27 | "jobName": "build_and_release" 28 | } 29 | ] 30 | timeout-minutes: 10 31 | - name: Approve and merge 32 | if: ${{ (steps.metadata.outputs.update-type != 'version-update:semver-major') || contains(steps.metadata.outputs.dependency-names, 'cachix') }} 33 | run: gh pr review --approve "$PR_URL" && gh pr merge --auto --squash --delete-branch "$PR_URL" 34 | env: 35 | PR_URL: ${{ github.event.pull_request.html_url }} 36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 37 | 38 | # Avoid `automerge` renovate official feature. 39 | # It wait longtime to be merged. 40 | # Avoid `platformAutomerge` renovate official feature. 41 | # It requires many changes in GitHub settings. 42 | # - `Allow auto-merge` 43 | # - `Require status checks to pass before merging` and specify the status names 44 | # Changing in all personal repository is annoy task for me. Even if using terrafform, getting mandatory CI names in each repo is too annoy! 45 | renovate: 46 | timeout-minutes: 30 47 | runs-on: ubuntu-24.04 48 | if: ${{ github.actor == 'renovate[bot]' }} 49 | steps: 50 | - name: Wait other jobs 51 | uses: kachick/wait-other-jobs@v3 52 | with: 53 | skip-same-workflow: 'true' 54 | timeout-minutes: 10 55 | - name: Approve and merge 56 | run: gh pr review --approve "$PR_URL" && gh pr merge --auto --squash --delete-branch "$PR_URL" 57 | env: 58 | PR_URL: ${{ github.event.pull_request.html_url }} 59 | GITHUB_TOKEN: ${{ github.token }} 60 | 61 | # https://github.com/kachick/anylang-template/issues/51 62 | selfup-runner: 63 | timeout-minutes: 30 64 | runs-on: ubuntu-24.04 65 | if: ${{ github.actor == 'selfup-runner[bot]' }} 66 | steps: 67 | - name: Wait other jobs 68 | uses: kachick/wait-other-jobs@v3 69 | with: 70 | skip-same-workflow: 'true' 71 | timeout-minutes: 20 72 | - name: Approve and merge 73 | run: gh pr review --approve "$PR_URL" && gh pr merge --auto --delete-branch --squash "$PR_URL" 74 | env: 75 | PR_URL: ${{ github.event.pull_request.html_url }} 76 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 77 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | - rubocop-rake 3 | 4 | AllCops: 5 | TargetRubyVersion: 3.3 6 | DisplayCopNames: true 7 | DisabledByDefault: true 8 | Exclude: 9 | - '**/vendor/**/*' 10 | - 'pkg/**/*' 11 | NewCops: enable 12 | 13 | Security: 14 | Enabled: true 15 | 16 | Security/Eval: 17 | Exclude: 18 | - 'examples/**/*' 19 | 20 | Style/HashSyntax: 21 | Enabled: true 22 | 23 | Style/TrailingMethodEndStatement: 24 | Enabled: true 25 | 26 | Style/MethodDefParentheses: 27 | Enabled: true 28 | 29 | Style/TrailingCommaInBlockArgs: 30 | Enabled: true 31 | 32 | Style/StringLiterals: 33 | Enabled: true 34 | EnforcedStyle: 'single_quotes' 35 | 36 | Style/StringLiteralsInInterpolation: 37 | Enabled: true 38 | EnforcedStyle: 'single_quotes' 39 | 40 | Style/TopLevelMethodDefinition: 41 | Enabled: true 42 | 43 | Style/InPatternThen: 44 | Enabled: true 45 | 46 | Style/HashEachMethods: 47 | Enabled: true 48 | 49 | Style/QuotedSymbols: 50 | Enabled: true 51 | EnforcedStyle: 'single_quotes' 52 | 53 | Style/MultilineInPatternThen: 54 | Enabled: true 55 | 56 | Layout/TrailingEmptyLines: 57 | Enabled: true 58 | 59 | Layout/TrailingWhitespace: 60 | Enabled: true 61 | 62 | Layout/SpaceBeforeFirstArg: 63 | Enabled: true 64 | 65 | Layout/SpaceBeforeSemicolon: 66 | Enabled: true 67 | 68 | Layout/SpaceInsideArrayPercentLiteral: 69 | Enabled: true 70 | 71 | Layout/SpaceInsideBlockBraces: 72 | Enabled: true 73 | 74 | Layout/SpaceInsideParens: 75 | Enabled: true 76 | 77 | Layout/SpaceInsidePercentLiteralDelimiters: 78 | Enabled: true 79 | 80 | Layout/SpaceInsideRangeLiteral: 81 | Enabled: true 82 | 83 | Layout/SpaceInsideReferenceBrackets: 84 | Enabled: true 85 | 86 | Layout/SpaceInsideStringInterpolation: 87 | Enabled: true 88 | 89 | Layout/SpaceAroundMethodCallOperator: 90 | Enabled: true 91 | 92 | Layout/SpaceAroundKeyword: 93 | Enabled: true 94 | 95 | Layout/ArgumentAlignment: 96 | Enabled: true 97 | 98 | Layout/CaseIndentation: 99 | Enabled: true 100 | 101 | Naming/MethodName: 102 | Enabled: true 103 | 104 | Naming/FileName: 105 | Enabled: true 106 | Exclude: 107 | - 'lib/irb-power_assert.rb' 108 | 109 | Naming/ConstantName: 110 | Enabled: true 111 | 112 | Naming/ClassAndModuleCamelCase: 113 | Enabled: true 114 | 115 | Naming/BlockParameterName: 116 | Enabled: true 117 | 118 | Naming/HeredocDelimiterCase: 119 | Enabled: true 120 | 121 | Bundler: 122 | Enabled: true 123 | 124 | Bundler/OrderedGems: 125 | Enabled: false 126 | 127 | Gemspec: 128 | Enabled: true 129 | 130 | Gemspec/OrderedDependencies: 131 | Enabled: false 132 | 133 | Lint: 134 | Enabled: true 135 | 136 | Lint/InheritException: 137 | Enabled: false 138 | 139 | Lint/RedundantStringCoercion: 140 | Enabled: false 141 | 142 | Lint/BinaryOperatorWithIdenticalOperands: 143 | Exclude: 144 | - 'test/**/*' 145 | 146 | Lint/UnusedMethodArgument: 147 | Enabled: false 148 | 149 | Lint/AssignmentInCondition: 150 | Enabled: false 151 | 152 | Lint/RescueException: 153 | Enabled: false 154 | 155 | Lint/DuplicateMethods: 156 | Enabled: true 157 | 158 | Lint/EmptyInPattern: 159 | Enabled: true 160 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 2 | on: 3 | push: 4 | tags: 5 | - 'v[0-9]+.[0-9]+.[0-9]+*' 6 | branches: 7 | - main 8 | paths: 9 | - '.github/workflows/release.yml' 10 | - '.ruby-version' 11 | - '**.gemspec' 12 | - '**Gemfile' 13 | - 'Rakefile' 14 | - '**.rb' 15 | pull_request: 16 | paths: 17 | - '.github/workflows/release.yml' 18 | - '.ruby-version' 19 | - '**.gemspec' 20 | - '**Gemfile' 21 | - 'Rakefile' 22 | - '**.rb' 23 | workflow_dispatch: 24 | 25 | jobs: 26 | build: 27 | runs-on: 'ubuntu-24.04' 28 | steps: 29 | - uses: actions/checkout@v6 30 | - uses: ruby/setup-ruby@v1 31 | with: 32 | bundler-cache: true 33 | - run: mkdir -p pkg 34 | - run: bundle exec gem build --strict --norc --output=pkg/irb-power_assert.gem irb-power_assert.gemspec 35 | - name: Make sure we can use the gem 36 | run: | 37 | gem install pkg/irb-power_assert.gem 38 | echo 'pa (2 * 3 * 7).abs == 1010102.to_s.to_i(2)' | irb -r irb-power_assert --script - 39 | - name: Upload artifact 40 | uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 41 | with: 42 | name: 'pkg' 43 | path: pkg/irb-power_assert.gem 44 | 45 | github: 46 | runs-on: 'ubuntu-24.04' 47 | timeout-minutes: 15 48 | needs: 49 | - build 50 | env: 51 | GH_TOKEN: ${{ github.token }} 52 | if: startsWith(github.ref, 'refs/tags/') 53 | steps: 54 | # Required to checkout for gh command 55 | - uses: actions/checkout@v6 56 | - name: Dowbload prebuild assets 57 | run: | 58 | gh run download '${{ github.run_id }}' 59 | tree 60 | - name: Release 61 | run: | 62 | gh release create --verify-tag "$GITHUB_REF_NAME" --title "$GITHUB_REF_NAME" pkg/irb-power_assert.gem 63 | 64 | rubygems: 65 | name: Push gem to RubyGems.org 66 | runs-on: 'ubuntu-24.04' 67 | needs: 68 | - build 69 | - github # With the implementation, parallel is okay, however wait for it regarding rollback difficulty 70 | 71 | permissions: 72 | id-token: write # IMPORTANT: this permission is mandatory for trusted publishing 73 | contents: write # IMPORTANT: this permission is required for `rake release` to push the release tag 74 | 75 | # https://github.com/kachick/irb-power_assert/deployments/release 76 | # https://github.com/kachick/irb-power_assert/settings/environments 77 | environment: release 78 | 79 | if: startsWith(github.ref, 'refs/tags/') 80 | 81 | env: 82 | GH_TOKEN: ${{ github.token }} 83 | 84 | steps: 85 | - uses: actions/checkout@v6 86 | - name: Set up Ruby 87 | uses: ruby/setup-ruby@v1 88 | with: 89 | bundler-cache: false # Don't enable while using .bundle/config. See https://github.com/kachick/rspec-matchers-power_assert_matchers/issues/223#issuecomment-2562853948 90 | - run: bundle install 91 | - name: Dowbload prebuild assets 92 | run: | 93 | gh run download '${{ github.run_id }}' 94 | tree 95 | - name: Inspect the gem 96 | run: | 97 | cd pkg 98 | sha256sum ./irb-power_assert.gem 99 | gem unpack ./irb-power_assert.gem 100 | tree -I *.gem 101 | - uses: kachick/wait-other-jobs@v3 102 | with: 103 | skip-same-workflow: true 104 | skip-list: | 105 | [ 106 | { 107 | "workflowFile": "merge-bot-pr.yml" 108 | } 109 | ] 110 | - uses: rubygems/release-gem@v1 111 | -------------------------------------------------------------------------------- /test/test_irb_power_assert.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # frozen_string_literal: true 3 | 4 | require_relative 'helper' 5 | 6 | require 'stringio' 7 | 8 | class TestIRBPowerAssertNoEnv < Test::Unit::TestCase 9 | def test_constants 10 | assert(IRB::PowerAssert::VERSION.frozen?) 11 | assert do 12 | Gem::Version.correct?(IRB::PowerAssert::VERSION) 13 | end 14 | 15 | am = method(:assert_match) 16 | ::PowerAssert.class_exec do 17 | am.call(%r{#{Regexp.escape(Dir.pwd)}/lib}, const_get(:INTERNAL_LIB_DIRS)[IRB::PowerAssert]) 18 | end 19 | end 20 | end 21 | 22 | class TestIRBPowerAssertWithEnv < Test::Unit::TestCase 23 | include TestIRBPowerAssertHelpers 24 | 25 | def setup 26 | @pwd = Dir.pwd 27 | @tmpdir = File.join(Dir.tmpdir, "test_reline_config_#{$$}") 28 | begin 29 | Dir.mkdir(@tmpdir) 30 | rescue Errno::EEXIST 31 | FileUtils.rm_rf(@tmpdir) 32 | Dir.mkdir(@tmpdir) 33 | end 34 | Dir.chdir(@tmpdir) 35 | @home_backup = ENV['HOME'] 36 | ENV['HOME'] = @tmpdir 37 | @xdg_config_home_backup = ENV.delete('XDG_CONFIG_HOME') 38 | save_encodings 39 | IRB.instance_variable_get(:@CONF).clear 40 | IRB.instance_variable_set(:@existing_rc_name_generators, nil) 41 | @is_win = (RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/) 42 | end 43 | 44 | def teardown 45 | ENV['XDG_CONFIG_HOME'] = @xdg_config_home_backup 46 | ENV['HOME'] = @home_backup 47 | Dir.chdir(@pwd) 48 | FileUtils.rm_rf(@tmpdir) 49 | restore_encodings 50 | end 51 | 52 | def execute_lines(*lines, conf: {}, main: self, irb_path: nil) 53 | capture_output do 54 | IRB.init_config(nil) 55 | IRB.conf[:VERBOSE] = false 56 | IRB.conf[:PROMPT_MODE] = :SIMPLE 57 | IRB.conf[:USE_PAGER] = false 58 | IRB.conf.merge!(conf) 59 | input = TestInputMethod.new(lines) 60 | irb = IRB::Irb.new(IRB::WorkSpace.new(main), input) 61 | irb.context.return_format = "=> %s\n" 62 | irb.context.irb_path = irb_path if irb_path 63 | IRB.conf[:MAIN_CONTEXT] = irb.context 64 | irb.eval_input 65 | end 66 | end 67 | 68 | def test_typical_example 69 | expected =<<~'EOD' 70 | "0".class == "3".to_i.times.map {|i| i + 1 }.class 71 | | | | | | | 72 | | | | | | Array 73 | | | | | [1, 2, 3] 74 | | | | # 75 | | | 3 76 | | false 77 | String 78 | 79 | => false 80 | EOD 81 | 82 | out, err = execute_lines(%q{pa "0".class == "3".to_i.times.map {|i| i + 1 }.class}) 83 | 84 | assert_equal('', err) 85 | assert_equal(expected, out) 86 | end 87 | 88 | def test_usage 89 | out, err = execute_lines(%q{pa}) 90 | 91 | assert_equal('', err) 92 | assert_match(/will work for expressions that includes method calling/, out) 93 | 94 | # With whitespace 95 | out, err = execute_lines(%q{pa }) 96 | 97 | assert_equal('', err) 98 | assert_match(/will work for expressions that includes method calling/, out) 99 | 100 | # No variable and method callings 101 | out, err = execute_lines(%q{pa 42}) 102 | 103 | assert_equal('', err) 104 | assert_match(/will work for expressions that includes method calling/, out) 105 | 106 | # Includes method calling will not show usage 107 | expected =<<~'EOD' 108 | 42.abs 109 | | 110 | 42 111 | 112 | => 42 113 | EOD 114 | 115 | out, err = execute_lines(%q{pa 42.abs}) 116 | 117 | assert_equal('', err) 118 | assert_equal(expected, out) 119 | end 120 | 121 | def test_help 122 | out, err = execute_lines(%q{help pa}) 123 | 124 | assert_equal('', err) 125 | assert_match(/Print.+PowerAssert.+inspection/i, out) 126 | end 127 | end 128 | --------------------------------------------------------------------------------