hash_params 0.0.2 → 2.0.0

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +8 -8
  3. data/README.md +167 -109
  4. data/coverage/assets/0.9.0/application.css +799 -0
  5. data/coverage/assets/0.9.0/application.js +1707 -0
  6. data/coverage/assets/0.9.0/colorbox/border.png +0 -0
  7. data/coverage/assets/0.9.0/colorbox/controls.png +0 -0
  8. data/coverage/assets/0.9.0/colorbox/loading.gif +0 -0
  9. data/coverage/assets/0.9.0/colorbox/loading_background.png +0 -0
  10. data/coverage/assets/0.9.0/favicon_green.png +0 -0
  11. data/coverage/assets/0.9.0/favicon_red.png +0 -0
  12. data/coverage/assets/0.9.0/favicon_yellow.png +0 -0
  13. data/coverage/assets/0.9.0/loading.gif +0 -0
  14. data/coverage/assets/0.9.0/magnify.png +0 -0
  15. data/coverage/assets/0.9.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  16. data/coverage/assets/0.9.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  17. data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  18. data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  19. data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  20. data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  21. data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  22. data/coverage/assets/0.9.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  23. data/coverage/assets/0.9.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
  24. data/coverage/assets/0.9.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  25. data/coverage/assets/0.9.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
  26. data/coverage/assets/0.9.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
  27. data/coverage/assets/0.9.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  28. data/coverage/index.html +1597 -369
  29. data/hash_params.gemspec +14 -5
  30. data/lib/hash_params/binding_validator.rb +26 -0
  31. data/lib/hash_params/hash_validator.rb +71 -0
  32. data/lib/hash_params/validator.rb +119 -0
  33. data/lib/hash_params/yaml_params.rb +93 -0
  34. data/lib/hash_params.rb +15 -142
  35. data/spec/hash_params_spec.rb +100 -63
  36. data/spec/spec_helper.rb +0 -11
  37. data/tmp/hash_params.rb +181 -0
  38. data/tmp/hash_params_spec.rb +102 -0
  39. data/tmp/module_spec.rb +27 -0
  40. data/tmp/var_spec.rb +9 -0
  41. data/tmp/yaml_params.rb +109 -0
  42. metadata +36 -3
@@ -2,85 +2,122 @@ require_relative 'spec_helper'
2
2
 
3
3
 
4
4
  describe HashParams do
5
+ let(:v) { HashParams }
5
6
 
6
- let (:r) {
7
- HashParams.new(
8
- {
9
- ignored: "this will be ignored because it's not mentioned",
10
- to_be_renamed: :to_be_renamed,
11
- integer_coercion: "1",
12
- bad_number: '1aaa2',
13
- array_with_delim: '1|2|3',
14
- hash_as_string: "{a => 1,b => 2,c => d}",
15
- proc_validation: "is_this_valid?",
16
- some_number: 122,
17
- some_string: 'this is a test string' ,
18
- is_true: 'true',
19
- is_false: 'f',
20
- recursive: {}
21
- }
22
- ) do
23
- param :doesnt_exist, required: true
24
- param :to_be_renamed, as: :renamed
25
- param :no_value, default: 1
26
- #proc default relying on previously set value
27
- param :proc_default, default: lambda { |o| o[:no_value] * 5 }
28
- param :integer_coercion, coerce: Integer
29
- #chained coersions of various types
30
- param :bad_number, coerce: [lambda { |o| o.gsub('a', '') }, :to_i, Float]
31
- #arrays and hashes
32
- param :array_with_delim, coerce: Array, delimiter: '|'
33
- param :hash_as_string, coerce: Hash, delimiter: ',', separator: '=>'
34
- param :proc_validation, validate: lambda { |v| v == 'Failed_proc_validation' }
35
- #validations
36
- param :some_number, min: 120, max: 500, in: (100..200), is: 122
37
- param :some_string, min_length: 21, max_length: 30, format: /^t.*g$/
38
- #combinations
39
- param :missing_with_validation, coerce: Integer, :default => 60 * 60, :validate => lambda { |v| v >= 60 * 60 }
40
- param :is_true, coerce: :boolean
41
- param :is_false, coerce: :boolean
7
+ it 'raises error if required and missing' do
8
+ proc {
9
+ v.validate(nil, nil, required: true)
10
+ }.must_raise HashParams::Validator::ValidationError
11
+ end
12
+ it 'runs multiple coersions' do
13
+ v.validate('1aaa2', Float, coerce: [lambda { |o| o.gsub('a', '') }, :to_i]).must_equal(12.0)
14
+ end
15
+
16
+ it 'defaults missing values' do
17
+ v.validate(nil, Integer, default: 1).must_equal(1)
18
+ v.validate(nil, Integer, default: lambda { 2 * 5 }).must_equal(10)
19
+ end
20
+
21
+ it 'validates with lambdas' do
22
+ v.validate(nil, Integer, :validate => lambda { |v| v = 60 * 60 }).must_equal(60 * 60)
23
+ end
24
+
25
+ it 'validates with procs' do
26
+ v.validate('is_this_valid?', String) do |v|
27
+ v = 'Validated with Proc'
28
+ end.must_equal('Validated with Proc')
29
+ end
30
+
31
+ it 'verifies numbers with common params' do
32
+ v.validate(122, Integer, min: 120, max: 500, in: (100..200), is: 122).must_equal(122)
33
+ end
34
+
35
+ it 'verifies strings with common params' do
36
+ v.validate('this is a test string', String, min_length: 21, max_length: 30, format: /^t.*g$/).must_equal 'this is a test string'
37
+ end
38
+
39
+ it 'coerces true' do
40
+ v.validate('t', :boolean).must_equal true
41
+ v.validate('true', :boolean).must_equal true
42
+ v.validate('yes', :boolean).must_equal true
43
+ v.validate('1', :boolean).must_equal true
44
+ v.validate(1, :boolean).must_equal true
45
+ end
46
+
47
+ it 'coerces false' do
48
+ v.validate('f', :boolean).must_equal false
49
+ v.validate('false', :boolean).must_equal false
50
+ v.validate('no', :boolean).must_equal false
51
+ v.validate('0', :boolean).must_equal false
52
+ v.validate(0, :boolean).must_equal false
53
+ end
54
+
55
+
56
+ it 'coerces array' do
57
+ v.validate('1|2|3', Array, delimiter: '|').must_equal ["1", "2", "3"]
58
+ end
59
+
60
+ it 'coerces hash' do
61
+ v.validate('{a => 1,b => 2,c => d}', Hash, delimiter: ',', separator: '=>').must_equal({"a" => "1", "b" => "2", "c" => "d"})
62
+ end
63
+
64
+ it 'validates a hash using a block' do
65
+ h = {
66
+ ignored: "this will be ignored because it's not mentioned",
67
+ to_be_renamed: :renamed_value,
68
+ 'integer_coercion': "1",
69
+ proc_validation: "is_this_valid?",
70
+ recursive: {}
71
+ }
72
+ r = v.validate(h, Hash, symbolize_keys: true) do
73
+ key :doesnt_exist, nil, required: true
74
+ key :to_be_renamed, Symbol, as: :renamed
75
+ #Default Lambdas take no parameters
76
+ key :proc_default, Integer, default: lambda { 1 * 5 }
77
+ key :proc_validation, String, validate: lambda { |v| v = 'Validated in proc' }
42
78
  #recursive
43
- param :recursive do
44
- param :wasnt_here_before, default: true
79
+ key :recursive, Hash do
80
+ key :wasnt_here_before, :boolean, default: true
45
81
  end
46
82
  end
47
- }
48
83
 
49
-
50
- it 'does amazing things' do
51
84
  (r.valid?).must_equal false
52
85
  r[:ignored].must_be_nil
53
- r[:no_value].must_equal 1
54
- r[:proc_default].must_equal 5
55
- r[:renamed].must_equal :to_be_renamed
56
- r[:integer_coercion].must_equal 1
57
- r[:bad_number].must_equal 12.0
58
-
59
- r[:array_with_delim].must_equal ["1", "2", "3"]
60
- r[:hash_as_string].must_equal ({ "a" => "1", "b" => "2", "c" => "d" })
61
- r[:missing_with_validation].must_equal 60 * 60
62
- r[:is_true].must_equal true
63
- r[:is_false].must_equal false
64
-
86
+ # r[:proc_default].must_equal 5
87
+ r[:renamed].must_equal :renamed_value
65
88
  #recursive checking
66
89
  r[:recursive][:wasnt_here_before].must_equal true
67
90
 
68
91
  #failed items don't show up
69
- r.errors.size.must_equal 2
70
92
  r[:doesnt_exist].must_be_nil
71
- r[:proc_validation].must_be_nil
72
- r.errors[0].must_equal 'Parameter doesnt_exist is required and missing'
73
- r.errors[1].must_equal 'is_this_valid? failed validation using proc'
93
+ r[:proc_validation].must_equal 'Validated in proc'
94
+
95
+ r.validation_errors.size.must_equal 1
96
+ r.validation_errors[0].must_equal "Error processing key 'doesnt_exist': Required Parameter missing and has no default specified"
74
97
 
75
98
  end
76
99
 
77
- it 'injects into current class' do
78
- r = HashParams.new({will_be_injected: 12345}, self) do
79
- param :will_be_injected
100
+ it 'validates variables in the local binding' do
101
+
102
+ x='10'
103
+ y='this is a test string'
104
+ z={}
105
+ will_be_int='100'
106
+
107
+ HashParams.with_binding do
108
+ var :x, Integer, min: 10, max: 100
109
+ var :y, String, min_length: 21, max_length: 30, format: /^t.*g$/
110
+ var :z, Hash, raise_errors: true, symbolize_keys: true, make_methods: true do
111
+ key :blah, String, default: 1
112
+ end
113
+ var :will_be_int, :to_i
80
114
  end
81
- r[:will_be_injected].must_equal 12345
82
- @will_be_injected.must_equal 12345
83
- will_be_injected.must_equal 12345
115
+ x.must_equal 10
116
+ y.must_equal 'this is a test string'
117
+ z[:blah].must_equal '1'
118
+ z.blah.must_equal '1'
119
+ will_be_int.must_equal 100
84
120
  end
85
121
 
122
+
86
123
  end
data/spec/spec_helper.rb CHANGED
@@ -11,14 +11,3 @@ require 'minitest/spec'
11
11
  require 'minitest/autorun'
12
12
  require 'pry'
13
13
 
14
- #require 'minitest/mock'
15
-
16
- # require 'rack/test'
17
- #
18
- # require 'dummy/app'
19
- #
20
- # def app
21
- # App
22
- # end
23
- #
24
- # #include Rack::Test::Methods
@@ -0,0 +1,181 @@
1
+ class HashParams < Hash
2
+ VERSION = '0.0.3'
3
+
4
+ attr :errors
5
+
6
+ def initialize(incoming_hash={}, opts={})
7
+ @opts = opts
8
+ @incoming_hash = incoming_hash
9
+ @errors =[]
10
+ # @parent = code.binding.eval 'self'
11
+
12
+ #@opts[:injection_target] = self if @opts[:injection_target] == :self
13
+
14
+ #binding.pry
15
+
16
+ if block_given?
17
+ instance_eval(&Proc.new)
18
+ else
19
+ #no proc was given. This means pass all values
20
+ @incoming_hash.each do |k, v|
21
+ set_key_value k, v
22
+ end
23
+ end
24
+ end
25
+
26
+ def valid?
27
+ @errors.empty?
28
+ end
29
+
30
+ def param(key, h = {})
31
+ begin
32
+ #What happens if value is FalseClass ? Need something a little better
33
+ val = @incoming_hash[key] || @incoming_hash[key.to_sym] || @incoming_hash[key.to_s]
34
+ if val.nil? && h[:default]
35
+ val = h[:default].respond_to?(:call) ? h[:default].call(self) : h[:default]
36
+ end
37
+ #don't bother with the rest if required parameter is missing
38
+ raise "Parameter #{key} is required and missing" if h[:required] && val.nil?
39
+ #do all coercion and transformation first there could be an array of coersions they will be run in order
40
+ Array(h[:coerce]).each do |c|
41
+ begin
42
+ val = HashParams.coerce(val, c, h)
43
+ rescue => e
44
+ @errors << e.to_s
45
+ end
46
+ end
47
+ binding.pry if key == :integer_coercion
48
+ #coersion could return a nil which won't validate, it could return a false which will attempt to validate
49
+ begin
50
+ if HashParams.validate(val, h)
51
+ #The value is valid add it
52
+ set_key_value key, val, h[:as]
53
+ end
54
+ rescue => e
55
+ @errors << e.to_s
56
+ end
57
+
58
+ #after all that see if a block is given and process that
59
+ if block_given? && val.is_a?(Hash)
60
+ #Proc.new references the implict block
61
+ val = HashParams.new(val, {}, &Proc.new)
62
+ set_key_value key, val, h[:as]
63
+ end
64
+ val
65
+ rescue => e
66
+ @errors << e.to_s
67
+ end
68
+ if @errors.length > 0 && @opts[:raise_errors]
69
+ raise @errors.join("\n")
70
+ end
71
+ val
72
+ end
73
+
74
+ def inject_into_target(target, var_name, val)
75
+ if target
76
+ #for read write methods
77
+ target.singleton_class.class_eval do
78
+ attr_accessor var_name;
79
+ end
80
+ target.send("#{var_name}=", val)
81
+ end
82
+ end
83
+
84
+ def self.validate(param, options ={})
85
+ return false if param.nil?
86
+ is_valid = true
87
+ errors =[]
88
+ options.each do |key, value|
89
+
90
+ error = case key
91
+ when :validate
92
+ "#{param.to_s} failed validation using proc" if value.respond_to?(:call) && !value.call(param)
93
+ when :blank
94
+ 'Parameter cannot be blank' if !value && blank?(param)
95
+ when :format
96
+ 'Parameter must be a string if using the format validation' && next unless param.kind_of?(String)
97
+ "Parameter must match format #{value}" unless param =~ value
98
+ when :is
99
+ "Parameter must be #{value}" unless param === value
100
+ when :in, :within, :range
101
+ "Parameter must be within #{value}" unless value.respond_to?(:include) ? value.include?(param) : Array(value).include?(param)
102
+ when :min
103
+ "Parameter cannot be less than #{value}" unless value <= param
104
+ when :max
105
+ "Parameter cannot be greater than #{value}" unless value >= param
106
+ when :min_length
107
+ "Parameter cannot have length less than #{value}" unless value <= param.length
108
+ when :max_length
109
+ "Parameter cannot have length greater than #{value}" unless value >= param.length
110
+ else
111
+ nil
112
+ end
113
+ if error
114
+ errors << error
115
+ is_valid = false
116
+ end
117
+ end
118
+
119
+ #return true or false depending on if it validated
120
+ unless errors.empty?
121
+ raise errors.join("\n")
122
+ end
123
+ is_valid
124
+ end
125
+
126
+
127
+ def self.coerce(val, type, h)
128
+
129
+ # exceptions bubble up
130
+ #order is important
131
+ return val if type.nil? || val.nil?
132
+
133
+ #two special types of transforms
134
+ #There is no Boolean type so we handle them special
135
+ if type == :boolean || type =='boolean'
136
+ return val if (val == true || val == false)
137
+ return false if /(false|f|no|n|0)$/i === val.to_s.downcase
138
+ return true if /(true|t|yes|y|1)$/i === val.to_s.downcase
139
+
140
+ # if we can't parse we return a nil
141
+ # maybe !!val is a better return?
142
+ return nil
143
+ end
144
+ #they have given us a coercion which is a string or symbol which is not "boolean", we are going to cast this into a proc and run it
145
+
146
+ return type.to_proc.call(val) if type.is_a?(Symbol) || type.is_a?(String)
147
+ #could be a proc
148
+
149
+ return type.call(val) if type.respond_to?(:call)
150
+ #nothing but simple types left
151
+ return val if val.is_a?(type)
152
+ return Integer(val) if type == Integer
153
+ return Float(val) if type == Float
154
+ return String(val) if type == String
155
+ return Date.parse(val) if type == Date
156
+ return Time.parse(val) if type == Time
157
+ return DateTime.parse(val) if type == DateTime
158
+ return Array(val.split(h[:delimiter] || ',')) if type == Array
159
+ return Hash[val.gsub(/[{}]/, '').gsub('}', '').split(h[:delimiter] || ',').map { |c| c.split(h[:separator] ||':').map { |i| i.strip } }] if type == Hash
160
+
161
+ nil
162
+ end
163
+
164
+ def present?(object)
165
+ !blank?(object)
166
+ end
167
+
168
+ def blank?(object)
169
+ object.nil? || (object.respond_to?(:empty) && object.empty)
170
+ end
171
+
172
+ def set_key_value(key, value, as = nil)
173
+ key = as unless as.nil?
174
+ key = key.to_s.to_sym if @opts[:symbolize_keys]
175
+ inject_into_target(@opts[:injection_target], key, value) if @opts[:injection_target]
176
+ inject_into_target(self, key, value) if @opts[:make_methods]
177
+ self[key]=value
178
+ end
179
+
180
+
181
+ end
@@ -0,0 +1,102 @@
1
+ require_relative 'spec_helper'
2
+
3
+
4
+ describe HashParams do
5
+
6
+ let (:r) {
7
+ HashParams.new(
8
+ {
9
+ ignored: "this will be ignored because it's not mentioned",
10
+ to_be_renamed: :to_be_renamed,
11
+ integer_coercion: "1",
12
+ bad_number: '1aaa2',
13
+ array_with_delim: '1|2|3',
14
+ hash_as_string: "{a => 1,b => 2,c => d}",
15
+ proc_validation: "is_this_valid?",
16
+ some_number: 122,
17
+ some_string: 'this is a test string' ,
18
+ is_true: 'true',
19
+ is_false: 'f',
20
+ recursive: {}
21
+ }
22
+ ) do
23
+ param :doesnt_exist, required: true
24
+ param :to_be_renamed, as: :renamed
25
+ param :no_value, default: 1
26
+ #proc default relying on previously set value
27
+ param :proc_default, default: lambda { |o| o[:no_value] * 5 }
28
+ param :integer_coercion, coerce: Integer
29
+ #chained coersions of various types
30
+ param :bad_number, coerce: [lambda { |o| o.gsub('a', '') }, :to_i, Float]
31
+ #arrays and hashes
32
+ param :array_with_delim, coerce: Array, delimiter: '|'
33
+ param :hash_as_string, coerce: Hash, delimiter: ',', separator: '=>'
34
+ param :proc_validation, validate: lambda { |v| v == 'Failed_proc_validation' }
35
+ #validations
36
+ param :some_number, min: 120, max: 500, in: (100..200), is: 122
37
+ param :some_string, min_length: 21, max_length: 30, format: /^t.*g$/
38
+ #combinations
39
+ param :missing_with_validation, coerce: Integer, :default => 60 * 60, :validate => lambda { |v| v >= 60 * 60 }
40
+ param :is_true, coerce: :boolean
41
+ param :is_false, coerce: :boolean
42
+ #recursive
43
+ param :recursive do
44
+ param :wasnt_here_before, default: true
45
+ end
46
+ end
47
+ }
48
+
49
+
50
+ it 'does amazing things' do
51
+ (r.valid?).must_equal false
52
+ r[:ignored].must_be_nil
53
+ r[:no_value].must_equal 1
54
+ r[:proc_default].must_equal 5
55
+ r[:renamed].must_equal :to_be_renamed
56
+ r[:integer_coercion].must_equal 1
57
+ r[:bad_number].must_equal 12.0
58
+
59
+ r[:array_with_delim].must_equal ["1", "2", "3"]
60
+ r[:hash_as_string].must_equal ({ "a" => "1", "b" => "2", "c" => "d" })
61
+ r[:missing_with_validation].must_equal 60 * 60
62
+ r[:is_true].must_equal true
63
+ r[:is_false].must_equal false
64
+
65
+ #recursive checking
66
+ r[:recursive][:wasnt_here_before].must_equal true
67
+
68
+ #failed items don't show up
69
+ r.errors.size.must_equal 2
70
+ r[:doesnt_exist].must_be_nil
71
+ r[:proc_validation].must_be_nil
72
+ r.errors[0].must_equal 'Parameter doesnt_exist is required and missing'
73
+ r.errors[1].must_equal 'is_this_valid? failed validation using proc'
74
+
75
+ end
76
+
77
+ it 'injects into current class' do
78
+ r = HashParams.new({will_be_injected: 12345}, injection_target: self) do
79
+ param :will_be_injected
80
+ end
81
+ r[:will_be_injected].must_equal 12345
82
+ @will_be_injected.must_equal 12345
83
+ will_be_injected.must_equal 12345
84
+ end
85
+
86
+ it 'passes through without alteration' do
87
+ r=HashParams.new(test: 1, two: {three: :four})
88
+ r[:test].must_equal 1
89
+ r[:two][:three].must_equal :four
90
+ end
91
+
92
+ it 'validates plain objects' do
93
+ HashParams.validate(1, min: 0, max: 10, is: 1).must_equal true
94
+ end
95
+ it 'coerces plain objects' do
96
+ hash_as_string = "{a => 1,b => 2,c => d}"
97
+ h=HashParams.coerce(hash_as_string, Hash, delimiter: ',', separator: '=>' )
98
+ h.must_be_instance_of Hash
99
+
100
+
101
+ end
102
+ end
@@ -0,0 +1,27 @@
1
+ require 'pry'
2
+ module M1
3
+ def im
4
+ puts 'm1 im'
5
+ end
6
+ end
7
+
8
+ module M2
9
+ def self.cm
10
+ puts 'm2 cm'
11
+ end
12
+ end
13
+
14
+
15
+ module T1
16
+ include M1
17
+ end
18
+ module T2
19
+ extend M1
20
+ end
21
+ module T3
22
+ include M2
23
+ end
24
+ module T4
25
+ extend M2
26
+ end
27
+
data/tmp/var_spec.rb ADDED
@@ -0,0 +1,9 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe HashParams do
4
+ let(:v) { HashParams }
5
+ it 'does things' do
6
+ HashParams::BindingValidator("test")
7
+ binding.pry
8
+ end
9
+ end
@@ -0,0 +1,109 @@
1
+ class YamlParams < HashParams
2
+
3
+ ENVIRONMENT = ENV['HASH_PARAMS_ENV'] || (defined?(Rails) && Rails.env) || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
4
+
5
+ def initialize(file_name=nil, opts={})
6
+
7
+ env ||= opts[:env] || opts[:environment] || ENVIRONMENT
8
+
9
+ file_name = nil if [:defaults, :default, :auto].include?(file_name)
10
+
11
+ h =if file_name
12
+ hash_from_yaml_file(file_name)
13
+ else
14
+ hash_from_default_yaml_files(opts[:app_name], env, opts[:roots], opts[:file_separator], opts[:file_extension])
15
+ end
16
+
17
+ if block_given?
18
+ # warn '[DEPRECATION] Passing blocks into the constructor is deprecated. Please use validate or strictly validate in the future'
19
+ super(h, opts, &Proc.new)
20
+ else
21
+ super(h, opts)
22
+ end
23
+ end
24
+
25
+
26
+ def hash_from_yaml_file(filename, env=ENVIRONMENT)
27
+ r = File.exists?(filename) ? YAML::load(ERB.new(File.read(filename)).result) : {}
28
+ r[env] || r
29
+ end
30
+
31
+
32
+ def hash_from_default_yaml_files(app_name=nil, env=nil, roots=nil, file_separator=nil, file_extension=nil)
33
+ #if a nil is passed in we still use the defaults
34
+ app_name ||= ''
35
+ env ||= ENVIRONMENT
36
+ roots ||= nil
37
+ file_separator ||= '_'
38
+ file_extension ||= 'yml'
39
+
40
+ h = {}
41
+ home_dir = File.expand_path('~')
42
+ hostname = Socket.gethostname
43
+
44
+ base_file_names = %W(
45
+ settings.#{file_extension}
46
+ default.#{file_extension}
47
+
48
+ #{env}.#{file_extension}
49
+
50
+ #{hostname}.#{file_extension}
51
+ #{hostname}#{file_separator}#{env}.#{file_extension}
52
+
53
+ local.#{file_extension}
54
+ local#{file_separator}#{env}.#{file_extension}
55
+ settings.local.#{file_extension}
56
+ settings.local#{file_separator}#{env}.#{file_extension}
57
+ config.local.#{file_extension}
58
+ config.local#{file_separator}#{env}.#{file_extension}
59
+ #{app_name}#{file_separator}settings.#{file_extension}
60
+ #{app_name}#{file_separator}config.#{file_extension}
61
+ #{app_name}#{file_separator}default.#{file_extension}
62
+ #{app_name}#{file_separator}#{env}.#{file_extension}
63
+ #{app_name}#{file_separator}#{hostname}.#{file_extension}
64
+ #{app_name}#{file_separator}#{hostname}#{file_separator}#{env}.#{file_extension}
65
+ #{app_name}#{file_separator}local.#{file_extension}
66
+ #{app_name}#{file_separator}local#{file_separator}#{env}.#{file_extension}
67
+ #{app_name}#{file_separator}settings.local.#{file_extension}
68
+ #{app_name}#{file_separator}settings.local#{file_separator}#{env}.#{file_extension}
69
+ #{app_name}#{file_separator}config.local.#{file_extension}
70
+ #{app_name}#{file_separator}config.local#{file_separator}#{env}.#{file_extension}
71
+
72
+ )
73
+
74
+ all_roots = Array(roots) if roots
75
+ all_roots ||= [
76
+ Dir.pwd,
77
+ File.join('/etc', app_name.to_s),
78
+ File.join('/usr', 'local', 'etc', app_name.to_s),
79
+ File.join(home_dir, 'etc', app_name.to_s),
80
+ File.join(home_dir, ".#{app_name}"),
81
+ File.join(home_dir, '.hash_params', app_name.to_s),
82
+ File.join(Dir.pwd, 'config'),
83
+ File.join(Dir.pwd, 'settings')
84
+ ]
85
+ if defined?(Rails)
86
+ all_roots << Rails.root.join('config')
87
+ end
88
+
89
+ all_roots.each do |root|
90
+ base_file_names.each do |fname|
91
+ file = File.join(root, fname)
92
+ h = deep_merge(h, hash_from_yaml_file(file)) if File.exists?(file)
93
+ end
94
+ end
95
+ h
96
+ end
97
+
98
+ def deep_merge(hash, other_hash)
99
+ if other_hash.is_a?(::Hash) && hash.is_a?(::Hash)
100
+ other_hash.each do |k, v|
101
+ hash[k] = hash.key?(k) ? deep_merge(hash[k], v) : v
102
+ end
103
+ hash
104
+ else
105
+ other_hash
106
+ end
107
+ end
108
+ end
109
+