ENVied
TL;DR ensure presence and type of your app's ENV-variables.
This gem will provide:
- A fail-fast check for presence of ENV-variables
- A fail-fast check whether the values can be coerced to the correct type
- Access to typed ENV-variables (instead of just strings)
Quickstart
1) Configure
After successful installation, define some variables in Envfile
:
# file: Envfile
variable :FORCE_SSL, :Boolean
variable :PORT, :Integer
2) Check for presence and coercibility
# file: some file that'll be run on initialization (e.g. `config/application.rb`)
ENVied.require
This will throw an error if:
- not both
ENV['FORCE_SSL']
andENV['PORT']
are present. - the values can't be coerced to resp. Boolean and Integer.
3) Use coerced variables
Variables accessed via ENVied are of the correct type:
ENVied.PORT # => 3001
ENVied.FORCE_SSL # => false
Configuration
Types
The following types are supported:
:String
(implied):Boolean
(e.g. '0'/'1', 'f'/'t', 'false'/'true', 'off'/'on', 'no'/'yes' for resp. false and true):Integer
:Symbol
:Date
(e.g. '2014-3-26'):Time
(e.g. '14:00'):Hash
(e.g. 'a=1&b=2' becomes{'a' => '1', 'b' => '2'}
):Array
(e.g. 'tag1,tag2' becomes['tag1', 'tag2']
)
Groups
Groups give you more flexibility to define when variables are needed.
It's similar to groups in a Gemfile:
# file: Envfile
variable :FORCE_SSL, :Boolean
group :production do
variable :NEW_RELIC_LICENSE_KEY
end
# For local development you would typically do:
ENVied.require(:default) #=> Only ENV['FORCE_SSL'] is required
# On the production server:
ENVied.require(:default, :production) #=> ...also ENV['NEW_RELIC_LICENSE_KEY'] is required
# BTW the following are equivalent:
ENVied.require
ENVied.require(:default)
ENVied.require('default')
ENVied.require(nil)
Defaults
In order to let other developers easily bootstrap the application, you can assign defaults to variables.
Defaults can be a value or a Proc
(see example below).
Note that 'easily bootstrap' is quite the opposite of 'fail-fast when not all ENV-variables are present'. Therefor you should explicitly state whén defaults are allowed:
# Envfile
enable_defaults! { ENV['RACK_ENV'] == 'development' }
variable :FORCE_SSL, :Boolean, default: false
variable :PORT, :Integer, default: proc {|envied| envied.FORCE_SSL ? 443 : 80 }
Please remember that ENVied only reads from ENV; it doesn't mutate ENV.
Don't let setting a default for, say RAILS_ENV
, give you the impression that ENV['RAILS_ENV']
is set.
As a rule of thumb you should only use defaults:
- for local development
- for ENV-variables that your application introduces (i.e. for
ENV['STAFF_EMAILS']
not forENV['REDIS_URL']
)
A more extensive example
# Envfile
# We allow defaults for local development (and local tests), but want our CI
# to mimic our production as much as possible.
# New developers that don't have RACK_ENV set, will in this way not be presented with a huge
# list of missing variables, as defaults are still enabled.
not_production_nor_ci = ->{ !(ENV['RACK_ENV'] == 'production' || ENV['CI']) }
enable_defaults!(¬_production_nor_ci)
# Your code will likely not use ENVied.RACK_ENV (better use Rails.env),
# we want it to be present though; heck, we're using it in this file!
variable :RACK_ENV
variable :FORCE_SSL, :Boolean, default: false
variable :PORT, :Integer, default: 3000
# generate the default value using the value of PORT:
variable :PUBLIC_HOST_WITH_PORT, :String, default: proc {|envied| "localhost:#{envied.PORT}" }
group :production do
variable :MAIL_PAAS_USERNAME
variable :DATABASE_URL
end
group :ci do
# ci-only stuff
end
group :not_ci do
# CI needs no puma-threads, and sidekiq-stuff etc.
# Define that here:
variable :MIN_THREADS, :Integer, default: 1
# more...
end
# Depending on our situation, we can now require the groups needed:
# At local machines:
ENVied.require(:default, :development, :not_ci) or
ENVied.require(:default, :test, :not_ci)
# At the server:
ENVied.require(:default, :production, :not_ci)
# At CI:
ENVied.require(:default, :test, :ci)
# All in one line:
ENVied.require(:default, ENV['RACK_ENV'], (ENV['CI'] ? :ci : :not_ci))
command-line interface
$ envied help
Commands:
envied check # Checks whether all ENV-variables are present and valid
envied help [COMMAND] # Describe available commands or one specific command
envied init # Generates a default Envfile in the current working directory
Installation
Add this line to your application's Gemfile:
gem 'envied'
...then bundle:
$ bundle
...and generate the Envfile
:
$ bundle exec envied init
Testing
bundle install --binstubs
bin/rspec
# or
bin/rake
Developing
bin/pry --gem
Contributing
- Fork it ( http://github.com/eval/envied/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request