env_parser 0.8.0 → 1.3.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.
Files changed (43) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +7 -6
  3. data/.rubocop.yml +56 -57
  4. data/.ruby-version +1 -1
  5. data/Gemfile.lock +58 -28
  6. data/README.md +252 -176
  7. data/docs/EnvParser.html +305 -169
  8. data/docs/EnvParser/AutoregisterFileNotFound.html +143 -0
  9. data/docs/EnvParser/Error.html +9 -9
  10. data/docs/EnvParser/TypeAlreadyDefinedError.html +143 -0
  11. data/docs/EnvParser/Types.html +128 -0
  12. data/docs/EnvParser/Types/BaseTypes.html +177 -0
  13. data/docs/EnvParser/Types/ChronologyTypes.html +159 -0
  14. data/docs/EnvParser/Types/InternetTypes.html +159 -0
  15. data/docs/EnvParser/UnknownTypeError.html +143 -0
  16. data/docs/EnvParser/UnparseableAutoregisterSpec.html +143 -0
  17. data/docs/EnvParser/ValueNotAllowedError.html +143 -0
  18. data/docs/EnvParser/ValueNotConvertibleError.html +143 -0
  19. data/docs/EnvParserTypes.html +129 -0
  20. data/docs/EnvParserTypes/BaseTypes.html +178 -0
  21. data/docs/EnvParserTypes/ChronologyTypes.html +159 -0
  22. data/docs/EnvParserTypes/InternetTypes.html +159 -0
  23. data/docs/EnvParserTypes/TimeTypes.html +158 -0
  24. data/docs/_index.html +108 -9
  25. data/docs/class_list.html +3 -3
  26. data/docs/css/style.css +7 -9
  27. data/docs/file.README.html +215 -226
  28. data/docs/file_list.html +2 -2
  29. data/docs/frames.html +2 -2
  30. data/docs/index.html +215 -226
  31. data/docs/js/app.js +69 -3
  32. data/docs/method_list.html +13 -5
  33. data/docs/top-level-namespace.html +9 -9
  34. data/env_parser.gemspec +6 -2
  35. data/lib/env_parser.rb +111 -83
  36. data/lib/env_parser/autoregister.rb +3 -0
  37. data/lib/env_parser/errors.rb +40 -0
  38. data/lib/env_parser/types.rb +3 -0
  39. data/lib/env_parser/types/base_types.rb +99 -26
  40. data/lib/env_parser/types/chronology_types.rb +104 -0
  41. data/lib/env_parser/types/internet_types.rb +99 -0
  42. data/lib/env_parser/version.rb +1 -1
  43. metadata +85 -10
@@ -120,6 +120,49 @@ function summaryToggle() {
120
120
  } else { localStorage.summaryCollapsed = "expand"; }
121
121
  }
122
122
 
123
+ function constantSummaryToggle() {
124
+ $('.constants_summary_toggle').click(function(e) {
125
+ e.preventDefault();
126
+ localStorage.summaryCollapsed = $(this).text();
127
+ $('.constants_summary_toggle').each(function() {
128
+ $(this).text($(this).text() == "collapse" ? "expand" : "collapse");
129
+ var next = $(this).parent().parent().nextAll('dl.constants').first();
130
+ if (next.hasClass('compact')) {
131
+ next.toggle();
132
+ next.nextAll('dl.constants').first().toggle();
133
+ }
134
+ else if (next.hasClass('constants')) {
135
+ var list = $('<dl class="constants compact" />');
136
+ list.html(next.html());
137
+ list.find('dt').each(function() {
138
+ $(this).addClass('summary_signature');
139
+ $(this).text( $(this).text().split('=')[0]);
140
+ if ($(this).has(".deprecated").length) {
141
+ $(this).addClass('deprecated');
142
+ };
143
+ });
144
+ // Add the value of the constant as "Tooltip" to the summary object
145
+ list.find('pre.code').each(function() {
146
+ console.log($(this).parent());
147
+ var dt_element = $(this).parent().prev();
148
+ var tooltip = $(this).text();
149
+ if (dt_element.hasClass("deprecated")) {
150
+ tooltip = 'Deprecated. ' + tooltip;
151
+ };
152
+ dt_element.attr('title', tooltip);
153
+ });
154
+ list.find('.docstring, .tags, dd').remove();
155
+ next.before(list);
156
+ next.toggle();
157
+ }
158
+ });
159
+ return false;
160
+ });
161
+ if (localStorage.summaryCollapsed == "collapse") {
162
+ $('.constants_summary_toggle').first().click();
163
+ } else { localStorage.summaryCollapsed = "expand"; }
164
+ }
165
+
123
166
  function generateTOC() {
124
167
  if ($('#filecontents').length === 0) return;
125
168
  var _toc = $('<ol class="top"></ol>');
@@ -128,6 +171,7 @@ function generateTOC() {
128
171
  var counter = 0;
129
172
  var tags = ['h2', 'h3', 'h4', 'h5', 'h6'];
130
173
  var i;
174
+ var curli;
131
175
  if ($('#filecontents h1').length > 1) tags.unshift('h1');
132
176
  for (i = 0; i < tags.length; i++) { tags[i] = '#filecontents ' + tags[i]; }
133
177
  var lastTag = parseInt(tags[0][1], 10);
@@ -147,15 +191,25 @@ function generateTOC() {
147
191
  }
148
192
  if (thisTag > lastTag) {
149
193
  for (i = 0; i < thisTag - lastTag; i++) {
150
- var tmp = $('<ol/>'); toc.append(tmp); toc = tmp;
194
+ if ( typeof(curli) == "undefined" ) {
195
+ curli = $('<li/>');
196
+ toc.append(curli);
197
+ }
198
+ toc = $('<ol/>');
199
+ curli.append(toc);
200
+ curli = undefined;
151
201
  }
152
202
  }
153
203
  if (thisTag < lastTag) {
154
- for (i = 0; i < lastTag - thisTag; i++) toc = toc.parent();
204
+ for (i = 0; i < lastTag - thisTag; i++) {
205
+ toc = toc.parent();
206
+ toc = toc.parent();
207
+ }
155
208
  }
156
209
  var title = $(this).attr('toc-title');
157
210
  if (typeof(title) == "undefined") title = $(this).text();
158
- toc.append('<li><a href="#' + this.id + '">' + title + '</a></li>');
211
+ curli =$('<li><a href="#' + this.id + '">' + title + '</a></li>');
212
+ toc.append(curli);
159
213
  lastTag = thisTag;
160
214
  });
161
215
  if (!show) return;
@@ -232,6 +286,16 @@ function mainFocus() {
232
286
  setTimeout(function() { $('#main').focus(); }, 10);
233
287
  }
234
288
 
289
+ function navigationChange() {
290
+ // This works around the broken anchor navigation with the YARD template.
291
+ window.onpopstate = function() {
292
+ var hash = window.location.hash;
293
+ if (hash !== '' && $(hash)[0]) {
294
+ $(hash)[0].scrollIntoView();
295
+ }
296
+ };
297
+ }
298
+
235
299
  $(document).ready(function() {
236
300
  navResizer();
237
301
  navExpander();
@@ -241,8 +305,10 @@ $(document).ready(function() {
241
305
  searchFrameButtons();
242
306
  linkSummaries();
243
307
  summaryToggle();
308
+ constantSummaryToggle();
244
309
  generateTOC();
245
310
  mainFocus();
311
+ navigationChange();
246
312
  });
247
313
 
248
314
  })();
@@ -4,9 +4,9 @@
4
4
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
5
  <meta charset="utf-8" />
6
6
 
7
- <link rel="stylesheet" href="css/full_list.css" type="text/css" media="screen" charset="utf-8" />
7
+ <link rel="stylesheet" href="css/full_list.css" type="text/css" media="screen" />
8
8
 
9
- <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
9
+ <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" />
10
10
 
11
11
 
12
12
 
@@ -54,13 +54,21 @@
54
54
 
55
55
  <li class="even ">
56
56
  <div class="item">
57
- <span class='object_link'><a href="EnvParser.html#define_type-class_method" title="EnvParser.define_type (method)">define_type</a></span>
57
+ <span class='object_link'><a href="EnvParser.html#autoregister-class_method" title="EnvParser.autoregister (method)">autoregister</a></span>
58
58
  <small>EnvParser</small>
59
59
  </div>
60
60
  </li>
61
61
 
62
62
 
63
63
  <li class="odd ">
64
+ <div class="item">
65
+ <span class='object_link'><a href="EnvParser.html#define_type-class_method" title="EnvParser.define_type (method)">define_type</a></span>
66
+ <small>EnvParser</small>
67
+ </div>
68
+ </li>
69
+
70
+
71
+ <li class="even ">
64
72
  <div class="item">
65
73
  <span class='object_link'><a href="top-level-namespace.html#filename-instance_method" title="#filename (method)">#filename</a></span>
66
74
  <small>Top Level Namespace</small>
@@ -68,7 +76,7 @@
68
76
  </li>
69
77
 
70
78
 
71
- <li class="even ">
79
+ <li class="odd ">
72
80
  <div class="item">
73
81
  <span class='object_link'><a href="EnvParser.html#parse-class_method" title="EnvParser.parse (method)">parse</a></span>
74
82
  <small>EnvParser</small>
@@ -76,7 +84,7 @@
76
84
  </li>
77
85
 
78
86
 
79
- <li class="odd ">
87
+ <li class="even ">
80
88
  <div class="item">
81
89
  <span class='object_link'><a href="EnvParser.html#register-class_method" title="EnvParser.register (method)">register</a></span>
82
90
  <small>EnvParser</small>
@@ -6,15 +6,15 @@
6
6
  <title>
7
7
  Top Level Namespace
8
8
 
9
- &mdash; Documentation by YARD 0.9.11
9
+ &mdash; Documentation by YARD 0.9.26
10
10
 
11
11
  </title>
12
12
 
13
- <link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" />
14
14
 
15
- <link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" />
16
16
 
17
- <script type="text/javascript" charset="utf-8">
17
+ <script type="text/javascript">
18
18
  pathId = "";
19
19
  relpath = '';
20
20
  </script>
@@ -162,12 +162,12 @@
162
162
  <pre class="lines">
163
163
 
164
164
 
165
- 315</pre>
165
+ 3</pre>
166
166
  </td>
167
167
  <td>
168
- <pre class="code"><span class="info file"># File 'lib/env_parser.rb', line 315</span>
168
+ <pre class="code"><span class="info file"># File 'lib/env_parser/types.rb', line 3</span>
169
169
 
170
- <span class='const'>Dir</span><span class='period'>.</span><span class='id identifier rubyid_glob'>glob</span><span class='lparen'>(</span><span class='const'>File</span><span class='period'>.</span><span class='id identifier rubyid_join'>join</span><span class='lparen'>(</span><span class='id identifier rubyid___dir__'>__dir__</span><span class='comma'>,</span> <span class='qwords_beg'>%w[</span><span class='tstring_content'>env_parser</span><span class='words_sep'> </span><span class='tstring_content'>types</span><span class='words_sep'> </span><span class='tstring_content'>*.rb</span><span class='words_sep'>]</span><span class='rparen'>)</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_each'>each</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_filename'>filename</span><span class='op'>|</span> <span class='id identifier rubyid_require_relative'>require_relative</span> <span class='id identifier rubyid_filename'>filename</span> <span class='rbrace'>}</span></pre>
170
+ <span class='const'>Dir</span><span class='period'>.</span><span class='id identifier rubyid_glob'>glob</span><span class='lparen'>(</span><span class='const'>File</span><span class='period'>.</span><span class='id identifier rubyid_join'>join</span><span class='lparen'>(</span><span class='id identifier rubyid___dir__'>__dir__</span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>types</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>*.rb</span><span class='tstring_end'>&#39;</span></span><span class='rparen'>)</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_each'>each</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_filename'>filename</span><span class='op'>|</span> <span class='id identifier rubyid_require_relative'>require_relative</span> <span class='id identifier rubyid_filename'>filename</span> <span class='rbrace'>}</span></pre>
171
171
  </td>
172
172
  </tr>
173
173
  </table>
@@ -178,9 +178,9 @@
178
178
  </div>
179
179
 
180
180
  <div id="footer">
181
- Generated on Sun Dec 24 19:33:35 2017 by
181
+ Generated on Sat Jan 2 17:31:17 2021 by
182
182
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
183
- 0.9.11 (ruby-2.4.2).
183
+ 0.9.26 (ruby-2.7.2).
184
184
  </div>
185
185
 
186
186
  </div>
@@ -20,10 +20,14 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ['lib']
22
22
 
23
- spec.add_development_dependency 'bundler', '~> 1.16'
24
- spec.add_development_dependency 'rake', '~> 10.0'
23
+ spec.add_development_dependency 'bundler', '~> 2.0'
24
+ spec.add_development_dependency 'rake'
25
25
  spec.add_development_dependency 'rspec', '~> 3.0'
26
26
  spec.add_development_dependency 'rspec_junit_formatter'
27
+ spec.add_development_dependency 'rubocop', '1.7'
28
+ spec.add_development_dependency 'yard'
27
29
 
28
30
  spec.add_dependency 'activesupport', '>= 5.0.0'
31
+ spec.add_dependency 'chronic'
32
+ spec.add_dependency 'chronic_duration'
29
33
  end
@@ -1,61 +1,52 @@
1
+ require 'env_parser/errors'
1
2
  require 'env_parser/version'
2
3
  require 'active_support/all'
4
+ require 'psych'
3
5
 
4
6
  ## The EnvParser class simplifies parsing of environment variables as different data types.
5
7
  ##
6
8
  class EnvParser
7
- ## Base exception class for EnvParser.
9
+ ## The default filename to use for {.autoregister} requests.
8
10
  ##
9
- class Error < ::StandardError
10
- end
11
-
12
- ## Exception class used to indicate parsed values not allowed per a "from_set" option.
13
- ##
14
- class ValueNotAllowed < Error
15
- end
16
-
17
- ## Exception class used to indicate a type has already been defined.
18
- ##
19
- class TypeAlreadyDefined < Error
20
- end
11
+ AUTOREGISTER_FILE = '.env_parser.yml'.freeze
21
12
 
22
13
  class << self
23
- ## Defines a new type for use as the "as" option on a subsequent `.parse` or `.register` call.
14
+ ## Defines a new type for use as the "as" option on a subsequent {.parse} or {.register} call.
24
15
  ##
25
16
  ## @param name [Symbol]
26
17
  ## The name to assign to the type.
27
18
  ##
28
- ## @option options aliases [Array<Symbol>]
19
+ ## @option options [Array<Symbol>] aliases
29
20
  ## An array of additional names you'd like to see refer to this same type.
30
21
  ##
31
- ## @option options if_unset
22
+ ## @option options if_unset (nil)
32
23
  ## Specifies a "sensible default" to return for this type if the value being parsed (via
33
- ## `.parse` or `.register`) is either unset (`nil`) or blank (`''`). Note this may be
34
- ## overridden by the user via the `.parse`/`.register` "if_unset" option.
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.
35
26
  ##
36
- ## @yield
27
+ ## @yield [value]
37
28
  ## A block to act as the parser for the this type. If no block is given, an ArgumentError is
38
29
  ## raised.
39
30
  ##
40
- ## When the type defined is used via a `.parse`/`.register` call, this block is invoked with
31
+ ## When the type defined is used via a {.parse}/{.register} call, this block is invoked with
41
32
  ## the value to be parsed. Said value is guaranteed to be a non-empty String (the "if_unset"
42
33
  ## check will have already run), but no other assurances as to content are given. The block
43
34
  ## should return the final output of parsing the given String value as the type being defined.
44
35
  ##
45
36
  ## If the value given cannot be sensibly parsed into the type defined, the block should raise
46
- ## an EnvParser::ValueNotAllowed exception.
37
+ ## an {EnvParser::ValueNotConvertibleError}.
47
38
  ##
48
39
  ## @return [nil]
49
40
  ## This generates no usable value.
50
41
  ##
51
- ## @raise [ArgumentError, EnvParser::TypeAlreadyDefined]
42
+ ## @raise [ArgumentError, EnvParser::TypeAlreadyDefinedError]
52
43
  ##
53
44
  def define_type(name, options = {}, &parser)
54
45
  raise(ArgumentError, 'no parsing block given') unless block_given?
55
46
 
56
47
  given_types = (Array(name) + Array(options[:aliases])).map(&:to_s).map(&:to_sym)
57
48
  given_types.each do |type|
58
- raise(TypeAlreadyDefined, "cannot redefine #{type.inspect}") if known_types.key?(type)
49
+ raise(TypeAlreadyDefinedError, "cannot redefine #{type.inspect}") if known_types.key?(type)
59
50
 
60
51
  known_types[type] = {
61
52
  parser: parser,
@@ -72,12 +63,13 @@ class EnvParser
72
63
  ## The value to parse/interpret. If a String is given, the value will be used as-is. If a
73
64
  ## Symbol is given, the ENV value for the matching string key will be used.
74
65
  ##
75
- ## @option options as [Symbol]
66
+ ## @option options [Symbol] as
76
67
  ## The expected return type. A best-effort attempt is made to convert the source String to the
77
68
  ## requested type.
78
69
  ##
79
- ## If no "as" option is given (or the "as" value given has not been defined), an ArgumentError
80
- ## exception is raised.
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.
81
73
  ##
82
74
  ## @option options if_unset
83
75
  ## Specifies the default value to return if the given "value" is either unset (`nil`) or blank
@@ -85,43 +77,45 @@ class EnvParser
85
77
  ## change having been made. If unspecified, the "default" value for `nil`/`''` input will
86
78
  ## depend on the "as" type.
87
79
  ##
88
- ## @option options from_set [Array, Range]
80
+ ## @option options [Array, Range] from_set
89
81
  ## Gives a limited set of allowed values (after type conversion). If, after parsing, the final
90
- ## value is not included in the "from_set" list/range, an EnvParser::ValueNotAllowed exception
91
- ## is raised.
82
+ ## value is not included in the "from_set" list/range, an {EnvParser::ValueNotAllowedError} is
83
+ ## raised.
92
84
  ##
93
85
  ## Note that if the "if_unset" option is given and the value to parse is `nil`/`''`, the
94
86
  ## "if_unset" value will be returned, even if it is not part of the "from_set" list/range.
95
87
  ##
96
88
  ## Also note that, due to the nature of the lookup, the "from_set" option is only available
97
89
  ## for scalar values (i.e. not arrays, hashes, or other enumerables). An attempt to use the
98
- ## "from_set" option with a non-scalar value will raise an ArgumentError exception.
90
+ ## "from_set" option with a non-scalar value will raise an ArgumentError.
99
91
  ##
100
- ## @option options validated_by [Proc]
101
- ## If given, the "validated_by" proc is called with the parsed value (after type conversion)
92
+ ## @option options [Proc] validated_by
93
+ ## If given, the "validated_by" Proc is called with the parsed value (after type conversion)
102
94
  ## as its sole argument. This allows for user-defined validation of the parsed value beyond
103
- ## what can be enforced by use of the "from_set" option alone. If the proc's return value is
104
- ## `#blank?`, an EnvParser::ValueNotAllowed exception is raised. To accomodate your syntax of
105
- ## choice, this validation proc may be given as a yield block instead.
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.
106
98
  ##
107
99
  ## Note that this option is intended to provide an inspection mechanism only -- no mutation
108
- ## of the parsed value should occur within the given proc. To that end, the argument passed is
100
+ ## of the parsed value should occur within the given Proc. To that end, the argument passed is
109
101
  ## a *frozen* duplicate of the parsed value.
110
102
  ##
111
103
  ## @yield [value]
112
- ## A block (if given) is treated exactly as the "validated_by" Proc would. Although there is
113
- ## no compelling reason to provide both a "validated_by" proc *and* a validation block, there
114
- ## is no technical limitation preventing this. **If both are given, both validation checks
115
- ## must pass.**
104
+ ## A block (if given) is treated exactly as the "validated_by" Proc would.
116
105
  ##
117
- ## @raise [ArgumentError, EnvParser::ValueNotAllowed]
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]
118
111
  ##
119
112
  def parse(value, options = {}, &validation_block)
120
113
  value = ENV[value.to_s] if value.is_a? Symbol
121
114
  value = value.to_s
122
115
 
123
116
  type = known_types[options[:as]]
124
- raise(ArgumentError, "invalid `as` parameter: #{options[:as].inspect}") unless type
117
+ raise(ArgumentError, 'missing `as` parameter') unless options.key?(:as)
118
+ raise(UnknownTypeError, "invalid `as` parameter: #{options[:as].inspect}") unless type
125
119
 
126
120
  return (options.key?(:if_unset) ? options[:if_unset] : type[:if_unset]) if value.blank?
127
121
 
@@ -134,9 +128,8 @@ class EnvParser
134
128
 
135
129
  ## Parses the referenced value and creates a matching constant in the requested context.
136
130
  ##
137
- ## Multiple calls to "register" may be shortcutted by passing in a Hash with the same keys as
138
- ## those in the "from" Hash and each value being the "register" options set for each variable's
139
- ## "register" call.
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.
140
133
  ##
141
134
  ## <pre>
142
135
  ## ## Example shortcut usage:
@@ -153,40 +146,39 @@ class EnvParser
153
146
  ## </pre>
154
147
  ##
155
148
  ## @param name
156
- ## The name of the value to parse/interpret from the "from" Hash. If the "from" value is ENV,
157
- ## you may give a Symbol and the corresponding String key will be used instead.
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.
158
151
  ##
159
- ## @option options from [Hash]
160
- ## The source Hash from which to pull the value referenced by the "name" key. Defaults to ENV.
152
+ ## @option options [Hash] from (ENV)
153
+ ## The source Hash from which to pull the value referenced by the "name" key.
161
154
  ##
162
- ## @option options within [Module, Class]
163
- ## The module or class in which the constant should be created. Defaults to Kernel (making it
164
- ## a global constant).
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.
165
158
  ##
166
- ## @option options as [Symbol]
167
- ## See `.parse`.
159
+ ## @option options [Symbol] as
160
+ ## See {.parse}.
168
161
  ##
169
162
  ## @option options if_unset
170
- ## See `.parse`.
163
+ ## See {.parse}.
171
164
  ##
172
- ## @option options from_set [Array, Range]
173
- ## See `.parse`.
165
+ ## @option options [Array, Range] from_set
166
+ ## See {.parse}.
174
167
  ##
175
- ## @option options validated_by [Proc]
176
- ## See `.parse`.
168
+ ## @option options [Proc] validated_by
169
+ ## See {.parse}.
177
170
  ##
178
171
  ## @yield [value]
179
- ## A block (if given) is treated exactly as in `.parse`. Note, however, that a single yield
180
- ## block cannot be used to register multiple constants simultaneously -- each value needing
181
- ## validation must give its own "validated_by" proc.
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.
182
175
  ##
183
176
  ## @raise [ArgumentError]
184
177
  ##
185
178
  def register(name, options = {}, &validation_block)
186
- ## We want to allow for registering multiple variables simultaneously via a single `.register`
187
- ## method call.
179
+ ## Allow for registering multiple variables simultaneously via a single call.
188
180
  if name.is_a? Hash
189
- raise ArgumentError, 'cannot register multiple values with one yield block' if block_given?
181
+ raise(ArgumentError, 'cannot register multiple values with one block') if block_given?
190
182
  return register_all(name)
191
183
  end
192
184
 
@@ -202,9 +194,7 @@ class EnvParser
202
194
  name = name.to_s
203
195
  end
204
196
 
205
- unless from.is_a?(Hash)
206
- raise ArgumentError, "invalid `from` parameter: #{from.class}"
207
- end
197
+ raise ArgumentError, "invalid `from` parameter: #{from.class}" unless from.is_a? Hash
208
198
 
209
199
  unless within.is_a?(Module) || within.is_a?(Class)
210
200
  raise ArgumentError, "invalid `within` parameter: #{within.inspect}"
@@ -217,14 +207,14 @@ class EnvParser
217
207
  value
218
208
  end
219
209
 
220
- ## Creates ENV bindings for EnvParser.parse and EnvParser.register proxy methods.
210
+ ## Creates ENV bindings for {.parse} and {.register} proxy methods.
221
211
  ##
222
212
  ## The sole difference between these proxy methods and their EnvParser counterparts is that
223
213
  ## ENV.parse will interpret any value given as an ENV key (as a String), not the given value
224
214
  ## itself. i.e. ENV.parse('XYZ', ...) is equivalent to EnvParser.parse(ENV['XYZ'], ...)
225
215
  ##
226
216
  ## @return [ENV]
227
- ## This generates no usable value, so we may as well return ENV for chaining?
217
+ ## This generates no usable value.
228
218
  ##
229
219
  def add_env_bindings
230
220
  ENV.instance_eval do
@@ -240,6 +230,47 @@ class EnvParser
240
230
  ENV
241
231
  end
242
232
 
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
+ ##
248
+ def autoregister(filename = nil)
249
+ filename ||= AUTOREGISTER_FILE
250
+ autoregister_spec = Psych.load_file(filename)
251
+
252
+ autoregister_spec.deep_symbolize_keys!
253
+ autoregister_spec.transform_values! do |spec|
254
+ sanitized = spec.slice(:as, :within, :if_unset, :from_set)
255
+ sanitized[:as] = sanitized[:as].to_sym if sanitized.key? :as
256
+ sanitized[:within] = sanitized[:within].constantize if sanitized.key? :within
257
+
258
+ sanitized
259
+ end
260
+
261
+ register_all autoregister_spec
262
+
263
+ ## Psych raises an Errno::ENOENT on file-not-found.
264
+ ##
265
+ rescue Errno::ENOENT
266
+ raise EnvParser::AutoregisterFileNotFound, %(file not found: "#{filename}")
267
+
268
+ ## Psych raises a Psych::SyntaxError on unparseable YAML.
269
+ ##
270
+ rescue Psych::SyntaxError => e
271
+ raise EnvParser::UnparseableAutoregisterSpec, "malformed YAML in spec file: #{e.message}"
272
+ end
273
+
243
274
  private
244
275
 
245
276
  ## Class instance variable for storing known type data.
@@ -256,7 +287,7 @@ class EnvParser
256
287
  ## @return [nil]
257
288
  ## This generates no usable value.
258
289
  ##
259
- ## @raise [ArgumentError, EnvParser::ValueNotAllowed]
290
+ ## @raise [ArgumentError, EnvParser::ValueNotAllowedError]
260
291
  ##
261
292
  def check_for_set_inclusion(value, set: nil)
262
293
  if value.respond_to?(:each)
@@ -267,9 +298,7 @@ class EnvParser
267
298
  raise ArgumentError, "invalid `from_set` parameter type: #{set.class}"
268
299
  end
269
300
 
270
- raise ValueNotAllowed, 'parsed value not in allowed list/range' unless set.include?(value)
271
-
272
- nil
301
+ raise(ValueNotAllowedError, 'parsed value not in allowed set') unless set.include?(value)
273
302
  end
274
303
 
275
304
  ## Verifies that the given "value" passes both the "proc" and "block" validations.
@@ -281,18 +310,17 @@ class EnvParser
281
310
  ## @return [nil]
282
311
  ## This generates no usable value.
283
312
  ##
284
- ## @raise [EnvParser::ValueNotAllowed]
313
+ ## @raise [EnvParser::ValueNotAllowedError]
285
314
  ##
286
315
  def check_user_defined_validations(value, proc: nil, block: nil)
287
316
  immutable_value = value.dup.freeze
288
- error = 'parsed value failed user validation'
289
- raise ValueNotAllowed, error unless [proc, block].compact.all? { |i| i.call(immutable_value) }
317
+ all_tests_passed = [proc, block].compact.all? { |i| i.call(immutable_value) }
290
318
 
291
- nil
319
+ raise(ValueNotAllowedError, 'parsed value failed user validation') unless all_tests_passed
292
320
  end
293
321
 
294
- ## Receives a list of "register" calls to make, as a Hash keyed with variable names and the
295
- ## values being each "register" call's option set.
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.
296
324
  ##
297
325
  ## @param list [Hash]
298
326
  ##
@@ -301,7 +329,7 @@ class EnvParser
301
329
  ## @raise [ArgumentError]
302
330
  ##
303
331
  def register_all(list)
304
- raise ArgumentError, "invalid 'list' parameter type: #{list.class}" unless list.is_a?(Hash)
332
+ raise(ArgumentError, "invalid 'list' parameter type: #{list.class}") unless list.is_a? Hash
305
333
 
306
334
  list.to_a.each_with_object({}) do |tuple, output|
307
335
  output[tuple.first] = register(tuple.first, tuple.second)
@@ -310,6 +338,6 @@ class EnvParser
310
338
  end
311
339
  end
312
340
 
313
- ## Load all files listed in "/lib/env_parser/types".
341
+ ## Load predefined types.
314
342
  ##
315
- Dir.glob(File.join(__dir__, %w[env_parser types *.rb])).each { |filename| require_relative filename }
343
+ require 'env_parser/types'