[
  {
    "path": ".github/FUNDING.yml",
    "content": "github: hanami\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.md",
    "content": "---\nname: \"\\U0001F41B Bug report\"\nabout: See CONTRIBUTING.md for more information\ntitle: ''\nlabels: bug, help wanted\nassignees: ''\n\n---\n\n## Describe the bug\n\nA clear and concise description of what the bug is.\n\n## To Reproduce\n\nProvide detailed steps to reproduce, **an executable script would be best**.\n\n## Expected behavior\n\nA clear and concise description of what you expected to happen.\n\n## My environment\n\n- Ruby version: ...\n- OS: ...\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Community support\n    url: https://discourse.hanamirb.org\n    about: Please ask and answer questions here.\n"
  },
  {
    "path": ".github/SUPPORT.md",
    "content": "## Support\n\nIf you need help with any of the Hanami, Dry or Rom libraries, feel free to ask questions on our [discussion forum](https://discourse.hanamirb.org/). This is the best place to seek help. Make sure to search for a potential solution in past threads before posting your question. Thanks! :heart:\n"
  },
  {
    "path": ".github/workflows/ci-lint.yml",
    "content": "name: CI lint\n\non:\n  push:\n    branches: [\"main\", \"release-*\", \"ci/*\"]\n    tags: [\"v*\"]\n    paths:\n      - \".github/**\"\n  pull_request:\n    branches: [\"main\", \"release-*\"]\n    paths:\n      - \".github/**\"\n  schedule:\n    - cron: \"0 0 * * 0\" # every Sunday at midnight\n\npermissions: {}\n\njobs:\n  zizmor:\n    name: Run zizmor\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd\n        with:\n          persist-credentials: false\n\n      - name: Run zizmor\n        uses: zizmorcore/zizmor-action@0dce2577a4760a2749d8cfb7a84b7d5585ebcb7d\n        with:\n          advanced-security: false\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "# This file is synced from hanakai-rb/repo-sync\n\nname: CI\nrun-name: ${{ github.ref_type == 'tag' && format('Release {0}', github.ref_name) || 'CI' }}\n\non:\n  push:\n    branches: [\"main\", \"release-*\", \"ci/*\"]\n    tags: [\"v*\"]\n  pull_request:\n    branches: [\"main\", \"release-*\"]\n  schedule:\n    - cron: \"30 4 * * *\"\n\npermissions:\n  contents: read\n\njobs:\n  tests:\n    name: Tests (Ruby ${{ matrix.ruby }})\n    runs-on: ubuntu-latest\n    continue-on-error: ${{ matrix.optional || false }}\n    strategy:\n      fail-fast: false\n      matrix:\n        ruby:\n          - \"4.0\"\n          - \"3.4\"\n          - \"3.3\"\n          - \"jruby\"\n        include:\n          - ruby: \"4.0\"\n            coverage: \"true\"\n    env:\n      COVERAGE: ${{ matrix.coverage }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98\n        with:\n          persist-credentials: false\n      - name: Install package dependencies\n        run: \"[ -e $APT_DEPS ] || sudo apt-get install -y --no-install-recommends $APT_DEPS\"\n      - name: Set up Ruby\n        uses: ruby/setup-ruby@0cb964fd540e0a24c900370abf38a33466142735 # zizmor: ignore[cache-poisoning]\n        with:\n          ruby-version: ${{ matrix.ruby }}\n          bundler-cache: true\n      - name: Run all tests\n        id: test\n        run: |\n          status=0\n          bundle exec rake || status=$?\n          if [ ${status} -ne 0 ] && [ \"${{ matrix.optional }}\" == \"true\" ]; then\n            echo \"::warning::Optional matrix job failed.\"\n            echo \"optional_fail=true\" >> \"${GITHUB_OUTPUT}\"\n            echo \"optional_fail_status=${status}\" >> \"${GITHUB_OUTPUT}\"\n            exit 0  # Ignore error here to keep the green checkmark\n          fi\n          exit ${status}\n      - name: Create optional failure comment\n        if: ${{ matrix.optional && github.event.pull_request }}\n        uses: hanakai-rb/repo-sync/pr-comment-artifact@main\n        with:\n          name: ci-ruby-${{ matrix.ruby }}\n          pr-number: ${{ github.event.pull_request.number }}\n          comment-tag: ruby-${{ matrix.ruby }}-optional-failure\n          message: \"ℹ️ Optional job failed: Ruby ${{ matrix.ruby }}\"\n          mode: ${{ steps.test.outputs.optional_fail == 'true' && 'upsert' || 'delete' }}\n\n  workflow-keepalive:\n    if: github.event_name == 'schedule'\n    runs-on: ubuntu-latest\n    permissions:\n      actions: write\n    steps:\n      - uses: liskin/gh-workflow-keepalive@7a9194bad497f0b993708eeaf10fc0a2d726eb71\n\n  release:\n    runs-on: ubuntu-latest\n    if: github.ref_type == 'tag'\n    needs: tests\n    steps:\n      - name: Trigger release workflow\n        uses: actions/github-script@450193c5abd4cdb17ba9f3ffcfe8f635c4bb6c2a\n        with:\n          github-token: ${{ secrets.RELEASE_MACHINE_DISPATCH_TOKEN }}\n          script: |\n            const tag = context.ref.replace(\"refs/tags/\", \"\");\n            const repo = context.repo.owner + \"/\" + context.repo.repo;\n\n            const tagMessage = await github.rest.git.getTag({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              tag_sha: context.sha\n            }).then(res => res.data.message).catch(() => \"\");\n            const announce = /(skip-announce|no-announce)/i.test(tagMessage) ? \"false\" : \"true\";\n\n            await github.rest.actions.createWorkflowDispatch({\n              owner: \"hanakai-rb\",\n              repo: \"release-machine\",\n              workflow_id: \"release.yml\",\n              ref: \"main\",\n              inputs: { repo, tag, announce }\n            });\n\n            const workflowUrl = \"https://github.com/hanakai-rb/release-machine/actions/workflows/release.yml\";\n            await core.summary\n              .addHeading(\"Release Triggered\")\n              .addRaw(`Triggered release workflow for <code>${tag}</code>`)\n              .addLink(\"View release workflow\", workflowUrl)\n              .write();\n  \n\n"
  },
  {
    "path": ".github/workflows/pr-comments.yml",
    "content": "# This file is synced from hanakai-rb/repo-sync\n\n# Downloads comment artifacts from completed workflows and posts them to PRs. This allows source\n# workflows to run with read-only permissions on fork PRs while still posting comments via this\n# privileged workflow that runs in the base repo context.\n#\n# Comment artifacts should be generated using the `hanakai-rb/repo-sync/pr-comment-artifact@main`\n# action.\n\nname: PR comments\n\non: # zizmor: ignore[dangerous-triggers]\n  workflow_run:\n    workflows: [\"CI\"]\n    types:\n      - completed\n\npermissions:\n  pull-requests: write\n\njobs:\n  post-comments:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    if: github.event.workflow_run.event == 'pull_request'\n\n    steps:\n      - name: Post comments\n        uses: hanakai-rb/repo-sync/pr-comments-from-artifacts@main\n        with:\n          workflow-run-id: ${{ github.event.workflow_run.id }}\n"
  },
  {
    "path": ".github/workflows/repo-sync-preview.yml",
    "content": "name: Repo-sync preview\n\non: # zizmor: ignore[dangerous-triggers]\n  workflow_run:\n    workflows: [\"CI\", \"RuboCop\", \"CI lint\"]\n    types: [completed]\n    branches:\n      - \"ci/repo-sync-preview-*\"\n\njobs:\n  report:\n    runs-on: ubuntu-latest\n    permissions: {}\n    if: >\n      github.event.workflow_run.event == 'push' &&\n      github.event.workflow_run.head_repository.fork == false\n    steps:\n      - name: Dispatch status to repo-sync\n        uses: actions/github-script@450193c5abd4cdb17ba9f3ffcfe8f635c4bb6c2a\n        with:\n          github-token: ${{ secrets.REPO_SYNC_DISPATCH_TOKEN }}\n          script: |\n            const { BRANCH, REPO, WORKFLOW, STATUS, RUN_URL } = process.env;\n            await github.rest.actions.createWorkflowDispatch({\n              owner: \"hanakai-rb\",\n              repo: \"repo-sync\",\n              workflow_id: \"aggregate-preview-status.yml\",\n              ref: \"main\",\n              inputs: {\n                pr_number: BRANCH.replace(\"ci/repo-sync-preview-\", \"\"),\n                repo_name: REPO,\n                workflow_name: WORKFLOW,\n                status: STATUS,\n                run_url: RUN_URL\n              }\n            });\n        env:\n          BRANCH: ${{ github.event.workflow_run.head_branch }}\n          REPO: ${{ github.repository }}\n          WORKFLOW: ${{ github.event.workflow_run.name }}\n          STATUS: ${{ github.event.workflow_run.conclusion }}\n          RUN_URL: ${{ github.event.workflow_run.html_url }}\n"
  },
  {
    "path": ".github/workflows/rubocop.yml",
    "content": "# frozen_string_literal: true\n\n# This file is synced from hanakai-rb/repo-sync\n\nname: RuboCop\n\non:\n  push:\n    branches: [\"main\", \"release-*\", \"ci/*\"]\n    tags: [\"v*\"]\n  pull_request:\n    branches: [\"main\", \"release-*\"]\n\npermissions:\n  contents: read\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    env:\n      BUNDLE_ONLY: tools\n\n    steps:\n      - uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98\n        with:\n          persist-credentials: false\n\n      - name: Set up Ruby 4.0\n        uses: ruby/setup-ruby@0cb964fd540e0a24c900370abf38a33466142735 # zizmor: ignore[cache-poisoning]\n        with:\n          ruby-version: 4.0\n          bundler-cache: true\n\n      - name: Run RuboCop\n        run: bundle exec rubocop --parallel\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\ncoverage\n/.bundle\nvendor/bundle\ntmp/\npkg/\n.idea/\nGemfile.lock\n/.rubocop-*\n"
  },
  {
    "path": ".rspec",
    "content": "--color\n--require spec_helper\n--order random\n--warnings\n"
  },
  {
    "path": ".rubocop.yml",
    "content": "# This file is synced from hanakai-rb/repo-sync\n\ninherit_from:\n  - https://raw.githubusercontent.com/hanakai-rb/repo-sync/main/rubocop/rubocop.yml\n  <% if File.exist?(\".rubocop.local.yml\") %>\n  - .rubocop.local.yml\n  <% end %>\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Break Versioning](https://www.taoensso.com/break-versioning).\n\n## [Unreleased]\n\n### Changed\n\n- Set minumum Ruby version to 3.2 (@alassek)\n\n## [1.6.0] - 2025-01-04\n\n\n### Added\n\n- Support for more UUID formats (via #110) (@Ptico)\n\n### Fixed\n\n- Fix NoMethodError when trying to get AST of a Builder's result. (via #107) (@estum)\n\n### Changed\n\n- Set 3.1 as minimum ruby version (@flash-gordon)\n\n[Compare v1.5.0...v1.6.0](https://github.com/dry-rb/dry-logic/compare/v1.5.0...v1.6.0)\n\n## [1.5.0] - 2022-11-24\n\n\n### Added\n\n- `uri_rfc3986?` predicate that uses a better regexp than `uri?` (see #94 for more details) (@hieuk09)\n\n### Changed\n\n- Made `Predicates.respond_to?` compatible with `Object#respond_to?` (via #105) (@solnic)\n- Made `Predicates.eql?` compatible with `Object#eql?` (via #106) (@solnic)\n\n[Compare v1.4.0...v1.5.0](https://github.com/dry-rb/dry-logic/compare/v1.4.0...v1.5.0)\n\n## [1.4.0] - 2022-11-04\n\n\n### Changed\n\n- Updated to dry-core 1.0 (@flash-gordon + @solnic)\n\n[Compare v1.3.0...v1.4.0](https://github.com/dry-rb/dry-logic/compare/v1.3.0...v1.4.0)\n\n## [1.3.0] - 2022-10-15\n\n\n### Changed\n\n- Use zeitwerk for auto-loading (@solnic + @flash-gordon)\n\n[Compare v1.2.0...v1.3.0](https://github.com/dry-rb/dry-logic/compare/v1.2.0...v1.3.0)\n\n## [1.2.0] - 2021-04-26\n\n\n### Added\n\n- Add predicate and operation builder DSL (@oleander)\n\n\n[Compare v1.1.1...v1.2.0](https://github.com/dry-rb/dry-logic/compare/v1.1.1...v1.2.0)\n\n## [1.1.1] - 2021-04-14\n\n\n### Fixed\n\n- Fixed a crash under jruby caused by arg splatting in Binary operations (@flash-gordon)\n\n\n[Compare v1.1.0...v1.1.1](https://github.com/dry-rb/dry-logic/compare/v1.1.0...v1.1.1)\n\n## [1.1.0] - 2020-12-26\n\n\n### Fixed\n\n- Nested `Check` operations no longer crash under MRI 3.0 (@oleander)\n\n### Changed\n\n- Switched to equalizer from dry-core (@solnic)\n\n[Compare v1.0.8...v1.1.0](https://github.com/dry-rb/dry-logic/compare/v1.0.8...v1.1.0)\n\n## [1.0.8] - 2020-09-28\n\n\n### Fixed\n\n- Better Ruby 3 support with fixed specialization for rules of negative arity (@flash-gordon)\n\n\n[Compare v1.0.7...v1.0.8](https://github.com/dry-rb/dry-logic/compare/v1.0.7...v1.0.8)\n\n## [1.0.7] - 2020-08-13\n\n\n### Added\n\n- A new `uri?` predicate that you can use to verify `URI` strings, ie `uri?(\"https\", \"https://dry-rb.org\")` (@nerburish)\n- New predicates: `uuid_v1?`, `uuid_v2?`, `uuid_v3?` and `uuid_v5?` (via #75) (@jamesbrauman)\n\n\n[Compare v1.0.6...v1.0.7](https://github.com/dry-rb/dry-logic/compare/v1.0.6...v1.0.7)\n\n## [1.0.6] - 2020-02-10\n\n\n### Fixed\n\n- Made the regexp used by `uuid_v4?` more secure (@kml)\n\n\n[Compare v1.0.5...v1.0.6](https://github.com/dry-rb/dry-logic/compare/v1.0.5...v1.0.6)\n\n## [1.0.5] - 2019-11-07\n\n\n### Fixed\n\n- Make `format?` tolerant to `nil` values. It already worked like that before, but starting Ruby 2.7 it would produce warnings. Now it won't. Don't rely on this behavior, it's only added to make tests pass in dry-schema. Use explicit type checks instead (@flash-gordon)\n\n\n[Compare v1.0.4...v1.0.5](https://github.com/dry-rb/dry-logic/compare/v1.0.4...v1.0.5)\n\n## [1.0.4] - 2019-11-06\n\n\n### Fixed\n\n- Fix keyword warnings (@flash-gordon)\n\n\n[Compare v1.0.3...v1.0.4](https://github.com/dry-rb/dry-logic/compare/v1.0.3...v1.0.4)\n\n## [1.0.3] - 2019-08-01\n\n\n### Added\n\n- `bytesize?` predicate (@bmalinconico)\n- `min_bytesize?` predicate (@bmalinconico)\n- `max_bytesize? predicate (@bmalinconico)\n\n### Changed\n\n- Min ruby version was set to `>= 2.4.0` (@flash-gordon)\n\n[Compare v1.0.2...v1.0.3](https://github.com/dry-rb/dry-logic/compare/v1.0.2...v1.0.3)\n\n## [1.0.2] - 2019-06-14\n\nRe-pushed 1.0.1 after dry-schema 1.2.0 release.\n\n\n[Compare v1.0.1...v1.0.2](https://github.com/dry-rb/dry-logic/compare/v1.0.1...v1.0.2)\n\n## [1.0.1] - 2019-06-04\n\nThis release was removed from rubygems because it broke dry-schema.\n\n### Added\n\n- `uuid_v4?` predicate (radar)\n- `respond_to?` predicate (waiting-for-dev)\n\n\n[Compare v1.0.0...v1.0.1](https://github.com/dry-rb/dry-logic/compare/v1.0.0...v1.0.1)\n\n## [1.0.0] - 2019-04-23\n\n\n### Changed\n\n- Version bump to `1.0.0` (flash-gordon)\n\n[Compare v0.6.1...v1.0.0](https://github.com/dry-rb/dry-logic/compare/v0.6.1...v1.0.0)\n\n## [0.6.1] - 2019-04-18\n\n\n### Fixed\n\n- Fix a regression in dry-validation 0.x for argument-less predicates (flash-gordon)\n\n\n[Compare v0.6.0...v0.6.1](https://github.com/dry-rb/dry-logic/compare/v0.6.0...v0.6.1)\n\n## [0.6.0] - 2019-04-04\n\n\n### Added\n\n- Generating hints can be disabled by building `Operations::And` with `hints: false` option set (solnic)\n\n### Changed\n\n- `Rule` construction has been optimized so that currying and application is multiple-times faster (flash-gordon)\n\n[Compare v0.5.0...v0.6.0](https://github.com/dry-rb/dry-logic/compare/v0.5.0...v0.6.0)\n\n## [0.5.0] - 2019-01-29\n\n\n### Added\n\n- `:nil?` predicate (`none?` is now an alias) (solnic)\n\n### Fixed\n\n- `Operation::Key#ast` will now return a correct AST with non-Undefined inputs (solnic)\n\n\n[Compare v0.4.2...v0.5.0](https://github.com/dry-rb/dry-logic/compare/v0.4.2...v0.5.0)\n\n## [0.4.2] - 2017-09-15\n\n\n### Added\n\n- New `:case?` predicate matches a value against the given object with `#===` (flash-gordon)\n- New `:is?` predicate checks objects identity (using `#equal?`) (flash-gordon)\n\n### Fixed\n\n- A bug with using custom predicates within a standalone module in `dry-validation` (flash-gordon)\n\n\n[Compare v0.4.1...v0.4.2](https://github.com/dry-rb/dry-logic/compare/v0.4.1...v0.4.2)\n\n## [0.4.1] - 2017-01-23\n\n\n### Fixed\n\n- Warnings on MRI 2.4.0 are gone (jtippett)\n\n### Changed\n\n- Predicates simply reuse other predicate methods instead of referring to them via `#[]` (georgemillo)\n\n[Compare v0.4.0...v0.4.1](https://github.com/dry-rb/dry-logic/compare/v0.4.0...v0.4.1)\n\n## [0.4.0] - 2016-09-21\n\nThis is a partial rewrite focused on internal clean up and major performance improvements. This is also the beginning of the work to make this library first-class rather than \"just\" a rule backend for dry-validation and dry-types.\n\n### Added\n\n- `Rule#[]` which applies a rule and always returns `true` or `false` (solnic)\n- `Rule#bind` which returns a rule with its predicate bound to a given object (solnic)\n- `Rule#eval_args` which evaluates unbound-methods-args in the context of a given object (solnic)\n- `Logic.Rule` builder function (solnic)\n- Nice `#inspect` on rules and operation objects (solnic)\n\n### Changed\n\n- [BRAEKING] New result API (solnic)\n- [BREAKING] `Predicate` is now `Rule::Predicate` (solnic)\n- [BREAKING] `Rule::Conjunction` is now `Operation::And` (solnic)\n- [BREAKING] `Rule::Disjunction` is now `Operation::Or` (solnic)\n- [BREAKING] `Rule::ExlusiveDisjunction` is now `Operation::Xor` (solnic)\n- [BREAKING] `Rule::Implication` is now `Operation::Implication` (solnic)\n- [BREAKING] `Rule::Set` is now `Operation::Set` (solnic)\n- [BREAKING] `Rule::Each` is now `Operation::Each` (solnic)\n- [BREAKING] `Rule.new` accepts a predicate function as its first arg now (solnic)\n- [BREAKING] `Rule#name` is now `Rule#id` (solnic)\n- `Rule#parameters` is public now (solnic)\n\n[Compare v0.3.0...v0.4.0](https://github.com/dry-rb/dry-logic/compare/v0.3.0...v0.4.0)\n\n## [0.3.0] - 2016-07-01\n\n\n### Added\n\n- `:type?` predicate imported from dry-types (solnic)\n- `Rule#curry` interface (solnic)\n\n### Changed\n\n- Predicates AST now includes information about args (names & possible values) (fran-worley + solnic)\n- Predicates raise errors when they are called with invalid arity (fran-worley + solnic)\n- Rules no longer evaluate input twice when building result objects (solnic)\n\n[Compare v0.2.3...v0.3.0](https://github.com/dry-rb/dry-logic/compare/v0.2.3...v0.3.0)\n\n## [0.2.3] - 2016-05-11\n\n\n### Added\n\n- `not_eql?`, `includes?`, `excludes?` predicates (fran-worley)\n\n### Changed\n\n- Renamed `inclusion?` to `included_in?` and deprecated `inclusion?` (fran-worley)\n- Renamed `exclusion?` to `excluded_from?` and deprecated `exclusion?` (fran-worley)\n\n[Compare v0.2.2...v0.2.3](https://github.com/dry-rb/dry-logic/compare/v0.2.2...v0.2.3)\n\n## [0.2.2] - 2016-03-30\n\n\n### Added\n\n- `number?`, `odd?`, `even?` predicates (fran-worley)\n\n\n[Compare v0.2.1...v0.2.2](https://github.com/dry-rb/dry-logic/compare/v0.2.1...v0.2.2)\n\n## [0.2.1] - 2016-03-20\n\n\n### Fixed\n\n- Result AST for `Rule::Each` correctly maps elements with eql inputs (solnic)\n\n\n[Compare v0.2.0...v0.2.1](https://github.com/dry-rb/dry-logic/compare/v0.2.0...v0.2.1)\n\n## [0.2.0] - 2016-03-11\n\n\n### Changed\n\n- Entire AST has been redefined (solnic)\n\n[Compare v0.1.4...v0.2.0](https://github.com/dry-rb/dry-logic/compare/v0.1.4...v0.2.0)\n\n## [0.1.4] - 2016-01-27\n\n\n### Added\n\n- Support for hash-names in `Check` and `Result` which can properly resolve input\n  from nested results (solnic)\n\n\n[Compare v0.1.3...v0.1.4](https://github.com/dry-rb/dry-logic/compare/v0.1.3...v0.1.4)\n\n## [0.1.3] - 2016-01-27\n\n\n### Added\n\n- Support for resolving input from `Rule::Result` (solnic)\n\n### Changed\n\n- `Check` and `Result` carry original input(s) (solnic)\n\n[Compare v0.1.2...v0.1.3](https://github.com/dry-rb/dry-logic/compare/v0.1.2...v0.1.3)\n\n## [0.1.2] - 2016-01-19\n\n\n### Fixed\n\n- `xor` returns wrapped results when used against another result-rule (solnic)\n\n\n[Compare v0.1.1...v0.1.2](https://github.com/dry-rb/dry-logic/compare/v0.1.1...v0.1.2)\n\n## [0.1.1] - 2016-01-18\n\n\n### Added\n\n- `Rule::Attr` which can be applied to a data object with attr readers (SunnyMagadan)\n- `Rule::Result` which can be applied to a result object (solnic)\n- `true?` and `false?` predicates (solnic)\n\n\n[Compare v0.1.0...v0.1.1](https://github.com/dry-rb/dry-logic/compare/v0.1.0...v0.1.1)\n\n## [0.1.0] - 2016-01-11\n\nCode extracted from dry-validation 0.4.1\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe pledge to make our community welcoming, safe, and equitable for all.\n\nWe are committed to fostering an environment that respects and promotes the dignity, rights, and contributions of all individuals, regardless of characteristics including race, ethnicity, caste, color, age, physical characteristics, neurodiversity, disability, sex or gender, gender identity or expression, sexual orientation, language, philosophy or religion, national or social origin, socio-economic position, level of education, or other status. The same privileges of participation are extended to everyone who participates in good faith and in accordance with this Covenant.\n\n## Encouraged Behaviors\n\nWhile acknowledging differences in social norms, we all strive to meet our community's expectations for positive behavior. We also understand that our words and actions may be interpreted differently than we intend based on culture, background, or native language.\n\nWith these considerations in mind, we agree to behave mindfully toward each other and act in ways that center our shared values, including:\n\n1. Respecting the **purpose of our community**, our activities, and our ways of gathering.\n2. Engaging **kindly and honestly** with others.\n3. Respecting **different viewpoints** and experiences.\n4. **Taking responsibility** for our actions and contributions.\n5. Gracefully giving and accepting **constructive feedback**.\n6. Committing to **repairing harm** when it occurs.\n7. Behaving in other ways that promote and sustain the **well-being of our community**.\n\n## Restricted Behaviors\n\nWe agree to restrict the following behaviors in our community. Instances, threats, and promotion of these behaviors are violations of this Code of Conduct.\n\n1. **Harassment.** Violating explicitly expressed boundaries or engaging in unnecessary personal attention after any clear request to stop.\n2. **Character attacks.** Making insulting, demeaning, or pejorative comments directed at a community member or group of people.\n3. **Stereotyping or discrimination.** Characterizing anyone’s personality or behavior on the basis of immutable identities or traits.\n4. **Sexualization.** Behaving in a way that would generally be considered inappropriately intimate in the context or purpose of the community.\n5. **Violating confidentiality**. Sharing or acting on someone's personal or private information without their permission.\n6. **Endangerment.** Causing, encouraging, or threatening violence or other harm toward any person or group.\n7. Behaving in other ways that **threaten the well-being** of our community.\n\n### Other Restrictions\n\n1. **Misleading identity.** Impersonating someone else for any reason, or pretending to be someone else to evade enforcement actions.\n2. **Failing to credit sources.** Not properly crediting the sources of content you contribute.\n3. **Promotional materials**. Sharing marketing or other commercial content in a way that is outside the norms of the community.\n4. **Irresponsible communication.** Failing to responsibly present content which includes, links or describes any other restricted behaviors.\n\n## Reporting an Issue\n\nTensions can occur between community members even when they are trying their best to collaborate. Not every conflict represents a code of conduct violation, and this Code of Conduct reinforces encouraged behaviors and norms that can help avoid conflicts and minimize harm.\n\nWhen an incident does occur, it is important to report it promptly. To report a possible violation, email conduct@hanakai.org.\n\nCommunity Moderators take reports of violations seriously and will make every effort to respond in a timely manner. They will investigate all reports of code of conduct violations, reviewing messages, logs, and recordings, or interviewing witnesses and other participants. Community Moderators will keep investigation and enforcement actions as transparent as possible while prioritizing safety and confidentiality. In order to honor these values, enforcement actions are carried out in private with the involved parties, but communicating to the whole community may be part of a mutually agreed upon resolution.\n\n## Addressing and Repairing Harm\n\nIf an investigation by the Community Moderators finds that this Code of Conduct has been violated, the following enforcement ladder may be used to determine how best to repair harm, based on the incident's impact on the individuals involved and the community as a whole. Depending on the severity of a violation, lower rungs on the ladder may be skipped.\n\n1) Warning\n   1) Event: A violation involving a single incident or series of incidents.\n   2) Consequence: A private, written warning from the Community Moderators.\n   3) Repair: Examples of repair include a private written apology, acknowledgement of responsibility, and seeking clarification on expectations.\n2) Temporarily Limited Activities\n   1) Event: A repeated incidence of a violation that previously resulted in a warning, or the first incidence of a more serious violation.\n   2) Consequence: A private, written warning with a time-limited cooldown period designed to underscore the seriousness of the situation and give the community members involved time to process the incident. The cooldown period may be limited to particular communication channels or interactions with particular community members.\n   3) Repair: Examples of repair may include making an apology, using the cooldown period to reflect on actions and impact, and being thoughtful about re-entering community spaces after the period is over.\n3) Temporary Suspension\n   1) Event: A pattern of repeated violation which the Community Moderators have tried to address with warnings, or a single serious violation.\n   2) Consequence: A private written warning with conditions for return from suspension. In general, temporary suspensions give the person being suspended time to reflect upon their behavior and possible corrective actions.\n   3) Repair: Examples of repair include respecting the spirit of the suspension, meeting the specified conditions for return, and being thoughtful about how to reintegrate with the community when the suspension is lifted.\n4) Permanent Ban\n   1) Event: A pattern of repeated code of conduct violations that other steps on the ladder have failed to resolve, or a violation so serious that the Community Moderators determine there is no way to keep the community safe with this person as a member.\n   2) Consequence: Access to all community spaces, tools, and communication channels is removed. In general, permanent bans should be rarely used, should have strong reasoning behind them, and should only be resorted to if working through other remedies has failed to change the behavior.\n   3) Repair: There is no possible repair in cases of this severity.\n\nThis enforcement ladder is intended as a guideline. It does not limit the ability of Community Managers to use their discretion and judgment, in keeping with the best interests of our community.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public or other spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event.\n\n## Attribution\n\nThis Code of Conduct is adapted from the Contributor Covenant, version 3.0, permanently available at [https://www.contributor-covenant.org/version/3/0/](https://www.contributor-covenant.org/version/3/0/).\n\nContributor Covenant is stewarded by the Organization for Ethical Source and licensed under CC BY-SA 4.0. To view a copy of this license, visit [https://creativecommons.org/licenses/by-sa/4.0/](https://creativecommons.org/licenses/by-sa/4.0/)\n\nFor answers to common questions about Contributor Covenant, see the FAQ at [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). Translations are provided at [https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations). Additional enforcement and community guideline resources can be found at [https://www.contributor-covenant.org/resources](https://www.contributor-covenant.org/resources). The enforcement ladder was inspired by the work of [Mozilla’s code of conduct team](https://github.com/mozilla/inclusion).\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Issue guidelines\n\n## Reporting bugs\n\nIf you’ve found a bug, please report an issue and describe the expected behavior versus what actually happens. If the bug causes a crash, attach a full backtrace. If possible, a reproduction script showing the problem is highly appreciated.\n\n## Reporting feature requests\n\nReport a feature request **only after discussing it first on [our forum](https://discourse.hanamirb.org)** and having it accepted. Please provide a concise description of the feature.\n\n## Reporting questions, support requests, ideas, concerns etc.\n\n**Please don’t.** Use [our forum](https://discourse.hanamirb.org) instead.\n\n# Pull request guidelines\n\nA pull request will only be accepted if it addresses a specific issue that was reported previously, or fixes typos, mistakes in documentation etc.\n\nOther requirements:\n\n1. Do not open a pull request if you can't provide tests along with it. If you have problems writing tests, ask for help in the related issue.\n2. Follow the style conventions of the surrounding code. In most cases, this is standard ruby style.\n3. Add API documentation if it's a new feature.\n4. Update API documentation if it changes an existing feature.\n5. Bonus points for sending a PR which updates user documentation in our [site repository](https://github.com/hanakai-rb/site).\n\n# Asking for help\n\nIf these guidelines aren't helpful, and you're stuck, please post a message on [our forum](https://discourse.dry-rb.org) or [find us in chat](https://discord.gg/KFCxDmk3JQ).\n"
  },
  {
    "path": "Gemfile",
    "content": "# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\n\neval_gemfile \"Gemfile.devtools\"\n\ngemspec\n\ngroup :tools do\n  gem \"benchmark-ips\", platform: :mri\n  # gem \"hotch\", platform: :mri\nend\n"
  },
  {
    "path": "Gemfile.devtools",
    "content": "# frozen_string_literal: true\n\n# This file is synced from hanakai-rb/repo-sync\n\ngem \"rake\", \">= 12.3.3\"\n\ngroup :test do\n  gem \"simplecov\", require: false, platforms: :ruby\n  gem \"simplecov-cobertura\", require: false, platforms: :ruby\n  gem \"rexml\", require: false\n\n  gem \"warning\"\nend\n\ngroup :tools do\n  gem \"rubocop\"\nend\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015-2026 Hanakai team\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<!--- This file is synced from hanakai-rb/repo-sync -->\n\n[actions]: https://github.com/dry-rb/dry-logic/actions\n[chat]: https://discord.gg/naQApPAsZB\n[forum]: https://discourse.hanamirb.org\n[rubygem]: https://rubygems.org/gems/dry-logic\n\n# dry-logic [![Gem Version](https://badge.fury.io/rb/dry-logic.svg)][rubygem] [![CI Status](https://github.com/dry-rb/dry-logic/workflows/CI/badge.svg)][actions]\n\n[![Forum](https://img.shields.io/badge/Forum-dc360f?logo=discourse&logoColor=white)][forum]\n[![Chat](https://img.shields.io/badge/Chat-717cf8?logo=discord&logoColor=white)][chat]\n\n## Links\n\n- [User documentation](https://dry-rb.org/gems/dry-logic)\n- [API documentation](http://rubydoc.info/gems/dry-logic)\n- [Forum](https://discourse.dry-rb.org)\n\n## License\n\nSee `LICENSE` file.\n\n"
  },
  {
    "path": "Rakefile",
    "content": "#!/usr/bin/env rake\n# frozen_string_literal: true\n\nrequire \"bundler/gem_tasks\"\n\n$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), \"lib\"))\n\nrequire \"rspec/core\"\nrequire \"rspec/core/rake_task\"\n\ntask default: :spec\n\ndesc \"Run all specs in spec directory\"\nRSpec::Core::RakeTask.new(:spec)\n"
  },
  {
    "path": "benchmarks/builder.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"benchmark/ips\"\nrequire \"dry/logic\"\nrequire \"dry/logic/builder\"\n\ndef regular\n  user_present = Dry::Logic::Rule::Predicate.new(Dry::Logic::Predicates[:key?]).curry(:user)\n  min_age = Dry::Logic::Rule::Predicate.new(Dry::Logic::Predicates[:gt?]).curry(18)\n  has_min_age = Dry::Logic::Operations::Key.new(min_age, name: %i[user age])\n  user_present & has_min_age\nend\n\ndef builder\n  Dry::Logic::Builder.call do\n    key?(:user) & key(name: %i[user age]) { gt?(18) }\n  end\nend\n\nBenchmark.ips do |x|\n  x.report(\"builder\") do\n    builder.(user: {age: 19})\n    builder.(user: {age: 18})\n  end\n\n  x.report(\"regular\") do\n    regular.(user: {age: 18})\n    regular.(user: {age: 19})\n  end\n\n  x.compare!\nend\n"
  },
  {
    "path": "benchmarks/rule_application.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative \"setup\"\n\nunless Dry::Logic::Rule.respond_to?(:build)\n  Dry::Logic::Rule.singleton_class.alias_method(:build, :new)\nend\n\npredicates = Dry::Logic::Predicates\n\ntype_check = Dry::Logic::Rule.build(predicates[:type?]).curry(Integer)\nint_check = Dry::Logic::Rule.build(predicates[:int?])\nkey_check = Dry::Logic::Rule.build(predicates[:key?]).curry(:user)\nwith_user = { user: {} }\nwithout_user = {}\n\ncomparison = Dry::Logic::Rule.build(predicates[:gteq?]).curry(18)\n\nBenchmark.ips do |x|\n  x.report(\"type check - success\") { type_check.(0) }\n  x.report(\"type check - failure\") { type_check.(\"0\") }\n  x.report(\"int check - success\") { int_check.(0) }\n  x.report(\"int check - failure\") { int_check.(\"0\") }\n  x.report(\"key check - success\") { key_check.(with_user) }\n  x.report(\"key check - failure\") { key_check.(without_user) }\n  x.report(\"comparison - success\") { comparison.(20) }\n  x.report(\"comparison - failure\") { comparison.(17) }\n\n  x.compare!\nend\n"
  },
  {
    "path": "benchmarks/setup.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"benchmark/ips\"\nrequire \"hotch\"\nENV[\"HOTCH_VIEWER\"] ||= \"open\"\n\nrequire \"dry/logic\"\nrequire \"dry/logic/predicates\"\n\ndef profile(&block)\n  Hotch(filter: \"Dry\", &block)\nend\n\n"
  },
  {
    "path": "bin/.gitkeep",
    "content": ""
  },
  {
    "path": "bin/console",
    "content": "#!/usr/bin/env ruby\n# frozen_string_literal: true\n\nrequire \"bundler/setup\"\nrequire \"dry/logic\"\nrequire \"dry/logic/predicates\"\n\n# rubocop:disable Style/MixinUsage\ninclude Dry::Logic\n# rubocop:enable Style/MixinUsage\n\nrequire \"irb\"\nIRB.start\n"
  },
  {
    "path": "dry-logic.gemspec",
    "content": "# frozen_string_literal: true\n\n# This file is synced from hanakai-rb/repo-sync. To update it, edit repo-sync.yml.\n\nlib = File.expand_path(\"lib\", __dir__)\n$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)\nrequire \"dry/logic/version\"\n\nGem::Specification.new do |spec|\n  spec.name          = \"dry-logic\"\n  spec.authors       = [\"Hanakai team\"]\n  spec.email         = [\"info@hanakai.org\"]\n  spec.license       = \"MIT\"\n  spec.version       = Dry::Logic::VERSION.dup\n\n  spec.summary       = \"Predicate logic with rule composition\"\n  spec.description   = spec.summary\n  spec.homepage      = \"https://dry-rb.org/gems/dry-logic\"\n  spec.files         = Dir[\"CHANGELOG.md\", \"LICENSE\", \"README.md\", \"dry-logic.gemspec\", \"lib/**/*\"]\n  spec.bindir        = \"exe\"\n  spec.executables   = Dir[\"exe/*\"].map { |f| File.basename(f) }\n  spec.require_paths = [\"lib\"]\n\n  spec.extra_rdoc_files = [\"README.md\", \"CHANGELOG.md\", \"LICENSE\"]\n\n  spec.metadata[\"changelog_uri\"]     = \"https://github.com/dry-rb/dry-logic/blob/main/CHANGELOG.md\"\n  spec.metadata[\"source_code_uri\"]   = \"https://github.com/dry-rb/dry-logic\"\n  spec.metadata[\"bug_tracker_uri\"]   = \"https://github.com/dry-rb/dry-logic/issues\"\n  spec.metadata[\"funding_uri\"]       = \"https://github.com/sponsors/hanami\"\n\n  spec.required_ruby_version = \">= 3.3\"\n\n  spec.add_runtime_dependency \"bigdecimal\"\n  spec.add_runtime_dependency \"concurrent-ruby\", \"~> 1.0\"\n  spec.add_runtime_dependency \"dry-core\", \"~> 1.1\"\n  spec.add_runtime_dependency \"zeitwerk\", \"~> 2.6\"\n  spec.add_development_dependency \"bundler\"\n  spec.add_development_dependency \"rake\"\n  spec.add_development_dependency \"rspec\"\nend\n\n"
  },
  {
    "path": "examples/basic.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic\"\nrequire \"dry/logic/predicates\"\n\n# rubocop:disable Style/MixinUsage\ninclude Dry::Logic\n# rubocop:enable Style/MixinUsage\n\nuser_present = Rule::Predicate.build(Predicates[:key?]).curry(:user)\n\nhas_min_age = Operations::Key.new(Rule::Predicate.build(Predicates[:gt?]).curry(18),\n                                  name: %i[user age])\n\nuser_rule = user_present & has_min_age\n\nputs user_rule.(user: {age: 19}).success?\n\nputs user_rule.(user: {age: 18}).success?\n"
  },
  {
    "path": "lib/dry/logic/appliable.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    module Appliable\n      def id\n        options[:id]\n      end\n\n      def result\n        options[:result]\n      end\n\n      def applied?\n        !result.nil?\n      end\n\n      def success?\n        result.equal?(true)\n      end\n\n      def failure?\n        !success?\n      end\n\n      def to_ast\n        if applied? && id\n          [success? ? :success : :failure, [id, ast]]\n        else\n          ast\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/builder.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"singleton\"\nrequire \"delegate\"\n\nmodule Dry\n  module Logic\n    module Builder\n      IGNORED_OPERATIONS = %i[\n        Abstract\n        Binary\n        Unary\n      ].freeze\n\n      IGNORED_PREDICATES = [\n        :predicate\n      ].freeze\n\n      # Predicate and operation builder\n      #\n      # @block [Proc]\n      # @return [Builder::Result]\n      # @example Check if input is zero\n      #   is_zero = Dry::Logic::Builder.call do\n      #     negation { lt?(0) ^ gt?(0) }\n      #   end\n      #\n      #   p is_zero.call(1) # => false\n      #   p is_zero.call(0) # => true\n      #   p is_zero.call(-1) # => false\n      def call(&)\n        Context.instance.call(&)\n      end\n      module_function :call\n      alias_method :build, :call\n      public :call, :build\n\n      class Context\n        include Dry::Logic\n        include Singleton\n\n        module Predicates\n          include Logic::Predicates\n        end\n\n        # @see Builder#call\n        def call(&)\n          instance_eval(&)\n        end\n\n        # Defines custom predicate\n        #\n        # @name [Symbol] Name of predicate\n        # @Context [Proc]\n        def predicate(name, context = nil, &block)\n          if singleton_class.method_defined?(name)\n            singleton_class.undef_method(name)\n          end\n\n          predicate = Rule::Predicate.new(context || block)\n\n          define_singleton_method(name) do |*args|\n            predicate.curry(*args)\n          end\n        end\n\n        # Defines methods for operations and predicates\n        def initialize\n          Operations.constants(false).each do |name|\n            next if IGNORED_OPERATIONS.include?(name)\n\n            operation = Operations.const_get(name)\n\n            define_singleton_method(name.downcase) do |*args, **kwargs, &block|\n              operation.new(*call(&block), *args, **kwargs)\n            end\n          end\n\n          Predicates::Methods.instance_methods(false).each do |name|\n            unless IGNORED_PREDICATES.include?(name)\n              predicate(name, Predicates[name])\n            end\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/evaluator.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    class Evaluator\n      include Dry::Equalizer(:path)\n\n      attr_reader :path\n\n      class Set\n        include Dry::Equalizer(:evaluators)\n\n        attr_reader :evaluators\n\n        def self.new(paths)\n          super(paths.map { |path| Evaluator::Key.new(path) })\n        end\n\n        def initialize(evaluators)\n          @evaluators = evaluators\n        end\n\n        def call(input)\n          evaluators.map { |evaluator| evaluator[input] }\n        end\n        alias_method :[], :call\n      end\n\n      class Key < Evaluator\n        def call(input)\n          path.reduce(input) { |a, e| a[e] }\n        end\n        alias_method :[], :call\n      end\n\n      class Attr < Evaluator\n        def call(input)\n          path.reduce(input) { |a, e| a.public_send(e) }\n        end\n        alias_method :[], :call\n      end\n\n      def initialize(path)\n        @path = Array(path)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/operations/abstract.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    module Operations\n      class Abstract\n        include Core::Constants\n        include ::Dry::Equalizer(:rules, :options)\n        include Operators\n\n        attr_reader :rules\n\n        attr_reader :options\n\n        def initialize(*rules, **options)\n          @rules = rules\n          @options = options\n        end\n\n        def id\n          options[:id]\n        end\n\n        def curry(*args)\n          new(rules.map { |rule| rule.curry(*args) }, **options)\n        end\n\n        def new(rules, **new_options)\n          self.class.new(*rules, **options, **new_options)\n        end\n\n        def with(new_options)\n          new(rules, **options, **new_options)\n        end\n\n        def to_ast\n          ast\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/operations/and.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    module Operations\n      class And < Binary\n        attr_reader :hints\n\n        def initialize(*, **)\n          super\n          @hints = options.fetch(:hints, true)\n        end\n\n        def type\n          :and\n        end\n        alias_method :operator, :type\n\n        def call(input)\n          left_result = left.(input)\n\n          if left_result.success?\n            right_result = right.(input)\n\n            if right_result.success?\n              Result::SUCCESS\n            else\n              Result.new(false, id) { right_result.ast(input) }\n            end\n          else\n            Result.new(false, id) do\n              left_ast = left_result.to_ast\n              hints ? [type, [left_ast, [:hint, right.ast(input)]]] : left_ast\n            end\n          end\n        end\n\n        def [](input)\n          left[input] && right[input]\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/operations/attr.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    module Operations\n      class Attr < Key\n        def self.evaluator(name)\n          Evaluator::Attr.new(name)\n        end\n\n        def type\n          :attr\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/operations/binary.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    module Operations\n      class Binary < Abstract\n        attr_reader :left\n\n        attr_reader :right\n\n        def initialize(left, right, **options)\n          super\n          @left = left\n          @right = right\n        end\n\n        def ast(input = Undefined)\n          [type, [left.ast(input), right.ast(input)]]\n        end\n\n        def to_s\n          \"#{left} #{operator.to_s.upcase} #{right}\"\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/operations/check.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    module Operations\n      class Check < Unary\n        attr_reader :evaluator\n\n        def self.new(rule, **options)\n          if options[:evaluator]\n            super\n          else\n            keys = options.fetch(:keys)\n            evaluator = Evaluator::Set.new(keys)\n\n            super(rule, **options, evaluator: evaluator)\n          end\n        end\n\n        def initialize(*rules, **options)\n          super\n          @evaluator = options[:evaluator]\n        end\n\n        def type\n          :check\n        end\n\n        def call(input)\n          *head, tail = evaluator[input]\n          result = rule.curry(*head).(tail)\n\n          if result.success?\n            Result::SUCCESS\n          else\n            Result.new(false, id) { [type, [options[:keys], result.to_ast]] }\n          end\n        end\n\n        def [](input)\n          rule[*evaluator[input].reverse]\n        end\n\n        def ast(input = Undefined)\n          [type, [options[:keys], rule.ast(input)]]\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/operations/each.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    module Operations\n      class Each < Unary\n        def type\n          :each\n        end\n\n        def call(input)\n          results = input.map { |element| rule.(element) }\n          success = results.all?(&:success?)\n\n          Result.new(success, id) do\n            failures = results\n              .map\n              .with_index { |result, idx| [:key, [idx, result.ast(input[idx])]] if result.failure? }\n              .compact\n\n            [:set, failures]\n          end\n        end\n\n        def [](arr)\n          arr.all? { |input| rule[input] }\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/operations/implication.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    module Operations\n      class Implication < Binary\n        def type\n          :implication\n        end\n\n        def operator\n          :then\n        end\n\n        def call(input)\n          left_result = left.(input)\n\n          if left_result.success?\n            right_result = right.(input)\n            Result.new(right_result.success?, id) { right_result.to_ast }\n          else\n            Result::SUCCESS\n          end\n        end\n\n        def [](input)\n          if left[input]\n            right[input]\n          else\n            true\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/operations/key.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    module Operations\n      class Key < Unary\n        attr_reader :evaluator\n\n        attr_reader :path\n\n        def self.new(rules, **options)\n          if options[:evaluator]\n            super\n          else\n            name = options.fetch(:name)\n            eval = options.fetch(:evaluator, evaluator(name))\n            super(rules, **options, evaluator: eval, path: name)\n          end\n        end\n\n        def self.evaluator(name)\n          Evaluator::Key.new(name)\n        end\n\n        def initialize(*rules, **options)\n          super\n          @evaluator = options[:evaluator]\n          @path = options[:path]\n        end\n\n        def type\n          :key\n        end\n\n        def call(hash)\n          input = evaluator[hash]\n          result = rule.(input)\n\n          if result.success?\n            Result::SUCCESS\n          else\n            Result.new(false, path) { [type, [path, result.to_ast]] }\n          end\n        end\n\n        def [](hash)\n          rule[evaluator[hash]]\n        end\n\n        def ast(input = Undefined)\n          if input.equal?(Undefined) || !input.is_a?(Hash)\n            [type, [path, rule.ast]]\n          else\n            [type, [path, rule.ast(evaluator[input])]]\n          end\n        end\n\n        def to_s\n          \"#{type}[#{path}](#{rule})\"\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/operations/negation.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    module Operations\n      class Negation < Unary\n        def type\n          :not\n        end\n\n        def call(input)\n          Result.new(rule.(input).failure?, id) { ast(input) }\n        end\n\n        def [](input)\n          !rule[input]\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/operations/or.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    module Operations\n      class Or < Binary\n        def type\n          :or\n        end\n        alias_method :operator, :type\n\n        def call(input)\n          left_result = left.(input)\n\n          if left_result.success?\n            Result::SUCCESS\n          else\n            right_result = right.(input)\n\n            if right_result.success?\n              Result::SUCCESS\n            else\n              Result.new(false, id) { [:or, [left_result.to_ast, right_result.to_ast]] }\n            end\n          end\n        end\n\n        def [](input)\n          left[input] || right[input]\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/operations/set.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    module Operations\n      class Set < Abstract\n        def type\n          :set\n        end\n\n        def call(input)\n          results = rules.map { |rule| rule.(input) }\n          success = results.all?(&:success?)\n\n          Result.new(success, id) do\n            [type, results.select(&:failure?).map(&:to_ast)]\n          end\n        end\n\n        def [](input)\n          rules.map { |rule| rule[input] }.all?\n        end\n\n        def ast(input = Undefined)\n          [type, rules.map { |rule| rule.ast(input) }]\n        end\n\n        def to_s\n          \"#{type}(#{rules.map(&:to_s).join(\", \")})\"\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/operations/unary.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    module Operations\n      class Unary < Abstract\n        attr_reader :rule\n\n        def initialize(*rules, **options)\n          super\n          @rule = rules.first\n        end\n\n        def ast(input = Undefined)\n          [type, rule.ast(input)]\n        end\n\n        def to_s\n          \"#{type}(#{rule})\"\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/operations/xor.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    module Operations\n      class Xor < Binary\n        def type\n          :xor\n        end\n        alias_method :operator, :type\n\n        def call(input)\n          Result.new(self[input], id) { ast(input) }\n        end\n\n        def [](input)\n          left[input] ^ right[input]\n        end\n\n        def ast(input = Undefined)\n          [type, rules.map { |rule| rule.ast(input) }]\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/operators.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    module Operators\n      def and(other)\n        Operations::And.new(self, other)\n      end\n      alias_method :&, :and\n\n      def or(other)\n        Operations::Or.new(self, other)\n      end\n      alias_method :|, :or\n\n      def xor(other)\n        Operations::Xor.new(self, other)\n      end\n      alias_method :^, :xor\n\n      def then(other)\n        Operations::Implication.new(self, other)\n      end\n      alias_method :>, :then\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/predicates.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/core/constants\"\n\nrequire \"bigdecimal\"\nrequire \"bigdecimal/util\"\nrequire \"date\"\nrequire \"uri\"\n\nmodule Dry\n  module Logic\n    module Predicates\n      include ::Dry::Core::Constants\n\n      module Methods\n        def self.uuid_format(version)\n          ::Regexp.new(<<~FORMAT.chomp, ::Regexp::IGNORECASE)\n            \\\\A[0-9A-F]{8}-[0-9A-F]{4}-#{version}[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}\\\\z\n          FORMAT\n        end\n\n        UUIDv1 = uuid_format(1)\n\n        UUIDv2 = uuid_format(2)\n\n        UUIDv3 = uuid_format(3)\n\n        UUIDv4 = uuid_format(4)\n\n        UUIDv5 = uuid_format(5)\n\n        UUIDv6 = uuid_format(6)\n\n        UUIDv7 = uuid_format(7)\n\n        UUIDv8 = uuid_format(8)\n\n        def [](name)\n          method(name)\n        end\n\n        def type?(type, input) = input.is_a?(type)\n\n        def nil?(input) = input.nil?\n        alias_method :none?, :nil?\n\n        def key?(name, input) = input.key?(name)\n\n        def attr?(name, input) = input.respond_to?(name)\n\n        def empty?(input)\n          case input\n          when ::String, ::Array, ::Hash then input.empty?\n          when nil then true\n          else\n            false\n          end\n        end\n\n        def filled?(input) = !empty?(input)\n\n        def bool?(input) = input.equal?(true) || input.equal?(false)\n\n        def date?(input) = input.is_a?(::Date)\n\n        def date_time?(input) = input.is_a?(::DateTime)\n\n        def time?(input) = input.is_a?(::Time)\n\n        def number?(input)\n          true if Float(input)\n        rescue ::ArgumentError, ::TypeError\n          false\n        end\n\n        def int?(input) = input.is_a?(::Integer)\n\n        def float?(input) = input.is_a?(::Float)\n\n        def decimal?(input) = input.is_a?(::BigDecimal)\n\n        def str?(input) = input.is_a?(::String)\n\n        def hash?(input) = input.is_a?(::Hash)\n\n        def array?(input) = input.is_a?(::Array)\n\n        def odd?(input) = input.odd?\n\n        def even?(input) = input.even?\n\n        def lt?(num, input) = input < num\n\n        def gt?(num, input) = input > num\n\n        def lteq?(num, input) = !gt?(num, input)\n\n        def gteq?(num, input) = !lt?(num, input)\n\n        def size?(size, input)\n          case size\n          when ::Integer then size.equal?(input.size)\n          when ::Range, ::Array then size.include?(input.size)\n          else\n            raise ::ArgumentError, \"+#{size}+ is not supported type for size? predicate.\"\n          end\n        end\n\n        def min_size?(num, input) = input.size >= num\n\n        def max_size?(num, input) = input.size <= num\n\n        def bytesize?(size, input)\n          case size\n          when ::Integer then size.equal?(input.bytesize)\n          when ::Range, ::Array then size.include?(input.bytesize)\n          else\n            raise ::ArgumentError, \"+#{size}+ is not supported type for bytesize? predicate.\"\n          end\n        end\n\n        def min_bytesize?(num, input) = input.bytesize >= num\n\n        def max_bytesize?(num, input) = input.bytesize <= num\n\n        def inclusion?(list, input)\n          deprecated(:inclusion?, :included_in?)\n          included_in?(list, input)\n        end\n\n        def exclusion?(list, input)\n          deprecated(:exclusion?, :excluded_from?)\n          excluded_from?(list, input)\n        end\n\n        def included_in?(list, input) = list.include?(input)\n\n        def excluded_from?(list, input) = !list.include?(input)\n\n        def includes?(value, input)\n          if input.respond_to?(:include?)\n            input.include?(value)\n          else\n            false\n          end\n        rescue ::TypeError\n          false\n        end\n\n        def excludes?(value, input) = !includes?(value, input)\n\n        # This overrides Object#eql? so we need to make it compatible\n        def eql?(left, right = Undefined)\n          return super(left) if right.equal?(Undefined)\n\n          left.eql?(right)\n        end\n\n        def is?(left, right) = left.equal?(right)\n\n        def not_eql?(left, right) = !left.eql?(right)\n\n        def true?(value) = value.equal?(true)\n\n        def false?(value) = value.equal?(false)\n\n        def format?(regex, input) = !input.nil? && regex.match?(input)\n\n        def case?(pattern, input) = pattern === input # rubocop:disable Style/CaseEquality\n\n        def uuid_v1?(input) = format?(UUIDv1, input)\n\n        def uuid_v2?(input) = format?(UUIDv2, input)\n\n        def uuid_v3?(input) = format?(UUIDv3, input)\n\n        def uuid_v4?(input) = format?(UUIDv4, input)\n\n        def uuid_v5?(input) = format?(UUIDv5, input)\n\n        def uuid_v6?(input) = format?(UUIDv6, input)\n\n        def uuid_v7?(input) = format?(UUIDv7, input)\n\n        def uuid_v8?(input) = format?(UUIDv8, input)\n\n        if defined?(::URI::RFC2396_PARSER)\n          def uri?(schemes, input)\n            uri_format = ::URI::RFC2396_PARSER.make_regexp(schemes)\n            format?(uri_format, input)\n          end\n        else\n          def uri?(schemes, input)\n            uri_format = ::URI::DEFAULT_PARSER.make_regexp(schemes)\n            format?(uri_format, input)\n          end\n        end\n\n        def uri_rfc3986?(input) = format?(::URI::RFC3986_Parser::RFC3986_URI, input)\n\n        # This overrides Object#respond_to? so we need to make it compatible\n        def respond_to?(method, input = Undefined)\n          return super if input.equal?(Undefined)\n\n          input.respond_to?(method)\n        end\n\n        def predicate(name, &)\n          define_singleton_method(name, &)\n        end\n\n        def deprecated(name, in_favor_of)\n          Core::Deprecations.warn(\n            \"#{name} predicate is deprecated and will \" \\\n            \"be removed in the next major version\\n\" \\\n            \"Please use #{in_favor_of} predicate instead\",\n            tag: \"dry-logic\",\n            uplevel: 3\n          )\n        end\n      end\n\n      extend Methods\n\n      def self.included(other)\n        super\n        other.extend(Methods)\n      end\n    end\n    # rubocop:enable Metrics/ModuleLength\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/result.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    class Result\n      SUCCESS = ::Class.new {\n        def success?\n          true\n        end\n\n        def failure?\n          false\n        end\n      }.new.freeze\n\n      attr_reader :success\n\n      attr_reader :id\n\n      attr_reader :serializer\n\n      def initialize(success, id = nil, &block)\n        @success = success\n        @id = id\n        @serializer = block\n      end\n\n      def success?\n        success\n      end\n\n      def failure?\n        !success?\n      end\n\n      def type\n        success? ? :success : :failure\n      end\n\n      def ast(input = Undefined)\n        serializer.(input)\n      end\n\n      def to_ast\n        if id\n          [type, [id, ast]]\n        else\n          ast\n        end\n      end\n\n      def to_s\n        visit(to_ast)\n      end\n\n      private\n\n      def visit(ast)\n        __send__(:\"visit_#{ast[0]}\", ast[1])\n      end\n\n      def visit_predicate(node)\n        name, args = node\n\n        if args.empty?\n          name.to_s\n        else\n          \"#{name}(#{args.map(&:last).map(&:inspect).join(\", \")})\"\n        end\n      end\n\n      def visit_and(node)\n        left, right = node\n        \"#{visit(left)} AND #{visit(right)}\"\n      end\n\n      def visit_or(node)\n        left, right = node\n        \"#{visit(left)} OR #{visit(right)}\"\n      end\n\n      def visit_xor(node)\n        left, right = node\n        \"#{visit(left)} XOR #{visit(right)}\"\n      end\n\n      def visit_not(node)\n        \"not(#{visit(node)})\"\n      end\n\n      def visit_hint(node)\n        visit(node)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/rule/interface.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    class Rule\n      class Interface < ::Module\n        SPLAT = [\"*rest\"].freeze\n\n        attr_reader :arity\n\n        attr_reader :curried\n\n        def initialize(arity, curried)\n          super()\n\n          @arity = arity\n          @curried = curried\n\n          if !variable_arity? && curried > arity\n            raise ArgumentError, \"wrong number of arguments (#{curried} for #{arity})\"\n          end\n\n          define_constructor if curried?\n\n          if constant?\n            define_constant_application\n          else\n            define_application\n          end\n        end\n\n        def constant? = arity.zero?\n\n        def variable_arity? = arity.negative?\n\n        def curried? = !curried.zero?\n\n        def unapplied\n          if variable_arity?\n            unapplied = arity.abs - 1 - curried\n\n            if unapplied.negative?\n              0\n            else\n              unapplied\n            end\n          else\n            arity - curried\n          end\n        end\n\n        def name\n          if constant?\n            \"Constant\"\n          else\n            arity_str =\n              if variable_arity?\n                \"Variable#{arity.abs - 1}Arity\"\n              else\n                \"#{arity}Arity\"\n              end\n\n            curried_str =\n              if curried?\n                \"#{curried}Curried\"\n              else\n                EMPTY_STRING\n              end\n\n            \"#{arity_str}#{curried_str}\"\n          end\n        end\n\n        def define_constructor\n          assignment =\n            if curried.equal?(1)\n              \"@arg0 = @args[0]\"\n            else\n              \"#{curried_args.join(\", \")} = @args\"\n            end\n\n          module_eval(<<~RUBY, __FILE__, __LINE__ + 1)\n            def initialize(*)  # def initialize(*)\n              super            #   super\n                               #\n              #{assignment}    #   @arg0 = @args[0]\n            end                # end\n          RUBY\n        end\n\n        def define_constant_application\n          module_exec do\n            def call(*)\n              if @predicate[]\n                Result::SUCCESS\n              else\n                Result.new(false, id) { ast }\n              end\n            end\n\n            def [](*)\n              @predicate[]\n            end\n          end\n        end\n\n        def define_application\n          splat = variable_arity? ? SPLAT : EMPTY_ARRAY\n          parameters = (unapplied_args + splat).join(\", \")\n          application = \"@predicate[#{(curried_args + unapplied_args + splat).join(\", \")}]\"\n\n          module_eval(<<~RUBY, __FILE__, __LINE__ + 1)\n            def call(#{parameters})                          # def call(input0, input1, *rest)\n              if #{application}                              #   if @predicate[@arg0, @arg1, input0, input1, *rest]\n                Result::SUCCESS                              #     ::Dry::Logic::Result::Success\n              else                                           #   else\n                Result.new(false, id) { ast(#{parameters}) } #     ::Dry::Logic::Result.new(false, id) { ast(input0, input1, *rest) }\n              end                                            #   end\n            end                                              # end\n                                                             #\n            def [](#{parameters})                            # def [](@arg0, @arg1, input0, input1, *rest)\n              #{application}                                 #   @predicate[@arg0, @arg1, input0, input1, *rest]\n            end                                              # end\n          RUBY\n        end\n\n        def curried_args\n          @curried_args ||= ::Array.new(curried) { \"@arg#{_1}\" }\n        end\n\n        def unapplied_args\n          @unapplied_args ||= ::Array.new(unapplied) { \"input#{_1}\" }\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/rule/predicate.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    class Rule\n      class Predicate < Rule\n        def self.specialize(arity, curried, base = Predicate)\n          super\n        end\n\n        def type\n          :predicate\n        end\n\n        def name\n          predicate.name\n        end\n\n        def to_s\n          if args.empty?\n            name.to_s\n          else\n            \"#{name}(#{args.map(&:inspect).join(\", \")})\"\n          end\n        end\n\n        def ast(input = Undefined)\n          [type, [name, args_with_names(input)]]\n        end\n        alias_method :to_ast, :ast\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/rule.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"concurrent/map\"\n\nmodule Dry\n  module Logic\n    def self.Rule(*args, **options, &block)\n      if args.any?\n        Rule.build(*args, **options)\n      elsif block\n        Rule.build(block, **options)\n      end\n    end\n\n    class Rule\n      include Core::Constants\n      include ::Dry::Equalizer(:predicate, :options)\n      include Operators\n\n      attr_reader :predicate\n\n      attr_reader :options\n\n      attr_reader :args\n\n      attr_reader :arity\n\n      def self.interfaces\n        @interfaces ||= ::Concurrent::Map.new\n      end\n\n      def self.specialize(arity, curried, base = Rule)\n        base.interfaces.fetch_or_store([arity, curried]) do\n          interface = Interface.new(arity, curried)\n          klass = ::Class.new(base) { include interface }\n          base.const_set(\"#{base.name.split(\"::\").last}#{interface.name}\", klass)\n          klass\n        end\n      end\n\n      def self.build(predicate, args: EMPTY_ARRAY, arity: predicate.arity, **options)\n        specialize(arity, args.size).new(predicate, {args: args, arity: arity, **options})\n      end\n\n      def initialize(predicate, options = EMPTY_HASH)\n        @predicate = predicate\n        @options = options\n        @args = options[:args] || EMPTY_ARRAY\n        @arity = options[:arity] || predicate.arity\n      end\n\n      def type\n        :rule\n      end\n\n      def id\n        options[:id]\n      end\n\n      def curry(*new_args)\n        with(args: args + new_args)\n      end\n\n      def bind(object)\n        if predicate.respond_to?(:bind)\n          self.class.build(predicate.bind(object), **options)\n        else\n          self.class.build(\n            -> *args { object.instance_exec(*args, &predicate) },\n            **options, arity: arity, parameters: parameters\n          )\n        end\n      end\n\n      def eval_args(object)\n        with(args: args.map { |arg| arg.is_a?(UnboundMethod) ? arg.bind(object).() : arg })\n      end\n\n      def with(new_opts)\n        self.class.build(predicate, **options, **new_opts)\n      end\n\n      def parameters\n        options[:parameters] || predicate.parameters\n      end\n\n      def ast(input = Undefined)\n        [:predicate, [id, args_with_names(input)]]\n      end\n\n      private\n\n      def args_with_names(*input)\n        parameters.map(&:last).zip(args + input)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/rule_compiler.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    class RuleCompiler\n      attr_reader :predicates\n\n      def initialize(predicates)\n        @predicates = predicates\n      end\n\n      def call(ast)\n        ast.map { |node| visit(node) }\n      end\n\n      def visit(node)\n        name, nodes = node\n        send(:\"visit_#{name}\", nodes)\n      end\n\n      def visit_check(node)\n        keys, predicate = node\n        Operations::Check.new(visit(predicate), keys: keys)\n      end\n\n      def visit_not(node)\n        Operations::Negation.new(visit(node))\n      end\n\n      def visit_key(node)\n        name, predicate = node\n        Operations::Key.new(visit(predicate), name: name)\n      end\n\n      def visit_attr(node)\n        name, predicate = node\n        Operations::Attr.new(visit(predicate), name: name)\n      end\n\n      def visit_set(node)\n        Operations::Set.new(*call(node))\n      end\n\n      def visit_each(node)\n        Operations::Each.new(visit(node))\n      end\n\n      def visit_predicate(node)\n        name, params = node\n        predicate = Rule::Predicate.build(predicates[name])\n\n        if params.size > 1\n          args = params.map(&:last).reject { |val| val == Undefined }\n          predicate.curry(*args)\n        else\n          predicate\n        end\n      end\n\n      def visit_and(node)\n        left, right = node\n        visit(left).and(visit(right))\n      end\n\n      def visit_or(node)\n        left, right = node\n        visit(left).or(visit(right))\n      end\n\n      def visit_xor(node)\n        left, right = node\n        visit(left).xor(visit(right))\n      end\n\n      def visit_implication(node)\n        left, right = node\n        visit(left).then(visit(right))\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic/version.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module Logic\n    VERSION = \"1.6.0\"\n  end\nend\n"
  },
  {
    "path": "lib/dry/logic.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"zeitwerk\"\nrequire \"dry/core\"\n\nmodule Dry\n  module Logic\n    include Dry::Core::Constants\n\n    def self.loader\n      @loader ||= Zeitwerk::Loader.new.tap do |loader|\n        root = File.expand_path(\"..\", __dir__)\n        loader.tag = \"dry-logic\"\n        loader.inflector = Zeitwerk::GemInflector.new(\"#{root}/dry-logic.rb\")\n        loader.push_dir(root)\n        loader.ignore(\n          \"#{root}/dry-logic.rb\",\n          \"#{root}/dry/logic/version.rb\"\n        )\n      end\n    end\n\n    loader.setup\n  end\nend\n"
  },
  {
    "path": "lib/dry-logic.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic\"\n"
  },
  {
    "path": "repo-sync.yml",
    "content": "name:\n  gem: dry-logic\n  constant: Dry::Logic\ngithub_org: dry-rb\ngemspec:\n  authors: [\"Hanakai team\"]\n  email: [\"info@hanakai.org\"]\n  summary: \"Predicate logic with rule composition\"\n  homepage: \"https://dry-rb.org/gems/dry-logic\"\n  development_dependencies:\n    - bundler\n    - rake\n    - rspec\n  runtime_dependencies:\n    - [bigdecimal]\n    - [concurrent-ruby, \"~> 1.0\"]\n    - [dry-core, \"~> 1.1\"]\n    - [zeitwerk, \"~> 2.6\"]\n"
  },
  {
    "path": "spec/integration/builder/operation_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative \"../../shared/operation\"\n\nRSpec.describe \"operations\" do\n  describe \"nested\" do\n    let(:predicate) do\n      Dry::Logic::Builder.call do\n        check keys: [:person] do\n          check keys: [:age] do\n            gt?(50) & lt?(200)\n          end\n        end\n      end\n    end\n\n    describe \"success\" do\n      subject { predicate.call({person: {age: 100}}) }\n      it { is_expected.to be_a_success }\n    end\n\n    describe \"failure\" do\n      subject { predicate.call({person: {age: 10}}) }\n      it { is_expected.not_to be_a_success }\n    end\n  end\n\n  describe :check do\n    describe \"one path\" do\n      let(:expression) do\n        lambda do |*|\n          check keys: [:age] do\n            gt?(50)\n          end\n        end\n      end\n\n      describe \"success\" do\n        it_behaves_like \"operation\" do\n          let(:input) { {age: 100} }\n          let(:output) { true }\n        end\n      end\n\n      describe \"failure\" do\n        it_behaves_like \"operation\" do\n          let(:input) { {age: 10} }\n          let(:output) { false }\n        end\n      end\n    end\n\n    describe \"two paths\" do\n      let(:expression) do\n        lambda do |*|\n          check keys: %i[speed limit] do\n            gt?\n          end\n        end\n      end\n\n      describe \"success\" do\n        it_behaves_like \"operation\" do\n          let(:input) { {speed: 50, limit: 100} }\n          let(:output) { true }\n        end\n      end\n\n      describe \"failure\" do\n        it_behaves_like \"operation\" do\n          let(:input) { {speed: 100, limit: 50} }\n          let(:output) { false }\n        end\n      end\n    end\n  end\n\n  describe :implication do\n    let(:expression) do\n      lambda do |*|\n        implication { [gt?(0), lt?(10)] }\n      end\n    end\n\n    describe \"[true => true]\" do\n      it_behaves_like \"operation\" do\n        let(:input) { 5 }\n        let(:output) { true }\n      end\n    end\n\n    describe \"[true => false]\" do\n      it_behaves_like \"operation\" do\n        let(:input) { 20 }\n        let(:output) { false }\n      end\n    end\n\n    describe \"[false => true]\" do\n      it_behaves_like \"operation\" do\n        let(:input) { -5 }\n        let(:output) { true }\n      end\n    end\n  end\n\n  describe :key do\n    let(:expression) do\n      lambda do |*|\n        key name: %i[user age] do\n          gt?(10)\n        end\n      end\n    end\n\n    describe \"success\" do\n      it_behaves_like \"operation\" do\n        let(:input) { {user: {age: 20}} }\n        let(:output) { true }\n      end\n    end\n\n    describe \"failure\" do\n      it_behaves_like \"operation\" do\n        let(:input) { {user: {age: 5}} }\n        let(:output) { false }\n      end\n    end\n  end\n\n  describe :and do\n    let(:expression) do\n      lambda do |*|\n        even?.and(int?)\n      end\n    end\n\n    describe \"success\" do\n      it_behaves_like \"operation\" do\n        let(:input) { 2 }\n        let(:output) { true }\n      end\n    end\n\n    describe \"failure\" do\n      it_behaves_like \"operation\" do\n        let(:input) { 5 }\n        let(:output) { false }\n      end\n    end\n  end\n\n  describe :or do\n    let(:expression) do\n      lambda do |*|\n        even?.or(odd?)\n      end\n    end\n\n    describe \"success\" do\n      it_behaves_like \"operation\" do\n        let(:input) { 10 }\n        let(:output) { true }\n      end\n\n      it_behaves_like \"operation\" do\n        let(:input) { 9 }\n        let(:output) { true }\n      end\n    end\n  end\n\n  describe :negation do\n    let(:expression) do\n      lambda do |*|\n        negation { even? }\n      end\n    end\n\n    describe \"success\" do\n      it_behaves_like \"operation\" do\n        let(:input) { 9 }\n        let(:output) { true }\n      end\n    end\n\n    describe \"failure\" do\n      it_behaves_like \"operation\" do\n        let(:input) { 6 }\n        let(:output) { false }\n      end\n    end\n  end\n\n  describe :set do\n    let(:expression) do\n      lambda do |*|\n        set { [lt?(5), gt?(2)] }\n      end\n    end\n\n    describe \"success\" do\n      it_behaves_like \"operation\" do\n        let(:input) { 3 }\n        let(:output) { true }\n      end\n    end\n\n    describe \"success\" do\n      it_behaves_like \"operation\" do\n        let(:input) { 7 }\n        let(:output) { false }\n      end\n    end\n  end\n\n  describe :each do\n    let(:expression) do\n      lambda do |*|\n        each { gt?(10) }\n      end\n    end\n\n    describe \"success\" do\n      it_behaves_like \"operation\" do\n        let(:input) { [20, 30] }\n        let(:output) { true }\n      end\n    end\n\n    describe \"failure\" do\n      it_behaves_like \"operation\" do\n        let(:input) { [10, 20, 30] }\n        let(:output) { false }\n      end\n    end\n  end\n\n  describe :xor do\n    let(:expression) do\n      lambda do |*|\n        even?.xor(gt?(4))\n      end\n    end\n\n    describe \"success\" do\n      it_behaves_like \"operation\" do\n        let(:input) { 5 }\n        let(:output) { true }\n      end\n\n      it_behaves_like \"operation\" do\n        let(:input) { 2 }\n        let(:output) { true }\n      end\n    end\n\n    describe \"failure\" do\n      it_behaves_like \"operation\" do\n        let(:input) { 6 }\n        let(:output) { false }\n      end\n    end\n  end\n\n  # describe :attr do\n  #   let(:expression) do\n  #     lambda do |*|\n  #       attr name: :age do\n  #         gt?(50)\n  #       end\n  #     end\n  #   end\n  #\n  #   let(:person) { Struct.new(:age) }\n  #\n  #   describe \"success\" do\n  #     it_behaves_like \"operation\" do\n  #       let(:input) { person.new(100) }\n  #       let(:output) { true }\n  #     end\n  #   end\n  #\n  #   describe \"failure\" do\n  #     it_behaves_like \"operation\" do\n  #       let(:input) { person.new(0) }\n  #       let(:output) { false }\n  #     end\n  #   end\n  # end\n\n  describe \"operators\" do\n    describe :& do\n      let(:expression) do\n        lambda do |*|\n          even? & int?\n        end\n      end\n\n      describe \"success\" do\n        it_behaves_like \"operation\" do\n          let(:input) { 2 }\n          let(:output) { true }\n        end\n      end\n\n      describe \"failure\" do\n        it_behaves_like \"operation\" do\n          let(:input) { 5 }\n          let(:output) { false }\n        end\n      end\n    end\n\n    describe :^ do\n      let(:expression) do\n        lambda do |*|\n          even? ^ gt?(4)\n        end\n      end\n\n      describe \"success\" do\n        it_behaves_like \"operation\" do\n          let(:input) { 5 }\n          let(:output) { true }\n        end\n\n        it_behaves_like \"operation\" do\n          let(:input) { 2 }\n          let(:output) { true }\n        end\n      end\n\n      describe \"failure\" do\n        it_behaves_like \"operation\" do\n          let(:input) { 6 }\n          let(:output) { false }\n        end\n      end\n    end\n\n    describe :> do\n      let(:expression) do\n        lambda do |*|\n          gt?(0) > lt?(10)\n        end\n      end\n\n      describe \"[true => true]\" do\n        it_behaves_like \"operation\" do\n          let(:input) { 5 }\n          let(:output) { true }\n        end\n      end\n\n      describe \"[true => false]\" do\n        it_behaves_like \"operation\" do\n          let(:input) { 20 }\n          let(:output) { false }\n        end\n      end\n\n      describe \"[false => true]\" do\n        it_behaves_like \"operation\" do\n          let(:input) { -5 }\n          let(:output) { true }\n        end\n      end\n    end\n\n    describe :then do\n      let(:expression) do\n        lambda do |*|\n          gt?(0).then(lt?(10))\n        end\n      end\n\n      describe \"[true => true]\" do\n        it_behaves_like \"operation\" do\n          let(:input) { 5 }\n          let(:output) { true }\n        end\n      end\n\n      describe \"[true => false]\" do\n        it_behaves_like \"operation\" do\n          let(:input) { 20 }\n          let(:output) { false }\n        end\n      end\n\n      describe \"[false => true]\" do\n        it_behaves_like \"operation\" do\n          let(:input) { -5 }\n          let(:output) { true }\n        end\n      end\n    end\n\n    describe :| do\n      let(:expression) do\n        lambda do |*|\n          even? | odd?\n        end\n      end\n\n      describe \"success\" do\n        it_behaves_like \"operation\" do\n          let(:input) { 10 }\n          let(:output) { true }\n        end\n\n        it_behaves_like \"operation\" do\n          let(:input) { 9 }\n          let(:output) { true }\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/builder/predicate_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative \"../../shared/predicate\"\n\nRSpec.describe \"predicates\" do\n  let(:input) { described_class }\n\n  describe :key? do\n    let(:expression) { ->(*) { key?(:speed) } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      describe({speed: 100}) do\n        it_behaves_like \"predicate\"\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      describe({age: 50}) do\n        it_behaves_like \"predicate\"\n      end\n    end\n  end\n\n  describe :format? do\n    let(:expression) { ->(*) { format?(/^(A|B)$/) } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      it_behaves_like \"predicate\" do\n        let(:input) { \"A\" }\n      end\n\n      it_behaves_like \"predicate\" do\n        let(:input) { \"B\" }\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      it_behaves_like \"predicate\" do\n        let(:input) { \"C\" }\n      end\n\n      it_behaves_like \"predicate\" do\n        let(:input) { \"D\" }\n      end\n    end\n  end\n\n  describe :type? do\n    let(:expression) { ->(*) { type?(String) } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      describe \"string\" do\n        it_behaves_like \"predicate\" do\n          let(:input) { \"string\" }\n        end\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      it_behaves_like \"predicate\" do\n        let(:input) { :symbol }\n      end\n    end\n  end\n\n  describe :nil? do\n    let(:expression) { ->(*) { nil? } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      it_behaves_like \"predicate\" do\n        let(:input) { nil }\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      describe :symbol do\n        it_behaves_like \"predicate\"\n      end\n    end\n  end\n\n  describe :attr? do\n    let(:expression) { ->(*) { attr?(:name) } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      describe Struct.new(:name).new(\"John\") do\n        it_behaves_like \"predicate\"\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      describe Struct.new(:age).new(50) do\n        it_behaves_like \"predicate\"\n      end\n    end\n  end\n\n  describe :empty? do\n    let(:expression) { ->(*) { empty? } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      describe({}) do\n        it_behaves_like \"predicate\"\n      end\n\n      describe String do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class.new }\n        end\n      end\n\n      describe [] do\n        it_behaves_like \"predicate\"\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n      describe({key: \"value\"}) do\n        it_behaves_like \"predicate\"\n      end\n\n      describe \"string\" do\n        it_behaves_like \"predicate\"\n      end\n\n      describe nil do\n        it_behaves_like \"predicate\"\n      end\n\n      describe [1, 2] do\n        it_behaves_like \"predicate\"\n      end\n    end\n  end\n\n  describe :filled? do\n    let(:expression) { ->(*) { filled? } }\n\n    describe \"success\" do\n      let(:output) { true }\n      describe({key: \"value\"}) do\n        it_behaves_like \"predicate\"\n      end\n\n      describe \"string\" do\n        it_behaves_like \"predicate\"\n      end\n\n      describe nil do\n        it_behaves_like \"predicate\"\n      end\n\n      describe [1, 2] do\n        it_behaves_like \"predicate\"\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n      describe({}) do\n        it_behaves_like \"predicate\"\n      end\n\n      describe String do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class.new }\n        end\n      end\n\n      describe [] do\n        it_behaves_like \"predicate\"\n      end\n    end\n  end\n\n  describe :bool? do\n    let(:expression) { ->(*) { bool? } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      describe true do\n        it_behaves_like \"predicate\"\n      end\n\n      describe false do\n        it_behaves_like \"predicate\"\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      describe :symbol do\n        it_behaves_like \"predicate\"\n      end\n\n      describe 5 do\n        it_behaves_like \"predicate\"\n      end\n    end\n  end\n\n  describe :date? do\n    let(:expression) { ->(*) { date? } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      describe Date.new do\n        it_behaves_like \"predicate\"\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      describe :symbol do\n        it_behaves_like \"predicate\"\n      end\n    end\n  end\n\n  describe :date_time? do\n    let(:expression) { ->(*) { date_time? } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      it_behaves_like \"predicate\" do\n        let(:input) { DateTime.new }\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      it_behaves_like \"predicate\" do\n        let(:input) { :symbol }\n      end\n    end\n  end\n\n  describe :time? do\n    let(:expression) { ->(*) { time? } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      it_behaves_like \"predicate\" do\n        let(:input) { Time.new }\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      it_behaves_like \"predicate\" do\n        let(:input) { :symbol }\n      end\n    end\n  end\n\n  describe :number? do\n    let(:expression) { ->(*) { number? } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      it_behaves_like \"predicate\" do\n        let(:input) { -4 }\n      end\n\n      it_behaves_like \"predicate\" do\n        let(:input) { 10.0 }\n      end\n\n      it_behaves_like \"predicate\" do\n        let(:input) { 10 }\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      it_behaves_like \"predicate\" do\n        let(:input) { \"A-4\" }\n      end\n\n      it_behaves_like \"predicate\" do\n        let(:input) { \"A10\" }\n      end\n\n      it_behaves_like \"predicate\" do\n        let(:input) { nil }\n      end\n\n      it_behaves_like \"predicate\" do\n        let(:input) { :nope }\n      end\n    end\n  end\n\n  describe :int? do\n    let(:expression) { ->(*) { int? } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      it_behaves_like \"predicate\" do\n        let(:input) { 10 }\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      it_behaves_like \"predicate\" do\n        let(:input) { 10.0 }\n      end\n    end\n  end\n\n  describe :float? do\n    let(:expression) { ->(*) { float? } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      it_behaves_like \"predicate\" do\n        let(:input) { 1.0 }\n      end\n    end\n\n    describe \"success\" do\n      let(:output) { false }\n\n      it_behaves_like \"predicate\" do\n        let(:input) { 1 }\n      end\n    end\n  end\n\n  describe :decimal? do\n    let(:expression) { ->(*) { decimal? } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      it_behaves_like \"predicate\" do\n        let(:input) { BigDecimal(1) }\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      it_behaves_like \"predicate\" do\n        let(:input) { 10 }\n      end\n    end\n  end\n\n  describe :str? do\n    let(:expression) { ->(*) { str? } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      describe String do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class.new }\n        end\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      describe Array do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class.new }\n        end\n      end\n    end\n  end\n\n  describe :hash? do\n    let(:expression) { ->(*) { hash? } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      describe Hash do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class.new }\n        end\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      describe Array do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class.new }\n        end\n      end\n    end\n  end\n\n  describe :array? do\n    let(:expression) { ->(*) { array? } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      describe Array do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class.new }\n        end\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      describe Hash do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class.new }\n        end\n      end\n    end\n  end\n\n  describe :even? do\n    let(:expression) { ->(*) { even? } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      describe 10 do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class }\n        end\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      describe 5 do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class }\n        end\n      end\n    end\n  end\n\n  describe :odd? do\n    let(:expression) { ->(*) { odd? } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      describe 5 do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class }\n        end\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      describe 10 do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class }\n        end\n      end\n    end\n  end\n\n  describe :lt? do\n    let(:expression) { ->(*) { lt?(10) } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      describe 5 do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class }\n        end\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      describe 200 do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class }\n        end\n      end\n    end\n  end\n\n  describe :gt? do\n    let(:expression) { ->(*) { gt?(10) } }\n\n    describe \"failure\" do\n      let(:output) { false }\n      describe 5 do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class }\n        end\n      end\n    end\n\n    describe \"success\" do\n      let(:output) { true }\n\n      describe 200 do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class }\n        end\n      end\n    end\n  end\n\n  describe :gteq? do\n    let(:expression) { ->(*) { gteq?(10) } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      describe 10 do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class }\n        end\n      end\n\n      describe 11 do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class }\n        end\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      describe 9 do\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class }\n        end\n      end\n    end\n  end\n\n  describe :lteq? do\n    let(:expression) { ->(*) { lteq?(10) } }\n\n    describe \"success\" do\n      let(:output) { true }\n\n      describe 9 do\n        it_behaves_like \"predicate\"\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      describe 11 do\n        it_behaves_like \"predicate\"\n      end\n    end\n  end\n\n  describe :size? do\n    describe \"success\" do\n      let(:output) { true }\n\n      describe \"Integer\" do\n        it_behaves_like \"predicate\" do\n          let(:expression) { ->(*) { size?(2) } }\n          let(:input) { [1, 2] }\n        end\n      end\n\n      describe \"Range\" do\n        it_behaves_like \"predicate\" do\n          let(:expression) { ->(*) { size?(1..3) } }\n          let(:input) { [1, 2] }\n        end\n      end\n\n      describe \"Array\" do\n        it_behaves_like \"predicate\" do\n          let(:expression) { ->(*) { size?([3]) } }\n          let(:input) { [1, 2, 3] }\n        end\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      describe \"Integer\" do\n        it_behaves_like \"predicate\" do\n          let(:expression) { ->(*) { size?(2) } }\n          let(:input) { [1] }\n        end\n      end\n\n      describe \"Range\" do\n        it_behaves_like \"predicate\" do\n          let(:expression) { ->(*) { size?(1..3) } }\n          let(:input) { [1, 2, 3, 4] }\n        end\n      end\n\n      describe \"Array\" do\n        it_behaves_like \"predicate\" do\n          let(:expression) { ->(*) { size?([3]) } }\n          let(:input) { [1, 2] }\n        end\n      end\n    end\n  end\n\n  describe :min_size? do\n    let(:expression) { ->(*) { min_size?(2) } }\n\n    describe \"success\" do\n      describe [1, 2, 3] do\n        let(:output) { true }\n\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class }\n        end\n      end\n    end\n\n    describe \"failure\" do\n      describe [1] do\n        let(:output) { false }\n\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class }\n        end\n      end\n    end\n  end\n\n  describe :max_size? do\n    let(:expression) { ->(*) { max_size?(2) } }\n\n    describe \"success\" do\n      describe [1] do\n        let(:output) { true }\n\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class }\n        end\n      end\n    end\n\n    describe \"failure\" do\n      describe [1, 2, 3] do\n        let(:output) { false }\n\n        it_behaves_like \"predicate\" do\n          let(:input) { described_class }\n        end\n      end\n    end\n  end\n\n  describe :bytesize? do\n    describe \"success\" do\n      let(:output) { true }\n\n      describe \"Integer\" do\n        let(:expression) { ->(*) { bytesize?(1) } }\n\n        it_behaves_like \"predicate\" do\n          let(:input) { \"A\" }\n        end\n      end\n\n      describe \"Range\" do\n        let(:expression) { ->(*) { bytesize?(2..3) } }\n\n        it_behaves_like \"predicate\" do\n          let(:input) { \"AB\" }\n        end\n      end\n\n      describe \"Array\" do\n        let(:expression) { ->(*) { bytesize?([2, 3]) } }\n\n        it_behaves_like \"predicate\" do\n          let(:input) { \"AB\" }\n        end\n      end\n    end\n\n    describe \"failure\" do\n      let(:output) { false }\n\n      describe \"Integer\" do\n        let(:expression) { ->(*) { bytesize?(1) } }\n\n        it_behaves_like \"predicate\" do\n          let(:input) { \"AB\" }\n        end\n      end\n\n      describe \"Range\" do\n        let(:expression) { ->(*) { bytesize?(2..3) } }\n\n        it_behaves_like \"predicate\" do\n          let(:input) { \"A\" }\n        end\n      end\n\n      describe \"Array\" do\n        let(:expression) { ->(*) { bytesize?([2, 3]) } }\n\n        it_behaves_like \"predicate\" do\n          let(:input) { \"A\" }\n        end\n      end\n    end\n  end\n\n  describe :min_bytesize? do\n    let(:expression) { ->(*) { min_bytesize?(1) } }\n\n    describe \"success\" do\n      it_behaves_like \"predicate\" do\n        let(:output) { true }\n        let(:input) { \"A\" }\n      end\n    end\n\n    describe \"failure\" do\n      it_behaves_like \"predicate\" do\n        let(:output) { false }\n        let(:input) { \"\" }\n      end\n    end\n  end\n\n  describe :max_bytesize? do\n    let(:expression) { ->(*) { max_bytesize?(1) } }\n\n    describe \"success\" do\n      it_behaves_like \"predicate\" do\n        let(:output) { false }\n        let(:input) { \"AB\" }\n      end\n    end\n\n    describe \"failure\" do\n      it_behaves_like \"predicate\" do\n        let(:output) { true }\n        let(:input) { \"\" }\n      end\n    end\n  end\n\n  describe :included_in? do\n    let(:expression) { ->(*) { included_in?([1, 2, 3]) } }\n\n    describe \"success\" do\n      it_behaves_like \"predicate\" do\n        let(:output) { true }\n        let(:input) { 1 }\n      end\n    end\n\n    describe \"failure\" do\n      it_behaves_like \"predicate\" do\n        let(:output) { false }\n        let(:input) { 4 }\n      end\n    end\n  end\n\n  describe :excluded_from? do\n    let(:expression) { ->(*) { excluded_from?([1, 2, 3]) } }\n\n    describe \"success\" do\n      it_behaves_like \"predicate\" do\n        let(:output) { false }\n        let(:input) { 1 }\n      end\n    end\n\n    describe \"failure\" do\n      it_behaves_like \"predicate\" do\n        let(:output) { true }\n        let(:input) { 4 }\n      end\n    end\n  end\n\n  describe :includes? do\n    let(:expression) { ->(*) { includes?(1) } }\n\n    describe \"success\" do\n      it_behaves_like \"predicate\" do\n        let(:output) { true }\n        let(:input) { [1, 2, 3] }\n      end\n    end\n\n    describe \"failure\" do\n      it_behaves_like \"predicate\" do\n        let(:output) { false }\n        let(:input) { [2, 3, 4] }\n      end\n    end\n  end\n\n  describe :excludes? do\n    describe Array do\n      let(:expression) { ->(*) { excludes?(1) } }\n\n      describe \"success\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { false }\n          let(:input) { described_class.new([1, 2, 3]) }\n        end\n      end\n\n      describe \"failure\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { true }\n          let(:input) { described_class.new([2, 3, 4]) }\n        end\n      end\n    end\n\n    describe String do\n      let(:expression) { ->(*) { excludes?(\"A\") } }\n\n      describe \"success\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { true }\n          let(:input) { described_class.new(\"B\") }\n        end\n      end\n\n      describe \"failure\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { false }\n          let(:input) { described_class.new(\"A\") }\n        end\n      end\n    end\n  end\n\n  describe \"compare methods\" do\n    describe :eql? do\n      let(:expression) { ->(*) { eql?(10) } }\n\n      describe \"success\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { true }\n          let(:input) { 10 }\n        end\n      end\n\n      describe \"failure\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { false }\n          let(:input) { 20 }\n        end\n      end\n    end\n\n    describe :not_eql? do\n      let(:expression) { ->(*) { not_eql?(10) } }\n\n      describe \"success\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { false }\n          let(:input) { 10 }\n        end\n      end\n\n      describe \"failure\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { true }\n          let(:input) { 20 }\n        end\n      end\n    end\n  end\n\n  describe :is? do\n    describe \"success\" do\n      it_behaves_like \"predicate\" do\n        let(:expression) { ->(*) { is?(nil) } }\n        let(:output) { true }\n        let(:input) { nil }\n      end\n    end\n\n    describe \"failure\" do\n      it_behaves_like \"predicate\" do\n        let(:expression) { ->(*) { is?(Class.new) } }\n        let(:output) { false }\n        let(:input) { Class.new }\n      end\n    end\n  end\n\n  describe \"true? & false?\" do\n    describe :true? do\n      let(:expression) { ->(*) { true? } }\n\n      describe \"success\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { true }\n          let(:input) { true }\n        end\n      end\n\n      describe \"failure\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { false }\n          let(:input) { false }\n        end\n      end\n    end\n\n    describe :false? do\n      let(:expression) { ->(*) { false? } }\n\n      describe \"success\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { true }\n          let(:input) { false }\n        end\n      end\n\n      describe \"failure\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { false }\n          let(:input) { true }\n        end\n      end\n    end\n  end\n\n  describe :case? do\n    describe \"Range\" do\n      let(:expression) { ->(*) { case?(5..10) } }\n\n      describe \"success\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { true }\n          let(:input) { 6 }\n        end\n      end\n    end\n\n    describe \"Fixnum\" do\n      let(:expression) { ->(*) { case?(Integer) } }\n\n      describe \"success\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { true }\n          let(:input) { 10 }\n        end\n      end\n    end\n  end\n\n  describe \"uuid\" do\n    describe :uuid_v2?\n    describe :uuid_v3?\n    describe :uuid_v5?\n\n    describe :uuid_v1? do\n      let(:expression) do\n        ->(*) { uuid_v1? }\n      end\n\n      describe \"success\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { true }\n          let(:input) { \"554ef240-5433-11eb-ae93-0242ac130002\" }\n        end\n      end\n    end\n\n    describe :uuid_v4? do\n      let(:expression) do\n        ->(*) { uuid_v4? }\n      end\n\n      describe \"success\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { true }\n          let(:input) { \"f2711f00-5602-45c7-ae01-c94d285592c3\" }\n        end\n      end\n    end\n  end\n\n  describe :uri? do\n    describe :http do\n      let(:expression) do\n        ->(*) { uri?(:http) }\n      end\n\n      describe \"success\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { true }\n          let(:input) { \"http://google.com\" }\n        end\n      end\n\n      describe \"failure\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { false }\n          let(:input) { \"https://google.com\" }\n        end\n      end\n    end\n\n    describe [:http, :https] do\n      let(:expression) do\n        ->(*) { uri?(%w[http https]) }\n      end\n\n      describe \"success\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { true }\n          let(:input) { \"https://google.com\" }\n        end\n\n        it_behaves_like \"predicate\" do\n          let(:output) { true }\n          let(:input) { \"http://google.com\" }\n        end\n      end\n    end\n\n    describe Regexp do\n      let(:expression) do\n        ->(*) { uri?(/https?/) }\n      end\n\n      describe \"success\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { true }\n          let(:input) { \"https://google.com\" }\n        end\n\n        it_behaves_like \"predicate\" do\n          let(:output) { true }\n          let(:input) { \"http://google.com\" }\n        end\n      end\n    end\n\n    describe :https do\n      let(:expression) do\n        ->(*) { uri?(:https) }\n      end\n\n      describe \"success\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { true }\n          let(:input) { \"https://google.com\" }\n        end\n      end\n\n      describe \"failure\" do\n        it_behaves_like \"predicate\" do\n          let(:output) { false }\n          let(:input) { \"http://google.com\" }\n        end\n      end\n    end\n  end\n\n  describe :respond_to? do\n    let(:expression) do\n      ->(*) { respond_to?(:awesome?) }\n    end\n\n    describe \"success\" do\n      it_behaves_like \"predicate\" do\n        let(:output) { true }\n        let(:input) { Struct.new(:awesome?).new(true) }\n      end\n    end\n\n    describe \"failure\" do\n      it_behaves_like \"predicate\" do\n        let(:output) { false }\n        let(:input) { Struct.new(:not_awesome?).new(true) }\n      end\n    end\n  end\n\n  describe :predicate do\n    before { extend Dry::Logic::Builder }\n\n    before(:each) do\n      build do\n        predicate :divisible_with? do |num, input|\n          (input % num).zero?\n        end\n      end\n    end\n\n    let(:expression) do\n      lambda do |*|\n        divisible_with?(10)\n      end\n    end\n\n    describe \"success\" do\n      it_behaves_like \"predicate\" do\n        let(:input) { 10 }\n        let(:output) { true }\n      end\n    end\n\n    describe \"success\" do\n      it_behaves_like \"predicate\" do\n        let(:input) { 3 }\n        let(:output) { false }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/result_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::Logic::Result do\n  include_context \"predicates\"\n\n  describe \"#to_s\" do\n    shared_examples_for \"string representation\" do\n      it \"returns string representation\" do\n        expect(rule.(input).to_s).to eql(output)\n      end\n    end\n\n    context \"with a predicate\" do\n      let(:rule) { Dry::Logic::Rule::Predicate.build(gt?, args: [18]) }\n      let(:input) { 17 }\n      let(:output) { \"gt?(18, 17)\" }\n\n      it_behaves_like \"string representation\"\n    end\n\n    context \"with AND operation\" do\n      let(:rule) do\n        Dry::Logic::Rule::Predicate.build(array?).and(Dry::Logic::Rule::Predicate.build(empty?))\n      end\n      let(:input) { \"\" }\n      let(:output) { 'array?(\"\") AND empty?(\"\")' }\n\n      it_behaves_like \"string representation\"\n    end\n\n    context \"with OR operation\" do\n      let(:rule) do\n        Dry::Logic::Rule::Predicate.build(array?).or(Dry::Logic::Rule::Predicate.build(empty?))\n      end\n      let(:input) { 123 }\n      let(:output) { \"array?(123) OR empty?(123)\" }\n\n      it_behaves_like \"string representation\"\n    end\n\n    context \"with XOR operation\" do\n      let(:rule) do\n        Dry::Logic::Rule::Predicate.build(array?).xor(Dry::Logic::Rule::Predicate.build(empty?))\n      end\n      let(:input) { [] }\n      let(:output) { \"array?([]) XOR empty?([])\" }\n\n      it_behaves_like \"string representation\"\n    end\n\n    context \"with THEN operation\" do\n      let(:rule) do\n        Dry::Logic::Rule::Predicate.build(array?).then(Dry::Logic::Rule::Predicate.build(empty?))\n      end\n      let(:input) { [1, 2, 3] }\n      let(:output) { \"empty?([1, 2, 3])\" }\n\n      it_behaves_like \"string representation\"\n    end\n\n    context \"with NOT operation\" do\n      let(:rule) { Dry::Logic::Operations::Negation.new(Dry::Logic::Rule::Predicate.build(array?)) }\n      let(:input) { \"foo\" }\n      let(:output) { 'not(array?(\"foo\"))' }\n\n      it_behaves_like \"string representation\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/rule_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry-logic\"\n\nRSpec.describe \"Rules\" do\n  specify \"defining an anonymous rule with an arbitrary predicate\" do\n    rule = Dry::Logic.Rule { |value| value.is_a?(Integer) }\n\n    expect(rule.(1)).to be_success\n    expect(rule[1]).to be(true)\n  end\n\n  specify \"defining a conjunction\" do\n    rule = Dry::Logic.Rule(&:even?) & Dry::Logic.Rule { |v| v > 4 }\n\n    expect(rule.(3)).to be_failure\n    expect(rule.(4)).to be_failure\n    expect(rule.(5)).to be_failure\n    expect(rule.(6)).to be_success\n  end\n\n  specify \"defining a disjunction\" do\n    rule = Dry::Logic.Rule { |v| v < 4 } | Dry::Logic.Rule { |v| v > 6 }\n\n    expect(rule.(5)).to be_failure\n    expect(rule.(3)).to be_success\n    expect(rule.(7)).to be_success\n  end\n\n  specify \"defining an implication\" do\n    rule = Dry::Logic.Rule(&:empty?) > Dry::Logic.Rule { |v| v.is_a?(Array) }\n\n    expect(rule.(\"foo\")).to be_success\n    expect(rule.([1, 2])).to be_success\n    expect(rule.([])).to be_success\n    expect(rule.(\"\")).to be_failure\n  end\n\n  specify \"defining an exclusive disjunction\" do\n    rule = Dry::Logic.Rule(&:empty?) ^ Dry::Logic.Rule { |v| v.is_a?(Array) }\n\n    expect(rule.(\"foo\")).to be_failure\n    expect(rule.([])).to be_failure\n    expect(rule.([1, 2])).to be_success\n    expect(rule.(\"\")).to be_success\n  end\n\n  specify \"defining a rule with options\" do\n    # using &:empty? breaks the spec\n    rule = Dry::Logic::Rule(id: :empty?) { |value| value.empty? }\n    # rubocop:enable Style/SymbolProc\n\n    expect(rule.(\"foo\")).to be_failure\n    expect(rule.(\"\")).to be_success\n    expect(rule.ast(\"foo\")).to eql([:predicate, [:empty?, [[:value, \"foo\"]]]])\n  end\nend\n"
  },
  {
    "path": "spec/shared/built_rule.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/builder\"\n\nRSpec.shared_examples \"built rule\" do |rule_type, *args|\n  subject(:built_rule) { Dry::Logic::Builder.call(&expression) }\n  let(:rule_type) { rule_type }\n\n  case rule_type\n  when :predicate\n    include_examples \"built rule predicate\", *args\n  else\n    include_examples \"built rule operation\", *args\n  end\n\n  describe \"#to_ast\" do\n    subject(:ast) { built_rule.to_ast }\n    it { is_expected.to include(rule_type, rule_node) }\n  end\nend\n\nRSpec.shared_examples \"built rule predicate\" do |predicate_name, *args|\n  it { is_expected.to be_kind_of(Dry::Logic::Rule::Predicate) }\n  let(:predicate_name) { predicate_name }\n  let(:rule_node) { [predicate_name, include(*args)] }\n\n  describe \"#predicate\" do\n    subject(:predicate) { built_rule.predicate }\n\n    describe \"#name\" do\n      subject(:name) { predicate.name }\n      it { is_expected.to eq(predicate_name) }\n    end\n  end\nend\n\nRSpec.shared_examples \"built rule operation\" do |node|\n  it { is_expected.to be_kind_of(Dry::Logic::Operation::Abstract) }\n  let(:rule_node) { node }\nend\n"
  },
  {
    "path": "spec/shared/operation.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/builder\"\n\nRSpec.shared_examples \"operation\" do\n  before { extend Dry::Logic::Builder }\n  let(:operation) { build(&expression) }\n  let(:args) { defined?(input) ? [input] : [] }\n  subject { operation.call(*args).success? }\n  it { is_expected.to eq(output) }\nend\n"
  },
  {
    "path": "spec/shared/predicate.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/builder\"\n\n# TODO: Merge with {operation}?\nRSpec.shared_examples \"predicate\" do\n  before { extend Dry::Logic::Builder }\n  let(:predicate) { build(&expression) }\n  let(:args) { defined?(input) ? [input] : [] }\n  subject { predicate.call(*args).success? }\n  it { is_expected.to eq(output) }\nend\n"
  },
  {
    "path": "spec/shared/predicates.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.shared_examples \"predicates\" do\n  let(:nil?) { Dry::Logic::Predicates[:nil?] }\n\n  let(:array?) { Dry::Logic::Predicates[:array?] }\n\n  let(:empty?) { Dry::Logic::Predicates[:empty?] }\n\n  let(:str?) { Dry::Logic::Predicates[:str?] }\n\n  let(:true?) { Dry::Logic::Predicates[:true?] }\n\n  let(:hash?) { Dry::Logic::Predicates[:hash?] }\n\n  let(:int?) { Dry::Logic::Predicates[:int?] }\n\n  let(:filled?) { Dry::Logic::Predicates[:filled?] }\n\n  let(:min_size?) { Dry::Logic::Predicates[:min_size?] }\n\n  let(:lt?) { Dry::Logic::Predicates[:lt?] }\n\n  let(:gt?) { Dry::Logic::Predicates[:gt?] }\n\n  let(:key?) { Dry::Logic::Predicates[:key?] }\n\n  let(:attr?) { Dry::Logic::Predicates[:attr?] }\n\n  let(:eql?) { Dry::Logic::Predicates[:eql?] }\n\n  let(:size?) { Dry::Logic::Predicates[:size?] }\n\n  let(:case?) { Dry::Logic::Predicates[:case?] }\n\n  let(:equal?) { Dry::Logic::Predicates[:equal?] }\nend\n\nRSpec.shared_examples \"a passing predicate\" do\n  let(:predicate) { Dry::Logic::Predicates[predicate_name] }\n\n  it do\n    arguments_list.each do |args|\n      expect(predicate.call(*args)).to be(true)\n    end\n  end\nend\n\nRSpec.shared_examples \"a failing predicate\" do\n  let(:predicate) { Dry::Logic::Predicates[predicate_name] }\n\n  it do\n    arguments_list.each do |args|\n      expect(predicate.call(*args)).to be(false)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/shared/rule.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.shared_examples_for Dry::Logic::Rule do\n  let(:arity) { 2 }\n  let(:predicate) { double(:predicate, arity: arity, name: predicate_name) }\n  let(:rule_type) { described_class }\n  let(:predicate_name) { :good? }\n\n  describe \"#arity\" do\n    it \"returns its predicate arity\" do\n      rule = rule_type.build(predicate)\n\n      expect(rule.arity).to be(2)\n    end\n  end\n\n  describe \"#parameters\" do\n    it \"returns a list of args with their names\" do\n      rule = rule_type.build(-> foo, bar { true }, args: [312])\n\n      expect(rule.parameters).to eql([%i[req foo], %i[req bar]])\n    end\n  end\n\n  describe \"#call\" do\n    let(:arity) { 1 }\n\n    it \"returns success for valid input\" do\n      rule = rule_type.build(predicate)\n\n      expect(predicate).to receive(:[]).with(2).and_return(true)\n\n      expect(rule.(2)).to be_success\n    end\n\n    it \"returns failure for invalid input\" do\n      rule = rule_type.build(predicate)\n\n      expect(predicate).to receive(:[]).with(2).and_return(false)\n\n      expect(rule.(2)).to be_failure\n    end\n  end\n\n  describe \"#[]\" do\n    let(:arity) { 1 }\n\n    it \"delegates to its predicate\" do\n      rule = rule_type.build(predicate)\n\n      expect(predicate).to receive(:[]).with(2).and_return(true)\n      expect(rule[2]).to be(true)\n    end\n  end\n\n  describe \"#curry\" do\n    it \"returns a curried rule\" do\n      rule = rule_type.build(predicate).curry(3)\n\n      expect(predicate).to receive(:[]).with(3, 2).and_return(true)\n      expect(rule.args).to eql([3])\n\n      expect(rule.(2)).to be_success\n    end\n\n    it \"raises argument error when arity does not match\" do\n      expect(predicate).to receive(:arity).and_return(2)\n\n      expect { rule_type.build(predicate).curry(3, 2, 1) }.to raise_error(\n        ArgumentError, \"wrong number of arguments (3 for 2)\"\n      )\n    end\n  end\nend\n"
  },
  {
    "path": "spec/spec_helper.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative \"support/coverage\"\nrequire_relative \"support/warnings\"\n\nbegin\n  require \"pry-byebug\"\nrescue LoadError;\nend\n\nrequire \"dry/logic\"\nrequire \"pathname\"\n\nSPEC_ROOT = Pathname(__dir__)\n\nDir[SPEC_ROOT.join(\"shared/**/*.rb\")].each(&method(:require))\nDir[SPEC_ROOT.join(\"support/**/*.rb\")].each(&method(:require))\n\nRSpec.configure do |config|\n  config.include Module.new {\n    def undefined\n      Dry::Core::Constants::Undefined\n    end\n  }\nend\n"
  },
  {
    "path": "spec/support/coverage.rb",
    "content": "# frozen_string_literal: true\n\n# This file is synced from hanakai-rb/repo-sync\n\nif ENV[\"COVERAGE\"] == \"true\"\n  require \"simplecov\"\n  require \"simplecov-cobertura\"\n\n  SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter\n\n  SimpleCov.start do\n    add_filter \"/spec/\"\n    enable_coverage :branch\n  end\nend\n"
  },
  {
    "path": "spec/support/mutant.rb",
    "content": "# frozen_string_literal: true\n\nmodule Mutant\n  class Selector\n    class Expression < self\n      def call(_subject)\n        integration.all_tests\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/support/rspec.rb",
    "content": "# frozen_string_literal: true\n\n# This file is synced from hanakai-rb/repo-sync\n\nRSpec.configure do |config|\n  # When no filter given, search and run focused tests\n  config.filter_run_when_matching :focus\n\n  # Disables rspec monkey patches (no reason for their existence tbh)\n  config.disable_monkey_patching!\n\n  # Run ruby in verbose mode\n  config.warnings = true\n\n  # Collect all failing expectations automatically,\n  # without calling aggregate_failures everywhere\n  config.define_derived_metadata do |meta|\n    meta[:aggregate_failures] = true\n  end\n\n  if ENV[\"CI\"]\n    # No focused specs should be committed. This ensures\n    # builds fail when this happens.\n    config.before(:each, :focus) do\n      raise StandardError, \"You've committed a focused spec!\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/support/warnings.rb",
    "content": "# frozen_string_literal: true\n\n# This file is synced from hanakai-rb/repo-sync\n\nrequire \"warning\"\n\n# Ignore warnings for experimental features\nWarning[:experimental] = false if Warning.respond_to?(:[])\n\n# Ignore all warnings coming from gem dependencies\nGem.path.each do |path|\n  Warning.ignore(//, path)\nend\n"
  },
  {
    "path": "spec/unit/builder_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::Logic::Builder do\n  describe \"undefined methods\" do\n    it \"raises NameError\" do\n      expect do\n        described_class.call { does_not_exist }\n      end.to raise_error(NameError, /does_not_exist/)\n    end\n  end\n\n  describe \"leakage\" do\n    context \"given a module extending ::Builder\" do\n      subject do\n        Module.new do\n          extend Dry::Logic::Builder\n        end\n      end\n\n      it { is_expected.not_to respond_to(:int?) }\n      it { is_expected.to respond_to(:call) }\n      it { is_expected.to respond_to(:build) }\n    end\n  end\n\n  describe \"ast of built rule\" do\n    let(:expression) { -> (*) { key?(:speed) } }\n    it_behaves_like \"built rule\", :predicate, :key?, [:name, :speed]\n  end\nend\n"
  },
  {
    "path": "spec/unit/operations/and_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::Logic::Operations::And do\n  subject(:operation) { described_class.new(left, right) }\n\n  include_context \"predicates\"\n\n  let(:left) { Dry::Logic::Rule::Predicate.build(int?) }\n  let(:right) { Dry::Logic::Rule::Predicate.build(gt?).curry(18) }\n\n  describe \"#call\" do\n    it \"calls left and right\" do\n      expect(operation.(18)).to be_failure\n    end\n  end\n\n  describe \"#to_ast\" do\n    it \"returns ast\" do\n      expect(operation.to_ast).to eql(\n        [:and, [[:predicate, [:int?, [[:input, undefined]]]], [:predicate, [:gt?, [[:num, 18], [:input, undefined]]]]]]\n      )\n    end\n\n    it \"returns result ast\" do\n      expect(operation.(\"18\").to_ast).to eql(\n        [:and, [[:predicate, [:int?, [[:input, \"18\"]]]], [:hint, [:predicate, [:gt?, [[:num, 18], [:input, \"18\"]]]]]]]\n      )\n\n      expect(operation.with(hints: false).(\"18\").to_ast).to eql(\n        [:predicate, [:int?, [[:input, \"18\"]]]]\n      )\n\n      expect(operation.(18).to_ast).to eql(\n        [:predicate, [:gt?, [[:num, 18], [:input, 18]]]]\n      )\n    end\n\n    it \"returns failure result ast\" do\n      expect(operation.with(id: :age).(\"18\").to_ast).to eql(\n        [:failure, [:age, [:and, [[:predicate, [:int?, [[:input, \"18\"]]]], [:hint, [:predicate, [:gt?, [[:num, 18], [:input, \"18\"]]]]]]]]]\n      )\n\n      expect(operation.with(id: :age).(18).to_ast).to eql(\n        [:failure, [:age, [:predicate, [:gt?, [[:num, 18], [:input, 18]]]]]]\n      )\n    end\n  end\n\n  describe \"#and\" do\n    let(:other) { Dry::Logic::Rule::Predicate.build(lt?).curry(30) }\n\n    it \"creates and with the other\" do\n      expect(operation.and(other).(31)).to be_failure\n    end\n  end\n\n  describe \"#or\" do\n    let(:other) { Dry::Logic::Rule::Predicate.build(lt?).curry(14) }\n\n    it \"creates or with the other\" do\n      expect(operation.or(other).(13)).to be_success\n    end\n  end\n\n  describe \"#to_s\" do\n    it \"returns string representation\" do\n      expect(operation.to_s).to eql(\"int? AND gt?(18)\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/operations/attr_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::Logic::Operations::Attr do\n  subject(:operation) do\n    Dry::Logic::Operations::Attr.new(Dry::Logic::Rule::Predicate.build(str?), name: :name)\n  end\n\n  include_context \"predicates\"\n\n  let(:model) { Struct.new(:name) }\n\n  describe \"#call\" do\n    it \"applies predicate to the value\" do\n      expect(operation.(model.new(\"Jane\"))).to be_success\n      expect(operation.(model.new(nil))).to be_failure\n    end\n  end\n\n  describe \"#and\" do\n    let(:other) do\n      Dry::Logic::Operations::Attr.new(Dry::Logic::Rule::Predicate.build(min_size?).curry(3), name: :name)\n    end\n\n    it \"returns and where value is passed to the right\" do\n      present_and_string = operation.and(other)\n\n      expect(present_and_string.(model.new(\"Jane\"))).to be_success\n\n      expect(present_and_string.(model.new(\"Ja\"))).to be_failure\n      expect(present_and_string.(model.new(1))).to be_failure\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/operations/check_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::Logic::Operations::Check do\n  include_context \"predicates\"\n\n  describe \"#call\" do\n    context \"with 1-level nesting\" do\n      subject(:operation) do\n        described_class.new(Dry::Logic::Rule::Predicate.build(eql?).curry(1), id: :compare, keys: [:num])\n      end\n\n      it \"applies predicate to args extracted from the input\" do\n        expect(operation.(num: 1)).to be_success\n        expect(operation.(num: 2)).to be_failure\n      end\n    end\n\n    context \"with 2-levels nesting\" do\n      subject(:operation) do\n        described_class.new(\n          Dry::Logic::Rule::Predicate.build(eql?), id: :compare, keys: [[:nums, :left], [:nums, :right]]\n        )\n      end\n\n      it \"applies predicate to args extracted from the input\" do\n        expect(operation.(nums: {left: 1, right: 1})).to be_success\n        expect(operation.(nums: {left: 1, right: 2})).to be_failure\n      end\n\n      it \"curries args properly\" do\n        result = operation.(nums: {left: 1, right: 2})\n\n        expect(result.to_ast).to eql(\n          [:failure, [:compare, [:check, [\n            [[:nums, :left], [:nums, :right]], [:predicate, [:eql?, [[:left, 1], [:right, 2]]]]\n          ]]]]\n        )\n      end\n    end\n\n    context \"with its output as input\" do\n      let(:gt?) { Dry::Logic::Predicates[:gt?] }\n      let(:min) { Dry::Logic::Rule::Predicate.new(gt?).curry(18) }\n      let(:inner) { described_class.new(min, keys: [:age]) }\n      let(:outer) { described_class.new(inner, keys: [:person]) }\n\n      subject { outer.call(input) }\n\n      describe \"success\" do\n        let(:input) { {person: {age: 20}} }\n        it { is_expected.to be_a_success }\n      end\n\n      describe \"failure\" do\n        let(:input) { {person: {age: 10}} }\n        it { is_expected.not_to be_a_success }\n      end\n    end\n  end\n\n  describe \"#to_ast\" do\n    subject(:operation) do\n      described_class.new(Dry::Logic::Rule::Predicate.build(str?), keys: [:email])\n    end\n\n    it \"returns ast\" do\n      expect(operation.to_ast).to eql(\n        [:check, [[:email], [:predicate, [:str?, [[:input, undefined]]]]]]\n      )\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/operations/each_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::Logic::Operations::Each do\n  subject(:operation) { described_class.new(is_string) }\n\n  include_context \"predicates\"\n\n  let(:is_string) { Dry::Logic::Rule::Predicate.build(str?) }\n\n  describe \"#call\" do\n    it \"applies its rules to all elements in the input\" do\n      expect(operation.([\"Address\"])).to be_success\n\n      expect(operation.([nil, \"Address\"])).to be_failure\n      expect(operation.([:Address, \"Address\"])).to be_failure\n    end\n  end\n\n  describe \"#to_ast\" do\n    it \"returns ast\" do\n      expect(operation.to_ast).to eql([:each, [:predicate, [:str?, [[:input, undefined]]]]])\n    end\n\n    it \"returns result ast\" do\n      expect(operation.([nil, 12, nil]).to_ast).to eql(\n        [:set, [\n          [:key, [0, [:predicate, [:str?, [[:input, nil]]]]]],\n          [:key, [1, [:predicate, [:str?, [[:input, 12]]]]]],\n          [:key, [2, [:predicate, [:str?, [[:input, nil]]]]]]\n        ]]\n      )\n    end\n\n    it \"returns failure result ast\" do\n      expect(operation.with(id: :tags).([nil, \"red\", 12]).to_ast).to eql(\n        [:failure, [:tags, [:set, [\n          [:key, [0, [:predicate, [:str?, [[:input, nil]]]]]],\n          [:key, [2, [:predicate, [:str?, [[:input, 12]]]]]]\n        ]]]]\n      )\n    end\n  end\n\n  describe \"#to_s\" do\n    it \"returns string representation\" do\n      expect(operation.to_s).to eql(\"each(str?)\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/operations/implication_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::Logic::Operations::Implication do\n  subject(:operation) { described_class.new(left, right) }\n\n  include_context \"predicates\"\n\n  let(:left) { Dry::Logic::Rule::Predicate.build(int?) }\n  let(:right) { Dry::Logic::Rule::Predicate.build(gt?).curry(18) }\n\n  describe \"#call\" do\n    it \"calls left and right\" do\n      expect(operation.(\"19\")).to be_success\n      expect(operation.(19)).to be_success\n      expect(operation.(18)).to be_failure\n    end\n  end\n\n  describe \"#to_ast\" do\n    it \"returns ast\" do\n      expect(operation.to_ast).to eql(\n        [:implication, [[:predicate, [:int?, [[:input, undefined]]]], [:predicate, [:gt?, [[:num, 18], [:input, undefined]]]]]]\n      )\n    end\n  end\n\n  describe \"#to_s\" do\n    it \"returns string representation\" do\n      expect(operation.to_s).to eql(\"int? THEN gt?(18)\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/operations/key_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::Logic::Operations::Key do\n  subject(:operation) { described_class.new(predicate, name: :user) }\n\n  include_context \"predicates\"\n\n  let(:predicate) do\n    Dry::Logic::Rule::Predicate.build(key?).curry(:age)\n  end\n\n  describe \"#call\" do\n    context \"with a plain predicate\" do\n      it \"returns a success for valid input\" do\n        expect(operation.(user: {age: 18})).to be_success\n      end\n\n      it \"returns a failure for invalid input\" do\n        result = operation.(user: {})\n\n        expect(result).to be_failure\n\n        expect(result.to_ast).to eql(\n          [:failure, [:user, [:key, [:user,\n                                     [:predicate, [:key?, [[:name, :age], [:input, {}]]]]]]]]\n        )\n      end\n    end\n\n    context \"with a set rule as predicate\" do\n      subject(:operation) do\n        described_class.new(predicate, name: :address)\n      end\n\n      let(:predicate) do\n        Dry::Logic::Operations::Set.new(\n          Dry::Logic::Rule::Predicate.build(key?).curry(:city),\n          Dry::Logic::Rule::Predicate.build(key?).curry(:zipcode)\n        )\n      end\n\n      it \"applies set rule to the value that passes\" do\n        result = operation.(address: {city: \"NYC\", zipcode: \"123\"})\n\n        expect(result).to be_success\n      end\n\n      it \"applies set rule to the value that fails\" do\n        result = operation.(address: {city: \"NYC\"})\n\n        expect(result).to be_failure\n\n        expect(result.to_ast).to eql(\n          [:failure, [:address, [:key, [:address, [:set, [\n            [:predicate, [:key?, [[:name, :zipcode], [:input, {city: \"NYC\"}]]]]\n          ]]]]]]\n        )\n      end\n    end\n\n    context \"with an each rule as predicate\" do\n      subject(:operation) do\n        described_class.new(predicate, name: :nums)\n      end\n\n      let(:predicate) do\n        Dry::Logic::Operations::Each.new(Dry::Logic::Rule::Predicate.build(str?))\n      end\n\n      it \"applies each rule to the value that passses\" do\n        result = operation.(nums: %w[1 2 3])\n\n        expect(result).to be_success\n      end\n\n      it \"applies each rule to the value that fails\" do\n        failure = operation.(nums: [1, \"3\", 3])\n\n        expect(failure).to be_failure\n\n        expect(failure.to_ast).to eql(\n          [:failure, [:nums, [:key, [:nums, [:set, [\n            [:key, [0, [:predicate, [:str?, [[:input, 1]]]]]],\n            [:key, [2, [:predicate, [:str?, [[:input, 3]]]]]]\n          ]]]]]]\n        )\n      end\n    end\n  end\n\n  describe \"#to_ast\" do\n    it \"returns ast\" do\n      expect(operation.to_ast).to eql(\n        [:key, [:user, [:predicate, [:key?, [[:name, :age], [:input, undefined]]]]]]\n      )\n    end\n  end\n\n  describe \"#ast\" do\n    it \"returns ast without the input\" do\n      expect(operation.ast).to eql(\n        [:key, [:user, [:predicate, [:key?, [[:name, :age], [:input, undefined]]]]]]\n      )\n    end\n\n    it \"returns ast with the input\" do\n      expect(operation.ast(user: \"jane\")).to eql(\n        [:key, [:user, [:predicate, [:key?, [[:name, :age], [:input, \"jane\"]]]]]]\n      )\n    end\n  end\n\n  describe \"#and\" do\n    subject(:operation) do\n      described_class.new(Dry::Logic::Rule::Predicate.build(str?), name: [:user, :name])\n    end\n\n    let(:other) do\n      described_class.new(Dry::Logic::Rule::Predicate.build(filled?), name: [:user, :name])\n    end\n\n    it \"returns and rule where value is passed to the right\" do\n      present_and_string = operation.and(other)\n\n      expect(present_and_string.(user: {name: \"Jane\"})).to be_success\n\n      expect(present_and_string.(user: {})).to be_failure\n      expect(present_and_string.(user: {name: 1})).to be_failure\n    end\n  end\n\n  describe \"#to_s\" do\n    it \"returns string representation\" do\n      expect(operation.to_s).to eql(\"key[user](key?(:age))\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/operations/negation_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::Logic::Operations::Negation do\n  subject(:operation) { described_class.new(is_int) }\n\n  include_context \"predicates\"\n\n  let(:is_int) { Dry::Logic::Rule::Predicate.build(int?) }\n\n  describe \"#call\" do\n    it \"negates its rule\" do\n      expect(operation.(\"19\")).to be_success\n      expect(operation.(17)).to be_failure\n    end\n\n    context \"double negation\" do\n      subject(:double_negation) { described_class.new(operation) }\n\n      it \"works as rule\" do\n        expect(double_negation.(\"19\")).to be_failure\n        expect(double_negation.(17)).to be_success\n      end\n    end\n  end\n\n  describe \"#to_ast\" do\n    it \"returns ast\" do\n      expect(operation.to_ast).to eql(\n        [:not, [:predicate, [:int?, [[:input, undefined]]]]]\n      )\n    end\n\n    it \"returns result ast\" do\n      expect(operation.(17).to_ast).to eql(\n        [:not, [:predicate, [:int?, [[:input, 17]]]]]\n      )\n    end\n\n    it \"returns result ast with an :id\" do\n      expect(operation.with(id: :age).(17).to_ast).to eql(\n        [:failure, [:age, [:not, [:predicate, [:int?, [[:input, 17]]]]]]]\n      )\n    end\n  end\n\n  describe \"#to_s\" do\n    it \"returns string representation\" do\n      expect(operation.to_s).to eql(\"not(int?)\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/operations/or_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::Logic::Operations::Or do\n  subject(:operation) { described_class.new(left, right) }\n\n  include_context \"predicates\"\n\n  let(:left) { Dry::Logic::Rule::Predicate.build(nil?) }\n  let(:right) { Dry::Logic::Rule::Predicate.build(gt?).curry(18) }\n\n  let(:other) do\n    Dry::Logic::Rule::Predicate.build(int?) & Dry::Logic::Rule::Predicate.build(lt?).curry(14)\n  end\n\n  describe \"#call\" do\n    it \"calls left and right\" do\n      expect(operation.(nil)).to be_success\n      expect(operation.(19)).to be_success\n      expect(operation.(18)).to be_failure\n    end\n  end\n\n  describe \"#to_ast\" do\n    it \"returns ast\" do\n      expect(operation.to_ast).to eql(\n        [:or, [\n          [:predicate, [:nil?, [[:input, undefined]]]],\n          [:predicate, [:gt?, [[:num, 18], [:input, undefined]]]]\n        ]]\n      )\n    end\n\n    it \"returns result ast\" do\n      expect(operation.(17).to_ast).to eql(\n        [:or, [\n          [:predicate, [:nil?, [[:input, 17]]]],\n          [:predicate, [:gt?, [[:num, 18], [:input, 17]]]]\n        ]]\n      )\n    end\n\n    it \"returns failure result ast\" do\n      expect(operation.with(id: :age).(17).to_ast).to eql(\n        [:failure, [:age, [:or, [\n          [:predicate, [:nil?, [[:input, 17]]]],\n          [:predicate, [:gt?, [[:num, 18], [:input, 17]]]]\n        ]]]]\n      )\n    end\n  end\n\n  describe \"#and\" do\n    it \"creates and with the other\" do\n      expect(operation.and(other).(nil)).to be_failure\n      expect(operation.and(other).(19)).to be_failure\n      expect(operation.and(other).(13)).to be_failure\n      expect(operation.and(other).(14)).to be_failure\n    end\n  end\n\n  describe \"#or\" do\n    it \"creates or with the other\" do\n      expect(operation.or(other).(nil)).to be_success\n      expect(operation.or(other).(19)).to be_success\n      expect(operation.or(other).(13)).to be_success\n      expect(operation.or(other).(14)).to be_failure\n    end\n  end\n\n  describe \"#to_s\" do\n    it \"returns string representation\" do\n      expect(operation.to_s).to eql(\"nil? OR gt?(18)\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/operations/set_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::Logic::Operations::Set do\n  subject(:operation) { described_class.new(is_int, gt_18) }\n\n  include_context \"predicates\"\n\n  let(:is_int) { Dry::Logic::Rule::Predicate.build(int?) }\n  let(:gt_18) { Dry::Logic::Rule::Predicate.build(gt?, args: [18]) }\n\n  describe \"#call\" do\n    it \"applies all its rules to the input\" do\n      expect(operation.(19)).to be_success\n      expect(operation.(17)).to be_failure\n    end\n  end\n\n  describe \"#to_ast\" do\n    it \"returns ast\" do\n      expect(operation.to_ast).to eql(\n        [:set, [[:predicate, [:int?, [[:input, undefined]]]], [:predicate, [:gt?, [[:num, 18], [:input, undefined]]]]]]\n      )\n    end\n\n    it \"returns result ast\" do\n      expect(operation.(17).to_ast).to eql(\n        [:set, [[:predicate, [:gt?, [[:num, 18], [:input, 17]]]]]]\n      )\n    end\n\n    it \"returns result ast with an :id\" do\n      expect(operation.with(id: :age).(17).to_ast).to eql(\n        [:failure, [:age, [:set, [[:predicate, [:gt?, [[:num, 18], [:input, 17]]]]]]]]\n      )\n    end\n  end\n\n  describe \"#to_s\" do\n    it \"returns string representation\" do\n      expect(operation.to_s).to eql(\"set(int?, gt?(18))\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/operations/xor_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::Logic::Operations::Xor do\n  subject(:operation) { described_class.new(left, right) }\n\n  include_context \"predicates\"\n\n  let(:left) { Dry::Logic::Rule::Predicate.build(array?) }\n  let(:right) { Dry::Logic::Rule::Predicate.build(empty?) }\n\n  let(:other) do\n    Dry::Logic::Rule::Predicate.build(str?)\n  end\n\n  describe \"#call\" do\n    it \"calls left and right\" do\n      expect(operation.(nil)).to be_success\n      expect(operation.(\"\")).to be_success\n      expect(operation.([])).to be_failure\n    end\n  end\n\n  describe \"#to_ast\" do\n    it \"returns ast\" do\n      expect(operation.to_ast).to eql(\n        [:xor, [[:predicate, [:array?, [[:input, undefined]]]], [:predicate, [:empty?, [[:input, undefined]]]]]]\n      )\n    end\n\n    it \"returns result ast\" do\n      expect(operation.([]).to_ast).to eql(\n        [:xor, [[:predicate, [:array?, [[:input, []]]]], [:predicate, [:empty?, [[:input, []]]]]]]\n      )\n    end\n\n    it \"returns failure result ast\" do\n      expect(operation.with(id: :name).([]).to_ast).to eql(\n        [:failure, [:name, [:xor, [[:predicate, [:array?, [[:input, []]]]], [:predicate, [:empty?, [[:input, []]]]]]]]]\n      )\n    end\n  end\n\n  describe \"#and\" do\n    it \"creates conjunction with the other\" do\n      expect(operation.and(other).(nil)).to be_failure\n      expect(operation.and(other).(19)).to be_failure\n      expect(operation.and(other).(\"\")).to be_success\n    end\n  end\n\n  describe \"#or\" do\n    it \"creates disjunction with the other\" do\n      expect(operation.or(other).([])).to be_failure\n      expect(operation.or(other).(\"\")).to be_success\n    end\n  end\n\n  describe \"#to_s\" do\n    it \"returns string representation\" do\n      expect(operation.to_s).to eql(\"array? XOR empty?\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/array_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#array?\" do\n    let(:predicate_name) { :array? }\n\n    context \"when value is an array\" do\n      let(:arguments_list) do\n        [\n          [[]],\n          [%w[other array]],\n          [[123, \"really\", :blah]],\n          [[]],\n          [[nil]],\n          [[false]],\n          [[true]]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when value is not an array\" do\n      let(:arguments_list) do\n        [\n          [\"\"],\n          [{}],\n          [nil],\n          [:symbol],\n          [String],\n          [1],\n          [1.0],\n          [true],\n          [{}]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/attr_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#attr?\" do\n    let(:predicate_name) { :attr? }\n\n    context \"when value responds to the attr name\" do\n      let(:arguments_list) do\n        [\n          [:name, Struct.new(:name).new(\"John\")],\n          [:age, Struct.new(:age).new(18)]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value does not respond to the attr name\" do\n      let(:arguments_list) do\n        [\n          [:name, Struct.new(:age).new(18)],\n          [:age, Struct.new(:name).new(\"Jill\")]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/bool_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#bool?\" do\n    let(:predicate_name) { :bool? }\n\n    context \"when value is a boolean\" do\n      let(:arguments_list) do\n        [[true], [false]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when value is not a bool\" do\n      let(:arguments_list) do\n        [\n          [\"\"],\n          [[]],\n          [{}],\n          [nil],\n          [:symbol],\n          [String],\n          [1],\n          [0],\n          [\"true\"],\n          [\"false\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/bytesize_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#bytesize?\" do\n    let(:predicate_name) { :bytesize? }\n\n    context \"when value size is equal to n\" do\n      let(:arguments_list) do\n        [\n          [4, \"こa\"],\n          [1..8, \"こa\"]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when value size is greater than n\" do\n      let(:arguments_list) do\n        [\n          [3, \"こa\"],\n          [1..3, \"こa\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n\n    context \"with value size is less than n\" do\n      let(:arguments_list) do\n        [\n          [5, \"こa\"],\n          [5..10, \"こa\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n\n    context \"with an unsupported size\" do\n      it \"raises an error\" do\n        expect { Dry::Logic::Predicates[:bytesize?].call(\"oops\", 1) }.to raise_error(ArgumentError, /oops/)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/case_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#case?\" do\n    let(:predicate_name) { :case? }\n\n    context \"when the value matches the pattern\" do\n      let(:arguments_list) do\n        [\n          [11, 11],\n          [:odd?.to_proc, 11],\n          [/\\Af/, \"foo\"],\n          [Integer, 11]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when the value doesn't match the pattern\" do\n      let(:arguments_list) do\n        [\n          [13, 14],\n          [:odd?.to_proc, 12],\n          [/\\Af/, \"bar\"],\n          [String, 11]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/date_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#date?\" do\n    let(:predicate_name) { :date? }\n\n    context \"when value is a date\" do\n      let(:arguments_list) do\n        [[Date.today]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not an integer\" do\n      let(:arguments_list) do\n        [\n          [\"\"],\n          [[]],\n          [{}],\n          [nil],\n          [:symbol],\n          [String],\n          [1]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/date_time_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#date_time?\" do\n    let(:predicate_name) { :date_time? }\n\n    context \"when value is a datetime\" do\n      let(:arguments_list) do\n        [[DateTime.now]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not an integer\" do\n      let(:arguments_list) do\n        [\n          [\"\"],\n          [[]],\n          [{}],\n          [nil],\n          [:symbol],\n          [String],\n          [1]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/decimal_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#decimal?\" do\n    let(:predicate_name) { :decimal? }\n\n    context \"when value is a decimal\" do\n      let(:arguments_list) do\n        [[1.2.to_d]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not an integer\" do\n      let(:arguments_list) do\n        [\n          [\"\"],\n          [[]],\n          [{}],\n          [nil],\n          [:symbol],\n          [String],\n          [1],\n          [1.0]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/empty_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#empty?\" do\n    let(:predicate_name) { :empty? }\n\n    context \"when value is empty\" do\n      let(:arguments_list) do\n        [\n          [\"\"],\n          [[]],\n          [{}],\n          [nil]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not empty\" do\n      let(:arguments_list) do\n        [\n          [\"Jill\"],\n          [[1, 2, 3]],\n          [{name: \"John\"}],\n          [true],\n          [false],\n          [\"1\"],\n          [\"0\"],\n          [:symbol],\n          [String]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/eql_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates, \"#eql?\" do\n  let(:predicate_name) { :eql? }\n\n  context \"when value is equal to the arg\" do\n    let(:arguments_list) do\n      [%w[Foo Foo]]\n    end\n\n    it_behaves_like \"a passing predicate\"\n  end\n\n  context \"with value is not equal to the arg\" do\n    let(:arguments_list) do\n      [%w[Bar Foo]]\n    end\n\n    it_behaves_like \"a failing predicate\"\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/even_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#even?\" do\n    let(:predicate_name) { :even? }\n\n    context \"when value is an odd int\" do\n      let(:arguments_list) do\n        [\n          [13],\n          [1],\n          [1111]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n\n    context \"with value is an even int\" do\n      let(:arguments_list) do\n        [\n          [0],\n          [2],\n          [2222]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/excluded_from_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#excluded_from?\" do\n    let(:predicate_name) { :excluded_from? }\n\n    context \"when value is not present in list\" do\n      let(:arguments_list) do\n        [\n          [%w[Jill John], \"Jack\"],\n          [1..2, 0],\n          [1..2, 3],\n          [[nil, false], true]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is present in list\" do\n      let(:arguments_list) do\n        [\n          [%w[Jill John], \"Jill\"],\n          [%w[Jill John], \"John\"],\n          [1..2, 1],\n          [1..2, 2],\n          [[nil, false], nil],\n          [[nil, false], false]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/excludes_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#excludes?\" do\n    let(:predicate_name) { :excludes? }\n\n    context \"with input excludes value\" do\n      let(:arguments_list) do\n        [\n          [\"Jack\", %w[Jill John]],\n          [0, 1..2],\n          [3, 1..2],\n          [\"foo\", \"Hello World\"],\n          [:foo, {bar: 0}],\n          [true, [nil, false]]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with input of invalid type\" do\n      let(:arguments_list) do\n        [\n          [2, 1],\n          [1, nil],\n          [\"foo\", 1],\n          [1, \"foo\"],\n          [1..2, \"foo\"],\n          [\"foo\", 1..2],\n          [:key, \"foo\"]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when input includes value\" do\n      let(:arguments_list) do\n        [\n          [\"Jill\", %w[Jill John]],\n          [\"John\", %w[Jill John]],\n          [1, 1..2],\n          [2, 1..2],\n          [\"Hello\", \"Hello World\"],\n          [\"World\", \"Hello World\"],\n          [:bar, {bar: 0}],\n          [nil, [nil, false]],\n          [false, [nil, false]]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/false_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#false?\" do\n    let(:predicate_name) { :false? }\n\n    context \"when value is false\" do\n      let(:arguments_list) do\n        [[false]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when value is not false\" do\n      let(:arguments_list) do\n        [\n          [true],\n          [\"\"],\n          [[]],\n          [{}],\n          [nil],\n          [:symbol],\n          [String],\n          [1],\n          [0],\n          [\"true\"],\n          [\"false\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/filled_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#filled?\" do\n    let(:predicate_name) { :filled? }\n\n    context \"when value is filled\" do\n      let(:arguments_list) do\n        [\n          [\"Jill\"],\n          [[1, 2, 3]],\n          [{name: \"John\"}],\n          [true],\n          [false],\n          [\"1\"],\n          [\"0\"],\n          [:symbol],\n          [String]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not filled\" do\n      let(:arguments_list) do\n        [\n          [\"\"],\n          [[]],\n          [{}],\n          [nil]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/float_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#float?\" do\n    let(:predicate_name) { :float? }\n\n    context \"when value is a float\" do\n      let(:arguments_list) do\n        [[1.0]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not an integer\" do\n      let(:arguments_list) do\n        [\n          [\"\"],\n          [[]],\n          [{}],\n          [nil],\n          [:symbol],\n          [String],\n          [1]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/format_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates, \"#format?\" do\n  let(:predicate_name) { :format? }\n\n  context \"when value matches provided regexp\" do\n    let(:arguments_list) do\n      [[/^F/, \"Foo\"]]\n    end\n\n    it_behaves_like \"a passing predicate\"\n  end\n\n  context \"when value does not match provided regexp\" do\n    let(:arguments_list) do\n      [[/^F/, \"Bar\"]]\n    end\n\n    it_behaves_like \"a failing predicate\"\n  end\n\n  context \"when input is nil\" do\n    let(:arguments_list) do\n      [[/^F/, nil]]\n    end\n\n    it_behaves_like \"a failing predicate\"\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/gt_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#gt?\" do\n    let(:predicate_name) { :gt? }\n\n    context \"when value is greater than n\" do\n      let(:arguments_list) do\n        [\n          [13, 14],\n          [13.37, 13.38]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when value is equal to n\" do\n      let(:arguments_list) do\n        [\n          [13, 13],\n          [13.37, 13.37]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n\n    context \"with value is less than n\" do\n      let(:arguments_list) do\n        [\n          [13, 12],\n          [13.37, 13.36]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/gteq_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#gteq?\" do\n    let(:predicate_name) { :gteq? }\n\n    context \"when value is greater than n\" do\n      let(:arguments_list) do\n        [\n          [13, 14],\n          [13.37, 13.38]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when value is equal to n\" do\n      let(:arguments_list) do\n        [\n          [13, 13],\n          [13.37, 13.37]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is less than n\" do\n      let(:arguments_list) do\n        [\n          [13, 12],\n          [13.37, 13.36]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/hash_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#hash?\" do\n    let(:predicate_name) { :hash? }\n\n    context \"when value is a hash\" do\n      let(:arguments_list) do\n        [\n          [{}],\n          [foo: :bar],\n          [{}]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when value is not a hash\" do\n      let(:arguments_list) do\n        [\n          [\"\"],\n          [[]],\n          [nil],\n          [:symbol],\n          [String],\n          [1],\n          [1.0],\n          [true],\n          [[]],\n          [Hash]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/included_in_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#included_in?\" do\n    let(:predicate_name) { :included_in? }\n\n    context \"when value is present in list\" do\n      let(:arguments_list) do\n        [\n          [%w[Jill John], \"Jill\"],\n          [%w[Jill John], \"John\"],\n          [1..2, 1],\n          [1..2, 2],\n          [[nil, false], nil],\n          [[nil, false], false]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not present in list\" do\n      let(:arguments_list) do\n        [\n          [%w[Jill John], \"Jack\"],\n          [1..2, 0],\n          [1..2, 3],\n          [[nil, false], true]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/includes_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates, \"#is?\" do\n  let(:predicate_name) { :is? }\n  let(:one) { Object.new }\n  let(:two) { Object.new }\n\n  context \"when value is equal to the arg\" do\n    let(:arguments_list) do\n      [[one, one], [:one, :one]]\n    end\n\n    it_behaves_like \"a passing predicate\"\n  end\n\n  context \"with value is not equal to the arg\" do\n    let(:arguments_list) do\n      [[one, two], [{}, {}]]\n    end\n\n    it_behaves_like \"a failing predicate\"\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/int_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#int?\" do\n    let(:predicate_name) { :int? }\n\n    context \"when value is an integer\" do\n      let(:arguments_list) do\n        [\n          [1],\n          [33],\n          [7]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not an integer\" do\n      let(:arguments_list) do\n        [\n          [\"\"],\n          [[]],\n          [{}],\n          [nil],\n          [:symbol],\n          [String]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/key_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#key?\" do\n    let(:predicate_name) { :key? }\n\n    context \"when key is present in value\" do\n      let(:arguments_list) do\n        [\n          [:name, {name: \"John\"}],\n          [:age, {age: 18}]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with key is not present in value\" do\n      let(:arguments_list) do\n        [\n          [:name, {age: 18}],\n          [:age, {name: \"Jill\"}]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/lt_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#lt?\" do\n    let(:predicate_name) { :lt? }\n\n    context \"when value is less than n\" do\n      let(:arguments_list) do\n        [\n          [13, 12],\n          [13.37, 13.36]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when value is equal to n\" do\n      let(:arguments_list) do\n        [\n          [13, 13],\n          [13.37, 13.37]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n\n    context \"with value is greater than n\" do\n      let(:arguments_list) do\n        [\n          [13, 14],\n          [13.37, 13.38]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/lteq_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#lteq?\" do\n    let(:predicate_name) { :lteq? }\n\n    context \"when value is less than n\" do\n      let(:arguments_list) do\n        [\n          [13, 12],\n          [13.37, 13.36]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when value is equal to n\" do\n      let(:arguments_list) do\n        [\n          [13, 13],\n          [13.37, 13.37]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is greater than n\" do\n      let(:arguments_list) do\n        [\n          [13, 14],\n          [13.37, 13.38]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/max_bytesize_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#max_bytesize?\" do\n    let(:predicate_name) { :max_bytesize? }\n\n    context \"when value size is less than n\" do\n      let(:arguments_list) do\n        [\n          [5, \"こa\"]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when value size is equal to n\" do\n      let(:arguments_list) do\n        [\n          [5, \"こab\"]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value size is greater than n\" do\n      let(:arguments_list) do\n        [\n          [5, \"こabc\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/max_size_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#max_size?\" do\n    let(:predicate_name) { :max_size? }\n\n    context \"when value size is less than n\" do\n      let(:arguments_list) do\n        [\n          [3, [1, 2]],\n          [5, \"Jill\"],\n          [3, {1 => \"st\", 2 => \"nd\"}],\n          [6, 1..5]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when value size is equal to n\" do\n      let(:arguments_list) do\n        [\n          [2, [1, 2]],\n          [4, \"Jill\"],\n          [2, {1 => \"st\", 2 => \"nd\"}],\n          [5, 1..5]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value size is greater than n\" do\n      let(:arguments_list) do\n        [\n          [1, [1, 2]],\n          [3, \"Jill\"],\n          [1, {1 => \"st\", 2 => \"nd\"}],\n          [4, 1..5]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/min_bytesize_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#min_bytesize?\" do\n    let(:predicate_name) { :min_bytesize? }\n\n    context \"when value size is greater than n\" do\n      let(:arguments_list) do\n        [\n          [3, \"こa\"]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when value size is equal to n\" do\n      let(:arguments_list) do\n        [\n          [5, \"こab\"]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value size is less than n\" do\n      let(:arguments_list) do\n        [\n          [5, \"こ\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/min_size_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#min_size?\" do\n    let(:predicate_name) { :min_size? }\n\n    context \"when value size is greater than n\" do\n      let(:arguments_list) do\n        [\n          [1, [1, 2]],\n          [3, \"Jill\"],\n          [1, {1 => \"st\", 2 => \"nd\"}],\n          [4, 1..5]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when value size is equal to n\" do\n      let(:arguments_list) do\n        [\n          [2, [1, 2]],\n          [4, \"Jill\"],\n          [2, {1 => \"st\", 2 => \"nd\"}],\n          [5, 1..5]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value size is less than n\" do\n      let(:arguments_list) do\n        [\n          [3, [1, 2]],\n          [5, \"Jill\"],\n          [3, {1 => \"st\", 2 => \"nd\"}],\n          [6, 1..5]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/none_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#nil?\" do\n    let(:predicate_name) { :nil? }\n\n    context \"when value is nil\" do\n      let(:arguments_list) { [[nil]] }\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when value is not nil\" do\n      let(:arguments_list) do\n        [\n          [\"\"],\n          [true],\n          [false],\n          [0],\n          [:symbol],\n          [[]],\n          [{}],\n          [String]\n        ]\n      end\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/not_eql_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates, \"#not_eql?\" do\n  let(:predicate_name) { :not_eql? }\n\n  context \"when value is equal to the arg\" do\n    let(:arguments_list) do\n      [%w[Foo Foo]]\n    end\n\n    it_behaves_like \"a failing predicate\"\n  end\n\n  context \"with value is not equal to the arg\" do\n    let(:arguments_list) do\n      [%w[Bar Foo]]\n    end\n\n    it_behaves_like \"a passing predicate\"\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/number_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#number?\" do\n    let(:predicate_name) { :number? }\n\n    context \"when value is numerical\" do\n      let(:arguments_list) do\n        [\n          [\"34\"],\n          [\"1.000004\"],\n          [\"0\"],\n          [4],\n          [\"-15.24\"],\n          [-3.5]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not numerical\" do\n      let(:arguments_list) do\n        [\n          [\"\"],\n          [\"-14px\"],\n          [\"10,150.00\"],\n          [nil],\n          [:symbol],\n          [String]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/odd_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#odd?\" do\n    let(:predicate_name) { :odd? }\n\n    context \"when value is an odd int\" do\n      let(:arguments_list) do\n        [\n          [13],\n          [1],\n          [1111]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is an even int\" do\n      let(:arguments_list) do\n        [\n          [0],\n          [2],\n          [2222]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/respond_to_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#respond_to?\" do\n    let(:predicate_name) { :respond_to? }\n\n    context \"when value responds to method\" do\n      let(:arguments_list) do\n        [\n          [:method, Object],\n          [:new, Hash]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when value does not respond to method\" do\n      let(:arguments_list) do\n        [\n          [:foo, Object],\n          [:bar, Hash]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/size_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#size?\" do\n    let(:predicate_name) { :size? }\n\n    context \"when value size is equal to n\" do\n      let(:arguments_list) do\n        [\n          [[2, 4, 6], \"abcd\"],\n          [4, \"Jill\"],\n          [2, {1 => \"st\", 2 => \"nd\"}],\n          [1..8, \"qwerty\"]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"when value size is greater than n\" do\n      let(:arguments_list) do\n        [\n          [[1, 2], \"abc\"],\n          [5, \"Jill\"],\n          [3, {1 => \"st\", 2 => \"nd\"}],\n          [1..5, \"qwerty\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n\n    context \"with value size is less than n\" do\n      let(:arguments_list) do\n        [\n          [[1, 2], 1],\n          [3, \"Jill\"],\n          [1, {1 => \"st\", 2 => \"nd\"}],\n          [1..5, \"qwerty\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n\n    context \"with an unsupported size\" do\n      it \"raises an error\" do\n        expect { Dry::Logic::Predicates[:size?].call(\"oops\", 1) }.to raise_error(ArgumentError, /oops/)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/str_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#str?\" do\n    let(:predicate_name) { :str? }\n\n    context \"when value is a string\" do\n      let(:arguments_list) do\n        [\n          [\"\"],\n          [\"John\"]\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not a string\" do\n      let(:arguments_list) do\n        [\n          [[]],\n          [{}],\n          [nil],\n          [:symbol],\n          [String]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/time_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#time?\" do\n    let(:predicate_name) { :time? }\n\n    context \"when value is a time\" do\n      let(:arguments_list) do\n        [[Time.now]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not an integer\" do\n      let(:arguments_list) do\n        [\n          [\"\"],\n          [[]],\n          [{}],\n          [nil],\n          [:symbol],\n          [String],\n          [1]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/true_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#true?\" do\n    let(:predicate_name) { :true? }\n\n    context \"when value is true\" do\n      let(:arguments_list) do\n        [[true]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not true\" do\n      let(:arguments_list) do\n        [\n          [false],\n          [\"\"],\n          [[]],\n          [{}],\n          [nil],\n          [:symbol],\n          [String],\n          [1],\n          [0],\n          [\"true\"],\n          [\"false\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/type_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#type?\" do\n    let(:predicate_name) { :type? }\n\n    context \"when value has a correct type\" do\n      let(:arguments_list) do\n        [[TrueClass, true]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not true\" do\n      let(:arguments_list) do\n        [\n          [TrueClass, false],\n          [TrueClass, \"\"],\n          [TrueClass, []],\n          [TrueClass, {}],\n          [TrueClass, nil],\n          [TrueClass, :symbol],\n          [TrueClass, String],\n          [TrueClass, 1],\n          [TrueClass, 0],\n          [TrueClass, \"true\"],\n          [TrueClass, \"false\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/uri_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#uri?\" do\n    let(:predicate_name) { :uri? }\n\n    context \"when value is a valid URI\" do\n      let(:arguments_list) do\n        [\n          [nil, \"https://github.com/dry-rb/dry-logic\"], # without schemes param\n          [\"https\", \"https://github.com/dry-rb/dry-logic\"], # with scheme param\n          [%w[http https], \"https://github.com/dry-rb/dry-logic\"], # with schemes array\n          [\"mailto\", \"mailto:myemail@host.com\"], # with mailto format\n          [\"urn\", \"urn:isbn:0451450523\"] # with URN format\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not a valid URI\" do\n      let(:arguments_list) do\n        [\n          [\"http\", \"mailto:myemail@host.com\"], # scheme not allowed\n          [%w[http https], \"ftp:://myftp.com\"], # scheme not allowed\n          [\"\", \"not-a-uri-at-all\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\n\n  describe \"#uri_rfc3986?\" do\n    let(:predicate_name) { :uri_rfc3986? }\n\n    context \"when value is a valid URI\" do\n      let(:arguments_list) do\n        [\n          [\"https://github.com/dry-rb/dry-logic\"], # with https format\n          [\"mailto:myemail@host.com\"], # with mailto format\n          [\"urn:isbn:0451450523\"] # with URN format\n        ]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not a valid URI\" do\n      let(:arguments_list) do\n        [\n          [\"not-a-uri-at-all\"],\n          [\"[https://github.com/dry-rb/dry-logic]\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/uuid_v1_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#uuid_v1?\" do\n    let(:predicate_name) { :uuid_v1? }\n\n    context \"when value is a valid V1 UUID\" do\n      let(:arguments_list) do\n        [[\"f2d26c57-e07c-1416-a749-57e937930e04\"]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not a valid V1 UUID\" do\n      let(:arguments_list) do\n        [\n          [\"not-a-uuid-at-all\\nf2d26c57-e07c-1416-a749-57e937930e04\"], # V1 with invalid prefix\n          [\"f2d26c57-e07c-1416-a749-57e937930e04\\nnot-a-uuid-at-all\"], # V1 with invalid suffix\n          [\"f2d26c57-e07c-3416-a749-57e937930e04\"], # wrong version number (3, not 1)\n          [\"20633928-6a07-41e9-a923-1681be663d3e\"], # UUID V4\n          [\"not-a-uuid-at-all\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/uuid_v2_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#uuid_v2?\" do\n    let(:predicate_name) { :uuid_v2? }\n\n    context \"when value is a valid V1 UUID\" do\n      let(:arguments_list) do\n        [[\"f2d26c57-e07c-2416-a749-57e937930e04\"]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not a valid V4 UUID\" do\n      let(:arguments_list) do\n        [\n          [\"not-a-uuid-at-all\\nf2d26c57-e07c-2416-a749-57e937930e04\"], # V2 with invalid prefix\n          [\"f2d26c57-e07c-2416-a749-57e937930e04\\nnot-a-uuid-at-all\"], # V2 with invalid suffix\n          [\"f2d26c57-e07c-3416-a749-57e937930e04\"], # wrong version number (3, not 2)\n          [\"20633928-6a07-11e9-a923-1681be663d3e\"], # UUID V1\n          [\"not-a-uuid-at-all\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/uuid_v3_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#uuid_v3?\" do\n    let(:predicate_name) { :uuid_v3? }\n\n    context \"when value is a valid V3 UUID\" do\n      let(:arguments_list) do\n        [[\"f2d26c57-e07c-3416-a749-57e937930e04\"]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not a valid V4 UUID\" do\n      let(:arguments_list) do\n        [\n          [\"not-a-uuid-at-all\\nf2d26c57-e07c-3416-a749-57e937930e04\"], # V3 with invalid prefix\n          [\"f2d26c57-e07c-3416-a749-57e937930e04\\nnot-a-uuid-at-all\"], # V3 with invalid suffix\n          [\"f2d26c57-e07c-4416-a749-57e937930e04\"], # wrong version number (4, not 3)\n          [\"20633928-6a07-11e9-a923-1681be663d3e\"], # UUID V1\n          [\"not-a-uuid-at-all\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/uuid_v4_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#uuid_v4?\" do\n    let(:predicate_name) { :uuid_v4? }\n\n    context \"when value is a valid V4 UUID\" do\n      let(:arguments_list) do\n        [[\"f2d26c57-e07c-4416-a749-57e937930e04\"]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not a valid V4 UUID\" do\n      let(:arguments_list) do\n        [\n          [\"not-a-uuid-at-all\\nf2d26c57-e07c-4416-a749-57e937930e04\"], # V4 with invalid prefix\n          [\"f2d26c57-e07c-4416-a749-57e937930e04\\nnot-a-uuid-at-all\"], # V4 with invalid suffix\n          [\"f2d26c57-e07c-3416-a749-57e937930e04\"], # wrong version number (3, not 4)\n          [\"20633928-6a07-11e9-a923-1681be663d3e\"], # UUID V1\n          [\"not-a-uuid-at-all\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/uuid_v5_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#uuid_v5?\" do\n    let(:predicate_name) { :uuid_v5? }\n\n    context \"when value is a valid V5 UUID\" do\n      let(:arguments_list) do\n        [[\"f2d26c57-e07c-5416-a749-57e937930e04\"]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not a valid V5 UUID\" do\n      let(:arguments_list) do\n        [\n          [\"not-a-uuid-at-all\\nf2d26c57-e07c-5416-a749-57e937930e04\"], # V5 with invalid prefix\n          [\"f2d26c57-e07c-5416-a749-57e937930e04\\nnot-a-uuid-at-all\"], # V5 with invalid suffix\n          [\"f2d26c57-e07c-3416-a749-57e937930e04\"], # wrong version number (3, not 5)\n          [\"20633928-6a07-11e9-a923-1681be663d3e\"], # UUID V1\n          [\"not-a-uuid-at-all\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/uuid_v6_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#uuid_v6?\" do\n    let(:predicate_name) { :uuid_v6? }\n\n    context \"when value is a valid V6 UUID\" do\n      let(:arguments_list) do\n        [[\"1ec9414c-232a-6b00-b3c8-9e6bdeced846\"]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not a valid V6 UUID\" do\n      let(:arguments_list) do\n        [\n          [\"not-a-uuid-at-all\\n1ec9414c-232a-6b00-b3c8-9e6bdeced846\"], # V6 with invalid prefix\n          [\"1ec9414c-232a-6b00-b3c8-9e6bdeced846\\nnot-a-uuid-at-all\"], # V6 with invalid suffix\n          [\"1ec9414c-232a-3b00-b3c8-9e6bdeced846\"], # wrong version number (3, not 6)\n          [\"20633928-6a07-11e9-a923-1681be663d3e\"], # UUID V1\n          [\"not-a-uuid-at-all\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/uuid_v7_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#uuid_v7?\" do\n    let(:predicate_name) { :uuid_v7? }\n\n    context \"when value is a valid V7 UUID\" do\n      let(:arguments_list) do\n        [[\"017f22e2-79b0-7cc3-98c4-dc0c0c07398f\"]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not a valid V7 UUID\" do\n      let(:arguments_list) do\n        [\n          [\"not-a-uuid-at-all\\n017f22e2-79b0-7cc3-98c4-dc0c0c07398f\"], # V6 with invalid prefix\n          [\"017f22e2-79b0-7cc3-98c4-dc0c0c07398f\\nnot-a-uuid-at-all\"], # V6 with invalid suffix\n          [\"017f22e2-79b0-4cc3-98c4-dc0c0c07398f\"], # wrong version number (4, not 7)\n          [\"20633928-6a07-11e9-a923-1681be663d3e\"], # UUID V1\n          [\"not-a-uuid-at-all\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates/uuid_v8_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  describe \"#uuid_v8?\" do\n    let(:predicate_name) { :uuid_v8? }\n\n    context \"when value is a valid V8 UUID\" do\n      let(:arguments_list) do\n        [[\"320c3d4d-cc00-875b-8ec9-32d5f69181c0\"]]\n      end\n\n      it_behaves_like \"a passing predicate\"\n    end\n\n    context \"with value is not a valid V8 UUID\" do\n      let(:arguments_list) do\n        [\n          [\"not-a-uuid-at-all\\n320c3d4d-cc00-875b-8ec9-32d5f69181c0\"], # V6 with invalid prefix\n          [\"320c3d4d-cc00-875b-8ec9-32d5f69181c0\\nnot-a-uuid-at-all\"], # V6 with invalid suffix\n          [\"320c3d4d-cc00-475b-8ec9-32d5f69181c0\"], # wrong version number (4, not 8)\n          [\"20633928-6a07-11e9-a923-1681be663d3e\"], # UUID V1\n          [\"not-a-uuid-at-all\"]\n        ]\n      end\n\n      it_behaves_like \"a failing predicate\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/predicates_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/predicates\"\n\nRSpec.describe Dry::Logic::Predicates do\n  it \"can be included in another module\" do\n    mod = Module.new { include Dry::Logic::Predicates }\n\n    expect(mod[:key?]).to be_a(Method)\n  end\n\n  describe \".predicate\" do\n    it \"defines a predicate method\" do\n      mod = Module.new {\n        include Dry::Logic::Predicates\n\n        predicate(:test?) do |foo|\n          true\n        end\n      }\n\n      expect(mod.test?(\"arg\")).to be(true)\n    end\n  end\n\n  describe \".respond_to?\" do\n    it \"works with a just the method name\" do\n      expect(Dry::Logic::Predicates.respond_to?(:predicate)).to be(true)\n      expect(Dry::Logic::Predicates.respond_to?(:not_here)).to be(false)\n    end\n  end\n\n  describe \".eql?\" do\n    it \"works with another object to compare to\" do\n      expect(Dry::Logic::Predicates.eql?(Dry::Logic::Predicates)).to be(true)\n      expect(Dry::Logic::Predicates.eql?(\"something else\")).to be(false)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/rule/predicate_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::Logic::Rule::Predicate do\n  subject(:rule) { described_class.build(predicate) }\n\n  let(:predicate) { str? }\n\n  include_context \"predicates\"\n\n  it_behaves_like Dry::Logic::Rule\n\n  describe \"#name\" do\n    it \"returns predicate identifier\" do\n      expect(rule.name).to be(:str?)\n    end\n  end\n\n  describe \"#to_ast\" do\n    context \"without a result\" do\n      it \"returns rule ast\" do\n        expect(rule.to_ast).to eql([:predicate, [:str?, [[:input, undefined]]]])\n      end\n\n      it \"returns :failure with an id\" do\n        email = rule.with(id: :email)\n\n        expect(email.(11).to_ast).to eql([:failure, [:email, [:predicate, [:str?, [[:input, 11]]]]]])\n      end\n    end\n\n    context \"with a result\" do\n      it \"returns success\" do\n        expect(rule.(\"foo\")).to be_success\n      end\n\n      it \"returns failure ast\" do\n        expect(rule.(5).to_ast).to eql([:predicate, [:str?, [[:input, 5]]]])\n      end\n    end\n\n    context \"with a zero-arity predicate\" do\n      let(:predicate) {\n        Module.new {\n          def self.test?\n            true\n          end\n        } .method(:test?)\n      }\n\n      it \"returns ast\" do\n        expect(rule.to_ast).to eql([:predicate, [:test?, []]])\n      end\n    end\n  end\n\n  describe \"#to_s\" do\n    it \"returns string representation\" do\n      expect(rule.curry(\"foo\").to_s).to eql('str?(\"foo\")')\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/rule_compiler_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/logic/rule_compiler\"\n\nRSpec.describe Dry::Logic::RuleCompiler, \"#call\" do\n  subject(:compiler) { described_class.new(predicates) }\n\n  let(:predicates) {\n    {key?: predicate,\n     attr?: predicate,\n     filled?: predicate,\n     gt?: predicate,\n     one: predicate}\n  }\n\n  let(:predicate) { double(:predicate, name: :test?, arity: 2).as_null_object }\n\n  let(:rule) { Dry::Logic::Rule::Predicate.build(predicate) }\n  let(:key_op) { Dry::Logic::Operations::Key.new(rule, name: :email) }\n  let(:attr_op) { Dry::Logic::Operations::Attr.new(rule, name: :email) }\n  let(:check_op) { Dry::Logic::Operations::Check.new(rule, keys: [:email]) }\n  let(:not_key_op) { Dry::Logic::Operations::Negation.new(key_op) }\n  let(:and_op) { key_op.curry(:email) & rule }\n  let(:or_op) { key_op.curry(:email) | rule }\n  let(:xor_op) { key_op.curry(:email) ^ rule }\n  let(:set_op) { Dry::Logic::Operations::Set.new(rule) }\n  let(:each_op) { Dry::Logic::Operations::Each.new(rule) }\n\n  it \"compiles key rules\" do\n    ast = [[:key, [:email, [:predicate, [:filled?, [[:input, undefined]]]]]]]\n\n    rules = compiler.(ast)\n\n    expect(rules).to eql([key_op])\n  end\n\n  it \"compiles attr rules\" do\n    ast = [[:attr, [:email, [:predicate, [:filled?, [[:input, undefined]]]]]]]\n\n    rules = compiler.(ast)\n\n    expect(rules).to eql([attr_op])\n  end\n\n  it \"compiles check rules\" do\n    ast = [[:check, [[:email], [:predicate, [:filled?, [[:input, undefined]]]]]]]\n\n    rules = compiler.(ast)\n\n    expect(rules).to eql([check_op])\n  end\n\n  it \"compiles attr rules\" do\n    ast = [[:attr, [:email, [:predicate, [:filled?, [[:input, undefined]]]]]]]\n\n    rules = compiler.(ast)\n\n    expect(rules).to eql([attr_op])\n  end\n\n  it \"compiles negated rules\" do\n    ast = [[:not, [:key, [:email, [:predicate, [:filled?, [[:input, undefined]]]]]]]]\n\n    rules = compiler.(ast)\n\n    expect(rules).to eql([not_key_op])\n  end\n\n  it \"compiles and rules\" do\n    ast = [\n      [\n        :and, [\n          [:key, [:email, [:predicate, [:key?, [[:name, :email], [:input, undefined]]]]]],\n          [:predicate, [:filled?, [[:input, undefined]]]]\n        ]\n      ]\n    ]\n\n    rules = compiler.(ast)\n\n    expect(rules).to eql([and_op])\n  end\n\n  it \"compiles or rules\" do\n    ast = [\n      [\n        :or, [\n          [:key, [:email, [:predicate, [:key?, [[:name, :email], [:input, undefined]]]]]],\n          [:predicate, [:filled?, [[:input, undefined]]]]\n        ]\n      ]\n    ]\n\n    rules = compiler.(ast)\n\n    expect(rules).to eql([or_op])\n  end\n\n  it \"compiles exclusive or rules\" do\n    ast = [\n      [\n        :xor, [\n          [:key, [:email, [:predicate, [:key?, [[:name, :email], [:input, undefined]]]]]],\n          [:predicate, [:filled?, [[:input, undefined]]]]\n        ]\n      ]\n    ]\n\n    rules = compiler.(ast)\n\n    expect(rules).to eql([xor_op])\n  end\n\n  it \"compiles set rules\" do\n    ast = [[:set, [[:predicate, [:filled?, [[:input, nil]]]]]]]\n\n    rules = compiler.(ast)\n\n    expect(rules).to eql([set_op])\n  end\n\n  it \"compiles each rules\" do\n    ast = [[:each, [:predicate, [:filled?, [[:input, nil]]]]]]\n\n    rules = compiler.(ast)\n\n    expect(rules).to eql([each_op])\n  end\nend\n"
  },
  {
    "path": "spec/unit/rule_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::Logic::Rule do\n  subject(:rule) { described_class.build(predicate, **options) }\n\n  let(:predicate) { -> { true } }\n  let(:options) { {} }\n\n  let(:schema) do\n    Class.new do\n      define_method(:class, Kernel.instance_method(:class))\n\n      def respond_to_missing?(m, *)\n        super || m.to_s.end_with?(\"?\")\n      end\n\n      def method_missing(m, *)\n        if m.to_s.end_with?(\"?\")\n          self.class.new\n        else\n          super\n        end\n      end\n\n      def to_proc\n        -> value { value }\n      end\n\n      def arity\n        1\n      end\n\n      def parameters\n        [[:req, :value]]\n      end\n    end.new\n  end\n\n  it_behaves_like described_class\n\n  describe \".new\" do\n    it \"accepts an :id\" do\n      expect(described_class.build(predicate, id: :check_num).id).to be(:check_num)\n    end\n  end\n\n  describe \"with a function returning truthy value\" do\n    it \"is successful for valid input\" do\n      expect(described_class.build(-> val { val }).(\"true\")).to be_success\n    end\n\n    it \"is not successful for invalid input\" do\n      expect(described_class.build(-> val { val }).(nil)).to be_failure\n    end\n  end\n\n  describe \"#ast\" do\n    it \"returns predicate node with :id\" do\n      expect(described_class.build(-> value { true }).with(id: :email?).ast(\"oops\")).to eql(\n        [:predicate, [:email?, [[:value, \"oops\"]]]]\n      )\n    end\n\n    it \"returns predicate node with undefined args\" do\n      expect(described_class.build(-> value { true }).with(id: :email?).ast).to eql(\n        [:predicate, [:email?, [[:value, undefined]]]]\n      )\n    end\n  end\n\n  describe \"#type\" do\n    it \"returns rule type\" do\n      expect(rule.type).to be(:rule)\n    end\n  end\n\n  describe \"#bind\" do\n    let(:bound) { rule.with(id: :bound).bind(object) }\n\n    context \"with an unbound method\" do\n      let(:predicate) { klass.instance_method(:test?) }\n      let(:klass) {\n        Class.new {\n          def test?\n            true\n          end\n        }\n      }\n      let(:object) { klass.new }\n\n      it \"returns a new rule with its predicate bound to a specific object\" do\n        expect(bound.()).to be_success\n      end\n\n      it \"carries id\" do\n        expect(bound.id).to be(:bound)\n      end\n    end\n\n    context \"with an arbitrary block\" do\n      let(:predicate) { -> value { value == expected } }\n      let(:object) {\n        Class.new {\n          def expected\n            \"test\"\n          end\n        } .new\n      }\n\n      it \"returns a new with its predicate executed in the context of the provided object\" do\n        expect(bound.(\"test\")).to be_success\n        expect(bound.(\"oops\")).to be_failure\n      end\n\n      it \"carries id\" do\n        expect(bound.id).to be(:bound)\n      end\n\n      it \"stores arity\" do\n        expect(bound.options[:arity]).to be(rule.arity)\n      end\n\n      it \"stores parameters\" do\n        expect(bound.options[:parameters]).to eql(rule.parameters)\n      end\n    end\n\n    context \"with a schema instance\" do\n      let(:object) { schema }\n      let(:predicate) { schema }\n\n      it \"returns a new with its predicate executed in the context of the provided object\" do\n        expect(bound.(true)).to be_success\n        expect(bound.(false)).to be_failure\n      end\n    end\n  end\n\n  describe \"#eval_args\" do\n    context \"with an unbound method\" do\n      let(:options) { {args: [1, klass.instance_method(:num), :foo], arity: 3} }\n      let(:klass) {\n        Class.new {\n          def num\n            7\n          end\n        }\n      }\n      let(:object) { klass.new }\n\n      it \"evaluates args in the context of the provided object\" do\n        expect(rule.eval_args(object).args).to eql([1, 7, :foo])\n      end\n    end\n\n    context \"with a schema instance\" do\n      let(:options) { {args: [1, schema, :foo], arity: 3} }\n      let(:object) { Object.new }\n\n      it \"returns a new with its predicate executed in the context of the provided object\" do\n        expect(rule.eval_args(object).args).to eql([1, schema, :foo])\n      end\n    end\n  end\n\n  describe \"arity specialization\" do\n    describe \"0-arity rule\" do\n      let(:options) { {args: [1], arity: 1} }\n      let(:predicate) { :odd?.to_proc }\n\n      it \"generates interface with the right arity\" do\n        expect(rule.method(:call).arity).to be_zero\n        expect(rule.method(:[]).arity).to be_zero\n        expect(rule[]).to be(true)\n        expect(rule.()).to be_success\n      end\n    end\n\n    describe \"1-arity rule\" do\n      let(:options) { {args: [1], arity: 2} }\n      let(:predicate) { -> a, b { a + b } }\n\n      it \"generates interface with the right arity\" do\n        expect(rule.method(:call).arity).to be(1)\n        expect(rule.method(:[]).arity).to be(1)\n        expect(rule[10]).to be(11)\n        expect(rule.(1)).to be_success\n      end\n    end\n\n    describe \"currying\" do\n      let(:options) { {args: [], arity: 2} }\n      let(:predicate) { -> a, b { a + b } }\n      let(:rule) { super().curry(1) }\n\n      it \"generates correct arity on currying\" do\n        expect(rule.method(:call).arity).to be(1)\n        expect(rule.method(:[]).arity).to be(1)\n        expect(rule[10]).to be(11)\n        expect(rule.(1)).to be_success\n      end\n    end\n\n    describe \"arbitrary arity\" do\n      let(:arity) { rand(1..20) }\n      let(:curried) { rand(arity) }\n\n      let(:options) { {args: [1] * curried, arity: arity} }\n      let(:predicate) { double(:predicate) }\n\n      it \"generates correct arity\" do\n        expect(rule.method(:call).arity).to be(arity - curried)\n        expect(rule.method(:[]).arity).to be(arity - curried)\n      end\n    end\n\n    describe \"-1 arity\" do\n      let(:options) { {args: [], arity: -1} }\n\n      it \"accepts variable number of arguments\" do\n        expect(rule.method(:call).arity).to be(-1)\n        expect(rule.method(:[]).arity).to be(-1)\n      end\n    end\n\n    describe \"-2 arity\" do\n      let(:options) { {args: [], arity: -2} }\n\n      it \"accepts variable number of arguments\" do\n        expect(rule.method(:call).arity).to be(-2)\n        expect(rule.method(:[]).arity).to be(-2)\n      end\n\n      context \"curried 1\" do\n        let(:options) { {args: [1], arity: -2} }\n\n        it \"doesn't have required arguments\" do\n          expect(rule.method(:call).arity).to be(-1)\n          expect(rule.method(:[]).arity).to be(-1)\n        end\n      end\n\n      context \"curried 2\" do\n        let(:options) { {args: [1, 2], arity: -2} }\n\n        it \"doesn't have required arguments\" do\n          expect(rule.method(:call).arity).to be(-1)\n          expect(rule.method(:[]).arity).to be(-1)\n        end\n      end\n    end\n\n    describe \"constants\" do\n      let(:options) { {args: [], arity: 0} }\n\n      it \"accepts variable number of arguments\" do\n        expect(rule.method(:call).arity).to be(-1)\n        expect(rule.method(:[]).arity).to be(-1)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "zizmor.yml",
    "content": "rules:\n  unpinned-uses:\n    config:\n      policies:\n        hanakai-rb/*: ref-pin\n"
  }
]