ensure_it 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +7 -0
  6. data/Gemfile +6 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +332 -0
  9. data/Rakefile +11 -0
  10. data/ensure_it.gemspec +39 -0
  11. data/lib/ensure_it/config.rb +23 -0
  12. data/lib/ensure_it/ensure_array.rb +67 -0
  13. data/lib/ensure_it/ensure_class.rb +30 -0
  14. data/lib/ensure_it/ensure_float.rb +48 -0
  15. data/lib/ensure_it/ensure_hash.rb +22 -0
  16. data/lib/ensure_it/ensure_instance_of.rb +27 -0
  17. data/lib/ensure_it/ensure_integer.rb +89 -0
  18. data/lib/ensure_it/ensure_string.rb +43 -0
  19. data/lib/ensure_it/ensure_symbol.rb +26 -0
  20. data/lib/ensure_it/errors.rb +173 -0
  21. data/lib/ensure_it/patch.rb +17 -0
  22. data/lib/ensure_it/version.rb +3 -0
  23. data/lib/ensure_it.rb +18 -0
  24. data/lib/ensure_it_refines.rb +8 -0
  25. data/spec/integration/refines_spec.rb +37 -0
  26. data/spec/lib/config_spec.rb +50 -0
  27. data/spec/lib/ensure_array_spec.rb +75 -0
  28. data/spec/lib/ensure_class_spec.rb +54 -0
  29. data/spec/lib/ensure_float_spec.rb +65 -0
  30. data/spec/lib/ensure_hash_spec.rb +45 -0
  31. data/spec/lib/ensure_instance_of_spec.rb +49 -0
  32. data/spec/lib/ensure_integer_spec.rb +89 -0
  33. data/spec/lib/ensure_string_spec.rb +53 -0
  34. data/spec/lib/ensure_symbol_spec.rb +39 -0
  35. data/spec/lib/errors_spec.rb +124 -0
  36. data/spec/lib/patch_spec.rb +31 -0
  37. data/spec/spec_helper.rb +19 -0
  38. data/spec/support/example_groups/ensure_it_example_group.rb +66 -0
  39. data/spec/support/matchers/warn_matcher.rb +30 -0
  40. data/spec/support/shared_examples/unmet_objects.rb +60 -0
  41. metadata +177 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: efbdf0a3bed9ded886ef7d1170937026c97921ba
4
+ data.tar.gz: 37e7605734053df525d58d23160f9e610722eb72
5
+ SHA512:
6
+ metadata.gz: 77cef5c0dda07903b845259cd3ee07e72a66f46650a741cf1dd1b5d8a05c25459423bbc8e2dfc5d0ea8df6ba9d30e74c5099aa4de1aa78ba7d59ab5cfec04a8b
7
+ data.tar.gz: 0432891707fbdbd1e4e6e1d2737040ffb1bcbec5368a8f80b4d3756544a32222b359d175af1266e4a63b8b8ca2715a3d9d90d03121e9866da63ae8e53206872d
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0.0-p353
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1.1
5
+ env:
6
+ - USE_REFINES=true
7
+ - USE_REFINES=false
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ensure_it.gemspec
4
+ gemspec
5
+
6
+ #gem 'coveralls', require: false
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Алексей Овчинников
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,332 @@
1
+ [![Code Climate](https://codeclimate.com/github/cybernetlab/ensure_it.png)](https://codeclimate.com/github/cybernetlab/ensure_it)
2
+ [![Build Status](https://travis-ci.org/cybernetlab/ensure_it.svg?branch=master)](https://travis-ci.org/cybernetlab/ensure_it)
3
+ [![Coverage Status](https://coveralls.io/repos/cybernetlab/ensure_it/badge.png?branch=master)](https://coveralls.io/r/cybernetlab/ensure_it?branch=master)
4
+
5
+ # EnsureIt
6
+
7
+ This library provides way to check and converts local variables for every-method usage, like arguments checking.
8
+
9
+ The main goal of EnsureIt is to provide as fast executed code as it possible with simple and usable syntax.
10
+
11
+ > **Note:** this library doesn't support ruby older than `2.0.0`
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'ensure_it'
19
+ ```
20
+
21
+ or for [refinements](#refinements) version:
22
+
23
+ ```ruby
24
+ gem 'ensure_it', require: 'ensure_it_refines'
25
+ ```
26
+
27
+ And then execute:
28
+
29
+ ```sh
30
+ $ bundle
31
+ ```
32
+
33
+ Or install it yourself as:
34
+
35
+ ```sh
36
+ $ gem install ensure_it
37
+ ```
38
+
39
+ ## Configuration
40
+
41
+ For this moment only one configuration option available - global setting of smart errors (see [Usage section](usage)):
42
+
43
+ ```ruby
44
+ require 'ensure_it'
45
+
46
+ EnsureIt.configuration do |config|
47
+ # config.errors = :standard
48
+ config.errors = :smart
49
+ end
50
+ ```
51
+
52
+ ## Usage
53
+
54
+ EnsureIt does monkey-patching or provides refines (see [Refinements section](#refinements)) for general ruby objects with set of `ensure_*` methods. So you can call this methods with everything in ruby. Corresponding to method name it returns `nil` (or raise exception for bang version of method, that name ended with `!`) for unusual or impossible type conversions and returns object of ensured type if conversion is possible.
55
+
56
+ For example `ensure_symbol` method returns symbol itself for Symbols, converted to symbol value for Strings and nil for all other. Same way `ensure_symbol!` returns symbol for String and Symbol, and raises exception for all other.
57
+
58
+ The special thing, that EnsureIt can do (and do it by default) is smart error messages in bang methods. In most cases, EnsureIt guesses right context in wich `ensure_*` method called and froms more informative message. It recognizes name of local variable if method called for variable like `my_var.ensure_symbol`, argument name, if variable is argument of method and method calls itself like `'some_string'.to_sym.ensure_symbol` - so `ensure_symbol` called on result of `to_sym` method. You can disable this functionality at all (see [Configuration section](configuration)) or override globally configuration for any method call by `smart` option like this `:symbol.ensure_symbol(smart: true)` or `:symbol.ensure_symbol(smart: false)`. In any way, this `:smart` errors doesn't affect execution speed because the analyzing block of code executed only on exception - not on every `ensure_*` call.
59
+
60
+ For example, following code
61
+
62
+ ```ruby
63
+ def awesome(arg)
64
+ arg = arg.ensure_symbol!
65
+ end
66
+
67
+ awesome(0)
68
+ ```
69
+
70
+ will produce error message `argument 'arg' of 'awesome' method should be a Symbol or a String`.
71
+
72
+ For bang methods you can override error class with `error` option and error message with `message` option. In message you can specify a placeholder for subject as `#{subject}`, just subject name as `#{name}` and method name as `#{method_name}`. For example:
73
+
74
+ ```ruby
75
+ def awesome(arg)
76
+ arg = arg.ensure_symbol!(
77
+ error: ArgumentError,
78
+ message: 'it\'s bad that #{subject} with name #{name} is not a symbol.' \
79
+ ' Raised by #{method_name}'
80
+ )
81
+ end
82
+
83
+ awesome(0)
84
+ ```
85
+
86
+ will produce ArgumentError with message `it's unusual that 'arg' of 'awesome' method with name arg is not a symbol. Raised in ensure_symbol!`.
87
+
88
+ ### ensure_symbol, ensure_symbol!
89
+
90
+ Returns self for Symbol, converted value for String, nil (or raise) for other:
91
+
92
+ ```ruby
93
+ :test.ensure_symbol # => :test
94
+ 'test'.ensure_symbol # => :test
95
+ 100.ensure_symbol # => nil
96
+ ```
97
+
98
+ ### ensure_string, ensure_string!
99
+
100
+ By default, returns self for String, converted value for Symbol and nil (or raise) for other. With `numbers: true` option returns number, converted to string for Numeric and Rational objects:
101
+
102
+ ```ruby
103
+ :test.ensure_string # => 'test'
104
+ 'test'.ensure_string # => 'test'
105
+ 100.ensure_string # => nil
106
+ 100.ensure_string(numbers: true) # => '100'
107
+ ```
108
+
109
+ ### ensure_integer, ensure_integer!
110
+
111
+ By default, returns Fixnum or Bignum for Integer itself, rounded value for Float, converted Strings with strong check ('123test' will return nil) and nil (or raise) for other. With `boolean: true` option returns `0` for `false` and `1` for `true`, with `boolean: Fixnum-value` returns `0` for false and specified value for true:
112
+
113
+ ```ruby
114
+ :test.ensure_integer # => nil
115
+ :'100'.ensure_integer # => nil
116
+ '100'.ensure_integer # => 100
117
+ '1_200'.ensure_integer # => 1200
118
+ '0x0a'.ensure_integer # => 10
119
+ '0b100'.ensure_integer # => 4
120
+ '010'.ensure_integer # => 10 !!! Octals are not accepted by default,
121
+ # use octal: true for this
122
+ '010'.ensure_integer(octal: true) # => 8
123
+ 100.4.ensure_integer # => 100
124
+ 100.5.ensure_integer # => 101
125
+ true.ensure_integer # => nil
126
+ true.ensure_integer(boolean: true) # => 1
127
+ true.ensure_integer(boolean: 1000) # => 1000
128
+ ```
129
+
130
+ Be aware that octal numbers, beginning with `0` is not accepted by default, because its usage is rarely, that more common situation to have leading zeroes in decimal numbers while loading data from something like csv file. To recognize zero-strated numbers as octals, use `octal: true` option.
131
+
132
+ ### ensure_float, ensure_float!
133
+
134
+ By default, returns Float for Numerics, converted Strings with strong check ('123test' will return nil) and nil (or raise) for other:
135
+
136
+ ```ruby
137
+ :test.ensure_float # => nil
138
+ :'100'.ensure_float # => nil
139
+ '100'.ensure_float # => 100.0
140
+ '.1'.ensure_float # => 0.1
141
+ '1e3'.ensure_float # => 1000.0
142
+ 100.ensure_float # => 100.0
143
+ 100.5.ensure_float # => 100.5
144
+ ('1/2').to_r.ensure_float # => 0.5
145
+ true.ensure_float # => nil
146
+ ```
147
+
148
+ ### ensure_array, ensure_array!
149
+
150
+ By default, returns Array only for Array itself and **empty** array (not nil) for others. This method have many usefull optioins. Just list it in example:
151
+
152
+ ```ruby
153
+ [1, nil, 2].ensure_array # => [1, nil, 2]
154
+ true.ensure_array # => []
155
+ true.ensure_array(wrong: nil) # => nil
156
+ [1, nil, 2].ensure_array(compact: true) # => [1, 2]
157
+ [1, [2, 3], 4].ensure_array(flatten: true) # => [1, 2, 3, 4]
158
+ [1, [5, 6], 4].ensure_array(flatten: true, sorted: true) # => [1, 4, 5, 6]
159
+ [1, [5, 6], 4].ensure_array(flatten: true, sorted: :desc) # => [6, 5, 4, 1]
160
+ [1, [5, 6], 4].ensure_array(flatten: true, ordered: true) # => alias to sorted
161
+ arr = ['some', nil, :value]
162
+ arr.ensure_array(:ensure_symbol, compact: true) # => [:some, :value]
163
+ arr.ensure_array(:ensure_symbol!, compact: true) # => raise on second element
164
+ arr = ['some', :value]
165
+ arr.ensure_array(:to_s) # => ['some', 'value'] standard methods can be used
166
+ arr.ensure_array(:ensure_string, :to_sym) # => [:some, :value] you can chain methods
167
+ ```
168
+
169
+ Simple usage example:
170
+
171
+ ```ruby
172
+ require 'ensure_it'
173
+
174
+ class Awesome
175
+ def self.define_getters(*args)
176
+ args.ensure_array(:ensure_symbol, compact: true).each do |n|
177
+ define_method(n) { instance_variable_get("@#{n}") }
178
+ end
179
+ end
180
+ end
181
+
182
+ Awesome.define_getters(:one, 'two', nil, false, Object, :three)
183
+ Awesome.methods(false) #=> [:one, :two, :three]
184
+ ```
185
+
186
+ ### ensure_hash, ensure_hash!
187
+
188
+ Returns Hash only for Hash itself and **empty** hash (not nil) for others. Symbolizes keys with `symbolize_keys: true` option:
189
+
190
+ ```ruby
191
+ {some: 0, 'key' => 1}.ensure_hash # => {some: 0, 'key' => 1}
192
+ 0.ensure_hash # => {}
193
+ 0.ensure_hash(wrong: nil) # => nil
194
+ {some: 0, 'key' => 1}.ensure_hash(symbolize_keys: true) # => {some: 0, key: 0}
195
+ ```
196
+
197
+ ### ensure_instance_of, ensure_instance_of!
198
+
199
+ Returns self only if it instance of specified class or nil (or raise) elsewhere:
200
+
201
+ ```ruby
202
+ 10.ensure_instance_of(Fixnum) # => 10
203
+ 10.0.ensure_instance_of(Fixnum) # => nil
204
+ 10.0.ensure_instance_of(Fixnum, wrong: -1) # => -1
205
+ ```
206
+
207
+ ### ensure_class, ensure_class!
208
+
209
+ Returns self only if it is a class and optionally have specified ancestors or nil (or raise) elsewhere:
210
+
211
+ ```ruby
212
+ 10.ensure_class # => nil
213
+ String.ensure_class # => String
214
+ Fixnum.ensure_class(Integer) # => Fixnum
215
+ Float.ensure_class(Integer) # => nil
216
+
217
+ module CustomModule; end
218
+ class CustomArray < Array;
219
+ include CustomModule
220
+ end
221
+ CustomArray.ensure_class(Enumerable, CustomModule) # => CustomArray
222
+ Array.ensure_class(Enumerable, CustomModule) # => nil
223
+ Array.ensure_class(Enumerable) # => Array
224
+ ```
225
+
226
+ ### Common options for all non-bang methods
227
+
228
+ |option|possible values|meaning|
229
+ |------|---------------|-------|
230
+ |`:wrong`|any|if present then will be used as wrong value instead of default `nil`|
231
+
232
+ ### Common options for all bang methods
233
+
234
+ |option|possible values|meaning|
235
+ |------|---------------|-------|
236
+ |`:message`|`String`|custom error message|
237
+ |`:error`|`Exception` class|custom error class|
238
+ |`:smart`|`true` or `false`|use smart errors|
239
+
240
+ ## Refinements
241
+
242
+ Since ruby `2.0.0` [refinements](http://www.ruby-doc.org/core-2.1.1/doc/syntax/refinements_rdoc.html) mechanism intorduced and was experimental till `2.1.0`. Starting from `2.1.0` you can use it without warnings and in module and class scope.
243
+
244
+ EnsureIt is fully tested and working with refinements. But not by default and not for ruby `< 2.1.0`. To use refined version of EnsureIt (with zero-monkey-pathing) just require `ensure_it_refines` instead of `ensure_it`. If you use bundler, you can do it, by specifying `require: 'ensure_it_refines'` option for `gem 'ensure_it'` in your `Gemfile`:
245
+
246
+ ```ruby
247
+ gem 'ensure_it', require: 'ensure_it_refines'
248
+ ```
249
+
250
+ Or without bundler:
251
+
252
+ ```ruby
253
+ # In you code initialization
254
+ require 'ensure_it_refines'
255
+ ```
256
+
257
+ Then activate EnsureIt refines by `using EnsureIt` in needed scope:
258
+
259
+ ```ruby
260
+ require 'ensure_it_refines'
261
+
262
+ class AwesomeClass
263
+ using EnsureIt
264
+
265
+ def awesome_method(arg)
266
+ arg = arg.ensure_symbol!
267
+ end
268
+ end
269
+
270
+ AwesomeClass.new.awesome_method(0) # => raises EnsureIt::Error with message
271
+ # "argument 'arg' of 'awesome_method'
272
+ # method should be a Symbol or a String"
273
+ ```
274
+
275
+ Please read carefully [refinements](http://www.ruby-doc.org/core-2.1.1/doc/syntax/refinements_rdoc.html) documentation before using refined EnsureIt. Don't forget to call `using EnsureIt` in every file (not class or method if your class or method placed in many files) you need it.
276
+
277
+ ## Changelog
278
+
279
+ `0.1.0`
280
+ * set of methods for beginning:
281
+ - ensure_symbol
282
+ - ensure_string
283
+ - ensure_integer
284
+ - ensure_float
285
+ - ensure_array
286
+ - ensure_hash
287
+ - ensure_instance_of
288
+ - ensure_class
289
+
290
+ ## Versions
291
+
292
+ `0.x.x` is pre-release. After some testing in real applications, `1.x.x` as first release will be started.
293
+
294
+ ## Todo
295
+
296
+ * enlarge method set
297
+ * enlarge number of options for arrays and hashes
298
+ * block processing for arrays and hashes
299
+ * benchmarking and profiling
300
+ * custom extending functionality support
301
+
302
+ ## Contributing
303
+
304
+ 1. Fork it ( http://github.com/<my-github-username>/skeleton/fork )
305
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
306
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
307
+ 4. Push to the branch (`git push origin my-new-feature`)
308
+ 5. Create new Pull Request
309
+
310
+ # License
311
+
312
+ The MIT License (MIT)
313
+
314
+ Copyright (c) 2014 Alexey Ovchinnikov
315
+
316
+ Permission is hereby granted, free of charge, to any person obtaining a copy
317
+ of this software and associated documentation files (the "Software"), to deal
318
+ in the Software without restriction, including without limitation the rights
319
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
320
+ copies of the Software, and to permit persons to whom the Software is
321
+ furnished to do so, subject to the following conditions:
322
+
323
+ The above copyright notice and this permission notice shall be included in
324
+ all copies or substantial portions of the Software.
325
+
326
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
327
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
328
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
329
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
330
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
331
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
332
+ THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require File.join %w(bundler gem_tasks)
8
+ require File.join %w(rspec core rake_task)
9
+
10
+ RSpec::Core::RakeTask.new(:spec)
11
+ task :default => :spec
data/ensure_it.gemspec ADDED
@@ -0,0 +1,39 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path(File.join('..', 'lib'), __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require File.join %w(ensure_it version)
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.required_ruby_version = '>= 2.0.0'
8
+
9
+ spec.name = 'ensure_it'
10
+ spec.version = EnsureIt::VERSION
11
+ spec.authors = ['Alexey Ovchinnikov']
12
+ spec.email = ['alexiss@cybernetlab.ru', 'alexey.ovchinnikov@yandex.ru']
13
+ spec.summary = %q{Provides variables and arguments parsing}
14
+ spec.description = %q{Main goal of project is to provide fastest way to
15
+ every-method arguments and variables checks with
16
+ minimal coding requirements}
17
+ spec.summary = <<-EOL.gsub(/^\s+\|/, '')
18
+ |This library provides way to check and converts local variables for
19
+ |every-method usage, like arguments checking.
20
+ |The main goal of EnsureIt is to provide as fast executed code as it
21
+ |possible with simple and usable syntax.
22
+ EOL
23
+ spec.homepage = 'http://github.com/cybernetlab/ensure_it'
24
+ spec.license = 'MIT'
25
+ spec.metadata = {
26
+ 'issue_tracker' => 'https://github.com/cybernetlab/ensure_it/issues'
27
+ }
28
+
29
+ spec.files = `git ls-files`.split($/)
30
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
31
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
32
+ spec.require_paths = ['lib']
33
+
34
+ spec.add_development_dependency 'bundler', '~> 1.5'
35
+ spec.add_development_dependency 'rake', '~> 10.1'
36
+ spec.add_development_dependency 'redcarpet', '~> 3.1'
37
+ spec.add_development_dependency 'yard', '~> 0.8'
38
+ spec.add_development_dependency 'rspec', '~> 2.14'
39
+ end
@@ -0,0 +1,23 @@
1
+ module EnsureIt
2
+ module Config
3
+ ERRORS = %i(smart standard)
4
+
5
+ def self.errors(value = nil)
6
+ value.nil? ? @errors ||= ERRORS.first : self.errors = value
7
+ end
8
+
9
+ def self.errors=(value)
10
+ value = value.to_sym if value.is_a?(String)
11
+ @errors = ERRORS.include?(value) ? value : ERRORS.first
12
+ end
13
+ end
14
+
15
+ def self.config
16
+ Config
17
+ end
18
+
19
+ def self.configure
20
+ yield(Config) if block_given?
21
+ Config
22
+ end
23
+ end
@@ -0,0 +1,67 @@
1
+ module EnsureIt
2
+ patch Object do
3
+ def ensure_array(*args, **opts)
4
+ opts.key?(:wrong) ? opts[:wrong] : []
5
+ end
6
+
7
+ def ensure_array!(*args, **opts)
8
+ opts[:message] ||= '#{subject} should be an Array'
9
+ EnsureIt.raise_error(:ensure_array!, **opts)
10
+ end
11
+ end
12
+
13
+ patch Array do
14
+ using EnsureIt if ENSURE_IT_REFINES
15
+
16
+ if ENSURE_IT_REFINES
17
+ def ensure_array(*args, **opts)
18
+ arr = self
19
+ args.each do |arg|
20
+ arg = arg.ensure_symbol || next
21
+ arr =
22
+ if arg.to_s.index('ensure_') == 0
23
+ case arg
24
+ when :ensure_symbol then map { |x| x.ensure_symbol }
25
+ when :ensure_symbol! then map { |x| x.ensure_symbol! }
26
+ when :ensure_string then map { |x| x.ensure_string }
27
+ when :ensure_string! then map { |x| x.ensure_string! }
28
+ when :ensure_integer then map { |x| x.ensure_integer }
29
+ when :ensure_integer! then map { |x| x.ensure_integer! }
30
+ when :ensure_float then map { |x| x.ensure_float }
31
+ when :ensure_float! then map { |x| x.ensure_float! }
32
+ when :ensure_array then map { |x| x.ensure_array }
33
+ when :ensure_array! then map { |x| x.ensure_array! }
34
+ end
35
+ else
36
+ arr.map(&arg)
37
+ end
38
+ end
39
+ return arr if opts.empty?
40
+ arr = arr.map { |x| x } if arr == self
41
+ arr.flatten! if opts[:flatten] == true
42
+ opts[:sorted] ||= opts.delete(:ordered) if opts.key?(:ordered)
43
+ arr.sort! if opts.key?(:sorted)
44
+ arr.reverse! if opts[:sorted].ensure_symbol == :desc
45
+ arr.compact! if opts[:compact] == true
46
+ arr
47
+ end
48
+ else
49
+ def ensure_array(*args, **opts)
50
+ arr = self
51
+ args.each do |arg|
52
+ arg = arg.ensure_symbol || next
53
+ arr = arr.map(&arg)
54
+ end
55
+ return arr if opts.empty?
56
+ arr = arr.map { |x| x } if arr == self
57
+ arr.flatten! if opts[:flatten] == true
58
+ opts[:sorted] ||= opts.delete(:ordered) if opts.key?(:ordered)
59
+ arr.sort! if opts.key?(:sorted)
60
+ arr.reverse! if opts[:sorted].ensure_symbol == :desc
61
+ arr.compact! if opts[:compact] == true
62
+ arr
63
+ end
64
+ end
65
+ alias_method :ensure_array!, :ensure_array
66
+ end
67
+ end
@@ -0,0 +1,30 @@
1
+ module EnsureIt
2
+ patch Object do
3
+ def ensure_class(*args, **opts)
4
+ opts.key?(:wrong) ? opts[:wrong] : nil
5
+ end
6
+
7
+ def ensure_class!(*args, **opts)
8
+ opts[:message] ||= '#{subject} should be a class'
9
+ EnsureIt.raise_error(:ensure_class!, **opts)
10
+ end
11
+ end
12
+
13
+ patch Class do
14
+ using EnsureIt if ENSURE_IT_REFINES
15
+
16
+ def ensure_class(*args, **opts)
17
+ args.select! { |x| x.is_a?(Module) }
18
+ args.all? { |x| self <= x } ? self : super(**opts)
19
+ end
20
+
21
+ def ensure_class!(*args, **opts)
22
+ args.select! { |x| x.is_a?(Module) }
23
+ return self if args.all? { |x| self <= x }
24
+ args = args.map!(&:name).join(', ')
25
+ opts[:message] ||=
26
+ "\#{subject} should subclass or extend all of ['#{args}']"
27
+ EnsureIt.raise_error(:ensure_class!, **opts)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,48 @@
1
+ module EnsureIt
2
+ FLOAT_REGEXP = /\A[+\-]?(?:\d+(?:\.\d*)?|\d*\.\d+)(?:[eE][+\-]?\d+)?\z/
3
+
4
+ patch Object do
5
+ def ensure_float(**opts)
6
+ opts.key?(:wrong) ? opts[:wrong] : nil
7
+ end
8
+
9
+ def ensure_float!(**opts)
10
+ opts[:message] ||= '#{subject} should be a float or be able' \
11
+ ' to convert to it'
12
+ EnsureIt.raise_error(:ensure_float!, **opts)
13
+ end
14
+ end
15
+
16
+ patch String do
17
+ using EnsureIt if ENSURE_IT_REFINES
18
+
19
+ def ensure_float(**opts)
20
+ self =~ FLOAT_REGEXP ? to_f : nil
21
+ end
22
+
23
+ def ensure_float!(**opts)
24
+ ensure_float(**opts) || super(**opts)
25
+ end
26
+ end
27
+
28
+ patch Integer do
29
+ def ensure_float(**opts)
30
+ to_f
31
+ end
32
+ alias_method :ensure_float!, :ensure_float
33
+ end
34
+
35
+ patch Float do
36
+ def ensure_float(**opts)
37
+ self
38
+ end
39
+ alias_method :ensure_float!, :ensure_float
40
+ end
41
+
42
+ patch Rational do
43
+ def ensure_float(**opts)
44
+ to_f
45
+ end
46
+ alias_method :ensure_float!, :ensure_float
47
+ end
48
+ end
@@ -0,0 +1,22 @@
1
+ module EnsureIt
2
+ patch Object do
3
+ def ensure_hash(*args, **opts)
4
+ opts.key?(:wrong) ? opts[:wrong] : {}
5
+ end
6
+
7
+ def ensure_hash!(*args, **opts)
8
+ opts[:message] ||= '#{subject} should be a Hash'
9
+ EnsureIt.raise_error(:ensure_hash!, **opts)
10
+ end
11
+ end
12
+
13
+ patch Hash do
14
+ using EnsureIt if ENSURE_IT_REFINES
15
+
16
+ def ensure_hash(*args, **opts)
17
+ return self if opts[:symbolize_keys] != true
18
+ Hash[map { |k, v| [k.ensure_symbol, v] }.reject { |x| x[0].nil? }]
19
+ end
20
+ alias_method :ensure_hash!, :ensure_hash
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ module EnsureIt
2
+ patch Object do
3
+ def ensure_instance_of(klass, **opts)
4
+ unless klass.is_a?(Class)
5
+ fail(
6
+ ArgumentError,
7
+ 'Wrong class argument for #ensure_instance_of specified'
8
+ )
9
+ end
10
+ return self if is_a?(klass)
11
+ opts.key?(:wrong) ? opts[:wrong] : nil
12
+ end
13
+
14
+ def ensure_instance_of!(klass, **opts)
15
+ unless klass.is_a?(Class)
16
+ fail(
17
+ ArgumentError,
18
+ 'Wrong class argument for #ensure_instance_of specified'
19
+ )
20
+ end
21
+ return self if is_a?(klass)
22
+ opts[:message] ||=
23
+ "\#{subject} should be an instance of '#{klass.name}' class"
24
+ EnsureIt.raise_error(:ensure_instance_of!, **opts)
25
+ end
26
+ end
27
+ end