{"id":33134980,"url":"https://github.com/beatrichartz/configurations","last_synced_at":"2025-11-20T04:02:12.883Z","repository":{"id":19764803,"uuid":"23022648","full_name":"beatrichartz/configurations","owner":"beatrichartz","description":"Configurations provides a unified approach to do configurations for gems or other ruby code","archived":true,"fork":false,"pushed_at":"2016-11-12T13:43:14.000Z","size":155,"stargazers_count":141,"open_issues_count":2,"forks_count":7,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-11-07T13:05:51.216Z","etag":null,"topics":["arbitrary-configurations","nested-configurations","ruby","typed-configurations"],"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/beatrichartz.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":"2014-08-16T16:53:17.000Z","updated_at":"2025-01-25T03:00:28.000Z","dependencies_parsed_at":"2022-08-26T07:40:53.748Z","dependency_job_id":null,"html_url":"https://github.com/beatrichartz/configurations","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/beatrichartz/configurations","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beatrichartz%2Fconfigurations","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beatrichartz%2Fconfigurations/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beatrichartz%2Fconfigurations/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beatrichartz%2Fconfigurations/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/beatrichartz","download_url":"https://codeload.github.com/beatrichartz/configurations/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beatrichartz%2Fconfigurations/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":284861040,"owners_count":27075156,"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","status":"online","status_checked_at":"2025-11-17T02:00:06.431Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["arbitrary-configurations","nested-configurations","ruby","typed-configurations"],"created_at":"2025-11-15T10:00:48.327Z","updated_at":"2025-11-20T04:02:12.875Z","avatar_url":"https://github.com/beatrichartz.png","language":"Ruby","readme":"# Configurations\n[![Build Status](https://travis-ci.org/beatrichartz/configurations.svg?branch=master)](https://travis-ci.org/beatrichartz/configurations) [![Test Coverage](https://codeclimate.com/github/beatrichartz/configurations/badges/coverage.svg)](https://codeclimate.com/github/beatrichartz/configurations) [![Code Climate](https://codeclimate.com/github/beatrichartz/configurations/badges/gpa.svg)](https://codeclimate.com/github/beatrichartz/configurations) [![Inline docs](http://inch-ci.org/github/beatrichartz/configurations.svg?branch=master)](http://inch-ci.org/github/beatrichartz/configurations) [![Dependency Status](https://gemnasium.com/beatrichartz/configurations.svg)](https://gemnasium.com/beatrichartz/configurations)\n\n\nConfigurations provides a unified approach to do configurations using the `MyGem.configure do ... end` idiom with the flexibility to do everything from arbitrary configurations to type asserted configurations for your gem or any other ruby code.\n\n## Install\n\n```ruby\ngem install configurations\n```\n\nor with Bundler\n\n```ruby\ngem 'configurations', '~\u003e 2.2.0'\n```\n\nConfigurations uses [Semver 2.0](http://semver.org/)\n\n## Compatibility\n\nCompatible with MRI 1.9.2 - 2.2, Rubinius 2.x, jRuby 1.7 and 9K\n\n## Why?\n\nThere are various ways to do configurations, yet there seems to be a broad consensus on the `MyGem.configure do ... end` idiom.\nSo instead of rolling your own, you can add this gem to your gem and get that functionality for free, plus some goodies you may want\nbut do not have the time to write like type assertion or nested configurations.\n\nLess time copy pasting configuration code, more time writing exciting code for you.\n\n## Configure\n\n### First way: Arbitrary Configuration\n\nGo boom! with ease. This allows your gem / code users to set any value they like.\n\n```ruby\nmodule MyGem\n  include Configurations\nend\n```\n\nGives your users:\n\n```ruby\nMyGem.configure do |c|\n  c.foo.bar.baz = 'fizz'\n  c.hi = 'Hello-o'\n  c.class = 'oooh wow' # Such flexible!\nend\n```\n\nGives you:\n\n```ruby\nMyGem.configuration.class #=\u003e 'oooh wow'\nMyGem.configuration.foo.bar.baz #=\u003e 'fizz'\n```\n\nUndefined properties on an arbitrary configuration will return `nil`\n\n```ruby\nMyGem.configuration.not_set #=\u003e nil\n```\n\nIf you want to define the behaviour for not set properties yourself, use `not_configured`. You can either define a catch-all `not_configured` which will be executed whenever you call a value that has not been configured and has no default:\n\n```ruby\nmodule MyGem\n  not_configured do |prop|\n\traise NoMethodError, \"#{prop} must be configured\"\n  end\nend\n```\n\nOr you can define finer-grained callbacks:\n\n```ruby\nmodule MyGem\n  not_configured my: { nested: :prop } do |prop|\n\traise NoMethodError, \"#{prop} must be configured\"\n  end\nend\n```\n\n### Second way: Restricted Configuration\n\nIf you just want some properties to be configurable, consider this option\n\n```ruby\nmodule MyGem\n  include Configurations\n  configurable :foo, bar: :baz, biz: %i(bi ba bu)\nend\n```\n\nGives your users:\n\n```ruby\nMyGem.configure do |c|\n  c.foo = 'FOO'\n  c.bar.baz = 'FIZZ'\n  c.biz.bi = 'BI'\n  c.biz.ba = 'BA'\n\n  # This would raise NoMethodError\n  # c.bar.biz\nend\n```\n\nGives you:\n\n```ruby\nMyGem.configuration.foo #=\u003e 'FOO'\nMyGem.configuration.bar.baz #=\u003e 'FIZZ'\n```\n\nNot configured properties on a restricted configuration will raise `NoMethodError`\n\n```ruby\nMyGem.configuration.not_set #=\u003e \u003c#NoMethodError\u003e\n```\n\nIf you want to define the behaviour for not set properties yourself, use `not_configured`. This will only affect properties set to configurable. All not configurable properties will raise `NoMethodError`.\n\n```ruby\nmodule MyGem\n  not_configured :awesome, :nice do |prop| # omit the arguments to get a catch-all not_configured\n\twarn :not_configured, \"Please configure #{prop} or live in danger: youtube.com/watch?v=yZ15vCGuvH0\"\n  end\nend\n```\n\n### Third way: Type Restricted Configuration\n\nIf you want to make sure your configurations only accept one type, consider this option\n\n```ruby\nmodule MyGem\n  include Configurations\n  configurable String, :foo\n  configurable Array, bar: :baz\nend\n```\n\nGives your users:\n\n```ruby\nMyGem.configure do |c|\n  c.foo = 'FOO'\n  c.bar.baz = %w(hello)\n\n  # This would raise Configurations::ConfigurationError\n  # c.foo = :not_so_foo\n  # c.bar.baz = 'oh my cannot configure'\nend\n```\n\n### Fourth way: Custom asserted or changed values\n\nIf you need further assertions or you need to change a value before it gets stored in the configuration, consider passing a block\n\n```ruby\nmodule MyGem\n  include Configurations\n  configurable :foo do |value|\n\n\t# The return value is what gets assigned, unless it is nil,\n\t# in which case the original value persists\n\t#\n\tvalue + ' ooooh my'\n  end\n  configurable String, bar: :baz do |value|\n\n\t# value is guaranteed to be a string at this point\n\t#\n\tunless %w(bi ba bu).include?(value)\n\t  raise ArgumentError, 'baz needs to be one of bi, ba, bu'\n\tend\n  end\nend\n```\n\nGives your users:\n\n```ruby\nMyGem.configure do |c|\n  c.foo = 'FOO'\n  c.bar.baz = %w(bi)\n\n  # This would raise the ArgumentError in the block\n  # c.bar.baz = %w(boooh)\nend\n```\n\nGives you:\n\n```ruby\nMyGem.configuration.foo #=\u003e 'FOO ooooh my'\nMyGem.configuration.bar.baz #=\u003e one of %w(bi ba bu)\n```\n\n### Configuration Methods\n\nYou might want to define methods on your configuration which use configuration values to bring out another value.\nThis is what `configuration_method` is here to help you with:\n\n```ruby\nmodule MyGem\n  include Configurations\n  configurable :foo, :bar\n  configuration_method :foobar do |arg|\n\tfoo + bar + arg\n  end\nend\n```\n\nYour users do:\n\n```ruby\nMyGem.configure do |c|\n  c.foo = 'FOO'\n  c.bar = 'BAR'\nend\n```\n\nYou get:\n\n```ruby\nMyGem.configuration.foobar('ARG') #=\u003e 'FOOBARARG'\n```\n\nconfiguration methods can also be installed on nested properties using hashes:\n\n```ruby\nconfiguration_method foo: :bar do |arg|\n  foo + bar + arg\nend\n```\n\n### Defaults:\n\n```ruby\nmodule MyGem\n  include Configurations\n  configuration_defaults do |c|\n\tc.foo.bar.baz = 'BAR'\n  end\nend\n```\n\n### Get a hash if you need it\n\n```ruby\nMyGem.configuration.to_h #=\u003e a Hash\n```\n\n### Configure with a hash where needed\n\nSometimes your users will have a hash of configuration values which are not handy to press into the block form. In that case, they can use `from_h` inside the `configure` block to either read in the full or a nested configuration. With a everything besides arbitrary configurations, `from_h` can also be used outside the block.\n\n```ruby\nyaml_hash = YAML.load_file('configuration.yml')\n\nMyGem.configure do |c|\n  c.foo = 'bar'\n  c.baz.from_h(yaml_hash)\nend\n```\n\n### Some caveats\n\n#### Reserved Methods\nThese are reserved methods on the configuration instance and should not be defined:\n- `initialize`\n- `inspect`\n- `method_missing`\n- `object_id`\n- `singleton_class`\n- `to_h`\n- `to_s`\n\n`Configuration` inherits from `BasicObject`, so method names defined through `Kernel` and `Object` are available.\n\n## Thread safety\nConfiguration is synchronized. Re-configuration via the `configure` block switches out the configuration in place rather than mutating its properties, so don't hold on to configuration objects in another context.\nThat said, please bear in mind that keeping mutable state in configurations is as bad an idea as every other kind of global mutable state, if you expect values to change at runtime, configurations are not the right place to keep them:\n\nEncourage your users to configure once when initializing the environment, reconfigure on reload, but never ever at runtime.\n\n## Contributing\n\nYES!\n\nLet's make this awesome. Write tests for your added stuff, bonus points for feature branches. If you don't have the time to write a fix, raise an issue.\n\n### Copyright\n\nCopyright © 2015 Beat Richartz. See LICENSE.txt for further details.\n","funding_links":[],"categories":["Gems"],"sub_categories":["Misc"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeatrichartz%2Fconfigurations","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbeatrichartz%2Fconfigurations","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeatrichartz%2Fconfigurations/lists"}