env_parser 1.3.3 → 1.6.1

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.
data/docs/index.html CHANGED
@@ -76,13 +76,13 @@
76
76
  <li>
77
77
  <p>Add one of the following to your application’s Gemfile:
78
78
  ```ruby
79
- ## For on-demand usage …
80
- ##
79
+ # For on-demand usage …
80
+ #
81
81
  gem ‘env_parser’</p>
82
82
 
83
- <h2 id="to-automatically-register-env">To automatically register ENV</h2>
84
- <p>## constants per “.env_parser.yml” …
85
- ##
83
+ <h1 id="to-automatically-register-env">To automatically register ENV</h1>
84
+ <p># constants per “.env_parser.yml” …
85
+ #
86
86
  gem ‘env_parser’, require: ‘env_parser/autoregister’
87
87
  ```</p>
88
88
  </li>
@@ -103,33 +103,33 @@ $ gem install env_parser
103
103
  <h2 id="syntax-cheat-sheet">Syntax Cheat Sheet</h2>
104
104
 
105
105
  <p>```ruby
106
- ## Returns an ENV value parsed “as” a specific type:
107
- ##
106
+ # Returns an ENV value parsed “as” a specific type:
107
+ #
108
108
  EnvParser.parse env_key_as_a_symbol
109
- as: … ## ➜ required
110
- if_unset: … ## ➜ optional; default value
111
- from_set: … ## ➜ optional; an Array or Range
112
- validated_by: -&gt;(value) { … } ## ➜ optional; may also be given as a block</p>
109
+ as: … # ➜ required
110
+ if_unset: … # ➜ optional; default value
111
+ from_set: … # ➜ optional; an Array or Range
112
+ validated_by: -&gt;(value) { … } # ➜ optional; may also be given as a block</p>
113
113
 
114
- <h2 id="parse-an-env-value-and-register-it-as-a-constant">Parse an ENV value and register it as a constant:</h2>
115
- <p>##
114
+ <h1 id="parse-an-env-value-and-register-it-as-a-constant">Parse an ENV value and register it as a constant:</h1>
115
+ <p>#
116
116
  EnvParser.register env_key_as_a_symbol
117
- as: … ## ➜ required
118
- within: … ## ➜ optional; Class or Module
119
- if_unset: … ## ➜ optional; default value
120
- from_set: … ## ➜ optional; an Array or Range
121
- validated_by: -&gt;(value) { … } ## ➜ optional; may also be given as a block</p>
122
-
123
- <h2 id="registers-all-env-variables-as-speced-in-envparseryml">Registers all ENV variables as spec’ed in “.env_parser.yml”:</h2>
124
- <p>##
125
- EnvParser.autoregister ## Note this is automatically called if your
126
- ## Gemfile included the “env_parser” gem with
127
- ## the “require: ‘env_parser/autoregister’” option.</p>
128
-
129
- <h2 id="lets-you-call-parse-and-register-on-env-itself">Lets you call “parse” and “register” on ENV itself:</h2>
130
- <p>##
131
- EnvParser.add_env_bindings ## ENV.parse will now be a proxy for EnvParser.parse
132
- ## and ENV.register will now be a proxy for EnvParser.register
117
+ as: … # ➜ required
118
+ within: … # ➜ optional; Class or Module
119
+ if_unset: … # ➜ optional; default value
120
+ from_set: … # ➜ optional; an Array or Range
121
+ validated_by: -&gt;(value) { … } # ➜ optional; may also be given as a block</p>
122
+
123
+ <h1 id="registers-all-env-variables-as-speced-in-envparseryml">Registers all ENV variables as spec’ed in “.env_parser.yml”:</h1>
124
+ <p>#
125
+ EnvParser.autoregister # Note this is automatically called if your
126
+ # Gemfile included the “env_parser” gem with
127
+ # the “require: ‘env_parser/autoregister’” option.</p>
128
+
129
+ <h1 id="lets-you-call-parse-and-register-on-env-itself">Lets you call “parse” and “register” on ENV itself:</h1>
130
+ <p>#
131
+ EnvParser.add_env_bindings # ENV.parse will now be a proxy for EnvParser.parse
132
+ # and ENV.register will now be a proxy for EnvParser.register
133
133
  ```</p>
134
134
 
135
135
  <h2 id="extended-how-to-use">Extended How-To-Use</h2>
@@ -143,9 +143,9 @@ EnvParser.add_env_bindings ## ENV.parse will now be a proxy for EnvParser.parse
143
143
  <p>At its core, EnvParser is a straight-forward parser for string values (since that’s all <code>ENV</code> ever gives you), allowing you to read a given string <strong><em>as</em></strong> a variety of types.</p>
144
144
 
145
145
  <p><code>ruby
146
- ## Returns ENV['TIMEOUT_MS'] as an Integer,
147
- ## or a sensible default (0) if ENV['TIMEOUT_MS'] is unset.
148
- ##
146
+ # Returns ENV['TIMEOUT_MS'] as an Integer,
147
+ # or a sensible default (0) if ENV['TIMEOUT_MS'] is unset.
148
+ #
149
149
  timeout_ms = EnvParser.parse ENV['TIMEOUT_MS'], as: :integer
150
150
  </code></p>
151
151
 
@@ -157,9 +157,9 @@ timeout_ms = EnvParser.parse ENV['TIMEOUT_MS'], as: :integer
157
157
  <p>EnvParser is all about ~~simplification~~ ~~less typing~~ <em>laziness</em>. If you pass in a symbol instead of a string, EnvParser will look to <code>ENV</code> and use the value from the corresponding (string) key.</p>
158
158
 
159
159
  <p><code>ruby
160
- ## YAY, LESS TYPING! 😃
161
- ## These two are the same:
162
- ##
160
+ # YAY, LESS TYPING! 😃
161
+ # These two are the same:
162
+ #
163
163
  more_typing = EnvParser.parse ENV['TIMEOUT_MS'], as: :integer
164
164
  less_typing = EnvParser.parse :TIMEOUT_MS, as: :integer
165
165
  </code></p>
@@ -170,20 +170,20 @@ less_typing = EnvParser.parse :TIMEOUT_MS, as: :integer
170
170
  <p>The <code>EnvParser.register</code> method lets you “promote” <code>ENV</code> variables into their own constants, already parsed into the correct type.</p>
171
171
 
172
172
  <p>```ruby
173
- ENV[‘API_KEY’] ## =&gt; ‘unbreakable p4$$w0rd’</p>
173
+ ENV[‘API_KEY’] # =&gt; ‘unbreakable p4$$w0rd’</p>
174
174
 
175
175
  <p>EnvParser.register :API_KEY, as: :string
176
- API_KEY ## =&gt; ‘unbreakable p4$$w0rd’
176
+ API_KEY # =&gt; ‘unbreakable p4$$w0rd’
177
177
  ```</p>
178
178
 
179
179
  <p>By default, <code>EnvParser.register</code> will create the requested constant within the Kernel module (making it available everywhere), but you can specify any class or module you like.</p>
180
180
 
181
181
  <p>```ruby
182
- ENV[‘BEST_VIDEO’] ## =&gt; ‘https://youtu.be/L_jWHffIx5E’</p>
182
+ ENV[‘BEST_VIDEO’] # =&gt; ‘https://youtu.be/L_jWHffIx5E’</p>
183
183
 
184
184
  <p>EnvParser.register :BEST_VIDEO, as: :string, within: URI
185
- URI::BEST_VIDEO ## =&gt; ‘https://youtu.be/L_jWHffIx5E’
186
- BEST_VIDEO ## =&gt; raises NameError
185
+ URI::BEST_VIDEO # =&gt; ‘https://youtu.be/L_jWHffIx5E’
186
+ BEST_VIDEO # =&gt; raises NameError
187
187
  ```</p>
188
188
 
189
189
  <p>You can also register multiple constants with a single call, which is a bit cleaner.</p>
@@ -193,7 +193,7 @@ EnvParser.register :USERNAME, as: :string
193
193
  EnvParser.register :PASSWORD, as: :string
194
194
  EnvParser.register :MOCK_API, as: :boolean, within: MyClassOrModule }</p>
195
195
 
196
- <h2 id="is-equivalent-to-">… is equivalent to …</h2>
196
+ <h1 id="is-equivalent-to-">… is equivalent to …</h1>
197
197
 
198
198
  <p>EnvParser.register USERNAME: { as: :string },
199
199
  PASSWORD: { as: :string },
@@ -206,31 +206,31 @@ EnvParser.register :MOCK_API, as: :boolean, within: MyClassOrModule }</p>
206
206
  <p>Calling <code>EnvParser.add_env_bindings</code> binds proxy <code>parse</code> and <code>register</code> methods onto <code>ENV</code>. With these bindings in place, you can call <code>parse</code> or <code>register</code> on <code>ENV</code> itself, which is more legible and feels more straight-forward.</p>
207
207
 
208
208
  <p>```ruby
209
- ENV[‘SHORT_PI’] ## =&gt; ‘3.1415926’
210
- ENV[‘BETTER_PI’] ## =&gt; ‘[“flaky crust”, “strawberry filling”]’</p>
209
+ ENV[‘SHORT_PI’] # =&gt; ‘3.1415926’
210
+ ENV[‘BETTER_PI’] # =&gt; ‘[“flaky crust”, “strawberry filling”]’</p>
211
211
 
212
- <h2 id="bind-the-proxy-methods">Bind the proxy methods.</h2>
213
- <p>##
212
+ <h1 id="bind-the-proxy-methods">Bind the proxy methods.</h1>
213
+ <p>#
214
214
  EnvParser.add_env_bindings</p>
215
215
 
216
- <p>ENV.parse :SHORT_PI, as: :float ## =&gt; 3.1415926
217
- ENV.register :BETTER_PI, as: :array ## Your constant is set!
216
+ <p>ENV.parse :SHORT_PI, as: :float # =&gt; 3.1415926
217
+ ENV.register :BETTER_PI, as: :array # Your constant is set!
218
218
  ```</p>
219
219
 
220
220
  <p>Note that the proxy <code>ENV.parse</code> method will (naturally) <em>always</em> interpret the value given as an <code>ENV</code> key (converting it to a string, if necessary), which is slightly different from the original <code>EnvParser.parse</code> method.</p>
221
221
 
222
222
  <p>```ruby
223
- ENV[‘SHORT_PI’] ## =&gt; ‘3.1415926’</p>
223
+ ENV[‘SHORT_PI’] # =&gt; ‘3.1415926’</p>
224
224
 
225
- <p>EnvParser.parse ‘SHORT_PI’, as: :float ## =&gt; ‘SHORT_PI’ as a float: 0.0
226
- EnvParser.parse :SHORT_PI , as: :float ## =&gt; ENV[‘SHORT_PI’] as a float: 3.1415926</p>
225
+ <p>EnvParser.parse ‘SHORT_PI’, as: :float # =&gt; ‘SHORT_PI’ as a float: 0.0
226
+ EnvParser.parse :SHORT_PI , as: :float # =&gt; ENV[‘SHORT_PI’] as a float: 3.1415926</p>
227
227
 
228
- <h2 id="bind-the-proxy-methods-1">Bind the proxy methods.</h2>
229
- <p>##
228
+ <h1 id="bind-the-proxy-methods-1">Bind the proxy methods.</h1>
229
+ <p>#
230
230
  EnvParser.add_env_bindings</p>
231
231
 
232
- <p>ENV.parse ‘SHORT_PI’, as: :float ## =&gt; ENV[‘SHORT_PI’] as a float: 3.1415926
233
- ENV.parse :SHORT_PI , as: :float ## =&gt; ENV[‘SHORT_PI’] as a float: 3.1415926
232
+ <p>ENV.parse ‘SHORT_PI’, as: :float # =&gt; ENV[‘SHORT_PI’] as a float: 3.1415926
233
+ ENV.parse :SHORT_PI , as: :float # =&gt; ENV[‘SHORT_PI’] as a float: 3.1415926
234
234
  ```</p>
235
235
 
236
236
  <p>Note also that the <code>ENV.parse</code> and <code>ENV.register</code> binding is done safely and without polluting the method space for other objects.</p>
@@ -248,14 +248,14 @@ ENV.parse :SHORT_PI , as: :float ## =&gt; ENV[‘SHORT_PI’] as a float: 3.141
248
248
  <p>If the <code>ENV</code> variable you want is unset (<code>nil</code>) or blank (<code>''</code>), the return value is a sensible default for the given <strong><em>as</em></strong> type: 0 or 0.0 for numbers, an empty string/array/hash, etc. Sometimes you want a non-trivial default, however. The <strong><em>if_unset</em></strong> option lets you specify a default that better meets your needs.</p>
249
249
 
250
250
  <p><code>ruby
251
- ENV.parse :MISSING_VAR, as: :integer ## =&gt; 0
252
- ENV.parse :MISSING_VAR, as: :integer, if_unset: 250 ## =&gt; 250
251
+ ENV.parse :MISSING_VAR, as: :integer # =&gt; 0
252
+ ENV.parse :MISSING_VAR, as: :integer, if_unset: 250 # =&gt; 250
253
253
  </code></p>
254
254
 
255
255
  <p>Note these default values are used as-is with no type conversion, so exercise caution.</p>
256
256
 
257
257
  <p><code>ruby
258
- ENV.parse :MISSING_VAR, as: :integer, if_unset: 'Careful!' ## =&gt; 'Careful!' (NOT AN INTEGER)
258
+ ENV.parse :MISSING_VAR, as: :integer, if_unset: 'Careful!' # =&gt; 'Careful!' (NOT AN INTEGER)
259
259
  </code></p>
260
260
  </li>
261
261
  <li>
@@ -267,9 +267,9 @@ ENV.parse :MISSING_VAR, as: :integer, if_unset: 'Careful!' ## =&gt; 'Careful!'
267
267
  ENV.parse :API_TO_USE, as: :symbol, from_set: %i[internal external]
268
268
  ENV.parse :NETWORK_PORT, as: :integer, from_set: (1..65535), if_unset: 80</p>
269
269
 
270
- <h2 id="and-if-the-value-is-not-in-the-allowed-set-">And if the value is not in the allowed set …</h2>
271
- <p>##
272
- ENV.parse :TWELVE, as: :integer, from_set: (1..5) ## =&gt; raises EnvParser::ValueNotAllowedError
270
+ <h1 id="and-if-the-value-is-not-in-the-allowed-set-">And if the value is not in the allowed set …</h1>
271
+ <p>#
272
+ ENV.parse :TWELVE, as: :integer, from_set: (1..5) # =&gt; raises EnvParser::ValueNotAllowedError
273
273
  ```</p>
274
274
  </li>
275
275
  <li>
@@ -278,12 +278,12 @@ ENV.parse :TWELVE, as: :integer, from_set: (1..5) ## =&gt; raises EnvParser::Va
278
278
  <p>You can write your own, more complex validations by passing in a <strong><em>validated_by</em></strong> lambda or an equivalent block. The lambda/block should take one value and return true if the given value passes the custom validation.</p>
279
279
 
280
280
  <p>```ruby
281
- ## Via a “validated_by” lambda …
282
- ##
281
+ # Via a “validated_by” lambda …
282
+ #
283
283
  ENV.parse :MUST_BE_LOWERCASE, as: :string, validated_by: -&gt;(value) { value == value.downcase }</p>
284
284
 
285
- <h2 id="or-with-a-block">… or with a block!</h2>
286
- <p>##
285
+ <h1 id="or-with-a-block">… or with a block!</h1>
286
+ <p>#
287
287
  ENV.parse(:MUST_BE_LOWERCASE, as: :string) { |value| value == value.downcase }
288
288
  ENV.parse(:CONNECTION_RETRIES, as: :integer, &amp;:positive?)
289
289
  ```</p>
@@ -347,7 +347,7 @@ EnvParser.register :USERNAME, as: :string
347
347
  EnvParser.register :PASSWORD, as: :string
348
348
  EnvParser.register :MOCK_API, as: :boolean, within: MyClassOrModule }</p>
349
349
 
350
- <h2 id="is-equivalent-to--1">… is equivalent to …</h2>
350
+ <h1 id="is-equivalent-to--1">… is equivalent to …</h1>
351
351
 
352
352
  <p>EnvParser.register USERNAME: { as: :string },
353
353
  PASSWORD: { as: :string },
@@ -396,7 +396,7 @@ USERNAME:
396
396
  </div></div>
397
397
 
398
398
  <div id="footer">
399
- Generated on Sun Dec 25 21:09:36 2022 by
399
+ Generated on Fri Dec 30 17:49:58 2022 by
400
400
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
401
401
  0.9.28 (ruby-3.0.4).
402
402
  </div>
@@ -100,7 +100,7 @@
100
100
  </div>
101
101
 
102
102
  <div id="footer">
103
- Generated on Sun Dec 25 21:09:36 2022 by
103
+ Generated on Fri Dec 30 17:49:58 2022 by
104
104
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
105
105
  0.9.28 (ruby-3.0.4).
106
106
  </div>
data/env_parser.gemspec CHANGED
@@ -21,11 +21,10 @@ Gem::Specification.new do |spec|
21
21
  spec.metadata['rubygems_mfa_required'] = 'true'
22
22
 
23
23
  spec.add_dependency 'activesupport', ['>= 6.1.0', '< 7.1']
24
- spec.add_dependency 'chronic'
25
- spec.add_dependency 'chronic_duration'
24
+ spec.add_dependency 'chronic', '~> 0'
25
+ spec.add_dependency 'chronic_duration', '~> 0'
26
26
 
27
27
  spec.add_development_dependency 'bundler', '~> 2'
28
- spec.add_development_dependency 'rake'
29
28
  spec.add_development_dependency 'rspec', '~> 3'
30
29
  spec.add_development_dependency 'rspec_junit_formatter'
31
30
  spec.add_development_dependency 'rubocop'
@@ -48,6 +48,18 @@ module EnvParser::Types
48
48
  # Note this does not guarantee RFC5322-conformity.
49
49
  # </td>
50
50
  # </tr>
51
+ # <tr>
52
+ # <td>:version / :semver</td>
53
+ # <td>MatchData</td>
54
+ # <td><code>nil</code></td>
55
+ # <td>
56
+ # The resulting MatchData has named captures for "major", "minor", "patch", "prerelease", and "buildmetadata".
57
+ # <br />
58
+ # The Regex used for generating this MatchData is available at: https://regex101.com/r/Ly7O1x/3/
59
+ # <br />
60
+ # See https://semver.org for additional info.
61
+ # </td>
62
+ # </tr>
51
63
  # </tbody>
52
64
  # </table>
53
65
  #
@@ -95,5 +107,15 @@ module EnvParser::Types
95
107
 
96
108
  value
97
109
  end
110
+
111
+ EnvParser.define_type(:version, aliases: :semver, if_unset: nil) do |value|
112
+ # We're using the official semver.org-provided regex.
113
+ semver = %r{^(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-(?<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$} ## rubocop:disable Layout/LineLength
114
+
115
+ match_data = value.match(semver)
116
+ raise(EnvParser::ValueNotConvertibleError, 'not a semver-compliant value') unless match_data
117
+
118
+ match_data
119
+ end
98
120
  end
99
121
  end
@@ -1,3 +1,3 @@
1
1
  class EnvParser
2
- VERSION = '1.3.3'.freeze
2
+ VERSION = '1.6.1'.freeze
3
3
  end
data/lib/env_parser.rb CHANGED
@@ -132,12 +132,12 @@ class EnvParser
132
132
  # variable names and whose values are the options set for each variable's {.register} call.
133
133
  #
134
134
  # <pre>
135
- # ## Example shortcut usage:
135
+ # # Example shortcut usage:
136
136
  #
137
137
  # EnvParser.register :A, from: one_hash, as: :integer
138
138
  # EnvParser.register :B, from: another_hash, as: :string, if_unset: 'none'
139
139
  #
140
- # ## ... is equivalent to ...
140
+ # # ... is equivalent to ...
141
141
  #
142
142
  # EnvParser.register(
143
143
  # A: { from: one_hash, as: :integer }
@@ -152,6 +152,19 @@ class EnvParser
152
152
  # @option options [Hash] from (ENV)
153
153
  # The source Hash from which to pull the value referenced by the "name" key.
154
154
  #
155
+ # @option options [Symbol] named
156
+ # The name the constant should be given. Valid only when a "within" value is *explicitly*
157
+ # given. This allows for decoupling ENV variable names from the constant name defined
158
+ # within its target class or module, allowing for the ENV variables to be namespaced in
159
+ # some way.
160
+ #
161
+ # <pre>
162
+ # EnvParser.register(
163
+ # CUSTOM_CLIENT_DEFAULT_HOSTNAME: { as: :string, named: :DEFAULT_HOSTNAME, within: CustomClient },
164
+ # CUSTOM_CLIENT_DEFAULT_PORT: { as: :integer, named: :DEFAULT_PORT, within: CustomClient }
165
+ # )
166
+ # </pre>
167
+ #
155
168
  # @option options [Module, Class] within (Kernel)
156
169
  # The module or class in which the constant should be created. Creates global constants by
157
170
  # default.
@@ -185,6 +198,9 @@ class EnvParser
185
198
  from = options.fetch(:from, ENV)
186
199
  within = options.fetch(:within, Kernel)
187
200
 
201
+ named = name
202
+ named = options.fetch(:named, name) if options.key? :within
203
+
188
204
  # ENV *seems* like a Hash and it does *some* Hash-y things, but it is NOT a Hash and that can
189
205
  # bite you in some cases. Making sure we're working with a straight-up Hash saves a lot of
190
206
  # sanity checks later on. This is also a good place to make sure we're working with a String
@@ -199,7 +215,7 @@ class EnvParser
199
215
 
200
216
  value = from[name]
201
217
  value = parse(value, options, &validation_block)
202
- within.const_set(name.upcase.to_sym, value.dup.freeze)
218
+ within.const_set(named.upcase.to_sym, value.dup.freeze)
203
219
 
204
220
  value
205
221
  end
@@ -248,7 +264,7 @@ class EnvParser
248
264
 
249
265
  autoregister_spec.deep_symbolize_keys!
250
266
  autoregister_spec.transform_values! do |spec|
251
- sanitized = spec.slice(:as, :within, :if_unset, :from_set)
267
+ sanitized = spec.slice(:as, :named, :within, :if_unset, :from_set)
252
268
  sanitized[:as] = sanitized[:as].to_sym if sanitized.key? :as
253
269
  sanitized[:within] = sanitized[:within].constantize if sanitized.key? :within
254
270
 
@@ -42,4 +42,54 @@ RSpec.describe EnvParser::Types::InternetTypes do
42
42
 
43
43
  expect { EnvParser.parse('not an email address', as: :email_address) }.to raise_error(EnvParser::ValueNotConvertibleError)
44
44
  end
45
+
46
+ it 'can parse version numbers' do
47
+ %i[version semver].each do |type|
48
+ expect(EnvParser.parse(nil, as: type)).to eq(nil)
49
+ expect(EnvParser.parse('', as: type)).to eq(nil)
50
+
51
+ # Our list of valid version strings is a subset of those in the official semver.org-provided regex suite.
52
+ # rubocop:disable Layout
53
+ #
54
+ valid_version_strings = {
55
+ '0.0.4' => { major: '0' , minor: '0', patch: '4', prerelease: nil , buildmetadata: nil },
56
+ '1.2.3' => { major: '1' , minor: '2', patch: '3', prerelease: nil , buildmetadata: nil },
57
+ '1.1.2-prerelease+meta' => { major: '1' , minor: '1', patch: '2', prerelease: 'prerelease' , buildmetadata: 'meta' },
58
+ '1.1.2+meta' => { major: '1' , minor: '1', patch: '2', prerelease: nil , buildmetadata: 'meta' },
59
+ '1.1.2+meta-valid' => { major: '1' , minor: '1', patch: '2', prerelease: nil , buildmetadata: 'meta-valid' },
60
+ '1.0.0-alpha' => { major: '1' , minor: '0', patch: '0', prerelease: 'alpha' , buildmetadata: nil },
61
+ '1.0.0-beta' => { major: '1' , minor: '0', patch: '0', prerelease: 'beta' , buildmetadata: nil },
62
+ '1.0.0-alpha.beta' => { major: '1' , minor: '0', patch: '0', prerelease: 'alpha.beta' , buildmetadata: nil },
63
+ '1.0.0-alpha.beta.1' => { major: '1' , minor: '0', patch: '0', prerelease: 'alpha.beta.1', buildmetadata: nil },
64
+ '1.0.0-alpha.1' => { major: '1' , minor: '0', patch: '0', prerelease: 'alpha.1' , buildmetadata: nil },
65
+ '1.0.0-alpha0.valid' => { major: '1' , minor: '0', patch: '0', prerelease: 'alpha0.valid', buildmetadata: nil },
66
+ '1.0.0-alpha.0valid' => { major: '1' , minor: '0', patch: '0', prerelease: 'alpha.0valid', buildmetadata: nil },
67
+ '1.0.0-rc.1+build.1' => { major: '1' , minor: '0', patch: '0', prerelease: 'rc.1' , buildmetadata: 'build.1' },
68
+ '2.0.0-rc.1+build.123' => { major: '2' , minor: '0', patch: '0', prerelease: 'rc.1' , buildmetadata: 'build.123' },
69
+ '1.2.3-beta' => { major: '1' , minor: '2', patch: '3', prerelease: 'beta' , buildmetadata: nil },
70
+ '10.2.3-DEV-SNAPSHOT' => { major: '10', minor: '2', patch: '3', prerelease: 'DEV-SNAPSHOT', buildmetadata: nil },
71
+ '1.2.3-SNAPSHOT-123' => { major: '1' , minor: '2', patch: '3', prerelease: 'SNAPSHOT-123', buildmetadata: nil },
72
+ '2.0.0+build.1848' => { major: '2' , minor: '0', patch: '0', prerelease: nil , buildmetadata: 'build.1848' },
73
+ '2.0.1-alpha.1227' => { major: '2' , minor: '0', patch: '1', prerelease: 'alpha.1227' , buildmetadata: nil },
74
+ '1.0.0-alpha+beta' => { major: '1' , minor: '0', patch: '0', prerelease: 'alpha' , buildmetadata: 'beta' },
75
+ '1.0.0-0A.is.legal' => { major: '1' , minor: '0', patch: '0', prerelease: '0A.is.legal' , buildmetadata: nil }
76
+ }
77
+ # rubocop:enable Layout
78
+
79
+ valid_version_strings.each do |version, expected_matches|
80
+ parsed_value = EnvParser.parse(version, as: type)
81
+
82
+ expect(parsed_value).to_not eq(nil)
83
+ expected_matches.each { |match_name, expected_value| expect(parsed_value[match_name]).to eq(expected_value) }
84
+ end
85
+
86
+ # Our list of invalid version strings is a subset of those in the official semver.org-provided regex suite.
87
+ #
88
+ invalid_version_strings = ['1', '1.2', '1.2.3-0123', '1.2.3-0123.0123', '1.1.2+.123', '+invalid', '-invalid', '-invalid+invalid',
89
+ '-invalid.01', 'alpha', 'alpha.1', 'alpha+beta', '1.0.0-alpha..', '1.0.0-alpha..1', '01.1.1', '1.01.1',
90
+ '1.1.01', '1.2.3.DEV', '1.2-SNAPSHOT', '+justmeta', '9.8.7+meta+meta', '9.8.7-whatever+meta+meta']
91
+
92
+ invalid_version_strings.each { |version| expect { EnvParser.parse(version, as: type) }.to raise_error(EnvParser::ValueNotConvertibleError) }
93
+ end
94
+ end
45
95
  end
@@ -60,9 +60,16 @@ RSpec.describe EnvParser do
60
60
  end
61
61
 
62
62
  it 'creates module constants' do
63
- source_hash = { XYZ: '456' }
64
- EnvParser.register(:XYZ, from: source_hash, as: :integer, within: Sample)
65
- expect(Sample::XYZ).to eq(456)
63
+ source_hash = { DEF: '456' }
64
+ EnvParser.register(:DEF, from: source_hash, as: :integer, within: Sample)
65
+ expect(Sample::DEF).to eq(456)
66
+ end
67
+
68
+ it 'creates named module constants' do
69
+ source_hash = { GHI: '789' }
70
+ EnvParser.register(:GHI, from: source_hash, as: :integer, named: :JKL, within: Sample)
71
+ expect { Sample::GHI }.to raise_error(NameError)
72
+ expect(Sample::JKL).to eq(789)
66
73
  end
67
74
 
68
75
  it 'will accept a hash keyed by variable names' do
@@ -117,6 +124,13 @@ RSpec.describe EnvParser do
117
124
  expect(Sample::WXYZ).to eq(5678)
118
125
  end
119
126
 
127
+ it 'creates module constants' do
128
+ ENV['ORIGINAL_NAME'] = '9999'
129
+ ENV.register(:ORIGINAL_NAME, as: :integer, named: :DIFFERENT_NAME, within: Sample)
130
+ expect { Sample::ORIGINAL_NAME }.to raise_error(NameError)
131
+ expect(Sample::DIFFERENT_NAME).to eq(9999)
132
+ end
133
+
120
134
  it 'will accept a hash keyed by variable names' do
121
135
  ENV['FIFTH'] = 'fifth'
122
136
  ENV['SIXTH'] = '99'
@@ -156,6 +170,11 @@ RSpec.describe EnvParser do
156
170
  CLASS_CONSTANT:
157
171
  as: :string
158
172
  within: String
173
+
174
+ NAMED_CLASS_CONSTANT:
175
+ as: :string
176
+ named: :OTHER_CLASS_CONSTANT
177
+ within: String
159
178
  YAML
160
179
 
161
180
  file.path
@@ -164,11 +183,14 @@ RSpec.describe EnvParser do
164
183
  ENV['SOME_INT'] = '99'
165
184
  ENV['SOME_STRING'] = 'twelve'
166
185
  ENV['CLASS_CONSTANT'] = 'tricky'
186
+ ENV['NAMED_CLASS_CONSTANT'] = 'quizzical'
167
187
  EnvParser.autoregister filename
168
188
 
169
189
  expect(SOME_INT).to eq(99)
170
190
  expect(SOME_STRING).to eq('twelve')
171
191
  expect(String::CLASS_CONSTANT).to eq('tricky')
192
+ expect { String::NAMED_CLASS_CONSTANT }.to raise_error(NameError)
193
+ expect(String::OTHER_CLASS_CONSTANT).to eq('quizzical')
172
194
  end
173
195
 
174
196
  it 'properly handles file-not-found' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: env_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.3
4
+ version: 1.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nestor Custodio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-26 00:00:00.000000000 Z
11
+ date: 2023-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -34,28 +34,28 @@ dependencies:
34
34
  name: chronic
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - ">="
37
+ - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: '0'
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
- - - ">="
44
+ - - "~>"
45
45
  - !ruby/object:Gem::Version
46
46
  version: '0'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: chronic_duration
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
- - - ">="
51
+ - - "~>"
52
52
  - !ruby/object:Gem::Version
53
53
  version: '0'
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
- - - ">="
58
+ - - "~>"
59
59
  - !ruby/object:Gem::Version
60
60
  version: '0'
61
61
  - !ruby/object:Gem::Dependency
@@ -72,20 +72,6 @@ dependencies:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
74
  version: '2'
75
- - !ruby/object:Gem::Dependency
76
- name: rake
77
- requirement: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - ">="
80
- - !ruby/object:Gem::Version
81
- version: '0'
82
- type: :development
83
- prerelease: false
84
- version_requirements: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - ">="
87
- - !ruby/object:Gem::Version
88
- version: '0'
89
75
  - !ruby/object:Gem::Dependency
90
76
  name: rspec
91
77
  requirement: !ruby/object:Gem::Requirement