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