Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Converting to RSpec 2.0

  • Loading branch information...
commit 3221dff29ba20d6f934eb63a4525045599425474 1 parent 66c7034
@railsjedi railsjedi authored
Showing with 431 additions and 455 deletions.
  1. +2 −0  .bundle/config
  2. +7 −0 Gemfile
  3. +30 −0 Gemfile.lock
  4. +4 −1 Rakefile
  5. +2 −0  autotest/discover.rb
  6. +3 −2 lib/rails_config.rb
  7. +2 −3 lib/rails_config/railtie.rb
  8. +61 −0 lib/rails_config/setting_builder.rb
  9. +0 −170 lib/rails_config/settings/builder.rb
  10. +0 −185 lib/rails_config/settings/deep_merge.rb
  11. +180 −0 lib/rails_config/vendor/deep_merge.rb
  12. +9 −3 rails_config.gemspec
  13. 0  {test/test_configs → spec/fixtures}/bool_override/config1.yml
  14. 0  {test/test_configs → spec/fixtures}/bool_override/config2.yml
  15. 0  {test/test_configs → spec/fixtures}/deep_merge/config1.yml
  16. 0  {test/test_configs → spec/fixtures}/deep_merge/config2.yml
  17. 0  {test/test_configs → spec/fixtures}/deep_merge2/config1.yml
  18. 0  {test/test_configs → spec/fixtures}/deep_merge2/config2.yml
  19. +0 −1  {test/test_configs → spec/fixtures}/development.yml
  20. 0  {test/test_configs → spec/fixtures}/empty1.yml
  21. 0  {test/test_configs → spec/fixtures}/empty2.yml
  22. 0  test/test_configs/app_config.yml → spec/fixtures/settings.yml
  23. +4 −0 spec/fixtures/with_erb.yml
  24. +102 −0 spec/rails_config/setting_builder_spec.rb
  25. +25 −0 spec/spec_helper.rb
  26. +0 −90 test/config_builder_test.rb
View
2  .bundle/config
@@ -0,0 +1,2 @@
+---
+BUNDLE_DISABLE_SHARED_GEMS: "1"
View
7 Gemfile
@@ -0,0 +1,7 @@
+source 'http://rubygems.org'
+
+gem "rspec", ">= 2.0.0.beta.19"
+gem 'autotest'
+gem "growl-glue"
+
+gem "ruby-debug"
View
30 Gemfile.lock
@@ -0,0 +1,30 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ autotest (4.3.2)
+ columnize (0.3.1)
+ diff-lcs (1.1.2)
+ growl-glue (1.0.7)
+ linecache (0.43)
+ rspec (2.0.0.beta.19)
+ rspec-core (= 2.0.0.beta.19)
+ rspec-expectations (= 2.0.0.beta.19)
+ rspec-mocks (= 2.0.0.beta.19)
+ rspec-core (2.0.0.beta.19)
+ rspec-expectations (2.0.0.beta.19)
+ diff-lcs (>= 1.1.2)
+ rspec-mocks (2.0.0.beta.19)
+ ruby-debug (0.10.3)
+ columnize (>= 0.1)
+ ruby-debug-base (~> 0.10.3.0)
+ ruby-debug-base (0.10.3)
+ linecache (>= 0.3)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ autotest
+ growl-glue
+ rspec (>= 2.0.0.beta.19)
+ ruby-debug
View
5 Rakefile
@@ -9,7 +9,10 @@ begin
s.homepage = "http://github.com/railsjedi/rails_config"
s.description = "Provides an easy to use Application Configuration object"
s.authors = ["Jacques Crocker"]
- s.files = FileList["[A-Z]*", "{bin,generators,lib,test}/**/*"]
+ s.files = FileList["[A-Z]*", "{bin,generators,lib,spec}/**/*"]
+
+ s.add_development_dependency 'rspec', ">=2.0.0.beta.19"
+
end
Jeweler::GemcutterTasks.new
rescue LoadError
View
2  autotest/discover.rb
@@ -0,0 +1,2 @@
+Autotest.add_discovery { "rspec2" }
+
View
5 lib/rails_config.rb
@@ -1,4 +1,5 @@
-require 'rails_config/settings/deep_merge' unless defined?(DeepMerge)
-require 'rails_config/settings/builder'
+require 'rails_config/vendor/deep_merge' unless defined?(DeepMerge)
+require 'pathname'
+require 'rails_config/setting_builder'
require 'rails_config/railtie'
View
5 lib/rails_config/railtie.rb
@@ -2,13 +2,12 @@
module RailsConfig
class Railtie < Rails::Railtie
initializer :setup_rails_config do
- ::Settings = RailsConfig::Settings::Builder.load_files(
+ ::Settings = RailsConfig::SettingBuilder.load_files(
:paths => [
Rails.root.join("config", "settings.yml").to_s,
Rails.root.join("config", "settings", "#{Rails.env}.yml").to_s,
Rails.root.join("config", "environments", "#{Rails.env}.yml").to_s
- ],
- :root_path => Rails.root
+ ]
)
end
end
View
61 lib/rails_config/setting_builder.rb
@@ -0,0 +1,61 @@
+require 'ostruct'
+require 'yaml'
+require 'erb'
+
+module RailsConfig
+ module SettingBuilder
+ @@load_paths = []
+
+ # 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
+ # if the first file if they exist in the first file.
+ def self.load_files(*files)
+ config = OpenStruct.new
+
+ @@load_paths = [files].flatten.compact.uniq
+ # add singleton method to our Settings that reloads its settings from the load_paths
+ def config.reload!
+
+ conf = {}
+ SettingBuilder.load_paths.to_a.each do |path|
+ file_conf = YAML.load(ERB.new(IO.read(path.to_s)).result) if path and File.exists?(path.to_s)
+ next unless file_conf
+
+ if conf.size > 0
+ DeepMerge.deep_merge!(file_conf, conf, :preserve_unmergeables => false)
+ else
+ conf = file_conf
+ end
+ end
+
+ # load all the new values into the openstruct
+ marshal_load(RailsConfig::SettingBuilder.convert(conf).marshal_dump)
+
+ return self
+ end
+
+ config.reload!
+ return config
+ end
+
+ def self.load_paths
+ @@load_paths
+ end
+
+ # Recursively converts Hashes to OpenStructs (including Hashes inside Arrays)
+ def self.convert(h) #:nodoc:
+ s = OpenStruct.new
+ h.each do |k, v|
+ s.new_ostruct_member(k)
+ if v.is_a?(Hash)
+ s.send( (k+'=').to_sym, convert(v))
+ elsif v.is_a?(Array)
+ converted_array = v.collect { |e| e.instance_of?(Hash) ? convert(e) : e }
+ s.send("#{k}=".to_sym, converted_array)
+ else
+ s.send("#{k}=".to_sym, v)
+ end
+ end
+ s
+ end
+ end
+end
View
170 lib/rails_config/settings/builder.rb
@@ -1,170 +0,0 @@
-require 'ostruct'
-require 'yaml'
-require 'erb'
-
-module RailsConfig
- module Settings
- # == Summary
- # This is API documentation, NOT documentation on how to use this plugin. For that, see the README.
- class Builder
- @@load_paths = []
- @@expand_keys = []
- @@root_path = ""
-
- # 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
- # if the first file if they exist in the first file.
- def self.load_files(options = {})
- config = OpenStruct.new
-
- @@load_paths = [options[:paths]].flatten.compact.uniq
- @@expand_keys = [options[:expand_keys]].flatten.compact.uniq
- @@root_path = options[:root_path]
-
- # add singleton method to our Settings that reloads its settings from the load_paths options
- def config.reload!
-
- conf = {}
- Builder.load_paths.to_a.each do |path|
- file_conf = YAML.load(ERB.new(IO.read(path)).result) if path and File.exists?(path)
- next unless file_conf
-
- if conf.size > 0
- DeepMerge.deep_merge!(file_conf, conf, :preserve_unmergeables => false)
- else
- conf = file_conf
- end
- end
-
- # expand the javascripts config to handle *.* paths
- Builder.expand_keys.to_a.each do |expand_path|
- expand_path = expand_path.to_s
- if conf[expand_path]
- conf[expand_path] = RailsConfig::Settings::Builder.expand(conf[expand_path], "#{Builder.root_path}/public/#{expand_path}")
- end
- end
-
- # load all the new values into the openstruct
- marshal_load(RailsConfig::Settings::Builder.convert(conf).marshal_dump)
-
- return self
- end
-
- config.reload!
- return config
- end
-
- def self.load_paths
- @@load_paths
- end
-
- def self.expand_keys
- @@expand_keys
- end
-
- def self.root_path
- @@root_path
- end
-
- # Recursively converts Hashes to OpenStructs (including Hashes inside Arrays)
- def self.convert(h) #:nodoc:
- s = OpenStruct.new
- h.each do |k, v|
- s.new_ostruct_member(k)
- if v.is_a?(Hash)
- s.send( (k+'=').to_sym, convert(v))
- elsif v.is_a?(Array)
- converted_array = v.collect { |e| e.instance_of?(Hash) ? convert(e) : e }
- s.send("#{k}=".to_sym, converted_array)
- else
- s.send("#{k}=".to_sym, v)
- end
- end
- s
- end
-
- # expand a config val
- def self.expand(config, base_path)
- case config.class.to_s
- when "Hash"
- return expand_hash(config, base_path)
- when "Array"
- return expand_array(config, base_path)
- when "String"
- return expand_string(config, base_path)
- end
- return config
- end
-
- # expand a string and returns a list
- def self.expand_string(config, base_path)
- # puts "Expanding String: #{config.inspect}"
- if config.include?("*")
- results = Dir["#{base_path}/#{config}"].map{|i| i.to_s.gsub("#{base_path}/", "") }
-
- # puts "EXPANDED PATH: #{base_path}/#{config}"
- # puts results.inspect
- return results
- else
- return config
- end
- end
-
- # expand a hash by cycling throw all the hash values
- def self.expand_hash(config, base_path)
- # puts "Expanding Hash: #{config.inspect}"
- new_config = {}
- config.each do |key, val|
- new_config[key] = expand(val, base_path)
- end
- return new_config
- end
-
- # expand an array by cycling through all the values
- def self.expand_array(config, base_path)
- # puts "Expanding Array: #{config.inspect}"
- new_config = []
- config.each do |val|
- new_val = expand(val, base_path)
- if new_val.is_a?(Array)
- new_val.each do |inner|
- new_config << inner
- end
- else
- new_config << new_val
- end
- end
- return new_config.uniq
- end
-
- # Cycles through the array of single element hashes
- # and deep merges any duplicates it finds
- #
- # This is needed so you can define stylesheet keys
- # in multiple config files
- def self.merge_assets(list)
- assets = Array(list).map do |i|
- if i.is_a?(OpenStruct)
- i.marshal_dump
- else
- i
- end
- end
-
- # filter out the duplicate single hash keys
- hash_keys = assets.select{|i| i.is_a?(Hash) and i.keys.size == 1}.group_by{|i| i.keys[0]}
- hash_keys.each do |key, value|
- if Array(value).size > 1
- merged = value.inject({}){|merged, v| DeepMerge.deep_merge!(v,merged)}
- value[0].replace(merged)
- value[1..-1].each do |v|
- v.clear
- end
- end
- end
-
- assets.select{|i| !i.blank? }
- end
-
- end
- end
-end
View
185 lib/rails_config/settings/deep_merge.rb
@@ -1,185 +0,0 @@
-module RailsConfig
- module Settings
- module DeepMerge
-
- class InvalidParameter < StandardError; end
-
- DEFAULT_FIELD_KNOCKOUT_PREFIX = '--'
-
- # Deep Merge core documentation.
- # deep_merge! method permits merging of arbitrary child elements. The two top level
- # elements must be hashes. These hashes can contain unlimited (to stack limit) levels
- # of child elements. These child elements to not have to be of the same types.
- # Where child elements are of the same type, deep_merge will attempt to merge them together.
- # Where child elements are not of the same type, deep_merge will skip or optionally overwrite
- # the destination element with the contents of the source element at that level.
- # So if you have two hashes like this:
- # source = {:x => [1,2,3], :y => 2}
- # dest = {:x => [4,5,'6'], :y => [7,8,9]}
- # dest.deep_merge!(source)
- # Results: {:x => [1,2,3,4,5,'6'], :y => 2}
- # By default, "deep_merge!" will overwrite any unmergeables and merge everything else.
- # To avoid this, use "deep_merge" (no bang/exclamation mark)
- #
- # Options:
- # Options are specified in the last parameter passed, which should be in hash format:
- # hash.deep_merge!({:x => [1,2]}, {:knockout_prefix => '--'})
- # :preserve_unmergeables DEFAULT: false
- # Set to true to skip any unmergeable elements from source
- # :knockout_prefix DEFAULT: nil
- # Set to string value to signify prefix which deletes elements from existing element
- # :sort_merged_arrays DEFAULT: false
- # Set to true to sort all arrays that are merged together
- # :unpack_arrays DEFAULT: nil
- # Set to string value to run "Array::join" then "String::split" against all arrays
- # :merge_debug DEFAULT: false
- # Set to true to get console output of merge process for debugging
- #
- # Selected Options Details:
- # :knockout_prefix => The purpose of this is to provide a way to remove elements
- # from existing Hash by specifying them in a special way in incoming hash
- # source = {:x => ['--1', '2']}
- # dest = {:x => ['1', '3']}
- # dest.ko_deep_merge!(source)
- # Results: {:x => ['2','3']}
- # Additionally, if the knockout_prefix is passed alone as a string, it will cause
- # the entire element to be removed:
- # source = {:x => '--'}
- # dest = {:x => [1,2,3]}
- # dest.ko_deep_merge!(source)
- # Results: {:x => ""}
- # :unpack_arrays => The purpose of this is to permit compound elements to be passed
- # in as strings and to be converted into discrete array elements
- # irsource = {:x => ['1,2,3', '4']}
- # dest = {:x => ['5','6','7,8']}
- # dest.deep_merge!(source, {:unpack_arrays => ','})
- # Results: {:x => ['1','2','3','4','5','6','7','8'}
- # Why: If receiving data from an HTML form, this makes it easy for a checkbox
- # to pass multiple values from within a single HTML element
- #
- # There are many tests for this library - and you can learn more about the features
- # and usages of deep_merge! by just browsing the test examples
- def DeepMerge.deep_merge!(source, dest, options = {})
- # turn on this line for stdout debugging text
- merge_debug = options[:merge_debug] || false
- overwrite_unmergeable = !options[:preserve_unmergeables]
- knockout_prefix = options[:knockout_prefix] || nil
- if knockout_prefix == ""; raise InvalidParameter, "knockout_prefix cannot be an empty string in deep_merge!"; end
- if knockout_prefix && !overwrite_unmergeable; raise InvalidParameter, "overwrite_unmergeable must be true if knockout_prefix is specified in deep_merge!"; end
- # if present: we will split and join arrays on this char before merging
- array_split_char = options[:unpack_arrays] || false
- # request that we sort together any arrays when they are merged
- sort_merged_arrays = options[:sort_merged_arrays] || false
- di = options[:debug_indent] || ''
- # do nothing if source is nil
- if source.nil? || (!source.is_a?(FalseClass) && source.respond_to?(:blank?) && source.blank?); return dest; end
- # if dest doesn't exist, then simply copy source to it
- if dest.nil? && overwrite_unmergeable; dest = source; return dest; end
-
- puts "#{di}Source class: #{source.class.inspect} :: Dest class: #{dest.class.inspect}" if merge_debug
- if source.kind_of?(Hash)
- puts "#{di}Hashes: #{source.inspect} :: #{dest.inspect}" if merge_debug
- source.each do |src_key, src_value|
- if dest.kind_of?(Hash)
- puts "#{di} looping: #{src_key.inspect} => #{src_value.inspect} :: #{dest.inspect}" if merge_debug
- if !dest[src_key].nil?
- puts "#{di} ==>merging: #{src_key.inspect} => #{src_value.inspect} :: #{dest[src_key].inspect}" if merge_debug
- dest[src_key] = deep_merge!(src_value, dest[src_key], options.merge(:debug_indent => di + ' '))
- else # dest[src_key] doesn't exist so we want to create and overwrite it (but we do this via deep_merge!)
- puts "#{di} ==>merging over: #{src_key.inspect} => #{src_value.inspect}" if merge_debug
- # note: we rescue here b/c some classes respond to "dup" but don't implement it (Numeric, TrueClass, FalseClass, NilClass among maybe others)
- begin
- src_dup = src_value.dup # we dup src_value if possible because we're going to merge into it (since dest is empty)
- rescue TypeError
- src_dup = src_value
- end
- dest[src_key] = deep_merge!(src_value, src_dup, options.merge(:debug_indent => di + ' '))
- end
- else # dest isn't a hash, so we overwrite it completely (if permitted)
- if overwrite_unmergeable
- puts "#{di} overwriting dest: #{src_key.inspect} => #{src_value.inspect} -over-> #{dest.inspect}" if merge_debug
- dest = overwrite_unmergeables(source, dest, options)
- end
- end
- end
- elsif source.kind_of?(Array)
- puts "#{di}Arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
- # if we are instructed, join/split any source arrays before processing
- if array_split_char
- puts "#{di} split/join on source: #{source.inspect}" if merge_debug
- source = source.join(array_split_char).split(array_split_char)
- if dest.kind_of?(Array); dest = dest.join(array_split_char).split(array_split_char); end
- end
- # if there's a naked knockout_prefix in source, that means we are to truncate dest
- if source.index(knockout_prefix); dest = clear_or_nil(dest); source.delete(knockout_prefix); end
- if dest.kind_of?(Array)
- if knockout_prefix
- print "#{di} knocking out: " if merge_debug
- # remove knockout prefix items from both source and dest
- source.delete_if do |ko_item|
- retval = false
- item = ko_item.respond_to?(:gsub) ? ko_item.gsub(%r{^#{knockout_prefix}}, "") : ko_item
- if item != ko_item
- print "#{ko_item} - " if merge_debug
- dest.delete(item)
- dest.delete(ko_item)
- retval = true
- end
- retval
- end
- puts if merge_debug
- end
- puts "#{di} merging arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
- dest = dest | source
- if sort_merged_arrays; dest.sort!; end
- elsif overwrite_unmergeable
- puts "#{di} overwriting dest: #{source.inspect} -over-> #{dest.inspect}" if merge_debug
- dest = overwrite_unmergeables(source, dest, options)
- end
- else # src_hash is not an array or hash, so we'll have to overwrite dest
- puts "#{di}Others: #{source.inspect} :: #{dest.inspect}" if merge_debug
- dest = overwrite_unmergeables(source, dest, options)
- end
- puts "#{di}Returning #{dest.inspect}" if merge_debug
- dest
- end # deep_merge!
-
- # allows deep_merge! to uniformly handle overwriting of unmergeable entities
- def DeepMerge::overwrite_unmergeables(source, dest, options)
- merge_debug = options[:merge_debug] || false
- overwrite_unmergeable = !options[:preserve_unmergeables]
- knockout_prefix = options[:knockout_prefix] || false
- di = options[:debug_indent] || ''
- if knockout_prefix && overwrite_unmergeable
- if source.kind_of?(String) # remove knockout string from source before overwriting dest
- src_tmp = source.gsub(%r{^#{knockout_prefix}},"")
- elsif source.kind_of?(Array) # remove all knockout elements before overwriting dest
- src_tmp = source.delete_if {|ko_item| ko_item.kind_of?(String) && ko_item.match(%r{^#{knockout_prefix}}) }
- else
- src_tmp = source
- end
- if src_tmp == source # if we didn't find a knockout_prefix then we just overwrite dest
- puts "#{di}#{src_tmp.inspect} -over-> #{dest.inspect}" if merge_debug
- dest = src_tmp
- else # if we do find a knockout_prefix, then we just delete dest
- puts "#{di}\"\" -over-> #{dest.inspect}" if merge_debug
- dest = ""
- end
- elsif overwrite_unmergeable
- dest = source
- end
- dest
- end
-
- def DeepMerge::clear_or_nil(obj)
- if obj.respond_to?(:clear)
- obj.clear
- else
- obj = nil
- end
- obj
- end
-
- end # module DeepMerge
- end
-end
View
180 lib/rails_config/vendor/deep_merge.rb
@@ -0,0 +1,180 @@
+module DeepMerge
+ class InvalidParameter < StandardError; end
+
+ DEFAULT_FIELD_KNOCKOUT_PREFIX = '--'
+
+ # Deep Merge core documentation.
+ # deep_merge! method permits merging of arbitrary child elements. The two top level
+ # elements must be hashes. These hashes can contain unlimited (to stack limit) levels
+ # of child elements. These child elements to not have to be of the same types.
+ # Where child elements are of the same type, deep_merge will attempt to merge them together.
+ # Where child elements are not of the same type, deep_merge will skip or optionally overwrite
+ # the destination element with the contents of the source element at that level.
+ # So if you have two hashes like this:
+ # source = {:x => [1,2,3], :y => 2}
+ # dest = {:x => [4,5,'6'], :y => [7,8,9]}
+ # dest.deep_merge!(source)
+ # Results: {:x => [1,2,3,4,5,'6'], :y => 2}
+ # By default, "deep_merge!" will overwrite any unmergeables and merge everything else.
+ # To avoid this, use "deep_merge" (no bang/exclamation mark)
+ #
+ # Options:
+ # Options are specified in the last parameter passed, which should be in hash format:
+ # hash.deep_merge!({:x => [1,2]}, {:knockout_prefix => '--'})
+ # :preserve_unmergeables DEFAULT: false
+ # Set to true to skip any unmergeable elements from source
+ # :knockout_prefix DEFAULT: nil
+ # Set to string value to signify prefix which deletes elements from existing element
+ # :sort_merged_arrays DEFAULT: false
+ # Set to true to sort all arrays that are merged together
+ # :unpack_arrays DEFAULT: nil
+ # Set to string value to run "Array::join" then "String::split" against all arrays
+ # :merge_debug DEFAULT: false
+ # Set to true to get console output of merge process for debugging
+ #
+ # Selected Options Details:
+ # :knockout_prefix => The purpose of this is to provide a way to remove elements
+ # from existing Hash by specifying them in a special way in incoming hash
+ # source = {:x => ['--1', '2']}
+ # dest = {:x => ['1', '3']}
+ # dest.ko_deep_merge!(source)
+ # Results: {:x => ['2','3']}
+ # Additionally, if the knockout_prefix is passed alone as a string, it will cause
+ # the entire element to be removed:
+ # source = {:x => '--'}
+ # dest = {:x => [1,2,3]}
+ # dest.ko_deep_merge!(source)
+ # Results: {:x => ""}
+ # :unpack_arrays => The purpose of this is to permit compound elements to be passed
+ # in as strings and to be converted into discrete array elements
+ # irsource = {:x => ['1,2,3', '4']}
+ # dest = {:x => ['5','6','7,8']}
+ # dest.deep_merge!(source, {:unpack_arrays => ','})
+ # Results: {:x => ['1','2','3','4','5','6','7','8'}
+ # Why: If receiving data from an HTML form, this makes it easy for a checkbox
+ # to pass multiple values from within a single HTML element
+ #
+ # There are many tests for this library - and you can learn more about the features
+ # and usages of deep_merge! by just browsing the test examples
+ def DeepMerge.deep_merge!(source, dest, options = {})
+ # turn on this line for stdout debugging text
+ merge_debug = options[:merge_debug] || false
+ overwrite_unmergeable = !options[:preserve_unmergeables]
+ knockout_prefix = options[:knockout_prefix] || nil
+ if knockout_prefix == ""; raise InvalidParameter, "knockout_prefix cannot be an empty string in deep_merge!"; end
+ if knockout_prefix && !overwrite_unmergeable; raise InvalidParameter, "overwrite_unmergeable must be true if knockout_prefix is specified in deep_merge!"; end
+ # if present: we will split and join arrays on this char before merging
+ array_split_char = options[:unpack_arrays] || false
+ # request that we sort together any arrays when they are merged
+ sort_merged_arrays = options[:sort_merged_arrays] || false
+ di = options[:debug_indent] || ''
+ # do nothing if source is nil
+ if source.nil? || (!source.is_a?(FalseClass) && source.respond_to?(:blank?) && source.blank?); return dest; end
+ # if dest doesn't exist, then simply copy source to it
+ if dest.nil? && overwrite_unmergeable; dest = source; return dest; end
+
+ puts "#{di}Source class: #{source.class.inspect} :: Dest class: #{dest.class.inspect}" if merge_debug
+ if source.kind_of?(Hash)
+ puts "#{di}Hashes: #{source.inspect} :: #{dest.inspect}" if merge_debug
+ source.each do |src_key, src_value|
+ if dest.kind_of?(Hash)
+ puts "#{di} looping: #{src_key.inspect} => #{src_value.inspect} :: #{dest.inspect}" if merge_debug
+ if !dest[src_key].nil?
+ puts "#{di} ==>merging: #{src_key.inspect} => #{src_value.inspect} :: #{dest[src_key].inspect}" if merge_debug
+ dest[src_key] = deep_merge!(src_value, dest[src_key], options.merge(:debug_indent => di + ' '))
+ else # dest[src_key] doesn't exist so we want to create and overwrite it (but we do this via deep_merge!)
+ puts "#{di} ==>merging over: #{src_key.inspect} => #{src_value.inspect}" if merge_debug
+ # note: we rescue here b/c some classes respond to "dup" but don't implement it (Numeric, TrueClass, FalseClass, NilClass among maybe others)
+ begin
+ src_dup = src_value.dup # we dup src_value if possible because we're going to merge into it (since dest is empty)
+ rescue TypeError
+ src_dup = src_value
+ end
+ dest[src_key] = deep_merge!(src_value, src_dup, options.merge(:debug_indent => di + ' '))
+ end
+ else # dest isn't a hash, so we overwrite it completely (if permitted)
+ if overwrite_unmergeable
+ puts "#{di} overwriting dest: #{src_key.inspect} => #{src_value.inspect} -over-> #{dest.inspect}" if merge_debug
+ dest = overwrite_unmergeables(source, dest, options)
+ end
+ end
+ end
+ elsif source.kind_of?(Array)
+ puts "#{di}Arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
+ # if we are instructed, join/split any source arrays before processing
+ if array_split_char
+ puts "#{di} split/join on source: #{source.inspect}" if merge_debug
+ source = source.join(array_split_char).split(array_split_char)
+ if dest.kind_of?(Array); dest = dest.join(array_split_char).split(array_split_char); end
+ end
+ # if there's a naked knockout_prefix in source, that means we are to truncate dest
+ if source.index(knockout_prefix); dest = clear_or_nil(dest); source.delete(knockout_prefix); end
+ if dest.kind_of?(Array)
+ if knockout_prefix
+ print "#{di} knocking out: " if merge_debug
+ # remove knockout prefix items from both source and dest
+ source.delete_if do |ko_item|
+ retval = false
+ item = ko_item.respond_to?(:gsub) ? ko_item.gsub(%r{^#{knockout_prefix}}, "") : ko_item
+ if item != ko_item
+ print "#{ko_item} - " if merge_debug
+ dest.delete(item)
+ dest.delete(ko_item)
+ retval = true
+ end
+ retval
+ end
+ puts if merge_debug
+ end
+ puts "#{di} merging arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
+ dest = dest | source
+ if sort_merged_arrays; dest.sort!; end
+ elsif overwrite_unmergeable
+ puts "#{di} overwriting dest: #{source.inspect} -over-> #{dest.inspect}" if merge_debug
+ dest = overwrite_unmergeables(source, dest, options)
+ end
+ else # src_hash is not an array or hash, so we'll have to overwrite dest
+ puts "#{di}Others: #{source.inspect} :: #{dest.inspect}" if merge_debug
+ dest = overwrite_unmergeables(source, dest, options)
+ end
+ puts "#{di}Returning #{dest.inspect}" if merge_debug
+ dest
+ end # deep_merge!
+
+ # allows deep_merge! to uniformly handle overwriting of unmergeable entities
+ def DeepMerge::overwrite_unmergeables(source, dest, options)
+ merge_debug = options[:merge_debug] || false
+ overwrite_unmergeable = !options[:preserve_unmergeables]
+ knockout_prefix = options[:knockout_prefix] || false
+ di = options[:debug_indent] || ''
+ if knockout_prefix && overwrite_unmergeable
+ if source.kind_of?(String) # remove knockout string from source before overwriting dest
+ src_tmp = source.gsub(%r{^#{knockout_prefix}},"")
+ elsif source.kind_of?(Array) # remove all knockout elements before overwriting dest
+ src_tmp = source.delete_if {|ko_item| ko_item.kind_of?(String) && ko_item.match(%r{^#{knockout_prefix}}) }
+ else
+ src_tmp = source
+ end
+ if src_tmp == source # if we didn't find a knockout_prefix then we just overwrite dest
+ puts "#{di}#{src_tmp.inspect} -over-> #{dest.inspect}" if merge_debug
+ dest = src_tmp
+ else # if we do find a knockout_prefix, then we just delete dest
+ puts "#{di}\"\" -over-> #{dest.inspect}" if merge_debug
+ dest = ""
+ end
+ elsif overwrite_unmergeable
+ dest = source
+ end
+ dest
+ end
+
+ def DeepMerge::clear_or_nil(obj)
+ if obj.respond_to?(:clear)
+ obj.clear
+ else
+ obj = nil
+ end
+ obj
+ end
+
+end # module DeepMerge
View
12 rails_config.gemspec
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Jacques Crocker"]
- s.date = %q{2010-08-07}
+ s.date = %q{2010-08-08}
s.description = %q{Provides an easy to use Application Configuration object}
s.email = %q{railsjedi@gmail.com}
s.extra_rdoc_files = [
@@ -17,7 +17,9 @@ Gem::Specification.new do |s|
"README"
]
s.files = [
- "LICENSE",
+ "Gemfile",
+ "Gemfile.lock",
+ "LICENSE",
"README",
"Rakefile",
"VERSION",
@@ -43,7 +45,8 @@ Gem::Specification.new do |s|
s.rubygems_version = %q{1.3.7}
s.summary = %q{provides an Settings for rails3 that reads config/settings.yml}
s.test_files = [
- "test/config_builder_test.rb"
+ "spec/spec_helper.rb",
+ "test/config_builder_test.rb"
]
if s.respond_to? :specification_version then
@@ -51,9 +54,12 @@ Gem::Specification.new do |s|
s.specification_version = 3
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
+ s.add_development_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
else
+ s.add_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
end
else
+ s.add_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
end
end
View
0  test/test_configs/bool_override/config1.yml → spec/fixtures/bool_override/config1.yml
File renamed without changes
View
0  test/test_configs/bool_override/config2.yml → spec/fixtures/bool_override/config2.yml
File renamed without changes
View
0  test/test_configs/deep_merge/config1.yml → spec/fixtures/deep_merge/config1.yml
File renamed without changes
View
0  test/test_configs/deep_merge/config2.yml → spec/fixtures/deep_merge/config2.yml
File renamed without changes
View
0  test/test_configs/deep_merge2/config1.yml → spec/fixtures/deep_merge2/config1.yml
File renamed without changes
View
0  test/test_configs/deep_merge2/config2.yml → spec/fixtures/deep_merge2/config2.yml
File renamed without changes
View
1  test/test_configs/development.yml → spec/fixtures/development.yml
@@ -1,5 +1,4 @@
size: 2
-computed: <%= 1 + 2 + 3 %>
section:
size: 3
servers: [ {name: yahoo.com}, {name: amazon.com} ]
View
0  test/test_configs/empty1.yml → spec/fixtures/empty1.yml
File renamed without changes
View
0  test/test_configs/empty2.yml → spec/fixtures/empty2.yml
File renamed without changes
View
0  test/test_configs/app_config.yml → spec/fixtures/settings.yml
File renamed without changes
View
4 spec/fixtures/with_erb.yml
@@ -0,0 +1,4 @@
+computed: <%= 1 + 2 + 3 %>
+section:
+ computed1: <%= "1" %>
+ computed2: <%= "2" %>
View
102 spec/rails_config/setting_builder_spec.rb
@@ -0,0 +1,102 @@
+require 'spec_helper'
+
+module RailsConfig
+ describe SettingBuilder do
+
+ it "should load a basic config file" do
+ config = SettingBuilder.load_files(setting_path("settings.yml"))
+ config.size.should == 1
+ config.server.should == "google.com"
+ end
+
+ it "should load empty config for a missing file path" do
+ config = SettingBuilder.load_files(setting_path("some_file_that_doesnt_exist.yml"))
+ config.should == OpenStruct.new
+ end
+
+ it "should load an empty config for multiple missing file paths" do
+ files = [setting_path("doesnt_exist1.yml"), setting_path("doesnt_exist2.yml")]
+ config = SettingBuilder.load_files(files)
+ config.should == OpenStruct.new
+ end
+
+ it "should load empty config for an empty setting file" do
+ config = SettingBuilder.load_files(setting_path("empty1.yml"))
+ config.should == OpenStruct.new
+ end
+
+ it "should load an empty config for multiple missing file paths" do
+ files = [setting_path("empty1.yml"), setting_path("empty2.yml")]
+ config = SettingBuilder.load_files(files)
+ config.should == OpenStruct.new
+ end
+
+ it "should allow overrides" do
+ files = [setting_path("settings.yml"), setting_path("development.yml")]
+ config = SettingBuilder.load_files(files)
+ config.server.should == "google.com"
+ config.size.should == 2
+ end
+
+ context "Nested Settings" do
+ let(:config) do
+ SettingBuilder.load_files(setting_path("development.yml"))
+ end
+
+ it "should allow nested sections" do
+ config.section.size.should == 3
+ end
+
+ it "should allow configuration collections (arrays)" do
+ config.section.servers[0].name.should == "yahoo.com"
+ config.section.servers[1].name.should == "amazon.com"
+ end
+ end
+
+ context "Settings with ERB tags" do
+ let(:config) do
+ SettingBuilder.load_files(setting_path("with_erb.yml"))
+ end
+
+ it "should evaluate ERB tags" do
+ config.computed.should == 6
+ end
+
+ it "should evaluated nested ERB tags" do
+ config.section.computed1.should == 1
+ config.section.computed2.should == 2
+ end
+ end
+
+ context "Deep Merging" do
+ let(:config) do
+ files = [setting_path("deep_merge/config1.yml"), setting_path("deep_merge/config2.yml")]
+ SettingBuilder.load_files(files)
+ end
+
+ it "should merge hashes from multiple configs" do
+ config.inner.marshal_dump.keys.size.should == 3
+ config.inner2.inner2_inner.marshal_dump.keys.size.should == 3
+ end
+
+ it "should merge arrays from multiple configs" do
+ config.arraylist1.size.should == 6
+ config.arraylist2.inner.size.should == 6
+ end
+ end
+
+ context "Boolean Overrides" do
+ let(:config) do
+ files = [setting_path("bool_override/config1.yml"), setting_path("bool_override/config2.yml")]
+ SettingBuilder.load_files(files)
+ end
+
+ it "should allow overriding of bool settings" do
+ config.override_bool.should == false
+ config.override_bool_opposite.should == true
+ end
+ end
+
+
+ end
+end
View
25 spec/spec_helper.rb
@@ -0,0 +1,25 @@
+require 'rails_config'
+require "bundler"
+Bundler.setup
+
+def in_editor?
+ ENV.has_key?('TM_MODE') || ENV.has_key?('EMACS') || ENV.has_key?('VIM')
+end
+
+RSpec.configure do |c|
+ c.color_enabled = !in_editor?
+ c.run_all_when_everything_filtered = true
+
+ # setup fixtures path
+ c.before(:all) do
+ @fixture_path = Pathname.new(File.join(File.dirname(__FILE__), "/fixtures"))
+ raise "Fixture folder not found: #{@fixture_path}" unless @fixture_path.directory?
+ end
+
+ # returns the file path of a fixture setting file
+ def setting_path(filename)
+ @fixture_path.join(filename)
+ end
+
+end
+
View
90 test/config_builder_test.rb
@@ -1,90 +0,0 @@
-require 'rubygems'
-require 'test/unit'
-require 'extlib'
-require File.dirname(__FILE__)+'/../lib/application_config/config_builder'
-require File.dirname(__FILE__)+'/../lib/application_config/deep_merge'
-
-module RailsConfig
- module Settings
- class BuilderTest < Test::Unit::TestCase
- def setup
- @settings_path = File.dirname(__FILE__)+"/test_configs"
- end
-
- def test_missing_files
- files = ["#{@settings_path}/empty1.yml", "#{@settings_path}/empty2.yml"]
- config = RailsConfig::Settings::Builder.load_files(:paths => files)
- assert_equal OpenStruct.new, config
- end
-
- def test_empty_files
- files = ["#{@settings_path}/empty1.yml", "#{@settings_path}/empty2.yml"]
- config = RailsConfig::Settings::Builder.load_files(:paths => files)
- assert_equal OpenStruct.new, config
- end
-
- def test_common
- config = RailsConfig::Settings::Builder.load_files(:paths => "#{@settings_path}/settings.yml")
- assert_equal 1, config.size
- assert_equal 'google.com', config.server
- end
-
- def test_environment_override
- config = RailsConfig::Settings::Builder.load_files(:paths => ["#{@settings_path}/settings.yml", "#{@settings_path}/development.yml"])
- assert_equal 2, config.size
- assert_equal 'google.com', config.server
- end
-
- def test_nested
- config = RailsConfig::Settings::Builder.load_files(:paths => ["#{@settings_path}/development.yml"])
- assert_equal 3, config.section.size
- end
-
- def test_array
- config = RailsConfig::Settings::Builder.load_files(:paths => "#{@settings_path}/development.yml")
- assert_equal 'yahoo.com', config.section.servers[0].name
- assert_equal 'amazon.com', config.section.servers[1].name
- end
-
- def test_erb
- config = RailsConfig::Settings::Builder.load_files(:paths => "#{@settings_path}/development.yml")
- assert_equal 6, config.computed
- end
-
- def test_merge_hashes_from_multiple_configs
- config = RailsConfig::Settings::Builder.load_files(:paths => ["#{@settings_path}/deep_merge/config1.yml", "#{@settings_path}/deep_merge/config2.yml"])
-
- assert_equal 3, config.inner.marshal_dump.keys.size
- assert_equal 3, config.inner2.inner2_inner.marshal_dump.keys.size
- end
-
-
- def test_merge_arrays_from_multiple_configs
- config = RailsConfig::Settings::Builder.load_files(:paths => ["#{@settings_path}/deep_merge/config1.yml", "#{@settings_path}/deep_merge/config2.yml"])
- assert_equal 6, config.arraylist1.size
- assert_equal 6, config.arraylist2.inner.size
- end
-
- def test_merge_assets
- config = RailsConfig::Settings::Builder.load_files(:paths => ["#{@settings_path}/deep_merge/config1.yml", "#{@settings_path}/deep_merge/config2.yml"])
- merged = RailsConfig::Settings::Builder.merge_assets(config.hash_array)
-
- assert_equal 3, merged.size
- assert_equal 6, merged.select{|i| i.is_a?(Hash)}.first[:inner].size
- end
-
- def test_merge_assets2
- config = RailsConfig::Settings::Builder.load_files(:paths => ["#{@settings_path}/deep_merge2/config1.yml", "#{@settings_path}/deep_merge2/config2.yml"])
-
- assert_equal 500, config.tvrage.cache
- assert_equal "http://url2", config.tvrage.service_url
- end
-
- def test_boolean_overrides
- config = RailsConfig::Settings::Builder.load_files(:paths => ["#{@settings_path}/bool_override/config1.yml", "#{@settings_path}/bool_override/config2.yml"])
- assert_equal false, config.override_bool
- assert_equal true, config.override_bool_opposite
- end
- end
- end
-end
Please sign in to comment.
Something went wrong with that request. Please try again.