envied 0.3.1 → 0.4.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 591c914549fd162d08a2cb78db12f68b7eab29e8
4
- data.tar.gz: 87b5af48a1422bb8f2ff6bb8c9c566fbd86f909e
3
+ metadata.gz: 5d3ba3eb81e06018962bb52faa7caf1fdf044aca
4
+ data.tar.gz: a92a83a6a9272771f39eca36b3f0126aac9fd439
5
5
  SHA512:
6
- metadata.gz: 7ab15f9483472b1977f56fbbb224fe880ac40e126e36972ddf0908dcd0cc5baa28c3d9e3aa7f47f6784160796cf94f752ebbb328fa0fcb0ed7763dd66de98fbc
7
- data.tar.gz: fa3a4be832c289a0bc4ca2b6ba423224d2b6590b9e0836345b1d915a72291a0bf7ed3e13d4b74b5fdbfa731348c521ef3bf1de1b1761c89360944e968043276b
6
+ metadata.gz: 7d4643b26e39b59b534285cc8f58f0228285468ec3860c3479b0a1cd3b5041a2d7fae2b40ce176c985105d4a793f705d226eef3ccf9591bc1c87a50f9d1b90a5
7
+ data.tar.gz: 2407bd5bf9a1700b76d81d77de7a4de9b2b7da1fba44257119444afb9e0e08ed2e4badf19d0f8d7cdecdf314c9a3affb4ef89119d42e0f3a9426bd0ac1d10bae
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - 2.0.0
4
+ - 2.1.0
5
+ - jruby
data/CHANGELOG.md ADDED
@@ -0,0 +1,37 @@
1
+ # 0.4.0 / 2014-05-16
2
+
3
+ * groups added
4
+
5
+ This allows for more fine-grained requiring.
6
+ See the section in the [README](https://github.com/eval/envied/tree/v0.4.0#groups).
7
+
8
+ * configuring is now simpler:
9
+
10
+ ```ruby
11
+ ENVied.configure { variable :RACK_ENV }
12
+ # vs
13
+ ENVied.configure {|env| env.variable :RACK_ENV }
14
+ ```
15
+
16
+ * Deprecate `require!`. Use `require` instead.
17
+
18
+ Just like requiring groups with Bundler.
19
+
20
+ * Deprecate lowercase methods for uppercase ENV-variables.
21
+
22
+ `ENV['RACK_ENV']` is no longer accessible as `ENVied.rack_env`, only as `ENVied.RACK_ENV`.
23
+ This is not only what you would expect, but it also reduces the chance of clashing with existing class-methods.
24
+
25
+ # 0.3.0 / 2014-03-14
26
+
27
+ * defaults need to be enabled explicitly:
28
+
29
+ `ENVied.configure(enable_defaults: Rails.env.development?) { ... }`
30
+
31
+ # 0.2.0 / 2014-03-14
32
+
33
+ * add defaults
34
+
35
+ # 0.1.0 / 2014-03-13
36
+
37
+ * add defaults
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # ENVied
1
+ # ENVied [![travis](https://secure.travis-ci.org/eval/envied.png?branch=master)](https://secure.travis-ci.org/#!/eval/envied)
2
2
 
3
3
  ### TL;DR ensure presence and type of your app's ENV-variables.
4
4
 
@@ -20,33 +20,61 @@ Let's configure the ENV-variables we need:
20
20
 
21
21
  ```ruby
22
22
  # e.g. config/application.rb
23
- ENVied.configure do |env|
24
- env.variable :force_ssl, :Boolean
25
- env.variable :port, :Integer
23
+ ENVied.configure do
24
+ variable :FORCE_SSL, :Boolean
25
+ variable :PORT, :Integer
26
26
  end
27
27
  ```
28
28
 
29
29
  ### 2) Check for presence and type
30
30
 
31
31
  ```ruby
32
- ENVied.require!
32
+ ENVied.require
33
33
  ```
34
- Excecution will halt unless ENV is something like
35
- `{'FORCE_SSL' => 'false', 'PORT' => '3001'}`.
36
34
 
37
- A meaningful error will in this case explain what key and type is needed.
35
+ This will throw an error if not:
36
+ * both `ENV['FORCE_SSL']` and `ENV['PORT']` are present
37
+ * both the values of `ENV['FORCE_SSL']` and `ENV['PORT']` can be coerced (to resp. Boolean or Integer).
38
+
39
+ (The error contains exactly what ENV-variables are missing/faulty.)
38
40
 
39
41
  ### 3) Use typed variables
40
42
 
41
43
  Variables accessed via ENVied have the configured type:
42
44
 
43
45
  ```ruby
44
- ENVied.port # => 3001
45
- ENVied.force_ssl # => false
46
+ ENVied.PORT # => 3001
47
+ ENVied.FORCE_SSL # => false
46
48
  ```
47
49
 
48
50
  ## Configuration
49
51
 
52
+ ### Groups
53
+
54
+ Groups give you more flexibility to define when variables are needed.
55
+ It's just like you Gemfile:
56
+
57
+ ```ruby
58
+ ENVied.configure do
59
+ variable :FORCE_SSL, :Boolean
60
+
61
+ group :production do
62
+ variable :NEW_RELIC_LICENSE_KEY
63
+ end
64
+ end
65
+
66
+ # For local development you would typically do:
67
+ ENVied.require(:default) #=> Only ENV['FORCE_SSL'] is required
68
+ # On the server:
69
+ ENVied.require(:default, :production) #=> ...also ENV['NEW_RELIC_LICENSE_KEY'] is required
70
+
71
+ # BTW the following are equivalent:
72
+ ENVied.require
73
+ ENVied.require(:default)
74
+ ENVied.require('default')
75
+ ENVied.require(nil)
76
+ ```
77
+
50
78
  ### Types
51
79
 
52
80
  The following types are supported:
@@ -63,20 +91,71 @@ The following types are supported:
63
91
  In order to let other developers easily bootstrap the application, you can assign defaults to variables.
64
92
  Defaults can be a value or a `Proc` (see example below).
65
93
 
66
- Note that 'easily bootstrap' is quite the opposite of 'fail-fast when not all ENV-variables are present'. Therefor it's disabled by default and you should explicitly state whén it is allowed:
94
+ 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:
67
95
 
68
96
  ```ruby
69
- ENVied.configure(enable_defaults: Rails.env.development?) do |env|
70
- env.variable :port, :Integer, default: proc {|env, variable| env.force_ssl ? 443 : 80 }
71
- env.variable :force_ssl, :Boolean, default: false
97
+ ENVied.configure(enable_defaults: ENV['RACK_ENV'] == 'development') do
98
+ variable :FORCE_SSL, :Boolean, default: false
99
+ variable :PORT, :Integer, default: proc {|envied| envied.FORCE_SSL ? 443 : 80 }
72
100
  end
73
101
  ```
74
102
 
75
- Please remember that ENVied only **reads** from ENV; don't let setting a default for, say `rails_env`, give you or your team the impression that `ENV['RAILS_ENV']` is set.
76
- As a rule of thumb: you should only use defaults:
77
- * in a development-environment
103
+ Please remember that ENVied only **reads** from ENV; it doesn't set ENV-variables.
104
+ Don't let setting a default for, say `RAILS_ENV`, give you the impression that `ENV['RAILS_ENV']` is set.
105
+ As a rule of thumb you should only use defaults:
106
+ * for local development
78
107
  * for ENV-variables that your application introduces (i.e. for `ENV['DEFAULT_SENDER']` not for `ENV['REDIS_URL']`)
79
108
 
109
+ ### A more extensive example:
110
+
111
+ ```ruby
112
+ # We allow defaults for local development (and local tests), but want our CI
113
+ # to mimic our production as much as possible.
114
+ # New developers that don't have RACK_ENV set, will in this way not be presented with a huge
115
+ # list of missing variables, as defaults are still enabled.
116
+ not_production_nor_ci = ->{ !(ENV['RACK_ENV'] == 'production' || ENV['CI']) }
117
+ ENVied.configure(enable_defaults: &not_production_nor_ci) do
118
+ # Your code will likely not use ENVied.RACK_ENV (better use Rails.env),
119
+ # we want it to be present though; heck, we're using it in this file!
120
+ variable :RACK_ENV
121
+
122
+ variable :FORCE_SSL, :Boolean, default: false
123
+ variable :PORT, :Integer, default: 3000
124
+ # generate the default value using the value of PORT:
125
+ variable :PUBLIC_HOST_WITH_PORT, :String, default: proc {|envied| "localhost:#{envied.PORT}" }
126
+
127
+ group :production do
128
+ variable :MAIL_PAAS_USERNAME
129
+ variable :DATABASE_URL, :Symbol
130
+ end
131
+
132
+ group :ci do
133
+ # ci-only stuff
134
+ end
135
+
136
+ group :not_ci do
137
+ # CI needs no puma-threads, and sidekiq-stuff etc.
138
+ # Define that here:
139
+ variable :MIN_THREADS, :Integer, default: 1
140
+ # more...
141
+ end
142
+ end
143
+
144
+ # Depending on our situation, we can now require the groups needed:
145
+ # At local machines:
146
+ ENVied.require(:default, :development, :not_ci) or
147
+ ENVied.require(:default, :test, :not_ci)
148
+
149
+ # At the server:
150
+ ENVied.require(:default, :production, :not_ci)
151
+
152
+ # At CI:
153
+ ENVied.require(:default, :test, :ci)
154
+
155
+ # All in one line:
156
+ ENVied.require(:default, ENV['RACK_ENV'], (ENV['CI'] ? :ci : :not_ci))
157
+ ```
158
+
80
159
 
81
160
  ## Installation
82
161
 
@@ -0,0 +1,3 @@
1
+ class ENVied
2
+ VERSION = '0.4.0'
3
+ end
data/lib/envied.rb CHANGED
@@ -1,137 +1,172 @@
1
+ require 'virtus'
2
+
1
3
  class ENVied
2
- module Configurable
3
- require 'virtus'
4
+ class Configuration
5
+ include Virtus.model
4
6
 
5
- class VariableError < StandardError
6
- attr_reader :variable
7
- def initialize(variable)
8
- @variable = variable
9
- end
7
+ def self.variable(name, type = :String, options = {})
8
+ options = { strict: true, group: self.current_group }.merge(options)
9
+ attribute(name, type, options)
10
+ end
10
11
 
11
- def variable_type
12
- variable.type.to_s.split("::").last
13
- end
12
+ def self.group(name, &block)
13
+ self.current_group = name.to_sym
14
+ yield
15
+ ensure
16
+ self.current_group = :default
14
17
  end
15
18
 
16
- class VariableMissingError < VariableError
17
- def message
18
- "Please provide ENV['#{variable.name.to_s.upcase}'] of type #{variable_type}"
19
- end
19
+ def self.enable_defaults
20
+ @enable_defaults.respond_to?(:call) ?
21
+ @enable_defaults.call :
22
+ @enable_defaults
20
23
  end
21
24
 
22
- class VariableTypeError < VariableError
23
- def message
24
- "ENV['#{variable.name.to_s.upcase}'] should be of type #{variable_type}"
25
- end
25
+ class << self
26
+ attr_writer :enable_defaults
27
+ alias_method :defaults_enabled?, :enable_defaults
28
+ attr_accessor :current_group
26
29
  end
27
30
 
28
- def self.included(base)
29
- base.class_eval do
30
- include Virtus.model
31
+ def self.current_group
32
+ @current_group ||= :default
33
+ end
34
+ end
31
35
 
32
- class << self
33
- attr_accessor :enable_defaults
34
- end
36
+ def self.configuration(options = {}, &block)
37
+ if block_given?
38
+ @configuration = build_configuration(&block).tap do |c|
39
+ options.each{|k, v| c.public_send("#{k}=", v) }
35
40
  end
36
- base.extend ClassMethods
37
41
  end
42
+ @configuration ||= build_configuration
43
+ end
38
44
 
39
- module ClassMethods
40
- # Creates a configuration instance from env.
41
- #
42
- # Will raise VariableMissingError for variables not present in ENV.
43
- #
44
- # Will raise VariableTypeError for variables whose ENV-value can't be coerced to the configured type.
45
- #
46
- # @param env [Hash] the env
47
- def parse_env(env)
48
- atts = attribute_set.map(&:name).each_with_object({}) do |name, result|
49
- variable = attribute_set[name]
50
- default = variable.options[:default]
51
- value = env[name.to_s] || env[name.to_s.upcase]
52
- if !(value || default)
53
- raise VariableMissingError, variable
54
- end
55
-
56
- try_coercion(variable, value, default)
57
- result[name] = value if value
58
- end
59
-
60
- new(atts)
61
- end
45
+ class << self
46
+ alias_method :configure, :configuration
47
+ attr_accessor :required_groups
48
+ end
62
49
 
63
- # Define a variable.
64
- #
65
- # @param name [Symbol] name of the variable
66
- # @param type [Symbol] type (one of :String (default), :Symbol, :Integer, :Boolean,
67
- # :Date, :Time)
68
- # @param options [Hash]
69
- # @option options [String, Integer, Boolean, #call] :default (nil) what value will be
70
- # used when no ENV-variable is present.
71
- # @note Defaults are ignored by default, see {configure}.
72
- #
73
- def variable(name, type = :String, options = {})
74
- options.delete(:default) unless self.enable_defaults
75
- attribute name, type, { strict: true }.merge(options)
76
- end
50
+ def self.build_configuration(&block)
51
+ Class.new(Configuration).tap do |c|
52
+ c.instance_eval(&block) if block_given?
53
+ end
54
+ end
55
+
56
+ def self.require(*groups)
57
+ groups.compact!
58
+ @instance = nil
59
+ if groups.any?
60
+ self.required_groups = groups.map(&:to_sym)
61
+ else
62
+ self.required_groups = [:default]
63
+ end
64
+ error_on_missing_variables!
65
+ error_on_uncoercible_variables!
77
66
 
78
- private
79
- def try_coercion(variable, value, default)
80
- value ||= begin
81
- default unless default.respond_to?(:call)
82
- end
83
- return unless value
84
- @variable = variable
85
-
86
- variable.coerce(value)
87
- rescue Virtus::CoercionError => e
88
- raise VariableTypeError.new(@variable)
67
+ _required_variables = required_variables
68
+ group_configuration = build_configuration do
69
+ _required_variables.each do |v|
70
+ @attribute_set << v
89
71
  end
90
72
  end
73
+ @instance = group_configuration.new(ENV.to_hash)
91
74
  end
92
75
 
93
- class << self
94
- attr_accessor :configuration
76
+ def self.error_on_missing_variables!
77
+ if missing_variable_names.any?
78
+ raise "Please set the following ENV-variables: #{missing_variable_names.sort.join(',')}"
79
+ end
95
80
  end
96
81
 
97
- # Configure ENVied.
98
- #
99
- # @param options [Hash]
100
- # @option options [Boolean] :enable_defaults (false) whether or not defaults are used.
82
+ def self.error_on_uncoercible_variables!
83
+ if non_coercible_variables.any?
84
+ single_error = "ENV['%{name}'] ('%{value}' can't be coerced to %{type})"
85
+ errors = non_coercible_variables.map do |v|
86
+ var_type = v.type.to_s.split("::").last
87
+ single_error % { name: v.name, value: env_value_or_default(v), type: var_type }
88
+ end.join ", "
89
+
90
+ raise "Some ENV-variables are not coercible: #{errors}"
91
+ end
92
+ end
93
+
94
+ def self.env_value(variable)
95
+ ENV[variable.name.to_s]
96
+ end
97
+
98
+ def self.env_value_or_default(variable)
99
+ env_value(variable) || default_value(variable)
100
+ end
101
+
102
+ # Yields the assigned default for the variable.
103
+ # When defaults are disabled, nil is returned.
104
+ def self.default_value(variable)
105
+ defaults_enabled? ? variable.default_value.value : nil
106
+ end
107
+
108
+ # A list of all configured variable names.
101
109
  #
102
110
  # @example
103
- # ENVied.configure(enable_defaults: Rails.env.development?) do
104
- # variable :force_ssl, :Boolean, default: false
105
- # end
111
+ # ENVied.configured_variable_names
112
+ # # => [:DATABASE_URL]
106
113
  #
107
- def self.configure(options = {}, &block)
108
- options = { enable_defaults: false }.merge(options)
109
- @configuration = Class.new { include Configurable }.tap do |k|
110
- k.enable_defaults = options[:enable_defaults]
111
- k.instance_eval(&block)
112
- end
113
- # or define this thing as ENVied::Configuration? prolly not threadsafe
114
- ensure
115
- @instance = nil
114
+ # @return [Array<Symbol>] the list of variable names
115
+ def self.required_variable_names
116
+ required_variables.map(&:name).map(&:to_sym)
116
117
  end
117
118
 
118
- def self.instance
119
- @instance ||= @configuration.parse_env(ENV.to_hash)
119
+ def self.required_variables
120
+ from_required_group = ->(var){ self.required_groups.include?(var.options[:group]) }
121
+ configured_variables.to_a.keep_if(&from_required_group)
120
122
  end
121
- class << self
122
- alias_method :require!, :instance
123
+
124
+ def self.configured_variables
125
+ configuration.attribute_set.dup#.to_a.keep_if(&var_from_required_group)
126
+ end
127
+
128
+ def self.provided_variable_names
129
+ ENV.keys.map(&:to_sym)
130
+ end
131
+
132
+ def self.non_coercible_variables
133
+ required_variables.reject(&method(:variable_coercible?))
134
+ end
135
+
136
+ def self.variable_coercible?(variable)
137
+ var_value = env_value_or_default(variable)
138
+ return true if var_value.respond_to?(:call)
139
+
140
+ variable.coerce var_value
141
+ rescue Virtus::CoercionError
142
+ return false
143
+ end
144
+
145
+ def self.missing_variable_names
146
+ unprovided = required_variable_names - provided_variable_names
147
+ unprovided -= names_of_required_variables_with_defaults if defaults_enabled?
148
+ unprovided
149
+ end
150
+
151
+ def self.names_of_required_variables_with_defaults
152
+ required_variables_with_defaults.map(&:name).map(&:to_sym)
153
+ end
154
+
155
+ def self.required_variables_with_defaults
156
+ required_variables.map do |v|
157
+ v unless v.default_value.value.nil?
158
+ end.compact
123
159
  end
124
160
 
125
- def self.[](key)
126
- instance.attributes[key]
127
- #instance[key] # will raise and complain that <class <>> doesn't response; better?
161
+ def self.defaults_enabled?
162
+ configuration.enable_defaults
128
163
  end
129
164
 
130
165
  def self.method_missing(method, *args, &block)
131
- respond_to_missing?(method) ? instance.public_send(method, *args, &block) : super
166
+ respond_to_missing?(method) ? @instance.public_send(method, *args, &block) : super
132
167
  end
133
168
 
134
169
  def self.respond_to_missing?(method, include_private = false)
135
- instance.attributes.key?(method) || super
170
+ @instance.respond_to?(method) || super
136
171
  end
137
172
  end
data/spec/envied_spec.rb CHANGED
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe ENVied do
4
4
  subject { described_class }
5
5
 
6
- it { should respond_to :require! }
6
+ it { should respond_to :require }
7
7
  it { should respond_to :configure }
8
8
 
9
9
  context 'configured' do
@@ -14,14 +14,16 @@ describe ENVied do
14
14
  end
15
15
 
16
16
  def configure(options = {}, &block)
17
+ described_class.instance_eval { @configuration = nil }
17
18
  described_class.configure(options, &block)
18
19
  self
19
20
  end
20
21
 
21
22
  def configured_with(hash = {})
22
- described_class.configure do |env|
23
+ described_class.instance_eval { @configuration = nil }
24
+ described_class.configure do
23
25
  hash.each do |name, type|
24
- env.variable(name, *type)
26
+ variable(name, *type)
25
27
  end
26
28
  end
27
29
  self
@@ -37,62 +39,155 @@ describe ENVied do
37
39
  end
38
40
 
39
41
  it 'responds to configured variables' do
40
- configured_with(a: :Integer).and_ENV({'A' => '1'})
42
+ configured_with(a: :Integer).and_ENV({'a' => '1'})
43
+ described_class.require
44
+
41
45
  is_expected.to respond_to :a
42
46
  end
43
47
 
44
48
  it 'responds not to unconfigured variables' do
45
49
  unconfigured.and_ENV({'A' => '1'})
46
- is_expected.to_not respond_to :a
50
+ described_class.require
51
+
52
+ is_expected.to_not respond_to :B
47
53
  end
48
54
 
49
55
  context 'ENV contains not all configured variables' do
50
56
  before { configured_with(a: :Integer).and_no_ENV }
51
57
 
52
- it 'raises EnvMissing on calling require!' do
53
- expect {
54
- ENVied.require!
55
- }.to raise_error(ENVied::Configurable::VariableMissingError)
56
- end
57
-
58
- it 'raises EnvMissing when interacted with' do
58
+ specify do
59
59
  expect {
60
- ENVied.any_missing_method
61
- }.to raise_error(ENVied::Configurable::VariableMissingError)
60
+ ENVied.require
61
+ }.to raise_error /set the following ENV-variables: a/
62
62
  end
63
63
  end
64
64
 
65
- context 'ENV containing variable of different type' do
66
- before { configured_with(a: :Integer).and_ENV('A' => 'NaN') }
65
+ context 'ENV variables are not coercible' do
66
+ before { configured_with(A: :Integer).and_ENV('A' => 'NaN') }
67
67
 
68
68
  specify do
69
69
  expect {
70
- ENVied.a
71
- }.to raise_error(ENVied::Configurable::VariableTypeError)
70
+ ENVied.require
71
+ }.to raise_error /ENV\['A'\] \('NaN' can't be coerced to Integer/
72
72
  end
73
73
  end
74
74
 
75
- describe 'variable with default' do
76
- it "are disabled by default" do
77
- configured_with(a: [:Integer, default: 1]).and_no_ENV
75
+ describe 'defaults' do
76
+ describe 'setting' do
77
+ subject { described_class.configuration }
78
+
79
+ it 'is disabled by default' do
80
+ expect(subject.enable_defaults).to_not be
81
+ end
78
82
 
79
- expect { ENVied.a }.to raise_error
83
+ it 'can be enabled via #configure' do
84
+ configure(enable_defaults: true){ }
85
+
86
+ expect(subject.enable_defaults).to be
87
+ end
88
+
89
+ it 'can be enabled via a configure-block' do
90
+ configure { self.enable_defaults = true }
91
+
92
+ expect(subject.enable_defaults).to be
93
+ end
94
+
95
+ it 'can be assigned a Proc' do
96
+ configure { self.enable_defaults = -> { true } }
97
+
98
+ expect(subject.enable_defaults).to be
99
+ end
80
100
  end
81
101
 
82
- it 'can be a value' do
83
- configure(enable_defaults: true) do
84
- variable :a, :Integer, default: 1
85
- end.and_no_ENV
102
+ describe 'assigning' do
103
+ it 'can be a value' do
104
+ configure(enable_defaults: true) do
105
+ variable :A, :Integer, default: 1
106
+ end
107
+ described_class.require
108
+
109
+ expect(described_class.A).to eq 1
110
+ end
111
+
112
+ it 'can be a Proc' do
113
+ configure(enable_defaults: true) do
114
+ variable :A, :Integer, default: proc { 1 }
115
+ end
116
+ described_class.require
86
117
 
87
- expect(ENVied.a).to eq 1
118
+ expect(described_class.A).to eq 1
119
+ end
120
+
121
+ it 'is ignored if defaults are disabled' do
122
+ configure(enable_defaults: false) do
123
+ variable :A, :Integer, default: 1
124
+ end.and_no_ENV
125
+
126
+ expect {
127
+ described_class.require
128
+ }.to raise_error
129
+ end
130
+
131
+ it 'is is ignored if ENV is provided' do
132
+ configure(enable_defaults: true) do
133
+ variable :A, :Integer, default: 1
134
+ end.and_ENV('A' => '2')
135
+ described_class.require
136
+
137
+ expect(described_class.A).to eq 2
138
+ end
139
+
140
+ it 'can be defined in terms of other variables' do
141
+ configure(enable_defaults: true) do
142
+ variable :A, :Integer
143
+ variable :B, :Integer, default: proc {|env| env.A * 2 }
144
+ end.and_ENV('A' => '1')
145
+ described_class.require
146
+
147
+ expect(described_class.B).to eq 2
148
+ end
88
149
  end
150
+ end
151
+ describe "groups" do
152
+ context 'a variable in a group' do
153
+ before do
154
+ configure do
155
+ variable :moar
156
+
157
+ group :foo do
158
+ variable :bar
159
+ end
160
+ end.and_no_ENV
161
+ end
89
162
 
90
- it "can be anything callable" do
91
- configure(enable_defaults: true) do
92
- variable :a, :Integer, default: proc { 1 }
93
- end.and_no_ENV
163
+ it 'is required when requiring the group' do
164
+ expect {
165
+ described_class.require(:foo)
166
+ }.to raise_error /bar/
167
+ end
168
+
169
+ it 'is not required when requiring another group' do
170
+ expect {
171
+ described_class.require(:bat)
172
+ }.to_not raise_error
173
+ end
94
174
 
95
- expect(ENVied.a).to eq 1
175
+ it 'wont define non-required variables on ENVied' do
176
+ stub_const("ENV", {'moar' => 'yes'})
177
+ described_class.require(:default)
178
+
179
+ expect {
180
+ described_class.bar
181
+ }.to raise_error
182
+ end
183
+
184
+ it 'requires variables without a group when requiring the default group' do
185
+ [:default, 'default'].each do |groups|
186
+ expect {
187
+ described_class.require(*groups)
188
+ }.to raise_error /moar/
189
+ end
190
+ end
96
191
  end
97
192
  end
98
193
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: envied
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
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-05-10 00:00:00.000000000 Z
11
+ date: 2014-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: virtus
@@ -74,12 +74,15 @@ extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
76
  - ".gitignore"
77
+ - ".travis.yml"
78
+ - CHANGELOG.md
77
79
  - Gemfile
78
80
  - LICENSE.txt
79
81
  - README.md
80
82
  - Rakefile
81
83
  - envied.gemspec
82
84
  - lib/envied.rb
85
+ - lib/envied/version.rb
83
86
  - spec/envied_spec.rb
84
87
  - spec/spec_helper.rb
85
88
  - underconstruction.gif