Skip to content
Browse files

Initial commit

  • Loading branch information...
0 parents commit 444ec87caf799b982da9c7d78186c17aaee88d14 @kindkid committed Jul 29, 2011
5 .gitignore
@@ -0,0 +1,5 @@
+*.gem
+.bundle
+Gemfile.lock
+pkg/*
+coverage/*
1 .rvmrc
@@ -0,0 +1 @@
+rvm use ruby-1.9.2@constantinople
4 Gemfile
@@ -0,0 +1,4 @@
+source "http://rubygems.org"
+
+# Specify your gem's dependencies in constantinople.gemspec
+gemspec
14 Guardfile
@@ -0,0 +1,14 @@
+# A sample Guardfile
+# More info at https://github.com/guard/guard#readme
+
+guard 'bundler' do
+ watch('Gemfile')
+ watch(/^.+\.gemspec/)
+end
+
+guard 'rspec', :cli => '-c --format documentation -r ./spec/spec_helper.rb',
+ :version => 2 do
+ watch(%r{^spec/.+_spec\.rb})
+ watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
+ watch('spec/spec_helper.rb') { "spec" }
+end
66 README.md
@@ -0,0 +1,66 @@
+Constantinople
+==============
+
+Usage
+=====
+Place all your configuration parameters in YAML files within a config/
+directory under the top level of your project. For example, you might have a
+config/database.yml file.
+
+In an initializer at the top level of your project,
+or within your config/ directory, do this:
+
+ require 'constantinople'
+
+You may then use CONSTANTINOPLE from anywhere in your app:
+
+ CONSTANTINOPLE.database.username
+
+
+Defaults and Overrides
+======================
+You can create default and over-ride versions of config files. Constantinople
+will look for and load config files in the following order:
+
+ config/*.yml.default
+ config/*.yml
+ config/*.yml.override
+
+The results are merged together. We recommended you gitignore config/*.yml.
+
+Environments
+============
+If there is a non-empty ENV['RAILS_ENV'], ENV['RACK_ENV'] or ENV['APP_ENV'] the
+first such environment will be used as a key whose values will be merged into
+the level above. So for example, if your database.yml file has
+
+ username: root
+ password:
+ production:
+ password: d87gfds09ds8a
+
+Then in your development environment:
+
+ CONSTANTINOPLE.database.username # root
+ CONSTANTINOPLE.database.password # nil
+
+And in your production environment:
+
+ CONSTANTINOPLE.database.username # root
+ CONSTANTINOPLE.database.password # d87gfds09ds8a
+
+
+Working on the Gem
+==================
+Install rvm, including ruby 1.9.2
+Clone the git repo, then...
+
+ cd constantinople
+ gem install bundler
+ bundle install
+ rake coverage
+
+
+Forking
+=======
+Yeah, fine. But please rename to Istanbul.
24 Rakefile
@@ -0,0 +1,24 @@
+require 'bundler/gem_tasks'
+require 'rspec/core/rake_task'
+
+desc "Run all specs"
+RSpec::Core::RakeTask.new(:spec) do |t|
+ t.rspec_opts = [
+ '-c',
+ '--format documentation',
+ '-r ./spec/spec_helper.rb'
+ ]
+ t.pattern = 'spec/**/*_spec.rb'
+end
+
+desc "open coverage report"
+task :coverage do
+ system 'rake spec'
+ system 'open coverage/index.html'
+end
+
+desc "Open development console"
+task :console do
+ puts "Loading development console..."
+ system "irb -I #{File.join('.', 'lib')} -r #{File.join('.', 'lib', 'constantinople')}"
+end
28 constantinople.gemspec
@@ -0,0 +1,28 @@
+# -*- encoding: utf-8 -*-
+$:.push File.expand_path("../lib", __FILE__)
+require "constantinople/version"
+
+Gem::Specification.new do |s|
+ s.name = "constantinople"
+ s.version = Constantinople::VERSION
+ s.authors = ["Chris Johnson"]
+ s.email = ["chris@kindkid.com"]
+ s.homepage = "https://github.com/kindkid/constantinople"
+ s.summary = "Load all your config/*.yml files"
+ s.description = "Supports defaults, over-rides, and environments"
+
+ s.rubyforge_project = "constantinople"
+
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.require_paths = ["lib"]
+ s.add_dependency "map", "~> 4.2"
+ s.add_dependency "deep_merge", "0.2.0"
+ s.add_development_dependency "rspec", "~> 2.6"
+ s.add_development_dependency "simplecov", "~> 0.4"
+ s.add_development_dependency("rb-fsevent", "~> 0.4") if RUBY_PLATFORM =~ /darwin/i
+ s.add_development_dependency "guard", "~> 0.5"
+ s.add_development_dependency "guard-bundler", "~> 0.1"
+ s.add_development_dependency "guard-rspec", "~> 0.4"
+end
69 lib/constantinople.rb
@@ -0,0 +1,69 @@
+require "map"
+require 'yaml'
+require "deep_merge/core"
+require "constantinople/deep_merge_map"
+require "constantinople/version"
+
+module Constantinople
+
+ def self.reload!
+ result = Map.new
+ caller_config_directories do |dir|
+ result.deeper_merge!(load_from_directory(dir))
+ end
+ env = environment
+ result.each do |key, value|
+ value.deeper_merge!(value[env]) if value.include?(env)
+ end
+ result # I'm the map, I'm the map, I'm the map, I'm the map...
+ end
+
+ private
+
+ def self.load_from_directory(dir)
+ result = Map.new
+ ['.yml.default', '.yml', '.yml.override'].each do |ext|
+ Dir.glob(File.join(dir,"*#{ext}")) do |path|
+ filename = File.basename(path,ext)
+ result.deeper_merge!(filename => YAML.load_file(path))
+ end
+ end
+ result
+ end
+
+ def self.environment
+ ['RAILS_ENV', 'RACK_ENV', 'APP_ENV'].each do |env|
+ environment = ENV[env]
+ return environment unless environment.nil? || environment.empty?
+ end
+ nil
+ end
+
+ def self.caller_config_directories
+ possible_caller_config_directories do |dir|
+ yield dir if Dir.exist?(dir)
+ end
+ end
+
+ def self.possible_caller_config_directories
+ caller_directories do |d|
+ yield File.join(d,'config')
+ yield File.join(File.dirname(d),'config')
+ end
+ end
+
+ def self.caller_directories
+ results = []
+ regex = /^(.*)\:\d+\:in .*$/
+ caller.each do |trace|
+ next unless match = regex.match(trace)
+ file = match[1]
+ next unless file && File.exist?(file)
+ dir = File.dirname(file)
+ yield dir unless results.include?(dir)
+ end
+ end
+
+end
+
+CONSTANTINOPLE = Constantinople.reload!
13 lib/constantinople/deep_merge_map.rb
@@ -0,0 +1,13 @@
+module Constantinople
+ module DeepMergeMap
+ # deep_merge! will merge and overwrite any unmergeables in destination hash
+ def deeper_merge!(source, options = {})
+ default_opts = {:preserve_unmergeables => false}
+ ::DeepMerge::deep_merge!(source, self, default_opts.merge(options))
+ end
+ end
+end
+
+class Map
+ include ::Constantinople::DeepMergeMap
+end
3 lib/constantinople/version.rb
@@ -0,0 +1,3 @@
+module Constantinople
+ VERSION = "0.0.1"
+end
9 spec/config/spec.yml
@@ -0,0 +1,9 @@
+b: standard
+c: standard
+animal: unicorn
+development:
+ animal: dolphin
+test:
+ animal: turtle
+production:
+ animal: penguin
3 spec/config/spec.yml.default
@@ -0,0 +1,3 @@
+a: default
+b: default
+c: default
1 spec/config/spec.yml.override
@@ -0,0 +1 @@
+c: override
18 spec/lib/constantinople_spec.rb
@@ -0,0 +1,18 @@
+describe Constantinople do
+
+ before(:all) do
+ CONSTANTINOPLE.spec.a.should == 'default' # just showing we do auto-load
+
+ ENV['RAILS_ENV'] ||= 'test'
+ CONFIG = Constantinople.reload!
+ end
+
+ it "just works" do
+ CONFIG.should_not be_nil
+ CONFIG.spec.should_not be_nil
+ CONFIG.spec.a.should == 'default'
+ CONFIG.spec.b.should == 'standard'
+ CONFIG.spec.c.should == 'override'
+ CONFIG.spec.animal.should == 'turtle' # from test environment
+ end
+end
7 spec/spec_helper.rb
@@ -0,0 +1,7 @@
+require 'simplecov'
+SimpleCov.start
+
+require 'rubygems'
+require 'bundler'
+
+Bundler.require(:default, :test, :development)

0 comments on commit 444ec87

Please sign in to comment.
Something went wrong with that request. Please try again.