env_parser 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1074b534666060176bf44c5b5d96c91ebf87f13e
4
- data.tar.gz: a4bbaf7ec568cf6fb1a3c8adb75b0ba36e0abfcc
3
+ metadata.gz: e4e18299d9f60e90144794c743405a7719404e8a
4
+ data.tar.gz: 57ea9d3762d0e6294600afc8df35968bd290dbd8
5
5
  SHA512:
6
- metadata.gz: '0778ff18e226b11676ac3ef7b2c0d4ec939ce6ca5a272e5d2ddbfc29827ff29bb1fe96d5028190fa4deec42858a1235de02ca783fa04902c4eca140e62d0ff12'
7
- data.tar.gz: 4e11313dca4ee78652b0dbe34af9d47b8bf7a61aa5ed7ebc7d119d8ada62a5b2d4d977caf194e6f88f0d4591e2fc902eaed9bd6ea665faa12fcfc07347cb69ee
6
+ metadata.gz: dc3918f1dd9be06601fe68826fd891f76081fa424a1607453f2956f09590e469b53029c8c4ad2b541f5619343ef44e132ac784e96e7c028da51bdc73b19ae886
7
+ data.tar.gz: 34b54cc90f38bfe93994a42e90fd351573476bc503174de330258ffb7c8639c0bc147baaac079e5eff1eaffa5f02b01a6aed75adb41340c4fec90b40976e17c8
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- env_parser (0.6.0)
4
+ env_parser (0.7.0)
5
5
  activesupport (>= 5.0.0)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -1,10 +1,8 @@
1
- # EnvParser
1
+ # EnvParser [![Gem Version](https://badge.fury.io/rb/env_parser.svg)](https://badge.fury.io/rb/env_parser)
2
2
 
3
- If your code uses environment variables, you know that `ENV` will always surface these as strings. Interpreting these strings as the value you *actually* want to see/use takes some additional effort, however.
3
+ If your code uses environment variables, you know that `ENV` will always surface these as strings. Interpreting these strings as the value you *actually* want to see/use takes some work, however: for numbers you need to cast with `#to_i`/`#to_f`, for booleans you need to check for a specific value (`ENV['SOME_VAR'] == 'true'`), etc. Maybe you want to set non-trivial defaults (something other than `0` or `''`)? Maybe you only want to allow values from a limited set? ...
4
4
 
5
- If you want a number, you need to cast: `#to_i`/`#to_f`. If you want a boolean, you need to check for a specific value: `ENV['SOME_VAR'] == 'true'`. Maybe you want to set non-trivial defaults (something other than `0` or `''`)? Maybe you only want to allow values from a limited set.
6
-
7
- Things can get out of control pretty fast, especially as the number of environment variables in play grows. EnvParser aims to help keep things simple.
5
+ Things can get out of control pretty fast, especially as the number of environment variables in play grows. Tools like [dotenv](https://github.com/bkeepers/dotenv) help to make sure you're loading the correct set of *variables*, but EnvParser makes *the values themselves* usable with a minimum of effort.
8
6
 
9
7
 
10
8
  ## Installation
@@ -122,6 +120,15 @@ EnvParser.parse :SOME_CUSTOM_NETWORK_PORT, as: :integer, from_set: (1..65535), i
122
120
  ## And if the value is not allowed...
123
121
  ##
124
122
  EnvParser.parse :NEGATIVE_NUMBER, as: :integer, from_set: (1..5) ## => raises EnvParser::ValueNotAllowed
123
+
124
+
125
+ ## The "validated_by" option allows for more complex validation.
126
+ ##
127
+ EnvParser.parse :MUST_BE_LOWERCASE, as: :string, validated_by: ->(value) { value == value.downcase }
128
+
129
+ ## ... but a block will also do the trick!
130
+ EnvParser.parse(:MUST_BE_LOWERCASE, as: :string) { |value| value == value.downcase }
131
+ EnvParser.parse(:CONNECTION_RETRIES, as: :integer, &:nonzero?)
125
132
  ```
126
133
 
127
134
 
@@ -182,7 +189,7 @@ ENV.register :SHORT_PI, as: :float ## Your constant is set, my man!
182
189
  ## Feature Roadmap / Future Development
183
190
 
184
191
  Additional features/options coming in the future:
185
- - A `validator` option that lets you pass in a validator lambda/block for things more complex than what a simple `from_set` can enforce.
192
+
186
193
  - A means to register validation blocks as new "as" types. This will allow for custom "as" types like `:url`, `:email`, etc.
187
194
  - ... ?
188
195
 
@@ -126,7 +126,7 @@ option.</p>
126
126
  </div>
127
127
 
128
128
  <div id="footer">
129
- Generated on Sun Dec 3 16:33:44 2017 by
129
+ Generated on Mon Dec 11 23:37:25 2017 by
130
130
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
131
131
  0.9.11 (ruby-2.4.2).
132
132
  </div>
data/docs/EnvParser.html CHANGED
@@ -130,7 +130,7 @@ different data types.</p>
130
130
  <dt id="VERSION-constant" class="">VERSION =
131
131
 
132
132
  </dt>
133
- <dd><pre class="code"><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>0.6.0</span><span class='tstring_end'>&#39;</span></span><span class='period'>.</span><span class='id identifier rubyid_freeze'>freeze</span></pre></dd>
133
+ <dd><pre class="code"><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>0.7.0</span><span class='tstring_end'>&#39;</span></span><span class='period'>.</span><span class='id identifier rubyid_freeze'>freeze</span></pre></dd>
134
134
 
135
135
  </dl>
136
136
 
@@ -176,7 +176,7 @@ methods.</p>
176
176
  <li class="public ">
177
177
  <span class="summary_signature">
178
178
 
179
- <a href="#parse-class_method" title="parse (class method)">.<strong>parse</strong>(value, options = {}) &#x21d2; Object </a>
179
+ <a href="#parse-class_method" title="parse (class method)">.<strong>parse</strong>(value, options = {}) {|value| ... } &#x21d2; Object </a>
180
180
 
181
181
 
182
182
 
@@ -200,7 +200,7 @@ methods.</p>
200
200
  <li class="public ">
201
201
  <span class="summary_signature">
202
202
 
203
- <a href="#register-class_method" title="register (class method)">.<strong>register</strong>(name, options = {}) &#x21d2; Object </a>
203
+ <a href="#register-class_method" title="register (class method)">.<strong>register</strong>(name, options = {}) {|value| ... } &#x21d2; Object </a>
204
204
 
205
205
 
206
206
 
@@ -281,27 +281,27 @@ is equivalent to <a href="'XYZ'">EnvParser.parse(ENV</a>, …)</p>
281
281
  <pre class="lines">
282
282
 
283
283
 
284
- 160
285
- 161
286
- 162
287
- 163
288
- 164
289
- 165
290
- 166
291
- 167
292
- 168
293
- 169
294
- 170
295
- 171
296
- 172</pre>
284
+ 190
285
+ 191
286
+ 192
287
+ 193
288
+ 194
289
+ 195
290
+ 196
291
+ 197
292
+ 198
293
+ 199
294
+ 200
295
+ 201
296
+ 202</pre>
297
297
  </td>
298
298
  <td>
299
- <pre class="code"><span class="info file"># File 'lib/env_parser.rb', line 160</span>
299
+ <pre class="code"><span class="info file"># File 'lib/env_parser.rb', line 190</span>
300
300
 
301
301
  <span class='kw'>def</span> <span class='id identifier rubyid_add_env_bindings'>add_env_bindings</span>
302
302
  <span class='const'>ENV</span><span class='period'>.</span><span class='id identifier rubyid_instance_eval'>instance_eval</span> <span class='kw'>do</span>
303
- <span class='kw'>def</span> <span class='id identifier rubyid_parse'>parse</span><span class='lparen'>(</span><span class='id identifier rubyid_name'>name</span><span class='comma'>,</span> <span class='id identifier rubyid_options'>options</span> <span class='op'>=</span> <span class='lbrace'>{</span><span class='rbrace'>}</span><span class='rparen'>)</span>
304
- <span class='const'><span class='object_link'><a href="" title="EnvParser (class)">EnvParser</a></span></span><span class='period'>.</span><span class='id identifier rubyid_parse'><span class='object_link'><a href="#parse-class_method" title="EnvParser.parse (method)">parse</a></span></span><span class='lparen'>(</span><span class='kw'>self</span><span class='lbracket'>[</span><span class='id identifier rubyid_name'>name</span><span class='period'>.</span><span class='id identifier rubyid_to_s'>to_s</span><span class='rbracket'>]</span><span class='comma'>,</span> <span class='id identifier rubyid_options'>options</span><span class='rparen'>)</span>
303
+ <span class='kw'>def</span> <span class='id identifier rubyid_parse'>parse</span><span class='lparen'>(</span><span class='id identifier rubyid_name'>name</span><span class='comma'>,</span> <span class='id identifier rubyid_options'>options</span> <span class='op'>=</span> <span class='lbrace'>{</span><span class='rbrace'>}</span><span class='comma'>,</span> <span class='op'>&amp;</span><span class='id identifier rubyid_validation_block'>validation_block</span><span class='rparen'>)</span>
304
+ <span class='const'><span class='object_link'><a href="" title="EnvParser (class)">EnvParser</a></span></span><span class='period'>.</span><span class='id identifier rubyid_parse'><span class='object_link'><a href="#parse-class_method" title="EnvParser.parse (method)">parse</a></span></span><span class='lparen'>(</span><span class='kw'>self</span><span class='lbracket'>[</span><span class='id identifier rubyid_name'>name</span><span class='period'>.</span><span class='id identifier rubyid_to_s'>to_s</span><span class='rbracket'>]</span><span class='comma'>,</span> <span class='id identifier rubyid_options'>options</span><span class='comma'>,</span> <span class='op'>&amp;</span><span class='id identifier rubyid_validation_block'>validation_block</span><span class='rparen'>)</span>
305
305
  <span class='kw'>end</span>
306
306
 
307
307
  <span class='kw'>def</span> <span class='id identifier rubyid_register'>register</span><span class='lparen'>(</span><span class='op'>*</span><span class='id identifier rubyid_args'>args</span><span class='rparen'>)</span>
@@ -319,7 +319,7 @@ is equivalent to <a href="'XYZ'">EnvParser.parse(ENV</a>, …)</p>
319
319
  <div class="method_details ">
320
320
  <h3 class="signature " id="parse-class_method">
321
321
 
322
- .<strong>parse</strong>(value, options = {}) &#x21d2; <tt>Object</tt>
322
+ .<strong>parse</strong>(value, options = {}) {|value| ... } &#x21d2; <tt>Object</tt>
323
323
 
324
324
 
325
325
 
@@ -455,6 +455,30 @@ returned, even if it is not part of the “from_set” list/range.</p>
455
455
  only available for scalar values (i.e. not arrays, hashes, or other
456
456
  enumerables). An attempt to use the “from_set” option with a non-scalar
457
457
  value will raise an ArgumentError exception.</p>
458
+ </div>
459
+
460
+ </li>
461
+
462
+ <li>
463
+ <span class="name">validated_by</span>
464
+ <span class="type">(<tt>Proc</tt>)</span>
465
+ <span class="default">
466
+
467
+ </span>
468
+
469
+ &mdash; <div class='inline'>
470
+ <p>If given, the “validated_by” proc is called with the parsed value (after
471
+ type conversion) as its sole argument. This allows for user-defined
472
+ validation of the parsed value beyond what can be enforced by use of the
473
+ “from_set” option alone. If the proc&#39;s return value is
474
+ <code>#blank?</code>, an EnvParser::ValueNotAllowed exception is raised. To
475
+ accomodate your syntax of choice, this validation proc may be given as a
476
+ yield block instead.</p>
477
+
478
+ <p>Note that this option is intended to provide an inspection mechanism only –
479
+ no mutation of the parsed value should occur within the given proc. To that
480
+ end, the argument passed is a <em>frozen</em> duplicate of the parsed
481
+ value.</p>
458
482
  </div>
459
483
 
460
484
  </li>
@@ -462,6 +486,28 @@ value will raise an ArgumentError exception.</p>
462
486
  </ul>
463
487
 
464
488
 
489
+ <p class="tag_title">Yields:</p>
490
+ <ul class="yield">
491
+
492
+ <li>
493
+
494
+
495
+ <span class='type'>(<tt>value</tt>)</span>
496
+
497
+
498
+
499
+ &mdash;
500
+ <div class='inline'>
501
+ <p>A block (if given) is treated exactly as the “validated_by” Proc would.
502
+ Although there is no compelling reason to provide both a “validated_by”
503
+ proc <em>and</em> a validation block, there is no technical limitation
504
+ preventing this. <strong>If both are given, both validation checks must
505
+ pass.</strong></p>
506
+ </div>
507
+
508
+ </li>
509
+
510
+ </ul>
465
511
  <p class="tag_title">Raises:</p>
466
512
  <ul class="raise">
467
513
 
@@ -482,32 +528,34 @@ value will raise an ArgumentError exception.</p>
482
528
  <pre class="lines">
483
529
 
484
530
 
485
- 55
486
- 56
487
- 57
488
- 58
489
- 59
490
- 60
491
- 61
492
- 62
493
- 63
494
- 64
495
- 65
496
- 66
497
- 67
498
- 68
499
- 69
500
- 70
501
- 71
502
531
  72
503
532
  73
504
533
  74
505
- 75</pre>
534
+ 75
535
+ 76
536
+ 77
537
+ 78
538
+ 79
539
+ 80
540
+ 81
541
+ 82
542
+ 83
543
+ 84
544
+ 85
545
+ 86
546
+ 87
547
+ 88
548
+ 89
549
+ 90
550
+ 91
551
+ 92
552
+ 93
553
+ 94</pre>
506
554
  </td>
507
555
  <td>
508
- <pre class="code"><span class="info file"># File 'lib/env_parser.rb', line 55</span>
556
+ <pre class="code"><span class="info file"># File 'lib/env_parser.rb', line 72</span>
509
557
 
510
- <span class='kw'>def</span> <span class='id identifier rubyid_parse'>parse</span><span class='lparen'>(</span><span class='id identifier rubyid_value'>value</span><span class='comma'>,</span> <span class='id identifier rubyid_options'>options</span> <span class='op'>=</span> <span class='lbrace'>{</span><span class='rbrace'>}</span><span class='rparen'>)</span>
558
+ <span class='kw'>def</span> <span class='id identifier rubyid_parse'>parse</span><span class='lparen'>(</span><span class='id identifier rubyid_value'>value</span><span class='comma'>,</span> <span class='id identifier rubyid_options'>options</span> <span class='op'>=</span> <span class='lbrace'>{</span><span class='rbrace'>}</span><span class='comma'>,</span> <span class='op'>&amp;</span><span class='id identifier rubyid_validation_block'>validation_block</span><span class='rparen'>)</span>
511
559
  <span class='id identifier rubyid_value'>value</span> <span class='op'>=</span> <span class='const'>ENV</span><span class='lbracket'>[</span><span class='id identifier rubyid_value'>value</span><span class='period'>.</span><span class='id identifier rubyid_to_s'>to_s</span><span class='rbracket'>]</span> <span class='kw'>if</span> <span class='id identifier rubyid_value'>value</span><span class='period'>.</span><span class='id identifier rubyid_is_a?'>is_a?</span> <span class='const'>Symbol</span>
512
560
  <span class='id identifier rubyid_value'>value</span> <span class='op'>=</span> <span class='id identifier rubyid_value'>value</span><span class='period'>.</span><span class='id identifier rubyid_to_s'>to_s</span>
513
561
 
@@ -526,6 +574,8 @@ value will raise an ArgumentError exception.</p>
526
574
  <span class='kw'>end</span>
527
575
 
528
576
  <span class='id identifier rubyid_check_for_set_inclusion'>check_for_set_inclusion</span><span class='lparen'>(</span><span class='id identifier rubyid_value'>value</span><span class='comma'>,</span> <span class='label'>set:</span> <span class='id identifier rubyid_options'>options</span><span class='lbracket'>[</span><span class='symbol'>:from_set</span><span class='rbracket'>]</span><span class='rparen'>)</span> <span class='kw'>if</span> <span class='id identifier rubyid_options'>options</span><span class='period'>.</span><span class='id identifier rubyid_key?'>key?</span><span class='lparen'>(</span><span class='symbol'>:from_set</span><span class='rparen'>)</span>
577
+ <span class='id identifier rubyid_check_user_defined_validations'>check_user_defined_validations</span><span class='lparen'>(</span><span class='id identifier rubyid_value'>value</span><span class='comma'>,</span> <span class='label'>proc:</span> <span class='id identifier rubyid_options'>options</span><span class='lbracket'>[</span><span class='symbol'>:validated_by</span><span class='rbracket'>]</span><span class='comma'>,</span> <span class='label'>block:</span> <span class='id identifier rubyid_validation_block'>validation_block</span><span class='rparen'>)</span>
578
+
529
579
  <span class='id identifier rubyid_value'>value</span>
530
580
  <span class='kw'>end</span></pre>
531
581
  </td>
@@ -536,7 +586,7 @@ value will raise an ArgumentError exception.</p>
536
586
  <div class="method_details ">
537
587
  <h3 class="signature " id="register-class_method">
538
588
 
539
- .<strong>register</strong>(name, options = {}) &#x21d2; <tt>Object</tt>
589
+ .<strong>register</strong>(name, options = {}) {|value| ... } &#x21d2; <tt>Object</tt>
540
590
 
541
591
 
542
592
 
@@ -650,11 +700,12 @@ Kernel (making it a global constant).</p>
650
700
  <span class="type">(<tt>Symbol</tt>)</span>
651
701
  <span class="default">
652
702
 
653
- &mdash; default:
654
- <tt>See `.parse`</tt>
655
-
656
703
  </span>
657
704
 
705
+ &mdash; <div class='inline'>
706
+ <p>See <code>.parse</code>.</p>
707
+ </div>
708
+
658
709
  </li>
659
710
 
660
711
  <li>
@@ -662,11 +713,12 @@ Kernel (making it a global constant).</p>
662
713
  <span class="type">(<tt>Object</tt>)</span>
663
714
  <span class="default">
664
715
 
665
- &mdash; default:
666
- <tt>See `.parse`</tt>
667
-
668
716
  </span>
669
717
 
718
+ &mdash; <div class='inline'>
719
+ <p>See <code>.parse</code>.</p>
720
+ </div>
721
+
670
722
  </li>
671
723
 
672
724
  <li>
@@ -674,16 +726,51 @@ Kernel (making it a global constant).</p>
674
726
  <span class="type">(<tt>Array</tt>, <tt>Range</tt>)</span>
675
727
  <span class="default">
676
728
 
677
- &mdash; default:
678
- <tt>See `.parse`</tt>
729
+ </span>
730
+
731
+ &mdash; <div class='inline'>
732
+ <p>See <code>.parse</code>.</p>
733
+ </div>
734
+
735
+ </li>
736
+
737
+ <li>
738
+ <span class="name">validated_by</span>
739
+ <span class="type">(<tt>Proc</tt>)</span>
740
+ <span class="default">
679
741
 
680
742
  </span>
681
743
 
744
+ &mdash; <div class='inline'>
745
+ <p>See <code>.parse</code>.</p>
746
+ </div>
747
+
682
748
  </li>
683
749
 
684
750
  </ul>
685
751
 
686
752
 
753
+ <p class="tag_title">Yields:</p>
754
+ <ul class="yield">
755
+
756
+ <li>
757
+
758
+
759
+ <span class='type'>(<tt>value</tt>)</span>
760
+
761
+
762
+
763
+ &mdash;
764
+ <div class='inline'>
765
+ <p>A block (if given) is treated exactly as in <code>.parse</code>. Note,
766
+ however, that a single yield block cannot be used to register multiple
767
+ constants simultaneously – each value needing validation must give its own
768
+ “validated_by” proc.</p>
769
+ </div>
770
+
771
+ </li>
772
+
773
+ </ul>
687
774
  <p class="tag_title">Raises:</p>
688
775
  <ul class="raise">
689
776
 
@@ -704,45 +791,51 @@ Kernel (making it a global constant).</p>
704
791
  <pre class="lines">
705
792
 
706
793
 
707
- 119
708
- 120
709
- 121
710
- 122
711
- 123
712
- 124
713
- 125
714
- 126
715
- 127
716
- 128
717
- 129
718
- 130
719
- 131
720
- 132
721
- 133
722
- 134
723
- 135
724
- 136
725
- 137
726
- 138
727
- 139
728
- 140
729
- 141
730
- 142
731
- 143
732
- 144
733
- 145
734
794
  146
735
795
  147
736
796
  148
737
- 149</pre>
797
+ 149
798
+ 150
799
+ 151
800
+ 152
801
+ 153
802
+ 154
803
+ 155
804
+ 156
805
+ 157
806
+ 158
807
+ 159
808
+ 160
809
+ 161
810
+ 162
811
+ 163
812
+ 164
813
+ 165
814
+ 166
815
+ 167
816
+ 168
817
+ 169
818
+ 170
819
+ 171
820
+ 172
821
+ 173
822
+ 174
823
+ 175
824
+ 176
825
+ 177
826
+ 178
827
+ 179</pre>
738
828
  </td>
739
829
  <td>
740
- <pre class="code"><span class="info file"># File 'lib/env_parser.rb', line 119</span>
830
+ <pre class="code"><span class="info file"># File 'lib/env_parser.rb', line 146</span>
741
831
 
742
- <span class='kw'>def</span> <span class='id identifier rubyid_register'>register</span><span class='lparen'>(</span><span class='id identifier rubyid_name'>name</span><span class='comma'>,</span> <span class='id identifier rubyid_options'>options</span> <span class='op'>=</span> <span class='lbrace'>{</span><span class='rbrace'>}</span><span class='rparen'>)</span>
832
+ <span class='kw'>def</span> <span class='id identifier rubyid_register'>register</span><span class='lparen'>(</span><span class='id identifier rubyid_name'>name</span><span class='comma'>,</span> <span class='id identifier rubyid_options'>options</span> <span class='op'>=</span> <span class='lbrace'>{</span><span class='rbrace'>}</span><span class='comma'>,</span> <span class='op'>&amp;</span><span class='id identifier rubyid_validation_block'>validation_block</span><span class='rparen'>)</span>
743
833
  <span class='comment'>## We want to allow for registering multiple variables simultaneously via a single `.register`
744
834
  </span> <span class='comment'>## method call.
745
- </span> <span class='kw'>return</span> <span class='id identifier rubyid_register_all'>register_all</span><span class='lparen'>(</span><span class='id identifier rubyid_name'>name</span><span class='rparen'>)</span> <span class='kw'>if</span> <span class='id identifier rubyid_name'>name</span><span class='period'>.</span><span class='id identifier rubyid_is_a?'>is_a?</span> <span class='const'>Hash</span>
835
+ </span> <span class='kw'>if</span> <span class='id identifier rubyid_name'>name</span><span class='period'>.</span><span class='id identifier rubyid_is_a?'>is_a?</span> <span class='const'>Hash</span>
836
+ <span class='id identifier rubyid_raise'>raise</span> <span class='const'>ArgumentError</span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>cannot register multiple values with one yield block</span><span class='tstring_end'>&#39;</span></span> <span class='kw'>if</span> <span class='id identifier rubyid_block_given?'>block_given?</span>
837
+ <span class='kw'>return</span> <span class='id identifier rubyid_register_all'>register_all</span><span class='lparen'>(</span><span class='id identifier rubyid_name'>name</span><span class='rparen'>)</span>
838
+ <span class='kw'>end</span>
746
839
 
747
840
  <span class='id identifier rubyid_from'>from</span> <span class='op'>=</span> <span class='id identifier rubyid_options'>options</span><span class='period'>.</span><span class='id identifier rubyid_fetch'>fetch</span><span class='lparen'>(</span><span class='symbol'>:from</span><span class='comma'>,</span> <span class='const'>ENV</span><span class='rparen'>)</span>
748
841
  <span class='id identifier rubyid_within'>within</span> <span class='op'>=</span> <span class='id identifier rubyid_options'>options</span><span class='period'>.</span><span class='id identifier rubyid_fetch'>fetch</span><span class='lparen'>(</span><span class='symbol'>:within</span><span class='comma'>,</span> <span class='const'>Kernel</span><span class='rparen'>)</span>
@@ -765,7 +858,7 @@ Kernel (making it a global constant).</p>
765
858
  <span class='kw'>end</span>
766
859
 
767
860
  <span class='id identifier rubyid_value'>value</span> <span class='op'>=</span> <span class='id identifier rubyid_from'>from</span><span class='lbracket'>[</span><span class='id identifier rubyid_name'>name</span><span class='rbracket'>]</span>
768
- <span class='id identifier rubyid_value'>value</span> <span class='op'>=</span> <span class='id identifier rubyid_parse'>parse</span><span class='lparen'>(</span><span class='id identifier rubyid_value'>value</span><span class='comma'>,</span> <span class='id identifier rubyid_options'>options</span><span class='rparen'>)</span>
861
+ <span class='id identifier rubyid_value'>value</span> <span class='op'>=</span> <span class='id identifier rubyid_parse'>parse</span><span class='lparen'>(</span><span class='id identifier rubyid_value'>value</span><span class='comma'>,</span> <span class='id identifier rubyid_options'>options</span><span class='comma'>,</span> <span class='op'>&amp;</span><span class='id identifier rubyid_validation_block'>validation_block</span><span class='rparen'>)</span>
769
862
  <span class='id identifier rubyid_within'>within</span><span class='period'>.</span><span class='id identifier rubyid_const_set'>const_set</span><span class='lparen'>(</span><span class='id identifier rubyid_name'>name</span><span class='period'>.</span><span class='id identifier rubyid_upcase'>upcase</span><span class='period'>.</span><span class='id identifier rubyid_to_sym'>to_sym</span><span class='comma'>,</span> <span class='id identifier rubyid_value'>value</span><span class='period'>.</span><span class='id identifier rubyid_dup'>dup</span><span class='period'>.</span><span class='id identifier rubyid_freeze'>freeze</span><span class='rparen'>)</span>
770
863
 
771
864
  <span class='id identifier rubyid_value'>value</span>
@@ -780,7 +873,7 @@ Kernel (making it a global constant).</p>
780
873
  </div>
781
874
 
782
875
  <div id="footer">
783
- Generated on Sun Dec 3 16:33:44 2017 by
876
+ Generated on Mon Dec 11 23:37:25 2017 by
784
877
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
785
878
  0.9.11 (ruby-2.4.2).
786
879
  </div>
data/docs/_index.html CHANGED
@@ -112,7 +112,7 @@
112
112
  </div>
113
113
 
114
114
  <div id="footer">
115
- Generated on Sun Dec 3 16:33:43 2017 by
115
+ Generated on Mon Dec 11 23:37:25 2017 by
116
116
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
117
117
  0.9.11 (ruby-2.4.2).
118
118
  </div>
@@ -58,23 +58,22 @@
58
58
  </div>
59
59
 
60
60
  <div id="content"><div id='filecontents'>
61
- <h1 id="label-EnvParser">EnvParser</h1>
61
+ <h1 id="label-EnvParser+rdoc-image-3Ahttps-3A-2F-2Fbadge.fury.io-2Frb-2Fenv_parser.svg">EnvParser <a href="https://badge.fury.io/rb/env_parser"><img src="https://badge.fury.io/rb/env_parser.svg"></a></h1>
62
62
 
63
63
  <p>If your code uses environment variables, you know that <code>ENV</code>
64
64
  will always surface these as strings. Interpreting these strings as the
65
- value you <em>actually</em> want to see/use takes some additional effort,
66
- however.</p>
67
-
68
- <p>If you want a number, you need to cast:
69
- <code>#to_i</code>/<code>#to_f</code>. If you want a boolean, you need to
70
- check for a specific value: <code>ENV['SOME_VAR'] == &#39;true&#39;</code>.
71
- Maybe you want to set non-trivial defaults (something other than
72
- <code>0</code> or <code>&#39;&#39;</code>)? Maybe you only want to allow
73
- values from a limited set.</p>
65
+ value you <em>actually</em> want to see/use takes some work, however: for
66
+ numbers you need to cast with <code>#to_i</code>/<code>#to_f</code>, for
67
+ booleans you need to check for a specific value (<code>ENV['SOME_VAR'] ==
68
+ &#39;true&#39;</code>), etc. Maybe you want to set non-trivial defaults
69
+ (something other than <code>0</code> or <code>&#39;&#39;</code>)? Maybe you
70
+ only want to allow values from a limited set? …</p>
74
71
 
75
72
  <p>Things can get out of control pretty fast, especially as the number of
76
- environment variables in play grows. EnvParser aims to help keep things
77
- simple.</p>
73
+ environment variables in play grows. Tools like <a
74
+ href="https://github.com/bkeepers/dotenv">dotenv</a> help to make sure
75
+ you&#39;re loading the correct set of <em>variables</em>, but EnvParser
76
+ makes <em>the values themselves</em> usable with a minimum of effort.</p>
78
77
 
79
78
  <h2 id="label-Installation">Installation</h2>
80
79
 
@@ -181,7 +180,16 @@ simple.</p>
181
180
  <span class='comment'>## And if the value is not allowed...
182
181
  </span><span class='comment'>##
183
182
  </span><span class='const'><span class='object_link'><a href="EnvParser.html" title="EnvParser (class)">EnvParser</a></span></span><span class='period'>.</span><span class='id identifier rubyid_parse'><span class='object_link'><a href="EnvParser.html#parse-class_method" title="EnvParser.parse (method)">parse</a></span></span> <span class='symbol'>:NEGATIVE_NUMBER</span><span class='comma'>,</span> <span class='label'>as:</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='label'>from_set:</span> <span class='lparen'>(</span><span class='int'>1</span><span class='op'>..</span><span class='int'>5</span><span class='rparen'>)</span> <span class='comment'>## =&gt; raises EnvParser::ValueNotAllowed
184
- </span></code></pre>
183
+ </span>
184
+
185
+ <span class='comment'>## The &quot;validated_by&quot; option allows for more complex validation.
186
+ </span><span class='comment'>##
187
+ </span><span class='const'><span class='object_link'><a href="EnvParser.html" title="EnvParser (class)">EnvParser</a></span></span><span class='period'>.</span><span class='id identifier rubyid_parse'><span class='object_link'><a href="EnvParser.html#parse-class_method" title="EnvParser.parse (method)">parse</a></span></span> <span class='symbol'>:MUST_BE_LOWERCASE</span><span class='comma'>,</span> <span class='label'>as:</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>validated_by:</span> <span class='tlambda'>-&gt;</span><span class='lparen'>(</span><span class='id identifier rubyid_value'>value</span><span class='rparen'>)</span> <span class='tlambeg'>{</span> <span class='id identifier rubyid_value'>value</span> <span class='op'>==</span> <span class='id identifier rubyid_value'>value</span><span class='period'>.</span><span class='id identifier rubyid_downcase'>downcase</span> <span class='rbrace'>}</span>
188
+
189
+ <span class='comment'>## ... but a block will also do the trick!
190
+ </span><span class='const'><span class='object_link'><a href="EnvParser.html" title="EnvParser (class)">EnvParser</a></span></span><span class='period'>.</span><span class='id identifier rubyid_parse'><span class='object_link'><a href="EnvParser.html#parse-class_method" title="EnvParser.parse (method)">parse</a></span></span><span class='lparen'>(</span><span class='symbol'>:MUST_BE_LOWERCASE</span><span class='comma'>,</span> <span class='label'>as:</span> <span class='symbol'>:string</span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_value'>value</span><span class='op'>|</span> <span class='id identifier rubyid_value'>value</span> <span class='op'>==</span> <span class='id identifier rubyid_value'>value</span><span class='period'>.</span><span class='id identifier rubyid_downcase'>downcase</span> <span class='rbrace'>}</span>
191
+ <span class='const'><span class='object_link'><a href="EnvParser.html" title="EnvParser (class)">EnvParser</a></span></span><span class='period'>.</span><span class='id identifier rubyid_parse'><span class='object_link'><a href="EnvParser.html#parse-class_method" title="EnvParser.parse (method)">parse</a></span></span><span class='lparen'>(</span><span class='symbol'>:CONNECTION_RETRIES</span><span class='comma'>,</span> <span class='label'>as:</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='op'>&amp;</span><span class='symbol'>:nonzero?</span><span class='rparen'>)</span>
192
+ </code></pre>
185
193
 
186
194
  <h4 id="label-Setting+Constants+From+ENV+Values">Setting Constants From ENV Values</h4>
187
195
 
@@ -235,12 +243,13 @@ docs</a> for the full EnvParser documentation.</p>
235
243
 
236
244
  <h2 id="label-Feature+Roadmap+-2F+Future+Development">Feature Roadmap / Future Development</h2>
237
245
 
238
- <p>Additional features/options coming in the future: - A
239
- <code>validator</code> option that lets you pass in a validator
240
- lambda/block for things more complex than what a simple
241
- <code>from_set</code> can enforce. - A means to register validation blocks
242
- as new “as” types. This will allow for custom “as” types like
243
- <code>:url</code>, <code>:email</code>, etc. - … ?</p>
246
+ <p>Additional features/options coming in the future:</p>
247
+ <ul><li>
248
+ <p>A means to register validation blocks as new “as” types. This will allow
249
+ for custom “as” types like <code>:url</code>, <code>:email</code>, etc.</p>
250
+ </li><li>
251
+ <p>… ?</p>
252
+ </li></ul>
244
253
 
245
254
  <h2 id="label-Contribution+-2F+Development">Contribution / Development</h2>
246
255
 
@@ -271,7 +280,7 @@ href="https://opensource.org/licenses/MIT">MIT License</a>.</p>
271
280
  </div></div>
272
281
 
273
282
  <div id="footer">
274
- Generated on Sun Dec 3 16:33:43 2017 by
283
+ Generated on Mon Dec 11 23:37:25 2017 by
275
284
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
276
285
  0.9.11 (ruby-2.4.2).
277
286
  </div>
data/docs/index.html CHANGED
@@ -58,23 +58,22 @@
58
58
  </div>
59
59
 
60
60
  <div id="content"><div id='filecontents'>
61
- <h1 id="label-EnvParser">EnvParser</h1>
61
+ <h1 id="label-EnvParser+rdoc-image-3Ahttps-3A-2F-2Fbadge.fury.io-2Frb-2Fenv_parser.svg">EnvParser <a href="https://badge.fury.io/rb/env_parser"><img src="https://badge.fury.io/rb/env_parser.svg"></a></h1>
62
62
 
63
63
  <p>If your code uses environment variables, you know that <code>ENV</code>
64
64
  will always surface these as strings. Interpreting these strings as the
65
- value you <em>actually</em> want to see/use takes some additional effort,
66
- however.</p>
67
-
68
- <p>If you want a number, you need to cast:
69
- <code>#to_i</code>/<code>#to_f</code>. If you want a boolean, you need to
70
- check for a specific value: <code>ENV['SOME_VAR'] == &#39;true&#39;</code>.
71
- Maybe you want to set non-trivial defaults (something other than
72
- <code>0</code> or <code>&#39;&#39;</code>)? Maybe you only want to allow
73
- values from a limited set.</p>
65
+ value you <em>actually</em> want to see/use takes some work, however: for
66
+ numbers you need to cast with <code>#to_i</code>/<code>#to_f</code>, for
67
+ booleans you need to check for a specific value (<code>ENV['SOME_VAR'] ==
68
+ &#39;true&#39;</code>), etc. Maybe you want to set non-trivial defaults
69
+ (something other than <code>0</code> or <code>&#39;&#39;</code>)? Maybe you
70
+ only want to allow values from a limited set? …</p>
74
71
 
75
72
  <p>Things can get out of control pretty fast, especially as the number of
76
- environment variables in play grows. EnvParser aims to help keep things
77
- simple.</p>
73
+ environment variables in play grows. Tools like <a
74
+ href="https://github.com/bkeepers/dotenv">dotenv</a> help to make sure
75
+ you&#39;re loading the correct set of <em>variables</em>, but EnvParser
76
+ makes <em>the values themselves</em> usable with a minimum of effort.</p>
78
77
 
79
78
  <h2 id="label-Installation">Installation</h2>
80
79
 
@@ -181,7 +180,16 @@ simple.</p>
181
180
  <span class='comment'>## And if the value is not allowed...
182
181
  </span><span class='comment'>##
183
182
  </span><span class='const'><span class='object_link'><a href="EnvParser.html" title="EnvParser (class)">EnvParser</a></span></span><span class='period'>.</span><span class='id identifier rubyid_parse'><span class='object_link'><a href="EnvParser.html#parse-class_method" title="EnvParser.parse (method)">parse</a></span></span> <span class='symbol'>:NEGATIVE_NUMBER</span><span class='comma'>,</span> <span class='label'>as:</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='label'>from_set:</span> <span class='lparen'>(</span><span class='int'>1</span><span class='op'>..</span><span class='int'>5</span><span class='rparen'>)</span> <span class='comment'>## =&gt; raises EnvParser::ValueNotAllowed
184
- </span></code></pre>
183
+ </span>
184
+
185
+ <span class='comment'>## The &quot;validated_by&quot; option allows for more complex validation.
186
+ </span><span class='comment'>##
187
+ </span><span class='const'><span class='object_link'><a href="EnvParser.html" title="EnvParser (class)">EnvParser</a></span></span><span class='period'>.</span><span class='id identifier rubyid_parse'><span class='object_link'><a href="EnvParser.html#parse-class_method" title="EnvParser.parse (method)">parse</a></span></span> <span class='symbol'>:MUST_BE_LOWERCASE</span><span class='comma'>,</span> <span class='label'>as:</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>validated_by:</span> <span class='tlambda'>-&gt;</span><span class='lparen'>(</span><span class='id identifier rubyid_value'>value</span><span class='rparen'>)</span> <span class='tlambeg'>{</span> <span class='id identifier rubyid_value'>value</span> <span class='op'>==</span> <span class='id identifier rubyid_value'>value</span><span class='period'>.</span><span class='id identifier rubyid_downcase'>downcase</span> <span class='rbrace'>}</span>
188
+
189
+ <span class='comment'>## ... but a block will also do the trick!
190
+ </span><span class='const'><span class='object_link'><a href="EnvParser.html" title="EnvParser (class)">EnvParser</a></span></span><span class='period'>.</span><span class='id identifier rubyid_parse'><span class='object_link'><a href="EnvParser.html#parse-class_method" title="EnvParser.parse (method)">parse</a></span></span><span class='lparen'>(</span><span class='symbol'>:MUST_BE_LOWERCASE</span><span class='comma'>,</span> <span class='label'>as:</span> <span class='symbol'>:string</span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_value'>value</span><span class='op'>|</span> <span class='id identifier rubyid_value'>value</span> <span class='op'>==</span> <span class='id identifier rubyid_value'>value</span><span class='period'>.</span><span class='id identifier rubyid_downcase'>downcase</span> <span class='rbrace'>}</span>
191
+ <span class='const'><span class='object_link'><a href="EnvParser.html" title="EnvParser (class)">EnvParser</a></span></span><span class='period'>.</span><span class='id identifier rubyid_parse'><span class='object_link'><a href="EnvParser.html#parse-class_method" title="EnvParser.parse (method)">parse</a></span></span><span class='lparen'>(</span><span class='symbol'>:CONNECTION_RETRIES</span><span class='comma'>,</span> <span class='label'>as:</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='op'>&amp;</span><span class='symbol'>:nonzero?</span><span class='rparen'>)</span>
192
+ </code></pre>
185
193
 
186
194
  <h4 id="label-Setting+Constants+From+ENV+Values">Setting Constants From ENV Values</h4>
187
195
 
@@ -235,12 +243,13 @@ docs</a> for the full EnvParser documentation.</p>
235
243
 
236
244
  <h2 id="label-Feature+Roadmap+-2F+Future+Development">Feature Roadmap / Future Development</h2>
237
245
 
238
- <p>Additional features/options coming in the future: - A
239
- <code>validator</code> option that lets you pass in a validator
240
- lambda/block for things more complex than what a simple
241
- <code>from_set</code> can enforce. - A means to register validation blocks
242
- as new “as” types. This will allow for custom “as” types like
243
- <code>:url</code>, <code>:email</code>, etc. - … ?</p>
246
+ <p>Additional features/options coming in the future:</p>
247
+ <ul><li>
248
+ <p>A means to register validation blocks as new “as” types. This will allow
249
+ for custom “as” types like <code>:url</code>, <code>:email</code>, etc.</p>
250
+ </li><li>
251
+ <p>… ?</p>
252
+ </li></ul>
244
253
 
245
254
  <h2 id="label-Contribution+-2F+Development">Contribution / Development</h2>
246
255
 
@@ -271,7 +280,7 @@ href="https://opensource.org/licenses/MIT">MIT License</a>.</p>
271
280
  </div></div>
272
281
 
273
282
  <div id="footer">
274
- Generated on Sun Dec 3 16:33:43 2017 by
283
+ Generated on Mon Dec 11 23:37:25 2017 by
275
284
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
276
285
  0.9.11 (ruby-2.4.2).
277
286
  </div>
@@ -100,7 +100,7 @@
100
100
  </div>
101
101
 
102
102
  <div id="footer">
103
- Generated on Sun Dec 3 16:33:43 2017 by
103
+ Generated on Mon Dec 11 23:37:25 2017 by
104
104
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
105
105
  0.9.11 (ruby-2.4.2).
106
106
  </div>
@@ -1,3 +1,3 @@
1
1
  class EnvParser
2
- VERSION = '0.6.0'.freeze
2
+ VERSION = '0.7.0'.freeze
3
3
  end
data/lib/env_parser.rb CHANGED
@@ -50,9 +50,26 @@ class EnvParser
50
50
  ## for scalar values (i.e. not arrays, hashes, or other enumerables). An attempt to use the
51
51
  ## "from_set" option with a non-scalar value will raise an ArgumentError exception.
52
52
  ##
53
+ ## @option options validated_by [Proc]
54
+ ## If given, the "validated_by" proc is called with the parsed value (after type conversion)
55
+ ## as its sole argument. This allows for user-defined validation of the parsed value beyond
56
+ ## what can be enforced by use of the "from_set" option alone. If the proc's return value is
57
+ ## `#blank?`, an EnvParser::ValueNotAllowed exception is raised. To accomodate your syntax of
58
+ ## choice, this validation proc may be given as a yield block instead.
59
+ ##
60
+ ## Note that this option is intended to provide an inspection mechanism only -- no mutation
61
+ ## of the parsed value should occur within the given proc. To that end, the argument passed is
62
+ ## a *frozen* duplicate of the parsed value.
63
+ ##
64
+ ## @yield [value]
65
+ ## A block (if given) is treated exactly as the "validated_by" Proc would. Although there is
66
+ ## no compelling reason to provide both a "validated_by" proc *and* a validation block, there
67
+ ## is no technical limitation preventing this. **If both are given, both validation checks
68
+ ## must pass.**
69
+ ##
53
70
  ## @raise [ArgumentError, EnvParser::ValueNotAllowed]
54
71
  ##
55
- def parse(value, options = {})
72
+ def parse(value, options = {}, &validation_block)
56
73
  value = ENV[value.to_s] if value.is_a? Symbol
57
74
  value = value.to_s
58
75
 
@@ -71,6 +88,8 @@ class EnvParser
71
88
  end
72
89
 
73
90
  check_for_set_inclusion(value, set: options[:from_set]) if options.key?(:from_set)
91
+ check_user_defined_validations(value, proc: options[:validated_by], block: validation_block)
92
+
74
93
  value
75
94
  end
76
95
 
@@ -106,20 +125,31 @@ class EnvParser
106
125
  ## a global constant).
107
126
  ##
108
127
  ## @option options as [Symbol]
109
- ## (See `.parse`)
128
+ ## See `.parse`.
110
129
  ##
111
130
  ## @option options if_unset
112
- ## (See `.parse`)
131
+ ## See `.parse`.
113
132
  ##
114
133
  ## @option options from_set [Array, Range]
115
- ## (See `.parse`)
134
+ ## See `.parse`.
135
+ ##
136
+ ## @option options validated_by [Proc]
137
+ ## See `.parse`.
138
+ ##
139
+ ## @yield [value]
140
+ ## A block (if given) is treated exactly as in `.parse`. Note, however, that a single yield
141
+ ## block cannot be used to register multiple constants simultaneously -- each value needing
142
+ ## validation must give its own "validated_by" proc.
116
143
  ##
117
144
  ## @raise [ArgumentError]
118
145
  ##
119
- def register(name, options = {})
146
+ def register(name, options = {}, &validation_block)
120
147
  ## We want to allow for registering multiple variables simultaneously via a single `.register`
121
148
  ## method call.
122
- return register_all(name) if name.is_a? Hash
149
+ if name.is_a? Hash
150
+ raise ArgumentError, 'cannot register multiple values with one yield block' if block_given?
151
+ return register_all(name)
152
+ end
123
153
 
124
154
  from = options.fetch(:from, ENV)
125
155
  within = options.fetch(:within, Kernel)
@@ -142,7 +172,7 @@ class EnvParser
142
172
  end
143
173
 
144
174
  value = from[name]
145
- value = parse(value, options)
175
+ value = parse(value, options, &validation_block)
146
176
  within.const_set(name.upcase.to_sym, value.dup.freeze)
147
177
 
148
178
  value
@@ -159,8 +189,8 @@ class EnvParser
159
189
  ##
160
190
  def add_env_bindings
161
191
  ENV.instance_eval do
162
- def parse(name, options = {})
163
- EnvParser.parse(self[name.to_s], options)
192
+ def parse(name, options = {}, &validation_block)
193
+ EnvParser.parse(self[name.to_s], options, &validation_block)
164
194
  end
165
195
 
166
196
  def register(*args)
@@ -226,7 +256,6 @@ class EnvParser
226
256
  ## Verifies that the given "value" is included in the "set".
227
257
  ##
228
258
  ## @param value
229
- ##
230
259
  ## @param set [Array, Range]
231
260
  ##
232
261
  ## @return [nil]
@@ -248,6 +277,25 @@ class EnvParser
248
277
  nil
249
278
  end
250
279
 
280
+ ## Verifies that the given "value" passes both the "proc" and "block" validations.
281
+ ##
282
+ ## @param value
283
+ ## @param proc [Proc, nil]
284
+ ## @param block [Proc, nil]
285
+ ##
286
+ ## @return [nil]
287
+ ## This generates no usable value.
288
+ ##
289
+ ## @raise [EnvParser::ValueNotAllowed]
290
+ ##
291
+ def check_user_defined_validations(value, proc: nil, block: nil)
292
+ immutable_value = value.dup.freeze
293
+ error = 'parsed value failed user validation'
294
+ raise ValueNotAllowed, error unless [proc, block].compact.all? { |i| i.call(immutable_value) }
295
+
296
+ nil
297
+ end
298
+
251
299
  ## Receives a list of "register" calls to make, as a Hash keyed with variable names and the
252
300
  ## values being each "register" call's option set.
253
301
  ##
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: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nestor Custodio
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-12-03 00:00:00.000000000 Z
11
+ date: 2017-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler