pax_global_header00006660000000000000000000000064136022207530014512gustar00rootroot0000000000000052 comment=5fbeb6e1e523a200925bff22af2e302dec2271e0 mixlib-config-3.0.6/000077500000000000000000000000001360222075300142475ustar00rootroot00000000000000mixlib-config-3.0.6/.expeditor/000077500000000000000000000000001360222075300163305ustar00rootroot00000000000000mixlib-config-3.0.6/.expeditor/config.yml000066400000000000000000000026761360222075300203330ustar00rootroot00000000000000# Documentation available at https://expeditor.chef.io/docs/getting-started/ --- # Slack channel in Chef Software slack to send notifications about build failures, etc slack: notify_channel: chef-found-notify # This publish is triggered by the `built_in:publish_rubygems` artifact_action. rubygems: - mixlib-config github: # This deletes the GitHub PR branch after successfully merged into the release branch delete_branch_on_merge: true # The tag format to use (e.g. v1.0.0) version_tag_format: "v{{version}}" # allow bumping the minor release via label minor_bump_labels: - "Expeditor: Bump Version Minor" # allow bumping the major release via label major_bump_labels: - "Expeditor: Bump Version Major" changelog: rollup_header: Changes not yet released to rubygems.org # These actions are taken, in order they are specified, anytime a Pull Request is merged. merge_actions: - built_in:bump_version: ignore_labels: - "Expeditor: Skip Version Bump" - "Expeditor: Skip All" - bash:.expeditor/update_version.sh: only_if: built_in:bump_version - built_in:update_changelog: ignore_labels: - "Expeditor: Skip Changelog" - "Expeditor: Skip All" - built_in:build_gem: only_if: built_in:bump_version promote: actions: - built_in:rollover_changelog - built_in:publish_rubygems pipelines: - verify: description: Pull Request validation tests public: true mixlib-config-3.0.6/.expeditor/update_version.sh000066400000000000000000000007071360222075300217170ustar00rootroot00000000000000#!/bin/sh # # After a PR merge, Chef Expeditor will bump the PATCH version in the VERSION file. # It then executes this file to update any other files/components with that new version. # set -evx sed -i -r "s/^(\s*)VERSION = \".+\"/\1VERSION = \"$(cat VERSION)\"/" lib/mixlib/config/version.rb # Once Expeditor finshes executing this script, it will commit the changes and push # the commit as a new tag corresponding to the value in the VERSION file. mixlib-config-3.0.6/.expeditor/verify.pipeline.yml000066400000000000000000000015661360222075300221730ustar00rootroot00000000000000--- expeditor: defaults: buildkite: timeout_in_minutes: 30 steps: - label: run-lint-and-specs-ruby-2.4 command: - bundle install --jobs=7 --retry=3 --without docs debug - bundle exec rake expeditor: executor: docker: image: ruby:2.4-stretch - label: run-lint-and-specs-ruby-2.5 command: - bundle install --jobs=7 --retry=3 --without docs debug - bundle exec rake expeditor: executor: docker: image: ruby:2.5-stretch - label: run-lint-and-specs-ruby-2.6 command: - bundle install --jobs=7 --retry=3 --without docs debug - bundle exec rake expeditor: executor: docker: image: ruby:2.6-stretch - label: run-specs-windows command: - bundle install --jobs=7 --retry=3 --without docs debug - bundle exec rake expeditor: executor: docker: host_os: windows mixlib-config-3.0.6/.github/000077500000000000000000000000001360222075300156075ustar00rootroot00000000000000mixlib-config-3.0.6/.github/CODEOWNERS000066400000000000000000000003741360222075300172060ustar00rootroot00000000000000# Order is important. The last matching pattern has the most precedence. * @chef/chef-foundation-owners @chef/chef-foundation-approvers @chef/chef-foundation-reviewers .expeditor/ @chef/jex-team *.md @chef/docs-team mixlib-config-3.0.6/.github/ISSUE_TEMPLATE/000077500000000000000000000000001360222075300177725ustar00rootroot00000000000000mixlib-config-3.0.6/.github/ISSUE_TEMPLATE/BUG_TEMPLATE.md000066400000000000000000000011521360222075300222230ustar00rootroot00000000000000--- name: � Bug Report about: If something isn't working as expected �. labels: "Status: Untriaged" --- # Version: [Version of the project installed] # Environment: [Details about the environment such as the Operating System, cookbook details, etc...] # Scenario: [What you are trying to achieve and you can't?] # Steps to Reproduce: [If you are filing an issue what are the things we need to do in order to repro your problem?] # Expected Result: [What are you expecting to happen as the consequence of above reproduction steps?] # Actual Result: [What actually happens after the reproduction steps?] mixlib-config-3.0.6/.github/ISSUE_TEMPLATE/DESIGN_PROPOSAL.md000066400000000000000000000023431360222075300226060ustar00rootroot00000000000000--- name: Design Proposal about: I have a significant change I would like to propose and discuss before starting labels: "Status: Untriaged" --- ### When a Change Needs a Design Proposal A design proposal should be opened any time a change meets one of the following qualifications: - Significantly changes the user experience of a project in a way that impacts users. - Significantly changes the underlying architecture of the project in a way that impacts other developers. - Changes the development or testing process of the project such as a change of CI systems or test frameworks. ### Why We Use This Process - Allows all interested parties (including any community member) to discuss large impact changes to a project. - Serves as a durable paper trail for discussions regarding project architecture. - Forces design discussions to occur before PRs are created. - Reduces PR refactoring and rejected PRs. --- ## Motivation ## Specification ## Downstream Impact mixlib-config-3.0.6/.github/ISSUE_TEMPLATE/ENHANCEMENT_REQUEST_TEMPLATE.md000066400000000000000000000014071360222075300245460ustar00rootroot00000000000000--- name: 🚀 Enhancement Request about: I have a suggestion (and may want to implement it 🙂)! labels: "Status: Untriaged" --- ### Describe the Enhancement: ### Describe the Need: ### Current Alternative ### Can We Help You Implement This?: mixlib-config-3.0.6/.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md000066400000000000000000000006601360222075300230210ustar00rootroot00000000000000--- name: 🤗 Support Question about: If you have a question 💬, please check out our Slack! --- We use GitHub issues to track bugs and feature requests. If you need help please post to our Mailing List or join the Chef Community Slack. * Chef Community Slack at http://community-slack.chef.io/. * Chef Mailing List https://discourse.chef.io/ Support issues opened here will be closed and redirected to Slack or Discourse. mixlib-config-3.0.6/.github/lock.yml000066400000000000000000000000221360222075300172540ustar00rootroot00000000000000daysUntilLock: 60 mixlib-config-3.0.6/.gitignore000066400000000000000000000003671360222075300162450ustar00rootroot00000000000000.yardoc .bundle .config .DS_Store .idea .rake_tasks~ .rspec .ruby-version .rvmrc .yardoc .yardopts *.gem *.rbc *.sw? bin/ coverage doc Gemfile.local Gemfile.lock InstalledFiles lib/bundler/man pkg spec/reports test/tmp test/version_tmp tmp vendor mixlib-config-3.0.6/.rspec000066400000000000000000000000201360222075300153540ustar00rootroot00000000000000--colour -f doc mixlib-config-3.0.6/.rubocop.yml000066400000000000000000000001331360222075300165160ustar00rootroot00000000000000Lint/Void: Exclude: - 'spec/mixlib/config_spec.rb' Style/HashSyntax: Enabled: true mixlib-config-3.0.6/CHANGELOG.md000066400000000000000000000320651360222075300160660ustar00rootroot00000000000000 # Change Log ## [v3.0.6](https://github.com/chef/mixlib-config/tree/v3.0.6) (2019-12-29) #### Merged Pull Requests - Substitute require for require_relative [#80](https://github.com/chef/mixlib-config/pull/80) ([tas50](https://github.com/tas50)) ### Changes not yet released to rubygems.org #### Merged Pull Requests - Substitute require for require_relative [#80](https://github.com/chef/mixlib-config/pull/80) ([tas50](https://github.com/tas50)) ## [v3.0.5](https://github.com/chef/mixlib-config/tree/v3.0.5) (2019-11-14) ## [v3.0.5](https://github.com/chef/mixlib-config/tree/v3.0.5) (2019-11-14) #### Merged Pull Requests - Add BuildKite PR Testing [#75](https://github.com/chef/mixlib-config/pull/75) ([tas50](https://github.com/tas50)) - Remove Travis PR testing + add foundation team as the project owner [#76](https://github.com/chef/mixlib-config/pull/76) ([tas50](https://github.com/tas50)) - Test on Windows and use the smaller containers [#77](https://github.com/chef/mixlib-config/pull/77) ([tas50](https://github.com/tas50)) - Do not crash when loading undefined context from hash [#79](https://github.com/chef/mixlib-config/pull/79) ([marcparadise](https://github.com/marcparadise)) ## [v3.0.1](https://github.com/chef/mixlib-config/tree/v3.0.1) (2019-04-23) #### Merged Pull Requests - update travis, drop ruby < 2.5, major version bump [#73](https://github.com/chef/mixlib-config/pull/73) ([lamont-granquist](https://github.com/lamont-granquist)) - Allow Ruby 2.4 / Update github templates [#74](https://github.com/chef/mixlib-config/pull/74) ([tas50](https://github.com/tas50)) ## [v2.2.18](https://github.com/chef/mixlib-config/tree/v2.2.18) (2018-12-17) #### Merged Pull Requests - Add github issue and PR templates [#68](https://github.com/chef/mixlib-config/pull/68) ([tas50](https://github.com/tas50)) - Resolve chefstyle and expeditor issues [#69](https://github.com/chef/mixlib-config/pull/69) ([tas50](https://github.com/tas50)) - Expand ruby testing in Travis [#70](https://github.com/chef/mixlib-config/pull/70) ([tas50](https://github.com/tas50)) - Standardize the gemfile and rakefile [#71](https://github.com/chef/mixlib-config/pull/71) ([tas50](https://github.com/tas50)) - Only ship the required library files in the gem artifact [#72](https://github.com/chef/mixlib-config/pull/72) ([tas50](https://github.com/tas50)) ## [v2.2.13](https://github.com/chef/mixlib-config/tree/v2.2.13) (2018-07-12) #### Merged Pull Requests - Avoid converting to text representation when parsing JSON/TOML/etc [#66](https://github.com/chef/mixlib-config/pull/66) ([lamont-granquist](https://github.com/lamont-granquist)) ## [v2.2.12](https://github.com/chef/mixlib-config/tree/v2.2.12) (2018-07-06) #### Merged Pull Requests - add is_default? inspection method [#65](https://github.com/chef/mixlib-config/pull/65) ([lamont-granquist](https://github.com/lamont-granquist)) ## [v2.2.11](https://github.com/chef/mixlib-config/tree/v2.2.11) (2018-07-02) #### Merged Pull Requests - key? and has_key? should find subcontexts [#64](https://github.com/chef/mixlib-config/pull/64) ([lamont-granquist](https://github.com/lamont-granquist)) ## [v2.2.10](https://github.com/chef/mixlib-config/tree/v2.2.10) (2018-07-02) #### Merged Pull Requests - remove hashrocket syntax [#62](https://github.com/chef/mixlib-config/pull/62) ([lamont-granquist](https://github.com/lamont-granquist)) - add `#key?` alias to `#has_key?` [#63](https://github.com/chef/mixlib-config/pull/63) ([lamont-granquist](https://github.com/lamont-granquist)) ## [v2.2.8](https://github.com/chef/mixlib-config/tree/v2.2.8) (2018-06-13) #### Merged Pull Requests - fix style warnings with latest rubocop [#60](https://github.com/chef/mixlib-config/pull/60) ([thommay](https://github.com/thommay)) - Fix config_context_list/hash in strict mode [#57](https://github.com/chef/mixlib-config/pull/57) ([elyscape](https://github.com/elyscape)) ## [v2.2.6](https://github.com/chef/mixlib-config/tree/v2.2.6) (2018-03-22) #### Merged Pull Requests - Adding support for reading from TOML files [#55](https://github.com/chef/mixlib-config/pull/55) ([tyler-ball](https://github.com/tyler-ball)) ## [v2.2.5](https://github.com/chef/mixlib-config/tree/v2.2.5) (2018-02-09) #### Merged Pull Requests - Add support for reading from JSON files [#53](https://github.com/chef/mixlib-config/pull/53) ([tduffield](https://github.com/tduffield)) ## [2.2.4](https://github.com/chef/mixlib-config/tree/2.2.4) (2016-09-02) [Full Changelog](https://github.com/chef/mixlib-config/compare/v2.2.3...2.2.4) **Merged pull requests:** - Allow a config context to be set from another config context [\#42](https://github.com/chef/mixlib-config/pull/42) ([mwrock](https://github.com/mwrock)) - Allow configuring contexts via block [\#35](https://github.com/chef/mixlib-config/pull/35) ([KierranM](https://github.com/KierranM)) ## [2.2.3](https://github.com/chef/mixlib-config/tree/2.2.3) (2016-08-30) [Full Changelog](https://github.com/chef/mixlib-config/compare/v2.2.2...2.2.3) **Merged pull requests:** - Dont reset state during restore [\#40](https://github.com/chef/mixlib-config/pull/40) ([mwrock](https://github.com/mwrock)) - Ignore Gemfile.lock [\#39](https://github.com/chef/mixlib-config/pull/39) ([tas50](https://github.com/tas50)) - Update specs for rspec 3.0 [\#38](https://github.com/chef/mixlib-config/pull/38) ([tas50](https://github.com/tas50)) - Bump version to 2.2.2 [\#37](https://github.com/chef/mixlib-config/pull/37) ([jkeiser](https://github.com/jkeiser)) ## [2.2.2](https://github.com/chef/mixlib-config/tree/2.2.2) (2016-08-22) [Full Changelog](https://github.com/chef/mixlib-config/compare/v2.2.1...2.2.2) **Merged pull requests:** - chefstyle fixes [\#33](https://github.com/chef/mixlib-config/pull/33) ([lamont-granquist](https://github.com/lamont-granquist)) - Add gemspec files to allow bundler to run from the gem [\#32](https://github.com/chef/mixlib-config/pull/32) ([ksubrama](https://github.com/ksubrama)) - Fix ruby warnings [\#30](https://github.com/chef/mixlib-config/pull/30) ([danielsdeleo](https://github.com/danielsdeleo)) ## [v2.2.1](https://github.com/chef/mixlib-config/tree/v2.2.1) (2015-05-12) [Full Changelog](https://github.com/chef/mixlib-config/compare/v2.2.0...v2.2.1) **Merged pull requests:** - Revert "Rename has\_key? -\> key? \(BC compatible\)" [\#28](https://github.com/chef/mixlib-config/pull/28) ([jaym](https://github.com/jaym)) ## [v2.2.0](https://github.com/chef/mixlib-config/tree/v2.2.0) (2015-05-11) [Full Changelog](https://github.com/chef/mixlib-config/compare/v2.1.0...v2.2.0) **Merged pull requests:** - Add license to gemspec and update other fields for new company name. [\#27](https://github.com/chef/mixlib-config/pull/27) ([juliandunn](https://github.com/juliandunn)) - Revert "Fix README typos" [\#23](https://github.com/chef/mixlib-config/pull/23) ([mriddle](https://github.com/mriddle)) - Fix README typos [\#22](https://github.com/chef/mixlib-config/pull/22) ([mriddle](https://github.com/mriddle)) - Rename has\_key? -\> key? \(BC compatible\) [\#21](https://github.com/chef/mixlib-config/pull/21) ([sethvargo](https://github.com/sethvargo)) - Fix strict mode errors to actually print symbol [\#20](https://github.com/chef/mixlib-config/pull/20) ([jkeiser](https://github.com/jkeiser)) - New policy files. [\#19](https://github.com/chef/mixlib-config/pull/19) ([sersut](https://github.com/sersut)) ## [v2.1.0](https://github.com/chef/mixlib-config/tree/v2.1.0) (2013-12-05) [Full Changelog](https://github.com/chef/mixlib-config/compare/v2.1.0.rc.1...v2.1.0) ## [v2.1.0.rc.1](https://github.com/chef/mixlib-config/tree/v2.1.0.rc.1) (2013-12-05) [Full Changelog](https://github.com/chef/mixlib-config/compare/v2.0.0...v2.1.0.rc.1) **Merged pull requests:** - Add save/reset, reopen config\_context, = {} for contexts [\#18](https://github.com/chef/mixlib-config/pull/18) ([jkeiser](https://github.com/jkeiser)) ## [v2.0.0](https://github.com/chef/mixlib-config/tree/v2.0.0) (2013-09-25) [Full Changelog](https://github.com/chef/mixlib-config/compare/v2.0.0.rc.5...v2.0.0) ## [v2.0.0.rc.5](https://github.com/chef/mixlib-config/tree/v2.0.0.rc.5) (2013-09-17) [Full Changelog](https://github.com/chef/mixlib-config/compare/v2.0.0.rc.4...v2.0.0.rc.5) **Merged pull requests:** - Define explicit getter/setter methods for configurables instead of relyi... [\#17](https://github.com/chef/mixlib-config/pull/17) ([jkeiser](https://github.com/jkeiser)) ## [v2.0.0.rc.4](https://github.com/chef/mixlib-config/tree/v2.0.0.rc.4) (2013-09-16) [Full Changelog](https://github.com/chef/mixlib-config/compare/v2.0.0.rc.3...v2.0.0.rc.4) **Merged pull requests:** - Fix issue with Config\['a'\] = b [\#16](https://github.com/chef/mixlib-config/pull/16) ([jkeiser](https://github.com/jkeiser)) ## [v2.0.0.rc.3](https://github.com/chef/mixlib-config/tree/v2.0.0.rc.3) (2013-09-13) [Full Changelog](https://github.com/chef/mixlib-config/compare/v2.0.0.rc.2...v2.0.0.rc.3) **Merged pull requests:** - Jk/dup defaults [\#15](https://github.com/chef/mixlib-config/pull/15) ([jkeiser](https://github.com/jkeiser)) ## [v2.0.0.rc.2](https://github.com/chef/mixlib-config/tree/v2.0.0.rc.2) (2013-09-11) [Full Changelog](https://github.com/chef/mixlib-config/compare/v2.0.0.rc.1...v2.0.0.rc.2) **Merged pull requests:** - Make config\_strict\_mode on by default [\#13](https://github.com/chef/mixlib-config/pull/13) ([jkeiser](https://github.com/jkeiser)) ## [v2.0.0.rc.1](https://github.com/chef/mixlib-config/tree/v2.0.0.rc.1) (2013-09-11) [Full Changelog](https://github.com/chef/mixlib-config/compare/beta-1...v2.0.0.rc.1) **Merged pull requests:** - Jk/version2 [\#12](https://github.com/chef/mixlib-config/pull/12) ([jkeiser](https://github.com/jkeiser)) - Jk/strict [\#11](https://github.com/chef/mixlib-config/pull/11) ([jkeiser](https://github.com/jkeiser)) - Add Travis config, basic Gemfile [\#10](https://github.com/chef/mixlib-config/pull/10) ([jkeiser](https://github.com/jkeiser)) - Add context\(\) DSL for config classes [\#9](https://github.com/chef/mixlib-config/pull/9) ([jkeiser](https://github.com/jkeiser)) - Jk/configurables [\#8](https://github.com/chef/mixlib-config/pull/8) ([jkeiser](https://github.com/jkeiser)) - Methods uber alles [\#6](https://github.com/chef/mixlib-config/pull/6) ([danielsdeleo](https://github.com/danielsdeleo)) - Modernize [\#5](https://github.com/chef/mixlib-config/pull/5) ([danielsdeleo](https://github.com/danielsdeleo)) - add require 'rspec' to spec/spec\_helper.rb [\#2](https://github.com/chef/mixlib-config/pull/2) ([pravi](https://github.com/pravi)) ## [beta-1](https://github.com/chef/mixlib-config/tree/beta-1) (2010-06-21) [Full Changelog](https://github.com/chef/mixlib-config/compare/1.1.2...beta-1) ## [1.1.2](https://github.com/chef/mixlib-config/tree/1.1.2) (2010-06-21) [Full Changelog](https://github.com/chef/mixlib-config/compare/1.1.2.rc01...1.1.2) ## [1.1.2.rc01](https://github.com/chef/mixlib-config/tree/1.1.2.rc01) (2010-06-16) [Full Changelog](https://github.com/chef/mixlib-config/compare/alpha_deploy_4...1.1.2.rc01) ## [alpha_deploy_4](https://github.com/chef/mixlib-config/tree/alpha_deploy_4) (2010-02-28) [Full Changelog](https://github.com/chef/mixlib-config/compare/alpha_deploy_3...alpha_deploy_4) ## [alpha_deploy_3](https://github.com/chef/mixlib-config/tree/alpha_deploy_3) (2010-02-28) [Full Changelog](https://github.com/chef/mixlib-config/compare/alpha_deploy_2...alpha_deploy_3) ## [alpha_deploy_2](https://github.com/chef/mixlib-config/tree/alpha_deploy_2) (2010-02-28) [Full Changelog](https://github.com/chef/mixlib-config/compare/1.1.0...alpha_deploy_2) ## [1.1.0](https://github.com/chef/mixlib-config/tree/1.1.0) (2010-02-28) [Full Changelog](https://github.com/chef/mixlib-config/compare/v1.0.12...1.1.0) ## [v1.0.12](https://github.com/chef/mixlib-config/tree/v1.0.12) (2009-08-25) [Full Changelog](https://github.com/chef/mixlib-config/compare/alpha_deploy_1...v1.0.12) ## [alpha_deploy_1](https://github.com/chef/mixlib-config/tree/alpha_deploy_1) (2009-08-25) [Full Changelog](https://github.com/chef/mixlib-config/compare/v1.0.11...alpha_deploy_1) ## [v1.0.11](https://github.com/chef/mixlib-config/tree/v1.0.11) (2009-08-23) [Full Changelog](https://github.com/chef/mixlib-config/compare/v1.0.9...v1.0.11) ## [v1.0.9](https://github.com/chef/mixlib-config/tree/v1.0.9) (2009-06-24) [Full Changelog](https://github.com/chef/mixlib-config/compare/v1.0.8...v1.0.9) ## [v1.0.8](https://github.com/chef/mixlib-config/tree/v1.0.8) (2009-06-24) [Full Changelog](https://github.com/chef/mixlib-config/compare/v1.0.7...v1.0.8) ## [v1.0.7](https://github.com/chef/mixlib-config/tree/v1.0.7) (2009-05-14) [Full Changelog](https://github.com/chef/mixlib-config/compare/v1.0.6...v1.0.7) ## [v1.0.6](https://github.com/chef/mixlib-config/tree/v1.0.6) (2009-05-12) [Full Changelog](https://github.com/chef/mixlib-config/compare/v1.0.5...v1.0.6) ## [v1.0.5](https://github.com/chef/mixlib-config/tree/v1.0.5) (2009-05-12)mixlib-config-3.0.6/CODE_OF_CONDUCT.md000066400000000000000000000001331360222075300170430ustar00rootroot00000000000000Please refer to the Chef Community Code of Conduct at https://www.chef.io/code-of-conduct/ mixlib-config-3.0.6/CONTRIBUTING.md000066400000000000000000000001111360222075300164710ustar00rootroot00000000000000Please refer to https://github.com/chef/chef/blob/master/CONTRIBUTING.md mixlib-config-3.0.6/Gemfile000066400000000000000000000005361360222075300155460ustar00rootroot00000000000000source "https://rubygems.org" gemspec group :docs do gem "github-markup" gem "redcarpet" gem "yard" end group :test do gem "chefstyle", git: "https://github.com/chef/chefstyle.git", branch: "master" gem "rake" gem "rspec", "~> 3.0" end group :debug do gem "pry" gem "pry-byebug" gem "pry-stack_explorer" gem "rb-readline" end mixlib-config-3.0.6/LICENSE000066400000000000000000000251421360222075300152600ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. mixlib-config-3.0.6/NOTICE000066400000000000000000000016571360222075300151640ustar00rootroot00000000000000Mixlib::Config NOTICE ================= Developed at Chef (http://www.chef.io). * Copyright 2009-2016, Chef Software, Inc. Mixlib::Config incorporates code from Chef. The Chef notice file follows: Chef NOTICE =========== Developed at Chef (http://www.chef.io). Contributors and Copyright holders: * Copyright 2008, Adam Jacob * Copyright 2008, Arjuna Christensen * Copyright 2008, Bryan McLellan * Copyright 2008, Ezra Zygmuntowicz * Copyright 2009, Sean Cribbs * Copyright 2009, Christopher Brown * Copyright 2009, Thom May Chef incorporates code modified from Open4 (http://www.codeforpeople.com/lib/ruby/open4/), which was written by Ara T. Howard. Chef incorporates code modified from Merb (http://www.merbivore.com), which is Copyright (c) 2008 Engine Yard. mixlib-config-3.0.6/README.md000066400000000000000000000226541360222075300155370ustar00rootroot00000000000000# Mixlib::Config [![Gem Version](https://badge.fury.io/rb/mixlib-config.svg)](https://badge.fury.io/rb/mixlib-config) [![Build status](https://badge.buildkite.com/038bff14d03b1f91115dbb444ca81b387bd23855413f017fc0.svg?branch=master)](https://buildkite.com/chef-oss/chef-mixlib-config-master-verify) **Umbrella Project**: [Chef Foundation](https://github.com/chef/chef-oss-practices/blob/master/projects/chef-foundation.md) **Project State**: [Active](https://github.com/chef/chef-oss-practices/blob/master/repo-management/repo-states.md#active) **Issues [Response Time Maximum](https://github.com/chef/chef-oss-practices/blob/master/repo-management/repo-states.md)**: 14 days **Pull Request [Response Time Maximum](https://github.com/chef/chef-oss-practices/blob/master/repo-management/repo-states.md)**: 14 days Mixlib::Config provides a class-based configuration object, as used in Chef. To use in your project: ```ruby require 'mixlib/config' module MyConfig extend Mixlib::Config config_strict_mode true default :first_value, 'something' default :other_value, 'something_else' end ``` You can use this to provide a configuration file for a user. For example, if you do this: ```ruby MyConfig.from_file('~/.myconfig.rb') ``` A user could write a Ruby config file that looked like this: ```ruby first_value 'hi' second_value "#{first_value}! 10 times 10 is #{10*10}!" ``` Inside your app, you can check configuration values with this syntax: ```ruby MyConfig.first_value # returns 'something' MyConfig[:first_value] # returns 'something' ``` And you can modify configuration values with this syntax: ```ruby MyConfig.first_value('foobar') # sets first_value to 'foobar' MyConfig.first_value = 'foobar' # sets first_value to 'foobar' MyConfig[:first_value] = 'foobar' # sets first_value to 'foobar' ``` If you prefer to allow your users to pass in configuration via YAML, JSON or TOML files, `mixlib-config` supports that too! ```ruby MyConfig.from_file('~/.myconfig.yml') MyConfig.from_file('~/.myconfig.json') MyConfig.from_file('~/.myconfig.toml') ``` This way, a user could write a YAML config file that looked like this: ```yaml --- first_value: 'hi' second_value: 'goodbye' ``` or a JSON file that looks like this: ```json { "first_value": "hi", "second_value": "goodbye" } ``` or a TOML file that looks like this: ```toml first_value = "hi" second_value = "goodbye" ``` Please note: There is an inherent limitation in the logic you can do with YAML and JSON file. At this time, `mixlib-config` does not support ERB or other logic in YAML or JSON config (read "static content only"). ## Nested Configuration Often you want to be able to group configuration options to provide a common context. Mixlib::Config supports this thus: ```ruby require 'mixlib/config' module MyConfig extend Mixlib::Config config_context :logging do default :base_filename, 'mylog' default :max_log_files, 10 end end ``` The user can write their config file in one of three formats: ### Method Style ```ruby logging.base_filename 'superlog' logging.max_log_files 2 ``` ### Block Style Using this format the block is executed in the context, so all configurables on that context is directly accessible ```ruby logging do base_filename 'superlog' max_log_files 2 end ``` ### Block with Argument Style Using this format the context is given to the block as an argument ```ruby logging do |l| l.base_filename = 'superlog' l.max_log_files = 2 end ``` You can access these variables thus: ```ruby MyConfig.logging.base_filename MyConfig[:logging][:max_log_files] ``` ### Lists of Contexts For use cases where you need to be able to specify a list of things with identical configuration you can define a `context_config_list` like so: ```ruby require 'mixlib/config' module MyConfig extend Mixlib::Config # The first argument is the plural word for your item, the second is the singular config_context_list :apples, :apple do default :species default :color, 'red' default :crispness, 10 end end ``` With this definition everytime the `apple` is called within the config file it will create a new item that can be configured with a block like so: ```ruby apple do species 'Royal Gala' end apple do species 'Granny Smith' color 'green' end ``` You can then iterate over the defined values in code: ```ruby MyConfig.apples.each do |apple| puts "#{apple.species} are #{apple.color}" end # => Royal Gala are red # => Granny Smith are green ``` _**Note**: When using the config context lists they must use the [block style](#block-style) or [block with argument style](#block-with-argument-style)_ ### Hashes of Contexts For use cases where you need to be able to specify a list of things with identical configuration that are keyed to a specific value, you can define a `context_config_hash` like so: ```ruby require 'mixlib/config' module MyConfig extend Mixlib::Config # The first argument is the plural word for your item, the second is the singular config_context_hash :apples, :apple do default :species default :color, 'red' default :crispness, 10 end end ``` This can then be used in the config file like so: ```ruby apple 'Royal Gala' do species 'Royal Gala' end apple 'Granny Smith' do species 'Granny Smith' color 'green' end # You can also reopen a context to edit a value apple 'Royal Gala' do crispness 3 end ``` You can then iterate over the defined values in code: ```ruby MyConfig.apples.each do |key, apple| puts "#{key} => #{apple.species} are #{apple.color}" end # => Royal Gala => Royal Gala are red # => Granny Smith => Granny Smith are green ``` _**Note**: When using the config context hashes they must use the [block style](#block-style) or [block with argument style](#block-with-argument-style)_ ## Default Values Mixlib::Config has a powerful default value facility. In addition to being able to specify explicit default values, you can even specify Ruby code blocks that will run if the config value is not set. This can allow you to build options whose values are based on other options. ```ruby require 'mixlib/config' module MyConfig extend Mixlib::Config config_strict_mode true default :verbosity, 1 default(:print_network_requests) { verbosity >= 2 } default(:print_ridiculously_unimportant_stuff) { verbosity >= 10 } end ``` This allows the user to quickly specify a number of values with one default, while still allowing them to override anything: ```ruby verbosity 5 print_network_requests false ``` You can also inspect if the values are still their defaults or not: ```ruby MyConfig.is_default?(:verbosity) # == true MyConfig[:verbosity] = 5 MyConfig.is_default?(:verbosity) # == false MyConfig[:verbosity] = 1 MyConfig.is_default?(:verbosity) # == true ``` Trying to call `is_default?` on a config context or a config which does not have a declared default is an error and will raise. ## Strict Mode Misspellings are a common configuration problem, and Mixlib::Config has an answer: `config_strict_mode`. Setting `config_strict_mode` to `true` will cause any misspelled or incorrect configuration option references to throw `Mixlib::Config::UnknownConfigOptionError`. ```ruby require 'mixlib/config' module MyConfig extend Mixlib::Config config_strict_mode true default :filename, '~/output.txt' configurable :server_url # configurable declares an option with no default value config_context :logging do default :base_name, 'log' default :max_files, 20 end end ``` Now if a user types `fielname "~/output-mine.txt"` in their configuration file, it will toss an exception telling them that the option "fielname" is unknown. If you do not set config_strict_mode, the fielname option will be merrily set and the application just won't know about it. Different config_contexts can have different strict modes; but they inherit the strict mode of their parent if you don't explicitly set it. So setting it once at the top level is sufficient. In the above example, `logging.base_naem 'mylog'` will raise an error. In conclusion: _always set config_strict_mode to true_. You know you want to. ## Testing and Reset Testing your application with different sets of arguments can by simplified with `reset`. Call `MyConfig.reset` before each test and all configuration will be reset to its default value. There's no need to explicitly unset all your options between each run. NOTE: if you have arrays of arrays, or other deep nesting, we suggest you use code blocks to set up your default values (`default(:option) { [ [ 1, 2 ], [ 3, 4 ] ] }`). Deep children will not always be reset to their default values. Enjoy! ## Contributing For information on contributing to this project see ## License - Copyright:: Copyright (c) 2009-2019 Chef Software, Inc. - License:: Apache License, Version 2.0 ```text Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. mixlib-config-3.0.6/Rakefile000066400000000000000000000014611360222075300157160ustar00rootroot00000000000000require "bundler/gem_tasks" require "rspec/core/rake_task" Bundler::GemHelper.install_tasks task default: %i{style spec} desc "Run specs" RSpec::Core::RakeTask.new(:spec) do |spec| spec.pattern = "spec/**/*_spec.rb" end begin require "chefstyle" require "rubocop/rake_task" RuboCop::RakeTask.new(:style) do |task| task.options += ["--display-cop-names", "--no-color"] end rescue LoadError puts "chefstyle/rubocop is not available. bundle install first to make sure all dependencies are installed." end begin require "yard" YARD::Rake::YardocTask.new(:docs) rescue LoadError puts "yard is not available. bundle install first to make sure all dependencies are installed." end task :console do require "irb" require "irb/completion" require "mixlib/config" ARGV.clear IRB.start end mixlib-config-3.0.6/VERSION000066400000000000000000000000051360222075300153120ustar00rootroot000000000000003.0.6mixlib-config-3.0.6/features/000077500000000000000000000000001360222075300160655ustar00rootroot00000000000000mixlib-config-3.0.6/features/mixlib_config.feature000066400000000000000000000022461360222075300222570ustar00rootroot00000000000000Feature: Configure an application In order to make it trivial to configure an application As a Developer I want to utilize a simple configuration object Scenario: Set a configuration option to a string Given a configuration class 'ConfigIt' When I set 'foo' to 'bar' in configuration class 'ConfigIt' Then config option 'foo' is 'bar' Scenario: Set the same configuration option to different strings for two configuration classes Given a configuration class 'ConfigIt' And a configuration class 'ConfigItToo' When I set 'foo' to 'bar' in configuration class 'ConfigIt' And I set 'foo' to 'bar2' in configuration class 'ConfigItToo' Then in configuration class 'ConfigItToo' config option 'foo' is 'bar2' And in configuration class 'ConfigIt' config option 'foo' is 'bar' Scenario: Set a configuration option to an Array Given a configuration class 'ConfigIt' When I set 'foo' to: |key| |bar| |baz| Then an array is returned for 'foo' Scenario: Set a configuration option from a file Given a configuration file 'bobo.config' When I load the configuration Then config option 'foo' is 'bar' And config option 'baz' is 'snarl' mixlib-config-3.0.6/features/step_definitions/000077500000000000000000000000001360222075300214335ustar00rootroot00000000000000mixlib-config-3.0.6/features/step_definitions/mixlib_config_steps.rb000066400000000000000000000000001360222075300257750ustar00rootroot00000000000000mixlib-config-3.0.6/features/steps/000077500000000000000000000000001360222075300172235ustar00rootroot00000000000000mixlib-config-3.0.6/features/steps/config_steps.rb000066400000000000000000000037521360222075300222420ustar00rootroot00000000000000# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008-2016 Chef Software, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Given(/^a configuration class '(.+)'$/) do |classname| end When(/^I set '(.+)' to '(.+)' in configuration class '(.+)'$/) do |key, value, classname| # ConfigIt[key.to_sym] = value if classname == "ConfigIt" ConfigIt[key.to_sym] = value elsif classname == "ConfigItToo" ConfigItToo[key.to_sym] = value else raise ArgumentError, "configuration class must be ConfigIt or ConfigItToo" end end Then(/^config option '(.+)' is '(.+)'$/) do |key, value| ConfigIt[key.to_sym].should == value end Then(/^in configuration class '(.+)' config option '(.+)' is '(.+)'$/) do |classname, key, value| if classname == "ConfigIt" ConfigIt[key.to_sym].should == value elsif classname == "ConfigItToo" ConfigItToo[key.to_sym].should == value else raise ArgumentError, "configuration class must be ConfigIt or ConfigItToo" end end When(/^I set '(.+)' to:$/) do |key, foo_table| ConfigIt[key.to_sym] = [] foo_table.hashes.each do |hash| ConfigIt[key.to_sym] << hash["key"] end end Then(/^an array is returned for '(.+)'$/) do |key| ConfigIt[key.to_sym].should be_a_kind_of(Array) end Given(/^a configuration file '(.+)'$/) do |filename| @config_file = File.join(File.dirname(__FILE__), "..", "support", filename) end When(/^I load the configuration$/) do ConfigIt.from_file(@config_file) end mixlib-config-3.0.6/features/support/000077500000000000000000000000001360222075300176015ustar00rootroot00000000000000mixlib-config-3.0.6/features/support/bobo.config000066400000000000000000000000521360222075300217060ustar00rootroot00000000000000# Sample config file foo 'bar' baz 'snarl'mixlib-config-3.0.6/features/support/config_it.rb000066400000000000000000000015361360222075300220740ustar00rootroot00000000000000# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008-2016 Chef Software, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # $: << File.join(File.dirname(__FILE__), "..", "..", "lib") require "mixlib/config" class ConfigIt extend Mixlib::Config end class ConfigItToo extend Mixlib::Config end mixlib-config-3.0.6/features/support/env.rb000066400000000000000000000015641360222075300207240ustar00rootroot00000000000000# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008-2016 Chef Software, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # $: << File.join(File.dirname(__FILE__), "..", "..", "lib") require "rspec/expectations" require "mixlib/config" require "tmpdir" require "stringio" class MyWorld end World do MyWorld.new end mixlib-config-3.0.6/lib/000077500000000000000000000000001360222075300150155ustar00rootroot00000000000000mixlib-config-3.0.6/lib/mixlib/000077500000000000000000000000001360222075300163015ustar00rootroot00000000000000mixlib-config-3.0.6/lib/mixlib/config.rb000066400000000000000000000574251360222075300201100ustar00rootroot00000000000000# # Author:: Adam Jacob () # Author:: Nuo Yan () # Author:: Christopher Brown () # Copyright:: Copyright (c) 2008-2018, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # require_relative "config/version" require_relative "config/configurable" require_relative "config/unknown_config_option_error" require_relative "config/reopened_config_context_with_configurable_error" require_relative "config/reopened_configurable_with_config_context_error" module Mixlib module Config def self.extended(base) class << base; attr_accessor :configuration; end class << base; attr_accessor :configurables; end class << base; attr_accessor :config_contexts; end class << base; attr_accessor :config_context_lists; end class << base; attr_accessor :config_context_hashes; end class << base; attr_accessor :config_parent; end base.configuration = ({}) base.configurables = ({}) base.config_contexts = ({}) base.config_context_lists = ({}) base.config_context_hashes = ({}) base.initialize_mixlib_config end def initialize_mixlib_config @config_strict_mode = nil end # Loads a given ruby file, and runs instance_eval against it in the context of the current # object. # # Raises an IOError if the file cannot be found, or is not readable. # # === Parameters # filename:: A filename to read from def from_file(filename) if %w{ .yml .yaml }.include?(File.extname(filename)) from_yaml(filename) elsif File.extname(filename) == ".json" from_json(filename) elsif File.extname(filename) == ".toml" from_toml(filename) else instance_eval(IO.read(filename), filename, 1) end end # Parses valid YAML structure into Ruby so it can be ingested into the Class # # === Parameters # filename:: A filename to read from def from_yaml(filename) require "yaml" from_hash(YAML.load(IO.read(filename))) end # Parses valid JSON structure into Ruby # # === Parameters # filename:: A filename to read from def from_json(filename) require "json" from_hash(JSON.parse(IO.read(filename))) end def from_toml(filename) require "tomlrb" from_hash(Tomlrb.parse(IO.read(filename), symbolize_keys: true)) end # Transforms a Hash into method-style configuration syntax to be processed # # === Parameters # hash:: A Hash containing configuration def from_hash(hash) apply_nested_hash(hash) end # Pass Mixlib::Config.configure() a block, and it will yield itself # # === Parameters # block:: A block that is called with self.configuration as the argument. def configure(&block) yield(configuration) end # Get the value of a config option # # === Parameters # config_option:: The config option to return # # === Returns # value:: The value of the config option # # === Raises # :: If the config option does not exist and strict mode is on. def [](config_option) internal_get(config_option.to_sym) end # Set the value of a config option # # === Parameters # config_option:: The config option to set (within the []) # value:: The value for the config option # # === Returns # value:: The new value of the config option # # === Raises # :: If the config option does not exist and strict mode is on. def []=(config_option, value) internal_set(config_option.to_sym, value) end # Check if Mixlib::Config has a config option. # # === Parameters # key:: The config option to check for # # === Returns # :: If the config option exists # :: If the config option does not exist def key?(key) configuration.key?(key.to_sym) || config_contexts.key?(key.to_sym) end alias_method :has_key?, :key? def is_default?(key) symbol = key.to_sym if configurables.key?(symbol) configurables[symbol].is_default?(configuration) else raise ArgumentError, "config option must exist, and not be a context to check for default values" end end # Resets a config option to its default. # # === Parameters # symbol:: Name of the config option def delete(symbol) configuration.delete(symbol) end # Resets all config options to their defaults. def reset self.configuration = ({}) config_contexts.values.each(&:reset) end # Makes a copy of any non-default values. # # This returns a shallow copy of the hash; while the hash itself is # duplicated a la dup, modifying data inside arrays and hashes may modify # the original Config object. # # === Returns # # Hash of values the user has set. # # === Examples # # For example, this config class: # # class MyConfig < Mixlib::Config # default :will_be_set, 1 # default :will_be_set_to_default, 1 # default :will_not_be_set, 1 # configurable(:computed_value) { |x| x*2 } # config_context :group do # default :will_not_be_set, 1 # end # config_context :group_never_set # end # # MyConfig.x = 2 # MyConfig.will_be_set = 2 # MyConfig.will_be_set_to_default = 1 # MyConfig.computed_value = 2 # MyConfig.group.x = 3 # # produces this: # # MyConfig.save == { # :x => 2, # :will_be_set => 2, # :will_be_set_to_default => 1, # :computed_value => 4, # :group => { # :x => 3 # } # } # def save(include_defaults = false) result = configuration.dup if include_defaults (configurables.keys - result.keys).each do |missing_default| # Ask any configurables to save themselves into the result array if configurables[missing_default].has_default result[missing_default] = configurables[missing_default].default end end end config_contexts.each_pair do |key, context| context_result = context.save(include_defaults) result[key] = context_result if context_result.size != 0 || include_defaults end config_context_lists.each_pair do |key, meta| meta[:values].each do |context| context_result = context.save(include_defaults) result[key] = (result[key] || []) << context_result if context_result.size != 0 || include_defaults end end config_context_hashes.each_pair do |key, meta| meta[:values].each_pair do |context_key, context| context_result = context.save(include_defaults) (result[key] ||= {})[context_key] = context_result if context_result.size != 0 || include_defaults end end result end alias :to_hash :save # Restore non-default values from the given hash. # # === Parameters # hash: a hash in the same format as output by save. # # === Returns # self def restore(hash) self.configuration = hash.reject { |key, value| config_contexts.key?(key) } config_contexts.each do |key, config_context| if hash.key?(key) config_context.restore(hash[key]) else config_context.reset end end config_context_lists.each do |key, meta| meta[:values] = [] if hash.key?(key) hash[key].each do |val| context = define_context(meta[:definition_blocks]) context.restore(val) meta[:values] << context end end end config_context_hashes.each do |key, meta| meta[:values] = {} if hash.key?(key) hash[key].each do |vkey, val| context = define_context(meta[:definition_blocks]) context.restore(val) meta[:values][vkey] = context end end end end # Merge an incoming hash with our config options # # === Parameters # hash: a hash in the same format as output by save. # # === Returns # self def merge!(hash) hash.each do |key, value| if config_contexts.key?(key) # Grab the config context and let internal_get cache it if so desired config_contexts[key].restore(value) else configuration[key] = value end end self end # Return the set of config hash keys. # This *only* returns hash keys which have been set by the user. In future # versions this will likely be removed in favor of something more explicit. # For now though, we want this to match has_key? # # === Returns # result of Hash#keys def keys configuration.keys end # Creates a shallow copy of the internal hash # NOTE: remove this in 3.0 in favor of save. This is completely useless # with default values and configuration_context. # # === Returns # result of Hash#dup def hash_dup save end # metaprogramming to ensure that the slot for method_symbol # gets set to value after any other logic is run # # === Parameters # method_symbol:: Name of the method (variable setter) # blk:: logic block to run in setting slot method_symbol to value # value:: Value to be set in config hash # def config_attr_writer(method_symbol, &block) configurable(method_symbol).writes_value(&block) end # metaprogramming to set the default value for the given config option # # === Parameters # symbol:: Name of the config option # default_value:: Default value (can be unspecified) # block:: Logic block that calculates default value def default(symbol, default_value = nil, &block) configurable(symbol).defaults_to(default_value, &block) end # metaprogramming to set information about a config option. This may be # used in one of two ways: # # 1. Block-based: # configurable(:attr) do # defaults_to 4 # writes_value { |value| 10 } # end # # 2. Chain-based: # configurable(:attr).defaults_to(4).writes_value { |value| 10 } # # Currently supported configuration: # # defaults_to(value): value returned when configurable has no explicit value # defaults_to BLOCK: block is run when the configurable has no explicit value # writes_value BLOCK: block that is run to filter a value when it is being set # # === Parameters # symbol:: Name of the config option # default_value:: Default value [optional] # block:: Logic block that calculates default value [optional] # # === Returns # The value of the config option. def configurable(symbol, &block) unless configurables[symbol] if config_contexts.key?(symbol) raise ReopenedConfigContextWithConfigurableError, "Cannot redefine config_context #{symbol} as a configurable value" end configurables[symbol] = Configurable.new(symbol) define_attr_accessor_methods(symbol) end if block yield(configurables[symbol]) end configurables[symbol] end # Allows you to create a new config context where you can define new # options with default values. # # This method allows you to open up the configurable more than once. # # For example: # # config_context :server_info do # configurable(:url).defaults_to("http://localhost") # end # # === Parameters # symbol: the name of the context # block: a block that will be run in the context of this new config # class. def config_context(symbol, &block) if configurables.key?(symbol) raise ReopenedConfigurableWithConfigContextError, "Cannot redefine config value #{symbol} with a config context" end if config_contexts.key?(symbol) context = config_contexts[symbol] else context = Class.new context.extend(::Mixlib::Config) context.config_parent = self config_contexts[symbol] = context define_attr_accessor_methods(symbol) end if block context.instance_eval(&block) end context end # Allows you to create a new list of config contexts where you can define new # options with default values. # # This method allows you to open up the configurable more than once. # # For example: # # config_context_list :listeners, :listener do # configurable(:url).defaults_to("http://localhost") # end # # === Parameters # symbol: the plural name for contexts in the list # symbol: the singular name for contexts in the list # block: a block that will be run in the context of this new config # class. def config_context_list(plural_symbol, singular_symbol, &block) if configurables.key?(plural_symbol) raise ReopenedConfigurableWithConfigContextError, "Cannot redefine config value #{plural_symbol} with a config context" end unless config_context_lists.key?(plural_symbol) config_context_lists[plural_symbol] = { definition_blocks: [], values: [], } define_list_attr_accessor_methods(plural_symbol, singular_symbol) end config_context_lists[plural_symbol][:definition_blocks] << block if block_given? end # Allows you to create a new hash of config contexts where you can define new # options with default values. # # This method allows you to open up the configurable more than once. # # For example: # # config_context_hash :listeners, :listener do # configurable(:url).defaults_to("http://localhost") # end # # === Parameters # symbol: the plural name for contexts in the list # symbol: the singular name for contexts in the list # block: a block that will be run in the context of this new config # class. def config_context_hash(plural_symbol, singular_symbol, &block) if configurables.key?(plural_symbol) raise ReopenedConfigurableWithConfigContextError, "Cannot redefine config value #{plural_symbol} with a config context" end unless config_context_hashes.key?(plural_symbol) config_context_hashes[plural_symbol] = { definition_blocks: [], values: {}, } define_hash_attr_accessor_methods(plural_symbol, singular_symbol) end config_context_hashes[plural_symbol][:definition_blocks] << block if block_given? end NOT_PASSED = Object.new # Gets or sets strict mode. When strict mode is on, only values which # were specified with configurable(), default() or writes_with() may be # retrieved or set. Getting or setting anything else will cause # Mixlib::Config::UnknownConfigOptionError to be thrown. # # If this is set to :warn, unknown values may be get or set, but a warning # will be printed with Chef::Log.warn if this occurs. # # === Parameters # value:: pass this value to set strict mode [optional] # # === Returns # Current value of config_strict_mode # # === Raises # :: if value is set to something other than true, false, or :warn # def config_strict_mode(value = NOT_PASSED) if value == NOT_PASSED if @config_strict_mode.nil? if config_parent config_parent.config_strict_mode else false end else @config_strict_mode end else self.config_strict_mode = value end end # Sets strict mode. When strict mode is on, only values which # were specified with configurable(), default() or writes_with() may be # retrieved or set. All other values # # If this is set to :warn, unknown values may be get or set, but a warning # will be printed with Chef::Log.warn if this occurs. # # === Parameters # value:: pass this value to set strict mode [optional] # # === Raises # :: if value is set to something other than true, false, or :warn # def config_strict_mode=(value) unless [ true, false, :warn, nil ].include?(value) raise ArgumentError, "config_strict_mode must be true, false, nil or :warn" end @config_strict_mode = value end # Allows for simple lookups and setting of config options via method calls # on Mixlib::Config. If there any arguments to the method, they are used to set # the value of the config option. Otherwise, it's a simple get operation. # # === Parameters # method_symbol:: The method called. Must match a config option. # *args:: Any arguments passed to the method # # === Returns # value:: The value of the config option. # # === Raises # :: If the config option does not exist and strict mode is on. def method_missing(method_symbol, *args) method_symbol = $1.to_sym if method_symbol.to_s =~ /(.+)=$/ internal_get_or_set(method_symbol, *args) end protected # Given a (nested) Hash, apply it to the config object and any contexts. # # This is preferable to converting it to the string representation with # the #to_dotted_hash method above. # # === Parameters # hash:: The hash to apply to the config oject def apply_nested_hash(hash) hash.each do |k, v| if v.is_a? Hash # If loading from hash, and we reference a context that doesn't exist # and warning/strict is off, we need to create the config context that we expected to be here. context = internal_get(k.to_sym) || config_context(k.to_sym) context.apply_nested_hash(v) else internal_set(k.to_sym, v) end end end private # Given a (nested) Hash, turn it into a single top-level hash using dots as # nesting notation. This allows for direction translation into method-style # setting of Config. # # === Parameters # hash:: The hash to "de-nestify" # recursive_key:: The existing key to prepend going forward # # === Returns # value:: A single-depth Hash using dot notation to indicate nesting def to_dotted_hash(hash, recursive_key = "") hash.each_with_object({}) do |(k , v), ret| key = recursive_key + k.to_s if v.is_a? Hash ret.merge!(to_dotted_hash(v, key + ".")) else ret[key] = v end end end # Internal dispatch setter for config values. # # === Parameters # symbol:: Name of the method (variable setter) # value:: Value to be set in config hash # def internal_set(symbol, value) if configurables.key?(symbol) configurables[symbol].set(configuration, value) elsif config_contexts.key?(symbol) config_contexts[symbol].restore(value.to_hash) else if config_strict_mode == :warn Chef::Log.warn("Setting unsupported config value #{symbol}.") elsif config_strict_mode raise UnknownConfigOptionError, "Cannot set unsupported config value #{symbol}." end configuration[symbol] = value end end def internal_get(symbol) if configurables.key?(symbol) configurables[symbol].get(configuration) elsif config_contexts.key?(symbol) config_contexts[symbol] elsif config_context_lists.key?(symbol) config_context_lists[symbol] elsif config_context_hashes.key?(symbol) config_context_hashes[symbol] else if config_strict_mode == :warn Chef::Log.warn("Reading unsupported config value #{symbol}.") elsif config_strict_mode raise UnknownConfigOptionError, "Reading unsupported config value #{symbol}." end configuration[symbol] end end def internal_get_or_set(symbol, *args) num_args = args.length # Setting if num_args > 0 internal_set(symbol, num_args == 1 ? args[0] : args) end # Returning internal_get(symbol) end def define_attr_accessor_methods(symbol) # When Ruby 1.8.7 is no longer supported, this stuff can be done with define_singleton_method! meta = class << self; self; end # Setter meta.send :define_method, "#{symbol}=".to_sym do |value| internal_set(symbol, value) end # Getter meta.send :define_method, symbol do |*args, &block| # If a block was given, eval it in the context if block # If the block expects no arguments, then instance_eval if block.arity == 0 internal_get(symbol).instance_eval(&block) else # yield to the block block.yield(internal_get(symbol)) end else internal_get_or_set(symbol, *args) end end end def define_list_attr_accessor_methods(plural_symbol, singular_symbol) # When Ruby 1.8.7 is no longer supported, this stuff can be done with define_singleton_method! meta = class << self; self; end # Getter for list meta.send :define_method, plural_symbol do internal_get(plural_symbol)[:values] end # Adds a single new context to the list meta.send :define_method, singular_symbol do |&block| context_list_details = internal_get(plural_symbol) new_context = define_context(context_list_details[:definition_blocks]) context_list_details[:values] << new_context # If the block expects no arguments, then instance_eval if block.arity == 0 new_context.instance_eval(&block) else # yield to the block block.yield(new_context) end end end def define_hash_attr_accessor_methods(plural_symbol, singular_symbol) # When Ruby 1.8.7 is no longer supported, this stuff can be done with define_singleton_method! meta = class << self; self; end # Getter for list meta.send :define_method, plural_symbol do internal_get(plural_symbol)[:values] end # Adds a single new context to the list meta.send :define_method, singular_symbol do |key, &block| context_hash_details = internal_get(plural_symbol) context = if context_hash_details[:values].key? key context_hash_details[:values][key] else new_context = define_context(context_hash_details[:definition_blocks]) context_hash_details[:values][key] = new_context new_context end # If the block expects no arguments, then instance_eval if block.arity == 0 context.instance_eval(&block) else # yield to the block block.yield(context) end end end def define_context(definition_blocks) context = Class.new context.extend(::Mixlib::Config) context.config_parent = self definition_blocks.each do |block| context.instance_eval(&block) end context end end end mixlib-config-3.0.6/lib/mixlib/config/000077500000000000000000000000001360222075300175465ustar00rootroot00000000000000mixlib-config-3.0.6/lib/mixlib/config/configurable.rb000066400000000000000000000041411360222075300225330ustar00rootroot00000000000000# # Author:: John Keiser () # Copyright:: Copyright (c) 2013-2018, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # module Mixlib module Config class Configurable attr_reader :symbol attr_reader :default_value attr_reader :default_block def initialize(symbol) @symbol = symbol end def has_default? instance_variable_defined?(:@default_value) end def writes_value? instance_variable_defined?(:@writes_value) end def default_block? instance_variable_defined?(:@default_block) end alias_method :has_default, :has_default? def defaults_to(default_value = nil, &block) @default_value = default_value @default_block = block if block_given? self end def writes_value(&block) @writes_value = block self end def get(config) if config.key?(symbol) config[symbol] elsif default_block? default_block.call else config[symbol] = safe_dup(default_value) end end def set(config, value) config[symbol] = writes_value? ? @writes_value.call(value) : value end def default if default_block? default_block.call else default_value end end def is_default?(config) !config.key?(symbol) || config[symbol] == default_value end private def safe_dup(e) e.dup rescue TypeError e end end end end mixlib-config-3.0.6/lib/mixlib/config/reopened_config_context_with_configurable_error.rb000066400000000000000000000014511360222075300317520ustar00rootroot00000000000000# # Author:: John Keiser () # Copyright:: Copyright (c) 2013-2016 Chef Software, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # module Mixlib module Config class ReopenedConfigContextWithConfigurableError < StandardError end end end mixlib-config-3.0.6/lib/mixlib/config/reopened_configurable_with_config_context_error.rb000066400000000000000000000014511360222075300317520ustar00rootroot00000000000000# # Author:: John Keiser () # Copyright:: Copyright (c) 2013-2016 Chef Software, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # module Mixlib module Config class ReopenedConfigurableWithConfigContextError < StandardError end end end mixlib-config-3.0.6/lib/mixlib/config/unknown_config_option_error.rb000066400000000000000000000014271360222075300257240ustar00rootroot00000000000000# # Author:: John Keiser () # Copyright:: Copyright (c) 2013-2016 Chef Software, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # module Mixlib module Config class UnknownConfigOptionError < StandardError end end end mixlib-config-3.0.6/lib/mixlib/config/version.rb000066400000000000000000000013701360222075300215610ustar00rootroot00000000000000# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2013-2018, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # module Mixlib module Config VERSION = "3.0.6".freeze end end mixlib-config-3.0.6/mixlib-config.gemspec000066400000000000000000000011711360222075300203430ustar00rootroot00000000000000# -*- encoding: utf-8 -*- $:.unshift(File.dirname(__FILE__) + "/lib") require "mixlib/config/version" Gem::Specification.new do |s| s.name = "mixlib-config" s.version = Mixlib::Config::VERSION s.authors = ["Chef Software, Inc."] s.email = "info@chef.io" s.files = %w{LICENSE NOTICE} + Dir.glob("lib/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) } s.homepage = "https://github.com/chef/mixlib-config" s.require_paths = ["lib"] s.required_ruby_version = ">= 2.4" s.summary = "A class based configuration library" s.description = s.summary s.license = "Apache-2.0" s.add_dependency "tomlrb" end mixlib-config-3.0.6/spec/000077500000000000000000000000001360222075300152015ustar00rootroot00000000000000mixlib-config-3.0.6/spec/mixlib/000077500000000000000000000000001360222075300164655ustar00rootroot00000000000000mixlib-config-3.0.6/spec/mixlib/config_spec.rb000066400000000000000000001117131360222075300212750ustar00rootroot00000000000000# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008-2018, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper")) describe Mixlib::Config do before(:each) do ConfigIt.configure do |c| c[:alpha] = "omega" c[:foo] = nil end end it "loads a config file" do allow(File).to receive(:exists?).and_return(true) allow(File).to receive(:readable?).and_return(true) allow(IO).to receive(:read).with("config.rb").and_return("alpha = 'omega'\nfoo = 'bar'") expect(lambda do ConfigIt.from_file("config.rb") end).to_not raise_error end it "doesn't raise an ArgumentError with an explanation if you try and set a non-existent variable" do expect(lambda do ConfigIt[:foobar] = "blah" end).to_not raise_error end it "raises an Errno::ENOENT if it can't find the file" do expect(lambda do ConfigIt.from_file("/tmp/timmytimmytimmy") end).to raise_error(Errno::ENOENT) end it "allows the error to bubble up when it's anything other than IOError" do allow(IO).to receive(:read).with("config.rb").and_return("@#asdf") expect(lambda do ConfigIt.from_file("config.rb") end).to raise_error(SyntaxError) end it "allows you to reference a value by index" do expect(ConfigIt[:alpha]).to eql("omega") end it "allows you to reference a value by string index" do expect(ConfigIt["alpha"]).to eql("omega") end it "allows you to set a value by index" do ConfigIt[:alpha] = "one" expect(ConfigIt[:alpha]).to eql("one") end it "allows you to set a value by string index" do ConfigIt["alpha"] = "one" expect(ConfigIt[:alpha]).to eql("one") end it "allows setting a value with attribute form" do ConfigIt.arbitrary_value = 50 expect(ConfigIt.arbitrary_value).to eql(50) expect(ConfigIt[:arbitrary_value]).to eql(50) end it "allows setting a value with method form" do ConfigIt.arbitrary_value 50 expect(ConfigIt.arbitrary_value).to eql(50) expect(ConfigIt[:arbitrary_value]).to eql(50) end describe "when strict mode is on" do class StrictClass extend ::Mixlib::Config config_strict_mode true default :x, 1 end it "allows you to get and set configured values" do StrictClass.x = StrictClass.x * 2 StrictClass[:x] = StrictClass[:x] * 2 end it "raises an error when you get an arbitrary config option with .y" do expect(lambda { StrictClass.y }).to raise_error(Mixlib::Config::UnknownConfigOptionError, "Reading unsupported config value y.") end it "raises an error when you get an arbitrary config option with [:y]" do expect(lambda { StrictClass[:y] }).to raise_error(Mixlib::Config::UnknownConfigOptionError, "Reading unsupported config value y.") end it "raises an error when you set an arbitrary config option with .y = 10" do expect(lambda { StrictClass.y = 10 }).to raise_error(Mixlib::Config::UnknownConfigOptionError, "Cannot set unsupported config value y.") end it "raises an error when you set an arbitrary config option with .y 10" do expect(lambda { StrictClass.y 10 }).to raise_error(Mixlib::Config::UnknownConfigOptionError, "Cannot set unsupported config value y.") end it "raises an error when you set an arbitrary config option with [:y] = 10" do expect(lambda { StrictClass[:y] = 10 }).to raise_error(Mixlib::Config::UnknownConfigOptionError, "Cannot set unsupported config value y.") end it "does not break config_context_list" do expect(lambda do StrictClass.class_eval do config_context_list(:lists, :list) do default :y, 20 end end end).not_to raise_error end it "does not break config_context_hash" do expect(lambda do StrictClass.class_eval do config_context_hash(:hashes, :hash) do default :z, 20 end end end).not_to raise_error end end describe "when a block has been used to set config values" do before do ConfigIt.configure { |c| c[:cookbook_path] = "monkey_rabbit"; c[:otherthing] = "boo" } end { cookbook_path: "monkey_rabbit", otherthing: "boo" }.each do |k, v| it "allows you to retrieve the config value for #{k} via []" do expect(ConfigIt[k]).to eql(v) end it "allows you to retrieve the config value for #{k} via method_missing" do expect(ConfigIt.send(k)).to eql(v) end end end it "doesn't raise an ArgumentError if you access a config option that does not exist" do expect(lambda { ConfigIt[:snob_hobbery] }).to_not raise_error end it "returns true or false with has_key?" do expect(ConfigIt.key?(:monkey)).to be false ConfigIt[:monkey] = "gotcha" expect(ConfigIt.key?(:monkey)).to be true end it "returns true or false with key?" do expect(ConfigIt.key?(:monkey2)).to be false ConfigIt[:monkey2] = "gotcha" expect(ConfigIt.key?(:monkey2)).to be true end describe "when a class method override writer exists" do before do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do config_attr_writer :test_method do |blah| blah.is_a?(Integer) ? blah * 1000 : blah end end end it "multiplies an integer by 1000" do @klass[:test_method] = 53 expect(@klass[:test_method]).to eql(53000) end it "multiplies an integer by 1000 with the method_missing form" do @klass.test_method = 63 expect(@klass.test_method).to eql(63000) end it "multiplies an integer by 1000 with the instance_eval DSL form" do @klass.instance_eval("test_method 73") expect(@klass.test_method).to eql(73000) end it "multiplies an integer by 1000 via from-file, too" do allow(IO).to receive(:read).with("config.rb").and_return("test_method 99") @klass.from_file("config.rb") expect(@klass.test_method).to eql(99000) end it "receives internal_set with the method name and config value" do expect(@klass).to receive(:internal_set).with(:test_method, 53).and_return(true) @klass[:test_method] = 53 end end describe "When a configurable exists" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do configurable :daemonizeme default :a, 1 config_attr_writer(:b) { |v| v } config_context(:c) end end it "Getter methods are created for the configurable" do expect(@klass.respond_to?(:daemonizeme)).to be true expect(@klass.respond_to?(:a)).to be true expect(@klass.respond_to?(:b)).to be true expect(@klass.respond_to?(:c)).to be true expect(@klass.respond_to?(:z)).to be false end it "Setter methods are created for the configurable" do expect(@klass.respond_to?("daemonizeme=".to_sym)).to be true expect(@klass.respond_to?("a=".to_sym)).to be true expect(@klass.respond_to?("b=".to_sym)).to be true expect(@klass.respond_to?("c=".to_sym)).to be true expect(@klass.respond_to?("z=".to_sym)).to be false end it "returns true for is_default? for a default value" do expect(@klass[:a]).to eql(1) expect(@klass.is_default?(:a)).to be true end it "returns true for is_default? for an overwritten default value" do @klass[:a] = 1 expect(@klass[:a]).to eql(1) expect(@klass.is_default?(:a)).to be true end it "returns false for is_default? for a value that is not the default" do @klass[:a] = 2 expect(@klass[:a]).to eql(2) expect(@klass.is_default?(:a)).to be false end describe "and extra methods have been dumped into Object" do class NopeError < StandardError end before :each do Object.send :define_method, :daemonizeme do raise NopeError, "NOPE" end Object.send :define_method, "daemonizeme=".to_sym do raise NopeError, "NOPE" end end after do Object.send :remove_method, :daemonizeme Object.send :remove_method, :'daemonizeme=' end it "Normal classes call the extra method" do normal_class = Class.new normal_class.extend(::Mixlib::Config) expect(lambda { normal_class.daemonizeme }).to raise_error(NopeError) end it "Configurables with the same name as the extra method can be set" do @klass.daemonizeme = 10 expect(@klass[:daemonizeme]).to eql(10) end it "Configurables with the same name as the extra method can be retrieved" do @klass[:daemonizeme] = 10 expect(@klass.daemonizeme).to eql(10) end end end describe "When config has a default value" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval { default :attr, 4 } end it "defaults to that value" do expect(@klass.attr).to eql(4) end it "defaults to that value when retrieved as a hash" do expect(@klass[:attr]).to eql(4) end it "is settable to another value" do @klass.attr 5 expect(@klass.attr).to eql(5) end it "still defaults to that value after delete" do @klass.attr 5 @klass.delete(:attr) expect(@klass.attr).to eql(4) end it "still defaults to that value after reset" do @klass.attr 5 @klass.reset expect(@klass.attr).to eql(4) end it "save should not save anything for it" do expect(@klass.save).to eql({}) end it "save with include_defaults should save all defaults" do expect(@klass.save(true)).to eql({ attr: 4 }) end it "saves the new value if it gets set" do @klass.attr 5 expect((saved = @klass.save)).to eql({ attr: 5 }) @klass.reset expect(@klass.attr).to eql(4) @klass.restore(saved) expect(@klass.attr).to eql(5) end it "saves the new value even if it is set to its default value" do @klass.attr 4 expect((saved = @klass.save)).to eql({ attr: 4 }) @klass.reset expect(@klass.save).to eql({}) @klass.restore(saved) expect(@klass.save).to eql({ attr: 4 }) end end describe "When config has a default value block" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do default :x, 4 default(:attr) { x * 2 } end end it "defaults to that value" do expect(@klass.attr).to eql(8) end it "is recalculated each time it is retrieved" do expect(@klass.attr).to eql(8) @klass.x = 2 expect(@klass.attr).to eql(4) end it "defaults to that value when retrieved as a hash" do expect(@klass[:attr]).to eql(8) end it "is settable to another value" do @klass.attr 5 expect(@klass.attr).to eql(5) end it "still defaults to that value after delete" do @klass.attr 5 @klass.delete(:attr) expect(@klass.attr).to eql(8) end it "still defaults to that value after reset" do @klass.attr 5 @klass.reset expect(@klass.attr).to eql(8) end it "save should not save anything for it" do expect(@klass.save).to eql({}) end it "save with include_defaults should save all defaults" do expect(@klass.save(true)).to eql({ attr: 8, x: 4 }) end it "saves the new value if it gets set" do @klass.attr 5 expect((saved = @klass.save)).to eql({ attr: 5 }) @klass.reset expect(@klass.attr).to eql(8) @klass.restore(saved) expect(@klass.attr).to eql(5) end it "saves the new value even if it is set to its default value" do @klass.attr 8 expect((saved = @klass.save)).to eql({ attr: 8 }) @klass.reset expect(@klass.save).to eql({}) @klass.restore(saved) expect(@klass.save).to eql({ attr: 8 }) end end describe "When config has an array default value" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval { default :attr, [] } end it "reset clears it to its default" do @klass.attr << "x" expect(@klass.attr).to eql([ "x" ]) @klass.reset expect(@klass.attr).to eql([]) end it "save should not save anything for it" do expect(@klass.save).to eql({}) end it "save with include_defaults should save all defaults" do expect(@klass.save(true)).to eql({ attr: [] }) end it "saves the new value if it gets set" do @klass.attr << "x" expect((saved = @klass.save)).to eql({ attr: [ "x" ] }) @klass.reset expect(@klass.attr).to eql([]) @klass.restore(saved) expect(@klass.attr).to eql([ "x" ]) end it "saves the new value even if it is set to its default value" do @klass.attr = [] expect((saved = @klass.save)).to eql({ attr: [] }) @klass.reset expect(@klass.save).to eql({}) @klass.restore(saved) expect(@klass.save).to eql({ attr: [] }) end end describe "When config has a hash default value" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval { default :attr, {} } end it "reset clears it to its default" do @klass.attr[:x] = 10 expect(@klass.attr[:x]).to eql(10) @klass.reset expect(@klass.attr[:x]).to be_nil end it "save should not save anything for it" do expect(@klass.save).to eql({}) end it "save with include_defaults should save all defaults" do expect(@klass.save(true)).to eql({ attr: {} }) end it "saves the new value if it gets set" do @klass.attr[:hi] = "lo" expect((saved = @klass.save)).to eql({ attr: { hi: "lo" } }) @klass.reset expect(@klass.attr).to eql({}) @klass.restore(saved) expect(@klass.save).to eql({ attr: { hi: "lo" } }) end it "saves the new value even if it is set to its default value" do @klass.attr = {} expect((saved = @klass.save)).to eql({ attr: {} }) @klass.reset expect(@klass.save).to eql({}) @klass.restore(saved) expect(@klass.save).to eql({ attr: {} }) end end describe "When config has a string default value" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval { default :attr, "hello" } end it "reset clears it to its default" do @klass.attr << " world" expect(@klass.attr).to eql("hello world") @klass.reset expect(@klass.attr).to eql("hello") end it "save should not save anything for it" do expect(@klass.save).to eql({}) end it "save with include_defaults should save all defaults" do expect(@klass.save(true)).to eql({ attr: "hello" }) end it "saves the new value if it gets set" do @klass.attr << " world" expect((saved = @klass.save)).to eql({ attr: "hello world" }) @klass.reset expect(@klass.attr).to eql("hello") @klass.restore(saved) expect(@klass.attr).to eql("hello world") end it "saves the new value even if it is set to its default value" do @klass.attr "hello world" expect((saved = @klass.save)).to eql({ attr: "hello world" }) @klass.reset expect(@klass.save).to eql({}) @klass.restore(saved) expect(@klass.save).to eql({ attr: "hello world" }) end end describe "When config has a a default value block" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do default(:attr) { 4 } end end it "defaults to that value" do expect(@klass.attr).to eql(4) end it "defaults to that value when retrieved as a hash" do expect(@klass[:attr]).to eql(4) end it "is settable to another value" do @klass.attr 5 expect(@klass.attr).to eql(5) expect(@klass[:attr]).to eql(5) end it "still defaults to that value after delete" do @klass.attr 5 @klass.delete(:attr) expect(@klass.attr).to eql(4) end it "still defaults to that value after reset" do @klass.attr 5 @klass.reset expect(@klass.attr).to eql(4) end it "save should not save anything for it" do expect(@klass.save).to eql({}) end it "save with include_defaults should save all defaults" do expect(@klass.save(true)).to eql({ attr: 4 }) end it "saves the new value if it gets set" do @klass.attr 5 expect((saved = @klass.save)).to eql({ attr: 5 }) @klass.reset expect(@klass.attr).to eql(4) @klass.restore(saved) expect(@klass.attr).to eql(5) end it "saves the new value even if it is set to its default value" do @klass.attr 4 expect((saved = @klass.save)).to eql({ attr: 4 }) @klass.reset expect(@klass.save).to eql({}) @klass.restore(saved) expect(@klass.save).to eql({ attr: 4 }) end end describe "When a configurable exists with writer and default value" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do configurable(:attr) do |c| c.defaults_to(4) c.writes_value { |value| value * 2 } end end end it "defaults to that value" do expect(@klass.attr).to eql(4) end it "defaults to that value when retrieved as a hash" do expect(@klass[:attr]).to eql(4) end it "is settable to another value" do @klass.attr 5 expect(@klass.attr).to eql(10) expect(@klass[:attr]).to eql(10) end it "is settable to another value with attr=" do @klass.attr = 5 expect(@klass.attr).to eql(10) expect(@klass[:attr]).to eql(10) end it "is settable to another value with [:attr]=" do @klass[:attr] = 5 expect(@klass.attr).to eql(10) expect(@klass[:attr]).to eql(10) end it "still defaults to that value after delete" do @klass.attr 5 @klass.delete(:attr) expect(@klass.attr).to eql(4) end it "still defaults to that value after reset" do @klass.attr 5 @klass.reset expect(@klass.attr).to eql(4) end it "save should not save anything for it" do expect(@klass.save).to eql({}) end it "save with include_defaults should save all defaults" do expect(@klass.save(true)).to eql({ attr: 4 }) end it "saves the new value if it gets set" do @klass.attr 5 expect((saved = @klass.save)).to eql({ attr: 10 }) @klass.reset expect(@klass.attr).to eql(4) @klass.restore(saved) expect(@klass.attr).to eql(10) end it "saves the new value even if it is set to its default value" do @klass.attr 4 expect((saved = @klass.save)).to eql({ attr: 8 }) @klass.reset expect(@klass.save).to eql({}) @klass.restore(saved) expect(@klass.save).to eql({ attr: 8 }) end end describe "When a configurable exists with writer and default value set in chained form" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do configurable(:attr).defaults_to(4).writes_value { |value| value * 2 } end end it "defaults to that value" do expect(@klass.attr).to eql(4) end it "defaults to that value when retrieved as a hash" do expect(@klass[:attr]).to eql(4) end it "is settable to another value" do @klass.attr 5 expect(@klass.attr).to eql(10) expect(@klass[:attr]).to eql(10) end it "is settable to another value with attr=" do @klass.attr = 5 expect(@klass.attr).to eql(10) expect(@klass[:attr]).to eql(10) end it "is settable to another value with [:attr]=" do @klass[:attr] = 5 expect(@klass.attr).to eql(10) expect(@klass[:attr]).to eql(10) end it "still defaults to that value after delete" do @klass.attr 5 @klass.delete(:attr) expect(@klass.attr).to eql(4) end it "still defaults to that value after reset" do @klass.attr 5 @klass.reset expect(@klass.attr).to eql(4) end it "save should not save anything for it" do expect(@klass.save).to eql({}) end it "save with include_defaults should save all defaults" do expect(@klass.save(true)).to eql({ attr: 4 }) end it "saves the new value if it gets set" do @klass.attr 5 expect((saved = @klass.save)).to eql({ attr: 10 }) @klass.reset expect(@klass.attr).to eql(4) @klass.restore(saved) expect(@klass.attr).to eql(10) end it "saves the new value even if it is set to its default value" do @klass.attr 2 expect((saved = @klass.save)).to eql({ attr: 4 }) @klass.reset expect(@klass.save).to eql({}) @klass.restore(saved) expect(@klass.save).to eql({ attr: 4 }) end end describe "When a configurable exists with a context" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do configurable :x config_context(:blah) do default :x, 5 end end end it "configurable defaults in that context work" do expect(@klass.blah.x).to eql(5) end it "after setting values in the context, the values remain set" do @klass.blah.x = 10 expect(@klass.blah.x).to eql(10) end it "setting values with the same name in the parent context do not affect the child context" do @klass.x = 10 expect(@klass.x).to eql(10) expect(@klass.blah.x).to eql(5) end it "setting the entire context to a hash with default value overridden sets the value" do @klass.blah = { x: 10 } expect(@klass.blah.x).to eql(10) end it "setting the entire context to a hash sets non-default values" do @klass.blah = { y: 10 } expect(@klass.blah.x).to eql(5) expect(@klass.blah.y).to eql(10) end it "setting the entire context to a hash deletes any non-default values and resets default values" do @klass.blah.x = 10 @klass.blah.y = 10 @klass.blah = { z: 10 } expect(@klass.blah.x).to eql(5) expect(@klass.blah.y).to be_nil expect(@klass.blah.z).to eql(10) end it "setting the context values in a block overrides the default values" do @klass.blah do x 10 y 20 end expect(@klass.blah.x).to eq 10 expect(@klass.blah.y).to eq 20 end it "setting the context values in a yielded block overrides the default values" do @klass.blah do |b| b.x = 10 b.y = 20 end expect(@klass.blah.x).to eq 10 expect(@klass.blah.y).to eq 20 end it "after reset of the parent class, children are reset" do @klass.blah.x = 10 expect(@klass.blah.x).to eql(10) @klass.reset expect(@klass.blah.x).to eql(5) end it "save should not save anything for it by default" do expect(@klass.save).to eql({}) end it "save with include_defaults should save all defaults" do expect(@klass.save(true)).to eql({ blah: { x: 5 } }) end it "saves any new values that are set in the context" do @klass.blah.x = 10 expect((saved = @klass.save)).to eql({ blah: { x: 10 } }) @klass.reset expect(@klass.blah.x).to eql(5) @klass.restore(saved) expect(@klass.blah.x).to eql(10) expect(@klass.save).to eql({ blah: { x: 10 } }) end # this tests existing (somewhat bizzare) behavior of mixlib-config where testing to # see if a key exists is equivalent to testing if the key has been set -- we can still # retrieve the default value if it was set. the code in chef/chef which merges # knife config values into cli values will be sensitive to this behavior. it "defaults values do not show up when querying with #has_key?" do expect(@klass.blah.key?(:x)).to be false expect(@klass.blah.x).to be 5 end it "if we assign the values, they show up when querying with #has_key?" do @klass.blah.x = 5 expect(@klass.blah.key?(:x)).to be true end end describe "When a configurable exists with a nested context" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do config_context(:blah) do config_context(:yarr) do default :x, 5 default :y, 6 end end configurable :x end end it "configurable defaults in that context work" do expect(@klass.blah.yarr.x).to eql(5) expect(@klass.blah.yarr.y).to eql(6) end it "after setting values in the context, the values remain set" do @klass.blah.yarr.x = 10 @klass.blah.yarr.y = 11 expect(@klass.blah.yarr.x).to eql(10) expect(@klass.blah.yarr.y).to eql(11) end it "setting values with the same name in the parent context do not affect the child context" do @klass.x = 10 expect(@klass.x).to eql(10) expect(@klass.blah.yarr.x).to eql(5) end it "after reset of the parent class, children are reset" do @klass.blah.yarr.x = 10 @klass.blah.yarr.y = 11 expect(@klass.blah.yarr.x).to eql(10) expect(@klass.blah.yarr.y).to eql(11) @klass.reset expect(@klass.blah.yarr.x).to eql(5) expect(@klass.blah.yarr.y).to eql(6) end it "save should not save anything for it by default" do expect(@klass.save).to eql({}) end it "save with include_defaults should save all defaults" do expect(@klass.save(true)).to eql({ blah: { yarr: { x: 5, y: 6 } } }) end it "saves any new values that are set in the context" do @klass.blah.yarr.x = 10 @klass.blah.yarr.y = 11 expect((saved = @klass.save)).to eql({ blah: { yarr: { x: 10, y: 11 } } }) @klass.reset expect(@klass.blah.yarr.x).to eql(5) expect(@klass.blah.yarr.y).to eql(6) @klass.restore(saved) expect(@klass.blah.yarr.x).to eql(10) expect(@klass.blah.yarr.y).to eql(11) expect(@klass.save).to eql({ blah: { yarr: { x: 10, y: 11 } } }) end it "restores defaults not included in saved data" do @klass.restore( blah: { yarr: { x: 10 } } ) expect(@klass.blah.yarr.x).to eql(10) expect(@klass.blah.yarr.y).to eql(6) end it "removes added properties not included in saved state" do @klass.blah.yarr.z = 12 @klass.restore( blah: { yarr: { x: 10 } } ) expect(@klass.blah.yarr.x).to eql(10) expect(@klass.blah.yarr.z).to eql(nil) end it "can set a config context from another context" do @klass.blah.blyme = { x: 7 } blyme = @klass.blah.blyme @klass.blah.yarr.x = 12 @klass.blah.yarr = blyme expect(@klass.blah.yarr.x).to eql(7) end end describe "When a config_context with no defaulted values exists" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do config_context(:blah) do configurable(:x) end end end it "has_key? finds the subcontext" do expect(@klass.key?(:blah)).to be true end it "key? finds the subcontext" do expect(@klass.key?(:blah)).to be true end it "save does not save the hash for the config_context" do expect(@klass.save).to eql({}) end it "save with defaults saves the hash for the config_context" do expect(@klass.save(true)).to eql({ blah: {} }) end end describe "When a config_context with no configurables exists" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do config_context(:blah) end end it "save does not save the hash for the config_context" do expect(@klass.save).to eql({}) end it "save with defaults saves the hash for the config_context" do expect(@klass.save(true)).to eql({ blah: {} }) end end describe "When a nested context has strict mode on" do class StrictClass2 extend ::Mixlib::Config config_context :c do config_strict_mode true default :x, 1 end end it "The parent class allows you to set arbitrary config options" do StrictClass2.y = 10 end it "The nested class does not allow you to set arbitrary config options" do expect(lambda { StrictClass2.c.y = 10 }).to raise_error(Mixlib::Config::UnknownConfigOptionError, "Cannot set unsupported config value y.") end end describe "When strict mode is on but a nested context has strict mode unspecified" do class StrictClass3 extend ::Mixlib::Config config_strict_mode true default :x, 1 config_context :c end it "The parent class does not allow you to set arbitrary config options" do expect(lambda { StrictClass3.y = 10 }).to raise_error(Mixlib::Config::UnknownConfigOptionError, "Cannot set unsupported config value y.") end it "The nested class does not allow you to set arbitrary config options" do expect(lambda { StrictClass3.y = 10 }).to raise_error(Mixlib::Config::UnknownConfigOptionError, "Cannot set unsupported config value y.") end end describe "When a config_context is opened twice" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do config_context(:blah) do default :x, 10 end config_context(:blah) do default :y, 20 end end end it "Both config_context blocks are honored" do @klass.blah.x == 10 @klass.blah.y == 20 end end it "When a config_context is opened in place of a regular configurable, an error is raised" do klass = Class.new klass.extend(::Mixlib::Config) expect(lambda do klass.class_eval do default :blah, 10 config_context(:blah) do default :y, 20 end end end).to raise_error(Mixlib::Config::ReopenedConfigurableWithConfigContextError) end it "When a config_context is opened in place of a regular configurable, an error is raised" do klass = Class.new klass.extend(::Mixlib::Config) expect(lambda do klass.class_eval do config_context(:blah) do default :y, 20 end default :blah, 10 end end).to raise_error(Mixlib::Config::ReopenedConfigContextWithConfigurableError) end describe "config context lists" do let(:klass) do klass = Class.new klass.extend ::Mixlib::Config klass.instance_eval do config_context_list(:tests, :test) do default :y, 20 end end klass end it "defines list methods when declaring a config_context_list" do expect(klass.methods).to include :test expect(klass.methods).to include :tests end it "creates a new item each time the singular list is called" do klass.test do y 40 end klass.test do y 50 end expect(klass.tests.length).to be 2 expect(klass.tests.first.y).to be 40 expect(klass.tests.last.y).to be 50 end it "can save the config list" do klass.test do y 40 end klass.test do y 50 end expect(klass.save).to eq({ tests: [ { y: 40 }, { y: 50 }, ], }) end it "can restore the config list from a hash" do hash = { tests: [ { y: 40 }, { y: 50 }, ], } klass.restore(hash) expect(klass.tests.length).to be 2 expect(klass.tests.first.y).to be 40 expect(klass.tests.last.y).to be 50 end end describe "config context hashes" do let(:klass) do klass = Class.new klass.extend ::Mixlib::Config klass.instance_eval do config_context_hash(:tests, :test) do default :y, 20 end end klass end it "defines list methods when declaring a config_context_hash" do expect(klass.methods).to include :test expect(klass.methods).to include :tests end context "when called with a new key each time" do it "creates a new item each time" do klass.test :one do y 40 end klass.test :two do y 50 end expect(klass.tests.length).to be 2 expect(klass.tests[:one].y).to be 40 expect(klass.tests[:two].y).to be 50 end end context "when called with the same key" do it "modifies the existing value" do klass.test :only do y 40 end klass.test :only do y 50 end expect(klass.tests.length).to be 1 expect(klass.tests[:only].y).to be 50 end end it "can save the config hash" do klass.test :one do y 40 end klass.test :two do y 50 end expect(klass.save).to eq({ tests: { one: { y: 40 }, two: { y: 50 }, }, }) end it "can restore the config hash from a hash" do hash = { tests: { one: { y: 40 }, two: { y: 50 }, }, } klass.restore(hash) expect(klass.tests.length).to be 2 expect(klass.tests[:one].y).to be 40 expect(klass.tests[:two].y).to be 50 end end describe ".from_yaml" do let(:yaml) do <<~EOH --- foo: - bar - baz - matazz alpha: beta EOH end it "turns YAML into method-style setting" do allow(File).to receive(:exists?).and_return(true) allow(File).to receive(:readable?).and_return(true) allow(IO).to receive(:read).with("config.yml").and_return(yaml) expect(lambda do ConfigIt.from_file("config.yml") end).to_not raise_error expect(ConfigIt.foo).to eql(%w{ bar baz matazz }) expect(ConfigIt.alpha).to eql("beta") end end describe ".from_json" do let(:json) do <<~EOH { "foo": [ "bar", "baz", "matazz" ], "alpha": "beta" } EOH end it "turns JSON into method-style setting" do allow(File).to receive(:exists?).and_return(true) allow(File).to receive(:readable?).and_return(true) allow(IO).to receive(:read).with("config.json").and_return(json) expect(lambda do ConfigIt.from_file("config.json") end).to_not raise_error expect(ConfigIt.foo).to eql(%w{ bar baz matazz }) expect(ConfigIt.alpha).to eql("beta") end end describe ".from_toml" do let(:toml) do <<~EOH foo = ["bar", "baz", "matazz"] alpha = "beta" EOH end it "turns TOML into method-style setting" do allow(File).to receive(:exists?).and_return(true) allow(File).to receive(:readable?).and_return(true) allow(IO).to receive(:read).with("config.toml").and_return(toml) expect(lambda do ConfigIt.from_file("config.toml") end).to_not raise_error expect(ConfigIt.foo).to eql(%w{ bar baz matazz }) expect(ConfigIt.alpha).to eql("beta") end end describe ".from_hash" do context "when contexts in the hash are defined" do let(:hash) do { "alpha" => "beta", gamma: "delta", "foo" => %w{ bar baz matazz}, "bar" => { "baz" => { "fizz" => "buzz" } }, "windows_path" => 'C:\Windows Has Awful\Paths', } end it "configures the config object from a hash" do ConfigIt.config_context :bar do config_context :baz do default :fizz, "quux" end end ConfigIt.from_hash(hash) expect(ConfigIt.foo).to eql(%w{ bar baz matazz }) expect(ConfigIt.alpha).to eql("beta") expect(ConfigIt.gamma).to eql("delta") expect(ConfigIt[:bar][:baz][:fizz]).to eql("buzz") expect(ConfigIt.windows_path).to eql('C:\Windows Has Awful\Paths') end end context "when contexts in the hash are undefined and strict disabled" do before do ConfigIt.strict_mode = true end let(:hash) do { "brrr" => { "baz" => { "fizz" => "buzz" } }, "windows_path" => 'C:\Windows Has Awful\Paths', } end it "configures the config object, creating contexts as needed" do ConfigIt.from_hash(hash) expect(ConfigIt[:brrr][:baz][:fizz]).to eql("buzz") expect(ConfigIt.windows_path).to eql('C:\Windows Has Awful\Paths') end end end end mixlib-config-3.0.6/spec/spec_helper.rb000066400000000000000000000004471360222075300200240ustar00rootroot00000000000000$TESTING = true $:.push File.join(File.dirname(__FILE__), "..", "lib") require "rspec" require "mixlib/config" class ConfigIt extend Mixlib::Config end RSpec.configure do |config| config.filter_run focus: true config.run_all_when_everything_filtered = true config.warnings = true end