configulations 0.1.5 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.2
data/Gemfile CHANGED
@@ -5,4 +5,5 @@ group :development do
5
5
  gem "bundler", "~> 1.0.0"
6
6
  gem "jeweler", "~> 1.6.2"
7
7
  gem "rcov", ">= 0"
8
+ gem "ruby-debug19"
8
9
  end
data/Gemfile.lock CHANGED
@@ -1,12 +1,16 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
+ archive-tar-minitar (0.5.2)
5
+ columnize (0.3.4)
4
6
  diff-lcs (1.1.2)
5
7
  git (1.2.5)
6
8
  jeweler (1.6.2)
7
9
  bundler (~> 1.0)
8
10
  git (>= 1.2.5)
9
11
  rake
12
+ linecache19 (0.5.12)
13
+ ruby_core_source (>= 0.1.4)
10
14
  rake (0.9.2)
11
15
  rcov (0.9.9)
12
16
  rspec (2.3.0)
@@ -17,6 +21,16 @@ GEM
17
21
  rspec-expectations (2.3.0)
18
22
  diff-lcs (~> 1.1.2)
19
23
  rspec-mocks (2.3.0)
24
+ ruby-debug-base19 (0.11.25)
25
+ columnize (>= 0.3.1)
26
+ linecache19 (>= 0.5.11)
27
+ ruby_core_source (>= 0.1.4)
28
+ ruby-debug19 (0.11.6)
29
+ columnize (>= 0.3.1)
30
+ linecache19 (>= 0.5.11)
31
+ ruby-debug-base19 (>= 0.11.19)
32
+ ruby_core_source (0.1.5)
33
+ archive-tar-minitar (>= 0.5.2)
20
34
 
21
35
  PLATFORMS
22
36
  ruby
@@ -26,3 +40,4 @@ DEPENDENCIES
26
40
  jeweler (~> 1.6.2)
27
41
  rcov
28
42
  rspec (~> 2.3.0)
43
+ ruby-debug19
@@ -1,4 +1,4 @@
1
- = Configulations - You can have a simple configuration class for Ruby apps!
1
+ # Configulations - You can have a simple configuration class for Ruby apps!
2
2
 
3
3
  This is a bare bones, simple way to add configuration files to your ruby
4
4
  apps using either json or yml. Then, you can simply call into the configurator like
@@ -11,18 +11,20 @@ To ensure as much flexibility without damaging Hash directly, configurator simpl
11
11
  the instance of the property bag so that we get the power of hash without messing up
12
12
  hash for any one that is using it.
13
13
 
14
- == EXAMPLE
14
+ ## EXAMPLE
15
15
 
16
16
  by default, Configulations is going to recursively dive into a "config" directory located
17
17
  by the location of the executing ruby process. from there, any files ending in .yml or .json
18
18
  with the respetive content-types of YAML or JSON will be loaded. The name of the file is
19
19
  the first key and all properties can be fetched from there.
20
20
 
21
+ ```ruby
21
22
  config = Configulations.new #=> finds config/server.json and config/admins.yml
22
23
  config.server.host #=> "localhost"
23
24
  config.admins.include? User.find_by_name("leon") #=> true
25
+ ```
24
26
 
25
- == Known Issues
27
+ ## Known Issues
26
28
 
27
29
  * Right now data is first in- first out. If you have 2 config files with the same name
28
30
  the last one in, wins.
@@ -31,16 +33,18 @@ another file.
31
33
 
32
34
  You can however, augment the settings anytime you like.
33
35
 
36
+ ```ruby
34
37
  config.admins.pop #=> gives one of our admins.
38
+ ```
35
39
 
36
- == Future
40
+ ## Future
37
41
 
38
42
  This is all I needed for now but I'd love to work out those issues mentioned above
39
43
  as well as allow for some robust Ruby configuration files that could take advantage
40
44
  of run time-evaluation and flow control for those situations when you'd like to let
41
45
  configuration be a bit more flexible than a yml, json file would allow.
42
46
 
43
- == Contributing to configulations
47
+ ## Contributing to configulations
44
48
 
45
49
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
46
50
  * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
@@ -51,7 +55,7 @@ configuration be a bit more flexible than a yml, json file would allow.
51
55
  * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
52
56
  * This list is from Jeweler. Which is awesome...
53
57
 
54
- == Copyright
58
+ ## Copyright
55
59
 
56
60
  Copyright (c) 2011 Leon Gersing. See LICENSE.txt for
57
61
  further details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.5
1
+ 0.2.0
@@ -0,0 +1,2 @@
1
+ host: "production.local"
2
+ port: 4200
@@ -0,0 +1 @@
1
+ host: "development.local"
@@ -0,0 +1 @@
1
+ host: "test.local"
@@ -0,0 +1,4 @@
1
+ { "favorite_actor" : "Harrison Ford"
2
+ , "favorite_movie" : "Lord of the Rings"
3
+ , "favorite_trilogy" : "Lord of the Rings"
4
+ }
@@ -0,0 +1,3 @@
1
+ { "favorite_trilogy": "Star Wars",
2
+ "favorite_movie" : "Empire Strikes Back" }
3
+
File without changes
@@ -0,0 +1,2 @@
1
+ star_wars: ["slave1", "x-wing"]
2
+ doctor_who: "tardis"
File without changes
@@ -0,0 +1,3 @@
1
+ name: "foo"
2
+ age: 33
3
+ location: "Miami, FL"
File without changes
@@ -1 +1,2 @@
1
1
  name: "Leon"
2
+ age : 23
File without changes
File without changes
@@ -5,40 +5,48 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{configulations}
8
- s.version = "0.1.5"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Leon Gersing"]
12
- s.date = %q{2011-07-06}
12
+ s.date = %q{2011-07-12}
13
13
  s.description = %q{Auto-create configuration objects for your applications from yml and json files.}
14
14
  s.email = %q{leongersing@gmail.com}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE.txt",
17
- "README.rdoc"
17
+ "README.md"
18
18
  ]
19
19
  s.files = [
20
20
  ".document",
21
21
  ".rspec",
22
+ ".rvmrc",
22
23
  "Gemfile",
23
24
  "Gemfile.lock",
24
25
  "LICENSE.txt",
25
- "README.rdoc",
26
+ "README.md",
26
27
  "Rakefile",
27
28
  "VERSION",
29
+ "config/application.yml",
30
+ "config/application/development.yml",
31
+ "config/application/test.yml",
28
32
  "config/development.yml",
29
33
  "config/foo.json",
34
+ "config/parent.json",
35
+ "config/parent/child.json",
30
36
  "config/server.yml",
31
- "config/singles/first.yml",
32
- "config/singles/fourth.json",
33
- "config/singles/second.yml",
34
- "config/singles/third.js",
37
+ "config/ships/flying/classic.yml",
38
+ "config/ships/flying/fictional.yml",
39
+ "config/ships/flying/modern.yml",
40
+ "config/singles.yml",
41
+ "config/singles/person_four.json",
42
+ "config/singles/person_one.yml",
43
+ "config/singles/person_three.js",
44
+ "config/singles/person_two.yaml",
35
45
  "configulations.gemspec",
36
46
  "lib/configulations.rb",
37
47
  "lib/magic_hash.rb",
38
48
  "spec/configurator_spec.rb",
39
- "spec/inclusive_spec.rb",
40
49
  "spec/magic_hash_spec.rb",
41
- "spec/sample_spec.rb",
42
50
  "spec/spec_helper.rb"
43
51
  ]
44
52
  s.homepage = %q{http://github.com/leongersing/configulations}
@@ -55,17 +63,20 @@ Gem::Specification.new do |s|
55
63
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
56
64
  s.add_development_dependency(%q<jeweler>, ["~> 1.6.2"])
57
65
  s.add_development_dependency(%q<rcov>, [">= 0"])
66
+ s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
58
67
  else
59
68
  s.add_dependency(%q<rspec>, ["~> 2.3.0"])
60
69
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
61
70
  s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
62
71
  s.add_dependency(%q<rcov>, [">= 0"])
72
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
63
73
  end
64
74
  else
65
75
  s.add_dependency(%q<rspec>, ["~> 2.3.0"])
66
76
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
67
77
  s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
68
78
  s.add_dependency(%q<rcov>, [">= 0"])
79
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
69
80
  end
70
81
  end
71
82
 
@@ -3,45 +3,75 @@ require 'json'
3
3
  require 'magic_hash'
4
4
 
5
5
  class Configulations
6
+ attr_accessor :root
6
7
  attr_accessor :properties
7
- attr_accessor :include_pattern
8
+ attr_accessor :supported_extensions
9
+ attr_accessor :environments
8
10
 
9
- def initialize
10
- @include_pattern = File.expand_path(".") << "/config/**/*.{yml,json}"
11
- find_properties
11
+ def initialize(root="./config")
12
+ @root = File.expand_path(root)
13
+ @supported_extensions = [:yml, :yaml, :js, :json]
14
+ @environments = ["RAILS_ENV", "RACK_ENV", "APP_ENV"]
15
+ @properties = MagicHash.new
16
+ find_properties(config_files_at_dir(@root))
17
+ @properties.objectify
12
18
  end
13
19
 
14
- def self.configure(&blk)
15
- me = Configulations.new
16
- blk.call(me)
17
- me.find_properties
18
- me
20
+ def environmental_override?(base)
21
+ !@environments.select{|ev| base.downcase == (ENV[ev] || "").downcase}.empty?
19
22
  end
20
23
 
21
- def find_properties
22
- @properties = {}
23
- @properties.extend(MagicHash)
24
+ def find_properties(config_files, props=@properties, parent=nil)
25
+ return if config_files.empty?
26
+ file = config_files.shift
27
+ ext = File.extname(file)
28
+ base = File.basename(file, ext)
29
+ parser = parser_for_extname(ext)
30
+ config_data = parser.send(:load, File.read(file))
24
31
 
25
- Dir[@include_pattern].each do |file|
26
- ext = File.extname(file)
27
- base = File.basename(file, ext)
28
- parser = parser_for_extname(ext)
29
- @properties[base]= parser.send(:load, File.read(file))
32
+ if parent
33
+ props.merge!(config_data) if environmental_override?(base)
34
+ props[parent] = config_data if props[parent]
30
35
  end
31
36
 
32
- @properties.objectify
37
+ props[base] = config_data
38
+
39
+ if Dir.exists?(dir = "#{File.dirname(file)}/#{base}")
40
+ child_configs = glob_directory_against_supported_extensions(dir)
41
+ find_properties(child_configs, props[base], base)
42
+ end
43
+
44
+ find_properties(config_files, props, parent)
45
+ end
46
+
47
+ def glob_directory_against_supported_extensions(dir)
48
+ Dir.glob("#{dir}/*.{#{ext_glob_string}}")
49
+ end
50
+
51
+ def ext_glob_string
52
+ supported_extensions.map{|x|x.to_s}.join(",")
33
53
  end
34
54
 
35
55
  def parser_for_extname(extname)
36
- if(extname =~ /\.js(?:on)?/i)
56
+ case extname
57
+ when /\.js(?:on)?/i
37
58
  return JSON
38
- elsif(extname =~ /\.ya?ml/i)
59
+ when /\.ya?ml/i
39
60
  return YAML
40
61
  else
41
62
  raise "Only files ending in .js, .json, .yml, .yaml have parsers at the moment."
42
63
  end
43
64
  end
44
65
 
66
+ def config_files_at_dir(dir)
67
+ ( config_files = glob_directory_against_supported_extensions(dir.to_s) ).reject do |file|
68
+ ext = File.extname(file)
69
+ base = File.basename(file, ext)
70
+ parent_config = file.gsub(/\/#{base}#{ext}/, ext)
71
+ config_files.include?(parent_config)
72
+ end
73
+ end
74
+
45
75
  def method_missing(message_name, *message_arguments, &optional_block)
46
76
  message = message_name.to_s.strip.gsub(/-/,"_")
47
77
  if message =~ /=/
@@ -55,4 +85,5 @@ class Configulations
55
85
 
56
86
  super message_name, *message_arguments, &optional_block
57
87
  end
88
+
58
89
  end
data/lib/magic_hash.rb CHANGED
@@ -1,24 +1,21 @@
1
1
  module MagicHash
2
2
 
3
- def objectify
4
- self.make_keys_valid_message_aliases
5
- self.hash_all_keys
6
- self
3
+ def self.new
4
+ Hash.new.extend(MagicHash)
7
5
  end
8
6
 
9
- def make_keys_valid_message_aliases
10
- tmp={}
11
- tmp.extend(MagicHash)
7
+ def objectify
8
+ tmp = MagicHash.new
12
9
  self.each_pair do |key, value|
13
10
  new_key = key.is_a?(Symbol) ? key : key.gsub(/\s|-/,"_").strip.to_sym
14
11
  if(value.is_a? Hash)
15
12
  value.extend(MagicHash) unless value.respond_to? :objectify
16
- tmp[new_key] = value.make_keys_valid_message_aliases
13
+ tmp[new_key] = value.objectify
17
14
  elsif(value.is_a? Array)
18
15
  tmp[new_key] = value.map do |val|
19
16
  if val.is_a?(Hash)
20
17
  val.extend(MagicHash) unless val.respond_to? :objectify
21
- val.make_keys_valid_message_aliases
18
+ val.objectify
22
19
  else
23
20
  val
24
21
  end
@@ -30,30 +27,6 @@ module MagicHash
30
27
  self.replace(tmp)
31
28
  end
32
29
 
33
- def hash_all_keys()
34
- tmp = {}
35
- tmp.extend(MagicHash)
36
- self.each_pair do |k, v|
37
- if v.is_a? Hash
38
- v.extend(MagicHash) unless v.respond_to? :objectify
39
- tmp[k.to_sym]= v.hash_all_keys
40
- elsif v.is_a? Array
41
- v = v.map do |value|
42
- if value.is_a?(Hash.class)
43
- value.extend(MagicHash) unless value.respond_to? :objectify
44
- value.hash_all_keys
45
- else
46
- value
47
- end
48
- end
49
- tmp[k.to_sym]= v
50
- else
51
- tmp[k.to_sym]= v
52
- end
53
- end
54
- self.replace(tmp)
55
- end
56
-
57
30
  def method_missing(method_name, *args, &blk)
58
31
  message = method_name.to_s.strip.downcase.gsub(/-/,"_")
59
32
  if message =~ /=/
@@ -29,6 +29,48 @@ describe Configulations do
29
29
  c.server.cache_enabled?.should == true
30
30
  c.server.cache_enabled?.should be_true
31
31
  end
32
+
33
+ it "is recursive when it needs to be" do
34
+ c = Configulations.new
35
+ c.singles.person_one.name.should == "Leon"
36
+ end
37
+
38
+ it "can be used from constants defined in the executing process." do
39
+ MyConfig.should_not be_nil
40
+ MyConfig.root.should_not be_nil
41
+ MyConfig.root.should == "/usr/local/bin/awesome"
42
+ end
43
+ end
44
+
45
+ describe "Inheritance" do
46
+ before do
47
+ @config = Configulations.new
48
+ end
49
+
50
+ context "when child introduces new config option" do
51
+ it "is appended and namespaced to parent" do
52
+ @config.parent.child.favorite_movie.should == "Empire Strikes Back"
53
+ @config.parent.favorite_movie.should == "Lord of the Rings"
54
+ end
55
+
56
+ it "retains non-overwritten options" do
57
+ @config.parent.favorite_actor.should == "Harrison Ford"
58
+ end
59
+
60
+ context "environmental overrides." do
61
+ it "accepts the will of ENV specific children" do
62
+ @config.application.host.should == "test.local"
63
+ @config.application.test.host.should == "test.local"
64
+ end
65
+
66
+ it "maintains the un-overrided values" do
67
+ @config.application.port.should == 4200
68
+ @config.application.host.should == "test.local"
69
+ end
70
+ end
71
+ end
72
+
73
+
32
74
  end
33
75
  end
34
76
 
data/spec/spec_helper.rb CHANGED
@@ -3,6 +3,8 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
3
  require 'rspec'
4
4
  require 'configulations'
5
5
 
6
+ ENV["APP_ENV"] ||= "test"
7
+
6
8
  MyConfig = Configulations.new
7
9
  MyConfig.root = "/usr/local/bin/awesome"
8
10
 
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: configulations
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.5
5
+ version: 0.2.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Leon Gersing
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-07-06 00:00:00 -04:00
13
+ date: 2011-07-12 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -57,6 +57,17 @@ dependencies:
57
57
  type: :development
58
58
  prerelease: false
59
59
  version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: ruby-debug19
62
+ requirement: &id005 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: *id005
60
71
  description: Auto-create configuration objects for your applications from yml and json files.
61
72
  email: leongersing@gmail.com
62
73
  executables: []
@@ -65,30 +76,38 @@ extensions: []
65
76
 
66
77
  extra_rdoc_files:
67
78
  - LICENSE.txt
68
- - README.rdoc
79
+ - README.md
69
80
  files:
70
81
  - .document
71
82
  - .rspec
83
+ - .rvmrc
72
84
  - Gemfile
73
85
  - Gemfile.lock
74
86
  - LICENSE.txt
75
- - README.rdoc
87
+ - README.md
76
88
  - Rakefile
77
89
  - VERSION
90
+ - config/application.yml
91
+ - config/application/development.yml
92
+ - config/application/test.yml
78
93
  - config/development.yml
79
94
  - config/foo.json
95
+ - config/parent.json
96
+ - config/parent/child.json
80
97
  - config/server.yml
81
- - config/singles/first.yml
82
- - config/singles/fourth.json
83
- - config/singles/second.yml
84
- - config/singles/third.js
98
+ - config/ships/flying/classic.yml
99
+ - config/ships/flying/fictional.yml
100
+ - config/ships/flying/modern.yml
101
+ - config/singles.yml
102
+ - config/singles/person_four.json
103
+ - config/singles/person_one.yml
104
+ - config/singles/person_three.js
105
+ - config/singles/person_two.yaml
85
106
  - configulations.gemspec
86
107
  - lib/configulations.rb
87
108
  - lib/magic_hash.rb
88
109
  - spec/configurator_spec.rb
89
- - spec/inclusive_spec.rb
90
110
  - spec/magic_hash_spec.rb
91
- - spec/sample_spec.rb
92
111
  - spec/spec_helper.rb
93
112
  has_rdoc: true
94
113
  homepage: http://github.com/leongersing/configulations
@@ -104,7 +123,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
104
123
  requirements:
105
124
  - - ">="
106
125
  - !ruby/object:Gem::Version
107
- hash: 2698804338379669907
126
+ hash: 2454716717098569719
108
127
  segments:
109
128
  - 0
110
129
  version: "0"
@@ -1,40 +0,0 @@
1
- require "spec_helper"
2
-
3
- YamlSingleConfig = Configulations.configure do |config|
4
- config.include_pattern = File.expand_path(".") << "/config/singles/*.yml"
5
- end
6
-
7
- JsonSingleConfig = Configulations.configure do |config|
8
- config.include_pattern = File.expand_path(".") << "/config/singles/*.js*"
9
- end
10
-
11
- SingleConfig = Configulations.configure do |config|
12
- config.include_pattern = File.expand_path(".") << "/config/singles/*.*" #DANGER WILL ROBINSON!
13
- end
14
-
15
- describe "Inclusion" do
16
- describe "yaml" do
17
- it "finds first and second" do
18
- YamlSingleConfig.first.name.should == "Leon"
19
- YamlSingleConfig.second.name.should == "Marc"
20
- lambda{ YamlSingleConfig.third }.should raise_error
21
- end
22
- end
23
-
24
- describe "json" do
25
- it "finds third and fourth" do
26
- JsonSingleConfig.third.name.should == "Felix"
27
- JsonSingleConfig.fourth.name.should == "Mike"
28
- lambda{ JsonSingleConfig.first }.should raise_error
29
- end
30
- end
31
-
32
- describe "mixing json and yml" do
33
- it "finds eveything" do
34
- SingleConfig.first.name.should == "Leon"
35
- SingleConfig.second.name.should == "Marc"
36
- SingleConfig.third.name.should == "Felix"
37
- SingleConfig.fourth.name.should == "Mike"
38
- end
39
- end
40
- end
data/spec/sample_spec.rb DELETED
@@ -1,10 +0,0 @@
1
- require "spec_helper"
2
-
3
- # see the spec_helper to see a crazy MyConfig class.
4
- describe "Sample use" do
5
- it "just works." do
6
- MyConfig.should_not be_nil
7
- MyConfig.root.should_not be_nil
8
- MyConfig.root.should == "/usr/local/bin/awesome"
9
- end
10
- end