envied 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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