├── .github ├── FUNDING.yml ├── .kodiak.toml ├── dependabot.yml └── workflows │ ├── publish-to-github-pages.yml │ └── ruby.yml ├── .rspec ├── sorbet ├── rbi │ ├── gems │ │ ├── .gitattributes │ │ ├── rspec@3.13.2.rbi │ │ ├── simplecov-cobertura@3.1.0.rbi │ │ ├── lint_roller@1.1.0.rbi │ │ ├── ast@2.4.3.rbi │ │ └── rspec-support@3.13.6.rbi │ ├── annotations │ │ ├── .gitattributes │ │ └── rainbow.rbi │ ├── .rubocop.yml │ └── shims │ │ ├── rakefile.rbi │ │ ├── spec.rbi │ │ └── gemfile.rbi ├── config └── tapioca │ ├── require.rb │ └── config.yml ├── .yamllint.yml ├── spec ├── data │ ├── include_handler.txt │ ├── sig_handler_ignored.txt │ ├── enums_handler.txt │ ├── sig_handler.rbi.txt │ ├── abstract_handler.txt │ ├── abstract_dsl_handler.txt │ ├── struct_handler.txt │ ├── mixes_in_class_methods_handler.txt │ └── sig_handler.txt ├── yard_sorbet │ ├── node_utils_spec.rb │ └── handlers │ │ ├── sig_handler_ignored_spec.rb │ │ ├── enums_handler_spec.rb │ │ ├── include_handler_spec.rb │ │ ├── abstract_dsl_handler_spec.rb │ │ ├── struct_prop_handler_spec.rb │ │ ├── struct_class_handler_spec.rb │ │ └── sig_handler_spec.rb └── spec_helper.rb ├── lib ├── yard-sorbet │ ├── version.rb │ ├── handlers │ │ ├── struct_class_handler.rbi │ │ ├── enums_handler.rb │ │ ├── mixes_in_class_methods_handler.rb │ │ ├── abstract_dsl_handler.rb │ │ ├── include_handler.rb │ │ ├── struct_prop_handler.rb │ │ ├── struct_class_handler.rb │ │ └── sig_handler.rb │ ├── t_struct_prop.rb │ ├── handlers.rb │ ├── directives.rb │ ├── tag_utils.rb │ ├── node_utils.rb │ └── sig_to_yard.rb └── yard-sorbet.rb ├── bin ├── console └── tapioca ├── .yardopts ├── yard ├── ignore_monkey_patch_mixins.rbi ├── magic_comment_handler.rb └── ignore_monkey_patch_mixins.rb ├── Gemfile ├── Rakefile ├── .rubocop.yml ├── .gitignore ├── .pre-commit-config.yaml ├── yard-sorbet.gemspec ├── README.md ├── Gemfile.lock ├── CHANGELOG.md └── LICENSE /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | --- 2 | github: [dduugg] 3 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/.gitattributes: -------------------------------------------------------------------------------- 1 | **/*.rbi linguist-generated=true 2 | -------------------------------------------------------------------------------- /sorbet/rbi/annotations/.gitattributes: -------------------------------------------------------------------------------- 1 | **/*.rbi linguist-vendored=true 2 | -------------------------------------------------------------------------------- /.yamllint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | 4 | ignore: | 5 | /vendor/bundle/ 6 | -------------------------------------------------------------------------------- /sorbet/rbi/.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | inherit_gem: 3 | rubocop-sorbet: config/rbi.yml 4 | -------------------------------------------------------------------------------- /sorbet/rbi/shims/rakefile.rbi: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | 3 | extend Rake::DSL # rubocop:disable Style/MixinUsage 4 | -------------------------------------------------------------------------------- /spec/data/include_handler.txt: -------------------------------------------------------------------------------- 1 | require_relative 'mixes_in_class_methods_handler' 2 | 3 | class C2 4 | include M 5 | 6 | def self.bar; end 7 | end 8 | -------------------------------------------------------------------------------- /spec/data/sig_handler_ignored.txt: -------------------------------------------------------------------------------- 1 | # typed: ignore 2 | # frozen_string_literal: true 3 | 4 | class Weird 5 | sig {returns(1)} 6 | def one; 1; end 7 | end 8 | -------------------------------------------------------------------------------- /sorbet/config: -------------------------------------------------------------------------------- 1 | --allowed-extension=.gemspec,.rb,.rbi 2 | --dir=. 3 | --enable-experimental-requires-ancestor 4 | --enable-experimental-rspec 5 | --ignore=/vendor/bundle 6 | Gemfile 7 | Rakefile 8 | -------------------------------------------------------------------------------- /lib/yard-sorbet/version.rb: -------------------------------------------------------------------------------- 1 | # typed: strong 2 | # frozen_string_literal: true 3 | 4 | # Types are documentation 5 | module YARDSorbet 6 | # {https://rubygems.org/gems/yard-sorbet Version history} 7 | VERSION = '0.9.0' 8 | end 9 | -------------------------------------------------------------------------------- /sorbet/tapioca/require.rb: -------------------------------------------------------------------------------- 1 | # typed: strong 2 | # frozen_string_literal: true 3 | 4 | # Add your extra requires here (`bin/tapioca require` can be used to bootstrap this list) 5 | require 'rspec/core/rake_task' 6 | require 'rubocop/rake_task' 7 | -------------------------------------------------------------------------------- /.github/.kodiak.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [merge] 4 | delete_branch_on_merge = true 5 | notify_on_conflict = false 6 | 7 | [merge.automerge_dependencies] 8 | usernames = ["dependabot", "pre-commit-ci"] 9 | 10 | [update] 11 | always = true 12 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # typed: strict 3 | # frozen_string_literal: true 4 | 5 | require 'bundler/setup' 6 | require 'irb' 7 | require 'yard-sorbet' 8 | 9 | # To require all gems in the Gemfile: 10 | # Bundler.require 11 | 12 | IRB.start(__FILE__) 13 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --load yard/ignore_monkey_patch_mixins.rb 2 | --load yard/magic_comment_handler.rb 3 | --main README.md 4 | --markup-provider=redcarpet 5 | --markup=markdown 6 | --private 7 | --plugin sorbet 8 | lib/**/*.rb 9 | - 10 | CHANGELOG.md 11 | LICENSE 12 | README.md 13 | -------------------------------------------------------------------------------- /lib/yard-sorbet/handlers/struct_class_handler.rbi: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | # This is in an rbi so the runtime doesn't depend on experimental sorbet features 5 | module YARDSorbet::Handlers::StructClassHandler 6 | requires_ancestor { YARD::Handlers::Ruby::ClassHandler } 7 | end 8 | -------------------------------------------------------------------------------- /sorbet/rbi/shims/spec.rbi: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | 3 | class RSpec::Core::ExampleGroup 4 | include RSpec::SharedContext 5 | include RSpec::Matchers 6 | include RSpec::Mocks::ExampleMethods 7 | 8 | # RSpec::Core::ExampleGroup methods 9 | def self.described_class; end 10 | def self.it(*all_args, &block); end 11 | end 12 | -------------------------------------------------------------------------------- /yard/ignore_monkey_patch_mixins.rbi: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | # @todo This should be unnecessary in the next YARD release 5 | # @see https://github.com/lsegal/yard/commit/cbd40ea783f352ac64aec1623e06ac56afadbcc1 6 | module IgnoreMonkeyPatchMixins 7 | requires_ancestor { YARD::Handlers::Ruby::MixinHandler } 8 | end 9 | -------------------------------------------------------------------------------- /spec/yard_sorbet/node_utils_spec.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | RSpec.describe YARDSorbet::NodeUtils do 5 | describe 'sigable_node?' do 6 | it 'returns false for non-method nodes' do 7 | node = YARD::Parser::Ruby::AstNode.new(:hash, []) 8 | expect(described_class.sigable_node?(node)).to be(false) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/yard-sorbet/t_struct_prop.rb: -------------------------------------------------------------------------------- 1 | # typed: strong 2 | # frozen_string_literal: true 3 | 4 | module YARDSorbet 5 | # Used to store the details of a `T::Struct` `prop` definition 6 | class TStructProp < T::Struct 7 | const :default, T.nilable(String) 8 | const :doc, String 9 | const :prop_name, String 10 | const :source, String 11 | const :types, T::Array[String] 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/yard-sorbet.rb: -------------------------------------------------------------------------------- 1 | # typed: strong 2 | # frozen_string_literal: true 3 | 4 | require 'sorbet-runtime' 5 | require 'yard' 6 | 7 | require_relative 'yard-sorbet/version' 8 | 9 | require_relative 'yard-sorbet/directives' 10 | require_relative 'yard-sorbet/handlers' 11 | require_relative 'yard-sorbet/node_utils' 12 | require_relative 'yard-sorbet/sig_to_yard' 13 | require_relative 'yard-sorbet/t_struct_prop' 14 | require_relative 'yard-sorbet/tag_utils' 15 | -------------------------------------------------------------------------------- /spec/data/enums_handler.txt: -------------------------------------------------------------------------------- 1 | # typed: true 2 | # frozen_string_literal: true 3 | 4 | # An enum representing card suits 5 | class Suit < T::Enum 6 | enums do 7 | # The spades suit 8 | # @see https://en.wikipedia.org/wiki/Spades_(suit) 9 | Spades = new 10 | # The hearts suit 11 | Hearts = new 12 | Clubs = new('Clubs') 13 | diamonds_serialized_value = 'Diamonds' 14 | Diamonds = new(diamonds_serialized_value) 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/rspec@3.13.2.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `rspec` gem. 5 | # Please instead update this file by running `bin/tapioca gem rspec`. 6 | 7 | 8 | # source://rspec//lib/rspec/version.rb#1 9 | module RSpec; end 10 | 11 | # source://rspec//lib/rspec/version.rb#2 12 | module RSpec::Version; end 13 | 14 | # source://rspec//lib/rspec/version.rb#3 15 | RSpec::Version::STRING = T.let(T.unsafe(nil), String) 16 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | source 'https://rubygems.org' 5 | 6 | gemspec 7 | 8 | gem 'rake', '~> 13.3.1' 9 | gem 'redcarpet', '~> 3.6.0' 10 | gem 'rspec', '~> 3.13.2' 11 | gem 'rubocop', '~> 1.81.7' 12 | gem 'rubocop-packaging', '~> 0.6.0' 13 | gem 'rubocop-performance', '~> 1.26.1' 14 | gem 'rubocop-rake', '~> 0.7.1' 15 | gem 'rubocop-rspec', '~> 3.8.0' 16 | gem 'rubocop-sorbet', '~> 0.11.0' 17 | gem 'simplecov' 18 | gem 'simplecov-cobertura' 19 | gem 'sorbet', '~> 0.6.12798' 20 | gem 'tapioca', '~> 0.17.9' 21 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | require 'bundler/gem_tasks' 5 | require 'rspec/core/rake_task' 6 | require 'rubocop/rake_task' 7 | require 'yard' 8 | 9 | RSpec::Core::RakeTask.new(:spec) 10 | RuboCop::RakeTask.new(:rubocop) 11 | YARD::Rake::YardocTask.new 12 | 13 | desc 'Typecheck files with sorbet' 14 | task :typecheck do 15 | sh 'bundle exec srb typecheck' 16 | end 17 | 18 | desc 'Generate RBI files with tapioca' 19 | task :rbi do 20 | sh 'bin/tapioca gems' 21 | end 22 | 23 | task default: %i[typecheck rubocop spec] 24 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: "bundler" 5 | directory: "/" 6 | schedule: 7 | interval: "monthly" 8 | groups: 9 | rubocop: 10 | patterns: 11 | - "rubocop*" 12 | sorbet: 13 | patterns: 14 | - "*sorbet*" 15 | - "tapioca" 16 | labels: 17 | - "automerge" 18 | - "dependencies" 19 | - package-ecosystem: "github-actions" 20 | directory: "/" 21 | schedule: 22 | interval: "monthly" 23 | labels: 24 | - "automerge" 25 | - "dependencies" 26 | -------------------------------------------------------------------------------- /.github/workflows/publish-to-github-pages.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Publish Docs to GitHub Pages 3 | 'on': 4 | push: 5 | branches: 6 | - main 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v6 12 | - uses: ruby/setup-ruby@v1 13 | with: 14 | ruby-version: ruby 15 | bundler-cache: true 16 | - run: bundle exec rake yard 17 | - name: Deploy 18 | uses: peaceiris/actions-gh-pages@v4 19 | with: 20 | github_token: ${{ secrets.GITHUB_TOKEN }} 21 | publish_dir: ./doc 22 | -------------------------------------------------------------------------------- /lib/yard-sorbet/handlers.rb: -------------------------------------------------------------------------------- 1 | # typed: strong 2 | # frozen_string_literal: true 3 | 4 | module YARDSorbet 5 | # Custom YARD Handlers 6 | # @see https://rubydoc.info/gems/yard/YARD/Handlers/Base YARD Base Handler documentation 7 | module Handlers; end 8 | end 9 | 10 | require_relative 'handlers/abstract_dsl_handler' 11 | require_relative 'handlers/enums_handler' 12 | require_relative 'handlers/include_handler' 13 | require_relative 'handlers/mixes_in_class_methods_handler' 14 | require_relative 'handlers/sig_handler' 15 | require_relative 'handlers/struct_class_handler' 16 | require_relative 'handlers/struct_prop_handler' 17 | -------------------------------------------------------------------------------- /yard/magic_comment_handler.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | require 'sorbet-runtime' 5 | 6 | # Removes docstrings that consist solely of magic comments 7 | class MagicCommentHandler < YARD::Handlers::Ruby::Base 8 | extend T::Sig 9 | 10 | # File header regexp that matches magic comments 11 | FILE_HEADER = T.let(/\Atyped: [[:alpha:]]+\nfrozen_string_literal: [[:alpha:]]+/, Regexp) 12 | 13 | handles :class, :module 14 | namespace_only 15 | 16 | sig { void } 17 | def process 18 | return unless statement.docstring&.match?(FILE_HEADER) 19 | 20 | statement.docstring = nil 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /sorbet/tapioca/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | gem: 3 | exclude: 4 | - diff-lcs 5 | - docile 6 | - erubi 7 | - json 8 | - language_server-protocol 9 | - netrc 10 | - parallel 11 | - prettier_print 12 | - racc 13 | - rainbow 14 | - rbi 15 | - redcarpet 16 | - rexml 17 | - rubocop-packaging 18 | - rubocop-performance 19 | - rubocop-rake 20 | - rubocop-sorbet 21 | - ruby-progressbar 22 | - simplecov-html 23 | - simplecov_json_formatter 24 | - spoom 25 | - strscan 26 | - syntax_tree 27 | - tapioca 28 | - thor 29 | - unicode-display_width 30 | - unicode-emoji 31 | -------------------------------------------------------------------------------- /spec/data/sig_handler.rbi.txt: -------------------------------------------------------------------------------- 1 | module Merge 2 | class A 3 | sig { returns(Numeric) } 4 | attr_accessor :a_foo 5 | 6 | sig { returns(T.nilable(String)) } 7 | attr_reader :a_bar 8 | 9 | sig { params(writer: Integer).returns(Integer) } 10 | attr_writer :a_baz 11 | 12 | sig { returns(String) } 13 | def foo; end 14 | 15 | sig { params(a: Integer).returns(Float) } 16 | def self.bar(a); end 17 | 18 | sig { returns(String) } 19 | def baz; end 20 | 21 | sig { returns(Integer) } 22 | def bat; end 23 | 24 | # new docstring 25 | sig { returns(T::Boolean) } 26 | def xyz; end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | inherit_mode: 3 | merge: 4 | - Exclude 5 | - Include 6 | 7 | plugins: 8 | - rubocop-packaging 9 | - rubocop-performance 10 | - rubocop-rake 11 | - rubocop-rspec 12 | - rubocop-sorbet 13 | 14 | AllCops: 15 | Include: 16 | - "sorbet/rbi/shims/**/*.rbi" 17 | NewCops: enable 18 | TargetRubyVersion: 3.2 19 | 20 | Layout/ClassStructure: 21 | Enabled: true 22 | # Cannot add type annotations to forwarded blocks 23 | Naming/BlockForwarding: 24 | Enabled: false 25 | Naming/FileName: 26 | Exclude: 27 | - lib/yard-sorbet.rb 28 | Sorbet/ForbidTUntyped: 29 | Enabled: true 30 | Sorbet/StrictSigil: 31 | Enabled: true 32 | -------------------------------------------------------------------------------- /.github/workflows/ruby.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Ruby 3 | 'on': 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | jobs: 9 | Ruby-CI: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | ruby-version: ['3.2', '3.3', '3.4', '4.0'] 14 | steps: 15 | - uses: actions/checkout@v6 16 | - name: Set up Ruby 17 | uses: ruby/setup-ruby@v1 18 | with: 19 | ruby-version: ${{ matrix.ruby-version }} 20 | bundler-cache: true 21 | - run: bundle install 22 | - name: Run tests 23 | run: bundle exec rake 24 | - name: Upload to Codecov 25 | uses: codecov/codecov-action@v5 26 | -------------------------------------------------------------------------------- /spec/data/abstract_handler.txt: -------------------------------------------------------------------------------- 1 | # typed: true 2 | # frozen_string_literal: true 3 | 4 | 5 | module MyInterface 6 | extend T::Helpers 7 | extend T::Sig 8 | 9 | interface! 10 | sig { abstract.returns(T::Boolean) } 11 | def ibool; end 12 | end 13 | 14 | # An abstract class 15 | # @note this class is abstract 16 | class MyAbstractClass 17 | extend T::Helpers 18 | extend T::Sig 19 | 20 | abstract! 21 | 22 | sig { abstract.void } 23 | def abstract_method; end 24 | end 25 | 26 | # @abstract Existing abstract tag 27 | module MyTaggedAbstractModule 28 | extend T::Helpers 29 | extend T::Sig 30 | 31 | abstract! 32 | sig { abstract.returns(T::Boolean) } 33 | def ibool; end 34 | end 35 | -------------------------------------------------------------------------------- /spec/data/abstract_dsl_handler.txt: -------------------------------------------------------------------------------- 1 | # typed: true 2 | # frozen_string_literal: true 3 | 4 | # An abstract class 5 | # @note this class is abstract 6 | class MyAbstractClass 7 | extend T::Helpers 8 | extend T::Sig 9 | 10 | abstract! 11 | 12 | sig { abstract.void } 13 | def abstract_method; end 14 | end 15 | 16 | 17 | module MyInterface 18 | extend T::Helpers 19 | extend T::Sig 20 | 21 | interface! 22 | sig { abstract.returns(T::Boolean) } 23 | def ibool; end 24 | end 25 | 26 | 27 | # @abstract Existing abstract tag 28 | module MyTaggedAbstractModule 29 | extend T::Helpers 30 | extend T::Sig 31 | 32 | abstract! 33 | sig { abstract.returns(T::Boolean) } 34 | def ibool; end 35 | end 36 | -------------------------------------------------------------------------------- /yard/ignore_monkey_patch_mixins.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | require 'sorbet-runtime' 5 | 6 | # YARD erroneously attaches some `include` invocations to the root level, so we omit them instead. (The resulting 7 | # documentation would not be helpful anyway.) 8 | # 9 | # @see https://github.com/lsegal/yard/issues/1386 10 | module IgnoreMonkeyPatchMixins 11 | extend T::Helpers 12 | extend T::Sig 13 | 14 | sig { params(content: YARD::Parser::Ruby::AstNode).returns(T.nilable(YARD::CodeObjects::Base)) } 15 | def recipient(content) 16 | return unless namespace.to_s.start_with?('YARDSorbet') 17 | 18 | super 19 | end 20 | end 21 | 22 | YARD::Handlers::Ruby::MixinHandler.prepend IgnoreMonkeyPatchMixins 23 | -------------------------------------------------------------------------------- /spec/yard_sorbet/handlers/sig_handler_ignored_spec.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | RSpec.describe YARDSorbet::Handlers::SigHandler do 5 | before do 6 | path = File.join(File.expand_path('../../data', __dir__), 'sig_handler_ignored.txt') 7 | allow(log).to receive(:warn) 8 | YARD::Registry.clear 9 | YARD::Parser::SourceParser.parse(path) 10 | end 11 | 12 | describe 'sig parsing' do 13 | it 'warns on unsupported node types' do 14 | expect(log).to have_received(:warn).with('Unsupported sig int node 1') 15 | end 16 | 17 | it 'handles unsupported node types' do 18 | node = YARD::Registry.at('Weird#one') 19 | expect(node.tag(:return).type).to eq('1') 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /bin/tapioca: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'tapioca' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 12 | 13 | bundle_binstub = File.expand_path('bundle', __dir__) 14 | 15 | if File.file?(bundle_binstub) 16 | if File.read(bundle_binstub, 300).include?('This file was generated by Bundler') 17 | load(bundle_binstub) 18 | else 19 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 20 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 21 | end 22 | end 23 | 24 | require 'rubygems' 25 | require 'bundler/setup' 26 | 27 | load Gem.bin_path('tapioca', 'tapioca') 28 | -------------------------------------------------------------------------------- /.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 | ## Documentation cache and generated files: 20 | /.yardoc/ 21 | /_yardoc/ 22 | /doc/ 23 | /rdoc/ 24 | 25 | ## Environment normalization: 26 | /.bundle/ 27 | /vendor/bundle 28 | /lib/bundler/man/ 29 | 30 | # for a library or gem, you might want to ignore these files since the code is 31 | # intended to run in multiple environments; otherwise, check them in: 32 | # Gemfile.lock 33 | .ruby-version 34 | .ruby-gemset 35 | 36 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 37 | .rvmrc 38 | 39 | # Used by RuboCop. Remote config files pulled in from inherit_from directive. 40 | # .rubocop-https?--* 41 | -------------------------------------------------------------------------------- /lib/yard-sorbet/handlers/enums_handler.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | module YARDSorbet 5 | module Handlers 6 | # Handle `enums` calls, registering enum values as constants 7 | class EnumsHandler < YARD::Handlers::Ruby::Base 8 | extend T::Sig 9 | 10 | handles method_call(:enums) 11 | namespace_only 12 | 13 | sig { void } 14 | def process 15 | statement.traverse do |node| 16 | if const_assign_node?(node) 17 | register YARD::CodeObjects::ConstantObject.new(namespace, node.first.source) do |obj| 18 | obj.docstring = node.docstring 19 | obj.source = node 20 | obj.value = node.last.source 21 | end 22 | end 23 | end 24 | end 25 | 26 | private 27 | 28 | sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Boolean) } 29 | def const_assign_node?(node) = node.type == :assign && node[0][0].type == :const 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/yard-sorbet/directives.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | module YARDSorbet 5 | # Extract & re-add directives to a docstring 6 | module Directives 7 | extend T::Sig 8 | 9 | sig { params(docstring: T.nilable(String)).returns([YARD::Docstring, T::Array[String]]) } 10 | def self.extract_directives(docstring) 11 | parser = YARD::DocstringParser.new.parse(docstring) 12 | # Directives are already parsed at this point, and there doesn't 13 | # seem to be an API to tweeze them from one node to another without 14 | # managing YARD internal state. Instead, we just extract them from 15 | # the raw text and re-attach them. 16 | directives = parser.raw_text&.split("\n")&.select { _1.start_with?('@!') } || [] 17 | [parser.to_docstring, directives] 18 | end 19 | 20 | sig { params(docstring: String, directives: T::Array[String]).void } 21 | def self.add_directives(docstring, directives) = directives.each { docstring.concat("\n#{_1}") } 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | ci: 3 | autoupdate_schedule: quarterly 4 | repos: 5 | - repo: https://github.com/pre-commit/pre-commit-hooks 6 | rev: v6.0.0 7 | hooks: 8 | - id: check-added-large-files 9 | args: [--maxkb=2000] 10 | - id: check-case-conflict 11 | - id: check-executables-have-shebangs 12 | - id: check-json 13 | - id: check-merge-conflict 14 | - id: check-shebang-scripts-are-executable 15 | - id: check-toml 16 | - id: check-vcs-permalinks 17 | exclude: sorbet/rbi/annotations 18 | - id: detect-private-key 19 | - id: end-of-file-fixer 20 | - id: forbid-submodules 21 | - id: mixed-line-ending 22 | - id: sort-simple-yaml 23 | - id: trailing-whitespace 24 | - repo: https://github.com/crate-ci/typos 25 | rev: v1 26 | hooks: 27 | - id: typos 28 | args: [--exclude=sorbet/rbi/gems, --force-exclude] 29 | - repo: https://github.com/adrienverge/yamllint 30 | rev: v1.37.1 31 | hooks: 32 | - id: yamllint 33 | args: [--strict] 34 | -------------------------------------------------------------------------------- /lib/yard-sorbet/handlers/mixes_in_class_methods_handler.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | module YARDSorbet 5 | module Handlers 6 | # Tracks modules that invoke `mixes_in_class_methods` for use in {IncludeHandler} 7 | # @see https://sorbet.org/docs/abstract#interfaces-and-the-included-hook 8 | # Sorbet `mixes_in_class_methods` documentation 9 | class MixesInClassMethodsHandler < YARD::Handlers::Ruby::Base 10 | extend T::Sig 11 | 12 | handles method_call(:mixes_in_class_methods) 13 | namespace_only 14 | 15 | @@mix_in_class_methods = T.let({}, T::Hash[String, T::Array[String]]) # rubocop:disable Style/ClassVars 16 | 17 | sig { params(code_obj: String).returns(T.nilable(T::Array[String])) } 18 | def self.mixed_in_class_methods(code_obj) = @@mix_in_class_methods[code_obj] 19 | 20 | sig { void } 21 | def process 22 | @@mix_in_class_methods[namespace.to_s] ||= [] 23 | @@mix_in_class_methods.fetch(namespace.to_s) << statement.parameters(false)[0].source 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/data/struct_handler.txt: -------------------------------------------------------------------------------- 1 | # typed: true 2 | # frozen_string_literal: true 3 | 4 | # Comment on PersonStruct 5 | class PersonStruct < T::Struct 6 | # A name 7 | const :name, String 8 | # An age 9 | const :age, Integer 10 | # An optional 11 | const :optional, T.nilable(String) 12 | # A writable 13 | prop :writable, String 14 | const :mystery, T.untyped 15 | prop :not_mutable, Integer, default: 0, immutable: true 16 | end 17 | 18 | class SpecializedPersonStruct < T::Struct 19 | const :special, String 20 | 21 | # This is a special initializer 22 | # @param special a very special param 23 | # @return an initialized struct 24 | def initialize(special:) 25 | raise ArgumentError.new("bad human") if special != "special" 26 | super 27 | end 28 | end 29 | 30 | class DefaultPersonStruct < T::Struct 31 | # This has a default 32 | const :defaulted, String, default: 'hello' 33 | end 34 | 35 | # Symbols that will cause the ruby lexer to capture something other than an :ident 36 | # @see https://bugs.ruby-lang.org/issues/6306 37 | class ExceptionalPersonStruct < T::Struct 38 | const :end, String 39 | const :Foo, String 40 | end 41 | -------------------------------------------------------------------------------- /yard-sorbet.gemspec: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | require_relative 'lib/yard-sorbet/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = 'yard-sorbet' 8 | spec.version = YARDSorbet::VERSION 9 | spec.author = 'Douglas Eichelberger' 10 | spec.email = 'dduugg@gmail.com' 11 | spec.license = 'Apache-2.0' 12 | 13 | spec.summary = 'Create YARD docs from Sorbet type signatures' 14 | spec.description = 'A YARD plugin that incorporates Sorbet type information' 15 | spec.homepage = 'https://github.com/dduugg/yard-sorbet' 16 | spec.required_ruby_version = Gem::Requirement.new('>= 3.2') 17 | 18 | spec.metadata = { 19 | 'bug_tracker_uri' => "#{spec.homepage}/issues", 20 | 'changelog_uri' => "#{spec.homepage}/blob/main/CHANGELOG.md", 21 | 'documentation_uri' => 'https://dduugg.github.io/yard-sorbet/', 22 | 'homepage_uri' => spec.homepage, 23 | 'rubygems_mfa_required' => 'true', 24 | 'source_code_uri' => spec.homepage, 25 | 'wiki_uri' => "#{spec.homepage}/wiki" 26 | } 27 | 28 | spec.files = Dir['lib/**/*', 'LICENSE'] 29 | 30 | spec.add_dependency 'sorbet-runtime' 31 | spec.add_dependency 'yard' 32 | end 33 | -------------------------------------------------------------------------------- /lib/yard-sorbet/handlers/abstract_dsl_handler.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | module YARDSorbet 5 | module Handlers 6 | # Applies an `@abstract` tag to `abstract!`/`interface!` modules (if not already present). 7 | class AbstractDSLHandler < YARD::Handlers::Ruby::Base 8 | extend T::Sig 9 | 10 | handles method_call(:abstract!), method_call(:interface!) 11 | namespace_only 12 | 13 | # The text accompanying the `@abstract` tag. 14 | # @see https://github.com/lsegal/yard/blob/main/templates/default/docstring/html/abstract.erb 15 | # The `@abstract` tag template 16 | TAG_TEXT = 'Subclasses must implement the `abstract` methods below.' 17 | # Extra text for class namespaces 18 | CLASS_TAG_TEXT = T.let("It cannot be directly instantiated. #{TAG_TEXT}".freeze, String) 19 | 20 | sig { void } 21 | def process 22 | return if namespace.has_tag?(:abstract) 23 | 24 | text = namespace.is_a?(YARD::CodeObjects::ClassObject) ? CLASS_TAG_TEXT : TAG_TEXT 25 | tag = YARD::Tags::Tag.new(:abstract, text) 26 | namespace.add_tag(tag) 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/yard-sorbet/handlers/include_handler.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | module YARDSorbet 5 | module Handlers 6 | # Extends any modules included via `mixes_in_class_methods` 7 | # @see https://sorbet.org/docs/abstract#interfaces-and-the-included-hook 8 | # Sorbet `mixes_in_class_methods` documentation 9 | class IncludeHandler < YARD::Handlers::Ruby::Base 10 | extend T::Sig 11 | 12 | handles method_call(:include) 13 | namespace_only 14 | 15 | sig { void } 16 | def process 17 | statement.parameters(false).each do |mixin| 18 | obj = YARD::CodeObjects::Proxy.new(namespace, mixin.source) 19 | class_methods_namespaces = MixesInClassMethodsHandler.mixed_in_class_methods(obj.to_s) 20 | class_methods_namespaces&.each { included_in.mixins(:class) << YARD::CodeObjects::Proxy.new(obj, _1) } 21 | end 22 | end 23 | 24 | private 25 | 26 | # @return the namespace object that is including the module 27 | sig { returns(YARD::CodeObjects::NamespaceObject) } 28 | def included_in 29 | statement.namespace ? YARD::CodeObjects::Proxy.new(namespace, statement.namespace.source) : namespace 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/data/mixes_in_class_methods_handler.txt: -------------------------------------------------------------------------------- 1 | # typed: true 2 | module M 3 | extend T::Helpers 4 | interface! 5 | 6 | module ClassMethods 7 | extend T::Sig 8 | extend T::Helpers 9 | abstract! 10 | 11 | sig {void} 12 | def foo 13 | bar 14 | end 15 | 16 | sig {abstract.void} 17 | def bar; end 18 | end 19 | 20 | mixes_in_class_methods(ClassMethods) 21 | end 22 | 23 | class A # error: Missing definition for abstract method 24 | include M 25 | 26 | extend T::Sig 27 | 28 | sig {override.void} 29 | def self.bar; end 30 | end 31 | 32 | # Sorbet knows that `foo` is a class method on `A` 33 | A.foo 34 | 35 | module Receiver; end 36 | 37 | Receiver.include(M) 38 | 39 | module OuterModule 40 | module InnerModule 41 | extend T::Helpers 42 | module ClassMethodsA 43 | def foo; end 44 | end 45 | module ClassMethodsB 46 | def bar; end 47 | end 48 | mixes_in_class_methods(ClassMethodsA) 49 | mixes_in_class_methods(ClassMethodsB) 50 | end 51 | 52 | class InnerClass 53 | include InnerModule 54 | end 55 | end 56 | 57 | module M2; end 58 | module M3; end 59 | 60 | class C 61 | extend T::Sig 62 | 63 | include M2, M, M3 64 | 65 | sig {override.void} 66 | def self.bar; end 67 | end 68 | -------------------------------------------------------------------------------- /spec/yard_sorbet/handlers/enums_handler_spec.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | RSpec.describe YARDSorbet::Handlers::EnumsHandler do 5 | before do 6 | path = File.join(File.expand_path('../../data', __dir__), 'enums_handler.txt') 7 | YARD::Registry.clear 8 | YARD::Parser::SourceParser.parse(path) 9 | end 10 | 11 | describe 'T::Enum subclass' do 12 | it 'registers constants' do 13 | node = YARD::Registry.at('Suit') 14 | expect(node.constants.size).to eq(4) # rubocop:disable Sorbet/ConstantsFromStrings 15 | end 16 | 17 | describe 'enums' do 18 | it 'keep existing tag count' do 19 | expect(YARD::Registry.at('Suit::Spades').tags.size).to be(1) 20 | end 21 | 22 | it 'attach existing tags' do 23 | node = YARD::Registry.at('Suit::Spades') 24 | expect(node.tag(:see).name).to eq('https://en.wikipedia.org/wiki/Spades_(suit)') 25 | end 26 | 27 | it 'attach docstrings' do 28 | node = YARD::Registry.at('Suit::Hearts') 29 | expect(node.docstring).to eq('The hearts suit') 30 | end 31 | 32 | it 'include serialized values' do 33 | node = YARD::Registry.at('Suit::Clubs') 34 | expect(node.value).to eq("new('Clubs')") 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /sorbet/rbi/shims/gemfile.rbi: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | 3 | # This may include Gem::RequestSet::GemDependencyAPI methods from 4 | # https://github.com/sorbet/sorbet/blob/master/rbi/stdlib/rubygems.rbi 5 | 6 | # Loads dependencies from a gemspec file. 7 | # 8 | # `options` include: 9 | # 10 | # name: 11 | # : The name portion of the gemspec file. Defaults to searching for any 12 | # gemspec file in the current directory. 13 | # 14 | # ```ruby 15 | # gemspec name: 'my_gem' 16 | # ``` 17 | # 18 | # path: 19 | # : The path the gemspec lives in. Defaults to the current directory: 20 | # 21 | # ```ruby 22 | # gemspec 'my_gem', path: 'gemspecs', name: 'my_gem' 23 | # ``` 24 | # 25 | # development\_group: 26 | # : The group to add development dependencies to. By default this is 27 | # :development. Only one group may be specified. 28 | def gemspec(options = T.unsafe(nil)); end 29 | 30 | # Sets `url` as a source for gems for this dependency API. RubyGems uses the 31 | # default configured sources if no source was given. If a source is set only 32 | # that source is used. 33 | # 34 | # This method differs in behavior from Bundler: 35 | # 36 | # * The `:gemcutter`, # `:rubygems` and `:rubyforge` sources are not 37 | # supported as they are deprecated in bundler. 38 | # * The `prepend:` option is not supported. If you wish to order sources 39 | # then list them in your preferred order. 40 | def source(url); end 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # yard-sorbet 2 | [![Gem Version](https://badge.fury.io/rb/yard-sorbet.svg)](https://badge.fury.io/rb/yard-sorbet) 3 | [![Build Status](https://github.com/dduugg/yard-sorbet/actions/workflows/ruby.yml/badge.svg)](https://github.com/dduugg/yard-sorbet/actions/workflows/ruby.yml) 4 | [![codecov](https://codecov.io/gh/dduugg/yard-sorbet/branch/master/graph/badge.svg)](https://codecov.io/gh/dduugg/yard-sorbet) 5 | 6 | A YARD [plugin](https://rubydoc.info/gems/yard/file/docs/GettingStarted.md#plugin-support) that parses Sorbet type annotations 7 | 8 | ## Features 9 | - Attaches existing documentation to methods and attributes that follow `sig` declarations. (This information is otherwise discarded.) 10 | - Translates `sig` type signatures into corresponding YARD tags 11 | - Generates method definitions from `T::Struct` fields 12 | - Generates constant definitions from `T::Enum` enums 13 | - Modules marked `abstract!` or `interface!` are tagged `@abstract` 14 | - Modules using `mixes_in_class_methods` will attach class methods 15 | - Merges `sig`s in rbi files with source code documentation (rbi files must come after source code in yard configuration) 16 | 17 | ## Usage 18 | 19 | See the Plugin Support [section](https://rubydoc.info/gems/yard/file/docs/GettingStarted.md#plugin-support) of the YARD docs. 20 | 21 | ## Used By 22 | 23 | This plugin is used by: 24 | - The [Homebrew Ruby API](https://rubydoc.brew.sh/index.html) 25 | - [Tapioca](https://github.com/Shopify/tapioca), to optionally include YARD documentation from sources when generating RBIs 26 | - `yard-sorbet` [itself](https://dduugg.github.io/yard-sorbet/) 27 | -------------------------------------------------------------------------------- /lib/yard-sorbet/tag_utils.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | module YARDSorbet 5 | # Helper methods for working with `YARD` tags 6 | module TagUtils 7 | extend T::Sig 8 | 9 | # The `void` return type, as a constant to reduce array allocations 10 | VOID_RETURN_TYPE = T.let(['void'].freeze, [String]) 11 | 12 | # @return the tag with the matching `tag_name` and `name`, or `nil` 13 | sig do 14 | params(docstring: YARD::Docstring, tag_name: String, name: T.nilable(String)).returns(T.nilable(YARD::Tags::Tag)) 15 | end 16 | def self.find_tag(docstring, tag_name, name) = docstring.tags.find { _1.tag_name == tag_name && _1.name == name } 17 | 18 | # Create or update a `YARD` tag with type information 19 | sig do 20 | params( 21 | docstring: YARD::Docstring, 22 | tag_name: String, 23 | types: T.nilable(T::Array[String]), 24 | name: T.nilable(String), 25 | text: String 26 | ).void 27 | end 28 | def self.upsert_tag(docstring, tag_name, types = nil, name = nil, text = '') 29 | tag = find_tag(docstring, tag_name, name) 30 | if tag 31 | return unless types 32 | 33 | # Updating a tag in place doesn't seem to work, so we'll delete it, add the types, and re-add it 34 | docstring.delete_tag_if { _1 == tag } 35 | # overwrite any existing type annotation (sigs should win) 36 | tag.types = types 37 | tag.text = text unless text.empty? 38 | else 39 | tag = YARD::Tags::Tag.new(tag_name, text, types, name) 40 | end 41 | docstring.add_tag(tag) 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /spec/yard_sorbet/handlers/include_handler_spec.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | RSpec.describe YARDSorbet::Handlers::IncludeHandler do 5 | before do 6 | mixes_in_path = File.join(File.expand_path('../../data', __dir__), 'mixes_in_class_methods_handler.txt') 7 | include_path = File.join(File.expand_path('../../data', __dir__), 'include_handler.txt') 8 | YARD::Registry.clear 9 | YARD::Parser::SourceParser.parse(mixes_in_path) 10 | YARD::Parser::SourceParser.parse(include_path) 11 | end 12 | 13 | describe 'including a module with `mixes_in_class_methods`' do 14 | it 'adds the class method namespace to `class_mixins`' do 15 | node = YARD::Registry.at('A') 16 | expect(node.class_mixins.map(&:to_s)).to include('M::ClassMethods') 17 | end 18 | 19 | it 'attaches class method namespace to explicit receiver' do 20 | node = YARD::Registry.at('Receiver') 21 | expect(node.class_mixins.map(&:to_s)).to include('M::ClassMethods') 22 | end 23 | 24 | it 'resolves full class method namespace' do 25 | node = YARD::Registry.at('OuterModule::InnerClass') 26 | expect(node.class_mixins.map(&:to_s)).to( 27 | include('OuterModule::InnerModule::ClassMethodsA', 'OuterModule::InnerModule::ClassMethodsB') 28 | ) 29 | end 30 | 31 | it 'handles multiple parameters to include' do 32 | node = YARD::Registry.at('C') 33 | expect(node.class_mixins.map(&:to_s)).to include('M::ClassMethods') 34 | end 35 | 36 | it 'includes class methods from another file' do 37 | node = YARD::Registry.at('C2') 38 | expect(node.class_mixins.map(&:to_s)).to include('M::ClassMethods') 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/yard_sorbet/handlers/abstract_dsl_handler_spec.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | RSpec.describe YARDSorbet::Handlers::AbstractDSLHandler do 5 | before do 6 | path = File.join(File.expand_path('../../data', __dir__), 'abstract_dsl_handler.txt') 7 | YARD::Registry.clear 8 | YARD::Parser::SourceParser.parse(path) 9 | end 10 | 11 | describe 'interfaces' do 12 | it 'have @abstract tags' do 13 | expect(YARD::Registry.at('MyInterface').has_tag?(:abstract)).to be(true) 14 | end 15 | 16 | it 'have abstract tag text string' do 17 | node = YARD::Registry.at('MyInterface') 18 | expect(node.tags.first.text).to(eq(YARDSorbet::Handlers::AbstractDSLHandler::TAG_TEXT)) 19 | end 20 | end 21 | 22 | describe 'abstract classes' do 23 | it 'keep existing docstring' do 24 | expect(YARD::Registry.at('MyAbstractClass').docstring).to eq('An abstract class') 25 | end 26 | 27 | it 'keep existing tags' do 28 | expect(YARD::Registry.at('MyAbstractClass').tag(:note).text).to eq('this class is abstract') 29 | end 30 | 31 | it 'have abstract tags' do 32 | expect(YARD::Registry.at('MyAbstractClass').has_tag?(:abstract)).to be(true) 33 | end 34 | 35 | it 'have abstract tag text string' do 36 | node = YARD::Registry.at('MyAbstractClass') 37 | expect(node.tag(:abstract).text).to(eq(YARDSorbet::Handlers::AbstractDSLHandler::CLASS_TAG_TEXT)) 38 | end 39 | end 40 | 41 | describe 'When existing abstract tag exists' do 42 | it 'does not create a redundant tag' do 43 | expect(YARD::Registry.at('MyTaggedAbstractModule').tags(:abstract).size).to be(1) 44 | end 45 | 46 | it 'preserves tag text' do 47 | node = YARD::Registry.at('MyTaggedAbstractModule') 48 | expect(node.tag(:abstract).text).to eq('Existing abstract tag') 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /spec/yard_sorbet/handlers/struct_prop_handler_spec.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | RSpec.describe YARDSorbet::Handlers::StructPropHandler do 5 | before do 6 | path = File.join(File.expand_path('../../data', __dir__), 'struct_handler.txt') 7 | YARD::Registry.clear 8 | YARD::Parser::SourceParser.parse(path) 9 | end 10 | 11 | describe 'attributes' do 12 | it 'creates accessor method docs' do 13 | node = YARD::Registry.at('PersonStruct#optional') 14 | expect(node.tag(:return).types).to eq(%w[String nil]) 15 | end 16 | 17 | it 'attaches the docstring to the accessor' do 18 | node = YARD::Registry.at('PersonStruct#age') 19 | expect(node.docstring).to eq('An age') 20 | end 21 | 22 | it 'creates a docstring if it does not exist' do 23 | node = YARD::Registry.at('PersonStruct#mystery') 24 | expect(node.docstring).to eq('Returns the value of prop `mystery`.') 25 | end 26 | 27 | it 'handles default values appropriately' do 28 | node = YARD::Registry.at('DefaultPersonStruct#initialize') 29 | expect(node.parameters).to eq([['defaulted:', "'hello'"]]) 30 | end 31 | 32 | it 'marks `const` attributes read-only' do 33 | node = YARD::Registry.at('PersonStruct#age') 34 | expect(node.writer?).to be(false) 35 | end 36 | 37 | it 'marks `immutable: true` attributes read-only' do 38 | node = YARD::Registry.at('PersonStruct#not_mutable') 39 | expect(node.writer?).to be(false) 40 | end 41 | 42 | it 'does not mark `prop` attributes read-only' do 43 | node = YARD::Registry.at('PersonStruct#writable') 44 | expect(node.writer?).to be(true) 45 | end 46 | 47 | it 'does not trigger a redundant call to `register`' do 48 | path = File.join(File.expand_path('../../data', __dir__), 'struct_handler.txt') 49 | YARD::Registry.clear 50 | expect_any_instance_of(described_class).not_to receive(:register) # rubocop:disable RSpec/AnyInstance 51 | YARD::Parser::SourceParser.parse(path) 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/simplecov-cobertura@3.1.0.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `simplecov-cobertura` gem. 5 | # Please instead update this file by running `bin/tapioca gem simplecov-cobertura`. 6 | 7 | 8 | # source://simplecov-cobertura//lib/simplecov-cobertura/version.rb#1 9 | module SimpleCov; end 10 | 11 | # source://simplecov-cobertura//lib/simplecov-cobertura/version.rb#2 12 | module SimpleCov::Formatter; end 13 | 14 | # source://simplecov-cobertura//lib/simplecov-cobertura/version.rb#3 15 | class SimpleCov::Formatter::CoberturaFormatter 16 | # @return [CoberturaFormatter] a new instance of CoberturaFormatter 17 | # 18 | # source://simplecov-cobertura//lib/simplecov-cobertura.rb#13 19 | def initialize(result_file_name: T.unsafe(nil)); end 20 | 21 | # source://simplecov-cobertura//lib/simplecov-cobertura.rb#17 22 | def format(result); end 23 | 24 | private 25 | 26 | # source://simplecov-cobertura//lib/simplecov-cobertura.rb#158 27 | def extract_rate(percent); end 28 | 29 | # Roughly mirrors private method SimpleCov::Formatter::HTMLFormatter#output_coverage 30 | # 31 | # source://simplecov-cobertura//lib/simplecov-cobertura.rb#147 32 | def output_message(result, output_path); end 33 | 34 | # source://simplecov-cobertura//lib/simplecov-cobertura.rb#162 35 | def project_root; end 36 | 37 | # source://simplecov-cobertura//lib/simplecov-cobertura.rb#154 38 | def resolve_filename(filename); end 39 | 40 | # source://simplecov-cobertura//lib/simplecov-cobertura.rb#35 41 | def result_to_xml(result); end 42 | 43 | # source://simplecov-cobertura//lib/simplecov-cobertura.rb#136 44 | def set_branch_attributes(line, file_line, branched_lines, branched_lines_covered); end 45 | 46 | # source://simplecov-cobertura//lib/simplecov-cobertura.rb#117 47 | def set_class_attributes(class_, file); end 48 | 49 | # source://simplecov-cobertura//lib/simplecov-cobertura.rb#88 50 | def set_coverage_attributes(coverage, result); end 51 | 52 | # source://simplecov-cobertura//lib/simplecov-cobertura.rb#131 53 | def set_line_attributes(line, file_line); end 54 | 55 | # source://simplecov-cobertura//lib/simplecov-cobertura.rb#105 56 | def set_package_attributes(package, name, result); end 57 | end 58 | 59 | # source://simplecov-cobertura//lib/simplecov-cobertura.rb#11 60 | SimpleCov::Formatter::CoberturaFormatter::DTD_URL = T.let(T.unsafe(nil), String) 61 | 62 | # source://simplecov-cobertura//lib/simplecov-cobertura.rb#10 63 | SimpleCov::Formatter::CoberturaFormatter::RESULT_FILE_NAME = T.let(T.unsafe(nil), String) 64 | 65 | # source://simplecov-cobertura//lib/simplecov-cobertura/version.rb#4 66 | SimpleCov::Formatter::CoberturaFormatter::VERSION = T.let(T.unsafe(nil), String) 67 | -------------------------------------------------------------------------------- /spec/yard_sorbet/handlers/struct_class_handler_spec.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | RSpec.describe YARDSorbet::Handlers::StructClassHandler do 5 | before do 6 | path = File.join(File.expand_path('../../data', __dir__), 'struct_handler.txt') 7 | YARD::Registry.clear 8 | YARD::Parser::SourceParser.parse(path) 9 | end 10 | 11 | describe 'constructor' do 12 | it 'has the parameter tag type' do 13 | node = YARD::Registry.at('PersonStruct#initialize') 14 | tag = YARDSorbet::TagUtils.find_tag(node.docstring, 'param', 'name') 15 | expect(tag&.types).to eq(['String']) 16 | end 17 | 18 | it 'has the nilable parameter tag type' do 19 | node = YARD::Registry.at('PersonStruct#initialize') 20 | tag = YARDSorbet::TagUtils.find_tag(node.docstring, 'param', 'optional') 21 | expect(tag&.types).to eq(%w[String nil]) 22 | end 23 | 24 | it 'return tag has type annotation' do 25 | node = YARD::Registry.at('PersonStruct#initialize') 26 | expect(node.tag(:return).type).to eq('void') 27 | end 28 | 29 | it 'uses the docstring from an explicit initializer' do 30 | node = YARD::Registry.at('SpecializedPersonStruct#initialize') 31 | expect(node.docstring).to eq('This is a special initializer') 32 | end 33 | 34 | it 'preserves param tag text' do 35 | node = YARD::Registry.at('SpecializedPersonStruct#initialize') 36 | tag = YARDSorbet::TagUtils.find_tag(node.docstring, 'param', 'special') 37 | expect(tag&.text).to eq('a very special param') 38 | end 39 | 40 | it 'adds param type to param tag' do 41 | node = YARD::Registry.at('SpecializedPersonStruct#initialize') 42 | tag = YARDSorbet::TagUtils.find_tag(node.docstring, 'param', 'special') 43 | expect(tag&.types).to eq(['String']) 44 | end 45 | 46 | it 'preserves return tag text' do 47 | node = YARD::Registry.at('SpecializedPersonStruct#initialize') 48 | expect(node.tag(:return).text).to eq('an initialized struct') 49 | end 50 | 51 | it 'adds return type to return tag' do 52 | node = YARD::Registry.at('SpecializedPersonStruct#initialize') 53 | expect(node.tag(:return).types).to eq(['void']) 54 | end 55 | 56 | it 'adds raise tag' do 57 | node = YARD::Registry.at('SpecializedPersonStruct#initialize') 58 | expect(node.tag(:raise).types).to eq(['ArgumentError']) 59 | end 60 | 61 | it 'handles keyword node prop names' do 62 | node = YARD::Registry.at('ExceptionalPersonStruct#initialize') 63 | tag = YARDSorbet::TagUtils.find_tag(node.docstring, 'param', 'end') 64 | expect(tag&.types).to eq(['String']) 65 | end 66 | 67 | it 'handles const node prop names' do 68 | node = YARD::Registry.at('ExceptionalPersonStruct#initialize') 69 | tag = YARDSorbet::TagUtils.find_tag(node.docstring, 'param', 'Foo') 70 | expect(tag&.types).to eq(['String']) 71 | end 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /lib/yard-sorbet/handlers/struct_prop_handler.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | module YARDSorbet 5 | module Handlers 6 | # Handles all `const`/`prop` calls, creating accessor methods, and compiles them for later usage at the class level 7 | # in creating a constructor 8 | class StructPropHandler < YARD::Handlers::Ruby::Base 9 | extend T::Sig 10 | 11 | handles method_call(:const), method_call(:prop) 12 | namespace_only 13 | 14 | sig { void } 15 | def process 16 | name = params.dig(0, -1, -1).source 17 | prop = make_prop(name) 18 | update_state(prop) 19 | object = YARD::CodeObjects::MethodObject.new(namespace, name, scope) 20 | decorate_object(object, prop) 21 | register_attrs(object, name) 22 | end 23 | 24 | private 25 | 26 | # Add the source and docstring to the method object 27 | sig { params(object: YARD::CodeObjects::MethodObject, prop: TStructProp).void } 28 | def decorate_object(object, prop) 29 | object.source = prop.source 30 | # TODO: this should use `+` to delimit the prop name when markdown is disabled 31 | reader_docstring = prop.doc.empty? ? "Returns the value of prop `#{prop.prop_name}`." : prop.doc 32 | docstring = YARD::DocstringParser.new.parse(reader_docstring).to_docstring 33 | docstring.add_tag(YARD::Tags::Tag.new(:return, '', prop.types)) 34 | object.docstring = docstring.to_raw 35 | end 36 | 37 | sig { returns(T::Boolean) } 38 | def immutable? = statement.method_name(true) == :const || kw_arg('immutable:') == 'true' 39 | 40 | # @return the value passed to the keyword argument, or nil 41 | sig { params(kwd: String).returns(T.nilable(String)) } 42 | def kw_arg(kwd) = params[2]&.find { _1[0].source == kwd }&.[](1)&.source 43 | 44 | sig { params(name: String).returns(TStructProp) } 45 | def make_prop(name) 46 | TStructProp.new( 47 | default: kw_arg('default:'), 48 | doc: statement.docstring.to_s, 49 | prop_name: name, 50 | source: statement.source, 51 | types: SigToYARD.convert(params.fetch(1)) 52 | ) 53 | end 54 | 55 | sig { returns(T::Array[YARD::Parser::Ruby::AstNode]) } 56 | def params = @params ||= T.let(statement.parameters(false), T.nilable(T::Array[YARD::Parser::Ruby::AstNode])) 57 | 58 | # Register the field explicitly as an attribute. 59 | sig { params(object: YARD::CodeObjects::MethodObject, name: String).void } 60 | def register_attrs(object, name) 61 | write = immutable? ? nil : object 62 | # Create the virtual attribute in our current scope 63 | namespace.attributes[scope][name] ||= SymbolHash[read: object, write:] 64 | end 65 | 66 | # Store the prop for use in the constructor definition 67 | sig { params(prop: TStructProp).void } 68 | def update_state(prop) 69 | extra_state.prop_docs ||= Hash.new { |h, k| h[k] = [] } 70 | extra_state.prop_docs[namespace] << prop 71 | end 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /lib/yard-sorbet/handlers/struct_class_handler.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | module YARDSorbet 5 | module Handlers 6 | # Class-level handler that folds all `const` and `prop` declarations into the constructor documentation 7 | # this needs to be injected as a module otherwise the default Class handler will overwrite documentation 8 | # 9 | # @note this module is included in `YARD::Handlers::Ruby::ClassHandler` 10 | module StructClassHandler 11 | extend T::Sig 12 | 13 | sig { void } 14 | def process 15 | super 16 | return if extra_state.prop_docs.nil? 17 | 18 | # lookup the full YARD path for the current class 19 | class_ns = YARD::CodeObjects::ClassObject.new(namespace, statement[0].source.gsub(/\s/, '')) 20 | props = extra_state.prop_docs[class_ns] 21 | return if props.empty? 22 | 23 | process_t_struct_props(props, class_ns) 24 | end 25 | 26 | private 27 | 28 | # Create a virtual `initialize` method with all the `prop`/`const` arguments 29 | sig { params(props: T::Array[TStructProp], class_ns: YARD::CodeObjects::ClassObject).void } 30 | def process_t_struct_props(props, class_ns) 31 | # having the name :initialize & the scope :instance marks this as the constructor. 32 | object = YARD::CodeObjects::MethodObject.new(class_ns, :initialize, :instance) 33 | # There is a chance that there is a custom initializer, so make sure we steal the existing docstring 34 | # and source 35 | docstring, directives = Directives.extract_directives(object.docstring) 36 | object.tags.each { docstring.add_tag(_1) } 37 | props.each { TagUtils.upsert_tag(docstring, 'param', _1.types, _1.prop_name, _1.doc) } 38 | TagUtils.upsert_tag(docstring, 'return', TagUtils::VOID_RETURN_TYPE) 39 | decorate_t_struct_init(object, props, docstring, directives) 40 | end 41 | 42 | sig do 43 | params( 44 | object: YARD::CodeObjects::MethodObject, 45 | props: T::Array[TStructProp], 46 | docstring: YARD::Docstring, 47 | directives: T::Array[String] 48 | ).void 49 | end 50 | def decorate_t_struct_init(object, props, docstring, directives) 51 | # Use kwarg style arguments, with optionals being marked with a default (unless an actual default was specified) 52 | object.parameters = to_object_parameters(props) 53 | # The "source" of our constructor is the field declarations 54 | object.source ||= props.map(&:source).join("\n") 55 | object.docstring = docstring 56 | Directives.add_directives(object.docstring, directives) 57 | end 58 | 59 | sig { params(props: T::Array[TStructProp]).returns(T::Array[[String, T.nilable(String)]]) } 60 | def to_object_parameters(props) 61 | props.map do |prop| 62 | default = prop.default || (prop.types.include?('nil') ? 'nil' : nil) 63 | ["#{prop.prop_name}:", default] 64 | end 65 | end 66 | end 67 | end 68 | end 69 | 70 | YARD::Handlers::Ruby::ClassHandler.include YARDSorbet::Handlers::StructClassHandler 71 | -------------------------------------------------------------------------------- /lib/yard-sorbet/node_utils.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | module YARDSorbet 5 | # Helper methods for working with `YARD` AST Nodes 6 | module NodeUtils 7 | extend T::Sig 8 | 9 | # Command node types that can have type signatures 10 | ATTRIBUTE_METHODS = T.let(%i[attr attr_accessor attr_reader attr_writer].freeze, T::Array[Symbol]) 11 | # Skip these method contents during BFS node traversal, they can have their own nested types via `T.Proc` 12 | SKIP_METHOD_CONTENTS = T.let(%i[params returns].freeze, T::Array[Symbol]) 13 | # Node types that can have type signatures 14 | SigableNode = T.type_alias { T.any(YARD::Parser::Ruby::MethodDefinitionNode, YARD::Parser::Ruby::MethodCallNode) } 15 | private_constant :ATTRIBUTE_METHODS, :SKIP_METHOD_CONTENTS, :SigableNode 16 | 17 | # Traverse AST nodes in breadth-first order 18 | # @note This will skip over some node types. 19 | # @yield [YARD::Parser::Ruby::AstNode] 20 | sig { params(node: YARD::Parser::Ruby::AstNode, _blk: T.proc.params(n: YARD::Parser::Ruby::AstNode).void).void } 21 | def self.bfs_traverse(node, &_blk) 22 | queue = Queue.new << node 23 | until queue.empty? 24 | n = queue.deq(true) 25 | yield n 26 | enqueue_children(queue, n) 27 | end 28 | end 29 | 30 | sig { params(node: YARD::Parser::Ruby::AstNode).void } 31 | def self.delete_node(node) = node.parent.children.delete(node) 32 | 33 | # Enqueue the eligible children of a node in the BFS queue 34 | sig { params(queue: Queue, node: YARD::Parser::Ruby::AstNode).void } 35 | def self.enqueue_children(queue, node) 36 | last_child = node.children.last 37 | node.children.each do |child| 38 | next if child == last_child && 39 | node.is_a?(YARD::Parser::Ruby::MethodCallNode) && 40 | SKIP_METHOD_CONTENTS.include?(node.method_name(true)) 41 | 42 | queue.enq(child) 43 | end 44 | end 45 | 46 | # Gets the node that a sorbet `sig` can be attached do, bypassing visibility modifiers and the like 47 | sig { params(node: YARD::Parser::Ruby::AstNode).returns(SigableNode) } 48 | def self.get_method_node(node) = sigable_node?(node) ? node : node.jump(:def, :defs) 49 | 50 | # Find and return the adjacent node (ascending) 51 | # @raise [IndexError] if the node does not have an adjacent sibling (ascending) 52 | sig { params(node: YARD::Parser::Ruby::AstNode).returns(YARD::Parser::Ruby::AstNode) } 53 | def self.sibling_node(node) 54 | siblings = node.parent.children 55 | node_index = siblings.find_index { _1.equal?(node) } 56 | siblings.fetch(node_index + 1) 57 | end 58 | 59 | sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Boolean) } 60 | def self.sigable_node?(node) 61 | case node 62 | when YARD::Parser::Ruby::MethodDefinitionNode then true 63 | when YARD::Parser::Ruby::MethodCallNode then ATTRIBUTE_METHODS.include?(node.method_name(true)) 64 | else false 65 | end 66 | end 67 | 68 | # @see https://github.com/lsegal/yard/blob/main/lib/yard/handlers/ruby/attribute_handler.rb 69 | # YARD::Handlers::Ruby::AttributeHandler.validated_attribute_names 70 | sig { params(attr_node: YARD::Parser::Ruby::MethodCallNode).returns(T::Array[String]) } 71 | def self.validated_attribute_names(attr_node) 72 | attr_node.parameters(false).map do |obj| 73 | case obj 74 | when YARD::Parser::Ruby::LiteralNode then obj[0][0].source 75 | else raise YARD::Parser::UndocumentableError, obj.source 76 | end 77 | end 78 | end 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | yard-sorbet (0.9.0) 5 | sorbet-runtime 6 | yard 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | ast (2.4.3) 12 | benchmark (0.5.0) 13 | diff-lcs (1.6.2) 14 | docile (1.4.1) 15 | erubi (1.13.1) 16 | json (2.16.0) 17 | language_server-protocol (3.17.0.5) 18 | lint_roller (1.1.0) 19 | logger (1.7.0) 20 | netrc (0.11.0) 21 | parallel (1.27.0) 22 | parser (3.3.10.0) 23 | ast (~> 2.4.1) 24 | racc 25 | prism (1.6.0) 26 | racc (1.8.1) 27 | rainbow (3.1.1) 28 | rake (13.3.1) 29 | rbi (0.3.7) 30 | prism (~> 1.0) 31 | rbs (>= 3.4.4) 32 | rbs (4.0.0.dev.4) 33 | logger 34 | prism (>= 1.3.0) 35 | redcarpet (3.6.1) 36 | regexp_parser (2.11.3) 37 | require-hooks (0.2.2) 38 | rexml (3.4.4) 39 | rspec (3.13.2) 40 | rspec-core (~> 3.13.0) 41 | rspec-expectations (~> 3.13.0) 42 | rspec-mocks (~> 3.13.0) 43 | rspec-core (3.13.6) 44 | rspec-support (~> 3.13.0) 45 | rspec-expectations (3.13.5) 46 | diff-lcs (>= 1.2.0, < 2.0) 47 | rspec-support (~> 3.13.0) 48 | rspec-mocks (3.13.7) 49 | diff-lcs (>= 1.2.0, < 2.0) 50 | rspec-support (~> 3.13.0) 51 | rspec-support (3.13.6) 52 | rubocop (1.81.7) 53 | json (~> 2.3) 54 | language_server-protocol (~> 3.17.0.2) 55 | lint_roller (~> 1.1.0) 56 | parallel (~> 1.10) 57 | parser (>= 3.3.0.2) 58 | rainbow (>= 2.2.2, < 4.0) 59 | regexp_parser (>= 2.9.3, < 3.0) 60 | rubocop-ast (>= 1.47.1, < 2.0) 61 | ruby-progressbar (~> 1.7) 62 | unicode-display_width (>= 2.4.0, < 4.0) 63 | rubocop-ast (1.48.0) 64 | parser (>= 3.3.7.2) 65 | prism (~> 1.4) 66 | rubocop-packaging (0.6.0) 67 | lint_roller (~> 1.1.0) 68 | rubocop (>= 1.72.1, < 2.0) 69 | rubocop-performance (1.26.1) 70 | lint_roller (~> 1.1) 71 | rubocop (>= 1.75.0, < 2.0) 72 | rubocop-ast (>= 1.47.1, < 2.0) 73 | rubocop-rake (0.7.1) 74 | lint_roller (~> 1.1) 75 | rubocop (>= 1.72.1) 76 | rubocop-rspec (3.8.0) 77 | lint_roller (~> 1.1) 78 | rubocop (~> 1.81) 79 | rubocop-sorbet (0.11.0) 80 | lint_roller 81 | rubocop (>= 1.75.2) 82 | ruby-progressbar (1.13.0) 83 | simplecov (0.22.0) 84 | docile (~> 1.1) 85 | simplecov-html (~> 0.11) 86 | simplecov_json_formatter (~> 0.1) 87 | simplecov-cobertura (3.1.0) 88 | rexml 89 | simplecov (~> 0.19) 90 | simplecov-html (0.13.2) 91 | simplecov_json_formatter (0.1.4) 92 | sorbet (0.6.12798) 93 | sorbet-static (= 0.6.12798) 94 | sorbet-runtime (0.6.12798) 95 | sorbet-static (0.6.12798-universal-darwin) 96 | sorbet-static (0.6.12798-x86_64-linux) 97 | sorbet-static-and-runtime (0.6.12798) 98 | sorbet (= 0.6.12798) 99 | sorbet-runtime (= 0.6.12798) 100 | spoom (1.7.10) 101 | erubi (>= 1.10.0) 102 | prism (>= 0.28.0) 103 | rbi (>= 0.3.3) 104 | rbs (>= 4.0.0.dev.4) 105 | rexml (>= 3.2.6) 106 | sorbet-static-and-runtime (>= 0.5.10187) 107 | thor (>= 0.19.2) 108 | tapioca (0.17.9) 109 | benchmark 110 | bundler (>= 2.2.25) 111 | netrc (>= 0.11.0) 112 | parallel (>= 1.21.0) 113 | rbi (>= 0.3.7) 114 | require-hooks (>= 0.2.2) 115 | sorbet-static-and-runtime (>= 0.5.11087) 116 | spoom (>= 1.7.9) 117 | thor (>= 1.2.0) 118 | yard-sorbet 119 | thor (1.4.0) 120 | unicode-display_width (3.2.0) 121 | unicode-emoji (~> 4.1) 122 | unicode-emoji (4.1.0) 123 | yard (0.9.37) 124 | 125 | PLATFORMS 126 | universal-darwin 127 | x86_64-linux 128 | 129 | DEPENDENCIES 130 | rake (~> 13.3.1) 131 | redcarpet (~> 3.6.0) 132 | rspec (~> 3.13.2) 133 | rubocop (~> 1.81.7) 134 | rubocop-packaging (~> 0.6.0) 135 | rubocop-performance (~> 1.26.1) 136 | rubocop-rake (~> 0.7.1) 137 | rubocop-rspec (~> 3.8.0) 138 | rubocop-sorbet (~> 0.11.0) 139 | simplecov 140 | simplecov-cobertura 141 | sorbet (~> 0.6.12798) 142 | tapioca (~> 0.17.9) 143 | yard-sorbet! 144 | 145 | BUNDLED WITH 146 | 2.7.2 147 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## main 4 | 5 | ### Changes 6 | * Increase minimum required ruby version to `3.2` 7 | 8 | ### Bug Fixes 9 | * [#351](https://github.com/dduugg/yard-sorbet/pull/351) Fix handling of empty tuples (fixed arrays) 10 | 11 | ## 0.9.0 (2024-06-30) 12 | 13 | ### Bug Fixes 14 | * [Fix](https://github.com/dduugg/yard-sorbet/commit/f44388b) syntax of order-dependent lists 15 | 16 | ### Changes 17 | * [#311](https://github.com/dduugg/yard-sorbet/issues/311) Increase minimum required ruby version to `3.1` 18 | 19 | ## 0.8.1 (2023-04-03) 20 | 21 | ### Bug Fixes 22 | * [#201](https://github.com/dduugg/yard-sorbet/issues/201) Caching not reloading docstring when using Sorbet signature 23 | 24 | ## 0.8.0 (2023-01-14) 25 | 26 | ### New Features 27 | * [#141](https://github.com/dduugg/yard-sorbet/issues/141) Merge RBI sigs into existing documentation 28 | 29 | ### Bug Fixes 30 | * Handle multiple invocations of `mixes_in_class_methods` within a class 31 | * Label `T::Struct` `prop`s with `immutable: true` as `readonly` 32 | 33 | ## 0.7.0 (2022-08-24) 34 | 35 | ### Bug Fixes 36 | * [#98](https://github.com/dduugg/yard-sorbet/pull/98) Fix typo in abstract tag text 37 | 38 | ### Changes 39 | * Increase minimum required ruby version to `2.7` 40 | 41 | ## 0.6.1 (2021-11-01) 42 | 43 | ### Bug fixes 44 | * [#78](https://github.com/dduugg/yard-sorbet/pull/78) Fix `mixes_in_class_methods` across files 45 | 46 | ## 0.6.0 (2021-10-13) 47 | 48 | ### New features 49 | * [#77](https://github.com/dduugg/yard-sorbet/pull/77) Add `mixes_in_class_methods` support 50 | 51 | ## 0.5.3 (2021-08-01) 52 | 53 | ### Bug fixes 54 | * [#71](https://github.com/dduugg/yard-sorbet/pull/71) Fix `T::Struct` constructor object creation 55 | 56 | ## 0.5.2 (2021-07-01) 57 | 58 | ### Bug fixes 59 | * [#61](https://github.com/dduugg/yard-sorbet/pull/61) Fix parsing of `sig` with nested return types 60 | * [#63](https://github.com/dduugg/yard-sorbet/pull/63) Fix parsing of `top_const_ref` nodes (e.g. `::Foo`) 61 | * [#64](https://github.com/dduugg/yard-sorbet/pull/64) Fix parsing of `list` nodes 62 | * [#65](https://github.com/dduugg/yard-sorbet/pull/65) Fix parsing of nested `array` nodes 63 | 64 | ## 0.5.1 (2021-06-08) 65 | 66 | ### Bug fixes 67 | * [#52](https://github.com/dduugg/yard-sorbet/issues/52) Fix `sig` parsing of attr_* methods that use parens 68 | 69 | ## 0.5.0 (2021-05-28) 70 | 71 | ### New features 72 | * [#49](https://github.com/dduugg/yard-sorbet/issues/49) Apply `@abstract` tags to `abstract!`/`interface!` modules 73 | * [#43](https://github.com/dduugg/yard-sorbet/issues/43) Add `T::Enum` support 74 | 75 | ### Bug fixes 76 | * [#41](https://github.com/dduugg/yard-sorbet/issues/41) Fix superfluous return type of boolean methods with inline modifiers 77 | 78 | ### Changes 79 | * Increase minimum `sorbet` version to `0.5.6289` 80 | * Increase minimum `yard` version to `0.9.21` 81 | 82 | ## 0.4.1 (2021-04-28) 83 | 84 | ### Bug fixes 85 | * [#32](https://github.com/dduugg/yard-sorbet/issues/32) Fix processing of `T::Struct` field names that are ruby keywords or capitalized 86 | 87 | ## 0.4.0 (2021-04-02) 88 | 89 | ### New features 90 | * [#15](https://github.com/dduugg/yard-sorbet/issues/15) Add support for `T::Struct` `prop` declarations 91 | 92 | ## 0.3.0 (2021-03-11) 93 | 94 | ### New features 95 | * Add `YARDSorbet::VERSION` 96 | 97 | ### Bug fixes 98 | * [#26](https://github.com/dduugg/yard-sorbet/pull/26): Remove sorbet `default_checked_level` 99 | 100 | ## 0.2.0 (2021-01-14) 101 | 102 | ### Bug fixes 103 | * [#17](https://github.com/dduugg/yard-sorbet/pull/17): Fix docstrings for methods that contain a comment on method definition line 104 | 105 | ### Changes 106 | * [#16](https://github.com/dduugg/yard-sorbet/pull/16): Enforce strict typing in non-spec code. 107 | * Require yard >= 0.9.16 and sorbet-runtime >= 0.5.5845 108 | 109 | ## 0.1.0 (2020-12-01) 110 | 111 | ### New features 112 | * [#8](https://github.com/dduugg/yard-sorbet/pull/8): Add support for singleton class syntax. 113 | * [#7](https://github.com/dduugg/yard-sorbet/pull/7): Add support for top-level constants in sigs. 114 | 115 | ### Bug fixes 116 | * [#9](https://github.com/dduugg/yard-sorbet/pull/9): Remove warning for use of `T.attached_class`. 117 | * [#11](https://github.com/dduugg/yard-sorbet/pull/11): Fix parsing of custom parameterized types. 118 | * [#12](https://github.com/dduugg/yard-sorbet/pull/12): Fix parsing of recursive custom parameterized types. 119 | 120 | ### Changes 121 | * [#10](https://github.com/dduugg/yard-sorbet/pull/10): Downgrade log level of unsupported `sig` `aref` nodes. 122 | * Drop Ruby 2.4 support 123 | 124 | ## 0.0.1 (2020-01-24) 125 | 126 | ### New Features 127 | * [#1](https://github.com/dduugg/yard-sorbet/pull/1): Add `T::Struct` support. 128 | 129 | ### Changes 130 | * [#3](https://github.com/dduugg/yard-sorbet/pull/3): Rename require path to be conistent with gem name. 131 | 132 | ## 0.0.0 (2020-01-05) 133 | * Initial Release 134 | -------------------------------------------------------------------------------- /lib/yard-sorbet/handlers/sig_handler.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | module YARDSorbet 5 | module Handlers 6 | # A YARD Handler for Sorbet type declarations 7 | class SigHandler < YARD::Handlers::Ruby::Base 8 | extend T::Sig 9 | 10 | handles method_call(:sig) 11 | namespace_only 12 | 13 | # YARD types that can have docstrings attached to them 14 | Documentable = T.type_alias do 15 | T.any( 16 | YARD::CodeObjects::MethodObject, YARD::Parser::Ruby::MethodCallNode, YARD::Parser::Ruby::MethodDefinitionNode 17 | ) 18 | end 19 | private_constant :Documentable 20 | 21 | # Swap the method definition docstring and the sig docstring. 22 | # Parse relevant parts of the `sig` and include them as well. 23 | sig { void } 24 | def process 25 | method_node = NodeUtils.get_method_node(NodeUtils.sibling_node(statement)) 26 | case method_node 27 | when YARD::Parser::Ruby::MethodDefinitionNode then process_def(method_node) 28 | when YARD::Parser::Ruby::MethodCallNode then process_attr(method_node) 29 | end 30 | statement.docstring = nil 31 | end 32 | 33 | private 34 | 35 | sig { params(def_node: YARD::Parser::Ruby::MethodDefinitionNode).void } 36 | def process_def(def_node) 37 | separator = scope == :instance && def_node.type == :def ? '#' : '.' 38 | registered = YARD::Registry.at("#{namespace}#{separator}#{def_node.method_name(true)}") 39 | if registered 40 | parse_node(registered, statement.docstring || registered.docstring) 41 | # Since we're probably in an RBI file, delete the def node, which could otherwise erroneously override the 42 | # visibility setting 43 | NodeUtils.delete_node(def_node) 44 | else 45 | parse_node(def_node, statement.docstring) 46 | end 47 | end 48 | 49 | sig { params(attr_node: YARD::Parser::Ruby::MethodCallNode).void } 50 | def process_attr(attr_node) 51 | return if merged_into_attr?(attr_node) 52 | 53 | parse_node(attr_node, statement.docstring, include_params: false) 54 | end 55 | 56 | # An attr* sig can be merged into a previous attr* docstring if it is the only parameter passed to the attr* 57 | # declaration. This is to avoid needing to rewrite the source code to separate merged and unmerged attr* 58 | # declarations. 59 | sig { params(attr_node: YARD::Parser::Ruby::MethodCallNode).returns(T::Boolean) } 60 | def merged_into_attr?(attr_node) 61 | names = NodeUtils.validated_attribute_names(attr_node) 62 | return false if names.size != 1 63 | 64 | attrs = namespace.attributes[scope][names[0]] 65 | return false if attrs.nil? || attrs.empty? 66 | 67 | document_attrs(attrs.values.compact) 68 | attr_node.docstring = nil 69 | true 70 | end 71 | 72 | sig { params(method_objects: T::Array[YARD::CodeObjects::MethodObject]).void } 73 | def document_attrs(method_objects) = method_objects.each { parse_node(_1, _1.docstring, include_params: false) } 74 | 75 | sig { params(attach_to: Documentable, docstring: T.nilable(String), include_params: T::Boolean).void } 76 | def parse_node(attach_to, docstring, include_params: true) 77 | existing_docstring = docstring.is_a?(YARD::Docstring) 78 | docstring, directives = Directives.extract_directives(docstring) unless existing_docstring 79 | parse_sig(docstring, include_params:) 80 | attach_to.docstring = docstring.to_raw 81 | Directives.add_directives(attach_to.docstring, directives) unless existing_docstring 82 | end 83 | 84 | sig { params(docstring: YARD::Docstring, include_params: T::Boolean).void } 85 | def parse_sig(docstring, include_params: true) 86 | NodeUtils.bfs_traverse(statement) do |node| 87 | case node.source 88 | when 'returns' then parse_return(node, docstring) 89 | when 'params' then parse_params(node, docstring) if include_params 90 | when 'void' then TagUtils.upsert_tag(docstring, 'return', TagUtils::VOID_RETURN_TYPE) 91 | when 'abstract' then TagUtils.upsert_tag(docstring, 'abstract') 92 | end 93 | end 94 | end 95 | 96 | sig { params(node: YARD::Parser::Ruby::AstNode, docstring: YARD::Docstring).void } 97 | def parse_params(node, docstring) 98 | sibling = NodeUtils.sibling_node(node) 99 | sibling[0][0].each do |param| 100 | param_name = param[0][0] 101 | types = SigToYARD.convert(param.last) 102 | TagUtils.upsert_tag(docstring, 'param', types, param_name) 103 | end 104 | end 105 | 106 | sig { params(node: YARD::Parser::Ruby::AstNode, docstring: YARD::Docstring).void } 107 | def parse_return(node, docstring) 108 | type = SigToYARD.convert(NodeUtils.sibling_node(node)) 109 | TagUtils.upsert_tag(docstring, 'return', type) 110 | end 111 | end 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /lib/yard-sorbet/sig_to_yard.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | module YARDSorbet 5 | # Translate `sig` type syntax to `YARD` type syntax. 6 | module SigToYARD 7 | class << self 8 | extend T::Sig 9 | 10 | # Map of common types to YARD conventions (in order to reduce allocations) 11 | REF_TYPES = T.let({ 12 | 'T::Boolean' => ['Boolean'].freeze, # YARD convention for booleans 13 | # YARD convention is to use singleton objects when applicable: 14 | # https://www.rubydoc.info/gems/yard/file/docs/Tags.md#literals 15 | 'FalseClass' => ['false'].freeze, 16 | 'NilClass' => ['nil'].freeze, 17 | 'TrueClass' => ['true'].freeze 18 | }.freeze, T::Hash[String, [String]]) 19 | private_constant :REF_TYPES 20 | 21 | # @see https://yardoc.org/types.html 22 | sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) } 23 | def convert(node) = convert_node(node).map { _1.gsub(/\n\s*/, ' ') } 24 | 25 | private 26 | 27 | sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) } 28 | def convert_node(node) 29 | case node 30 | when YARD::Parser::Ruby::MethodCallNode 31 | node.namespace.source == 'T' ? convert_t_method(node) : [node.source] 32 | when YARD::Parser::Ruby::ReferenceNode 33 | node_source = node.source 34 | REF_TYPES[node_source] || [node_source] 35 | else convert_node_type(node) 36 | end 37 | end 38 | 39 | sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) } 40 | def convert_node_type(node) 41 | case node.type 42 | when :aref then convert_aref(node) 43 | when :arg_paren then convert_node(node.first) 44 | when :array then convert_array(node) 45 | # Fixed hashes as return values are unsupported: 46 | # https://github.com/lsegal/yard/issues/425 47 | # 48 | # Hash key params can be individually documented with `@option`, but 49 | # sig translation is currently unsupported. 50 | when :hash then ['Hash'] 51 | # seen when sig methods omit parentheses 52 | when :list then convert_list(node) 53 | else convert_unknown(node) 54 | end 55 | end 56 | 57 | sig { params(node: YARD::Parser::Ruby::AstNode).returns(String) } 58 | def build_generic_type(node) 59 | return node.source if node.empty? || node.type != :aref 60 | 61 | collection_type = node.first.source 62 | member_type = node.last.children.map { build_generic_type(_1) }.join(', ') 63 | "#{collection_type}[#{member_type}]" 64 | end 65 | 66 | sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) } 67 | def convert_aref(node) 68 | # https://www.rubydoc.info/gems/yard/file/docs/Tags.md#parametrized-types 69 | case node.first.source 70 | when 'T::Array', 'T::Enumerable', 'T::Range', 'T::Set' then convert_collection(node) 71 | when 'T::Hash' then convert_hash(node) 72 | else 73 | log.info("Unsupported sig aref node #{node.source}") 74 | [build_generic_type(node)] 75 | end 76 | end 77 | 78 | # @see https://www.rubydoc.info/gems/yard/file/docs/Tags.md#order-dependent-lists Order-Dependent Lists 79 | sig { params(node: YARD::Parser::Ruby::AstNode).returns([String]) } 80 | def convert_array(node) = ["Array<(#{sequence(node.first)})>"] 81 | 82 | sig { params(node: T.nilable(YARD::Parser::Ruby::AstNode)).returns(String) } 83 | def sequence(node) 84 | return '' unless node 85 | 86 | node.children.map { convert_node(_1) }.map { _1.size == 1 ? _1[0] : _1.to_s.tr('"', '') }.join(', ') 87 | end 88 | 89 | sig { params(node: YARD::Parser::Ruby::AstNode).returns([String]) } 90 | def convert_collection(node) 91 | collection_type = node.first.source.split('::').last 92 | member_type = convert_node(node[-1][0]).join(', ') 93 | ["#{collection_type}<#{member_type}>"] 94 | end 95 | 96 | sig { params(node: YARD::Parser::Ruby::AstNode).returns([String]) } 97 | def convert_hash(node) 98 | kv = node.last.children 99 | key_type = convert_node(kv.first).join(', ') 100 | value_type = convert_node(kv.last).join(', ') 101 | ["Hash{#{key_type} => #{value_type}}"] 102 | end 103 | 104 | sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) } 105 | def convert_list(node) 106 | node.children.size == 1 ? convert_node(node.children.first) : [node.source] 107 | end 108 | 109 | sig { params(node: YARD::Parser::Ruby::MethodCallNode).returns(T::Array[String]) } 110 | def convert_t_method(node) 111 | case node.method_name(true) 112 | # Order matters here, putting `nil` last results in a more concise return syntax in the UI (superscripted `?`): 113 | # https://github.com/lsegal/yard/blob/cfa62ae/lib/yard/templates/helpers/html_helper.rb#L499-L500 114 | when :nilable then convert_node(node.last) + REF_TYPES.fetch('NilClass') 115 | when :any then node[-1][0].children.flat_map { convert_node(_1) } 116 | else [node.source] 117 | end 118 | end 119 | 120 | sig { params(node: YARD::Parser::Ruby::AstNode).returns([String]) } 121 | def convert_unknown(node) 122 | log.warn("Unsupported sig #{node.type} node #{node.source}") 123 | [node.source] 124 | end 125 | end 126 | end 127 | end 128 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | require 'sorbet-runtime' 5 | 6 | T::Configuration.enable_checking_for_sigs_marked_checked_tests 7 | 8 | if ENV['CI'] 9 | require 'simplecov' 10 | require 'simplecov-cobertura' 11 | SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter 12 | SimpleCov.start 13 | end 14 | 15 | require 'yard-sorbet' 16 | 17 | # This file was generated by the `rspec --init` command. Conventionally, all 18 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 19 | # The generated `.rspec` file contains `--require spec_helper` which will cause 20 | # this file to always be loaded, without a need to explicitly require it in any 21 | # files. 22 | # 23 | # Given that it is always loaded, you are encouraged to keep this file as 24 | # light-weight as possible. Requiring heavyweight dependencies from this file 25 | # will add to the boot time of your test suite on EVERY test run, even for an 26 | # individual file that may not need all of that loaded. Instead, consider making 27 | # a separate helper file that requires the additional dependencies and performs 28 | # the additional setup, and require it from the spec files that actually need 29 | # it. 30 | # 31 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 32 | RSpec.configure do |config| 33 | # rspec-expectations config goes here. You can use an alternate 34 | # assertion/expectation library such as wrong or the stdlib/minitest 35 | # assertions if you prefer. 36 | config.expect_with :rspec do |expectations| 37 | # This option will default to `true` in RSpec 4. It makes the `description` 38 | # and `failure_message` of custom matchers include text for helper methods 39 | # defined using `chain`, e.g.: 40 | # be_bigger_than(2).and_smaller_than(4).description 41 | # # => "be bigger than 2 and smaller than 4" 42 | # ...rather than: 43 | # # => "be bigger than 2" 44 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 45 | end 46 | 47 | # rspec-mocks config goes here. You can use an alternate test double 48 | # library (such as bogus or mocha) by changing the `mock_with` option here. 49 | config.mock_with :rspec do |mocks| 50 | # Prevents you from mocking or stubbing a method that does not exist on 51 | # a real object. This is generally recommended, and will default to 52 | # `true` in RSpec 4. 53 | mocks.verify_partial_doubles = true 54 | end 55 | 56 | # This option will default to `:apply_to_host_groups` in RSpec 4 (and will 57 | # have no way to turn it off -- the option exists only for backwards 58 | # compatibility in RSpec 3). It causes shared context metadata to be 59 | # inherited by the metadata hash of host groups and examples, rather than 60 | # triggering implicit auto-inclusion in groups with matching metadata. 61 | config.shared_context_metadata_behavior = :apply_to_host_groups 62 | 63 | # The settings below are suggested to provide a good initial experience 64 | # with RSpec, but feel free to customize to your heart's content. 65 | 66 | # This allows you to limit a spec run to individual examples or groups 67 | # you care about by tagging them with `:focus` metadata. When nothing 68 | # is tagged with `:focus`, all examples get run. RSpec also provides 69 | # aliases for `it`, `describe`, and `context` that include `:focus` 70 | # metadata: `fit`, `fdescribe` and `fcontext`, respectively. 71 | config.filter_run_when_matching :focus 72 | 73 | # Allows RSpec to persist some state between runs in order to support 74 | # the `--only-failures` and `--next-failure` CLI options. We recommend 75 | # you configure your source control system to ignore this file. 76 | config.example_status_persistence_file_path = 'spec/examples.txt' 77 | 78 | # Limits the available syntax to the non-monkey patched syntax that is 79 | # recommended. For more details, see: 80 | # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ 81 | # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 82 | # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode 83 | config.disable_monkey_patching! 84 | 85 | # This setting enables warnings. It's recommended, but in some cases may 86 | # be too noisy due to issues in dependencies. 87 | # config.warnings = true 88 | 89 | # Many RSpec users commonly either run the entire suite or an individual 90 | # file, and it's useful to allow more verbose output when running an 91 | # individual spec file. 92 | if config.files_to_run.one? 93 | # Use the documentation formatter for detailed output, 94 | # unless a formatter has already been configured 95 | # (e.g. via a command-line flag). 96 | config.default_formatter = 'doc' 97 | end 98 | 99 | # Print the 10 slowest examples and example groups at the 100 | # end of the spec run, to help surface which specs are running 101 | # particularly slow. 102 | # config.profile_examples = 10 103 | 104 | # Run specs in random order to surface order dependencies. If you find an 105 | # order dependency and want to debug it, you can fix the order by providing 106 | # the seed, which is printed after each run. 107 | # --seed 1234 108 | config.order = :random 109 | 110 | # Seed global randomization in this process using the `--seed` CLI option. 111 | # Setting this allows you to use `--seed` to deterministically reproduce 112 | # test failures related to randomization by passing the same `--seed` value 113 | # as the one that triggered the failure. 114 | Kernel.srand config.seed 115 | end 116 | -------------------------------------------------------------------------------- /sorbet/rbi/annotations/rainbow.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This file was pulled from a central RBI files repository. 5 | # Please run `bin/tapioca annotations` to update it. 6 | 7 | module Rainbow 8 | # @shim: https://github.com/sickill/rainbow/blob/master/lib/rainbow.rb#L10-L12 9 | sig { returns(T::Boolean) } 10 | attr_accessor :enabled 11 | 12 | class Color 13 | sig { returns(Symbol) } 14 | attr_reader :ground 15 | 16 | sig { params(ground: Symbol, values: T.any([Integer], [Integer, Integer, Integer])).returns(Color) } 17 | def self.build(ground, values); end 18 | 19 | sig { params(hex: String).returns([Integer, Integer, Integer]) } 20 | def self.parse_hex_color(hex); end 21 | 22 | class Indexed < Rainbow::Color 23 | sig { returns(Integer) } 24 | attr_reader :num 25 | 26 | sig { params(ground: Symbol, num: Integer).void } 27 | def initialize(ground, num); end 28 | 29 | sig { returns(T::Array[Integer]) } 30 | def codes; end 31 | end 32 | 33 | class Named < Rainbow::Color::Indexed 34 | NAMES = T.let(nil, T::Hash[Symbol, Integer]) 35 | 36 | sig { params(ground: Symbol, name: Symbol).void } 37 | def initialize(ground, name); end 38 | 39 | sig { returns(T::Array[Symbol]) } 40 | def self.color_names; end 41 | 42 | sig { returns(String) } 43 | def self.valid_names; end 44 | end 45 | 46 | class RGB < Rainbow::Color::Indexed 47 | sig { returns(Integer) } 48 | attr_reader :r, :g, :b 49 | 50 | sig { params(ground: Symbol, values: Integer).void } 51 | def initialize(ground, *values); end 52 | 53 | sig { returns(T::Array[Integer]) } 54 | def codes; end 55 | 56 | sig { params(value: Numeric).returns(Integer) } 57 | def self.to_ansi_domain(value); end 58 | end 59 | 60 | class X11Named < Rainbow::Color::RGB 61 | include Rainbow::X11ColorNames 62 | 63 | sig { params(ground: Symbol, name: Symbol).void } 64 | def initialize(ground, name); end 65 | 66 | sig { returns(T::Array[Symbol]) } 67 | def self.color_names; end 68 | 69 | sig { returns(String) } 70 | def self.valid_names; end 71 | end 72 | end 73 | 74 | sig { returns(Wrapper) } 75 | def self.global; end 76 | 77 | sig { returns(T::Boolean) } 78 | def self.enabled; end 79 | 80 | sig { params(value: T::Boolean).returns(T::Boolean) } 81 | def self.enabled=(value); end 82 | 83 | sig { params(string: String).returns(String) } 84 | def self.uncolor(string); end 85 | 86 | class NullPresenter < String 87 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(NullPresenter) } 88 | def color(*values); end 89 | 90 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(NullPresenter) } 91 | def foreground(*values); end 92 | 93 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(NullPresenter) } 94 | def fg(*values); end 95 | 96 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(NullPresenter) } 97 | def background(*values); end 98 | 99 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(NullPresenter) } 100 | def bg(*values); end 101 | 102 | sig { returns(NullPresenter) } 103 | def reset; end 104 | 105 | sig { returns(NullPresenter) } 106 | def bright; end 107 | 108 | sig { returns(NullPresenter) } 109 | def faint; end 110 | 111 | sig { returns(NullPresenter) } 112 | def italic; end 113 | 114 | sig { returns(NullPresenter) } 115 | def underline; end 116 | 117 | sig { returns(NullPresenter) } 118 | def blink; end 119 | 120 | sig { returns(NullPresenter) } 121 | def inverse; end 122 | 123 | sig { returns(NullPresenter) } 124 | def hide; end 125 | 126 | sig { returns(NullPresenter) } 127 | def cross_out; end 128 | 129 | sig { returns(NullPresenter) } 130 | def black; end 131 | 132 | sig { returns(NullPresenter) } 133 | def red; end 134 | 135 | sig { returns(NullPresenter) } 136 | def green; end 137 | 138 | sig { returns(NullPresenter) } 139 | def yellow; end 140 | 141 | sig { returns(NullPresenter) } 142 | def blue; end 143 | 144 | sig { returns(NullPresenter) } 145 | def magenta; end 146 | 147 | sig { returns(NullPresenter) } 148 | def cyan; end 149 | 150 | sig { returns(NullPresenter) } 151 | def white; end 152 | 153 | sig { returns(NullPresenter) } 154 | def bold; end 155 | 156 | sig { returns(NullPresenter) } 157 | def dark; end 158 | 159 | sig { returns(NullPresenter) } 160 | def strike; end 161 | end 162 | 163 | class Presenter < String 164 | TERM_EFFECTS = T.let(nil, T::Hash[Symbol, Integer]) 165 | 166 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(Presenter) } 167 | def color(*values); end 168 | 169 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(Presenter) } 170 | def foreground(*values); end 171 | 172 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(Presenter) } 173 | def fg(*values); end 174 | 175 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(Presenter) } 176 | def background(*values); end 177 | 178 | sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(Presenter) } 179 | def bg(*values); end 180 | 181 | sig { returns(Presenter) } 182 | def reset; end 183 | 184 | sig { returns(Presenter) } 185 | def bright; end 186 | 187 | sig { returns(Presenter) } 188 | def faint; end 189 | 190 | sig { returns(Presenter) } 191 | def italic; end 192 | 193 | sig { returns(Presenter) } 194 | def underline; end 195 | 196 | sig { returns(Presenter) } 197 | def blink; end 198 | 199 | sig { returns(Presenter) } 200 | def inverse; end 201 | 202 | sig { returns(Presenter) } 203 | def hide; end 204 | 205 | sig { returns(Presenter) } 206 | def cross_out; end 207 | 208 | sig { returns(Presenter) } 209 | def black; end 210 | 211 | sig { returns(Presenter) } 212 | def red; end 213 | 214 | sig { returns(Presenter) } 215 | def green; end 216 | 217 | sig { returns(Presenter) } 218 | def yellow; end 219 | 220 | sig { returns(Presenter) } 221 | def blue; end 222 | 223 | sig { returns(Presenter) } 224 | def magenta; end 225 | 226 | sig { returns(Presenter) } 227 | def cyan; end 228 | 229 | sig { returns(Presenter) } 230 | def white; end 231 | 232 | sig { returns(Presenter) } 233 | def bold; end 234 | 235 | sig { returns(Presenter) } 236 | def dark; end 237 | 238 | sig { returns(Presenter) } 239 | def strike; end 240 | end 241 | 242 | class StringUtils 243 | sig { params(string: String, codes: T::Array[Integer]).returns(String) } 244 | def self.wrap_with_sgr(string, codes); end 245 | 246 | sig { params(string: String).returns(String) } 247 | def self.uncolor(string); end 248 | end 249 | 250 | VERSION = T.let(nil, String) 251 | 252 | class Wrapper 253 | sig { returns(T::Boolean) } 254 | attr_accessor :enabled 255 | 256 | sig { params(enabled: T::Boolean).void } 257 | def initialize(enabled = true); end 258 | 259 | sig { params(string: String).returns(T.any(Rainbow::Presenter, Rainbow::NullPresenter)) } 260 | def wrap(string); end 261 | end 262 | 263 | module X11ColorNames 264 | NAMES = T.let(nil, T::Hash[Symbol, [Integer, Integer, Integer]]) 265 | end 266 | end 267 | 268 | sig { params(string: String).returns(Rainbow::Presenter) } 269 | def Rainbow(string); end 270 | -------------------------------------------------------------------------------- /spec/data/sig_handler.txt: -------------------------------------------------------------------------------- 1 | # typed: false 2 | # frozen_string_literal: true 3 | 4 | class Bar; end 5 | class Boolean; end 6 | class Custom; end 7 | class Custom1; end 8 | class Custom2; end 9 | class Custom3; end 10 | class Custom4; end 11 | class EmailConversation; end 12 | class Foo; class Bar; end; end 13 | 14 | class B 15 | def sig_override_void; end 16 | end 17 | 18 | class Signatures < B 19 | # comment sig_void 20 | sig {void} 21 | def sig_void; end 22 | 23 | # comment sig_override_void 24 | sig {override.void} 25 | def sig_override_void; end 26 | 27 | # comment sig_arguments 28 | sig {params(a: Integer, b: Integer).void} 29 | def sig_arguments(a, b); end 30 | 31 | # comment sig_multiline_arguments 32 | sig do 33 | params( 34 | a: Integer, 35 | b: Integer, 36 | ).void 37 | end 38 | def sig_multiline_arguments(a, b); end 39 | 40 | # comment sig_multiline_comments 41 | # comment sig_multiline_comments 42 | sig {void} 43 | def sig_multiline_comments; end 44 | 45 | # comment sig_class_method 46 | sig {void} 47 | def self.sig_class_method; end 48 | 49 | class << self 50 | # comment reopening 51 | sig {void} 52 | def reopening; end 53 | end 54 | end 55 | 56 | class Subclass < Signatures 57 | # with subclass 58 | sig {void} 59 | def method; end 60 | end 61 | 62 | class ClassWithCode 63 | # bar 64 | sig {void} 65 | def bar; end 66 | 67 | puts 'foobar' 68 | 69 | # foo 70 | sig {void} 71 | def foo; end 72 | end 73 | 74 | class Outer 75 | # outer method 76 | sig {void} 77 | def outer; end 78 | 79 | class Inner 80 | # inner method 81 | sig {void} 82 | def inner; end 83 | end 84 | 85 | # outer method 2 86 | sig {void} 87 | def outer2; end 88 | end 89 | 90 | module MyModule 91 | # module function 92 | sig {void} 93 | def self.foo; end 94 | 95 | # module instance method 96 | sig {void} 97 | def bar; end 98 | end 99 | 100 | class SigReturn 101 | # attr has trailing comment 102 | sig {returns(String)} 103 | attr_reader :attr_contains_comment # rubocop:disable ... 104 | 105 | sig {returns(Integer)} 106 | def one; 1; end 107 | 108 | # @deprecated do not use 109 | sig {returns(Integer)} 110 | def two; 2; end 111 | 112 | # @return [Numeric] 113 | sig {returns(Integer)} 114 | def three; 3; end 115 | 116 | # @return the number four 117 | sig {returns(Integer)} 118 | def four; 4; end 119 | 120 | sig {params(int: Integer).returns(Float)} 121 | def plus_one(int); int + 1.0; end 122 | 123 | sig {params(a: Numeric, b: Numeric).returns(T.any(Numeric, String))} 124 | def plus(a, b); a + b; end 125 | 126 | sig {void} 127 | def void_method; end 128 | 129 | # method definition contains comment 130 | sig {void} 131 | def method_definition_contains_comment # rubocop:disable ... 132 | end 133 | 134 | # class method definition contains comment 135 | sig {void} 136 | def self.class_method_definition_contains_comment # rubocop:disable ... 137 | end 138 | 139 | sig {returns Integer} 140 | def no_parens; end 141 | end 142 | 143 | class SigAbstract 144 | abstract! 145 | 146 | sig {abstract.void} 147 | def one; end 148 | 149 | # @abstract subclass must implement 150 | sig {abstract.returns(NilClass)} 151 | def two; end 152 | 153 | sig {abstract.returns(Boolean)} 154 | def with_return; end 155 | 156 | sig {abstract.void} 157 | def with_void; end 158 | end 159 | 160 | class A 161 | def impl_blk_method(&block); end 162 | end 163 | 164 | class SigParams < A 165 | # @param bar the thing 166 | # @param baz [Object] the other thing 167 | sig {params(bar: T.any(String, Symbol), baz: T.nilable(String)).void} 168 | def foo(bar, baz); end 169 | 170 | sig do 171 | params( 172 | blk: T.proc.params(arg0: String).returns(T::Array[Hash]) 173 | ) 174 | .returns(NilClass) 175 | end 176 | def blk_method(&blk); nil; end 177 | 178 | sig do 179 | override 180 | .params(block: T.proc.params( 181 | model: EmailConversation, 182 | mutator: T.untyped, 183 | ).void) 184 | .void 185 | end 186 | def impl_blk_method(&block); end 187 | end 188 | 189 | class CollectionSigs 190 | sig {params(arr: T::Array[String]).void} 191 | def collection(arr); end 192 | 193 | sig {params(arr: T::Array[T::Array[String]]).void} 194 | def nested_collection(arr); end 195 | 196 | sig {params(arr: T::Array[T.any(String, Symbol)]).returns(TrueClass)} 197 | def mixed_collection(arr); true; end 198 | 199 | sig {returns(T::Hash[String, Symbol])} 200 | def hash_method; end 201 | 202 | sig{params(arr: Custom[String]).void} 203 | def custom_collection(arr); end 204 | 205 | sig{params(arr: T::Array[Custom1[Custom2[String, Integer, T::Boolean], T.any(Custom3[String], Custom4[Integer])]]).void} 206 | def nested_custom_collection(arr); end 207 | 208 | sig{params(arr: Custom[T.all(T.any(Foo, Bar), T::Array[String], T::Hash[Integer, Symbol])]).void} 209 | def custom_collection_with_inner_nodes(arr); end 210 | 211 | sig {returns([String, Integer])} 212 | def fixed_array; ['', 0]; end 213 | 214 | sig {params(arr: [Foo, Bar]).returns([])} 215 | def fixed_empty_array(arr); []; end 216 | 217 | sig {returns(T.any([String], []))} 218 | def maybe_empty_array; []; end 219 | 220 | # @!visibility protected 221 | sig {returns({foo: T.nilable(String)})} 222 | def fixed_hash; {foo: nil}; end 223 | 224 | sig do 225 | params( 226 | tos_acceptance: T.nilable({ 227 | date: Integer, 228 | ip: String, 229 | user_agent: T.nilable(String), 230 | signator: T.nilable(String), 231 | iovation_blackbox: T.nilable(String), 232 | }) 233 | ) 234 | .returns(NilClass) 235 | end 236 | def fixed_param_hash(tos_acceptance); nil; end 237 | end 238 | 239 | class VariousTypedSigs 240 | sig { returns(String) } 241 | def arg_paren; end 242 | 243 | sig { returns([String]) } 244 | def array; end 245 | 246 | sig { returns(T.all(Foo, Bar)) } 247 | def call_T_all; end 248 | 249 | sig { returns(T.attached_class) } 250 | def self.call_T_attached_class; end 251 | 252 | sig { returns(T.class_of(String)) } 253 | def call_T_class_of; String; end 254 | 255 | sig { returns(T.enum) } 256 | def call_T_enum; end 257 | 258 | sig { returns(T.noreturn) } 259 | def call_T_noreturn; end 260 | 261 | sig { returns(T.self_type) } 262 | def call_T_self_type; end 263 | 264 | sig { returns(T.type_parameter) } 265 | def call_T_type_parameter; end 266 | 267 | sig { returns(T.untyped) } 268 | def call_T_untyped; end 269 | 270 | sig { returns(T.any(Integer, String)) } 271 | def call_T_any; end 272 | 273 | sig { returns(T.nilable(String)) } 274 | def call_T_nilable; end 275 | 276 | sig { returns(Foo::Bar) } 277 | def const_path_ref; end 278 | 279 | sig { returns( {foo: Integer} ) } 280 | def hash; end 281 | 282 | sig { returns(FalseClass) } 283 | def var_ref_false_class; end 284 | 285 | sig { returns(NilClass) } 286 | def var_ref_nil_class; end 287 | 288 | sig { returns(TrueClass) } 289 | def var_ref_true_class; end 290 | 291 | sig { returns(Foo) } 292 | def var_ref; end 293 | 294 | sig { returns(::Foo) } 295 | def top_const_ref; end 296 | 297 | sig { params(props: T::Array[String]).returns(T::Array[[String, T.nilable(String)]]) } 298 | private def nested_array_return(props); end 299 | end 300 | 301 | class AttrSigs 302 | sig {returns(String)} 303 | attr_accessor 'my_accessor' 304 | 305 | sig {returns(Integer)} 306 | attr_reader :my_reader 307 | 308 | sig {params(my_writer: T.nilable(Symbol)).returns(T.nilable(Symbol))} 309 | attr_writer :my_writer 310 | 311 | sig {params(with_parens: T::Boolean).returns(T::Boolean)} 312 | attr_writer(:with_parens) 313 | end 314 | 315 | class SigInlineVisibility 316 | sig { params(next_statement: T.nilable(YARD::Parser::Ruby::AstNode)).returns(T::Boolean) } 317 | private def boolean_method?(next_statement) 318 | true 319 | end 320 | end 321 | 322 | module Cask; class DSL; end; end 323 | class BlockDSL 324 | module PageWithURL; end 325 | 326 | sig { 327 | params( 328 | uri: T.nilable(T.any(URI::Generic, String)), 329 | dsl: T.nilable(Cask::DSL), 330 | block: T.proc.params(arg0: T.all(String, PageWithURL)).returns(T.untyped), 331 | ).void 332 | } 333 | def initialize(uri, dsl: nil, &block) 334 | @uri = uri 335 | @dsl = dsl 336 | @block = block 337 | end 338 | end 339 | 340 | class Nodes 341 | INT = Integer 342 | 343 | sig { returns(INT) } 344 | def returns_const; 1; end 345 | end 346 | 347 | module Merge 348 | class A 349 | # annotated attr_accessor 350 | attr_accessor :a_foo 351 | 352 | attr_reader :a_bar 353 | 354 | attr_writer :a_baz 355 | 356 | # The foo instance method for A 357 | def foo; end 358 | 359 | # The bar singleton method for A 360 | def self.bar(a); end 361 | 362 | private def baz; end 363 | 364 | # @return the result 365 | def bat; end 366 | 367 | # old doctsring 368 | def xyz; end 369 | end 370 | end 371 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/lint_roller@1.1.0.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `lint_roller` gem. 5 | # Please instead update this file by running `bin/tapioca gem lint_roller`. 6 | 7 | 8 | # source://lint_roller//lib/lint_roller/context.rb#1 9 | module LintRoller; end 10 | 11 | # source://lint_roller//lib/lint_roller/about.rb#2 12 | class LintRoller::About < ::Struct 13 | # Returns the value of attribute description 14 | # 15 | # @return [Object] the current value of description 16 | # 17 | # source://lint_roller//lib/lint_roller/about.rb#2 18 | def description; end 19 | 20 | # Sets the attribute description 21 | # 22 | # @param value [Object] the value to set the attribute description to. 23 | # @return [Object] the newly set value 24 | # 25 | # source://lint_roller//lib/lint_roller/about.rb#2 26 | def description=(_); end 27 | 28 | # Returns the value of attribute homepage 29 | # 30 | # @return [Object] the current value of homepage 31 | # 32 | # source://lint_roller//lib/lint_roller/about.rb#2 33 | def homepage; end 34 | 35 | # Sets the attribute homepage 36 | # 37 | # @param value [Object] the value to set the attribute homepage to. 38 | # @return [Object] the newly set value 39 | # 40 | # source://lint_roller//lib/lint_roller/about.rb#2 41 | def homepage=(_); end 42 | 43 | # Returns the value of attribute name 44 | # 45 | # @return [Object] the current value of name 46 | # 47 | # source://lint_roller//lib/lint_roller/about.rb#2 48 | def name; end 49 | 50 | # Sets the attribute name 51 | # 52 | # @param value [Object] the value to set the attribute name to. 53 | # @return [Object] the newly set value 54 | # 55 | # source://lint_roller//lib/lint_roller/about.rb#2 56 | def name=(_); end 57 | 58 | # Returns the value of attribute version 59 | # 60 | # @return [Object] the current value of version 61 | # 62 | # source://lint_roller//lib/lint_roller/about.rb#2 63 | def version; end 64 | 65 | # Sets the attribute version 66 | # 67 | # @param value [Object] the value to set the attribute version to. 68 | # @return [Object] the newly set value 69 | # 70 | # source://lint_roller//lib/lint_roller/about.rb#2 71 | def version=(_); end 72 | 73 | class << self 74 | # source://lint_roller//lib/lint_roller/about.rb#2 75 | def [](*_arg0); end 76 | 77 | # source://lint_roller//lib/lint_roller/about.rb#2 78 | def inspect; end 79 | 80 | # source://lint_roller//lib/lint_roller/about.rb#2 81 | def keyword_init?; end 82 | 83 | # source://lint_roller//lib/lint_roller/about.rb#2 84 | def members; end 85 | 86 | # source://lint_roller//lib/lint_roller/about.rb#2 87 | def new(*_arg0); end 88 | end 89 | end 90 | 91 | # source://lint_roller//lib/lint_roller/context.rb#2 92 | class LintRoller::Context < ::Struct 93 | # Returns the value of attribute engine 94 | # 95 | # @return [Object] the current value of engine 96 | # 97 | # source://lint_roller//lib/lint_roller/context.rb#2 98 | def engine; end 99 | 100 | # Sets the attribute engine 101 | # 102 | # @param value [Object] the value to set the attribute engine to. 103 | # @return [Object] the newly set value 104 | # 105 | # source://lint_roller//lib/lint_roller/context.rb#2 106 | def engine=(_); end 107 | 108 | # Returns the value of attribute engine_version 109 | # 110 | # @return [Object] the current value of engine_version 111 | # 112 | # source://lint_roller//lib/lint_roller/context.rb#2 113 | def engine_version; end 114 | 115 | # Sets the attribute engine_version 116 | # 117 | # @param value [Object] the value to set the attribute engine_version to. 118 | # @return [Object] the newly set value 119 | # 120 | # source://lint_roller//lib/lint_roller/context.rb#2 121 | def engine_version=(_); end 122 | 123 | # Returns the value of attribute rule_format 124 | # 125 | # @return [Object] the current value of rule_format 126 | # 127 | # source://lint_roller//lib/lint_roller/context.rb#2 128 | def rule_format; end 129 | 130 | # Sets the attribute rule_format 131 | # 132 | # @param value [Object] the value to set the attribute rule_format to. 133 | # @return [Object] the newly set value 134 | # 135 | # source://lint_roller//lib/lint_roller/context.rb#2 136 | def rule_format=(_); end 137 | 138 | # Returns the value of attribute runner 139 | # 140 | # @return [Object] the current value of runner 141 | # 142 | # source://lint_roller//lib/lint_roller/context.rb#2 143 | def runner; end 144 | 145 | # Sets the attribute runner 146 | # 147 | # @param value [Object] the value to set the attribute runner to. 148 | # @return [Object] the newly set value 149 | # 150 | # source://lint_roller//lib/lint_roller/context.rb#2 151 | def runner=(_); end 152 | 153 | # Returns the value of attribute runner_version 154 | # 155 | # @return [Object] the current value of runner_version 156 | # 157 | # source://lint_roller//lib/lint_roller/context.rb#2 158 | def runner_version; end 159 | 160 | # Sets the attribute runner_version 161 | # 162 | # @param value [Object] the value to set the attribute runner_version to. 163 | # @return [Object] the newly set value 164 | # 165 | # source://lint_roller//lib/lint_roller/context.rb#2 166 | def runner_version=(_); end 167 | 168 | # Returns the value of attribute target_ruby_version 169 | # 170 | # @return [Object] the current value of target_ruby_version 171 | # 172 | # source://lint_roller//lib/lint_roller/context.rb#2 173 | def target_ruby_version; end 174 | 175 | # Sets the attribute target_ruby_version 176 | # 177 | # @param value [Object] the value to set the attribute target_ruby_version to. 178 | # @return [Object] the newly set value 179 | # 180 | # source://lint_roller//lib/lint_roller/context.rb#2 181 | def target_ruby_version=(_); end 182 | 183 | class << self 184 | # source://lint_roller//lib/lint_roller/context.rb#2 185 | def [](*_arg0); end 186 | 187 | # source://lint_roller//lib/lint_roller/context.rb#2 188 | def inspect; end 189 | 190 | # source://lint_roller//lib/lint_roller/context.rb#2 191 | def keyword_init?; end 192 | 193 | # source://lint_roller//lib/lint_roller/context.rb#2 194 | def members; end 195 | 196 | # source://lint_roller//lib/lint_roller/context.rb#2 197 | def new(*_arg0); end 198 | end 199 | end 200 | 201 | # source://lint_roller//lib/lint_roller/error.rb#2 202 | class LintRoller::Error < ::StandardError; end 203 | 204 | # source://lint_roller//lib/lint_roller/plugin.rb#2 205 | class LintRoller::Plugin 206 | # `config' is a Hash of options passed to the plugin by the user 207 | # 208 | # @return [Plugin] a new instance of Plugin 209 | # 210 | # source://lint_roller//lib/lint_roller/plugin.rb#4 211 | def initialize(config = T.unsafe(nil)); end 212 | 213 | # @raise [Error] 214 | # 215 | # source://lint_roller//lib/lint_roller/plugin.rb#8 216 | def about; end 217 | 218 | # `context' is an instance of LintRoller::Context provided by the runner 219 | # 220 | # @raise [Error] 221 | # 222 | # source://lint_roller//lib/lint_roller/plugin.rb#18 223 | def rules(context); end 224 | 225 | # `context' is an instance of LintRoller::Context provided by the runner 226 | # 227 | # @return [Boolean] 228 | # 229 | # source://lint_roller//lib/lint_roller/plugin.rb#13 230 | def supported?(context); end 231 | end 232 | 233 | # source://lint_roller//lib/lint_roller/rules.rb#2 234 | class LintRoller::Rules < ::Struct 235 | # Returns the value of attribute config_format 236 | # 237 | # @return [Object] the current value of config_format 238 | # 239 | # source://lint_roller//lib/lint_roller/rules.rb#2 240 | def config_format; end 241 | 242 | # Sets the attribute config_format 243 | # 244 | # @param value [Object] the value to set the attribute config_format to. 245 | # @return [Object] the newly set value 246 | # 247 | # source://lint_roller//lib/lint_roller/rules.rb#2 248 | def config_format=(_); end 249 | 250 | # Returns the value of attribute error 251 | # 252 | # @return [Object] the current value of error 253 | # 254 | # source://lint_roller//lib/lint_roller/rules.rb#2 255 | def error; end 256 | 257 | # Sets the attribute error 258 | # 259 | # @param value [Object] the value to set the attribute error to. 260 | # @return [Object] the newly set value 261 | # 262 | # source://lint_roller//lib/lint_roller/rules.rb#2 263 | def error=(_); end 264 | 265 | # Returns the value of attribute type 266 | # 267 | # @return [Object] the current value of type 268 | # 269 | # source://lint_roller//lib/lint_roller/rules.rb#2 270 | def type; end 271 | 272 | # Sets the attribute type 273 | # 274 | # @param value [Object] the value to set the attribute type to. 275 | # @return [Object] the newly set value 276 | # 277 | # source://lint_roller//lib/lint_roller/rules.rb#2 278 | def type=(_); end 279 | 280 | # Returns the value of attribute value 281 | # 282 | # @return [Object] the current value of value 283 | # 284 | # source://lint_roller//lib/lint_roller/rules.rb#2 285 | def value; end 286 | 287 | # Sets the attribute value 288 | # 289 | # @param value [Object] the value to set the attribute value to. 290 | # @return [Object] the newly set value 291 | # 292 | # source://lint_roller//lib/lint_roller/rules.rb#2 293 | def value=(_); end 294 | 295 | class << self 296 | # source://lint_roller//lib/lint_roller/rules.rb#2 297 | def [](*_arg0); end 298 | 299 | # source://lint_roller//lib/lint_roller/rules.rb#2 300 | def inspect; end 301 | 302 | # source://lint_roller//lib/lint_roller/rules.rb#2 303 | def keyword_init?; end 304 | 305 | # source://lint_roller//lib/lint_roller/rules.rb#2 306 | def members; end 307 | 308 | # source://lint_roller//lib/lint_roller/rules.rb#2 309 | def new(*_arg0); end 310 | end 311 | end 312 | 313 | # source://lint_roller//lib/lint_roller/support/merges_upstream_metadata.rb#2 314 | module LintRoller::Support; end 315 | 316 | # source://lint_roller//lib/lint_roller/support/merges_upstream_metadata.rb#3 317 | class LintRoller::Support::MergesUpstreamMetadata 318 | # source://lint_roller//lib/lint_roller/support/merges_upstream_metadata.rb#4 319 | def merge(plugin_yaml, upstream_yaml); end 320 | end 321 | 322 | # source://lint_roller//lib/lint_roller/version.rb#2 323 | LintRoller::VERSION = T.let(T.unsafe(nil), String) 324 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /spec/yard_sorbet/handlers/sig_handler_spec.rb: -------------------------------------------------------------------------------- 1 | # typed: strict 2 | # frozen_string_literal: true 3 | 4 | RSpec.describe YARDSorbet::Handlers::SigHandler do 5 | # The :all (and corresponding rubocop disable) isn't strictly necessary, but it speeds up tests considerably 6 | before(:all) do # rubocop:disable RSpec/BeforeAfterAll 7 | YARD::Registry.clear 8 | path = File.join(File.expand_path('../../data', __dir__), 'sig_handler.txt') 9 | YARD::Parser::SourceParser.parse(path) 10 | rbi_path = File.join(File.expand_path('../../data', __dir__), 'sig_handler.rbi.txt') 11 | YARD::Parser::SourceParser.parse(rbi_path) 12 | end 13 | 14 | describe 'Merging an RBI file' do 15 | it 'includes docstring from original attr_accessor' do 16 | expect(YARD::Registry.at('Merge::A#a_foo').docstring).to eq('annotated attr_accessor') 17 | end 18 | 19 | it 'merges attr_accessor sig' do 20 | expect(YARD::Registry.at('Merge::A#a_foo').tag(:return).types).to eq(['Numeric']) 21 | end 22 | 23 | it 'includes docstring from original attr_reader' do 24 | expect(YARD::Registry.at('Merge::A#a_bar').docstring).to eq('Returns the value of attribute a_bar.') 25 | end 26 | 27 | it 'merges attr_reader sig' do 28 | expect(YARD::Registry.at('Merge::A#a_bar').tag(:return).types).to eq(%w[String nil]) 29 | end 30 | 31 | it 'includes docstring from original attr_writer' do 32 | expect(YARD::Registry.at('Merge::A#a_baz=').docstring).to eq('Sets the attribute a_baz') 33 | end 34 | 35 | it 'merges attr_writer sig' do 36 | expect(YARD::Registry.at('Merge::A#a_baz=').tag(:return).types).to eq(['Integer']) 37 | end 38 | 39 | it 'includes docstring from original instance def' do 40 | expect(YARD::Registry.at('Merge::A#foo').docstring).to eq('The foo instance method for A') 41 | end 42 | 43 | it 'merges instance def sig' do 44 | expect(YARD::Registry.at('Merge::A#foo').tag(:return).types).to eq(['String']) 45 | end 46 | 47 | it 'includes docstring from original singleton def' do 48 | expect(YARD::Registry.at('Merge::A.bar').docstring).to eq('The bar singleton method for A') 49 | end 50 | 51 | it 'merges singleton def sig' do 52 | expect(YARD::Registry.at('Merge::A.bar').tag(:return).types).to eq(['Float']) 53 | end 54 | 55 | it 'preserves the visibility of the original method' do 56 | expect(YARD::Registry.at('Merge::A#baz').visibility).to be(:private) 57 | end 58 | 59 | it 'merges sig return type with return tag' do 60 | expect(YARD::Registry.at('Merge::A#bat').tag(:return).types).to eq(['Integer']) 61 | end 62 | 63 | it 'merges return tag comment with sig return type' do 64 | expect(YARD::Registry.at('Merge::A#bat').tag(:return).text).to eq('the result') 65 | end 66 | 67 | it 'overwrites the prior docstring when a new docstring exists' do 68 | expect(YARD::Registry.at('Merge::A#xyz').docstring).to eq('new docstring') 69 | end 70 | end 71 | 72 | describe 'attaching to method' do 73 | it 'handles signatures without arguments' do 74 | node = YARD::Registry.at('Signatures#sig_void') 75 | expect(node.docstring).to eq('comment sig_void') 76 | end 77 | 78 | it 'handles chaining' do 79 | node = YARD::Registry.at('Signatures#sig_override_void') 80 | expect(node.docstring).to eq('comment sig_override_void') 81 | end 82 | 83 | it 'handles arguments' do 84 | node = YARD::Registry.at('Signatures#sig_arguments') 85 | expect(node.docstring).to eq('comment sig_arguments') 86 | end 87 | 88 | it 'handles multiline arguments' do 89 | node = YARD::Registry.at('Signatures#sig_multiline_arguments') 90 | expect(node.docstring).to eq('comment sig_multiline_arguments') 91 | end 92 | 93 | it 'handles multiline comments' do 94 | node = YARD::Registry.at('Signatures#sig_multiline_comments') 95 | expect(node.docstring).to eq("comment sig_multiline_comments\ncomment sig_multiline_comments") 96 | end 97 | 98 | it 'handles class methods' do 99 | node = YARD::Registry.at('Signatures.sig_class_method') 100 | expect(node.docstring).to eq('comment sig_class_method') 101 | end 102 | 103 | it 'handles subclasses' do 104 | node = YARD::Registry.at('Subclass#method') 105 | expect(node.docstring).to eq('with subclass') 106 | end 107 | 108 | it 'handles classes executing code' do 109 | node = YARD::Registry.at('ClassWithCode#foo') 110 | expect(node.docstring).to eq('foo') 111 | end 112 | 113 | it 'handles module singleton methods' do 114 | node = YARD::Registry.at('MyModule.foo') 115 | expect(node.docstring).to eq('module function') 116 | end 117 | 118 | it 'handles module instance methods' do 119 | node = YARD::Registry.at('MyModule#bar') 120 | expect(node.docstring).to eq('module instance method') 121 | end 122 | 123 | it 'handles singleton class syntax' do 124 | node = YARD::Registry.at('Signatures.reopening') 125 | expect(node.docstring).to eq('comment reopening') 126 | end 127 | end 128 | 129 | describe 'nested classes' do 130 | it 'keep docstrings for outer class methods preceding inner classes' do 131 | expect(YARD::Registry.at('Outer#outer').docstring).to eq('outer method') 132 | end 133 | 134 | it 'keep docstrings for inner class methods' do 135 | expect(YARD::Registry.at('Outer#outer2').docstring).to eq('outer method 2') 136 | end 137 | 138 | it 'keep docstrings for outer class methods following inner class' do 139 | expect(YARD::Registry.at('Outer::Inner#inner').docstring).to eq('inner method') 140 | end 141 | end 142 | 143 | describe 'sig parsing' do 144 | it 'parses return types' do 145 | node = YARD::Registry.at('SigReturn#one') 146 | expect(node.tag(:return).types).to eq(['Integer']) 147 | end 148 | 149 | it 'merges docstring tags' do 150 | expect(YARD::Registry.at('SigReturn#two').tag(:deprecated).text).to eq('do not use') 151 | end 152 | 153 | it 'merges sig tags' do 154 | expect(YARD::Registry.at('SigReturn#two').tag(:return).types).to eq(['Integer']) 155 | end 156 | 157 | it 'overrides explicit tag' do 158 | node = YARD::Registry.at('SigReturn#three') 159 | expect(node.tag(:return).types).to eq(['Integer']) 160 | end 161 | 162 | it 'merges sig return type with return tag' do 163 | expect(YARD::Registry.at('SigReturn#four').tag(:return).types).to eq(['Integer']) 164 | end 165 | 166 | it 'merges return tag comment with sig return type' do 167 | expect(YARD::Registry.at('SigReturn#four').tag(:return).text).to eq('the number four') 168 | end 169 | 170 | it 'with params' do 171 | node = YARD::Registry.at('SigReturn#plus_one') 172 | expect(node.tag(:return).types).to eq(['Float']) 173 | end 174 | 175 | it 'with T syntax' do 176 | node = YARD::Registry.at('SigReturn#plus') 177 | expect(node.tag(:return).types).to eq(%w[Numeric String]) 178 | end 179 | 180 | it 'with void sig' do 181 | node = YARD::Registry.at('SigReturn#void_method') 182 | expect(node.tag(:return).types).to eq(['void']) 183 | end 184 | 185 | it 'with abstract sig' do 186 | node = YARD::Registry.at('SigAbstract#one') 187 | expect(node.tag(:abstract).text).to eq('') 188 | end 189 | 190 | it 'merges abstract tag' do 191 | node = YARD::Registry.at('SigAbstract#two') 192 | expect(node.tag(:abstract).text).to eq('subclass must implement') 193 | end 194 | 195 | it 'merges abstract tag with returns type' do 196 | expect(YARD::Registry.at('SigAbstract#with_return').tag(:abstract).text).to eq('') 197 | end 198 | 199 | it 'merges return type with abstract tag' do 200 | expect(YARD::Registry.at('SigAbstract#with_return').tag(:return).types).to eq(['Boolean']) 201 | end 202 | 203 | it 'merges abstract tag with void' do 204 | expect(YARD::Registry.at('SigAbstract#with_void').tag(:abstract).text).to eq('') 205 | end 206 | 207 | it 'merges void return type with abstract tag' do 208 | expect(YARD::Registry.at('SigAbstract#with_void').tag(:return).types).to eq(['void']) 209 | end 210 | 211 | it 'parses T.any param text' do 212 | bar_tag = YARD::Registry.at('SigParams#foo').tags.find { _1.name == 'bar' } 213 | expect(bar_tag.text).to eq('the thing') 214 | end 215 | 216 | it 'parses T.any param types' do 217 | bar_tag = YARD::Registry.at('SigParams#foo').tags.find { _1.name == 'bar' } 218 | expect(bar_tag.types).to eq(%w[String Symbol]) 219 | end 220 | 221 | it 'parses T.nilable param text' do 222 | baz_tag = YARD::Registry.at('SigParams#foo').tags.find { _1.name == 'baz' } 223 | expect(baz_tag.text).to eq('the other thing') 224 | end 225 | 226 | it 'parses T.nilable param type' do 227 | baz_tag = YARD::Registry.at('SigParams#foo').tags.find { _1.name == 'baz' } 228 | expect(baz_tag.types).to eq(%w[String nil]) 229 | end 230 | 231 | it 'parses block param type' do 232 | blk_tag = YARD::Registry.at('SigParams#blk_method').tags.find { _1.name == 'blk' } 233 | expect(blk_tag.types).to eq(['T.proc.params(arg0: String).returns(T::Array[Hash])']) 234 | end 235 | 236 | it 'parses return type of method with block param' do 237 | expect(YARD::Registry.at('SigParams#blk_method').tag(:return).types).to eq(['nil']) 238 | end 239 | 240 | it 'parses type of block param with newlines' do 241 | blk_tag = YARD::Registry.at('SigParams#impl_blk_method').tags.find { _1.name == 'block' } 242 | expect(blk_tag.types).to eq(['T.proc.params( model: EmailConversation, mutator: T.untyped, ).void']) 243 | end 244 | 245 | it 'parses return type of method with block param type with newlines' do 246 | expect(YARD::Registry.at('SigParams#impl_blk_method').tag(:return).types).to eq(['void']) 247 | end 248 | 249 | it 'T::Array' do 250 | node = YARD::Registry.at('CollectionSigs#collection') 251 | param_tag = node.tags.find { _1.name == 'arr' } 252 | expect(param_tag.types).to eq(['Array']) 253 | end 254 | 255 | it 'nested T::Array' do 256 | node = YARD::Registry.at('CollectionSigs#nested_collection') 257 | param_tag = node.tags.find { _1.name == 'arr' } 258 | expect(param_tag.types).to eq(['Array>']) 259 | end 260 | 261 | it 'mixed T::Array' do 262 | node = YARD::Registry.at('CollectionSigs#mixed_collection') 263 | param_tag = node.tags.find { _1.name == 'arr' } 264 | expect(param_tag.types).to eq(['Array']) 265 | end 266 | 267 | it 'T::Hash' do 268 | node = YARD::Registry.at('CollectionSigs#hash_method') 269 | expect(node.tag(:return).types).to eq(['Hash{String => Symbol}']) 270 | end 271 | 272 | it 'custom collection' do 273 | node = YARD::Registry.at('CollectionSigs#custom_collection') 274 | param_tag = node.tags.find { _1.name == 'arr' } 275 | expect(param_tag.types).to eq(['Custom[String]']) 276 | end 277 | 278 | it 'nested custom collection' do 279 | node = YARD::Registry.at('CollectionSigs#nested_custom_collection') 280 | param_tag = node.tags.find { _1.name == 'arr' } 281 | expect(param_tag.types).to eq( 282 | ['Array'] 283 | ) 284 | end 285 | 286 | it 'custom collection with inner nodes' do 287 | node = YARD::Registry.at('CollectionSigs#custom_collection_with_inner_nodes') 288 | param_tag = node.tags.find { _1.name == 'arr' } 289 | expect(param_tag.types).to eq(['Custom[T.all(T.any(Foo, Bar), T::Array[String], T::Hash[Integer, Symbol])]']) 290 | end 291 | 292 | it 'fixed Array' do 293 | node = YARD::Registry.at('CollectionSigs#fixed_array') 294 | expect(node.tag(:return).types).to eq(['Array<(String, Integer)>']) 295 | end 296 | 297 | it 'fixed empty Array return' do 298 | node = YARD::Registry.at('CollectionSigs#fixed_empty_array') 299 | expect(node.tag(:return).types).to eq(['Array<()>']) 300 | end 301 | 302 | it 'maybe empty Array' do 303 | node = YARD::Registry.at('CollectionSigs#maybe_empty_array') 304 | expect(node.tag(:return).types).to eq(%w[Array<(String)> Array<()>]) 305 | end 306 | 307 | describe 'of fixed Hash' do 308 | it 'has Hash return type' do 309 | expect(YARD::Registry.at('CollectionSigs#fixed_hash').tag(:return).types).to eq(['Hash']) 310 | end 311 | 312 | it 'preserves visibility modifier' do 313 | expect(YARD::Registry.at('CollectionSigs#fixed_hash').visibility).to be(:protected) 314 | end 315 | end 316 | 317 | it 'fixed param Hash' do 318 | node = YARD::Registry.at('CollectionSigs#fixed_param_hash') 319 | param_tag = node.tags.find { _1.name == 'tos_acceptance' } 320 | expect(param_tag.types).to eq(%w[Hash nil]) 321 | end 322 | 323 | it 'arg_paren' do 324 | node = YARD::Registry.at('VariousTypedSigs#arg_paren') 325 | expect(node.tag(:return).types).to eq(['String']) 326 | end 327 | 328 | it 'array' do 329 | node = YARD::Registry.at('VariousTypedSigs#array') 330 | expect(node.tag(:return).types).to eq(['Array<(String)>']) 331 | end 332 | 333 | it 'call_T_all' do 334 | node = YARD::Registry.at('VariousTypedSigs#call_T_all') 335 | expect(node.tag(:return).types).to eq(['T.all(Foo, Bar)']) 336 | end 337 | 338 | it 'call_T_attached_class' do 339 | node = YARD::Registry.at('VariousTypedSigs.call_T_attached_class') 340 | expect(node.tag(:return).types).to eq(['T.attached_class']) 341 | end 342 | 343 | it 'call_T_class_of' do 344 | node = YARD::Registry.at('VariousTypedSigs#call_T_class_of') 345 | expect(node.tag(:return).types).to eq(['T.class_of(String)']) 346 | end 347 | 348 | it 'call_T_enum' do 349 | node = YARD::Registry.at('VariousTypedSigs#call_T_enum') 350 | expect(node.tag(:return).types).to eq(['T.enum']) 351 | end 352 | 353 | it 'call_T_noreturn' do 354 | node = YARD::Registry.at('VariousTypedSigs#call_T_noreturn') 355 | expect(node.tag(:return).types).to eq(['T.noreturn']) 356 | end 357 | 358 | it 'call_T_self_type' do 359 | node = YARD::Registry.at('VariousTypedSigs#call_T_self_type') 360 | expect(node.tag(:return).types).to eq(['T.self_type']) 361 | end 362 | 363 | it 'call_T_type_parameter' do 364 | node = YARD::Registry.at('VariousTypedSigs#call_T_type_parameter') 365 | expect(node.tag(:return).types).to eq(['T.type_parameter']) 366 | end 367 | 368 | it 'call_T_untyped' do 369 | node = YARD::Registry.at('VariousTypedSigs#call_T_untyped') 370 | expect(node.tag(:return).types).to eq(['T.untyped']) 371 | end 372 | 373 | it 'call_T_any' do 374 | node = YARD::Registry.at('VariousTypedSigs#call_T_any') 375 | expect(node.tag(:return).types).to eq(%w[Integer String]) 376 | end 377 | 378 | it 'call_T_nilable' do 379 | node = YARD::Registry.at('VariousTypedSigs#call_T_nilable') 380 | expect(node.tag(:return).types).to eq(%w[String nil]) 381 | end 382 | 383 | it 'const_path_ref' do 384 | node = YARD::Registry.at('VariousTypedSigs#const_path_ref') 385 | expect(node.tag(:return).types).to eq(['Foo::Bar']) 386 | end 387 | 388 | it 'hash' do 389 | node = YARD::Registry.at('VariousTypedSigs#hash') 390 | expect(node.tag(:return).types).to eq(['Hash']) 391 | end 392 | 393 | it 'var_ref_false_class' do 394 | node = YARD::Registry.at('VariousTypedSigs#var_ref_false_class') 395 | expect(node.tag(:return).types).to eq(['false']) 396 | end 397 | 398 | it 'var_ref_nil_class' do 399 | node = YARD::Registry.at('VariousTypedSigs#var_ref_nil_class') 400 | expect(node.tag(:return).types).to eq(['nil']) 401 | end 402 | 403 | it 'var_ref_true_class' do 404 | node = YARD::Registry.at('VariousTypedSigs#var_ref_true_class') 405 | expect(node.tag(:return).types).to eq(['true']) 406 | end 407 | 408 | it 'var_ref' do 409 | node = YARD::Registry.at('VariousTypedSigs#var_ref') 410 | expect(node.tag(:return).types).to eq(['Foo']) 411 | end 412 | 413 | it 'top_const_ref' do 414 | node = YARD::Registry.at('VariousTypedSigs#top_const_ref') 415 | expect(node.tag(:return).types).to eq(['::Foo']) 416 | end 417 | 418 | it 'renders nested array types' do 419 | node = YARD::Registry.at('VariousTypedSigs#nested_array_return') 420 | expect(node.tag(:return).types).to eq(['Array>']) 421 | end 422 | 423 | it 'has single return tag when inline modifier exists' do 424 | node = YARD::Registry.at('SigInlineVisibility#boolean_method?') 425 | return_tags = node.tags.select { _1.tag_name == 'return' } 426 | expect(return_tags.size).to eq(1) 427 | end 428 | 429 | it 'parses return type with inline modifier' do 430 | node = YARD::Registry.at('SigInlineVisibility#boolean_method?') 431 | expect(node.tag(:return).types).to eq(['Boolean']) 432 | end 433 | 434 | it 'parses void methods with proc params' do 435 | expect(YARD::Registry.at('BlockDSL#initialize').tag(:return).types).to eq(['void']) 436 | end 437 | 438 | it 'handles omitting parens' do 439 | node = YARD::Registry.at('SigReturn#no_parens') 440 | expect(node.tag(:return).types).to eq(['Integer']) 441 | end 442 | 443 | it 'parses const nodes' do 444 | node = YARD::Registry.at('Nodes#returns_const') 445 | expect(node.tag(:return).types).to eq(['INT']) 446 | end 447 | end 448 | 449 | describe 'attributes' do 450 | it 'handles attr_accessor getter' do 451 | node = YARD::Registry.at('AttrSigs#my_accessor') 452 | expect(node.tag(:return).types).to eq(['String']) 453 | end 454 | 455 | it 'handles attr_accessor setter' do 456 | node = YARD::Registry.at('AttrSigs#my_accessor=') 457 | expect(node.tag(:return).types).to eq(['String']) 458 | end 459 | 460 | it 'handles attr_reader' do 461 | node = YARD::Registry.at('AttrSigs#my_reader') 462 | expect(node.tag(:return).types).to eq(['Integer']) 463 | end 464 | 465 | it 'handles attr_writer' do 466 | node = YARD::Registry.at('AttrSigs#my_writer=') 467 | expect(node.tag(:return).types).to eq(%w[Symbol nil]) 468 | end 469 | 470 | it 'handles parens' do 471 | node = YARD::Registry.at('AttrSigs#with_parens=') 472 | expect(node.tag(:return).types).to eq(%w[Boolean]) 473 | end 474 | end 475 | 476 | describe 'parsing with trailing comments' do 477 | describe 'on attr declaration' do 478 | it 'preserves return type' do 479 | node = YARD::Registry.at('SigReturn#attr_contains_comment') 480 | expect(node.tag(:return).types).to eq(['String']) 481 | end 482 | 483 | it 'preserves docstring' do 484 | node = YARD::Registry.at('SigReturn#attr_contains_comment') 485 | expect(node.docstring).to eq('attr has trailing comment') 486 | end 487 | end 488 | 489 | describe 'on the method definition line' do 490 | it 'preserves return type' do 491 | node = YARD::Registry.at('SigReturn#method_definition_contains_comment') 492 | expect(node.tag(:return).types).to eq(['void']) 493 | end 494 | 495 | it 'preserves docstring' do 496 | node = YARD::Registry.at('SigReturn#method_definition_contains_comment') 497 | expect(node.docstring).to eq('method definition contains comment') 498 | end 499 | end 500 | 501 | describe 'with trailing comment on the class method definition line' do 502 | it 'preserves return type' do 503 | node = YARD::Registry.at('SigReturn.class_method_definition_contains_comment') 504 | expect(node.tag(:return).types).to eq(['void']) 505 | end 506 | 507 | it 'preserves docstring' do 508 | node = YARD::Registry.at('SigReturn.class_method_definition_contains_comment') 509 | expect(node.docstring).to eq('class method definition contains comment') 510 | end 511 | end 512 | end 513 | 514 | describe 'Unparsable sigs' do 515 | before do 516 | allow(log).to receive(:warn) 517 | YARD::Parser::SourceParser.parse_string(<<~RUBY) 518 | class Test 519 | CONST = :foo 520 | sig { returns(Integer) } 521 | attr_reader CONST 522 | end 523 | RUBY 524 | end 525 | 526 | it 'warn when parsing an attr* with a constant param' do 527 | expect(log).to have_received(:warn).with(/Undocumentable CONST/).twice 528 | end 529 | end 530 | 531 | describe 'sig-to-yard conversion' do 532 | before do 533 | allow(log).to receive(:error) 534 | YARD::Parser::SourceParser.parse_string(<<~RUBY) 535 | class MyClass 536 | sig { returns(T.nilable(T::Boolean)) } 537 | def my_method; end 538 | end 539 | RUBY 540 | end 541 | 542 | it 'does not error when parsing T.nilable' do 543 | expect(log).not_to have_received(:error) 544 | end 545 | end 546 | end 547 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/ast@2.4.3.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `ast` gem. 5 | # Please instead update this file by running `bin/tapioca gem ast`. 6 | 7 | 8 | # {AST} is a library for manipulating abstract syntax trees. 9 | # 10 | # It embraces immutability; each AST node is inherently frozen at 11 | # creation, and updating a child node requires recreating that node 12 | # and its every parent, recursively. 13 | # This is a design choice. It does create some pressure on 14 | # garbage collector, but completely eliminates all concurrency 15 | # and aliasing problems. 16 | # 17 | # See also {AST::Node}, {AST::Processor::Mixin} and {AST::Sexp} for 18 | # additional recommendations and design patterns. 19 | # 20 | # source://ast//lib/ast.rb#13 21 | module AST; end 22 | 23 | # Node is an immutable class, instances of which represent abstract 24 | # syntax tree nodes. It combines semantic information (i.e. anything 25 | # that affects the algorithmic properties of a program) with 26 | # meta-information (line numbers or compiler intermediates). 27 | # 28 | # Notes on inheritance 29 | # ==================== 30 | # 31 | # The distinction between semantics and metadata is important. Complete 32 | # semantic information should be contained within just the {#type} and 33 | # {#children} of a Node instance; in other words, if an AST was to be 34 | # stripped of all meta-information, it should remain a valid AST which 35 | # could be successfully processed to yield a result with the same 36 | # algorithmic properties. 37 | # 38 | # Thus, Node should never be inherited in order to define methods which 39 | # affect or return semantic information, such as getters for `class_name`, 40 | # `superclass` and `body` in the case of a hypothetical `ClassNode`. The 41 | # correct solution is to use a generic Node with a {#type} of `:class` 42 | # and three children. See also {Processor} for tips on working with such 43 | # ASTs. 44 | # 45 | # On the other hand, Node can and should be inherited to define 46 | # application-specific metadata (see also {#initialize}) or customize the 47 | # printing format. It is expected that an application would have one or two 48 | # such classes and use them across the entire codebase. 49 | # 50 | # The rationale for this pattern is extensibility and maintainability. 51 | # Unlike static ones, dynamic languages do not require the presence of a 52 | # predefined, rigid structure, nor does it improve dispatch efficiency, 53 | # and while such a structure can certainly be defined, it does not add 54 | # any value but incurs a maintaining cost. 55 | # For example, extending the AST even with a transformation-local 56 | # temporary node type requires making globally visible changes to 57 | # the codebase. 58 | # 59 | # source://ast//lib/ast/node.rb#40 60 | class AST::Node 61 | # Constructs a new instance of Node. 62 | # 63 | # The arguments `type` and `children` are converted with `to_sym` and 64 | # `to_a` respectively. Additionally, the result of converting `children` 65 | # is frozen. While mutating the arguments is generally considered harmful, 66 | # the most common case is to pass an array literal to the constructor. If 67 | # your code does not expect the argument to be frozen, use `#dup`. 68 | # 69 | # The `properties` hash is passed to {#assign_properties}. 70 | # 71 | # @return [Node] a new instance of Node 72 | # 73 | # source://ast//lib/ast/node.rb#72 74 | def initialize(type, children = T.unsafe(nil), properties = T.unsafe(nil)); end 75 | 76 | # Concatenates `array` with `children` and returns the resulting node. 77 | # 78 | # @return [AST::Node] 79 | # 80 | # source://ast//lib/ast/node.rb#172 81 | def +(array); end 82 | 83 | # Appends `element` to `children` and returns the resulting node. 84 | # 85 | # @return [AST::Node] 86 | # 87 | # source://ast//lib/ast/node.rb#181 88 | def <<(element); end 89 | 90 | # Compares `self` to `other`, possibly converting with `to_ast`. Only 91 | # `type` and `children` are compared; metadata is deliberately ignored. 92 | # 93 | # @return [Boolean] 94 | # 95 | # source://ast//lib/ast/node.rb#153 96 | def ==(other); end 97 | 98 | # Appends `element` to `children` and returns the resulting node. 99 | # 100 | # @return [AST::Node] 101 | # 102 | # source://ast//lib/ast/node.rb#177 103 | def append(element); end 104 | 105 | # Returns the children of this node. 106 | # The returned value is frozen. 107 | # The to_a alias is useful for decomposing nodes concisely. 108 | # For example: 109 | # 110 | # node = s(:gasgn, :$foo, s(:integer, 1)) 111 | # var_name, value = *node 112 | # p var_name # => :$foo 113 | # p value # => (integer 1) 114 | # 115 | # @return [Array] 116 | # 117 | # source://ast//lib/ast/node.rb#56 118 | def children; end 119 | 120 | # Nodes are already frozen, so there is no harm in returning the 121 | # current node as opposed to initializing from scratch and freezing 122 | # another one. 123 | # 124 | # @return self 125 | # 126 | # source://ast//lib/ast/node.rb#118 127 | def clone; end 128 | 129 | # Concatenates `array` with `children` and returns the resulting node. 130 | # 131 | # @return [AST::Node] 132 | # 133 | # source://ast//lib/ast/node.rb#168 134 | def concat(array); end 135 | 136 | # Enables matching for Node, where type is the first element 137 | # and the children are remaining items. 138 | # 139 | # @return [Array] 140 | # 141 | # source://ast//lib/ast/node.rb#253 142 | def deconstruct; end 143 | 144 | # Nodes are already frozen, so there is no harm in returning the 145 | # current node as opposed to initializing from scratch and freezing 146 | # another one. 147 | # 148 | # @return self 149 | # 150 | # source://ast//lib/ast/node.rb#115 151 | def dup; end 152 | 153 | # Test if other object is equal to 154 | # 155 | # @param other [Object] 156 | # @return [Boolean] 157 | # 158 | # source://ast//lib/ast/node.rb#85 159 | def eql?(other); end 160 | 161 | # Returns the precomputed hash value for this node 162 | # 163 | # @return [Integer] 164 | # 165 | # source://ast//lib/ast/node.rb#61 166 | def hash; end 167 | 168 | # Converts `self` to a s-expression ruby string. 169 | # The code return will recreate the node, using the sexp module s() 170 | # 171 | # @param indent [Integer] Base indentation level. 172 | # @return [String] 173 | # 174 | # source://ast//lib/ast/node.rb#211 175 | def inspect(indent = T.unsafe(nil)); end 176 | 177 | # Returns the children of this node. 178 | # The returned value is frozen. 179 | # The to_a alias is useful for decomposing nodes concisely. 180 | # For example: 181 | # 182 | # node = s(:gasgn, :$foo, s(:integer, 1)) 183 | # var_name, value = *node 184 | # p var_name # => :$foo 185 | # p value # => (integer 1) 186 | # 187 | # @return [Array] 188 | # 189 | # source://ast//lib/ast/node.rb#57 190 | def to_a; end 191 | 192 | # @return [AST::Node] self 193 | # 194 | # source://ast//lib/ast/node.rb#229 195 | def to_ast; end 196 | 197 | # Converts `self` to a pretty-printed s-expression. 198 | # 199 | # @param indent [Integer] Base indentation level. 200 | # @return [String] 201 | # 202 | # source://ast//lib/ast/node.rb#204 203 | def to_s(indent = T.unsafe(nil)); end 204 | 205 | # Converts `self` to a pretty-printed s-expression. 206 | # 207 | # @param indent [Integer] Base indentation level. 208 | # @return [String] 209 | # 210 | # source://ast//lib/ast/node.rb#187 211 | def to_sexp(indent = T.unsafe(nil)); end 212 | 213 | # Converts `self` to an Array where the first element is the type as a Symbol, 214 | # and subsequent elements are the same representation of its children. 215 | # 216 | # @return [Array] 217 | # 218 | # source://ast//lib/ast/node.rb#237 219 | def to_sexp_array; end 220 | 221 | # Returns the type of this node. 222 | # 223 | # @return [Symbol] 224 | # 225 | # source://ast//lib/ast/node.rb#43 226 | def type; end 227 | 228 | # Returns a new instance of Node where non-nil arguments replace the 229 | # corresponding fields of `self`. 230 | # 231 | # For example, `Node.new(:foo, [ 1, 2 ]).updated(:bar)` would yield 232 | # `(bar 1 2)`, and `Node.new(:foo, [ 1, 2 ]).updated(nil, [])` would 233 | # yield `(foo)`. 234 | # 235 | # If the resulting node would be identical to `self`, does nothing. 236 | # 237 | # @param children [Array, nil] 238 | # @param properties [Hash, nil] 239 | # @param type [Symbol, nil] 240 | # @return [AST::Node] 241 | # 242 | # source://ast//lib/ast/node.rb#133 243 | def updated(type = T.unsafe(nil), children = T.unsafe(nil), properties = T.unsafe(nil)); end 244 | 245 | protected 246 | 247 | # By default, each entry in the `properties` hash is assigned to 248 | # an instance variable in this instance of Node. A subclass should define 249 | # attribute readers for such variables. The values passed in the hash 250 | # are not frozen or whitelisted; such behavior can also be implemented 251 | # by subclassing Node and overriding this method. 252 | # 253 | # @return [nil] 254 | # 255 | # source://ast//lib/ast/node.rb#98 256 | def assign_properties(properties); end 257 | 258 | # Returns `@type` with all underscores replaced by dashes. This allows 259 | # to write symbol literals without quotes in Ruby sources and yet have 260 | # nicely looking s-expressions. 261 | # 262 | # @return [String] 263 | # 264 | # source://ast//lib/ast/node.rb#264 265 | def fancy_type; end 266 | 267 | private 268 | 269 | # source://ast//lib/ast/node.rb#107 270 | def original_dup; end 271 | end 272 | 273 | # This class includes {AST::Processor::Mixin}; however, it is 274 | # deprecated, since the module defines all of the behaviors that 275 | # the processor includes. Any new libraries should use 276 | # {AST::Processor::Mixin} instead of subclassing this. 277 | # 278 | # @deprecated Use {AST::Processor::Mixin} instead. 279 | # 280 | # source://ast//lib/ast/processor.rb#8 281 | class AST::Processor 282 | include ::AST::Processor::Mixin 283 | end 284 | 285 | # The processor module is a module which helps transforming one 286 | # AST into another. In a nutshell, the {#process} method accepts 287 | # a {Node} and dispatches it to a handler corresponding to its 288 | # type, and returns a (possibly) updated variant of the node. 289 | # 290 | # The processor module has a set of associated design patterns. 291 | # They are best explained with a concrete example. Let's define a 292 | # simple arithmetic language and an AST format for it: 293 | # 294 | # Terminals (AST nodes which do not have other AST nodes inside): 295 | # 296 | # * `(integer )`, 297 | # 298 | # Nonterminals (AST nodes with other nodes as children): 299 | # 300 | # * `(add )`, 301 | # * `(multiply )`, 302 | # * `(divide )`, 303 | # * `(negate )`, 304 | # * `(store )`: stores value of `` 305 | # into a variable named ``, 306 | # * `(load )`: loads value of a variable named 307 | # ``, 308 | # * `(each ...)`: computes each of the ``s and 309 | # prints the result. 310 | # 311 | # All AST nodes have the same Ruby class, and therefore they don't 312 | # know how to traverse themselves. (A solution which dynamically 313 | # checks the type of children is possible, but is slow and 314 | # error-prone.) So, a class including the module which knows how 315 | # to traverse the entire tree should be defined. Such classes 316 | # have a handler for each nonterminal node which recursively 317 | # processes children nodes: 318 | # 319 | # require 'ast' 320 | # 321 | # class ArithmeticsProcessor 322 | # include AST::Processor::Mixin 323 | # # This method traverses any binary operators such as (add) 324 | # # or (multiply). 325 | # def process_binary_op(node) 326 | # # Children aren't decomposed automatically; it is 327 | # # suggested to use Ruby multiple assignment expansion, 328 | # # as it is very convenient here. 329 | # left_expr, right_expr = *node 330 | # 331 | # # AST::Node#updated won't change node type if nil is 332 | # # passed as a first argument, which allows to reuse the 333 | # # same handler for multiple node types using `alias' 334 | # # (below). 335 | # node.updated(nil, [ 336 | # process(left_expr), 337 | # process(right_expr) 338 | # ]) 339 | # end 340 | # alias_method :on_add, :process_binary_op 341 | # alias_method :on_multiply, :process_binary_op 342 | # alias_method :on_divide, :process_binary_op 343 | # 344 | # def on_negate(node) 345 | # # It is also possible to use #process_all for more 346 | # # compact code if every child is a Node. 347 | # node.updated(nil, process_all(node)) 348 | # end 349 | # 350 | # def on_store(node) 351 | # expr, variable_name = *node 352 | # 353 | # # Note that variable_name is not a Node and thus isn't 354 | # # passed to #process. 355 | # node.updated(nil, [ 356 | # process(expr), 357 | # variable_name 358 | # ]) 359 | # end 360 | # 361 | # # (load) is effectively a terminal node, and so it does 362 | # # not need an explicit handler, as the following is the 363 | # # default behavior. Essentially, for any nodes that don't 364 | # # have a defined handler, the node remains unchanged. 365 | # def on_load(node) 366 | # nil 367 | # end 368 | # 369 | # def on_each(node) 370 | # node.updated(nil, process_all(node)) 371 | # end 372 | # end 373 | # 374 | # Let's test our ArithmeticsProcessor: 375 | # 376 | # include AST::Sexp 377 | # expr = s(:add, s(:integer, 2), s(:integer, 2)) 378 | # 379 | # p ArithmeticsProcessor.new.process(expr) == expr # => true 380 | # 381 | # As expected, it does not change anything at all. This isn't 382 | # actually very useful, so let's now define a Calculator, which 383 | # will compute the expression values: 384 | # 385 | # # This Processor folds nonterminal nodes and returns an 386 | # # (integer) terminal node. 387 | # class ArithmeticsCalculator < ArithmeticsProcessor 388 | # def compute_op(node) 389 | # # First, node children are processed and then unpacked 390 | # # to local variables. 391 | # nodes = process_all(node) 392 | # 393 | # if nodes.all? { |node| node.type == :integer } 394 | # # If each of those nodes represents a literal, we can 395 | # # fold this node! 396 | # values = nodes.map { |node| node.children.first } 397 | # AST::Node.new(:integer, [ 398 | # yield(values) 399 | # ]) 400 | # else 401 | # # Otherwise, we can just leave the current node in the 402 | # # tree and only update it with processed children 403 | # # nodes, which can be partially folded. 404 | # node.updated(nil, nodes) 405 | # end 406 | # end 407 | # 408 | # def on_add(node) 409 | # compute_op(node) { |left, right| left + right } 410 | # end 411 | # 412 | # def on_multiply(node) 413 | # compute_op(node) { |left, right| left * right } 414 | # end 415 | # end 416 | # 417 | # Let's check: 418 | # 419 | # p ArithmeticsCalculator.new.process(expr) # => (integer 4) 420 | # 421 | # Excellent, the calculator works! Now, a careful reader could 422 | # notice that the ArithmeticsCalculator does not know how to 423 | # divide numbers. What if we pass an expression with division to 424 | # it? 425 | # 426 | # expr_with_division = \ 427 | # s(:add, 428 | # s(:integer, 1), 429 | # s(:divide, 430 | # s(:add, s(:integer, 8), s(:integer, 4)), 431 | # s(:integer, 3))) # 1 + (8 + 4) / 3 432 | # 433 | # folded_expr_with_division = ArithmeticsCalculator.new.process(expr_with_division) 434 | # p folded_expr_with_division 435 | # # => (add 436 | # # (integer 1) 437 | # # (divide 438 | # # (integer 12) 439 | # # (integer 3))) 440 | # 441 | # As you can see, the expression was folded _partially_: the inner 442 | # `(add)` node which could be computed was folded to 443 | # `(integer 12)`, the `(divide)` node is left as-is because there 444 | # is no computing handler for it, and the root `(add)` node was 445 | # also left as it is because some of its children were not 446 | # literals. 447 | # 448 | # Note that this partial folding is only possible because the 449 | # _data_ format, i.e. the format in which the computed values of 450 | # the nodes are represented, is the same as the AST itself. 451 | # 452 | # Let's extend our ArithmeticsCalculator class further. 453 | # 454 | # class ArithmeticsCalculator 455 | # def on_divide(node) 456 | # compute_op(node) { |left, right| left / right } 457 | # end 458 | # 459 | # def on_negate(node) 460 | # # Note how #compute_op works regardless of the operator 461 | # # arity. 462 | # compute_op(node) { |value| -value } 463 | # end 464 | # end 465 | # 466 | # Now, let's apply our renewed ArithmeticsCalculator to a partial 467 | # result of previous evaluation: 468 | # 469 | # p ArithmeticsCalculator.new.process(expr_with_division) # => (integer 5) 470 | # 471 | # Five! Excellent. This is also pretty much how CRuby 1.8 executed 472 | # its programs. 473 | # 474 | # Now, let's do some automated bug searching. Division by zero is 475 | # an error, right? So if we could detect that someone has divided 476 | # by zero before the program is even run, that could save some 477 | # debugging time. 478 | # 479 | # class DivisionByZeroVerifier < ArithmeticsProcessor 480 | # class VerificationFailure < Exception; end 481 | # 482 | # def on_divide(node) 483 | # # You need to process the children to handle nested divisions 484 | # # such as: 485 | # # (divide 486 | # # (integer 1) 487 | # # (divide (integer 1) (integer 0)) 488 | # left, right = process_all(node) 489 | # 490 | # if right.type == :integer && 491 | # right.children.first == 0 492 | # raise VerificationFailure, "Ouch! This code divides by zero." 493 | # end 494 | # end 495 | # 496 | # def divides_by_zero?(ast) 497 | # process(ast) 498 | # false 499 | # rescue VerificationFailure 500 | # true 501 | # end 502 | # end 503 | # 504 | # nice_expr = \ 505 | # s(:divide, 506 | # s(:add, s(:integer, 10), s(:integer, 2)), 507 | # s(:integer, 4)) 508 | # 509 | # p DivisionByZeroVerifier.new.divides_by_zero?(nice_expr) 510 | # # => false. Good. 511 | # 512 | # bad_expr = \ 513 | # s(:add, s(:integer, 10), 514 | # s(:divide, s(:integer, 1), s(:integer, 0))) 515 | # 516 | # p DivisionByZeroVerifier.new.divides_by_zero?(bad_expr) 517 | # # => true. WHOOPS. DO NOT RUN THIS. 518 | # 519 | # Of course, this won't detect more complex cases... unless you 520 | # use some partial evaluation before! The possibilites are 521 | # endless. Have fun. 522 | # 523 | # source://ast//lib/ast/processor/mixin.rb#240 524 | module AST::Processor::Mixin 525 | # Default handler. Does nothing. 526 | # 527 | # @param node [AST::Node] 528 | # @return [AST::Node, nil] 529 | # 530 | # source://ast//lib/ast/processor/mixin.rb#284 531 | def handler_missing(node); end 532 | 533 | # Dispatches `node`. If a node has type `:foo`, then a handler 534 | # named `on_foo` is invoked with one argument, the `node`; if 535 | # there isn't such a handler, {#handler_missing} is invoked 536 | # with the same argument. 537 | # 538 | # If the handler returns `nil`, `node` is returned; otherwise, 539 | # the return value of the handler is passed along. 540 | # 541 | # @param node [AST::Node, nil] 542 | # @return [AST::Node, nil] 543 | # 544 | # source://ast//lib/ast/processor/mixin.rb#251 545 | def process(node); end 546 | 547 | # {#process}es each node from `nodes` and returns an array of 548 | # results. 549 | # 550 | # @param nodes [Array] 551 | # @return [Array] 552 | # 553 | # source://ast//lib/ast/processor/mixin.rb#274 554 | def process_all(nodes); end 555 | end 556 | 557 | # This simple module is very useful in the cases where one needs 558 | # to define deeply nested ASTs from Ruby code, for example, in 559 | # tests. It should be used like this: 560 | # 561 | # describe YourLanguage do 562 | # include ::AST::Sexp 563 | # 564 | # it "should correctly parse expressions" do 565 | # YourLanguage.parse("1 + 2 * 3").should == 566 | # s(:add, 567 | # s(:integer, 1), 568 | # s(:multiply, 569 | # s(:integer, 2), 570 | # s(:integer, 3))) 571 | # end 572 | # end 573 | # 574 | # This way the amount of boilerplate code is greatly reduced. 575 | # 576 | # source://ast//lib/ast/sexp.rb#20 577 | module AST::Sexp 578 | # Creates a {Node} with type `type` and children `children`. 579 | # Note that the resulting node is of the type AST::Node and not a 580 | # subclass. 581 | # This would not pose a problem with comparisons, as {Node#==} 582 | # ignores metadata. 583 | # 584 | # source://ast//lib/ast/sexp.rb#26 585 | def s(type, *children); end 586 | end 587 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/rspec-support@3.13.6.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `rspec-support` gem. 5 | # Please instead update this file by running `bin/tapioca gem rspec-support`. 6 | 7 | 8 | # source://rspec-support//lib/rspec/support.rb#3 9 | module RSpec 10 | extend ::RSpec::Support::Warnings 11 | end 12 | 13 | # Consistent implementation for "cleaning" the caller method to strip out 14 | # non-rspec lines. This enables errors to be reported at the call site in 15 | # the code using the library, which is far more useful than the particular 16 | # internal method that raised an error. 17 | # 18 | # source://rspec-support//lib/rspec/support/caller_filter.rb#10 19 | class RSpec::CallerFilter 20 | class << self 21 | # Earlier rubies do not support the two argument form of `caller`. This 22 | # fallback is logically the same, but slower. 23 | # 24 | # source://rspec-support//lib/rspec/support/caller_filter.rb#49 25 | def first_non_rspec_line(skip_frames = T.unsafe(nil), increment = T.unsafe(nil)); end 26 | end 27 | end 28 | 29 | # source://rspec-support//lib/rspec/support/caller_filter.rb#20 30 | RSpec::CallerFilter::ADDITIONAL_TOP_LEVEL_FILES = T.let(T.unsafe(nil), Array) 31 | 32 | # rubygems/core_ext/kernel_require.rb isn't actually part of rspec (obviously) but we want 33 | # it ignored when we are looking for the first meaningful line of the backtrace outside 34 | # of RSpec. It can show up in the backtrace as the immediate first caller 35 | # when `CallerFilter.first_non_rspec_line` is called from the top level of a required 36 | # file, but it depends on if rubygems is loaded or not. We don't want to have to deal 37 | # with this complexity in our `RSpec.deprecate` calls, so we ignore it here. 38 | # 39 | # source://rspec-support//lib/rspec/support/caller_filter.rb#30 40 | RSpec::CallerFilter::IGNORE_REGEX = T.let(T.unsafe(nil), Regexp) 41 | 42 | # source://rspec-support//lib/rspec/support/caller_filter.rb#22 43 | RSpec::CallerFilter::LIB_REGEX = T.let(T.unsafe(nil), Regexp) 44 | 45 | # source://rspec-support//lib/rspec/support/caller_filter.rb#11 46 | RSpec::CallerFilter::RSPEC_LIBS = T.let(T.unsafe(nil), Array) 47 | 48 | # source://rspec-support//lib/rspec/support.rb#4 49 | module RSpec::Support 50 | class << self 51 | # Used internally to get a class of a given object, even if it does not respond to #class. 52 | # 53 | # @api private 54 | # 55 | # source://rspec-support//lib/rspec/support.rb#86 56 | def class_of(object); end 57 | 58 | # Defines a helper method that is optimized to require files from the 59 | # named lib. The passed block MUST be `{ |f| require_relative f }` 60 | # because for `require_relative` to work properly from within the named 61 | # lib the line of code must be IN that lib. 62 | # 63 | # `require_relative` is preferred when available because it is always O(1), 64 | # regardless of the number of dirs in $LOAD_PATH. `require`, on the other 65 | # hand, does a linear O(N) search over the dirs in the $LOAD_PATH until 66 | # it can resolve the file relative to one of the dirs. 67 | # 68 | # @api private 69 | # 70 | # source://rspec-support//lib/rspec/support.rb#16 71 | def define_optimized_require_for_rspec(lib, &require_relative); end 72 | 73 | # Remove a previously registered matcher. Useful for cleaning up after 74 | # yourself in specs. 75 | # 76 | # @private 77 | # 78 | # source://rspec-support//lib/rspec/support/matcher_definition.rb#24 79 | def deregister_matcher_definition(&block); end 80 | 81 | # @api private 82 | # 83 | # source://rspec-support//lib/rspec/support.rb#113 84 | def failure_notifier; end 85 | 86 | # @api private 87 | # 88 | # source://rspec-support//lib/rspec/support.rb#105 89 | def failure_notifier=(callable); end 90 | 91 | # @private 92 | # @return [Boolean] 93 | # 94 | # source://rspec-support//lib/rspec/support/matcher_definition.rb#29 95 | def is_a_matcher?(object); end 96 | 97 | # @private 98 | # 99 | # source://rspec-support//lib/rspec/support/matcher_definition.rb#6 100 | def matcher_definitions; end 101 | 102 | # source://rspec-support//lib/rspec/support.rb#54 103 | def method_handle_for(object, method_name); end 104 | 105 | # @api private 106 | # 107 | # source://rspec-support//lib/rspec/support.rb#118 108 | def notify_failure(failure, options = T.unsafe(nil)); end 109 | 110 | # Used internally to break cyclic dependency between mocks, expectations, 111 | # and support. We don't currently have a consistent implementation of our 112 | # matchers, though we are considering changing that: 113 | # https://github.com/rspec/rspec-mocks/issues/513 114 | # 115 | # @private 116 | # 117 | # source://rspec-support//lib/rspec/support/matcher_definition.rb#16 118 | def register_matcher_definition(&block); end 119 | 120 | # source://rspec-support//lib/rspec/support.rb#25 121 | def require_rspec_support(f); end 122 | 123 | # gives a string representation of an object for use in RSpec descriptions 124 | # 125 | # @api private 126 | # 127 | # source://rspec-support//lib/rspec/support/matcher_definition.rb#36 128 | def rspec_description_for_object(object); end 129 | 130 | # source://rspec-support//lib/rspec/support.rb#95 131 | def thread_local_data; end 132 | 133 | # @api private 134 | # 135 | # source://rspec-support//lib/rspec/support.rb#140 136 | def warning_notifier; end 137 | 138 | # @api private 139 | # 140 | # source://rspec-support//lib/rspec/support.rb#133 141 | def warning_notifier=(_arg0); end 142 | 143 | # @api private 144 | # 145 | # source://rspec-support//lib/rspec/support.rb#123 146 | def with_failure_notifier(callable); end 147 | end 148 | end 149 | 150 | # @private 151 | # 152 | # source://rspec-support//lib/rspec/support.rb#145 153 | module RSpec::Support::AllExceptionsExceptOnesWeMustNotRescue 154 | class << self 155 | # source://rspec-support//lib/rspec/support.rb#150 156 | def ===(exception); end 157 | end 158 | end 159 | 160 | # These exceptions are dangerous to rescue as rescuing them 161 | # would interfere with things we should not interfere with. 162 | # 163 | # source://rspec-support//lib/rspec/support.rb#148 164 | RSpec::Support::AllExceptionsExceptOnesWeMustNotRescue::AVOID_RESCUING = T.let(T.unsafe(nil), Array) 165 | 166 | # Deals with the slightly different semantics of block arguments. 167 | # For methods, arguments are required unless a default value is provided. 168 | # For blocks, arguments are optional, even if no default value is provided. 169 | # 170 | # However, we want to treat block args as required since you virtually 171 | # always want to pass a value for each received argument and our 172 | # `and_yield` has treated block args as required for many years. 173 | # 174 | # @api private 175 | # 176 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#293 177 | class RSpec::Support::BlockSignature < ::RSpec::Support::MethodSignature 178 | # @api private 179 | # 180 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#295 181 | def classify_parameters; end 182 | end 183 | 184 | # @private 185 | # 186 | # source://rspec-support//lib/rspec/support/comparable_version.rb#6 187 | class RSpec::Support::ComparableVersion 188 | include ::Comparable 189 | 190 | # @return [ComparableVersion] a new instance of ComparableVersion 191 | # 192 | # source://rspec-support//lib/rspec/support/comparable_version.rb#11 193 | def initialize(string); end 194 | 195 | # source://rspec-support//lib/rspec/support/comparable_version.rb#15 196 | def <=>(other); end 197 | 198 | # source://rspec-support//lib/rspec/support/comparable_version.rb#37 199 | def segments; end 200 | 201 | # Returns the value of attribute string. 202 | # 203 | # source://rspec-support//lib/rspec/support/comparable_version.rb#9 204 | def string; end 205 | end 206 | 207 | # @private 208 | # 209 | # source://rspec-support//lib/rspec/support.rb#110 210 | RSpec::Support::DEFAULT_FAILURE_NOTIFIER = T.let(T.unsafe(nil), Proc) 211 | 212 | # @private 213 | # 214 | # source://rspec-support//lib/rspec/support.rb#137 215 | RSpec::Support::DEFAULT_WARNING_NOTIFIER = T.let(T.unsafe(nil), Proc) 216 | 217 | # source://rspec-support//lib/rspec/support/differ.rb#11 218 | class RSpec::Support::Differ 219 | # @return [Differ] a new instance of Differ 220 | # 221 | # source://rspec-support//lib/rspec/support/differ.rb#68 222 | def initialize(opts = T.unsafe(nil)); end 223 | 224 | # @return [Boolean] 225 | # 226 | # source://rspec-support//lib/rspec/support/differ.rb#64 227 | def color?; end 228 | 229 | # source://rspec-support//lib/rspec/support/differ.rb#12 230 | def diff(actual, expected); end 231 | 232 | # source://rspec-support//lib/rspec/support/differ.rb#58 233 | def diff_as_object(actual, expected); end 234 | 235 | # source://rspec-support//lib/rspec/support/differ.rb#29 236 | def diff_as_string(actual, expected); end 237 | 238 | private 239 | 240 | # source://rspec-support//lib/rspec/support/differ.rb#129 241 | def add_old_hunk_to_hunk(hunk, oldhunk); end 242 | 243 | # source://rspec-support//lib/rspec/support/differ.rb#125 244 | def add_to_output(output, string); end 245 | 246 | # @return [Boolean] 247 | # 248 | # source://rspec-support//lib/rspec/support/differ.rb#79 249 | def all_strings?(*args); end 250 | 251 | # @return [Boolean] 252 | # 253 | # source://rspec-support//lib/rspec/support/differ.rb#83 254 | def any_multiline_strings?(*args); end 255 | 256 | # source://rspec-support//lib/rspec/support/differ.rb#154 257 | def blue(text); end 258 | 259 | # source://rspec-support//lib/rspec/support/differ.rb#116 260 | def build_hunks(actual, expected); end 261 | 262 | # source://rspec-support//lib/rspec/support/differ.rb#91 263 | def coerce_to_string(string_or_array); end 264 | 265 | # source://rspec-support//lib/rspec/support/differ.rb#142 266 | def color(text, color_code); end 267 | 268 | # source://rspec-support//lib/rspec/support/differ.rb#162 269 | def color_diff(diff); end 270 | 271 | # source://rspec-support//lib/rspec/support/differ.rb#96 272 | def diffably_stringify(array); end 273 | 274 | # source://rspec-support//lib/rspec/support/differ.rb#120 275 | def finalize_output(output, final_line); end 276 | 277 | # source://rspec-support//lib/rspec/support/differ.rb#138 278 | def format_type; end 279 | 280 | # source://rspec-support//lib/rspec/support/differ.rb#150 281 | def green(text); end 282 | 283 | # source://rspec-support//lib/rspec/support/differ.rb#203 284 | def handle_encoding_errors(actual, expected); end 285 | 286 | # source://rspec-support//lib/rspec/support/differ.rb#193 287 | def hash_to_string(hash); end 288 | 289 | # @return [Boolean] 290 | # 291 | # source://rspec-support//lib/rspec/support/differ.rb#107 292 | def multiline?(string); end 293 | 294 | # @return [Boolean] 295 | # 296 | # source://rspec-support//lib/rspec/support/differ.rb#87 297 | def no_numbers?(*args); end 298 | 299 | # @return [Boolean] 300 | # 301 | # source://rspec-support//lib/rspec/support/differ.rb#75 302 | def no_procs?(*args); end 303 | 304 | # source://rspec-support//lib/rspec/support/differ.rb#158 305 | def normal(text); end 306 | 307 | # source://rspec-support//lib/rspec/support/differ.rb#179 308 | def object_to_string(object); end 309 | 310 | # source://rspec-support//lib/rspec/support/differ.rb#146 311 | def red(text); end 312 | 313 | # source://rspec-support//lib/rspec/support/differ.rb#133 314 | def safely_flatten(array); end 315 | end 316 | 317 | # Replacement for fileutils#mkdir_p because we don't want to require parts 318 | # of stdlib in RSpec. 319 | # 320 | # @api private 321 | # 322 | # source://rspec-support//lib/rspec/support/directory_maker.rb#11 323 | class RSpec::Support::DirectoryMaker 324 | class << self 325 | # Implements nested directory construction 326 | # 327 | # @api private 328 | # 329 | # source://rspec-support//lib/rspec/support/directory_maker.rb#15 330 | def mkdir_p(path); end 331 | 332 | private 333 | 334 | # @api private 335 | # @return [Boolean] 336 | # 337 | # source://rspec-support//lib/rspec/support/directory_maker.rb#57 338 | def directory_exists?(dirname); end 339 | 340 | # @api private 341 | # 342 | # source://rspec-support//lib/rspec/support/directory_maker.rb#52 343 | def generate_path(stack, part); end 344 | 345 | # @api private 346 | # 347 | # source://rspec-support//lib/rspec/support/directory_maker.rb#49 348 | def generate_stack(path); end 349 | end 350 | end 351 | 352 | # @private 353 | # 354 | # source://rspec-support//lib/rspec/support/encoded_string.rb#6 355 | class RSpec::Support::EncodedString 356 | # @return [EncodedString] a new instance of EncodedString 357 | # 358 | # source://rspec-support//lib/rspec/support/encoded_string.rb#16 359 | def initialize(string, encoding = T.unsafe(nil)); end 360 | 361 | # source://rspec-support//lib/rspec/support/encoded_string.rb#28 362 | def <<(string); end 363 | 364 | # source://rspec-support//lib/rspec/support/encoded_string.rb#25 365 | def ==(*args, &block); end 366 | 367 | # source://rspec-support//lib/rspec/support/encoded_string.rb#25 368 | def empty?(*args, &block); end 369 | 370 | # source://rspec-support//lib/rspec/support/encoded_string.rb#25 371 | def encoding(*args, &block); end 372 | 373 | # source://rspec-support//lib/rspec/support/encoded_string.rb#25 374 | def eql?(*args, &block); end 375 | 376 | # source://rspec-support//lib/rspec/support/encoded_string.rb#25 377 | def lines(*args, &block); end 378 | 379 | # Returns the value of attribute source_encoding. 380 | # 381 | # source://rspec-support//lib/rspec/support/encoded_string.rb#21 382 | def source_encoding; end 383 | 384 | # source://rspec-support//lib/rspec/support/encoded_string.rb#41 385 | def split(regex_or_string); end 386 | 387 | # source://rspec-support//lib/rspec/support/encoded_string.rb#46 388 | def to_s; end 389 | 390 | # source://rspec-support//lib/rspec/support/encoded_string.rb#49 391 | def to_str; end 392 | 393 | private 394 | 395 | # source://rspec-support//lib/rspec/support/encoded_string.rb#139 396 | def detect_source_encoding(string); end 397 | 398 | # Encoding Exceptions: 399 | # 400 | # Raised by Encoding and String methods: 401 | # Encoding::UndefinedConversionError: 402 | # when a transcoding operation fails 403 | # if the String contains characters invalid for the target encoding 404 | # e.g. "\x80".encode('UTF-8','ASCII-8BIT') 405 | # vs "\x80".encode('UTF-8','ASCII-8BIT', undef: :replace, replace: '') 406 | # # => '' 407 | # Encoding::CompatibilityError 408 | # when Encoding.compatible?(str1, str2) is nil 409 | # e.g. utf_16le_emoji_string.split("\n") 410 | # e.g. valid_unicode_string.encode(utf8_encoding) << ascii_string 411 | # Encoding::InvalidByteSequenceError: 412 | # when the string being transcoded contains a byte invalid for 413 | # either the source or target encoding 414 | # e.g. "\x80".encode('UTF-8','US-ASCII') 415 | # vs "\x80".encode('UTF-8','US-ASCII', invalid: :replace, replace: '') 416 | # # => '' 417 | # ArgumentError 418 | # when operating on a string with invalid bytes 419 | # e.g."\x80".split("\n") 420 | # TypeError 421 | # when a symbol is passed as an encoding 422 | # Encoding.find(:"UTF-8") 423 | # when calling force_encoding on an object 424 | # that doesn't respond to #to_str 425 | # 426 | # Raised by transcoding methods: 427 | # Encoding::ConverterNotFoundError: 428 | # when a named encoding does not correspond with a known converter 429 | # e.g. 'abc'.force_encoding('UTF-8').encode('foo') 430 | # or a converter path cannot be found 431 | # e.g. "\x80".force_encoding('ASCII-8BIT').encode('Emacs-Mule') 432 | # 433 | # Raised by byte <-> char conversions 434 | # RangeError: out of char range 435 | # e.g. the UTF-16LE emoji: 128169.chr 436 | # 437 | # source://rspec-support//lib/rspec/support/encoded_string.rb#93 438 | def matching_encoding(string); end 439 | 440 | # http://stackoverflow.com/a/8711118/879854 441 | # Loop over chars in a string replacing chars 442 | # with invalid encoding, which is a pretty good proxy 443 | # for the invalid byte sequence that causes an ArgumentError 444 | # 445 | # source://rspec-support//lib/rspec/support/encoded_string.rb#124 446 | def remove_invalid_bytes(string); end 447 | 448 | class << self 449 | # source://rspec-support//lib/rspec/support/encoded_string.rb#143 450 | def pick_encoding(source_a, source_b); end 451 | end 452 | end 453 | 454 | # Ruby's default replacement string is: 455 | # U+FFFD ("\xEF\xBF\xBD"), for Unicode encoding forms, else 456 | # ? ("\x3F") 457 | # 458 | # source://rspec-support//lib/rspec/support/encoded_string.rb#14 459 | RSpec::Support::EncodedString::REPLACE = T.let(T.unsafe(nil), String) 460 | 461 | # source://rspec-support//lib/rspec/support/encoded_string.rb#9 462 | RSpec::Support::EncodedString::US_ASCII = T.let(T.unsafe(nil), String) 463 | 464 | # Reduce allocations by storing constants. 465 | # 466 | # source://rspec-support//lib/rspec/support/encoded_string.rb#8 467 | RSpec::Support::EncodedString::UTF_8 = T.let(T.unsafe(nil), String) 468 | 469 | # @private 470 | # 471 | # source://rspec-support//lib/rspec/support/hunk_generator.rb#9 472 | class RSpec::Support::HunkGenerator 473 | # @return [HunkGenerator] a new instance of HunkGenerator 474 | # 475 | # source://rspec-support//lib/rspec/support/hunk_generator.rb#10 476 | def initialize(actual, expected); end 477 | 478 | # source://rspec-support//lib/rspec/support/hunk_generator.rb#15 479 | def hunks; end 480 | 481 | private 482 | 483 | # source://rspec-support//lib/rspec/support/hunk_generator.rb#32 484 | def actual_lines; end 485 | 486 | # source://rspec-support//lib/rspec/support/hunk_generator.rb#36 487 | def build_hunk(piece); end 488 | 489 | # source://rspec-support//lib/rspec/support/hunk_generator.rb#44 490 | def context_lines; end 491 | 492 | # source://rspec-support//lib/rspec/support/hunk_generator.rb#24 493 | def diffs; end 494 | 495 | # source://rspec-support//lib/rspec/support/hunk_generator.rb#28 496 | def expected_lines; end 497 | end 498 | 499 | # @api private 500 | # 501 | # source://rspec-support//lib/rspec/support.rb#40 502 | RSpec::Support::KERNEL_METHOD_METHOD = T.let(T.unsafe(nil), UnboundMethod) 503 | 504 | # Allows matchers to be used instead of providing keyword arguments. In 505 | # practice, when this happens only the arity of the method is verified. 506 | # 507 | # @private 508 | # 509 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#420 510 | class RSpec::Support::LooseSignatureVerifier < ::RSpec::Support::MethodSignatureVerifier 511 | private 512 | 513 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#423 514 | def split_args(args); end 515 | end 516 | 517 | # If a matcher is used in a signature in place of keyword arguments, all 518 | # keyword argument validation needs to be skipped since the matcher is 519 | # opaque. 520 | # 521 | # Instead, keyword arguments will be validated when the method is called 522 | # and they are actually known. 523 | # 524 | # @private 525 | # 526 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#440 527 | class RSpec::Support::LooseSignatureVerifier::SignatureWithKeywordArgumentsMatcher 528 | # @return [SignatureWithKeywordArgumentsMatcher] a new instance of SignatureWithKeywordArgumentsMatcher 529 | # 530 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#441 531 | def initialize(signature); end 532 | 533 | # @return [Boolean] 534 | # 535 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#461 536 | def has_kw_args_in?(args); end 537 | 538 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#449 539 | def invalid_kw_args_from(_kw_args); end 540 | 541 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#445 542 | def missing_kw_args_from(_kw_args); end 543 | 544 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#453 545 | def non_kw_args_arity_description; end 546 | 547 | # @return [Boolean] 548 | # 549 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#457 550 | def valid_non_kw_args?(*args); end 551 | end 552 | 553 | # Extracts info about the number of arguments and allowed/required 554 | # keyword args of a given method. 555 | # 556 | # @private 557 | # 558 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#13 559 | class RSpec::Support::MethodSignature 560 | # @return [MethodSignature] a new instance of MethodSignature 561 | # 562 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#16 563 | def initialize(method); end 564 | 565 | # @return [Boolean] 566 | # 567 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#123 568 | def arbitrary_kw_args?; end 569 | 570 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#38 571 | def classify_arity(arity = T.unsafe(nil)); end 572 | 573 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#131 574 | def classify_parameters; end 575 | 576 | # Without considering what the last arg is, could it 577 | # contain keyword arguments? 578 | # 579 | # @return [Boolean] 580 | # 581 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#117 582 | def could_contain_kw_args?(args); end 583 | 584 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#51 585 | def description; end 586 | 587 | # @return [Boolean] 588 | # 589 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#84 590 | def has_kw_args_in?(args); end 591 | 592 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#77 593 | def invalid_kw_args_from(given_kw_args); end 594 | 595 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#14 596 | def max_non_kw_args; end 597 | 598 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#14 599 | def min_non_kw_args; end 600 | 601 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#73 602 | def missing_kw_args_from(given_kw_args); end 603 | 604 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#23 605 | def non_kw_args_arity_description; end 606 | 607 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#14 608 | def optional_kw_args; end 609 | 610 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#14 611 | def required_kw_args; end 612 | 613 | # @return [Boolean] 614 | # 615 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#127 616 | def unlimited_args?; end 617 | 618 | # @return [Boolean] 619 | # 620 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#31 621 | def valid_non_kw_args?(positional_arg_count, optional_max_arg_count = T.unsafe(nil)); end 622 | end 623 | 624 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#187 625 | RSpec::Support::MethodSignature::INFINITY = T.let(T.unsafe(nil), Float) 626 | 627 | # Encapsulates expectations about the number of arguments and 628 | # allowed/required keyword args of a given method. 629 | # 630 | # @api private 631 | # 632 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#244 633 | class RSpec::Support::MethodSignatureExpectation 634 | # @api private 635 | # @return [MethodSignatureExpectation] a new instance of MethodSignatureExpectation 636 | # 637 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#245 638 | def initialize; end 639 | 640 | # @api private 641 | # @return [Boolean] 642 | # 643 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#272 644 | def empty?; end 645 | 646 | # @api private 647 | # 648 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#256 649 | def expect_arbitrary_keywords; end 650 | 651 | # @api private 652 | # 653 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#256 654 | def expect_arbitrary_keywords=(_arg0); end 655 | 656 | # @api private 657 | # 658 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#256 659 | def expect_unlimited_arguments; end 660 | 661 | # @api private 662 | # 663 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#256 664 | def expect_unlimited_arguments=(_arg0); end 665 | 666 | # @api private 667 | # 668 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#254 669 | def keywords; end 670 | 671 | # @api private 672 | # 673 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#279 674 | def keywords=(values); end 675 | 676 | # @api private 677 | # 678 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#254 679 | def max_count; end 680 | 681 | # @api private 682 | # @raise [ArgumentError] 683 | # 684 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#258 685 | def max_count=(number); end 686 | 687 | # @api private 688 | # 689 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#254 690 | def min_count; end 691 | 692 | # @api private 693 | # @raise [ArgumentError] 694 | # 695 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#265 696 | def min_count=(number); end 697 | end 698 | 699 | # Abstract base class for signature verifiers. 700 | # 701 | # @api private 702 | # 703 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#305 704 | class RSpec::Support::MethodSignatureVerifier 705 | # @api private 706 | # @return [MethodSignatureVerifier] a new instance of MethodSignatureVerifier 707 | # 708 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#308 709 | def initialize(signature, args = T.unsafe(nil)); end 710 | 711 | # @api private 712 | # 713 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#351 714 | def error_message; end 715 | 716 | # @api private 717 | # 718 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#306 719 | def kw_args; end 720 | 721 | # @api private 722 | # 723 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#306 724 | def max_non_kw_args; end 725 | 726 | # @api private 727 | # 728 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#306 729 | def min_non_kw_args; end 730 | 731 | # @api private 732 | # 733 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#306 734 | def non_kw_args; end 735 | 736 | # @api private 737 | # @return [Boolean] 738 | # 739 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#343 740 | def valid?; end 741 | 742 | # @api private 743 | # 744 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#315 745 | def with_expectation(expectation); end 746 | 747 | private 748 | 749 | # @api private 750 | # @return [Boolean] 751 | # 752 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#382 753 | def arbitrary_kw_args?; end 754 | 755 | # @api private 756 | # 757 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#378 758 | def invalid_kw_args; end 759 | 760 | # @api private 761 | # 762 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#374 763 | def missing_kw_args; end 764 | 765 | # @api private 766 | # 767 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#390 768 | def split_args(args); end 769 | 770 | # @api private 771 | # @return [Boolean] 772 | # 773 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#386 774 | def unlimited_args?; end 775 | 776 | # @api private 777 | # @return [Boolean] 778 | # 779 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#370 780 | def valid_non_kw_args?; end 781 | end 782 | 783 | # On 1.9 and up, this is in core, so we just use the real one 784 | # 785 | # source://rspec-support//lib/rspec/support/reentrant_mutex.rb#65 786 | class RSpec::Support::Mutex < ::Thread::Mutex 787 | class << self 788 | # source://rspec-support//lib/rspec/support/reentrant_mutex.rb#70 789 | def new; end 790 | end 791 | end 792 | 793 | # If you mock Mutex.new you break our usage of Mutex, so 794 | # instead we capture the original method to return Mutexes. 795 | # 796 | # source://rspec-support//lib/rspec/support/reentrant_mutex.rb#68 797 | RSpec::Support::Mutex::NEW_MUTEX_METHOD = T.let(T.unsafe(nil), Method) 798 | 799 | # Provides query methods for different OS or OS features. 800 | # 801 | # @api private 802 | # 803 | # source://rspec-support//lib/rspec/support/ruby_features.rb#11 804 | module RSpec::Support::OS 805 | private 806 | 807 | # @api private 808 | # 809 | # source://rspec-support//lib/rspec/support/ruby_features.rb#14 810 | def windows?; end 811 | 812 | # @api private 813 | # 814 | # source://rspec-support//lib/rspec/support/ruby_features.rb#18 815 | def windows_file_path?; end 816 | 817 | class << self 818 | # @api private 819 | # @return [Boolean] 820 | # 821 | # source://rspec-support//lib/rspec/support/ruby_features.rb#14 822 | def windows?; end 823 | 824 | # @api private 825 | # @return [Boolean] 826 | # 827 | # source://rspec-support//lib/rspec/support/ruby_features.rb#18 828 | def windows_file_path?; end 829 | end 830 | end 831 | 832 | # Provide additional output details beyond what `inspect` provides when 833 | # printing Time, DateTime, or BigDecimal 834 | # 835 | # @api private 836 | # 837 | # source://rspec-support//lib/rspec/support/object_formatter.rb#10 838 | class RSpec::Support::ObjectFormatter 839 | # @api private 840 | # @return [ObjectFormatter] a new instance of ObjectFormatter 841 | # 842 | # source://rspec-support//lib/rspec/support/object_formatter.rb#29 843 | def initialize(max_formatted_output_length = T.unsafe(nil)); end 844 | 845 | # @api private 846 | # 847 | # source://rspec-support//lib/rspec/support/object_formatter.rb#34 848 | def format(object); end 849 | 850 | # @api private 851 | # 852 | # source://rspec-support//lib/rspec/support/object_formatter.rb#13 853 | def max_formatted_output_length; end 854 | 855 | # @api private 856 | # 857 | # source://rspec-support//lib/rspec/support/object_formatter.rb#13 858 | def max_formatted_output_length=(_arg0); end 859 | 860 | # @api private 861 | # 862 | # source://rspec-support//lib/rspec/support/object_formatter.rb#72 863 | def prepare_array(array); end 864 | 865 | # @api private 866 | # 867 | # source://rspec-support//lib/rspec/support/object_formatter.rb#96 868 | def prepare_element(element); end 869 | 870 | # Prepares the provided object to be formatted by wrapping it as needed 871 | # in something that, when `inspect` is called on it, will produce the 872 | # desired output. 873 | # 874 | # This allows us to apply the desired formatting to hash/array data structures 875 | # at any level of nesting, simply by walking that structure and replacing items 876 | # with custom items that have `inspect` defined to return the desired output 877 | # for that item. Then we can just use `Array#inspect` or `Hash#inspect` to 878 | # format the entire thing. 879 | # 880 | # @api private 881 | # 882 | # source://rspec-support//lib/rspec/support/object_formatter.rb#58 883 | def prepare_for_inspection(object); end 884 | 885 | # @api private 886 | # 887 | # source://rspec-support//lib/rspec/support/object_formatter.rb#78 888 | def prepare_hash(input_hash); end 889 | 890 | # @api private 891 | # @return [Boolean] 892 | # 893 | # source://rspec-support//lib/rspec/support/object_formatter.rb#115 894 | def recursive_structure?(object); end 895 | 896 | # @api private 897 | # 898 | # source://rspec-support//lib/rspec/support/object_formatter.rb#88 899 | def sort_hash_keys(input_hash); end 900 | 901 | # @api private 902 | # 903 | # source://rspec-support//lib/rspec/support/object_formatter.rb#108 904 | def with_entering_structure(structure); end 905 | 906 | private 907 | 908 | # Returns the substring defined by the start_index and end_index 909 | # If the string ends with a partial ANSI code code then that 910 | # will be removed as printing partial ANSI 911 | # codes to the terminal can lead to corruption 912 | # 913 | # @api private 914 | # 915 | # source://rspec-support//lib/rspec/support/object_formatter.rb#270 916 | def truncate_string(str, start_index, end_index); end 917 | 918 | class << self 919 | # Methods are deferred to a default instance of the class to maintain the interface 920 | # For example, calling ObjectFormatter.format is still possible 921 | # 922 | # @api private 923 | # 924 | # source://rspec-support//lib/rspec/support/object_formatter.rb#17 925 | def default_instance; end 926 | 927 | # @api private 928 | # 929 | # source://rspec-support//lib/rspec/support/object_formatter.rb#21 930 | def format(object); end 931 | 932 | # @api private 933 | # 934 | # source://rspec-support//lib/rspec/support/object_formatter.rb#25 935 | def prepare_for_inspection(object); end 936 | end 937 | end 938 | 939 | # @api private 940 | # 941 | # source://rspec-support//lib/rspec/support/object_formatter.rb#129 942 | class RSpec::Support::ObjectFormatter::BaseInspector < ::Struct 943 | # Returns the value of attribute formatter 944 | # 945 | # @return [Object] the current value of formatter 946 | # 947 | # source://rspec-support//lib/rspec/support/object_formatter.rb#129 948 | def formatter; end 949 | 950 | # Sets the attribute formatter 951 | # 952 | # @param value [Object] the value to set the attribute formatter to. 953 | # @return [Object] the newly set value 954 | # 955 | # source://rspec-support//lib/rspec/support/object_formatter.rb#129 956 | def formatter=(_); end 957 | 958 | # @api private 959 | # @raise [NotImplementedError] 960 | # 961 | # source://rspec-support//lib/rspec/support/object_formatter.rb#134 962 | def inspect; end 963 | 964 | # Returns the value of attribute object 965 | # 966 | # @return [Object] the current value of object 967 | # 968 | # source://rspec-support//lib/rspec/support/object_formatter.rb#129 969 | def object; end 970 | 971 | # Sets the attribute object 972 | # 973 | # @param value [Object] the value to set the attribute object to. 974 | # @return [Object] the newly set value 975 | # 976 | # source://rspec-support//lib/rspec/support/object_formatter.rb#129 977 | def object=(_); end 978 | 979 | # @api private 980 | # 981 | # source://rspec-support//lib/rspec/support/object_formatter.rb#138 982 | def pretty_print(pp); end 983 | 984 | class << self 985 | # source://rspec-support//lib/rspec/support/object_formatter.rb#129 986 | def [](*_arg0); end 987 | 988 | # @api private 989 | # @raise [NotImplementedError] 990 | # @return [Boolean] 991 | # 992 | # source://rspec-support//lib/rspec/support/object_formatter.rb#130 993 | def can_inspect?(_object); end 994 | 995 | # source://rspec-support//lib/rspec/support/object_formatter.rb#129 996 | def inspect; end 997 | 998 | # source://rspec-support//lib/rspec/support/object_formatter.rb#129 999 | def keyword_init?; end 1000 | 1001 | # source://rspec-support//lib/rspec/support/object_formatter.rb#129 1002 | def members; end 1003 | 1004 | # source://rspec-support//lib/rspec/support/object_formatter.rb#129 1005 | def new(*_arg0); end 1006 | end 1007 | end 1008 | 1009 | # @api private 1010 | # 1011 | # source://rspec-support//lib/rspec/support/object_formatter.rb#179 1012 | class RSpec::Support::ObjectFormatter::BigDecimalInspector < ::RSpec::Support::ObjectFormatter::BaseInspector 1013 | # @api private 1014 | # 1015 | # source://rspec-support//lib/rspec/support/object_formatter.rb#184 1016 | def inspect; end 1017 | 1018 | class << self 1019 | # @api private 1020 | # @return [Boolean] 1021 | # 1022 | # source://rspec-support//lib/rspec/support/object_formatter.rb#180 1023 | def can_inspect?(object); end 1024 | end 1025 | end 1026 | 1027 | # @api private 1028 | # 1029 | # source://rspec-support//lib/rspec/support/object_formatter.rb#161 1030 | class RSpec::Support::ObjectFormatter::DateTimeInspector < ::RSpec::Support::ObjectFormatter::BaseInspector 1031 | # ActiveSupport sometimes overrides inspect. If `ActiveSupport` is 1032 | # defined use a custom format string that includes more time precision. 1033 | # 1034 | # @api private 1035 | # 1036 | # source://rspec-support//lib/rspec/support/object_formatter.rb#170 1037 | def inspect; end 1038 | 1039 | class << self 1040 | # @api private 1041 | # @return [Boolean] 1042 | # 1043 | # source://rspec-support//lib/rspec/support/object_formatter.rb#164 1044 | def can_inspect?(object); end 1045 | end 1046 | end 1047 | 1048 | # @api private 1049 | # 1050 | # source://rspec-support//lib/rspec/support/object_formatter.rb#162 1051 | RSpec::Support::ObjectFormatter::DateTimeInspector::FORMAT = T.let(T.unsafe(nil), String) 1052 | 1053 | # @api private 1054 | # 1055 | # source://rspec-support//lib/rspec/support/object_formatter.rb#226 1056 | class RSpec::Support::ObjectFormatter::DelegatorInspector < ::RSpec::Support::ObjectFormatter::BaseInspector 1057 | # @api private 1058 | # 1059 | # source://rspec-support//lib/rspec/support/object_formatter.rb#231 1060 | def inspect; end 1061 | 1062 | class << self 1063 | # @api private 1064 | # @return [Boolean] 1065 | # 1066 | # source://rspec-support//lib/rspec/support/object_formatter.rb#227 1067 | def can_inspect?(object); end 1068 | end 1069 | end 1070 | 1071 | # @api private 1072 | # 1073 | # source://rspec-support//lib/rspec/support/object_formatter.rb#189 1074 | class RSpec::Support::ObjectFormatter::DescribableMatcherInspector < ::RSpec::Support::ObjectFormatter::BaseInspector 1075 | # @api private 1076 | # 1077 | # source://rspec-support//lib/rspec/support/object_formatter.rb#194 1078 | def inspect; end 1079 | 1080 | class << self 1081 | # @api private 1082 | # @return [Boolean] 1083 | # 1084 | # source://rspec-support//lib/rspec/support/object_formatter.rb#190 1085 | def can_inspect?(object); end 1086 | end 1087 | end 1088 | 1089 | # @api private 1090 | # 1091 | # source://rspec-support//lib/rspec/support/object_formatter.rb#11 1092 | RSpec::Support::ObjectFormatter::ELLIPSIS = T.let(T.unsafe(nil), String) 1093 | 1094 | # @api private 1095 | # 1096 | # source://rspec-support//lib/rspec/support/object_formatter.rb#249 1097 | RSpec::Support::ObjectFormatter::INSPECTOR_CLASSES = T.let(T.unsafe(nil), Array) 1098 | 1099 | # @api private 1100 | # 1101 | # source://rspec-support//lib/rspec/support/object_formatter.rb#119 1102 | class RSpec::Support::ObjectFormatter::InspectableItem < ::Struct 1103 | # @api private 1104 | # 1105 | # source://rspec-support//lib/rspec/support/object_formatter.rb#120 1106 | def inspect; end 1107 | 1108 | # @api private 1109 | # 1110 | # source://rspec-support//lib/rspec/support/object_formatter.rb#124 1111 | def pretty_print(pp); end 1112 | 1113 | # Returns the value of attribute text 1114 | # 1115 | # @return [Object] the current value of text 1116 | # 1117 | # source://rspec-support//lib/rspec/support/object_formatter.rb#119 1118 | def text; end 1119 | 1120 | # Sets the attribute text 1121 | # 1122 | # @param value [Object] the value to set the attribute text to. 1123 | # @return [Object] the newly set value 1124 | # 1125 | # source://rspec-support//lib/rspec/support/object_formatter.rb#119 1126 | def text=(_); end 1127 | 1128 | class << self 1129 | # source://rspec-support//lib/rspec/support/object_formatter.rb#119 1130 | def [](*_arg0); end 1131 | 1132 | # source://rspec-support//lib/rspec/support/object_formatter.rb#119 1133 | def inspect; end 1134 | 1135 | # source://rspec-support//lib/rspec/support/object_formatter.rb#119 1136 | def keyword_init?; end 1137 | 1138 | # source://rspec-support//lib/rspec/support/object_formatter.rb#119 1139 | def members; end 1140 | 1141 | # source://rspec-support//lib/rspec/support/object_formatter.rb#119 1142 | def new(*_arg0); end 1143 | end 1144 | end 1145 | 1146 | # @api private 1147 | # 1148 | # source://rspec-support//lib/rspec/support/object_formatter.rb#236 1149 | class RSpec::Support::ObjectFormatter::InspectableObjectInspector < ::RSpec::Support::ObjectFormatter::BaseInspector 1150 | # @api private 1151 | # 1152 | # source://rspec-support//lib/rspec/support/object_formatter.rb#244 1153 | def inspect; end 1154 | 1155 | class << self 1156 | # @api private 1157 | # @return [Boolean] 1158 | # 1159 | # source://rspec-support//lib/rspec/support/object_formatter.rb#237 1160 | def can_inspect?(object); end 1161 | end 1162 | end 1163 | 1164 | # @api private 1165 | # 1166 | # source://rspec-support//lib/rspec/support/object_formatter.rb#143 1167 | class RSpec::Support::ObjectFormatter::TimeInspector < ::RSpec::Support::ObjectFormatter::BaseInspector 1168 | # for 1.8.7 1169 | # 1170 | # @api private 1171 | # 1172 | # source://rspec-support//lib/rspec/support/object_formatter.rb#151 1173 | def inspect; end 1174 | 1175 | class << self 1176 | # @api private 1177 | # @return [Boolean] 1178 | # 1179 | # source://rspec-support//lib/rspec/support/object_formatter.rb#146 1180 | def can_inspect?(object); end 1181 | end 1182 | end 1183 | 1184 | # @api private 1185 | # 1186 | # source://rspec-support//lib/rspec/support/object_formatter.rb#144 1187 | RSpec::Support::ObjectFormatter::TimeInspector::FORMAT = T.let(T.unsafe(nil), String) 1188 | 1189 | # @api private 1190 | # 1191 | # source://rspec-support//lib/rspec/support/object_formatter.rb#199 1192 | class RSpec::Support::ObjectFormatter::UninspectableObjectInspector < ::RSpec::Support::ObjectFormatter::BaseInspector 1193 | # @api private 1194 | # 1195 | # source://rspec-support//lib/rspec/support/object_formatter.rb#209 1196 | def inspect; end 1197 | 1198 | # @api private 1199 | # 1200 | # source://rspec-support//lib/rspec/support/object_formatter.rb#213 1201 | def klass; end 1202 | 1203 | # http://stackoverflow.com/a/2818916 1204 | # 1205 | # @api private 1206 | # 1207 | # source://rspec-support//lib/rspec/support/object_formatter.rb#218 1208 | def native_object_id; end 1209 | 1210 | class << self 1211 | # @api private 1212 | # @return [Boolean] 1213 | # 1214 | # source://rspec-support//lib/rspec/support/object_formatter.rb#202 1215 | def can_inspect?(object); end 1216 | end 1217 | end 1218 | 1219 | # @api private 1220 | # 1221 | # source://rspec-support//lib/rspec/support/object_formatter.rb#200 1222 | RSpec::Support::ObjectFormatter::UninspectableObjectInspector::OBJECT_ID_FORMAT = T.let(T.unsafe(nil), String) 1223 | 1224 | # Provides recursive constant lookup methods useful for 1225 | # constant stubbing. 1226 | # 1227 | # source://rspec-support//lib/rspec/support/recursive_const_methods.rb#7 1228 | module RSpec::Support::RecursiveConstMethods 1229 | # @return [Boolean] 1230 | # 1231 | # source://rspec-support//lib/rspec/support/recursive_const_methods.rb#45 1232 | def const_defined_on?(mod, const_name); end 1233 | 1234 | # source://rspec-support//lib/rspec/support/recursive_const_methods.rb#53 1235 | def constants_defined_on(mod); end 1236 | 1237 | # @raise [NameError] 1238 | # 1239 | # source://rspec-support//lib/rspec/support/recursive_const_methods.rb#49 1240 | def get_const_defined_on(mod, const_name); end 1241 | 1242 | # source://rspec-support//lib/rspec/support/recursive_const_methods.rb#73 1243 | def normalize_const_name(const_name); end 1244 | 1245 | # @return [Boolean] 1246 | # 1247 | # source://rspec-support//lib/rspec/support/recursive_const_methods.rb#64 1248 | def recursive_const_defined?(const_name); end 1249 | 1250 | # source://rspec-support//lib/rspec/support/recursive_const_methods.rb#58 1251 | def recursive_const_get(const_name); end 1252 | end 1253 | 1254 | # Allows a thread to lock out other threads from a critical section of code, 1255 | # while allowing the thread with the lock to reenter that section. 1256 | # 1257 | # Based on Monitor as of 2.2 - 1258 | # https://github.com/ruby/ruby/blob/eb7ddaa3a47bf48045d26c72eb0f263a53524ebc/lib/monitor.rb#L9 1259 | # 1260 | # Depends on Mutex, but Mutex is only available as part of core since 1.9.1: 1261 | # exists - http://ruby-doc.org/core-1.9.1/Mutex.html 1262 | # dne - http://ruby-doc.org/core-1.9.0/Mutex.html 1263 | # 1264 | # @private 1265 | # 1266 | # source://rspec-support//lib/rspec/support/reentrant_mutex.rb#16 1267 | class RSpec::Support::ReentrantMutex 1268 | # @return [ReentrantMutex] a new instance of ReentrantMutex 1269 | # 1270 | # source://rspec-support//lib/rspec/support/reentrant_mutex.rb#17 1271 | def initialize; end 1272 | 1273 | # source://rspec-support//lib/rspec/support/reentrant_mutex.rb#23 1274 | def synchronize; end 1275 | 1276 | private 1277 | 1278 | # source://rspec-support//lib/rspec/support/reentrant_mutex.rb#35 1279 | def enter; end 1280 | 1281 | # source://rspec-support//lib/rspec/support/reentrant_mutex.rb#40 1282 | def exit; end 1283 | end 1284 | 1285 | # Provides query methods for different rubies 1286 | # 1287 | # @api private 1288 | # 1289 | # source://rspec-support//lib/rspec/support/ruby_features.rb#26 1290 | module RSpec::Support::Ruby 1291 | private 1292 | 1293 | # @api private 1294 | # 1295 | # source://rspec-support//lib/rspec/support/ruby_features.rb#29 1296 | def jruby?; end 1297 | 1298 | # @api private 1299 | # 1300 | # source://rspec-support//lib/rspec/support/ruby_features.rb#37 1301 | def jruby_9000?; end 1302 | 1303 | # @api private 1304 | # 1305 | # source://rspec-support//lib/rspec/support/ruby_features.rb#33 1306 | def jruby_version; end 1307 | 1308 | # @api private 1309 | # 1310 | # source://rspec-support//lib/rspec/support/ruby_features.rb#49 1311 | def mri?; end 1312 | 1313 | # @api private 1314 | # 1315 | # source://rspec-support//lib/rspec/support/ruby_features.rb#45 1316 | def non_mri?; end 1317 | 1318 | # @api private 1319 | # 1320 | # source://rspec-support//lib/rspec/support/ruby_features.rb#41 1321 | def rbx?; end 1322 | 1323 | # @api private 1324 | # 1325 | # source://rspec-support//lib/rspec/support/ruby_features.rb#53 1326 | def truffleruby?; end 1327 | 1328 | class << self 1329 | # @api private 1330 | # @return [Boolean] 1331 | # 1332 | # source://rspec-support//lib/rspec/support/ruby_features.rb#29 1333 | def jruby?; end 1334 | 1335 | # @api private 1336 | # @return [Boolean] 1337 | # 1338 | # source://rspec-support//lib/rspec/support/ruby_features.rb#37 1339 | def jruby_9000?; end 1340 | 1341 | # @api private 1342 | # 1343 | # source://rspec-support//lib/rspec/support/ruby_features.rb#33 1344 | def jruby_version; end 1345 | 1346 | # @api private 1347 | # @return [Boolean] 1348 | # 1349 | # source://rspec-support//lib/rspec/support/ruby_features.rb#49 1350 | def mri?; end 1351 | 1352 | # @api private 1353 | # @return [Boolean] 1354 | # 1355 | # source://rspec-support//lib/rspec/support/ruby_features.rb#45 1356 | def non_mri?; end 1357 | 1358 | # @api private 1359 | # @return [Boolean] 1360 | # 1361 | # source://rspec-support//lib/rspec/support/ruby_features.rb#41 1362 | def rbx?; end 1363 | 1364 | # @api private 1365 | # @return [Boolean] 1366 | # 1367 | # source://rspec-support//lib/rspec/support/ruby_features.rb#53 1368 | def truffleruby?; end 1369 | end 1370 | end 1371 | 1372 | # Provides query methods for ruby features that differ among 1373 | # implementations. 1374 | # 1375 | # @api private 1376 | # 1377 | # source://rspec-support//lib/rspec/support/ruby_features.rb#62 1378 | module RSpec::Support::RubyFeatures 1379 | private 1380 | 1381 | # @api private 1382 | # 1383 | # source://rspec-support//lib/rspec/support/ruby_features.rb#85 1384 | def caller_locations_supported?; end 1385 | 1386 | # @api private 1387 | # 1388 | # source://rspec-support//lib/rspec/support/ruby_features.rb#155 1389 | def distincts_kw_args_from_positional_hash?; end 1390 | 1391 | # On JRuby 1.7 `--1.8` mode, `Process.respond_to?(:fork)` returns true, 1392 | # but when you try to fork, it raises an error: 1393 | # NotImplementedError: fork is not available on this platform 1394 | # 1395 | # When we drop support for JRuby 1.7 and/or Ruby 1.8, we can drop 1396 | # this special case. 1397 | # 1398 | # @api private 1399 | # @return [Boolean] 1400 | # 1401 | # source://rspec-support//lib/rspec/support/ruby_features.rb#76 1402 | def fork_supported?; end 1403 | 1404 | # https://rubyreferences.github.io/rubychanges/3.0.html#keyword-arguments-are-now-fully-separated-from-positional-arguments 1405 | # 1406 | # @api private 1407 | # @return [Boolean] 1408 | # 1409 | # source://rspec-support//lib/rspec/support/ruby_features.rb#111 1410 | def kw_arg_separation?; end 1411 | 1412 | # @api private 1413 | # @return [Boolean] 1414 | # 1415 | # source://rspec-support//lib/rspec/support/ruby_features.rb#160 1416 | def kw_args_supported?; end 1417 | 1418 | # @api private 1419 | # 1420 | # source://rspec-support//lib/rspec/support/ruby_features.rb#216 1421 | def module_prepends_supported?; end 1422 | 1423 | # @api private 1424 | # 1425 | # source://rspec-support//lib/rspec/support/ruby_features.rb#212 1426 | def module_refinement_supported?; end 1427 | 1428 | # @api private 1429 | # 1430 | # source://rspec-support//lib/rspec/support/ruby_features.rb#81 1431 | def optional_and_splat_args_supported?; end 1432 | 1433 | # @api private 1434 | # @return [Boolean] 1435 | # 1436 | # source://rspec-support//lib/rspec/support/ruby_features.rb#164 1437 | def required_kw_args_supported?; end 1438 | 1439 | # @api private 1440 | # @return [Boolean] 1441 | # 1442 | # source://rspec-support//lib/rspec/support/ruby_features.rb#146 1443 | def ripper_supported?; end 1444 | 1445 | # @api private 1446 | # @return [Boolean] 1447 | # 1448 | # source://rspec-support//lib/rspec/support/ruby_features.rb#90 1449 | def supports_exception_cause?; end 1450 | 1451 | # @api private 1452 | # @return [Boolean] 1453 | # 1454 | # source://rspec-support//lib/rspec/support/ruby_features.rb#168 1455 | def supports_rebinding_module_methods?; end 1456 | 1457 | # @api private 1458 | # @return [Boolean] 1459 | # 1460 | # source://rspec-support//lib/rspec/support/ruby_features.rb#100 1461 | def supports_syntax_suggest?; end 1462 | 1463 | # @api private 1464 | # @return [Boolean] 1465 | # 1466 | # source://rspec-support//lib/rspec/support/ruby_features.rb#121 1467 | def supports_taint?; end 1468 | 1469 | class << self 1470 | # @api private 1471 | # @return [Boolean] 1472 | # 1473 | # source://rspec-support//lib/rspec/support/ruby_features.rb#85 1474 | def caller_locations_supported?; end 1475 | 1476 | # @api private 1477 | # @return [Boolean] 1478 | # 1479 | # source://rspec-support//lib/rspec/support/ruby_features.rb#155 1480 | def distincts_kw_args_from_positional_hash?; end 1481 | 1482 | # source://rspec-support//lib/rspec/support/ruby_features.rb#76 1483 | def fork_supported?; end 1484 | 1485 | # source://rspec-support//lib/rspec/support/ruby_features.rb#111 1486 | def kw_arg_separation?; end 1487 | 1488 | # source://rspec-support//lib/rspec/support/ruby_features.rb#160 1489 | def kw_args_supported?; end 1490 | 1491 | # @api private 1492 | # @return [Boolean] 1493 | # 1494 | # source://rspec-support//lib/rspec/support/ruby_features.rb#216 1495 | def module_prepends_supported?; end 1496 | 1497 | # @api private 1498 | # @return [Boolean] 1499 | # 1500 | # source://rspec-support//lib/rspec/support/ruby_features.rb#212 1501 | def module_refinement_supported?; end 1502 | 1503 | # @api private 1504 | # @return [Boolean] 1505 | # 1506 | # source://rspec-support//lib/rspec/support/ruby_features.rb#81 1507 | def optional_and_splat_args_supported?; end 1508 | 1509 | # source://rspec-support//lib/rspec/support/ruby_features.rb#164 1510 | def required_kw_args_supported?; end 1511 | 1512 | # source://rspec-support//lib/rspec/support/ruby_features.rb#146 1513 | def ripper_supported?; end 1514 | 1515 | # source://rspec-support//lib/rspec/support/ruby_features.rb#90 1516 | def supports_exception_cause?; end 1517 | 1518 | # source://rspec-support//lib/rspec/support/ruby_features.rb#168 1519 | def supports_rebinding_module_methods?; end 1520 | 1521 | # source://rspec-support//lib/rspec/support/ruby_features.rb#100 1522 | def supports_syntax_suggest?; end 1523 | 1524 | # source://rspec-support//lib/rspec/support/ruby_features.rb#121 1525 | def supports_taint?; end 1526 | end 1527 | end 1528 | 1529 | # Figures out whether a given method can accept various arguments. 1530 | # Surprisingly non-trivial. 1531 | # 1532 | # @private 1533 | # 1534 | # source://rspec-support//lib/rspec/support/method_signature_verifier.rb#414 1535 | RSpec::Support::StrictSignatureVerifier = RSpec::Support::MethodSignatureVerifier 1536 | 1537 | # source://rspec-support//lib/rspec/support/version.rb#5 1538 | module RSpec::Support::Version; end 1539 | 1540 | # source://rspec-support//lib/rspec/support/version.rb#6 1541 | RSpec::Support::Version::STRING = T.let(T.unsafe(nil), String) 1542 | 1543 | # source://rspec-support//lib/rspec/support/warnings.rb#8 1544 | module RSpec::Support::Warnings 1545 | # source://rspec-support//lib/rspec/support/warnings.rb#9 1546 | def deprecate(deprecated, options = T.unsafe(nil)); end 1547 | 1548 | # Used internally to print deprecation warnings 1549 | # when rspec-core isn't loaded 1550 | # 1551 | # @private 1552 | # 1553 | # source://rspec-support//lib/rspec/support/warnings.rb#17 1554 | def warn_deprecation(message, options = T.unsafe(nil)); end 1555 | 1556 | # Used internally to print longer warnings 1557 | # 1558 | # @private 1559 | # 1560 | # source://rspec-support//lib/rspec/support/warnings.rb#31 1561 | def warn_with(message, options = T.unsafe(nil)); end 1562 | 1563 | # Used internally to print warnings 1564 | # 1565 | # @private 1566 | # 1567 | # source://rspec-support//lib/rspec/support/warnings.rb#24 1568 | def warning(text, options = T.unsafe(nil)); end 1569 | end 1570 | 1571 | # source://rspec-support//lib/rspec/support/with_keywords_when_needed.rb#7 1572 | module RSpec::Support::WithKeywordsWhenNeeded 1573 | private 1574 | 1575 | # Remove this in RSpec 4 in favour of explicitly passed in kwargs where 1576 | # this is used. Works around a warning in Ruby 2.7 1577 | # 1578 | # source://rspec-support//lib/rspec/support/with_keywords_when_needed.rb#17 1579 | def class_exec(klass, *args, **_arg2, &block); end 1580 | 1581 | class << self 1582 | # source://rspec-support//lib/rspec/support/with_keywords_when_needed.rb#17 1583 | def class_exec(klass, *args, **_arg2, &block); end 1584 | end 1585 | end 1586 | --------------------------------------------------------------------------------