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.
- checksums.yaml +4 -4
- data/Gemfile.lock +8 -8
- data/README.md +167 -109
- data/coverage/assets/0.9.0/application.css +799 -0
- data/coverage/assets/0.9.0/application.js +1707 -0
- data/coverage/assets/0.9.0/colorbox/border.png +0 -0
- data/coverage/assets/0.9.0/colorbox/controls.png +0 -0
- data/coverage/assets/0.9.0/colorbox/loading.gif +0 -0
- data/coverage/assets/0.9.0/colorbox/loading_background.png +0 -0
- data/coverage/assets/0.9.0/favicon_green.png +0 -0
- data/coverage/assets/0.9.0/favicon_red.png +0 -0
- data/coverage/assets/0.9.0/favicon_yellow.png +0 -0
- data/coverage/assets/0.9.0/loading.gif +0 -0
- data/coverage/assets/0.9.0/magnify.png +0 -0
- data/coverage/assets/0.9.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/coverage/assets/0.9.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/coverage/assets/0.9.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/coverage/assets/0.9.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/coverage/assets/0.9.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/coverage/assets/0.9.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/coverage/assets/0.9.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/coverage/assets/0.9.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/coverage/index.html +1597 -369
- data/hash_params.gemspec +14 -5
- data/lib/hash_params/binding_validator.rb +26 -0
- data/lib/hash_params/hash_validator.rb +71 -0
- data/lib/hash_params/validator.rb +119 -0
- data/lib/hash_params/yaml_params.rb +93 -0
- data/lib/hash_params.rb +15 -142
- data/spec/hash_params_spec.rb +100 -63
- data/spec/spec_helper.rb +0 -11
- data/tmp/hash_params.rb +181 -0
- data/tmp/hash_params_spec.rb +102 -0
- data/tmp/module_spec.rb +27 -0
- data/tmp/var_spec.rb +9 -0
- data/tmp/yaml_params.rb +109 -0
- metadata +36 -3
data/spec/hash_params_spec.rb
CHANGED
@@ -2,85 +2,122 @@ require_relative 'spec_helper'
|
|
2
2
|
|
3
3
|
|
4
4
|
describe HashParams do
|
5
|
+
let(:v) { HashParams }
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
44
|
-
|
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[:
|
54
|
-
r[:
|
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].
|
72
|
-
|
73
|
-
r.
|
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 '
|
78
|
-
|
79
|
-
|
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
|
-
|
82
|
-
|
83
|
-
|
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
data/tmp/hash_params.rb
ADDED
@@ -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
|
data/tmp/module_spec.rb
ADDED
@@ -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
data/tmp/yaml_params.rb
ADDED
@@ -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
|
+
|