configurate 0.0.2 → 0.0.3
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 +7 -0
- checksums.yaml.gz.asc +11 -0
- data.tar.gz.asc +11 -0
- data/lib/configurate.rb +13 -8
- data/lib/configurate/lookup_chain.rb +8 -9
- data/lib/configurate/provider.rb +5 -6
- data/lib/configurate/provider/dynamic.rb +3 -4
- data/lib/configurate/provider/env.rb +9 -7
- data/lib/configurate/provider/yaml.rb +12 -9
- data/lib/configurate/proxy.rb +34 -32
- data/lib/configurate/setting_path.rb +30 -0
- data/spec/configurate/lookup_chain_spec.rb +84 -0
- data/spec/configurate/provider/dynamic_spec.rb +23 -0
- data/spec/configurate/provider/env_spec.rb +39 -0
- data/spec/configurate/provider/yaml_spec.rb +72 -0
- data/spec/configurate/provider_spec.rb +19 -0
- data/spec/configurate/proxy_spec.rb +78 -0
- data/spec/configurate/setting_path_spec.rb +57 -0
- data/spec/configurate_spec.rb +25 -0
- data/spec/spec_helper.rb +26 -0
- metadata +58 -12
- metadata.gz.asc +11 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b50fb25fde4dc42ae6cdc150bb6042fea6c0cd09
|
4
|
+
data.tar.gz: 3a9b3988d4d030c58a14d58c116fdb6a3682629c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b30760168a9e5da90281dd3756f661c05ef4db4f27a8cce9eb08c1d3fb3cf2ad609992af0685511ad027eb6398665a12c07b87f6e508e08cbe05643a740abcd5
|
7
|
+
data.tar.gz: 387ce8d7237c183a3b214b9308d5c3227dfef1dbeea7b1ff97c208bceae2888483f2efce0aae60190a49c81e64e27ed20da6897741ec69e82078cfe4454677da
|
checksums.yaml.gz.asc
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
-----BEGIN PGP SIGNATURE-----
|
2
|
+
Version: GnuPG v2.0.19 (GNU/Linux)
|
3
|
+
|
4
|
+
iQEcBAABAgAGBQJRaxYFAAoJEPNH4OtHrHDWk80H/jAcCNmTYyFrUrm6lK3kOlo3
|
5
|
+
SnhKm+xDqB/izEJD7EZMtCEPVeC4ArrNbrN10PJZ6mQgHApenBJ5CDXqFdlTIT0b
|
6
|
+
n+qFL+kcfK0abBrJz5g0Sv4wS5rCDWWYZLl4CiGLmbalQRB6fSsWiXFNlBVawt7l
|
7
|
+
88ZGE8vL8eR/F0JycjiE6fjryvg8qplZiC7NzqkpSmN0hxzqc5leHY7JoYgAP4PN
|
8
|
+
cloCT0I3iUH+fCqez8ujX3NX2RdURVfL+bilLf4LROOlaAvZgYYjngWUOWFnv3AJ
|
9
|
+
e9+JXSgNme9zmuTA/DtD29r9CSHf0Sc7EO18vJrJTJ6a+Dv9Qe/2IwBYWkmibdo=
|
10
|
+
=rgFX
|
11
|
+
-----END PGP SIGNATURE-----
|
data.tar.gz.asc
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
-----BEGIN PGP SIGNATURE-----
|
2
|
+
Version: GnuPG v2.0.19 (GNU/Linux)
|
3
|
+
|
4
|
+
iQEcBAABAgAGBQJRaxYFAAoJEPNH4OtHrHDWpOIH/jkbHhYBNcCMizn4WTWWKvx+
|
5
|
+
rIUozwKicxON4uebRoP6RIuzKQzhSs1mYZbQebo4qY/EVAI2zU+ysuyhCJlsELZG
|
6
|
+
Au/Lh3xYCS7OIP3KGVCo8eblenEG0OjaeDIfe08TuoZumx9Hv39jmK6uRG9jvCBX
|
7
|
+
tEZmw1T2bDn2uDOaolUD7BiMZgXYigH4RIZcpsd7qb7nniyHH7ULET2ofSWQpK3a
|
8
|
+
GGHV6yZdtbgnpt3f4o3dFKF4+aEYmWZ/deJbCwsvA9rNIIDfQZzS91sNCQAPp7RK
|
9
|
+
y8ryytPhGb2hCUqgNLZpNg/cfSwgkU3PRmcq2q8FxHvu9qCxafgmSYq4LWy70tA=
|
10
|
+
=99eN
|
11
|
+
-----END PGP SIGNATURE-----
|
data/lib/configurate.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
|
2
|
+
require 'configurate/setting_path'
|
2
3
|
require 'configurate/lookup_chain'
|
3
4
|
require 'configurate/provider'
|
4
5
|
require 'configurate/proxy'
|
@@ -6,12 +7,12 @@ require 'configurate/proxy'
|
|
6
7
|
|
7
8
|
# A flexible and extendable configuration system.
|
8
9
|
# The calling logic is isolated from the lookup logic
|
9
|
-
# through configuration providers,
|
10
|
+
# through configuration providers, whose only requirement
|
10
11
|
# is to define the +#lookup+ method and show a certain behavior on that.
|
11
12
|
# The providers are asked in the order they were added until one provides
|
12
13
|
# a response. This allows to even add multiple providers of the same type,
|
13
14
|
# you never easier defined your default configuration parameters.
|
14
|
-
# There
|
15
|
+
# There is no shared state, you can have an unlimited amount of
|
15
16
|
# independent configuration sources at the same time.
|
16
17
|
#
|
17
18
|
# See {Settings} for a quick start.
|
@@ -19,7 +20,7 @@ module Configurate
|
|
19
20
|
# This is your main entry point. Instead of lengthy explanations
|
20
21
|
# let an example demonstrate its usage:
|
21
22
|
#
|
22
|
-
# require
|
23
|
+
# require 'configuration_methods'
|
23
24
|
#
|
24
25
|
# AppSettings = Configurate::Settings.create do
|
25
26
|
# add_provider Configurate::Provider::Env
|
@@ -40,15 +41,19 @@ module Configurate
|
|
40
41
|
undef_method :method # Remove possible conflicts with common setting names
|
41
42
|
|
42
43
|
# @!method lookup(setting)
|
43
|
-
#
|
44
|
+
# (see {LookupChain#lookup})
|
45
|
+
|
44
46
|
# @!method add_provider(provider, *args)
|
45
|
-
#
|
47
|
+
# (see {LookupChain#add_provider})
|
48
|
+
|
46
49
|
# @!method [](setting)
|
47
|
-
# (see LookupChain#[])
|
50
|
+
# (see {LookupChain#[]})
|
51
|
+
|
52
|
+
# See description and {#lookup}, {#[]} and {#add_provider}
|
48
53
|
def method_missing(method, *args, &block)
|
49
|
-
return @lookup_chain.
|
54
|
+
return @lookup_chain.public_send(method, *args, &block) if [:lookup, :add_provider, :[]].include?(method)
|
50
55
|
|
51
|
-
Proxy.new(@lookup_chain).
|
56
|
+
Proxy.new(@lookup_chain).public_send(method, *args, &block)
|
52
57
|
end
|
53
58
|
|
54
59
|
def initialize
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module Configurate
|
2
2
|
# This object builds a chain of configuration providers to try to find
|
3
|
-
# a setting.
|
3
|
+
# the value of a setting.
|
4
4
|
class LookupChain
|
5
5
|
def initialize
|
6
6
|
@provider = []
|
7
7
|
end
|
8
8
|
|
9
|
-
#
|
9
|
+
# Adds a provider to the chain. Providers are tried in the order
|
10
10
|
# they are added, so the order is important.
|
11
11
|
#
|
12
12
|
# @param provider [#lookup]
|
@@ -25,14 +25,13 @@ module Configurate
|
|
25
25
|
# Tries all providers in the order they were added to provide a response
|
26
26
|
# for setting.
|
27
27
|
#
|
28
|
-
# @param setting [
|
29
|
-
#
|
30
|
-
# @param
|
31
|
-
# @return [Array,String,Boolean,nil] whatever the
|
32
|
-
# is casted to a {String}, except for some special values
|
28
|
+
# @param setting [SettingPath,String] nested settings as strings should
|
29
|
+
# be separated by a dot
|
30
|
+
# @param ... further args passed to the provider
|
31
|
+
# @return [Array,Hash,String,Boolean,nil] whatever the responding
|
32
|
+
# provider provides is casted to a {String}, except for some special values
|
33
33
|
def lookup(setting, *args)
|
34
|
-
setting = setting.
|
35
|
-
|
34
|
+
setting = SettingPath.from_string(setting) if setting.is_a? String
|
36
35
|
@provider.each do |provider|
|
37
36
|
begin
|
38
37
|
return special_value_or_string(provider.lookup(setting, *args))
|
data/lib/configurate/provider.rb
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
module Configurate; module Provider
|
2
2
|
# This provides a basic {#lookup} method for other providers to build
|
3
|
-
# upon. Childs are expected to define +lookup_path(path, *args)
|
4
|
-
#
|
5
|
-
# called setting at the dots. The method should return nil if the setting
|
3
|
+
# upon. Childs are expected to define +lookup_path(path, *args)+.
|
4
|
+
# The method should return nil if the setting
|
6
5
|
# wasn't found and {#lookup} will raise an {SettingNotFoundError} in that
|
7
6
|
# case.
|
8
7
|
class Base
|
9
|
-
def lookup(
|
10
|
-
result = lookup_path(
|
8
|
+
def lookup(*args)
|
9
|
+
result = lookup_path(*args)
|
11
10
|
return result unless result.nil?
|
12
|
-
raise Configurate::SettingNotFoundError, "The setting #{
|
11
|
+
raise Configurate::SettingNotFoundError, "The setting #{args.first} was not found"
|
13
12
|
end
|
14
13
|
end
|
15
14
|
end; end
|
@@ -8,11 +8,10 @@ module Configurate; module Provider
|
|
8
8
|
@settings = {}
|
9
9
|
end
|
10
10
|
|
11
|
-
def lookup_path(
|
12
|
-
key =
|
11
|
+
def lookup_path(setting_path, *args)
|
12
|
+
key = setting_path.to_s
|
13
13
|
|
14
|
-
if
|
15
|
-
key = key.chomp("=")
|
14
|
+
if setting_path.is_setter? && args.length > 0
|
16
15
|
value = args.first
|
17
16
|
value = value.get if value.respond_to?(:_proxy?) && value._proxy?
|
18
17
|
@settings[key] = value
|
@@ -1,14 +1,16 @@
|
|
1
1
|
module Configurate; module Provider
|
2
2
|
# This provider looks for settings in the environment.
|
3
3
|
# For the setting +foo.bar_baz+ this provider will look for an
|
4
|
-
# environment variable +FOO_BAR_BAZ+,
|
5
|
-
# and upcasing the result.
|
6
|
-
# and returned as array.
|
4
|
+
# environment variable +FOO_BAR_BAZ+, joining all components of the
|
5
|
+
# setting with underscores and upcasing the result.
|
6
|
+
# If an value contains any commas (,) it's split at them and returned as array.
|
7
7
|
class Env < Base
|
8
|
-
def lookup_path(
|
9
|
-
value = ENV[
|
10
|
-
|
11
|
-
|
8
|
+
def lookup_path(setting_path, *args)
|
9
|
+
value = ENV[setting_path.join("_").upcase]
|
10
|
+
unless value.nil?
|
11
|
+
value = value.dup
|
12
|
+
value = value.split(",") if value.include?(",")
|
13
|
+
end
|
12
14
|
value
|
13
15
|
end
|
14
16
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
|
3
3
|
module Configurate; module Provider
|
4
|
-
# This provider tries to open a YAML file and does
|
4
|
+
# This provider tries to open a YAML file and does nested lookups
|
5
5
|
# in it.
|
6
6
|
class YAML < Base
|
7
7
|
# @param file [String] the path to the file
|
@@ -13,27 +13,30 @@ module Configurate; module Provider
|
|
13
13
|
# @raise [Errno:ENOENT] if the file isn't found
|
14
14
|
def initialize(file, opts = {})
|
15
15
|
@settings = {}
|
16
|
-
required = opts.
|
16
|
+
required = opts.delete(:required) { true }
|
17
17
|
|
18
18
|
@settings = ::YAML.load_file(file)
|
19
19
|
|
20
20
|
namespace = opts.delete(:namespace)
|
21
21
|
unless namespace.nil?
|
22
|
-
|
23
|
-
|
22
|
+
namespace = SettingPath.from_string(namespace)
|
23
|
+
actual_settings = lookup_in_hash(namespace, @settings)
|
24
|
+
if !actual_settings.nil?
|
24
25
|
@settings = actual_settings
|
26
|
+
elsif required
|
27
|
+
raise ArgumentError, "Namespace #{namespace} not found in #{file}"
|
25
28
|
else
|
26
|
-
|
29
|
+
$stderr.puts "WARNING: Namespace #{namespace} not found in #{file}"
|
27
30
|
end
|
28
31
|
end
|
29
32
|
rescue Errno::ENOENT => e
|
30
|
-
$stderr.puts "WARNING:
|
33
|
+
$stderr.puts "WARNING: Configuration file #{file} not found, ensure it's present"
|
31
34
|
raise e if required
|
32
35
|
end
|
33
36
|
|
34
37
|
|
35
|
-
def lookup_path(
|
36
|
-
lookup_in_hash(
|
38
|
+
def lookup_path(setting_path, *args)
|
39
|
+
lookup_in_hash(setting_path, @settings)
|
37
40
|
end
|
38
41
|
|
39
42
|
private
|
@@ -42,7 +45,7 @@ module Configurate; module Provider
|
|
42
45
|
setting = setting_path.shift
|
43
46
|
if hash.has_key?(setting)
|
44
47
|
if setting_path.length > 0 && hash[setting].is_a?(Hash)
|
45
|
-
return lookup_in_hash(setting_path, hash[setting]) if setting.length
|
48
|
+
return lookup_in_hash(setting_path, hash[setting]) if setting.length >= 1
|
46
49
|
else
|
47
50
|
return hash[setting]
|
48
51
|
end
|
data/lib/configurate/proxy.rb
CHANGED
@@ -1,32 +1,34 @@
|
|
1
1
|
module Configurate
|
2
2
|
# Proxy object to support nested settings
|
3
|
-
#
|
3
|
+
#
|
4
|
+
# *Cavehats*: Since this object is always true, adding a +?+ at the end
|
4
5
|
# returns the value, if found, instead of the proxy object.
|
5
6
|
# So instead of +if settings.foo.bar+ use +if settings.foo.bar?+
|
6
7
|
# to check for boolean values, +if settings.foo.bar.nil?+ to
|
7
|
-
# check for nil values
|
8
|
-
# empty values if you're in Rails
|
9
|
-
# commonly when doing +settings.foo.bar.get ||
|
10
|
-
#
|
8
|
+
# check for nil values and of course you can do +if settings.foo.bar.present?+ to check for
|
9
|
+
# empty values if you're in Rails. Call {#get} to actually return the value,
|
10
|
+
# commonly when doing +settings.foo.bar.get || "default"+. Also don't
|
11
|
+
# use this in case statements since +Module#===+ can't be fooled, again
|
12
|
+
# call {#get}.
|
13
|
+
#
|
14
|
+
# If a setting ends with +=+ it's too called directly, just like with +?+.
|
11
15
|
class Proxy < BasicObject
|
12
|
-
COMMON_KEY_NAMES = [:key, :method]
|
13
|
-
|
14
16
|
# @param lookup_chain [#lookup]
|
15
17
|
def initialize(lookup_chain)
|
16
18
|
@lookup_chain = lookup_chain
|
17
|
-
@
|
19
|
+
@setting_path = SettingPath.new
|
18
20
|
end
|
19
21
|
|
20
22
|
def !
|
21
|
-
!
|
23
|
+
!target
|
22
24
|
end
|
23
25
|
|
24
26
|
def !=(other)
|
25
|
-
|
27
|
+
target != other
|
26
28
|
end
|
27
29
|
|
28
30
|
def ==(other)
|
29
|
-
|
31
|
+
target == other
|
30
32
|
end
|
31
33
|
|
32
34
|
def _proxy?
|
@@ -34,43 +36,43 @@ module Configurate
|
|
34
36
|
end
|
35
37
|
|
36
38
|
def respond_to?(method, include_private=false)
|
37
|
-
method == :_proxy? ||
|
39
|
+
method == :_proxy? || target.respond_to?(method, include_private)
|
38
40
|
end
|
39
41
|
|
40
42
|
def send(*args, &block)
|
41
|
-
|
43
|
+
__send__(*args, &block)
|
42
44
|
end
|
45
|
+
alias_method :public_send, :send
|
43
46
|
|
44
47
|
def method_missing(setting, *args, &block)
|
45
|
-
|
46
|
-
target = self.get
|
47
|
-
if !(target.respond_to?(:_proxy?) && target._proxy?) && target.respond_to?(setting)
|
48
|
-
return target.send(setting, *args, &block)
|
49
|
-
end
|
50
|
-
end
|
48
|
+
return target.public_send(setting, *args, &block) if target_respond_to? setting
|
51
49
|
|
52
|
-
|
53
|
-
|
54
|
-
self.append_setting(setting)
|
50
|
+
@setting_path << setting
|
55
51
|
|
56
|
-
return
|
52
|
+
return target(*args) if @setting_path.is_question_or_setter?
|
57
53
|
|
58
54
|
self
|
59
55
|
end
|
60
56
|
|
61
57
|
# Get the setting at the current path, if found.
|
62
58
|
# (see LookupChain#lookup)
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
val
|
59
|
+
def target(*args)
|
60
|
+
return if @setting_path.empty?
|
61
|
+
|
62
|
+
@lookup_chain.lookup(@setting_path, *args)
|
68
63
|
end
|
64
|
+
alias_method :get, :target
|
69
65
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
66
|
+
private
|
67
|
+
COMMON_KEY_NAMES = [:key, :method]
|
68
|
+
|
69
|
+
def target_respond_to?(setting)
|
70
|
+
return false if COMMON_KEY_NAMES.include? setting
|
71
|
+
|
72
|
+
value = target
|
73
|
+
return false if value.respond_to?(:_proxy?) && value._proxy?
|
74
|
+
|
75
|
+
value.respond_to?(setting)
|
74
76
|
end
|
75
77
|
end
|
76
78
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Configurate
|
2
|
+
# Class encapsulating the concept of a path to a setting
|
3
|
+
class SettingPath < Array
|
4
|
+
|
5
|
+
# Create a path from the string format (+foo.bar+).
|
6
|
+
# @param path [String]
|
7
|
+
# @return [SettingPath]
|
8
|
+
def self.from_string(path)
|
9
|
+
SettingPath.new(path.split("."))
|
10
|
+
end
|
11
|
+
|
12
|
+
# Whether the current path looks like a question or setter method
|
13
|
+
def is_question_or_setter?
|
14
|
+
last.to_s.end_with?("?") || is_setter?
|
15
|
+
end
|
16
|
+
|
17
|
+
# Whether the current path looks like a setter method
|
18
|
+
def is_setter?
|
19
|
+
last.to_s.end_with?("=")
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
join(".").chomp("?").chomp("=")
|
24
|
+
end
|
25
|
+
|
26
|
+
def inspect
|
27
|
+
"<SettingPath path=#{to_s}>"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class InvalidConfigurationProvider; end
|
4
|
+
class ValidConfigurationProvider
|
5
|
+
def lookup(setting, *args); end
|
6
|
+
end
|
7
|
+
|
8
|
+
describe Configurate::LookupChain do
|
9
|
+
subject { described_class.new }
|
10
|
+
|
11
|
+
describe "#add_provider" do
|
12
|
+
it "adds a valid provider" do
|
13
|
+
expect {
|
14
|
+
subject.add_provider ValidConfigurationProvider
|
15
|
+
}.to change { subject.instance_variable_get(:@provider).size }.by 1
|
16
|
+
end
|
17
|
+
|
18
|
+
it "doesn't add an invalid provider" do
|
19
|
+
expect {
|
20
|
+
subject.add_provider InvalidConfigurationProvider
|
21
|
+
}.to raise_error ArgumentError
|
22
|
+
end
|
23
|
+
|
24
|
+
it "passes extra args to the provider" do
|
25
|
+
ValidConfigurationProvider.should_receive(:new).with(:extra)
|
26
|
+
subject.add_provider ValidConfigurationProvider, :extra
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#lookup" do
|
31
|
+
before do
|
32
|
+
subject.add_provider ValidConfigurationProvider
|
33
|
+
subject.add_provider ValidConfigurationProvider
|
34
|
+
@provider = subject.instance_variable_get(:@provider)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "it tries all providers" do
|
38
|
+
setting = Configurate::SettingPath.from_string "some.setting"
|
39
|
+
@provider.each do |provider|
|
40
|
+
provider.should_receive(:lookup).with(setting).and_raise(Configurate::SettingNotFoundError)
|
41
|
+
end
|
42
|
+
|
43
|
+
subject.lookup(setting)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "stops if a value is found" do
|
47
|
+
@provider[0].should_receive(:lookup).and_return("something")
|
48
|
+
@provider[1].should_not_receive(:lookup)
|
49
|
+
subject.lookup("bla")
|
50
|
+
end
|
51
|
+
|
52
|
+
it "converts numbers to strings" do
|
53
|
+
@provider[0].stub(:lookup).and_return(5)
|
54
|
+
subject.lookup("foo").should == "5"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "does not convert false to a string" do
|
58
|
+
@provider[0].stub(:lookup).and_return(false)
|
59
|
+
subject.lookup("enable").should be_false
|
60
|
+
end
|
61
|
+
|
62
|
+
it "converts 'true' to true" do
|
63
|
+
@provider[0].stub(:lookup).and_return("true")
|
64
|
+
subject.lookup("enable").should be_true
|
65
|
+
end
|
66
|
+
|
67
|
+
it "converts 'false' to false" do
|
68
|
+
@provider[0].stub(:lookup).and_return("false")
|
69
|
+
subject.lookup("enable").should be_false
|
70
|
+
end
|
71
|
+
|
72
|
+
it "returns the value unchanged if it can't be converted" do
|
73
|
+
value = mock
|
74
|
+
value.stub(:respond_to?).with(:to_s).and_return(false)
|
75
|
+
@provider[0].stub(:lookup).and_return(value)
|
76
|
+
subject.lookup("enable").should == value
|
77
|
+
end
|
78
|
+
|
79
|
+
it "returns nil if no value is found" do
|
80
|
+
@provider.each { |p| p.stub(:lookup).and_raise(Configurate::SettingNotFoundError) }
|
81
|
+
subject.lookup("not.me").should be_nil
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Configurate::Provider::Dynamic do
|
4
|
+
subject { described_class.new }
|
5
|
+
describe "#lookup_path" do
|
6
|
+
it "returns nil if the setting was never set" do
|
7
|
+
subject.lookup_path(Configurate::SettingPath.new(["not_me"])).should be_nil
|
8
|
+
end
|
9
|
+
|
10
|
+
it "remembers the setting if it ends with =" do
|
11
|
+
subject.lookup_path(Configurate::SettingPath.new(["find_me", "later="]), "there")
|
12
|
+
subject.lookup_path(Configurate::SettingPath.new(["find_me", "later"])).should == "there"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "calls .get on the argument if a proxy object is given" do
|
16
|
+
proxy = mock
|
17
|
+
proxy.stub(:respond_to?).and_return(true)
|
18
|
+
proxy.stub(:_proxy?).and_return(true)
|
19
|
+
proxy.should_receive(:get)
|
20
|
+
subject.lookup_path(Configurate::SettingPath.new(["bla="]), proxy)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Configurate::Provider::Env do
|
4
|
+
subject { described_class.new }
|
5
|
+
let(:existing_path) { ['existing', 'setting']}
|
6
|
+
let(:not_existing_path) { ['not', 'existing', 'path']}
|
7
|
+
let(:array_path) { ['array'] }
|
8
|
+
before(:all) do
|
9
|
+
ENV['EXISTING_SETTING'] = "there"
|
10
|
+
ENV['ARRAY'] = "foo,bar,baz"
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:all) do
|
14
|
+
ENV['EXISTING_SETTING'] = nil
|
15
|
+
ENV['ARRAY'] = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#lookup_path' do
|
19
|
+
it "joins and upcases the path" do
|
20
|
+
ENV.should_receive(:[]).with("EXISTING_SETTING")
|
21
|
+
subject.lookup_path(existing_path)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "returns nil if the setting isn't available" do
|
25
|
+
subject.lookup_path(not_existing_path).should be_nil
|
26
|
+
end
|
27
|
+
|
28
|
+
it "makes an array out of comma separated values" do
|
29
|
+
subject.lookup_path(array_path).should == ["foo", "bar", "baz"]
|
30
|
+
end
|
31
|
+
|
32
|
+
it "returns a unfrozen string" do
|
33
|
+
expect {
|
34
|
+
setting = subject.lookup_path(existing_path)
|
35
|
+
setting << "foo"
|
36
|
+
}.to_not raise_error
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Configurate::Provider::YAML do
|
4
|
+
let(:settings) { {"toplevel" => "bar",
|
5
|
+
"some" => {
|
6
|
+
"nested" => { "some" => "lala", "setting" => "foo"}
|
7
|
+
}
|
8
|
+
} }
|
9
|
+
|
10
|
+
describe "#initialize" do
|
11
|
+
it "loads the file" do
|
12
|
+
file = "foobar.yml"
|
13
|
+
::YAML.should_receive(:load_file).with(file).and_return({})
|
14
|
+
described_class.new file
|
15
|
+
end
|
16
|
+
|
17
|
+
it "raises if the file is not found" do
|
18
|
+
::YAML.stub(:load_file).and_raise(Errno::ENOENT)
|
19
|
+
expect {
|
20
|
+
described_class.new "foo"
|
21
|
+
}.to raise_error Errno::ENOENT
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
context "with a namespace" do
|
26
|
+
it "looks in the file for that namespace" do
|
27
|
+
namespace = "some"
|
28
|
+
::YAML.stub(:load_file).and_return(settings)
|
29
|
+
provider = described_class.new 'bla', namespace: namespace
|
30
|
+
provider.instance_variable_get(:@settings).should == settings[namespace]
|
31
|
+
end
|
32
|
+
|
33
|
+
it "raises if the namespace isn't found" do
|
34
|
+
::YAML.stub(:load_file).and_return({})
|
35
|
+
expect {
|
36
|
+
described_class.new 'bla', namespace: "foo"
|
37
|
+
}.to raise_error ArgumentError
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "with required set to false" do
|
42
|
+
it "doesn't raise if a file isn't found" do
|
43
|
+
::YAML.stub(:load_file).and_raise(Errno::ENOENT)
|
44
|
+
expect {
|
45
|
+
described_class.new "not_me", required: false
|
46
|
+
}.not_to raise_error Errno::ENOENT
|
47
|
+
end
|
48
|
+
|
49
|
+
it "doesn't raise if a namespace isn't found" do
|
50
|
+
::YAML.stub(:load_file).and_return({})
|
51
|
+
expect {
|
52
|
+
described_class.new 'bla', namespace: "foo", required: false
|
53
|
+
}.not_to raise_error ArgumentError
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#lookup_path" do
|
59
|
+
before do
|
60
|
+
::YAML.stub(:load_file).and_return(settings)
|
61
|
+
@provider = described_class.new 'dummy'
|
62
|
+
end
|
63
|
+
|
64
|
+
it "looks up the whole nesting" do
|
65
|
+
@provider.lookup_path(["some", "nested", "some"]).should == settings["some"]["nested"]["some"]
|
66
|
+
end
|
67
|
+
|
68
|
+
it "returns nil if no setting is found" do
|
69
|
+
@provider.lookup_path(["not_me"]).should be_nil
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Configurate::Provider::Base do
|
4
|
+
describe "#lookup" do
|
5
|
+
subject { described_class.new }
|
6
|
+
it "calls #lookup_path" do
|
7
|
+
path = Configurate::SettingPath.new(["foo", "bar"])
|
8
|
+
subject.should_receive(:lookup_path).with(path).and_return("something")
|
9
|
+
subject.lookup(path).should == "something"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "raises SettingNotFoundError if the #lookup_path returns nil" do
|
13
|
+
subject.stub(:lookup_path).and_return(nil)
|
14
|
+
expect {
|
15
|
+
subject.lookup("bla")
|
16
|
+
}.to raise_error Configurate::SettingNotFoundError
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Configurate::Proxy do
|
4
|
+
let(:lookup_chain) { mock(lookup: "something") }
|
5
|
+
let(:proxy) { described_class.new(lookup_chain) }
|
6
|
+
|
7
|
+
describe "in case statements" do
|
8
|
+
it "acts like the target" do
|
9
|
+
pending "If anyone knows a way to overwrite ===, please tell me :P"
|
10
|
+
result = case proxy
|
11
|
+
when String
|
12
|
+
"string"
|
13
|
+
else
|
14
|
+
"wrong"
|
15
|
+
end
|
16
|
+
result.should == "string"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#method_missing" do
|
21
|
+
it "calls #target if the method ends with a ?" do
|
22
|
+
lookup_chain.should_receive(:lookup).and_return(false)
|
23
|
+
proxy.method_missing(:enable?)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "calls #target if the method ends with a =" do
|
27
|
+
lookup_chain.should_receive(:lookup).and_return(false)
|
28
|
+
proxy.method_missing(:url=)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "delegations" do
|
33
|
+
it "calls the target when negating" do
|
34
|
+
target = mock
|
35
|
+
lookup_chain.stub(:lookup).and_return(target)
|
36
|
+
target.should_receive(:!)
|
37
|
+
proxy.something.__send__(:!)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "calls __send__ on send" do
|
41
|
+
proxy.should_receive(:__send__).with(:foo).and_return(nil)
|
42
|
+
proxy.send(:foo)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#proxy" do
|
47
|
+
subject { proxy._proxy? }
|
48
|
+
it { should be_true }
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#target" do
|
52
|
+
[:to_str, :to_s, :to_xml, :respond_to?, :present?, :!=,
|
53
|
+
:each, :try, :size, :length, :count, :==, :=~, :gsub, :blank?, :chop,
|
54
|
+
:start_with?, :end_with?].each do |method|
|
55
|
+
it "is called for accessing #{method} on the proxy" do
|
56
|
+
target = mock
|
57
|
+
lookup_chain.stub(:lookup).and_return(target)
|
58
|
+
target.stub(:respond_to?).and_return(true)
|
59
|
+
target.stub(:_proxy?).and_return(false)
|
60
|
+
target.should_receive(method).and_return("something")
|
61
|
+
proxy.something.__send__(method, mock)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
described_class::COMMON_KEY_NAMES.each do |method|
|
66
|
+
it "is not called for accessing #{method} on the proxy" do
|
67
|
+
target = mock
|
68
|
+
lookup_chain.should_not_receive(:lookup)
|
69
|
+
target.should_not_receive(method)
|
70
|
+
proxy.something.__send__(method, mock)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it "returns nil if no setting is given" do
|
75
|
+
proxy.target.should be_nil
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Configurate::SettingPath do
|
4
|
+
describe "::from_string" do
|
5
|
+
it "creates a path" do
|
6
|
+
described_class.from_string("foo.bar").should == described_class.new(["foo", "bar"])
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#is_setter?" do
|
11
|
+
context "with a setter signature as setting" do
|
12
|
+
subject { described_class.new([:foo=]).is_setter? }
|
13
|
+
it { should be_true }
|
14
|
+
end
|
15
|
+
|
16
|
+
context "with a normal path as setting" do
|
17
|
+
subject { described_class.new([:foo]).is_setter? }
|
18
|
+
it { should be_false }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
describe "#is_question_or_setter?" do
|
24
|
+
context "with a question signature as setting" do
|
25
|
+
subject { described_class.new([:foo?]).is_question_or_setter? }
|
26
|
+
it { should be_true }
|
27
|
+
end
|
28
|
+
|
29
|
+
context "with a setter signature as setting" do
|
30
|
+
subject { described_class.new([:foo=]).is_question_or_setter? }
|
31
|
+
it { should be_true }
|
32
|
+
end
|
33
|
+
|
34
|
+
context "with a normal path as setting" do
|
35
|
+
subject { described_class.new([:foo]).is_question_or_setter? }
|
36
|
+
it { should be_false }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#to_s" do
|
41
|
+
let(:path) { "example.path" }
|
42
|
+
subject { described_class.new(path.split(".")).to_s }
|
43
|
+
it { should == path }
|
44
|
+
|
45
|
+
context "with a question signature as setting" do
|
46
|
+
subject { described_class.new("#{path}?".split(".")).to_s }
|
47
|
+
it { should == path }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#inspect" do
|
52
|
+
it "includes the dotted path" do
|
53
|
+
path = described_class.new([:foo, :bar])
|
54
|
+
path.inspect.should include "foo.bar"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Configurate::Settings do
|
4
|
+
describe "#method_missing" do
|
5
|
+
subject { described_class.create }
|
6
|
+
|
7
|
+
it "delegates the call to a new proxy object" do
|
8
|
+
proxy = mock
|
9
|
+
Configurate::Proxy.should_receive(:new).and_return(proxy)
|
10
|
+
proxy.should_receive(:method_missing).with(:some_setting).and_return("foo")
|
11
|
+
subject.some_setting
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
[:lookup, :add_provider, :[]].each do |method|
|
16
|
+
describe "#{method}" do
|
17
|
+
subject { described_class.create }
|
18
|
+
|
19
|
+
it "delegates the call to #lookup_chain" do
|
20
|
+
subject.lookup_chain.should_receive(method)
|
21
|
+
subject.send(method)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
|
8
|
+
|
9
|
+
begin
|
10
|
+
require 'coveralls'
|
11
|
+
Coveralls.wear!
|
12
|
+
rescue; end
|
13
|
+
|
14
|
+
require 'configurate'
|
15
|
+
|
16
|
+
RSpec.configure do |config|
|
17
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
18
|
+
config.run_all_when_everything_filtered = true
|
19
|
+
config.filter_run :focus
|
20
|
+
|
21
|
+
# Run specs in random order to surface order dependencies. If you find an
|
22
|
+
# order dependency and want to debug it, you can fix the order by providing
|
23
|
+
# the seed, which is printed after each run.
|
24
|
+
# --seed 1234
|
25
|
+
config.order = 'random'
|
26
|
+
end
|
metadata
CHANGED
@@ -1,16 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: configurate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.3
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Jonne Haß
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
13
|
-
dependencies:
|
11
|
+
date: 2013-04-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 10.0.3
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 10.0.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.12.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.12.0
|
14
41
|
description: Configurate is a flexible configuration system that can read settings
|
15
42
|
from multiple sources at the same time.
|
16
43
|
email: me@mrzyx.de
|
@@ -24,30 +51,49 @@ files:
|
|
24
51
|
- lib/configurate/proxy.rb
|
25
52
|
- lib/configurate/lookup_chain.rb
|
26
53
|
- lib/configurate/provider.rb
|
54
|
+
- lib/configurate/setting_path.rb
|
27
55
|
- lib/configurate.rb
|
28
|
-
|
56
|
+
- spec/configurate/provider_spec.rb
|
57
|
+
- spec/configurate/lookup_chain_spec.rb
|
58
|
+
- spec/configurate/provider/yaml_spec.rb
|
59
|
+
- spec/configurate/provider/env_spec.rb
|
60
|
+
- spec/configurate/provider/dynamic_spec.rb
|
61
|
+
- spec/configurate/setting_path_spec.rb
|
62
|
+
- spec/configurate/proxy_spec.rb
|
63
|
+
- spec/spec_helper.rb
|
64
|
+
- spec/configurate_spec.rb
|
65
|
+
homepage: http://mrzyx.github.com/configurate
|
29
66
|
licenses:
|
30
67
|
- MIT
|
68
|
+
metadata: {}
|
31
69
|
post_install_message:
|
32
70
|
rdoc_options: []
|
33
71
|
require_paths:
|
34
72
|
- lib
|
35
73
|
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
-
none: false
|
37
74
|
requirements:
|
38
|
-
- -
|
75
|
+
- - '>='
|
39
76
|
- !ruby/object:Gem::Version
|
40
77
|
version: 1.9.2
|
41
78
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
42
|
-
none: false
|
43
79
|
requirements:
|
44
|
-
- -
|
80
|
+
- - '>='
|
45
81
|
- !ruby/object:Gem::Version
|
46
82
|
version: '0'
|
47
83
|
requirements: []
|
48
84
|
rubyforge_project:
|
49
|
-
rubygems_version:
|
85
|
+
rubygems_version: 2.0.3
|
50
86
|
signing_key:
|
51
|
-
specification_version:
|
87
|
+
specification_version: 4
|
52
88
|
summary: Flexbile configuration system
|
53
|
-
test_files:
|
89
|
+
test_files:
|
90
|
+
- spec/configurate/provider_spec.rb
|
91
|
+
- spec/configurate/lookup_chain_spec.rb
|
92
|
+
- spec/configurate/provider/yaml_spec.rb
|
93
|
+
- spec/configurate/provider/env_spec.rb
|
94
|
+
- spec/configurate/provider/dynamic_spec.rb
|
95
|
+
- spec/configurate/setting_path_spec.rb
|
96
|
+
- spec/configurate/proxy_spec.rb
|
97
|
+
- spec/spec_helper.rb
|
98
|
+
- spec/configurate_spec.rb
|
99
|
+
has_rdoc:
|
metadata.gz.asc
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
-----BEGIN PGP SIGNATURE-----
|
2
|
+
Version: GnuPG v2.0.19 (GNU/Linux)
|
3
|
+
|
4
|
+
iQEcBAABAgAGBQJRaxYFAAoJEPNH4OtHrHDW48EIAKYLXtBlFZNnezvqLJr7aQYt
|
5
|
+
6HGva0USAoso1Rvn7t3HV4BIR7rFhscOUMMWwddHElNMnLxzsQU1vLQ0Zzk7+bGZ
|
6
|
+
pR2irAuTjEJHZUCifVwSmIGK5CbyHbwqDhFOhexQOh8cPxYWo3IcHT/Pq7H3graS
|
7
|
+
/POfxD1kUClc/l/NMV0OdCCXjdDisbVP+j2Ju6pNQU8QPk7QOjKDlmx7WTmlP3c7
|
8
|
+
RA+gzCqxpYw2+F6XHCFoQRAdb8KYLOkn2YGUmGzcpbh19qniEMTVcum4YhWqvG+S
|
9
|
+
3igR/0DX219J0332XhbqlcLzfcB+EeGHrRKlY1LGm8JeHA9MR6JNGpoROSPP2TY=
|
10
|
+
=0vyr
|
11
|
+
-----END PGP SIGNATURE-----
|