├── .github
└── workflows
│ └── tests.yml
├── .ruby-version
├── Gemfile
├── Gemfile.lock
├── Guardfile
├── LICENSE
├── README.md
├── bin
└── tapioca
├── examples
└── sinatra-pet-shelter
│ ├── Gemfile
│ ├── Gemfile.lock
│ ├── README.md
│ ├── lib
│ ├── app.rb
│ ├── repository.rb
│ └── resources
│ │ └── dogs.rb
│ ├── sorbet
│ ├── config
│ ├── rbi
│ │ ├── annotations
│ │ │ ├── .gitattributes
│ │ │ ├── activesupport.rbi
│ │ │ └── minitest.rbi
│ │ ├── dsl
│ │ │ ├── .gitattributes
│ │ │ └── active_support
│ │ │ │ └── callbacks.rbi
│ │ └── gems
│ │ │ ├── .gitattributes
│ │ │ ├── activesupport@8.0.0.rbi
│ │ │ ├── base64@0.2.0.rbi
│ │ │ ├── benchmark@0.4.0.rbi
│ │ │ ├── bigdecimal@3.1.8.rbi
│ │ │ ├── coderay@1.1.3.rbi
│ │ │ ├── concurrent-ruby@1.3.4.rbi
│ │ │ ├── connection_pool@2.4.1.rbi
│ │ │ ├── diff-lcs@1.5.1.rbi
│ │ │ ├── drb@2.2.1.rbi
│ │ │ ├── erubi@1.13.0.rbi
│ │ │ ├── i18n@1.14.6.rbi
│ │ │ ├── json@2.7.2.rbi
│ │ │ ├── logger@1.6.1.rbi
│ │ │ ├── method_source@1.1.0.rbi
│ │ │ ├── minitest@5.25.2.rbi
│ │ │ ├── multi_json@1.15.0.rbi
│ │ │ ├── mustermann@3.0.3.rbi
│ │ │ ├── netrc@0.11.0.rbi
│ │ │ ├── parallel@1.26.3.rbi
│ │ │ ├── polyfill@1.9.0.rbi
│ │ │ ├── prism@0.30.0.rbi
│ │ │ ├── pry@0.14.2.rbi
│ │ │ ├── rack-protection@3.2.0.rbi
│ │ │ ├── rack-test@2.1.0.rbi
│ │ │ ├── rack@2.2.9.rbi
│ │ │ ├── rbi@0.1.14.rbi
│ │ │ ├── resource_registry@0.0.0-61b71b89d828ae8b3da80256be9e5b817b48a49c.rbi
│ │ │ ├── rspec-core@3.13.1.rbi
│ │ │ ├── rspec-expectations@3.13.3.rbi
│ │ │ ├── rspec-mocks@3.13.1.rbi
│ │ │ ├── rspec-support@3.13.1.rbi
│ │ │ ├── rspec@3.13.0.rbi
│ │ │ ├── ruby2_keywords@0.0.5.rbi
│ │ │ ├── safe_type@1.1.1.rbi
│ │ │ ├── securerandom@0.3.2.rbi
│ │ │ ├── sinatra-contrib@3.2.0.rbi
│ │ │ ├── sinatra@3.2.0.rbi
│ │ │ ├── sorbet-coerce@0.7.0.rbi
│ │ │ ├── spoom@1.5.0.rbi
│ │ │ ├── tapioca@0.15.1.rbi
│ │ │ ├── thor@1.3.2.rbi
│ │ │ ├── tilt@2.4.0.rbi
│ │ │ ├── tzinfo@2.0.6.rbi
│ │ │ ├── uri@1.0.2.rbi
│ │ │ ├── yard-sorbet@0.9.0.rbi
│ │ │ └── yard@0.9.37.rbi
│ └── tapioca
│ │ ├── config.yml
│ │ └── require.rb
│ └── spec
│ ├── app_spec.rb
│ └── spec_helper.rb
├── lib
├── README.md
├── package.yml
├── package_todo.yml
├── resource_definition.schema.json
├── resource_registry.rb
├── resource_registry
│ ├── capabilities
│ │ └── capability_config.rb
│ ├── capability_factory.rb
│ ├── configuration.rb
│ ├── entity_finder.rb
│ ├── load_resources_from_cache.rb
│ ├── registry.rb
│ ├── relationship.rb
│ ├── relationship_type.rb
│ ├── relationship_type_factory.rb
│ ├── relationship_types
│ │ ├── belongs_to.rb
│ │ ├── has_many.rb
│ │ ├── has_many_through.rb
│ │ └── has_one.rb
│ ├── repositories
│ │ └── base.rb
│ ├── resource.rb
│ ├── serializer.rb
│ ├── verb.rb
│ ├── versions.rb
│ └── versions
│ │ └── version.rb
├── runtime_generic.rb
└── schema_registry
│ ├── README.md
│ ├── filter_field.rb
│ ├── json_schema_mapper.rb
│ ├── maybe.rb
│ ├── maybe
│ ├── absent.rb
│ └── present.rb
│ ├── property.rb
│ ├── property_mapper.rb
│ ├── property_type.rb
│ ├── registry.rb
│ └── schema.rb
├── rbi
└── resource_registry.rbi
├── resource_registry.gemspec
├── sorbet
├── config
├── rbi
│ ├── annotations
│ │ ├── .gitattributes
│ │ ├── activesupport.rbi
│ │ └── minitest.rbi
│ ├── dsl
│ │ ├── .gitattributes
│ │ └── active_support
│ │ │ └── callbacks.rbi
│ ├── gems
│ │ ├── .gitattributes
│ │ ├── activesupport.rbi
│ │ ├── activesupport@7.2.2.rbi
│ │ ├── base64@0.2.0.rbi
│ │ ├── benchmark@0.4.0.rbi
│ │ ├── bigdecimal.rbi
│ │ ├── bigdecimal@3.1.8.rbi
│ │ ├── coderay@1.1.3.rbi
│ │ ├── concurrent-ruby.rbi
│ │ ├── concurrent-ruby@1.3.4.rbi
│ │ ├── connection_pool.rbi
│ │ ├── connection_pool@2.4.1.rbi
│ │ ├── diff-lcs@1.5.1.rbi
│ │ ├── drb.rbi
│ │ ├── drb@2.2.1.rbi
│ │ ├── erubi@1.13.1.rbi
│ │ ├── ffi@1.17.0.rbi
│ │ ├── formatador@1.1.0.rbi
│ │ ├── guard-compat@1.2.1.rbi
│ │ ├── guard-rspec@4.7.3.rbi
│ │ ├── guard@2.18.1.rbi
│ │ ├── i18n.rbi
│ │ ├── i18n@1.14.6.rbi
│ │ ├── listen@3.9.0.rbi
│ │ ├── logger@1.6.1.rbi
│ │ ├── lumberjack@1.2.10.rbi
│ │ ├── method_source@1.1.0.rbi
│ │ ├── minitest.rbi
│ │ ├── minitest@5.25.2.rbi
│ │ ├── nenv@0.3.0.rbi
│ │ ├── netrc@0.11.0.rbi
│ │ ├── notiffany@0.1.3.rbi
│ │ ├── parallel@1.26.3.rbi
│ │ ├── polyfill.rbi
│ │ ├── polyfill@1.9.0.rbi
│ │ ├── prettier_print@1.2.1.rbi
│ │ ├── prism@1.3.0.rbi
│ │ ├── pry@0.14.2.rbi
│ │ ├── rb-fsevent@0.11.2.rbi
│ │ ├── rb-inotify@0.11.1.rbi
│ │ ├── rbi@0.2.4.rbi
│ │ ├── rspec-core.rbi
│ │ ├── rspec-core@3.13.0.rbi
│ │ ├── rspec-expectations.rbi
│ │ ├── rspec-expectations@3.13.1.rbi
│ │ ├── rspec-json_expectations@2.2.0.rbi
│ │ ├── rspec-mocks.rbi
│ │ ├── rspec-mocks@3.13.1.rbi
│ │ ├── rspec-sorbet@1.9.2.rbi
│ │ ├── rspec-support.rbi
│ │ ├── rspec-support@3.13.1.rbi
│ │ ├── rspec.rbi
│ │ ├── rspec@3.13.0.rbi
│ │ ├── safe_type.rbi
│ │ ├── safe_type@1.1.1.rbi
│ │ ├── securerandom@0.3.2.rbi
│ │ ├── shellany@0.0.1.rbi
│ │ ├── sorbet-coerce.rbi
│ │ ├── sorbet-coerce@0.7.0.rbi
│ │ ├── spoom@1.5.4.rbi
│ │ ├── syntax_tree@6.2.0.rbi
│ │ ├── tapioca@0.16.11.rbi
│ │ ├── thor@1.3.0.rbi
│ │ ├── tzinfo.rbi
│ │ ├── tzinfo@2.0.6.rbi
│ │ ├── uri@1.0.2.rbi
│ │ ├── yard-sorbet@0.9.0.rbi
│ │ └── yard@0.9.37.rbi
│ └── shims
│ │ ├── rails.rbi
│ │ └── repositories.rbi
└── tapioca
│ ├── config.yml
│ └── require.rb
└── spec
├── capability_factory_spec.rb
├── dummy_capability.rb
├── dummy_repo.rb
├── resource_registry
├── capabilities
│ └── capability_config_spec.rb
├── registry_spec.rb
├── relationship_spec.rb
├── resource_spec.rb
└── versions_spec.rb
├── schema_registry
└── maybe_spec.rb
├── spec_helper.rb
└── void_capability.rb
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Run tests
2 | on:
3 | push:
4 | branches:
5 | - "**" # matches every branch
6 | jobs:
7 | run-rspec-tests:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Set up Ruby
12 | uses: ruby/setup-ruby@v1
13 | with:
14 | # Not needed with a .ruby-version file
15 | ruby-version: 3.3.3
16 | # runs 'bundle install' and caches installed gems automatically
17 | bundler-cache: true
18 | - name: Run sorbet typechecks
19 | run: |
20 | bundle exec srb tc --ignore examples
21 | - name: Run rspec tests
22 | run: |
23 | bundle exec rspec
24 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 3.3.3
2 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "activesupport"
6 | gem "rspec"
7 | gem "rspec-json_expectations"
8 | gem "rspec-sorbet", "~> 1.9.2"
9 | gem "sorbet-coerce", "~> 0.7"
10 | gem "sorbet-static-and-runtime", "0.5.11845"
11 | gem "tapioca", "~> 0.16.11", require: false
12 | gem "syntax_tree", "~> 6.2", require: false
13 |
14 | gem "guard"
15 | gem "guard-rspec"
16 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | activesupport (7.2.2)
5 | base64
6 | benchmark (>= 0.3)
7 | bigdecimal
8 | concurrent-ruby (~> 1.0, >= 1.3.1)
9 | connection_pool (>= 2.2.5)
10 | drb
11 | i18n (>= 1.6, < 2)
12 | logger (>= 1.4.2)
13 | minitest (>= 5.1)
14 | securerandom (>= 0.3)
15 | tzinfo (~> 2.0, >= 2.0.5)
16 | uri (>= 0.13.1)
17 | base64 (0.2.0)
18 | benchmark (0.4.0)
19 | bigdecimal (3.1.8)
20 | coderay (1.1.3)
21 | concurrent-ruby (1.3.4)
22 | connection_pool (2.4.1)
23 | diff-lcs (1.5.1)
24 | drb (2.2.1)
25 | erubi (1.13.1)
26 | ffi (1.17.0-arm64-darwin)
27 | ffi (1.17.0-x86_64-linux-gnu)
28 | formatador (1.1.0)
29 | guard (2.18.1)
30 | formatador (>= 0.2.4)
31 | listen (>= 2.7, < 4.0)
32 | lumberjack (>= 1.0.12, < 2.0)
33 | nenv (~> 0.1)
34 | notiffany (~> 0.0)
35 | pry (>= 0.13.0)
36 | shellany (~> 0.0)
37 | thor (>= 0.18.1)
38 | guard-compat (1.2.1)
39 | guard-rspec (4.7.3)
40 | guard (~> 2.1)
41 | guard-compat (~> 1.1)
42 | rspec (>= 2.99.0, < 4.0)
43 | i18n (1.14.6)
44 | concurrent-ruby (~> 1.0)
45 | listen (3.9.0)
46 | rb-fsevent (~> 0.10, >= 0.10.3)
47 | rb-inotify (~> 0.9, >= 0.9.10)
48 | logger (1.6.1)
49 | lumberjack (1.2.10)
50 | method_source (1.1.0)
51 | minitest (5.25.2)
52 | nenv (0.3.0)
53 | netrc (0.11.0)
54 | notiffany (0.1.3)
55 | nenv (~> 0.1)
56 | shellany (~> 0.0)
57 | parallel (1.26.3)
58 | polyfill (1.9.0)
59 | prettier_print (1.2.1)
60 | prism (1.3.0)
61 | pry (0.14.2)
62 | coderay (~> 1.1)
63 | method_source (~> 1.0)
64 | rb-fsevent (0.11.2)
65 | rb-inotify (0.11.1)
66 | ffi (~> 1.0)
67 | rbi (0.2.4)
68 | prism (~> 1.0)
69 | sorbet-runtime (>= 0.5.9204)
70 | rspec (3.13.0)
71 | rspec-core (~> 3.13.0)
72 | rspec-expectations (~> 3.13.0)
73 | rspec-mocks (~> 3.13.0)
74 | rspec-core (3.13.0)
75 | rspec-support (~> 3.13.0)
76 | rspec-expectations (3.13.1)
77 | diff-lcs (>= 1.2.0, < 2.0)
78 | rspec-support (~> 3.13.0)
79 | rspec-json_expectations (2.2.0)
80 | rspec-mocks (3.13.1)
81 | diff-lcs (>= 1.2.0, < 2.0)
82 | rspec-support (~> 3.13.0)
83 | rspec-sorbet (1.9.2)
84 | sorbet-runtime
85 | rspec-support (3.13.1)
86 | safe_type (1.1.1)
87 | securerandom (0.3.2)
88 | shellany (0.0.1)
89 | sorbet (0.5.11845)
90 | sorbet-static (= 0.5.11845)
91 | sorbet-coerce (0.7.0)
92 | polyfill (~> 1.8)
93 | safe_type (~> 1.1, >= 1.1.1)
94 | sorbet-runtime (>= 0.4.4704)
95 | sorbet-runtime (0.5.11845)
96 | sorbet-static (0.5.11845-universal-darwin)
97 | sorbet-static (0.5.11845-x86_64-linux)
98 | sorbet-static-and-runtime (0.5.11845)
99 | sorbet (= 0.5.11845)
100 | sorbet-runtime (= 0.5.11845)
101 | spoom (1.5.4)
102 | erubi (>= 1.10.0)
103 | prism (>= 0.28.0)
104 | rbi (>= 0.2.3)
105 | sorbet-static-and-runtime (>= 0.5.10187)
106 | thor (>= 0.19.2)
107 | syntax_tree (6.2.0)
108 | prettier_print (>= 1.2.0)
109 | tapioca (0.16.11)
110 | benchmark
111 | bundler (>= 2.2.25)
112 | netrc (>= 0.11.0)
113 | parallel (>= 1.21.0)
114 | rbi (~> 0.2)
115 | sorbet-static-and-runtime (>= 0.5.11087)
116 | spoom (>= 1.2.0)
117 | thor (>= 1.2.0)
118 | yard-sorbet
119 | thor (1.3.0)
120 | tzinfo (2.0.6)
121 | concurrent-ruby (~> 1.0)
122 | uri (1.0.2)
123 | yard (0.9.37)
124 | yard-sorbet (0.9.0)
125 | sorbet-runtime
126 | yard
127 |
128 | PLATFORMS
129 | arm64-darwin-23
130 | x86_64-linux
131 |
132 | DEPENDENCIES
133 | activesupport
134 | guard
135 | guard-rspec
136 | rspec
137 | rspec-json_expectations
138 | rspec-sorbet (~> 1.9.2)
139 | sorbet-coerce (~> 0.7)
140 | sorbet-static-and-runtime (= 0.5.11845)
141 | syntax_tree (~> 6.2)
142 | tapioca (~> 0.16.11)
143 |
144 | BUNDLED WITH
145 | 2.5.11
146 |
--------------------------------------------------------------------------------
/Guardfile:
--------------------------------------------------------------------------------
1 | # A sample Guardfile
2 | # More info at https://github.com/guard/guard#readme
3 |
4 | ## Uncomment and set this to only include directories you want to watch
5 | # directories %w(app lib config test spec features) \
6 | # .select{|d| Dir.exist?(d) ? d : UI.warning("Directory #{d} does not exist")}
7 |
8 | ## Note: if you are using the `directories` clause above and you are not
9 | ## watching the project directory ('.'), then you will want to move
10 | ## the Guardfile to a watched dir and symlink it back, e.g.
11 | #
12 | # $ mkdir config
13 | # $ mv Guardfile config/
14 | # $ ln -s config/Guardfile .
15 | #
16 | # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
17 |
18 | # Note: The cmd option is now required due to the increasing number of ways
19 | # rspec may be run, below are examples of the most common uses.
20 | # * bundler: 'bundle exec rspec'
21 | # * bundler binstubs: 'bin/rspec'
22 | # * spring: 'bin/rspec' (This will use spring if running and you have
23 | # installed the spring binstubs per the docs)
24 | # * zeus: 'zeus rspec' (requires the server to be started separately)
25 | # * 'just' rspec: 'rspec'
26 |
27 | guard :rspec, cmd: "bundle exec rspec" do
28 | require "guard/rspec/dsl"
29 | dsl = Guard::RSpec::Dsl.new(self)
30 |
31 | # Feel free to open issues for suggestions and improvements
32 |
33 | # RSpec files
34 | rspec = dsl.rspec
35 | watch(rspec.spec_helper) { rspec.spec_dir }
36 | watch(rspec.spec_support) { rspec.spec_dir }
37 | watch(rspec.spec_files)
38 |
39 | # Ruby files
40 | ruby = dsl.ruby
41 | dsl.watch_spec_files_for(ruby.lib_files)
42 |
43 | # Rails files
44 | rails = dsl.rails(view_extensions: %w(erb haml slim))
45 | dsl.watch_spec_files_for(rails.app_files)
46 | dsl.watch_spec_files_for(rails.views)
47 |
48 | watch(rails.controllers) do |m|
49 | [
50 | rspec.spec.call("routing/#{m[1]}_routing"),
51 | rspec.spec.call("controllers/#{m[1]}_controller"),
52 | rspec.spec.call("acceptance/#{m[1]}")
53 | ]
54 | end
55 |
56 | # Rails config changes
57 | watch(rails.spec_helper) { rspec.spec_dir }
58 | watch(rails.routes) { "#{rspec.spec_dir}/routing" }
59 | watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
60 |
61 | # Capybara features specs
62 | watch(rails.view_dirs) { |m| rspec.spec.call("features/#{m[1]}") }
63 | watch(rails.layouts) { |m| rspec.spec.call("features/#{m[1]}") }
64 |
65 | # Turnip features and steps
66 | watch(%r{^spec/acceptance/(.+)\.feature$})
67 | watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
68 | Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
69 | end
70 | end
71 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Factorial
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Resource Registry
2 |
3 | A declarative resource-oriented registry for a generic usage.
4 |
5 | ## What is this?
6 |
7 | Resource Registry allows you to define resources and their actions in a
8 | declarative way. Leaving the imperative implementation of the business logic
9 | behavior to the user. (Using the repository pattern). And allowing to create
10 | generic features for the whole catalog of resources at once.
11 |
12 | This is very useful to scale big projects codebases in order to implement
13 | generic features for the whole catalog or resources.
14 |
15 | Resource Registry defines a few basic concepts to build this catalog.
16 |
17 | ### Anatomy of a resource, `ResourceRegistry::Resource`
18 |
19 | Resource represent the central part of this library. They should contain and
20 | provide all the necessary information to generate features. This includes
21 | Capabilities, Repository, verbs and Entity/DTOs schemas.
22 |
23 | An example of a resource:
24 |
25 | ```ruby
26 | class GraphqlCapability < T::Struct
27 | extend T::Sig
28 |
29 | include ResourceRegistry::Capabilities::CapabilityConfig
30 |
31 | sig { override.returns(Symbol) }
32 | def self.key
33 | :void_capability
34 | end
35 | end
36 |
37 | ResourceRegistry::Resource.new(
38 | repository_raw: YourRepositoryClass.to_s,
39 | capabilities: {
40 | graphql: GraphqlCapability.new
41 | },
42 | verbs: {
43 | read: ResourceRegistry::Verb.new(
44 | id: verb,
45 | dto_raw: dto_klass.to_s,
46 | schema: read_verb_schema,
47 | return_many: true
48 | )
49 | },
50 | schema: SchemaRegistry::Schema.new(
51 | name: 'employees',
52 | namespace: 'employees',
53 | properties: [
54 | SchemaRegistry::Property.new(
55 | name: 'id',
56 | types: [SchemaRegistry::PropertyType::String],
57 | required: true
58 | ),
59 | SchemaRegistry::Property.new(
60 | name: 'fullName',
61 | types: [SchemaRegistry::PropertyType::String],
62 | required: true
63 | )
64 | ]
65 | )
66 | )
67 | ```
68 |
69 | ### The registry itself, `ResourceRegistry::Registry`
70 |
71 | Gives you access to the whole library using the following API:
72 |
73 | ```ruby
74 | registry = ResourceRegistry::Registry.new
75 |
76 | # Fetch a resource by its identifier
77 | registry.fetch(:employees)
78 |
79 | # Fetch all resources
80 | registry.fetch_rall
81 | ```
82 |
83 | ## What does this gem bring to the table?
84 |
85 | - Schema registry for resources, maybe we can infere them from entities
86 | - Relate events to resources actions (CRUD and not CRUD)
87 |
88 | ## Install
89 |
90 | Add the following lines in your Gemfile:
91 |
92 | ```ruby
93 | gem 'resource_registry', github: 'factorialco/resource-registry'
94 | ```
95 |
96 | And run `bundle install`
97 |
98 | ## Setting up your first resources
99 |
100 | - [Check this project to see an example Sinatra based app using Resource Registry](examples/sinatra-pet-shelter)
101 |
102 | ## Similar projects
103 |
104 | Check [ash](https://ash-hq.org/) for a similar and much mature approach applied to Elixir apps.
105 |
--------------------------------------------------------------------------------
/bin/tapioca:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | #
5 | # This file was generated by Bundler.
6 | #
7 | # The application 'tapioca' is installed as part of a gem, and
8 | # this file is here to facilitate running it.
9 | #
10 |
11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12 |
13 | bundle_binstub = File.expand_path("bundle", __dir__)
14 |
15 | if File.file?(bundle_binstub)
16 | if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17 | load(bundle_binstub)
18 | else
19 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21 | end
22 | end
23 |
24 | require "rubygems"
25 | require "bundler/setup"
26 |
27 | load Gem.bin_path("tapioca", "tapioca")
28 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "json"
6 | gem "resource_registry", github: "factorialco/resource-registry", branch: "main"
7 | gem "sinatra"
8 | gem "sinatra-contrib"
9 | gem "tapioca", "~> 0.15.1", require: false
10 |
11 | group :development, :test do
12 | gem "pry"
13 | gem "rack-test"
14 | gem "rspec"
15 | end
16 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GIT
2 | remote: https://github.com/factorialco/resource-registry.git
3 | revision: 61b71b89d828ae8b3da80256be9e5b817b48a49c
4 | branch: chore/update-sorbet-version-and-fixes
5 | specs:
6 | resource_registry (0.0.0)
7 | activesupport (>= 7.1.3)
8 | sorbet-coerce (~> 0.7)
9 | sorbet-runtime (= 0.5.11670)
10 |
11 | GEM
12 | remote: https://rubygems.org/
13 | specs:
14 | activesupport (8.0.0)
15 | base64
16 | benchmark (>= 0.3)
17 | bigdecimal
18 | concurrent-ruby (~> 1.0, >= 1.3.1)
19 | connection_pool (>= 2.2.5)
20 | drb
21 | i18n (>= 1.6, < 2)
22 | logger (>= 1.4.2)
23 | minitest (>= 5.1)
24 | securerandom (>= 0.3)
25 | tzinfo (~> 2.0, >= 2.0.5)
26 | uri (>= 0.13.1)
27 | base64 (0.2.0)
28 | benchmark (0.4.0)
29 | bigdecimal (3.1.8)
30 | coderay (1.1.3)
31 | concurrent-ruby (1.3.4)
32 | connection_pool (2.4.1)
33 | diff-lcs (1.5.1)
34 | drb (2.2.1)
35 | erubi (1.13.0)
36 | i18n (1.14.6)
37 | concurrent-ruby (~> 1.0)
38 | json (2.7.2)
39 | logger (1.6.1)
40 | method_source (1.1.0)
41 | minitest (5.25.2)
42 | multi_json (1.15.0)
43 | mustermann (3.0.3)
44 | ruby2_keywords (~> 0.0.1)
45 | netrc (0.11.0)
46 | parallel (1.26.3)
47 | polyfill (1.9.0)
48 | prism (0.30.0)
49 | pry (0.14.2)
50 | coderay (~> 1.1)
51 | method_source (~> 1.0)
52 | rack (2.2.9)
53 | rack-protection (3.2.0)
54 | base64 (>= 0.1.0)
55 | rack (~> 2.2, >= 2.2.4)
56 | rack-test (2.1.0)
57 | rack (>= 1.3)
58 | rbi (0.1.14)
59 | prism (>= 0.18.0, < 1.0.0)
60 | sorbet-runtime (>= 0.5.9204)
61 | rspec (3.13.0)
62 | rspec-core (~> 3.13.0)
63 | rspec-expectations (~> 3.13.0)
64 | rspec-mocks (~> 3.13.0)
65 | rspec-core (3.13.1)
66 | rspec-support (~> 3.13.0)
67 | rspec-expectations (3.13.3)
68 | diff-lcs (>= 1.2.0, < 2.0)
69 | rspec-support (~> 3.13.0)
70 | rspec-mocks (3.13.1)
71 | diff-lcs (>= 1.2.0, < 2.0)
72 | rspec-support (~> 3.13.0)
73 | rspec-support (3.13.1)
74 | ruby2_keywords (0.0.5)
75 | safe_type (1.1.1)
76 | securerandom (0.3.2)
77 | sinatra (3.2.0)
78 | mustermann (~> 3.0)
79 | rack (~> 2.2, >= 2.2.4)
80 | rack-protection (= 3.2.0)
81 | tilt (~> 2.0)
82 | sinatra-contrib (3.2.0)
83 | multi_json (>= 0.0.2)
84 | mustermann (~> 3.0)
85 | rack-protection (= 3.2.0)
86 | sinatra (= 3.2.0)
87 | tilt (~> 2.0)
88 | sorbet (0.5.11670)
89 | sorbet-static (= 0.5.11670)
90 | sorbet-coerce (0.7.0)
91 | polyfill (~> 1.8)
92 | safe_type (~> 1.1, >= 1.1.1)
93 | sorbet-runtime (>= 0.4.4704)
94 | sorbet-runtime (0.5.11670)
95 | sorbet-static (0.5.11670-universal-darwin)
96 | sorbet-static (0.5.11670-x86_64-linux)
97 | sorbet-static-and-runtime (0.5.11670)
98 | sorbet (= 0.5.11670)
99 | sorbet-runtime (= 0.5.11670)
100 | spoom (1.5.0)
101 | erubi (>= 1.10.0)
102 | prism (>= 0.28.0)
103 | sorbet-static-and-runtime (>= 0.5.10187)
104 | thor (>= 0.19.2)
105 | tapioca (0.15.1)
106 | bundler (>= 2.2.25)
107 | netrc (>= 0.11.0)
108 | parallel (>= 1.21.0)
109 | rbi (>= 0.1.4, < 0.2)
110 | sorbet-static-and-runtime (>= 0.5.11087)
111 | spoom (>= 1.2.0)
112 | thor (>= 1.2.0)
113 | yard-sorbet
114 | thor (1.3.2)
115 | tilt (2.4.0)
116 | tzinfo (2.0.6)
117 | concurrent-ruby (~> 1.0)
118 | uri (1.0.2)
119 | yard (0.9.37)
120 | yard-sorbet (0.9.0)
121 | sorbet-runtime
122 | yard
123 |
124 | PLATFORMS
125 | arm64-darwin-23
126 | x86_64-linux
127 |
128 | DEPENDENCIES
129 | json
130 | pry
131 | rack-test
132 | resource_registry!
133 | rspec
134 | sinatra
135 | sinatra-contrib
136 | tapioca (~> 0.15.1)
137 |
138 | BUNDLED WITH
139 | 2.4.7
140 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/README.md:
--------------------------------------------------------------------------------
1 | # Pet shelter example application
2 |
3 | This is just an example API to show up how to use Resource Registry in a Ruby application.
4 |
5 | ## Start server
6 |
7 | In order to start the server, run the following command:
8 |
9 | ```bash
10 | ruby app.rb
11 | ```
12 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/lib/app.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "sinatra"
4 | require "sinatra/multi_route"
5 | require "resource_registry"
6 |
7 | require "sinatra/reloader" if development?
8 | require "pry"
9 |
10 | require_relative "repository"
11 |
12 | Dir[File.expand_path("lib/resources/*.rb")].each { |f| require_relative(f) }
13 |
14 | # Main entrypoint of the application
15 | class App < Sinatra::Base
16 | register Sinatra::MultiRoute
17 |
18 | registry, =
19 | ResourceRegistry::Initializer.new(repository_base_klass: Repository).call
20 | resources = registry.fetch_all
21 |
22 | resources.each do |id, resource|
23 | next unless resource.verbs.include?(:read)
24 |
25 | route :get, "/#{resource.collection_name}" do
26 | content_type :json
27 | { data: [] }.to_json
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/lib/repository.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: true
3 |
4 | class Repository
5 | extend T::Sig
6 |
7 | include ::ResourceRegistry::Repositories::Base
8 | extend RuntimeGeneric
9 |
10 | Entity = type_member { { upper: T::Struct } }
11 |
12 | sig { returns(T.untyped) }
13 | def self.entity
14 | # Dirty hack to make Tapioca work with `tapioca dsl` command, our
15 | # RuntimeGeneric is not compatible with it
16 | return if defined?(Tapioca)
17 |
18 | T.unsafe(const_get(:Entity)).inner_type[:fixed]
19 | end
20 |
21 | # Migrate to RR gem
22 | # FIXME: Review
23 | sig(:final) { returns(String) }
24 | def self.namespace
25 | ""
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/lib/resources/dogs.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 | # frozen_string_literal: true
3 |
4 | require_relative "../repository"
5 |
6 | class ReadDto < T::Struct
7 | const :id, String
8 | end
9 |
10 | class Dog < T::Struct
11 | const :id, String
12 | end
13 |
14 | class Dogs < Repository
15 | extend T::Sig
16 |
17 | Entity = type_member { { fixed: Dog } }
18 |
19 | # FIXME: Review `context`
20 | sig do
21 | override.params(dto: ReadDto, context: T.untyped).returns(T::Array[Dog])
22 | end
23 | def read(dto:, context:)
24 | []
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/config:
--------------------------------------------------------------------------------
1 | --dir
2 | .
3 | --ignore=/tmp/
4 | --ignore=/vendor/bundle
5 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/rbi/annotations/.gitattributes:
--------------------------------------------------------------------------------
1 | **/*.rbi linguist-vendored=true
2 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/rbi/annotations/minitest.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This file was pulled from a central RBI files repository.
5 | # Please run `bin/tapioca annotations` to update it.
6 |
7 | module Minitest::Assertions
8 | sig { params(test: T.anything, msg: T.anything).returns(TrueClass) }
9 | def assert(test, msg = nil); end
10 |
11 | sig { params(obj: T.anything, msg: T.anything).returns(TrueClass) }
12 | def assert_empty(obj, msg = nil); end
13 |
14 | sig { params(exp: T.anything, act: T.anything, msg: T.anything).returns(TrueClass) }
15 | def assert_equal(exp, act, msg = nil); end
16 |
17 | sig { params(exp: T.anything, act: T.anything, delta: Numeric, msg: T.anything).returns(TrueClass) }
18 | def assert_in_delta(exp, act, delta = T.unsafe(nil), msg = nil); end
19 |
20 | sig { params(a: T.anything, b: T.anything, epsilon: Numeric, msg: T.anything).returns(TrueClass) }
21 | def assert_in_epsilon(a, b, epsilon = T.unsafe(nil), msg = nil); end
22 |
23 | sig { params(collection: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
24 | def assert_includes(collection, obj, msg = nil); end
25 |
26 | sig { params(cls: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
27 | def assert_instance_of(cls, obj, msg = nil); end
28 |
29 | sig { params(cls: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
30 | def assert_kind_of(cls, obj, msg = nil); end
31 |
32 | sig { params(matcher: T.any(String, Regexp), obj: T.anything, msg: T.anything).returns(MatchData) }
33 | def assert_match(matcher, obj, msg = nil); end
34 |
35 | sig { params(obj: T.anything, msg: T.anything).returns(TrueClass) }
36 | def assert_nil(obj, msg = nil); end
37 |
38 | sig { params(o1: T.anything, op: T.any(Symbol, String), o2: T.anything, msg: T.anything).returns(TrueClass) }
39 | def assert_operator(o1, op, o2 = T.unsafe(nil), msg = nil); end
40 |
41 | sig { params(stdout: T.nilable(T.any(String, Regexp)), stderr: T.nilable(T.any(String, Regexp)), block: T.proc.void).returns(T::Boolean) }
42 | def assert_output(stdout = nil, stderr = nil, &block); end
43 |
44 | sig { params(path: T.any(String, Pathname), msg: T.anything).returns(TrueClass) }
45 | def assert_path_exists(path, msg = nil); end
46 |
47 | sig { params(block: T.proc.void).returns(TrueClass) }
48 | def assert_pattern(&block); end
49 |
50 | sig { params(o1: T.anything, op: T.any(String, Symbol), msg: T.anything).returns(TrueClass) }
51 | def assert_predicate(o1, op, msg = nil); end
52 |
53 | sig { params(exp: NilClass, block: T.proc.void).returns(StandardError) }
54 | sig { type_parameters(:T).params(exp: T.any(T::Class[T.type_parameter(:T)], Regexp, String), block: T.proc.void).returns(T.type_parameter(:T)) }
55 | def assert_raises(*exp, &block); end
56 |
57 | sig { params(obj: T.anything, meth: T.any(String, Symbol), msg: T.anything, include_all: T::Boolean).returns(TrueClass) }
58 | def assert_respond_to(obj, meth, msg = nil, include_all: false); end
59 |
60 | sig { params(exp: T.anything, act: T.anything, msg: T.anything).returns(TrueClass) }
61 | def assert_same(exp, act, msg = nil); end
62 |
63 | sig { params(send_ary: T::Array[T.anything], m: T.anything).returns(T::Boolean) }
64 | def assert_send(send_ary, m = nil); end
65 |
66 | sig { params(block: T.proc.void).returns(T::Boolean) }
67 | def assert_silent(&block); end
68 |
69 | sig { params(sym: Symbol, msg: T.anything, block: T.proc.void).returns(T.anything) }
70 | def assert_throws(sym, msg = nil, &block); end
71 |
72 | sig { params(test: T.anything, msg: T.anything).returns(TrueClass) }
73 | def refute(test, msg = nil); end
74 |
75 | sig { params(obj: T.anything, msg: T.anything).returns(TrueClass) }
76 | def refute_empty(obj, msg = nil); end
77 |
78 | sig { params(exp: T.anything, act: T.anything, msg: T.anything).returns(TrueClass) }
79 | def refute_equal(exp, act, msg = nil); end
80 |
81 | sig { params(exp: T.anything, act: T.anything, delta: Numeric, msg: T.anything).returns(TrueClass) }
82 | def refute_in_delta(exp, act, delta = T.unsafe(nil), msg = nil); end
83 |
84 | sig { params(a: T.anything, b: T.anything, epsilon: Numeric, msg: T.anything).returns(TrueClass) }
85 | def refute_in_epsilon(a, b, epsilon = T.unsafe(nil), msg = nil); end
86 |
87 | sig { params(collection: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
88 | def refute_includes(collection, obj, msg = nil); end
89 |
90 | sig { params(cls: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
91 | def refute_instance_of(cls, obj, msg = nil); end
92 |
93 | sig { params(cls: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
94 | def refute_kind_of(cls, obj, msg = nil); end
95 |
96 | sig { params(matcher: T.any(String, Regexp), obj: T.anything, msg: T.anything).returns(TrueClass) }
97 | def refute_match(matcher, obj, msg = nil); end
98 |
99 | sig { params(obj: T.anything, msg: T.anything).returns(TrueClass) }
100 | def refute_nil(obj, msg = nil); end
101 |
102 | sig { params(block: T.proc.void).returns(TrueClass) }
103 | def refute_pattern(&block); end
104 |
105 | sig { params(o1: T.anything, op: T.any(Symbol, String), o2: T.anything, msg: T.anything).returns(TrueClass) }
106 | def refute_operator(o1, op, o2 = T.unsafe(nil), msg = nil); end
107 |
108 | sig { params(path: T.any(String, Pathname), msg: T.anything).returns(TrueClass) }
109 | def refute_path_exists(path, msg = nil); end
110 |
111 | sig { params(o1: T.anything, op: T.any(String, Symbol), msg: T.anything).returns(TrueClass) }
112 | def refute_predicate(o1, op, msg = nil); end
113 |
114 | sig { params(obj: T.anything, meth: T.any(String, Symbol), msg: T.anything, include_all: T::Boolean).returns(TrueClass) }
115 | def refute_respond_to(obj, meth, msg = nil, include_all: false); end
116 |
117 | sig { params(exp: T.anything, act: T.anything, msg: T.anything).returns(TrueClass) }
118 | def refute_same(exp, act, msg = nil); end
119 | end
120 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/rbi/dsl/.gitattributes:
--------------------------------------------------------------------------------
1 | **/*.rbi linguist-generated=true
2 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/rbi/dsl/active_support/callbacks.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for dynamic methods in `ActiveSupport::Callbacks`.
5 | # Please instead update this file by running `bin/tapioca dsl ActiveSupport::Callbacks`.
6 |
7 |
8 | module ActiveSupport::Callbacks
9 | include GeneratedInstanceMethods
10 |
11 | mixes_in_class_methods GeneratedClassMethods
12 |
13 | module GeneratedClassMethods
14 | def __callbacks; end
15 | def __callbacks=(value); end
16 | end
17 |
18 | module GeneratedInstanceMethods
19 | def __callbacks; end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/rbi/gems/.gitattributes:
--------------------------------------------------------------------------------
1 | **/*.rbi linguist-generated=true
2 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/rbi/gems/bigdecimal@3.1.8.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `bigdecimal` gem.
5 | # Please instead update this file by running `bin/tapioca gem bigdecimal`.
6 |
7 |
8 | # source://bigdecimal//lib/bigdecimal/util.rb#78
9 | class BigDecimal < ::Numeric
10 | # call-seq:
11 | # a.to_d -> bigdecimal
12 | #
13 | # Returns self.
14 | #
15 | # require 'bigdecimal/util'
16 | #
17 | # d = BigDecimal("3.14")
18 | # d.to_d # => 0.314e1
19 | #
20 | # source://bigdecimal//lib/bigdecimal/util.rb#110
21 | def to_d; end
22 |
23 | # call-seq:
24 | # a.to_digits -> string
25 | #
26 | # Converts a BigDecimal to a String of the form "nnnnnn.mmm".
27 | # This method is deprecated; use BigDecimal#to_s("F") instead.
28 | #
29 | # require 'bigdecimal/util'
30 | #
31 | # d = BigDecimal("3.14")
32 | # d.to_digits # => "3.14"
33 | #
34 | # source://bigdecimal//lib/bigdecimal/util.rb#90
35 | def to_digits; end
36 | end
37 |
38 | BigDecimal::VERSION = T.let(T.unsafe(nil), String)
39 |
40 | # source://bigdecimal//lib/bigdecimal/util.rb#138
41 | class Complex < ::Numeric
42 | # call-seq:
43 | # cmp.to_d -> bigdecimal
44 | # cmp.to_d(precision) -> bigdecimal
45 | #
46 | # Returns the value as a BigDecimal.
47 | #
48 | # The +precision+ parameter is required for a rational complex number.
49 | # This parameter is used to determine the number of significant digits
50 | # for the result.
51 | #
52 | # require 'bigdecimal'
53 | # require 'bigdecimal/util'
54 | #
55 | # Complex(0.1234567, 0).to_d(4) # => 0.1235e0
56 | # Complex(Rational(22, 7), 0).to_d(3) # => 0.314e1
57 | #
58 | # See also Kernel.BigDecimal.
59 | #
60 | # source://bigdecimal//lib/bigdecimal/util.rb#157
61 | def to_d(*args); end
62 | end
63 |
64 | # source://bigdecimal//lib/bigdecimal/util.rb#171
65 | class NilClass
66 | # call-seq:
67 | # nil.to_d -> bigdecimal
68 | #
69 | # Returns nil represented as a BigDecimal.
70 | #
71 | # require 'bigdecimal'
72 | # require 'bigdecimal/util'
73 | #
74 | # nil.to_d # => 0.0
75 | #
76 | # source://bigdecimal//lib/bigdecimal/util.rb#182
77 | def to_d; end
78 | end
79 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/rbi/gems/connection_pool@2.4.1.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `connection_pool` gem.
5 | # Please instead update this file by running `bin/tapioca gem connection_pool`.
6 |
7 |
8 | # THIS IS AN EMPTY RBI FILE.
9 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem
10 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/rbi/gems/erubi@1.13.0.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `erubi` gem.
5 | # Please instead update this file by running `bin/tapioca gem erubi`.
6 |
7 |
8 | # source://erubi//lib/erubi.rb#3
9 | module Erubi
10 | private
11 |
12 | def h(_arg0); end
13 |
14 | class << self
15 | def h(_arg0); end
16 | end
17 | end
18 |
19 | # source://erubi//lib/erubi.rb#51
20 | class Erubi::Engine
21 | # Initialize a new Erubi::Engine. Options:
22 | # +:bufval+ :: The value to use for the buffer variable, as a string (default '::String.new').
23 | # +:bufvar+ :: The variable name to use for the buffer variable, as a string.
24 | # +:chain_appends+ :: Whether to chain << calls to the buffer variable. Offers better
25 | # performance, but can cause issues when the buffer variable is reassigned during
26 | # template rendering (default +false+).
27 | # +:ensure+ :: Wrap the template in a begin/ensure block restoring the previous value of bufvar.
28 | # +:escapefunc+ :: The function to use for escaping, as a string (default: '::Erubi.h').
29 | # +:escape+ :: Whether to make <%= escape by default, and <%== not escape by default.
30 | # +:escape_html+ :: Same as +:escape+, with lower priority.
31 | # +:filename+ :: The filename for the template.
32 | # the resulting source code. Note this may cause problems if you are wrapping the resulting
33 | # source code in other code, because the magic comment only has an effect at the beginning of
34 | # the file, and having the magic comment later in the file can trigger warnings.
35 | # +:freeze_template_literals+ :: Whether to suffix all literal strings for template code with .freeze
36 | # (default: +true+ on Ruby 2.1+, +false+ on Ruby 2.0 and older).
37 | # Can be set to +false+ on Ruby 2.3+ when frozen string literals are enabled
38 | # in order to improve performance.
39 | # +:literal_prefix+ :: The prefix to output when using escaped tag delimiters (default '<%').
40 | # +:literal_postfix+ :: The postfix to output when using escaped tag delimiters (default '%>').
41 | # +:outvar+ :: Same as +:bufvar+, with lower priority.
42 | # +:postamble+ :: The postamble for the template, by default returns the resulting source code.
43 | # +:preamble+ :: The preamble for the template, by default initializes the buffer variable.
44 | # +:regexp+ :: The regexp to use for scanning.
45 | # +:src+ :: The initial value to use for the source code, an empty string by default.
46 | # +:trim+ :: Whether to trim leading and trailing whitespace, true by default.
47 | #
48 | # @return [Engine] a new instance of Engine
49 | #
50 | # source://erubi//lib/erubi.rb#91
51 | def initialize(input, properties = T.unsafe(nil)); end
52 |
53 | # The variable name used for the buffer variable.
54 | #
55 | # source://erubi//lib/erubi.rb#62
56 | def bufvar; end
57 |
58 | # The filename of the template, if one was given.
59 | #
60 | # source://erubi//lib/erubi.rb#59
61 | def filename; end
62 |
63 | # The frozen ruby source code generated from the template, which can be evaled.
64 | #
65 | # source://erubi//lib/erubi.rb#56
66 | def src; end
67 |
68 | private
69 |
70 | # Add ruby code to the template
71 | #
72 | # source://erubi//lib/erubi.rb#223
73 | def add_code(code); end
74 |
75 | # Add the given ruby expression result to the template,
76 | # escaping it based on the indicator given and escape flag.
77 | #
78 | # source://erubi//lib/erubi.rb#232
79 | def add_expression(indicator, code); end
80 |
81 | # Add the result of Ruby expression to the template
82 | #
83 | # source://erubi//lib/erubi.rb#241
84 | def add_expression_result(code); end
85 |
86 | # Add the escaped result of Ruby expression to the template
87 | #
88 | # source://erubi//lib/erubi.rb#246
89 | def add_expression_result_escaped(code); end
90 |
91 | # Add the given postamble to the src. Can be overridden in subclasses
92 | # to make additional changes to src that depend on the current state.
93 | #
94 | # source://erubi//lib/erubi.rb#252
95 | def add_postamble(postamble); end
96 |
97 | # Add raw text to the template. Modifies argument if argument is mutable as a memory optimization.
98 | # Must be called with a string, cannot be called with nil (Rails's subclass depends on it).
99 | #
100 | # source://erubi//lib/erubi.rb#210
101 | def add_text(text); end
102 |
103 | # Raise an exception, as the base engine class does not support handling other indicators.
104 | #
105 | # @raise [ArgumentError]
106 | #
107 | # source://erubi//lib/erubi.rb#258
108 | def handle(indicator, code, tailch, rspace, lspace); end
109 |
110 | # Make sure that any current expression has been terminated.
111 | # The default is to terminate all expressions, but when
112 | # the chain_appends option is used, expressions may not be
113 | # terminated.
114 | #
115 | # source://erubi//lib/erubi.rb#286
116 | def terminate_expression; end
117 |
118 | # Make sure the buffer variable is the target of the next append
119 | # before yielding to the block. Mark that the buffer is the target
120 | # of the next append after the block executes.
121 | #
122 | # This method should only be called if the block will result in
123 | # code where << will append to the bufvar.
124 | #
125 | # source://erubi//lib/erubi.rb#268
126 | def with_buffer; end
127 | end
128 |
129 | # The default regular expression used for scanning.
130 | #
131 | # source://erubi//lib/erubi.rb#53
132 | Erubi::Engine::DEFAULT_REGEXP = T.let(T.unsafe(nil), Regexp)
133 |
134 | # source://erubi//lib/erubi.rb#17
135 | Erubi::FREEZE_TEMPLATE_LITERALS = T.let(T.unsafe(nil), TrueClass)
136 |
137 | # source://erubi//lib/erubi.rb#15
138 | Erubi::MATCH_METHOD = T.let(T.unsafe(nil), Symbol)
139 |
140 | # source://erubi//lib/erubi.rb#8
141 | Erubi::RANGE_FIRST = T.let(T.unsafe(nil), Integer)
142 |
143 | # source://erubi//lib/erubi.rb#9
144 | Erubi::RANGE_LAST = T.let(T.unsafe(nil), Integer)
145 |
146 | # source://erubi//lib/erubi.rb#16
147 | Erubi::SKIP_DEFINED_FOR_INSTANCE_VARIABLE = T.let(T.unsafe(nil), TrueClass)
148 |
149 | # source://erubi//lib/erubi.rb#4
150 | Erubi::VERSION = T.let(T.unsafe(nil), String)
151 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/rbi/gems/multi_json@1.15.0.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `multi_json` gem.
5 | # Please instead update this file by running `bin/tapioca gem multi_json`.
6 |
7 |
8 | # source://multi_json//lib/multi_json/options.rb#1
9 | module MultiJson
10 | include ::MultiJson::Options
11 | extend ::MultiJson::Options
12 | extend ::MultiJson
13 |
14 | # Get the current adapter class.
15 | #
16 | # source://multi_json//lib/multi_json.rb#70
17 | def adapter; end
18 |
19 | # Set the JSON parser utilizing a symbol, string, or class.
20 | # Supported by default are:
21 | #
22 | # * :oj
23 | # * :json_gem
24 | # * :json_pure
25 | # * :ok_json
26 | # * :yajl
27 | # * :nsjsonserialization (MacRuby only)
28 | # * :gson (JRuby only)
29 | # * :jr_jackson (JRuby only)
30 | #
31 | # source://multi_json//lib/multi_json.rb#90
32 | def adapter=(new_adapter); end
33 |
34 | # source://multi_json//lib/multi_json.rb#26
35 | def cached_options(*_arg0); end
36 |
37 | # source://multi_json//lib/multi_json.rb#129
38 | def current_adapter(options = T.unsafe(nil)); end
39 |
40 | # Decode a JSON string into Ruby.
41 | #
42 | # Options
43 | #
44 | # :symbolize_keys :: If true, will use symbols instead of strings for the keys.
45 | # :adapter :: If set, the selected adapter will be used for this call.
46 | #
47 | # source://multi_json//lib/multi_json.rb#119
48 | def decode(string, options = T.unsafe(nil)); end
49 |
50 | # The default adapter based on what you currently
51 | # have loaded and installed. First checks to see
52 | # if any adapters are already loaded, then checks
53 | # to see which are installed if none are loaded.
54 | #
55 | # source://multi_json//lib/multi_json.rb#46
56 | def default_adapter; end
57 |
58 | # The default adapter based on what you currently
59 | # have loaded and installed. First checks to see
60 | # if any adapters are already loaded, then checks
61 | # to see which are installed if none are loaded.
62 | #
63 | # source://multi_json//lib/multi_json.rb#46
64 | def default_engine; end
65 |
66 | # source://multi_json//lib/multi_json.rb#18
67 | def default_options; end
68 |
69 | # source://multi_json//lib/multi_json.rb#11
70 | def default_options=(value); end
71 |
72 | # Encodes a Ruby object as JSON.
73 | #
74 | # source://multi_json//lib/multi_json.rb#138
75 | def dump(object, options = T.unsafe(nil)); end
76 |
77 | # Encodes a Ruby object as JSON.
78 | #
79 | # source://multi_json//lib/multi_json.rb#138
80 | def encode(object, options = T.unsafe(nil)); end
81 |
82 | # Get the current adapter class.
83 | #
84 | # source://multi_json//lib/multi_json.rb#70
85 | def engine; end
86 |
87 | # Set the JSON parser utilizing a symbol, string, or class.
88 | # Supported by default are:
89 | #
90 | # * :oj
91 | # * :json_gem
92 | # * :json_pure
93 | # * :ok_json
94 | # * :yajl
95 | # * :nsjsonserialization (MacRuby only)
96 | # * :gson (JRuby only)
97 | # * :jr_jackson (JRuby only)
98 | #
99 | # source://multi_json//lib/multi_json.rb#90
100 | def engine=(new_adapter); end
101 |
102 | # Decode a JSON string into Ruby.
103 | #
104 | # Options
105 | #
106 | # :symbolize_keys :: If true, will use symbols instead of strings for the keys.
107 | # :adapter :: If set, the selected adapter will be used for this call.
108 | #
109 | # source://multi_json//lib/multi_json.rb#119
110 | def load(string, options = T.unsafe(nil)); end
111 |
112 | # source://multi_json//lib/multi_json.rb#98
113 | def load_adapter(new_adapter); end
114 |
115 | # source://multi_json//lib/multi_json.rb#26
116 | def reset_cached_options!(*_arg0); end
117 |
118 | # Set the JSON parser utilizing a symbol, string, or class.
119 | # Supported by default are:
120 | #
121 | # * :oj
122 | # * :json_gem
123 | # * :json_pure
124 | # * :ok_json
125 | # * :yajl
126 | # * :nsjsonserialization (MacRuby only)
127 | # * :gson (JRuby only)
128 | # * :jr_jackson (JRuby only)
129 | #
130 | # source://multi_json//lib/multi_json.rb#90
131 | def use(new_adapter); end
132 |
133 | # Executes passed block using specified adapter.
134 | #
135 | # source://multi_json//lib/multi_json.rb#144
136 | def with_adapter(new_adapter); end
137 |
138 | # Executes passed block using specified adapter.
139 | #
140 | # source://multi_json//lib/multi_json.rb#144
141 | def with_engine(new_adapter); end
142 |
143 | private
144 |
145 | # source://multi_json//lib/multi_json.rb#155
146 | def load_adapter_from_string_name(name); end
147 | end
148 |
149 | # source://multi_json//lib/multi_json.rb#31
150 | MultiJson::ALIASES = T.let(T.unsafe(nil), Hash)
151 |
152 | # source://multi_json//lib/multi_json/adapter_error.rb#2
153 | class MultiJson::AdapterError < ::ArgumentError
154 | # Returns the value of attribute cause.
155 | #
156 | # source://multi_json//lib/multi_json/adapter_error.rb#3
157 | def cause; end
158 |
159 | class << self
160 | # source://multi_json//lib/multi_json/adapter_error.rb#5
161 | def build(original_exception); end
162 | end
163 | end
164 |
165 | # Legacy support
166 | #
167 | # source://multi_json//lib/multi_json/parse_error.rb#16
168 | MultiJson::DecodeError = MultiJson::ParseError
169 |
170 | # source://multi_json//lib/multi_json/parse_error.rb#16
171 | MultiJson::LoadError = MultiJson::ParseError
172 |
173 | # source://multi_json//lib/multi_json/options.rb#2
174 | module MultiJson::Options
175 | # source://multi_json//lib/multi_json/options.rb#25
176 | def default_dump_options; end
177 |
178 | # source://multi_json//lib/multi_json/options.rb#21
179 | def default_load_options; end
180 |
181 | # source://multi_json//lib/multi_json/options.rb#17
182 | def dump_options(*args); end
183 |
184 | # source://multi_json//lib/multi_json/options.rb#8
185 | def dump_options=(options); end
186 |
187 | # source://multi_json//lib/multi_json/options.rb#13
188 | def load_options(*args); end
189 |
190 | # source://multi_json//lib/multi_json/options.rb#3
191 | def load_options=(options); end
192 |
193 | private
194 |
195 | # source://multi_json//lib/multi_json/options.rb#31
196 | def get_options(options, *args); end
197 | end
198 |
199 | # source://multi_json//lib/multi_json/options_cache.rb#2
200 | module MultiJson::OptionsCache
201 | extend ::MultiJson::OptionsCache
202 |
203 | # source://multi_json//lib/multi_json/options_cache.rb#10
204 | def fetch(type, key, &block); end
205 |
206 | # source://multi_json//lib/multi_json/options_cache.rb#5
207 | def reset; end
208 |
209 | private
210 |
211 | # source://multi_json//lib/multi_json/options_cache.rb#24
212 | def write(cache, key); end
213 | end
214 |
215 | # Normally MultiJson is used with a few option sets for both dump/load
216 | # methods. When options are generated dynamically though, every call would
217 | # cause a cache miss and the cache would grow indefinitely. To prevent
218 | # this, we just reset the cache every time the number of keys outgrows
219 | # 1000.
220 | #
221 | # source://multi_json//lib/multi_json/options_cache.rb#22
222 | MultiJson::OptionsCache::MAX_CACHE_SIZE = T.let(T.unsafe(nil), Integer)
223 |
224 | # source://multi_json//lib/multi_json/parse_error.rb#2
225 | class MultiJson::ParseError < ::StandardError
226 | # Returns the value of attribute cause.
227 | #
228 | # source://multi_json//lib/multi_json/parse_error.rb#3
229 | def cause; end
230 |
231 | # Returns the value of attribute data.
232 | #
233 | # source://multi_json//lib/multi_json/parse_error.rb#3
234 | def data; end
235 |
236 | class << self
237 | # source://multi_json//lib/multi_json/parse_error.rb#5
238 | def build(original_exception, data); end
239 | end
240 | end
241 |
242 | # source://multi_json//lib/multi_json.rb#33
243 | MultiJson::REQUIREMENT_MAP = T.let(T.unsafe(nil), Array)
244 |
245 | # source://multi_json//lib/multi_json/version.rb#16
246 | MultiJson::VERSION = T.let(T.unsafe(nil), String)
247 |
248 | # source://multi_json//lib/multi_json/version.rb#2
249 | class MultiJson::Version
250 | class << self
251 | # @return [String]
252 | #
253 | # source://multi_json//lib/multi_json/version.rb#10
254 | def to_s; end
255 | end
256 | end
257 |
258 | # source://multi_json//lib/multi_json/version.rb#3
259 | MultiJson::Version::MAJOR = T.let(T.unsafe(nil), Integer)
260 |
261 | # source://multi_json//lib/multi_json/version.rb#4
262 | MultiJson::Version::MINOR = T.let(T.unsafe(nil), Integer)
263 |
264 | # source://multi_json//lib/multi_json/version.rb#5
265 | MultiJson::Version::PATCH = T.let(T.unsafe(nil), Integer)
266 |
267 | # source://multi_json//lib/multi_json/version.rb#6
268 | MultiJson::Version::PRE = T.let(T.unsafe(nil), T.untyped)
269 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/rbi/gems/netrc@0.11.0.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `netrc` gem.
5 | # Please instead update this file by running `bin/tapioca gem netrc`.
6 |
7 |
8 | # source://netrc//lib/netrc.rb#3
9 | class Netrc
10 | # @return [Netrc] a new instance of Netrc
11 | #
12 | # source://netrc//lib/netrc.rb#166
13 | def initialize(path, data); end
14 |
15 | # source://netrc//lib/netrc.rb#180
16 | def [](k); end
17 |
18 | # source://netrc//lib/netrc.rb#188
19 | def []=(k, info); end
20 |
21 | # source://netrc//lib/netrc.rb#200
22 | def delete(key); end
23 |
24 | # source://netrc//lib/netrc.rb#211
25 | def each(&block); end
26 |
27 | # source://netrc//lib/netrc.rb#196
28 | def length; end
29 |
30 | # source://netrc//lib/netrc.rb#215
31 | def new_item(m, l, p); end
32 |
33 | # Returns the value of attribute new_item_prefix.
34 | #
35 | # source://netrc//lib/netrc.rb#178
36 | def new_item_prefix; end
37 |
38 | # Sets the attribute new_item_prefix
39 | #
40 | # @param value the value to set the attribute new_item_prefix to.
41 | #
42 | # source://netrc//lib/netrc.rb#178
43 | def new_item_prefix=(_arg0); end
44 |
45 | # source://netrc//lib/netrc.rb#219
46 | def save; end
47 |
48 | # source://netrc//lib/netrc.rb#233
49 | def unparse; end
50 |
51 | class << self
52 | # source://netrc//lib/netrc.rb#42
53 | def check_permissions(path); end
54 |
55 | # source://netrc//lib/netrc.rb#33
56 | def config; end
57 |
58 | # @yield [self.config]
59 | #
60 | # source://netrc//lib/netrc.rb#37
61 | def configure; end
62 |
63 | # source://netrc//lib/netrc.rb#10
64 | def default_path; end
65 |
66 | # source://netrc//lib/netrc.rb#14
67 | def home_path; end
68 |
69 | # source://netrc//lib/netrc.rb#85
70 | def lex(lines); end
71 |
72 | # source://netrc//lib/netrc.rb#29
73 | def netrc_filename; end
74 |
75 | # Returns two values, a header and a list of items.
76 | # Each item is a tuple, containing some or all of:
77 | # - machine keyword (including trailing whitespace+comments)
78 | # - machine name
79 | # - login keyword (including surrounding whitespace+comments)
80 | # - login
81 | # - password keyword (including surrounding whitespace+comments)
82 | # - password
83 | # - trailing chars
84 | # This lets us change individual fields, then write out the file
85 | # with all its original formatting.
86 | #
87 | # source://netrc//lib/netrc.rb#129
88 | def parse(ts); end
89 |
90 | # Reads path and parses it as a .netrc file. If path doesn't
91 | # exist, returns an empty object. Decrypt paths ending in .gpg.
92 | #
93 | # source://netrc//lib/netrc.rb#51
94 | def read(path = T.unsafe(nil)); end
95 |
96 | # @return [Boolean]
97 | #
98 | # source://netrc//lib/netrc.rb#112
99 | def skip?(s); end
100 | end
101 | end
102 |
103 | # source://netrc//lib/netrc.rb#8
104 | Netrc::CYGWIN = T.let(T.unsafe(nil), T.untyped)
105 |
106 | # source://netrc//lib/netrc.rb#244
107 | class Netrc::Entry < ::Struct
108 | # Returns the value of attribute login
109 | #
110 | # @return [Object] the current value of login
111 | def login; end
112 |
113 | # Sets the attribute login
114 | #
115 | # @param value [Object] the value to set the attribute login to.
116 | # @return [Object] the newly set value
117 | def login=(_); end
118 |
119 | # Returns the value of attribute password
120 | #
121 | # @return [Object] the current value of password
122 | def password; end
123 |
124 | # Sets the attribute password
125 | #
126 | # @param value [Object] the value to set the attribute password to.
127 | # @return [Object] the newly set value
128 | def password=(_); end
129 |
130 | def to_ary; end
131 |
132 | class << self
133 | def [](*_arg0); end
134 | def inspect; end
135 | def keyword_init?; end
136 | def members; end
137 | def new(*_arg0); end
138 | end
139 | end
140 |
141 | # source://netrc//lib/netrc.rb#250
142 | class Netrc::Error < ::StandardError; end
143 |
144 | # source://netrc//lib/netrc.rb#68
145 | class Netrc::TokenArray < ::Array
146 | # source://netrc//lib/netrc.rb#76
147 | def readto; end
148 |
149 | # source://netrc//lib/netrc.rb#69
150 | def take; end
151 | end
152 |
153 | # source://netrc//lib/netrc.rb#4
154 | Netrc::VERSION = T.let(T.unsafe(nil), String)
155 |
156 | # see http://stackoverflow.com/questions/4871309/what-is-the-correct-way-to-detect-if-ruby-is-running-on-windows
157 | #
158 | # source://netrc//lib/netrc.rb#7
159 | Netrc::WINDOWS = T.let(T.unsafe(nil), T.untyped)
160 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/rbi/gems/polyfill@1.9.0.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `polyfill` gem.
5 | # Please instead update this file by running `bin/tapioca gem polyfill`.
6 |
7 |
8 | # THIS IS AN EMPTY RBI FILE.
9 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem
10 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/rbi/gems/rspec@3.13.0.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `rspec` gem.
5 | # Please instead update this file by running `bin/tapioca gem rspec`.
6 |
7 |
8 | # source://rspec//lib/rspec/version.rb#1
9 | module RSpec
10 | class << self
11 | # source://rspec-core/3.13.1/lib/rspec/core.rb#70
12 | def clear_examples; end
13 |
14 | # source://rspec-core/3.13.1/lib/rspec/core.rb#85
15 | def configuration; end
16 |
17 | # source://rspec-core/3.13.1/lib/rspec/core.rb#49
18 | def configuration=(_arg0); end
19 |
20 | # source://rspec-core/3.13.1/lib/rspec/core.rb#97
21 | def configure; end
22 |
23 | # source://rspec-core/3.13.1/lib/rspec/core.rb#194
24 | def const_missing(name); end
25 |
26 | # source://rspec-core/3.13.1/lib/rspec/core/dsl.rb#42
27 | def context(*args, &example_group_block); end
28 |
29 | # source://rspec-core/3.13.1/lib/rspec/core.rb#122
30 | def current_example; end
31 |
32 | # source://rspec-core/3.13.1/lib/rspec/core.rb#128
33 | def current_example=(example); end
34 |
35 | # source://rspec-core/3.13.1/lib/rspec/core.rb#154
36 | def current_scope; end
37 |
38 | # source://rspec-core/3.13.1/lib/rspec/core.rb#134
39 | def current_scope=(scope); end
40 |
41 | # source://rspec-core/3.13.1/lib/rspec/core/dsl.rb#42
42 | def describe(*args, &example_group_block); end
43 |
44 | # source://rspec-core/3.13.1/lib/rspec/core/dsl.rb#42
45 | def example_group(*args, &example_group_block); end
46 |
47 | # source://rspec-core/3.13.1/lib/rspec/core/dsl.rb#42
48 | def fcontext(*args, &example_group_block); end
49 |
50 | # source://rspec-core/3.13.1/lib/rspec/core/dsl.rb#42
51 | def fdescribe(*args, &example_group_block); end
52 |
53 | # source://rspec-core/3.13.1/lib/rspec/core.rb#58
54 | def reset; end
55 |
56 | # source://rspec-core/3.13.1/lib/rspec/core/shared_example_group.rb#110
57 | def shared_context(name, *args, &block); end
58 |
59 | # source://rspec-core/3.13.1/lib/rspec/core/shared_example_group.rb#110
60 | def shared_examples(name, *args, &block); end
61 |
62 | # source://rspec-core/3.13.1/lib/rspec/core/shared_example_group.rb#110
63 | def shared_examples_for(name, *args, &block); end
64 |
65 | # source://rspec-core/3.13.1/lib/rspec/core.rb#160
66 | def world; end
67 |
68 | # source://rspec-core/3.13.1/lib/rspec/core.rb#49
69 | def world=(_arg0); end
70 |
71 | # source://rspec-core/3.13.1/lib/rspec/core/dsl.rb#42
72 | def xcontext(*args, &example_group_block); end
73 |
74 | # source://rspec-core/3.13.1/lib/rspec/core/dsl.rb#42
75 | def xdescribe(*args, &example_group_block); end
76 | end
77 | end
78 |
79 | # source://rspec//lib/rspec/version.rb#2
80 | module RSpec::Version; end
81 |
82 | # source://rspec//lib/rspec/version.rb#3
83 | RSpec::Version::STRING = T.let(T.unsafe(nil), String)
84 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/rbi/gems/ruby2_keywords@0.0.5.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `ruby2_keywords` gem.
5 | # Please instead update this file by running `bin/tapioca gem ruby2_keywords`.
6 |
7 |
8 | # THIS IS AN EMPTY RBI FILE.
9 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem
10 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/rbi/gems/safe_type@1.1.1.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `safe_type` gem.
5 | # Please instead update this file by running `bin/tapioca gem safe_type`.
6 |
7 |
8 | # THIS IS AN EMPTY RBI FILE.
9 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem
10 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/rbi/gems/sorbet-coerce@0.7.0.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `sorbet-coerce` gem.
5 | # Please instead update this file by running `bin/tapioca gem sorbet-coerce`.
6 |
7 |
8 | # THIS IS AN EMPTY RBI FILE.
9 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem
10 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/tapioca/config.yml:
--------------------------------------------------------------------------------
1 | gem:
2 | # Add your `gem` command parameters here:
3 | #
4 | # exclude:
5 | # - gem_name
6 | # doc: true
7 | # workers: 5
8 | dsl:
9 | # Add your `dsl` command parameters here:
10 | #
11 | # exclude:
12 | # - SomeGeneratorName
13 | # workers: 5
14 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/sorbet/tapioca/require.rb:
--------------------------------------------------------------------------------
1 | # typed: true
2 | # frozen_string_literal: true
3 |
4 | require "pry"
5 | require "rack/test"
6 | require "resource_registry"
7 | require "rspec"
8 | require "sinatra"
9 | require "sinatra/multi_route"
10 | require "sinatra/reloader"
11 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/spec/app_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "spec_helper"
4 |
5 | describe App do
6 | let(:app) { App.new }
7 |
8 | context "GET /dogs" do
9 | let(:response) { get "/dogs" }
10 |
11 | it "returns 200 OK" do
12 | expect(response.status).to eq 200
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/examples/sinatra-pet-shelter/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | ENV["APP_ENV"] = "test"
4 |
5 | require_relative "../lib/app"
6 | require "rspec"
7 | require "rack/test"
8 |
9 | RSpec.configure { |_config| include Rack::Test::Methods }
10 |
--------------------------------------------------------------------------------
/lib/README.md:
--------------------------------------------------------------------------------
1 | # Resource Registry
2 |
3 | A service discovery mechanism for Factorial backend
4 |
5 | ## Features
6 |
7 | - Schema registry for resources, maybe we can infere them from entities
8 | - Relate events to resources actions (CRUD and not CRUD)
9 |
10 | ## Examples
11 |
12 | ```ruby
13 | ResourceRegistry.add(
14 | Resource.new(
15 | slug: 'employees', # Maybe we will need component Namespacing / Category to prefix routes
16 | repository: Employees::Repositories::Employees,
17 | verbs: {
18 | index: {
19 | type: :read
20 | }, # => Repository.read
21 | show: {
22 | type: :read
23 | },
24 | create: {
25 | type: :write
26 | }, # => Repository.create
27 | update: {
28 | type: :write
29 | },
30 | destroy: {
31 | event: Employee::Events::EmployeeRemoved
32 | },
33 | # RPCs they are all http POST method
34 | approve: {
35 | event: Employee::Events::EmployeeApproved
36 | } # => Repository.approve
37 | }
38 | )
39 | )
40 | ```
41 |
--------------------------------------------------------------------------------
/lib/package.yml:
--------------------------------------------------------------------------------
1 | ---
2 | enforce_privacy: true
3 | enforce_dependencies: true
4 | dependencies:
5 | - '.'
6 | - 'components/telemetry'
7 | metadata:
8 | owner: '@factorialco/developer-experience'
9 |
--------------------------------------------------------------------------------
/lib/package_todo.yml:
--------------------------------------------------------------------------------
1 | # This file contains a list of dependencies that are not part of the long term plan for the
2 | # 'lib/resource_registry' package.
3 | # We should generally work to reduce this list over time.
4 | #
5 | # You can regenerate this file using the following command:
6 | #
7 | # bin/packwerk update-todo
8 | ---
9 | components/api_public:
10 | "::ApiPublic::Authentication::InvalidState":
11 | violations:
12 | - dependency
13 | - privacy
14 | files:
15 | - lib/resource_registry/graphql/base_schema.rb
16 | components/features:
17 | "::Features::Catalog::DEV_REALTIME_ENGINE":
18 | violations:
19 | - dependency
20 | files:
21 | - lib/resource_registry/public/trigger.rb
22 | components/permissions:
23 | "::Permissions::PolicyContext":
24 | violations:
25 | - dependency
26 | files:
27 | - lib/resource_registry/graphql/graphql_repository_source.rb
28 | - lib/resource_registry/public/graphql/resource_query.rb
29 |
--------------------------------------------------------------------------------
/lib/resource_registry.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: true
3 |
4 | require "sorbet-runtime"
5 | require "active_support/all"
6 |
7 | require "resource_registry/configuration"
8 | require "resource_registry/resource"
9 | require "resource_registry/versions"
10 | require "resource_registry/versions/version"
11 | require "resource_registry/entity_finder"
12 | require "resource_registry/registry"
13 | require "resource_registry/serializer"
14 | require "resource_registry/repositories/base"
15 | require "schema_registry/registry"
16 | require "schema_registry/json_schema_mapper"
17 | require "schema_registry/maybe"
18 | require "runtime_generic"
19 |
20 | # Entry point for ResourceRegistry
21 | module ResourceRegistry
22 | class << self
23 | extend T::Sig
24 |
25 | sig { returns(Configuration) }
26 | def configuration
27 | @configuration ||= Configuration.new
28 | end
29 |
30 | sig { void }
31 | def configure
32 | yield(configuration)
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/lib/resource_registry/capabilities/capability_config.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: strict
3 |
4 | module ResourceRegistry
5 | module Capabilities
6 | # Represents configuration for a specific resource capability
7 | module CapabilityConfig
8 | extend T::Helpers
9 | extend T::Sig
10 | include Kernel
11 |
12 | interface!
13 |
14 | # Class methods interface for capability configuration
15 | module ClassMethods
16 | extend T::Sig
17 | extend T::Generic
18 | extend T::Helpers
19 | abstract!
20 |
21 | has_attached_class!
22 |
23 | # The key of the capability, this key will be used to take it from yaml configuration
24 | sig { abstract.returns(Symbol) }
25 | def key
26 | end
27 |
28 | sig { params(resource: Resource).returns(T::Boolean) }
29 | def resource_capability?(resource:)
30 | resource.capabilities.key?(key)
31 | end
32 |
33 | sig do
34 | params(resource: Resource).returns(
35 | T.nilable(T.attached_class)
36 | )
37 | end
38 | def resource_capability(resource:)
39 | return unless resource_capability?(resource:)
40 |
41 | T.cast(resource.capabilities[key], T.attached_class)
42 | end
43 |
44 | sig do
45 | params(resource: Resource).returns(T.attached_class)
46 | end
47 | def resource_capability!(resource:)
48 | T.must(resource_capability(resource: ))
49 | end
50 | end
51 |
52 | requires_ancestor { Object }
53 |
54 | mixes_in_class_methods(ClassMethods)
55 |
56 | sig { abstract.returns(T::Hash[String, T.untyped]) }
57 | def serialize
58 | end
59 | end
60 | end
61 | end
62 |
--------------------------------------------------------------------------------
/lib/resource_registry/capability_factory.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 |
3 | module ResourceRegistry
4 | # This class enumerates features that are available to a resource. Each
5 | # resource knows which subset of these it needs to be used with.
6 | class CapabilityFactory
7 | extend T::Sig
8 |
9 | sig do
10 | params(
11 | data: T::Hash[String, T.untyped],
12 | capabilities:
13 | T::Hash[
14 | Symbol,
15 | T.all(
16 | T::Class[Capabilities::CapabilityConfig],
17 | T.class_of(T::Struct)
18 | )
19 | ]
20 | ).returns(Capabilities::CapabilityConfig)
21 | end
22 | def self.load(
23 | data,
24 | capabilities: ResourceRegistry.configuration.capabilities
25 | )
26 | key = data["key"]
27 | capability = capabilities.fetch(key.to_sym)
28 | # FIXME: This T.let should not be needed
29 | T.let(capability, T.class_of(T::Struct)).from_hash(data)
30 | end
31 |
32 | sig do
33 | params(capability: Capabilities::CapabilityConfig).returns(
34 | T::Hash[String, T.untyped]
35 | )
36 | end
37 | def self.dump(capability)
38 | { "key" => capability.class.key }.merge!(capability.serialize)
39 | end
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/lib/resource_registry/configuration.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: true
3 |
4 | require_relative "relationship_types/has_many"
5 | require_relative "relationship_types/has_many_through"
6 | require_relative "relationship_types/has_one"
7 | require_relative "relationship_types/belongs_to"
8 |
9 | module ResourceRegistry
10 | class Configuration
11 | extend T::Sig
12 |
13 | DEFAULT_RELATIONSHIP_TYPES = {
14 | "has_many_through" => RelationshipTypes::HasManyThrough,
15 | "has_many" => RelationshipTypes::HasMany,
16 | "has_one" => RelationshipTypes::HasOne,
17 | "belongs_to" => RelationshipTypes::BelongsTo
18 | }.freeze
19 |
20 | sig { void }
21 | def initialize
22 | @relationship_types = DEFAULT_RELATIONSHIP_TYPES.dup
23 | @capabilities = {}
24 | end
25 |
26 | sig { params(type: String, klass: T.class_of(RelationshipType)).void }
27 | def register_relationship_type(type, klass)
28 | @relationship_types[type] = klass
29 | end
30 |
31 | sig do
32 | params(
33 | capability: Symbol,
34 | klass: T.class_of(Capabilities::CapabilityConfig)
35 | ).void
36 | end
37 | def register_capability(capability, klass)
38 | @capabilities[capability] = klass
39 | end
40 |
41 | sig { returns(T::Hash[String, T::Class[RelationshipType]]) }
42 | attr_reader :relationship_types
43 |
44 | sig do
45 | returns(
46 | T::Hash[
47 | Symbol,
48 | T.all(T::Class[Capabilities::CapabilityConfig], T.class_of(T::Struct))
49 | ]
50 | )
51 | end
52 | attr_reader :capabilities
53 | end
54 | end
55 |
--------------------------------------------------------------------------------
/lib/resource_registry/entity_finder.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 |
3 | module ResourceRegistry
4 | class EntityFinder
5 | extend T::Sig
6 |
7 | sig do
8 | params(repository: T.class_of(Repositories::Base)).returns(
9 | T.nilable(T.class_of(T::Struct))
10 | )
11 | end
12 | def self.call(repository:)
13 | entity = repository.entity
14 |
15 | return nil if entity.is_a?(T::Types::Untyped)
16 |
17 | entity
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/lib/resource_registry/load_resources_from_cache.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 |
3 | module ResourceRegistry
4 | class LoadResourcesFromCache
5 | extend T::Sig
6 |
7 | sig { returns(T::Array[Resource]) }
8 | def call
9 | # We early return to being able to generate this file in development,
10 | # otherwise the script generating it fails
11 | unless File.exist?(Rails.root.join("resources.json"))
12 | puts "Cache not found. Skipping loading resources from cache. Consider running `bin/rails resource_registry:generate_cache`"
13 |
14 | return []
15 | end
16 |
17 | cache_path = Rails.root.join("resources.json")
18 | resources = JSON.load_file(cache_path)
19 | resources
20 | .map { |res_def| ResourceRegistry::Resource.load(res_def) }
21 | .sort_by(&:path)
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/lib/resource_registry/registry.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 | # frozen_string_literal: true
3 |
4 | require_relative "resource"
5 | require_relative "capabilities/capability_config"
6 |
7 | module ResourceRegistry
8 | class Registry
9 | extend T::Sig
10 |
11 | class UnableToFindResourceError < StandardError
12 | end
13 |
14 | class DuplicatedIdentifierError < StandardError
15 | end
16 |
17 | sig { params(resources: T::Array[Resource]).void }
18 | def initialize(resources:)
19 | if duplicated_identifier?(resources)
20 | raise DuplicatedIdentifierError,
21 | "You have a duplicated resource in a component. Check that you don't have more than one repository with the same name in a component."
22 | end
23 |
24 | @resources =
25 | T.let(
26 | resources.index_by { |res| res.identifier.to_s },
27 | T::Hash[String, Resource]
28 | )
29 | end
30 |
31 | sig { params(identifier: String).returns(T.nilable(Resource)) }
32 | def fetch(identifier)
33 | resources[identifier]
34 | end
35 |
36 | sig { params(identifier: String).returns(Resource) }
37 | def fetch!(identifier)
38 | resource = fetch(identifier)
39 |
40 | return resource if resource.present?
41 |
42 | raise UnableToFindResourceError, "#{identifier} does not exist"
43 | end
44 |
45 | sig do
46 | params(
47 | repository_class:
48 | T::Class[ResourceRegistry::Repositories::Base[T.untyped]]
49 | ).returns(T.nilable(Resource))
50 | end
51 | def fetch_for_repository(repository_class)
52 | resources_by_raw_repository[repository_class.to_s]
53 | end
54 |
55 | alias find_for_repository fetch_for_repository
56 |
57 | sig { returns(T::Hash[String, Resource]) }
58 | def fetch_all
59 | resources
60 | end
61 |
62 | sig do
63 | params(capabilities: T::Class[Capabilities::CapabilityConfig]).returns(
64 | T::Array[Resource]
65 | )
66 | end
67 | def fetch_with_capabilities(*capabilities)
68 | # FIXME: This is a hack to avoid having to change the interface of the method
69 | capabilities_set = T.unsafe(capabilities).to_set(&:key)
70 |
71 | fetch_all.values.select do |resource|
72 | capabilities_set <= resource.capabilities.keys.to_set
73 | end
74 | end
75 |
76 | private
77 |
78 | sig { returns(T::Hash[String, Resource]) }
79 | attr_accessor :resources
80 |
81 | sig { returns(T::Hash[String, Resource]) }
82 | def resources_by_raw_repository
83 | @resources_by_raw_repository ||=
84 | T.let(
85 | resources.values.index_by(&:repository_raw),
86 | T.nilable(T::Hash[String, Resource])
87 | )
88 | end
89 |
90 | sig { params(resources: T::Array[Resource]).returns(T::Boolean) }
91 | def duplicated_identifier?(resources)
92 | resources.map(&:identifier).uniq.size != resources.size
93 | end
94 | end
95 | end
96 |
--------------------------------------------------------------------------------
/lib/resource_registry/relationship.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: true
3 |
4 | require_relative "relationship_type"
5 | require_relative "relationship_type_factory"
6 |
7 | module ResourceRegistry
8 | class Relationship < T::Struct
9 | extend T::Sig
10 |
11 | const :name, String
12 | const :resource_id, Symbol
13 | const :field, Symbol
14 | const :primary_key, Symbol, default: :id
15 | const :type, RelationshipType
16 | const :fixed_dto_params, T.nilable(T::Hash[String, T.untyped])
17 | const :optional, T::Boolean
18 |
19 | # Are there multiple resources in the other side of the relationship?
20 | sig { returns(T::Boolean) }
21 | def many_cardinality?
22 | type.many_cardinality?
23 | end
24 |
25 | sig { returns(T::Hash[String, T.untyped]) }
26 | def dump
27 | {}.tap do |result|
28 | result["name"] = name
29 | result["resource_id"] = resource_id
30 | result["primary_key"] = primary_key
31 | result["field"] = field
32 | result["type"] = type.serialize
33 | result["optional"] = optional
34 | result["fixed_dto_params"] = fixed_dto_params
35 | end
36 | end
37 |
38 | sig { params(spec: T::Hash[String, T.untyped]).returns(Relationship) }
39 | def self.load(spec)
40 | type = RelationshipTypeFactory.from_spec(spec)
41 |
42 | new(
43 | name: type.name,
44 | resource_id: type.resource_id,
45 | field: type.field,
46 | primary_key: type.primary_key,
47 | type: type,
48 | fixed_dto_params: spec["fixed_dto_params"],
49 | optional: !spec["optional"].to_s.casecmp("false").zero?
50 | )
51 | end
52 |
53 | # We provide this in the dataloader, we encourage not to perform joins in
54 | # frontend, so we skip ids to be exposed.
55 | # FIXME: Review if this belongs to this layer or is coupled to GraphQL
56 | sig { params(argument: String).returns(T::Boolean) }
57 | def should_skip_argument?(argument)
58 | return true if fixed_dto_params&.key?(argument)
59 |
60 | type.should_skip_argument?(argument, self)
61 | end
62 |
63 | # The field used to define the left side of a relationship. This is the
64 | # field that it will be passed to the next resolver to fetch the data.
65 | sig { returns(T.nilable(Symbol)) }
66 | def reference_id
67 | type.reference_id(self)
68 | end
69 |
70 | sig { returns(T::Boolean) }
71 | def optional?
72 | case type
73 | when ResourceRegistry::RelationshipTypes::HasMany,
74 | ResourceRegistry::RelationshipTypes::HasManyThrough
75 | false
76 | else
77 | optional
78 | end
79 | end
80 | end
81 | end
82 |
--------------------------------------------------------------------------------
/lib/resource_registry/relationship_type.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 |
3 | module ResourceRegistry
4 | module RelationshipType
5 | extend T::Sig
6 | extend T::Helpers
7 |
8 | InvalidRelationshipSpec = Class.new(StandardError)
9 |
10 | abstract!
11 |
12 | # This enables `is_a?` check type to sorbet
13 | requires_ancestor { Object }
14 |
15 | ResultShape =
16 | T.type_alias do
17 | T::Array[
18 | T.nilable(
19 | T.any(
20 | T::Hash[String, T.untyped],
21 | T::Array[T::Hash[String, T.untyped]]
22 | )
23 | )
24 | ]
25 | end
26 |
27 | sig { params(spec: T::Hash[String, T.untyped]).void }
28 | def initialize(spec)
29 | @spec = spec
30 | validate_spec!
31 | end
32 |
33 | sig { abstract.returns(String) }
34 | def serialize
35 | end
36 |
37 | sig do
38 | abstract
39 | .params(argument: String, relationship: Relationship)
40 | .returns(T::Boolean)
41 | end
42 | def should_skip_argument?(argument, relationship)
43 | end
44 |
45 | sig { abstract.returns(T::Boolean) }
46 | def many_cardinality?
47 | end
48 |
49 | # The field defined to resolve the other side of the relationship, it can be field or primary_key
50 | sig { abstract.params(relationship: Relationship).returns(Symbol) }
51 | def reference_id(relationship)
52 | end
53 |
54 | sig do
55 | abstract
56 | .params(
57 | loaded_data: T::Array[T::Hash[String, T.untyped]],
58 | ids: T.untyped, # FIXME
59 | relationship: Relationship
60 | )
61 | .returns(ResultShape)
62 | end
63 | def shape_result(loaded_data, ids, relationship)
64 | end
65 |
66 | sig { abstract.returns(Integer) }
67 | def complexity
68 | end
69 |
70 | sig { returns(T::Boolean) }
71 | def forward_entities?
72 | false
73 | end
74 |
75 | sig { returns(T::Boolean) }
76 | # TODO: doc
77 | def forward_selected_fields?
78 | false
79 | end
80 |
81 | sig do
82 | abstract
83 | .params(
84 | dto: T::Hash[Symbol, T.untyped],
85 | ids: T::Array[T.any(String, Integer)],
86 | rel: Relationship,
87 | parent_resource: T.nilable(Resource)
88 | )
89 | .returns(T::Hash[Symbol, T.untyped])
90 | end
91 | def prepare_dto(dto, ids, rel, parent_resource)
92 | end
93 |
94 | sig { returns(T::Array[T::Hash[String, T.untyped]]) }
95 | def nested_fields
96 | []
97 | end
98 |
99 | sig { returns(String) }
100 | def name
101 | @spec["name"]
102 | end
103 |
104 | sig { returns(Symbol) }
105 | def resource_id
106 | @spec["resource_id"]&.to_sym
107 | end
108 |
109 | sig { returns(Symbol) }
110 | def field
111 | @spec["field"]&.to_sym
112 | end
113 |
114 | sig { returns(Symbol) }
115 | def primary_key
116 | @spec["primary_key"]&.to_sym
117 | end
118 |
119 | sig do
120 | overridable
121 | .params(read_dto: T.nilable(T.class_of(T::Struct)))
122 | .returns(T::Boolean)
123 | end
124 | def valid_relationship_field?(read_dto)
125 | return true unless relationship_field_name
126 |
127 | !!read_dto&.props&.keys&.include?(T.must(relationship_field_name))
128 | end
129 |
130 | sig { overridable.returns(T.nilable(Symbol)) }
131 | def relationship_field_name
132 | end
133 |
134 | private
135 |
136 | sig { void }
137 | def validate_spec!
138 | errors = []
139 | errors << "name is required" unless @spec["name"]
140 | errors << "resource_id is required" unless @spec["resource_id"]
141 | errors << "field is required" unless @spec["field"]
142 | errors << "primary_key is required" unless @spec["primary_key"]
143 | errors << "name must be a string" unless @spec["name"].is_a?(String)
144 |
145 | return if errors.empty?
146 |
147 | Kernel.raise InvalidRelationshipSpec,
148 | "The given relationship spec is not valid: #{errors.join(", ")}. The spec is: #{@spec}"
149 | end
150 | end
151 | end
152 |
--------------------------------------------------------------------------------
/lib/resource_registry/relationship_type_factory.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 |
3 | module ResourceRegistry
4 | module RelationshipTypeFactory
5 | extend T::Sig
6 |
7 | # FIXME: Allow a more dynamic and future proof way to register relationship types
8 | sig { params(spec: T.untyped).returns(RelationshipType) }
9 | def self.from_spec(spec)
10 | type = ResourceRegistry.configuration.relationship_types[spec["type"]]
11 |
12 | raise "Unknown relationship type #{spec}" unless type
13 |
14 | type.new(spec)
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/resource_registry/relationship_types/belongs_to.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: strict
3 |
4 | require_relative "../relationship_type"
5 |
6 | module ResourceRegistry
7 | module RelationshipTypes
8 | class BelongsTo
9 | extend T::Sig
10 |
11 | include RelationshipType
12 |
13 | sig { override.returns(String) }
14 | def serialize
15 | "belongs_to"
16 | end
17 |
18 | sig do
19 | override
20 | .params(argument: String, relationship: Relationship)
21 | .returns(T::Boolean)
22 | end
23 | def should_skip_argument?(argument, relationship)
24 | argument == relationship.primary_key.to_s.pluralize
25 | end
26 |
27 | sig { override.returns(T::Boolean) }
28 | def many_cardinality?
29 | false
30 | end
31 |
32 | sig { override.params(relationship: Relationship).returns(Symbol) }
33 | def reference_id(relationship)
34 | relationship.field
35 | end
36 |
37 | sig do
38 | override
39 | .params(
40 | loaded_data: T::Array[T::Hash[String, T.untyped]],
41 | ids: T.untyped, # FIXME
42 | relationship: Relationship
43 | )
44 | .returns(
45 | T::Array[
46 | T.nilable(
47 | T.any(
48 | T::Hash[String, T.untyped],
49 | T::Array[T::Hash[String, T.untyped]]
50 | )
51 | )
52 | ]
53 | )
54 | end
55 | def shape_result(loaded_data, ids, relationship)
56 | indexed_res =
57 | loaded_data.index_by do |resource|
58 | resource[relationship.primary_key.to_s]
59 | end
60 | ids.map { |id| indexed_res[id] }
61 | end
62 |
63 | sig { override.returns(Integer) }
64 | def complexity
65 | 5
66 | end
67 |
68 | sig do
69 | override
70 | .params(
71 | dto: T::Hash[Symbol, T.untyped],
72 | ids: T::Array[T.any(String, Integer)],
73 | rel: Relationship,
74 | _parent_resource: T.nilable(Resource)
75 | )
76 | .returns(T::Hash[Symbol, T.untyped])
77 | end
78 | def prepare_dto(dto, ids, rel, _parent_resource)
79 | dto[rel.primary_key.to_s.pluralize.to_sym] = ids.compact
80 | dto
81 | end
82 |
83 | sig { override.returns(Symbol) }
84 | def relationship_field_name
85 | primary_key.to_s.pluralize.to_sym
86 | end
87 | end
88 | end
89 | end
90 |
--------------------------------------------------------------------------------
/lib/resource_registry/relationship_types/has_many.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: strict
3 |
4 | require_relative "../relationship_type"
5 |
6 | module ResourceRegistry
7 | module RelationshipTypes
8 | class HasMany
9 | extend T::Sig
10 |
11 | include RelationshipType
12 |
13 | sig { override.returns(String) }
14 | def serialize
15 | "has_many"
16 | end
17 |
18 | sig do
19 | override
20 | .params(argument: String, relationship: Relationship)
21 | .returns(T::Boolean)
22 | end
23 | def should_skip_argument?(argument, relationship)
24 | argument == relationship.field.to_s.pluralize
25 | end
26 |
27 | sig { override.returns(T::Boolean) }
28 | def many_cardinality?
29 | true
30 | end
31 |
32 | sig { override.params(relationship: Relationship).returns(Symbol) }
33 | def reference_id(relationship)
34 | relationship.primary_key
35 | end
36 |
37 | sig do
38 | override
39 | .params(
40 | loaded_data: T::Array[T::Hash[String, T.untyped]],
41 | ids: T.untyped, # FIXME
42 | relationship: Relationship
43 | )
44 | .returns(
45 | T::Array[
46 | T.nilable(
47 | T.any(
48 | T::Hash[String, T.untyped],
49 | T::Array[T::Hash[String, T.untyped]]
50 | )
51 | )
52 | ]
53 | )
54 | end
55 | def shape_result(loaded_data, ids, relationship)
56 | indexed_res = loaded_data.group_by { |r| r[relationship.field.to_s] }
57 | ids.map { |id| indexed_res[id] || [] }
58 | end
59 |
60 | sig { override.returns(Integer) }
61 | def complexity
62 | 10
63 | end
64 |
65 | sig do
66 | override
67 | .params(
68 | dto: T::Hash[Symbol, T.untyped],
69 | ids: T::Array[T.any(String, Integer)],
70 | rel: Relationship,
71 | _parent_resource: T.nilable(Resource)
72 | )
73 | .returns(T::Hash[Symbol, T.untyped])
74 | end
75 | def prepare_dto(dto, ids, rel, _parent_resource)
76 | dto[rel.field.to_s.pluralize.to_sym] = ids.compact
77 | dto
78 | end
79 |
80 | sig { override.returns(Symbol) }
81 | def relationship_field_name
82 | field.to_s.pluralize.to_sym
83 | end
84 | end
85 | end
86 | end
87 |
--------------------------------------------------------------------------------
/lib/resource_registry/relationship_types/has_many_through.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: strict
3 |
4 | require_relative "../relationship_type"
5 |
6 | module ResourceRegistry
7 | module RelationshipTypes
8 | class HasManyThrough
9 | extend T::Sig
10 |
11 | include RelationshipType
12 |
13 | sig { override.returns(String) }
14 | def serialize
15 | "has_many_through"
16 | end
17 |
18 | sig do
19 | override
20 | .params(argument: String, relationship: Relationship)
21 | .returns(T::Boolean)
22 | end
23 | def should_skip_argument?(argument, relationship)
24 | argument == relationship.primary_key.to_s.pluralize
25 | end
26 |
27 | sig { override.returns(T::Boolean) }
28 | def many_cardinality?
29 | true
30 | end
31 |
32 | sig { override.params(relationship: Relationship).returns(Symbol) }
33 | def reference_id(relationship)
34 | relationship.field
35 | end
36 |
37 | sig do
38 | override
39 | .params(
40 | loaded_data: T::Array[T::Hash[String, T.untyped]],
41 | ids: T.untyped, # FIXME
42 | _relationship: Relationship
43 | )
44 | .returns(
45 | T::Array[
46 | T.nilable(
47 | T.any(
48 | T::Hash[String, T.untyped],
49 | T::Array[T::Hash[String, T.untyped]]
50 | )
51 | )
52 | ]
53 | )
54 | end
55 | def shape_result(loaded_data, ids, _relationship)
56 | ids.map do |many_ids|
57 | loaded_data.filter { |r| many_ids.include?(r["id"]) }
58 | end
59 | end
60 |
61 | sig { override.returns(Integer) }
62 | def complexity
63 | 10
64 | end
65 |
66 | sig do
67 | override
68 | .params(
69 | dto: T::Hash[Symbol, T.untyped],
70 | ids: T::Array[T.any(String, Integer)],
71 | _rel: Relationship,
72 | _parent_resource: T.nilable(Resource)
73 | )
74 | .returns(T::Hash[Symbol, T.untyped])
75 | end
76 | def prepare_dto(dto, ids, _rel, _parent_resource)
77 | dto[:ids] = ids.flatten.compact.uniq
78 | dto
79 | end
80 |
81 | sig { override.returns(Symbol) }
82 | def relationship_field_name
83 | :ids
84 | end
85 | end
86 | end
87 | end
88 |
--------------------------------------------------------------------------------
/lib/resource_registry/relationship_types/has_one.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: strict
3 |
4 | require_relative "../relationship_type"
5 |
6 | module ResourceRegistry
7 | module RelationshipTypes
8 | class HasOne
9 | extend T::Sig
10 |
11 | include RelationshipType
12 |
13 | sig { override.returns(String) }
14 | def serialize
15 | "has_one"
16 | end
17 |
18 | sig do
19 | override
20 | .params(argument: String, relationship: Relationship)
21 | .returns(T::Boolean)
22 | end
23 | def should_skip_argument?(argument, relationship)
24 | argument == relationship.field.to_s.pluralize
25 | end
26 |
27 | sig { override.returns(T::Boolean) }
28 | def many_cardinality?
29 | false
30 | end
31 |
32 | # FIXME: Review if this is actually reference_id
33 | sig { override.params(relationship: Relationship).returns(Symbol) }
34 | def reference_id(relationship)
35 | relationship.primary_key
36 | end
37 |
38 | sig do
39 | override
40 | .params(
41 | loaded_data: T::Array[T::Hash[String, T.untyped]],
42 | ids: T.untyped, # FIXME
43 | relationship: Relationship
44 | )
45 | .returns(
46 | T::Array[
47 | T.nilable(
48 | T.any(
49 | T::Hash[String, T.untyped],
50 | T::Array[T::Hash[String, T.untyped]]
51 | )
52 | )
53 | ]
54 | )
55 | end
56 | def shape_result(loaded_data, ids, relationship)
57 | indexed_res =
58 | loaded_data.index_by { |resource| resource[relationship.field.to_s] }
59 | ids.map { |id| indexed_res[id] }
60 | end
61 |
62 | sig { override.returns(Integer) }
63 | def complexity
64 | 5
65 | end
66 |
67 | sig do
68 | override
69 | .params(
70 | dto: T::Hash[Symbol, T.untyped],
71 | ids: T::Array[T.any(String, Integer)],
72 | rel: Relationship,
73 | _parent_resource: T.nilable(Resource)
74 | )
75 | .returns(T::Hash[Symbol, T.untyped])
76 | end
77 | def prepare_dto(dto, ids, rel, _parent_resource)
78 | dto[rel.field.to_s.pluralize.to_sym] = ids.compact
79 | dto
80 | end
81 |
82 | sig { override.returns(Symbol) }
83 | def relationship_field_name
84 | field.to_s.pluralize.to_sym
85 | end
86 | end
87 | end
88 | end
89 |
--------------------------------------------------------------------------------
/lib/resource_registry/repositories/base.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: false
3 |
4 | require_relative "../../runtime_generic"
5 | require_relative "../serializer"
6 |
7 | module ResourceRegistry
8 | module Repositories
9 | module Base
10 | extend T::Sig
11 | extend T::Helpers
12 | extend T::Generic
13 | # CAUTION This is not supported by sorbet, consider using T::Generic
14 | # instead if yo don't need to preserve generic runtime information
15 | extend RuntimeGeneric
16 |
17 | include Kernel
18 |
19 | abstract!
20 |
21 | Entity = type_member { { upper: T::Struct } }
22 |
23 | sig { returns(T.untyped) }
24 | def self.entity
25 | T.unsafe(const_get(:Entity)).inner_type[:fixed]
26 | end
27 |
28 | sig do
29 | overridable
30 | .params(dto: T.untyped, context: T.untyped)
31 | .returns(T.untyped)
32 | end
33 | def read(dto:, context:)
34 | raise_error(__method__)
35 | end
36 |
37 | sig do
38 | overridable
39 | .params(entity: Entity, tags: T::Set[T.untyped])
40 | .returns(T::Hash[Symbol, T.untyped])
41 | end
42 | def serialize(entity:, tags: [])
43 | serializer.serialize(entity: entity, tags: tags)
44 | end
45 |
46 | sig(:final) { returns(String) }
47 | def self.namespace
48 | namespace = to_s.split("::Repositories").first
49 | return T.must(namespace).sub("::", "") if namespace != to_s
50 |
51 | T.must(to_s.split("::").first)
52 | end
53 |
54 | sig(:final) { returns(String) }
55 | def self.resource_name
56 | T.must(to_s.split("::").last)
57 | end
58 |
59 | private
60 |
61 | sig { returns(ResourceRegistry::Serializer) }
62 | def serializer
63 | @serializer ||=
64 | T.let(
65 | ResourceRegistry::Serializer.new(
66 | resource: T.must(self.class.resource)
67 | ),
68 | T.nilable(ResourceRegistry::Serializer)
69 | )
70 | end
71 |
72 | sig { params(method: T.nilable(Symbol)).returns(T.noreturn) }
73 | def raise_error(method)
74 | raise NotImplementedError,
75 | "#{method} must be implemented in #{self.class} repository"
76 | end
77 | end
78 | end
79 | end
80 |
--------------------------------------------------------------------------------
/lib/resource_registry/serializer.rb:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | module ResourceRegistry
4 | class Serializer
5 | extend T::Sig
6 |
7 | # Maybe this should be a generic?
8 | sig { params(resource: Resource).void }
9 | def initialize(resource:)
10 | @resource = resource
11 | end
12 |
13 | sig do
14 | params(entity: T::Struct, tags: T::Set[Symbol]).returns(
15 | T::Hash[Symbol, T.untyped]
16 | )
17 | end
18 | def serialize(entity:, tags:)
19 | entity_methods = Set.new(entity.methods)
20 |
21 | resource_schema
22 | .properties
23 | .each_with_object({}) do |property, acc|
24 | # If property has serialization groups and they are not included in the tags this property is skipped
25 | if property.serialization_groups.any? &&
26 | (property.serialization_groups & tags).none?
27 | next
28 | end
29 |
30 | property_value =
31 | if entity_methods.include?(property.name.to_sym)
32 | entity.send(property.name)
33 | elsif property.resolvable &&
34 | (property.resolver&.values&.size || 0) > 1
35 | # Review all this mess with resolvers
36 | property
37 | .resolver
38 | &.map { |_, value| entity.send(value) }
39 | &.join(" ")
40 | else
41 | next
42 | end
43 |
44 | acc[property.name.to_sym] = recursive_serialization(property_value)
45 | end
46 | end
47 |
48 | private
49 |
50 | sig { params(property_value: T.untyped).returns(T.untyped) }
51 | def recursive_serialization(property_value)
52 | if property_value.is_a?(Array)
53 | return property_value.map { |pv| recursive_serialization(pv) }
54 | end
55 |
56 | if property_value.respond_to?(:serialize, false)
57 | property_value.serialize
58 | else
59 | property_value
60 | end
61 | end
62 |
63 | sig { returns(SchemaRegistry::Schema) }
64 | def resource_schema
65 | @resource.schema
66 | end
67 | end
68 | end
69 |
--------------------------------------------------------------------------------
/lib/resource_registry/verb.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: strict
3 |
4 | require_relative "../schema_registry/schema"
5 |
6 | module ResourceRegistry
7 | # This is the representation of a verb over a resource. Each resource can
8 | # have multiple verbs that should be exposed by its repository
9 | class Verb < T::Struct
10 | extend T::Sig
11 |
12 | DtoClassNotFound = Class.new(StandardError)
13 |
14 | const :id, Symbol
15 | const :dto_raw, String
16 | const :summary, T.nilable(String), default: nil
17 | const :description, T.nilable(String), default: nil
18 | const :deprecated_on, T.nilable(Date), default: nil
19 | const :webhook_description, T.nilable(String), default: nil
20 | const :schema, SchemaRegistry::Schema
21 | const :return_many, T::Boolean, default: false
22 |
23 | sig { returns(Symbol) }
24 | def schema_identifier
25 | @schema_identifier ||=
26 | T.let(:"#{id.to_s.underscore}_dto", T.nilable(Symbol))
27 | end
28 |
29 | sig { returns(T::Boolean) }
30 | def deprecated?
31 | return false if deprecated_on.blank?
32 |
33 | T.must(deprecated_on) < Time.zone.today
34 | end
35 |
36 | sig { returns(T::Boolean) }
37 | def mutation?
38 | destroy? || update? || create?
39 | end
40 |
41 | sig { returns(T::Boolean) }
42 | def get?
43 | %i[find show read].include? id
44 | end
45 |
46 | sig { returns(T::Boolean) }
47 | def destroy?
48 | id == :delete
49 | end
50 |
51 | sig { returns(T::Boolean) }
52 | def update?
53 | id == :update
54 | end
55 |
56 | sig { returns(T::Boolean) }
57 | def create?
58 | id == :create
59 | end
60 |
61 | sig { returns(T.class_of(T::Struct)) }
62 | def dto
63 | dto_klass = dto_raw.safe_constantize
64 |
65 | if dto_klass.nil?
66 | raise DtoClassNotFound, "DTO class #{dto_raw} for verb #{id} not found"
67 | end
68 |
69 | dto_klass
70 | end
71 |
72 | sig { returns(T::Hash[Symbol, T.untyped]) }
73 | def dump
74 | {}.tap do |result|
75 | result["id"] = id
76 | result["dto"] = dto.to_s
77 | result["schema"] = schema.dump
78 | result["return_many"] = return_many
79 | end
80 | end
81 |
82 | sig { params(spec: T.untyped).returns(Verb) }
83 | def self.load(spec)
84 | id = spec["id"]&.to_sym
85 | raise ArgumentError, "Missing verb ID: #{id}" if id.nil?
86 |
87 | dto = spec["dto"]
88 | raise ArgumentError, "DTO for verb #{id} not found" if dto.nil?
89 |
90 | new(
91 | id: id,
92 | dto_raw: dto,
93 | schema: SchemaRegistry::Schema.load(spec["schema"]),
94 | summary: spec["summary"],
95 | return_many: spec["return_many"],
96 | description: spec["description"],
97 | webhook_description: spec["webhook_description"]
98 | )
99 | end
100 | end
101 | end
102 |
--------------------------------------------------------------------------------
/lib/resource_registry/versions.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 |
3 | module ResourceRegistry
4 | class Versions
5 | extend T::Sig
6 | extend T::Helpers
7 |
8 | sig { params(versions: T::Array[Version]).void }
9 | def initialize(versions:)
10 | @versions = versions
11 | end
12 |
13 | sig { params(name: T.nilable(String)).returns(T.nilable(Version)) }
14 | def find(name)
15 | return if name.blank?
16 |
17 | versions.find { |version| version.matches?(name) }
18 | end
19 |
20 | sig { params(name: String).returns(Version) }
21 | def find!(name)
22 | find(name) || raise("Version '#{name}' not found")
23 | end
24 |
25 | sig do
26 | params(name_or_version: T.any(String, Version)).returns(
27 | T.nilable(Version)
28 | )
29 | end
30 | def find_next(name_or_version)
31 | version =
32 | name_or_version.is_a?(String) ? find!(name_or_version) : name_or_version
33 | index = T.must(sorted_versions.index(version))
34 |
35 | sorted_versions[index + 1]
36 | end
37 |
38 | sig { returns(T::Array[Version]) }
39 | def sorted_versions
40 | versions.sort
41 | end
42 |
43 | sig do
44 | params(from: T.nilable(String), to: T.nilable(String)).returns(
45 | T::Array[ResourceRegistry::Versions::Version]
46 | )
47 | end
48 | def in_range(from, to)
49 | from = find!(from) unless from.nil?
50 | to = find!(to) unless to.nil?
51 | versions.select do |version|
52 | (from.nil? || version >= from) && (to.nil? || version <= to)
53 | end
54 | end
55 |
56 | private
57 |
58 | sig { returns(T::Array[Version]) }
59 | attr_reader :versions
60 | end
61 | end
62 |
--------------------------------------------------------------------------------
/lib/resource_registry/versions/version.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 |
3 | module ResourceRegistry
4 | class Versions
5 | class Version
6 | extend T::Sig
7 |
8 | sig do
9 | params(
10 | name: String,
11 | aliases: T.nilable(T.any(String, T::Array[String]))
12 | ).void
13 | end
14 | def initialize(name, aliases: nil)
15 | @name = name
16 | @aliases = T.let(Array(aliases), T::Array[String])
17 | end
18 |
19 | sig { returns(String) }
20 | attr_reader :name
21 |
22 | sig { returns(T::Array[String]) }
23 | attr_reader :aliases
24 |
25 | sig { returns(String) }
26 | def to_s
27 | name
28 | end
29 |
30 | sig { params(str: String).returns(T::Boolean) }
31 | def matches?(str)
32 | [name, *aliases].include?(str)
33 | end
34 |
35 | sig { params(other: Version).returns(T.nilable(Integer)) }
36 | def <=>(other)
37 | name <=> other.name
38 | end
39 |
40 | sig { params(other: Version).returns(T::Boolean) }
41 | def >=(other)
42 | name >= other.name
43 | end
44 |
45 | sig { params(other: Version).returns(T::Boolean) }
46 | def <=(other)
47 | name <= other.name
48 | end
49 | end
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/lib/runtime_generic.rb:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # This module allows using type introspection to serialize/deserialize custom generics in
4 | # T::Structs.
5 | #
6 | # While Sorbet can answer questions about types in T::Structs and arrays, it erases generic types
7 | # at runtime. To support custom generics, we must manually preserve the type information with
8 | # which they were declared.
9 | #
10 | # Use this module instead of `T::Generic` to create generic types with runtime type information.
11 | module RuntimeGeneric
12 | extend T::Helpers
13 | extend T::Sig
14 | include T::Generic
15 |
16 | class TypedGeneric < T::Types::Simple
17 | extend T::Sig
18 |
19 | def name
20 | "#{raw_type.name}[#{inner_type.name}]"
21 | end
22 |
23 | def initialize(raw_type, inner_type)
24 | super(raw_type)
25 | @inner_type = inner_type
26 | end
27 |
28 | attr_reader :inner_type
29 | end
30 |
31 | class MyTypeMember < T::Types::TypeMember
32 | def initialize(variance, &type_proc)
33 | super(variance)
34 | @type_proc = type_proc
35 | end
36 |
37 | def inner_type
38 | @inner_type ||= @type_proc.call
39 | end
40 | end
41 |
42 | def [](inner_type)
43 | RuntimeGeneric::TypedGeneric.new(self, inner_type)
44 | end
45 |
46 | def type_member(variance = :invariant, &blk)
47 | if defined?(Tapioca::TypeVariableModule)
48 | # `T::Generic#type_member` just instantiates a `T::Type::TypeMember` instance and returns it.
49 | # We use that when registering the type member and then later return it from this method.
50 | return(
51 | Tapioca::TypeVariableModule
52 | .new(
53 | T.cast(self, Module),
54 | Tapioca::TypeVariableModule::Type::Member,
55 | variance,
56 | blk
57 | )
58 | .tap do |type_variable|
59 | Tapioca::Runtime::GenericTypeRegistry.register_type_variable(
60 | self,
61 | type_variable
62 | )
63 | end
64 | )
65 | end
66 |
67 | MyTypeMember.new(variance, &blk)
68 | end
69 | end
70 |
--------------------------------------------------------------------------------
/lib/schema_registry/README.md:
--------------------------------------------------------------------------------
1 | # Schema registry
2 |
3 | A json-schema based registry
4 |
5 | ## Features
6 |
7 | - Versioning
8 | - Unneeded version blocking through CI/CD
9 | - Required version blocking through CI/CD
10 | - Lifecycle / States: Dead, Stable, Next (alpha/beta)
11 | - `schema_registry version:bump employee`
12 | - Track version usage to clean up unused deprecated versions
13 | - Typing (?) -> Sorbet
14 | - Validation
15 |
16 | ## What is an schema?
17 |
18 | - Metadata (generated files, similar to RBI generation)
19 |
20 | - Last stable json-schema
21 | - Last unstable tag
22 |
23 | - Schema itself (json-schema)
24 |
25 | ## Adding a new schema
26 |
27 | Just drop a json-schema formatted in YAML into your-component/app/schemas
28 | folder and the SchemaRegistry system will load it automatically into the
29 | registry for you.
30 |
31 | ## Generating RBIs from schemas
32 |
33 | ```bash
34 | bin/rails schema_registry:generate_rbis
35 | ```
36 |
37 | ## Generate a json-schema representation of a T::Struct
38 |
39 | This is specially useful when you need to define the initial version of a
40 | json-schema for an entity or DTO since both are usually defined with
41 | `T::Struct`.
42 |
43 | ```bash
44 | bin/rails "schema_registry:generate_schema_from_struct[Ats::Entities::JobPosting]"
45 | ```
46 |
47 | ## What abstractions can use schemas?
48 |
49 | - DTOs (Repositories parameters shape)
50 | - Entities
51 | - Events
52 |
53 | ## To research
54 |
55 | - [JSON-ld](https://json-ld.org/)
56 |
--------------------------------------------------------------------------------
/lib/schema_registry/filter_field.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 |
3 | module SchemaRegistry
4 | class FilterField < T::Struct
5 | extend T::Sig
6 |
7 | const :name, String
8 | const :resolver, T.nilable(T::Hash[Symbol, String])
9 | const :type, PropertyType
10 | const :in_memory, T::Boolean, default: false
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/lib/schema_registry/json_schema_mapper.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 |
3 | module SchemaRegistry
4 | class JsonSchemaMapper
5 | extend T::Sig
6 |
7 | class UnrecognizedJsonSchemaTypeError < StandardError
8 | end
9 |
10 | DATE_FIELDS = T.let(%w[date-time date].freeze, T::Array[String])
11 |
12 | # TODO: Proper type json-schema
13 | sig { params(namespace: String, definition: T.untyped).void }
14 | def initialize(namespace:, definition:)
15 | @namespace = namespace
16 | @definition = definition
17 | end
18 |
19 | sig { returns(Schema) }
20 | def call
21 | key = definition.keys.first
22 |
23 | properties =
24 | handle_properties(
25 | definition[key]["properties"],
26 | definition[key]["required"]
27 | )
28 |
29 | Schema.new(
30 | name: key,
31 | namespace: namespace,
32 | properties: properties || [],
33 | raw_json_schema: definition,
34 | additional_filter_fields:
35 | handle_fields(definition[key]["additional_filter_fields"])
36 | )
37 | end
38 |
39 | private
40 |
41 | sig { returns(T.untyped) }
42 | attr_reader :definition
43 |
44 | sig { returns(String) }
45 | attr_reader :namespace
46 |
47 | sig do
48 | params(items: T.nilable(T::Hash[T.untyped, T.untyped])).returns(
49 | T::Array[SchemaRegistry::Property]
50 | )
51 | end
52 | def handle_items(items)
53 | return [] if items.nil?
54 |
55 | types = handle_types(items["type"], items["format"])
56 |
57 | [
58 | SchemaRegistry::Property.new(
59 | name: "",
60 | types: types,
61 | type_name: items["typedef"].to_s,
62 | items: handle_items(items["items"]),
63 | enum_values: items.dig("items", "enum") || items["enum"],
64 | default: items["default"],
65 | properties:
66 | handle_properties(items["properties"], items["required"]) || [],
67 | required: types.exclude?(SchemaRegistry::PropertyType::Null)
68 | )
69 | ]
70 | end
71 |
72 | sig do
73 | params(input: T.nilable(T::Array[T::Hash[String, T.untyped]])).returns(
74 | T::Array[FilterField]
75 | )
76 | end
77 | def handle_fields(input)
78 | return [] if input.nil?
79 |
80 | input.map do |obj|
81 | FilterField.new(
82 | name: obj["name"],
83 | resolver: handle_resolver(obj["resolver"] || obj["field"]),
84 | type: type_to_sorbet(obj["type"], nil),
85 | in_memory: obj["in_memory"] == true
86 | )
87 | end
88 | end
89 |
90 | sig do
91 | params(
92 | properties: T.nilable(T::Hash[T.untyped, T.untyped]),
93 | required: T.nilable(T::Array[String])
94 | ).returns(T.nilable(T::Array[SchemaRegistry::Property]))
95 | end
96 | def handle_properties(properties, required)
97 | properties&.map do |key, value|
98 | enum_values =
99 | (value.dig("items", "enum") || value["enum"] || []).map do |v|
100 | next v if v.is_a?(String)
101 |
102 | v.serialize
103 | end
104 |
105 | default =
106 | if enum_values.any? && value["default"].kind_of?(Array)
107 | # Handle arrays
108 | value["default"]&.map do |v|
109 | next v if v.is_a?(String)
110 |
111 | v.serialize
112 | end
113 | else
114 | value["default"]
115 | end
116 |
117 | SchemaRegistry::Property.new(
118 | name: key,
119 | types: handle_types(value["type"], value["format"]),
120 | type_name: value["typedef"].to_s,
121 | items: handle_items(value["items"]),
122 | example: value["example"],
123 | description: value["description"],
124 | enum_values: enum_values,
125 | default: default,
126 | resolver: handle_resolver(value["resolver"]),
127 | resolvable: !value["resolvable"].nil? && value["resolvable"],
128 | properties:
129 | handle_properties(value["properties"], value["required"]) || [],
130 | required: required ? required.include?(key) : false,
131 | serialization_groups:
132 | handle_serialization_groups(value["serialization_groups"])
133 | )
134 | end
135 | end
136 |
137 | sig do
138 | params(
139 | prop_type: T.any(String, T::Array[String]),
140 | format: T.nilable(String)
141 | ).returns(T::Array[PropertyType])
142 | end
143 | def handle_types(prop_type, format)
144 | Array(prop_type).map { |type| type_to_sorbet(type, format) }
145 | end
146 |
147 | sig do
148 | params(prop_type: T.any(String, T::Array[String])).returns(T::Boolean)
149 | end
150 | def nilable?(prop_type)
151 | return false unless prop_type.is_a?(Array)
152 |
153 | prop_type.include?("null")
154 | end
155 |
156 | sig do
157 | params(
158 | resolver: T.any(NilClass, String, T::Hash[Symbol, String])
159 | ).returns(T.nilable(T::Hash[Symbol, String]))
160 | end
161 | def handle_resolver(resolver)
162 | if resolver.is_a?(String)
163 | { all: resolver }
164 | elsif resolver.present?
165 | resolver.symbolize_keys
166 | end
167 | end
168 |
169 | sig do
170 | params(serialization_groups: T.any(NilClass, T::Array[String])).returns(
171 | T::Set[Symbol]
172 | )
173 | end
174 | def handle_serialization_groups(serialization_groups)
175 | return Set[] if serialization_groups.blank?
176 |
177 | serialization_groups.compact.to_set(&:to_sym)
178 | end
179 |
180 | sig do
181 | params(
182 | json_schema_type: T.nilable(String),
183 | format: T.nilable(String)
184 | ).returns(PropertyType)
185 | end
186 | def type_to_sorbet(json_schema_type, format)
187 | case json_schema_type
188 | when "string"
189 | string_format_to_sorbet(format)
190 | when "number"
191 | PropertyType::Number
192 | when "integer"
193 | if format == "big"
194 | PropertyType::BigInteger
195 | else
196 | PropertyType::Integer
197 | end
198 | when "boolean"
199 | PropertyType::Boolean
200 | when "null"
201 | PropertyType::Null
202 | when "array"
203 | PropertyType::Array
204 | when "object"
205 | PropertyType::Object
206 | else
207 | raise UnrecognizedJsonSchemaTypeError,
208 | "unrecognized type #{json_schema_type}"
209 | end
210 | end
211 |
212 | sig { params(format: T.nilable(String)).returns(PropertyType) }
213 | def string_format_to_sorbet(format)
214 | case format
215 | when "date-time"
216 | PropertyType::DateTime
217 | when "time"
218 | PropertyType::Time
219 | when "date"
220 | PropertyType::Date
221 | when "duration"
222 | PropertyType::Duration
223 | when "email"
224 | PropertyType::Email
225 | when "uri"
226 | PropertyType::Uri
227 | when "regex"
228 | PropertyType::Regex
229 | when "binary"
230 | PropertyType::File
231 | else
232 | PropertyType::String
233 | end
234 | end
235 | end
236 | end
237 |
--------------------------------------------------------------------------------
/lib/schema_registry/maybe.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 | # frozen_string_literal: true
3 |
4 | require_relative("../runtime_generic")
5 | require_relative("maybe/absent")
6 | require_relative("maybe/present")
7 |
8 | # Represents an instance of an object that may or may not be present. This can be useful in certain
9 | # cases where `nil` represents a valid value instead of an absent value, i.e. update DTOs.
10 | #
11 | # An useful way to think about `Maybe` is as a collection, like `Array` or `Set` but that can only
12 | # hold a maximum of 1 elements at a time.
13 | module Maybe
14 | extend T::Sig
15 | extend T::Helpers
16 | extend RuntimeGeneric
17 | include Kernel
18 | interface!
19 | # NOTE: Beware of implementing a `Maybe#value` method in the interface so you can call it without
20 | # type safety. >:(
21 |
22 | Value = type_member(:out) { { upper: BasicObject } }
23 |
24 | sig do
25 | type_parameters(:Key)
26 | .params(input: T::Hash[T.type_parameter(:Key), T.untyped])
27 | .returns(T::Hash[T.type_parameter(:Key), T.untyped])
28 | end
29 | # You can use this method to easily transform a Hash with `Maybe` values into one without them,
30 | # filtering out `Maybe` instances that are empty and unwrapping the present ones.
31 | #
32 | # Given a hash containing `Maybe` instances, returns a hash with only the values that are present.
33 | # It also unwraps the present values.
34 | #
35 | # For convenience, it also recursively serializes nested T::Structs and strips nested hashes,
36 | # arrays and sets.
37 | #
38 | # ```ruby
39 | # Maybe.strip({ a: Maybe.from(1), b: Maybe.empty, c: Maybe.from(3) })
40 | # # => { a: 1, c: 3 }
41 | # ```
42 | def self.strip(input) # rubocop:disable Metrics/PerceivedComplexity
43 | input
44 | .reject { |_key, value| value == Maybe.empty }
45 | .to_h do |key, value|
46 | unwrapped = value.is_a?(Maybe::Present) ? value.value : value
47 | enumerated =
48 | if unwrapped.is_a?(Array) || unwrapped.is_a?(Set)
49 | unwrapped.map do |v|
50 | v.is_a?(T::Struct) ? Maybe.strip(v.serialize) : Maybe.strip(v)
51 | end
52 | else
53 | unwrapped
54 | end
55 | serialized =
56 | enumerated.is_a?(T::Struct) ? enumerated.serialize : enumerated
57 | stripped = serialized.is_a?(Hash) ? Maybe.strip(serialized) : serialized
58 |
59 | [key, stripped]
60 | end
61 | end
62 |
63 | sig { returns(Absent) }
64 | # Creates an empty instance.
65 | def self.empty
66 | Absent.new
67 | end
68 |
69 | sig { returns(Absent) }
70 | # Creates an empty instance.
71 | # Alias for self.empty
72 | def self.none
73 | empty
74 | end
75 |
76 | sig { returns(Absent) }
77 | # Creates an empty instance.
78 | # Alias for self.empty
79 | def self.absent
80 | empty
81 | end
82 |
83 | sig do
84 | type_parameters(:Value)
85 | .params(value: T.all(BasicObject, T.type_parameter(:Value)))
86 | .returns(Maybe[T.all(BasicObject, T.type_parameter(:Value))])
87 | end
88 | # Creates an instance containing the specified value.
89 | # Necessary to make this work with sorbet-coerce
90 | def self.new(value)
91 | from(value)
92 | end
93 |
94 | sig do
95 | type_parameters(:Value)
96 | .params(value: T.all(BasicObject, T.type_parameter(:Value)))
97 | .returns(Maybe[T.all(BasicObject, T.type_parameter(:Value))])
98 | end
99 | # Creates an instance containing the specified value.
100 | def self.from(value)
101 | Present[T.all(BasicObject, T.type_parameter(:Value))].new(value)
102 | end
103 |
104 | sig { abstract.returns(T::Boolean) }
105 | # `true` if this `Maybe` contains a value, `false` otherwise.
106 | def present?
107 | end
108 |
109 | sig { abstract.returns(T::Boolean) }
110 | # `true` if this `Maybe` does not contain a value, `false` otherwise.
111 | def absent?
112 | end
113 |
114 | sig { abstract.returns(T::Boolean) }
115 | # `true` if this `Maybe` does not contain a value, `false` otherwise.
116 | #
117 | # alias of `#absent`
118 | def empty?
119 | end
120 |
121 | sig do
122 | abstract
123 | .type_parameters(:Default)
124 | .params(default: T.type_parameter(:Default))
125 | .returns(T.any(Value, T.type_parameter(:Default)))
126 | end
127 | # Returns the value if there's one, else, it returns the provided default.
128 | def or_default(default)
129 | end
130 |
131 | sig do
132 | abstract
133 | .type_parameters(:Return)
134 | .params(
135 | _block: T.proc.params(v: Value).returns(T.type_parameter(:Return))
136 | )
137 | .returns(T.nilable(T.type_parameter(:Return)))
138 | end
139 | # Executes the given code block if there's a value present, the code block will receive the value
140 | # as an argument and the method will return whatever the code block returns or `nil` if no value
141 | # present.
142 | def when_present(&_block)
143 | end
144 |
145 | sig do
146 | abstract
147 | .type_parameters(:Return)
148 | .params(_block: T.proc.returns(T.type_parameter(:Return)))
149 | .returns(T.nilable(T.type_parameter(:Return)))
150 | end
151 | # Executes the given code block if a value isn't present, returns whatever the code block returned
152 | # or `nil` if if the value was present.
153 | def when_absent(&_block)
154 | end
155 |
156 | sig do
157 | abstract
158 | .params(_block: T.proc.params(value: Value).returns(T::Boolean))
159 | .returns(Maybe[Value])
160 | end
161 | # Evaluate the specified block passing it the value if one is present, if the block returns true,
162 | # returns an instance containing the same value, if the block returns false, returns an empty
163 | # instance. If the instance is already empty, it returns an empty instance and the block is not
164 | # evaluated.
165 | #
166 | # This is analogous to the `Array#filter` method if the `Maybe` class were an `Array` that can
167 | # hold one element at maximum.
168 | def filter(&_block)
169 | end
170 |
171 | sig do
172 | abstract
173 | .type_parameters(:Default)
174 | .params(
175 | _block:
176 | T
177 | .proc
178 | .params(value: Value)
179 | .returns(T.all(BasicObject, T.type_parameter(:Default)))
180 | )
181 | .returns(Maybe[T.all(BasicObject, T.type_parameter(:Default))])
182 | end
183 | # Evaluate the specified block passing it the value if one is present, returns an instance
184 | # containing the result of the evaluation. If no element is present, returns an empty instance.
185 | #
186 | # This is analogous to the `Array#map` method if the `Maybe` class were an `Array` that can
187 | # hold one element at maximum.
188 | def map(&_block)
189 | end
190 | end
191 |
--------------------------------------------------------------------------------
/lib/schema_registry/maybe/absent.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 | # frozen_string_literal: true
3 |
4 | module Maybe
5 | # Class used to represent the empty case
6 | class Absent
7 | extend T::Sig
8 | extend T::Generic
9 | include Maybe
10 | # final! FIXME
11 |
12 | Value = type_member { { fixed: T.noreturn } }
13 |
14 | sig(:final) { override.returns(FalseClass) }
15 | def present?
16 | false
17 | end
18 |
19 | sig(:final) { override.returns(TrueClass) }
20 | def absent?
21 | true
22 | end
23 |
24 | sig(:final) { override.returns(TrueClass) }
25 | def empty?
26 | absent?
27 | end
28 |
29 | sig(:final) do
30 | override
31 | .type_parameters(:Default)
32 | .params(default: T.type_parameter(:Default))
33 | .returns(T.type_parameter(:Default))
34 | end
35 | def or_default(default)
36 | default
37 | end
38 |
39 | sig(:final) do
40 | override
41 | .type_parameters(:Return)
42 | .params(
43 | _block: T.proc.params(v: Value).returns(T.type_parameter(:Return))
44 | )
45 | .returns(T.nilable(T.type_parameter(:Return)))
46 | end
47 | def when_present(&_block)
48 | nil
49 | end
50 |
51 | sig(:final) do
52 | override
53 | .type_parameters(:Return)
54 | .params(_block: T.proc.returns(T.type_parameter(:Return)))
55 | .returns(T.nilable(T.type_parameter(:Return)))
56 | end
57 | def when_absent(&_block)
58 | yield
59 | end
60 |
61 | sig(:final) do
62 | override
63 | .params(_block: T.proc.params(value: Value).returns(T::Boolean))
64 | .returns(Maybe[Value])
65 | end
66 | def filter(&_block)
67 | self
68 | end
69 |
70 | sig(:final) do
71 | override
72 | .type_parameters(:Default)
73 | .params(
74 | _block:
75 | T.proc.params(value: Value).returns(T.type_parameter(:Default))
76 | )
77 | .returns(Maybe[T.all(BasicObject, T.type_parameter(:Default))])
78 | end
79 | def map(&_block)
80 | self
81 | end
82 |
83 | sig(:final) { override.params(other: BasicObject).returns(T::Boolean) }
84 | def ==(other)
85 | self.class === other # rubocop:disable Style/CaseEquality
86 | end
87 | end
88 | end
89 |
--------------------------------------------------------------------------------
/lib/schema_registry/maybe/present.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 | # frozen_string_literal: true
3 |
4 | module Maybe
5 | # Class used to represent the case when a value is available
6 | class Present
7 | extend T::Sig
8 | extend T::Generic
9 | include Maybe
10 | # final! FIXME
11 |
12 | Value = type_member(:out) { { upper: BasicObject } }
13 |
14 | sig(:final) { params(value: Value).void }
15 | def initialize(value)
16 | @value = value
17 | end
18 |
19 | sig(:final) { override.returns(TrueClass) }
20 | def present?
21 | true
22 | end
23 |
24 | sig(:final) { override.returns(FalseClass) }
25 | def absent?
26 | false
27 | end
28 |
29 | sig(:final) { override.returns(FalseClass) }
30 | def empty?
31 | absent?
32 | end
33 |
34 | sig(:final) do
35 | override
36 | .type_parameters(:Default)
37 | .params(_default: T.type_parameter(:Default))
38 | .returns(Value)
39 | end
40 | def or_default(_default)
41 | value
42 | end
43 |
44 | sig(:final) do
45 | override
46 | .type_parameters(:Return)
47 | .params(
48 | _block: T.proc.params(v: Value).returns(T.type_parameter(:Return))
49 | )
50 | .returns(T.nilable(T.type_parameter(:Return)))
51 | end
52 | def when_present(&_block)
53 | yield value
54 | end
55 |
56 | sig(:final) do
57 | override
58 | .type_parameters(:Return)
59 | .params(_block: T.proc.returns(T.type_parameter(:Return)))
60 | .returns(T.nilable(T.type_parameter(:Return)))
61 | end
62 | def when_absent(&_block)
63 | nil
64 | end
65 |
66 | sig(:final) do
67 | override
68 | .params(_block: T.proc.params(value: Value).returns(T::Boolean))
69 | .returns(Maybe[Value])
70 | end
71 | def filter(&_block)
72 | return self if yield value
73 |
74 | Absent.new
75 | end
76 |
77 | sig(:final) do
78 | override
79 | .type_parameters(:Default)
80 | .params(
81 | _block:
82 | T
83 | .proc
84 | .params(value: Value)
85 | .returns(T.all(BasicObject, T.type_parameter(:Default)))
86 | )
87 | .returns(Maybe[T.all(BasicObject, T.type_parameter(:Default))])
88 | end
89 | def map(&_block)
90 | mapped = yield value
91 | Present[T.all(BasicObject, T.type_parameter(:Default))].new(mapped)
92 | end
93 |
94 | sig(:final) { override.params(other: BasicObject).returns(T::Boolean) }
95 | def ==(other)
96 | return false unless self.class === other # rubocop:disable Style/CaseEquality
97 |
98 | value == other.value
99 | end
100 |
101 | sig(:final) { returns(Value) }
102 | attr_reader :value
103 | end
104 | end
105 |
--------------------------------------------------------------------------------
/lib/schema_registry/property.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: strict
3 |
4 | require "date"
5 | require "bigdecimal"
6 | require_relative "property_type"
7 | require_relative "maybe"
8 | require_relative "../resource_registry/versions/version"
9 |
10 | module SchemaRegistry
11 | class Property < T::Struct
12 | extend T::Sig
13 |
14 | ValueType =
15 | T.type_alias do
16 | T.nilable(
17 | T.any(
18 | T::Boolean,
19 | Integer,
20 | Float,
21 | BigDecimal,
22 | String,
23 | Date,
24 | Time,
25 | DateTime,
26 | T::Array[T.untyped],
27 | T::Hash[String, T.untyped],
28 | Maybe[T.untyped],
29 | ResourceRegistry::Versions::Version
30 | )
31 | )
32 | end
33 |
34 | const :name, String
35 | const :types, T::Array[PropertyType]
36 | const :type_name, T.nilable(String)
37 | const :items, T::Array[Property], default: []
38 | const :properties, T::Array[Property], default: []
39 | const :description, T.nilable(String), default: nil
40 | const :resolver, T.nilable(T::Hash[Symbol, String]), default: nil
41 | const :resolvable, T::Boolean, default: false
42 | const :deprecated, T::Boolean, default: false
43 | const :deprecated_on, T.nilable(Date), default: nil
44 | const :example, T.nilable(ValueType), default: nil
45 | const :enum_values, T.nilable(T::Array[String]), default: []
46 | const :required, T::Boolean
47 | const :default, ValueType, default: nil
48 | const :serialization_groups, T::Set[Symbol], default: Set[]
49 |
50 | sig { returns(T::Boolean) }
51 | def deprecated?
52 | return false if deprecated_on.blank?
53 |
54 | T.must(deprecated_on) < Time.zone.today
55 | end
56 |
57 | sig { returns(T::Boolean) }
58 | def null?
59 | @types == [PropertyType::Null]
60 | end
61 |
62 | sig { returns(T::Array[PropertyType]) }
63 | def types
64 | return @types if null?
65 |
66 | @types - [PropertyType::Null]
67 | end
68 |
69 | sig { returns(T::Boolean) }
70 | def nilable?
71 | return false if null?
72 |
73 | @types.include?(PropertyType::Null)
74 | end
75 |
76 | sig { returns(T::Boolean) }
77 | def required?
78 | required
79 | end
80 |
81 | sig { returns(T::Boolean) }
82 | def enum?
83 | enum_values.present?
84 | end
85 |
86 | sig { returns(T::Boolean) }
87 | def value_object?
88 | !!type_name.to_s.split("::").any?("ValueObjects")
89 | end
90 |
91 | sig { params(group: Symbol).returns(T::Boolean) }
92 | def serialization_group?(group)
93 | serialization_groups.include?(group)
94 | end
95 | end
96 | end
97 |
--------------------------------------------------------------------------------
/lib/schema_registry/property_mapper.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 |
3 | module SchemaRegistry
4 | class PropertyMapper
5 | extend T::Sig
6 |
7 | # TODO: Proper type json-schema
8 | sig { params(schema: Schema).void }
9 | def initialize(schema:)
10 | @schema = schema
11 | end
12 |
13 | sig { returns(T::Hash[String, T.untyped]) }
14 | def call
15 | schema
16 | .properties
17 | .each_with_object({}) do |property, memo|
18 | json_type = sorbet_to_json_schema(property)
19 | json_type = ["null", json_type] if property.nilable?
20 |
21 | memo[property.name] = { "type" => json_type }
22 | end
23 | end
24 |
25 | private
26 |
27 | sig { returns(Schema) }
28 | attr_reader :schema
29 |
30 | sig { params(property: Property).returns(T.untyped) }
31 | def sorbet_to_json_schema(property)
32 | properties = property.types.map(&:serialize)
33 |
34 | return "integer" if properties.include?("integer")
35 | return "boolean" if properties.include?("boolean")
36 | return "number" if properties.include?("number")
37 |
38 | "string"
39 | end
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/lib/schema_registry/property_type.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 |
3 | module SchemaRegistry
4 | extend T::Sig
5 |
6 | class PropertyType < T::Enum
7 | extend T::Sig
8 |
9 | enums do
10 | # Basic types
11 | String = new
12 | Number = new
13 | Integer = new
14 | BigInteger = new
15 | Object = new
16 | Array = new
17 | Boolean = new
18 | Null = new
19 |
20 | # String format specializations
21 | DateTime = new
22 | Time = new
23 | Date = new
24 | Duration = new
25 | Email = new
26 | Uri = new
27 | Regex = new
28 |
29 | # Other
30 | File = new
31 | end
32 |
33 | sig { returns(T.nilable(::String)) }
34 | # rubocop:disable Metrics/CyclomaticComplexity
35 | def sorbet_type
36 | case self
37 | when String
38 | "String"
39 | when Number
40 | "Float"
41 | when Integer, BigInteger
42 | "Integer"
43 | when Object
44 | "T::Hash[Symbol, T.untyped]"
45 | when Array
46 | "T::Array[T.untyped]"
47 | when Boolean
48 | "T::Boolean"
49 | when Null
50 | "NilClass"
51 | when DateTime, Time
52 | "Time"
53 | when Date
54 | "Date"
55 | when Duration
56 | "ActiveSupport::Duration"
57 | when Email
58 | "Mail::Address"
59 | when Uri
60 | "URI::Generic"
61 | when Regex
62 | "Regexp"
63 | when File
64 | "ActionDispatch::Http::UploadedFile"
65 | else
66 | T.absurd(self)
67 | end
68 | end
69 | # rubocop:enable Metrics/CyclomaticComplexity
70 | end
71 | end
72 |
--------------------------------------------------------------------------------
/lib/schema_registry/registry.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 |
3 | module SchemaRegistry
4 | class Registry
5 | extend T::Sig
6 |
7 | SchemaNotFound = Class.new(StandardError)
8 |
9 | sig { void }
10 | def initialize
11 | @schemas = T.let({}, T::Hash[Symbol, Schema])
12 | end
13 |
14 | sig { params(schema: Schema).returns(SchemaRegistry::Registry) }
15 | def register(schema)
16 | @schemas[schema.identifier] = schema
17 |
18 | self
19 | end
20 |
21 | sig do
22 | params(identifier: Symbol).returns(T.nilable(SchemaRegistry::Schema))
23 | end
24 | def fetch!(identifier)
25 | unless @schemas[identifier]
26 | raise SchemaNotFound, "Schema for #{identifier} can not be found"
27 | end
28 |
29 | @schemas[identifier]
30 | end
31 |
32 | sig do
33 | params(identifier: Symbol).returns(T.nilable(SchemaRegistry::Schema))
34 | end
35 | def fetch(identifier)
36 | @schemas[identifier]
37 | end
38 |
39 | sig { returns(T::Hash[Symbol, SchemaRegistry::Schema]) }
40 | def fetch_all
41 | @schemas
42 | end
43 |
44 | sig { returns(SchemaRegistry::Registry) }
45 | def cleanup
46 | @schemas = {}
47 |
48 | self
49 | end
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/lib/schema_registry/schema.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: strict
3 |
4 | require_relative "property"
5 | require_relative "filter_field"
6 | require_relative "property_mapper"
7 |
8 | module SchemaRegistry
9 | class Schema < T::Struct
10 | extend T::Sig
11 |
12 | const :name, String
13 | const :namespace, String
14 | const :properties, T::Array[Property]
15 | const :raw_json_schema, T::Hash[String, T.untyped], default: {}
16 | const :additional_filter_fields, T::Array[FilterField], default: []
17 |
18 | sig { returns(String) }
19 | def schema_module_name
20 | name
21 | end
22 |
23 | sig { returns(String) }
24 | def slug
25 | name.underscore
26 | end
27 |
28 | sig { returns(Symbol) }
29 | def identifier
30 | :"#{namespace.underscore}.#{slug}"
31 | end
32 |
33 | sig { returns(String) }
34 | def namespace_with_slug
35 | "#{namespace.underscore}_#{slug}"
36 | end
37 |
38 | sig { params(name: String).returns(T.nilable(Property)) }
39 | def find_property(name)
40 | properties.find { |property| property.name == name }
41 | end
42 |
43 | sig { params(name: String).returns(T.nilable(FilterField)) }
44 | def find_additional_filter_field(name)
45 | additional_filter_fields.find { |field| field.name == name }
46 | end
47 |
48 | sig { params(name: String).returns(T::Boolean) }
49 | def has_property?(name)
50 | find_property(name).present?
51 | end
52 |
53 | sig { returns(String) }
54 | def namespace_with_slug
55 | "#{namespace.underscore}_#{slug}"
56 | end
57 |
58 | sig { params(name: String).returns(T.nilable(T::Hash[Symbol, String])) }
59 | def get_resolver(name)
60 | property = find_property(name)
61 | unless property&.resolvable
62 | raise "No resolvable schema property of name #{name} exists"
63 | end
64 |
65 | property.resolver
66 | end
67 |
68 | sig { returns(T::Hash[String, T.untyped]) }
69 | def raw_json_schema
70 | return @raw_json_schema if @raw_json_schema.present?
71 |
72 | properties = PropertyMapper.new(schema: self).call
73 |
74 | { name => { "type" => "object", "properties" => properties } }
75 | end
76 |
77 | sig { returns(T::Hash[Symbol, T.untyped]) }
78 | def dump
79 | {}.tap do |result|
80 | result["namespace"] = namespace
81 | result["raw_json_schema"] = raw_json_schema
82 | end
83 | end
84 |
85 | sig { params(spec: T.untyped).returns(Schema) }
86 | def self.load(spec)
87 | JsonSchemaMapper.new(
88 | namespace: spec["namespace"],
89 | definition: spec["raw_json_schema"]
90 | ).call
91 | end
92 | end
93 | end
94 |
--------------------------------------------------------------------------------
/rbi/resource_registry.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | module Maybe
4 | sig do
5 | type_parameters(:Value)
6 | .params(value: T.all(BasicObject, T.type_parameter(:Value)))
7 | .returns(Maybe[T.all(BasicObject, T.type_parameter(:Value))])
8 | end
9 | # Creates an instance containing the specified value.
10 | # Necessary to make this work with sorbet-coerce
11 | def self.new(value); end
12 | end
13 |
--------------------------------------------------------------------------------
/resource_registry.gemspec:
--------------------------------------------------------------------------------
1 | Gem::Specification.new do |s|
2 | s.name = "resource_registry"
3 | s.version = "0.0.0"
4 | s.summary = "Resource Registry"
5 | s.description =
6 | "A declarative approach to define resources and their relationships"
7 | s.authors = ["Genar Trias Ortiz"]
8 | s.email = "genar.factorial@factorial.co"
9 | s.files = %w[
10 | lib/resource_registry.rb
11 | lib/resource_registry/repositories/base.rb
12 | rbi/resource_registry.rbi
13 | ]
14 | s.homepage = "https://rubygems.org/gems/resource_registry"
15 | s.license = "MIT"
16 | s.required_ruby_version = ">= 3.0"
17 | s.add_development_dependency "sorbet", "0.5.11845"
18 | s.add_runtime_dependency "sorbet-runtime", "0.5.11845"
19 | s.add_dependency "sorbet-coerce", "~> 0.7"
20 | s.add_runtime_dependency "activesupport", ">= 7.1.3"
21 | end
22 |
--------------------------------------------------------------------------------
/sorbet/config:
--------------------------------------------------------------------------------
1 | --dir
2 | .
3 | --ignore=/tmp/
4 | --ignore=/vendor/bundle
5 | --ignore=/examples
--------------------------------------------------------------------------------
/sorbet/rbi/annotations/.gitattributes:
--------------------------------------------------------------------------------
1 | **/*.rbi linguist-vendored=true
2 |
--------------------------------------------------------------------------------
/sorbet/rbi/annotations/minitest.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This file was pulled from a central RBI files repository.
5 | # Please run `bin/tapioca annotations` to update it.
6 |
7 | module Minitest::Assertions
8 | sig { params(test: T.anything, msg: T.anything).returns(TrueClass) }
9 | def assert(test, msg = nil); end
10 |
11 | sig { params(obj: T.anything, msg: T.anything).returns(TrueClass) }
12 | def assert_empty(obj, msg = nil); end
13 |
14 | sig { params(exp: T.anything, act: T.anything, msg: T.anything).returns(TrueClass) }
15 | def assert_equal(exp, act, msg = nil); end
16 |
17 | sig { params(exp: T.anything, act: T.anything, delta: Numeric, msg: T.anything).returns(TrueClass) }
18 | def assert_in_delta(exp, act, delta = T.unsafe(nil), msg = nil); end
19 |
20 | sig { params(a: T.anything, b: T.anything, epsilon: Numeric, msg: T.anything).returns(TrueClass) }
21 | def assert_in_epsilon(a, b, epsilon = T.unsafe(nil), msg = nil); end
22 |
23 | sig { params(collection: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
24 | def assert_includes(collection, obj, msg = nil); end
25 |
26 | sig { params(cls: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
27 | def assert_instance_of(cls, obj, msg = nil); end
28 |
29 | sig { params(cls: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
30 | def assert_kind_of(cls, obj, msg = nil); end
31 |
32 | sig { params(matcher: T.any(String, Regexp), obj: T.anything, msg: T.anything).returns(MatchData) }
33 | def assert_match(matcher, obj, msg = nil); end
34 |
35 | sig { params(obj: T.anything, msg: T.anything).returns(TrueClass) }
36 | def assert_nil(obj, msg = nil); end
37 |
38 | sig { params(o1: T.anything, op: T.any(Symbol, String), o2: T.anything, msg: T.anything).returns(TrueClass) }
39 | def assert_operator(o1, op, o2 = T.unsafe(nil), msg = nil); end
40 |
41 | sig { params(stdout: T.nilable(T.any(String, Regexp)), stderr: T.nilable(T.any(String, Regexp)), block: T.proc.void).returns(T::Boolean) }
42 | def assert_output(stdout = nil, stderr = nil, &block); end
43 |
44 | sig { params(path: T.any(String, Pathname), msg: T.anything).returns(TrueClass) }
45 | def assert_path_exists(path, msg = nil); end
46 |
47 | sig { params(block: T.proc.void).returns(TrueClass) }
48 | def assert_pattern(&block); end
49 |
50 | sig { params(o1: T.anything, op: T.any(String, Symbol), msg: T.anything).returns(TrueClass) }
51 | def assert_predicate(o1, op, msg = nil); end
52 |
53 | sig { params(exp: NilClass, block: T.proc.void).returns(StandardError) }
54 | sig { type_parameters(:T).params(exp: T.any(T::Class[T.type_parameter(:T)], Regexp, String), block: T.proc.void).returns(T.type_parameter(:T)) }
55 | def assert_raises(*exp, &block); end
56 |
57 | sig { params(obj: T.anything, meth: T.any(String, Symbol), msg: T.anything, include_all: T::Boolean).returns(TrueClass) }
58 | def assert_respond_to(obj, meth, msg = nil, include_all: false); end
59 |
60 | sig { params(exp: T.anything, act: T.anything, msg: T.anything).returns(TrueClass) }
61 | def assert_same(exp, act, msg = nil); end
62 |
63 | sig { params(send_ary: T::Array[T.anything], m: T.anything).returns(T::Boolean) }
64 | def assert_send(send_ary, m = nil); end
65 |
66 | sig { params(block: T.proc.void).returns(T::Boolean) }
67 | def assert_silent(&block); end
68 |
69 | sig { params(sym: Symbol, msg: T.anything, block: T.proc.void).returns(T.anything) }
70 | def assert_throws(sym, msg = nil, &block); end
71 |
72 | sig { params(test: T.anything, msg: T.anything).returns(TrueClass) }
73 | def refute(test, msg = nil); end
74 |
75 | sig { params(obj: T.anything, msg: T.anything).returns(TrueClass) }
76 | def refute_empty(obj, msg = nil); end
77 |
78 | sig { params(exp: T.anything, act: T.anything, msg: T.anything).returns(TrueClass) }
79 | def refute_equal(exp, act, msg = nil); end
80 |
81 | sig { params(exp: T.anything, act: T.anything, delta: Numeric, msg: T.anything).returns(TrueClass) }
82 | def refute_in_delta(exp, act, delta = T.unsafe(nil), msg = nil); end
83 |
84 | sig { params(a: T.anything, b: T.anything, epsilon: Numeric, msg: T.anything).returns(TrueClass) }
85 | def refute_in_epsilon(a, b, epsilon = T.unsafe(nil), msg = nil); end
86 |
87 | sig { params(collection: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
88 | def refute_includes(collection, obj, msg = nil); end
89 |
90 | sig { params(cls: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
91 | def refute_instance_of(cls, obj, msg = nil); end
92 |
93 | sig { params(cls: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
94 | def refute_kind_of(cls, obj, msg = nil); end
95 |
96 | sig { params(matcher: T.any(String, Regexp), obj: T.anything, msg: T.anything).returns(TrueClass) }
97 | def refute_match(matcher, obj, msg = nil); end
98 |
99 | sig { params(obj: T.anything, msg: T.anything).returns(TrueClass) }
100 | def refute_nil(obj, msg = nil); end
101 |
102 | sig { params(block: T.proc.void).returns(TrueClass) }
103 | def refute_pattern(&block); end
104 |
105 | sig { params(o1: T.anything, op: T.any(Symbol, String), o2: T.anything, msg: T.anything).returns(TrueClass) }
106 | def refute_operator(o1, op, o2 = T.unsafe(nil), msg = nil); end
107 |
108 | sig { params(path: T.any(String, Pathname), msg: T.anything).returns(TrueClass) }
109 | def refute_path_exists(path, msg = nil); end
110 |
111 | sig { params(o1: T.anything, op: T.any(String, Symbol), msg: T.anything).returns(TrueClass) }
112 | def refute_predicate(o1, op, msg = nil); end
113 |
114 | sig { params(obj: T.anything, meth: T.any(String, Symbol), msg: T.anything, include_all: T::Boolean).returns(TrueClass) }
115 | def refute_respond_to(obj, meth, msg = nil, include_all: false); end
116 |
117 | sig { params(exp: T.anything, act: T.anything, msg: T.anything).returns(TrueClass) }
118 | def refute_same(exp, act, msg = nil); end
119 | end
120 |
--------------------------------------------------------------------------------
/sorbet/rbi/dsl/.gitattributes:
--------------------------------------------------------------------------------
1 | **/*.rbi linguist-generated=true
2 |
--------------------------------------------------------------------------------
/sorbet/rbi/dsl/active_support/callbacks.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for dynamic methods in `ActiveSupport::Callbacks`.
5 | # Please instead update this file by running `bin/tapioca dsl ActiveSupport::Callbacks`.
6 |
7 |
8 | module ActiveSupport::Callbacks
9 | include GeneratedInstanceMethods
10 |
11 | mixes_in_class_methods GeneratedClassMethods
12 |
13 | module GeneratedClassMethods
14 | def __callbacks; end
15 | def __callbacks=(value); end
16 | def __callbacks?; end
17 | end
18 |
19 | module GeneratedInstanceMethods
20 | def __callbacks; end
21 | def __callbacks?; end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/.gitattributes:
--------------------------------------------------------------------------------
1 | **/*.rbi linguist-generated=true
2 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/base64@0.2.0.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `base64` gem.
5 | # Please instead update this file by running `bin/tapioca gem base64`.
6 |
7 |
8 | # THIS IS AN EMPTY RBI FILE.
9 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem
10 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/bigdecimal.rbi:
--------------------------------------------------------------------------------
1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with:
2 | # srb rbi gems
3 |
4 | # typed: false
5 | #
6 | # If you would like to make changes to this file, great! Please create the gem's shim here:
7 | #
8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/bigdecimal/all/bigdecimal.rbi
9 | #
10 | # bigdecimal-3.1.8
11 |
12 | module Kernel
13 | def BigDecimal(*arg0); end
14 | def self.BigDecimal(*arg0); end
15 | end
16 | class BigDecimal < Numeric
17 | def %(arg0); end
18 | def *(arg0); end
19 | def **(arg0); end
20 | def +(arg0); end
21 | def +@; end
22 | def -(arg0); end
23 | def -@; end
24 | def /(arg0); end
25 | def <(arg0); end
26 | def <=(arg0); end
27 | def <=>(arg0); end
28 | def ==(arg0); end
29 | def ===(arg0); end
30 | def >(arg0); end
31 | def >=(arg0); end
32 | def _dump(*arg0); end
33 | def abs; end
34 | def add(arg0, arg1); end
35 | def ceil(*arg0); end
36 | def clone; end
37 | def coerce(arg0); end
38 | def div(*arg0); end
39 | def divmod(arg0); end
40 | def dup; end
41 | def eql?(arg0); end
42 | def exponent; end
43 | def finite?; end
44 | def fix; end
45 | def floor(*arg0); end
46 | def frac; end
47 | def hash; end
48 | def infinite?; end
49 | def inspect; end
50 | def modulo(arg0); end
51 | def mult(arg0, arg1); end
52 | def n_significant_digits; end
53 | def nan?; end
54 | def nonzero?; end
55 | def power(*arg0); end
56 | def precision; end
57 | def precision_scale; end
58 | def precs; end
59 | def quo(*arg0); end
60 | def remainder(arg0); end
61 | def round(*arg0); end
62 | def scale; end
63 | def self._load(arg0); end
64 | def self.double_fig; end
65 | def self.interpret_loosely(arg0); end
66 | def self.limit(*arg0); end
67 | def self.mode(*arg0); end
68 | def self.save_exception_mode; end
69 | def self.save_limit; end
70 | def self.save_rounding_mode; end
71 | def sign; end
72 | def split; end
73 | def sqrt(arg0); end
74 | def sub(arg0, arg1); end
75 | def to_f; end
76 | def to_i; end
77 | def to_int; end
78 | def to_r; end
79 | def to_s(*arg0); end
80 | def truncate(*arg0); end
81 | def zero?; end
82 | end
83 | module BigMath
84 | def self.exp(arg0, arg1); end
85 | def self.log(arg0, arg1); end
86 | end
87 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/bigdecimal@3.1.8.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `bigdecimal` gem.
5 | # Please instead update this file by running `bin/tapioca gem bigdecimal`.
6 |
7 |
8 | # THIS IS AN EMPTY RBI FILE.
9 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem
10 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/concurrent-ruby@1.3.4.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `concurrent-ruby` gem.
5 | # Please instead update this file by running `bin/tapioca gem concurrent-ruby`.
6 |
7 |
8 | # THIS IS AN EMPTY RBI FILE.
9 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem
10 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/connection_pool.rbi:
--------------------------------------------------------------------------------
1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with:
2 | # srb rbi gems
3 |
4 | # typed: strict
5 | #
6 | # If you would like to make changes to this file, great! Please create the gem's shim here:
7 | #
8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/connection_pool/all/connection_pool.rbi
9 | #
10 | # connection_pool-2.4.1
11 |
12 | class ConnectionPool
13 | def auto_reload_after_fork; end
14 | def available; end
15 | def checkin(force: nil); end
16 | def checkout(options = nil); end
17 | def initialize(options = nil, &block); end
18 | def reload(&block); end
19 | def self.after_fork; end
20 | def self.wrap(options, &block); end
21 | def shutdown(&block); end
22 | def size; end
23 | def then(options = nil); end
24 | def with(options = nil); end
25 | end
26 | class ConnectionPool::TimedStack
27 | def <<(obj, options = nil); end
28 | def connection_stored?(options = nil); end
29 | def current_time; end
30 | def empty?; end
31 | def fetch_connection(options = nil); end
32 | def initialize(size = nil, &block); end
33 | def length; end
34 | def max; end
35 | def pop(timeout = nil, options = nil); end
36 | def push(obj, options = nil); end
37 | def shutdown(reload: nil, &block); end
38 | def shutdown_connections(options = nil); end
39 | def store_connection(obj, options = nil); end
40 | def try_create(options = nil); end
41 | end
42 | class ConnectionPool::Wrapper < BasicObject
43 | def initialize(options = nil, &block); end
44 | def method_missing(name, *args, **kwargs, &block); end
45 | def pool_available; end
46 | def pool_shutdown(&block); end
47 | def pool_size; end
48 | def respond_to?(id, *args); end
49 | def with(&block); end
50 | def wrapped_pool; end
51 | end
52 | class ConnectionPool::Error < RuntimeError
53 | end
54 | class ConnectionPool::PoolShuttingDownError < ConnectionPool::Error
55 | end
56 | class ConnectionPool::TimeoutError < Timeout::Error
57 | end
58 | module ConnectionPool::ForkTracker
59 | def _fork; end
60 | end
61 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/connection_pool@2.4.1.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `connection_pool` gem.
5 | # Please instead update this file by running `bin/tapioca gem connection_pool`.
6 |
7 |
8 | # THIS IS AN EMPTY RBI FILE.
9 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem
10 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/drb.rbi:
--------------------------------------------------------------------------------
1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with:
2 | # srb rbi gems
3 |
4 | # typed: false
5 | #
6 | # If you would like to make changes to this file, great! Please create the gem's shim here:
7 | #
8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/drb/all/drb.rbi
9 | #
10 | # drb-2.2.1
11 |
12 | module DRb
13 | def config; end
14 | def current_server; end
15 | def fetch_server(uri); end
16 | def front; end
17 | def here?(uri); end
18 | def install_acl(acl); end
19 | def install_id_conv(idconv); end
20 | def mutex; end
21 | def primary_server; end
22 | def primary_server=(arg0); end
23 | def regist_server(server); end
24 | def remove_server(server); end
25 | def self.config; end
26 | def self.current_server; end
27 | def self.fetch_server(uri); end
28 | def self.front; end
29 | def self.here?(uri); end
30 | def self.install_acl(acl); end
31 | def self.install_id_conv(idconv); end
32 | def self.mutex; end
33 | def self.primary_server; end
34 | def self.primary_server=(arg0); end
35 | def self.regist_server(server); end
36 | def self.remove_server(server); end
37 | def self.start_service(uri = nil, front = nil, config = nil); end
38 | def self.stop_service; end
39 | def self.thread; end
40 | def self.to_id(obj); end
41 | def self.to_obj(ref); end
42 | def self.uri; end
43 | def start_service(uri = nil, front = nil, config = nil); end
44 | def stop_service; end
45 | def thread; end
46 | def to_id(obj); end
47 | def to_obj(ref); end
48 | def uri; end
49 | end
50 | class DRb::DRbObject
51 | def ==(other); end
52 | def __drbref; end
53 | def __drburi; end
54 | def _dump(lv); end
55 | def eql?(other); end
56 | def hash; end
57 | def initialize(obj, uri = nil); end
58 | def method_missing(msg_id, *a, **, &b); end
59 | def pretty_print(q); end
60 | def pretty_print_cycle(q); end
61 | def respond_to?(msg_id, priv = nil); end
62 | def self._load(s); end
63 | def self.new_with(uri, ref); end
64 | def self.new_with_uri(uri); end
65 | def self.prepare_backtrace(uri, result); end
66 | def self.with_friend(uri); end
67 | end
68 | class DRb::DRbServer
69 | def alive?; end
70 | def any_to_s(obj); end
71 | def check_insecure_method(obj, msg_id); end
72 | def config; end
73 | def error_print(exception); end
74 | def front; end
75 | def here?(uri); end
76 | def initialize(uri = nil, front = nil, config_or_acl = nil); end
77 | def insecure_method?(msg_id); end
78 | def main_loop; end
79 | def run; end
80 | def self.default_acl(acl); end
81 | def self.default_argc_limit(argc); end
82 | def self.default_id_conv(idconv); end
83 | def self.default_load_limit(sz); end
84 | def self.make_config(hash = nil); end
85 | def self.verbose; end
86 | def self.verbose=(on); end
87 | def shutdown; end
88 | def stop_service; end
89 | def thread; end
90 | def to_id(obj); end
91 | def to_obj(ref); end
92 | def uri; end
93 | def verbose; end
94 | def verbose=(v); end
95 | end
96 | module DRb::DRbServer::InvokeMethod18Mixin
97 | def block_yield(x); end
98 | def perform_with_block; end
99 | end
100 | class DRb::DRbError < RuntimeError
101 | end
102 | class DRb::DRbConnError < DRb::DRbError
103 | end
104 | class DRb::DRbIdConv
105 | def to_id(obj); end
106 | def to_obj(ref); end
107 | end
108 | module DRb::DRbUndumped
109 | def _dump(dummy); end
110 | end
111 | class DRb::DRbServerNotFound < DRb::DRbError
112 | end
113 | class DRb::DRbBadURI < DRb::DRbError
114 | end
115 | class DRb::DRbBadScheme < DRb::DRbError
116 | end
117 | class DRb::DRbUnknownError < DRb::DRbError
118 | def _dump(lv); end
119 | def initialize(unknown); end
120 | def self._load(s); end
121 | def unknown; end
122 | end
123 | class DRb::DRbRemoteError < DRb::DRbError
124 | def initialize(error); end
125 | def reason; end
126 | end
127 | class DRb::DRbUnknown
128 | def _dump(lv); end
129 | def buf; end
130 | def exception; end
131 | def initialize(err, buf); end
132 | def name; end
133 | def reload; end
134 | def self._load(s); end
135 | end
136 | class DRb::DRbArray
137 | def _dump(lv); end
138 | def initialize(ary); end
139 | def self._load(s); end
140 | end
141 | class DRb::DRbMessage
142 | def dump(obj, error = nil); end
143 | def initialize(config); end
144 | def load(soc); end
145 | def make_proxy(obj, error = nil); end
146 | def recv_reply(stream); end
147 | def recv_request(stream); end
148 | def send_reply(stream, succ, result); end
149 | def send_request(stream, ref, msg_id, arg, b); end
150 | end
151 | module DRb::DRbProtocol
152 | def add_protocol(prot); end
153 | def auto_load(uri); end
154 | def open(uri, config, first = nil); end
155 | def open_server(uri, config, first = nil); end
156 | def self.add_protocol(prot); end
157 | def self.auto_load(uri); end
158 | def self.open(uri, config, first = nil); end
159 | def self.open_server(uri, config, first = nil); end
160 | def self.uri_option(uri, config, first = nil); end
161 | def uri_option(uri, config, first = nil); end
162 | end
163 | class DRb::DRbTCPSocket
164 | def accept; end
165 | def accept_or_shutdown; end
166 | def alive?; end
167 | def close; end
168 | def close_shutdown_pipe; end
169 | def initialize(uri, soc, config = nil); end
170 | def peeraddr; end
171 | def recv_reply; end
172 | def recv_request; end
173 | def self.getservername; end
174 | def self.open(uri, config); end
175 | def self.open_server(uri, config); end
176 | def self.open_server_inaddr_any(host, port); end
177 | def self.parse_uri(uri); end
178 | def self.uri_option(uri, config); end
179 | def send_reply(succ, result); end
180 | def send_request(ref, msg_id, arg, b); end
181 | def set_sockopt(soc); end
182 | def shutdown; end
183 | def stream; end
184 | def uri; end
185 | end
186 | class DRb::DRbURIOption
187 | def ==(other); end
188 | def eql?(other); end
189 | def hash; end
190 | def initialize(option); end
191 | def option; end
192 | def to_s; end
193 | end
194 | class DRb::ThreadObject
195 | def _execute; end
196 | def alive?; end
197 | def initialize(&blk); end
198 | def kill; end
199 | def method_missing(msg, *arg, &blk); end
200 | include MonitorMixin
201 | end
202 | class DRb::DRbConn
203 | def alive?; end
204 | def close; end
205 | def initialize(remote_uri); end
206 | def self.make_pool; end
207 | def self.open(remote_uri); end
208 | def self.stop_pool; end
209 | def send_message(ref, msg_id, arg, block); end
210 | def uri; end
211 | end
212 | class DRb::DRbServer::InvokeMethod
213 | def check_insecure_method; end
214 | def init_with_client; end
215 | def initialize(drb_server, client); end
216 | def perform; end
217 | def perform_without_block; end
218 | def setup_message; end
219 | include DRb::DRbServer::InvokeMethod18Mixin
220 | end
221 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/erubi@1.13.1.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `erubi` gem.
5 | # Please instead update this file by running `bin/tapioca gem erubi`.
6 |
7 |
8 | # source://erubi//lib/erubi.rb#3
9 | module Erubi
10 | private
11 |
12 | def h(_arg0); end
13 |
14 | class << self
15 | def h(_arg0); end
16 | end
17 | end
18 |
19 | # source://erubi//lib/erubi.rb#51
20 | class Erubi::Engine
21 | # Initialize a new Erubi::Engine. Options:
22 | # +:bufval+ :: The value to use for the buffer variable, as a string (default '::String.new').
23 | # +:bufvar+ :: The variable name to use for the buffer variable, as a string.
24 | # +:chain_appends+ :: Whether to chain << calls to the buffer variable. Offers better
25 | # performance, but can cause issues when the buffer variable is reassigned during
26 | # template rendering (default +false+).
27 | # +:ensure+ :: Wrap the template in a begin/ensure block restoring the previous value of bufvar.
28 | # +:escapefunc+ :: The function to use for escaping, as a string (default: '::Erubi.h').
29 | # +:escape+ :: Whether to make <%= escape by default, and <%== not escape by default.
30 | # +:escape_html+ :: Same as +:escape+, with lower priority.
31 | # +:filename+ :: The filename for the template.
32 | # the resulting source code. Note this may cause problems if you are wrapping the resulting
33 | # source code in other code, because the magic comment only has an effect at the beginning of
34 | # the file, and having the magic comment later in the file can trigger warnings.
35 | # +:freeze_template_literals+ :: Whether to suffix all literal strings for template code with .freeze
36 | # (default: +true+ on Ruby 2.1+, +false+ on Ruby 2.0 and older).
37 | # Can be set to +false+ on Ruby 2.3+ when frozen string literals are enabled
38 | # in order to improve performance.
39 | # +:literal_prefix+ :: The prefix to output when using escaped tag delimiters (default '<%').
40 | # +:literal_postfix+ :: The postfix to output when using escaped tag delimiters (default '%>').
41 | # +:outvar+ :: Same as +:bufvar+, with lower priority.
42 | # +:postamble+ :: The postamble for the template, by default returns the resulting source code.
43 | # +:preamble+ :: The preamble for the template, by default initializes the buffer variable.
44 | # +:regexp+ :: The regexp to use for scanning.
45 | # +:src+ :: The initial value to use for the source code, an empty string by default.
46 | # +:trim+ :: Whether to trim leading and trailing whitespace, true by default.
47 | #
48 | # @return [Engine] a new instance of Engine
49 | #
50 | # source://erubi//lib/erubi.rb#91
51 | def initialize(input, properties = T.unsafe(nil)); end
52 |
53 | # The variable name used for the buffer variable.
54 | #
55 | # source://erubi//lib/erubi.rb#62
56 | def bufvar; end
57 |
58 | # The filename of the template, if one was given.
59 | #
60 | # source://erubi//lib/erubi.rb#59
61 | def filename; end
62 |
63 | # The frozen ruby source code generated from the template, which can be evaled.
64 | #
65 | # source://erubi//lib/erubi.rb#56
66 | def src; end
67 |
68 | private
69 |
70 | # :nocov:
71 | #
72 | # source://erubi//lib/erubi.rb#209
73 | def _dup_string_if_frozen(string); end
74 |
75 | # Add ruby code to the template
76 | #
77 | # source://erubi//lib/erubi.rb#232
78 | def add_code(code); end
79 |
80 | # Add the given ruby expression result to the template,
81 | # escaping it based on the indicator given and escape flag.
82 | #
83 | # source://erubi//lib/erubi.rb#241
84 | def add_expression(indicator, code); end
85 |
86 | # Add the result of Ruby expression to the template
87 | #
88 | # source://erubi//lib/erubi.rb#250
89 | def add_expression_result(code); end
90 |
91 | # Add the escaped result of Ruby expression to the template
92 | #
93 | # source://erubi//lib/erubi.rb#255
94 | def add_expression_result_escaped(code); end
95 |
96 | # Add the given postamble to the src. Can be overridden in subclasses
97 | # to make additional changes to src that depend on the current state.
98 | #
99 | # source://erubi//lib/erubi.rb#261
100 | def add_postamble(postamble); end
101 |
102 | # Add raw text to the template. Modifies argument if argument is mutable as a memory optimization.
103 | # Must be called with a string, cannot be called with nil (Rails's subclass depends on it).
104 | #
105 | # source://erubi//lib/erubi.rb#222
106 | def add_text(text); end
107 |
108 | # Raise an exception, as the base engine class does not support handling other indicators.
109 | #
110 | # @raise [ArgumentError]
111 | #
112 | # source://erubi//lib/erubi.rb#267
113 | def handle(indicator, code, tailch, rspace, lspace); end
114 |
115 | # Make sure that any current expression has been terminated.
116 | # The default is to terminate all expressions, but when
117 | # the chain_appends option is used, expressions may not be
118 | # terminated.
119 | #
120 | # source://erubi//lib/erubi.rb#295
121 | def terminate_expression; end
122 |
123 | # Make sure the buffer variable is the target of the next append
124 | # before yielding to the block. Mark that the buffer is the target
125 | # of the next append after the block executes.
126 | #
127 | # This method should only be called if the block will result in
128 | # code where << will append to the bufvar.
129 | #
130 | # source://erubi//lib/erubi.rb#277
131 | def with_buffer; end
132 | end
133 |
134 | # The default regular expression used for scanning.
135 | #
136 | # source://erubi//lib/erubi.rb#53
137 | Erubi::Engine::DEFAULT_REGEXP = T.let(T.unsafe(nil), Regexp)
138 |
139 | # source://erubi//lib/erubi.rb#17
140 | Erubi::FREEZE_TEMPLATE_LITERALS = T.let(T.unsafe(nil), TrueClass)
141 |
142 | # source://erubi//lib/erubi.rb#15
143 | Erubi::MATCH_METHOD = T.let(T.unsafe(nil), Symbol)
144 |
145 | # source://erubi//lib/erubi.rb#8
146 | Erubi::RANGE_FIRST = T.let(T.unsafe(nil), Integer)
147 |
148 | # source://erubi//lib/erubi.rb#9
149 | Erubi::RANGE_LAST = T.let(T.unsafe(nil), Integer)
150 |
151 | # source://erubi//lib/erubi.rb#16
152 | Erubi::SKIP_DEFINED_FOR_INSTANCE_VARIABLE = T.let(T.unsafe(nil), TrueClass)
153 |
154 | # source://erubi//lib/erubi.rb#4
155 | Erubi::VERSION = T.let(T.unsafe(nil), String)
156 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/ffi@1.17.0.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `ffi` gem.
5 | # Please instead update this file by running `bin/tapioca gem ffi`.
6 |
7 |
8 | # THIS IS AN EMPTY RBI FILE.
9 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem
10 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/formatador@1.1.0.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `formatador` gem.
5 | # Please instead update this file by running `bin/tapioca gem formatador`.
6 |
7 |
8 | # THIS IS AN EMPTY RBI FILE.
9 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem
10 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/guard-compat@1.2.1.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `guard-compat` gem.
5 | # Please instead update this file by running `bin/tapioca gem guard-compat`.
6 |
7 |
8 | # Provided empty definition so requiring the plugin without Guard won't crash
9 | # (e.g. when added to a Gemfile without `require: false`)
10 | #
11 | # source://guard-compat//lib/guard/compat/plugin.rb#23
12 | module Guard
13 | extend ::Guard::Internals::Helpers
14 |
15 | class << self
16 | # source://guard/2.18.1/lib/guard.rb#87
17 | def async_queue_add(changes); end
18 |
19 | # source://guard/2.18.1/lib/guard.rb#73
20 | def init(cmdline_options); end
21 |
22 | # source://guard/2.18.1/lib/guard.rb#24
23 | def interactor; end
24 |
25 | # source://guard/2.18.1/lib/guard.rb#23
26 | def listener; end
27 |
28 | # source://guard/2.18.1/lib/guard.rb#22
29 | def queue; end
30 |
31 | # source://guard/2.18.1/lib/guard.rb#44
32 | def setup(cmdline_options = T.unsafe(nil)); end
33 |
34 | # source://guard/2.18.1/lib/guard.rb#21
35 | def state; end
36 |
37 | private
38 |
39 | # source://guard/2.18.1/lib/guard.rb#132
40 | def _evaluate(options); end
41 |
42 | # source://guard/2.18.1/lib/guard.rb#152
43 | def _guardfile_deprecated_check(modified); end
44 |
45 | # source://guard/2.18.1/lib/guard.rb#113
46 | def _listener_callback; end
47 |
48 | # source://guard/2.18.1/lib/guard.rb#128
49 | def _pluginless_guardfile?; end
50 |
51 | # source://guard/2.18.1/lib/guard.rb#109
52 | def _relative_pathnames(paths); end
53 |
54 | # source://guard/2.18.1/lib/guard.rb#99
55 | def _relevant_changes?(changes); end
56 | end
57 | end
58 |
59 | # source://guard-compat//lib/guard/compat/plugin.rb#24
60 | module Guard::Compat
61 | class << self
62 | # TODO: this is just a temporary workaround to allow plugins
63 | # to use watcher patterns in run_all
64 | #
65 | # source://guard-compat//lib/guard/compat/plugin.rb#27
66 | def matching_files(plugin, files); end
67 |
68 | # source://guard-compat//lib/guard/compat/plugin.rb#39
69 | def watched_directories; end
70 | end
71 | end
72 |
73 | # source://guard-compat//lib/guard/compat/plugin.rb#54
74 | module Guard::Compat::UI
75 | class << self
76 | # source://guard-compat//lib/guard/compat/plugin.rb#55
77 | def color(text, *colors); end
78 |
79 | # @return [Boolean]
80 | #
81 | # source://guard-compat//lib/guard/compat/plugin.rb#63
82 | def color_enabled?; end
83 |
84 | # source://guard-compat//lib/guard/compat/plugin.rb#95
85 | def debug(message, options = T.unsafe(nil)); end
86 |
87 | # source://guard-compat//lib/guard/compat/plugin.rb#103
88 | def deprecation(message, options = T.unsafe(nil)); end
89 |
90 | # source://guard-compat//lib/guard/compat/plugin.rb#87
91 | def error(message, options = T.unsafe(nil)); end
92 |
93 | # source://guard-compat//lib/guard/compat/plugin.rb#71
94 | def info(message, options = T.unsafe(nil)); end
95 |
96 | # source://guard-compat//lib/guard/compat/plugin.rb#111
97 | def notify(msg, options = T.unsafe(nil)); end
98 |
99 | # source://guard-compat//lib/guard/compat/plugin.rb#79
100 | def warning(message, options = T.unsafe(nil)); end
101 | end
102 | end
103 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/minitest@5.25.2.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `minitest` gem.
5 | # Please instead update this file by running `bin/tapioca gem minitest`.
6 |
7 |
8 | # THIS IS AN EMPTY RBI FILE.
9 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem
10 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/nenv@0.3.0.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `nenv` gem.
5 | # Please instead update this file by running `bin/tapioca gem nenv`.
6 |
7 |
8 | # source://nenv//lib/nenv/version.rb#1
9 | module Nenv
10 | class << self
11 | # source://nenv//lib/nenv.rb#26
12 | def instance; end
13 |
14 | # source://nenv//lib/nenv.rb#18
15 | def method_missing(meth, *args); end
16 |
17 | # source://nenv//lib/nenv.rb#22
18 | def reset; end
19 |
20 | # @return [Boolean]
21 | #
22 | # source://nenv//lib/nenv.rb#14
23 | def respond_to?(meth); end
24 | end
25 | end
26 |
27 | # source://nenv//lib/nenv/autoenvironment.rb#3
28 | class Nenv::AutoEnvironment < ::Nenv::Environment
29 | # source://nenv//lib/nenv/autoenvironment.rb#4
30 | def method_missing(meth, *args); end
31 | end
32 |
33 | # source://nenv//lib/nenv/builder.rb#4
34 | module Nenv::Builder
35 | class << self
36 | # source://nenv//lib/nenv/builder.rb#5
37 | def build(&block); end
38 | end
39 | end
40 |
41 | # source://nenv//lib/nenv/environment/dumper.rb#2
42 | class Nenv::Environment
43 | # @return [Environment] a new instance of Environment
44 | #
45 | # source://nenv//lib/nenv/environment.rb#21
46 | def initialize(namespace = T.unsafe(nil)); end
47 |
48 | # source://nenv//lib/nenv/environment.rb#25
49 | def create_method(meth, &block); end
50 |
51 | private
52 |
53 | # source://nenv//lib/nenv/environment.rb#35
54 | def _namespaced_sanitize(meth); end
55 |
56 | # source://nenv//lib/nenv/environment.rb#31
57 | def _sanitize(meth); end
58 |
59 | class << self
60 | # source://nenv//lib/nenv/environment.rb#44
61 | def _create_env_accessor(klass, meth, &block); end
62 |
63 | # source://nenv//lib/nenv/environment.rb#40
64 | def create_method(meth, &block); end
65 |
66 | private
67 |
68 | # source://nenv//lib/nenv/environment.rb#66
69 | def _create_env_reader(klass, meth, &block); end
70 |
71 | # source://nenv//lib/nenv/environment.rb#56
72 | def _create_env_writer(klass, meth, &block); end
73 |
74 | # source://nenv//lib/nenv/environment.rb#76
75 | def _fail_if_accessor_exists(klass, meth); end
76 | end
77 | end
78 |
79 | # source://nenv//lib/nenv/environment.rb#15
80 | class Nenv::Environment::AlreadyExistsError < ::Nenv::Environment::MethodError
81 | # source://nenv//lib/nenv/environment.rb#16
82 | def message; end
83 | end
84 |
85 | # source://nenv//lib/nenv/environment/dumper.rb#3
86 | module Nenv::Environment::Dumper
87 | class << self
88 | # source://nenv//lib/nenv/environment/dumper.rb#6
89 | def setup(&callback); end
90 | end
91 | end
92 |
93 | # source://nenv//lib/nenv/environment/dumper/default.rb#3
94 | module Nenv::Environment::Dumper::Default
95 | class << self
96 | # source://nenv//lib/nenv/environment/dumper/default.rb#4
97 | def call(raw_value); end
98 | end
99 | end
100 |
101 | # source://nenv//lib/nenv/environment.rb#6
102 | class Nenv::Environment::Error < ::ArgumentError; end
103 |
104 | # source://nenv//lib/nenv/environment/loader.rb#3
105 | module Nenv::Environment::Loader
106 | class << self
107 | # source://nenv//lib/nenv/environment/loader.rb#7
108 | def setup(meth, &callback); end
109 | end
110 | end
111 |
112 | # source://nenv//lib/nenv/environment/loader/default.rb#3
113 | module Nenv::Environment::Loader::Default
114 | class << self
115 | # source://nenv//lib/nenv/environment/loader/default.rb#4
116 | def call(raw_value); end
117 | end
118 | end
119 |
120 | # source://nenv//lib/nenv/environment/loader/predicate.rb#3
121 | module Nenv::Environment::Loader::Predicate
122 | class << self
123 | # source://nenv//lib/nenv/environment/loader/predicate.rb#4
124 | def call(raw_value); end
125 | end
126 | end
127 |
128 | # source://nenv//lib/nenv/environment.rb#9
129 | class Nenv::Environment::MethodError < ::Nenv::Environment::Error
130 | # @return [MethodError] a new instance of MethodError
131 | #
132 | # source://nenv//lib/nenv/environment.rb#10
133 | def initialize(meth); end
134 | end
135 |
136 | # source://nenv//lib/nenv/version.rb#2
137 | Nenv::VERSION = T.let(T.unsafe(nil), String)
138 |
139 | class Object < ::BasicObject
140 | include ::Kernel
141 | include ::PP::ObjectMixin
142 |
143 | private
144 |
145 | # source://nenv//lib/nenv.rb#6
146 | def Nenv(namespace = T.unsafe(nil)); end
147 | end
148 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/netrc@0.11.0.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `netrc` gem.
5 | # Please instead update this file by running `bin/tapioca gem netrc`.
6 |
7 |
8 | # source://netrc//lib/netrc.rb#3
9 | class Netrc
10 | # @return [Netrc] a new instance of Netrc
11 | #
12 | # source://netrc//lib/netrc.rb#166
13 | def initialize(path, data); end
14 |
15 | # source://netrc//lib/netrc.rb#180
16 | def [](k); end
17 |
18 | # source://netrc//lib/netrc.rb#188
19 | def []=(k, info); end
20 |
21 | # source://netrc//lib/netrc.rb#200
22 | def delete(key); end
23 |
24 | # source://netrc//lib/netrc.rb#211
25 | def each(&block); end
26 |
27 | # source://netrc//lib/netrc.rb#196
28 | def length; end
29 |
30 | # source://netrc//lib/netrc.rb#215
31 | def new_item(m, l, p); end
32 |
33 | # Returns the value of attribute new_item_prefix.
34 | #
35 | # source://netrc//lib/netrc.rb#178
36 | def new_item_prefix; end
37 |
38 | # Sets the attribute new_item_prefix
39 | #
40 | # @param value the value to set the attribute new_item_prefix to.
41 | #
42 | # source://netrc//lib/netrc.rb#178
43 | def new_item_prefix=(_arg0); end
44 |
45 | # source://netrc//lib/netrc.rb#219
46 | def save; end
47 |
48 | # source://netrc//lib/netrc.rb#233
49 | def unparse; end
50 |
51 | class << self
52 | # source://netrc//lib/netrc.rb#42
53 | def check_permissions(path); end
54 |
55 | # source://netrc//lib/netrc.rb#33
56 | def config; end
57 |
58 | # @yield [self.config]
59 | #
60 | # source://netrc//lib/netrc.rb#37
61 | def configure; end
62 |
63 | # source://netrc//lib/netrc.rb#10
64 | def default_path; end
65 |
66 | # source://netrc//lib/netrc.rb#14
67 | def home_path; end
68 |
69 | # source://netrc//lib/netrc.rb#85
70 | def lex(lines); end
71 |
72 | # source://netrc//lib/netrc.rb#29
73 | def netrc_filename; end
74 |
75 | # Returns two values, a header and a list of items.
76 | # Each item is a tuple, containing some or all of:
77 | # - machine keyword (including trailing whitespace+comments)
78 | # - machine name
79 | # - login keyword (including surrounding whitespace+comments)
80 | # - login
81 | # - password keyword (including surrounding whitespace+comments)
82 | # - password
83 | # - trailing chars
84 | # This lets us change individual fields, then write out the file
85 | # with all its original formatting.
86 | #
87 | # source://netrc//lib/netrc.rb#129
88 | def parse(ts); end
89 |
90 | # Reads path and parses it as a .netrc file. If path doesn't
91 | # exist, returns an empty object. Decrypt paths ending in .gpg.
92 | #
93 | # source://netrc//lib/netrc.rb#51
94 | def read(path = T.unsafe(nil)); end
95 |
96 | # @return [Boolean]
97 | #
98 | # source://netrc//lib/netrc.rb#112
99 | def skip?(s); end
100 | end
101 | end
102 |
103 | # source://netrc//lib/netrc.rb#8
104 | Netrc::CYGWIN = T.let(T.unsafe(nil), T.untyped)
105 |
106 | # source://netrc//lib/netrc.rb#244
107 | class Netrc::Entry < ::Struct
108 | # Returns the value of attribute login
109 | #
110 | # @return [Object] the current value of login
111 | def login; end
112 |
113 | # Sets the attribute login
114 | #
115 | # @param value [Object] the value to set the attribute login to.
116 | # @return [Object] the newly set value
117 | def login=(_); end
118 |
119 | # Returns the value of attribute password
120 | #
121 | # @return [Object] the current value of password
122 | def password; end
123 |
124 | # Sets the attribute password
125 | #
126 | # @param value [Object] the value to set the attribute password to.
127 | # @return [Object] the newly set value
128 | def password=(_); end
129 |
130 | def to_ary; end
131 |
132 | class << self
133 | def [](*_arg0); end
134 | def inspect; end
135 | def keyword_init?; end
136 | def members; end
137 | def new(*_arg0); end
138 | end
139 | end
140 |
141 | # source://netrc//lib/netrc.rb#250
142 | class Netrc::Error < ::StandardError; end
143 |
144 | # source://netrc//lib/netrc.rb#68
145 | class Netrc::TokenArray < ::Array
146 | # source://netrc//lib/netrc.rb#76
147 | def readto; end
148 |
149 | # source://netrc//lib/netrc.rb#69
150 | def take; end
151 | end
152 |
153 | # source://netrc//lib/netrc.rb#4
154 | Netrc::VERSION = T.let(T.unsafe(nil), String)
155 |
156 | # see http://stackoverflow.com/questions/4871309/what-is-the-correct-way-to-detect-if-ruby-is-running-on-windows
157 | #
158 | # source://netrc//lib/netrc.rb#7
159 | Netrc::WINDOWS = T.let(T.unsafe(nil), T.untyped)
160 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/rb-fsevent@0.11.2.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `rb-fsevent` gem.
5 | # Please instead update this file by running `bin/tapioca gem rb-fsevent`.
6 |
7 |
8 | # THIS IS AN EMPTY RBI FILE.
9 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem
10 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/rb-inotify@0.11.1.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `rb-inotify` gem.
5 | # Please instead update this file by running `bin/tapioca gem rb-inotify`.
6 |
7 |
8 | # THIS IS AN EMPTY RBI FILE.
9 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem
10 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/rspec-expectations@3.13.1.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `rspec-expectations` gem.
5 | # Please instead update this file by running `bin/tapioca gem rspec-expectations`.
6 |
7 |
8 | # THIS IS AN EMPTY RBI FILE.
9 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem
10 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/rspec-sorbet@1.9.2.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `rspec-sorbet` gem.
5 | # Please instead update this file by running `bin/tapioca gem rspec-sorbet`.
6 |
7 |
8 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#6
9 | module RSpec
10 | class << self
11 | # source://rspec-core/3.13.0/lib/rspec/core.rb#70
12 | def clear_examples; end
13 |
14 | # source://rspec-core/3.13.0/lib/rspec/core.rb#85
15 | def configuration; end
16 |
17 | # source://rspec-core/3.13.0/lib/rspec/core.rb#49
18 | def configuration=(_arg0); end
19 |
20 | # source://rspec-core/3.13.0/lib/rspec/core.rb#97
21 | def configure; end
22 |
23 | # source://rspec-core/3.13.0/lib/rspec/core.rb#194
24 | def const_missing(name); end
25 |
26 | # source://rspec-core/3.13.0/lib/rspec/core/dsl.rb#42
27 | def context(*args, &example_group_block); end
28 |
29 | # source://rspec-core/3.13.0/lib/rspec/core.rb#122
30 | def current_example; end
31 |
32 | # source://rspec-core/3.13.0/lib/rspec/core.rb#128
33 | def current_example=(example); end
34 |
35 | # source://rspec-core/3.13.0/lib/rspec/core.rb#154
36 | def current_scope; end
37 |
38 | # source://rspec-core/3.13.0/lib/rspec/core.rb#134
39 | def current_scope=(scope); end
40 |
41 | # source://rspec-core/3.13.0/lib/rspec/core/dsl.rb#42
42 | def describe(*args, &example_group_block); end
43 |
44 | # source://rspec-core/3.13.0/lib/rspec/core/dsl.rb#42
45 | def example_group(*args, &example_group_block); end
46 |
47 | # source://rspec-core/3.13.0/lib/rspec/core/dsl.rb#42
48 | def fcontext(*args, &example_group_block); end
49 |
50 | # source://rspec-core/3.13.0/lib/rspec/core/dsl.rb#42
51 | def fdescribe(*args, &example_group_block); end
52 |
53 | # source://rspec-core/3.13.0/lib/rspec/core.rb#58
54 | def reset; end
55 |
56 | # source://rspec-core/3.13.0/lib/rspec/core/shared_example_group.rb#110
57 | def shared_context(name, *args, &block); end
58 |
59 | # source://rspec-core/3.13.0/lib/rspec/core/shared_example_group.rb#110
60 | def shared_examples(name, *args, &block); end
61 |
62 | # source://rspec-core/3.13.0/lib/rspec/core/shared_example_group.rb#110
63 | def shared_examples_for(name, *args, &block); end
64 |
65 | # source://rspec-core/3.13.0/lib/rspec/core.rb#160
66 | def world; end
67 |
68 | # source://rspec-core/3.13.0/lib/rspec/core.rb#49
69 | def world=(_arg0); end
70 |
71 | # source://rspec-core/3.13.0/lib/rspec/core/dsl.rb#42
72 | def xcontext(*args, &example_group_block); end
73 |
74 | # source://rspec-core/3.13.0/lib/rspec/core/dsl.rb#42
75 | def xdescribe(*args, &example_group_block); end
76 | end
77 | end
78 |
79 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#7
80 | module RSpec::Sorbet
81 | extend ::RSpec::Sorbet::Doubles
82 | end
83 |
84 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#8
85 | module RSpec::Sorbet::Doubles
86 | requires_ancestor { Kernel }
87 |
88 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#15
89 | sig { void }
90 | def allow_doubles!; end
91 |
92 | # @return [void]
93 | #
94 | # source://sorbet-runtime/0.5.11609/lib/types/private/methods/_methods.rb#257
95 | def allow_instance_doubles!(*args, **_arg1, &blk); end
96 |
97 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#36
98 | sig { params(clear_existing: T::Boolean).void }
99 | def reset!(clear_existing: T.unsafe(nil)); end
100 |
101 | private
102 |
103 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#139
104 | sig { params(signature: T.untyped, opts: T::Hash[T.untyped, T.untyped]).void }
105 | def call_validation_error_handler(signature, opts); end
106 |
107 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#65
108 | sig { returns(T.nilable(T::Boolean)) }
109 | def configured; end
110 |
111 | # @return [Boolean, nil]
112 | #
113 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#65
114 | def configured=(_arg0); end
115 |
116 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#127
117 | sig { params(message: ::String).returns(T::Boolean) }
118 | def double_message_with_ellipsis?(message); end
119 |
120 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#62
121 | sig { returns(T.nilable(T.proc.params(signature: T.untyped, opts: T::Hash[T.untyped, T.untyped]).void)) }
122 | def existing_call_validation_error_handler; end
123 |
124 | # @return [T.proc.params(signature: T.untyped, opts: T::Hash[T.untyped, T.untyped]).void, nil]
125 | #
126 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#62
127 | def existing_call_validation_error_handler=(_arg0); end
128 |
129 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#59
130 | sig { returns(T.nilable(T.proc.params(signature: ::Exception).void)) }
131 | def existing_inline_type_error_handler; end
132 |
133 | # @return [T.proc.params(signature: Exception).void, nil]
134 | #
135 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#59
136 | def existing_inline_type_error_handler=(_arg0); end
137 |
138 | # @raise [TypeError]
139 | #
140 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#73
141 | sig { params(signature: T.untyped, opts: T.untyped).void }
142 | def handle_call_validation_error(signature, opts); end
143 |
144 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#80
145 | sig { params(error: ::Exception).void }
146 | def inline_type_error_handler(error); end
147 |
148 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#134
149 | sig { params(message: ::String).returns(T::Boolean) }
150 | def typed_array_message?(message); end
151 |
152 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#118
153 | sig { params(message: ::String).returns(T::Boolean) }
154 | def unable_to_check_type_for_message?(message); end
155 | end
156 |
157 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#68
158 | RSpec::Sorbet::Doubles::INLINE_DOUBLE_REGEX = T.let(T.unsafe(nil), Regexp)
159 |
160 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#131
161 | RSpec::Sorbet::Doubles::TYPED_ARRAY_MESSAGE = T.let(T.unsafe(nil), Regexp)
162 |
163 | # source://rspec-sorbet//lib/rspec/sorbet/doubles.rb#123
164 | RSpec::Sorbet::Doubles::VERIFYING_DOUBLE_OR_DOUBLE = T.let(T.unsafe(nil), Regexp)
165 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/rspec.rbi:
--------------------------------------------------------------------------------
1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with:
2 | # srb rbi gems
3 |
4 | # typed: strict
5 | #
6 | # If you would like to make changes to this file, great! Please create the gem's shim here:
7 | #
8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/rspec/all/rspec.rbi
9 | #
10 | # rspec-3.13.0
11 |
12 | module RSpec
13 | end
14 | module RSpec::Version
15 | end
16 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/rspec@3.13.0.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `rspec` gem.
5 | # Please instead update this file by running `bin/tapioca gem rspec`.
6 |
7 |
8 | # source://rspec//lib/rspec/version.rb#1
9 | module RSpec
10 | class << self
11 | # source://rspec-core/3.13.0/lib/rspec/core.rb#70
12 | def clear_examples; end
13 |
14 | # source://rspec-core/3.13.0/lib/rspec/core.rb#85
15 | def configuration; end
16 |
17 | # source://rspec-core/3.13.0/lib/rspec/core.rb#49
18 | def configuration=(_arg0); end
19 |
20 | # source://rspec-core/3.13.0/lib/rspec/core.rb#97
21 | def configure; end
22 |
23 | # source://rspec-core/3.13.0/lib/rspec/core.rb#194
24 | def const_missing(name); end
25 |
26 | # source://rspec-core/3.13.0/lib/rspec/core/dsl.rb#42
27 | def context(*args, &example_group_block); end
28 |
29 | # source://rspec-core/3.13.0/lib/rspec/core.rb#122
30 | def current_example; end
31 |
32 | # source://rspec-core/3.13.0/lib/rspec/core.rb#128
33 | def current_example=(example); end
34 |
35 | # source://rspec-core/3.13.0/lib/rspec/core.rb#154
36 | def current_scope; end
37 |
38 | # source://rspec-core/3.13.0/lib/rspec/core.rb#134
39 | def current_scope=(scope); end
40 |
41 | # source://rspec-core/3.13.0/lib/rspec/core/dsl.rb#42
42 | def describe(*args, &example_group_block); end
43 |
44 | # source://rspec-core/3.13.0/lib/rspec/core/dsl.rb#42
45 | def example_group(*args, &example_group_block); end
46 |
47 | # source://rspec-core/3.13.0/lib/rspec/core/dsl.rb#42
48 | def fcontext(*args, &example_group_block); end
49 |
50 | # source://rspec-core/3.13.0/lib/rspec/core/dsl.rb#42
51 | def fdescribe(*args, &example_group_block); end
52 |
53 | # source://rspec-core/3.13.0/lib/rspec/core.rb#58
54 | def reset; end
55 |
56 | # source://rspec-core/3.13.0/lib/rspec/core/shared_example_group.rb#110
57 | def shared_context(name, *args, &block); end
58 |
59 | # source://rspec-core/3.13.0/lib/rspec/core/shared_example_group.rb#110
60 | def shared_examples(name, *args, &block); end
61 |
62 | # source://rspec-core/3.13.0/lib/rspec/core/shared_example_group.rb#110
63 | def shared_examples_for(name, *args, &block); end
64 |
65 | # source://rspec-core/3.13.0/lib/rspec/core.rb#160
66 | def world; end
67 |
68 | # source://rspec-core/3.13.0/lib/rspec/core.rb#49
69 | def world=(_arg0); end
70 |
71 | # source://rspec-core/3.13.0/lib/rspec/core/dsl.rb#42
72 | def xcontext(*args, &example_group_block); end
73 |
74 | # source://rspec-core/3.13.0/lib/rspec/core/dsl.rb#42
75 | def xdescribe(*args, &example_group_block); end
76 | end
77 | end
78 |
79 | # source://rspec//lib/rspec/version.rb#2
80 | module RSpec::Version; end
81 |
82 | # source://rspec//lib/rspec/version.rb#3
83 | RSpec::Version::STRING = T.let(T.unsafe(nil), String)
84 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/safe_type.rbi:
--------------------------------------------------------------------------------
1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with:
2 | # srb rbi gems
3 |
4 | # typed: strict
5 | #
6 | # If you would like to make changes to this file, great! Please create the gem's shim here:
7 | #
8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/safe_type/all/safe_type.rbi
9 | #
10 | # safe_type-1.1.1
11 |
12 | module SafeType
13 | def self.coerce!(input, rule); end
14 | def self.coerce(input, rule, coerce_key = nil); end
15 | end
16 | class SafeType::Converter
17 | def self.to_bool(input); end
18 | def self.to_date(input); end
19 | def self.to_date_time(input); end
20 | def self.to_false(input); end
21 | def self.to_float(input); end
22 | def self.to_int(input); end
23 | def self.to_time(input); end
24 | def self.to_true(input); end
25 | def self.to_type(input, type); end
26 | end
27 | class SafeType::CoercionError < StandardError
28 | def desired_type; end
29 | def initialize(value, desired_type, key = nil); end
30 | def key; end
31 | def value; end
32 | end
33 | class SafeType::ValidationError < StandardError
34 | def desired_type; end
35 | def initialize(value, desired_type, key = nil); end
36 | def key; end
37 | def value; end
38 | end
39 | class SafeType::EmptyValueError < StandardError
40 | def desired_type; end
41 | def initialize(desired_type, key = nil); end
42 | def key; end
43 | end
44 | class SafeType::InvalidRuleError < ArgumentError
45 | def initialize; end
46 | end
47 | class SafeType::Rule
48 | def after(input); end
49 | def before(input); end
50 | def coerce(input, key = nil); end
51 | def initialize(type:, default: nil, required: nil, **args); end
52 | def is_valid?(input); end
53 | def self.coerce(input); end
54 | def self.default; end
55 | def self.strict; end
56 | end
57 | module SafeType::BooleanMixin
58 | end
59 | class TrueClass
60 | include SafeType::BooleanMixin
61 | end
62 | class FalseClass
63 | include SafeType::BooleanMixin
64 | end
65 | class SafeType::Boolean < SafeType::Rule
66 | def initialize(type: nil, **args); end
67 | def self.default(value = nil); end
68 | end
69 | class SafeType::Date < SafeType::Rule
70 | def initialize(type: nil, from: nil, to: nil, **args); end
71 | def is_valid?(input); end
72 | def self.default(value = nil, from: nil, to: nil); end
73 | def self.strict(from: nil, to: nil); end
74 | end
75 | class SafeType::DateTime < SafeType::Rule
76 | def initialize(type: nil, from: nil, to: nil, **args); end
77 | def is_valid?(input); end
78 | def self.default(value = nil, from: nil, to: nil); end
79 | def self.strict(from: nil, to: nil); end
80 | end
81 | class SafeType::Float < SafeType::Rule
82 | def initialize(type: nil, min: nil, max: nil, **args); end
83 | def is_valid?(input); end
84 | def self.default(value = nil, min: nil, max: nil); end
85 | def self.strict(min: nil, max: nil); end
86 | end
87 | class SafeType::Integer < SafeType::Rule
88 | def initialize(type: nil, min: nil, max: nil, **args); end
89 | def is_valid?(input); end
90 | def self.default(value = nil, min: nil, max: nil); end
91 | def self.strict(min: nil, max: nil); end
92 | end
93 | class SafeType::String < SafeType::Rule
94 | def after(input); end
95 | def initialize(type: nil, min_length: nil, max_length: nil, **args); end
96 | def is_valid?(input); end
97 | def self.default(value = nil, min_length: nil, max_length: nil); end
98 | def self.strict(min_length: nil, max_length: nil); end
99 | end
100 | class SafeType::Symbol < SafeType::Rule
101 | def after(input); end
102 | def initialize(type: nil, min_length: nil, max_length: nil, **args); end
103 | def is_valid?(input); end
104 | def self.default(value = nil, min_length: nil, max_length: nil); end
105 | def self.strict(min_length: nil, max_length: nil); end
106 | end
107 | class SafeType::Time < SafeType::Rule
108 | def initialize(type: nil, from: nil, to: nil, **args); end
109 | def is_valid?(input); end
110 | def self.default(value = nil, from: nil, to: nil); end
111 | def self.strict(from: nil, to: nil); end
112 | end
113 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/shellany@0.0.1.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `shellany` gem.
5 | # Please instead update this file by running `bin/tapioca gem shellany`.
6 |
7 |
8 | # source://shellany//lib/shellany/sheller.rb#3
9 | module Shellany; end
10 |
11 | # The Guard sheller abstract the actual subshell
12 | # calls and allow easier stubbing.
13 | #
14 | # source://shellany//lib/shellany/sheller.rb#7
15 | class Shellany::Sheller
16 | # Creates a new Guard::Sheller object.
17 | #
18 | # @param args [String] a command to run in a subshell
19 | # @param args [Array] an array of command parts to run in a subshell
20 | # @param args [*String] a list of command parts to run in a subshell
21 | # @return [Sheller] a new instance of Sheller
22 | #
23 | # source://shellany//lib/shellany/sheller.rb#16
24 | def initialize(*args); end
25 |
26 | # Returns true if the command succeeded, false otherwise.
27 | #
28 | # @return [Boolean] whether or not the command succeeded
29 | #
30 | # source://shellany//lib/shellany/sheller.rb#68
31 | def ok?; end
32 |
33 | # Returns true if the command has already been run, false otherwise.
34 | #
35 | # @return [Boolean] whether or not the command has already been run
36 | #
37 | # source://shellany//lib/shellany/sheller.rb#60
38 | def ran?; end
39 |
40 | # Runs the command.
41 | #
42 | # @return [Boolean] whether or not the command succeeded.
43 | #
44 | # source://shellany//lib/shellany/sheller.rb#44
45 | def run; end
46 |
47 | # Returns the value of attribute status.
48 | #
49 | # source://shellany//lib/shellany/sheller.rb#8
50 | def status; end
51 |
52 | # Returns the command's error output.
53 | #
54 | # @return [String] the command output
55 | #
56 | # source://shellany//lib/shellany/sheller.rb#88
57 | def stderr; end
58 |
59 | # Returns the command's output.
60 | #
61 | # @return [String] the command output
62 | #
63 | # source://shellany//lib/shellany/sheller.rb#78
64 | def stdout; end
65 |
66 | class << self
67 | # Only needed on JRUBY, because MRI properly detects ';' and metachars
68 | #
69 | # source://shellany//lib/shellany/sheller.rb#128
70 | def _shellize_if_needed(args); end
71 |
72 | # source://shellany//lib/shellany/sheller.rb#110
73 | def _system_with_capture(*args); end
74 |
75 | # source://shellany//lib/shellany/sheller.rb#103
76 | def _system_with_no_capture(*args); end
77 |
78 | # Shortcut for new(command).run
79 | #
80 | # source://shellany//lib/shellany/sheller.rb#24
81 | def run(*args); end
82 |
83 | # Shortcut for new(command).run.stderr
84 | #
85 | # source://shellany//lib/shellany/sheller.rb#36
86 | def stderr(*args); end
87 |
88 | # Shortcut for new(command).run.stdout
89 | #
90 | # source://shellany//lib/shellany/sheller.rb#30
91 | def stdout(*args); end
92 |
93 | # No output capturing
94 | #
95 | # NOTE: `$stdout.puts system('cls')` on Windows won't work like
96 | # it does for on systems with ansi terminals, so we need to be
97 | # able to call Kernel.system directly.
98 | #
99 | # source://shellany//lib/shellany/sheller.rb#99
100 | def system(*args); end
101 | end
102 | end
103 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/sorbet-coerce.rbi:
--------------------------------------------------------------------------------
1 | # This file is autogenerated. Do not edit it by hand. Regenerate it with:
2 | # srb rbi gems
3 |
4 | # typed: false
5 | #
6 | # If you would like to make changes to this file, great! Please create the gem's shim here:
7 | #
8 | # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/sorbet-coerce/all/sorbet-coerce.rbi
9 | #
10 | # sorbet-coerce-0.7.0
11 |
12 | module TypeCoerce
13 | def self.[](type); end
14 | end
15 | module TypeCoerce::Configuration
16 | def self.raise_coercion_error(*args, **, &blk); end
17 | def self.raise_coercion_error=(arg0); end
18 | end
19 | module Polyfill::Module::MezpIYXNoPT5bIiNzbGljZSJdfQ__
20 | end
21 | class TypeCoerce::CoercionError < SafeType::CoercionError
22 | end
23 | class TypeCoerce::ShapeError < SafeType::CoercionError
24 | end
25 | class TypeCoerce::Converter
26 | def _build_args(args, type, raise_coercion_error, coerce_empty_to_nil); end
27 | def _convert(value, type, raise_coercion_error, coerce_empty_to_nil); end
28 | def _convert_enum(value, type, raise_coercion_error, coerce_empty_to_nil); end
29 | def _convert_simple(value, type, raise_coercion_error, coerce_empty_to_nil); end
30 | def _convert_to_a(ary, type, raise_coercion_error, coerce_empty_to_nil); end
31 | def _nil_like?(value, type, coerce_empty_to_nil); end
32 | def coerce_nil(value, type, coerce_empty_to_nil); end
33 | def from(args, raise_coercion_error: nil, coerce_empty_to_nil: nil); end
34 | def initialize(type); end
35 | def new; end
36 | def to_s; end
37 | end
38 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/sorbet-coerce@0.7.0.rbi:
--------------------------------------------------------------------------------
1 | # typed: false
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `sorbet-coerce` gem.
5 | # Please instead update this file by running `bin/tapioca gem sorbet-coerce`.
6 |
7 |
8 | # source://sorbet-coerce//lib/sorbet-coerce/configuration.rb#4
9 | module TypeCoerce
10 | class << self
11 | # source://sorbet-coerce//lib/sorbet-coerce.rb#5
12 | def [](type); end
13 | end
14 | end
15 |
16 | # source://sorbet-coerce//lib/sorbet-coerce/converter.rb#11
17 | class TypeCoerce::CoercionError < ::SafeType::CoercionError; end
18 |
19 | # source://sorbet-coerce//lib/sorbet-coerce/configuration.rb#5
20 | module TypeCoerce::Configuration
21 | class << self
22 | # source://sorbet-coerce//lib/sorbet-coerce/configuration.rb#10
23 | sig { returns(T::Boolean) }
24 | def raise_coercion_error; end
25 |
26 | # @return [Boolean]
27 | #
28 | # source://sorbet-coerce//lib/sorbet-coerce/configuration.rb#10
29 | def raise_coercion_error=(_arg0); end
30 | end
31 | end
32 |
33 | # source://sorbet-coerce//lib/sorbet-coerce/converter.rb#15
34 | class TypeCoerce::Converter
35 | # @return [Converter] a new instance of Converter
36 | #
37 | # source://sorbet-coerce//lib/sorbet-coerce/converter.rb#16
38 | def initialize(type); end
39 |
40 | # source://sorbet-coerce//lib/sorbet-coerce/converter.rb#28
41 | def from(args, raise_coercion_error: T.unsafe(nil), coerce_empty_to_nil: T.unsafe(nil)); end
42 |
43 | # source://sorbet-coerce//lib/sorbet-coerce/converter.rb#20
44 | def new; end
45 |
46 | # source://sorbet-coerce//lib/sorbet-coerce/converter.rb#24
47 | def to_s; end
48 |
49 | private
50 |
51 | # source://sorbet-coerce//lib/sorbet-coerce/converter.rb#176
52 | def _build_args(args, type, raise_coercion_error, coerce_empty_to_nil); end
53 |
54 | # source://sorbet-coerce//lib/sorbet-coerce/converter.rb#48
55 | def _convert(value, type, raise_coercion_error, coerce_empty_to_nil); end
56 |
57 | # source://sorbet-coerce//lib/sorbet-coerce/converter.rb#120
58 | def _convert_enum(value, type, raise_coercion_error, coerce_empty_to_nil); end
59 |
60 | # source://sorbet-coerce//lib/sorbet-coerce/converter.rb#130
61 | def _convert_simple(value, type, raise_coercion_error, coerce_empty_to_nil); end
62 |
63 | # source://sorbet-coerce//lib/sorbet-coerce/converter.rb#160
64 | def _convert_to_a(ary, type, raise_coercion_error, coerce_empty_to_nil); end
65 |
66 | # @return [Boolean]
67 | #
68 | # source://sorbet-coerce//lib/sorbet-coerce/converter.rb#194
69 | def _nil_like?(value, type, coerce_empty_to_nil); end
70 |
71 | # source://sorbet-coerce//lib/sorbet-coerce/converter.rb#202
72 | def coerce_nil(value, type, coerce_empty_to_nil); end
73 | end
74 |
75 | # source://sorbet-coerce//lib/sorbet-coerce/converter.rb#38
76 | TypeCoerce::Converter::PRIMITIVE_TYPES = T.let(T.unsafe(nil), Set)
77 |
78 | # source://sorbet-coerce//lib/sorbet-coerce/converter.rb#12
79 | class TypeCoerce::ShapeError < ::SafeType::CoercionError; end
80 |
--------------------------------------------------------------------------------
/sorbet/rbi/gems/tzinfo@2.0.6.rbi:
--------------------------------------------------------------------------------
1 | # typed: true
2 |
3 | # DO NOT EDIT MANUALLY
4 | # This is an autogenerated file for types exported from the `tzinfo` gem.
5 | # Please instead update this file by running `bin/tapioca gem tzinfo`.
6 |
7 |
8 | # THIS IS AN EMPTY RBI FILE.
9 | # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem
10 |
--------------------------------------------------------------------------------
/sorbet/rbi/shims/rails.rbi:
--------------------------------------------------------------------------------
1 | # typed: strict
2 |
3 | module Rails
4 | sig { returns(T.untyped) }
5 | def self.root
6 | end
7 |
8 | class Engine
9 | end
10 | end
11 |
12 | module ActionDispatch
13 | module Http
14 | class UploadedFile
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/sorbet/rbi/shims/repositories.rbi:
--------------------------------------------------------------------------------
1 | # typed: strict
2 |
3 | # FIXME: This is a patch for some Factorial abstractions that haven't quite been
4 | # removed from the gem yet. Once a clearer boundary is established, this should
5 | # be removed.
6 | module Repositories
7 | module ReadResult
8 | end
9 | class InMemoryReadResult
10 | end
11 | module ReadOutputContext
12 | end
13 | module OutputContexts
14 | class Filter
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/sorbet/tapioca/config.yml:
--------------------------------------------------------------------------------
1 | gem:
2 | # Add your `gem` command parameters here:
3 | #
4 | # exclude:
5 | # - gem_name
6 | # doc: true
7 | # workers: 5
8 | dsl:
9 | # Add your `dsl` command parameters here:
10 | #
11 | # exclude:
12 | # - SomeGeneratorName
13 | # workers: 5
14 |
--------------------------------------------------------------------------------
/sorbet/tapioca/require.rb:
--------------------------------------------------------------------------------
1 | # typed: true
2 | # frozen_string_literal: true
3 |
4 | require "active_support/all"
5 | require "bigdecimal"
6 | require "date"
7 | require "pry"
8 | require "rbi"
9 | require "rspec"
10 | require "sorbet-coerce"
11 | require "sorbet-runtime"
12 |
--------------------------------------------------------------------------------
/spec/capability_factory_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: false
3 |
4 | require "spec_helper"
5 | require_relative "./dummy_capability"
6 | require_relative "../lib/resource_registry/capability_factory"
7 |
8 | RSpec.describe ResourceRegistry::CapabilityFactory do
9 | let(:capability) { described_class }
10 | let(:capability_config) { DummyCapability.new(time_dimension: "foo") }
11 |
12 | describe "#dump" do
13 | it do
14 | expect(capability.dump(capability_config)).to include_json(
15 | time_dimension: "foo"
16 | )
17 | end
18 | end
19 |
20 | describe "#load" do
21 | let(:data) { { "key" => "dummy_capability", :time_dimension => "bar" } }
22 |
23 | it do
24 | cap =
25 | capability.load(
26 | data,
27 | capabilities: {
28 | dummy_capability: DummyCapability
29 | }
30 | )
31 | expect(described_class.dump(cap)).to include_json(time_dimension: "bar")
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/spec/dummy_capability.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: strict
3 |
4 | class DummyCapability < T::Struct
5 | extend T::Sig
6 |
7 | include ResourceRegistry::Capabilities::CapabilityConfig
8 |
9 | const :time_dimension, T.nilable(String), default: "day"
10 |
11 | sig { override.returns(Symbol) }
12 | def self.key
13 | :dummy_capability
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/spec/dummy_repo.rb:
--------------------------------------------------------------------------------
1 | # typed: false
2 |
3 | require_relative "../lib/resource_registry/repositories/base"
4 |
5 | class DummyEntity < T::Struct
6 | const :id, Integer
7 | end
8 |
9 | class DummyRepo
10 | extend T::Sig
11 | extend T::Helpers
12 | extend T::Generic
13 |
14 | include ResourceRegistry::Repositories::Base
15 |
16 | Entity = type_member { { upper: DummyEntity } }
17 |
18 | sig do
19 | params(dto: T::Struct, context: T.untyped).returns(
20 | ::Repositories::ReadResult[Entity]
21 | )
22 | end
23 | def read(dto:, context: ::Repositories::ReadOutputContext.new)
24 | entities = (1..10).map { |i| DummyEntity.new(id: i) }
25 | Repositories::InMemoryReadResult.new(context: context.new, list: entities)
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/spec/resource_registry/capabilities/capability_config_spec.rb:
--------------------------------------------------------------------------------
1 | # typed: false
2 |
3 | require "spec_helper"
4 | require_relative "../../../lib/resource_registry/capabilities/capability_config"
5 |
6 | class DummyCapability < T::Struct
7 | include ResourceRegistry::Capabilities::CapabilityConfig
8 |
9 | def self.key
10 | :dummy_capability
11 | end
12 | end
13 |
14 | RSpec.describe ResourceRegistry::Capabilities::CapabilityConfig do
15 | let(:schema) do
16 | SchemaRegistry::Schema.new(
17 | name: "dummy",
18 | namespace: "dummies",
19 | properties: [
20 | SchemaRegistry::Property.new(
21 | name: "foo",
22 | types: [SchemaRegistry::PropertyType::String],
23 | required: true
24 | )
25 | ]
26 | )
27 | end
28 | let(:capabilities) { { dummy_capability: DummyCapability.new } }
29 | let(:resource) do
30 | ResourceRegistry::Resource.new(
31 | repository_raw: DummyRepo.to_s,
32 | capabilities:,
33 | verbs: {
34 | },
35 | schema:
36 | )
37 | end
38 |
39 | it "should return resource's capability" do
40 | expect(DummyCapability.resource_capability?(resource:)).to be true
41 | expect(DummyCapability.resource_capability(resource:)).to be_a(DummyCapability)
42 | expect(DummyCapability.resource_capability!(resource:)).to be_a(DummyCapability)
43 | end
44 |
45 | context 'without the capability' do
46 | let(:capabilities) { {} }
47 |
48 | it "should return resource's capability" do
49 | expect(DummyCapability.resource_capability?(resource:)).to be false
50 | expect(DummyCapability.resource_capability(resource:)).to be_nil
51 | end
52 | end
53 | end
54 |
55 |
56 |
--------------------------------------------------------------------------------
/spec/resource_registry/registry_spec.rb:
--------------------------------------------------------------------------------
1 | # typed: false
2 |
3 | require "spec_helper"
4 | require_relative "../../lib/resource_registry/registry"
5 | require_relative "../dummy_repo"
6 |
7 | class DummyCapability < T::Struct
8 | include ResourceRegistry::Capabilities::CapabilityConfig
9 |
10 | def self.key
11 | :dummy_capability
12 | end
13 | end
14 |
15 | class VoidCapability < T::Struct
16 | include ResourceRegistry::Capabilities::CapabilityConfig
17 |
18 | def self.key
19 | :void_capability
20 | end
21 | end
22 |
23 | RSpec.describe ResourceRegistry::Registry do
24 | let(:resources) { [resource] }
25 | let(:registry) { described_class.new(resources: resources) }
26 | let(:schema) do
27 | SchemaRegistry::Schema.new(
28 | name: "employees",
29 | namespace: "employees",
30 | properties: [
31 | SchemaRegistry::Property.new(
32 | name: "foo",
33 | types: [SchemaRegistry::PropertyType::String],
34 | required: true
35 | )
36 | ]
37 | )
38 | end
39 | let(:resource) do
40 | ResourceRegistry::Resource.new(
41 | repository_raw: DummyRepo.to_s,
42 | capabilities: {
43 | dummy_capability: DummyCapability.new
44 | },
45 | verbs: {
46 | },
47 | schema: schema
48 | )
49 | end
50 | let(:identifier) { resource.identifier.to_s }
51 |
52 | describe "#initialize" do
53 | let(:resources) { [resource, resource] }
54 |
55 | it "not allow duplicated identifiers" do
56 | expect { registry }.to raise_error(
57 | ResourceRegistry::Registry::DuplicatedIdentifierError
58 | )
59 | end
60 | end
61 |
62 | describe "#fetch" do
63 | it { expect(registry.fetch(identifier)).to be(resource) }
64 | end
65 |
66 | describe "#fetch_all" do
67 | it { expect(registry.fetch_all).to eq({ identifier => resource }) }
68 | end
69 |
70 | describe "#fetch_for_repository" do
71 | it { expect(registry.fetch_for_repository(DummyRepo)).to(eq(resource)) }
72 | end
73 |
74 | describe "#fetch_with_capabilities" do
75 | let(:features) { [DummyCapability] }
76 |
77 | subject { registry.fetch_with_capabilities(*features) }
78 |
79 | it { expect(subject.size).to eq(1) }
80 |
81 | context 'the resource doesn\t have the capability' do
82 | let(:features) { [VoidCapability] }
83 |
84 | it { expect(subject.size).to eq(0) }
85 | end
86 | end
87 | end
88 |
--------------------------------------------------------------------------------
/spec/resource_registry/relationship_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: false
3 |
4 | require "spec_helper"
5 | require_relative "../../lib/resource_registry/relationship"
6 |
7 | RSpec.describe ResourceRegistry::Relationship do
8 | describe "#load" do
9 | let(:params) do
10 | {
11 | "name" => "test",
12 | "type" => "has_one",
13 | "field" => :test,
14 | "resource_id" => :test,
15 | "optional" => true,
16 | "primary_key" => :test
17 | }
18 | end
19 |
20 | subject { described_class.load(params) }
21 |
22 | it { expect(subject).to be_a(described_class) }
23 |
24 | context "when the spec is not valid" do
25 | let(:params) { { "type" => "has_one" } }
26 |
27 | it "raises an error" do
28 | expect { subject }.to raise_error(
29 | ResourceRegistry::RelationshipType::InvalidRelationshipSpec
30 | )
31 | end
32 | end
33 |
34 | # TODO: Check how to test this
35 | xcontext "with a custom type" do
36 | let(:type) { "policy_resolution" }
37 | let(:params) do
38 | {
39 | "name" => "test",
40 | "type" => type,
41 | "field" => :test,
42 | "resource_id" => :test,
43 | "optional" => true,
44 | "policies" => []
45 | }
46 | end
47 |
48 | it { expect(subject).to be_a(described_class) }
49 | end
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/spec/resource_registry/resource_spec.rb:
--------------------------------------------------------------------------------
1 | # typed: false
2 |
3 | require "spec_helper"
4 | require_relative "../../lib/resource_registry/resource"
5 | require_relative "../dummy_repo"
6 | require_relative "../dummy_capability"
7 | require_relative "../void_capability"
8 |
9 | RSpec.describe ResourceRegistry::Resource do
10 | let(:capability) { DummyCapability.new }
11 | let(:dummy_struct) { T::Struct }
12 | let(:schema) do
13 | SchemaRegistry::Schema.new(
14 | name: "employees",
15 | namespace: "employees",
16 | properties: [
17 | SchemaRegistry::Property.new(
18 | name: "foo",
19 | types: [SchemaRegistry::PropertyType::String],
20 | required: true
21 | )
22 | ]
23 | )
24 | end
25 | let(:verbs) do
26 | {
27 | copy:
28 | ResourceRegistry::Verb.new(
29 | id: :copy,
30 | dto_raw: dummy_struct.to_s,
31 | schema: schema
32 | )
33 | }
34 | end
35 | let(:resource) do
36 | ResourceRegistry::Resource.new(
37 | repository_raw: DummyRepo.to_s,
38 | description: "foo",
39 | schema: schema,
40 | verbs: verbs,
41 | capabilities: {
42 | dummy_capability: capability
43 | }
44 | )
45 | end
46 |
47 | it { expect(resource.schema).to be_a(SchemaRegistry::Schema) }
48 | it { expect(resource.schema.properties.first.name).to eq "foo" }
49 |
50 | describe "#collection_name" do
51 | it { expect(resource.collection_name).to eq("dummy_repos") }
52 | end
53 |
54 | describe "#path" do
55 | it { expect(resource.path).to eq("dummyrepo/dummy_repo") }
56 | end
57 |
58 | describe "#dump" do
59 | it { expect(resource.dump).to include_json(description: "foo") }
60 | end
61 |
62 | describe "#load" do
63 | let(:spec) { resource.dump }
64 | let(:configuration) do
65 | ResourceRegistry::Configuration.new.tap do |conf|
66 | conf.register_capability(:dummy_capability, DummyCapability)
67 | end
68 | end
69 |
70 | subject { described_class.load(spec, configuration: configuration) }
71 |
72 | it { expect(subject).to be_a(described_class) }
73 |
74 | context "when verb has no id" do
75 | let(:dump) { resource.dump }
76 | let(:spec) { resource.dump.tap { |s| s["verbs"]["copy"].delete("id") } }
77 |
78 | it { expect { subject }.to raise_error(ArgumentError) }
79 | end
80 |
81 | describe "paginateable" do
82 | context "when the paginateable property is not provided" do
83 | it "is true by default" do
84 | expect(subject.paginateable).to be true
85 | end
86 | end
87 |
88 | context "when the paginateable property is provided" do
89 | before { spec["paginateable"] = false }
90 |
91 | it "uses the value from the resource definition" do
92 | expect(subject.paginateable).to be false
93 | end
94 | end
95 | end
96 |
97 | describe "#capability!" do
98 | let(:feature) { DummyCapability }
99 |
100 | subject { resource.capability!(feature) }
101 |
102 | it { expect(subject).to eq(capability) }
103 |
104 | context 'The resource don\'t have such capability' do
105 | let(:feature) { VoidCapability }
106 |
107 | it { expect { subject }.to raise_error(ArgumentError) }
108 | end
109 | end
110 | end
111 | end
112 |
--------------------------------------------------------------------------------
/spec/resource_registry/versions_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: false
3 |
4 | require "spec_helper"
5 | require_relative "../../lib/resource_registry/versions"
6 |
7 | RSpec.describe ResourceRegistry::Versions do
8 | subject { described_class.new(versions: versions) }
9 |
10 | let(:versions) do
11 | [
12 | ResourceRegistry::Versions::Version.new("2024-01-01"),
13 | ResourceRegistry::Versions::Version.new("2024-04-01", aliases: "stable")
14 | ]
15 | end
16 |
17 | describe "#find!" do
18 | it "returns a version" do
19 | expect(subject.find!("2024-04-01").to_s).to eq("2024-04-01")
20 | end
21 |
22 | it "raises error with wrong name" do
23 | expect { subject.find!("fake") }.to raise_error(
24 | RuntimeError,
25 | 'Version \'fake\' not found'
26 | )
27 | end
28 | end
29 |
30 | describe "#find" do
31 | it "finds a version from right name" do
32 | expect(subject.find("2024-04-01").to_s).to eq("2024-04-01")
33 | end
34 |
35 | it "does not find a version from wrong name" do
36 | expect(subject.find("unknown")).to be_nil
37 | end
38 |
39 | it "does not find a version from empty header" do
40 | expect(subject.find(nil)).to be_nil
41 | expect(subject.find("")).to be_nil
42 | end
43 |
44 | it "returns a version with an alias" do
45 | expect(subject.find!("stable").to_s).to eq("2024-04-01")
46 | end
47 | end
48 |
49 | describe "#find_next" do
50 | context "when given an old version" do
51 | it "returns the following version" do
52 | expect(subject.find_next("2024-01-01").to_s).to eq("2024-04-01")
53 | end
54 |
55 | context "when given a version object" do
56 | it "returns the following version" do
57 | version = subject.find!("2024-01-01")
58 |
59 | expect(subject.find_next(version).to_s).to eq("2024-04-01")
60 | end
61 | end
62 | end
63 |
64 | context "when given the last version" do
65 | it "does not returns a version" do
66 | expect(subject.find_next("2024-04-01")).to be_nil
67 | end
68 |
69 | context "when given a version object" do
70 | it "does not returns a version" do
71 | version = subject.find!("2024-04-01")
72 |
73 | expect(subject.find_next(version)).to be_nil
74 | end
75 | end
76 | end
77 |
78 | context "when given a random value" do
79 | it "does not returns a version" do
80 | expect { subject.find_next("2025-04-01") }.to raise_error(
81 | RuntimeError,
82 | 'Version \'2025-04-01\' not found'
83 | )
84 | end
85 | end
86 |
87 | context "when given a list of unsorted versions" do
88 | let(:versions) do
89 | [
90 | ResourceRegistry::Versions::Version.new(
91 | "2024-03-01",
92 | aliases: "stable"
93 | ),
94 | ResourceRegistry::Versions::Version.new(
95 | "2024-04-01",
96 | aliases: "deprecated"
97 | ),
98 | ResourceRegistry::Versions::Version.new("2024-02-01")
99 | ]
100 | end
101 |
102 | it "orders and returns the following version" do
103 | expect(subject.find_next("2024-02-01").to_s).to eq("2024-03-01")
104 | end
105 | end
106 | end
107 |
108 | describe "#in_range" do
109 | let(:versions) do
110 | [
111 | ResourceRegistry::Versions::Version.new("2024-01-01"),
112 | ResourceRegistry::Versions::Version.new("2024-04-28"),
113 | ResourceRegistry::Versions::Version.new("2024-09-20"),
114 | ResourceRegistry::Versions::Version.new("2025-01-09")
115 | ]
116 | end
117 |
118 | it "filters versions by >= from and <= to" do
119 | expect(subject.in_range("2024-04-28", "2024-09-20").count).to eq(2)
120 | end
121 |
122 | context "with only from" do
123 | it "filters versions by >= from" do
124 | expect(subject.in_range("2024-04-28", nil).count).to eq(3)
125 | end
126 | end
127 |
128 | context "with only to" do
129 | it "filters versions by <= to" do
130 | expect(subject.in_range(nil, "2024-09-20").count).to eq(3)
131 | end
132 | end
133 |
134 | context "with unexisting version" do
135 | it "raises error with wrong name" do
136 | expect { subject.in_range("2022-01-01", "2022-01-01") }.to raise_error(
137 | RuntimeError,
138 | 'Version \'2022-01-01\' not found'
139 | )
140 | end
141 | end
142 |
143 | context "without from and to" do
144 | it "does not apply any filter" do
145 | expect(subject.in_range(nil, nil).count).to eq(4)
146 | end
147 | end
148 | end
149 | end
150 |
--------------------------------------------------------------------------------
/spec/schema_registry/maybe_spec.rb:
--------------------------------------------------------------------------------
1 | # typed: false
2 |
3 | require "spec_helper" # you are forced to load the whole context for this :/
4 | require_relative "../../lib/schema_registry/maybe"
5 |
6 | RSpec.describe Maybe do
7 | let(:present) { Maybe.from(6) }
8 | let(:nilable) { Maybe.from(nil) }
9 | let(:absent) { Maybe.empty }
10 |
11 | describe "#strip" do
12 | let(:input) { { present: Maybe.from(6), absent: Maybe.empty, always: 5 } }
13 |
14 | subject { Maybe.strip(input) }
15 |
16 | it "removes all absent values, unwraps present `Maybe`s" do
17 | expect(subject).to match({ present: 6, always: 5 })
18 | end
19 | end
20 |
21 | describe "#present?" do
22 | subject { maybe.present? }
23 |
24 | context "when a value is present" do
25 | let(:maybe) { present }
26 |
27 | it "returns true" do
28 | expect(subject).to be true
29 | end
30 | end
31 |
32 | context "when a `nil` value is present" do
33 | let(:maybe) { nilable }
34 |
35 | it "returns true" do
36 | expect(subject).to be true
37 | end
38 | end
39 |
40 | context "when a value is not present" do
41 | let(:maybe) { absent }
42 |
43 | it "returns false" do
44 | expect(subject).to be false
45 | end
46 | end
47 | end
48 |
49 | describe "#absent?" do
50 | subject { maybe.absent? }
51 |
52 | context "when a value is present" do
53 | let(:maybe) { present }
54 |
55 | it "returns false" do
56 | expect(subject).to be false
57 | end
58 | end
59 |
60 | context "when a `nil` value is present" do
61 | let(:maybe) { nilable }
62 |
63 | it "returns false" do
64 | expect(subject).to be false
65 | end
66 | end
67 |
68 | context "when a value is not present" do
69 | let(:maybe) { absent }
70 |
71 | it "returns true" do
72 | expect(subject).to be true
73 | end
74 | end
75 | end
76 |
77 | describe "#or_default" do
78 | subject { maybe.or_default(default) }
79 |
80 | let(:default) { "1337" }
81 |
82 | context "when a value is present" do
83 | let(:maybe) { present }
84 |
85 | it "returns the contained value" do
86 | expect(subject).to be 6
87 | end
88 | end
89 |
90 | context "when a `nil` value is present" do
91 | let(:maybe) { nilable }
92 |
93 | it "returns the contained value" do
94 | expect(subject).to be_nil
95 | end
96 | end
97 |
98 | context "when a value is not present" do
99 | let(:maybe) { absent }
100 |
101 | it "returns the default value" do
102 | expect(subject).to be default
103 | end
104 | end
105 | end
106 |
107 | describe "#when_present" do
108 | subject { maybe.when_present { |v| (v || 0) + 1 } }
109 |
110 | context "when a value is present" do
111 | let(:maybe) { present }
112 |
113 | it "returns the value returned from the block" do
114 | expect(subject).to be 7
115 | end
116 | end
117 |
118 | context "when a `nil` value is present" do
119 | let(:maybe) { nilable }
120 |
121 | it "returns the value returned from the block" do
122 | expect(subject).to be 1
123 | end
124 | end
125 |
126 | context "when a value is not present" do
127 | let(:maybe) { absent }
128 |
129 | it "returns nil" do
130 | expect(subject).to be_nil
131 | end
132 | end
133 | end
134 |
135 | describe "#when_absent" do
136 | subject { maybe.when_absent { 1 + 1 } }
137 |
138 | context "when a value is present" do
139 | let(:maybe) { present }
140 |
141 | it "returns nil" do
142 | expect(subject).to be_nil
143 | end
144 | end
145 |
146 | context "when a `nil` value is present" do
147 | let(:maybe) { nilable }
148 |
149 | it "returns nil" do
150 | expect(subject).to be_nil
151 | end
152 | end
153 |
154 | context "when a value is not present" do
155 | let(:maybe) { absent }
156 |
157 | it "returns the value returned from the block" do
158 | expect(subject).to be 2
159 | end
160 | end
161 | end
162 |
163 | describe "#filter" do
164 | subject { maybe.filter { |_e| filter_output } }
165 |
166 | context "when the filter returns false" do
167 | let(:filter_output) { false }
168 |
169 | context "and a value is present" do
170 | let(:maybe) { present }
171 |
172 | it "returns an empty instance" do
173 | expect(subject.absent?).to be true
174 | end
175 | end
176 |
177 | context "and a `nil` value is present" do
178 | let(:maybe) { nilable }
179 |
180 | it "returns an empty instance" do
181 | expect(subject.absent?).to be true
182 | end
183 | end
184 |
185 | context "and a value is not present" do
186 | let(:maybe) { absent }
187 |
188 | it "returns an empty instance" do
189 | expect(subject.absent?).to be true
190 | end
191 | end
192 | end
193 |
194 | context "when the filter returns true" do
195 | let(:filter_output) { true }
196 |
197 | context "and a value is present" do
198 | let(:maybe) { present }
199 |
200 | it "returns the same instance" do
201 | expect(subject).to be maybe
202 | end
203 | end
204 |
205 | context "and a `nil` value is present" do
206 | let(:maybe) { nilable }
207 |
208 | it "returns the same instance" do
209 | expect(subject).to be maybe
210 | end
211 | end
212 |
213 | context "and a value is not present" do
214 | let(:maybe) { absent }
215 |
216 | it "returns the same instance" do
217 | expect(subject).to be maybe
218 | end
219 | end
220 | end
221 | end
222 |
223 | describe "#map" do
224 | subject { maybe.map { |e| (e || 0) + 1 } }
225 |
226 | context "when a value is present" do
227 | let(:maybe) { present }
228 |
229 | it "returns an instance containing the result of the block" do
230 | expect(subject.value).to eq Maybe.from(7).value
231 | end
232 | end
233 |
234 | context "when a `nil` value is present" do
235 | let(:maybe) { nilable }
236 |
237 | it "returns an instance containing the result of the block" do
238 | expect(subject.value).to eq Maybe.from(1).value
239 | end
240 | end
241 |
242 | context "when a value is not present" do
243 | let(:maybe) { absent }
244 |
245 | it "returns the same instance" do
246 | expect(subject).to be maybe
247 | end
248 | end
249 | end
250 |
251 | describe "#==" do
252 | subject { first == second }
253 |
254 | context "when both have values" do
255 | context "and the values are the same" do
256 | let(:first) { Maybe.from("Potato") }
257 | let(:second) { Maybe.from("Potato") }
258 |
259 | it("returns true") { expect(subject).to be true }
260 | end
261 |
262 | context "and the values are different" do
263 | let(:first) { Maybe.from("Tomato") }
264 | let(:second) { Maybe.from("Carrot") }
265 |
266 | it("returns false") { expect(subject).to be false }
267 | end
268 | end
269 |
270 | context "when only one has values" do
271 | let(:first) { Maybe.from("Apricot") }
272 | let(:second) { Maybe.empty }
273 |
274 | it("returns false") { expect(subject).to be false }
275 | end
276 |
277 | context "when neither has values" do
278 | let(:first) { Maybe.empty }
279 | let(:second) { Maybe.empty }
280 |
281 | it("returns true") { expect(subject).to be true }
282 | end
283 | end
284 | end
285 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | # typed: strict
2 | # frozen_string_literal: true
3 |
4 | require "sorbet-runtime"
5 | require "rspec/sorbet"
6 | require "rspec/json_expectations"
7 |
8 | require "pry"
9 | require_relative "../lib/resource_registry"
10 |
--------------------------------------------------------------------------------
/spec/void_capability.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # typed: strict
3 |
4 | class VoidCapability < T::Struct
5 | extend T::Sig
6 |
7 | include ResourceRegistry::Capabilities::CapabilityConfig
8 |
9 | sig { override.returns(Symbol) }
10 | def self.key
11 | :void_capability
12 | end
13 | end
14 |
--------------------------------------------------------------------------------