rb-optionsresolver 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 64f1580fdc0be144d8b75ac0083dbf605879cd91d32424cfc48aa0b0a548203e
4
+ data.tar.gz: 224c3d263123c0c571ccf360081b6dbce951ae2ff9d2fd5bec1caa009de37977
5
+ SHA512:
6
+ metadata.gz: 3da84da48bf6f4372e0d9e918d44495ed0b11e49a7c9bc9f84f1a56156cbeb904b1840da178f8d0a06a6eb71c2d018b23dc894ef98cbcaa6e41b3f1f8b5fe58e
7
+ data.tar.gz: 2be3435849f85b0a826ec0f2777dbf0e4a1ac53b62c181ca5926a1772955b4513b3ed183acab90bdddd675307bd0e8ae50451a7a5e23302ce41d9de8fc701f89
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ /Gemfile.lock
2
+ /*.gem
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 NamNV609
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,381 @@
1
+ # Rb OptionsResolver - Symfony OptionsResolver for Ruby
2
+
3
+ > The Rb OptionsResolver library is Symfony OptionsResolver for Ruby. It allows you to create an options system with required options, defaults, validation (type, value), normalization and more.
4
+
5
+ ## Installation
6
+
7
+ ```
8
+ $ gem install rb-optionsresolver
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ To use OptionsResolver:
14
+
15
+ ```ruby
16
+ require "rb-optionsresolver"
17
+ ```
18
+
19
+ Imagine you have a `Mailer` class which has four options: `host`, `username`, `password` and `port`:
20
+
21
+ ```ruby
22
+ class Mailer
23
+ def initialize options
24
+ @options = options
25
+ end
26
+ end
27
+ ```
28
+
29
+ When accessing the `@options`, you need to add a lot of boilerplate code to check which options are set:
30
+
31
+ ```ruby
32
+ class Mailer
33
+ # ...
34
+
35
+ def send_mail from, to
36
+ mail = ...
37
+ mail.set_host @options[:host] ? @options[:host] : "smtp.example.com"
38
+ mail.set_username @options[:username] ? @options[:username] : "user"
39
+ mail.set_password @options[:password] ? @options[:password] : "pa$$word"
40
+ mail.set_port @options[:port] ? @options[:port] : 25
41
+
42
+ # ...
43
+ end
44
+ end
45
+ ```
46
+
47
+ This boilerplate is hard to read and repetitive. Also, the default values of the options are buried in the business logic of your code. Use code below to fix that:
48
+
49
+ ```ruby
50
+ class Mailer
51
+ def initialize options
52
+ default_options = {
53
+ host: "smtp.example.com",
54
+ username: "user"
55
+ }
56
+
57
+ @options = [*default_options, *options].to_h
58
+ end
59
+ end
60
+ ```
61
+
62
+ Now all four options are guaranteed to be set. But what happens if the user of the `Mailer` class makes a mistake?
63
+
64
+ ```ruby
65
+ mailer_opts = {
66
+ usernme: "johndoe" # usernme misspelled (instead of username)
67
+ }
68
+ mailer = Mailer.new mailer_opts
69
+ ```
70
+
71
+ No error will be shown. In the best case, the bug will appear during testing, but the developer will spend time looking for the problem. In the worst case, the bug might not appear until it's deployed to the live system.
72
+
73
+ Fortunately, the `OptionsResolver` class helps you to fix this problem:
74
+
75
+ ```ruby
76
+ class Mailer
77
+ def initialize options
78
+ resolver = OptionsResolver.new
79
+ resolver.set_defaults({
80
+ host: "smtp.example.com",
81
+ username: "user",
82
+ password: "pa$$word",
83
+ port: 25
84
+ })
85
+
86
+ @options = resolver.resolve options
87
+ end
88
+ end
89
+ ```
90
+
91
+ Like before, all options will be guaranteed to be set. Additionally, an `UndefinedOptions` is thrown if an unknown option is passed:
92
+
93
+ ```ruby
94
+ mailer_opts = {usernme: "johndoe"}
95
+ mailer = Mailer.new mailer_opts
96
+
97
+ # The option "usernme" does not exist.
98
+ # Know options are: "host", "username", "password", "port" (UndefinedOptions)
99
+ ```
100
+
101
+ The rest of your code can access the values of the options without boilerplate code:
102
+
103
+ ```ruby
104
+ class Mailer
105
+ # ...
106
+
107
+ def send_mail from, to
108
+ mail = ...
109
+
110
+ mail.set_host @options[:host]
111
+ mail.set_username @options[:username]
112
+ mail.set_password @options[:password]
113
+ mail.set_port @options[:port]
114
+ end
115
+ end
116
+ ```
117
+
118
+ ### Required Options
119
+
120
+ If an option must be set by the caller, pass that option to `set_required()`. For example, to make the `host` option required, you can do:
121
+
122
+ ```ruby
123
+ class Mailer
124
+ def initialize options
125
+ resolver = OptionsResolver.new
126
+ resolver.set_required "host"
127
+
128
+ @options = resolver.resolve options
129
+ end
130
+ end
131
+ ```
132
+
133
+ If you omit a required option, a `MissingOptions` will be thrown:
134
+
135
+ ```ruby
136
+ mailer = Mailer.new
137
+
138
+ # The required options "host" is missing. (MissingOptions)
139
+ ```
140
+
141
+ The `set_required()` method accepts a single name or an array of option names if you have more than one required option:
142
+
143
+ ```ruby
144
+ class Mailer
145
+ # ...
146
+ resolver.set_required %w(host username password)
147
+ end
148
+ ```
149
+
150
+ Use `is_required?()` to find out if an option is required. You can use `get_required_options()` to retrieve the names of all required options:
151
+
152
+ ```
153
+ required_options = resolver.get_required_options()
154
+ ```
155
+
156
+ If you want to check whether a required option is still missing from the default options, you can use `is_missing?()`. The difference between this and `is_required?()` is that this method will return false if a required option has already been set:
157
+
158
+ ```ruby
159
+ # ...
160
+ resolver.is_required? "host" # true
161
+ resolver.is_missing? "host" # true
162
+ resolver.set_default "host", "smtp.example.com"
163
+ resolver.is_required? "host" # true
164
+ resolver.is_missing? "host" # false
165
+ ```
166
+
167
+ The method `get_missing_options()` lets you access the names of all missing options.
168
+
169
+ ### Type Validation
170
+
171
+ You can run additional checks on the options to make sure they were passed correctly. To validate the types of the options, call `set_allowed_types()`:
172
+
173
+ ```ruby
174
+ # ...
175
+ # specify one allowed type
176
+ resolver.set_allowed_types "port", "int"
177
+ ```
178
+
179
+ > **TODO**: Specify multiple allowed types and can pass fully qualified class names.
180
+
181
+ You can pass any type for which an:
182
+
183
+ * `integer` (`int`)
184
+ * `string` (`str`)
185
+ * `array` (`arr`)
186
+ * `boolean` (`bool`)
187
+ * `float`
188
+ * `hash`
189
+ * `symbol` (`sym`)
190
+ * `range`
191
+ * `regexp`
192
+ * `proc`
193
+
194
+ If you pass an invalid option now, an `InvalidOptions` is thrown:
195
+
196
+ ```ruby
197
+ mailer_opts = {
198
+ port: "465"
199
+ }
200
+ mailer = Mailer.new mailer_opts
201
+
202
+ # The option "port" with "465" is expected to be of type "int" (InvalidOptions)
203
+ ```
204
+
205
+ > **TODO**: In sub-classes, you can use `add_allowed_types()` to add additional allowed types without erasing the ones already set.
206
+
207
+ ### Value Validation
208
+
209
+ Some options can only take one of a fixed list of predefined values. For example, suppose the `Mailer` class has a `transport` option which can be one of `sendmail`, `mail` and `smtp`. Use the method `set_allowed_values()` to verify that the passed option contains one of these values:
210
+
211
+ ```ruby
212
+ class Mailer
213
+ # ...
214
+ resolver.set_default("transport", "sendmail")
215
+ .set_allowed_values("transport", %w(sendmail mail smtp))
216
+ end
217
+ ```
218
+
219
+ If you pass an invalid transport, an `InvalidOptions` is thrown:
220
+
221
+ ```ruby
222
+ mailer_opts = {
223
+ transport: "send-mail"
224
+ }
225
+ mailer = Mailer.new mailer_opts
226
+
227
+ # The option "transport" with value "send-mail" is invalid.
228
+ # Accepted values are "sendmail", "mail", "smtp" (RuntimeError)
229
+ ```
230
+
231
+ For options with more complicated validation schemes, pass a proc (or lambda) which returns `true` for acceptable values and `false` for invalid values:
232
+
233
+ ```ruby
234
+ # ...
235
+ resolver.set_allowed_values "transport", Proc.new{|transport|
236
+ # return true or false
237
+ %w(sendmail mail smtp).include? transport
238
+ }
239
+ ```
240
+
241
+ > **TODO**: In sub-classes, you can use `add_allowed_values()` to add additional allowed values without erasing the ones already set.
242
+
243
+ ### Option Normalization
244
+
245
+
246
+ Sometimes, option values need to be normalized before you can use them. For instance, assume that the `host` should always start with `http://`. To do that, you can write normalizers. Normalizers are executed after validating an option. You can configure a normalizer by calling `set_normailizer()`:
247
+
248
+ ```ruby
249
+ # ...
250
+ resolver.set_normailizer "host", lambda{|options, host|
251
+ host = "http://#{host}" unless /^https?\:\/\//.match? host
252
+ host
253
+ }
254
+ ```
255
+
256
+ The normalizer receives the actual `host` and returns the normalized form. You see that the proc (or lambda) also takes an `options` parameter. This is useful if you need to use other options during normalization:
257
+
258
+ ```ruby
259
+ # ...
260
+ .set_normalizer("host", Proc.new{|options, host|
261
+ unless /^https?\:\/\//.match? host
262
+ if options["encryption"] == "ssl"
263
+ host = "https://#{host}"
264
+ else
265
+ host = "http://#{host}"
266
+ end
267
+ end
268
+
269
+ host
270
+ })
271
+ ```
272
+
273
+ ### Default Values that Depend on another Option
274
+
275
+ Suppose you want to set the default value of the `port` option based on the encryption chosen by the user of the `Mailer` class. More precisely, you want to set the port to `465` if SSL is used and to `25` otherwise.
276
+
277
+ You can implement this feature by passing a proc (or lambda) as the default value of the `port` option. The proc (or lambda) receives the options as argument. Based on these options, you can return the desired default value:
278
+
279
+ ```ruby
280
+ # ...
281
+ resolver.set_default("encryption", nil)
282
+ .set_default("port", lambda{|options, _| options["encryption"] == "ssl" ? 465 :25})
283
+ ```
284
+
285
+ > The argument of the callable must be type hinted as `options`. Otherwise, the callable itself is considered as the default value of the option.
286
+
287
+ > The proc (or lambda) is only executed if the `port` option isn't set by the user or overwritten in a sub-class.
288
+
289
+ A previously set default value can be accessed by adding a second argument to the proc (or lambda):
290
+
291
+ ```ruby
292
+ resolver.set_defaults({
293
+ encryption: nil,
294
+ host: "example.org"
295
+ }).set_default("host", Proc.new{|options, previous_host_value|
296
+ options["encryption"] == "ssl" ? "secure.example.org" : previous_host_value
297
+ })
298
+ ```
299
+
300
+ As seen in the example, this feature is mostly useful if you want to reuse the default values set in parent classes in sub-classes.
301
+
302
+ ### Options without Default Values
303
+
304
+ In some cases, it is useful to define an option without setting a default value. This is useful if you need to know whether or not the user _actually_ set an option or not. For example, if you set the default value for an option, it's not possible to know whether the user passed this value or if it simply comes from the default:
305
+
306
+ ```ruby
307
+ class Mailer
308
+ def initialize options
309
+ resolver = OptionsResolver.new
310
+ resolver.set_default("port", 25)
311
+
312
+ @options = resolver.resolve options
313
+ end
314
+
315
+ def send_mail from, to
316
+ # Is this the default value or did the caller of the class really
317
+ # set the port to 25?
318
+
319
+ if @options["port"] == 25
320
+ # ...
321
+ end
322
+ end
323
+ end
324
+ ```
325
+
326
+ You can use `set_defined()` to define an option without setting a default value. Then the option will only be included in the resolved options if it was actually passed to `resolve()`:
327
+
328
+ ```ruby
329
+ class Mailer
330
+ def initialize options
331
+ resolver = OptionsResolver.new
332
+ resolver.set_defined "port"
333
+
334
+ @options = resolver.resolve options
335
+ end
336
+
337
+ def send_mail from = nil, to = nil
338
+ if @options["port"]
339
+ puts "Set!"
340
+ else
341
+ puts "Not set"
342
+ end
343
+ end
344
+ end
345
+
346
+ mailer_opts = {}
347
+ mailer = Mailer.new mailer_opts
348
+ mailer.send_mail
349
+ # => Not set!
350
+
351
+ mailer_opts = {port: 25}
352
+ mailer = Mailer.new mailer_opts
353
+ mailer.send_mail
354
+ # => Set!
355
+ ```
356
+
357
+ You can also pass an array of option names if you want to define multiple options in one go:
358
+
359
+ ```ruby
360
+ resolver.set_defined %w(port encryption)
361
+ ```
362
+
363
+ The methods `is_defined?()` and `get_defined_options()` let you find out which options are defined:
364
+
365
+ ```ruby
366
+ # ...
367
+ if resolver.is_defined? "host"
368
+ # One of the following was called:
369
+ # resolver.set_default "host", ...
370
+ # resolver.set_required "host"
371
+ # resolver.set_defined "host"
372
+ end
373
+
374
+ defined_options = resolver.get_defined_options
375
+ ```
376
+
377
+ That's it! You now have all the tools and knowledge needed to easily process options in your code.
378
+
379
+ # Credits
380
+
381
+ Original documentation for PHP: [https://symfony.com/doc/3.4/components/options_resolver.html](https://symfony.com/doc/3.4/components/options_resolver.html)
@@ -0,0 +1,5 @@
1
+ class InvalidOptions < StandardError
2
+ def initialize msg
3
+ super
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class InvalidParameter < StandardError
2
+ def initialize msg = "Default values is invalid object"
3
+ super
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class MissingOptions < StandardError
2
+ def initialize msg
3
+ super
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class UndefinedOptions < StandardError
2
+ def initialize msg
3
+ super
4
+ end
5
+ end
@@ -0,0 +1,242 @@
1
+ require "optionsresolver/exceptions/invalid_parameter"
2
+ require "optionsresolver/exceptions/undefined_options"
3
+ require "optionsresolver/exceptions/missing_options"
4
+ require "optionsresolver/exceptions/invalid_options"
5
+ require "optionsresolver/utils/hash_ext"
6
+
7
+ class OptionsResolver
8
+ def initialize
9
+ @defined_options = []
10
+ @required_options = []
11
+ @default_values = {}
12
+ @allowed_types = {}
13
+ @allowed_values = {}
14
+ @normalizers = {}
15
+ @previous_default_values = {}
16
+ end
17
+
18
+ def set_defined defined_keys
19
+ if defined_keys.is_a?(Array)
20
+ @defined_options.concat defined_keys
21
+ else
22
+ @defined_options.push defined_keys
23
+ end
24
+
25
+ self
26
+ end
27
+
28
+ def get_defined_options
29
+ @defined_options
30
+ end
31
+
32
+ def is_defined? option_key
33
+ @defined_options.include? option_key
34
+ end
35
+
36
+ def set_required required_keys
37
+ if required_keys.is_a?(Array)
38
+ @required_options.concat required_keys
39
+ @defined_options.concat required_keys
40
+ else
41
+ @required_options.push required_keys
42
+ @defined_options.push required_keys
43
+ end
44
+
45
+ self
46
+ end
47
+
48
+ def get_required_options
49
+ @required_options
50
+ end
51
+
52
+ def is_required? option_key
53
+ @required_options.include? option_key
54
+ end
55
+
56
+ def is_missing? option_key
57
+ !@default_values.include? option_key
58
+ end
59
+
60
+ def get_missing_options
61
+ @required_options.map do |required_key|
62
+ next if @default_values.include?(required_key)
63
+ required_key
64
+ end.compact
65
+ end
66
+
67
+ def set_default option_key, default_value
68
+ @previous_default_values[option_key] = @default_values[option_key] if
69
+ @default_values.include? option_key
70
+
71
+ @default_values[option_key] = default_value
72
+ self.set_defined option_key
73
+
74
+ self
75
+ end
76
+
77
+ def set_defaults option_default_values
78
+ raise InvalidParameter unless option_default_values.is_a? Hash
79
+
80
+ option_default_values.each do |opt_key, opt_value|
81
+ opt_key = opt_key.to_s
82
+
83
+ self.set_default(opt_key, opt_value).set_defined opt_key
84
+ end
85
+
86
+ self
87
+ end
88
+
89
+ def get_default_values option_key = nil
90
+ return @default_values unless option_key
91
+
92
+ @default_values[option_key]
93
+ end
94
+
95
+ def set_allowed_types option_key, option_value_types
96
+ @allowed_types[option_key] = option_value_types
97
+
98
+ self
99
+ end
100
+
101
+ def get_allowed_types option_key = nil
102
+ return @allowed_types unless option_key
103
+
104
+ @allowed_types[option_key]
105
+ end
106
+
107
+ def set_allowed_values option_key, option_allowed_value
108
+ @allowed_values[option_key] = option_allowed_value
109
+
110
+ self
111
+ end
112
+
113
+ def get_allowed_values option_key = nil
114
+ return @allowed_values unless option_key
115
+
116
+ @allowed_values
117
+ end
118
+
119
+ def set_normalizer option_key, normalizer_value
120
+ @normalizers[option_key] = normalizer_value
121
+
122
+ self
123
+ end
124
+
125
+ def resolve data_object
126
+ raise InvalidParameter unless data_object.is_a? Hash
127
+
128
+ # Unique @defined_options
129
+ @defined_options.uniq!
130
+ # Stringify hash keys
131
+ data_object = data_object.stringify_keys
132
+ # Check undefined options
133
+ check_undefined_options data_object.keys
134
+ # Set default values
135
+ data_object = set_options_default data_object
136
+ # Check missing required options
137
+ check_missing_required_options data_object
138
+ # Check invalid options type
139
+ check_invalid_options_type data_object
140
+ # Check invalid options value
141
+ check_invalid_options_value data_object
142
+ # Normalizer options value
143
+ data_object = normalizer_options_value data_object
144
+
145
+ data_object
146
+ end
147
+
148
+ private
149
+ def check_undefined_options option_keys
150
+ know_options_str = "\"#{@defined_options.join("\", \"")}\""
151
+
152
+ option_keys.each do |opt_key|
153
+ raise UndefinedOptions, "The option \"#{opt_key}\" does not exist. Know options are: #{know_options_str}" unless
154
+ @defined_options.include? opt_key.to_s
155
+ end
156
+ end
157
+
158
+ def set_options_default data_object
159
+ @default_values.each do |option_key, default_value|
160
+ next unless data_object[option_key].nil?
161
+
162
+ previous_default_value = @previous_default_values[option_key]
163
+ data_object[option_key] = default_value.is_a?(Proc) ? default_value.call(data_object, previous_default_value) : default_value
164
+ end
165
+
166
+ data_object
167
+ end
168
+
169
+ def check_missing_required_options data_object
170
+ @required_options.each do |required_key|
171
+ next if data_object[required_key.to_s]
172
+
173
+ raise MissingOptions, "The required options \"#{required_key}\" is missing."
174
+ end
175
+ end
176
+
177
+ def check_invalid_options_type data_object
178
+ @allowed_types.each do |option_key, allowed_type|
179
+ option_key = option_key.to_s
180
+ option_value = data_object[option_key]
181
+
182
+ case allowed_type.downcase
183
+ when "int", "integer"
184
+ throw_invalid_options_exception option_key, option_value, "int" unless option_value.is_a? Integer
185
+ when "str", "string"
186
+ throw_invalid_options_exception option_key, option_value, "str" unless option_value.is_a? String
187
+ when "arr", "array"
188
+ throw_invalid_options_exception option_key, option_value, "array" unless option_value.is_a? Array
189
+ when "bool", "boolean"
190
+ throw_invalid_options_exception option_key, option_value, "boolean" unless [true, false].include? option_value
191
+ when "float"
192
+ throw_invalid_options_exception option_key, option_value, "float" unless option_value.is_a? Float
193
+ when "hash"
194
+ throw_invalid_options_exception option_key, option_value, "hash" unless option_value.is_a? Hash
195
+ when "sym", "symbol"
196
+ throw_invalid_options_exception option_key, option_value, "symbol" unless option_value.is_a? Symbol
197
+ when "range"
198
+ throw_invalid_options_exception option_key, option_value, "range" unless option_value.is_a? Range
199
+ when "regexp"
200
+ throw_invalid_options_exception option_key, option_value, "regexp" unless option_value.is_a? Regexp
201
+ when "proc"
202
+ throw_invalid_options_exception option_key, option_value, "proc" unless option_value.is_a? Proc
203
+ end
204
+ end
205
+ end
206
+
207
+ def check_invalid_options_value data_object
208
+ @allowed_values.each do |option_key, allowed_value|
209
+ option_key = option_key.to_s
210
+ option_value = data_object[option_key]
211
+ is_valid_value = true
212
+ accepted_value_msg = ""
213
+
214
+ if allowed_value.is_a? Array
215
+ is_valid_value = allowed_value.include? option_value
216
+ accepted_value_msg = " Accepted values are \"#{allowed_value.join("\", \"")}\""
217
+ elsif allowed_value.is_a? Proc
218
+ is_valid_value = allowed_value.call option_value
219
+ else
220
+ is_valid_value = (option_value == allowed_value)
221
+ end
222
+
223
+ raise "The option \"#{option_key}\" with value \"#{option_value}\" is invalid.#{accepted_value_msg}" unless is_valid_value
224
+ end
225
+ end
226
+
227
+ def normalizer_options_value data_object
228
+ @normalizers.each do |option_key, normalizer_method|
229
+ raise InvalidParameter "Normalizer for key \"#{option_key}\" has invalid method." unless normalizer_method.is_a? Proc
230
+
231
+ option_value = data_object[option_key]
232
+ data_object[option_key] = normalizer_method.call data_object, option_value
233
+ end
234
+
235
+ data_object
236
+ end
237
+
238
+ def throw_invalid_options_exception key, val, expected_type
239
+ msg = "The option \"#{key}\" with \"#{val}\" is expected to be of type \"#{expected_type}\""
240
+ raise InvalidOptions, msg
241
+ end
242
+ end
@@ -0,0 +1,9 @@
1
+ class Hash
2
+ def stringify_keys
3
+ Hash[self.map{|key, val| [key.to_s, val]}]
4
+ end
5
+
6
+ def symbolize_keys
7
+ Hash[self.map{|key, val| [key.to_sym, val]}]
8
+ end
9
+ end
@@ -0,0 +1 @@
1
+ require "optionsresolver/optionsresolver"
@@ -0,0 +1,12 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "rb-optionsresolver"
3
+ spec.version = "0.0.1"
4
+ spec.authors = ["NamNV609"]
5
+ spec.email = ["namnv609@gmail.com"]
6
+ spec.description = "Ruby library like Symfony OptionsResolver"
7
+ spec.summary = "Allows to create an options system with required options, defaults, validation (type, value), normalization and more."
8
+ spec.license = "MIT"
9
+ spec.homepage = "https://github.com/namnv609/rb-optionsresolver"
10
+ spec.files = `git ls-files`.split($/)
11
+ spec.require_paths = ["lib"]
12
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rb-optionsresolver
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - NamNV609
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-07-05 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Ruby library like Symfony OptionsResolver
14
+ email:
15
+ - namnv609@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - Gemfile
22
+ - LICENSE
23
+ - README.md
24
+ - lib/optionsresolver/exceptions/invalid_options.rb
25
+ - lib/optionsresolver/exceptions/invalid_parameter.rb
26
+ - lib/optionsresolver/exceptions/missing_options.rb
27
+ - lib/optionsresolver/exceptions/undefined_options.rb
28
+ - lib/optionsresolver/optionsresolver.rb
29
+ - lib/optionsresolver/utils/hash_ext.rb
30
+ - lib/rb-optionsresolver.rb
31
+ - rb-optionsresolver.gemspec
32
+ homepage: https://github.com/namnv609/rb-optionsresolver
33
+ licenses:
34
+ - MIT
35
+ metadata: {}
36
+ post_install_message:
37
+ rdoc_options: []
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ requirements: []
51
+ rubyforge_project:
52
+ rubygems_version: 2.7.6
53
+ signing_key:
54
+ specification_version: 4
55
+ summary: Allows to create an options system with required options, defaults, validation
56
+ (type, value), normalization and more.
57
+ test_files: []