figgy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ coverage
6
+ tmp/
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use ruby-1.9.3-rc1@figgy --create
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in figgy.gemspec
4
+ gemspec
data/README ADDED
@@ -0,0 +1,21 @@
1
+ In Gemfile:
2
+
3
+ gem 'figgy'
4
+
5
+ Configure (say, in a Rails initializer):
6
+
7
+ APP_CONFIG = Figgy.build do |config|
8
+ config.root = Rails.root.join('etc')
9
+
10
+ # config.foo is read from etc/foo.yml
11
+ config.define_overlay :default, nil
12
+
13
+ # config.foo is then updated with values from etc/production/foo.yml
14
+ config.define_overlay(:environment) { Rails.env }
15
+ end
16
+
17
+ Access it as a dottable, indifferent-access hash:
18
+
19
+ APP_CONFIG["foo"]["some_key"]
20
+ APP_CONFIG[:foo].some_key
21
+ APP_CONFIG.foo[:some_key]
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require "rspec/core/rake_task"
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task :default => :spec
data/figgy.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "figgy/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "figgy"
7
+ s.version = Figgy::VERSION
8
+ s.authors = ["Kyle Hargraves"]
9
+ s.email = ["pd@krh.me"]
10
+ s.homepage = "http://github.com/pd/figgy"
11
+ s.summary = %q{Configuration file reading}
12
+ s.description = %q{Access YAML, JSON (and ...) configuration files with ease}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_dependency "json"
20
+ s.add_development_dependency "rake"
21
+ s.add_development_dependency "rspec"
22
+ s.add_development_dependency "simplecov"
23
+ s.add_development_dependency "aruba"
24
+ s.add_development_dependency "heredoc_unindent"
25
+ end
@@ -0,0 +1,85 @@
1
+ class Figgy
2
+ class Configuration
3
+ attr_reader :root, :overlays
4
+ attr_accessor :always_reload, :preload, :freeze
5
+
6
+ def initialize
7
+ self.root = Dir.pwd
8
+ @handlers = []
9
+ @overlays = []
10
+ @always_reload = false
11
+ @preload = false
12
+ @freeze = false
13
+
14
+ define_handler 'yml', 'yaml' do |contents|
15
+ YAML.load(contents)
16
+ end
17
+
18
+ define_handler 'yml.erb', 'yaml.erb' do |contents|
19
+ erb = ERB.new(contents).result
20
+ YAML.load(erb)
21
+ end
22
+
23
+ define_handler 'json' do |contents|
24
+ JSON.parse(contents)
25
+ end
26
+ end
27
+
28
+ def root=(path)
29
+ @root = File.expand_path(path)
30
+ end
31
+
32
+ def always_reload?
33
+ !!@always_reload
34
+ end
35
+
36
+ def preload?
37
+ !!@preload
38
+ end
39
+
40
+ def freeze?
41
+ !!@freeze
42
+ end
43
+
44
+ def define_overlay(name, value = nil)
45
+ value = yield if block_given?
46
+ @overlays << [name, value]
47
+ end
48
+
49
+ def define_combined_overlay(*names)
50
+ combined_name = names.join("_").to_sym
51
+ value = names.map { |name| overlay_value(name) }.join("_")
52
+ @overlays << [combined_name, value]
53
+ end
54
+
55
+ def overlay_dirs
56
+ return [@root] if @overlays.empty?
57
+ overlay_values.map { |v| v ? File.join(@root, v) : @root }.uniq
58
+ end
59
+
60
+ def define_handler(*extensions, &block)
61
+ @handlers += extensions.map { |ext| [ext, block] }
62
+ end
63
+
64
+ def extensions
65
+ @handlers.map { |ext, handler| ext }
66
+ end
67
+
68
+ def handler_for(filename)
69
+ match = @handlers.find { |ext, handler| filename =~ /\.#{ext}$/ }
70
+ match && match.last
71
+ end
72
+
73
+ private
74
+
75
+ def overlay_value(name)
76
+ overlay = @overlays.find { |n, v| name == n }
77
+ raise "No such overlay: #{name.inspect}" unless overlay
78
+ overlay.last
79
+ end
80
+
81
+ def overlay_values
82
+ @overlays.map &:last
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,71 @@
1
+ class Figgy
2
+ class Finder
3
+ def initialize(config)
4
+ @config = config
5
+ end
6
+
7
+ def load(name)
8
+ result = files_for(name).reduce(nil) do |result, file|
9
+ object = @config.handler_for(file).call(File.read(file))
10
+ if result && result.respond_to?(:merge)
11
+ deep_merge(result, object)
12
+ else
13
+ object
14
+ end
15
+ end
16
+
17
+ raise(Figgy::FileNotFound, "Can't find config files for key: #{name.inspect}") unless result
18
+ deep_freeze(to_figgy_hash(result))
19
+ end
20
+
21
+ def files_for(name)
22
+ Dir[*file_globs(name)]
23
+ end
24
+
25
+ def all_key_names
26
+ Dir[*file_globs].map { |file| File.basename(file).sub(/\..+$/, '') }.uniq
27
+ end
28
+
29
+ private
30
+
31
+ def file_globs(name = '*')
32
+ globs = extension_globs(name)
33
+ @config.overlay_dirs.map { |dir|
34
+ globs.map { |glob| File.join(dir, glob) }
35
+ }.flatten
36
+ end
37
+
38
+ def extension_globs(name = '*')
39
+ @config.extensions.map { |ext| "#{name}.#{ext}" }
40
+ end
41
+
42
+ def to_figgy_hash(obj)
43
+ case obj
44
+ when ::Hash
45
+ obj.each_pair { |k, v| obj[k] = to_figgy_hash(v) }
46
+ Figgy::Hash.new(obj)
47
+ when Array
48
+ obj.map { |v| to_figgy_hash(v) }
49
+ else
50
+ obj
51
+ end
52
+ end
53
+
54
+ def deep_freeze(obj)
55
+ return obj unless @config.freeze?
56
+ case obj
57
+ when ::Hash
58
+ obj.each_pair { |k, v| obj[deep_freeze(k)] = deep_freeze(v) }
59
+ when Array
60
+ obj.map! { |v| deep_freeze(v) }
61
+ end
62
+ obj.freeze
63
+ end
64
+
65
+ def deep_merge(a, b)
66
+ a.merge(b) do |key, oldval, newval|
67
+ oldval.respond_to?(:merge) && newval.respond_to?(:merge) ? deep_merge(oldval, newval) : newval
68
+ end
69
+ end
70
+ end
71
+ end
data/lib/figgy/hash.rb ADDED
@@ -0,0 +1,49 @@
1
+ class Figgy
2
+ # Stolen from Thor::CoreExt::HashWithIndifferentAccess
3
+ # It's smaller and more grokkable than ActiveSupport's.
4
+ class Hash < ::Hash
5
+ def initialize(hash = {})
6
+ super()
7
+ hash.each do |key, value|
8
+ self[convert_key(key)] = value
9
+ end
10
+ end
11
+
12
+ def [](key)
13
+ super(convert_key(key))
14
+ end
15
+
16
+ def []=(key, value)
17
+ super(convert_key(key), value)
18
+ end
19
+
20
+ def delete(key)
21
+ super(convert_key(key))
22
+ end
23
+
24
+ def values_at(*indices)
25
+ indices.collect { |key| self[convert_key(key)] }
26
+ end
27
+
28
+ def merge(other)
29
+ dup.merge!(other)
30
+ end
31
+
32
+ def merge!(other)
33
+ other.each do |key, value|
34
+ self[convert_key(key)] = value
35
+ end
36
+ self
37
+ end
38
+
39
+ protected
40
+
41
+ def convert_key(key)
42
+ key.is_a?(Symbol) ? key.to_s : key
43
+ end
44
+
45
+ def method_missing(m, *args, &block)
46
+ self[m]
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,19 @@
1
+ class Figgy
2
+ class Store
3
+ def initialize(finder, config)
4
+ @finder = finder
5
+ @config = config
6
+ @cache = {}
7
+ end
8
+
9
+ def get(key)
10
+ key = key.to_s
11
+ @cache.delete(key) if @config.always_reload?
12
+ if @cache.key?(key)
13
+ @cache[key]
14
+ else
15
+ @cache[key] = @finder.load(key)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ class Figgy
2
+ VERSION = "0.0.1"
3
+ end
data/lib/figgy.rb ADDED
@@ -0,0 +1,33 @@
1
+ require "yaml"
2
+ require "erb"
3
+ require "json"
4
+
5
+ require "figgy/version"
6
+ require "figgy/configuration"
7
+ require "figgy/hash"
8
+ require "figgy/finder"
9
+ require "figgy/store"
10
+
11
+ class Figgy
12
+ FileNotFound = Class.new(StandardError)
13
+
14
+ def self.build(&block)
15
+ config = Configuration.new
16
+ block.call(config)
17
+ new(config)
18
+ end
19
+
20
+ def initialize(config)
21
+ @config = config
22
+ @finder = Finder.new(config)
23
+ @store = Store.new(@finder, @config)
24
+
25
+ if @config.preload?
26
+ @finder.all_key_names.each { |key| @store.get(key) }
27
+ end
28
+ end
29
+
30
+ def method_missing(m, *args, &block)
31
+ @store.get(m)
32
+ end
33
+ end
@@ -0,0 +1,322 @@
1
+ require 'spec_helper'
2
+
3
+ describe Figgy do
4
+ it "reads YAML config files" do
5
+ write_config 'values', <<-YML
6
+ foo: 1
7
+ bar: 2
8
+ YML
9
+
10
+ test_config.values.should == { "foo" => 1, "bar" => 2 }
11
+ end
12
+
13
+ it "raises an exception if the file can't be found" do
14
+ expect { test_config.values }.to raise_error(Figgy::FileNotFound)
15
+ end
16
+
17
+ context "multiple extensions" do
18
+ it "supports .yaml" do
19
+ write_config 'values.yaml', 'foo: 1'
20
+ test_config.values.foo.should == 1
21
+ end
22
+
23
+ it "supports .yml.erb and .yaml.erb" do
24
+ write_config 'values.yml.erb', '<%= "foo" %>: <%= 1 %>'
25
+ write_config 'values.yaml.erb', '<%= "foo" %>: <%= 2 %>'
26
+ test_config.values.foo.should == 2
27
+ end
28
+
29
+ it "supports .json" do
30
+ write_config "values.json", '{ "json": true }'
31
+ test_config.values.json.should be_true
32
+ end
33
+
34
+ it "loads in the order named" do
35
+ write_config 'values.yml', 'foo: 1'
36
+ write_config 'values.yaml', 'foo: 2'
37
+
38
+ config = test_config do |config|
39
+ config.define_handler('yml', 'yaml') { |body| YAML.load(body) }
40
+ end
41
+ config.values.foo.should == 2
42
+ end
43
+ end
44
+
45
+ context "hash contents" do
46
+ it "makes the hash result dottable and indifferent" do
47
+ write_config 'values', <<-YML
48
+ outer:
49
+ also: dottable
50
+ YML
51
+
52
+ config = test_config
53
+ config.values.outer.should == { "also" => "dottable" }
54
+ config.values["outer"].should == { "also" => "dottable" }
55
+ config.values[:outer].should == { "also" => "dottable" }
56
+ end
57
+
58
+ it "makes a hash inside the hash result dottable and indifferent" do
59
+ write_config 'values', <<-YML
60
+ outer:
61
+ also: dottable
62
+ YML
63
+
64
+ config = test_config
65
+ config.values.outer.also.should == "dottable"
66
+ config.values.outer["also"].should == "dottable"
67
+ config.values.outer[:also].should == "dottable"
68
+ end
69
+
70
+ it "makes a hash inside an array result dottable and indifferent" do
71
+ write_config 'values', <<-YML
72
+ outer:
73
+ - in: an
74
+ array: it is
75
+ - still: a dottable hash
76
+ YML
77
+
78
+ config = test_config
79
+ config.values.outer.size.should == 2
80
+ first, second = *config.values.outer
81
+
82
+ first.should == { "in" => "an", "array" => "it is" }
83
+ first[:in].should == "an"
84
+ first.array.should == "it is"
85
+
86
+ second.still.should == "a dottable hash"
87
+ second[:still].should == "a dottable hash"
88
+ second["still"].should == "a dottable hash"
89
+ end
90
+ end
91
+
92
+ context "overlays" do
93
+ it "defaults to no overlay, thus reading directly from the config root" do
94
+ write_config 'values', "foo: 1"
95
+ test_config.values.should == { "foo" => 1 }
96
+ end
97
+
98
+ it "interprets a nil overlay value as an indication to read from the config root" do
99
+ write_config 'values', "foo: 1"
100
+ config = test_config do |config|
101
+ config.define_overlay :default, nil
102
+ end
103
+ config.values.should == { "foo" => 1 }
104
+ end
105
+
106
+ it "allows the overlay's value to be the result of a block" do
107
+ write_config 'prod/values', "foo: 1"
108
+ config = test_config do |config|
109
+ config.define_overlay(:environment) { 'prod' }
110
+ end
111
+ config.values.should == { "foo" => 1 }
112
+ end
113
+
114
+ it "overwrites values if the config file does not define a hash" do
115
+ write_config 'some_string', "foo bar baz"
116
+ write_config 'prod/some_string', "foo bar baz quux"
117
+
118
+ config = test_config do |config|
119
+ config.define_overlay :default, nil
120
+ config.define_overlay :environment, 'prod'
121
+ end
122
+
123
+ config.some_string.should == "foo bar baz quux"
124
+ end
125
+
126
+ it "deep merges hash contents from overlays" do
127
+ write_config 'defaults/values', <<-YML
128
+ foo:
129
+ bar: 1
130
+ baz: 2
131
+ YML
132
+
133
+ write_config 'prod/values', <<-YML
134
+ foo:
135
+ baz: 3
136
+ quux: hi!
137
+ YML
138
+
139
+ config = test_config do |config|
140
+ config.define_overlay :default, 'defaults'
141
+ config.define_overlay :environment, 'prod'
142
+ end
143
+
144
+ config.values.should == { "foo" => { "bar" => 1, "baz" => 3 }, "quux" => "hi!" }
145
+ end
146
+
147
+ it "can use both a nil overlay and an overlay with a value" do
148
+ write_config 'values', "foo: 1\nbar: 2"
149
+ write_config 'prod/values', "foo: 2"
150
+ config = test_config do |config|
151
+ config.define_overlay :default, nil
152
+ config.define_overlay :environment, 'prod'
153
+ end
154
+ config.values.should == { "foo" => 2, "bar" => 2 }
155
+ end
156
+
157
+ it "reads from overlays in order of definition" do
158
+ write_config 'defaults/values', <<-YML
159
+ foo: 1
160
+ bar: 1
161
+ baz: 1
162
+ YML
163
+
164
+ write_config 'prod/values', <<-YML
165
+ bar: 2
166
+ baz: 2
167
+ YML
168
+
169
+ write_config 'local/values', <<-YML
170
+ baz: 3
171
+ YML
172
+
173
+ config = test_config do |config|
174
+ config.define_overlay :default, 'defaults'
175
+ config.define_overlay :environment, 'prod'
176
+ config.define_overlay :local, 'local'
177
+ end
178
+
179
+ config.values.should == { "foo" => 1, "bar" => 2, "baz" => 3 }
180
+ end
181
+ end
182
+
183
+ context "combined overlays" do
184
+ it "allows new overlays to be defined from the values of others" do
185
+ write_config 'keys', "foo: 1"
186
+ write_config 'prod/keys', "foo: 2"
187
+ write_config 'prod_US/keys', "foo: 3"
188
+
189
+ config = test_config do |config|
190
+ config.define_overlay :default, nil
191
+ config.define_overlay :environment, 'prod'
192
+ config.define_overlay :country, 'US'
193
+ config.define_combined_overlay :environment, :country
194
+ end
195
+
196
+ config.keys.should == { "foo" => 3 }
197
+ end
198
+ end
199
+
200
+ context "reloading" do
201
+ it "can reload on each access when config.always_reload = true" do
202
+ write_config 'values', 'foo: 1'
203
+ config = test_config do |config|
204
+ config.always_reload = true
205
+ end
206
+ config.values.should == { "foo" => 1 }
207
+
208
+ write_config 'values', 'foo: bar'
209
+ config.values.should == { "foo" => "bar" }
210
+ end
211
+
212
+ it "does not reload when config.always_reload = false" do
213
+ write_config 'values', 'foo: 1'
214
+ config = test_config do |config|
215
+ config.always_reload = false
216
+ end
217
+ config.values.should == { "foo" => 1 }
218
+
219
+ write_config 'values', 'foo: bar'
220
+ config.values.should == { "foo" => 1 }
221
+ end
222
+ end
223
+
224
+ context "preloading" do
225
+ it "can preload all available configs when config.preload = true" do
226
+ write_config 'values', 'foo: 1'
227
+ write_config 'prod/values', 'foo: 2'
228
+ write_config 'prod/prod_only', 'bar: baz'
229
+
230
+ config = test_config do |config|
231
+ config.define_overlay :default, nil
232
+ config.define_overlay :environment, 'prod'
233
+ config.preload = true
234
+ end
235
+
236
+ write_config 'prod/values', 'foo: 3'
237
+ write_config 'prod_only', 'bar: quux'
238
+
239
+ config.values['foo'].should == 2
240
+ config.prod_only['bar'].should == 'baz'
241
+ end
242
+
243
+ it "still works with multiple extension support" do
244
+ write_config 'values.yaml', 'foo: 1'
245
+ write_config 'values.json', '{ "foo": 2 }'
246
+ write_config 'prod/lonely.yml', 'only: yml'
247
+ write_config 'local/json_values.json', '{ "json": true }'
248
+
249
+ config = test_config do |config|
250
+ config.define_overlay :default, nil
251
+ config.define_overlay :environment, 'prod'
252
+ config.define_overlay :local, 'local'
253
+ end
254
+
255
+ finder = config.instance_variable_get(:@finder)
256
+ finder.all_key_names.should == ['values', 'lonely', 'json_values']
257
+ end
258
+
259
+ it "still supports reloading when preloading is enabled" do
260
+ write_config 'values', 'foo: 1'
261
+
262
+ config = test_config do |config|
263
+ config.preload = true
264
+ config.always_reload = true
265
+ end
266
+
267
+ config.values['foo'].should == 1
268
+
269
+ write_config 'values', 'foo: 2'
270
+ config.values['foo'].should == 2
271
+ end
272
+ end
273
+
274
+ context "freezing" do
275
+ it "leaves results unfrozen by default" do
276
+ write_config 'values', 'foo: 1'
277
+ test_config.values.foo.should_not be_frozen
278
+ end
279
+
280
+ it "freezes the results when config.freeze = true" do
281
+ write_config 'values', 'foo: 1'
282
+ config = test_config do |config|
283
+ config.freeze = true
284
+ end
285
+ config.values.should be_frozen
286
+ end
287
+
288
+ it "freezes all the way down" do
289
+ write_config 'values', <<-YML
290
+ outer:
291
+ key: value
292
+ array:
293
+ - some string
294
+ - another string
295
+ - and: an inner hash
296
+ YML
297
+
298
+ config = test_config do |config|
299
+ config.freeze = true
300
+ end
301
+
302
+ expect { config.values.outer.array[2]['and'] = 'foo' }.to raise_error(/can't modify frozen/)
303
+ assert_deeply_frozen(config.values)
304
+ end
305
+
306
+ def assert_deeply_frozen(obj)
307
+ obj.should be_frozen
308
+ case obj
309
+ when Hash then obj.each { |k, v| assert_deeply_frozen(k); assert_deeply_frozen(v) }
310
+ when Array then obj.each { |v| assert_deeply_frozen(v) }
311
+ end
312
+ end
313
+ end
314
+ end
315
+
316
+ describe Figgy do
317
+ describe 'CnuConfig drop-in compatibility' do
318
+ it "should maybe support path_formatter = some_proc.call(config_name, overlays)"
319
+ it "should support preload's all_key_names when using path_formatter"
320
+ it "should support preload's all_key_names when using path_formatter"
321
+ end
322
+ end
@@ -0,0 +1,29 @@
1
+ require 'simplecov'
2
+
3
+ SimpleCov.start
4
+
5
+ require 'rspec'
6
+ require 'figgy'
7
+ require 'aruba/api'
8
+ require 'heredoc_unindent'
9
+
10
+ module Figgy::SpecHelpers
11
+ def test_config
12
+ Figgy.build do |config|
13
+ config.root = current_dir
14
+ yield config if block_given?
15
+ end
16
+ end
17
+
18
+ def write_config(filename, contents)
19
+ filename = "#{filename}.yml" unless filename =~ /\./
20
+ write_file(filename, contents.unindent)
21
+ end
22
+ end
23
+
24
+ RSpec.configure do |c|
25
+ c.include Aruba::Api
26
+ c.include Figgy::SpecHelpers
27
+
28
+ c.after { FileUtils.rm_rf(current_dir) }
29
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: figgy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kyle Hargraves
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-10-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: json
16
+ requirement: &70234275187800 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70234275187800
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &70234275187060 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70234275187060
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &70234275186200 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70234275186200
47
+ - !ruby/object:Gem::Dependency
48
+ name: simplecov
49
+ requirement: &70234275185340 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70234275185340
58
+ - !ruby/object:Gem::Dependency
59
+ name: aruba
60
+ requirement: &70234275184520 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70234275184520
69
+ - !ruby/object:Gem::Dependency
70
+ name: heredoc_unindent
71
+ requirement: &70234275177120 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70234275177120
80
+ description: Access YAML, JSON (and ...) configuration files with ease
81
+ email:
82
+ - pd@krh.me
83
+ executables: []
84
+ extensions: []
85
+ extra_rdoc_files: []
86
+ files:
87
+ - .gitignore
88
+ - .rvmrc
89
+ - .travis.yml
90
+ - Gemfile
91
+ - README
92
+ - Rakefile
93
+ - figgy.gemspec
94
+ - lib/figgy.rb
95
+ - lib/figgy/configuration.rb
96
+ - lib/figgy/finder.rb
97
+ - lib/figgy/hash.rb
98
+ - lib/figgy/store.rb
99
+ - lib/figgy/version.rb
100
+ - spec/figgy_spec.rb
101
+ - spec/spec_helper.rb
102
+ homepage: http://github.com/pd/figgy
103
+ licenses: []
104
+ post_install_message:
105
+ rdoc_options: []
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ! '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 1.8.10
123
+ signing_key:
124
+ specification_version: 3
125
+ summary: Configuration file reading
126
+ test_files:
127
+ - spec/figgy_spec.rb
128
+ - spec/spec_helper.rb