figgy 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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