├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .github ├── release.yml └── workflows │ ├── main.yml │ └── release.yml ├── .gitignore ├── .vscode ├── launch.json └── settings.json ├── CODE_OF_CONDUCT.md ├── Gemfile ├── Gemfile.lock ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin ├── console ├── setup └── tapioca ├── cspell.json ├── lib ├── rubrik.rb └── rubrik │ ├── document.rb │ ├── document │ ├── increment.rb │ └── serialize_object.rb │ ├── fill_signature.rb │ ├── pkcs7_signature.rb │ ├── sign.rb │ └── version.rb ├── rubrik.gemspec ├── sorbet ├── config ├── rbi │ ├── gems │ │ ├── .gitattributes │ │ ├── Ascii85@1.1.0.rbi │ │ ├── afm@0.2.2.rbi │ │ ├── docile@1.4.0.rbi │ │ ├── erubi@1.12.0.rbi │ │ ├── hashery@2.1.2.rbi │ │ ├── minitest@5.20.0.rbi │ │ ├── netrc@0.11.0.rbi │ │ ├── openssl@3.1.0.rbi │ │ ├── parallel@1.23.0.rbi │ │ ├── pdf-reader@2.11.0.rbi │ │ ├── prettier_print@1.2.1.rbi │ │ ├── prism@0.18.0.rbi │ │ ├── rake@13.1.0.rbi │ │ ├── rbi@0.1.5.rbi │ │ ├── ruby-rc4@0.1.5.rbi │ │ ├── simplecov-html@0.12.3.rbi │ │ ├── simplecov@0.22.0.rbi │ │ ├── simplecov_json_formatter@0.1.4.rbi │ │ ├── spoom@1.2.4.rbi │ │ ├── syntax_tree@6.2.0.rbi │ │ ├── tapioca@0.11.12.rbi │ │ ├── thor@1.3.0.rbi │ │ ├── ttfunk@1.7.0.rbi │ │ ├── yard-sorbet@0.8.1.rbi │ │ └── yard@0.9.34.rbi │ └── shims │ │ ├── io.rbi │ │ ├── pdf_reader.rbi │ │ └── test_helper.rbi └── tapioca │ ├── config.yml │ └── require.rb └── test ├── rubrik ├── document │ └── serialize_object_test.rb ├── document_test.rb ├── pkcs7_signature_test.rb └── sign_test.rb ├── rubrik_test.rb ├── support ├── demo_cert.pem ├── indirect_annots.expected.pdf ├── indirect_annots.pdf ├── indirect_fields.expected.pdf ├── indirect_fields.pdf ├── inline_interactive_form.expected.pdf ├── inline_interactive_form.pdf ├── unexpected_value_interactive_form.pdf ├── with_interactive_form.expected.pdf ├── with_interactive_form.pdf ├── without_interactive_form.expected.pdf └── without_interactive_form.pdf └── test_helper.rb /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM quay.io/evl.ms/fullstaq-ruby:3.2.2-jemalloc-bookworm 2 | 3 | RUN apt-get update -q \ 4 | && apt-get install --assume-yes -q --no-install-recommends \ 5 | build-essential \ 6 | watchman \ 7 | libyaml-dev \ 8 | && apt-get autoremove --assume-yes \ 9 | && rm -rf /var/lib/apt/lists \ 10 | && rm -fr /var/cache/apt 11 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/ruby 3 | { 4 | "name": "Ruby", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "build": { 7 | // Path is relative to the devcontainer.json file. 8 | "dockerfile": "Dockerfile" 9 | }, 10 | "features": { 11 | "ghcr.io/devcontainers-contrib/features/zsh-plugins:0": { 12 | "plugins": "ruby bundler", 13 | "omzPlugins": "https://github.com/zsh-users/zsh-autosuggestions", 14 | "username": "root" 15 | } 16 | }, 17 | "containerEnv": { 18 | "RUBY_YJIT_ENABLE": "true" 19 | }, 20 | "customizations": { 21 | "vscode": { 22 | "extensions": [ 23 | "jtr.vscode-position", 24 | "Shopify.ruby-extensions-pack", 25 | "streetsidesoftware.code-spell-checker", 26 | "yzhang.markdown-all-in-one", 27 | "GitHub.vscode-pull-request-github", 28 | "github.vscode-github-actions" 29 | ] 30 | } 31 | } 32 | 33 | // Features to add to the dev container. More info: https://containers.dev/features. 34 | // "features": {}, 35 | 36 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 37 | // "forwardPorts": [], 38 | 39 | // Use 'postCreateCommand' to run commands after the container is created. 40 | // "postCreateCommand": "ruby --version", 41 | 42 | // Configure tool-specific properties. 43 | // "customizations": {}, 44 | 45 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 46 | // "remoteUser": "root" 47 | } 48 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | labels: 4 | - dependencies 5 | - chore 6 | categories: 7 | - title: 💥 Breaking Changes 8 | labels: 9 | - breaking-change 10 | - title: ✨ Added 11 | labels: 12 | - enhancement 13 | - title: 🐛 Bug Fixes 14 | labels: 15 | - bugfix 16 | - title: 🛠 Other Changes 17 | labels: 18 | - "*" 19 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Ruby 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | pull_request: 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | name: Ruby ${{ matrix.ruby }} 14 | strategy: 15 | matrix: 16 | ruby: 17 | - '3.1' 18 | - '3.2' 19 | 20 | steps: 21 | - uses: actions/checkout@v3 22 | - name: Set up Ruby 23 | uses: ruby/setup-ruby@v1 24 | with: 25 | ruby-version: ${{ matrix.ruby }} 26 | bundler-cache: true 27 | - name: Type check 28 | run: bundle exec srb tc 29 | - name: Run the default task 30 | run: bundle exec rake 31 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v3 14 | name: Checkout 15 | 16 | - name: Create release 17 | uses: actions/github-script@v6 18 | with: 19 | script: | 20 | await github.rest.repos.createRelease({ 21 | owner: context.repo.owner, 22 | repo: context.repo.repo, 23 | tag_name: "${{ github.ref }}", 24 | name: "${{ github.ref_name }}", 25 | generate_release_notes: true 26 | }) 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /pkg/ 7 | /spec/reports/ 8 | /tmp/ 9 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "ruby_lsp", 9 | "name": "Debug script", 10 | "request": "launch", 11 | "program": "ruby ${file}" 12 | }, 13 | { 14 | "type": "ruby_lsp", 15 | "name": "Debug test", 16 | "request": "launch", 17 | "program": "ruby -Itest ${relativeFile}" 18 | }, 19 | { 20 | "type": "ruby_lsp", 21 | "name": "Attach debugger", 22 | "request": "attach" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[pdf]": { 3 | "files.trimTrailingWhitespace": false, 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. 8 | 9 | ## Our Standards 10 | 11 | Examples of behavior that contributes to a positive environment for our community include: 12 | 13 | * Demonstrating empathy and kindness toward other people 14 | * Being respectful of differing opinions, viewpoints, and experiences 15 | * Giving and gracefully accepting constructive feedback 16 | * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience 17 | * Focusing on what is best not just for us as individuals, but for the overall community 18 | 19 | Examples of unacceptable behavior include: 20 | 21 | * The use of sexualized language or imagery, and sexual attention or 22 | advances of any kind 23 | * Trolling, insulting or derogatory comments, and personal or political attacks 24 | * Public or private harassment 25 | * Publishing others' private information, such as a physical or email 26 | address, without their explicit permission 27 | * Other conduct which could reasonably be considered inappropriate in a 28 | professional setting 29 | 30 | ## Enforcement Responsibilities 31 | 32 | Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. 33 | 34 | Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. 35 | 36 | ## Scope 37 | 38 | This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. 39 | 40 | ## Enforcement 41 | 42 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at tomascoelho6@gmail.com. All complaints will be reviewed and investigated promptly and fairly. 43 | 44 | All community leaders are obligated to respect the privacy and security of the reporter of any incident. 45 | 46 | ## Enforcement Guidelines 47 | 48 | Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: 49 | 50 | ### 1. Correction 51 | 52 | **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. 53 | 54 | **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. 55 | 56 | ### 2. Warning 57 | 58 | **Community Impact**: A violation through a single incident or series of actions. 59 | 60 | **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. 61 | 62 | ### 3. Temporary Ban 63 | 64 | **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. 65 | 66 | **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. 67 | 68 | ### 4. Permanent Ban 69 | 70 | **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. 71 | 72 | **Consequence**: A permanent ban from any sort of public interaction within the community. 73 | 74 | ## Attribution 75 | 76 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, 77 | available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 78 | 79 | Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). 80 | 81 | [homepage]: https://www.contributor-covenant.org 82 | 83 | For answers to common questions about this code of conduct, see the FAQ at 84 | https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. 85 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | gemspec 6 | 7 | gem "minitest", "~> 5.0", group: :test 8 | gem "simplecov", require: false, group: :test 9 | gem "rake", "~> 13.0" 10 | gem "sorbet", group: :development 11 | gem "sorbet-runtime" 12 | gem "tapioca", require: false 13 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | rubrik (1.1.0) 5 | openssl (>= 2.2.1) 6 | pdf-reader (~> 2.10) 7 | sorbet-runtime (~> 0.5) 8 | 9 | GEM 10 | remote: https://rubygems.org/ 11 | specs: 12 | Ascii85 (1.1.0) 13 | afm (0.2.2) 14 | docile (1.4.0) 15 | erubi (1.12.0) 16 | hashery (2.1.2) 17 | minitest (5.20.0) 18 | netrc (0.11.0) 19 | openssl (3.1.0) 20 | parallel (1.23.0) 21 | pdf-reader (2.11.0) 22 | Ascii85 (~> 1.0) 23 | afm (~> 0.2.1) 24 | hashery (~> 2.0) 25 | ruby-rc4 26 | ttfunk 27 | prettier_print (1.2.1) 28 | prism (0.18.0) 29 | rake (13.1.0) 30 | rbi (0.1.5) 31 | prism (>= 0.18.0, < 0.19) 32 | sorbet-runtime (>= 0.5.9204) 33 | ruby-rc4 (0.1.5) 34 | simplecov (0.22.0) 35 | docile (~> 1.1) 36 | simplecov-html (~> 0.11) 37 | simplecov_json_formatter (~> 0.1) 38 | simplecov-html (0.12.3) 39 | simplecov_json_formatter (0.1.4) 40 | sorbet (0.5.11142) 41 | sorbet-static (= 0.5.11142) 42 | sorbet-runtime (0.5.11142) 43 | sorbet-static (0.5.11142-x86_64-linux) 44 | sorbet-static-and-runtime (0.5.11142) 45 | sorbet (= 0.5.11142) 46 | sorbet-runtime (= 0.5.11142) 47 | spoom (1.2.4) 48 | erubi (>= 1.10.0) 49 | sorbet-static-and-runtime (>= 0.5.10187) 50 | syntax_tree (>= 6.1.1) 51 | thor (>= 0.19.2) 52 | syntax_tree (6.2.0) 53 | prettier_print (>= 1.2.0) 54 | tapioca (0.11.12) 55 | bundler (>= 2.2.25) 56 | netrc (>= 0.11.0) 57 | parallel (>= 1.21.0) 58 | rbi (>= 0.1.4, < 0.2) 59 | sorbet-static-and-runtime (>= 0.5.10187) 60 | spoom (~> 1.2.0, >= 1.2.0) 61 | thor (>= 1.2.0) 62 | yard-sorbet 63 | thor (1.3.0) 64 | ttfunk (1.7.0) 65 | yard (0.9.34) 66 | yard-sorbet (0.8.1) 67 | sorbet-runtime (>= 0.5) 68 | yard (>= 0.9) 69 | 70 | PLATFORMS 71 | x86_64-linux 72 | 73 | DEPENDENCIES 74 | minitest (~> 5.0) 75 | rake (~> 13.0) 76 | rubrik! 77 | simplecov 78 | sorbet 79 | sorbet-runtime 80 | tapioca 81 | 82 | BUNDLED WITH 83 | 2.4.20 84 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022 Tomás Coêlho 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rubrik 2 | 3 | Rubrik is a complete and simple digital signature library that implements the PAdES standard (PDF Advanced Electronic 4 | Signatures) in pure Ruby. It conforms with PKCS#7 and **will be** compatible with Brazil's AD-RB, AD-RT and EU's B-B 5 | and B-T profiles. 6 | 7 | - [Rubrik](#rubrik) 8 | - [Implementation Status](#implementation-status) 9 | - [PDF Features](#pdf-features) 10 | - [Signature Profiles](#signature-profiles) 11 | - [Installation](#installation) 12 | - [Usage](#usage) 13 | - [Development](#development) 14 | - [References:](#references) 15 | - [Contributing](#contributing) 16 | - [License](#license) 17 | - [Code of Conduct](#code-of-conduct) 18 | 19 | ## Implementation Status 20 | 21 | This gem is under development and may be subjected to breaking changes. 22 | 23 | ### PDF Features 24 | - [x] Modify PDFs with incremental updates (doesn't modify the documents, only append signature appearance) 25 | - [ ] Encryption Support 26 | - [ ] Signature appearance (stamp) 27 | - [ ] External (offline) signatures 28 | 29 | ### Signature Profiles 30 | - [x] CMS (PKCS#7) 31 | - [ ] PAdES B-B (conforms with PAdES-E-BES) 32 | - [ ] PAdES B-T (conforms with PAdES-E-BES) 33 | - [ ] PAdES AD-RB 34 | - [ ] PAdES AD-RT 35 | 36 | ## Installation 37 | 38 | Install the gem and add to the application's Gemfile by executing: 39 | 40 | $ bundle add rubrik 41 | 42 | If bundler is not being used to manage dependencies, install the gem by executing: 43 | 44 | $ gem install rubrik 45 | 46 | ## Usage 47 | 48 | With the gem loaded, run the following to sign an document: 49 | 50 | ```ruby 51 | # The input and output can be of types `File`, `Tempfile` or `StringIO`. 52 | input_pdf = File.open("example.pdf", "rb") 53 | output_pdf = File.open("signed_example.pdf", "wb+") # needs read permission 54 | 55 | # Load Certificate(s) 56 | certificate_file = File.open("example_cert.pem", "rb") 57 | private_key = OpenSSL::PKey::RSA.new(certificate_file, "") 58 | certificate_file.rewind 59 | certificate = OpenSSL::X509::Certificate.new(certificate_file) 60 | certificate_file.close 61 | 62 | # Will write the signed document to `output_pdf` 63 | Rubrik::Sign.call(input_pdf, output_pdf, private_key:, certificate:, certificate_chain: []) 64 | 65 | # Don't forget to close the files 66 | input_pdf.close 67 | output_pdf.close 68 | ``` 69 | Multiple signatures on a single document can be achieved by calling `Rubrik::Sign` repeatedly using the last signature 70 | output as input for the next signature. A better API for this use case may be developed. 71 | 72 | 73 | ## Development 74 | 75 | After checking out the repo, run `bundle install` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 76 | 77 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org). 78 | 79 | ## References: 80 | 1. PDF References: 81 | - [ISO 3200-2](https://pdfa.org/sponsored-standards/) 82 | 83 | 2. Brazil's technical references: 84 | - [DOC-ICP-15.03](https://www.gov.br/iti/pt-br/assuntos/legislacao/instrucoes-normativas/IN032021_DOC_15.03_assinada.pdf) 85 | 3. EU's technical references: 86 | - [ETSI 319 122-1](https://www.etsi.org/deliver/etsi_en/319100_319199/31912201/01.02.01_60/en_31912201v010201p.pdf) 87 | - [ETSI 319 122-2](https://www.etsi.org/deliver/etsi_en/319100_319199/31912201/01.02.01_60/en_31912201v010201p.pdf) 88 | 89 | ## Contributing 90 | 91 | Bug reports and pull requests are welcome on GitHub at https://github.com/tomascco/rubrik. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/tomascco/rubrik/blob/main/CODE_OF_CONDUCT.md). 92 | 93 | ## License 94 | 95 | The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). 96 | 97 | ## Code of Conduct 98 | 99 | Everyone interacting in the rubrik project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/tomascco/rubrik/blob/main/CODE_OF_CONDUCT.md). 100 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # typed: ignore 2 | # frozen_string_literal: true 3 | 4 | require "bundler/gem_tasks" 5 | require "rake/testtask" 6 | 7 | Rake::TestTask.new(:test) do |t| 8 | t.libs << "test" 9 | t.libs << "lib" 10 | t.test_files = FileList["test/**/*_test.rb"] 11 | end 12 | 13 | task default: %i[test] 14 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require "bundler/setup" 5 | require "rubrik" 6 | 7 | # You can add fixtures and/or initialization code here to make experimenting 8 | # with your gem easier. You can also use a different console, if you like. 9 | 10 | # (If you use this, don't forget to add pry to your Gemfile!) 11 | # require "pry" 12 | # Pry.start 13 | 14 | require "irb" 15 | IRB.start(__FILE__) 16 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /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) =~ /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 | -------------------------------------------------------------------------------- /cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2", 3 | "ignorePaths": [], 4 | "dictionaryDefinitions": [], 5 | "dictionaries": [], 6 | "words": [ 7 | "Annots", 8 | "codebases", 9 | "devcontainer", 10 | "ETSI", 11 | "PKCS", 12 | "Rubrik", 13 | "rubygems", 14 | "simplecov", 15 | "Tempfile" 16 | ], 17 | "ignoreWords": [], 18 | "import": [] 19 | } 20 | -------------------------------------------------------------------------------- /lib/rubrik.rb: -------------------------------------------------------------------------------- 1 | # typed: true 2 | # frozen_string_literal: true 3 | 4 | require "sorbet-runtime" 5 | require "pdf-reader" 6 | 7 | module Rubrik 8 | class Error < StandardError; end 9 | end 10 | 11 | require_relative "rubrik/document" 12 | require_relative "rubrik/document/increment" 13 | require_relative "rubrik/document/serialize_object" 14 | require_relative "rubrik/fill_signature" 15 | require_relative "rubrik/pkcs7_signature" 16 | require_relative "rubrik/sign" 17 | -------------------------------------------------------------------------------- /lib/rubrik/document.rb: -------------------------------------------------------------------------------- 1 | # typed: true 2 | # frozen_string_literal: true 3 | 4 | require "securerandom" 5 | 6 | module Rubrik 7 | class Document 8 | extend T::Sig 9 | 10 | CONTENTS_PLACEHOLDER = Object.new.freeze 11 | BYTE_RANGE_PLACEHOLDER = Object.new.freeze 12 | SIGNATURE_SIZE = 8_192 13 | 14 | sig {returns(T.any(File, Tempfile, StringIO))} 15 | attr_accessor :io 16 | 17 | sig {returns(PDF::Reader::ObjectHash)} 18 | attr_accessor :objects 19 | 20 | sig {returns(Integer)} 21 | attr_accessor :first_free_object_id 22 | 23 | sig {returns(T::Array[{id: PDF::Reader::Reference, value: T.untyped}])} 24 | attr_accessor :modified_objects 25 | 26 | sig {returns(Integer)} 27 | attr_accessor :last_object_id 28 | 29 | private :io=, :objects=, :first_free_object_id=, :modified_objects=, :last_object_id= 30 | 31 | sig {params(input: T.any(File, Tempfile, StringIO)).void} 32 | def initialize(input) 33 | self.io = input 34 | self.objects = PDF::Reader::ObjectHash.new(input) 35 | 36 | self.last_object_id = objects.trailer[:Size] - 1 37 | self.first_free_object_id = find_first_free_object_id 38 | 39 | self.modified_objects = [] 40 | 41 | fetch_or_create_interactive_form! 42 | end 43 | 44 | sig {returns(PDF::Reader::Reference)} 45 | # Returns the reference of the Signature Value dictionary. 46 | def add_signature_field 47 | # To add an signature to the PDF, we need the following structure 48 | # Interactive Form -> Signature Field -> Signature Value 49 | signature_value_id = assign_new_object_id! 50 | modified_objects << { 51 | id: signature_value_id, 52 | value: { 53 | Type: :Sig, 54 | Filter: :"Adobe.PPKLite", 55 | SubFilter: :"adbe.pkcs7.detached", 56 | Contents: CONTENTS_PLACEHOLDER, 57 | ByteRange: BYTE_RANGE_PLACEHOLDER 58 | } 59 | } 60 | 61 | first_page_reference = T.must(objects.page_references[0]) 62 | 63 | # create signature field 64 | signature_field_id = assign_new_object_id! 65 | modified_objects << { 66 | id: signature_field_id, 67 | value: { 68 | T: "Signature-#{SecureRandom.hex(2)}", 69 | FT: :Sig, 70 | V: signature_value_id, 71 | Type: :Annot, 72 | Subtype: :Widget, 73 | Rect: [0, 0, 0, 0], 74 | F: 4, 75 | P: first_page_reference 76 | } 77 | } 78 | 79 | first_page = objects.fetch(first_page_reference) 80 | annots = first_page[:Annots] 81 | 82 | if annots.is_a?(PDF::Reader::Reference) 83 | new_annots = objects.fetch(annots).dup 84 | new_annots << signature_field_id 85 | 86 | modified_objects << {id: annots, value: new_annots} 87 | else 88 | new_first_page = first_page.dup 89 | (new_first_page[:Annots] ||= []) << signature_field_id 90 | 91 | modified_objects << {id: first_page_reference, value: new_first_page} 92 | end 93 | 94 | fields_entry = interactive_form[:Fields] 95 | if fields_entry.is_a?(PDF::Reader::Reference) 96 | new_fields_array = objects.fetch(fields_entry).dup 97 | new_fields_array << signature_field_id 98 | 99 | modified_objects << {id: fields_entry, value: new_fields_array} 100 | else 101 | (interactive_form[:Fields] ||= []) << signature_field_id 102 | end 103 | 104 | signature_value_id 105 | end 106 | 107 | private 108 | 109 | sig {returns(T::Hash[Symbol, T.untyped])} 110 | def interactive_form 111 | T.must(modified_objects.first).fetch(:value) 112 | end 113 | 114 | sig{returns(Integer)} 115 | def find_first_free_object_id 116 | return 0 if last_object_id == objects.size 117 | 118 | xref = objects.send(:xref).instance_variable_get(:@xref) 119 | missing_ids = (1..last_object_id).to_a - xref.keys 120 | 121 | T.must(missing_ids.min) 122 | end 123 | 124 | sig {void} 125 | def fetch_or_create_interactive_form! 126 | root_ref = objects.trailer[:Root] 127 | root = T.let(objects.fetch(root_ref), T::Hash[Symbol, T.untyped]) 128 | 129 | interactive_form_value = root[:AcroForm] 130 | case interactive_form_value 131 | when PDF::Reader::Reference 132 | form_id = root[:AcroForm] 133 | 134 | modified_objects << {id: form_id, value: objects.fetch(form_id).dup} 135 | when Hash 136 | interactive_form_id = assign_new_object_id! 137 | 138 | modified_objects << {id: interactive_form_id, value: interactive_form_value.dup} 139 | 140 | new_root = root.dup 141 | new_root[:AcroForm] = interactive_form_id 142 | 143 | modified_objects << {id: root_ref, value: new_root} 144 | when NilClass 145 | interactive_form_id = assign_new_object_id! 146 | modified_objects << {id: interactive_form_id, value: {Fields: []}} 147 | 148 | # we also need to create a new version of the document catalog to include the new form ref 149 | updated_root = root.dup 150 | updated_root[:AcroForm] = interactive_form_id 151 | 152 | modified_objects << {id: root_ref, value: updated_root} 153 | else 154 | raise Error.new( 155 | "Expected dictionary, reference or nil but got " \ 156 | "#{interactive_form_value.class} on AcroForm entry.") 157 | end 158 | 159 | interactive_form[:SigFlags] = 3 # dont modify, append only 160 | end 161 | 162 | sig {returns(PDF::Reader::Reference)} 163 | def assign_new_object_id! 164 | PDF::Reader::Reference.new(self.last_object_id += 1, 0) 165 | end 166 | end 167 | end 168 | -------------------------------------------------------------------------------- /lib/rubrik/document/increment.rb: -------------------------------------------------------------------------------- 1 | # typed: true 2 | # frozen_string_literal: true 3 | 4 | module Rubrik 5 | class Document 6 | module Increment 7 | include Kernel 8 | 9 | extend T::Sig 10 | extend self 11 | 12 | sig {params(document: Rubrik::Document, io: T.any(File, Tempfile, StringIO)).void} 13 | def call(document, io:) 14 | document.io.rewind 15 | IO.copy_stream(document.io, io) 16 | 17 | io << "\n" 18 | 19 | new_xref = T.let([], T::Array[T::Hash[Symbol, Integer]]) 20 | new_xref << {id: 0} 21 | 22 | document.modified_objects.each do |object| 23 | integer_id = T.let(object[:id].to_i, Integer) 24 | new_xref << {id: integer_id, offset: io.pos} 25 | 26 | value = object[:value] 27 | io << "#{integer_id} 0 obj\n" "#{SerializeObject[value]}\n" "endobj\n\n" 28 | end 29 | 30 | updated_trailer = document.objects.trailer.dup 31 | updated_trailer[:Prev] = last_xref_pos(document) 32 | updated_trailer[:Size] = document.last_object_id + 1 33 | 34 | new_xref_pos = io.pos 35 | 36 | new_xref_subsections = new_xref 37 | .sort_by { |entry| entry.fetch(:id) } 38 | .chunk_while { _1.fetch(:id) + 1 == _2[:id] } 39 | 40 | io << "xref\n" 41 | 42 | new_xref_subsections.each do |subsection| 43 | starting_id = T.must(subsection.first).fetch(:id) 44 | length = subsection.length 45 | 46 | io << "#{starting_id} #{length}\n" 47 | 48 | if starting_id.zero? 49 | io << "#{format("%010d", document.first_free_object_id)} 65535 f \n" 50 | subsection.shift 51 | end 52 | 53 | subsection.each { |entry| io << "#{format("%010d", entry[:offset])} 00000 n \n" } 54 | end 55 | 56 | io << "trailer\n" 57 | io << "#{SerializeObject[updated_trailer]}\n" 58 | io << "startxref\n" 59 | io << "#{new_xref_pos.to_s}\n" 60 | io << "%%EOF\n" 61 | end 62 | 63 | private 64 | 65 | sig {params(document: Rubrik::Document).returns(Integer)} 66 | def last_xref_pos(document) 67 | PDF::Reader::Buffer.new(document.io, seek: 0).find_first_xref_offset 68 | end 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /lib/rubrik/document/serialize_object.rb: -------------------------------------------------------------------------------- 1 | # typed: true 2 | # frozen_string_literal: true 3 | 4 | module Rubrik 5 | class Document 6 | module SerializeObject 7 | include Kernel 8 | extend T::Sig 9 | extend self 10 | 11 | sig {params(obj: T.untyped).returns(String)} 12 | def [](obj) 13 | case obj 14 | when Hash 15 | serialized_objs = obj.flatten.map { |e| SerializeObject[e] } 16 | "<<#{serialized_objs.join(" ")}>>" 17 | when Symbol 18 | serialize_symbol(obj) 19 | when Array 20 | serialized_objs = obj.map { |e| SerializeObject[e] } 21 | "[#{serialized_objs.join(" ")}]" 22 | when PDF::Reader::Reference 23 | "#{obj.id} #{obj.gen} R" 24 | when String 25 | serialize_string(obj) 26 | when TrueClass 27 | "true" 28 | when FalseClass 29 | "false" 30 | when Document::CONTENTS_PLACEHOLDER 31 | "<#{"0" * Document::SIGNATURE_SIZE}>" 32 | when Document::BYTE_RANGE_PLACEHOLDER 33 | "[0 0000000000 0000000000 0000000000]" 34 | when Float, Integer 35 | obj.to_s 36 | when NilClass 37 | "null" 38 | when PDF::Reader::Stream 39 | <<~OBJECT.chomp 40 | #{SerializeObject[obj.hash]} 41 | stream 42 | #{obj.data} 43 | endstream 44 | OBJECT 45 | else 46 | raise "Don't know how to serialize #{obj}" 47 | end 48 | end 49 | 50 | alias call [] 51 | 52 | private 53 | 54 | STRING_ESCAPE_MAP = { 55 | "\n" => "\\\n", 56 | "\r" => "\\\r", 57 | "\t" => "\\\t", 58 | "\b" => "\\\b", 59 | "\f" => "\\\f", 60 | "\\" => "\\\\", 61 | "(" => "\\(", 62 | ")" => "\\)" 63 | }.freeze 64 | 65 | sig {params(string: String).returns(String)} 66 | def serialize_string(string) 67 | "(#{string.gsub(/[\n\r\t\b\f\\()]/n, STRING_ESCAPE_MAP)})" 68 | end 69 | 70 | DELIMITERS = "()<>[]{}/%".bytes.freeze 71 | REGULAR_CHARACTERS = 72 | "!\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".bytes.freeze 73 | 74 | 75 | NAME_ESCAPE_CHARACTERS = (0..255).to_a - REGULAR_CHARACTERS + DELIMITERS + "#".bytes 76 | NAME_ESCAPE_CHARACTERS.freeze 77 | 78 | NAME_ESCAPE_MAP = NAME_ESCAPE_CHARACTERS.each_with_object({}) do |char, escape_map| 79 | escape_map[char.chr] = "##{char.to_s(16).rjust(2, "0")}" 80 | end.freeze 81 | 82 | NAME_ESCAPE_REGEX = /[#{Regexp.escape(NAME_ESCAPE_CHARACTERS.map(&:chr).join)}]/ 83 | 84 | sig {params(symbol: Symbol).returns(String)} 85 | def serialize_symbol(symbol) 86 | "/#{symbol.to_s.b.gsub(NAME_ESCAPE_REGEX, NAME_ESCAPE_MAP)}" 87 | end 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /lib/rubrik/fill_signature.rb: -------------------------------------------------------------------------------- 1 | # typed: true 2 | # frozen_string_literal: true 3 | 4 | module Rubrik 5 | module FillSignature 6 | extend T::Sig 7 | extend self 8 | include Kernel 9 | 10 | sig {params( 11 | io: T.any(File, StringIO, Tempfile), 12 | signature_value_ref: PDF::Reader::Reference, 13 | private_key: OpenSSL::PKey::RSA, 14 | certificate: OpenSSL::X509::Certificate, 15 | certificate_chain: T::Array[OpenSSL::X509::Certificate]) 16 | .void} 17 | 18 | FIRST_OFFSET = 0 19 | 20 | def call(io, signature_value_ref:, private_key:, certificate:, certificate_chain: []) 21 | io.rewind 22 | 23 | signature_value_offset = PDF::Reader::XRef.new(io)[signature_value_ref] 24 | 25 | io.pos = signature_value_offset 26 | io.gets("/Contents") 27 | io.gets("<") 28 | 29 | first_length = io.pos - 1 30 | # We need to sum +2 to account for "<" and ">" of the hex string 31 | second_offset = first_length + Document::SIGNATURE_SIZE + 2 32 | second_length = io.size - second_offset 33 | 34 | byte_range_array = [FIRST_OFFSET, first_length, second_offset, second_length] 35 | 36 | io.pos = signature_value_offset 37 | 38 | io.gets("/ByteRange") 39 | byte_range_start = io.pos - "/ByteRange".size 40 | 41 | io.gets("]") 42 | byte_range_end = io.pos 43 | 44 | byte_range_size = byte_range_end - byte_range_start + 1 45 | actual_byte_range = " /ByteRange [#{byte_range_array.join(" ")}]".ljust(byte_range_size, " ") 46 | 47 | io.seek(-byte_range_size, IO::SEEK_CUR) 48 | io.write(actual_byte_range) 49 | 50 | io.pos = FIRST_OFFSET 51 | data_to_sign = T.must(io.read(first_length)) 52 | 53 | io.pos = second_offset 54 | data_to_sign += T.must(io.read(second_length)) 55 | 56 | signature = PKCS7Signature.call(data_to_sign, private_key:, certificate:) 57 | hex_signature = T.let(signature, String).unpack1("H*") 58 | 59 | padded_contents_field = "<#{hex_signature.ljust(Document::SIGNATURE_SIZE, "0")}>" 60 | 61 | io.pos = first_length 62 | io.write(padded_contents_field) 63 | 64 | io.rewind 65 | io 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /lib/rubrik/pkcs7_signature.rb: -------------------------------------------------------------------------------- 1 | # typed: true 2 | # frozen_string_literal: true 3 | 4 | require "openssl" 5 | 6 | module Rubrik 7 | module PKCS7Signature 8 | extend T::Sig 9 | extend self 10 | 11 | OPEN_SSL_FLAGS = OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY 12 | 13 | sig {params( 14 | data: String, 15 | private_key: OpenSSL::PKey::RSA, 16 | certificate: OpenSSL::X509::Certificate, 17 | certificate_chain: T::Array[OpenSSL::X509::Certificate] 18 | ).returns(String) 19 | } 20 | def call(data, private_key:, certificate:, certificate_chain: []) 21 | OpenSSL::PKCS7.sign(certificate, private_key, data, certificate_chain, OPEN_SSL_FLAGS).to_der 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/rubrik/sign.rb: -------------------------------------------------------------------------------- 1 | # typed: true 2 | # frozen_string_literal: true 3 | 4 | module Rubrik 5 | module Sign 6 | extend T::Sig 7 | 8 | sig {params( 9 | input: T.any(File, Tempfile, StringIO), 10 | output: T.any(File, Tempfile, StringIO), 11 | private_key: OpenSSL::PKey::RSA, 12 | certificate: OpenSSL::X509::Certificate, 13 | certificate_chain: T::Array[OpenSSL::X509::Certificate]) 14 | .void} 15 | def self.call(input, output, private_key:, certificate:, certificate_chain: []) 16 | input.binmode 17 | output.reopen(T.unsafe(output), "wb+") if !output.is_a?(StringIO) 18 | 19 | document = Rubrik::Document.new(input) 20 | 21 | signature_value_ref = document.add_signature_field 22 | 23 | Document::Increment.call(document, io: output) 24 | 25 | FillSignature.call(output, signature_value_ref:, private_key:, certificate:, certificate_chain:) 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/rubrik/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Rubrik 4 | VERSION = "1.1.0" 5 | end 6 | -------------------------------------------------------------------------------- /rubrik.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "lib/rubrik/version" 4 | 5 | Gem::Specification.new do |spec| 6 | spec.name = "rubrik" 7 | spec.version = Rubrik::VERSION 8 | spec.authors = ["Tomás Coêlho"] 9 | spec.email = ["tomascoelho6@gmail.com"] 10 | 11 | spec.summary = "Sign PDFs digitally in pure Ruby" 12 | spec.description = "Sign PDFs digitally in pure Ruby" 13 | spec.homepage = "https://github.com/tomascco/rubrik" 14 | spec.license = "MIT" 15 | spec.required_ruby_version = ">= 3.1.0" 16 | 17 | spec.metadata["homepage_uri"] = spec.homepage 18 | spec.metadata["source_code_uri"] = "https://github.com/tomascco/rubrik" 19 | spec.metadata["changelog_uri"] = "https://github.com/tomascco/rubrik/releases" 20 | 21 | # Specify which files should be added to the gem when it is released. 22 | # The `git ls-files -z` loads the files in the RubyGem that have been added into git. 23 | spec.files = Dir.glob("lib/**/*.rb") + ["README.md", "LICENSE.txt"] 24 | spec.bindir = "exe" 25 | spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } 26 | spec.require_paths = ["lib"] 27 | 28 | # Uncomment to register a new dependency of your gem 29 | # spec.add_dependency "example-gem", "~> 1.0" 30 | 31 | spec.add_runtime_dependency "pdf-reader", "~> 2.10" 32 | spec.add_runtime_dependency "sorbet-runtime", "~> 0.5" 33 | spec.add_runtime_dependency "openssl", ">= 2.2.1" 34 | 35 | # For more information and examples about making a new gem, check out our 36 | # guide at: https://bundler.io/guides/creating_gem.html 37 | end 38 | -------------------------------------------------------------------------------- /sorbet/config: -------------------------------------------------------------------------------- 1 | --dir 2 | . 3 | --ignore=vendor/ 4 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/.gitattributes: -------------------------------------------------------------------------------- 1 | **/*.rbi linguist-generated=true 2 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/Ascii85@1.1.0.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `Ascii85` gem. 5 | # Please instead update this file by running `bin/tapioca gem Ascii85`. 6 | 7 | # source://Ascii85//lib/ascii85.rb#18 8 | module Ascii85 9 | class << self 10 | # Searches through +str+ and decodes the _first_ Ascii85-String found. 11 | # 12 | # #decode expects an Ascii85-encoded String enclosed in <~ and ~> — it will 13 | # ignore all characters outside these markers. The returned strings are always 14 | # encoded as ASCII-8BIT. 15 | # 16 | # Ascii85.decode("<~;KZGo~>") 17 | # => "Ruby" 18 | # 19 | # Ascii85.decode("Foo<~;KZGo~>Bar<~;KZGo~>Baz") 20 | # => "Ruby" 21 | # 22 | # Ascii85.decode("No markers") 23 | # => "" 24 | # 25 | # #decode will raise Ascii85::DecodingError when malformed input is 26 | # encountered. 27 | # 28 | # source://Ascii85//lib/ascii85.rb#122 29 | def decode(str); end 30 | 31 | # Encodes the bytes of the given String as Ascii85. 32 | # 33 | # If +wrap_lines+ evaluates to +false+, the output will be returned as 34 | # a single long line. Otherwise #encode formats the output into lines 35 | # of length +wrap_lines+ (minimum is 2). 36 | # 37 | # Ascii85.encode("Ruby") 38 | # => <~;KZGo~> 39 | # 40 | # Ascii85.encode("Supercalifragilisticexpialidocious", 15) 41 | # => <~;g!%jEarNoBkD 42 | # BoB5)0rF*),+AU& 43 | # 0.@;KXgDe!L"F`R 44 | # ~> 45 | # 46 | # Ascii85.encode("Supercalifragilisticexpialidocious", false) 47 | # => <~;g!%jEarNoBkDBoB5)0rF*),+AU&0.@;KXgDe!L"F`R~> 48 | # 49 | # source://Ascii85//lib/ascii85.rb#39 50 | def encode(str, wrap_lines = T.unsafe(nil)); end 51 | end 52 | end 53 | 54 | # This error is raised when Ascii85.decode encounters one of the following 55 | # problems in the input: 56 | # 57 | # * An invalid character. Valid characters are '!'..'u' and 'z'. 58 | # * A 'z' character inside a 5-tuple. 'z's are only valid on their own. 59 | # * An invalid 5-tuple that decodes to >= 2**32 60 | # * The last tuple consisting of a single character. Valid tuples always have 61 | # at least two characters. 62 | # 63 | # source://Ascii85//lib/ascii85.rb#222 64 | class Ascii85::DecodingError < ::StandardError; end 65 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/afm@0.2.2.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `afm` gem. 5 | # Please instead update this file by running `bin/tapioca gem afm`. 6 | 7 | # source://afm//lib/afm.rb#1 8 | module AFM; end 9 | 10 | # source://afm//lib/afm.rb#34 11 | class AFM::Font 12 | # Loading a Font Metrics file by absolute path (no automatic font path resolution) 13 | # 14 | # @return [Font] a new instance of Font 15 | # 16 | # source://afm//lib/afm.rb#38 17 | def initialize(filename); end 18 | 19 | # Get metadata by key 20 | # 21 | # source://afm//lib/afm.rb#88 22 | def [](key); end 23 | 24 | # Returns the value of attribute char_metrics. 25 | # 26 | # source://afm//lib/afm.rb#35 27 | def char_metrics; end 28 | 29 | # Returns the value of attribute char_metrics_by_code. 30 | # 31 | # source://afm//lib/afm.rb#35 32 | def char_metrics_by_code; end 33 | 34 | # Returns the value of attribute kern_pairs. 35 | # 36 | # source://afm//lib/afm.rb#35 37 | def kern_pairs; end 38 | 39 | # Returns the value of attribute metadata. 40 | # 41 | # source://afm//lib/afm.rb#35 42 | def metadata; end 43 | 44 | # Get metrics for character. Takes an integer (charcode) or 45 | # a one-char string. currently works only for Latin1 strings, 46 | # since we only have a chartable for the Latin1 charset so far. 47 | # (shamelessly stolen from AFM.pm by Gisle Aas) 48 | # 49 | # source://afm//lib/afm.rb#96 50 | def metrics_for(char); end 51 | 52 | class << self 53 | # alias for new() 54 | # 55 | # source://afm//lib/afm.rb#82 56 | def from_file(file); end 57 | end 58 | end 59 | 60 | # source://afm//lib/afm.rb#3 61 | AFM::ISO_LATIN1_ENCODING = T.let(T.unsafe(nil), Array) 62 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/docile@1.4.0.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `docile` gem. 5 | # Please instead update this file by running `bin/tapioca gem docile`. 6 | 7 | # Docile keeps your Ruby DSLs tame and well-behaved. 8 | # 9 | # source://docile//lib/docile/version.rb#3 10 | module Docile 11 | extend ::Docile::Execution 12 | 13 | private 14 | 15 | # Execute a block in the context of an object whose methods represent the 16 | # commands in a DSL. 17 | # 18 | # Use this method to execute an *imperative* DSL, which means that: 19 | # 20 | # 1. Each command mutates the state of the DSL context object 21 | # 2. The return value of each command is ignored 22 | # 3. The final return value is the original context object 23 | # 24 | # @example Use a String as a DSL 25 | # Docile.dsl_eval("Hello, world!") do 26 | # reverse! 27 | # upcase! 28 | # end 29 | # #=> "!DLROW ,OLLEH" 30 | # @example Use an Array as a DSL 31 | # Docile.dsl_eval([]) do 32 | # push 1 33 | # push 2 34 | # pop 35 | # push 3 36 | # end 37 | # #=> [1, 3] 38 | # @note Use with an *imperative* DSL (commands modify the context object) 39 | # @param dsl [Object] context object whose methods make up the DSL 40 | # @param args [Array] arguments to be passed to the block 41 | # @param block [Proc] the block of DSL commands to be executed against the 42 | # `dsl` context object 43 | # @return [Object] the `dsl` context object after executing the block 44 | # 45 | # source://docile//lib/docile.rb#45 46 | def dsl_eval(dsl, *args, **_arg2, &block); end 47 | 48 | # Execute a block in the context of an immutable object whose methods, 49 | # and the methods of their return values, represent the commands in a DSL. 50 | # 51 | # Use this method to execute a *functional* DSL, which means that: 52 | # 53 | # 1. The original DSL context object is never mutated 54 | # 2. Each command returns the next DSL context object 55 | # 3. The final return value is the value returned by the last command 56 | # 57 | # @example Use a frozen String as a DSL 58 | # Docile.dsl_eval_immutable("I'm immutable!".freeze) do 59 | # reverse 60 | # upcase 61 | # end 62 | # #=> "!ELBATUMMI M'I" 63 | # @example Use a Float as a DSL 64 | # Docile.dsl_eval_immutable(84.5) do 65 | # fdiv(2) 66 | # floor 67 | # end 68 | # #=> 42 69 | # @note Use with a *functional* DSL (commands return successor 70 | # context objects) 71 | # @param dsl [Object] immutable context object whose methods make up the 72 | # initial DSL 73 | # @param args [Array] arguments to be passed to the block 74 | # @param block [Proc] the block of DSL commands to be executed against the 75 | # `dsl` context object and successor return values 76 | # @return [Object] the return value of the final command in the block 77 | # 78 | # source://docile//lib/docile.rb#128 79 | def dsl_eval_immutable(dsl, *args, **_arg2, &block); end 80 | 81 | # Execute a block in the context of an object whose methods represent the 82 | # commands in a DSL, and return *the block's return value*. 83 | # 84 | # Use this method to execute an *imperative* DSL, which means that: 85 | # 86 | # 1. Each command mutates the state of the DSL context object 87 | # 2. The return value of each command is ignored 88 | # 3. The final return value is the original context object 89 | # 90 | # @example Use a String as a DSL 91 | # Docile.dsl_eval_with_block_return("Hello, world!") do 92 | # reverse! 93 | # upcase! 94 | # first 95 | # end 96 | # #=> "!" 97 | # @example Use an Array as a DSL 98 | # Docile.dsl_eval_with_block_return([]) do 99 | # push "a" 100 | # push "b" 101 | # pop 102 | # push "c" 103 | # length 104 | # end 105 | # #=> 2 106 | # @note Use with an *imperative* DSL (commands modify the context object) 107 | # @param dsl [Object] context object whose methods make up the DSL 108 | # @param args [Array] arguments to be passed to the block 109 | # @param block [Proc] the block of DSL commands to be executed against the 110 | # `dsl` context object 111 | # @return [Object] the return value from executing the block 112 | # 113 | # source://docile//lib/docile.rb#87 114 | def dsl_eval_with_block_return(dsl, *args, **_arg2, &block); end 115 | 116 | class << self 117 | # Execute a block in the context of an object whose methods represent the 118 | # commands in a DSL. 119 | # 120 | # Use this method to execute an *imperative* DSL, which means that: 121 | # 122 | # 1. Each command mutates the state of the DSL context object 123 | # 2. The return value of each command is ignored 124 | # 3. The final return value is the original context object 125 | # 126 | # @example Use a String as a DSL 127 | # Docile.dsl_eval("Hello, world!") do 128 | # reverse! 129 | # upcase! 130 | # end 131 | # #=> "!DLROW ,OLLEH" 132 | # @example Use an Array as a DSL 133 | # Docile.dsl_eval([]) do 134 | # push 1 135 | # push 2 136 | # pop 137 | # push 3 138 | # end 139 | # #=> [1, 3] 140 | # @note Use with an *imperative* DSL (commands modify the context object) 141 | # @param dsl [Object] context object whose methods make up the DSL 142 | # @param args [Array] arguments to be passed to the block 143 | # @param block [Proc] the block of DSL commands to be executed against the 144 | # `dsl` context object 145 | # @return [Object] the `dsl` context object after executing the block 146 | # 147 | # source://docile//lib/docile.rb#45 148 | def dsl_eval(dsl, *args, **_arg2, &block); end 149 | 150 | # Execute a block in the context of an immutable object whose methods, 151 | # and the methods of their return values, represent the commands in a DSL. 152 | # 153 | # Use this method to execute a *functional* DSL, which means that: 154 | # 155 | # 1. The original DSL context object is never mutated 156 | # 2. Each command returns the next DSL context object 157 | # 3. The final return value is the value returned by the last command 158 | # 159 | # @example Use a frozen String as a DSL 160 | # Docile.dsl_eval_immutable("I'm immutable!".freeze) do 161 | # reverse 162 | # upcase 163 | # end 164 | # #=> "!ELBATUMMI M'I" 165 | # @example Use a Float as a DSL 166 | # Docile.dsl_eval_immutable(84.5) do 167 | # fdiv(2) 168 | # floor 169 | # end 170 | # #=> 42 171 | # @note Use with a *functional* DSL (commands return successor 172 | # context objects) 173 | # @param dsl [Object] immutable context object whose methods make up the 174 | # initial DSL 175 | # @param args [Array] arguments to be passed to the block 176 | # @param block [Proc] the block of DSL commands to be executed against the 177 | # `dsl` context object and successor return values 178 | # @return [Object] the return value of the final command in the block 179 | # 180 | # source://docile//lib/docile.rb#128 181 | def dsl_eval_immutable(dsl, *args, **_arg2, &block); end 182 | 183 | # Execute a block in the context of an object whose methods represent the 184 | # commands in a DSL, and return *the block's return value*. 185 | # 186 | # Use this method to execute an *imperative* DSL, which means that: 187 | # 188 | # 1. Each command mutates the state of the DSL context object 189 | # 2. The return value of each command is ignored 190 | # 3. The final return value is the original context object 191 | # 192 | # @example Use a String as a DSL 193 | # Docile.dsl_eval_with_block_return("Hello, world!") do 194 | # reverse! 195 | # upcase! 196 | # first 197 | # end 198 | # #=> "!" 199 | # @example Use an Array as a DSL 200 | # Docile.dsl_eval_with_block_return([]) do 201 | # push "a" 202 | # push "b" 203 | # pop 204 | # push "c" 205 | # length 206 | # end 207 | # #=> 2 208 | # @note Use with an *imperative* DSL (commands modify the context object) 209 | # @param dsl [Object] context object whose methods make up the DSL 210 | # @param args [Array] arguments to be passed to the block 211 | # @param block [Proc] the block of DSL commands to be executed against the 212 | # `dsl` context object 213 | # @return [Object] the return value from executing the block 214 | # 215 | # source://docile//lib/docile.rb#87 216 | def dsl_eval_with_block_return(dsl, *args, **_arg2, &block); end 217 | end 218 | end 219 | 220 | # This is used to remove entries pointing to Docile's source files 221 | # from {Exception#backtrace} and {Exception#backtrace_locations}. 222 | # 223 | # If {NoMethodError} is caught then the exception object will be extended 224 | # by this module to add filter functionalities. 225 | # 226 | # @api private 227 | # 228 | # source://docile//lib/docile/backtrace_filter.rb#11 229 | module Docile::BacktraceFilter 230 | # @api private 231 | # 232 | # source://docile//lib/docile/backtrace_filter.rb#14 233 | def backtrace; end 234 | 235 | # @api private 236 | # 237 | # source://docile//lib/docile/backtrace_filter.rb#19 238 | def backtrace_locations; end 239 | end 240 | 241 | # @api private 242 | # 243 | # source://docile//lib/docile/backtrace_filter.rb#12 244 | Docile::BacktraceFilter::FILTER_PATTERN = T.let(T.unsafe(nil), Regexp) 245 | 246 | # Operates in the same manner as {FallbackContextProxy}, but replacing 247 | # the primary `receiver` object with the result of each proxied method. 248 | # 249 | # This is useful for implementing DSL evaluation for immutable context 250 | # objects. 251 | # 252 | # 253 | # @api private 254 | # @see Docile.dsl_eval_immutable 255 | # 256 | # source://docile//lib/docile/chaining_fallback_context_proxy.rb#17 257 | class Docile::ChainingFallbackContextProxy < ::Docile::FallbackContextProxy 258 | # Proxy methods as in {FallbackContextProxy#method_missing}, replacing 259 | # `receiver` with the returned value. 260 | # 261 | # @api private 262 | # 263 | # source://docile//lib/docile/chaining_fallback_context_proxy.rb#20 264 | def method_missing(method, *args, **_arg2, &block); end 265 | end 266 | 267 | # A namespace for functions relating to the execution of a block against a 268 | # proxy object. 269 | # 270 | # @api private 271 | # 272 | # source://docile//lib/docile/execution.rb#8 273 | module Docile::Execution 274 | private 275 | 276 | # Execute a block in the context of an object whose methods represent the 277 | # commands in a DSL, using a specific proxy class. 278 | # 279 | # @api private 280 | # @param dsl [Object] context object whose methods make up the 281 | # (initial) DSL 282 | # @param proxy_type [FallbackContextProxy, ChainingFallbackContextProxy] which class to instantiate as proxy context 283 | # @param args [Array] arguments to be passed to the block 284 | # @param block [Proc] the block of DSL commands to be executed 285 | # @return [Object] the return value of the block 286 | # 287 | # source://docile//lib/docile/execution.rb#19 288 | def exec_in_proxy_context(dsl, proxy_type, *args, **_arg3, &block); end 289 | 290 | class << self 291 | # Execute a block in the context of an object whose methods represent the 292 | # commands in a DSL, using a specific proxy class. 293 | # 294 | # @api private 295 | # @param dsl [Object] context object whose methods make up the 296 | # (initial) DSL 297 | # @param proxy_type [FallbackContextProxy, ChainingFallbackContextProxy] which class to instantiate as proxy context 298 | # @param args [Array] arguments to be passed to the block 299 | # @param block [Proc] the block of DSL commands to be executed 300 | # @return [Object] the return value of the block 301 | # 302 | # source://docile//lib/docile/execution.rb#19 303 | def exec_in_proxy_context(dsl, proxy_type, *args, **_arg3, &block); end 304 | end 305 | end 306 | 307 | # A proxy object with a primary receiver as well as a secondary 308 | # fallback receiver. 309 | # 310 | # Will attempt to forward all method calls first to the primary receiver, 311 | # and then to the fallback receiver if the primary does not handle that 312 | # method. 313 | # 314 | # This is useful for implementing DSL evaluation in the context of an object. 315 | # 316 | # 317 | # @api private 318 | # @see Docile.dsl_eval 319 | # 320 | # source://docile//lib/docile/fallback_context_proxy.rb#20 321 | class Docile::FallbackContextProxy 322 | # @api private 323 | # @param receiver [Object] the primary proxy target to which all methods 324 | # initially will be forwarded 325 | # @param fallback [Object] the fallback proxy target to which any methods 326 | # not handled by `receiver` will be forwarded 327 | # @return [FallbackContextProxy] a new instance of FallbackContextProxy 328 | # 329 | # source://docile//lib/docile/fallback_context_proxy.rb#46 330 | def initialize(receiver, fallback); end 331 | 332 | # @api private 333 | # @return [Array] Instance variable names, excluding 334 | # {NON_PROXIED_INSTANCE_VARIABLES} 335 | # 336 | # source://docile//lib/docile/fallback_context_proxy.rb#85 337 | def instance_variables; end 338 | 339 | # Proxy all methods, excluding {NON_PROXIED_METHODS}, first to `receiver` 340 | # and then to `fallback` if not found. 341 | # 342 | # @api private 343 | # 344 | # source://docile//lib/docile/fallback_context_proxy.rb#91 345 | def method_missing(method, *args, **_arg2, &block); end 346 | end 347 | 348 | # The set of methods which will **not** fallback from the block's context 349 | # to the dsl object. 350 | # 351 | # @api private 352 | # 353 | # source://docile//lib/docile/fallback_context_proxy.rb#30 354 | Docile::FallbackContextProxy::NON_FALLBACK_METHODS = T.let(T.unsafe(nil), Set) 355 | 356 | # The set of instance variables which are local to this object and hidden. 357 | # All other instance variables will be copied in and out of this object 358 | # from the scope in which this proxy was created. 359 | # 360 | # @api private 361 | # 362 | # source://docile//lib/docile/fallback_context_proxy.rb#35 363 | Docile::FallbackContextProxy::NON_PROXIED_INSTANCE_VARIABLES = T.let(T.unsafe(nil), Set) 364 | 365 | # The set of methods which will **not** be proxied, but instead answered 366 | # by this object directly. 367 | # 368 | # @api private 369 | # 370 | # source://docile//lib/docile/fallback_context_proxy.rb#23 371 | Docile::FallbackContextProxy::NON_PROXIED_METHODS = T.let(T.unsafe(nil), Set) 372 | 373 | # The current version of this library 374 | # 375 | # source://docile//lib/docile/version.rb#5 376 | Docile::VERSION = T.let(T.unsafe(nil), String) 377 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/erubi@1.12.0.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `erubi` gem. 5 | # Please instead update this file by running `bin/tapioca gem erubi`. 6 | 7 | # source://erubi//lib/erubi.rb#3 8 | module Erubi 9 | class << self 10 | def h(_arg0); end 11 | end 12 | end 13 | 14 | # source://erubi//lib/erubi.rb#54 15 | class Erubi::Engine 16 | # Initialize a new Erubi::Engine. Options: 17 | # +:bufval+ :: The value to use for the buffer variable, as a string (default '::String.new'). 18 | # +:bufvar+ :: The variable name to use for the buffer variable, as a string. 19 | # +:chain_appends+ :: Whether to chain << calls to the buffer variable. Offers better 20 | # performance, but can cause issues when the buffer variable is reassigned during 21 | # template rendering (default +false+). 22 | # +:ensure+ :: Wrap the template in a begin/ensure block restoring the previous value of bufvar. 23 | # +:escapefunc+ :: The function to use for escaping, as a string (default: '::Erubi.h'). 24 | # +:escape+ :: Whether to make <%= escape by default, and <%== not escape by default. 25 | # +:escape_html+ :: Same as +:escape+, with lower priority. 26 | # +:filename+ :: The filename for the template. 27 | # the resulting source code. Note this may cause problems if you are wrapping the resulting 28 | # source code in other code, because the magic comment only has an effect at the beginning of 29 | # the file, and having the magic comment later in the file can trigger warnings. 30 | # +:freeze_template_literals+ :: Whether to suffix all literal strings for template code with .freeze 31 | # (default: +true+ on Ruby 2.1+, +false+ on Ruby 2.0 and older). 32 | # Can be set to +false+ on Ruby 2.3+ when frozen string literals are enabled 33 | # in order to improve performance. 34 | # +:literal_prefix+ :: The prefix to output when using escaped tag delimiters (default '<%'). 35 | # +:literal_postfix+ :: The postfix to output when using escaped tag delimiters (default '%>'). 36 | # +:outvar+ :: Same as +:bufvar+, with lower priority. 37 | # +:postamble+ :: The postamble for the template, by default returns the resulting source code. 38 | # +:preamble+ :: The preamble for the template, by default initializes the buffer variable. 39 | # +:regexp+ :: The regexp to use for scanning. 40 | # +:src+ :: The initial value to use for the source code, an empty string by default. 41 | # +:trim+ :: Whether to trim leading and trailing whitespace, true by default. 42 | # 43 | # @return [Engine] a new instance of Engine 44 | # 45 | # source://erubi//lib/erubi.rb#94 46 | def initialize(input, properties = T.unsafe(nil)); end 47 | 48 | # The variable name used for the buffer variable. 49 | # 50 | # source://erubi//lib/erubi.rb#65 51 | def bufvar; end 52 | 53 | # The filename of the template, if one was given. 54 | # 55 | # source://erubi//lib/erubi.rb#62 56 | def filename; end 57 | 58 | # The frozen ruby source code generated from the template, which can be evaled. 59 | # 60 | # source://erubi//lib/erubi.rb#59 61 | def src; end 62 | 63 | private 64 | 65 | # Add ruby code to the template 66 | # 67 | # source://erubi//lib/erubi.rb#226 68 | def add_code(code); end 69 | 70 | # Add the given ruby expression result to the template, 71 | # escaping it based on the indicator given and escape flag. 72 | # 73 | # source://erubi//lib/erubi.rb#235 74 | def add_expression(indicator, code); end 75 | 76 | # Add the result of Ruby expression to the template 77 | # 78 | # source://erubi//lib/erubi.rb#244 79 | def add_expression_result(code); end 80 | 81 | # Add the escaped result of Ruby expression to the template 82 | # 83 | # source://erubi//lib/erubi.rb#249 84 | def add_expression_result_escaped(code); end 85 | 86 | # Add the given postamble to the src. Can be overridden in subclasses 87 | # to make additional changes to src that depend on the current state. 88 | # 89 | # source://erubi//lib/erubi.rb#255 90 | def add_postamble(postamble); end 91 | 92 | # Add raw text to the template. Modifies argument if argument is mutable as a memory optimization. 93 | # Must be called with a string, cannot be called with nil (Rails's subclass depends on it). 94 | # 95 | # source://erubi//lib/erubi.rb#213 96 | def add_text(text); end 97 | 98 | # Raise an exception, as the base engine class does not support handling other indicators. 99 | # 100 | # @raise [ArgumentError] 101 | # 102 | # source://erubi//lib/erubi.rb#261 103 | def handle(indicator, code, tailch, rspace, lspace); end 104 | 105 | # Make sure that any current expression has been terminated. 106 | # The default is to terminate all expressions, but when 107 | # the chain_appends option is used, expressions may not be 108 | # terminated. 109 | # 110 | # source://erubi//lib/erubi.rb#289 111 | def terminate_expression; end 112 | 113 | # Make sure the buffer variable is the target of the next append 114 | # before yielding to the block. Mark that the buffer is the target 115 | # of the next append after the block executes. 116 | # 117 | # This method should only be called if the block will result in 118 | # code where << will append to the bufvar. 119 | # 120 | # source://erubi//lib/erubi.rb#271 121 | def with_buffer; end 122 | end 123 | 124 | # The default regular expression used for scanning. 125 | # 126 | # source://erubi//lib/erubi.rb#56 127 | Erubi::Engine::DEFAULT_REGEXP = T.let(T.unsafe(nil), Regexp) 128 | 129 | # source://erubi//lib/erubi.rb#17 130 | Erubi::FREEZE_TEMPLATE_LITERALS = T.let(T.unsafe(nil), TrueClass) 131 | 132 | # source://erubi//lib/erubi.rb#15 133 | Erubi::MATCH_METHOD = T.let(T.unsafe(nil), Symbol) 134 | 135 | # source://erubi//lib/erubi.rb#8 136 | Erubi::RANGE_FIRST = T.let(T.unsafe(nil), Integer) 137 | 138 | # source://erubi//lib/erubi.rb#9 139 | Erubi::RANGE_LAST = T.let(T.unsafe(nil), Integer) 140 | 141 | # source://erubi//lib/erubi.rb#16 142 | Erubi::SKIP_DEFINED_FOR_INSTANCE_VARIABLE = T.let(T.unsafe(nil), TrueClass) 143 | 144 | # source://erubi//lib/erubi.rb#4 145 | Erubi::VERSION = T.let(T.unsafe(nil), String) 146 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/hashery@2.1.2.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `hashery` gem. 5 | # Please instead update this file by running `bin/tapioca gem hashery`. 6 | 7 | # source://hashery//lib/hashery/lru_hash.rb#3 8 | module Hashery; end 9 | 10 | # source://hashery//lib/hashery/lru_hash.rb#13 11 | class Hashery::LRUHash 12 | include ::Enumerable 13 | 14 | # Initialize new LRUHash instance. 15 | # 16 | # max_size - 17 | # default_value - 18 | # block - 19 | # 20 | # @return [LRUHash] a new instance of LRUHash 21 | # 22 | # source://hashery//lib/hashery/lru_hash.rb#30 23 | def initialize(max_size, default_value = T.unsafe(nil), &block); end 24 | 25 | # source://hashery//lib/hashery/lru_hash.rb#114 26 | def [](key); end 27 | 28 | # source://hashery//lib/hashery/lru_hash.rb#197 29 | def []=(key, value); end 30 | 31 | # source://hashery//lib/hashery/lru_hash.rb#165 32 | def assoc(key); end 33 | 34 | # source://hashery//lib/hashery/lru_hash.rb#253 35 | def clear; end 36 | 37 | # Returns the value of attribute default. 38 | # 39 | # source://hashery//lib/hashery/lru_hash.rb#19 40 | def default; end 41 | 42 | # Sets the attribute default 43 | # 44 | # @param value the value to set the attribute default to. 45 | # 46 | # source://hashery//lib/hashery/lru_hash.rb#19 47 | def default=(_arg0); end 48 | 49 | # Returns the value of attribute default_proc. 50 | # 51 | # source://hashery//lib/hashery/lru_hash.rb#20 52 | def default_proc; end 53 | 54 | # Sets the attribute default_proc 55 | # 56 | # @param value the value to set the attribute default_proc to. 57 | # 58 | # source://hashery//lib/hashery/lru_hash.rb#20 59 | def default_proc=(_arg0); end 60 | 61 | # source://hashery//lib/hashery/lru_hash.rb#224 62 | def delete(key); end 63 | 64 | # source://hashery//lib/hashery/lru_hash.rb#231 65 | def delete_if; end 66 | 67 | # Iterate over each pair. 68 | # 69 | # Same as each pair. 70 | # 71 | # source://hashery//lib/hashery/lru_hash.rb#43 72 | def each; end 73 | 74 | # Iterate over each key. 75 | # 76 | # source://hashery//lib/hashery/lru_hash.rb#61 77 | def each_key; end 78 | 79 | # Iterate over each pair. 80 | # 81 | # source://hashery//lib/hashery/lru_hash.rb#43 82 | def each_pair; end 83 | 84 | # Iterate over each value. 85 | # 86 | # source://hashery//lib/hashery/lru_hash.rb#74 87 | def each_value; end 88 | 89 | # @return [Boolean] 90 | # 91 | # source://hashery//lib/hashery/lru_hash.rb#94 92 | def empty?; end 93 | 94 | # source://hashery//lib/hashery/lru_hash.rb#101 95 | def fetch(key, &b); end 96 | 97 | # @return [Boolean] 98 | # 99 | # source://hashery//lib/hashery/lru_hash.rb#137 100 | def has_key?(key); end 101 | 102 | # @return [Boolean] 103 | # 104 | # source://hashery//lib/hashery/lru_hash.rb#148 105 | def has_value?(value); end 106 | 107 | # @return [Boolean] 108 | # 109 | # source://hashery//lib/hashery/lru_hash.rb#137 110 | def include?(key); end 111 | 112 | # source://hashery//lib/hashery/lru_hash.rb#264 113 | def inspect; end 114 | 115 | # source://hashery//lib/hashery/lru_hash.rb#190 116 | def key(value); end 117 | 118 | # @return [Boolean] 119 | # 120 | # source://hashery//lib/hashery/lru_hash.rb#137 121 | def key?(key); end 122 | 123 | # source://hashery//lib/hashery/lru_hash.rb#123 124 | def keys; end 125 | 126 | # Returns the value of attribute max_size. 127 | # 128 | # source://hashery//lib/hashery/lru_hash.rb#17 129 | def max_size; end 130 | 131 | # source://hashery//lib/hashery/lru_hash.rb#240 132 | def max_size=(limit); end 133 | 134 | # @return [Boolean] 135 | # 136 | # source://hashery//lib/hashery/lru_hash.rb#137 137 | def member?(key); end 138 | 139 | # source://hashery//lib/hashery/lru_hash.rb#177 140 | def rassoc(value); end 141 | 142 | # Returns the value of attribute release_proc. 143 | # 144 | # source://hashery//lib/hashery/lru_hash.rb#21 145 | def release_proc; end 146 | 147 | # Sets the attribute release_proc 148 | # 149 | # @param value the value to set the attribute release_proc to. 150 | # 151 | # source://hashery//lib/hashery/lru_hash.rb#21 152 | def release_proc=(_arg0); end 153 | 154 | # Size of the hash. 155 | # 156 | # source://hashery//lib/hashery/lru_hash.rb#87 157 | def size; end 158 | 159 | # source://hashery//lib/hashery/lru_hash.rb#197 160 | def store(key, value); end 161 | 162 | # source://hashery//lib/hashery/lru_hash.rb#264 163 | def to_s; end 164 | 165 | # @return [Boolean] 166 | # 167 | # source://hashery//lib/hashery/lru_hash.rb#148 168 | def value?(value); end 169 | 170 | # source://hashery//lib/hashery/lru_hash.rb#130 171 | def values; end 172 | 173 | # source://hashery//lib/hashery/lru_hash.rb#158 174 | def values_at(*key_list); end 175 | 176 | private 177 | 178 | # Remove the oldest node returning the node 179 | # 180 | # source://hashery//lib/hashery/lru_hash.rb#314 181 | def delete_oldest; end 182 | 183 | # Iterate nodes. 184 | # 185 | # source://hashery//lib/hashery/lru_hash.rb#277 186 | def each_node; end 187 | 188 | # Move node to front. 189 | # 190 | # node - [Node] 191 | # 192 | # source://hashery//lib/hashery/lru_hash.rb#294 193 | def front(node); end 194 | 195 | # Normalize the argument in order to be usable as max_size 196 | # criterion is that n.to_i must be an Integer and it must 197 | # be larger than zero. 198 | # 199 | # n - [#to_i] max size 200 | # 201 | # @raise [ArgumentError] 202 | # 203 | # source://hashery//lib/hashery/lru_hash.rb#327 204 | def normalize_max(n); end 205 | 206 | # Remove the node and invoke release_proc 207 | # if set 208 | # 209 | # node - [Node] 210 | # 211 | # source://hashery//lib/hashery/lru_hash.rb#304 212 | def remove_node(node); end 213 | end 214 | 215 | # source://hashery//lib/hashery/lru_hash.rb#334 216 | Hashery::LRUHash::FETCH = T.let(T.unsafe(nil), Proc) 217 | 218 | # A single node in the doubly linked LRU list of nodes. 219 | # 220 | # source://hashery//lib/hashery/lru_hash.rb#337 221 | class Hashery::LRUHash::Node < ::Struct 222 | # source://hashery//lib/hashery/lru_hash.rb#345 223 | def insert_after(node); end 224 | 225 | # Returns the value of attribute key 226 | # 227 | # @return [Object] the current value of key 228 | def key; end 229 | 230 | # Sets the attribute key 231 | # 232 | # @param value [Object] the value to set the attribute key to. 233 | # @return [Object] the newly set value 234 | def key=(_); end 235 | 236 | # Returns the value of attribute pred 237 | # 238 | # @return [Object] the current value of pred 239 | def pred; end 240 | 241 | # Sets the attribute pred 242 | # 243 | # @param value [Object] the value to set the attribute pred to. 244 | # @return [Object] the newly set value 245 | def pred=(_); end 246 | 247 | # Returns the value of attribute succ 248 | # 249 | # @return [Object] the current value of succ 250 | def succ; end 251 | 252 | # Sets the attribute succ 253 | # 254 | # @param value [Object] the value to set the attribute succ to. 255 | # @return [Object] the newly set value 256 | def succ=(_); end 257 | 258 | # source://hashery//lib/hashery/lru_hash.rb#338 259 | def unlink; end 260 | 261 | # Returns the value of attribute value 262 | # 263 | # @return [Object] the current value of value 264 | def value; end 265 | 266 | # Sets the attribute value 267 | # 268 | # @param value [Object] the value to set the attribute value to. 269 | # @return [Object] the newly set value 270 | def value=(_); end 271 | 272 | class << self 273 | def [](*_arg0); end 274 | def inspect; end 275 | def keyword_init?; end 276 | def members; end 277 | def new(*_arg0); end 278 | end 279 | end 280 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/netrc@0.11.0.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `netrc` gem. 5 | # Please instead update this file by running `bin/tapioca gem netrc`. 6 | 7 | # source://netrc//lib/netrc.rb#3 8 | class Netrc 9 | # @return [Netrc] a new instance of Netrc 10 | # 11 | # source://netrc//lib/netrc.rb#166 12 | def initialize(path, data); end 13 | 14 | # source://netrc//lib/netrc.rb#180 15 | def [](k); end 16 | 17 | # source://netrc//lib/netrc.rb#188 18 | def []=(k, info); end 19 | 20 | # source://netrc//lib/netrc.rb#200 21 | def delete(key); end 22 | 23 | # source://netrc//lib/netrc.rb#211 24 | def each(&block); end 25 | 26 | # source://netrc//lib/netrc.rb#196 27 | def length; end 28 | 29 | # source://netrc//lib/netrc.rb#215 30 | def new_item(m, l, p); end 31 | 32 | # Returns the value of attribute new_item_prefix. 33 | # 34 | # source://netrc//lib/netrc.rb#178 35 | def new_item_prefix; end 36 | 37 | # Sets the attribute new_item_prefix 38 | # 39 | # @param value the value to set the attribute new_item_prefix to. 40 | # 41 | # source://netrc//lib/netrc.rb#178 42 | def new_item_prefix=(_arg0); end 43 | 44 | # source://netrc//lib/netrc.rb#219 45 | def save; end 46 | 47 | # source://netrc//lib/netrc.rb#233 48 | def unparse; end 49 | 50 | class << self 51 | # source://netrc//lib/netrc.rb#42 52 | def check_permissions(path); end 53 | 54 | # source://netrc//lib/netrc.rb#33 55 | def config; end 56 | 57 | # @yield [self.config] 58 | # 59 | # source://netrc//lib/netrc.rb#37 60 | def configure; end 61 | 62 | # source://netrc//lib/netrc.rb#10 63 | def default_path; end 64 | 65 | # source://netrc//lib/netrc.rb#14 66 | def home_path; end 67 | 68 | # source://netrc//lib/netrc.rb#85 69 | def lex(lines); end 70 | 71 | # source://netrc//lib/netrc.rb#29 72 | def netrc_filename; end 73 | 74 | # Returns two values, a header and a list of items. 75 | # Each item is a tuple, containing some or all of: 76 | # - machine keyword (including trailing whitespace+comments) 77 | # - machine name 78 | # - login keyword (including surrounding whitespace+comments) 79 | # - login 80 | # - password keyword (including surrounding whitespace+comments) 81 | # - password 82 | # - trailing chars 83 | # This lets us change individual fields, then write out the file 84 | # with all its original formatting. 85 | # 86 | # source://netrc//lib/netrc.rb#129 87 | def parse(ts); end 88 | 89 | # Reads path and parses it as a .netrc file. If path doesn't 90 | # exist, returns an empty object. Decrypt paths ending in .gpg. 91 | # 92 | # source://netrc//lib/netrc.rb#51 93 | def read(path = T.unsafe(nil)); end 94 | 95 | # @return [Boolean] 96 | # 97 | # source://netrc//lib/netrc.rb#112 98 | def skip?(s); end 99 | end 100 | end 101 | 102 | # source://netrc//lib/netrc.rb#244 103 | class Netrc::Entry < ::Struct 104 | # Returns the value of attribute login 105 | # 106 | # @return [Object] the current value of login 107 | def login; end 108 | 109 | # Sets the attribute login 110 | # 111 | # @param value [Object] the value to set the attribute login to. 112 | # @return [Object] the newly set value 113 | def login=(_); end 114 | 115 | # Returns the value of attribute password 116 | # 117 | # @return [Object] the current value of password 118 | def password; end 119 | 120 | # Sets the attribute password 121 | # 122 | # @param value [Object] the value to set the attribute password to. 123 | # @return [Object] the newly set value 124 | def password=(_); end 125 | 126 | def to_ary; end 127 | 128 | class << self 129 | def [](*_arg0); end 130 | def inspect; end 131 | def keyword_init?; end 132 | def members; end 133 | def new(*_arg0); end 134 | end 135 | end 136 | 137 | # source://netrc//lib/netrc.rb#250 138 | class Netrc::Error < ::StandardError; end 139 | 140 | # source://netrc//lib/netrc.rb#68 141 | class Netrc::TokenArray < ::Array 142 | # source://netrc//lib/netrc.rb#76 143 | def readto; end 144 | 145 | # source://netrc//lib/netrc.rb#69 146 | def take; end 147 | end 148 | 149 | # source://netrc//lib/netrc.rb#4 150 | Netrc::VERSION = T.let(T.unsafe(nil), String) 151 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/parallel@1.23.0.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `parallel` gem. 5 | # Please instead update this file by running `bin/tapioca gem parallel`. 6 | 7 | # source://parallel//lib/parallel/version.rb#2 8 | module Parallel 9 | class << self 10 | # @return [Boolean] 11 | # 12 | # source://parallel//lib/parallel.rb#243 13 | def all?(*args, &block); end 14 | 15 | # @return [Boolean] 16 | # 17 | # source://parallel//lib/parallel.rb#238 18 | def any?(*args, &block); end 19 | 20 | # source://parallel//lib/parallel.rb#234 21 | def each(array, options = T.unsafe(nil), &block); end 22 | 23 | # source://parallel//lib/parallel.rb#248 24 | def each_with_index(array, options = T.unsafe(nil), &block); end 25 | 26 | # source://parallel//lib/parallel.rb#307 27 | def filter_map(*args, &block); end 28 | 29 | # source://parallel//lib/parallel.rb#303 30 | def flat_map(*args, &block); end 31 | 32 | # source://parallel//lib/parallel.rb#228 33 | def in_processes(options = T.unsafe(nil), &block); end 34 | 35 | # source://parallel//lib/parallel.rb#212 36 | def in_threads(options = T.unsafe(nil)); end 37 | 38 | # source://parallel//lib/parallel.rb#252 39 | def map(source, options = T.unsafe(nil), &block); end 40 | 41 | # source://parallel//lib/parallel.rb#299 42 | def map_with_index(array, options = T.unsafe(nil), &block); end 43 | 44 | # Number of physical processor cores on the current system. 45 | # 46 | # source://parallel//lib/parallel.rb#312 47 | def physical_processor_count; end 48 | 49 | # Number of processors seen by the OS, used for process scheduling 50 | # 51 | # source://parallel//lib/parallel.rb#345 52 | def processor_count; end 53 | 54 | # source://parallel//lib/parallel.rb#350 55 | def worker_number; end 56 | 57 | # TODO: this does not work when doing threads in forks, so should remove and yield the number instead if needed 58 | # 59 | # source://parallel//lib/parallel.rb#355 60 | def worker_number=(worker_num); end 61 | 62 | private 63 | 64 | # source://parallel//lib/parallel.rb#361 65 | def add_progress_bar!(job_factory, options); end 66 | 67 | # source://parallel//lib/parallel.rb#624 68 | def call_with_index(item, index, options, &block); end 69 | 70 | # source://parallel//lib/parallel.rb#556 71 | def create_workers(job_factory, options, &block); end 72 | 73 | # options is either a Integer or a Hash with :count 74 | # 75 | # source://parallel//lib/parallel.rb#614 76 | def extract_count_from_options(options); end 77 | 78 | # source://parallel//lib/parallel.rb#642 79 | def instrument_finish(item, index, result, options); end 80 | 81 | # source://parallel//lib/parallel.rb#647 82 | def instrument_start(item, index, options); end 83 | 84 | # source://parallel//lib/parallel.rb#590 85 | def process_incoming_jobs(read, write, job_factory, options, &block); end 86 | 87 | # source://parallel//lib/parallel.rb#544 88 | def replace_worker(job_factory, workers, index, options, blk); end 89 | 90 | # source://parallel//lib/parallel.rb#635 91 | def with_instrumentation(item, index, options); end 92 | 93 | # source://parallel//lib/parallel.rb#386 94 | def work_direct(job_factory, options, &block); end 95 | 96 | # source://parallel//lib/parallel.rb#496 97 | def work_in_processes(job_factory, options, &blk); end 98 | 99 | # source://parallel//lib/parallel.rb#430 100 | def work_in_ractors(job_factory, options); end 101 | 102 | # source://parallel//lib/parallel.rb#405 103 | def work_in_threads(job_factory, options, &block); end 104 | 105 | # source://parallel//lib/parallel.rb#564 106 | def worker(job_factory, options, &block); end 107 | end 108 | end 109 | 110 | # source://parallel//lib/parallel.rb#11 111 | class Parallel::Break < ::StandardError 112 | # @return [Break] a new instance of Break 113 | # 114 | # source://parallel//lib/parallel.rb#14 115 | def initialize(value = T.unsafe(nil)); end 116 | 117 | # Returns the value of attribute value. 118 | # 119 | # source://parallel//lib/parallel.rb#12 120 | def value; end 121 | end 122 | 123 | # source://parallel//lib/parallel.rb#8 124 | class Parallel::DeadWorker < ::StandardError; end 125 | 126 | # source://parallel//lib/parallel.rb#32 127 | class Parallel::ExceptionWrapper 128 | # @return [ExceptionWrapper] a new instance of ExceptionWrapper 129 | # 130 | # source://parallel//lib/parallel.rb#35 131 | def initialize(exception); end 132 | 133 | # Returns the value of attribute exception. 134 | # 135 | # source://parallel//lib/parallel.rb#33 136 | def exception; end 137 | end 138 | 139 | # source://parallel//lib/parallel.rb#98 140 | class Parallel::JobFactory 141 | # @return [JobFactory] a new instance of JobFactory 142 | # 143 | # source://parallel//lib/parallel.rb#99 144 | def initialize(source, mutex); end 145 | 146 | # source://parallel//lib/parallel.rb#107 147 | def next; end 148 | 149 | # generate item that is sent to workers 150 | # just index is faster + less likely to blow up with unserializable errors 151 | # 152 | # source://parallel//lib/parallel.rb#136 153 | def pack(item, index); end 154 | 155 | # source://parallel//lib/parallel.rb#126 156 | def size; end 157 | 158 | # unpack item that is sent to workers 159 | # 160 | # source://parallel//lib/parallel.rb#141 161 | def unpack(data); end 162 | 163 | private 164 | 165 | # @return [Boolean] 166 | # 167 | # source://parallel//lib/parallel.rb#147 168 | def producer?; end 169 | 170 | # source://parallel//lib/parallel.rb#151 171 | def queue_wrapper(array); end 172 | end 173 | 174 | # source://parallel//lib/parallel.rb#20 175 | class Parallel::Kill < ::Parallel::Break; end 176 | 177 | # source://parallel//lib/parallel.rb#6 178 | Parallel::Stop = T.let(T.unsafe(nil), Object) 179 | 180 | # source://parallel//lib/parallel.rb#23 181 | class Parallel::UndumpableException < ::StandardError 182 | # @return [UndumpableException] a new instance of UndumpableException 183 | # 184 | # source://parallel//lib/parallel.rb#26 185 | def initialize(original); end 186 | 187 | # Returns the value of attribute backtrace. 188 | # 189 | # source://parallel//lib/parallel.rb#24 190 | def backtrace; end 191 | end 192 | 193 | # source://parallel//lib/parallel.rb#156 194 | class Parallel::UserInterruptHandler 195 | class << self 196 | # source://parallel//lib/parallel.rb#181 197 | def kill(thing); end 198 | 199 | # kill all these pids or threads if user presses Ctrl+c 200 | # 201 | # source://parallel//lib/parallel.rb#161 202 | def kill_on_ctrl_c(pids, options); end 203 | 204 | private 205 | 206 | # source://parallel//lib/parallel.rb#205 207 | def restore_interrupt(old, signal); end 208 | 209 | # source://parallel//lib/parallel.rb#190 210 | def trap_interrupt(signal); end 211 | end 212 | end 213 | 214 | # source://parallel//lib/parallel.rb#157 215 | Parallel::UserInterruptHandler::INTERRUPT_SIGNAL = T.let(T.unsafe(nil), Symbol) 216 | 217 | # source://parallel//lib/parallel/version.rb#3 218 | Parallel::VERSION = T.let(T.unsafe(nil), String) 219 | 220 | # source://parallel//lib/parallel/version.rb#3 221 | Parallel::Version = T.let(T.unsafe(nil), String) 222 | 223 | # source://parallel//lib/parallel.rb#51 224 | class Parallel::Worker 225 | # @return [Worker] a new instance of Worker 226 | # 227 | # source://parallel//lib/parallel.rb#55 228 | def initialize(read, write, pid); end 229 | 230 | # might be passed to started_processes and simultaneously closed by another thread 231 | # when running in isolation mode, so we have to check if it is closed before closing 232 | # 233 | # source://parallel//lib/parallel.rb#68 234 | def close_pipes; end 235 | 236 | # Returns the value of attribute pid. 237 | # 238 | # source://parallel//lib/parallel.rb#52 239 | def pid; end 240 | 241 | # Returns the value of attribute read. 242 | # 243 | # source://parallel//lib/parallel.rb#52 244 | def read; end 245 | 246 | # source://parallel//lib/parallel.rb#61 247 | def stop; end 248 | 249 | # Returns the value of attribute thread. 250 | # 251 | # source://parallel//lib/parallel.rb#53 252 | def thread; end 253 | 254 | # Sets the attribute thread 255 | # 256 | # @param value the value to set the attribute thread to. 257 | # 258 | # source://parallel//lib/parallel.rb#53 259 | def thread=(_arg0); end 260 | 261 | # source://parallel//lib/parallel.rb#73 262 | def work(data); end 263 | 264 | # Returns the value of attribute write. 265 | # 266 | # source://parallel//lib/parallel.rb#52 267 | def write; end 268 | 269 | private 270 | 271 | # source://parallel//lib/parallel.rb#91 272 | def wait; end 273 | end 274 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/prettier_print@1.2.1.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `prettier_print` gem. 5 | # Please instead update this file by running `bin/tapioca gem prettier_print`. 6 | 7 | # This class implements a pretty printing algorithm. It finds line breaks and 8 | # nice indentations for grouped structure. 9 | # 10 | # By default, the class assumes that primitive elements are strings and each 11 | # byte in the strings is a single column in width. But it can be used for other 12 | # situations by giving suitable arguments for some methods: 13 | # 14 | # * newline object and space generation block for PrettierPrint.new 15 | # * optional width argument for PrettierPrint#text 16 | # * PrettierPrint#breakable 17 | # 18 | # There are several candidate uses: 19 | # * text formatting using proportional fonts 20 | # * multibyte characters which has columns different to number of bytes 21 | # * non-string formatting 22 | # 23 | # == Usage 24 | # 25 | # To use this module, you will need to generate a tree of print nodes that 26 | # represent indentation and newline behavior before it gets sent to the printer. 27 | # Each node has different semantics, depending on the desired output. 28 | # 29 | # The most basic node is a Text node. This represents plain text content that 30 | # cannot be broken up even if it doesn't fit on one line. You would create one 31 | # of those with the text method, as in: 32 | # 33 | # PrettierPrint.format { |q| q.text('my content') } 34 | # 35 | # No matter what the desired output width is, the output for the snippet above 36 | # will always be the same. 37 | # 38 | # If you want to allow the printer to break up the content on the space 39 | # character when there isn't enough width for the full string on the same line, 40 | # you can use the Breakable and Group nodes. For example: 41 | # 42 | # PrettierPrint.format do |q| 43 | # q.group do 44 | # q.text("my") 45 | # q.breakable 46 | # q.text("content") 47 | # end 48 | # end 49 | # 50 | # Now, if everything fits on one line (depending on the maximum width specified) 51 | # then it will be the same output as the first example. If, however, there is 52 | # not enough room on the line, then you will get two lines of output, one for 53 | # the first string and one for the second. 54 | # 55 | # There are other nodes for the print tree as well, described in the 56 | # documentation below. They control alignment, indentation, conditional 57 | # formatting, and more. 58 | # 59 | # == References 60 | # Christian Lindig, Strictly Pretty, March 2000 61 | # https://lindig.github.io/papers/strictly-pretty-2000.pdf 62 | # 63 | # Philip Wadler, A prettier printer, March 1998 64 | # https://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf 65 | # 66 | # source://prettier_print//lib/prettier_print.rb#62 67 | class PrettierPrint 68 | # Creates a buffer for pretty printing. 69 | # 70 | # +output+ is an output target. If it is not specified, '' is assumed. It 71 | # should have a << method which accepts the first argument +obj+ of 72 | # PrettierPrint#text, the first argument +separator+ of PrettierPrint#breakable, 73 | # the first argument +newline+ of PrettierPrint.new, and the result of a given 74 | # block for PrettierPrint.new. 75 | # 76 | # +maxwidth+ specifies maximum line length. If it is not specified, 80 is 77 | # assumed. However actual outputs may overflow +maxwidth+ if long 78 | # non-breakable texts are provided. 79 | # 80 | # +newline+ is used for line breaks. "\n" is used if it is not specified. 81 | # 82 | # The block is used to generate spaces. ->(n) { ' ' * n } is used if it is not 83 | # given. 84 | # 85 | # @return [PrettierPrint] a new instance of PrettierPrint 86 | # 87 | # source://prettier_print//lib/prettier_print.rb#441 88 | def initialize(output = T.unsafe(nil), maxwidth = T.unsafe(nil), newline = T.unsafe(nil), &genspace); end 89 | 90 | # This inserts a BreakParent node into the print tree which forces the 91 | # surrounding and all parent group nodes to break. 92 | # 93 | # source://prettier_print//lib/prettier_print.rb#814 94 | def break_parent; end 95 | 96 | # This says "you can break a line here if necessary", and a +width+\-column 97 | # text +separator+ is inserted if a line is not broken at the point. 98 | # 99 | # If +separator+ is not specified, ' ' is used. 100 | # 101 | # If +width+ is not specified, +separator.length+ is used. You will have to 102 | # specify this when +separator+ is a multibyte character, for example. 103 | # 104 | # By default, if the surrounding group is broken and a newline is inserted, 105 | # the printer will indent the subsequent line up to the current level of 106 | # indentation. You can disable this behavior with the +indent+ argument if 107 | # that's not desired (rare). 108 | # 109 | # By default, when you insert a Breakable into the print tree, it only breaks 110 | # the surrounding group when the group's contents cannot fit onto the 111 | # remaining space of the current line. You can force it to break the 112 | # surrounding group instead if you always want the newline with the +force+ 113 | # argument. 114 | # 115 | # There are a few circumstances where you'll want to force the newline into 116 | # the output but no insert a break parent (because you don't want to 117 | # necessarily force the groups to break unless they need to). In this case you 118 | # can pass `force: :skip_break_parent` to this method and it will not insert 119 | # a break parent.` 120 | # 121 | # source://prettier_print//lib/prettier_print.rb#802 122 | def breakable(separator = T.unsafe(nil), width = T.unsafe(nil), indent: T.unsafe(nil), force: T.unsafe(nil)); end 123 | 124 | # Another very common breakable call you receive while formatting is an 125 | # empty string in flat mode and a newline in break mode. Similar to 126 | # breakable_space, this is here for avoid unnecessary calculation. 127 | # 128 | # source://prettier_print//lib/prettier_print.rb#646 129 | def breakable_empty; end 130 | 131 | # The final of the very common breakable calls you receive while formatting 132 | # is the normal breakable space but with the addition of the break_parent. 133 | # 134 | # source://prettier_print//lib/prettier_print.rb#652 135 | def breakable_force; end 136 | 137 | # This is the same shortcut as breakable_force, except that it doesn't indent 138 | # the next line. This is necessary if you're trying to preserve some custom 139 | # formatting like a multi-line string. 140 | # 141 | # source://prettier_print//lib/prettier_print.rb#660 142 | def breakable_return; end 143 | 144 | # The vast majority of breakable calls you receive while formatting are a 145 | # space in flat mode and a newline in break mode. Since this is so common, 146 | # we have a method here to skip past unnecessary calculation. 147 | # 148 | # source://prettier_print//lib/prettier_print.rb#639 149 | def breakable_space; end 150 | 151 | # This is an output buffer that wraps the output object and provides 152 | # additional functionality depending on its type. 153 | # 154 | # This defaults to Buffer::StringBuffer.new("".dup) 155 | # 156 | # source://prettier_print//lib/prettier_print.rb#400 157 | def buffer; end 158 | 159 | # A convenience method which is same as follows: 160 | # 161 | # text(",") 162 | # breakable 163 | # 164 | # source://prettier_print//lib/prettier_print.rb#669 165 | def comma_breakable; end 166 | 167 | # Returns the group most recently added to the stack. 168 | # 169 | # Contrived example: 170 | # out = "" 171 | # => "" 172 | # q = PrettierPrint.new(out) 173 | # => # 174 | # q.group { 175 | # q.text q.current_group.inspect 176 | # q.text q.newline 177 | # q.group(q.current_group.depth + 1) { 178 | # q.text q.current_group.inspect 179 | # q.text q.newline 180 | # q.group(q.current_group.depth + 1) { 181 | # q.text q.current_group.inspect 182 | # q.text q.newline 183 | # q.group(q.current_group.depth + 1) { 184 | # q.text q.current_group.inspect 185 | # q.text q.newline 186 | # } 187 | # } 188 | # } 189 | # } 190 | # => 284 191 | # puts out 192 | # # 193 | # # 194 | # # 195 | # # 196 | # 197 | # source://prettier_print//lib/prettier_print.rb#484 198 | def current_group; end 199 | 200 | # This is similar to #breakable except the decision to break or not is 201 | # determined individually. 202 | # 203 | # Two #fill_breakable under a group may cause 4 results: 204 | # (break,break), (break,non-break), (non-break,break), (non-break,non-break). 205 | # This is different to #breakable because two #breakable under a group 206 | # may cause 2 results: (break,break), (non-break,non-break). 207 | # 208 | # The text +separator+ is inserted if a line is not broken at this point. 209 | # 210 | # If +separator+ is not specified, ' ' is used. 211 | # 212 | # If +width+ is not specified, +separator.length+ is used. You will have to 213 | # specify this when +separator+ is a multibyte character, for example. 214 | # 215 | # source://prettier_print//lib/prettier_print.rb#688 216 | def fill_breakable(separator = T.unsafe(nil), width = T.unsafe(nil)); end 217 | 218 | # Flushes all of the generated print tree onto the output buffer, then clears 219 | # the generated tree from memory. 220 | # 221 | # source://prettier_print//lib/prettier_print.rb#490 222 | def flush(base_indentation = T.unsafe(nil)); end 223 | 224 | # An object that responds to call that takes one argument, of an Integer, and 225 | # returns the corresponding number of spaces. 226 | # 227 | # By default this is: ->(n) { ' ' * n } 228 | # 229 | # source://prettier_print//lib/prettier_print.rb#416 230 | def genspace; end 231 | 232 | # Groups line break hints added in the block. The line break hints are all to 233 | # be used or not. 234 | # 235 | # If +indent+ is specified, the method call is regarded as nested by 236 | # nest(indent) { ... }. 237 | # 238 | # If +open_object+ is specified, text(open_object, open_width) is 239 | # called before grouping. If +close_object+ is specified, 240 | # text(close_object, close_width) is called after grouping. 241 | # 242 | # source://prettier_print//lib/prettier_print.rb#845 243 | def group(indent = T.unsafe(nil), open_object = T.unsafe(nil), close_object = T.unsafe(nil), open_width = T.unsafe(nil), close_width = T.unsafe(nil)); end 244 | 245 | # The stack of groups that are being printed. 246 | # 247 | # source://prettier_print//lib/prettier_print.rb#419 248 | def groups; end 249 | 250 | # Inserts an IfBreak node with the contents of the block being added to its 251 | # list of nodes that should be printed if the surrounding node breaks. If it 252 | # doesn't, then you can specify the contents to be printed with the #if_flat 253 | # method used on the return object from this method. For example, 254 | # 255 | # q.if_break { q.text('do') }.if_flat { q.text('{') } 256 | # 257 | # In the example above, if the surrounding group is broken it will print 'do' 258 | # and if it is not it will print '{'. 259 | # 260 | # source://prettier_print//lib/prettier_print.rb#917 261 | def if_break; end 262 | 263 | # This is similar to if_break in that it also inserts an IfBreak node into the 264 | # print tree, however it's starting from the flat contents, and cannot be used 265 | # to build the break contents. 266 | # 267 | # source://prettier_print//lib/prettier_print.rb#936 268 | def if_flat; end 269 | 270 | # Very similar to the #nest method, this indents the nested content by one 271 | # level by inserting an Indent node into the print tree. The contents of the 272 | # node are determined by the block. 273 | # 274 | # source://prettier_print//lib/prettier_print.rb#956 275 | def indent; end 276 | 277 | # This method calculates the position of the text relative to the current 278 | # indentation level when the doc has been printed. It's useful for 279 | # determining how to align text to doc nodes that are already built into the 280 | # tree. 281 | # 282 | # source://prettier_print//lib/prettier_print.rb#696 283 | def last_position(node); end 284 | 285 | # Inserts a LineSuffix node into the print tree. The contents of the node are 286 | # determined by the block. 287 | # 288 | # source://prettier_print//lib/prettier_print.rb#967 289 | def line_suffix(priority: T.unsafe(nil)); end 290 | 291 | # The maximum width of a line, before it is separated in to a newline 292 | # 293 | # This defaults to 80, and should be an Integer 294 | # 295 | # source://prettier_print//lib/prettier_print.rb#405 296 | def maxwidth; end 297 | 298 | # Increases left margin after newline with +indent+ for line breaks added in 299 | # the block. 300 | # 301 | # source://prettier_print//lib/prettier_print.rb#977 302 | def nest(indent); end 303 | 304 | # The value that is appended to +output+ to add a new line. 305 | # 306 | # This defaults to "\n", and should be String 307 | # 308 | # source://prettier_print//lib/prettier_print.rb#410 309 | def newline; end 310 | 311 | # The output object. It represents the final destination of the contents of 312 | # the print tree. It should respond to <<. 313 | # 314 | # This defaults to "".dup 315 | # 316 | # source://prettier_print//lib/prettier_print.rb#394 317 | def output; end 318 | 319 | # This method will remove any breakables from the list of contents so that 320 | # no newlines are present in the output. If a newline is being forced into 321 | # the output, the replace value will be used. 322 | # 323 | # source://prettier_print//lib/prettier_print.rb#721 324 | def remove_breaks(node, replace = T.unsafe(nil)); end 325 | 326 | # Adds a separated list. 327 | # The list is separated by comma with breakable space, by default. 328 | # 329 | # #seplist iterates the +list+ using +iter_method+. 330 | # It yields each object to the block given for #seplist. 331 | # The procedure +separator_proc+ is called between each yields. 332 | # 333 | # If the iteration is zero times, +separator_proc+ is not called at all. 334 | # 335 | # If +separator_proc+ is nil or not given, 336 | # +lambda { comma_breakable }+ is used. 337 | # If +iter_method+ is not given, :each is used. 338 | # 339 | # For example, following 3 code fragments has similar effect. 340 | # 341 | # q.seplist([1,2,3]) {|v| xxx v } 342 | # 343 | # q.seplist([1,2,3], lambda { q.comma_breakable }, :each) {|v| xxx v } 344 | # 345 | # xxx 1 346 | # q.comma_breakable 347 | # xxx 2 348 | # q.comma_breakable 349 | # xxx 3 350 | # 351 | # source://prettier_print//lib/prettier_print.rb#760 352 | def seplist(list, sep = T.unsafe(nil), iter_method = T.unsafe(nil)); end 353 | 354 | # The current array of contents that calls to methods that generate print tree 355 | # nodes will append to. 356 | # 357 | # source://prettier_print//lib/prettier_print.rb#423 358 | def target; end 359 | 360 | # This adds +object+ as a text of +width+ columns in width. 361 | # 362 | # If +width+ is not specified, object.length is used. 363 | # 364 | # source://prettier_print//lib/prettier_print.rb#989 365 | def text(object = T.unsafe(nil), width = T.unsafe(nil)); end 366 | 367 | # This inserts a Trim node into the print tree which, when printed, will clear 368 | # all whitespace at the end of the output buffer. This is useful for the rare 369 | # case where you need to delete printed indentation and force the next node 370 | # to start at the beginning of the line. 371 | # 372 | # source://prettier_print//lib/prettier_print.rb#828 373 | def trim; end 374 | 375 | # A convenience method used by a lot of the print tree node builders that 376 | # temporarily changes the target that the builders will append to. 377 | # 378 | # source://prettier_print//lib/prettier_print.rb#1007 379 | def with_target(target); end 380 | 381 | private 382 | 383 | # This method returns a boolean as to whether or not the remaining commands 384 | # fit onto the remaining space on the current line. If we finish printing 385 | # all of the commands or if we hit a newline, then we return true. Otherwise 386 | # if we continue printing past the remaining space, we return false. 387 | # 388 | # @return [Boolean] 389 | # 390 | # source://prettier_print//lib/prettier_print.rb#1019 391 | def fits?(next_commands, rest_commands, remaining); end 392 | 393 | # source://prettier_print//lib/prettier_print.rb#1091 394 | def remove_breaks_with(doc, replace); end 395 | 396 | # Resets the group stack and target array so that this pretty printer object 397 | # can continue to be used before calling flush again if desired. 398 | # 399 | # source://prettier_print//lib/prettier_print.rb#1085 400 | def reset; end 401 | 402 | class << self 403 | # This is a convenience method which is same as follows: 404 | # 405 | # begin 406 | # q = PrettierPrint.new(output, maxwidth, newline, &genspace) 407 | # ... 408 | # q.flush 409 | # output 410 | # end 411 | # 412 | # @yield [q] 413 | # 414 | # source://prettier_print//lib/prettier_print.rb#377 415 | def format(output = T.unsafe(nil), maxwidth = T.unsafe(nil), newline = T.unsafe(nil), genspace = T.unsafe(nil), indentation = T.unsafe(nil)); end 416 | 417 | # This is similar to PrettierPrint::format but the result has no breaks. 418 | # 419 | # +maxwidth+, +newline+ and +genspace+ are ignored. 420 | # 421 | # The invocation of +breakable+ in the block doesn't break a line and is 422 | # treated as just an invocation of +text+. 423 | # 424 | # @yield [q] 425 | # 426 | # source://prettier_print//lib/prettier_print/single_line.rb#156 427 | def singleline_format(output = T.unsafe(nil), _maxwidth = T.unsafe(nil), _newline = T.unsafe(nil), _genspace = T.unsafe(nil)); end 428 | end 429 | end 430 | 431 | # A node in the print tree that represents aligning nested nodes to a certain 432 | # prefix width or string. 433 | # 434 | # source://prettier_print//lib/prettier_print.rb#65 435 | class PrettierPrint::Align 436 | # @return [Align] a new instance of Align 437 | # 438 | # source://prettier_print//lib/prettier_print.rb#68 439 | def initialize(indent:, contents: T.unsafe(nil)); end 440 | 441 | # Returns the value of attribute contents. 442 | # 443 | # source://prettier_print//lib/prettier_print.rb#66 444 | def contents; end 445 | 446 | # Returns the value of attribute indent. 447 | # 448 | # source://prettier_print//lib/prettier_print.rb#66 449 | def indent; end 450 | 451 | # source://prettier_print//lib/prettier_print.rb#73 452 | def pretty_print(q); end 453 | end 454 | 455 | # source://prettier_print//lib/prettier_print.rb#126 456 | PrettierPrint::BREAKABLE_EMPTY = T.let(T.unsafe(nil), PrettierPrint::Breakable) 457 | 458 | # source://prettier_print//lib/prettier_print.rb#127 459 | PrettierPrint::BREAKABLE_FORCE = T.let(T.unsafe(nil), PrettierPrint::Breakable) 460 | 461 | # source://prettier_print//lib/prettier_print.rb#128 462 | PrettierPrint::BREAKABLE_RETURN = T.let(T.unsafe(nil), PrettierPrint::Breakable) 463 | 464 | # Below here are the most common combination of options that are created when 465 | # creating new breakables. They are here to cut down on some allocations. 466 | # 467 | # source://prettier_print//lib/prettier_print.rb#125 468 | PrettierPrint::BREAKABLE_SPACE = T.let(T.unsafe(nil), PrettierPrint::Breakable) 469 | 470 | # Since there's really no difference in these instances, just using the same 471 | # one saves on some allocations. 472 | # 473 | # source://prettier_print//lib/prettier_print.rb#141 474 | PrettierPrint::BREAK_PARENT = T.let(T.unsafe(nil), PrettierPrint::BreakParent) 475 | 476 | # A node in the print tree that forces the surrounding group to print out in 477 | # the "break" mode as opposed to the "flat" mode. Useful for when you need to 478 | # force a newline into a group. 479 | # 480 | # source://prettier_print//lib/prettier_print.rb#133 481 | class PrettierPrint::BreakParent 482 | # source://prettier_print//lib/prettier_print.rb#134 483 | def pretty_print(q); end 484 | end 485 | 486 | # A node in the print tree that represents a place in the buffer that the 487 | # content can be broken onto multiple lines. 488 | # 489 | # source://prettier_print//lib/prettier_print.rb#82 490 | class PrettierPrint::Breakable 491 | # @return [Breakable] a new instance of Breakable 492 | # 493 | # source://prettier_print//lib/prettier_print.rb#85 494 | def initialize(separator = T.unsafe(nil), width = T.unsafe(nil), force: T.unsafe(nil), indent: T.unsafe(nil)); end 495 | 496 | # @return [Boolean] 497 | # 498 | # source://prettier_print//lib/prettier_print.rb#97 499 | def force?; end 500 | 501 | # @return [Boolean] 502 | # 503 | # source://prettier_print//lib/prettier_print.rb#101 504 | def indent?; end 505 | 506 | # source://prettier_print//lib/prettier_print.rb#105 507 | def pretty_print(q); end 508 | 509 | # Returns the value of attribute separator. 510 | # 511 | # source://prettier_print//lib/prettier_print.rb#83 512 | def separator; end 513 | 514 | # Returns the value of attribute width. 515 | # 516 | # source://prettier_print//lib/prettier_print.rb#83 517 | def width; end 518 | end 519 | 520 | # When building up the contents in the output buffer, it's convenient to be 521 | # able to trim trailing whitespace before newlines. If the output object is a 522 | # string or array or strings, then we can do this with some gsub calls. If 523 | # not, then this effectively just wraps the output object and forwards on 524 | # calls to <<. 525 | # 526 | # source://prettier_print//lib/prettier_print.rb#277 527 | module PrettierPrint::Buffer 528 | class << self 529 | # This is a switch for building the correct output buffer wrapper class for 530 | # the given output object. 531 | # 532 | # source://prettier_print//lib/prettier_print.rb#336 533 | def for(output); end 534 | end 535 | end 536 | 537 | # This is an output buffer that wraps an array output object. It provides a 538 | # trim! method that trims off trailing whitespace from the last element in 539 | # the array if it's an unfrozen string using the same method as the 540 | # StringBuffer. 541 | # 542 | # source://prettier_print//lib/prettier_print.rb#303 543 | class PrettierPrint::Buffer::ArrayBuffer 544 | # @return [ArrayBuffer] a new instance of ArrayBuffer 545 | # 546 | # source://prettier_print//lib/prettier_print.rb#306 547 | def initialize(output = T.unsafe(nil)); end 548 | 549 | # source://prettier_print//lib/prettier_print.rb#310 550 | def <<(object); end 551 | 552 | # Returns the value of attribute output. 553 | # 554 | # source://prettier_print//lib/prettier_print.rb#304 555 | def output; end 556 | 557 | # source://prettier_print//lib/prettier_print.rb#314 558 | def trim!; end 559 | end 560 | 561 | # This is an output buffer that wraps a string output object. It provides a 562 | # trim! method that trims off trailing whitespace from the string using 563 | # gsub!. 564 | # 565 | # source://prettier_print//lib/prettier_print.rb#281 566 | class PrettierPrint::Buffer::StringBuffer 567 | # @return [StringBuffer] a new instance of StringBuffer 568 | # 569 | # source://prettier_print//lib/prettier_print.rb#284 570 | def initialize(output = T.unsafe(nil)); end 571 | 572 | # source://prettier_print//lib/prettier_print.rb#288 573 | def <<(object); end 574 | 575 | # Returns the value of attribute output. 576 | # 577 | # source://prettier_print//lib/prettier_print.rb#282 578 | def output; end 579 | 580 | # source://prettier_print//lib/prettier_print.rb#292 581 | def trim!; end 582 | end 583 | 584 | # When generating spaces after a newline for indentation, by default we 585 | # generate one space per character needed for indentation. You can change this 586 | # behavior (for instance to use tabs) by passing a different genspace 587 | # procedure. 588 | # 589 | # source://prettier_print//lib/prettier_print.rb#350 590 | PrettierPrint::DEFAULT_GENSPACE = T.let(T.unsafe(nil), Proc) 591 | 592 | # The default indentation for printing is zero, assuming that the code starts 593 | # at the top level. That can be changed if desired to start from a different 594 | # indentation level. 595 | # 596 | # source://prettier_print//lib/prettier_print.rb#366 597 | PrettierPrint::DEFAULT_INDENTATION = T.let(T.unsafe(nil), Integer) 598 | 599 | # When printing, you can optionally specify the value that should be used 600 | # whenever a group needs to be broken onto multiple lines. In this case the 601 | # default is \n. 602 | # 603 | # source://prettier_print//lib/prettier_print.rb#344 604 | PrettierPrint::DEFAULT_NEWLINE = T.let(T.unsafe(nil), String) 605 | 606 | # A node in the print tree that represents a group of items which the printer 607 | # should try to fit onto one line. This is the basic command to tell the 608 | # printer when to break. Groups are usually nested, and the printer will try 609 | # to fit everything on one line, but if it doesn't fit it will break the 610 | # outermost group first and try again. It will continue breaking groups until 611 | # everything fits (or there are no more groups to break). 612 | # 613 | # source://prettier_print//lib/prettier_print.rb#149 614 | class PrettierPrint::Group 615 | # @return [Group] a new instance of Group 616 | # 617 | # source://prettier_print//lib/prettier_print.rb#152 618 | def initialize(depth, contents: T.unsafe(nil)); end 619 | 620 | # source://prettier_print//lib/prettier_print.rb#158 621 | def break; end 622 | 623 | # @return [Boolean] 624 | # 625 | # source://prettier_print//lib/prettier_print.rb#162 626 | def break?; end 627 | 628 | # Returns the value of attribute contents. 629 | # 630 | # source://prettier_print//lib/prettier_print.rb#150 631 | def contents; end 632 | 633 | # Returns the value of attribute depth. 634 | # 635 | # source://prettier_print//lib/prettier_print.rb#150 636 | def depth; end 637 | 638 | # source://prettier_print//lib/prettier_print.rb#166 639 | def pretty_print(q); end 640 | end 641 | 642 | # A node in the print tree that represents printing one thing if the 643 | # surrounding group node is broken and another thing if the surrounding group 644 | # node is flat. 645 | # 646 | # source://prettier_print//lib/prettier_print.rb#176 647 | class PrettierPrint::IfBreak 648 | # @return [IfBreak] a new instance of IfBreak 649 | # 650 | # source://prettier_print//lib/prettier_print.rb#179 651 | def initialize(break_contents: T.unsafe(nil), flat_contents: T.unsafe(nil)); end 652 | 653 | # Returns the value of attribute break_contents. 654 | # 655 | # source://prettier_print//lib/prettier_print.rb#177 656 | def break_contents; end 657 | 658 | # Returns the value of attribute flat_contents. 659 | # 660 | # source://prettier_print//lib/prettier_print.rb#177 661 | def flat_contents; end 662 | 663 | # source://prettier_print//lib/prettier_print.rb#184 664 | def pretty_print(q); end 665 | end 666 | 667 | # A small DSL-like object used for specifying the alternative contents to be 668 | # printed if the surrounding group doesn't break for an IfBreak node. 669 | # 670 | # source://prettier_print//lib/prettier_print.rb#874 671 | class PrettierPrint::IfBreakBuilder 672 | # @return [IfBreakBuilder] a new instance of IfBreakBuilder 673 | # 674 | # source://prettier_print//lib/prettier_print.rb#877 675 | def initialize(q, flat_contents); end 676 | 677 | # Returns the value of attribute flat_contents. 678 | # 679 | # source://prettier_print//lib/prettier_print.rb#875 680 | def flat_contents; end 681 | 682 | # source://prettier_print//lib/prettier_print.rb#882 683 | def if_flat; end 684 | 685 | # Returns the value of attribute q. 686 | # 687 | # source://prettier_print//lib/prettier_print.rb#875 688 | def q; end 689 | end 690 | 691 | # When we already know that groups are broken, we don't actually need to track 692 | # the flat versions of the contents. So this builder version is effectively a 693 | # no-op, but we need it to maintain the same API. The only thing this can 694 | # impact is that if there's a forced break in the flat contents, then we need 695 | # to propagate that break up the whole tree. 696 | # 697 | # source://prettier_print//lib/prettier_print.rb#892 698 | class PrettierPrint::IfFlatIgnore 699 | # @return [IfFlatIgnore] a new instance of IfFlatIgnore 700 | # 701 | # source://prettier_print//lib/prettier_print.rb#895 702 | def initialize(q); end 703 | 704 | # source://prettier_print//lib/prettier_print.rb#899 705 | def if_flat; end 706 | 707 | # Returns the value of attribute q. 708 | # 709 | # source://prettier_print//lib/prettier_print.rb#893 710 | def q; end 711 | end 712 | 713 | # A node in the print tree that is a variant of the Align node that indents 714 | # its contents by one level. 715 | # 716 | # source://prettier_print//lib/prettier_print.rb#200 717 | class PrettierPrint::Indent 718 | # @return [Indent] a new instance of Indent 719 | # 720 | # source://prettier_print//lib/prettier_print.rb#203 721 | def initialize(contents: T.unsafe(nil)); end 722 | 723 | # Returns the value of attribute contents. 724 | # 725 | # source://prettier_print//lib/prettier_print.rb#201 726 | def contents; end 727 | 728 | # source://prettier_print//lib/prettier_print.rb#207 729 | def pretty_print(q); end 730 | end 731 | 732 | # A node in the print tree that has its own special buffer for implementing 733 | # content that should flush before any newline. 734 | # 735 | # Useful for implementating trailing content, as it's not always practical to 736 | # constantly check where the line ends to avoid accidentally printing some 737 | # content after a line suffix node. 738 | # 739 | # source://prettier_print//lib/prettier_print.rb#220 740 | class PrettierPrint::LineSuffix 741 | # @return [LineSuffix] a new instance of LineSuffix 742 | # 743 | # source://prettier_print//lib/prettier_print.rb#225 744 | def initialize(priority: T.unsafe(nil), contents: T.unsafe(nil)); end 745 | 746 | # Returns the value of attribute contents. 747 | # 748 | # source://prettier_print//lib/prettier_print.rb#223 749 | def contents; end 750 | 751 | # source://prettier_print//lib/prettier_print.rb#230 752 | def pretty_print(q); end 753 | 754 | # Returns the value of attribute priority. 755 | # 756 | # source://prettier_print//lib/prettier_print.rb#223 757 | def priority; end 758 | end 759 | 760 | # source://prettier_print//lib/prettier_print.rb#221 761 | PrettierPrint::LineSuffix::DEFAULT_PRIORITY = T.let(T.unsafe(nil), Integer) 762 | 763 | # There are two modes in printing, break and flat. When we're in break mode, 764 | # any lines will use their newline, any if-breaks will use their break 765 | # contents, etc. 766 | # 767 | # source://prettier_print//lib/prettier_print.rb#356 768 | PrettierPrint::MODE_BREAK = T.let(T.unsafe(nil), Integer) 769 | 770 | # This is another print mode much like MODE_BREAK. When we're in flat mode, we 771 | # attempt to print everything on one line until we either hit a broken group, 772 | # a forced line, or the maximum width. 773 | # 774 | # source://prettier_print//lib/prettier_print.rb#361 775 | PrettierPrint::MODE_FLAT = T.let(T.unsafe(nil), Integer) 776 | 777 | # PrettierPrint::SingleLine is used by PrettierPrint.singleline_format 778 | # 779 | # It is passed to be similar to a PrettierPrint object itself, by responding to 780 | # all of the same print tree node builder methods, as well as the #flush 781 | # method. 782 | # 783 | # The significant difference here is that there are no line breaks in the 784 | # output. If an IfBreak node is used, only the flat contents are printed. 785 | # LineSuffix nodes are printed at the end of the buffer when #flush is called. 786 | # 787 | # source://prettier_print//lib/prettier_print/single_line.rb#13 788 | class PrettierPrint::SingleLine 789 | # Create a PrettierPrint::SingleLine object 790 | # 791 | # Arguments: 792 | # * +output+ - String (or similar) to store rendered text. Needs to respond 793 | # to '<<'. 794 | # * +maxwidth+ - Argument position expected to be here for compatibility. 795 | # This argument is a noop. 796 | # * +newline+ - Argument position expected to be here for compatibility. 797 | # This argument is a noop. 798 | # 799 | # @return [SingleLine] a new instance of SingleLine 800 | # 801 | # source://prettier_print//lib/prettier_print/single_line.rb#34 802 | def initialize(output, _maxwidth = T.unsafe(nil), _newline = T.unsafe(nil)); end 803 | 804 | # Here for compatibility, does nothing. 805 | # 806 | # source://prettier_print//lib/prettier_print/single_line.rb#64 807 | def break_parent; end 808 | 809 | # Appends +separator+ to the text to be output. By default +separator+ is 810 | # ' ' 811 | # 812 | # The +width+, +indent+, and +force+ arguments are here for compatibility. 813 | # They are all noop arguments. 814 | # 815 | # source://prettier_print//lib/prettier_print/single_line.rb#54 816 | def breakable(separator = T.unsafe(nil), _width = T.unsafe(nil), indent: T.unsafe(nil), force: T.unsafe(nil)); end 817 | 818 | # Appends +separator+ to the output buffer. +width+ is a noop here for 819 | # compatibility. 820 | # 821 | # source://prettier_print//lib/prettier_print/single_line.rb#69 822 | def fill_breakable(separator = T.unsafe(nil), _width = T.unsafe(nil)); end 823 | 824 | # Flushes the line suffixes onto the output buffer. 825 | # 826 | # source://prettier_print//lib/prettier_print/single_line.rb#41 827 | def flush; end 828 | 829 | # Opens a block for grouping objects to be pretty printed. 830 | # 831 | # Arguments: 832 | # * +indent+ - noop argument. Present for compatibility. 833 | # * +open_obj+ - text appended before the &block. Default is '' 834 | # * +close_obj+ - text appended after the &block. Default is '' 835 | # * +open_width+ - noop argument. Present for compatibility. 836 | # * +close_width+ - noop argument. Present for compatibility. 837 | # 838 | # source://prettier_print//lib/prettier_print/single_line.rb#90 839 | def group(_indent = T.unsafe(nil), open_object = T.unsafe(nil), close_object = T.unsafe(nil), _open_width = T.unsafe(nil), _close_width = T.unsafe(nil)); end 840 | 841 | # Effectively unnecessary, but here for compatibility. 842 | # 843 | # source://prettier_print//lib/prettier_print/single_line.rb#113 844 | def if_break; end 845 | 846 | # Also effectively unnecessary, but here for compatibility. 847 | # 848 | # source://prettier_print//lib/prettier_print/single_line.rb#118 849 | def if_flat; end 850 | 851 | # A noop that immediately yields. 852 | # 853 | # source://prettier_print//lib/prettier_print/single_line.rb#122 854 | def indent; end 855 | 856 | # Changes the target output buffer to the line suffix output buffer which 857 | # will get flushed at the end of printing. 858 | # 859 | # source://prettier_print//lib/prettier_print/single_line.rb#128 860 | def line_suffix; end 861 | 862 | # A buffer output that wraps any calls to line_suffix that will be flushed 863 | # at the end of printing. 864 | # 865 | # source://prettier_print//lib/prettier_print/single_line.rb#23 866 | def line_suffixes; end 867 | 868 | # Takes +indent+ arg, but does nothing with it. 869 | # 870 | # Yields to a block. 871 | # 872 | # source://prettier_print//lib/prettier_print/single_line.rb#137 873 | def nest(_indent); end 874 | 875 | # The output object. It stores rendered text and should respond to <<. 876 | # 877 | # source://prettier_print//lib/prettier_print/single_line.rb#15 878 | def output; end 879 | 880 | # The current array of contents that the print tree builder methods should 881 | # append to. 882 | # 883 | # source://prettier_print//lib/prettier_print/single_line.rb#19 884 | def target; end 885 | 886 | # Add +object+ to the text to be output. 887 | # 888 | # +width+ argument is here for compatibility. It is a noop argument. 889 | # 890 | # source://prettier_print//lib/prettier_print/single_line.rb#144 891 | def text(object = T.unsafe(nil), _width = T.unsafe(nil)); end 892 | 893 | # Immediately trims the output buffer. 894 | # 895 | # source://prettier_print//lib/prettier_print/single_line.rb#74 896 | def trim; end 897 | end 898 | 899 | # A class that wraps the ability to call #if_flat. The contents of the 900 | # #if_flat block are executed immediately, so effectively this class and the 901 | # #if_break method that triggers it are unnecessary, but they're here to 902 | # maintain compatibility. 903 | # 904 | # source://prettier_print//lib/prettier_print/single_line.rb#106 905 | class PrettierPrint::SingleLine::IfBreakBuilder 906 | # source://prettier_print//lib/prettier_print/single_line.rb#107 907 | def if_flat; end 908 | end 909 | 910 | # Since all of the instances here are the same, we can reuse the same one to 911 | # cut down on allocations. 912 | # 913 | # source://prettier_print//lib/prettier_print.rb#270 914 | PrettierPrint::TRIM = T.let(T.unsafe(nil), PrettierPrint::Trim) 915 | 916 | # A node in the print tree that represents plain content that cannot be broken 917 | # up (by default this assumes strings, but it can really be anything). 918 | # 919 | # source://prettier_print//lib/prettier_print.rb#239 920 | class PrettierPrint::Text 921 | # @return [Text] a new instance of Text 922 | # 923 | # source://prettier_print//lib/prettier_print.rb#242 924 | def initialize; end 925 | 926 | # source://prettier_print//lib/prettier_print.rb#247 927 | def add(object: T.unsafe(nil), width: T.unsafe(nil)); end 928 | 929 | # Returns the value of attribute objects. 930 | # 931 | # source://prettier_print//lib/prettier_print.rb#240 932 | def objects; end 933 | 934 | # source://prettier_print//lib/prettier_print.rb#252 935 | def pretty_print(q); end 936 | 937 | # Returns the value of attribute width. 938 | # 939 | # source://prettier_print//lib/prettier_print.rb#240 940 | def width; end 941 | end 942 | 943 | # A node in the print tree that represents trimming all of the indentation of 944 | # the current line, in the rare case that you need to ignore the indentation 945 | # that you've already created. This node should be placed after a Breakable. 946 | # 947 | # source://prettier_print//lib/prettier_print.rb#262 948 | class PrettierPrint::Trim 949 | # source://prettier_print//lib/prettier_print.rb#263 950 | def pretty_print(q); end 951 | end 952 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/ruby-rc4@0.1.5.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `ruby-rc4` gem. 5 | # Please instead update this file by running `bin/tapioca gem ruby-rc4`. 6 | 7 | # source://ruby-rc4//lib/rc4.rb#1 8 | class RC4 9 | # @return [RC4] a new instance of RC4 10 | # 11 | # source://ruby-rc4//lib/rc4.rb#3 12 | def initialize(str); end 13 | 14 | # source://ruby-rc4//lib/rc4.rb#24 15 | def decrypt(text); end 16 | 17 | # source://ruby-rc4//lib/rc4.rb#24 18 | def encrypt(text); end 19 | 20 | # source://ruby-rc4//lib/rc4.rb#20 21 | def encrypt!(text); end 22 | 23 | private 24 | 25 | # source://ruby-rc4//lib/rc4.rb#32 26 | def process(text); end 27 | 28 | # source://ruby-rc4//lib/rc4.rb#36 29 | def round; end 30 | end 31 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/simplecov-html@0.12.3.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `simplecov-html` gem. 5 | # Please instead update this file by running `bin/tapioca gem simplecov-html`. 6 | 7 | # source://simplecov-html//lib/simplecov-html.rb#16 8 | module SimpleCov 9 | class << self 10 | # source://simplecov/0.22.0/lib/simplecov.rb#174 11 | def at_exit_behavior; end 12 | 13 | # source://simplecov/0.22.0/lib/simplecov.rb#170 14 | def clear_result; end 15 | 16 | # source://simplecov/0.22.0/lib/simplecov.rb#86 17 | def collate(result_filenames, profile = T.unsafe(nil), ignore_timeout: T.unsafe(nil), &block); end 18 | 19 | # source://simplecov/0.22.0/lib/simplecov.rb#223 20 | def exit_and_report_previous_error(exit_status); end 21 | 22 | # source://simplecov/0.22.0/lib/simplecov.rb#200 23 | def exit_status_from_exception; end 24 | 25 | # source://simplecov/0.22.0/lib/simplecov.rb#28 26 | def external_at_exit; end 27 | 28 | # source://simplecov/0.22.0/lib/simplecov.rb#28 29 | def external_at_exit=(_arg0); end 30 | 31 | # source://simplecov/0.22.0/lib/simplecov.rb#28 32 | def external_at_exit?; end 33 | 34 | # source://simplecov/0.22.0/lib/simplecov.rb#131 35 | def filtered(files); end 36 | 37 | # source://simplecov/0.22.0/lib/simplecov.rb#268 38 | def final_result_process?; end 39 | 40 | # source://simplecov/0.22.0/lib/simplecov.rb#142 41 | def grouped(files); end 42 | 43 | # source://simplecov/0.22.0/lib/simplecov.rb#162 44 | def load_adapter(name); end 45 | 46 | # source://simplecov/0.22.0/lib/simplecov.rb#158 47 | def load_profile(name); end 48 | 49 | # source://simplecov/0.22.0/lib/simplecov.rb#24 50 | def pid; end 51 | 52 | # source://simplecov/0.22.0/lib/simplecov.rb#24 53 | def pid=(_arg0); end 54 | 55 | # source://simplecov/0.22.0/lib/simplecov.rb#213 56 | def previous_error?(error_exit_status); end 57 | 58 | # source://simplecov/0.22.0/lib/simplecov.rb#248 59 | def process_result(result); end 60 | 61 | # source://simplecov/0.22.0/lib/simplecov.rb#233 62 | def process_results_and_report_error; end 63 | 64 | # source://simplecov/0.22.0/lib/simplecov.rb#229 65 | def ready_to_process_results?; end 66 | 67 | # source://simplecov/0.22.0/lib/simplecov.rb#101 68 | def result; end 69 | 70 | # source://simplecov/0.22.0/lib/simplecov.rb#124 71 | def result?; end 72 | 73 | # source://simplecov/0.22.0/lib/simplecov.rb#256 74 | def result_exit_status(result); end 75 | 76 | # source://simplecov/0.22.0/lib/simplecov.rb#296 77 | def round_coverage(coverage); end 78 | 79 | # source://simplecov/0.22.0/lib/simplecov.rb#186 80 | def run_exit_tasks!; end 81 | 82 | # source://simplecov/0.22.0/lib/simplecov.rb#24 83 | def running; end 84 | 85 | # source://simplecov/0.22.0/lib/simplecov.rb#24 86 | def running=(_arg0); end 87 | 88 | # source://simplecov/0.22.0/lib/simplecov.rb#48 89 | def start(profile = T.unsafe(nil), &block); end 90 | 91 | # source://simplecov/0.22.0/lib/simplecov.rb#276 92 | def wait_for_other_processes; end 93 | 94 | # source://simplecov/0.22.0/lib/simplecov.rb#285 95 | def write_last_run(result); end 96 | 97 | private 98 | 99 | # source://simplecov/0.22.0/lib/simplecov.rb#399 100 | def adapt_coverage_result; end 101 | 102 | # source://simplecov/0.22.0/lib/simplecov.rb#371 103 | def add_not_loaded_files(result); end 104 | 105 | # source://simplecov/0.22.0/lib/simplecov.rb#302 106 | def initial_setup(profile, &block); end 107 | 108 | # source://simplecov/0.22.0/lib/simplecov.rb#363 109 | def lookup_corresponding_ruby_coverage_name(criterion); end 110 | 111 | # source://simplecov/0.22.0/lib/simplecov.rb#425 112 | def make_parallel_tests_available; end 113 | 114 | # source://simplecov/0.22.0/lib/simplecov.rb#434 115 | def probably_running_parallel_tests?; end 116 | 117 | # source://simplecov/0.22.0/lib/simplecov.rb#388 118 | def process_coverage_result; end 119 | 120 | # source://simplecov/0.22.0/lib/simplecov.rb#410 121 | def remove_useless_results; end 122 | 123 | # source://simplecov/0.22.0/lib/simplecov.rb#420 124 | def result_with_not_loaded_files; end 125 | 126 | # source://simplecov/0.22.0/lib/simplecov.rb#314 127 | def start_coverage_measurement; end 128 | 129 | # source://simplecov/0.22.0/lib/simplecov.rb#349 130 | def start_coverage_with_criteria; end 131 | end 132 | end 133 | 134 | # source://simplecov-html//lib/simplecov-html.rb#17 135 | module SimpleCov::Formatter 136 | class << self 137 | # source://simplecov/0.22.0/lib/simplecov/default_formatter.rb#7 138 | def from_env(env); end 139 | end 140 | end 141 | 142 | # source://simplecov-html//lib/simplecov-html.rb#18 143 | class SimpleCov::Formatter::HTMLFormatter 144 | # @return [HTMLFormatter] a new instance of HTMLFormatter 145 | # 146 | # source://simplecov-html//lib/simplecov-html.rb#19 147 | def initialize; end 148 | 149 | # @return [Boolean] 150 | # 151 | # source://simplecov-html//lib/simplecov-html.rb#38 152 | def branchable_result?; end 153 | 154 | # source://simplecov-html//lib/simplecov-html.rb#23 155 | def format(result); end 156 | 157 | # @return [Boolean] 158 | # 159 | # source://simplecov-html//lib/simplecov-html.rb#45 160 | def line_status?(source_file, line); end 161 | 162 | # source://simplecov-html//lib/simplecov-html.rb#34 163 | def output_message(result); end 164 | 165 | private 166 | 167 | # source://simplecov-html//lib/simplecov-html.rb#64 168 | def asset_output_path; end 169 | 170 | # source://simplecov-html//lib/simplecov-html.rb#72 171 | def assets_path(name); end 172 | 173 | # source://simplecov-html//lib/simplecov-html.rb#97 174 | def coverage_css_class(covered_percent); end 175 | 176 | # source://simplecov-html//lib/simplecov-html.rb#93 177 | def covered_percent(percent); end 178 | 179 | # Returns a table containing the given source files 180 | # 181 | # source://simplecov-html//lib/simplecov-html.rb#84 182 | def formatted_file_list(title, source_files); end 183 | 184 | # Returns the html for the given source_file 185 | # 186 | # source://simplecov-html//lib/simplecov-html.rb#77 187 | def formatted_source_file(source_file); end 188 | 189 | # Return a (kind of) unique id for the source file given. Uses SHA1 on path for the id 190 | # 191 | # source://simplecov-html//lib/simplecov-html.rb#118 192 | def id(source_file); end 193 | 194 | # source://simplecov-html//lib/simplecov-html.rb#130 195 | def link_to_source_file(source_file); end 196 | 197 | # source://simplecov-html//lib/simplecov-html.rb#60 198 | def output_path; end 199 | 200 | # source://simplecov-html//lib/simplecov-html.rb#126 201 | def shortened_filename(source_file); end 202 | 203 | # source://simplecov-html//lib/simplecov-html.rb#107 204 | def strength_css_class(covered_strength); end 205 | 206 | # Returns the an erb instance for the template of given name 207 | # 208 | # source://simplecov-html//lib/simplecov-html.rb#56 209 | def template(name); end 210 | 211 | # source://simplecov-html//lib/simplecov-html.rb#122 212 | def timeago(time); end 213 | end 214 | 215 | # source://simplecov-html//lib/simplecov-html/version.rb#6 216 | SimpleCov::Formatter::HTMLFormatter::VERSION = T.let(T.unsafe(nil), String) 217 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/simplecov_json_formatter@0.1.4.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `simplecov_json_formatter` gem. 5 | # Please instead update this file by running `bin/tapioca gem simplecov_json_formatter`. 6 | 7 | # THIS IS AN EMPTY RBI FILE. 8 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem 9 | -------------------------------------------------------------------------------- /sorbet/rbi/gems/yard-sorbet@0.8.1.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | # DO NOT EDIT MANUALLY 4 | # This is an autogenerated file for types exported from the `yard-sorbet` gem. 5 | # Please instead update this file by running `bin/tapioca gem yard-sorbet`. 6 | 7 | class YARD::Handlers::Ruby::ClassHandler < ::YARD::Handlers::Ruby::Base 8 | include ::YARDSorbet::Handlers::StructClassHandler 9 | end 10 | 11 | # Types are documentation 12 | # 13 | # source://yard-sorbet//lib/yard-sorbet/version.rb#5 14 | module YARDSorbet; end 15 | 16 | # Extract & re-add directives to a docstring 17 | # 18 | # source://yard-sorbet//lib/yard-sorbet/directives.rb#6 19 | module YARDSorbet::Directives 20 | class << self 21 | # source://yard-sorbet//lib/yard-sorbet/directives.rb#21 22 | sig { params(docstring: ::String, directives: T::Array[::String]).void } 23 | def add_directives(docstring, directives); end 24 | 25 | # source://yard-sorbet//lib/yard-sorbet/directives.rb#10 26 | sig { params(docstring: T.nilable(::String)).returns([::YARD::Docstring, T::Array[::String]]) } 27 | def extract_directives(docstring); end 28 | end 29 | end 30 | 31 | # Custom YARD Handlers 32 | # 33 | # @see https://rubydoc.info/gems/yard/YARD/Handlers/Base YARD Base Handler documentation 34 | # 35 | # source://yard-sorbet//lib/yard-sorbet/handlers.rb#7 36 | module YARDSorbet::Handlers; end 37 | 38 | # Apllies an `@abstract` tag to `abstract!`/`interface!` modules (if not alerady present). 39 | # 40 | # source://yard-sorbet//lib/yard-sorbet/handlers/abstract_dsl_handler.rb#7 41 | class YARDSorbet::Handlers::AbstractDSLHandler < ::YARD::Handlers::Ruby::Base 42 | # source://yard-sorbet//lib/yard-sorbet/handlers/abstract_dsl_handler.rb#21 43 | sig { void } 44 | def process; end 45 | end 46 | 47 | # Extra text for class namespaces 48 | # 49 | # source://yard-sorbet//lib/yard-sorbet/handlers/abstract_dsl_handler.rb#18 50 | YARDSorbet::Handlers::AbstractDSLHandler::CLASS_TAG_TEXT = T.let(T.unsafe(nil), String) 51 | 52 | # The text accompanying the `@abstract` tag. 53 | # 54 | # @see https://github.com/lsegal/yard/blob/main/templates/default/docstring/html/abstract.erb The `@abstract` tag template 55 | # 56 | # source://yard-sorbet//lib/yard-sorbet/handlers/abstract_dsl_handler.rb#16 57 | YARDSorbet::Handlers::AbstractDSLHandler::TAG_TEXT = T.let(T.unsafe(nil), String) 58 | 59 | # Handle `enums` calls, registering enum values as constants 60 | # 61 | # source://yard-sorbet//lib/yard-sorbet/handlers/enums_handler.rb#7 62 | class YARDSorbet::Handlers::EnumsHandler < ::YARD::Handlers::Ruby::Base 63 | # source://yard-sorbet//lib/yard-sorbet/handlers/enums_handler.rb#14 64 | sig { void } 65 | def process; end 66 | 67 | private 68 | 69 | # source://yard-sorbet//lib/yard-sorbet/handlers/enums_handler.rb#29 70 | sig { params(node: ::YARD::Parser::Ruby::AstNode).returns(T::Boolean) } 71 | def const_assign_node?(node); end 72 | end 73 | 74 | # Extends any modules included via `mixes_in_class_methods` 75 | # 76 | # @see https://sorbet.org/docs/abstract#interfaces-and-the-included-hook Sorbet `mixes_in_class_methods` documentation 77 | # 78 | # source://yard-sorbet//lib/yard-sorbet/handlers/include_handler.rb#9 79 | class YARDSorbet::Handlers::IncludeHandler < ::YARD::Handlers::Ruby::Base 80 | # source://yard-sorbet//lib/yard-sorbet/handlers/include_handler.rb#16 81 | sig { void } 82 | def process; end 83 | 84 | private 85 | 86 | # source://yard-sorbet//lib/yard-sorbet/handlers/include_handler.rb#28 87 | sig { returns(::YARD::CodeObjects::NamespaceObject) } 88 | def included_in; end 89 | end 90 | 91 | # Tracks modules that invoke `mixes_in_class_methods` for use in {IncludeHandler} 92 | # 93 | # @see https://sorbet.org/docs/abstract#interfaces-and-the-included-hook Sorbet `mixes_in_class_methods` documentation 94 | # 95 | # source://yard-sorbet//lib/yard-sorbet/handlers/mixes_in_class_methods_handler.rb#9 96 | class YARDSorbet::Handlers::MixesInClassMethodsHandler < ::YARD::Handlers::Ruby::Base 97 | # source://yard-sorbet//lib/yard-sorbet/handlers/mixes_in_class_methods_handler.rb#23 98 | sig { void } 99 | def process; end 100 | 101 | class << self 102 | # source://yard-sorbet//lib/yard-sorbet/handlers/mixes_in_class_methods_handler.rb#18 103 | sig { params(code_obj: ::String).returns(T.nilable(T::Array[::String])) } 104 | def mixed_in_class_methods(code_obj); end 105 | end 106 | end 107 | 108 | # A YARD Handler for Sorbet type declarations 109 | # 110 | # source://yard-sorbet//lib/yard-sorbet/handlers/sig_handler.rb#7 111 | class YARDSorbet::Handlers::SigHandler < ::YARD::Handlers::Ruby::Base 112 | # Swap the method definition docstring and the sig docstring. 113 | # Parse relevant parts of the `sig` and include them as well. 114 | # 115 | # source://yard-sorbet//lib/yard-sorbet/handlers/sig_handler.rb#24 116 | sig { void } 117 | def process; end 118 | 119 | private 120 | 121 | # source://yard-sorbet//lib/yard-sorbet/handlers/sig_handler.rb#73 122 | sig { params(method_objects: T::Array[::YARD::CodeObjects::MethodObject]).void } 123 | def document_attr_methods(method_objects); end 124 | 125 | # An attr* sig can be merged into a previous attr* docstring if it is the only parameter passed to the attr* 126 | # declaration. This is to avoid needing to rewrite the source code to separate merged and unmerged attr* 127 | # declarations. 128 | # 129 | # source://yard-sorbet//lib/yard-sorbet/handlers/sig_handler.rb#60 130 | sig { params(attr_node: ::YARD::Parser::Ruby::MethodCallNode).returns(T::Boolean) } 131 | def merged_into_attr?(attr_node); end 132 | 133 | # source://yard-sorbet//lib/yard-sorbet/handlers/sig_handler.rb#78 134 | sig do 135 | params( 136 | attach_to: T.any(::YARD::CodeObjects::MethodObject, ::YARD::Parser::Ruby::MethodCallNode, ::YARD::Parser::Ruby::MethodDefinitionNode), 137 | docstring: T.nilable(::String), 138 | include_params: T::Boolean 139 | ).void 140 | end 141 | def parse_node(attach_to, docstring, include_params: T.unsafe(nil)); end 142 | 143 | # source://yard-sorbet//lib/yard-sorbet/handlers/sig_handler.rb#99 144 | sig { params(node: ::YARD::Parser::Ruby::AstNode, docstring: ::YARD::Docstring).void } 145 | def parse_params(node, docstring); end 146 | 147 | # source://yard-sorbet//lib/yard-sorbet/handlers/sig_handler.rb#109 148 | sig { params(node: ::YARD::Parser::Ruby::AstNode, docstring: ::YARD::Docstring).void } 149 | def parse_return(node, docstring); end 150 | 151 | # source://yard-sorbet//lib/yard-sorbet/handlers/sig_handler.rb#87 152 | sig { params(docstring: ::YARD::Docstring, include_params: T::Boolean).void } 153 | def parse_sig(docstring, include_params: T.unsafe(nil)); end 154 | 155 | # source://yard-sorbet//lib/yard-sorbet/handlers/sig_handler.rb#50 156 | sig { params(attr_node: ::YARD::Parser::Ruby::MethodCallNode).void } 157 | def process_attr(attr_node); end 158 | 159 | # source://yard-sorbet//lib/yard-sorbet/handlers/sig_handler.rb#36 160 | sig { params(def_node: ::YARD::Parser::Ruby::MethodDefinitionNode).void } 161 | def process_def(def_node); end 162 | end 163 | 164 | # YARD types that can have docstrings attached to them 165 | # 166 | # source://yard-sorbet//lib/yard-sorbet/handlers/sig_handler.rb#14 167 | YARDSorbet::Handlers::SigHandler::Documentable = T.type_alias { T.any(::YARD::CodeObjects::MethodObject, ::YARD::Parser::Ruby::MethodCallNode, ::YARD::Parser::Ruby::MethodDefinitionNode) } 168 | 169 | # Class-level handler that folds all `const` and `prop` declarations into the constructor documentation 170 | # this needs to be injected as a module otherwise the default Class handler will overwrite documentation 171 | # 172 | # @note this module is included in `YARD::Handlers::Ruby::ClassHandler` 173 | # 174 | # source://yard-sorbet//lib/yard-sorbet/handlers/struct_class_handler.rb#10 175 | module YARDSorbet::Handlers::StructClassHandler 176 | # source://yard-sorbet//lib/yard-sorbet/handlers/struct_class_handler.rb#14 177 | sig { void } 178 | def process; end 179 | 180 | private 181 | 182 | # source://yard-sorbet//lib/yard-sorbet/handlers/struct_class_handler.rb#50 183 | sig do 184 | params( 185 | object: ::YARD::CodeObjects::MethodObject, 186 | props: T::Array[::YARDSorbet::TStructProp], 187 | docstring: ::YARD::Docstring, 188 | directives: T::Array[::String] 189 | ).void 190 | end 191 | def decorate_t_struct_init(object, props, docstring, directives); end 192 | 193 | # Create a virtual `initialize` method with all the `prop`/`const` arguments 194 | # 195 | # source://yard-sorbet//lib/yard-sorbet/handlers/struct_class_handler.rb#30 196 | sig { params(props: T::Array[::YARDSorbet::TStructProp], class_ns: ::YARD::CodeObjects::ClassObject).void } 197 | def process_t_struct_props(props, class_ns); end 198 | 199 | # source://yard-sorbet//lib/yard-sorbet/handlers/struct_class_handler.rb#60 200 | sig { params(props: T::Array[::YARDSorbet::TStructProp]).returns(T::Array[[::String, T.nilable(::String)]]) } 201 | def to_object_parameters(props); end 202 | end 203 | 204 | # Handles all `const`/`prop` calls, creating accessor methods, and compiles them for later usage at the class level 205 | # in creating a constructor 206 | # 207 | # source://yard-sorbet//lib/yard-sorbet/handlers/struct_prop_handler.rb#8 208 | class YARDSorbet::Handlers::StructPropHandler < ::YARD::Handlers::Ruby::Base 209 | # source://yard-sorbet//lib/yard-sorbet/handlers/struct_prop_handler.rb#15 210 | sig { void } 211 | def process; end 212 | 213 | private 214 | 215 | # Add the source and docstring to the method object 216 | # 217 | # source://yard-sorbet//lib/yard-sorbet/handlers/struct_prop_handler.rb#28 218 | sig { params(object: ::YARD::CodeObjects::MethodObject, prop: ::YARDSorbet::TStructProp).void } 219 | def decorate_object(object, prop); end 220 | 221 | # source://yard-sorbet//lib/yard-sorbet/handlers/struct_prop_handler.rb#38 222 | sig { returns(T::Boolean) } 223 | def immutable?; end 224 | 225 | # source://yard-sorbet//lib/yard-sorbet/handlers/struct_prop_handler.rb#44 226 | sig { params(kwd: ::String).returns(T.nilable(::String)) } 227 | def kw_arg(kwd); end 228 | 229 | # source://yard-sorbet//lib/yard-sorbet/handlers/struct_prop_handler.rb#49 230 | sig { params(name: ::String).returns(::YARDSorbet::TStructProp) } 231 | def make_prop(name); end 232 | 233 | # source://yard-sorbet//lib/yard-sorbet/handlers/struct_prop_handler.rb#60 234 | sig { returns(T::Array[::YARD::Parser::Ruby::AstNode]) } 235 | def params; end 236 | 237 | # Register the field explicitly as an attribute. 238 | # 239 | # source://yard-sorbet//lib/yard-sorbet/handlers/struct_prop_handler.rb#66 240 | sig { params(object: ::YARD::CodeObjects::MethodObject, name: ::String).void } 241 | def register_attrs(object, name); end 242 | 243 | # Store the prop for use in the constructor definition 244 | # 245 | # source://yard-sorbet//lib/yard-sorbet/handlers/struct_prop_handler.rb#74 246 | sig { params(prop: ::YARDSorbet::TStructProp).void } 247 | def update_state(prop); end 248 | end 249 | 250 | # Helper methods for working with `YARD` AST Nodes 251 | # 252 | # source://yard-sorbet//lib/yard-sorbet/node_utils.rb#6 253 | module YARDSorbet::NodeUtils 254 | class << self 255 | # Traverse AST nodes in breadth-first order 256 | # 257 | # @note This will skip over some node types. 258 | # @yield [YARD::Parser::Ruby::AstNode] 259 | # 260 | # source://yard-sorbet//lib/yard-sorbet/node_utils.rb#21 261 | sig do 262 | params( 263 | node: ::YARD::Parser::Ruby::AstNode, 264 | _blk: T.proc.params(n: ::YARD::Parser::Ruby::AstNode).void 265 | ).void 266 | end 267 | def bfs_traverse(node, &_blk); end 268 | 269 | # source://yard-sorbet//lib/yard-sorbet/node_utils.rb#32 270 | sig { params(node: ::YARD::Parser::Ruby::AstNode).void } 271 | def delete_node(node); end 272 | 273 | # Gets the node that a sorbet `sig` can be attached do, bypassing visisbility modifiers and the like 274 | # 275 | # source://yard-sorbet//lib/yard-sorbet/node_utils.rb#38 276 | sig do 277 | params( 278 | node: ::YARD::Parser::Ruby::AstNode 279 | ).returns(T.any(::YARD::Parser::Ruby::MethodCallNode, ::YARD::Parser::Ruby::MethodDefinitionNode)) 280 | end 281 | def get_method_node(node); end 282 | 283 | # Find and return the adjacent node (ascending) 284 | # 285 | # @raise [IndexError] if the node does not have an adjacent sibling (ascending) 286 | # 287 | # source://yard-sorbet//lib/yard-sorbet/node_utils.rb#45 288 | sig { params(node: ::YARD::Parser::Ruby::AstNode).returns(::YARD::Parser::Ruby::AstNode) } 289 | def sibling_node(node); end 290 | 291 | # source://yard-sorbet//lib/yard-sorbet/node_utils.rb#52 292 | sig { params(node: ::YARD::Parser::Ruby::AstNode).returns(T::Boolean) } 293 | def sigable_node?(node); end 294 | 295 | # @see https://github.com/lsegal/yard/blob/main/lib/yard/handlers/ruby/attribute_handler.rb YARD::Handlers::Ruby::AttributeHandler.validated_attribute_names 296 | # 297 | # source://yard-sorbet//lib/yard-sorbet/node_utils.rb#63 298 | sig { params(attr_node: ::YARD::Parser::Ruby::MethodCallNode).returns(T::Array[::String]) } 299 | def validated_attribute_names(attr_node); end 300 | end 301 | end 302 | 303 | # Command node types that can have type signatures 304 | # 305 | # source://yard-sorbet//lib/yard-sorbet/node_utils.rb#10 306 | YARDSorbet::NodeUtils::ATTRIBUTE_METHODS = T.let(T.unsafe(nil), Array) 307 | 308 | # Skip these method contents during BFS node traversal, they can have their own nested types via `T.Proc` 309 | # 310 | # source://yard-sorbet//lib/yard-sorbet/node_utils.rb#12 311 | YARDSorbet::NodeUtils::SKIP_METHOD_CONTENTS = T.let(T.unsafe(nil), Array) 312 | 313 | # Node types that can have type signatures 314 | # 315 | # source://yard-sorbet//lib/yard-sorbet/node_utils.rb#14 316 | YARDSorbet::NodeUtils::SigableNode = T.type_alias { T.any(::YARD::Parser::Ruby::MethodCallNode, ::YARD::Parser::Ruby::MethodDefinitionNode) } 317 | 318 | # Translate `sig` type syntax to `YARD` type syntax. 319 | # 320 | # source://yard-sorbet//lib/yard-sorbet/sig_to_yard.rb#6 321 | module YARDSorbet::SigToYARD 322 | class << self 323 | # @see https://yardoc.org/types.html 324 | # 325 | # source://yard-sorbet//lib/yard-sorbet/sig_to_yard.rb#23 326 | sig { params(node: ::YARD::Parser::Ruby::AstNode).returns(T::Array[::String]) } 327 | def convert(node); end 328 | 329 | private 330 | 331 | # source://yard-sorbet//lib/yard-sorbet/sig_to_yard.rb#61 332 | sig { params(node: ::YARD::Parser::Ruby::AstNode).returns(::String) } 333 | def build_generic_type(node); end 334 | 335 | # source://yard-sorbet//lib/yard-sorbet/sig_to_yard.rb#70 336 | sig { params(node: ::YARD::Parser::Ruby::AstNode).returns(T::Array[::String]) } 337 | def convert_aref(node); end 338 | 339 | # source://yard-sorbet//lib/yard-sorbet/sig_to_yard.rb#82 340 | sig { params(node: ::YARD::Parser::Ruby::AstNode).returns([::String]) } 341 | def convert_array(node); end 342 | 343 | # source://yard-sorbet//lib/yard-sorbet/sig_to_yard.rb#90 344 | sig { params(node: ::YARD::Parser::Ruby::AstNode).returns([::String]) } 345 | def convert_collection(node); end 346 | 347 | # source://yard-sorbet//lib/yard-sorbet/sig_to_yard.rb#97 348 | sig { params(node: ::YARD::Parser::Ruby::AstNode).returns([::String]) } 349 | def convert_hash(node); end 350 | 351 | # source://yard-sorbet//lib/yard-sorbet/sig_to_yard.rb#105 352 | sig { params(node: ::YARD::Parser::Ruby::AstNode).returns(T::Array[::String]) } 353 | def convert_list(node); end 354 | 355 | # source://yard-sorbet//lib/yard-sorbet/sig_to_yard.rb#31 356 | sig { params(node: ::YARD::Parser::Ruby::AstNode).returns(T::Array[::String]) } 357 | def convert_node(node); end 358 | 359 | # source://yard-sorbet//lib/yard-sorbet/sig_to_yard.rb#43 360 | sig { params(node: ::YARD::Parser::Ruby::AstNode).returns(T::Array[::String]) } 361 | def convert_node_type(node); end 362 | 363 | # source://yard-sorbet//lib/yard-sorbet/sig_to_yard.rb#110 364 | sig { params(node: ::YARD::Parser::Ruby::MethodCallNode).returns(T::Array[::String]) } 365 | def convert_t_method(node); end 366 | 367 | # source://yard-sorbet//lib/yard-sorbet/sig_to_yard.rb#121 368 | sig { params(node: ::YARD::Parser::Ruby::AstNode).returns([::String]) } 369 | def convert_unknown(node); end 370 | end 371 | end 372 | 373 | # Used to store the details of a `T::Struct` `prop` definition 374 | # 375 | # source://yard-sorbet//lib/yard-sorbet/t_struct_prop.rb#6 376 | class YARDSorbet::TStructProp < ::T::Struct 377 | const :default, T.nilable(::String) 378 | const :doc, ::String 379 | const :prop_name, ::String 380 | const :source, ::String 381 | const :types, T::Array[::String] 382 | 383 | class << self 384 | # source://sorbet-runtime/0.5.11074/lib/types/struct.rb#13 385 | def inherited(s); end 386 | end 387 | end 388 | 389 | # Helper methods for working with `YARD` tags 390 | # 391 | # source://yard-sorbet//lib/yard-sorbet/tag_utils.rb#6 392 | module YARDSorbet::TagUtils 393 | class << self 394 | # source://yard-sorbet//lib/yard-sorbet/tag_utils.rb#16 395 | sig do 396 | params( 397 | docstring: ::YARD::Docstring, 398 | tag_name: ::String, 399 | name: T.nilable(::String) 400 | ).returns(T.nilable(::YARD::Tags::Tag)) 401 | end 402 | def find_tag(docstring, tag_name, name); end 403 | 404 | # Create or update a `YARD` tag with type information 405 | # 406 | # source://yard-sorbet//lib/yard-sorbet/tag_utils.rb#30 407 | sig do 408 | params( 409 | docstring: ::YARD::Docstring, 410 | tag_name: ::String, 411 | types: T.nilable(T::Array[::String]), 412 | name: T.nilable(::String), 413 | text: ::String 414 | ).void 415 | end 416 | def upsert_tag(docstring, tag_name, types = T.unsafe(nil), name = T.unsafe(nil), text = T.unsafe(nil)); end 417 | end 418 | end 419 | 420 | # The `void` return type, as a constant to reduce array allocations 421 | # 422 | # source://yard-sorbet//lib/yard-sorbet/tag_utils.rb#10 423 | YARDSorbet::TagUtils::VOID_RETURN_TYPE = T.let(T.unsafe(nil), Array) 424 | 425 | # {https://rubygems.org/gems/yard-sorbet Version history} 426 | # 427 | # source://yard-sorbet//lib/yard-sorbet/version.rb#7 428 | YARDSorbet::VERSION = T.let(T.unsafe(nil), String) 429 | -------------------------------------------------------------------------------- /sorbet/rbi/shims/io.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | class IO 4 | sig do 5 | params( 6 | src: T.any(String, IO, Tempfile, StringIO), 7 | dst: T.any(String, IO, Tempfile, StringIO), 8 | copy_length: Integer, 9 | src_offset: Integer, 10 | ) 11 | .returns(Integer) 12 | end 13 | def self.copy_stream(src, dst, copy_length = T.unsafe(nil), src_offset = T.unsafe(nil)); end 14 | end 15 | -------------------------------------------------------------------------------- /sorbet/rbi/shims/pdf_reader.rbi: -------------------------------------------------------------------------------- 1 | # typed: true 2 | 3 | class PDF::Reader::ObjectHash 4 | sig { returns(T::Array[PDF::Reader::Reference]) } 5 | def page_references; end 6 | end 7 | -------------------------------------------------------------------------------- /sorbet/rbi/shims/test_helper.rbi: -------------------------------------------------------------------------------- 1 | def add_filter(*); end 2 | def enable_coverage(*); end 3 | -------------------------------------------------------------------------------- /sorbet/tapioca/config.yml: -------------------------------------------------------------------------------- 1 | gem: 2 | # Add your `gem` command parameters here: 3 | # 4 | # exclude: 5 | # - gem_name 6 | # doc: true 7 | # workers: 5 8 | dsl: 9 | # Add your `dsl` command parameters here: 10 | # 11 | # exclude: 12 | # - SomeGeneratorName 13 | # workers: 5 14 | -------------------------------------------------------------------------------- /sorbet/tapioca/require.rb: -------------------------------------------------------------------------------- 1 | # typed: true 2 | # frozen_string_literal: true 3 | 4 | # Add your extra requires here (`bin/tapioca require` can be used to boostrap this list) 5 | -------------------------------------------------------------------------------- /test/rubrik/document/serialize_object_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # typed: true 3 | 4 | require "test_helper" 5 | 6 | class Rubrik::Document 7 | class SerializeObjectTest < Rubrik::Test 8 | def test_hash_serialization 9 | # Arrange 10 | hash = {Test: {Key: :Value, Array: []}} 11 | 12 | # Act 13 | result = SerializeObject[hash] 14 | 15 | # Assert 16 | assert_equal("<>>>", result) 17 | end 18 | 19 | def test_symbol_serialization 20 | # Act + Assert 21 | [ 22 | ["/Name1", :"Name1"], 23 | ["/ASomewhatLongerName", :"ASomewhatLongerName"], 24 | ["/A;Name_With-Various***Characters?", :"A;Name_With-Various***Characters?"], 25 | ["/1.2", :"1.2"], 26 | ["/$$", :"$$"], 27 | ["/@pattern", :"@pattern"], 28 | ["/.notdef", :".notdef"], 29 | ["/Lime#20Green", :"Lime Green"], 30 | ["/paired#28#29parentheses", :"paired()parentheses"], 31 | ["/The_Key_of_F#23_Minor", :"The_Key_of_F#_Minor"], 32 | ["/AB", :"AB"], 33 | ["/H#c3#b6#c3#9fgang", :"Hößgang"], 34 | ].each do |(expected, subject)| 35 | assert_equal(expected, SerializeObject[subject]) 36 | end 37 | end 38 | 39 | def test_array_serialization 40 | # Arrange 41 | array = [0, [PDF::Reader::Reference.new(1, 0), {Key: :Value}]] 42 | 43 | # Act 44 | result = SerializeObject[array] 45 | 46 | # Assert 47 | assert_equal("[0 [1 0 R <>]]", result) 48 | end 49 | 50 | def test_reference_serialization 51 | # Act 52 | result = SerializeObject[PDF::Reader::Reference.new(2, 1)] 53 | 54 | # Assert 55 | assert_equal("2 1 R", result) 56 | end 57 | 58 | def test_string_serialization 59 | # Act + Assert 60 | [ 61 | ["(Test)", "Test"], 62 | ["(Test\\))", "Test)"], 63 | ["(Test\\\n)", "Test\n"], 64 | ["(hello \\\f\\\b hi)", "hello \f\b hi"], 65 | ["(This is \\(\\)n inverted backslash \\\\)", "This is ()n inverted backslash \\"], 66 | ["(Really \\(\\) \\\r\\\n complicated\\\ttest)", "Really () \r\n complicated\ttest"] 67 | ].each do |(expected, subject)| 68 | assert_equal(expected, SerializeObject[subject]) 69 | end 70 | end 71 | 72 | def test_booleans_serialization 73 | # Assert 74 | assert_equal("true", SerializeObject[true]) 75 | assert_equal("false", SerializeObject[false]) 76 | end 77 | 78 | def test_contents_placeholder_serialization 79 | # Assert 80 | expected_result = "<#{"0" * 8_192}>" 81 | assert_equal(expected_result, SerializeObject[CONTENTS_PLACEHOLDER]) 82 | end 83 | 84 | def test_byte_range_placeholder_serialization 85 | # Assert 86 | assert_equal("[0 0000000000 0000000000 0000000000]", SerializeObject[BYTE_RANGE_PLACEHOLDER]) 87 | end 88 | 89 | def test_numeric_serialization 90 | # Assert 91 | [ 92 | ["30", SerializeObject.call(30)], 93 | ["-30", SerializeObject.call(-30)], 94 | ["-1.5", SerializeObject.call(-1.5)], 95 | ["3.3", SerializeObject.call(3.3)] 96 | ].each { |expectation| assert_equal(*expectation) } 97 | end 98 | 99 | def test_nil_serialization 100 | # Assert 101 | assert_equal("null", SerializeObject[nil]) 102 | end 103 | 104 | def test_stream_serialization 105 | # Arrange 106 | data = "Test Text\nTest x\x9C\xBDX[o\u00147\u0014\xB6\xB4HH\xF3\u0002)" 107 | stream = PDF::Reader::Stream.new({Length: data.bytesize}, data) 108 | 109 | # Act 110 | result = SerializeObject[stream] 111 | 112 | # Assert 113 | assert_equal(<<~STREAM.chomp, result) 114 | <> 115 | stream 116 | #{data} 117 | endstream 118 | STREAM 119 | end 120 | 121 | def test_raise_on_unknown_object_serialization 122 | # Assert 123 | assert_raises(RuntimeError, "Don't know how to serialize Object") do 124 | SerializeObject[Object.new] 125 | end 126 | end 127 | end 128 | end 129 | -------------------------------------------------------------------------------- /test/rubrik/document_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # typed: true 3 | 4 | require "test_helper" 5 | 6 | module Rubrik 7 | class DocumentTest < Rubrik::Test 8 | def test_initialize_document_without_interactive_form 9 | # Arrange 10 | input = File.open(SupportPDF["without_interactive_form"], "rb") 11 | 12 | # Act 13 | document = Document.new(input) 14 | 15 | # Assert 16 | assert_equal(input, document.send(:io)) 17 | # FACT: the interactive form was created 18 | assert_equal(6, document.last_object_id) 19 | assert_kind_of(PDF::Reader::ObjectHash, document.objects) 20 | 21 | acro_form = document.modified_objects.find { |obj| obj.is_a?(Hash) && obj.dig(:value, :Type) == :Catalog } 22 | acro_form_reference = T.must(acro_form).dig(:value, :AcroForm) 23 | assert_pattern do 24 | document.modified_objects => [*, {id: ^acro_form_reference, value: {Fields: [], SigFlags: 3}}, *] 25 | end 26 | ensure 27 | input&.close 28 | end 29 | 30 | def test_initialize_document_with_interactive_form 31 | # Arrange 32 | input = File.open(SupportPDF["with_interactive_form"], "rb") 33 | 34 | # Act 35 | document = Document.new(input) 36 | 37 | # Assert 38 | assert_equal(input, document.send(:io)) 39 | assert_equal(5, document.last_object_id) 40 | assert_kind_of(PDF::Reader::ObjectHash, document.objects) 41 | 42 | assert_pattern do 43 | document.modified_objects => [{ 44 | id: PDF::Reader::Reference, value: {Fields: [], SigFlags: 3, NeedAppearances: true} 45 | }] 46 | end 47 | ensure 48 | input&.close 49 | end 50 | 51 | def test_initialize_document_with_unexpected_interactive_form_input 52 | # Arrange 53 | input = File.open(SupportPDF["unexpected_value_interactive_form"], "rb") 54 | 55 | # Act + Assert 56 | assert_raises("Expected dictionary, reference or nil but got Array on AcroForm entry.") do 57 | Document.new(input) 58 | end 59 | ensure 60 | input&.close 61 | end 62 | 63 | def test_initialize_document_with_inline_interactive_form 64 | # Arrange 65 | input = File.open(SupportPDF["inline_interactive_form"], "rb") 66 | 67 | # Act 68 | document = Document.new(input) 69 | 70 | # Assert 71 | assert_equal(input, document.send(:io)) 72 | assert_equal(5, document.last_object_id) 73 | assert_kind_of(PDF::Reader::ObjectHash, document.objects) 74 | 75 | root_ref = PDF::Reader::Reference.new(1, 0) 76 | assert_pattern do 77 | document.modified_objects => [ 78 | {id: PDF::Reader::Reference, value: {Fields: [], SigFlags: 3, NeedAppearances: true}}, 79 | {id: ^root_ref, value: Hash} 80 | ] 81 | end 82 | ensure 83 | input&.close 84 | end 85 | 86 | def test_add_signature_field 87 | # Arrange 88 | input = File.open(SupportPDF["with_interactive_form"], "rb") 89 | document = Document.new(input) 90 | initial_number_of_objects = document.modified_objects.size 91 | 92 | # Act 93 | result = document.add_signature_field 94 | 95 | # Assert 96 | number_of_added_objects = document.modified_objects.size - initial_number_of_objects 97 | assert_equal(3, number_of_added_objects) 98 | 99 | assert_pattern do 100 | signature_value = document.modified_objects.find { _1.is_a?(Hash) && _1[:id] == result } 101 | signature_value => {id: ^result, 102 | value: { 103 | Type: :Sig, 104 | Filter: :"Adobe.PPKLite", 105 | SubFilter: :"adbe.pkcs7.detached", 106 | Contents: Document::CONTENTS_PLACEHOLDER, 107 | ByteRange: Document::BYTE_RANGE_PLACEHOLDER 108 | } 109 | } 110 | end 111 | 112 | signature_field = document.modified_objects.find { _1.is_a?(Hash) && _1.dig(:value, :FT) == :Sig } 113 | assert_pattern do 114 | first_page_reference = document.objects.page_references[0] 115 | signature_field => { 116 | id: PDF::Reader::Reference, 117 | value: { 118 | T: /Signature-\w{4}/, 119 | V: ^result, 120 | Type: :Annot, 121 | Subtype: :Widget, 122 | Rect: [0, 0, 0, 0], 123 | F: 4, 124 | P: ^first_page_reference 125 | } 126 | } 127 | end 128 | 129 | signature_field_id = T.must(signature_field)[:id] 130 | 131 | first_page = document.modified_objects.find { _1.is_a?(Hash) && _1.dig(:value, :Type) == :Page } 132 | assert_pattern { first_page => {value: {Annots: [*, ^signature_field_id, *]}}} 133 | 134 | assert_pattern { document.send(:interactive_form) => {Fields: [*, ^signature_field_id, *]} } 135 | ensure 136 | input&.close 137 | end 138 | 139 | def test_add_signature_field_with_indirect_annots 140 | # Arrange 141 | input = File.open(SupportPDF["indirect_annots"], "rb") 142 | document = Document.new(input) 143 | initial_number_of_objects = document.modified_objects.size 144 | 145 | # Act 146 | result = document.add_signature_field 147 | 148 | # Assert 149 | number_of_added_objects = document.modified_objects.size - initial_number_of_objects 150 | assert_equal(3, number_of_added_objects) 151 | 152 | assert_pattern do 153 | signature_value = document.modified_objects.find { _1.is_a?(Hash) && _1[:id] == result } 154 | signature_value => {id: ^result, 155 | value: { 156 | Type: :Sig, 157 | Filter: :"Adobe.PPKLite", 158 | SubFilter: :"adbe.pkcs7.detached", 159 | Contents: Document::CONTENTS_PLACEHOLDER, 160 | ByteRange: Document::BYTE_RANGE_PLACEHOLDER 161 | } 162 | } 163 | end 164 | 165 | signature_field = document.modified_objects.find { _1.is_a?(Hash) && _1.dig(:value, :FT) == :Sig } 166 | assert_pattern do 167 | first_page_reference = document.objects.page_references[0] 168 | signature_field => { 169 | id: PDF::Reader::Reference, 170 | value: { 171 | T: /Signature-\w{4}/, 172 | V: ^result, 173 | Type: :Annot, 174 | Subtype: :Widget, 175 | Rect: [0, 0, 0, 0], 176 | F: 4, 177 | P: ^first_page_reference 178 | } 179 | } 180 | end 181 | 182 | signature_field_id = T.must(signature_field)[:id] 183 | 184 | assert_pattern do 185 | document.modified_objects => [*, {id: PDF::Reader::Reference, value: [signature_field_id]} , *] 186 | end 187 | 188 | assert_pattern { document.send(:interactive_form) => {Fields: [*, ^signature_field_id, *]} } 189 | ensure 190 | input&.close 191 | end 192 | 193 | def test_add_signature_field_with_indirect_fields 194 | # Arrange 195 | input = File.open(SupportPDF["indirect_fields"], "rb") 196 | document = Document.new(input) 197 | initial_number_of_objects = document.modified_objects.size 198 | 199 | # Act 200 | result = document.add_signature_field 201 | 202 | # Assert 203 | number_of_added_objects = document.modified_objects.size - initial_number_of_objects 204 | assert_equal(4, number_of_added_objects) 205 | 206 | assert_pattern do 207 | document.modified_objects => [{id: PDF::Reader::Reference, value: {Fields: fields_ref}}, *] 208 | document.modified_objects => [*, {id: ^fields_ref, value: [signature_field_ref]}] 209 | document.modified_objects => [*, {id: ^signature_field_ref, value: {FT: :Sig}}, *] 210 | end 211 | ensure 212 | input&.close 213 | end 214 | end 215 | end 216 | -------------------------------------------------------------------------------- /test/rubrik/pkcs7_signature_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # typed: true 3 | 4 | require "test_helper" 5 | 6 | class Rubrik::PKCS7SignatureTest < Rubrik::Test 7 | def test_signature_generation 8 | # Arrange 9 | certificate_file = File.open("test/support/demo_cert.pem", "rb") 10 | 11 | private_key = OpenSSL::PKey::RSA.new(certificate_file, "") 12 | certificate_file.rewind 13 | certificate = OpenSSL::X509::Certificate.new(certificate_file) 14 | 15 | # Act 16 | raw_result = Rubrik::PKCS7Signature.call("test", private_key:, certificate:) 17 | 18 | # Assert 19 | result = OpenSSL::ASN1.decode(raw_result) 20 | 21 | assert_kind_of(OpenSSL::ASN1::Sequence, result) 22 | 23 | content_type = result.value.first 24 | assert_equal("pkcs7-signedData", content_type.value) 25 | 26 | ensure 27 | certificate_file&.close 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /test/rubrik/sign_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # typed: true 3 | 4 | require "test_helper" 5 | 6 | module Rubrik 7 | class SignTest < Rubrik::Test 8 | def test_document_with_interactive_form 9 | # Arrange 10 | input_pdf = File.open(SupportPDF["with_interactive_form"], "rb") 11 | output_pdf = StringIO.new 12 | certificate_file = File.open("test/support/demo_cert.pem", "rb") 13 | 14 | private_key = OpenSSL::PKey::RSA.new(certificate_file, "") 15 | certificate_file.rewind 16 | certificate = OpenSSL::X509::Certificate.new(certificate_file) 17 | 18 | # Act 19 | Sign.call(input_pdf, output_pdf, private_key:, certificate:) 20 | 21 | # Assert 22 | expected_output = File.open(SupportPDF["with_interactive_form.expected"], "rb") 23 | 24 | expected_output.readlines.zip(output_pdf.readlines).each do |(expected_line, actual_line)| 25 | # We must erase the signature because it is timestampped 26 | if actual_line&.match?("/Type /Sig") 27 | actual_line.sub!(/<[a-f0-9]+>/, "") 28 | expected_line.sub!(/<[a-f0-9]+>/, "") 29 | # The signature field name is also random 30 | elsif actual_line&.match?(/Signature-[a-f0-9]{4}/) 31 | actual_line.sub!(/Signature-[a-f0-9]{4}/, "") 32 | expected_line.sub!(/Signature-[a-f0-9]{4}/, "") 33 | end 34 | 35 | assert_equal(expected_line, actual_line) 36 | end 37 | ensure 38 | certificate_file&.close 39 | output_pdf&.close 40 | input_pdf&.close 41 | expected_output&.close 42 | end 43 | 44 | def test_document_without_interactive_form 45 | # Arrange 46 | input_pdf = File.open(SupportPDF["without_interactive_form"], "rb") 47 | output_pdf = StringIO.new 48 | certificate_file = File.open("test/support/demo_cert.pem", "rb") 49 | 50 | private_key = OpenSSL::PKey::RSA.new(certificate_file, "") 51 | certificate_file.rewind 52 | certificate = OpenSSL::X509::Certificate.new(certificate_file) 53 | 54 | # Act 55 | Sign.call(input_pdf, output_pdf, private_key:, certificate:) 56 | 57 | # Assert 58 | expected_output = File.open(SupportPDF["without_interactive_form.expected"], "rb") 59 | 60 | expected_output.readlines.zip(output_pdf.readlines).each do |(expected_line, actual_line)| 61 | # We can't verify the signature because it changes on every run 62 | if actual_line&.match?("/Type /Sig") 63 | actual_line.sub!(/<[a-f0-9]+>/, "") 64 | expected_line.sub!(/<[a-f0-9]+>/, "") 65 | # The signature field name is also random 66 | elsif actual_line&.match?(/Signature-[a-f0-9]{4}/) 67 | actual_line.sub!(/Signature-[a-f0-9]{4}/, "") 68 | expected_line.sub!(/Signature-[a-f0-9]{4}/, "") 69 | end 70 | 71 | assert_equal(expected_line, actual_line) 72 | end 73 | ensure 74 | certificate_file&.close 75 | output_pdf&.close 76 | input_pdf&.close 77 | expected_output&.close 78 | end 79 | 80 | def test_document_with_indirect_annots 81 | # Arrange 82 | input_pdf = File.open(SupportPDF["indirect_annots"], "rb") 83 | # FACT: the output file is opened with only write permission and should be later reopened to rw. 84 | output_pdf = File.open(SupportPDF["indirect_annots_temp"], "wb") 85 | certificate_file = File.open("test/support/demo_cert.pem", "rb") 86 | 87 | private_key = OpenSSL::PKey::RSA.new(certificate_file, "") 88 | certificate_file.rewind 89 | certificate = OpenSSL::X509::Certificate.new(certificate_file) 90 | 91 | # Act 92 | Sign.call(input_pdf, output_pdf, private_key:, certificate:) 93 | 94 | # Assert 95 | expected_output = File.open(SupportPDF["indirect_annots.expected"], "rb") 96 | 97 | expected_output.readlines.zip(output_pdf.readlines).each do |(expected_line, actual_line)| 98 | # We can't verify the signature because it changes on every run 99 | if actual_line&.match?("/Type /Sig") 100 | actual_line.sub!(/<[a-f0-9]+>/, "") 101 | expected_line.sub!(/<[a-f0-9]+>/, "") 102 | # The signature field name is also random 103 | elsif actual_line&.match?(/Signature-[a-f0-9]{4}/) 104 | actual_line.sub!(/Signature-[a-f0-9]{4}/, "") 105 | expected_line.sub!(/Signature-[a-f0-9]{4}/, "") 106 | end 107 | 108 | assert_equal(expected_line, actual_line) 109 | end 110 | ensure 111 | certificate_file&.close 112 | input_pdf&.close 113 | expected_output&.close 114 | 115 | output_pdf&.close 116 | File.delete(output_pdf.path) if output_pdf 117 | end 118 | 119 | def test_document_with_inline_interactive_form 120 | # Arrange 121 | input_pdf = File.open(SupportPDF["inline_interactive_form"], "rb") 122 | output_pdf = StringIO.new 123 | certificate_file = File.open("test/support/demo_cert.pem", "rb") 124 | 125 | private_key = OpenSSL::PKey::RSA.new(certificate_file, "") 126 | certificate_file.rewind 127 | certificate = OpenSSL::X509::Certificate.new(certificate_file) 128 | 129 | # Act 130 | Sign.call(input_pdf, output_pdf, private_key:, certificate:) 131 | 132 | # Assert 133 | expected_output = File.open(SupportPDF["inline_interactive_form.expected"], "rb") 134 | 135 | expected_output.readlines.zip(output_pdf.readlines).each do |(expected_line, actual_line)| 136 | # We must erase the signature because it is timestampped 137 | if actual_line&.match?("/Type /Sig") 138 | actual_line.sub!(/<[a-f0-9]+>/, "") 139 | expected_line.sub!(/<[a-f0-9]+>/, "") 140 | # The signature field name is also random 141 | elsif actual_line&.match?(/Signature-[a-f0-9]{4}/) 142 | actual_line.sub!(/Signature-[a-f0-9]{4}/, "") 143 | expected_line.sub!(/Signature-[a-f0-9]{4}/, "") 144 | end 145 | 146 | assert_equal(expected_line, actual_line) 147 | end 148 | ensure 149 | certificate_file&.close 150 | output_pdf&.close 151 | input_pdf&.close 152 | expected_output&.close 153 | end 154 | 155 | def test_document_with_indirect_fields 156 | # Arrange 157 | input_pdf = File.open(SupportPDF["indirect_fields"], "rb") 158 | output_pdf = StringIO.new 159 | certificate_file = File.open("test/support/demo_cert.pem", "rb") 160 | 161 | private_key = OpenSSL::PKey::RSA.new(certificate_file, "") 162 | certificate_file.rewind 163 | certificate = OpenSSL::X509::Certificate.new(certificate_file) 164 | 165 | # Act 166 | Sign.call(input_pdf, output_pdf, private_key:, certificate:) 167 | 168 | # Assert 169 | expected_output = File.open(SupportPDF["indirect_fields.expected"], "rb") 170 | 171 | expected_output.readlines.zip(output_pdf.readlines).each do |(expected_line, actual_line)| 172 | # We must erase the signature because it is timestampped 173 | if actual_line&.match?("/Type /Sig") 174 | actual_line.sub!(/<[a-f0-9]+>/, "") 175 | expected_line.sub!(/<[a-f0-9]+>/, "") 176 | # The signature field name is also random 177 | elsif actual_line&.match?(/Signature-[a-f0-9]{4}/) 178 | actual_line.sub!(/Signature-[a-f0-9]{4}/, "") 179 | expected_line.sub!(/Signature-[a-f0-9]{4}/, "") 180 | end 181 | 182 | assert_equal(expected_line, actual_line) 183 | end 184 | ensure 185 | certificate_file&.close 186 | output_pdf&.close 187 | input_pdf&.close 188 | expected_output&.close 189 | end 190 | end 191 | end 192 | -------------------------------------------------------------------------------- /test/rubrik_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "test_helper" 4 | 5 | class RubrikTest < Rubrik::Test 6 | def test_that_it_has_a_version_number 7 | refute_nil ::Rubrik::VERSION 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/support/demo_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFZTCCA02gAwIBAgIUKsEHzD+2TwI/R3ThNsWL8W0NE+YwDQYJKoZIhvcNAQEL 3 | BQAwQjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UE 4 | CgwTRGVmYXVsdCBDb21wYW55IEx0ZDAeFw0yMzAzMTAxOTM0NDBaFw0yNDAzMDkx 5 | OTM0NDBaMEIxCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAa 6 | BgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQwggIiMA0GCSqGSIb3DQEBAQUAA4IC 7 | DwAwggIKAoICAQCnQvEklyGXRZ/Ksk52VBEMW+RUh1Seya1F5I1F2bh7Dcz+68jL 8 | AqYj65MznWJTLcJ1T3r308fuF3TR3DYnx9uitUDCuKGm6fwAmpBhbxpVyfhzrdqH 9 | LVa4EV2QdQGoOQUpL6r2fe729KIThihDft6+0RZzabHPKm9nuMPehawgAoxEhhl0 10 | LRR9DArgdPJ0odIgdiHMUQprNlRqKSfRfs8xvf2tLD+xdvrHEErijyf16zFzGkSK 11 | OUM8I+KO7L0/JZdxdZinJNQYh3yJkKamSLRYIfxlvvAQpSIwQX10PR7hk3rR7WOy 12 | Drz74nuKI4NBWqa3mL1fQXAOUGzHzUhIQQMXlP4ITqbVYSpPwDIz3ireBs6dEZqR 13 | X3sG9MaEjnlkzayLs1lyNHH0sMwHot69y2bBClU0gxsdvBHm1ixekZyh+DFpYosB 14 | 5Y5rksVHjtdDAJTaj3Pm711u0awL043wrlKWORyrhKNYNS1q28jwN1gaGgv3sKP7 15 | 3/35SUfnH+m0VA4oduJi4kZBMO3jsifY2U5budq9cUG70Us30tlr0jZGMewatdl+ 16 | Qkra7V1ZdKrP6moH8ACJAWvSLwrFuW5j8VA+l15H1I2Asyfq1rFq4UfQQPDaU95Q 17 | Kgwdu9cRZmuckAuOfkowl73mqZwsbKMGkwH2hhx0+hFITSudOnWkHisEzQIDAQAB 18 | o1MwUTAdBgNVHQ4EFgQUix6QnNhWcOAtRyKJeGD8ndO/Jk8wHwYDVR0jBBgwFoAU 19 | ix6QnNhWcOAtRyKJeGD8ndO/Jk8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B 20 | AQsFAAOCAgEAj1bVHxcdU7VHdpWP9t8K4+zhRvOY6ScHDbl+mse0HaWJfGwcwC6a 21 | Ce4NMpzPsxlDEzCZxAhBpQ1GwLP66hpjHdSmp43ntMFRLdI2DCTX1UMjx5Cf5ZIA 22 | 9gXptV58xSbYI0smzvvCkjeMXsWOXAaR1CyafIDIR0fZ5aXz8GfnHO+ubTkR1uxv 23 | NgSVSu7ZjMME+RGokW5tW6oqMw8uF63xNribK+3ShBXJco3ipebo5eBGKWA44jP6 24 | PcAZIM1HKE66QyHdFpg3V+SZuysgqSZvnRKwt1AiGcGHsw855YxTUSOTey0qfpbK 25 | N5+5rwmksqnth7/tr9sAWNxU6Gcsk9oFCS0NAtJRljmPgYD4NvTE83DXwD8BZuyr 26 | WFdZF+TfTaDKHlgh/XX/zZHpmjQQk+bt2ppCLtUUsVNErTR28vwj7BGFzxX1MQ1U 27 | 9babtMbyL8XUD5DtlAyK7wvEyf8buIlb6FWIHo4Ml9/eASQlnThS4DZRiXsunRMn 28 | PS0S5n7mVTID0icuw+EGoN/BZxQQa1hysfXUqSRZfNwdtAIMHT9s5RTLrtYMDJBA 29 | LCRqE5gBvOquLO/gWjlT4FIyaEneYHZL1NzWwDsUh+w7bZjN5avhPuH63qwrZ0Ig 30 | tAJmOfb0Zl1G6TCntw4IlWuwQU6hYcxK2cxNF/uOEDReO9syHBgkp2g= 31 | -----END CERTIFICATE----- 32 | -----BEGIN PRIVATE KEY----- 33 | MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCnQvEklyGXRZ/K 34 | sk52VBEMW+RUh1Seya1F5I1F2bh7Dcz+68jLAqYj65MznWJTLcJ1T3r308fuF3TR 35 | 3DYnx9uitUDCuKGm6fwAmpBhbxpVyfhzrdqHLVa4EV2QdQGoOQUpL6r2fe729KIT 36 | hihDft6+0RZzabHPKm9nuMPehawgAoxEhhl0LRR9DArgdPJ0odIgdiHMUQprNlRq 37 | KSfRfs8xvf2tLD+xdvrHEErijyf16zFzGkSKOUM8I+KO7L0/JZdxdZinJNQYh3yJ 38 | kKamSLRYIfxlvvAQpSIwQX10PR7hk3rR7WOyDrz74nuKI4NBWqa3mL1fQXAOUGzH 39 | zUhIQQMXlP4ITqbVYSpPwDIz3ireBs6dEZqRX3sG9MaEjnlkzayLs1lyNHH0sMwH 40 | ot69y2bBClU0gxsdvBHm1ixekZyh+DFpYosB5Y5rksVHjtdDAJTaj3Pm711u0awL 41 | 043wrlKWORyrhKNYNS1q28jwN1gaGgv3sKP73/35SUfnH+m0VA4oduJi4kZBMO3j 42 | sifY2U5budq9cUG70Us30tlr0jZGMewatdl+Qkra7V1ZdKrP6moH8ACJAWvSLwrF 43 | uW5j8VA+l15H1I2Asyfq1rFq4UfQQPDaU95QKgwdu9cRZmuckAuOfkowl73mqZws 44 | bKMGkwH2hhx0+hFITSudOnWkHisEzQIDAQABAoICAAEfzZAh5etm3+aUYTuhYAX1 45 | viilSjfRAjWkjiCIkJlfI+AYxJ48s9Is/K3NooINni98q8ZrqX3bsYDRmpmU2dCT 46 | qE5GwGtnSjbU0yCchxBJjb51TjE3aExPbZIRf0PaskKvG9aRTSBiz44TCkU93pBo 47 | xl5bOQM79Ui8sLBXtKr4aWnyfsxNm0Ql5xLQJmsLRWbLdHmzl77VvCaEhUx+rjTW 48 | 4pQd5oWyV4gr/1zbenjILmpoJErLjLykPxsX00PP5F8yW6bP9A8AJiGkk8ItXezz 49 | uYcTi/iIq5yobAfyezkn7RzpHBDv0Wxd/teUWob/bXxxbeBsh6zI9Jo5MoGt0i/9 50 | Fk95exw0JFwTQq/cySCzPg7yaFUGu+WLLHgAbuWsdgiB3l5ojpjvr3YIyB7Ale1h 51 | sOu+wJkHWkeC5G/tSwSxXQ/QfGqfNFyJWfBOqYndp5kOkrmMDbLr1e+V/NyGZ1os 52 | 19GMhe1PE7/3Mhoc7ExhLsafgxEEHMACtwZ/QlE2kRItQ1jRVXz3JUUh0BLZfTjZ 53 | Ag48gEoE/LJ6eJ6Vpudd1GwWlNs8GOLWkW+0E6BZozu5C4/iZvCBGml/EIDHkAq6 54 | 50wvZOiRmf+yLL5IBvUSGWnbBMzfYe2+5Nsoym6UVpb8/Z/+qiklfb/dRf8P6vYS 55 | YjdpdMqGa+breBqnYoFhAoIBAQDqKgoDyaoOpVQhaTDa8izGL0LyKe+vLoqJJnvx 56 | 0Loh4nreXLTHPsm8nqnUXaMNT/BOfUUwat8le3qnv01GyUG2OjVBzc7I1ywe4+Po 57 | eE0kd606bBJwJ69Zrn/lAUCaFJQIEnTQDEJrd2XUQM/jZzrkMfCquYlSDcy6sdUx 58 | aSXrEivyvqkst4/cLQ2/3JS8bBEIUcmwWN3AmEW/8O69r9S8ZZ269mBBPBTy6GAd 59 | fxh3qLTpMNyTeGGCb4DfeQfZwNwrzqXjFGJXoMKtvbqYLUynN2U8GZL+76A45ZVJ 60 | 7aw2aJm6rV2L2o6187SqFPOFOuxRvnbQEgU/K9ht7Ftz6zNRAoIBAQC2282YsJp3 61 | rT9BW2RfVzYfWKGgARZ2hLJtXIR0niTL7F9YZqPmE8oG1XviwU15aHywC2eFoY1d 62 | Kh2gEoMQveGiSjSuaEm0/SMkkRjplZKo/kCzmHfuW9QUZ6dKZzIatM86DS6pRYex 63 | RKtFrSQXQu4Kdw2KBN+1TWDhq71/m+MJN/6litV/6cKwJhYdwuPlDRoIeWjS6SVj 64 | GPV2hRQGAMQjag8jmbUh0qk81wgnCJldfpKAZfGbrJfgqzFlb8i6+B0A5wuaPrvY 65 | cAc5QnYDOdb2uAff4wW09g8x0AmJslGJe9QsJ7rCkmG+QIZGjwqtSq2ZnJYJVZMh 66 | gp8ZPDV+R4K9AoIBAGSdq6/09x1T7NJuYI+zf4moxRtI6bRcSyqjXp6JEXF9302s 67 | iAEU+ZoSkuatVWJi9t7C9PfY9AknBY0OpiXEVHf4ium7hR7HVi3vvf4lsv/4bHat 68 | +T43zyC52jqMTzXlobXWOFss6V1D8H1DXBBaSvPCgabaEicvxshxoSmaBLD9HeUw 69 | B4EvXqE8uqu2HDLaPHdWrVMY3C/lPhM7c1oOM1rATwYG11Uwe8/kCWijM+A2nYWV 70 | eTHkiAGD59weJUFrnS81nBH2sEr2yK/e1k6NKGKxas5oLsFcNXw9KeiaN2UpjOSp 71 | mYh+YNPN49MxLXIR33lAXc0J8Tczn8ubw7ALYAECggEBALMRz2YO1EYMl9x2FnYz 72 | XqIV1rltN0U7L8xfBKt7TweQY9KbOTgP+xD0MUzfBfK1+x0fHfLEQT6SBs8CMe3M 73 | NVELoEmHgV7HYonlueLNggESc+QslI4MyURuOWpoYq26kREFZcOIfph/acZjBuvs 74 | tFX1PoIBwd23d/+ngnyb+RrHBg2xRuDr16dOtOvSNgDR8sOHubqJbP59q6u0KOa0 75 | C1+u9kJjvPjxZqBY5/fpuN7RG8C3lIJh4521qDrw3D8UyLpgiIE1nBkZpElTp2QD 76 | WVrk33lFxgnvyPN8CksZIDYl2KKhCYiPdz6ry5L/c3I+poC+0kMz1VDErO82giA3 77 | AXUCggEAARsg4tTWsBfQB+doB4LfwQJ42MxrmXrY/iN+IQKWv31n1eCi1Dh4nOT0 78 | +j7kjqLWdI+QG6C0lIwOTYMBzCoN8CiUTuuC30AqzLAkIhNM7uoAAnkMEtMQE+ep 79 | dQq02eF8AsfMXUEqYecUJT0AUkDAr+mQkBGgodrkf3maP8p9/yLhBNZDrFUcLYkJ 80 | FQozPNh++rDNuxoMX1WWS9+bDQ3GF1zX8dt/KM/RqutS8cRLK9vkM+IJjRG6yofI 81 | BkVQ9gCTnjXwyBSo3AYYUKLeDgOdGz9SKCaJiW1A1DqZeybCcR16Fjthyt4r3CGw 82 | M8981Pfvn8tiM23k0F4y+S3gD36+PQ== 83 | -----END PRIVATE KEY----- 84 | -------------------------------------------------------------------------------- /test/support/indirect_annots.expected.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 1 0 obj 3 | <> 4 | endobj 5 | 2 0 obj 6 | <> 7 | endobj 8 | 3 0 obj 9 | <> 10 | endobj 11 | 4 0 obj 12 | <> 13 | stream 14 | 1.0 0.0 0.0 RG 15 | 0.5 0.75 1.0 rg 16 | 97.72 220.84 400 400 re 17 | B 18 | endstream 19 | endobj 20 | 5 0 obj 21 | <> 22 | endobj 23 | 6 0 obj 24 | [] 25 | endobj 26 | xref 27 | 0 7 28 | 0000000000 65535 f 29 | 0000000009 00000 n 30 | 0000000072 00000 n 31 | 0000000127 00000 n 32 | 0000000232 00000 n 33 | 0000000336 00000 n 34 | 0000000417 00000 n 35 | trailer 36 | <> 37 | startxref 38 | 435 39 | %%EOF 40 | 41 | 5 0 obj 42 | <> 43 | endobj 44 | 45 | 7 0 obj 46 | < /ByteRange [0 812 9006 377] >> 47 | endobj 48 | 49 | 8 0 obj 50 | <> 51 | endobj 52 | 53 | 6 0 obj 54 | [8 0 R] 55 | endobj 56 | 57 | xref 58 | 0 1 59 | 0000000000 65535 f 60 | 5 4 61 | 0000000637 00000 n 62 | 0000009183 00000 n 63 | 0000000726 00000 n 64 | 0000009065 00000 n 65 | trailer 66 | <> 67 | startxref 68 | 9207 69 | %%EOF 70 | -------------------------------------------------------------------------------- /test/support/indirect_annots.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 1 0 obj 3 | <> 4 | endobj 5 | 2 0 obj 6 | <> 7 | endobj 8 | 3 0 obj 9 | <> 10 | endobj 11 | 4 0 obj 12 | <> 13 | stream 14 | 1.0 0.0 0.0 RG 15 | 0.5 0.75 1.0 rg 16 | 97.72 220.84 400 400 re 17 | B 18 | endstream 19 | endobj 20 | 5 0 obj 21 | <> 22 | endobj 23 | 6 0 obj 24 | [] 25 | endobj 26 | xref 27 | 0 7 28 | 0000000000 65535 f 29 | 0000000009 00000 n 30 | 0000000072 00000 n 31 | 0000000127 00000 n 32 | 0000000232 00000 n 33 | 0000000336 00000 n 34 | 0000000417 00000 n 35 | trailer 36 | <> 37 | startxref 38 | 435 39 | %%EOF 40 | -------------------------------------------------------------------------------- /test/support/indirect_fields.expected.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 1 0 obj 3 | <> 4 | endobj 5 | 2 0 obj 6 | <> 7 | endobj 8 | 3 0 obj 9 | <> 10 | endobj 11 | 4 0 obj 12 | <> 13 | stream 14 | 1.0 0.0 0.0 RG 15 | 0.5 0.75 1.0 rg 16 | 97.72 220.84 400 400 re 17 | B 18 | endstream 19 | endobj 20 | 5 0 obj 21 | <> 22 | endobj 23 | 6 0 obj 24 | [] 25 | endobj 26 | 7 0 obj 27 | [] 28 | endobj 29 | 30 | xref 31 | 0 8 32 | 0000000000 65535 f 33 | 0000000009 00000 n 34 | 0000000072 00000 n 35 | 0000000127 00000 n 36 | 0000000232 00000 n 37 | 0000000336 00000 n 38 | 0000000420 00000 n 39 | 0000000438 00000 n 40 | trailer 41 | <> 42 | startxref 43 | 457 44 | %%EOF 45 | 46 | 5 0 obj 47 | <> 48 | endobj 49 | 50 | 8 0 obj 51 | < /ByteRange [0 852 9046 422] >> 52 | endobj 53 | 54 | 9 0 obj 55 | <> 56 | endobj 57 | 58 | 6 0 obj 59 | [9 0 R] 60 | endobj 61 | 62 | 7 0 obj 63 | [9 0 R] 64 | endobj 65 | 66 | xref 67 | 0 1 68 | 0000000000 65535 f 69 | 5 5 70 | 0000000679 00000 n 71 | 0000009223 00000 n 72 | 0000009247 00000 n 73 | 0000000766 00000 n 74 | 0000009105 00000 n 75 | trailer 76 | <> 77 | startxref 78 | 9271 79 | %%EOF 80 | -------------------------------------------------------------------------------- /test/support/indirect_fields.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 1 0 obj 3 | <> 4 | endobj 5 | 2 0 obj 6 | <> 7 | endobj 8 | 3 0 obj 9 | <> 10 | endobj 11 | 4 0 obj 12 | <> 13 | stream 14 | 1.0 0.0 0.0 RG 15 | 0.5 0.75 1.0 rg 16 | 97.72 220.84 400 400 re 17 | B 18 | endstream 19 | endobj 20 | 5 0 obj 21 | <> 22 | endobj 23 | 6 0 obj 24 | [] 25 | endobj 26 | 7 0 obj 27 | [] 28 | endobj 29 | 30 | xref 31 | 0 8 32 | 0000000000 65535 f 33 | 0000000009 00000 n 34 | 0000000072 00000 n 35 | 0000000127 00000 n 36 | 0000000232 00000 n 37 | 0000000336 00000 n 38 | 0000000420 00000 n 39 | 0000000438 00000 n 40 | trailer 41 | <> 42 | startxref 43 | 457 44 | %%EOF 45 | -------------------------------------------------------------------------------- /test/support/inline_interactive_form.expected.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 1 0 obj 3 | <>>> 4 | endobj 5 | 2 0 obj 6 | <> 7 | endobj 8 | 3 0 obj 9 | <> 10 | endobj 11 | 4 0 obj 12 | <> 13 | stream 14 | 1.0 0.0 0.0 RG 15 | 0.5 0.75 1.0 rg 16 | 97.72 220.84 400 400 re 17 | B 18 | endstream 19 | endobj 20 | xref 21 | 0 5 22 | 0000000000 65535 f 23 | 0000000009 00000 n 24 | 0000000115 00000 n 25 | 0000000170 00000 n 26 | 0000000282 00000 n 27 | trailer 28 | <> 29 | startxref 30 | 386 31 | %%EOF 32 | 33 | 5 0 obj 34 | <> 35 | endobj 36 | 37 | 1 0 obj 38 | <> 39 | endobj 40 | 41 | 6 0 obj 42 | < /ByteRange [0 768 8962 504] >> 43 | endobj 44 | 45 | 7 0 obj 46 | <> 47 | endobj 48 | 49 | 3 0 obj 50 | <> 51 | endobj 52 | 53 | xref 54 | 0 2 55 | 0000000000 65535 f 56 | 0000000618 00000 n 57 | 3 1 58 | 0000009139 00000 n 59 | 5 3 60 | 0000000548 00000 n 61 | 0000000682 00000 n 62 | 0000009021 00000 n 63 | trailer 64 | <> 65 | startxref 66 | 9266 67 | %%EOF 68 | -------------------------------------------------------------------------------- /test/support/inline_interactive_form.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 1 0 obj 3 | <>>> 4 | endobj 5 | 2 0 obj 6 | <> 7 | endobj 8 | 3 0 obj 9 | <> 10 | endobj 11 | 4 0 obj 12 | <> 13 | stream 14 | 1.0 0.0 0.0 RG 15 | 0.5 0.75 1.0 rg 16 | 97.72 220.84 400 400 re 17 | B 18 | endstream 19 | endobj 20 | xref 21 | 0 5 22 | 0000000000 65535 f 23 | 0000000009 00000 n 24 | 0000000115 00000 n 25 | 0000000170 00000 n 26 | 0000000282 00000 n 27 | trailer 28 | <> 29 | startxref 30 | 386 31 | %%EOF 32 | -------------------------------------------------------------------------------- /test/support/unexpected_value_interactive_form.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 1 0 obj 3 | <> 4 | endobj 5 | 2 0 obj 6 | <> 7 | endobj 8 | 3 0 obj 9 | <> 10 | endobj 11 | 4 0 obj 12 | <> 13 | stream 14 | 1.0 0.0 0.0 RG 15 | 0.5 0.75 1.0 rg 16 | 97.72 220.84 400 400 re 17 | B 18 | endstream 19 | endobj 20 | xref 21 | 0 5 22 | 0000000000 65535 f 23 | 0000000009 00000 n 24 | 0000000078 00000 n 25 | 0000000133 00000 n 26 | 0000000224 00000 n 27 | trailer 28 | <> 29 | startxref 30 | 328 31 | %%EOF 32 | -------------------------------------------------------------------------------- /test/support/with_interactive_form.expected.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 1 0 obj 3 | <> 4 | endobj 5 | 2 0 obj 6 | <> 7 | endobj 8 | 3 0 obj 9 | <> 10 | endobj 11 | 4 0 obj 12 | <> 13 | stream 14 | 1.0 0.0 0.0 RG 15 | 0.5 0.75 1.0 rg 16 | 97.72 220.84 400 400 re 17 | B 18 | endstream 19 | endobj 20 | 5 0 obj 21 | <> 22 | endobj 23 | xref 24 | 0 6 25 | 0000000000 65535 f 26 | 0000000009 00000 n 27 | 0000000072 00000 n 28 | 0000000127 00000 n 29 | 0000000218 00000 n 30 | 0000000322 00000 n 31 | trailer 32 | <> 33 | startxref 34 | 386 35 | %%EOF 36 | 37 | 5 0 obj 38 | <> 39 | endobj 40 | 41 | 6 0 obj 42 | < /ByteRange [0 724 8918 465] >> 43 | endobj 44 | 45 | 7 0 obj 46 | <> 47 | endobj 48 | 49 | 3 0 obj 50 | <> 51 | endobj 52 | 53 | xref 54 | 0 1 55 | 0000000000 65535 f 56 | 3 1 57 | 0000009095 00000 n 58 | 5 3 59 | 0000000568 00000 n 60 | 0000000638 00000 n 61 | 0000008977 00000 n 62 | trailer 63 | <> 64 | startxref 65 | 9203 66 | %%EOF 67 | -------------------------------------------------------------------------------- /test/support/with_interactive_form.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 1 0 obj 3 | <> 4 | endobj 5 | 2 0 obj 6 | <> 7 | endobj 8 | 3 0 obj 9 | <> 10 | endobj 11 | 4 0 obj 12 | <> 13 | stream 14 | 1.0 0.0 0.0 RG 15 | 0.5 0.75 1.0 rg 16 | 97.72 220.84 400 400 re 17 | B 18 | endstream 19 | endobj 20 | 5 0 obj 21 | <> 22 | endobj 23 | xref 24 | 0 6 25 | 0000000000 65535 f 26 | 0000000009 00000 n 27 | 0000000072 00000 n 28 | 0000000127 00000 n 29 | 0000000218 00000 n 30 | 0000000322 00000 n 31 | trailer 32 | <> 33 | startxref 34 | 386 35 | %%EOF 36 | -------------------------------------------------------------------------------- /test/support/without_interactive_form.expected.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 1 0 obj 3 | <> 4 | endobj 5 | 2 0 obj 6 | <> 7 | endobj 8 | 3 0 obj 9 | <> 10 | endobj 11 | 4 0 obj 12 | <> 13 | stream 14 | 1.0 0.0 0.0 RG 15 | 0.5 0.75 1.0 rg 16 | 97.72 220.84 400 400 re 17 | B 18 | endstream 19 | endobj 20 | 5 0 obj 21 | <> 22 | endobj 23 | xref 24 | 0 6 25 | 0000000005 65535 f 26 | 0000000009 00000 n 27 | 0000000056 00000 n 28 | 0000000111 00000 n 29 | 0000000202 00000 n 30 | 0000000000 00000 f 31 | trailer 32 | <> 33 | startxref 34 | 339 35 | %%EOF 36 | 37 | 6 0 obj 38 | <> 39 | endobj 40 | 41 | 1 0 obj 42 | <> 43 | endobj 44 | 45 | 7 0 obj 46 | < /ByteRange [0 719 8913 485] >> 47 | endobj 48 | 49 | 8 0 obj 50 | <> 51 | endobj 52 | 53 | 3 0 obj 54 | <> 55 | endobj 56 | 57 | xref 58 | 0 2 59 | 0000000005 65535 f 60 | 0000000569 00000 n 61 | 3 1 62 | 0000009090 00000 n 63 | 6 3 64 | 0000000521 00000 n 65 | 0000000633 00000 n 66 | 0000008972 00000 n 67 | trailer 68 | <> 69 | startxref 70 | 9198 71 | %%EOF 72 | -------------------------------------------------------------------------------- /test/support/without_interactive_form.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 1 0 obj 3 | <> 4 | endobj 5 | 2 0 obj 6 | <> 7 | endobj 8 | 3 0 obj 9 | <> 10 | endobj 11 | 4 0 obj 12 | <> 13 | stream 14 | 1.0 0.0 0.0 RG 15 | 0.5 0.75 1.0 rg 16 | 97.72 220.84 400 400 re 17 | B 18 | endstream 19 | endobj 20 | 5 0 obj 21 | <> 22 | endobj 23 | xref 24 | 0 6 25 | 0000000005 65535 f 26 | 0000000009 00000 n 27 | 0000000056 00000 n 28 | 0000000111 00000 n 29 | 0000000202 00000 n 30 | 0000000000 00000 f 31 | trailer 32 | <> 33 | startxref 34 | 339 35 | %%EOF 36 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # typed: true 3 | 4 | require "simplecov" 5 | SimpleCov.start do 6 | add_filter "/test/" 7 | enable_coverage :branch 8 | end 9 | 10 | $LOAD_PATH.unshift File.expand_path("../lib", __dir__) 11 | require "rubrik" 12 | 13 | require "minitest/autorun" 14 | require "minitest/pride" 15 | 16 | class Rubrik::Test < Minitest::Test 17 | make_my_diffs_pretty! 18 | parallelize_me! 19 | end 20 | 21 | module SupportPDF 22 | extend self 23 | 24 | SUPPORT_PATH = Pathname.new(__dir__).join("support").freeze 25 | 26 | def [](arg) 27 | SUPPORT_PATH.join("#{arg}.pdf") 28 | end 29 | end 30 | --------------------------------------------------------------------------------