env_parser 1.3.1 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +1 -1
  3. data/.rubocop.yml +22 -35
  4. data/.ruby-version +1 -1
  5. data/Gemfile.lock +44 -42
  6. data/README.md +1 -1
  7. data/docs/EnvParser/AutoregisterFileNotFound.html +6 -6
  8. data/docs/EnvParser/Error.html +5 -6
  9. data/docs/EnvParser/TypeAlreadyDefinedError.html +5 -6
  10. data/docs/EnvParser/Types/BaseTypes.html +9 -7
  11. data/docs/EnvParser/Types/ChronologyTypes.html +7 -6
  12. data/docs/EnvParser/Types/InternetTypes.html +7 -6
  13. data/docs/EnvParser/Types.html +6 -6
  14. data/docs/EnvParser/UnknownTypeError.html +5 -6
  15. data/docs/EnvParser/UnparseableAutoregisterSpec.html +6 -6
  16. data/docs/EnvParser/ValueNotAllowedError.html +7 -6
  17. data/docs/EnvParser/ValueNotConvertibleError.html +5 -6
  18. data/docs/EnvParser.html +117 -121
  19. data/docs/_index.html +5 -7
  20. data/docs/file.README.html +241 -143
  21. data/docs/frames.html +1 -1
  22. data/docs/index.html +241 -143
  23. data/docs/method_list.html +1 -9
  24. data/docs/top-level-namespace.html +4 -82
  25. data/env_parser.gemspec +14 -14
  26. data/lib/env_parser/errors.rb +18 -18
  27. data/lib/env_parser/types/base_types.rb +69 -69
  28. data/lib/env_parser/types/chronology_types.rb +54 -54
  29. data/lib/env_parser/types/internet_types.rb +50 -50
  30. data/lib/env_parser/types.rb +2 -2
  31. data/lib/env_parser/version.rb +1 -1
  32. data/lib/env_parser.rb +205 -213
  33. data/spec/env_parser/types/base_types_spec.rb +98 -0
  34. data/spec/env_parser/types/chronology_types_spec.rb +49 -0
  35. data/spec/env_parser/types/internet_types_spec.rb +45 -0
  36. data/spec/env_parser_spec.rb +192 -0
  37. data/spec/spec_helper.rb +14 -0
  38. metadata +53 -48
  39. data/.travis.yml +0 -5
data/lib/env_parser.rb CHANGED
@@ -3,44 +3,44 @@ require 'env_parser/version'
3
3
  require 'active_support/all'
4
4
  require 'psych'
5
5
 
6
- ## The EnvParser class simplifies parsing of environment variables as different data types.
7
- ##
6
+ # The EnvParser class simplifies parsing of environment variables as different data types.
7
+ #
8
8
  class EnvParser
9
- ## The default filename to use for {.autoregister} requests.
10
- ##
9
+ # The default filename to use for {.autoregister} requests.
10
+ #
11
11
  AUTOREGISTER_FILE = '.env_parser.yml'.freeze
12
12
 
13
13
  class << self
14
- ## Defines a new type for use as the "as" option on a subsequent {.parse} or {.register} call.
15
- ##
16
- ## @param name [Symbol]
17
- ## The name to assign to the type.
18
- ##
19
- ## @option options [Array<Symbol>] aliases
20
- ## An array of additional names you'd like to see refer to this same type.
21
- ##
22
- ## @option options if_unset (nil)
23
- ## Specifies a "sensible default" to return for this type if the value being parsed (via
24
- ## {.parse} or {.register}) is either unset (`nil`) or blank (`''`). Note this may be
25
- ## overridden by the user via the {.parse}/{.register} "if_unset" option.
26
- ##
27
- ## @yield [value]
28
- ## A block to act as the parser for the this type. If no block is given, an ArgumentError is
29
- ## raised.
30
- ##
31
- ## When the type defined is used via a {.parse}/{.register} call, this block is invoked with
32
- ## the value to be parsed. Said value is guaranteed to be a non-empty String (the "if_unset"
33
- ## check will have already run), but no other assurances as to content are given. The block
34
- ## should return the final output of parsing the given String value as the type being defined.
35
- ##
36
- ## If the value given cannot be sensibly parsed into the type defined, the block should raise
37
- ## an {EnvParser::ValueNotConvertibleError}.
38
- ##
39
- ## @return [nil]
40
- ## This generates no usable value.
41
- ##
42
- ## @raise [ArgumentError, EnvParser::TypeAlreadyDefinedError]
43
- ##
14
+ # Defines a new type for use as the "as" option on a subsequent {.parse} or {.register} call.
15
+ #
16
+ # @param name [Symbol]
17
+ # The name to assign to the type.
18
+ #
19
+ # @option options [Array<Symbol>] aliases
20
+ # An array of additional names you'd like to see refer to this same type.
21
+ #
22
+ # @option options if_unset (nil)
23
+ # Specifies a "sensible default" to return for this type if the value being parsed (via
24
+ # {.parse} or {.register}) is either unset (`nil`) or blank (`''`). Note this may be
25
+ # overridden by the user via the {.parse}/{.register} "if_unset" option.
26
+ #
27
+ # @yield [value]
28
+ # A block to act as the parser for the this type. If no block is given, an ArgumentError is
29
+ # raised.
30
+ #
31
+ # When the type defined is used via a {.parse}/{.register} call, this block is invoked with
32
+ # the value to be parsed. Said value is guaranteed to be a non-empty String (the "if_unset"
33
+ # check will have already run), but no other assurances as to content are given. The block
34
+ # should return the final output of parsing the given String value as the type being defined.
35
+ #
36
+ # If the value given cannot be sensibly parsed into the type defined, the block should raise
37
+ # an {EnvParser::ValueNotConvertibleError}.
38
+ #
39
+ # @return [nil]
40
+ # This generates no usable value.
41
+ #
42
+ # @raise [ArgumentError, EnvParser::TypeAlreadyDefinedError]
43
+ #
44
44
  def define_type(name, options = {}, &parser)
45
45
  raise(ArgumentError, 'no parsing block given') unless block_given?
46
46
 
@@ -57,58 +57,58 @@ class EnvParser
57
57
  nil
58
58
  end
59
59
 
60
- ## Interprets the given value as the specified type.
61
- ##
62
- ## @param value [String, Symbol]
63
- ## The value to parse/interpret. If a String is given, the value will be used as-is. If a
64
- ## Symbol is given, the ENV value for the matching string key will be used.
65
- ##
66
- ## @option options [Symbol] as
67
- ## The expected return type. A best-effort attempt is made to convert the source String to the
68
- ## requested type.
69
- ##
70
- ## If no "as" option is given, an ArgumentError is raised. If the "as" option given is unknown
71
- ## (the given type has not been previously defined via {.define_type}), an
72
- ## {EnvParser::UnknownTypeError} is raised.
73
- ##
74
- ## @option options if_unset
75
- ## Specifies the default value to return if the given "value" is either unset (`nil`) or blank
76
- ## (`''`). Any "if_unset" value given will be returned as-is, with no type conversion or other
77
- ## change having been made. If unspecified, the "default" value for `nil`/`''` input will
78
- ## depend on the "as" type.
79
- ##
80
- ## @option options [Array, Range] from_set
81
- ## Gives a limited set of allowed values (after type conversion). If, after parsing, the final
82
- ## value is not included in the "from_set" list/range, an {EnvParser::ValueNotAllowedError} is
83
- ## raised.
84
- ##
85
- ## Note that if the "if_unset" option is given and the value to parse is `nil`/`''`, the
86
- ## "if_unset" value will be returned, even if it is not part of the "from_set" list/range.
87
- ##
88
- ## Also note that, due to the nature of the lookup, the "from_set" option is only available
89
- ## for scalar values (i.e. not arrays, hashes, or other enumerables). An attempt to use the
90
- ## "from_set" option with a non-scalar value will raise an ArgumentError.
91
- ##
92
- ## @option options [Proc] validated_by
93
- ## If given, the "validated_by" Proc is called with the parsed value (after type conversion)
94
- ## as its sole argument. This allows for user-defined validation of the parsed value beyond
95
- ## what can be enforced by use of the "from_set" option alone. If the Proc's return value is
96
- ## `#blank?`, an {EnvParser::ValueNotAllowedError} is raised. To accomodate your syntax of
97
- ## choice, this validation Proc may be given as a block instead.
98
- ##
99
- ## Note that this option is intended to provide an inspection mechanism only -- no mutation
100
- ## of the parsed value should occur within the given Proc. To that end, the argument passed is
101
- ## a *frozen* duplicate of the parsed value.
102
- ##
103
- ## @yield [value]
104
- ## A block (if given) is treated exactly as the "validated_by" Proc would.
105
- ##
106
- ## Although there is no compelling reason to provide both a "validated_by" Proc *and* a
107
- ## validation block, there is no technical limitation preventing this. **If both are given,
108
- ## both validation checks must pass.**
109
- ##
110
- ## @raise [ArgumentError, EnvParser::UnknownTypeError, EnvParser::ValueNotAllowedError]
111
- ##
60
+ # Interprets the given value as the specified type.
61
+ #
62
+ # @param value [String, Symbol]
63
+ # The value to parse/interpret. If a String is given, the value will be used as-is. If a
64
+ # Symbol is given, the ENV value for the matching string key will be used.
65
+ #
66
+ # @option options [Symbol] as
67
+ # The expected return type. A best-effort attempt is made to convert the source String to the
68
+ # requested type.
69
+ #
70
+ # If no "as" option is given, an ArgumentError is raised. If the "as" option given is unknown
71
+ # (the given type has not been previously defined via {.define_type}), an
72
+ # {EnvParser::UnknownTypeError} is raised.
73
+ #
74
+ # @option options if_unset
75
+ # Specifies the default value to return if the given "value" is either unset (`nil`) or blank
76
+ # (`''`). Any "if_unset" value given will be returned as-is, with no type conversion or other
77
+ # change having been made. If unspecified, the "default" value for `nil`/`''` input will
78
+ # depend on the "as" type.
79
+ #
80
+ # @option options [Array, Range] from_set
81
+ # Gives a limited set of allowed values (after type conversion). If, after parsing, the final
82
+ # value is not included in the "from_set" list/range, an {EnvParser::ValueNotAllowedError} is
83
+ # raised.
84
+ #
85
+ # Note that if the "if_unset" option is given and the value to parse is `nil`/`''`, the
86
+ # "if_unset" value will be returned, even if it is not part of the "from_set" list/range.
87
+ #
88
+ # Also note that, due to the nature of the lookup, the "from_set" option is only available
89
+ # for scalar values (i.e. not arrays, hashes, or other enumerables). An attempt to use the
90
+ # "from_set" option with a non-scalar value will raise an ArgumentError.
91
+ #
92
+ # @option options [Proc] validated_by
93
+ # If given, the "validated_by" Proc is called with the parsed value (after type conversion)
94
+ # as its sole argument. This allows for user-defined validation of the parsed value beyond
95
+ # what can be enforced by use of the "from_set" option alone. If the Proc's return value is
96
+ # `#blank?`, an {EnvParser::ValueNotAllowedError} is raised. To accomodate your syntax of
97
+ # choice, this validation Proc may be given as a block instead.
98
+ #
99
+ # Note that this option is intended to provide an inspection mechanism only -- no mutation
100
+ # of the parsed value should occur within the given Proc. To that end, the argument passed is
101
+ # a *frozen* duplicate of the parsed value.
102
+ #
103
+ # @yield [value]
104
+ # A block (if given) is treated exactly as the "validated_by" Proc would.
105
+ #
106
+ # Although there is no compelling reason to provide both a "validated_by" Proc *and* a
107
+ # validation block, there is no technical limitation preventing this. **If both are given,
108
+ # both validation checks must pass.**
109
+ #
110
+ # @raise [ArgumentError, EnvParser::UnknownTypeError, EnvParser::ValueNotAllowedError]
111
+ #
112
112
  def parse(value, options = {}, &validation_block)
113
113
  value = ENV[value.to_s] if value.is_a? Symbol
114
114
  value = value.to_s
@@ -126,57 +126,57 @@ class EnvParser
126
126
  value
127
127
  end
128
128
 
129
- ## Parses the referenced value and creates a matching constant in the requested context.
130
- ##
131
- ## Multiple calls to {.register} may be shortcutted by passing in a Hash whose keys are the
132
- ## variable names and whose values are the options set for each variable's {.register} call.
133
- ##
134
- ## <pre>
135
- ## ## Example shortcut usage:
136
- ##
137
- ## EnvParser.register :A, from: one_hash, as: :integer
138
- ## EnvParser.register :B, from: another_hash, as: :string, if_unset: 'none'
139
- ##
140
- ## ## ... is equivalent to ...
141
- ##
142
- ## EnvParser.register(
143
- ## A: { from: one_hash, as: :integer }
144
- ## B: { from: another_hash, as: :string, if_unset: 'none' }
145
- ## )
146
- ## </pre>
147
- ##
148
- ## @param name
149
- ## The name of the value to parse/interpret from the "from" Hash. If the "from" value is
150
- ## `ENV`, you may give a Symbol and the corresponding String key will be used instead.
151
- ##
152
- ## @option options [Hash] from (ENV)
153
- ## The source Hash from which to pull the value referenced by the "name" key.
154
- ##
155
- ## @option options [Module, Class] within (Kernel)
156
- ## The module or class in which the constant should be created. Creates global constants by
157
- ## default.
158
- ##
159
- ## @option options [Symbol] as
160
- ## See {.parse}.
161
- ##
162
- ## @option options if_unset
163
- ## See {.parse}.
164
- ##
165
- ## @option options [Array, Range] from_set
166
- ## See {.parse}.
167
- ##
168
- ## @option options [Proc] validated_by
169
- ## See {.parse}.
170
- ##
171
- ## @yield [value]
172
- ## A block (if given) is treated exactly as in {.parse}. Note, however, that a single block
173
- ## cannot be used to register multiple constants simultaneously -- each value needing
174
- ## validation must give its own "validated_by" Proc.
175
- ##
176
- ## @raise [ArgumentError]
177
- ##
129
+ # Parses the referenced value and creates a matching constant in the requested context.
130
+ #
131
+ # Multiple calls to {.register} may be shortcutted by passing in a Hash whose keys are the
132
+ # variable names and whose values are the options set for each variable's {.register} call.
133
+ #
134
+ # <pre>
135
+ # ## Example shortcut usage:
136
+ #
137
+ # EnvParser.register :A, from: one_hash, as: :integer
138
+ # EnvParser.register :B, from: another_hash, as: :string, if_unset: 'none'
139
+ #
140
+ # ## ... is equivalent to ...
141
+ #
142
+ # EnvParser.register(
143
+ # A: { from: one_hash, as: :integer }
144
+ # B: { from: another_hash, as: :string, if_unset: 'none' }
145
+ # )
146
+ # </pre>
147
+ #
148
+ # @param name
149
+ # The name of the value to parse/interpret from the "from" Hash. If the "from" value is
150
+ # `ENV`, you may give a Symbol and the corresponding String key will be used instead.
151
+ #
152
+ # @option options [Hash] from (ENV)
153
+ # The source Hash from which to pull the value referenced by the "name" key.
154
+ #
155
+ # @option options [Module, Class] within (Kernel)
156
+ # The module or class in which the constant should be created. Creates global constants by
157
+ # default.
158
+ #
159
+ # @option options [Symbol] as
160
+ # See {.parse}.
161
+ #
162
+ # @option options if_unset
163
+ # See {.parse}.
164
+ #
165
+ # @option options [Array, Range] from_set
166
+ # See {.parse}.
167
+ #
168
+ # @option options [Proc] validated_by
169
+ # See {.parse}.
170
+ #
171
+ # @yield [value]
172
+ # A block (if given) is treated exactly as in {.parse}. Note, however, that a single block
173
+ # cannot be used to register multiple constants simultaneously -- each value needing
174
+ # validation must give its own "validated_by" Proc.
175
+ #
176
+ # @raise [ArgumentError]
177
+ #
178
178
  def register(name, options = {}, &validation_block)
179
- ## Allow for registering multiple variables simultaneously via a single call.
179
+ # Allow for registering multiple variables simultaneously via a single call.
180
180
  if name.is_a? Hash
181
181
  raise(ArgumentError, 'cannot register multiple values with one block') if block_given?
182
182
  return register_all(name)
@@ -185,20 +185,17 @@ class EnvParser
185
185
  from = options.fetch(:from, ENV)
186
186
  within = options.fetch(:within, Kernel)
187
187
 
188
- ## ENV *seems* like a Hash and it does *some* Hash-y things, but it is NOT a Hash and that can
189
- ## bite you in some cases. Making sure we're working with a straight-up Hash saves a lot of
190
- ## sanity checks later on. This is also a good place to make sure we're working with a String
191
- ## key.
188
+ # ENV *seems* like a Hash and it does *some* Hash-y things, but it is NOT a Hash and that can
189
+ # bite you in some cases. Making sure we're working with a straight-up Hash saves a lot of
190
+ # sanity checks later on. This is also a good place to make sure we're working with a String
191
+ # key.
192
192
  if from == ENV
193
193
  from = from.to_h
194
194
  name = name.to_s
195
195
  end
196
196
 
197
197
  raise ArgumentError, "invalid `from` parameter: #{from.class}" unless from.is_a? Hash
198
-
199
- unless within.is_a?(Module) || within.is_a?(Class)
200
- raise ArgumentError, "invalid `within` parameter: #{within.inspect}"
201
- end
198
+ raise ArgumentError, "invalid `within` parameter: #{within.inspect}" unless within.is_a?(Module) || within.is_a?(Class)
202
199
 
203
200
  value = from[name]
204
201
  value = parse(value, options, &validation_block)
@@ -207,15 +204,15 @@ class EnvParser
207
204
  value
208
205
  end
209
206
 
210
- ## Creates ENV bindings for {.parse} and {.register} proxy methods.
211
- ##
212
- ## The sole difference between these proxy methods and their EnvParser counterparts is that
213
- ## ENV.parse will interpret any value given as an ENV key (as a String), not the given value
214
- ## itself. i.e. ENV.parse('XYZ', ...) is equivalent to EnvParser.parse(ENV['XYZ'], ...)
215
- ##
216
- ## @return [ENV]
217
- ## This generates no usable value.
218
- ##
207
+ # Creates ENV bindings for {.parse} and {.register} proxy methods.
208
+ #
209
+ # The sole difference between these proxy methods and their EnvParser counterparts is that
210
+ # ENV.parse will interpret any value given as an ENV key (as a String), not the given value
211
+ # itself. i.e. ENV.parse('XYZ', ...) is equivalent to EnvParser.parse(ENV['XYZ'], ...)
212
+ #
213
+ # @return [ENV]
214
+ # This generates no usable value.
215
+ #
219
216
  def add_env_bindings
220
217
  ENV.instance_eval do
221
218
  def parse(name, options = {}, &validation_block)
@@ -230,21 +227,21 @@ class EnvParser
230
227
  ENV
231
228
  end
232
229
 
233
- ## Reads an "autoregister" file and registers the ENV constants defined therein.
234
- ##
235
- ## The "autoregister" file is read, parsed as YAML, sanitized for use as a parameter to
236
- ## {.register_all}, and then passed along for processing. The return value from that
237
- ## {.register_all} call is passed through.
238
- ##
239
- ## @param filename [String]
240
- ## A path for the autoregister file to parse and process. Defaults to
241
- ## {EnvParser::AUTOREGISTER_FILE} if unset.
242
- ##
243
- ## @return [Hash]
244
- ## The return value from the {.register_all} call that handles the actual registration.
245
- ##
246
- ## @raise [EnvParser::AutoregisterFileNotFound, EnvParser::UnparseableAutoregisterSpec]
247
- ##
230
+ # Reads an "autoregister" file and registers the ENV constants defined therein.
231
+ #
232
+ # The "autoregister" file is read, parsed as YAML, sanitized for use as a parameter to
233
+ # {.register_all}, and then passed along for processing. The return value from that
234
+ # {.register_all} call is passed through.
235
+ #
236
+ # @param filename [String]
237
+ # A path for the autoregister file to parse and process. Defaults to
238
+ # {EnvParser::AUTOREGISTER_FILE} if unset.
239
+ #
240
+ # @return [Hash]
241
+ # The return value from the {.register_all} call that handles the actual registration.
242
+ #
243
+ # @raise [EnvParser::AutoregisterFileNotFound, EnvParser::UnparseableAutoregisterSpec]
244
+ #
248
245
  def autoregister(filename = nil)
249
246
  filename ||= AUTOREGISTER_FILE
250
247
  autoregister_spec = Psych.load_file(filename)
@@ -260,58 +257,53 @@ class EnvParser
260
257
 
261
258
  register_all autoregister_spec
262
259
 
263
- ## Psych raises an Errno::ENOENT on file-not-found.
264
- ##
260
+ # Psych raises an Errno::ENOENT on file-not-found.
261
+ #
265
262
  rescue Errno::ENOENT
266
263
  raise EnvParser::AutoregisterFileNotFound, %(file not found: "#{filename}")
267
264
 
268
- ## Psych raises a Psych::SyntaxError on unparseable YAML.
269
- ##
265
+ # Psych raises a Psych::SyntaxError on unparseable YAML.
266
+ #
270
267
  rescue Psych::SyntaxError => e
271
268
  raise EnvParser::UnparseableAutoregisterSpec, "malformed YAML in spec file: #{e.message}"
272
269
  end
273
270
 
274
271
  private
275
272
 
276
- ## Class instance variable for storing known type data.
277
- ##
273
+ # Class instance variable for storing known type data.
274
+ #
278
275
  def known_types
279
276
  @known_types ||= {}
280
277
  end
281
278
 
282
- ## Verifies that the given "value" is included in the "set".
283
- ##
284
- ## @param value
285
- ## @param set [Array, Range]
286
- ##
287
- ## @return [nil]
288
- ## This generates no usable value.
289
- ##
290
- ## @raise [ArgumentError, EnvParser::ValueNotAllowedError]
291
- ##
279
+ # Verifies that the given "value" is included in the "set".
280
+ #
281
+ # @param value
282
+ # @param set [Array, Range]
283
+ #
284
+ # @return [nil]
285
+ # This generates no usable value.
286
+ #
287
+ # @raise [ArgumentError, EnvParser::ValueNotAllowedError]
288
+ #
292
289
  def check_for_set_inclusion(value, set: nil)
293
- if value.respond_to?(:each)
294
- raise ArgumentError, "`from_set` option is not compatible with #{value.class} values"
295
- end
296
-
297
- unless set.is_a?(Array) || set.is_a?(Range)
298
- raise ArgumentError, "invalid `from_set` parameter type: #{set.class}"
299
- end
290
+ raise ArgumentError, "`from_set` option is not compatible with #{value.class} values" if value.respond_to?(:each)
291
+ raise ArgumentError, "invalid `from_set` parameter type: #{set.class}" unless set.is_a?(Array) || set.is_a?(Range)
300
292
 
301
293
  raise(ValueNotAllowedError, 'parsed value not in allowed set') unless set.include?(value)
302
294
  end
303
295
 
304
- ## Verifies that the given "value" passes both the "proc" and "block" validations.
305
- ##
306
- ## @param value
307
- ## @param proc [Proc, nil]
308
- ## @param block [Proc, nil]
309
- ##
310
- ## @return [nil]
311
- ## This generates no usable value.
312
- ##
313
- ## @raise [EnvParser::ValueNotAllowedError]
314
- ##
296
+ # Verifies that the given "value" passes both the "proc" and "block" validations.
297
+ #
298
+ # @param value
299
+ # @param proc [Proc, nil]
300
+ # @param block [Proc, nil]
301
+ #
302
+ # @return [nil]
303
+ # This generates no usable value.
304
+ #
305
+ # @raise [EnvParser::ValueNotAllowedError]
306
+ #
315
307
  def check_user_defined_validations(value, proc: nil, block: nil)
316
308
  immutable_value = value.dup.freeze
317
309
  all_tests_passed = [proc, block].compact.all? { |i| i.call(immutable_value) }
@@ -319,15 +311,15 @@ class EnvParser
319
311
  raise(ValueNotAllowedError, 'parsed value failed user validation') unless all_tests_passed
320
312
  end
321
313
 
322
- ## Receives a list of {.register} calls to make, as a Hash keyed with variable names and the
323
- ## values being each {.register} call's option set.
324
- ##
325
- ## @param list [Hash]
326
- ##
327
- ## @return [Hash]
328
- ##
329
- ## @raise [ArgumentError]
330
- ##
314
+ # Receives a list of {.register} calls to make, as a Hash keyed with variable names and the
315
+ # values being each {.register} call's option set.
316
+ #
317
+ # @param list [Hash]
318
+ #
319
+ # @return [Hash]
320
+ #
321
+ # @raise [ArgumentError]
322
+ #
331
323
  def register_all(list)
332
324
  raise(ArgumentError, "invalid 'list' parameter type: #{list.class}") unless list.is_a? Hash
333
325
 
@@ -338,6 +330,6 @@ class EnvParser
338
330
  end
339
331
  end
340
332
 
341
- ## Load predefined types.
342
- ##
333
+ # Load predefined types.
334
+ #
343
335
  require 'env_parser/types'
@@ -0,0 +1,98 @@
1
+ RSpec.describe EnvParser::Types::BaseTypes do
2
+ it 'can parse strings' do
3
+ expect(EnvParser.parse(nil, as: :string)).to eq('')
4
+ expect(EnvParser.parse('', as: :string)).to eq('')
5
+
6
+ expect(EnvParser.parse('value', as: :string)).to eq('value')
7
+ end
8
+
9
+ it 'can parse symbols' do
10
+ expect(EnvParser.parse(nil, as: :symbol)).to eq(:'')
11
+ expect(EnvParser.parse('', as: :symbol)).to eq(:'')
12
+
13
+ expect(EnvParser.parse('value', as: :symbol)).to eq(:value)
14
+ end
15
+
16
+ it 'can parse booleans' do
17
+ expect(EnvParser.parse(nil, as: :boolean)).to eq(false)
18
+ expect(EnvParser.parse('', as: :boolean)).to eq(false)
19
+
20
+ expect(EnvParser.parse('0', as: :boolean)).to eq(false)
21
+ expect(EnvParser.parse('f', as: :boolean)).to eq(false)
22
+ expect(EnvParser.parse('false', as: :boolean)).to eq(false)
23
+
24
+ expect(EnvParser.parse('1', as: :boolean)).to eq(true)
25
+ expect(EnvParser.parse('t', as: :boolean)).to eq(true)
26
+ expect(EnvParser.parse('true', as: :boolean)).to eq(true)
27
+ end
28
+
29
+ it 'can parse integers' do
30
+ %i[int integer].each do |type|
31
+ expect(EnvParser.parse(nil, as: type)).to eq(0)
32
+ expect(EnvParser.parse('', as: type)).to eq(0)
33
+
34
+ expect(EnvParser.parse('-1.9', as: type)).to eq(-1)
35
+ expect(EnvParser.parse('-1.1', as: type)).to eq(-1)
36
+ expect(EnvParser.parse('-1', as: type)).to eq(-1)
37
+ expect(EnvParser.parse('0', as: type)).to eq(0)
38
+ expect(EnvParser.parse('1', as: type)).to eq(1)
39
+ expect(EnvParser.parse('1.1', as: type)).to eq(1)
40
+ expect(EnvParser.parse('1.9', as: type)).to eq(1)
41
+
42
+ expect(EnvParser.parse('non-numeric', as: type)).to eq(0)
43
+ end
44
+ end
45
+
46
+ it 'can parse floats' do
47
+ %i[float decimal number].each do |type|
48
+ expect(EnvParser.parse(nil, as: type)).to eq(0.0)
49
+ expect(EnvParser.parse('', as: type)).to eq(0.0)
50
+
51
+ expect(EnvParser.parse('-1.9', as: type)).to eq(-1.9)
52
+ expect(EnvParser.parse('-1.1', as: type)).to eq(-1.1)
53
+ expect(EnvParser.parse('-1', as: type)).to eq(-1.0)
54
+ expect(EnvParser.parse('0', as: type)).to eq(0.0)
55
+ expect(EnvParser.parse('1', as: type)).to eq(1.0)
56
+ expect(EnvParser.parse('1.1', as: type)).to eq(1.1)
57
+ expect(EnvParser.parse('1.9', as: type)).to eq(1.9)
58
+
59
+ expect(EnvParser.parse('non-numeric', as: type)).to eq(0.0)
60
+ end
61
+ end
62
+
63
+ it 'can parse json' do
64
+ expect(EnvParser.parse(nil, as: :json)).to eq(nil)
65
+ expect(EnvParser.parse('', as: :json)).to eq(nil)
66
+
67
+ expect { EnvParser.parse('non-json-parseable string', as: :json) }.to raise_error(JSON::ParserError)
68
+
69
+ expect(EnvParser.parse('null', as: :json)).to eq(nil)
70
+ expect(EnvParser.parse('true', as: :json)).to eq(true)
71
+ expect(EnvParser.parse('false', as: :json)).to eq(false)
72
+ expect(EnvParser.parse('1', as: :json)).to eq(1)
73
+ expect(EnvParser.parse('1.1', as: :json)).to eq(1.1)
74
+ expect(EnvParser.parse('"some string"', as: :json)).to eq('some string')
75
+ expect(EnvParser.parse('["one", 2, "three"]', as: :json)).to eq(['one', 2, 'three'])
76
+ expect(EnvParser.parse('{ "one": 1, "two": 2, "three": "three" }', as: :json)).to eq('one' => 1, 'two' => 2, 'three' => 'three')
77
+ end
78
+
79
+ it 'can parse arrays' do
80
+ expect(EnvParser.parse(nil, as: :array)).to eq([])
81
+ expect(EnvParser.parse('', as: :array)).to eq([])
82
+
83
+ expect { EnvParser.parse('non-json-parseable string', as: :array) }.to raise_error(JSON::ParserError)
84
+ expect { EnvParser.parse('"parseable json, but not an array"', as: :array) }.to raise_error(EnvParser::ValueNotConvertibleError)
85
+
86
+ expect(EnvParser.parse('["one", 2, "three"]', as: :array)).to eq(['one', 2, 'three'])
87
+ end
88
+
89
+ it 'can parse hashes' do
90
+ expect(EnvParser.parse(nil, as: :hash)).to eq({})
91
+ expect(EnvParser.parse('', as: :hash)).to eq({})
92
+
93
+ expect { EnvParser.parse('non-json-parseable string', as: :hash) }.to raise_error(JSON::ParserError)
94
+ expect { EnvParser.parse('"parseable json, but not a hash"', as: :hash) }.to raise_error(EnvParser::ValueNotConvertibleError)
95
+
96
+ expect(EnvParser.parse('{ "one": 1, "two": 2, "three": "three" }', as: :hash)).to eq('one' => 1, 'two' => 2, 'three' => 'three')
97
+ end
98
+ end
@@ -0,0 +1,49 @@
1
+ RSpec.describe EnvParser::Types::ChronologyTypes do
2
+ it 'can parse dates' do
3
+ expect(EnvParser.parse(nil, as: :date)).to eq(nil)
4
+ expect(EnvParser.parse('', as: :date)).to eq(nil)
5
+
6
+ expect(EnvParser.parse('11/05/1955 06:00', as: :date)).to eq(Date.new(1955, 11, 5))
7
+ expect(EnvParser.parse('11/12/1955 22:04', as: :date)).to eq(Date.new(1955, 11, 12))
8
+ expect(EnvParser.parse('1885-09-02 08:00', as: :date)).to eq(Date.new(1885, 9, 2))
9
+ expect(EnvParser.parse('1885-09-07', as: :date)).to eq(Date.new(1885, 9, 7))
10
+
11
+ expect(EnvParser.parse('tomorrow', as: :date)).to eq(Date.today + 1.day)
12
+
13
+ expect { EnvParser.parse('not a date', as: :date) }.to raise_error(EnvParser::ValueNotConvertibleError)
14
+ expect { EnvParser.parse('2018-02-29', as: :date) }.to raise_error(EnvParser::ValueNotConvertibleError)
15
+ end
16
+
17
+ it 'can parse times' do
18
+ %i[time datetime].each do |type|
19
+ expect(EnvParser.parse(nil, as: type)).to eq(nil)
20
+ expect(EnvParser.parse('', as: type)).to eq(nil)
21
+
22
+ expect(EnvParser.parse('11/05/1955 06:00', as: type)).to eq(Time.new(1955, 11, 5, 6, 0))
23
+ expect(EnvParser.parse('11/12/1955 22:04', as: type)).to eq(Time.new(1955, 11, 12, 22, 4))
24
+ expect(EnvParser.parse('1885-09-02 08:00', as: type)).to eq(Time.new(1885, 9, 2, 8, 0))
25
+ expect(EnvParser.parse('1885-09-07', as: type)).to eq(Time.new(1885, 9, 7))
26
+
27
+ expect(EnvParser.parse('today at 07:15', as: type)).to eq(Date.today + 7.hours + 15.minutes)
28
+
29
+ expect { EnvParser.parse('not a date/time', as: type) }.to raise_error(EnvParser::ValueNotConvertibleError)
30
+ expect { EnvParser.parse('today at 33:25', as: type) }.to raise_error(EnvParser::ValueNotConvertibleError)
31
+ end
32
+ end
33
+
34
+ it 'can parse durations' do
35
+ expect(EnvParser.parse(nil, as: :duration)).to eq(nil)
36
+ expect(EnvParser.parse('', as: :duration)).to eq(nil)
37
+
38
+ expect(EnvParser.parse('12 seconds', as: :duration)).to eq(12)
39
+ expect(EnvParser.parse('5 minutes', as: :duration)).to eq(5 * 60)
40
+ expect(EnvParser.parse('24 hours', as: :duration)).to eq(24 * 60 * 60)
41
+ expect(EnvParser.parse('1.5 days', as: :duration)).to eq(1.5 * 24 * 60 * 60)
42
+ expect(EnvParser.parse('1 day', as: :duration)).to eq(24 * 60 * 60)
43
+ expect(EnvParser.parse('2 weeks, 1 day', as: :duration)).to eq((2 * 7 * 24 * 60 * 60) + (24 * 60 * 60))
44
+ expect(EnvParser.parse('P2W1DT3H', as: :duration)).to eq((2 * 7 * 24 * 60 * 60) + (24 * 60 * 60) + (3 * 60 * 60))
45
+
46
+ expect { EnvParser.parse('not a duration', as: :duration) }.to raise_error(EnvParser::ValueNotConvertibleError)
47
+ expect { EnvParser.parse('37 dinglebops', as: :duration) }.to raise_error(EnvParser::ValueNotConvertibleError)
48
+ end
49
+ end