rails_app_config 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2010 Jacques Crocker
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+
23
+ Deep Merge (deep_merge.rb) code Copyright (c) 2008 Steve Midgley, released under the MIT license
data/README ADDED
@@ -0,0 +1,73 @@
1
+ == Summary
2
+ Application level configuration.
3
+
4
+ == Author
5
+ Jacques Crocker
6
+ Modified from Original Project (AppConfig by Christopher J. Bottaro)
7
+
8
+ === Compatibility
9
+ Rails 3.0
10
+
11
+ === Installing on Rails 3
12
+
13
+ add this to your Gemfile
14
+
15
+ gem "rails_app_config"
16
+
17
+ === Accessing the AppConfig object
18
+ After installing this plugin, the AppConfig object will be global available. Entries are accessed via object member notation:
19
+ AppConfig.my_config_entry
20
+ Nested entries are supported:
21
+ AppConfig.my_section.some_entry
22
+
23
+ === Common config file
24
+ Config entries are compiled from
25
+ config/app_config.yml
26
+ config/app_config/settings.yml
27
+ config/app_config/#{environment}.yml
28
+ config/environments/#{environment}.yml
29
+
30
+ settings defined in files that are lower in the list override settings higher
31
+
32
+ === Reloading config files
33
+ You can reload the AppConfig from file at any time by running AppConfig.reload!
34
+
35
+ === Environment specific config files
36
+ You can have environment specific config files. Environment specific config entries take precedence over common config entries.
37
+
38
+ Example development environment config file:
39
+ RAILS_ROOT/config/environments/development.yml
40
+
41
+ Example production environment config file:
42
+ RAILS_ROOT/config/environments/production.yml
43
+
44
+ === Embedded Ruby (ERB)
45
+ Embedded Ruby is allowed in the configuration files. See examples below.
46
+
47
+ === Accessing Configuration Settings
48
+ Consider the two following config files.
49
+
50
+ RAILS_ROOT/config/app_config.yml:
51
+ size: 1
52
+ server: google.com
53
+
54
+ RAILS_ROOT/config/environments/development.yml:
55
+ size: 2
56
+ computed: <%= 1 + 2 + 3 %>
57
+ section:
58
+ size: 3
59
+ servers: [ {name: yahoo.com}, {name: amazon.com} ]
60
+
61
+ Notice that the environment specific config entries overwrite the common entries.
62
+ AppConfig.size -> 2
63
+ AppConfig.server -> google.com
64
+
65
+ Notice the embedded Ruby.
66
+ AppConfig.computed -> 6
67
+
68
+ Notice that object member notation is maintained even in nested entries.
69
+ AppConfig.section.size -> 3
70
+
71
+ Notice array notation and object member notation is maintained.
72
+ AppConfig.section.servers[0].name -> yahoo.com
73
+ AppConfig.section.servers[1].name -> amazon.com
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ require 'rake'
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |s|
6
+ s.name = "rails_app_config"
7
+ s.summary = "provides an AppConfig for rails3 that reads config/app_config.yml"
8
+ s.email = "railsjedi@gmail.com"
9
+ s.homepage = "http://github.com/railsjedi/rails_app_config"
10
+ s.description = "Provides an easy to use Application Configuration object"
11
+ s.authors = ["Jacques Crocker"]
12
+ s.files = FileList["[A-Z]*", "{bin,generators,lib,test}/**/*"]
13
+ end
14
+ Jeweler::GemcutterTasks.new
15
+ rescue LoadError
16
+ # puts "Jeweler, or one of its dependencies, is not available. Install it with: gem install jeweler"
17
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,168 @@
1
+ require 'ostruct'
2
+ require 'yaml'
3
+ require 'erb'
4
+
5
+ module ApplicationConfig
6
+ # == Summary
7
+ # This is API documentation, NOT documentation on how to use this plugin. For that, see the README.
8
+ class ConfigBuilder
9
+ @@load_paths = []
10
+ @@expand_keys = []
11
+ @@root_path = ""
12
+
13
+ # Create a config object (OpenStruct) from a yaml file. If a second yaml file is given, then the sections of that file will overwrite the sections
14
+ # if the first file if they exist in the first file.
15
+ def self.load_files(options = {})
16
+ config = OpenStruct.new
17
+
18
+ @@load_paths = [options[:paths]].flatten.compact.uniq
19
+ @@expand_keys = [options[:expand_keys]].flatten.compact.uniq
20
+ @@root_path = options[:root_path]
21
+
22
+ # add singleton method to our AppConfig that reloads its settings from the load_paths options
23
+ def config.reload!
24
+
25
+ conf = {}
26
+ ConfigBuilder.load_paths.to_a.each do |path|
27
+ file_conf = YAML.load(ERB.new(IO.read(path)).result) if path and File.exists?(path)
28
+ next unless file_conf
29
+
30
+ if conf.size > 0
31
+ DeepMerge.deep_merge!(file_conf, conf, :preserve_unmergeables => false)
32
+ else
33
+ conf = file_conf
34
+ end
35
+ end
36
+
37
+ # expand the javascripts config to handle *.* paths
38
+ ConfigBuilder.expand_keys.to_a.each do |expand_path|
39
+ expand_path = expand_path.to_s
40
+ if conf[expand_path]
41
+ conf[expand_path] = ApplicationConfig::ConfigBuilder.expand(conf[expand_path], "#{ConfigBuilder.root_path}/public/#{expand_path}")
42
+ end
43
+ end
44
+
45
+ # load all the new values into the openstruct
46
+ marshal_load(ApplicationConfig::ConfigBuilder.convert(conf).marshal_dump)
47
+
48
+ return self
49
+ end
50
+
51
+ config.reload!
52
+ return config
53
+ end
54
+
55
+ def self.load_paths
56
+ @@load_paths
57
+ end
58
+
59
+ def self.expand_keys
60
+ @@expand_keys
61
+ end
62
+
63
+ def self.root_path
64
+ @@root_path
65
+ end
66
+
67
+ # Recursively converts Hashes to OpenStructs (including Hashes inside Arrays)
68
+ def self.convert(h) #:nodoc:
69
+ s = OpenStruct.new
70
+ h.each do |k, v|
71
+ s.new_ostruct_member(k)
72
+ if v.is_a?(Hash)
73
+ s.send( (k+'=').to_sym, convert(v))
74
+ elsif v.is_a?(Array)
75
+ converted_array = v.collect { |e| e.instance_of?(Hash) ? convert(e) : e }
76
+ s.send("#{k}=".to_sym, converted_array)
77
+ else
78
+ s.send("#{k}=".to_sym, v)
79
+ end
80
+ end
81
+ s
82
+ end
83
+
84
+ # expand a config val
85
+ def self.expand(config, base_path)
86
+ case config.class.to_s
87
+ when "Hash"
88
+ return expand_hash(config, base_path)
89
+ when "Array"
90
+ return expand_array(config, base_path)
91
+ when "String"
92
+ return expand_string(config, base_path)
93
+ end
94
+ return config
95
+ end
96
+
97
+ # expand a string and returns a list
98
+ def self.expand_string(config, base_path)
99
+ # puts "Expanding String: #{config.inspect}"
100
+ if config.include?("*")
101
+ results = Dir["#{base_path}/#{config}"].map{|i| i.to_s.gsub("#{base_path}/", "") }
102
+
103
+ # puts "EXPANDED PATH: #{base_path}/#{config}"
104
+ # puts results.inspect
105
+ return results
106
+ else
107
+ return config
108
+ end
109
+ end
110
+
111
+ # expand a hash by cycling throw all the hash values
112
+ def self.expand_hash(config, base_path)
113
+ # puts "Expanding Hash: #{config.inspect}"
114
+ new_config = {}
115
+ config.each do |key, val|
116
+ new_config[key] = expand(val, base_path)
117
+ end
118
+ return new_config
119
+ end
120
+
121
+ # expand an array by cycling through all the values
122
+ def self.expand_array(config, base_path)
123
+ # puts "Expanding Array: #{config.inspect}"
124
+ new_config = []
125
+ config.each do |val|
126
+ new_val = expand(val, base_path)
127
+ if new_val.is_a?(Array)
128
+ new_val.each do |inner|
129
+ new_config << inner
130
+ end
131
+ else
132
+ new_config << new_val
133
+ end
134
+ end
135
+ return new_config.uniq
136
+ end
137
+
138
+ # Cycles through the array of single element hashes
139
+ # and deep merges any duplicates it finds
140
+ #
141
+ # This is needed so you can define stylesheet keys
142
+ # in multiple config files
143
+ def self.merge_assets(list)
144
+ assets = Array(list).map do |i|
145
+ if i.is_a?(OpenStruct)
146
+ i.marshal_dump
147
+ else
148
+ i
149
+ end
150
+ end
151
+
152
+ # filter out the duplicate single hash keys
153
+ hash_keys = assets.select{|i| i.is_a?(Hash) and i.keys.size == 1}.group_by{|i| i.keys[0]}
154
+ hash_keys.each do |key, value|
155
+ if Array(value).size > 1
156
+ merged = value.inject({}){|merged, v| DeepMerge.deep_merge!(v,merged)}
157
+ value[0].replace(merged)
158
+ value[1..-1].each do |v|
159
+ v.clear
160
+ end
161
+ end
162
+ end
163
+
164
+ assets.select{|i| !i.blank? }
165
+ end
166
+
167
+ end
168
+ end
@@ -0,0 +1,181 @@
1
+ module DeepMerge
2
+
3
+ class InvalidParameter < StandardError; end
4
+
5
+ DEFAULT_FIELD_KNOCKOUT_PREFIX = '--'
6
+
7
+ # Deep Merge core documentation.
8
+ # deep_merge! method permits merging of arbitrary child elements. The two top level
9
+ # elements must be hashes. These hashes can contain unlimited (to stack limit) levels
10
+ # of child elements. These child elements to not have to be of the same types.
11
+ # Where child elements are of the same type, deep_merge will attempt to merge them together.
12
+ # Where child elements are not of the same type, deep_merge will skip or optionally overwrite
13
+ # the destination element with the contents of the source element at that level.
14
+ # So if you have two hashes like this:
15
+ # source = {:x => [1,2,3], :y => 2}
16
+ # dest = {:x => [4,5,'6'], :y => [7,8,9]}
17
+ # dest.deep_merge!(source)
18
+ # Results: {:x => [1,2,3,4,5,'6'], :y => 2}
19
+ # By default, "deep_merge!" will overwrite any unmergeables and merge everything else.
20
+ # To avoid this, use "deep_merge" (no bang/exclamation mark)
21
+ #
22
+ # Options:
23
+ # Options are specified in the last parameter passed, which should be in hash format:
24
+ # hash.deep_merge!({:x => [1,2]}, {:knockout_prefix => '--'})
25
+ # :preserve_unmergeables DEFAULT: false
26
+ # Set to true to skip any unmergeable elements from source
27
+ # :knockout_prefix DEFAULT: nil
28
+ # Set to string value to signify prefix which deletes elements from existing element
29
+ # :sort_merged_arrays DEFAULT: false
30
+ # Set to true to sort all arrays that are merged together
31
+ # :unpack_arrays DEFAULT: nil
32
+ # Set to string value to run "Array::join" then "String::split" against all arrays
33
+ # :merge_debug DEFAULT: false
34
+ # Set to true to get console output of merge process for debugging
35
+ #
36
+ # Selected Options Details:
37
+ # :knockout_prefix => The purpose of this is to provide a way to remove elements
38
+ # from existing Hash by specifying them in a special way in incoming hash
39
+ # source = {:x => ['--1', '2']}
40
+ # dest = {:x => ['1', '3']}
41
+ # dest.ko_deep_merge!(source)
42
+ # Results: {:x => ['2','3']}
43
+ # Additionally, if the knockout_prefix is passed alone as a string, it will cause
44
+ # the entire element to be removed:
45
+ # source = {:x => '--'}
46
+ # dest = {:x => [1,2,3]}
47
+ # dest.ko_deep_merge!(source)
48
+ # Results: {:x => ""}
49
+ # :unpack_arrays => The purpose of this is to permit compound elements to be passed
50
+ # in as strings and to be converted into discrete array elements
51
+ # irsource = {:x => ['1,2,3', '4']}
52
+ # dest = {:x => ['5','6','7,8']}
53
+ # dest.deep_merge!(source, {:unpack_arrays => ','})
54
+ # Results: {:x => ['1','2','3','4','5','6','7','8'}
55
+ # Why: If receiving data from an HTML form, this makes it easy for a checkbox
56
+ # to pass multiple values from within a single HTML element
57
+ #
58
+ # There are many tests for this library - and you can learn more about the features
59
+ # and usages of deep_merge! by just browsing the test examples
60
+ def DeepMerge.deep_merge!(source, dest, options = {})
61
+ # turn on this line for stdout debugging text
62
+ merge_debug = options[:merge_debug] || false
63
+ overwrite_unmergeable = !options[:preserve_unmergeables]
64
+ knockout_prefix = options[:knockout_prefix] || nil
65
+ if knockout_prefix == ""; raise InvalidParameter, "knockout_prefix cannot be an empty string in deep_merge!"; end
66
+ if knockout_prefix && !overwrite_unmergeable; raise InvalidParameter, "overwrite_unmergeable must be true if knockout_prefix is specified in deep_merge!"; end
67
+ # if present: we will split and join arrays on this char before merging
68
+ array_split_char = options[:unpack_arrays] || false
69
+ # request that we sort together any arrays when they are merged
70
+ sort_merged_arrays = options[:sort_merged_arrays] || false
71
+ di = options[:debug_indent] || ''
72
+ # do nothing if source is nil
73
+ if source.nil? || (!source.is_a?(FalseClass) && source.respond_to?(:blank?) && source.blank?); return dest; end
74
+ # if dest doesn't exist, then simply copy source to it
75
+ if dest.nil? && overwrite_unmergeable; dest = source; return dest; end
76
+
77
+ puts "#{di}Source class: #{source.class.inspect} :: Dest class: #{dest.class.inspect}" if merge_debug
78
+ if source.kind_of?(Hash)
79
+ puts "#{di}Hashes: #{source.inspect} :: #{dest.inspect}" if merge_debug
80
+ source.each do |src_key, src_value|
81
+ if dest.kind_of?(Hash)
82
+ puts "#{di} looping: #{src_key.inspect} => #{src_value.inspect} :: #{dest.inspect}" if merge_debug
83
+ if !dest[src_key].nil?
84
+ puts "#{di} ==>merging: #{src_key.inspect} => #{src_value.inspect} :: #{dest[src_key].inspect}" if merge_debug
85
+ dest[src_key] = deep_merge!(src_value, dest[src_key], options.merge(:debug_indent => di + ' '))
86
+ else # dest[src_key] doesn't exist so we want to create and overwrite it (but we do this via deep_merge!)
87
+ puts "#{di} ==>merging over: #{src_key.inspect} => #{src_value.inspect}" if merge_debug
88
+ # note: we rescue here b/c some classes respond to "dup" but don't implement it (Numeric, TrueClass, FalseClass, NilClass among maybe others)
89
+ begin
90
+ src_dup = src_value.dup # we dup src_value if possible because we're going to merge into it (since dest is empty)
91
+ rescue TypeError
92
+ src_dup = src_value
93
+ end
94
+ dest[src_key] = deep_merge!(src_value, src_dup, options.merge(:debug_indent => di + ' '))
95
+ end
96
+ else # dest isn't a hash, so we overwrite it completely (if permitted)
97
+ if overwrite_unmergeable
98
+ puts "#{di} overwriting dest: #{src_key.inspect} => #{src_value.inspect} -over-> #{dest.inspect}" if merge_debug
99
+ dest = overwrite_unmergeables(source, dest, options)
100
+ end
101
+ end
102
+ end
103
+ elsif source.kind_of?(Array)
104
+ puts "#{di}Arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
105
+ # if we are instructed, join/split any source arrays before processing
106
+ if array_split_char
107
+ puts "#{di} split/join on source: #{source.inspect}" if merge_debug
108
+ source = source.join(array_split_char).split(array_split_char)
109
+ if dest.kind_of?(Array); dest = dest.join(array_split_char).split(array_split_char); end
110
+ end
111
+ # if there's a naked knockout_prefix in source, that means we are to truncate dest
112
+ if source.index(knockout_prefix); dest = clear_or_nil(dest); source.delete(knockout_prefix); end
113
+ if dest.kind_of?(Array)
114
+ if knockout_prefix
115
+ print "#{di} knocking out: " if merge_debug
116
+ # remove knockout prefix items from both source and dest
117
+ source.delete_if do |ko_item|
118
+ retval = false
119
+ item = ko_item.respond_to?(:gsub) ? ko_item.gsub(%r{^#{knockout_prefix}}, "") : ko_item
120
+ if item != ko_item
121
+ print "#{ko_item} - " if merge_debug
122
+ dest.delete(item)
123
+ dest.delete(ko_item)
124
+ retval = true
125
+ end
126
+ retval
127
+ end
128
+ puts if merge_debug
129
+ end
130
+ puts "#{di} merging arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
131
+ dest = dest | source
132
+ if sort_merged_arrays; dest.sort!; end
133
+ elsif overwrite_unmergeable
134
+ puts "#{di} overwriting dest: #{source.inspect} -over-> #{dest.inspect}" if merge_debug
135
+ dest = overwrite_unmergeables(source, dest, options)
136
+ end
137
+ else # src_hash is not an array or hash, so we'll have to overwrite dest
138
+ puts "#{di}Others: #{source.inspect} :: #{dest.inspect}" if merge_debug
139
+ dest = overwrite_unmergeables(source, dest, options)
140
+ end
141
+ puts "#{di}Returning #{dest.inspect}" if merge_debug
142
+ dest
143
+ end # deep_merge!
144
+
145
+ # allows deep_merge! to uniformly handle overwriting of unmergeable entities
146
+ def DeepMerge::overwrite_unmergeables(source, dest, options)
147
+ merge_debug = options[:merge_debug] || false
148
+ overwrite_unmergeable = !options[:preserve_unmergeables]
149
+ knockout_prefix = options[:knockout_prefix] || false
150
+ di = options[:debug_indent] || ''
151
+ if knockout_prefix && overwrite_unmergeable
152
+ if source.kind_of?(String) # remove knockout string from source before overwriting dest
153
+ src_tmp = source.gsub(%r{^#{knockout_prefix}},"")
154
+ elsif source.kind_of?(Array) # remove all knockout elements before overwriting dest
155
+ src_tmp = source.delete_if {|ko_item| ko_item.kind_of?(String) && ko_item.match(%r{^#{knockout_prefix}}) }
156
+ else
157
+ src_tmp = source
158
+ end
159
+ if src_tmp == source # if we didn't find a knockout_prefix then we just overwrite dest
160
+ puts "#{di}#{src_tmp.inspect} -over-> #{dest.inspect}" if merge_debug
161
+ dest = src_tmp
162
+ else # if we do find a knockout_prefix, then we just delete dest
163
+ puts "#{di}\"\" -over-> #{dest.inspect}" if merge_debug
164
+ dest = ""
165
+ end
166
+ elsif overwrite_unmergeable
167
+ dest = source
168
+ end
169
+ dest
170
+ end
171
+
172
+ def DeepMerge::clear_or_nil(obj)
173
+ if obj.respond_to?(:clear)
174
+ obj.clear
175
+ else
176
+ obj = nil
177
+ end
178
+ obj
179
+ end
180
+
181
+ end # module DeepMerge
@@ -0,0 +1,74 @@
1
+ module ApplicationConfig
2
+ module ViewHelpers
3
+ def javascripts_from_config(options = {})
4
+ html = ""
5
+ only = [options.delete(:only)].flatten.compact.map{|i| i.to_s}
6
+ if defined?(AppConfig) and AppConfig.javascripts
7
+
8
+ ConfigBuilder.merge_assets(AppConfig.javascripts).each do |javascript|
9
+ if javascript.is_a? Hash
10
+ javascript.each do |key, val|
11
+ next unless only.empty? || only.include?(key.to_s)
12
+
13
+ args = [val].flatten
14
+ args = args.map{|s| s.gsub("javascripts/", AppConfig.javascript_path)} if AppConfig.javascript_path
15
+ if defined?(Merb)
16
+ args << options.merge(:bundle => key.to_sym)
17
+ html << js_include_tag(*args).to_s
18
+ elsif defined?(Rails)
19
+ args << options.merge(:cache => key.to_s)
20
+ html << javascript_include_tag(*args).to_s
21
+ end
22
+ html << "\n"
23
+ end
24
+ else
25
+ args = [javascript].flatten
26
+ args = args.map{|s| s.gsub("javascripts/", AppConfig.javascript_path)} if AppConfig.javascript_path
27
+ args << options
28
+ if defined?(Merb)
29
+ html << js_include_tag(*args).to_s
30
+ elsif defined?(Rails)
31
+ html << javascript_include_tag(*args).to_s
32
+ end
33
+ end
34
+ end
35
+ end
36
+ return html
37
+ end
38
+
39
+ def stylesheets_from_config(options = {})
40
+ html = ""
41
+ only = [options.delete(:only)].flatten.compact.map{|i| i.to_s}
42
+ if defined?(AppConfig) and AppConfig.stylesheets
43
+ ConfigBuilder.merge_assets(AppConfig.stylesheets).each do |stylesheet|
44
+ if stylesheet.is_a? Hash
45
+ stylesheet.each do |key, val|
46
+ next unless only.empty? || only.include?(key.to_s)
47
+
48
+ args = [val].flatten
49
+ args = args.map{|s| s.gsub("stylesheets/", AppConfig.stylesheet_path)} if AppConfig.stylesheet_path
50
+ if defined?(Merb)
51
+ args << options.merge(:bundle => key.to_sym)
52
+ html << css_include_tag(*args).to_s
53
+ elsif defined?(Rails)
54
+ args << options.merge(:cache => key.to_s)
55
+ html << stylesheet_link_tag(*args).to_s
56
+ end
57
+ end
58
+ else
59
+ args = [stylesheet].flatten
60
+ args = args.map{|s| s.gsub("stylesheets/", AppConfig.stylesheet_path)} if AppConfig.stylesheet_path
61
+ args << options
62
+ if defined?(Merb)
63
+ html << css_include_tag(*args).to_s
64
+ elsif defined?(Rails)
65
+ html << stylesheet_link_tag(*args).to_s
66
+ end
67
+ end
68
+ html << "\n"
69
+ end
70
+ end
71
+ return html
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,5 @@
1
+ require 'application_config/deep_merge' unless defined?(DeepMerge)
2
+ require 'application_config/config_builder'
3
+ require 'application_config/view_helpers'
4
+
5
+ require 'rails_app_config/railtie'
@@ -0,0 +1,17 @@
1
+ if defined?(Rails::Railtie)
2
+ module RailsAppConfig
3
+ class Railtie < Rails::Railtie
4
+ initializer :setup_app_config do
5
+ ::AppConfig = ApplicationConfig::ConfigBuilder.load_files(
6
+ :paths => [
7
+ Rails.root.join("config", "app_config.yml").to_s,
8
+ Rails.root.join("config", "app_config", "settings.yml").to_s,
9
+ Rails.root.join("config", "app_config", "#{Rails.env}.yml").to_s,
10
+ Rails.root.join("config", "environments", "#{Rails.env}.yml").to_s
11
+ ],
12
+ :root_path => Rails.root
13
+ )
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ namespace :app_config do
2
+ desc "Create a blank config/app_config.yml file"
3
+ task :init do
4
+ puts "Setting up AppConfig files..."
5
+ `mkdir -p config/app_config`
6
+
7
+ ["config/app_config.yml",
8
+ "config/app_config/development.yml",
9
+ "config/app_config/production.yml"
10
+ ].each do |path|
11
+ `touch #{path}`
12
+ puts "Created: #{path}"
13
+ end
14
+ puts "Complete!"
15
+ puts "Add key/value pairs to your yaml file,\nthen access them in your Merb project via AppConfig.[key]"
16
+ end
17
+ end
@@ -0,0 +1,88 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'extlib'
4
+ require File.dirname(__FILE__)+'/../lib/application_config/config_builder'
5
+ require File.dirname(__FILE__)+'/../lib/application_config/deep_merge'
6
+
7
+ class ConfigBuilderTest < Test::Unit::TestCase
8
+ def setup
9
+ @settings_path = File.dirname(__FILE__)+"/test_configs"
10
+ end
11
+
12
+ def test_missing_files
13
+ files = ["#{@settings_path}/empty1.yml", "#{@settings_path}/empty2.yml"]
14
+ config = ApplicationConfig::ConfigBuilder.load_files(:paths => files)
15
+ assert_equal OpenStruct.new, config
16
+ end
17
+
18
+ def test_empty_files
19
+ files = ["#{@settings_path}/empty1.yml", "#{@settings_path}/empty2.yml"]
20
+ config = ApplicationConfig::ConfigBuilder.load_files(:paths => files)
21
+ assert_equal OpenStruct.new, config
22
+ end
23
+
24
+ def test_common
25
+ config = ApplicationConfig::ConfigBuilder.load_files(:paths => "#{@settings_path}/app_config.yml")
26
+ assert_equal 1, config.size
27
+ assert_equal 'google.com', config.server
28
+ end
29
+
30
+ def test_environment_override
31
+ config = ApplicationConfig::ConfigBuilder.load_files(:paths => ["#{@settings_path}/app_config.yml", "#{@settings_path}/development.yml"])
32
+ assert_equal 2, config.size
33
+ assert_equal 'google.com', config.server
34
+ end
35
+
36
+ def test_nested
37
+ config = ApplicationConfig::ConfigBuilder.load_files(:paths => ["#{@settings_path}/development.yml"])
38
+ assert_equal 3, config.section.size
39
+ end
40
+
41
+ def test_array
42
+ config = ApplicationConfig::ConfigBuilder.load_files(:paths => "#{@settings_path}/development.yml")
43
+ assert_equal 'yahoo.com', config.section.servers[0].name
44
+ assert_equal 'amazon.com', config.section.servers[1].name
45
+ end
46
+
47
+ def test_erb
48
+ config = ApplicationConfig::ConfigBuilder.load_files(:paths => "#{@settings_path}/development.yml")
49
+ assert_equal 6, config.computed
50
+ end
51
+
52
+ def test_merge_hashes_from_multiple_configs
53
+ config = ApplicationConfig::ConfigBuilder.load_files(:paths => ["#{@settings_path}/deep_merge/config1.yml", "#{@settings_path}/deep_merge/config2.yml"])
54
+
55
+ assert_equal 3, config.inner.marshal_dump.keys.size
56
+ assert_equal 3, config.inner2.inner2_inner.marshal_dump.keys.size
57
+ end
58
+
59
+
60
+ def test_merge_arrays_from_multiple_configs
61
+ config = ApplicationConfig::ConfigBuilder.load_files(:paths => ["#{@settings_path}/deep_merge/config1.yml", "#{@settings_path}/deep_merge/config2.yml"])
62
+ assert_equal 6, config.arraylist1.size
63
+ assert_equal 6, config.arraylist2.inner.size
64
+ end
65
+
66
+ def test_merge_assets
67
+ config = ApplicationConfig::ConfigBuilder.load_files(:paths => ["#{@settings_path}/deep_merge/config1.yml", "#{@settings_path}/deep_merge/config2.yml"])
68
+ merged = ApplicationConfig::ConfigBuilder.merge_assets(config.hash_array)
69
+
70
+ assert_equal 3, merged.size
71
+ assert_equal 6, merged.select{|i| i.is_a?(Hash)}.first[:inner].size
72
+ end
73
+
74
+ def test_merge_assets2
75
+ config = ApplicationConfig::ConfigBuilder.load_files(:paths => ["#{@settings_path}/deep_merge2/config1.yml", "#{@settings_path}/deep_merge2/config2.yml"])
76
+
77
+ assert_equal 500, config.tvrage.cache
78
+ assert_equal "http://url2", config.tvrage.service_url
79
+ end
80
+
81
+ def test_boolean_overrides
82
+ config = ApplicationConfig::ConfigBuilder.load_files(:paths => ["#{@settings_path}/bool_override/config1.yml", "#{@settings_path}/bool_override/config2.yml"])
83
+ assert_equal false, config.override_bool
84
+ assert_equal true, config.override_bool_opposite
85
+ end
86
+
87
+
88
+ end
@@ -0,0 +1,2 @@
1
+ size: 1
2
+ server: google.com
@@ -0,0 +1,2 @@
1
+ override_bool: true
2
+ override_bool_opposite: false
@@ -0,0 +1,2 @@
1
+ override_bool: false
2
+ override_bool_opposite: true
@@ -0,0 +1,28 @@
1
+ size: 1
2
+ server: google.com
3
+ inner:
4
+ something1: "blah1"
5
+ something2: "blah2"
6
+
7
+ inner2:
8
+ inner2_inner:
9
+ foo1: "blah1"
10
+
11
+
12
+ arraylist1:
13
+ - 1
14
+ - 2
15
+ - 3
16
+
17
+ arraylist2:
18
+ inner:
19
+ - 1
20
+ - 2
21
+ - 3
22
+
23
+ hash_array:
24
+ - 1
25
+ - inner:
26
+ - 1
27
+ - 2
28
+ - 3
@@ -0,0 +1,28 @@
1
+ server: google.com
2
+
3
+ inner:
4
+ something3: "blah3"
5
+
6
+ inner2:
7
+ inner2_inner:
8
+ foo2: "blah2"
9
+ foo3: "blah3"
10
+
11
+ arraylist1:
12
+ - 4
13
+ - 5
14
+ - 6
15
+
16
+
17
+ arraylist2:
18
+ inner:
19
+ - 4
20
+ - 5
21
+ - 6
22
+
23
+ hash_array:
24
+ - 2
25
+ - inner:
26
+ - 4
27
+ - 5
28
+ - 6
@@ -0,0 +1,3 @@
1
+ tvrage:
2
+ service_url: 'http://services.tvrage.com'
3
+ cache: 500
@@ -0,0 +1,2 @@
1
+ tvrage:
2
+ service_url: "http://url2"
@@ -0,0 +1,5 @@
1
+ size: 2
2
+ computed: <%= 1 + 2 + 3 %>
3
+ section:
4
+ size: 3
5
+ servers: [ {name: yahoo.com}, {name: amazon.com} ]
File without changes
File without changes
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_app_config
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Jacques Crocker
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-21 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Provides an easy to use Application Configuration object
22
+ email: railsjedi@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - LICENSE
29
+ - README
30
+ files:
31
+ - LICENSE
32
+ - README
33
+ - Rakefile
34
+ - VERSION
35
+ - lib/application_config/config_builder.rb
36
+ - lib/application_config/deep_merge.rb
37
+ - lib/application_config/view_helpers.rb
38
+ - lib/rails_app_config.rb
39
+ - lib/rails_app_config/railtie.rb
40
+ - lib/tasks/app_config.rake
41
+ - test/config_builder_test.rb
42
+ - test/test_configs/app_config.yml
43
+ - test/test_configs/bool_override/config1.yml
44
+ - test/test_configs/bool_override/config2.yml
45
+ - test/test_configs/deep_merge/config1.yml
46
+ - test/test_configs/deep_merge/config2.yml
47
+ - test/test_configs/deep_merge2/config1.yml
48
+ - test/test_configs/deep_merge2/config2.yml
49
+ - test/test_configs/development.yml
50
+ - test/test_configs/empty1.yml
51
+ - test/test_configs/empty2.yml
52
+ has_rdoc: true
53
+ homepage: http://github.com/railsjedi/rails_app_config
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options:
58
+ - --charset=UTF-8
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ requirements: []
76
+
77
+ rubyforge_project:
78
+ rubygems_version: 1.3.6
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: provides an AppConfig for rails3 that reads config/app_config.yml
82
+ test_files:
83
+ - test/config_builder_test.rb