yacht 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ gem 'rake'
data/README.rdoc ADDED
@@ -0,0 +1,73 @@
1
+ = Yacht
2
+
3
+ Yacht is an application configuration gem that lets you define settings for multiple environments in YAML files. It is similar to AppConfig[https://github.com/cjbottaro/app_config] with additional features like:
4
+ * use of ClassyStruct for improved performance over OpenStruct
5
+ * protection of sensitive settings by specifying a whitelist in a YAML file
6
+ * easy override of nested keys (not pretty with YAML references)
7
+
8
+ == Installation
9
+
10
+ * <b>Rails</b>:
11
+ Add this to your Gemfile and run the +bundle+ command.
12
+
13
+ gem "yacht"
14
+
15
+ * Outside of rails, just require the gem as usual:
16
+
17
+ require 'rubygems'
18
+ require 'yacht'
19
+
20
+ == Getting Started
21
+
22
+ === Step 1: YAML files
23
+
24
+ First create two (or more) YAML files in the same directory to define your settings:
25
+
26
+ # config/yacht/base.yml (required)
27
+ production:
28
+ cdn_host: 1.2.3.4
29
+ super_secret_info:
30
+ aws_key: foofoo
31
+ twitter_key: barbar
32
+ test:
33
+ cdn_host: localhost
34
+ super_secret_info:
35
+ # you can safely overwrite a single value in a nested key
36
+ # YAML references (& and *) don't let you do this
37
+ # see https://gist.github.com/979804 for an explanation
38
+ aws_key: bazbaz
39
+
40
+ # config/yacht/whitelist.yml (required)
41
+ # any keys specified here can be used as a whitelist filter:
42
+ # YachtLoader.to_hash(:apply_whitelist? => true)
43
+ # (by default the whitelist is ignored)
44
+ - super_secret_info
45
+
46
+ # config/yacht/local.yml (optional)
47
+ # any values set in local.yml will override values set in base.yml
48
+ # useful for development and testing
49
+ production:
50
+ cdn_host: localhost
51
+
52
+ === Step 2: Define a constant
53
+
54
+ * <b>Rails</b>:
55
+ # config/initializers/01_yacht.rb
56
+ # Define a constant that will store all settings
57
+ # looks for the following YAML files:
58
+ # * config/yacht/base.yml
59
+ # * config/yacht/local.yml
60
+ # * config/yacht/whitelist.yml
61
+ Yacht = YachtLoader.to_classy_struct
62
+ # now you can access any key set in your YAML files with:
63
+ # Yacht.my_key
64
+
65
+ * Outside of rails, you need to tell +YachtLoader+ where your YAML files are stored, and what environment you want to use.
66
+ YachtLoader.dir = '/path/to/YAML/dir'
67
+ YachtLoader.environment = 'my_environment'
68
+ Yacht = YachtLoader.to_classy_struct
69
+
70
+
71
+ == How it works
72
+
73
+ Currently, the +Yacht+ gem defines a class called +YachtLoader+ that will read your YAML files and output them as a regular +Hash+ or a +ClassyStruct+ . Then you use <tt>YachtLoader#to_classy_struct</tt> (or <tt>YachtLoader#to_hash</tt>) to define a constant. You can name the constant whatever you like, but you should use +Yacht+. This is because a planned feature is to have +Yacht+ defined when the gem is required and have everything namespaced under a single +Yacht+ class.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ Bundler.setup
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ Dir['gem_tasks/**/*.rake'].each { |rake| load rake }
8
+
9
+ task :default => [:spec]
@@ -0,0 +1,24 @@
1
+ if !Hash.instance_methods.include?(:deep_merge)
2
+ class Hash
3
+ # copied from ActiveSupport::CoreExtensions::Hash::DeepMerge 2.3.8
4
+ def deep_merge(other_hash)
5
+ self.merge(other_hash) do |key, oldval, newval|
6
+ oldval = oldval.to_hash if oldval.respond_to?(:to_hash)
7
+ newval = newval.to_hash if newval.respond_to?(:to_hash)
8
+ oldval.class.to_s == 'Hash' && newval.class.to_s == 'Hash' ? oldval.deep_merge(newval) : newval
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ if !Hash.instance_methods.include?(:slice)
15
+ class Hash
16
+ # copied from http://as.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Hash/Slice.html
17
+ def slice(*keys)
18
+ allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
19
+ hash = {}
20
+ allowed.each { |k| hash[k] = self[k] if has_key?(k) }
21
+ hash
22
+ end
23
+ end
24
+ end
data/lib/yacht.rb ADDED
@@ -0,0 +1,12 @@
1
+ # This file is named yacht.rb
2
+ # so that Bundler will automatically load YachtLoader
3
+ #
4
+ # In the future, once we figure out how to integrate ClassyStruct,
5
+ # YachtLoader will be renamed to Yacht
6
+
7
+ require "yacht_loader/base"
8
+ require "yacht_loader/classy_struct"
9
+ require "yacht_loader/version"
10
+
11
+ require "yacht_loader/rails" if Object.const_defined?(:Rails)
12
+ require 'monkeypatches/hash'
@@ -0,0 +1,112 @@
1
+ # TODO: Rename YachtLoader to Yacht and somehow incorporate ClassyStruct
2
+
3
+ class YachtLoader
4
+ class LoadError < StandardError
5
+ end
6
+
7
+ class << self
8
+ def environment
9
+ @environment ||= 'default'
10
+ end
11
+ attr_writer :environment
12
+
13
+ def dir
14
+ @dir ||= File.join( File.dirname(__FILE__), 'yacht')
15
+ end
16
+ attr_writer :dir
17
+
18
+ def full_file_path_for_config(config_type)
19
+ File.join( self.dir, "#{config_type}.yml" )
20
+ end
21
+
22
+ def config_file_for(config_type)
23
+ raise LoadError.new "#{config_type} is not a valid config type" unless valid_config_types.include?(config_type.to_s)
24
+
25
+ full_file_path_for_config(config_type)
26
+ end
27
+
28
+ def valid_config_types
29
+ %w( base local whitelist )
30
+ end
31
+
32
+ def all
33
+ chain_configs(base_config, self.environment).deep_merge(local_config)
34
+ end
35
+
36
+ def to_hash(opts={})
37
+ opts[:apply_whitelist?] = false unless opts.has_key?(:apply_whitelist?)
38
+ self.environment = opts[:env] if opts.has_key?(:env)
39
+
40
+ if opts[:apply_whitelist?]
41
+ all.slice(*whitelist)
42
+ else
43
+ all
44
+ end
45
+ end
46
+
47
+ def whitelist
48
+ load_config_file(:whitelist, :expect_to_load => Array) || begin
49
+ raise LoadError.new("Couldn't load whitelist")
50
+ end
51
+ end
52
+
53
+ def base_config
54
+ load_config_file(:base) || begin
55
+ raise LoadError.new("Couldn't load base config")
56
+ end
57
+ end
58
+
59
+ def local_config
60
+ load_config_file(:local, :require_presence? => false) || {}
61
+ end
62
+
63
+ protected
64
+ def load_config_file(file_type, opts={})
65
+ # by default, expect a Hash to be loaded
66
+ expected_class = opts[:expect_to_load] || Hash
67
+
68
+ # by default, raise error if file missing or empty
69
+ presence_required = if opts.has_key?(:require_presence?)
70
+ opts[:require_presence?]
71
+ else
72
+ true
73
+ end
74
+
75
+ file_name = self.config_file_for(file_type)
76
+
77
+ loaded = if File.exists?(file_name)
78
+ YAML.load( File.read(file_name) )
79
+ else
80
+ nil
81
+ end
82
+
83
+ # an empty YAML file will be converted to boolean false
84
+ raise LoadError.new "#{file_name} cannot be empty" if presence_required && loaded === false
85
+
86
+ # YAML contained the wrong type
87
+ raise LoadError.new "#{file_name} must contain #{expected_class} (got #{loaded.class})" if loaded && !loaded.is_a?(expected_class)
88
+
89
+ loaded
90
+ rescue => e
91
+ # don't do anything to our own custom errors
92
+ if e.is_a? YachtLoader::LoadError
93
+ raise e
94
+ else
95
+ # convert other errors to YachtLoader::LoadError
96
+ raise LoadError.new "ERROR: loading config file: '#{file_type}': #{e}"
97
+ end
98
+ end
99
+
100
+ def chain_configs(config, env)
101
+ raise LoadError.new "environment '#{env}' does not exist" unless config.has_key?(env)
102
+
103
+ parent = if config[env]['_parent']
104
+ chain_configs(config, config[env]['_parent'])
105
+ else
106
+ config['default'] || {}
107
+ end
108
+
109
+ parent.deep_merge(config[env])
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,15 @@
1
+ require 'classy_struct'
2
+
3
+ class YachtLoader
4
+ class << self
5
+ def classy_struct_instance
6
+ @classy_struct_instance ||= ClassyStruct.new
7
+ end
8
+
9
+ def to_classy_struct(opts={})
10
+ classy_struct_instance.new( self.to_hash(opts) )
11
+ rescue StandardError => e
12
+ raise LoadError.new("Error creating ClassyStruct: #{e.message}")
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ class YachtLoader
2
+ class << self
3
+ # use the current rails environment by default
4
+ def environment
5
+ @environment ||= Rails.env
6
+ end
7
+
8
+ def dir
9
+ @dir ||= Rails.root.join('config', 'yacht')
10
+ end
11
+
12
+ def full_file_path_for_config(config_type)
13
+ dir.join("#{config_type}.yml")
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ class YachtLoader
2
+ VERSION = "0.1.0"
3
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format nested
@@ -0,0 +1,115 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+ $:.unshift(File.dirname(__FILE__))
3
+
4
+ require 'rubygems'
5
+ require 'bundler'
6
+ Bundler.setup
7
+
8
+ # ==============
9
+ # = SimpleCov! =
10
+ # ==============
11
+ require 'simplecov'
12
+ SimpleCov.start
13
+
14
+ require 'yacht'
15
+
16
+ Spec::Runner.configure do |config|
17
+ config.after :each do
18
+ YachtLoader.environment = nil
19
+ YachtLoader.dir = nil
20
+ YachtLoader.instance_variable_set(:@config_file_names, nil)
21
+ end
22
+ end
23
+
24
+ BASE_CONFIG_FILE = <<EOF
25
+ default:
26
+ name: default
27
+ defaultkey: defaultvalue
28
+ dog: schnauzer
29
+ hashkey:
30
+ foo: bar
31
+ baz: wurble
32
+ xyzzy: thud
33
+ an_environment:
34
+ name: an_environment
35
+ hashkey:
36
+ baz: yay
37
+ dog: terrier
38
+ a_child_environment:
39
+ _parent: an_environment
40
+ name: a_child_environment
41
+ hashkey:
42
+ foo: kung
43
+ test:
44
+ baloney: delicious
45
+ EOF
46
+
47
+ WHITELIST_CONFIG_FILE = <<EOF
48
+ - defaultkey
49
+ - hashkey
50
+ EOF
51
+
52
+ EMPTY_WHITELIST_CONFIG_FILE = <<EOF
53
+ EOF
54
+
55
+ INVALID_WHITELIST_CONFIG_FILE = <<EOF
56
+ somenonsenseorother
57
+ EOF
58
+
59
+ LOCAL_CONFIG_FILE = <<EOF
60
+ localkey: localvalue
61
+ EOF
62
+
63
+ EMPTY_LOCAL_CONFIG_FILE = <<EOF
64
+ EOF
65
+
66
+ INVALID_LOCAL_CONFIG_FILE = <<EOF
67
+ someinvalidstufforother
68
+ EOF
69
+
70
+
71
+ # ===================================
72
+ # = Helpers to mock file operations =
73
+ # ===================================
74
+ def banish_config_file_from_prefix(prefix)
75
+ file_name = YachtLoader.config_file_for(prefix)
76
+ banish_file(file_name)
77
+ end
78
+
79
+ # shortcut to mock config file
80
+ def conjure_config_file_from_prefix(prefix, file_contents=nil)
81
+ file_name = YachtLoader.config_file_for(prefix)
82
+ file_contents ||= "#{prefix.upcase}_CONFIG_FILE".constantize
83
+
84
+ conjure_file(file_name, file_contents)
85
+ end
86
+
87
+ def conjure_bad_config_file_from_prefix(prefix)
88
+ file_name = "#{prefix}_config_file"
89
+ file_contents = file_name.upcase.constantize
90
+
91
+ conjure_file(file_name, file_contents)
92
+ end
93
+
94
+ # mock file existence & contents
95
+ def conjure_file(file_name, file_contents)
96
+ File.stub!(:exists?).with(file_name).and_return true
97
+ File.stub!(:read).with(file_name).and_return file_contents
98
+ end
99
+
100
+ # mock file non-existence
101
+ def banish_file(file_name)
102
+ File.stub!(:exists?).with(file_name).and_return(false)
103
+ File.stub!(:read).with(file_name).and_raise Errno::ENOENT.new("No such file or directory - #{file_name}")
104
+ end
105
+
106
+ # ================================================
107
+ # = Railsy helper to turn strings into constants =
108
+ # ================================================
109
+ if !String.instance_methods.include?(:constantize)
110
+ class String
111
+ def constantize # NOT as awesome as ActiveSupport::Inflector#constantize
112
+ Object.const_get(self)
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,179 @@
1
+ require 'spec_helper'
2
+
3
+ describe YachtLoader do
4
+ before(:each) do
5
+ # mock existence and content of files to avoid file system in specs
6
+ %w(base whitelist local).each do |prefix|
7
+ conjure_config_file_from_prefix(prefix)
8
+ end
9
+
10
+ # stub bad config files to check error handling
11
+ %w(empty_whitelist invalid_whitelist empty_local invalid_local).each do |baddie|
12
+ conjure_bad_config_file_from_prefix(baddie)
13
+ end
14
+ end
15
+
16
+ it "raises an error if base config file is missing" do
17
+ banish_config_file_from_prefix('base')
18
+
19
+ expect {
20
+ YachtLoader.to_hash
21
+ }.to raise_error( YachtLoader::LoadError, /Couldn't load base config/)
22
+ end
23
+
24
+ context "whitelist" do
25
+ it "loads keys into an Array" do
26
+ YachtLoader.whitelist.should == ["defaultkey", "hashkey"]
27
+ end
28
+
29
+ it "returns all keys by default, ignoring whitelist" do
30
+ YachtLoader.environment = 'default'
31
+ YachtLoader.to_hash.keys.should include("defaultkey", "hashkey")
32
+ end
33
+
34
+ it "only returns keys included in whitelist when :apply_whitelist? option is true" do
35
+ YachtLoader.environment = 'default'
36
+ YachtLoader.to_hash(:apply_whitelist? => true).keys.should == ["defaultkey", "hashkey"]
37
+ end
38
+
39
+ context "config file" do
40
+ it "raises an error if missing and whitelist is applied" do
41
+ banish_config_file_from_prefix('whitelist')
42
+
43
+ expect {
44
+ YachtLoader.to_hash(:apply_whitelist? => true)
45
+ }.to raise_error( YachtLoader::LoadError, /Couldn't load whitelist/)
46
+ end
47
+
48
+ it "raises an error if empty and whitelist is applied" do
49
+ conjure_config_file_from_prefix( :whitelist, File.read('empty_whitelist_config_file') )
50
+
51
+ expect {
52
+ YachtLoader.to_hash(:apply_whitelist? => true)
53
+ }.to raise_error( YachtLoader::LoadError, /whitelist.+ cannot be empty/)
54
+ end
55
+
56
+ it "raises an error if invalid and whitelist is applied" do
57
+ conjure_config_file_from_prefix( :whitelist, File.read('invalid_whitelist_config_file') )
58
+
59
+ expect {
60
+ YachtLoader.to_hash(:apply_whitelist? => true)
61
+ }.to raise_error( YachtLoader::LoadError, /whitelist.+ must contain Array/)
62
+ end
63
+ end
64
+ end
65
+
66
+ context "checks environment and sets sensible defaults" do
67
+ it "sets the environment to 'default'" do
68
+ YachtLoader.environment.should == "default"
69
+ end
70
+
71
+ it "allows setting the environment by passing an option to `to_hash`" do
72
+ YachtLoader.to_hash(:env => 'a_child_environment')
73
+ YachtLoader.environment.should == 'a_child_environment'
74
+ end
75
+
76
+
77
+ it "raises an error if an environment is requested that doesn't exist" do
78
+ expect {
79
+ YachtLoader.environment = 'nonexistent'
80
+ YachtLoader.to_hash
81
+ }.to raise_error( YachtLoader::LoadError, /does not exist/)
82
+ end
83
+
84
+ it "merges configuration for named environment onto defaults" do
85
+ YachtLoader.environment = 'an_environment'
86
+ YachtLoader.to_hash['defaultkey'].should == 'defaultvalue'
87
+ YachtLoader.to_hash['name'].should == 'an_environment'
88
+ end
89
+ end
90
+
91
+ context "handles child environment" do
92
+ before do
93
+ YachtLoader.environment = 'a_child_environment'
94
+ end
95
+
96
+ it "merges child onto the parent it names" do
97
+ YachtLoader.to_hash['dog'].should == 'terrier'
98
+ end
99
+
100
+ it "merges the hashes recursively" do
101
+ child = YachtLoader.to_hash['hashkey']
102
+
103
+ child['foo'].should == 'kung'
104
+ child['baz'].should == 'yay'
105
+ child['xyzzy'].should == 'thud'
106
+ end
107
+ end
108
+
109
+ context "handling of local config file" do
110
+ before do
111
+ YachtLoader.environment = 'an_environment'
112
+ end
113
+
114
+ it "merges values onto named environment and defaults" do
115
+ YachtLoader.to_hash['defaultkey'].should == 'defaultvalue'
116
+ YachtLoader.to_hash['name'].should == 'an_environment'
117
+ YachtLoader.to_hash['localkey'].should == 'localvalue'
118
+ end
119
+
120
+ it "uses base config if missing" do
121
+ banish_config_file_from_prefix('local')
122
+
123
+ File.should_not_receive(:read).with('local_config_file')
124
+
125
+ YachtLoader.send(:local_config).should == {}
126
+ YachtLoader.to_hash['defaultkey'].should == 'defaultvalue'
127
+ YachtLoader.to_hash['name'].should == 'an_environment'
128
+ end
129
+
130
+ it "uses base config if empty" do
131
+ conjure_config_file_from_prefix(:local, File.read('empty_local_config_file'))
132
+
133
+ File.should_not_receive(:read).with('local_config_file')
134
+
135
+ YachtLoader.send(:local_config).should == {}
136
+ YachtLoader.to_hash['defaultkey'].should == 'defaultvalue'
137
+ YachtLoader.to_hash['name'].should == 'an_environment'
138
+ end
139
+
140
+ it "raises an error if invalid" do
141
+ conjure_config_file_from_prefix( :local, File.read('invalid_local_config_file') )
142
+ expect {
143
+ YachtLoader.to_hash
144
+ }.to raise_error( YachtLoader::LoadError, %r{local.yml must contain Hash})
145
+ end
146
+ end
147
+
148
+ describe :config_file_for do
149
+ it "returns the full file path for the following config files: base, local & whitelist" do
150
+ %w(base local whitelist).each do |config_file|
151
+ YachtLoader.should_receive(:full_file_path_for_config).with(config_file)
152
+
153
+ YachtLoader.config_file_for(config_file)
154
+ end
155
+ end
156
+
157
+ it "raises an error if the config file is not found" do
158
+ expect {
159
+ YachtLoader.config_file_for(:foo)
160
+ }.to raise_error( YachtLoader::LoadError, "foo is not a valid config type")
161
+ end
162
+ end
163
+
164
+ describe :load_config_file do
165
+ it "loads the specified file" do
166
+ conjure_config_file_from_prefix("base", "some contents")
167
+
168
+ YachtLoader.send(:load_config_file, "base", :expect_to_load => String).should == "some contents"
169
+ end
170
+
171
+ it "raises an error if opening the file leads to an exception" do
172
+ YachtLoader.stub(:config_file_for).and_raise(StandardError.new("my_unique_error_message"))
173
+
174
+ expect {
175
+ YachtLoader.send(:load_config_file, "some file")
176
+ }.to raise_error( YachtLoader::LoadError, %r{ERROR: loading.+my_unique_error_message} )
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe "to_classy_struct" do
4
+ before do
5
+ conjure_config_file_from_prefix("base")
6
+ conjure_config_file_from_prefix("local")
7
+ conjure_config_file_from_prefix("whitelist")
8
+
9
+ YachtLoader.environment = 'an_environment'
10
+ end
11
+
12
+ it "creates a ClassyStruct based on to_hash" do
13
+ Yacht = YachtLoader.to_classy_struct
14
+ Yacht.dog.should == "terrier"
15
+ end
16
+
17
+ # ClassyStruct improves performance by adding accessors to the instance object
18
+ # If the instance is not reused, there is no advantage to ClassyStruct over OpenStruct
19
+ it "reuses the instance of ClassyStruct on subsequent calls" do
20
+ first_obj = YachtLoader.classy_struct_instance
21
+ second_obj = YachtLoader.classy_struct_instance
22
+
23
+ first_obj.object_id.should == second_obj.object_id.should
24
+ end
25
+
26
+ it "passes options to to_hash" do
27
+ YachtLoader.should_receive(:to_hash).with({:my => :awesome_option})
28
+
29
+ Yacht = YachtLoader.to_classy_struct({:my => :awesome_option})
30
+ end
31
+
32
+ it "raises a custom error if ClassyStruct cannot be created" do
33
+ YachtLoader.stub!(:to_hash).and_raise("some funky error")
34
+
35
+ expect {
36
+ Yacht = YachtLoader.to_classy_struct
37
+ }.to raise_error(YachtLoader::LoadError, /some funky error/)
38
+ end
39
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Rails support" do
4
+ before do
5
+ require "yacht_loader/rails"
6
+ @yacht_dir = "/path/to/rails/config/yacht"
7
+ end
8
+
9
+ describe :environment do
10
+ before do
11
+ Rails = stub("Rails")
12
+ end
13
+ it "uses the current rails environment by default" do
14
+ Rails.should_receive(:env)
15
+
16
+ YachtLoader.environment
17
+ end
18
+ end
19
+
20
+ describe :dir do
21
+ it "uses config/yacht by default" do
22
+ Rails.stub_chain(:root, :join).and_return(@yacht_dir)
23
+
24
+ YachtLoader.dir.should == @yacht_dir
25
+ end
26
+ end
27
+
28
+ describe :full_file_path_for_config do
29
+ it "calls dir.join" do
30
+ fake_dir = stub("dir stub")
31
+ YachtLoader.stub(:dir).and_return(fake_dir)
32
+ fake_dir.should_receive(:join).with("some.yml")
33
+
34
+ YachtLoader.full_file_path_for_config("some")
35
+ end
36
+ end
37
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yacht
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.0
6
+ platform: ruby
7
+ authors:
8
+ - Mani Tadayon
9
+ - Rico Rodriquez Collins
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2011-05-18 00:00:00 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: classy_struct
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 0.3.2
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - "="
34
+ - !ruby/object:Gem::Version
35
+ version: 1.3.1
36
+ type: :development
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: simplecov
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - "="
45
+ - !ruby/object:Gem::Version
46
+ version: 0.4.2
47
+ type: :development
48
+ version_requirements: *id003
49
+ description:
50
+ email:
51
+ - mtadayon@atti.com
52
+ - rcollins@atti.com
53
+ executables: []
54
+
55
+ extensions: []
56
+
57
+ extra_rdoc_files: []
58
+
59
+ files:
60
+ - lib/monkeypatches/hash.rb
61
+ - lib/yacht.rb
62
+ - lib/yacht_loader/base.rb
63
+ - lib/yacht_loader/classy_struct.rb
64
+ - lib/yacht_loader/rails.rb
65
+ - lib/yacht_loader/version.rb
66
+ - spec/spec.opts
67
+ - spec/spec_helper.rb
68
+ - spec/yacht_loader/base_spec.rb
69
+ - spec/yacht_loader/classy_struct_spec.rb
70
+ - spec/yacht_loader/rails_spec.rb
71
+ - Gemfile
72
+ - Rakefile
73
+ - README.rdoc
74
+ homepage: https://github.com/attinteractive/yacht
75
+ licenses: []
76
+
77
+ post_install_message:
78
+ rdoc_options: []
79
+
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: "0"
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: 1.3.7
94
+ requirements: []
95
+
96
+ rubyforge_project:
97
+ rubygems_version: 1.7.2
98
+ signing_key:
99
+ specification_version: 3
100
+ summary: Use YAML files to manage application configuration.
101
+ test_files: []
102
+