envied 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +5 -50
- data/envied.gemspec +1 -1
- data/examples/extensive_envfile +46 -0
- data/lib/envied.rb +24 -206
- data/lib/envied/coercer.rb +77 -0
- data/lib/envied/configuration.rb +109 -0
- data/lib/envied/templates/heroku-env-check.tt +2 -2
- data/lib/envied/variable.rb +18 -0
- data/lib/envied/version.rb +1 -1
- data/spec/coercer_spec.rb +99 -0
- data/spec/configuration_spec.rb +33 -0
- data/spec/envied_spec.rb +35 -27
- data/spec/variable_spec.rb +15 -0
- metadata +13 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 501198780ddc5bf4762c604f90938baad9258ee4
         | 
| 4 | 
            +
              data.tar.gz: 3027a30c7815e8925246e7f14d3e7ffcc7a3bfef
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 826a2dfaa0ac7730c2fcaa14e14ea997b3c5b665774eed3ed91110e5950a29d982c6eb761e783a7eee4be6b3d1629483b068e5a1971b0d9eccabb9dc329c41c2
         | 
| 7 | 
            +
              data.tar.gz: ad53e3a25cb8a9c817eb14fb0a0f0a8d815fd8dd87b54dfdf0653f920dd6e8f963014d2efdb9fd56405b8ec67d40f5df36930752c6d7794bdce41d61df8c2556
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -2,7 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            ### TL;DR ensure presence and type of your app's ENV-variables.
         | 
| 4 4 |  | 
| 5 | 
            -
            Features:
         | 
| 5 | 
            +
            ## Features:
         | 
| 6 6 |  | 
| 7 7 | 
             
            * check for presence and correctness of ENV-variables
         | 
| 8 8 | 
             
            * access to typed ENV-variables (integers, booleans etc. instead of just strings)
         | 
| @@ -16,6 +16,7 @@ Features: | |
| 16 16 | 
             
              * [Types](#types)
         | 
| 17 17 | 
             
              * [Groups](#groups)
         | 
| 18 18 | 
             
              * [Defaults](#defaults)
         | 
| 19 | 
            +
              * [More examples](#more-examples)
         | 
| 19 20 | 
             
            * [Rails](#rails)
         | 
| 20 21 | 
             
            * [Command-line interface](#command-line-interface)
         | 
| 21 22 | 
             
            * [Testing](#testing)
         | 
| @@ -135,56 +136,10 @@ As a rule of thumb you should only use defaults: | |
| 135 136 | 
             
            * for local development
         | 
| 136 137 | 
             
            * for ENV-variables that your application introduces (i.e. for `ENV['STAFF_EMAILS']` not for `ENV['REDIS_URL']`)
         | 
| 137 138 |  | 
| 138 | 
            -
            ###  | 
| 139 | 
            +
            ### More examples
         | 
| 139 140 |  | 
| 140 | 
            -
             | 
| 141 | 
            -
             | 
| 142 | 
            -
            # We allow defaults for local development (and local tests), but want our CI
         | 
| 143 | 
            -
            # to mimic our production as much as possible.
         | 
| 144 | 
            -
            # New developers that don't have RACK_ENV set, will in this way not be presented with a huge
         | 
| 145 | 
            -
            # list of missing variables, as defaults are still enabled.
         | 
| 146 | 
            -
            not_production_nor_ci = ->{ !(ENV['RACK_ENV'] == 'production' || ENV['CI']) }
         | 
| 147 | 
            -
            enable_defaults!(¬_production_nor_ci)
         | 
| 148 | 
            -
             | 
| 149 | 
            -
            # Your code will likely not use ENVied.RACK_ENV (better use Rails.env),
         | 
| 150 | 
            -
            # we want it to be present though; heck, we're using it in this file!
         | 
| 151 | 
            -
            variable :RACK_ENV
         | 
| 152 | 
            -
             | 
| 153 | 
            -
            variable :FORCE_SSL, :Boolean, default: false
         | 
| 154 | 
            -
            variable :PORT, :Integer, default: 3000
         | 
| 155 | 
            -
            # generate the default value using the value of PORT:
         | 
| 156 | 
            -
            variable :PUBLIC_HOST_WITH_PORT, :String, default: proc {|envied| "localhost:#{envied.PORT}" }
         | 
| 157 | 
            -
             | 
| 158 | 
            -
            group :production do
         | 
| 159 | 
            -
              variable :MAIL_PAAS_USERNAME
         | 
| 160 | 
            -
              variable :DATABASE_URL
         | 
| 161 | 
            -
            end
         | 
| 162 | 
            -
             | 
| 163 | 
            -
            group :ci do
         | 
| 164 | 
            -
              # ci-only stuff
         | 
| 165 | 
            -
            end
         | 
| 166 | 
            -
             | 
| 167 | 
            -
            group :not_ci do
         | 
| 168 | 
            -
              # CI needs no puma-threads, and sidekiq-stuff etc.
         | 
| 169 | 
            -
              # Define that here:
         | 
| 170 | 
            -
              variable :MIN_THREADS, :Integer, default: 1
         | 
| 171 | 
            -
              # more...
         | 
| 172 | 
            -
            end
         | 
| 173 | 
            -
             | 
| 174 | 
            -
            # Depending on our situation, we can now require the groups needed:
         | 
| 175 | 
            -
            # At local machines:
         | 
| 176 | 
            -
            ENVied.require(:default, :development, :not_ci) or
         | 
| 177 | 
            -
            ENVied.require(:default, :test, :not_ci)
         | 
| 178 | 
            -
             | 
| 179 | 
            -
            # At the server:
         | 
| 180 | 
            -
            ENVied.require(:default, :production, :not_ci)
         | 
| 181 | 
            -
             | 
| 182 | 
            -
            # At CI:
         | 
| 183 | 
            -
            ENVied.require(:default, :test, :ci)
         | 
| 184 | 
            -
             | 
| 185 | 
            -
            # All in one line:
         | 
| 186 | 
            -
            ENVied.require(:default, ENV['RACK_ENV'], (ENV['CI'] ? :ci : :not_ci))
         | 
| 187 | 
            -
            ```
         | 
| 141 | 
            +
            * See the [examples](/examples)-folder for a more extensive Envfile
         | 
| 142 | 
            +
            * See [the Envfile](https://github.com/eval/bunny_drain/blob/c54d7d977afb5e23a92da7a2fd0d39f6a7e29bf1/Envfile) for the bunndy_drain application
         | 
| 188 143 |  | 
| 189 144 | 
             
            ## Rails
         | 
| 190 145 |  | 
    
        data/envied.gemspec
    CHANGED
    
    | @@ -19,7 +19,7 @@ Gem::Specification.new do |spec| | |
| 19 19 | 
             
              spec.require_paths = ["lib"]
         | 
| 20 20 |  | 
| 21 21 | 
             
              spec.required_ruby_version = '>= 1.9.3'
         | 
| 22 | 
            -
              spec.add_dependency " | 
| 22 | 
            +
              spec.add_dependency "coercible", '~> 1.0'
         | 
| 23 23 | 
             
              spec.add_dependency "rack", "~> 1.4"
         | 
| 24 24 | 
             
              spec.add_dependency "thor", "~> 0.15"
         | 
| 25 25 | 
             
              spec.add_development_dependency "bundler", "~> 1.5"
         | 
| @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            # -*- mode: ruby -*-¬
         | 
| 2 | 
            +
            # We allow defaults for local development (and local tests), but want our CI
         | 
| 3 | 
            +
            # to mimic our production as much as possible.
         | 
| 4 | 
            +
            # New developers that don't have RACK_ENV set, will in this way not be presented with a huge
         | 
| 5 | 
            +
            # list of missing variables, as defaults are still enabled.
         | 
| 6 | 
            +
            not_production_nor_ci = ->{ !(ENV['RACK_ENV'] == 'production' || ENV['CI']) }
         | 
| 7 | 
            +
            enable_defaults!(¬_production_nor_ci)
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            # Your code will likely not use ENVied.RACK_ENV (better use Rails.env),
         | 
| 10 | 
            +
            # we want it to be present though; heck, we're using it in this file!
         | 
| 11 | 
            +
            variable :RACK_ENV
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            variable :FORCE_SSL, :Boolean, default: false
         | 
| 14 | 
            +
            variable :PORT, :Integer, default: 3000
         | 
| 15 | 
            +
            # generate the default value using the value of PORT:
         | 
| 16 | 
            +
            variable :PUBLIC_HOST_WITH_PORT, :String, default: proc {|envied| "localhost:#{envied.PORT}" }
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            group :production do
         | 
| 19 | 
            +
              variable :MAIL_PAAS_USERNAME
         | 
| 20 | 
            +
              variable :DATABASE_URL
         | 
| 21 | 
            +
            end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            group :ci do
         | 
| 24 | 
            +
              # ci-only stuff
         | 
| 25 | 
            +
            end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            group :not_ci do
         | 
| 28 | 
            +
              # CI needs no puma-threads, and sidekiq-stuff etc.
         | 
| 29 | 
            +
              # Define that here:
         | 
| 30 | 
            +
              variable :MIN_THREADS, :Integer, default: 1
         | 
| 31 | 
            +
              # more...
         | 
| 32 | 
            +
            end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            # Depending on our situation, we can now require the correct groups in our initialization-file:
         | 
| 35 | 
            +
            # At local machines:
         | 
| 36 | 
            +
            # ENVied.require(:default, :development, :not_ci) or
         | 
| 37 | 
            +
            # ENVied.require(:default, :test, :not_ci)
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            # At the server:
         | 
| 40 | 
            +
            # ENVied.require(:default, :production, :not_ci)
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            # At CI:
         | 
| 43 | 
            +
            # ENVied.require(:default, :test, :ci)
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            # All in one line:
         | 
| 46 | 
            +
            # ENVied.require(:default, ENV['RACK_ENV'], (ENV['CI'] ? :ci : :not_ci))
         | 
    
        data/lib/envied.rb
    CHANGED
    
    | @@ -1,238 +1,56 @@ | |
| 1 1 | 
             
            require 'envied/version'
         | 
| 2 2 | 
             
            require 'envied/cli'
         | 
| 3 | 
            -
            require ' | 
| 3 | 
            +
            require 'envied/coercer'
         | 
| 4 | 
            +
            require 'envied/variable'
         | 
| 5 | 
            +
            require 'envied/configuration'
         | 
| 4 6 |  | 
| 5 7 | 
             
            class ENVied
         | 
| 6 | 
            -
              module Hashable
         | 
| 7 | 
            -
                def to_hash
         | 
| 8 | 
            -
                  require 'rack/utils'
         | 
| 9 | 
            -
                  ::Rack::Utils.parse_nested_query(self)
         | 
| 10 | 
            -
                end
         | 
| 11 | 
            -
              end
         | 
| 12 | 
            -
             | 
| 13 | 
            -
              module Arrayable
         | 
| 14 | 
            -
                def to_a
         | 
| 15 | 
            -
                  self.split(/(?<!\\), ?/).map{|i| i.gsub(/\\,/,',') }
         | 
| 16 | 
            -
                end
         | 
| 17 | 
            -
              end
         | 
| 18 | 
            -
             | 
| 19 | 
            -
              class Configuration
         | 
| 20 | 
            -
                include Virtus.model
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                def self.variable(name, type = :String, options = {})
         | 
| 23 | 
            -
                  options = { default: nil, strict: true, group: self.current_group }.merge(options)
         | 
| 24 | 
            -
                  type = Array if type == :Array
         | 
| 25 | 
            -
                  attribute(name, type, options)
         | 
| 26 | 
            -
                end
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                def self.group(name, &block)
         | 
| 29 | 
            -
                  self.current_group = name.to_sym
         | 
| 30 | 
            -
                  yield
         | 
| 31 | 
            -
                ensure
         | 
| 32 | 
            -
                  self.current_group = :default
         | 
| 33 | 
            -
                end
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                def self.enable_defaults
         | 
| 36 | 
            -
                  (@enable_defaults ||= false).respond_to?(:call) ?
         | 
| 37 | 
            -
                    @enable_defaults.call :
         | 
| 38 | 
            -
                    @enable_defaults
         | 
| 39 | 
            -
                end
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                def self.enable_defaults!(value = nil, &block)
         | 
| 42 | 
            -
                  value ||= block if block_given?
         | 
| 43 | 
            -
                  @enable_defaults = value
         | 
| 44 | 
            -
                end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                class << self
         | 
| 47 | 
            -
                  alias_method :defaults_enabled?, :enable_defaults
         | 
| 48 | 
            -
                  alias_method :enable_defaults=, :enable_defaults!
         | 
| 49 | 
            -
                  attr_writer :current_group
         | 
| 50 | 
            -
                end
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                def self.current_group
         | 
| 53 | 
            -
                  @current_group ||= :default
         | 
| 54 | 
            -
                end
         | 
| 55 | 
            -
              end
         | 
| 56 | 
            -
             | 
| 57 | 
            -
              def self.configuration(options = {}, &block)
         | 
| 58 | 
            -
                if block_given?
         | 
| 59 | 
            -
                  @configuration = build_configuration(&block).tap do |c|
         | 
| 60 | 
            -
                    options.each {|k, v| c.public_send("#{k}=", v) }
         | 
| 61 | 
            -
                  end
         | 
| 62 | 
            -
                end
         | 
| 63 | 
            -
                @configuration ||= build_configuration
         | 
| 64 | 
            -
              end
         | 
| 65 | 
            -
             | 
| 66 | 
            -
              def self.configure(options = {}, &block)
         | 
| 67 | 
            -
                deprecation_warning "ENVied.configure will be deprecated. Please generate an Envfile instead (see the envied command)."
         | 
| 68 | 
            -
                configuration(options, &block)
         | 
| 69 | 
            -
              end
         | 
| 70 | 
            -
             | 
| 71 8 | 
             
              class << self
         | 
| 72 | 
            -
                 | 
| 73 | 
            -
              end
         | 
| 74 | 
            -
             | 
| 75 | 
            -
              def self.build_configuration(&block)
         | 
| 76 | 
            -
                Class.new(Configuration).tap do |c|
         | 
| 77 | 
            -
                  c.instance_eval(&block) if block_given?
         | 
| 78 | 
            -
                end
         | 
| 9 | 
            +
                attr_reader :env, :config
         | 
| 79 10 | 
             
              end
         | 
| 80 11 |  | 
| 81 12 | 
             
              def self.require(*groups)
         | 
| 82 | 
            -
                 | 
| 83 | 
            -
                @ | 
| 84 | 
            -
             | 
| 85 | 
            -
                  self.required_groups = groups.map(&:to_sym)
         | 
| 86 | 
            -
                else
         | 
| 87 | 
            -
                  self.required_groups = [:default]
         | 
| 88 | 
            -
                end
         | 
| 89 | 
            -
                ensure_configured!
         | 
| 13 | 
            +
                @config ||= Configuration.load
         | 
| 14 | 
            +
                @env ||= EnvProxy.new(@config, groups: required_groups(*groups))
         | 
| 15 | 
            +
             | 
| 90 16 | 
             
                error_on_missing_variables!
         | 
| 91 17 | 
             
                error_on_uncoercible_variables!
         | 
| 92 | 
            -
             | 
| 93 | 
            -
                _required_variables = required_variables
         | 
| 94 | 
            -
                group_configuration = build_configuration do
         | 
| 95 | 
            -
                  _required_variables.each do |v|
         | 
| 96 | 
            -
                    @attribute_set << v
         | 
| 97 | 
            -
                  end
         | 
| 98 | 
            -
                end
         | 
| 99 | 
            -
                @instance = group_configuration.new(env)
         | 
| 100 | 
            -
              end
         | 
| 101 | 
            -
             | 
| 102 | 
            -
              def self.springified_require(*args)
         | 
| 103 | 
            -
                springify { ENVied.require(*args) }
         | 
| 104 | 
            -
              end
         | 
| 105 | 
            -
             | 
| 106 | 
            -
              def self.springify(&block)
         | 
| 107 | 
            -
                if defined?(Spring) && Spring.respond_to?(:watcher)
         | 
| 108 | 
            -
                  Spring.after_fork(&block)
         | 
| 109 | 
            -
                else
         | 
| 110 | 
            -
                  block.call
         | 
| 111 | 
            -
                end
         | 
| 112 | 
            -
              end
         | 
| 113 | 
            -
             | 
| 114 | 
            -
              def self.ensure_configured!
         | 
| 115 | 
            -
                # Backward compat: load Envfile only when it's present
         | 
| 116 | 
            -
                configure_via_envfile if envfile_exist?
         | 
| 117 | 
            -
              end
         | 
| 118 | 
            -
             | 
| 119 | 
            -
              def self.envfile
         | 
| 120 | 
            -
                File.expand_path('Envfile')
         | 
| 121 | 
            -
              end
         | 
| 122 | 
            -
             | 
| 123 | 
            -
              def self.envfile_exist?
         | 
| 124 | 
            -
                File.exist?(envfile)
         | 
| 125 | 
            -
              end
         | 
| 126 | 
            -
             | 
| 127 | 
            -
              def self.configure_via_envfile
         | 
| 128 | 
            -
                configuration { eval(File.read(ENVied.envfile)) }
         | 
| 129 18 | 
             
              end
         | 
| 130 19 |  | 
| 131 20 | 
             
              def self.error_on_missing_variables!
         | 
| 132 | 
            -
                 | 
| 133 | 
            -
             | 
| 134 | 
            -
                end
         | 
| 21 | 
            +
                names = env.missing_variables.map(&:name)
         | 
| 22 | 
            +
                raise "The following environment variables should be set: #{names * ', '}" if names.any?
         | 
| 135 23 | 
             
              end
         | 
| 136 24 |  | 
| 137 25 | 
             
              def self.error_on_uncoercible_variables!
         | 
| 138 | 
            -
                 | 
| 139 | 
            -
             | 
| 140 | 
            -
                  single_error = "ENV['%{name}'] ('%{value}' can't be coerced to %{type})"
         | 
| 141 | 
            -
                  errors = non_coercible_variables.map do |v|
         | 
| 142 | 
            -
                    var_type = v.type.to_s.split("::").last
         | 
| 143 | 
            -
                    single_error % { name: v.name, value: env_value_or_default(v), type: var_type }
         | 
| 144 | 
            -
                  end.join ", "
         | 
| 145 | 
            -
             | 
| 146 | 
            -
                  raise "Some ENV-variables are not coercible: #{errors}"
         | 
| 26 | 
            +
                errors = env.uncoercible_variables.map do |v|
         | 
| 27 | 
            +
                  "%{name} ('%{value}' can't be coerced to %{type})" % {name: v.name, value: env.value_to_coerce(v), type: v.type }
         | 
| 147 28 | 
             
                end
         | 
| 29 | 
            +
                raise "The following environment variables are not coercible: #{errors.join(", ")}" if errors.any?
         | 
| 148 30 | 
             
              end
         | 
| 149 31 |  | 
| 150 | 
            -
              def self. | 
| 151 | 
            -
                 | 
| 32 | 
            +
              def self.required_groups(*groups)
         | 
| 33 | 
            +
                result = groups.compact
         | 
| 34 | 
            +
                result.any? ? result.map(&:to_sym) : [:default]
         | 
| 152 35 | 
             
              end
         | 
| 153 36 |  | 
| 154 | 
            -
              def self. | 
| 155 | 
            -
                 | 
| 156 | 
            -
                   | 
| 37 | 
            +
              def self.springify(&block)
         | 
| 38 | 
            +
                if spring_enabled?
         | 
| 39 | 
            +
                  Spring.after_fork(&block)
         | 
| 40 | 
            +
                else
         | 
| 41 | 
            +
                  block.call
         | 
| 157 42 | 
             
                end
         | 
| 158 43 | 
             
              end
         | 
| 159 44 |  | 
| 160 | 
            -
              def self. | 
| 161 | 
            -
                 | 
| 162 | 
            -
              end
         | 
| 163 | 
            -
             | 
| 164 | 
            -
              # Yields the assigned default for the variable.
         | 
| 165 | 
            -
              # When defaults are disabled, nil is returned.
         | 
| 166 | 
            -
              def self.default_value(variable)
         | 
| 167 | 
            -
                defaults_enabled? ? variable.default_value.value : nil
         | 
| 168 | 
            -
              end
         | 
| 169 | 
            -
             | 
| 170 | 
            -
              # A list of all configured variable names.
         | 
| 171 | 
            -
              #
         | 
| 172 | 
            -
              # @example
         | 
| 173 | 
            -
              #   ENVied.required_variable_names
         | 
| 174 | 
            -
              #   # => [:DATABASE_URL]
         | 
| 175 | 
            -
              #
         | 
| 176 | 
            -
              # @return [Array<Symbol>] the list of variable names
         | 
| 177 | 
            -
              def self.required_variable_names
         | 
| 178 | 
            -
                required_variables.map(&:name).map(&:to_sym)
         | 
| 179 | 
            -
              end
         | 
| 180 | 
            -
             | 
| 181 | 
            -
              def self.required_variables
         | 
| 182 | 
            -
                from_required_group = ->(var){ self.required_groups.include?(var.options[:group]) }
         | 
| 183 | 
            -
                configured_variables.to_a.keep_if(&from_required_group)
         | 
| 184 | 
            -
              end
         | 
| 185 | 
            -
             | 
| 186 | 
            -
              def self.configured_variables
         | 
| 187 | 
            -
                configuration.attribute_set.dup#.to_a.keep_if(&var_from_required_group)
         | 
| 188 | 
            -
              end
         | 
| 189 | 
            -
             | 
| 190 | 
            -
              def self.provided_variable_names
         | 
| 191 | 
            -
                ENV.keys.map(&:to_sym)
         | 
| 192 | 
            -
              end
         | 
| 193 | 
            -
             | 
| 194 | 
            -
              def self.non_coercible_variables
         | 
| 195 | 
            -
                required_variables.reject(&method(:variable_coercible?))
         | 
| 196 | 
            -
              end
         | 
| 197 | 
            -
             | 
| 198 | 
            -
              def self.variable_coercible?(variable)
         | 
| 199 | 
            -
                var_value = env_value_or_default(variable)
         | 
| 200 | 
            -
                return true if var_value.respond_to?(:call)
         | 
| 201 | 
            -
             | 
| 202 | 
            -
                !variable.coerce(var_value).nil?
         | 
| 203 | 
            -
              rescue Virtus::CoercionError
         | 
| 204 | 
            -
                return false
         | 
| 205 | 
            -
              end
         | 
| 206 | 
            -
             | 
| 207 | 
            -
              def self.missing_variable_names
         | 
| 208 | 
            -
                unprovided = required_variable_names - provided_variable_names
         | 
| 209 | 
            -
                unprovided -= names_of_required_variables_with_defaults if defaults_enabled?
         | 
| 210 | 
            -
                unprovided
         | 
| 211 | 
            -
              end
         | 
| 212 | 
            -
             | 
| 213 | 
            -
              def self.names_of_required_variables_with_defaults
         | 
| 214 | 
            -
                required_variables_with_defaults.map(&:name).map(&:to_sym)
         | 
| 215 | 
            -
              end
         | 
| 216 | 
            -
             | 
| 217 | 
            -
              def self.required_variables_with_defaults
         | 
| 218 | 
            -
                required_variables.map do |v|
         | 
| 219 | 
            -
                  v unless v.default_value.value.nil?
         | 
| 220 | 
            -
                end.compact
         | 
| 221 | 
            -
              end
         | 
| 222 | 
            -
             | 
| 223 | 
            -
              def self.defaults_enabled?
         | 
| 224 | 
            -
                configuration.enable_defaults
         | 
| 45 | 
            +
              def self.spring_enabled?
         | 
| 46 | 
            +
                defined?(Spring) && Spring.respond_to?(:watcher)
         | 
| 225 47 | 
             
              end
         | 
| 226 48 |  | 
| 227 49 | 
             
              def self.method_missing(method, *args, &block)
         | 
| 228 | 
            -
                respond_to_missing?(method) ?  | 
| 50 | 
            +
                respond_to_missing?(method) ? (env && env[method.to_s]) : super
         | 
| 229 51 | 
             
              end
         | 
| 230 52 |  | 
| 231 53 | 
             
              def self.respond_to_missing?(method, include_private = false)
         | 
| 232 | 
            -
                 | 
| 233 | 
            -
              end
         | 
| 234 | 
            -
             | 
| 235 | 
            -
              def self.deprecation_warning(msg)
         | 
| 236 | 
            -
                puts "DEPRECATION WARNING: #{msg}"
         | 
| 54 | 
            +
                (env && env.has_key?(method)) || super
         | 
| 237 55 | 
             
              end
         | 
| 238 56 | 
             
            end
         | 
| @@ -0,0 +1,77 @@ | |
| 1 | 
            +
            require 'coercible'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # Responsible for all string to type coercions.
         | 
| 4 | 
            +
            class ENVied::Coercer
         | 
| 5 | 
            +
              module CoercerExts
         | 
| 6 | 
            +
                def to_array(str)
         | 
| 7 | 
            +
                  str.split(/(?<!\\),/).map{|i| i.gsub(/\\,/,',') }
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def to_hash(str)
         | 
| 11 | 
            +
                  require 'rack/utils'
         | 
| 12 | 
            +
                  ::Rack::Utils.parse_query(str)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
              Coercible::Coercer::String.send(:include, CoercerExts)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              # Coerce strings to specific type.
         | 
| 18 | 
            +
              #
         | 
| 19 | 
            +
              # @param string [String] the string to be coerced
         | 
| 20 | 
            +
              # @param type [#to_sym] the type to coerce to
         | 
| 21 | 
            +
              #
         | 
| 22 | 
            +
              # @example
         | 
| 23 | 
            +
              #   ENVied::Coercer.new.coerce('1', :Integer)
         | 
| 24 | 
            +
              #   # => 1
         | 
| 25 | 
            +
              #
         | 
| 26 | 
            +
              # @return [type] the coerced string.
         | 
| 27 | 
            +
              def coerce(string, type)
         | 
| 28 | 
            +
                unless supported_type?(type)
         | 
| 29 | 
            +
                  raise ArgumentError, "#{type.inspect} is not supported type"
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
                coerce_method_for(type.to_sym)[string]
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              def coerce_method_for(type)
         | 
| 35 | 
            +
                return nil unless supported_type?(type)
         | 
| 36 | 
            +
                coercer.method("to_#{type.downcase}")
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              def self.supported_types
         | 
| 40 | 
            +
                @supported_types ||= begin
         | 
| 41 | 
            +
                  [:hash, :array, :time, :date, :symbol, :boolean, :integer, :string]
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              # Whether or not Coercer can coerce strings to the provided type.
         | 
| 46 | 
            +
              #
         | 
| 47 | 
            +
              # @param type [#to_sym] the type (case insensitive)
         | 
| 48 | 
            +
              #
         | 
| 49 | 
            +
              # @example
         | 
| 50 | 
            +
              #   ENVied::Coercer.supported_type?('string')
         | 
| 51 | 
            +
              #   # => true
         | 
| 52 | 
            +
              #
         | 
| 53 | 
            +
              # @return [Boolean] whether type is supported.
         | 
| 54 | 
            +
              def self.supported_type?(type)
         | 
| 55 | 
            +
                supported_types.include?(type.to_sym.downcase)
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
              def supported_type?(type)
         | 
| 59 | 
            +
                self.class.supported_type?(type)
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              def coercer
         | 
| 63 | 
            +
                @coercer ||= Coercible::Coercer.new[String]
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
              def coerced?(value)
         | 
| 67 | 
            +
                !value.kind_of?(String)
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              def coercible?(string, type)
         | 
| 71 | 
            +
                return false unless supported_type?(type)
         | 
| 72 | 
            +
                coerce(string, type)
         | 
| 73 | 
            +
                true
         | 
| 74 | 
            +
              rescue Coercible::UnsupportedCoercion
         | 
| 75 | 
            +
                false
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
            end
         | 
| @@ -0,0 +1,109 @@ | |
| 1 | 
            +
            class ENVied
         | 
| 2 | 
            +
              class Configuration
         | 
| 3 | 
            +
                attr_reader :current_group, :defaults_enabled
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def initialize(options = {})
         | 
| 6 | 
            +
                  @defaults_enabled = options.fetch(:enable_defaults, false)
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def self.load
         | 
| 10 | 
            +
                  new.tap do |v|
         | 
| 11 | 
            +
                    v.instance_eval(File.read(File.expand_path('Envfile')))
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def enable_defaults!(value = nil, &block)
         | 
| 16 | 
            +
                  @defaults_enabled = (value.nil? ? block : value)
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def defaults_enabled?
         | 
| 20 | 
            +
                  @defaults_enabled.respond_to?(:call) ?
         | 
| 21 | 
            +
                    @defaults_enabled.call :
         | 
| 22 | 
            +
                    @defaults_enabled
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def variable(name, type = :String, options = {})
         | 
| 26 | 
            +
                  options[:group] = current_group if current_group
         | 
| 27 | 
            +
                  variables << ENVied::Variable.new(name, type, options)
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def group(name, &block)
         | 
| 31 | 
            +
                  @current_group = name.to_sym
         | 
| 32 | 
            +
                  yield
         | 
| 33 | 
            +
                ensure
         | 
| 34 | 
            +
                  @current_group = nil
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def variables
         | 
| 38 | 
            +
                  @variables ||= []
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              # Responsible for anything related to the ENV.
         | 
| 43 | 
            +
              class EnvProxy
         | 
| 44 | 
            +
                attr_reader :config, :coercer, :groups
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def initialize(config, options = {})
         | 
| 47 | 
            +
                  @config = config
         | 
| 48 | 
            +
                  @coercer = options.fetch(:coercer, ENVied::Coercer.new)
         | 
| 49 | 
            +
                  @groups = options.fetch(:groups, [])
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def missing_variables
         | 
| 53 | 
            +
                  variables.select(&method(:missing?))
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                def uncoercible_variables
         | 
| 57 | 
            +
                  variables.reject(&method(:coerced?)).reject(&method(:coercible?))
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                def variables
         | 
| 61 | 
            +
                  @variables ||= begin
         | 
| 62 | 
            +
                    config.variables.select {|v| groups.include?(v.group) }
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                def variables_by_name
         | 
| 67 | 
            +
                  Hash[variables.map {|v| [v.name, v] }]
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                def [](name)
         | 
| 71 | 
            +
                  coerce(variables_by_name[name.to_sym])
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                def has_key?(name)
         | 
| 75 | 
            +
                  variables_by_name[name.to_sym]
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                def env_value_of(var)
         | 
| 79 | 
            +
                  ENV[var.name.to_s]
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                def default_value_of(var)
         | 
| 83 | 
            +
                  var.default_value(ENVied, var)
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                def value_to_coerce(var)
         | 
| 87 | 
            +
                  return env_value_of(var) unless env_value_of(var).nil?
         | 
| 88 | 
            +
                  config.defaults_enabled? ? default_value_of(var) : nil
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                def coerce(var)
         | 
| 92 | 
            +
                  coerced?(var) ?
         | 
| 93 | 
            +
                    value_to_coerce(var) :
         | 
| 94 | 
            +
                    coercer.coerce(value_to_coerce(var), var.type)
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                def coercible?(var)
         | 
| 98 | 
            +
                  coercer.coercible?(value_to_coerce(var), var.type)
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                def missing?(var)
         | 
| 102 | 
            +
                  value_to_coerce(var).nil?
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                def coerced?(var)
         | 
| 106 | 
            +
                  coercer.coerced?(value_to_coerce(var))
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
              end
         | 
| 109 | 
            +
            end
         | 
| @@ -3,7 +3,7 @@ | |
| 3 3 | 
             
            # Check the config of a Heroku app against the defined variables in `Envfile`
         | 
| 4 4 |  | 
| 5 5 | 
             
            <%- if @app %>
         | 
| 6 | 
            -
            HEROKU_APP=<%= @app %> exec heroku config | bundle exec envied check:heroku --groups <%= @groups.join(" | 
| 6 | 
            +
            HEROKU_APP=<%= @app %> exec heroku config | bundle exec envied check:heroku --groups <%= @groups.join(" ") %>
         | 
| 7 7 | 
             
            <%- else %>
         | 
| 8 | 
            -
            exec heroku config | bundle exec envied check:heroku --groups <%= @groups.join(" | 
| 8 | 
            +
            exec heroku config | bundle exec envied check:heroku --groups <%= @groups.join(" ") %>
         | 
| 9 9 | 
             
            <%- end %>
         | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            class ENVied::Variable
         | 
| 2 | 
            +
              attr_reader :name, :type, :group, :default
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              def initialize(name, type, options = {})
         | 
| 5 | 
            +
                @name = name.to_sym
         | 
| 6 | 
            +
                @type = type.to_sym
         | 
| 7 | 
            +
                @group = options.fetch(:group, :default).to_sym
         | 
| 8 | 
            +
                @default = options[:default]
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                #if !@default.is_a? String
         | 
| 11 | 
            +
                #  raise ArgumentError, "Default values should be strings (variable #{@name})"
         | 
| 12 | 
            +
                #end
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              def default_value(*args)
         | 
| 16 | 
            +
                default.respond_to?(:call) ? default[*args] : default
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
    
        data/lib/envied/version.rb
    CHANGED
    
    
| @@ -0,0 +1,99 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe ENVied::Coercer do
         | 
| 4 | 
            +
              it { is_expected.to respond_to :coerce }
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              describe '#coerce' do
         | 
| 7 | 
            +
                let(:coercer){ described_class.new }
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def coerce_to(type)
         | 
| 10 | 
            +
                  ->(str){ coercer.coerce(str, type) }
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                describe 'string coercion' do
         | 
| 14 | 
            +
                  let(:coerce){ coerce_to(:String) }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  it 'yields the input untouched' do
         | 
| 17 | 
            +
                    expect(coerce['1']).to eq '1'
         | 
| 18 | 
            +
                    expect(coerce[' 1']).to eq ' 1'
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                describe 'integer coercion' do
         | 
| 23 | 
            +
                  let(:coerce){ coerce_to(:Integer) }
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  it 'converts strings to integers' do
         | 
| 26 | 
            +
                    expect(coerce['1']).to eq 1
         | 
| 27 | 
            +
                    expect(coerce['-1']).to eq(-1)
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                describe 'boolean coercion' do
         | 
| 32 | 
            +
                  let(:coerce){ coerce_to(:Boolean) }
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  it "converts 'true' and 'false'" do
         | 
| 35 | 
            +
                    expect(coerce['true']).to eq true
         | 
| 36 | 
            +
                    expect(coerce['false']).to eq false
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  it "converts '1' and '0'" do
         | 
| 40 | 
            +
                    expect(coerce['1']).to eq true
         | 
| 41 | 
            +
                    expect(coerce['0']).to eq false
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                describe 'symbol coercion' do
         | 
| 46 | 
            +
                  let(:coerce){ coerce_to(:Symbol) }
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  it 'converts strings to symbols' do
         | 
| 49 | 
            +
                    expect(coerce['a']).to eq :a
         | 
| 50 | 
            +
                    expect(coerce['nice_symbol']).to eq :nice_symbol
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                describe 'date coercion' do
         | 
| 55 | 
            +
                  let(:coerce){ coerce_to(:Date) }
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  it 'converts strings to date' do
         | 
| 58 | 
            +
                    expect(coerce['2014-12-25']).to eq Date.parse('2014-12-25')
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                describe 'time coercion' do
         | 
| 63 | 
            +
                  let(:coerce){ coerce_to(:Time) }
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  it 'converts strings to time' do
         | 
| 66 | 
            +
                    expect(coerce['4:00']).to eq Time.parse('4:00')
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                describe 'array coercion' do
         | 
| 71 | 
            +
                  let(:coerce){ coerce_to(:Array) }
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  it 'converts strings to array' do
         | 
| 74 | 
            +
                    {
         | 
| 75 | 
            +
                      'a,b' => ['a','b'],
         | 
| 76 | 
            +
                      ' a, b' => [' a',' b'],
         | 
| 77 | 
            +
                      'apples,and\, of course\, pears' => ['apples','and, of course, pears'],
         | 
| 78 | 
            +
                    }.each do |i, o|
         | 
| 79 | 
            +
                      expect(coerce[i]).to eq o
         | 
| 80 | 
            +
                    end
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                describe 'hash coercion' do
         | 
| 85 | 
            +
                  let(:coerce){ coerce_to(:Hash) }
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  it 'converts strings to hashes' do
         | 
| 88 | 
            +
                    {
         | 
| 89 | 
            +
                      'a=1' => {'a' => '1'},
         | 
| 90 | 
            +
                      'a=1&b=2' => {'a' => '1', 'b' => '2'},
         | 
| 91 | 
            +
                      'a=&b=2' => {'a' => '', 'b' => '2'},
         | 
| 92 | 
            +
                      'a&b=2' => {'a' => nil, 'b' => '2'},
         | 
| 93 | 
            +
                    }.each do |i, o|
         | 
| 94 | 
            +
                      expect(coerce[i]).to eq o
         | 
| 95 | 
            +
                    end
         | 
| 96 | 
            +
                  end
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
              end
         | 
| 99 | 
            +
            end
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe ENVied::Configuration do
         | 
| 4 | 
            +
              it { is_expected.to respond_to :variable }
         | 
| 5 | 
            +
              it { is_expected.to respond_to :enable_defaults! }
         | 
| 6 | 
            +
              it { is_expected.to respond_to :defaults_enabled? }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              describe '#variable' do
         | 
| 9 | 
            +
                it 'results in an added variable' do
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              describe 'defaults' do
         | 
| 15 | 
            +
                it 'is disabled by default' do
         | 
| 16 | 
            +
                  expect(subject.defaults_enabled?).to_not be
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                describe '#enable_defaults!' do
         | 
| 20 | 
            +
                  it 'can be passed a value' do
         | 
| 21 | 
            +
                    expect {
         | 
| 22 | 
            +
                      subject.enable_defaults!(true)
         | 
| 23 | 
            +
                    }.to change { subject.defaults_enabled? }
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  it 'can be passed a block' do
         | 
| 27 | 
            +
                    expect {
         | 
| 28 | 
            +
                      subject.enable_defaults! { true }
         | 
| 29 | 
            +
                    }.to change { subject.defaults_enabled? }.to(true)
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
    
        data/spec/envied_spec.rb
    CHANGED
    
    | @@ -1,10 +1,14 @@ | |
| 1 1 | 
             
            require 'spec_helper'
         | 
| 2 2 |  | 
| 3 3 | 
             
            describe ENVied do
         | 
| 4 | 
            -
               | 
| 4 | 
            +
              describe 'class' do
         | 
| 5 | 
            +
                subject { described_class }
         | 
| 5 6 |  | 
| 6 | 
            -
             | 
| 7 | 
            -
               | 
| 7 | 
            +
                it { is_expected.to respond_to :require }
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              describe 'responding to methods that are variables' do
         | 
| 11 | 
            +
              end
         | 
| 8 12 |  | 
| 9 13 | 
             
              before do
         | 
| 10 14 | 
             
                reset_env
         | 
| @@ -12,7 +16,7 @@ describe ENVied do | |
| 12 16 | 
             
              end
         | 
| 13 17 |  | 
| 14 18 | 
             
              def reset_configuration
         | 
| 15 | 
            -
                ENVied.instance_eval { @ | 
| 19 | 
            +
                ENVied.instance_eval { @config = nil }
         | 
| 16 20 | 
             
              end
         | 
| 17 21 |  | 
| 18 22 | 
             
              def reset_env
         | 
| @@ -27,16 +31,19 @@ describe ENVied do | |
| 27 31 | 
             
                end
         | 
| 28 32 |  | 
| 29 33 | 
             
                def configure(options = {}, &block)
         | 
| 30 | 
            -
                   | 
| 34 | 
            +
                  ENVied.instance_eval do
         | 
| 35 | 
            +
                    @config = ENVied::Configuration.new(options).tap{|c| c.instance_eval(&block)}
         | 
| 36 | 
            +
                  end
         | 
| 31 37 | 
             
                  self
         | 
| 32 38 | 
             
                end
         | 
| 33 39 |  | 
| 34 40 | 
             
                def configured_with(hash = {})
         | 
| 35 | 
            -
                   | 
| 41 | 
            +
                  config = ENVied::Configuration.new.tap do |c|
         | 
| 36 42 | 
             
                    hash.each do |name, type|
         | 
| 37 | 
            -
                      variable(name, *type)
         | 
| 43 | 
            +
                      c.variable(name, *type)
         | 
| 38 44 | 
             
                    end
         | 
| 39 45 | 
             
                  end
         | 
| 46 | 
            +
                  ENVied.instance_eval{ @config = config }
         | 
| 40 47 | 
             
                  self
         | 
| 41 48 | 
             
                end
         | 
| 42 49 |  | 
| @@ -53,14 +60,14 @@ describe ENVied do | |
| 53 60 | 
             
                  configured_with(a: :Integer).and_ENV({'a' => '1'})
         | 
| 54 61 | 
             
                  described_class.require
         | 
| 55 62 |  | 
| 56 | 
            -
                   | 
| 63 | 
            +
                  expect(described_class).to respond_to :a
         | 
| 57 64 | 
             
                end
         | 
| 58 65 |  | 
| 59 66 | 
             
                it 'responds not to unconfigured variables' do
         | 
| 60 67 | 
             
                  unconfigured.and_ENV({'A' => '1'})
         | 
| 61 68 | 
             
                  described_class.require
         | 
| 62 69 |  | 
| 63 | 
            -
                   | 
| 70 | 
            +
                  expect(described_class).to_not respond_to :B
         | 
| 64 71 | 
             
                end
         | 
| 65 72 |  | 
| 66 73 | 
             
                context 'ENV contains not all configured variables' do
         | 
| @@ -69,7 +76,7 @@ describe ENVied do | |
| 69 76 | 
             
                  specify do
         | 
| 70 77 | 
             
                    expect {
         | 
| 71 78 | 
             
                      ENVied.require
         | 
| 72 | 
            -
                    }.to raise_error(/ | 
| 79 | 
            +
                    }.to raise_error(/The following environment variables should be set: a/)
         | 
| 73 80 | 
             
                  end
         | 
| 74 81 | 
             
                end
         | 
| 75 82 |  | 
| @@ -79,14 +86,14 @@ describe ENVied do | |
| 79 86 | 
             
                  specify do
         | 
| 80 87 | 
             
                    expect {
         | 
| 81 88 | 
             
                      ENVied.require
         | 
| 82 | 
            -
                    }.to raise_error(/ | 
| 89 | 
            +
                    }.to raise_error(/A \('NaN' can't be coerced to Integer/)
         | 
| 83 90 | 
             
                  end
         | 
| 84 91 | 
             
                end
         | 
| 85 92 |  | 
| 86 93 | 
             
                context 'bug: default value "false" is not coercible' do
         | 
| 87 94 | 
             
                  before {
         | 
| 88 95 | 
             
                    configure(enable_defaults: true) do
         | 
| 89 | 
            -
                      variable :FORCE_SSL, :Boolean, default:  | 
| 96 | 
            +
                      variable :FORCE_SSL, :Boolean, default: true
         | 
| 90 97 | 
             
                    end
         | 
| 91 98 | 
             
                  }
         | 
| 92 99 |  | 
| @@ -99,35 +106,36 @@ describe ENVied do | |
| 99 106 |  | 
| 100 107 | 
             
                describe 'defaults' do
         | 
| 101 108 | 
             
                  describe 'setting' do
         | 
| 102 | 
            -
                    subject { described_class. | 
| 109 | 
            +
                    subject { described_class.config }
         | 
| 110 | 
            +
                    #subject { ENVied::Configuration.new }
         | 
| 103 111 |  | 
| 104 | 
            -
                    it 'is disabled by default' do
         | 
| 105 | 
            -
             | 
| 106 | 
            -
                    end
         | 
| 112 | 
            +
                    #it 'is disabled by default' do
         | 
| 113 | 
            +
                    #  expect(subject.defaults_enabled?).to_not be
         | 
| 114 | 
            +
                    #end
         | 
| 107 115 |  | 
| 108 116 | 
             
                    it 'can be enabled via #configure' do
         | 
| 109 117 | 
             
                      configure(enable_defaults: true){ }
         | 
| 110 118 |  | 
| 111 | 
            -
                      expect(subject. | 
| 119 | 
            +
                      expect(subject.defaults_enabled?).to be
         | 
| 112 120 | 
             
                    end
         | 
| 113 121 |  | 
| 114 122 | 
             
                    it 'can be enabled via a configure-block' do
         | 
| 115 | 
            -
                      configure { self.enable_defaults | 
| 123 | 
            +
                      configure { self.enable_defaults!(true) }
         | 
| 116 124 |  | 
| 117 | 
            -
                      expect(subject. | 
| 125 | 
            +
                      expect(subject.defaults_enabled?).to be
         | 
| 118 126 | 
             
                    end
         | 
| 119 127 |  | 
| 120 128 | 
             
                    it 'can be assigned a Proc' do
         | 
| 121 | 
            -
                      configure { self.enable_defaults  | 
| 129 | 
            +
                      configure { self.enable_defaults! { true } }
         | 
| 122 130 |  | 
| 123 | 
            -
                      expect(subject. | 
| 131 | 
            +
                      expect(subject.defaults_enabled?).to be
         | 
| 124 132 | 
             
                    end
         | 
| 125 133 | 
             
                  end
         | 
| 126 134 |  | 
| 127 135 | 
             
                  describe 'assigning' do
         | 
| 128 136 | 
             
                    it 'can be a value' do
         | 
| 129 137 | 
             
                      configure(enable_defaults: true) do
         | 
| 130 | 
            -
                        variable :A, :Integer, default: 1
         | 
| 138 | 
            +
                        variable :A, :Integer, default: '1'
         | 
| 131 139 | 
             
                      end
         | 
| 132 140 | 
             
                      described_class.require
         | 
| 133 141 |  | 
| @@ -136,7 +144,7 @@ describe ENVied do | |
| 136 144 |  | 
| 137 145 | 
             
                    it 'can be a Proc' do
         | 
| 138 146 | 
             
                      configure(enable_defaults: true) do
         | 
| 139 | 
            -
                        variable :A, :Integer, default: proc { 1 }
         | 
| 147 | 
            +
                        variable :A, :Integer, default: proc { "1" }
         | 
| 140 148 | 
             
                      end
         | 
| 141 149 | 
             
                      described_class.require
         | 
| 142 150 |  | 
| @@ -145,7 +153,7 @@ describe ENVied do | |
| 145 153 |  | 
| 146 154 | 
             
                    it 'is ignored if defaults are disabled' do
         | 
| 147 155 | 
             
                      configure(enable_defaults: false) do
         | 
| 148 | 
            -
                        variable :A, :Integer, default: 1
         | 
| 156 | 
            +
                        variable :A, :Integer, default: "1"
         | 
| 149 157 | 
             
                      end.and_no_ENV
         | 
| 150 158 |  | 
| 151 159 | 
             
                      expect {
         | 
| @@ -153,9 +161,9 @@ describe ENVied do | |
| 153 161 | 
             
                      }.to raise_error
         | 
| 154 162 | 
             
                    end
         | 
| 155 163 |  | 
| 156 | 
            -
                    it 'is  | 
| 164 | 
            +
                    it 'is ignored if ENV is provided' do
         | 
| 157 165 | 
             
                      configure(enable_defaults: true) do
         | 
| 158 | 
            -
                        variable :A, :Integer, default: 1
         | 
| 166 | 
            +
                        variable :A, :Integer, default: "1"
         | 
| 159 167 | 
             
                      end.and_ENV('A' => '2')
         | 
| 160 168 | 
             
                      described_class.require
         | 
| 161 169 |  | 
| @@ -257,7 +265,7 @@ describe ENVied do | |
| 257 265 | 
             
                    end
         | 
| 258 266 |  | 
| 259 267 | 
             
                    it 'yields array from string' do
         | 
| 260 | 
            -
                      expect(ENVied.moar).to eq ['a','b','and, c']
         | 
| 268 | 
            +
                      expect(ENVied.moar).to eq ['a',' b',' and, c']
         | 
| 261 269 | 
             
                    end
         | 
| 262 270 | 
             
                  end
         | 
| 263 271 | 
             
                end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,17 +1,17 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: envied
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.7. | 
| 4 | 
            +
              version: 0.7.1
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Gert Goet
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2014-08- | 
| 11 | 
            +
            date: 2014-08-28 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            -
              name:  | 
| 14 | 
            +
              name: coercible
         | 
| 15 15 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 16 | 
             
                requirements:
         | 
| 17 17 | 
             
                - - "~>"
         | 
| @@ -112,14 +112,21 @@ files: | |
| 112 112 | 
             
            - Rakefile
         | 
| 113 113 | 
             
            - bin/envied
         | 
| 114 114 | 
             
            - envied.gemspec
         | 
| 115 | 
            +
            - examples/extensive_envfile
         | 
| 115 116 | 
             
            - lib/envied.rb
         | 
| 116 117 | 
             
            - lib/envied/cli.rb
         | 
| 118 | 
            +
            - lib/envied/coercer.rb
         | 
| 119 | 
            +
            - lib/envied/configuration.rb
         | 
| 117 120 | 
             
            - lib/envied/templates/Envfile.tt
         | 
| 118 121 | 
             
            - lib/envied/templates/heroku-env-check.tt
         | 
| 119 122 | 
             
            - lib/envied/templates/rails-initializer.tt
         | 
| 123 | 
            +
            - lib/envied/variable.rb
         | 
| 120 124 | 
             
            - lib/envied/version.rb
         | 
| 125 | 
            +
            - spec/coercer_spec.rb
         | 
| 126 | 
            +
            - spec/configuration_spec.rb
         | 
| 121 127 | 
             
            - spec/envied_spec.rb
         | 
| 122 128 | 
             
            - spec/spec_helper.rb
         | 
| 129 | 
            +
            - spec/variable_spec.rb
         | 
| 123 130 | 
             
            homepage: https://github.com/eval/envied
         | 
| 124 131 | 
             
            licenses:
         | 
| 125 132 | 
             
            - MIT
         | 
| @@ -145,5 +152,8 @@ signing_key: | |
| 145 152 | 
             
            specification_version: 4
         | 
| 146 153 | 
             
            summary: Ensure presence and type of ENV-variables
         | 
| 147 154 | 
             
            test_files:
         | 
| 155 | 
            +
            - spec/coercer_spec.rb
         | 
| 156 | 
            +
            - spec/configuration_spec.rb
         | 
| 148 157 | 
             
            - spec/envied_spec.rb
         | 
| 149 158 | 
             
            - spec/spec_helper.rb
         | 
| 159 | 
            +
            - spec/variable_spec.rb
         |