env_parser 1.3.3 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
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