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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +1 -1
- data/.rubocop.yml +22 -35
- data/.ruby-version +1 -1
- data/Gemfile.lock +44 -42
- data/README.md +1 -1
- data/docs/EnvParser/AutoregisterFileNotFound.html +6 -6
- data/docs/EnvParser/Error.html +5 -6
- data/docs/EnvParser/TypeAlreadyDefinedError.html +5 -6
- data/docs/EnvParser/Types/BaseTypes.html +9 -7
- data/docs/EnvParser/Types/ChronologyTypes.html +7 -6
- data/docs/EnvParser/Types/InternetTypes.html +7 -6
- data/docs/EnvParser/Types.html +6 -6
- data/docs/EnvParser/UnknownTypeError.html +5 -6
- data/docs/EnvParser/UnparseableAutoregisterSpec.html +6 -6
- data/docs/EnvParser/ValueNotAllowedError.html +7 -6
- data/docs/EnvParser/ValueNotConvertibleError.html +5 -6
- data/docs/EnvParser.html +117 -121
- data/docs/_index.html +5 -7
- data/docs/file.README.html +241 -143
- data/docs/frames.html +1 -1
- data/docs/index.html +241 -143
- data/docs/method_list.html +1 -9
- data/docs/top-level-namespace.html +4 -82
- data/env_parser.gemspec +14 -14
- data/lib/env_parser/errors.rb +18 -18
- data/lib/env_parser/types/base_types.rb +69 -69
- data/lib/env_parser/types/chronology_types.rb +54 -54
- data/lib/env_parser/types/internet_types.rb +50 -50
- data/lib/env_parser/types.rb +2 -2
- data/lib/env_parser/version.rb +1 -1
- data/lib/env_parser.rb +205 -213
- data/spec/env_parser/types/base_types_spec.rb +98 -0
- data/spec/env_parser/types/chronology_types_spec.rb +49 -0
- data/spec/env_parser/types/internet_types_spec.rb +45 -0
- data/spec/env_parser_spec.rb +192 -0
- data/spec/spec_helper.rb +14 -0
- metadata +53 -48
- 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
|
-
|
7
|
-
|
6
|
+
# The EnvParser class simplifies parsing of environment variables as different data types.
|
7
|
+
#
|
8
8
|
class EnvParser
|
9
|
-
|
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
|
-
|
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
|
-
|
42
|
-
|
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
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
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
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
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
|
-
|
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
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
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
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
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
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
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
|
-
|
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
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
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
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
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
|
-
|
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
|