foundry 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/README.md +66 -12
- data/foundry.gemspec +1 -0
- data/lib/foundry.rb +4 -2
- data/lib/foundry/configurator.rb +67 -38
- data/lib/foundry/refinements/hash.rb +25 -0
- data/lib/foundry/sources/file.rb +11 -0
- data/lib/foundry/sources/uri.rb +21 -0
- data/lib/foundry/version.rb +1 -1
- data/spec/configurator_spec.rb +63 -24
- data/spec/refinements/hash_spec.rb +170 -0
- data/spec/sources/file_spec.rb +14 -0
- data/spec/sources/uri_spec.rb +63 -0
- data/spec/spec_helper.rb +1 -4
- metadata +38 -21
- data/lib/foundry/loaders/file.rb +0 -9
- data/lib/foundry/loaders/uri.rb +0 -19
- data/spec/loaders/file_spec.rb +0 -15
- data/spec/loaders/uri_spec.rb +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b28681a81e233360028348be15505ab62d698a9c
|
4
|
+
data.tar.gz: 060e3a8c45400254f9fb8e926b75683f82a4fed9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52e33f3b602ff5a8dd9fdc6728a8898e42d3572bc4c147f4755cab966d4ceece89ce46639619302677882028620084aaf60c93cebf92e8490515fdfb8fb13a7d
|
7
|
+
data.tar.gz: 3bf3b2b64289087f2abd06816434e51590fd59add1fb82b0aee96522d1a5571d58a0496fc993d420e97b78191219324bd183a78b55e62a0de7bf4a50f508e8fe
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -36,40 +36,94 @@ Or install it yourself as:
|
|
36
36
|
Loading from a local-file:
|
37
37
|
|
38
38
|
```ruby
|
39
|
-
config = Foundry::Configurator.configure(
|
39
|
+
config = Foundry::Configurator.configure(
|
40
|
+
:root_path => 'local-root-path',
|
41
|
+
:relative_path => 'relative-path-to-file',
|
42
|
+
:source_type => Foundry::Sources::File
|
43
|
+
)
|
40
44
|
```
|
41
45
|
|
42
46
|
Loading from a HTTP/HTTPS endpoint:
|
43
47
|
|
44
48
|
```ruby
|
45
|
-
config = Foundry::Configurator.configure(
|
49
|
+
config = Foundry::Configurator.configure(
|
50
|
+
:root_path => 'http-or-https-root-url',
|
51
|
+
:relative_path => 'relative-path-to-file',
|
52
|
+
:source_type => Foundry::Sources::URI
|
53
|
+
)
|
46
54
|
```
|
47
55
|
|
48
56
|
Loading from a HTTP/HTTPS endpoint using "Basic Authentication":
|
49
57
|
|
50
58
|
```ruby
|
51
59
|
config = Foundry::Configurator.configure(
|
52
|
-
:
|
60
|
+
:root_path => 'http-or-https-root-url',
|
61
|
+
:relative_path => 'relative-path-to-file',
|
62
|
+
:source_type => Foundry::Sources::URI,
|
53
63
|
:username => 'basic-auth-username',
|
54
64
|
:password => 'basic-auth-password'
|
55
65
|
)
|
56
66
|
```
|
57
67
|
|
58
|
-
|
68
|
+
Fetching top-level and nested values:
|
59
69
|
|
60
70
|
```ruby
|
61
|
-
# The examples below assume that
|
62
|
-
#
|
71
|
+
# The examples below assume that a file containing the following has already
|
72
|
+
# been loaded and processed by a call to `Foundry::Configurator.configure` (into
|
73
|
+
# a variable named `config`).
|
63
74
|
#
|
64
75
|
# ---
|
65
|
-
#
|
66
|
-
#
|
76
|
+
# value1: value
|
77
|
+
# value2:
|
78
|
+
# nested_value1: value
|
79
|
+
|
80
|
+
# Fetching a top-level value using dot-notation
|
81
|
+
value1 = config.value1
|
82
|
+
|
83
|
+
# Fetching a nested value using dot-notation
|
84
|
+
nested_value1 = config.value2.nested_value1
|
85
|
+
|
86
|
+
# Fetching a top-level value by key
|
87
|
+
value1 = config['value1']
|
88
|
+
|
89
|
+
# Fetching a nested value by key
|
90
|
+
nested_value1 = config['value2']['nested_value1']
|
91
|
+
```
|
92
|
+
|
93
|
+
Inheritance support:
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
# The examples below assume that there are two files available, relative to the
|
97
|
+
# `root_path`, named "file1.yml" and "file2.yml" (and that "file2.yml" inherits
|
98
|
+
# from "file1.yml").
|
99
|
+
#
|
100
|
+
# The file contents are as follows:
|
101
|
+
#
|
102
|
+
# === file1.yml ===
|
103
|
+
#
|
104
|
+
# ---
|
105
|
+
# value1: value
|
106
|
+
#
|
107
|
+
# === file2.yml ===
|
108
|
+
#
|
109
|
+
# ---
|
110
|
+
# value2: value
|
111
|
+
# inherit: file1.yml
|
112
|
+
#
|
113
|
+
# It is also assumed that the files have already been loaded and processed by a
|
114
|
+
# call to `Foundry::Configurator.configure` (into a variable named `config`).
|
115
|
+
#
|
116
|
+
# The result now contains values for both `value1` and `value2` and can be used
|
117
|
+
# as follows (it is worth noting that the `inherit` key is removed during the
|
118
|
+
# configuration process):
|
67
119
|
|
68
|
-
#
|
69
|
-
|
120
|
+
# Fetching `value1` and `value2` using dot-notation
|
121
|
+
value1 = config.value1
|
122
|
+
value2 = config.value2
|
70
123
|
|
71
|
-
#
|
72
|
-
|
124
|
+
# Fetching `value1` and `value2` by key
|
125
|
+
value1 = config['value1']
|
126
|
+
value2 = config['value2']
|
73
127
|
```
|
74
128
|
|
75
129
|
## Contributing
|
data/foundry.gemspec
CHANGED
data/lib/foundry.rb
CHANGED
@@ -5,7 +5,9 @@ require 'ostruct'
|
|
5
5
|
require 'uri'
|
6
6
|
require 'yaml'
|
7
7
|
|
8
|
+
require 'foundry/refinements/hash'
|
9
|
+
|
8
10
|
require 'foundry/configurator'
|
9
|
-
require 'foundry/
|
10
|
-
require 'foundry/
|
11
|
+
require 'foundry/sources/file'
|
12
|
+
require 'foundry/sources/uri'
|
11
13
|
require 'foundry/version'
|
data/lib/foundry/configurator.rb
CHANGED
@@ -1,52 +1,81 @@
|
|
1
1
|
module Foundry
|
2
2
|
class Configurator
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
)
|
3
|
+
def self.configure(opts)
|
4
|
+
Configurator.new.configure(opts)
|
5
|
+
end
|
6
|
+
|
7
|
+
def configure(opts)
|
8
|
+
with_opts(opts) do
|
9
|
+
transmorgs = transmorgify(opts.fetch(:relative_path))
|
10
|
+
merged = mergify(transmorgs)
|
11
|
+
structify(merged)
|
12
12
|
end
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
+
private
|
15
16
|
|
16
|
-
|
17
|
-
ERB.new(str).result
|
18
|
-
end
|
17
|
+
attr_reader :opts
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
elsif uri = opts.delete(:uri)
|
24
|
-
Foundry::Loaders::Uri.load(uri, opts)
|
25
|
-
else
|
26
|
-
raise NotImplementedError
|
27
|
-
end
|
28
|
-
end
|
19
|
+
def erbify(str)
|
20
|
+
ERB.new(str).result
|
21
|
+
end
|
29
22
|
|
30
|
-
|
31
|
-
|
32
|
-
|
23
|
+
def loadify(relative_path)
|
24
|
+
source.load(
|
25
|
+
root_path,
|
26
|
+
relative_path,
|
27
|
+
opts
|
28
|
+
)
|
29
|
+
end
|
33
30
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
31
|
+
def mergify(transmorgs)
|
32
|
+
transmorgs.reduce({}) { |memo, transmorg| memo.deep_merge(transmorg) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def parsify(str)
|
36
|
+
YAML.load(str) || {}
|
37
|
+
end
|
38
|
+
|
39
|
+
def root_path
|
40
|
+
opts.fetch(:root_path)
|
41
|
+
end
|
42
|
+
|
43
|
+
def source
|
44
|
+
source_type.new
|
45
|
+
end
|
46
|
+
|
47
|
+
def source_type
|
48
|
+
opts.fetch(:source_type)
|
49
|
+
end
|
50
|
+
|
51
|
+
def structify(object)
|
52
|
+
case object
|
53
|
+
when Array
|
54
|
+
object.map do |value|
|
55
|
+
structify(value)
|
56
|
+
end
|
57
|
+
when Hash
|
58
|
+
OpenStruct.new.tap do |open_struct|
|
59
|
+
object.each do |key, value|
|
60
|
+
open_struct.send("#{key}=", structify(value))
|
45
61
|
end
|
46
|
-
else
|
47
|
-
object
|
48
62
|
end
|
63
|
+
else
|
64
|
+
object
|
49
65
|
end
|
50
66
|
end
|
67
|
+
|
68
|
+
def transmorgify(relative_path)
|
69
|
+
parsed = parsify(erbify(loadify(relative_path)))
|
70
|
+
inherit = parsed.delete('inherit')
|
71
|
+
Array(inherit && transmorgify(inherit)) << parsed
|
72
|
+
end
|
73
|
+
|
74
|
+
def with_opts(opts)
|
75
|
+
@opts = opts
|
76
|
+
yield
|
77
|
+
ensure
|
78
|
+
@opts = nil
|
79
|
+
end
|
51
80
|
end
|
52
81
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Hash
|
2
|
+
def deep_merge(other)
|
3
|
+
dup.deep_merge!(other)
|
4
|
+
end
|
5
|
+
|
6
|
+
def deep_merge!(other)
|
7
|
+
other.each_pair do |other_key, other_value|
|
8
|
+
this_value = self[other_key]
|
9
|
+
if this_value.is_a?(Hash) && other_value.is_a?(Hash)
|
10
|
+
self[other_key] = this_value.deep_merge(other_value)
|
11
|
+
else
|
12
|
+
self[other_key] = other_value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def without(*keys)
|
19
|
+
dup.without!(*keys)
|
20
|
+
end
|
21
|
+
|
22
|
+
def without!(*keys)
|
23
|
+
self.reject! { |key, _| keys.include?(key) }; self
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Foundry
|
2
|
+
module Sources
|
3
|
+
class File
|
4
|
+
def load(root_path, relative_path, opts)
|
5
|
+
file_path = ::File.join(root_path, relative_path)
|
6
|
+
raise "Unknown configuration file: #{file_path}" unless ::File.exists?(file_path)
|
7
|
+
::File.read(file_path)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Foundry
|
2
|
+
module Sources
|
3
|
+
class URI
|
4
|
+
def load(root_path, relative_path, opts)
|
5
|
+
uri = ::URI.join(root_path, relative_path)
|
6
|
+
client = Net::HTTP.new(uri.host, uri.port)
|
7
|
+
if uri.scheme == 'https'
|
8
|
+
client.use_ssl = true
|
9
|
+
client.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
10
|
+
end
|
11
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
12
|
+
if (username = opts[:username]) && (password = opts[:password])
|
13
|
+
request.basic_auth(username, password)
|
14
|
+
end
|
15
|
+
response = client.request(request)
|
16
|
+
raise "Unknown configuration file: #{uri}" unless response.is_a?(Net::HTTPSuccess)
|
17
|
+
response.body
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/foundry/version.rb
CHANGED
data/spec/configurator_spec.rb
CHANGED
@@ -1,36 +1,45 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'foundry/configurator'
|
3
2
|
|
4
3
|
describe Foundry::Configurator do
|
5
|
-
|
4
|
+
REQUIRED_OPTS = [
|
5
|
+
:root_path,
|
6
|
+
:relative_path,
|
7
|
+
:source_type,
|
8
|
+
]
|
6
9
|
|
7
|
-
|
8
|
-
|
9
|
-
end
|
10
|
+
subject { Foundry::Configurator.new }
|
11
|
+
let(:opts) { REQUIRED_OPTS.reduce({}) { |memo, opt| memo[opt] = nil; memo } }
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
REQUIRED_OPTS.each do |key|
|
14
|
+
it %{must be passed a "#{key}"} do
|
15
|
+
expect { subject.configure(opts.without(key)) }.to raise_error
|
16
|
+
end
|
14
17
|
end
|
15
18
|
|
16
|
-
it 'will
|
17
|
-
|
18
|
-
|
19
|
+
it 'will load from a source' do
|
20
|
+
with_source do |source|
|
21
|
+
expect(source).to receive(:load) { '' }
|
22
|
+
expect { subject.configure(opts) }.not_to raise_error
|
23
|
+
end
|
19
24
|
end
|
20
25
|
|
21
26
|
it 'will fail-fast if the YAML is invalid' do
|
22
|
-
|
23
|
-
|
27
|
+
with_source do |source|
|
28
|
+
expect(source).to receive(:load)
|
29
|
+
expect { subject.configure(opts) }.to raise_error
|
30
|
+
end
|
24
31
|
end
|
25
32
|
|
26
33
|
it 'will fail-fast if the ERB raises an error' do
|
27
|
-
|
28
|
-
|
34
|
+
with_source do |source|
|
35
|
+
expect(source).to receive(:load) { 'foo: <%= 1/0 %>' }
|
36
|
+
expect { subject.configure(opts) }.to raise_error
|
37
|
+
end
|
29
38
|
end
|
30
39
|
|
31
|
-
it 'can parse
|
32
|
-
|
33
|
-
|
40
|
+
it 'can parse YAML/ERB' do
|
41
|
+
with_source do |source|
|
42
|
+
expect(source).to receive(:load) { <<-YAML
|
34
43
|
erb: <%= 1 * 2 * 3 %>
|
35
44
|
float: 123.0
|
36
45
|
integer: 42
|
@@ -39,11 +48,10 @@ describe Foundry::Configurator do
|
|
39
48
|
- dos
|
40
49
|
- tres
|
41
50
|
string: hello world
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
'root' => OpenStruct.new(
|
51
|
+
YAML
|
52
|
+
}
|
53
|
+
expect(subject.configure(opts)).to eq(
|
54
|
+
OpenStruct.new(
|
47
55
|
'erb' => 6,
|
48
56
|
'float' => 123.0,
|
49
57
|
'integer' => 42,
|
@@ -51,6 +59,37 @@ describe Foundry::Configurator do
|
|
51
59
|
'string' => 'hello world'
|
52
60
|
)
|
53
61
|
)
|
54
|
-
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'supports inheritance' do
|
66
|
+
with_source(:exactly => :twice) do |source|
|
67
|
+
expect(source).to receive(:load).and_return(
|
68
|
+
"foo: foo\ninherit: bar",
|
69
|
+
"bar: bar"
|
70
|
+
)
|
71
|
+
expect(subject.configure(opts)).to eq(
|
72
|
+
OpenStruct.new(
|
73
|
+
'foo' => 'foo',
|
74
|
+
'bar' => 'bar'
|
75
|
+
)
|
76
|
+
)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def default_opts
|
83
|
+
{
|
84
|
+
:exactly => :once,
|
85
|
+
:type => Foundry::Sources::File,
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def with_source(opts={})
|
90
|
+
merged_opts = default_opts.merge(opts)
|
91
|
+
source = merged_opts[:type].new
|
92
|
+
expect(subject).to receive(:source).exactly(merged_opts[:exactly]) { source }
|
93
|
+
yield source
|
55
94
|
end
|
56
95
|
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hash do
|
4
|
+
subject do
|
5
|
+
{
|
6
|
+
:A => nil,
|
7
|
+
:B => nil,
|
8
|
+
:C => nil,
|
9
|
+
:D => nil,
|
10
|
+
}
|
11
|
+
end
|
12
|
+
let(:keys) do
|
13
|
+
[
|
14
|
+
:A,
|
15
|
+
:B,
|
16
|
+
:C,
|
17
|
+
:D,
|
18
|
+
]
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:other) do
|
22
|
+
{
|
23
|
+
:E => nil,
|
24
|
+
:F => nil,
|
25
|
+
:G => nil,
|
26
|
+
:H => nil,
|
27
|
+
}
|
28
|
+
end
|
29
|
+
let(:other_keys) do
|
30
|
+
[
|
31
|
+
:E,
|
32
|
+
:F,
|
33
|
+
:G,
|
34
|
+
:H,
|
35
|
+
]
|
36
|
+
end
|
37
|
+
|
38
|
+
let(:nested) do
|
39
|
+
{
|
40
|
+
:I => nil,
|
41
|
+
:J => nil,
|
42
|
+
:K => {
|
43
|
+
:L => nil,
|
44
|
+
},
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'destructive' do
|
49
|
+
describe 'deep_merge!' do
|
50
|
+
it 'can merge two hashes' do
|
51
|
+
expect(subject.deep_merge!(other)).to eq({
|
52
|
+
:A => nil,
|
53
|
+
:B => nil,
|
54
|
+
:C => nil,
|
55
|
+
:D => nil,
|
56
|
+
:E => nil,
|
57
|
+
:F => nil,
|
58
|
+
:G => nil,
|
59
|
+
:H => nil,
|
60
|
+
})
|
61
|
+
expect(subject.size).to eq(keys.size + other_keys.size)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'can merge nested hashes' do
|
65
|
+
expect(subject.deep_merge!(nested)).to eq({
|
66
|
+
:A => nil,
|
67
|
+
:B => nil,
|
68
|
+
:C => nil,
|
69
|
+
:D => nil,
|
70
|
+
:I => nil,
|
71
|
+
:J => nil,
|
72
|
+
:K => {
|
73
|
+
:L => nil,
|
74
|
+
},
|
75
|
+
})
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'without!' do
|
80
|
+
it 'can filter one key' do
|
81
|
+
expect(subject.without!(:A)).to eq({
|
82
|
+
:B => nil,
|
83
|
+
:C => nil,
|
84
|
+
:D => nil,
|
85
|
+
})
|
86
|
+
expect(subject.size).to eq(keys.size - 1)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'can filter multiple keys' do
|
90
|
+
expect(subject.without!(:A, :B)).to eq({
|
91
|
+
:C => nil,
|
92
|
+
:D => nil,
|
93
|
+
})
|
94
|
+
expect(subject.size).to eq(keys.size - 2)
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'skips keys that do not exist' do
|
98
|
+
expect(subject.without!(:E)).to eq({
|
99
|
+
:A => nil,
|
100
|
+
:B => nil,
|
101
|
+
:C => nil,
|
102
|
+
:D => nil,
|
103
|
+
})
|
104
|
+
expect(subject.size).to eq(keys.size)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe 'non-destructive' do
|
110
|
+
describe 'deep_merge' do
|
111
|
+
it 'can merge two hashes' do
|
112
|
+
expect(subject.deep_merge(other)).to eq({
|
113
|
+
:A => nil,
|
114
|
+
:B => nil,
|
115
|
+
:C => nil,
|
116
|
+
:D => nil,
|
117
|
+
:E => nil,
|
118
|
+
:F => nil,
|
119
|
+
:G => nil,
|
120
|
+
:H => nil,
|
121
|
+
})
|
122
|
+
expect(subject.size).to eq(keys.size)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'can merge nested hashes' do
|
126
|
+
expect(subject.deep_merge(nested)).to eq({
|
127
|
+
:A => nil,
|
128
|
+
:B => nil,
|
129
|
+
:C => nil,
|
130
|
+
:D => nil,
|
131
|
+
:I => nil,
|
132
|
+
:J => nil,
|
133
|
+
:K => {
|
134
|
+
:L => nil,
|
135
|
+
},
|
136
|
+
})
|
137
|
+
expect(subject.size).to eq(keys.size)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe 'without' do
|
142
|
+
it 'can filter one key' do
|
143
|
+
expect(subject.without(:A)).to eq({
|
144
|
+
:B => nil,
|
145
|
+
:C => nil,
|
146
|
+
:D => nil,
|
147
|
+
})
|
148
|
+
expect(subject.size).to eq(keys.size)
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'can filter multiple keys' do
|
152
|
+
expect(subject.without(:A, :B)).to eq({
|
153
|
+
:C => nil,
|
154
|
+
:D => nil,
|
155
|
+
})
|
156
|
+
expect(subject.size).to eq(keys.size)
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'skips keys that do not exist' do
|
160
|
+
expect(subject.without(:E)).to eq({
|
161
|
+
:A => nil,
|
162
|
+
:B => nil,
|
163
|
+
:C => nil,
|
164
|
+
:D => nil,
|
165
|
+
})
|
166
|
+
expect(subject.size).to eq(keys.size)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Foundry::Sources::File do
|
4
|
+
subject { Foundry::Sources::File.new }
|
5
|
+
|
6
|
+
it 'can load a file' do
|
7
|
+
expect(File).to receive(:read)
|
8
|
+
subject.load('', '', {})
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'will raise an error if the file does not exist' do
|
12
|
+
expect { subject.load('', '', {}) }.to raise_error
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Foundry::Sources::URI do
|
4
|
+
subject { Foundry::Sources::URI.new }
|
5
|
+
let(:domain) { 'foo.bar.com' }
|
6
|
+
let(:relative_path) { 'config.yml' }
|
7
|
+
|
8
|
+
let(:http_uri) { "#{http_root_path}/#{relative_path}" }
|
9
|
+
let(:http_root_path) { "http://#{domain}" }
|
10
|
+
let(:http_response_body) { 'http_response_body' }
|
11
|
+
let(:http_opts) { {} }
|
12
|
+
|
13
|
+
let(:https_uri) { "#{https_root_path}/#{relative_path}" }
|
14
|
+
let(:https_root_path) { "https://#{domain}" }
|
15
|
+
let(:https_response_body) { 'https_response_body' }
|
16
|
+
let(:https_opts) { {} }
|
17
|
+
|
18
|
+
let(:basic_auth_uri) { "http://#{basic_auth_username}:#{basic_auth_password}@#{domain}/#{relative_path}" }
|
19
|
+
let(:basic_auth_root_path) { http_root_path }
|
20
|
+
let(:basic_auth_response_body) { 'basic_auth_response_body' }
|
21
|
+
let(:basic_auth_username) { 'basic_auth_username' }
|
22
|
+
let(:basic_auth_password) { 'basic_auth_password' }
|
23
|
+
let(:basic_auth_opts) { { :username => basic_auth_username, :password => basic_auth_password } }
|
24
|
+
|
25
|
+
before do
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'can load from a HTTP endpoint' do
|
29
|
+
stub_request(:get, http_uri).to_return(:body => http_response_body)
|
30
|
+
|
31
|
+
expect(
|
32
|
+
subject.load(
|
33
|
+
http_root_path,
|
34
|
+
relative_path,
|
35
|
+
http_opts
|
36
|
+
)
|
37
|
+
).to eq(http_response_body)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'can load from a HTTPS endpoint' do
|
41
|
+
stub_request(:get, https_uri).to_return(:body => https_response_body)
|
42
|
+
|
43
|
+
expect(
|
44
|
+
subject.load(
|
45
|
+
https_root_path,
|
46
|
+
relative_path,
|
47
|
+
https_opts
|
48
|
+
)
|
49
|
+
).to eq(https_response_body)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'can load from a endpoint using basic-auth' do
|
53
|
+
stub_request(:get, basic_auth_uri).to_return(:body => basic_auth_response_body)
|
54
|
+
|
55
|
+
expect(
|
56
|
+
subject.load(
|
57
|
+
basic_auth_root_path,
|
58
|
+
relative_path,
|
59
|
+
basic_auth_opts
|
60
|
+
)
|
61
|
+
).to eq(basic_auth_response_body)
|
62
|
+
end
|
63
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,71 +1,85 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foundry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan W. Zaleski
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-10-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.6'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.6'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: pry
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0.10'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ~>
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.10'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ~>
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '10.3'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '10.3'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '3.0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ~>
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: webmock
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.20'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.20'
|
69
83
|
description: |2
|
70
84
|
Let's face it, there are a number of problems when application/environment
|
71
85
|
configuration logic is too tightly coupled with the configuration-data itself.
|
@@ -76,8 +90,8 @@ executables: []
|
|
76
90
|
extensions: []
|
77
91
|
extra_rdoc_files: []
|
78
92
|
files:
|
79
|
-
-
|
80
|
-
-
|
93
|
+
- .gitignore
|
94
|
+
- .travis.yml
|
81
95
|
- Gemfile
|
82
96
|
- LICENSE.txt
|
83
97
|
- README.md
|
@@ -86,12 +100,14 @@ files:
|
|
86
100
|
- foundry.gemspec
|
87
101
|
- lib/foundry.rb
|
88
102
|
- lib/foundry/configurator.rb
|
89
|
-
- lib/foundry/
|
90
|
-
- lib/foundry/
|
103
|
+
- lib/foundry/refinements/hash.rb
|
104
|
+
- lib/foundry/sources/file.rb
|
105
|
+
- lib/foundry/sources/uri.rb
|
91
106
|
- lib/foundry/version.rb
|
92
107
|
- spec/configurator_spec.rb
|
93
|
-
- spec/
|
94
|
-
- spec/
|
108
|
+
- spec/refinements/hash_spec.rb
|
109
|
+
- spec/sources/file_spec.rb
|
110
|
+
- spec/sources/uri_spec.rb
|
95
111
|
- spec/spec_helper.rb
|
96
112
|
homepage: https://github.com/jzaleski/foundry
|
97
113
|
licenses:
|
@@ -103,22 +119,23 @@ require_paths:
|
|
103
119
|
- lib
|
104
120
|
required_ruby_version: !ruby/object:Gem::Requirement
|
105
121
|
requirements:
|
106
|
-
- -
|
122
|
+
- - '>='
|
107
123
|
- !ruby/object:Gem::Version
|
108
124
|
version: '0'
|
109
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
126
|
requirements:
|
111
|
-
- -
|
127
|
+
- - '>='
|
112
128
|
- !ruby/object:Gem::Version
|
113
129
|
version: '0'
|
114
130
|
requirements: []
|
115
131
|
rubyforge_project:
|
116
|
-
rubygems_version: 2.
|
132
|
+
rubygems_version: 2.2.2
|
117
133
|
signing_key:
|
118
134
|
specification_version: 4
|
119
135
|
summary: An application configuration gem that aims to keep it simple
|
120
136
|
test_files:
|
121
137
|
- spec/configurator_spec.rb
|
122
|
-
- spec/
|
123
|
-
- spec/
|
138
|
+
- spec/refinements/hash_spec.rb
|
139
|
+
- spec/sources/file_spec.rb
|
140
|
+
- spec/sources/uri_spec.rb
|
124
141
|
- spec/spec_helper.rb
|
data/lib/foundry/loaders/file.rb
DELETED
data/lib/foundry/loaders/uri.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
module Foundry
|
2
|
-
module Loaders
|
3
|
-
class Uri
|
4
|
-
def self.load(uri, opts)
|
5
|
-
parsed_uri = URI.parse(uri)
|
6
|
-
http = Net::HTTP.new(parsed_uri.host, parsed_uri.port)
|
7
|
-
if parsed_uri.scheme == 'https'
|
8
|
-
http.use_ssl = true
|
9
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
10
|
-
end
|
11
|
-
request = Net::HTTP::Get.new(parsed_uri.request_uri)
|
12
|
-
if username = opts.delete(:username) && password = opts.delete(:password)
|
13
|
-
request.basic_auth(username, password)
|
14
|
-
end
|
15
|
-
http.request(request).body
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
data/spec/loaders/file_spec.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'foundry/loaders/file'
|
3
|
-
|
4
|
-
describe Foundry::Loaders::File do
|
5
|
-
subject { Foundry::Loaders::File }
|
6
|
-
|
7
|
-
it 'can load a file' do
|
8
|
-
expect(File).to receive(:read)
|
9
|
-
subject.load('', {})
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'will raise an error if the file does not exist' do
|
13
|
-
expect { subject.load('', {}) }.to raise_error
|
14
|
-
end
|
15
|
-
end
|
data/spec/loaders/uri_spec.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'foundry/loaders/uri'
|
3
|
-
|
4
|
-
describe Foundry::Loaders::Uri do
|
5
|
-
subject { Foundry::Loaders::Uri }
|
6
|
-
let(:request) { double }
|
7
|
-
let(:response_body) { 'response_body' }
|
8
|
-
let(:response) { double(:body => response_body) }
|
9
|
-
let(:http) { double(:request => response) }
|
10
|
-
let(:http_url) { 'http://foo.bar.com' }
|
11
|
-
let(:https_url) { http_url.gsub(/\Ahttp:/, 'https:') }
|
12
|
-
|
13
|
-
before do
|
14
|
-
expect(Net::HTTP).to receive(:new) { http }
|
15
|
-
expect(Net::HTTP::Get).to receive(:new) { request }
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'can load from a HTTP endpoint' do
|
19
|
-
expect(subject.load(http_url, {})).to eq(response_body)
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'can load from a HTTPS endpoint' do
|
23
|
-
expect(http).to receive_messages([:use_ssl=, :verify_mode=])
|
24
|
-
expect(subject.load(https_url, {})).to eq(response_body)
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'can load from a endpoint using basic-auth' do
|
28
|
-
expect(request).to receive(:basic_auth)
|
29
|
-
expect(subject.load(
|
30
|
-
http_url, {
|
31
|
-
:username => 'basic_auth_username',
|
32
|
-
:password => 'basic_auth_password',
|
33
|
-
}
|
34
|
-
)).to eq(response_body)
|
35
|
-
end
|
36
|
-
end
|