config_volumizer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 51fccd17634bc4c6605169c3f0aaa1552ed7e09b
4
+ data.tar.gz: 7eedb6855853b5e3e643bfd95dc4286b4ef6a654
5
+ SHA512:
6
+ metadata.gz: a451d91280f236cbc6fc3442f1be856542d5042f7ba1113fb4996a78f11b44a4f121c342edcb76138eea9459dffb553c71638b65ad7bf5b64acbfd56285fce6c
7
+ data.tar.gz: 493db1a62e270c7f0d01c4ca2545b85f9e38c33760ae6b3f4b24466210beff9dfda2625939bad0eed7dbdb058a869df008247017d97de59496058b326de97109
data/.document ADDED
@@ -0,0 +1,3 @@
1
+ -
2
+ ChangeLog.md
3
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ .ruby-version
2
+ Gemfile.lock
3
+ doc/
4
+ pkg/
5
+ vendor/cache/*.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - "2.0.0"
4
+ - "2.1.5"
5
+ - "2.2.1"
6
+ script: "bundle exec rspec"
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup markdown --title "config_volumizer Documentation" --protected
data/ChangeLog.md ADDED
@@ -0,0 +1,4 @@
1
+ ### 0.1.0 / 2015-04-03
2
+
3
+ * Initial release:
4
+
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'kramdown'
7
+ gem 'bundler'
8
+ gem 'rake'
9
+ gem 'rspec'
10
+ gem 'rubygems-tasks'
11
+ gem 'yard'
12
+ gem 'flay'
13
+ gem 'flog'
14
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2015 PayrollHero Pte. Ltd.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # config_volumizer
2
+
3
+ [![Build Status](https://travis-ci.org/payrollhero/config_volumizer.svg)](https://travis-ci.org/payrollhero/config_volumizer)
4
+ [![Code Climate](https://codeclimate.com/github/payrollhero/config_volumizer/badges/gpa.svg)](https://codeclimate.com/github/payrollhero/config_volumizer)
5
+
6
+ * [Homepage](https://rubygems.org/gems/config_volumizer)
7
+ * [Documentation](http://rubydoc.info/gems/config_volumizer/frames)
8
+ * [Email](mailto:piotr.banasik at gmail.com)
9
+
10
+ ## Description
11
+
12
+ Ever wanted to move to ENV based 12 Factor config but are stuck with somewhat complex yaml (or simillar) files
13
+ holding all your settings?
14
+
15
+ Been scratching your head how to convert your deeply nested config to ENV?
16
+
17
+ Config Volumizer comes to the rescue.
18
+
19
+ ## Examples
20
+
21
+ Convert this:
22
+ ```yaml
23
+ some:
24
+ setting:
25
+ - one
26
+ - two
27
+ - three
28
+ with:
29
+ another: setting
30
+ ```
31
+
32
+ info a series of ENV variables like so:
33
+
34
+ ```
35
+ some.setting[0] = one
36
+ some.setting[1] = two
37
+ some.setting[2] = three
38
+ some.with.another = setting
39
+ ```
40
+
41
+ ... and then just give it some volume with the volumizer to turn it back to the original rich structure
42
+
43
+ ```ruby
44
+ ConfigVolumizer.parse(ENV, 'some')
45
+ ```
46
+
47
+ ## Features
48
+
49
+ The gem basically smartly parses all keys within the passed in Hash that match the prefix specified.
50
+
51
+ It allows to nest either arrays or hashes inside eachother, basically any reasonable combination of hash/array notation should work.
52
+
53
+ ## Install
54
+
55
+ Add it to your gemfile and use it.
56
+
57
+ ```ruby
58
+ gem 'config_volumizer'
59
+ ```
60
+
61
+ ## Copyright
62
+
63
+ Copyright (c) 2015 PayrollHero Pte. Ltd.
64
+
65
+ See LICENSE.txt for details.
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+
5
+ begin
6
+ require 'bundler'
7
+ rescue LoadError => e
8
+ warn e.message
9
+ warn "Run `gem install bundler` to install Bundler."
10
+ exit -1
11
+ end
12
+
13
+ begin
14
+ Bundler.setup(:development)
15
+ rescue Bundler::BundlerError => e
16
+ warn e.message
17
+ warn "Run `bundle install` to install missing gems."
18
+ exit e.status_code
19
+ end
20
+
21
+ require 'rake'
22
+
23
+ require 'rubygems/tasks'
24
+ Gem::Tasks.new
25
+
26
+ require 'rspec/core/rake_task'
27
+ RSpec::Core::RakeTask.new
28
+
29
+ task :test => :spec
30
+ task :default => :spec
31
+
32
+ require 'yard'
33
+ YARD::Rake::YardocTask.new
34
+ task :doc => :yard
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require File.expand_path('../lib/config_volumizer/version', __FILE__)
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "config_volumizer"
7
+ gem.version = ConfigVolumizer::VERSION
8
+ gem.summary = "Adds volume to an otherwise flat config"
9
+ gem.description = "Allows turning dot notation config from ENV to rich Hash/Array structures"
10
+ gem.license = "MIT"
11
+ gem.authors = ["Piotr Banasik"]
12
+ gem.email = "piotr.banasik@gmail.com"
13
+ gem.homepage = "https://rubygems.org/gems/config_volumizer"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ['lib']
19
+ end
@@ -0,0 +1,82 @@
1
+ require 'strscan'
2
+ require 'yaml'
3
+
4
+ module ConfigVolumizer
5
+ module Parser
6
+
7
+ class << self
8
+
9
+ def parse(source, base_name)
10
+ result = {}
11
+ source.each do |key, value|
12
+ if matches_name(base_name, key)
13
+ fragments = key.gsub(/^#{base_name}/, '')
14
+ handle_item(result, base_name, fragments, value)
15
+ end
16
+ end
17
+ result
18
+ end
19
+
20
+ private
21
+
22
+ def matches_name(base_name, key)
23
+ key == base_name || key =~ /^#{base_name}([.\[])/
24
+ end
25
+
26
+ def format_value(value)
27
+ YAML.load(value)
28
+ end
29
+
30
+ def initialize_array(result, key)
31
+ validate_result_key_kind(result, key, Array)
32
+ result[key] ||= []
33
+ end
34
+
35
+ def initialize_hash(result, key)
36
+ validate_result_key_kind(result, key, Hash)
37
+ result[key] ||= {}
38
+ end
39
+
40
+ def validate_result_key_kind(result, key, kind)
41
+ if result[key] && !result[key].kind_of?(kind)
42
+ raise ArgumentError, "referencing #{kind} key #{name} when its already a #{result[key].class}"
43
+ end
44
+ end
45
+
46
+ def handle_item(result, base_name, name, value)
47
+ dst, key = result, base_name
48
+ scanner = StringScanner.new(name)
49
+
50
+ until scanner.eos?
51
+ dst, key = case next_fragment(scanner)
52
+ when /^\.(.+)/
53
+ handle_hash($~, dst, key)
54
+ when /\[(\d+)\]/
55
+ handle_array($~, dst, key)
56
+ end
57
+ end
58
+
59
+ dst[key] = format_value(value)
60
+ end
61
+
62
+ def handle_array(match, dst, key)
63
+ index = match[1].to_i
64
+ initialize_array(dst, key)
65
+ return dst[key], index
66
+ end
67
+
68
+ def handle_hash(match, dst, key)
69
+ hash_key = match[1]
70
+ initialize_hash(dst, key)
71
+ return dst[key], hash_key
72
+ end
73
+
74
+ def next_fragment(scanner)
75
+ fragment = scanner.scan /\.[^.\[]+|\[\d+\]/
76
+ raise "failed: rest: #{scanner.rest} inside #{scanner.string}" unless fragment
77
+ fragment
78
+ end
79
+
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,4 @@
1
+ module ConfigVolumizer
2
+ # config_volumizer version
3
+ VERSION = "0.1.0"
4
+ end
@@ -0,0 +1,12 @@
1
+ require 'config_volumizer/version'
2
+ require 'config_volumizer/parser'
3
+
4
+ module ConfigVolumizer
5
+ class << self
6
+
7
+ def parse(source, base_name)
8
+ Parser.parse(source, base_name)
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,224 @@
1
+ require 'spec_helper'
2
+
3
+ describe ConfigVolumizer do
4
+ let(:key) { 'ex' }
5
+ let(:result) { described_class.parse(input, key) }
6
+
7
+ describe "1 level hash" do
8
+ let(:input) { { "ex" => "1a" } }
9
+ let(:expected_result) { { 'ex' => '1a' } }
10
+
11
+ example do
12
+ expect(result).to eq(expected_result)
13
+ end
14
+ end
15
+
16
+ describe "2 level hash" do
17
+ let(:key) { 'ex1' }
18
+ let(:input) do
19
+ {
20
+ "ex1.bar" => "1a",
21
+ "ex1.bar2" => "2a",
22
+ }
23
+ end
24
+ let(:expected_result) do
25
+ {
26
+ 'ex1' => {
27
+ 'bar' => '1a',
28
+ 'bar2' => '2a',
29
+ },
30
+ }
31
+ end
32
+
33
+ example do
34
+ expect(result).to eq(expected_result)
35
+ end
36
+ end
37
+
38
+ describe "3 level hash" do
39
+ let(:key) { 'ex3' }
40
+ let(:input) do
41
+ {
42
+ "ex3.one.two" => "1a",
43
+ "ex3.one.three" => "2a",
44
+ "ex3.two.three" => "3a",
45
+ }
46
+ end
47
+ let(:expected_result) do
48
+ {
49
+ 'ex3' => {
50
+ 'one' => {
51
+ 'two' => '1a',
52
+ 'three' => '2a',
53
+ },
54
+ 'two' => {
55
+ 'three' => '3a',
56
+ },
57
+ },
58
+ }
59
+ end
60
+
61
+ example do
62
+ expect(result).to eq(expected_result)
63
+ end
64
+ end
65
+
66
+ describe "array of values in hash" do
67
+ let(:input) do
68
+ {
69
+ "ex.one[0]" => "1a",
70
+ "ex.one[1]" => "2a",
71
+ }
72
+ end
73
+ let(:expected_result) do
74
+ {
75
+ 'ex' => { 'one' => ['1a', '2a'] }
76
+ }
77
+ end
78
+
79
+ example do
80
+ expect(result).to eq(expected_result)
81
+ end
82
+ end
83
+
84
+ describe "just array of values" do
85
+ let(:input) do
86
+ {
87
+ "ex[0]" => "1a",
88
+ "ex[1]" => "2a",
89
+ }
90
+ end
91
+ let(:expected_result) do
92
+ {
93
+ 'ex' => ['1a', '2a']
94
+ }
95
+ end
96
+
97
+ example do
98
+ expect(result).to eq(expected_result)
99
+ end
100
+ end
101
+
102
+ describe "array of hashes" do
103
+ let(:input) do
104
+ {
105
+ "ex[0].foo" => "1a",
106
+ "ex[0].bar" => "2a",
107
+ "ex[1].foo" => "3a",
108
+ }
109
+ end
110
+ let(:expected_result) do
111
+ {
112
+ 'ex' => [
113
+ { 'foo' => '1a', 'bar' => '2a' },
114
+ { 'foo' => '3a' },
115
+ ]
116
+ }
117
+ end
118
+
119
+ example do
120
+ expect(result).to eq(expected_result)
121
+ end
122
+ end
123
+
124
+ describe "array of hash in hash" do
125
+ let(:key) { 'ex2' }
126
+ let(:input) do
127
+ {
128
+ "ex2.one[0].foo" => "1a",
129
+ "ex2.one[0].bar" => "2a",
130
+ "ex2.one[1].foo" => "3a",
131
+ }
132
+ end
133
+ let(:expected_result) do
134
+ {
135
+ 'ex2' => {
136
+ 'one' => [
137
+ {
138
+ "foo" => '1a',
139
+ "bar" => '2a',
140
+ },
141
+ {
142
+ "foo" => '3a',
143
+ }
144
+ ],
145
+ },
146
+ }
147
+ end
148
+
149
+ example do
150
+ expect(result).to eq(expected_result)
151
+ end
152
+ end
153
+
154
+ describe "empty hash value" do
155
+ let(:input) { { "ex" => "{}", } }
156
+ let(:expected_result) { { 'ex' => {} } }
157
+
158
+ example do
159
+ expect(result).to eq(expected_result)
160
+ end
161
+ end
162
+
163
+ describe "empty array value" do
164
+ let(:input) { { "ex" => "[]", } }
165
+ let(:expected_result) { { 'ex' => [] } }
166
+
167
+ example do
168
+ expect(result).to eq(expected_result)
169
+ end
170
+ end
171
+
172
+ describe "2d arrays" do
173
+ let(:input) do
174
+ {
175
+ "ex[0][0]" => "1a",
176
+ "ex[0][1]" => "2a",
177
+ "ex[1][0]" => "3a",
178
+ "ex[1][1]" => "4a",
179
+ }
180
+ end
181
+ let(:expected_result) do
182
+ {
183
+ 'ex' => [
184
+ ['1a', '2a'],
185
+ ['3a', '4a']
186
+ ]
187
+ }
188
+ end
189
+
190
+ example do
191
+ expect(result).to eq(expected_result)
192
+ end
193
+ end
194
+
195
+ describe "3d arrays" do
196
+ let(:input) do
197
+ {
198
+ 'ex[0][0][1]' => "1a",
199
+ 'ex[0][1][0]' => "2a",
200
+ 'ex[1][0][1]' => "3a",
201
+ 'ex[1][1][0]' => "4a",
202
+ }
203
+ end
204
+ let(:expected_result) do
205
+ {
206
+ 'ex' => [
207
+ [
208
+ [nil, '1a'],
209
+ ['2a'],
210
+ ],
211
+ [
212
+ [nil, '3a'],
213
+ ['4a'],
214
+ ]
215
+ ]
216
+ }
217
+ end
218
+
219
+ example do
220
+ expect(result).to eq(expected_result)
221
+ end
222
+ end
223
+
224
+ end
@@ -0,0 +1,2 @@
1
+ require 'rspec'
2
+ require 'config_volumizer'
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: config_volumizer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Piotr Banasik
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-03 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Allows turning dot notation config from ENV to rich Hash/Array structures
14
+ email: piotr.banasik@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - ".document"
20
+ - ".gitignore"
21
+ - ".rspec"
22
+ - ".travis.yml"
23
+ - ".yardopts"
24
+ - ChangeLog.md
25
+ - Gemfile
26
+ - LICENSE.txt
27
+ - README.md
28
+ - Rakefile
29
+ - config_volumizer.gemspec
30
+ - lib/config_volumizer.rb
31
+ - lib/config_volumizer/parser.rb
32
+ - lib/config_volumizer/version.rb
33
+ - spec/config_volumizer_spec.rb
34
+ - spec/spec_helper.rb
35
+ homepage: https://rubygems.org/gems/config_volumizer
36
+ licenses:
37
+ - MIT
38
+ metadata: {}
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubyforge_project:
55
+ rubygems_version: 2.4.5
56
+ signing_key:
57
+ specification_version: 4
58
+ summary: Adds volume to an otherwise flat config
59
+ test_files:
60
+ - spec/config_volumizer_spec.rb
61
+ - spec/spec_helper.rb