rails_config 0.0.4 → 0.0.5
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/Gemfile +7 -0
- data/Gemfile.lock +30 -0
- data/Rakefile +4 -1
- data/VERSION +1 -1
- data/lib/rails_config.rb +3 -2
- data/lib/rails_config/railtie.rb +4 -7
- data/lib/rails_config/setting_builder.rb +61 -0
- data/lib/rails_config/vendor/deep_merge.rb +180 -0
- data/{test/test_configs → spec/fixtures}/bool_override/config1.yml +0 -0
- data/{test/test_configs → spec/fixtures}/bool_override/config2.yml +0 -0
- data/{test/test_configs → spec/fixtures}/deep_merge/config1.yml +0 -0
- data/{test/test_configs → spec/fixtures}/deep_merge/config2.yml +0 -0
- data/{test/test_configs → spec/fixtures}/deep_merge2/config1.yml +0 -0
- data/{test/test_configs → spec/fixtures}/deep_merge2/config2.yml +0 -0
- data/{test/test_configs → spec/fixtures}/development.yml +0 -1
- data/{test/test_configs → spec/fixtures}/empty1.yml +0 -0
- data/{test/test_configs → spec/fixtures}/empty2.yml +0 -0
- data/{test/test_configs/app_config.yml → spec/fixtures/settings.yml} +0 -0
- data/spec/fixtures/settings2.yml +1 -0
- data/spec/fixtures/with_erb.yml +4 -0
- data/spec/rails_config/setting_builder_spec.rb +109 -0
- data/spec/spec_helper.rb +25 -0
- metadata +43 -20
- data/lib/rails_config/settings/builder.rb +0 -170
- data/lib/rails_config/settings/deep_merge.rb +0 -185
- data/test/config_builder_test.rb +0 -90
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
GEM
|
|
2
|
+
remote: http://rubygems.org/
|
|
3
|
+
specs:
|
|
4
|
+
autotest (4.3.2)
|
|
5
|
+
columnize (0.3.1)
|
|
6
|
+
diff-lcs (1.1.2)
|
|
7
|
+
growl-glue (1.0.7)
|
|
8
|
+
linecache (0.43)
|
|
9
|
+
rspec (2.0.0.beta.19)
|
|
10
|
+
rspec-core (= 2.0.0.beta.19)
|
|
11
|
+
rspec-expectations (= 2.0.0.beta.19)
|
|
12
|
+
rspec-mocks (= 2.0.0.beta.19)
|
|
13
|
+
rspec-core (2.0.0.beta.19)
|
|
14
|
+
rspec-expectations (2.0.0.beta.19)
|
|
15
|
+
diff-lcs (>= 1.1.2)
|
|
16
|
+
rspec-mocks (2.0.0.beta.19)
|
|
17
|
+
ruby-debug (0.10.3)
|
|
18
|
+
columnize (>= 0.1)
|
|
19
|
+
ruby-debug-base (~> 0.10.3.0)
|
|
20
|
+
ruby-debug-base (0.10.3)
|
|
21
|
+
linecache (>= 0.3)
|
|
22
|
+
|
|
23
|
+
PLATFORMS
|
|
24
|
+
ruby
|
|
25
|
+
|
|
26
|
+
DEPENDENCIES
|
|
27
|
+
autotest
|
|
28
|
+
growl-glue
|
|
29
|
+
rspec (>= 2.0.0.beta.19)
|
|
30
|
+
ruby-debug
|
data/Rakefile
CHANGED
|
@@ -9,7 +9,10 @@ begin
|
|
|
9
9
|
s.homepage = "http://github.com/railsjedi/rails_config"
|
|
10
10
|
s.description = "Provides an easy to use Application Configuration object"
|
|
11
11
|
s.authors = ["Jacques Crocker"]
|
|
12
|
-
s.files = FileList["[A-Z]*", "{bin,generators,lib,
|
|
12
|
+
s.files = FileList["[A-Z]*", "{bin,generators,lib,spec}/**/*"]
|
|
13
|
+
|
|
14
|
+
s.add_development_dependency 'rspec', ">=2.0.0.beta.19"
|
|
15
|
+
|
|
13
16
|
end
|
|
14
17
|
Jeweler::GemcutterTasks.new
|
|
15
18
|
rescue LoadError
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.0.
|
|
1
|
+
0.0.5
|
data/lib/rails_config.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
require 'rails_config/
|
|
2
|
-
require '
|
|
1
|
+
require 'rails_config/vendor/deep_merge' unless defined?(DeepMerge)
|
|
2
|
+
require 'pathname'
|
|
3
3
|
|
|
4
|
+
require 'rails_config/setting_builder'
|
|
4
5
|
require 'rails_config/railtie'
|
data/lib/rails_config/railtie.rb
CHANGED
|
@@ -2,13 +2,10 @@ if defined?(Rails::Railtie)
|
|
|
2
2
|
module RailsConfig
|
|
3
3
|
class Railtie < Rails::Railtie
|
|
4
4
|
initializer :setup_rails_config do
|
|
5
|
-
::Settings = RailsConfig::
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Rails.root.join("config", "environments", "#{Rails.env}.yml").to_s
|
|
10
|
-
],
|
|
11
|
-
:root_path => Rails.root
|
|
5
|
+
::Settings = RailsConfig::SettingBuilder.load_files(
|
|
6
|
+
Rails.root.join("config", "settings.yml").to_s,
|
|
7
|
+
Rails.root.join("config", "settings", "#{Rails.env}.yml").to_s,
|
|
8
|
+
Rails.root.join("config", "environments", "#{Rails.env}.yml").to_s
|
|
12
9
|
)
|
|
13
10
|
end
|
|
14
11
|
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'ostruct'
|
|
2
|
+
require 'yaml'
|
|
3
|
+
require 'erb'
|
|
4
|
+
|
|
5
|
+
module RailsConfig
|
|
6
|
+
module SettingBuilder
|
|
7
|
+
@@load_paths = []
|
|
8
|
+
|
|
9
|
+
# 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
|
|
10
|
+
# if the first file if they exist in the first file.
|
|
11
|
+
def self.load_files(*files)
|
|
12
|
+
config = OpenStruct.new
|
|
13
|
+
|
|
14
|
+
@@load_paths = [files].flatten.compact.uniq
|
|
15
|
+
# add singleton method to our Settings that reloads its settings from the load_paths
|
|
16
|
+
def config.reload!
|
|
17
|
+
|
|
18
|
+
conf = {}
|
|
19
|
+
SettingBuilder.load_paths.to_a.each do |path|
|
|
20
|
+
file_conf = YAML.load(ERB.new(IO.read(path.to_s)).result) if path and File.exists?(path.to_s)
|
|
21
|
+
next unless file_conf
|
|
22
|
+
|
|
23
|
+
if conf.size > 0
|
|
24
|
+
DeepMerge.deep_merge!(file_conf, conf, :preserve_unmergeables => false)
|
|
25
|
+
else
|
|
26
|
+
conf = file_conf
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# load all the new values into the openstruct
|
|
31
|
+
marshal_load(RailsConfig::SettingBuilder.convert(conf).marshal_dump)
|
|
32
|
+
|
|
33
|
+
return self
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
config.reload!
|
|
37
|
+
return config
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.load_paths
|
|
41
|
+
@@load_paths
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Recursively converts Hashes to OpenStructs (including Hashes inside Arrays)
|
|
45
|
+
def self.convert(h) #:nodoc:
|
|
46
|
+
s = OpenStruct.new
|
|
47
|
+
h.each do |k, v|
|
|
48
|
+
s.new_ostruct_member(k)
|
|
49
|
+
if v.is_a?(Hash)
|
|
50
|
+
s.send( (k+'=').to_sym, convert(v))
|
|
51
|
+
elsif v.is_a?(Array)
|
|
52
|
+
converted_array = v.collect { |e| e.instance_of?(Hash) ? convert(e) : e }
|
|
53
|
+
s.send("#{k}=".to_sym, converted_array)
|
|
54
|
+
else
|
|
55
|
+
s.send("#{k}=".to_sym, v)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
s
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
module DeepMerge
|
|
2
|
+
class InvalidParameter < StandardError; end
|
|
3
|
+
|
|
4
|
+
DEFAULT_FIELD_KNOCKOUT_PREFIX = '--'
|
|
5
|
+
|
|
6
|
+
# Deep Merge core documentation.
|
|
7
|
+
# deep_merge! method permits merging of arbitrary child elements. The two top level
|
|
8
|
+
# elements must be hashes. These hashes can contain unlimited (to stack limit) levels
|
|
9
|
+
# of child elements. These child elements to not have to be of the same types.
|
|
10
|
+
# Where child elements are of the same type, deep_merge will attempt to merge them together.
|
|
11
|
+
# Where child elements are not of the same type, deep_merge will skip or optionally overwrite
|
|
12
|
+
# the destination element with the contents of the source element at that level.
|
|
13
|
+
# So if you have two hashes like this:
|
|
14
|
+
# source = {:x => [1,2,3], :y => 2}
|
|
15
|
+
# dest = {:x => [4,5,'6'], :y => [7,8,9]}
|
|
16
|
+
# dest.deep_merge!(source)
|
|
17
|
+
# Results: {:x => [1,2,3,4,5,'6'], :y => 2}
|
|
18
|
+
# By default, "deep_merge!" will overwrite any unmergeables and merge everything else.
|
|
19
|
+
# To avoid this, use "deep_merge" (no bang/exclamation mark)
|
|
20
|
+
#
|
|
21
|
+
# Options:
|
|
22
|
+
# Options are specified in the last parameter passed, which should be in hash format:
|
|
23
|
+
# hash.deep_merge!({:x => [1,2]}, {:knockout_prefix => '--'})
|
|
24
|
+
# :preserve_unmergeables DEFAULT: false
|
|
25
|
+
# Set to true to skip any unmergeable elements from source
|
|
26
|
+
# :knockout_prefix DEFAULT: nil
|
|
27
|
+
# Set to string value to signify prefix which deletes elements from existing element
|
|
28
|
+
# :sort_merged_arrays DEFAULT: false
|
|
29
|
+
# Set to true to sort all arrays that are merged together
|
|
30
|
+
# :unpack_arrays DEFAULT: nil
|
|
31
|
+
# Set to string value to run "Array::join" then "String::split" against all arrays
|
|
32
|
+
# :merge_debug DEFAULT: false
|
|
33
|
+
# Set to true to get console output of merge process for debugging
|
|
34
|
+
#
|
|
35
|
+
# Selected Options Details:
|
|
36
|
+
# :knockout_prefix => The purpose of this is to provide a way to remove elements
|
|
37
|
+
# from existing Hash by specifying them in a special way in incoming hash
|
|
38
|
+
# source = {:x => ['--1', '2']}
|
|
39
|
+
# dest = {:x => ['1', '3']}
|
|
40
|
+
# dest.ko_deep_merge!(source)
|
|
41
|
+
# Results: {:x => ['2','3']}
|
|
42
|
+
# Additionally, if the knockout_prefix is passed alone as a string, it will cause
|
|
43
|
+
# the entire element to be removed:
|
|
44
|
+
# source = {:x => '--'}
|
|
45
|
+
# dest = {:x => [1,2,3]}
|
|
46
|
+
# dest.ko_deep_merge!(source)
|
|
47
|
+
# Results: {:x => ""}
|
|
48
|
+
# :unpack_arrays => The purpose of this is to permit compound elements to be passed
|
|
49
|
+
# in as strings and to be converted into discrete array elements
|
|
50
|
+
# irsource = {:x => ['1,2,3', '4']}
|
|
51
|
+
# dest = {:x => ['5','6','7,8']}
|
|
52
|
+
# dest.deep_merge!(source, {:unpack_arrays => ','})
|
|
53
|
+
# Results: {:x => ['1','2','3','4','5','6','7','8'}
|
|
54
|
+
# Why: If receiving data from an HTML form, this makes it easy for a checkbox
|
|
55
|
+
# to pass multiple values from within a single HTML element
|
|
56
|
+
#
|
|
57
|
+
# There are many tests for this library - and you can learn more about the features
|
|
58
|
+
# and usages of deep_merge! by just browsing the test examples
|
|
59
|
+
def DeepMerge.deep_merge!(source, dest, options = {})
|
|
60
|
+
# turn on this line for stdout debugging text
|
|
61
|
+
merge_debug = options[:merge_debug] || false
|
|
62
|
+
overwrite_unmergeable = !options[:preserve_unmergeables]
|
|
63
|
+
knockout_prefix = options[:knockout_prefix] || nil
|
|
64
|
+
if knockout_prefix == ""; raise InvalidParameter, "knockout_prefix cannot be an empty string in deep_merge!"; end
|
|
65
|
+
if knockout_prefix && !overwrite_unmergeable; raise InvalidParameter, "overwrite_unmergeable must be true if knockout_prefix is specified in deep_merge!"; end
|
|
66
|
+
# if present: we will split and join arrays on this char before merging
|
|
67
|
+
array_split_char = options[:unpack_arrays] || false
|
|
68
|
+
# request that we sort together any arrays when they are merged
|
|
69
|
+
sort_merged_arrays = options[:sort_merged_arrays] || false
|
|
70
|
+
di = options[:debug_indent] || ''
|
|
71
|
+
# do nothing if source is nil
|
|
72
|
+
if source.nil? || (!source.is_a?(FalseClass) && source.respond_to?(:blank?) && source.blank?); return dest; end
|
|
73
|
+
# if dest doesn't exist, then simply copy source to it
|
|
74
|
+
if dest.nil? && overwrite_unmergeable; dest = source; return dest; end
|
|
75
|
+
|
|
76
|
+
puts "#{di}Source class: #{source.class.inspect} :: Dest class: #{dest.class.inspect}" if merge_debug
|
|
77
|
+
if source.kind_of?(Hash)
|
|
78
|
+
puts "#{di}Hashes: #{source.inspect} :: #{dest.inspect}" if merge_debug
|
|
79
|
+
source.each do |src_key, src_value|
|
|
80
|
+
if dest.kind_of?(Hash)
|
|
81
|
+
puts "#{di} looping: #{src_key.inspect} => #{src_value.inspect} :: #{dest.inspect}" if merge_debug
|
|
82
|
+
if !dest[src_key].nil?
|
|
83
|
+
puts "#{di} ==>merging: #{src_key.inspect} => #{src_value.inspect} :: #{dest[src_key].inspect}" if merge_debug
|
|
84
|
+
dest[src_key] = deep_merge!(src_value, dest[src_key], options.merge(:debug_indent => di + ' '))
|
|
85
|
+
else # dest[src_key] doesn't exist so we want to create and overwrite it (but we do this via deep_merge!)
|
|
86
|
+
puts "#{di} ==>merging over: #{src_key.inspect} => #{src_value.inspect}" if merge_debug
|
|
87
|
+
# note: we rescue here b/c some classes respond to "dup" but don't implement it (Numeric, TrueClass, FalseClass, NilClass among maybe others)
|
|
88
|
+
begin
|
|
89
|
+
src_dup = src_value.dup # we dup src_value if possible because we're going to merge into it (since dest is empty)
|
|
90
|
+
rescue TypeError
|
|
91
|
+
src_dup = src_value
|
|
92
|
+
end
|
|
93
|
+
dest[src_key] = deep_merge!(src_value, src_dup, options.merge(:debug_indent => di + ' '))
|
|
94
|
+
end
|
|
95
|
+
else # dest isn't a hash, so we overwrite it completely (if permitted)
|
|
96
|
+
if overwrite_unmergeable
|
|
97
|
+
puts "#{di} overwriting dest: #{src_key.inspect} => #{src_value.inspect} -over-> #{dest.inspect}" if merge_debug
|
|
98
|
+
dest = overwrite_unmergeables(source, dest, options)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
elsif source.kind_of?(Array)
|
|
103
|
+
puts "#{di}Arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
|
|
104
|
+
# if we are instructed, join/split any source arrays before processing
|
|
105
|
+
if array_split_char
|
|
106
|
+
puts "#{di} split/join on source: #{source.inspect}" if merge_debug
|
|
107
|
+
source = source.join(array_split_char).split(array_split_char)
|
|
108
|
+
if dest.kind_of?(Array); dest = dest.join(array_split_char).split(array_split_char); end
|
|
109
|
+
end
|
|
110
|
+
# if there's a naked knockout_prefix in source, that means we are to truncate dest
|
|
111
|
+
if source.index(knockout_prefix); dest = clear_or_nil(dest); source.delete(knockout_prefix); end
|
|
112
|
+
if dest.kind_of?(Array)
|
|
113
|
+
if knockout_prefix
|
|
114
|
+
print "#{di} knocking out: " if merge_debug
|
|
115
|
+
# remove knockout prefix items from both source and dest
|
|
116
|
+
source.delete_if do |ko_item|
|
|
117
|
+
retval = false
|
|
118
|
+
item = ko_item.respond_to?(:gsub) ? ko_item.gsub(%r{^#{knockout_prefix}}, "") : ko_item
|
|
119
|
+
if item != ko_item
|
|
120
|
+
print "#{ko_item} - " if merge_debug
|
|
121
|
+
dest.delete(item)
|
|
122
|
+
dest.delete(ko_item)
|
|
123
|
+
retval = true
|
|
124
|
+
end
|
|
125
|
+
retval
|
|
126
|
+
end
|
|
127
|
+
puts if merge_debug
|
|
128
|
+
end
|
|
129
|
+
puts "#{di} merging arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
|
|
130
|
+
dest = dest | source
|
|
131
|
+
if sort_merged_arrays; dest.sort!; end
|
|
132
|
+
elsif overwrite_unmergeable
|
|
133
|
+
puts "#{di} overwriting dest: #{source.inspect} -over-> #{dest.inspect}" if merge_debug
|
|
134
|
+
dest = overwrite_unmergeables(source, dest, options)
|
|
135
|
+
end
|
|
136
|
+
else # src_hash is not an array or hash, so we'll have to overwrite dest
|
|
137
|
+
puts "#{di}Others: #{source.inspect} :: #{dest.inspect}" if merge_debug
|
|
138
|
+
dest = overwrite_unmergeables(source, dest, options)
|
|
139
|
+
end
|
|
140
|
+
puts "#{di}Returning #{dest.inspect}" if merge_debug
|
|
141
|
+
dest
|
|
142
|
+
end # deep_merge!
|
|
143
|
+
|
|
144
|
+
# allows deep_merge! to uniformly handle overwriting of unmergeable entities
|
|
145
|
+
def DeepMerge::overwrite_unmergeables(source, dest, options)
|
|
146
|
+
merge_debug = options[:merge_debug] || false
|
|
147
|
+
overwrite_unmergeable = !options[:preserve_unmergeables]
|
|
148
|
+
knockout_prefix = options[:knockout_prefix] || false
|
|
149
|
+
di = options[:debug_indent] || ''
|
|
150
|
+
if knockout_prefix && overwrite_unmergeable
|
|
151
|
+
if source.kind_of?(String) # remove knockout string from source before overwriting dest
|
|
152
|
+
src_tmp = source.gsub(%r{^#{knockout_prefix}},"")
|
|
153
|
+
elsif source.kind_of?(Array) # remove all knockout elements before overwriting dest
|
|
154
|
+
src_tmp = source.delete_if {|ko_item| ko_item.kind_of?(String) && ko_item.match(%r{^#{knockout_prefix}}) }
|
|
155
|
+
else
|
|
156
|
+
src_tmp = source
|
|
157
|
+
end
|
|
158
|
+
if src_tmp == source # if we didn't find a knockout_prefix then we just overwrite dest
|
|
159
|
+
puts "#{di}#{src_tmp.inspect} -over-> #{dest.inspect}" if merge_debug
|
|
160
|
+
dest = src_tmp
|
|
161
|
+
else # if we do find a knockout_prefix, then we just delete dest
|
|
162
|
+
puts "#{di}\"\" -over-> #{dest.inspect}" if merge_debug
|
|
163
|
+
dest = ""
|
|
164
|
+
end
|
|
165
|
+
elsif overwrite_unmergeable
|
|
166
|
+
dest = source
|
|
167
|
+
end
|
|
168
|
+
dest
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def DeepMerge::clear_or_nil(obj)
|
|
172
|
+
if obj.respond_to?(:clear)
|
|
173
|
+
obj.clear
|
|
174
|
+
else
|
|
175
|
+
obj = nil
|
|
176
|
+
end
|
|
177
|
+
obj
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
end # module DeepMerge
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
another: "something"
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module RailsConfig
|
|
4
|
+
describe SettingBuilder do
|
|
5
|
+
|
|
6
|
+
it "should load a basic config file" do
|
|
7
|
+
config = SettingBuilder.load_files(setting_path("settings.yml"))
|
|
8
|
+
config.size.should == 1
|
|
9
|
+
config.server.should == "google.com"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should load 2 basic config files" do
|
|
13
|
+
config = SettingBuilder.load_files(setting_path("settings.yml"), setting_path("settings2.yml"))
|
|
14
|
+
config.size.should == 1
|
|
15
|
+
config.server.should == "google.com"
|
|
16
|
+
config.another.should == "something"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "should load empty config for a missing file path" do
|
|
20
|
+
config = SettingBuilder.load_files(setting_path("some_file_that_doesnt_exist.yml"))
|
|
21
|
+
config.should == OpenStruct.new
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should load an empty config for multiple missing file paths" do
|
|
25
|
+
files = [setting_path("doesnt_exist1.yml"), setting_path("doesnt_exist2.yml")]
|
|
26
|
+
config = SettingBuilder.load_files(files)
|
|
27
|
+
config.should == OpenStruct.new
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should load empty config for an empty setting file" do
|
|
31
|
+
config = SettingBuilder.load_files(setting_path("empty1.yml"))
|
|
32
|
+
config.should == OpenStruct.new
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "should load an empty config for multiple missing file paths" do
|
|
36
|
+
files = [setting_path("empty1.yml"), setting_path("empty2.yml")]
|
|
37
|
+
config = SettingBuilder.load_files(files)
|
|
38
|
+
config.should == OpenStruct.new
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should allow overrides" do
|
|
42
|
+
files = [setting_path("settings.yml"), setting_path("development.yml")]
|
|
43
|
+
config = SettingBuilder.load_files(files)
|
|
44
|
+
config.server.should == "google.com"
|
|
45
|
+
config.size.should == 2
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context "Nested Settings" do
|
|
49
|
+
let(:config) do
|
|
50
|
+
SettingBuilder.load_files(setting_path("development.yml"))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "should allow nested sections" do
|
|
54
|
+
config.section.size.should == 3
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "should allow configuration collections (arrays)" do
|
|
58
|
+
config.section.servers[0].name.should == "yahoo.com"
|
|
59
|
+
config.section.servers[1].name.should == "amazon.com"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context "Settings with ERB tags" do
|
|
64
|
+
let(:config) do
|
|
65
|
+
SettingBuilder.load_files(setting_path("with_erb.yml"))
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "should evaluate ERB tags" do
|
|
69
|
+
config.computed.should == 6
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "should evaluated nested ERB tags" do
|
|
73
|
+
config.section.computed1.should == 1
|
|
74
|
+
config.section.computed2.should == 2
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
context "Deep Merging" do
|
|
79
|
+
let(:config) do
|
|
80
|
+
files = [setting_path("deep_merge/config1.yml"), setting_path("deep_merge/config2.yml")]
|
|
81
|
+
SettingBuilder.load_files(files)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "should merge hashes from multiple configs" do
|
|
85
|
+
config.inner.marshal_dump.keys.size.should == 3
|
|
86
|
+
config.inner2.inner2_inner.marshal_dump.keys.size.should == 3
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "should merge arrays from multiple configs" do
|
|
90
|
+
config.arraylist1.size.should == 6
|
|
91
|
+
config.arraylist2.inner.size.should == 6
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
context "Boolean Overrides" do
|
|
96
|
+
let(:config) do
|
|
97
|
+
files = [setting_path("bool_override/config1.yml"), setting_path("bool_override/config2.yml")]
|
|
98
|
+
SettingBuilder.load_files(files)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "should allow overriding of bool settings" do
|
|
102
|
+
config.override_bool.should == false
|
|
103
|
+
config.override_bool_opposite.should == true
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
end
|
|
109
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'rails_config'
|
|
2
|
+
require "bundler"
|
|
3
|
+
Bundler.setup
|
|
4
|
+
|
|
5
|
+
def in_editor?
|
|
6
|
+
ENV.has_key?('TM_MODE') || ENV.has_key?('EMACS') || ENV.has_key?('VIM')
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
RSpec.configure do |c|
|
|
10
|
+
c.color_enabled = !in_editor?
|
|
11
|
+
c.run_all_when_everything_filtered = true
|
|
12
|
+
|
|
13
|
+
# setup fixtures path
|
|
14
|
+
c.before(:all) do
|
|
15
|
+
@fixture_path = Pathname.new(File.join(File.dirname(__FILE__), "/fixtures"))
|
|
16
|
+
raise "Fixture folder not found: #{@fixture_path}" unless @fixture_path.directory?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# returns the file path of a fixture setting file
|
|
20
|
+
def setting_path(filename)
|
|
21
|
+
@fixture_path.join(filename)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails_config
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
4
|
+
hash: 21
|
|
5
5
|
prerelease: false
|
|
6
6
|
segments:
|
|
7
7
|
- 0
|
|
8
8
|
- 0
|
|
9
|
-
-
|
|
10
|
-
version: 0.0.
|
|
9
|
+
- 5
|
|
10
|
+
version: 0.0.5
|
|
11
11
|
platform: ruby
|
|
12
12
|
authors:
|
|
13
13
|
- Jacques Crocker
|
|
@@ -15,10 +15,27 @@ autorequire:
|
|
|
15
15
|
bindir: bin
|
|
16
16
|
cert_chain: []
|
|
17
17
|
|
|
18
|
-
date: 2010-08-
|
|
18
|
+
date: 2010-08-08 00:00:00 -07:00
|
|
19
19
|
default_executable:
|
|
20
|
-
dependencies:
|
|
21
|
-
|
|
20
|
+
dependencies:
|
|
21
|
+
- !ruby/object:Gem::Dependency
|
|
22
|
+
name: rspec
|
|
23
|
+
prerelease: false
|
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
hash: 62196421
|
|
30
|
+
segments:
|
|
31
|
+
- 2
|
|
32
|
+
- 0
|
|
33
|
+
- 0
|
|
34
|
+
- beta
|
|
35
|
+
- 19
|
|
36
|
+
version: 2.0.0.beta.19
|
|
37
|
+
type: :development
|
|
38
|
+
version_requirements: *id001
|
|
22
39
|
description: Provides an easy to use Application Configuration object
|
|
23
40
|
email: railsjedi@gmail.com
|
|
24
41
|
executables: []
|
|
@@ -29,25 +46,30 @@ extra_rdoc_files:
|
|
|
29
46
|
- LICENSE
|
|
30
47
|
- README
|
|
31
48
|
files:
|
|
49
|
+
- Gemfile
|
|
50
|
+
- Gemfile.lock
|
|
32
51
|
- LICENSE
|
|
33
52
|
- README
|
|
34
53
|
- Rakefile
|
|
35
54
|
- VERSION
|
|
36
55
|
- lib/rails_config.rb
|
|
37
56
|
- lib/rails_config/railtie.rb
|
|
38
|
-
- lib/rails_config/
|
|
39
|
-
- lib/rails_config/
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
57
|
+
- lib/rails_config/setting_builder.rb
|
|
58
|
+
- lib/rails_config/vendor/deep_merge.rb
|
|
59
|
+
- spec/fixtures/bool_override/config1.yml
|
|
60
|
+
- spec/fixtures/bool_override/config2.yml
|
|
61
|
+
- spec/fixtures/deep_merge/config1.yml
|
|
62
|
+
- spec/fixtures/deep_merge/config2.yml
|
|
63
|
+
- spec/fixtures/deep_merge2/config1.yml
|
|
64
|
+
- spec/fixtures/deep_merge2/config2.yml
|
|
65
|
+
- spec/fixtures/development.yml
|
|
66
|
+
- spec/fixtures/empty1.yml
|
|
67
|
+
- spec/fixtures/empty2.yml
|
|
68
|
+
- spec/fixtures/settings.yml
|
|
69
|
+
- spec/fixtures/settings2.yml
|
|
70
|
+
- spec/fixtures/with_erb.yml
|
|
71
|
+
- spec/rails_config/setting_builder_spec.rb
|
|
72
|
+
- spec/spec_helper.rb
|
|
51
73
|
has_rdoc: true
|
|
52
74
|
homepage: http://github.com/railsjedi/rails_config
|
|
53
75
|
licenses: []
|
|
@@ -83,4 +105,5 @@ signing_key:
|
|
|
83
105
|
specification_version: 3
|
|
84
106
|
summary: provides an Settings for rails3 that reads config/settings.yml
|
|
85
107
|
test_files:
|
|
86
|
-
-
|
|
108
|
+
- spec/rails_config/setting_builder_spec.rb
|
|
109
|
+
- spec/spec_helper.rb
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
require 'ostruct'
|
|
2
|
-
require 'yaml'
|
|
3
|
-
require 'erb'
|
|
4
|
-
|
|
5
|
-
module RailsConfig
|
|
6
|
-
module Settings
|
|
7
|
-
# == Summary
|
|
8
|
-
# This is API documentation, NOT documentation on how to use this plugin. For that, see the README.
|
|
9
|
-
class Builder
|
|
10
|
-
@@load_paths = []
|
|
11
|
-
@@expand_keys = []
|
|
12
|
-
@@root_path = ""
|
|
13
|
-
|
|
14
|
-
# 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
|
|
15
|
-
# if the first file if they exist in the first file.
|
|
16
|
-
def self.load_files(options = {})
|
|
17
|
-
config = OpenStruct.new
|
|
18
|
-
|
|
19
|
-
@@load_paths = [options[:paths]].flatten.compact.uniq
|
|
20
|
-
@@expand_keys = [options[:expand_keys]].flatten.compact.uniq
|
|
21
|
-
@@root_path = options[:root_path]
|
|
22
|
-
|
|
23
|
-
# add singleton method to our Settings that reloads its settings from the load_paths options
|
|
24
|
-
def config.reload!
|
|
25
|
-
|
|
26
|
-
conf = {}
|
|
27
|
-
Builder.load_paths.to_a.each do |path|
|
|
28
|
-
file_conf = YAML.load(ERB.new(IO.read(path)).result) if path and File.exists?(path)
|
|
29
|
-
next unless file_conf
|
|
30
|
-
|
|
31
|
-
if conf.size > 0
|
|
32
|
-
DeepMerge.deep_merge!(file_conf, conf, :preserve_unmergeables => false)
|
|
33
|
-
else
|
|
34
|
-
conf = file_conf
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# expand the javascripts config to handle *.* paths
|
|
39
|
-
Builder.expand_keys.to_a.each do |expand_path|
|
|
40
|
-
expand_path = expand_path.to_s
|
|
41
|
-
if conf[expand_path]
|
|
42
|
-
conf[expand_path] = RailsConfig::Settings::Builder.expand(conf[expand_path], "#{Builder.root_path}/public/#{expand_path}")
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# load all the new values into the openstruct
|
|
47
|
-
marshal_load(RailsConfig::Settings::Builder.convert(conf).marshal_dump)
|
|
48
|
-
|
|
49
|
-
return self
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
config.reload!
|
|
53
|
-
return config
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def self.load_paths
|
|
57
|
-
@@load_paths
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def self.expand_keys
|
|
61
|
-
@@expand_keys
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def self.root_path
|
|
65
|
-
@@root_path
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# Recursively converts Hashes to OpenStructs (including Hashes inside Arrays)
|
|
69
|
-
def self.convert(h) #:nodoc:
|
|
70
|
-
s = OpenStruct.new
|
|
71
|
-
h.each do |k, v|
|
|
72
|
-
s.new_ostruct_member(k)
|
|
73
|
-
if v.is_a?(Hash)
|
|
74
|
-
s.send( (k+'=').to_sym, convert(v))
|
|
75
|
-
elsif v.is_a?(Array)
|
|
76
|
-
converted_array = v.collect { |e| e.instance_of?(Hash) ? convert(e) : e }
|
|
77
|
-
s.send("#{k}=".to_sym, converted_array)
|
|
78
|
-
else
|
|
79
|
-
s.send("#{k}=".to_sym, v)
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
s
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# expand a config val
|
|
86
|
-
def self.expand(config, base_path)
|
|
87
|
-
case config.class.to_s
|
|
88
|
-
when "Hash"
|
|
89
|
-
return expand_hash(config, base_path)
|
|
90
|
-
when "Array"
|
|
91
|
-
return expand_array(config, base_path)
|
|
92
|
-
when "String"
|
|
93
|
-
return expand_string(config, base_path)
|
|
94
|
-
end
|
|
95
|
-
return config
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# expand a string and returns a list
|
|
99
|
-
def self.expand_string(config, base_path)
|
|
100
|
-
# puts "Expanding String: #{config.inspect}"
|
|
101
|
-
if config.include?("*")
|
|
102
|
-
results = Dir["#{base_path}/#{config}"].map{|i| i.to_s.gsub("#{base_path}/", "") }
|
|
103
|
-
|
|
104
|
-
# puts "EXPANDED PATH: #{base_path}/#{config}"
|
|
105
|
-
# puts results.inspect
|
|
106
|
-
return results
|
|
107
|
-
else
|
|
108
|
-
return config
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
# expand a hash by cycling throw all the hash values
|
|
113
|
-
def self.expand_hash(config, base_path)
|
|
114
|
-
# puts "Expanding Hash: #{config.inspect}"
|
|
115
|
-
new_config = {}
|
|
116
|
-
config.each do |key, val|
|
|
117
|
-
new_config[key] = expand(val, base_path)
|
|
118
|
-
end
|
|
119
|
-
return new_config
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
# expand an array by cycling through all the values
|
|
123
|
-
def self.expand_array(config, base_path)
|
|
124
|
-
# puts "Expanding Array: #{config.inspect}"
|
|
125
|
-
new_config = []
|
|
126
|
-
config.each do |val|
|
|
127
|
-
new_val = expand(val, base_path)
|
|
128
|
-
if new_val.is_a?(Array)
|
|
129
|
-
new_val.each do |inner|
|
|
130
|
-
new_config << inner
|
|
131
|
-
end
|
|
132
|
-
else
|
|
133
|
-
new_config << new_val
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
return new_config.uniq
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
# Cycles through the array of single element hashes
|
|
140
|
-
# and deep merges any duplicates it finds
|
|
141
|
-
#
|
|
142
|
-
# This is needed so you can define stylesheet keys
|
|
143
|
-
# in multiple config files
|
|
144
|
-
def self.merge_assets(list)
|
|
145
|
-
assets = Array(list).map do |i|
|
|
146
|
-
if i.is_a?(OpenStruct)
|
|
147
|
-
i.marshal_dump
|
|
148
|
-
else
|
|
149
|
-
i
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
# filter out the duplicate single hash keys
|
|
154
|
-
hash_keys = assets.select{|i| i.is_a?(Hash) and i.keys.size == 1}.group_by{|i| i.keys[0]}
|
|
155
|
-
hash_keys.each do |key, value|
|
|
156
|
-
if Array(value).size > 1
|
|
157
|
-
merged = value.inject({}){|merged, v| DeepMerge.deep_merge!(v,merged)}
|
|
158
|
-
value[0].replace(merged)
|
|
159
|
-
value[1..-1].each do |v|
|
|
160
|
-
v.clear
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
assets.select{|i| !i.blank? }
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
end
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
module RailsConfig
|
|
2
|
-
module Settings
|
|
3
|
-
module DeepMerge
|
|
4
|
-
|
|
5
|
-
class InvalidParameter < StandardError; end
|
|
6
|
-
|
|
7
|
-
DEFAULT_FIELD_KNOCKOUT_PREFIX = '--'
|
|
8
|
-
|
|
9
|
-
# Deep Merge core documentation.
|
|
10
|
-
# deep_merge! method permits merging of arbitrary child elements. The two top level
|
|
11
|
-
# elements must be hashes. These hashes can contain unlimited (to stack limit) levels
|
|
12
|
-
# of child elements. These child elements to not have to be of the same types.
|
|
13
|
-
# Where child elements are of the same type, deep_merge will attempt to merge them together.
|
|
14
|
-
# Where child elements are not of the same type, deep_merge will skip or optionally overwrite
|
|
15
|
-
# the destination element with the contents of the source element at that level.
|
|
16
|
-
# So if you have two hashes like this:
|
|
17
|
-
# source = {:x => [1,2,3], :y => 2}
|
|
18
|
-
# dest = {:x => [4,5,'6'], :y => [7,8,9]}
|
|
19
|
-
# dest.deep_merge!(source)
|
|
20
|
-
# Results: {:x => [1,2,3,4,5,'6'], :y => 2}
|
|
21
|
-
# By default, "deep_merge!" will overwrite any unmergeables and merge everything else.
|
|
22
|
-
# To avoid this, use "deep_merge" (no bang/exclamation mark)
|
|
23
|
-
#
|
|
24
|
-
# Options:
|
|
25
|
-
# Options are specified in the last parameter passed, which should be in hash format:
|
|
26
|
-
# hash.deep_merge!({:x => [1,2]}, {:knockout_prefix => '--'})
|
|
27
|
-
# :preserve_unmergeables DEFAULT: false
|
|
28
|
-
# Set to true to skip any unmergeable elements from source
|
|
29
|
-
# :knockout_prefix DEFAULT: nil
|
|
30
|
-
# Set to string value to signify prefix which deletes elements from existing element
|
|
31
|
-
# :sort_merged_arrays DEFAULT: false
|
|
32
|
-
# Set to true to sort all arrays that are merged together
|
|
33
|
-
# :unpack_arrays DEFAULT: nil
|
|
34
|
-
# Set to string value to run "Array::join" then "String::split" against all arrays
|
|
35
|
-
# :merge_debug DEFAULT: false
|
|
36
|
-
# Set to true to get console output of merge process for debugging
|
|
37
|
-
#
|
|
38
|
-
# Selected Options Details:
|
|
39
|
-
# :knockout_prefix => The purpose of this is to provide a way to remove elements
|
|
40
|
-
# from existing Hash by specifying them in a special way in incoming hash
|
|
41
|
-
# source = {:x => ['--1', '2']}
|
|
42
|
-
# dest = {:x => ['1', '3']}
|
|
43
|
-
# dest.ko_deep_merge!(source)
|
|
44
|
-
# Results: {:x => ['2','3']}
|
|
45
|
-
# Additionally, if the knockout_prefix is passed alone as a string, it will cause
|
|
46
|
-
# the entire element to be removed:
|
|
47
|
-
# source = {:x => '--'}
|
|
48
|
-
# dest = {:x => [1,2,3]}
|
|
49
|
-
# dest.ko_deep_merge!(source)
|
|
50
|
-
# Results: {:x => ""}
|
|
51
|
-
# :unpack_arrays => The purpose of this is to permit compound elements to be passed
|
|
52
|
-
# in as strings and to be converted into discrete array elements
|
|
53
|
-
# irsource = {:x => ['1,2,3', '4']}
|
|
54
|
-
# dest = {:x => ['5','6','7,8']}
|
|
55
|
-
# dest.deep_merge!(source, {:unpack_arrays => ','})
|
|
56
|
-
# Results: {:x => ['1','2','3','4','5','6','7','8'}
|
|
57
|
-
# Why: If receiving data from an HTML form, this makes it easy for a checkbox
|
|
58
|
-
# to pass multiple values from within a single HTML element
|
|
59
|
-
#
|
|
60
|
-
# There are many tests for this library - and you can learn more about the features
|
|
61
|
-
# and usages of deep_merge! by just browsing the test examples
|
|
62
|
-
def DeepMerge.deep_merge!(source, dest, options = {})
|
|
63
|
-
# turn on this line for stdout debugging text
|
|
64
|
-
merge_debug = options[:merge_debug] || false
|
|
65
|
-
overwrite_unmergeable = !options[:preserve_unmergeables]
|
|
66
|
-
knockout_prefix = options[:knockout_prefix] || nil
|
|
67
|
-
if knockout_prefix == ""; raise InvalidParameter, "knockout_prefix cannot be an empty string in deep_merge!"; end
|
|
68
|
-
if knockout_prefix && !overwrite_unmergeable; raise InvalidParameter, "overwrite_unmergeable must be true if knockout_prefix is specified in deep_merge!"; end
|
|
69
|
-
# if present: we will split and join arrays on this char before merging
|
|
70
|
-
array_split_char = options[:unpack_arrays] || false
|
|
71
|
-
# request that we sort together any arrays when they are merged
|
|
72
|
-
sort_merged_arrays = options[:sort_merged_arrays] || false
|
|
73
|
-
di = options[:debug_indent] || ''
|
|
74
|
-
# do nothing if source is nil
|
|
75
|
-
if source.nil? || (!source.is_a?(FalseClass) && source.respond_to?(:blank?) && source.blank?); return dest; end
|
|
76
|
-
# if dest doesn't exist, then simply copy source to it
|
|
77
|
-
if dest.nil? && overwrite_unmergeable; dest = source; return dest; end
|
|
78
|
-
|
|
79
|
-
puts "#{di}Source class: #{source.class.inspect} :: Dest class: #{dest.class.inspect}" if merge_debug
|
|
80
|
-
if source.kind_of?(Hash)
|
|
81
|
-
puts "#{di}Hashes: #{source.inspect} :: #{dest.inspect}" if merge_debug
|
|
82
|
-
source.each do |src_key, src_value|
|
|
83
|
-
if dest.kind_of?(Hash)
|
|
84
|
-
puts "#{di} looping: #{src_key.inspect} => #{src_value.inspect} :: #{dest.inspect}" if merge_debug
|
|
85
|
-
if !dest[src_key].nil?
|
|
86
|
-
puts "#{di} ==>merging: #{src_key.inspect} => #{src_value.inspect} :: #{dest[src_key].inspect}" if merge_debug
|
|
87
|
-
dest[src_key] = deep_merge!(src_value, dest[src_key], options.merge(:debug_indent => di + ' '))
|
|
88
|
-
else # dest[src_key] doesn't exist so we want to create and overwrite it (but we do this via deep_merge!)
|
|
89
|
-
puts "#{di} ==>merging over: #{src_key.inspect} => #{src_value.inspect}" if merge_debug
|
|
90
|
-
# note: we rescue here b/c some classes respond to "dup" but don't implement it (Numeric, TrueClass, FalseClass, NilClass among maybe others)
|
|
91
|
-
begin
|
|
92
|
-
src_dup = src_value.dup # we dup src_value if possible because we're going to merge into it (since dest is empty)
|
|
93
|
-
rescue TypeError
|
|
94
|
-
src_dup = src_value
|
|
95
|
-
end
|
|
96
|
-
dest[src_key] = deep_merge!(src_value, src_dup, options.merge(:debug_indent => di + ' '))
|
|
97
|
-
end
|
|
98
|
-
else # dest isn't a hash, so we overwrite it completely (if permitted)
|
|
99
|
-
if overwrite_unmergeable
|
|
100
|
-
puts "#{di} overwriting dest: #{src_key.inspect} => #{src_value.inspect} -over-> #{dest.inspect}" if merge_debug
|
|
101
|
-
dest = overwrite_unmergeables(source, dest, options)
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
elsif source.kind_of?(Array)
|
|
106
|
-
puts "#{di}Arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
|
|
107
|
-
# if we are instructed, join/split any source arrays before processing
|
|
108
|
-
if array_split_char
|
|
109
|
-
puts "#{di} split/join on source: #{source.inspect}" if merge_debug
|
|
110
|
-
source = source.join(array_split_char).split(array_split_char)
|
|
111
|
-
if dest.kind_of?(Array); dest = dest.join(array_split_char).split(array_split_char); end
|
|
112
|
-
end
|
|
113
|
-
# if there's a naked knockout_prefix in source, that means we are to truncate dest
|
|
114
|
-
if source.index(knockout_prefix); dest = clear_or_nil(dest); source.delete(knockout_prefix); end
|
|
115
|
-
if dest.kind_of?(Array)
|
|
116
|
-
if knockout_prefix
|
|
117
|
-
print "#{di} knocking out: " if merge_debug
|
|
118
|
-
# remove knockout prefix items from both source and dest
|
|
119
|
-
source.delete_if do |ko_item|
|
|
120
|
-
retval = false
|
|
121
|
-
item = ko_item.respond_to?(:gsub) ? ko_item.gsub(%r{^#{knockout_prefix}}, "") : ko_item
|
|
122
|
-
if item != ko_item
|
|
123
|
-
print "#{ko_item} - " if merge_debug
|
|
124
|
-
dest.delete(item)
|
|
125
|
-
dest.delete(ko_item)
|
|
126
|
-
retval = true
|
|
127
|
-
end
|
|
128
|
-
retval
|
|
129
|
-
end
|
|
130
|
-
puts if merge_debug
|
|
131
|
-
end
|
|
132
|
-
puts "#{di} merging arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
|
|
133
|
-
dest = dest | source
|
|
134
|
-
if sort_merged_arrays; dest.sort!; end
|
|
135
|
-
elsif overwrite_unmergeable
|
|
136
|
-
puts "#{di} overwriting dest: #{source.inspect} -over-> #{dest.inspect}" if merge_debug
|
|
137
|
-
dest = overwrite_unmergeables(source, dest, options)
|
|
138
|
-
end
|
|
139
|
-
else # src_hash is not an array or hash, so we'll have to overwrite dest
|
|
140
|
-
puts "#{di}Others: #{source.inspect} :: #{dest.inspect}" if merge_debug
|
|
141
|
-
dest = overwrite_unmergeables(source, dest, options)
|
|
142
|
-
end
|
|
143
|
-
puts "#{di}Returning #{dest.inspect}" if merge_debug
|
|
144
|
-
dest
|
|
145
|
-
end # deep_merge!
|
|
146
|
-
|
|
147
|
-
# allows deep_merge! to uniformly handle overwriting of unmergeable entities
|
|
148
|
-
def DeepMerge::overwrite_unmergeables(source, dest, options)
|
|
149
|
-
merge_debug = options[:merge_debug] || false
|
|
150
|
-
overwrite_unmergeable = !options[:preserve_unmergeables]
|
|
151
|
-
knockout_prefix = options[:knockout_prefix] || false
|
|
152
|
-
di = options[:debug_indent] || ''
|
|
153
|
-
if knockout_prefix && overwrite_unmergeable
|
|
154
|
-
if source.kind_of?(String) # remove knockout string from source before overwriting dest
|
|
155
|
-
src_tmp = source.gsub(%r{^#{knockout_prefix}},"")
|
|
156
|
-
elsif source.kind_of?(Array) # remove all knockout elements before overwriting dest
|
|
157
|
-
src_tmp = source.delete_if {|ko_item| ko_item.kind_of?(String) && ko_item.match(%r{^#{knockout_prefix}}) }
|
|
158
|
-
else
|
|
159
|
-
src_tmp = source
|
|
160
|
-
end
|
|
161
|
-
if src_tmp == source # if we didn't find a knockout_prefix then we just overwrite dest
|
|
162
|
-
puts "#{di}#{src_tmp.inspect} -over-> #{dest.inspect}" if merge_debug
|
|
163
|
-
dest = src_tmp
|
|
164
|
-
else # if we do find a knockout_prefix, then we just delete dest
|
|
165
|
-
puts "#{di}\"\" -over-> #{dest.inspect}" if merge_debug
|
|
166
|
-
dest = ""
|
|
167
|
-
end
|
|
168
|
-
elsif overwrite_unmergeable
|
|
169
|
-
dest = source
|
|
170
|
-
end
|
|
171
|
-
dest
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
def DeepMerge::clear_or_nil(obj)
|
|
175
|
-
if obj.respond_to?(:clear)
|
|
176
|
-
obj.clear
|
|
177
|
-
else
|
|
178
|
-
obj = nil
|
|
179
|
-
end
|
|
180
|
-
obj
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
end # module DeepMerge
|
|
184
|
-
end
|
|
185
|
-
end
|
data/test/config_builder_test.rb
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
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
|
-
module RailsConfig
|
|
8
|
-
module Settings
|
|
9
|
-
class BuilderTest < Test::Unit::TestCase
|
|
10
|
-
def setup
|
|
11
|
-
@settings_path = File.dirname(__FILE__)+"/test_configs"
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def test_missing_files
|
|
15
|
-
files = ["#{@settings_path}/empty1.yml", "#{@settings_path}/empty2.yml"]
|
|
16
|
-
config = RailsConfig::Settings::Builder.load_files(:paths => files)
|
|
17
|
-
assert_equal OpenStruct.new, config
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def test_empty_files
|
|
21
|
-
files = ["#{@settings_path}/empty1.yml", "#{@settings_path}/empty2.yml"]
|
|
22
|
-
config = RailsConfig::Settings::Builder.load_files(:paths => files)
|
|
23
|
-
assert_equal OpenStruct.new, config
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def test_common
|
|
27
|
-
config = RailsConfig::Settings::Builder.load_files(:paths => "#{@settings_path}/settings.yml")
|
|
28
|
-
assert_equal 1, config.size
|
|
29
|
-
assert_equal 'google.com', config.server
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def test_environment_override
|
|
33
|
-
config = RailsConfig::Settings::Builder.load_files(:paths => ["#{@settings_path}/settings.yml", "#{@settings_path}/development.yml"])
|
|
34
|
-
assert_equal 2, config.size
|
|
35
|
-
assert_equal 'google.com', config.server
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def test_nested
|
|
39
|
-
config = RailsConfig::Settings::Builder.load_files(:paths => ["#{@settings_path}/development.yml"])
|
|
40
|
-
assert_equal 3, config.section.size
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def test_array
|
|
44
|
-
config = RailsConfig::Settings::Builder.load_files(:paths => "#{@settings_path}/development.yml")
|
|
45
|
-
assert_equal 'yahoo.com', config.section.servers[0].name
|
|
46
|
-
assert_equal 'amazon.com', config.section.servers[1].name
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def test_erb
|
|
50
|
-
config = RailsConfig::Settings::Builder.load_files(:paths => "#{@settings_path}/development.yml")
|
|
51
|
-
assert_equal 6, config.computed
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def test_merge_hashes_from_multiple_configs
|
|
55
|
-
config = RailsConfig::Settings::Builder.load_files(:paths => ["#{@settings_path}/deep_merge/config1.yml", "#{@settings_path}/deep_merge/config2.yml"])
|
|
56
|
-
|
|
57
|
-
assert_equal 3, config.inner.marshal_dump.keys.size
|
|
58
|
-
assert_equal 3, config.inner2.inner2_inner.marshal_dump.keys.size
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def test_merge_arrays_from_multiple_configs
|
|
63
|
-
config = RailsConfig::Settings::Builder.load_files(:paths => ["#{@settings_path}/deep_merge/config1.yml", "#{@settings_path}/deep_merge/config2.yml"])
|
|
64
|
-
assert_equal 6, config.arraylist1.size
|
|
65
|
-
assert_equal 6, config.arraylist2.inner.size
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def test_merge_assets
|
|
69
|
-
config = RailsConfig::Settings::Builder.load_files(:paths => ["#{@settings_path}/deep_merge/config1.yml", "#{@settings_path}/deep_merge/config2.yml"])
|
|
70
|
-
merged = RailsConfig::Settings::Builder.merge_assets(config.hash_array)
|
|
71
|
-
|
|
72
|
-
assert_equal 3, merged.size
|
|
73
|
-
assert_equal 6, merged.select{|i| i.is_a?(Hash)}.first[:inner].size
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def test_merge_assets2
|
|
77
|
-
config = RailsConfig::Settings::Builder.load_files(:paths => ["#{@settings_path}/deep_merge2/config1.yml", "#{@settings_path}/deep_merge2/config2.yml"])
|
|
78
|
-
|
|
79
|
-
assert_equal 500, config.tvrage.cache
|
|
80
|
-
assert_equal "http://url2", config.tvrage.service_url
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def test_boolean_overrides
|
|
84
|
-
config = RailsConfig::Settings::Builder.load_files(:paths => ["#{@settings_path}/bool_override/config1.yml", "#{@settings_path}/bool_override/config2.yml"])
|
|
85
|
-
assert_equal false, config.override_bool
|
|
86
|
-
assert_equal true, config.override_bool_opposite
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
end
|