acook/config_module

View on GitHub
README.markdown

Summary

Maintainability
Test Coverage
ConfigModule
=============

Load important configuration files into their own modules!

Reference documentation for the [Latest Released](http://rubydoc.info/gems/config_module/file/README.markdown) and [Edge Version](https://github.com/acook/config_module#readme) is available.

[![Gem Version](https://img.shields.io/gem/v/config_module.svg?style=for-the-badge)](https://rubygems.org/gems/config_module)
[![Gem Downloads](https://img.shields.io/gem/dt/config_module.svg?style=for-the-badge)](https://rubygems.org/gems/config_module)
[![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/acook/config_module/ruby.yml?style=for-the-badge)](https://github.com/acook/config_module/actions/workflows/ruby.yml)
[![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability/acook/config_module?style=for-the-badge)](https://codeclimate.com/github/acook/config_module)

Installation
------------

Install the [gem](http://rubygems.org/gems/config_module), preferably using [Bundler](http://gembundler.com/):

  ```ruby
  gem 'config_module'     # in your Gemfile
  ```

  ```bash
  bundle install          # on the command line
  ```

You may need to tell Ruby that you want to use it (depending how you're using Bundler):

  ```ruby
  require 'config_module' # in your file
  ```

Setup
-----

You only need to add two lines inside any module definition to make it a ConfigModule.

1. Add the ConfigModule functionality to your module:

  ```ruby
  extend ConfigModule
  ```

2. Specify the name of your configuration file:

  ```ruby
  config_file './some_config.yml'
  ```

Done!

You're set up, and you can add any other functionality, aliases, or derived values to your module
like any other Ruby module.

Usage
-----

Now give it a try, any [valid](#caveats)
key in your configuration file will now be a method:

```ruby
SomeConfig.my_key
```

You can even chain them! Try it:

```ruby
SomeConfig.my_key.my_subkey
```

How cool is that?

Extras
------

In addition to the basics, ConfigModule also supplies a couple of helpers you might find useful.

### Namespaces

You can also set the "namespace" you want to use, this is great for apps with different configurations per environment:

```ruby
namespace ENV['my_environment']
```

This will set the root of the configuration tree to whichever branch you specify, so you don't have to.

Depending on your configuration file's structure, it might be useful to pull out a deeper subtree, in that case you can include multiple keys separated by commas, or even give it an array.

Check out the [example section](#example) below to see how it's used.

### The `config` Method

There's also a new method available in your module that points to the root of your configuration data:

```ruby
def foo
  config.foo
end
```

### Check for Presence of Configuration Keys with `has_key?`

You might want to check to see if the key exists (especially useful along with namespaces) before calling the method. Much like a Hash, you can use the `has_key?` method and do something like:

```ruby
if MyConfig.has_key? :some_option then
  MyConfig.some_option
else
  'my default value'
end
```

### Hash-like Access

You can access config options like a hash too, if you want:

  ```ruby
  MyConfig[:some_key].is_a? Hash #=> true
  ```

  This is useful mainly when you'd rather get a `nil` instead of raising an error for nonexistant keys:

  ```ruby
  MyConfig[:nonexistant_key] #=> nil
  MyConfig.nonexistant_key   #=> raises ConfigModule::ConfigOption::NotFoundError
  ```

  It'll also avoid any naming conflicts that might arise between methods names and key names. You can use it in concert with the above `config` method instead of `self` to enhance readability:

  ```ruby
  def bar
    config[:my_key]
  end
  ```
  
  Lastly, it also doesn't wrap the returned value in a `ConfigOption`, it will return the underlying value such as a `Hash` directly.


### Enumerable

  `ConfigOption` is the way ConfigModule packages up subtrees, and unlike `OpenStruct`, it is `Enumerable`:

  ```ruby
  MyConfig.some_key_with_subkeys.each do |subkey|
    puts subkey
  end
  ```

Example
-------

Given a YAML file `./config/example.yml':

```yaml
---
:example:
  :production:
    :foo: bar
    :noodle: boom!
```

And you set up your module:

```ruby
require 'config_module'

module ExampleConfig
  extend ConfigModule

  config_file './config/example.yml'
  namespace :example, Rails.env

  module_function

  def kanoodle
    'ka' + noodle
  end

  def all_keys
    config.map do |key, _|
      key
    end
  end
end
```

Then you can use it like this:

```ruby
ExampleConfig.foo       #=> 'bar'
ExampleConfig[:foo]     #=> 'bar'
ExampleConfig[:notakey] #=> nil
ExampleConfig.kanoodle  #=> 'kaboom!'
ExampleConfig.all_keys  #=> [:foo, :noodle]
```

Pretty nifty, huh?

Caveats
-------

- **Q:** You mention "valid key". What's a valid key?
- **A:** It's any object that you can call `.to_sym` on (same as `OpenStruct`)!

Who made this anyway?
---------------------

    © 2016-2019 Anthony M. Cook
    Contributors: Brian Hawley