├── .github ├── dependabot.yml └── workflows │ ├── push_gem.yml │ └── test.yml ├── .gitignore ├── LICENSE ├── README.md ├── Rakefile ├── docker-compose.yml ├── gems.rb ├── lib └── ruby2_keywords.rb ├── rakelib ├── changelogs.rake ├── epoch.rake └── version.rake ├── ruby2_keywords.gemspec └── test └── test_keyword.rb /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'github-actions' 4 | directory: '/' 5 | schedule: 6 | interval: 'weekly' 7 | -------------------------------------------------------------------------------- /.github/workflows/push_gem.yml: -------------------------------------------------------------------------------- 1 | name: Publish gem to rubygems.org 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | push: 13 | if: github.repository == 'ruby/ruby2_keywords' 14 | runs-on: ubuntu-latest 15 | 16 | environment: 17 | name: rubygems.org 18 | url: https://rubygems.org/gems/ruby2_keywords 19 | 20 | permissions: 21 | contents: write 22 | id-token: write 23 | 24 | steps: 25 | - name: Harden Runner 26 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 27 | with: 28 | egress-policy: audit 29 | 30 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 31 | 32 | - name: Set up Ruby 33 | uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0 34 | with: 35 | bundler-cache: true 36 | ruby-version: "ruby" 37 | 38 | - name: Publish to RubyGems 39 | uses: rubygems/release-gem@a25424ba2ba8b387abc8ef40807c2c85b96cbe32 # v1.1.1 40 | 41 | - name: Create GitHub release 42 | run: | 43 | tag_name="$(git describe --tags --abbrev=0)" 44 | gh release create "${tag_name}" --verify-tag --generate-notes 45 | env: 46 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 47 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | ruby-versions: 7 | uses: ruby/actions/.github/workflows/ruby_versions.yml@master 8 | with: 9 | engine: cruby 10 | min_version: 2.1 11 | 12 | build: 13 | needs: ruby-versions 14 | name: build (${{ matrix.ruby }} / ${{ matrix.os }}) 15 | strategy: 16 | matrix: 17 | ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }} 18 | os: [ ubuntu-latest, macos-latest, windows-latest ] 19 | include: 20 | - { os: ubuntu-latest, ruby: truffleruby-head } 21 | - { os: macos-latest, ruby: truffleruby-head } 22 | exclude: 23 | - { os: macos-latest, ruby: 2.1 } 24 | - { os: macos-latest, ruby: 2.2 } 25 | - { os: macos-latest, ruby: 2.3 } 26 | - { os: macos-latest, ruby: 2.4 } 27 | - { os: macos-latest, ruby: 2.5 } 28 | runs-on: ${{ matrix.os }} 29 | steps: 30 | - name: git config 31 | run: | 32 | git config --global core.autocrlf false 33 | git config --global core.eol lf 34 | git config --global advice.detachedHead 0 35 | - uses: actions/checkout@master 36 | - name: Set up Ruby 37 | uses: ruby/setup-ruby@v1 38 | with: 39 | ruby-version: ${{ matrix.ruby }} 40 | bundler-cache: true 41 | - name: Run test 42 | run: bundle exec rake test 43 | - id: build 44 | run: | 45 | rake build 46 | echo "pkg=${GITHUB_REPOSITORY#*/}-${RUNNING_OS%-*}" >> $GITHUB_OUTPUT 47 | env: 48 | RUNNING_OS: ${{matrix.os}} 49 | if: "matrix.ruby == '3.0'" 50 | shell: bash 51 | - name: Upload package 52 | uses: actions/upload-artifact@v4 53 | with: 54 | path: pkg/*.gem 55 | name: ${{steps.build.outputs.pkg}} 56 | if: steps.build.outputs.pkg 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ChangeLog 2 | logs/ 3 | gems.locked 4 | pkg/ 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019-2020 Nobuyoshi Nakada, Yusuke Endoh 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ruby2_keywords 2 | 3 | Provides empty `Module#ruby2_keywords` method, for the forward 4 | source-level compatibility against ruby2.7 and ruby3. 5 | 6 | ## Installation 7 | 8 | Add this line to your application's Gemfile: 9 | 10 | ```ruby 11 | gem 'ruby2_keywords' 12 | ``` 13 | 14 | And then execute: 15 | 16 | $ bundle 17 | 18 | Or install it yourself as: 19 | 20 | $ gem install ruby2_keywords 21 | 22 | ## Usage 23 | 24 | For class/module instance methods: 25 | 26 | ```ruby 27 | require 'ruby2_keywords' 28 | 29 | module YourModule 30 | ruby2_keywords def delegating_method(*args) 31 | other_method(*args) 32 | end 33 | end 34 | ``` 35 | 36 | For global methods: 37 | 38 | ```ruby 39 | require 'ruby2_keywords' 40 | 41 | ruby2_keywords def oldstyle_keywords(options = {}) 42 | end 43 | ``` 44 | 45 | You can do the same for a method defined by `Module#define_method`: 46 | 47 | ```ruby 48 | define_method :delegating_method do |*args, &block| 49 | other_method(*args, &block) 50 | end 51 | ruby2_keywords :delegating_method 52 | ``` 53 | 54 | ## Contributing 55 | 56 | Bug reports and pull requests are welcome on [GitHub] or 57 | [Ruby Issue Tracking System]. 58 | 59 | ## Development 60 | 61 | After checking out the repo, run `bundle install` to install dependencies. 62 | Then, run `bundle exec rake test` to run the tests. 63 | 64 | To test on older Ruby versions, you can use docker. E.g. to test on Ruby 2.0, 65 | use `docker-compose run ruby-2.0`. 66 | 67 | ## License 68 | 69 | The gem is available as open source under the terms of the 70 | [Ruby License] or the [2-Clause BSD License]. 71 | 72 | [GitHub]: https://github.com/ruby/ruby2_keywords/ 73 | [Ruby Issue Tracking System]: https://bugs.ruby-lang.org 74 | [Ruby License]: https://www.ruby-lang.org/en/about/license.txt 75 | [2-Clause BSD License]: https://opensource.org/licenses/BSD-2-Clause 76 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rake/testtask" 3 | 4 | Rake::TestTask.new(:test) do |t| 5 | t.test_files = FileList["test/**/test_*.rb"] 6 | end 7 | 8 | task :default => :test 9 | 10 | task "bump:minor" do 11 | raise "can't bump up minor" 12 | end 13 | 14 | task "bump:major" do 15 | raise "can't bump up major" 16 | end 17 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.0' 2 | 3 | services: 4 | ruby-2.0: 5 | image: ruby:2.0 6 | volumes: 7 | - .:/app 8 | command: 9 | bash -c 'cd /app && bundle install && bundle exec rake test' 10 | ruby-2.1: 11 | image: ruby:2.1 12 | volumes: 13 | - .:/app 14 | command: 15 | bash -c 'cd /app && bundle install && bundle exec rake test' 16 | ruby-2.2: 17 | image: ruby:2.2 18 | volumes: 19 | - .:/app 20 | command: 21 | bash -c 'cd /app && bundle install && bundle exec rake test' 22 | ruby-2.3: 23 | image: ruby:2.3 24 | volumes: 25 | - .:/app 26 | command: 27 | bash -c 'cd /app && bundle install && bundle exec rake test' 28 | ruby-2.4: 29 | image: ruby:2.4 30 | volumes: 31 | - .:/app 32 | command: 33 | bash -c 'cd /app && bundle install && bundle exec rake test' 34 | ruby-2.5: 35 | image: ruby:2.5 36 | volumes: 37 | - .:/app 38 | command: 39 | bash -c 'cd /app && bundle install && bundle exec rake test' 40 | ruby-2.6: 41 | image: ruby:2.6 42 | volumes: 43 | - .:/app 44 | command: 45 | bash -c 'cd /app && bundle install && bundle exec rake test' 46 | ruby-2.7: 47 | image: ruby:2.7 48 | volumes: 49 | - .:/app 50 | command: 51 | bash -c 'cd /app && bundle install && bundle exec rake test' 52 | ruby-3.0: 53 | image: ruby:3.0 54 | volumes: 55 | - .:/app 56 | command: 57 | bash -c 'cd /app && bundle install && bundle exec rake test' 58 | -------------------------------------------------------------------------------- /gems.rb: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | group :development do 6 | gem "test-unit", ">= 2.2" 7 | gem "rake" 8 | end 9 | -------------------------------------------------------------------------------- /lib/ruby2_keywords.rb: -------------------------------------------------------------------------------- 1 | class Module 2 | unless private_method_defined?(:ruby2_keywords) 3 | private 4 | # call-seq: 5 | # ruby2_keywords(method_name, ...) 6 | # 7 | # Does nothing. 8 | def ruby2_keywords(name, *) 9 | # nil 10 | end 11 | end 12 | end 13 | 14 | main = TOPLEVEL_BINDING.eval('self') 15 | unless main.respond_to?(:ruby2_keywords, true) 16 | # call-seq: 17 | # ruby2_keywords(method_name, ...) 18 | # 19 | # Does nothing. 20 | def main.ruby2_keywords(name, *) 21 | # nil 22 | end 23 | end 24 | 25 | class Proc 26 | unless method_defined?(:ruby2_keywords) 27 | # call-seq: 28 | # proc.ruby2_keywords -> proc 29 | # 30 | # Does nothing and just returns the receiver. 31 | def ruby2_keywords 32 | self 33 | end 34 | end 35 | end 36 | 37 | class << Hash 38 | unless method_defined?(:ruby2_keywords_hash?) 39 | # call-seq: 40 | # Hash.ruby2_keywords_hash?(hash) -> false 41 | # 42 | # Returns false. 43 | def ruby2_keywords_hash?(hash) 44 | false 45 | end 46 | end 47 | 48 | unless method_defined?(:ruby2_keywords_hash) 49 | # call-seq: 50 | # Hash.ruby2_keywords_hash(hash) -> new_hash 51 | # 52 | # Duplicates a given hash and returns the new hash. 53 | def ruby2_keywords_hash(hash) 54 | hash.dup 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /rakelib/changelogs.rake: -------------------------------------------------------------------------------- 1 | task "build" => "changelogs" 2 | 3 | changelog = proc do |output, ver = nil, prev = nil| 4 | ver &&= Gem::Version.new(ver) 5 | range = [[prev], [ver, "HEAD"]].map {|ver, branch| ver ? "v#{ver.to_s}" : branch}.compact.join("..") 6 | IO.popen(%W[git log --format=fuller --topo-order --no-merges #{range}]) do |log| 7 | line = log.gets 8 | FileUtils.mkpath(File.dirname(output)) 9 | File.open(output, "wb") do |f| 10 | f.print "-*- coding: utf-8 -*-\n\n", line 11 | log.each_line do |line| 12 | line.sub!(/^(?!:)(?:Author|Commit)?(?:Date)?: /, ' \&') 13 | line.sub!(/ +$/, '') 14 | f.print(line) 15 | end 16 | end 17 | end 18 | end 19 | 20 | tags = IO.popen(%w[git tag -l v[0-9]*]).grep(/v(.*)/) {$1} 21 | tags.sort_by! {|tag| tag.scan(/\d+/).map(&:to_i)} 22 | tags.inject(nil) do |prev, tag| 23 | task("logs/ChangeLog-#{tag}") {|t| changelog[t.name, tag, prev]} 24 | tag 25 | end 26 | 27 | desc "Make ChangeLog" 28 | task "ChangeLog", [:ver, :prev] do |t, ver: nil, prev: tags.last| 29 | changelog[t.name, ver, prev] 30 | end 31 | 32 | changelogs = ["ChangeLog", *tags.map {|tag| "logs/ChangeLog-#{tag}"}] 33 | task "changelogs" => changelogs 34 | CLOBBER.concat(changelogs) << "logs" 35 | -------------------------------------------------------------------------------- /rakelib/epoch.rake: -------------------------------------------------------------------------------- 1 | task "build" => "date_epoch" 2 | 3 | task "date_epoch" do 4 | ENV["SOURCE_DATE_EPOCH"] = IO.popen(%W[git -C #{__dir__} log -1 --format=%ct], &:read).chomp 5 | end 6 | -------------------------------------------------------------------------------- /rakelib/version.rake: -------------------------------------------------------------------------------- 1 | class << (helper = Bundler::GemHelper.instance) 2 | def update_gemspec 3 | path = gemspec.loaded_from 4 | File.open(path, "r+b") do |f| 5 | d = f.read 6 | if d.sub!(/^(_VERSION\s*=\s*)".*"/) {$1 + gemspec.version.to_s.dump} 7 | f.rewind 8 | f.truncate(0) 9 | f.print(d) 10 | end 11 | end 12 | end 13 | 14 | def commit_bump 15 | sh(%W[git commit -m bump\ up\ to\ #{gemspec.version} 16 | #{gemspec.loaded_from}]) 17 | end 18 | 19 | def version=(v) 20 | gemspec.version = v 21 | update_gemspec 22 | commit_bump 23 | end 24 | end 25 | 26 | major, minor, teeny = helper.gemspec.version.segments 27 | 28 | task "bump:teeny" do 29 | helper.version = Gem::Version.new("#{major}.#{minor}.#{teeny+1}") 30 | end 31 | 32 | task "bump:minor" do 33 | helper.version = Gem::Version.new("#{major}.#{minor+1}.0") 34 | end 35 | 36 | task "bump:major" do 37 | helper.version = Gem::Version.new("#{major+1}.0.0") 38 | end 39 | 40 | task "bump" => "bump:teeny" 41 | 42 | task "tag" do 43 | helper.__send__(:tag_version) 44 | end 45 | -------------------------------------------------------------------------------- /ruby2_keywords.gemspec: -------------------------------------------------------------------------------- 1 | _VERSION = "0.0.5" 2 | abort "Version must not reach 1" if _VERSION[/\d+/].to_i >= 1 3 | 4 | Gem::Specification.new do |s| 5 | s.name = "ruby2_keywords" 6 | s.version = _VERSION 7 | s.summary = "Shim library for Module#ruby2_keywords" 8 | s.homepage = "https://github.com/ruby/ruby2_keywords" 9 | s.licenses = ["Ruby", "BSD-2-Clause"] 10 | s.authors = ["Nobuyoshi Nakada"] 11 | s.require_paths = ["lib"] 12 | s.rdoc_options = ["--main", "README.md"] 13 | s.extra_rdoc_files = [ 14 | "LICENSE", 15 | "README.md", 16 | "ChangeLog", 17 | *Dir.glob("#{__dir__}/logs/ChangeLog-*[^~]").map {|path| path[(__dir__.size+1)..-1]}, 18 | ] 19 | s.files = [ 20 | "lib/ruby2_keywords.rb", 21 | ] 22 | s.required_ruby_version = '>= 2.0.0' 23 | end 24 | -------------------------------------------------------------------------------- /test/test_keyword.rb: -------------------------------------------------------------------------------- 1 | require 'test/unit' 2 | LOADING_RUBY2_KEYWORDS = (RUBY_VERSION.scan(/\d+/).map(&:to_i) <=> [2, 7]) < 0 3 | if LOADING_RUBY2_KEYWORDS 4 | require 'ruby2_keywords' 5 | end 6 | 7 | class TestKeywordArguments < Test::Unit::TestCase 8 | def test_loaded_features 9 | list = $LOADED_FEATURES.grep(%r[/ruby2_keywords\.rb\z]) 10 | if LOADING_RUBY2_KEYWORDS 11 | assert_not_empty(list) 12 | assert_not_include($LOADED_FEATURES, "ruby2_keywords.rb") 13 | else 14 | assert_empty(list) 15 | assert_include($LOADED_FEATURES, "ruby2_keywords.rb") 16 | end 17 | end 18 | 19 | def test_module_ruby2_keywords 20 | assert_send([Module, :private_method_defined?, :ruby2_keywords]) 21 | assert_operator(Module.instance_method(:ruby2_keywords).arity, :<, 0) 22 | end 23 | 24 | def test_toplevel_ruby2_keywords 25 | main = TOPLEVEL_BINDING.eval('self') 26 | assert_send([main, :respond_to?, :ruby2_keywords, true]) 27 | assert_operator(main.method(:ruby2_keywords).arity, :<, 0) 28 | end 29 | 30 | def test_proc_ruby2_keywords 31 | assert_respond_to(Proc.new {}, :ruby2_keywords) 32 | end 33 | 34 | def test_hash_ruby2_keywords_hash? 35 | assert_false(Hash.ruby2_keywords_hash?({})) 36 | end 37 | 38 | def test_hash_ruby2_keywords_hash 39 | assert_equal({}, Hash.ruby2_keywords_hash({}.freeze)) 40 | end 41 | end 42 | --------------------------------------------------------------------------------