{"id":17925002,"url":"https://github.com/mwpastore/ioughta","last_synced_at":"2025-03-24T03:30:58.589Z","repository":{"id":56877925,"uuid":"68061210","full_name":"mwpastore/ioughta","owner":"mwpastore","description":"Helpers for defining sequences of constants in Ruby using a Go-like syntax","archived":false,"fork":false,"pushed_at":"2017-01-24T00:59:34.000Z","size":17,"stargazers_count":11,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-04-26T00:05:55.676Z","etag":null,"topics":["enumeration","ruby","ruby-gem","syntax-sugar"],"latest_commit_sha":null,"homepage":"","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/mwpastore.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}},"created_at":"2016-09-13T01:06:42.000Z","updated_at":"2024-01-04T16:07:32.000Z","dependencies_parsed_at":"2022-08-20T23:10:13.349Z","dependency_job_id":null,"html_url":"https://github.com/mwpastore/ioughta","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mwpastore%2Fioughta","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mwpastore%2Fioughta/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mwpastore%2Fioughta/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mwpastore%2Fioughta/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mwpastore","download_url":"https://codeload.github.com/mwpastore/ioughta/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245204458,"owners_count":20577352,"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":["enumeration","ruby","ruby-gem","syntax-sugar"],"created_at":"2024-10-28T20:51:56.362Z","updated_at":"2025-03-24T03:30:58.311Z","avatar_url":"https://github.com/mwpastore.png","language":"Ruby","readme":"# Io(ugh)ta\n\n[![Build Status](https://travis-ci.org/mwpastore/ioughta.svg?branch=master)](https://travis-ci.org/mwpastore/ioughta)\n[![Gem Version](https://badge.fury.io/rb/ioughta.svg)](https://badge.fury.io/rb/ioughta)\n\nHelpers for defining sequences of constants in Ruby using a Go-like syntax.\n\nGo has quite a nice facility for defining constants derived from a sequential\nvalue using a [simple and elegant syntax][1], so I thought I'd steal it for\nRuby. Rubyists tend to group constants together in hashes rather than littering\ntheir programs with countless constants, so there's a mechanism for that, too.\n\nAlthough there isn't as strong of a need for sequences of constants in Ruby as\nthere is in other languages such as Go, they are still sometimes required when\nworking with external systems such as databases and web APIs for which Ruby\nsymbols don't map cleanly. For example, a database column might store users'\nprivilege levels as 0, 1, or 2, and it would be useful to define constants that\nmap to those values. Ruby doesn't have a native expression for this construct\n(other than simply defining them one at a time).\n\nHere's a simple example, written in Go:\n\n```go\ntype Allergen int\n\nconst (\n    IgEggs Allergen = 1 \u003c\u003c iota // 1 \u003c\u003c 0 which is 00000001\n    IgChocolate                 // 1 \u003c\u003c 1 which is 00000010\n    IgNuts                      // 1 \u003c\u003c 2 which is 00000100\n    IgStrawberries              // 1 \u003c\u003c 3 which is 00001000\n    IgShellfish                 // 1 \u003c\u003c 4 which is 00010000\n)\n```\n\nAnd here it is in Ruby, using ioughta:\n\n```ruby\nObject.ioughta_const(\n  :IG_EGGS, -\u003e(ioughta) { 1 \u003c\u003c ioughta },\n  :IG_CHOCOLATE,\n  :IG_NUTS,\n  :IG_STRAWBERRIES,\n  :IG_SHELLFISH\n)\n\nIG_STRAWBERRIES # =\u003e 8\n```\n\nOr, perhaps a bit more Rubyishly:\n\n```ruby\nIG = Object.iota_hash(%i[\n  eggs\n  chocolate\n  nuts\n  strawberries\n  shellfish\n]) { |i| 1 \u003c\u003c i }.freeze\n\nIG[:shellfish] # =\u003e 16\n```\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'ioughta'\n```\n\nAnd then execute:\n\n```sh\n$ bundle\n```\n\nOr install it yourself as:\n\n```sh\n$ gem install ioughta\n```\n\n## Usage\n\nIoughta works just like `const` and `iota` do in Go, with only a few minor\ndifferences. You must `include` the module in your program, class, or module in\norder to start using it. The iterator starts at zero (0) and increments for\neach constant (or hash key) being defined. A function (any Ruby callable) takes\nthe current iteration as input and returns the value to be assigned. The\ndefault function simply returns the iterator, so you can easily create\nsequences of constants with consecutive integer values:\n\n```ruby\nrequire 'ioughta'\ninclude Ioughta\n\nObject.ioughta_const(:FOO, :BAR, :QUX)\n\nFOO # =\u003e 0\nBAR # =\u003e 1\nQUX # =\u003e 2\n```\n\nTo skip value(s) in the sequence, use the `:_` symbol:\n\n```ruby\nObject.ioughta_const(:_, :FOO, :BAR, :_, :QUX)\n\nFOO # =\u003e 1\nBAR # =\u003e 2\nQUX # =\u003e 4\n```\n\nAs soon as Ioughta sees a lambda (or any Ruby callable), it will start using it\nto generate future values from the iterator. You can redefine the lambda as\nmany times as you like:\n\n```ruby\nObject.ioughta_const(\n  :A,                   # will use the default lambda  (0 =\u003e   0)\n  :B, -\u003e(i) { i * 2 },  # will multiply by two         (1 =\u003e   2)\n  :C,                   # will also multiply by two    (2 =\u003e   4)\n  :D, -\u003e(j) { j ** 3 }, # will cube                    (3 =\u003e  27)\n  :E,                   # will also cube               (4 =\u003e  64)\n  :F,                   # cube all the things          (5 =\u003e 125)\n  :G, -\u003e{ 0.5 }         # will use a simple value      (6 =\u003e 0.5)\n  :H, proc(\u0026:itself)    # restore the default behavior (7 =\u003e   7)\n)\n```\n\nYou can also pass the lambda as the first argument:\n\n```ruby\nObject.ioughta_const -\u003e(i) { 1 \u003c\u003c (10 * i) }, %i[_ KiB MiB GiB TiB PiB EiB ZiB YiB]\n```\n\nOr even pass a block, instead of a lambda (it's the Ruby way!):\n\n```ruby\nUNITS = Object.ioughta_hash(%i[_ KB MB GB TB PB EB ZB YB]) { |i| 10 ** (i * 3) }.freeze\n```\n\nIf the first argument is a lambda *and* a block is given, the block will be\nsilently ignored.\n\n## Notes\n\nThe only major feature missing from the Go implementation is the ability to\nperform parallel assignment in the constant list. We're defining a list of\nterms, not a list of expressions, so it's not possible to do in Ruby without\nresourcing to nasty `eval` tricks. **Don't forget to separate your terms with\ncommas and freeze your hash constants!**\n\nYou've probably noticed that in order to use Ioughta in the top-level\nnamespace, we need to explicitly specify the `Object` receiver (just like we\nneed to do for `#const_set`). I didn't want to get too crazy with the\nmonkey-patching and/or method delegation. No such limitation exists when\nincluding Ioughta in a module or class, thanks to the available context. Also,\nif the `ioughta_const` and `ioughta_hash` method names are too ugly for you (I\ndon't blame you), they're aliased as `iota_const` and `iota_hash`,\nrespectively.\n\nHere is a very contrived and arbitrary example:\n\n```ruby\nrequire 'ioughta'\n\nmodule MyFileUtils\n  include Ioughta\n\n  iota_const -\u003e(b) { 1 \u003c\u003c b }, %i[EXECUTE WRITE READ]\n  iota_const -\u003e(b) { 1 \u003c\u003c b }, %i[TACKY SETGID SETUID]\n\n  OFFSET = iota_hash(-\u003e(d) { d * 3 }, %i[other group user special]).freeze\n  MASK = iota_hash(OFFSET.keys) { |_, key| 7 \u003c\u003c OFFSET[key] }.freeze\n\n  def self.mask_and_shift(mode, field)\n    (mode \u0026 MASK[field]) \u003e\u003e OFFSET[field]\n  end\nend\n\nMyFileUtils.mask_and_shift(0644, :user) \u0026 MyFileUtils::EXECUTE # =\u003e 0\nMyFileUtils.mask_and_shift(01777, :special) \u0026 MyFileUtils::TACKY # =\u003e 1\n```\n\nOne note on the above: the lambda (or block) can take the \"key\" at the current\niteration as an optional second argument.\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run\n`rake spec` to run the tests.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To\nrelease a new version, update the version number in `version.rb`, and then run\n`bundle exec rake release`, which will create a git tag for the version, push\ngit commits and tags, and push the `.gem` file to\n[rubygems.org](https://rubygems.org).\n\n## Trivium\n\nPronounced /aɪ ˈɔtə/, as in the English phrase \"Why, I oughta...!\"\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at\nhttps://github.com/mwpastore/ioughta.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT\nLicense](http://opensource.org/licenses/MIT).\n\n[1]: https://splice.com/blog/iota-elegant-constants-golang/\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmwpastore%2Fioughta","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmwpastore%2Fioughta","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmwpastore%2Fioughta/lists"}