{"id":16737210,"url":"https://github.com/akxcv/thy","last_synced_at":"2025-03-21T22:31:28.399Z","repository":{"id":35136302,"uuid":"211420844","full_name":"akxcv/thy","owner":"akxcv","description":"A minimal, strict runtime type system for Ruby","archived":false,"fork":false,"pushed_at":"2023-03-16T06:07:17.000Z","size":20,"stargazers_count":7,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-18T05:34:44.339Z","etag":null,"topics":["minimal","runtime","strict","type-system"],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/akxcv.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-09-28T00:22:47.000Z","updated_at":"2024-07-12T12:44:28.000Z","dependencies_parsed_at":"2024-10-28T11:36:32.618Z","dependency_job_id":"b21fe756-44a0-41c5-96d8-f5ddbcc20319","html_url":"https://github.com/akxcv/thy","commit_stats":{"total_commits":12,"total_committers":3,"mean_commits":4.0,"dds":0.25,"last_synced_commit":"139499e3f3aebb343a5da2ae6bbc65e7c117e8e0"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akxcv%2Fthy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akxcv%2Fthy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akxcv%2Fthy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akxcv%2Fthy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/akxcv","download_url":"https://codeload.github.com/akxcv/thy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244880119,"owners_count":20525505,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["minimal","runtime","strict","type-system"],"created_at":"2024-10-13T00:25:19.265Z","updated_at":"2025-03-21T22:31:27.983Z","avatar_url":"https://github.com/akxcv.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Thy [![Build Status](https://travis-ci.org/akxcv/thy.svg?branch=master)](https://travis-ci.org/akxcv/thy)\n\nThy is a minimal, strict runtime type system for Ruby.\n\n## Motivation\n\nThere are many existing runtime type systems for Ruby, most notably, dry-types. Here's why you might\nprefer Thy:\n\n- Thy encourages strictness. Avoiding type coercion as much as possible is an excellent way to keep\nyour code predictable and straightforward.\n- Minimalism. Thy's API only has what's needed, nothing more.\n- No Any type. Don't worry, if you *have to*, you [can get it](#custom-types)!\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'thy'\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install thy\n\n## Usage\n\nIt's recommended not to use Thy directly (although [you can](#direct-usage)), but to create a module\nfor working with types, and to include `Thy::Types` into it.\n\n```ruby\nmodule Types\n  include Thy::Types\nend\n```\n\nTo run a type check, call `check` on a type you need. For example:\n\n```ruby\nmodule Types\n  include Thy::Types\nend\n\nTypes::String.check('a string').success? # =\u003e true\nTypes::Integer.check(3.14).success?      # =\u003e false\n```\n\nIf a check fails, a message describing the failure is provided:\n\n```ruby\nTypes::String.check(3).failure? # =\u003e true\nTypes::String.check(3).message # =\u003e \"Expected a String, but got: 3\"\n```\n\n### Custom types\n\nThy allows you to define custom types via `Thy::Type`'s constructor:\n\n```ruby\nmodule Types\n  include Thy::Types\n\n  NonZeroValue = Thy::Type.new { |value| value != 0 }\nend\n```\n\n#### Providing meaningful error messages\n\n```ruby\nmodule Types\n  include Thy::Types\n\n  NonZeroValue = Thy::Type.new do |value|\n    value != 0 || Thy::Result::Failure.new(\"Expected #{value.inspect} to be nonzero\")\n  end\nend\n```\n\n#### Building on top of existing types\n\nExtending existing types is simple, too:\n\n```ruby\nmodule Types\n  include Thy::Types\n\n  NonZeroInteger = Thy.refine_type(Integer, Thy::Type.new { |v| v != 0 })\nend\n```\n\n### Direct usage\n\nYou can use Thy types directly, for example, if you'd like to play around in the console:\n\n```ruby\nThy::String.check('Bob').success? # =\u003e true\nPositiveInteger = Thy.refine_type(Integer, Thy::Type.new { |v| v \u003e 0 })\n```\n\n## Built-in type reference\n\n### Primitive types\n\n```ruby\n# String\nThy::String.check('Bob').success? # =\u003e true\n\n# Symbol\nThy::Symbol.check(:bob).success? # =\u003e true\n\n# Numeric\nThy::Numeric.check(3.14).success? # =\u003e true\nThy::Numeric.check(0).success? # =\u003e true\n\n# Float\nThy::Float.check(3.14).success? # =\u003e true\n\n# Integer\nThy::Integer.check(3).success? # =\u003e true\n\n# Boolean\nThy::Boolean.check(true).success? # =\u003e true\nThy::Boolean.check(false).success? # =\u003e true\n\n# Time\nThy::Time.check(Time.now).success? # =\u003e true\nThy::Time.check(0).success? # =\u003e false\n\n# DateTime\nrequire 'date'\nThy::DateTime.check(DateTime.now).success? # =\u003e true\nThy::DateTime.check(0).success? # =\u003e false\n\n# nil\nThy::Nil.check(nil).success? # =\u003e true\nThy::Nil.check(0).success? # =\u003e false\n```\n\n### Parameterized types\n\n```ruby\n# Array\nThy::Array(Thy::Integer).check([1, 2, 3]).success? # =\u003e true\nThy::Array(Thy::String).check(%w[hi hello sup]).success? # =\u003e true\n\n# Hash\nThy::Hash({\n  name: Thy::String,\n  age: Thy::Integer,\n}).check({ name: 'Bob', age: 18 }).success? # =\u003e true\n\n# Map\nThy::Map(Thy::Symbol, Thy::Integer).check({ a: 1, b: 2 }).success? # =\u003e true\n\n# Variant\nThy::Variant(Thy::Integer, Thy::Float).check(3.14).success? # =\u003e true\nThy::Variant(Thy::Integer, Thy::Float).check(3).success? # =\u003e true\n\n# Enum\nThy::Enum('USD', 'EUR').check('EUR').success? # =\u003e true\n\n# Option\nThy::Option(Thy::String).check('a string').success? # =\u003e true\nThy::Option(Thy::String).check(nil).success? # =\u003e true\n\n# InstanceOf\nclass A; end\nclass B \u003c A; end\nclass C; end\nThy::InstanceOf(A).check(B.new).success? # =\u003e true\nThy::InstanceOf(A).check(C.new).success? # =\u003e false\n\n# ClassExtending\nThy::ClassExtending(A).check(B).success? # =\u003e true\nThy::ClassExtending(A).check(C).success? # =\u003e false\n```\n\n### Other types\n\n```ruby\n# UntypedArray\nThy::UntypedArray.check(1, 'string', 3.14).success? # =\u003e true\n\n# UntypedHash\nThy::UntypedHash.check({ a: 1, b: 'c', 1 =\u003e true }).success? # =\u003e true\n```\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/akxcv/thy.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakxcv%2Fthy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fakxcv%2Fthy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakxcv%2Fthy/lists"}