ensure_it 0.1.0

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 (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
@@ -0,0 +1,89 @@
1
+ module EnsureIt
2
+ OCT_REGEXP = /\A0\d+\z/
3
+ INT_REGEXP = /\A[+\-]?\d[\d_]*\z/
4
+ HEX_REGEXP = /\A0x[0-9a-zA-Z]+\z/
5
+ BIN_REGEXP = /\A0b[01]+\z/
6
+
7
+ patch Object do
8
+ def ensure_integer(**opts)
9
+ opts.key?(:wrong) ? opts[:wrong] : nil
10
+ end
11
+
12
+ def ensure_integer!(**opts)
13
+ opts[:message] ||= '#{subject} should be an integer or be able' \
14
+ ' to convert to it'
15
+ EnsureIt.raise_error(:ensure_integer!, **opts)
16
+ end
17
+ end
18
+
19
+ patch String do
20
+ using EnsureIt if ENSURE_IT_REFINES
21
+
22
+ def ensure_integer(**opts)
23
+ case self
24
+ when OCT_REGEXP then opts[:octal] == true ? self.to_i(8) : self.to_i
25
+ when INT_REGEXP then self.to_i
26
+ when HEX_REGEXP then self[2..-1].to_i(16)
27
+ when BIN_REGEXP then self[2..-1].to_i(2)
28
+ else nil
29
+ end
30
+ end
31
+
32
+ def ensure_integer!(**opts)
33
+ ensure_integer(**opts) || super(**opts)
34
+ end
35
+ end
36
+
37
+ patch Integer do
38
+ def ensure_integer(**opts)
39
+ self
40
+ end
41
+ alias_method :ensure_integer!, :ensure_integer
42
+ end
43
+
44
+ patch Float do
45
+ def ensure_integer(**opts)
46
+ round
47
+ end
48
+ alias_method :ensure_integer!, :ensure_integer
49
+ end
50
+
51
+ patch Rational do
52
+ def ensure_integer(**opts)
53
+ round
54
+ end
55
+ alias_method :ensure_integer!, :ensure_integer
56
+ end
57
+
58
+ patch TrueClass do
59
+ using EnsureIt if ENSURE_IT_REFINES
60
+
61
+ def ensure_integer(**opts)
62
+ if opts[:boolean] == true || opts[:boolean].is_a?(Integer)
63
+ opts[:boolean] == true ? 1 : opts[:boolean]
64
+ else
65
+ nil
66
+ end
67
+ end
68
+
69
+ def ensure_integer!(**opts)
70
+ if opts[:boolean] == true || opts[:boolean].is_a?(Integer)
71
+ opts[:boolean] == true ? 1 : opts[:boolean]
72
+ else
73
+ super(**opts)
74
+ end
75
+ end
76
+ end
77
+
78
+ patch FalseClass do
79
+ using EnsureIt if ENSURE_IT_REFINES
80
+
81
+ def ensure_integer(**opts)
82
+ opts[:boolean] == true || opts[:boolean].is_a?(Integer) ? 0 : nil
83
+ end
84
+
85
+ def ensure_integer!(**opts)
86
+ opts[:boolean] == true || opts[:boolean].is_a?(Integer) ? 0 : super(**opts)
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,43 @@
1
+ module EnsureIt
2
+ patch Object do
3
+ def ensure_string(**opts)
4
+ opts.key?(:wrong) ? opts[:wrong] : nil
5
+ end
6
+
7
+ def ensure_string!(**opts)
8
+ opts[:message] ||=
9
+ if opts[:numbers] == true
10
+ '#{subject} should be a String, Symbol, Numeric or Rational'
11
+ else
12
+ '#{subject} should be a String or a Symbol'
13
+ end
14
+ EnsureIt.raise_error(:ensure_string!, **opts)
15
+ end
16
+ end
17
+
18
+ patch String do
19
+ def ensure_string(**opts)
20
+ self
21
+ end
22
+ alias_method :ensure_string!, :ensure_string
23
+ end
24
+
25
+ patch Symbol do
26
+ def ensure_string(**opts)
27
+ to_s
28
+ end
29
+ alias_method :ensure_string!, :ensure_string
30
+ end
31
+
32
+ patch Numeric do
33
+ using EnsureIt if ENSURE_IT_REFINES
34
+
35
+ def ensure_string(**opts)
36
+ opts[:numbers] == true ? to_s : nil
37
+ end
38
+
39
+ def ensure_string!(**opts)
40
+ opts[:numbers] == true ? to_s : super(**opts)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,26 @@
1
+ module EnsureIt
2
+ patch Object do
3
+ def ensure_symbol(**opts)
4
+ opts.key?(:wrong) ? opts[:wrong] : nil
5
+ end
6
+
7
+ def ensure_symbol!(**opts)
8
+ opts[:message] ||= '#{subject} should be a Symbol or a String'
9
+ EnsureIt.raise_error(:ensure_symbol!, **opts)
10
+ end
11
+ end
12
+
13
+ patch String do
14
+ def ensure_symbol(**opts)
15
+ to_sym
16
+ end
17
+ alias_method :ensure_symbol!, :ensure_symbol
18
+ end
19
+
20
+ patch Symbol do
21
+ def ensure_symbol(**opts)
22
+ self
23
+ end
24
+ alias_method :ensure_symbol!, :ensure_symbol
25
+ end
26
+ end
@@ -0,0 +1,173 @@
1
+ module EnsureIt
2
+ class Error < StandardError; end
3
+
4
+ class ErrorMessage
5
+ attr_accessor :method_name, :subject, :subject_type, :inside, :backtrace
6
+ attr_writer :message
7
+
8
+ def initialize(method_name, message, backtrace)
9
+ method_name = method_name.to_sym if method_name.is_a?(String)
10
+ unless method_name.is_a?(Symbol)
11
+ raise ArgumentError, 'EnsureIt: Wrong method_name argument for Error'
12
+ end
13
+ @method_name, @message, @backtrace = method_name, message, backtrace
14
+ end
15
+
16
+ def subject_display_name
17
+ display_name =
18
+ if @subject.nil? && @subject_type != :unknown_method_result
19
+ "subject of '#{method_name}' method"
20
+ else
21
+ case @subject_type
22
+ when :local_variable then "local variable '#{@subject}'"
23
+ when :instance_variable then "instance variable '@#{@subject}'"
24
+ when :class_variable then "class variable '@@#{@subject}'"
25
+ when :method_result then "return value of '#{subject}' method"
26
+ when :unknown_method_result then 'return value of method'
27
+ when :req_argument then "argument '#{subject}'"
28
+ when :rest_argument then "argument '*#{subject}'"
29
+ when :opt_argument then "optional argument '#{subject}'"
30
+ when :key_argument then "key argument '#{subject}'"
31
+ when :keyrest_argument then "key argument '**#{subject}'"
32
+ when :block_argument then "block argument '&#{subject}'"
33
+ else "subject of '#{method_name}' method"
34
+ end
35
+ end
36
+ unless @inside.nil?
37
+ display_name +=
38
+ if !@subject_type.nil? && @subject_type.to_s =~ /_argument\z/
39
+ " of '#{@inside}' method"
40
+ else
41
+ " inside '#{@inside}' method"
42
+ end
43
+ end
44
+ display_name
45
+ end
46
+
47
+ def message
48
+ unless @message.is_a?(String)
49
+ @message =
50
+ if @subject.nil? && @subject_type != :unknown_method_result
51
+ '#{subject}'
52
+ else
53
+ '#{subject} of #{method_name}'
54
+ end
55
+ end
56
+ @message.gsub(/\#\{subject\}/, subject_display_name)
57
+ .gsub(/\#\{name\}/, @subject.to_s)
58
+ .gsub(/\#\{method_name\}/, @method_name.to_s)
59
+ end
60
+ end
61
+
62
+ def self.raise_error(method_name, message: nil, error: Error, **opts)
63
+ error = Error unless error <= Exception
64
+ error_msg = ErrorMessage.new(method_name, message, caller[1..-1])
65
+ if opts.key?(:smart) && opts[:smart] != true ||
66
+ EnsureIt.config.errors != :smart
67
+ raise error_class, error.message, error.backtrace
68
+ end
69
+ raise_smart_error(error_msg, error, **opts)
70
+ end
71
+
72
+ def self.raise_smart_error(error, error_class, **opts)
73
+ inspect_source(error, **opts)
74
+ tp_count = 0
75
+ error_obj = nil
76
+ error_message = error.message
77
+ error_backtrace = error.backtrace
78
+ #
79
+ # first trace point is to capture raise object before exitting
80
+ # from :ensure_* method
81
+ #
82
+ # after that with second trace point we try to return from :ensure_* method
83
+ # to caller and inspect code there for method name and arguments
84
+ TracePoint.trace(:return, :raise) do |first_tp|
85
+ if first_tp.event == :raise
86
+ # save error object for patching
87
+ error_obj = first_tp.raised_exception
88
+ else
89
+ # skip returns from :raise_smart_error and :raise_error
90
+ tp_count += 1
91
+ if tp_count > 1
92
+ # at this moment we are at end of 'ensure_' method
93
+ first_tp.disable
94
+ TracePoint.trace(:return) do |second_tp|
95
+ # skip return from :ensure_* method
96
+ tp_count += 1
97
+ if tp_count > 3
98
+ # now we are in caller context
99
+ second_tp.disable
100
+ unless error_obj.nil?
101
+ # inspect caller code
102
+ inspect_code(second_tp, error, **opts)
103
+ # patch error message
104
+ error_obj.extend(Module.new do
105
+ @@ensure_it_message = error.message
106
+ def message; @@ensure_it_message; end
107
+ end)
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ raise error_class, error_message, error_backtrace
115
+ end
116
+
117
+ def self.inspect_source(error, **opts)
118
+ file_name, line_no = error.backtrace.first.split(':', 2)
119
+ return unless File.exist?(file_name)
120
+ line_no = line_no.to_i
121
+ line = read_line_number(file_name, line_no)
122
+ return if line.nil?
123
+ m_name = error.method_name
124
+ m = /
125
+ (?:(?<method_access>\.)|(?<class_access>@{1,2}))?
126
+ (?<name>(?:[a-z_][a-zA-Z_0-9]*(?<modifier>[?!])?)|\))
127
+ (?:
128
+ (?<send>\.send\(\s*(?::#{m_name}|'#{m_name}'|"#{m_name}")\s*\))|
129
+ (?:\.#{m_name}(?:[^a-zA-Z_0-9]|\z))
130
+ )
131
+ /x.match(line)
132
+ return if m.nil? || m[:method_access].nil? && !m[:modifier].nil?
133
+ error.subject = m[:name]
134
+ error.subject_type = case
135
+ when m[:class_access] then
136
+ m[:class_access] == '@' ? :instance_variable : :class_variable
137
+ when m[:name] == ')' then
138
+ error.subject = nil
139
+ :unknown_method_result
140
+ when m[:method_access] then :method_result
141
+ else :local_variable
142
+ end
143
+ end
144
+
145
+ def self.inspect_code(tp, error, **opts)
146
+ return if tp.method_id.nil?
147
+ error.inside = tp.method_id
148
+ begin
149
+ method = eval("method(:#{tp.method_id})", tp.binding)
150
+ rescue NameError
151
+ return
152
+ end
153
+ param = method.parameters.find { |_, name| name.to_s == error.subject }
154
+ unless param.nil?
155
+ error.subject_type = "#{param[0]}_argument".to_sym
156
+ end
157
+ end
158
+
159
+ def self.read_line_number(file_name, number)
160
+ counter, line = 0, nil
161
+ File.foreach(file_name) do |l|
162
+ counter += 1
163
+ if counter == number
164
+ line = l.chomp!
165
+ break
166
+ end
167
+ end
168
+ line
169
+ end
170
+
171
+ private_class_method :raise_smart_error, :inspect_source, :inspect_code,
172
+ :read_line_number
173
+ end
@@ -0,0 +1,17 @@
1
+ module EnsureIt
2
+ if ENSURE_IT_REFINES
3
+ def self.patch(target, &block)
4
+ module_eval do
5
+ refine target do
6
+ class_eval(&block)
7
+ end
8
+ end
9
+ end
10
+ else
11
+ def self.patch(target, &block)
12
+ target.class_eval(&block)
13
+ end
14
+ end
15
+
16
+ private_class_method :patch
17
+ end
@@ -0,0 +1,3 @@
1
+ module EnsureIt
2
+ VERSION = '0.1.0'
3
+ end
data/lib/ensure_it.rb ADDED
@@ -0,0 +1,18 @@
1
+ if RUBY_VERSION < '2.0.0'
2
+ fail %q{EnsureIt: library doesn't support ruby < 2.0.0}
3
+ end
4
+
5
+ defined?(ENSURE_IT_REFINES) || ENSURE_IT_REFINES = false
6
+
7
+ require File.join %w(ensure_it version)
8
+ require File.join %w(ensure_it config)
9
+ require File.join %w(ensure_it errors)
10
+ require File.join %w(ensure_it patch)
11
+ require File.join %w(ensure_it ensure_symbol)
12
+ require File.join %w(ensure_it ensure_string)
13
+ require File.join %w(ensure_it ensure_integer)
14
+ require File.join %w(ensure_it ensure_float)
15
+ require File.join %w(ensure_it ensure_array)
16
+ require File.join %w(ensure_it ensure_hash)
17
+ require File.join %w(ensure_it ensure_instance_of)
18
+ require File.join %w(ensure_it ensure_class)
@@ -0,0 +1,8 @@
1
+ if RUBY_VERSION >= '2.1'
2
+ ENSURE_IT_REFINES = true
3
+ else
4
+ ENSURE_IT_REFINES = false
5
+ warn 'EsureIt: refines supported only for ruby >= 2.1'
6
+ end
7
+
8
+ require 'ensure_it'
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe EnsureIt do
4
+ describe 'refines requirement' do
5
+ before { @backup = ENSURE_IT_REFINES }
6
+
7
+ after do
8
+ if defined? ENSURE_IT_REFINES
9
+ Object.instance_eval { remove_const(:ENSURE_IT_REFINES) }
10
+ end
11
+ ENSURE_IT_REFINES = @backup
12
+ end
13
+
14
+ def load_refines
15
+ if defined? ENSURE_IT_REFINES
16
+ Object.instance_eval { remove_const(:ENSURE_IT_REFINES) }
17
+ end
18
+ load(File.expand_path(
19
+ File.join(%w(.. .. .. lib ensure_it_refines.rb)), __FILE__
20
+ ))
21
+ end
22
+
23
+ if RUBY_VERSION >= '2.1'
24
+ it 'defines ENSURE_IT_REFINES' do
25
+ load_refines
26
+ expect(ENSURE_IT_REFINES).to be_true
27
+ end
28
+ else
29
+ it %q{warns with ruby < 2.1 and doesn't defines ENSURE_IT_REFINES} do
30
+ expect {
31
+ load_refines
32
+ }.to warn('EsureIt: refines supported only for ruby >= 2.1')
33
+ expect(ENSURE_IT_REFINES).to be_false
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe EnsureIt::Config do
4
+ describe '::errors' do
5
+ after { described_class.instance_variable_set(:@errors, nil) }
6
+
7
+ it 'gives :smart by default' do
8
+ expect(described_class.errors).to eq :smart
9
+ end
10
+
11
+ it 'calls setter if value given' do
12
+ expect(described_class).to receive(:errors=).with(:standard)
13
+ described_class.errors :standard
14
+ end
15
+ end
16
+
17
+ describe '::errors=' do
18
+ after { described_class.instance_variable_set(:@errors, nil) }
19
+
20
+ it 'allows to change value' do
21
+ described_class.errors = :standard
22
+ expect(described_class.errors).to eq :standard
23
+ end
24
+
25
+ it 'sets to default for wrong values' do
26
+ described_class.errors = :bad_value
27
+ expect(described_class.errors).to eq :smart
28
+ end
29
+ end
30
+ end
31
+
32
+ describe EnsureIt do
33
+ describe '::config' do
34
+ it 'returns Config module' do
35
+ expect(described_class.config).to eq EnsureIt::Config
36
+ end
37
+ end
38
+
39
+ describe '::configure' do
40
+ it 'returns Config module' do
41
+ expect(described_class.config).to eq EnsureIt::Config
42
+ end
43
+
44
+ it 'yields block with Config module' do
45
+ expect { |b|
46
+ described_class.configure(&b)
47
+ }.to yield_with_args(EnsureIt::Config)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ class Tester
4
+ using EnsureIt if ENSURE_IT_REFINES
5
+
6
+ def ensure_array(*args)
7
+ obj.ensure_array(*args)
8
+ end
9
+
10
+ def ensure_array!(*args)
11
+ obj.ensure_array!(*args)
12
+ end
13
+ end
14
+
15
+ describe EnsureIt do
16
+ shared_examples 'array parser' do
17
+ it 'and returns self for array' do
18
+ obj = [1, nil, 2]
19
+ expect(call_for(obj)).to eq obj
20
+ end
21
+
22
+ it 'compacts array with compact option' do
23
+ expect(call_for([1, nil, 2], compact: true)).to eq [1, 2]
24
+ end
25
+
26
+ it 'flattens array with flatten option' do
27
+ expect(call_for([1, [2, 3], 4], flatten: true)).to eq [1, 2, 3, 4]
28
+ end
29
+
30
+ [:sorted, :ordered].each do |o|
31
+ it "flattens and then sorts array with flatten and #{o} options" do
32
+ expect(
33
+ call_for([1, [5, 6], 4], flatten: true, o => true)
34
+ ).to eq [1, 4, 5, 6]
35
+ end
36
+
37
+ it "sorts descending with #{o}: :desc option" do
38
+ expect(call_for([1, 5, 6, 4], o => :desc)).to eq [6, 5, 4, 1]
39
+ end
40
+ end
41
+
42
+ it 'calls :ensure_* for each element' do
43
+ arr = ['s', nil, :v]
44
+ expect(call_for(arr, :ensure_symbol, compact: true)).to eq [:s, :v]
45
+ end
46
+
47
+ it 'calls standard method for each element' do
48
+ arr = ['s', :v]
49
+ expect(call_for(arr, :to_s)).to eq ['s', 'v']
50
+ end
51
+
52
+ it 'chains methods for each element' do
53
+ arr = ['s', :v]
54
+ expect(call_for(arr, :ensure_string, :to_sym)).to eq [:s, :v]
55
+ end
56
+ end
57
+
58
+ describe '#ensure_array' do
59
+ it_behaves_like 'array parser'
60
+ it_behaves_like 'empty array creator for unmet objects', except: Array
61
+
62
+ it 'and returns nil with wrong: nil option' do
63
+ expect(call_for(true, wrong: nil)).to be_nil
64
+ expect(call_for(true, wrong: 1)).to eq 1
65
+ end
66
+ end
67
+
68
+ describe '#ensure_array!' do
69
+ it_behaves_like 'array parser'
70
+ it_behaves_like(
71
+ 'banger for unmet objects', except: Array,
72
+ message: /should be an Array/
73
+ )
74
+ end
75
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ class Tester
4
+ using EnsureIt if ENSURE_IT_REFINES
5
+
6
+ def ensure_class(*args)
7
+ obj.ensure_class(*args)
8
+ end
9
+
10
+ def ensure_class!(*args)
11
+ obj.ensure_class!(*args)
12
+ end
13
+ end
14
+
15
+ describe EnsureIt do
16
+ shared_examples 'class selector' do
17
+ it 'and returns self for right classes' do
18
+ expect(call_for(String)).to eq String
19
+ end
20
+
21
+ it 'and checks for ancestors' do
22
+ expect(call_for(Array, Enumerable, Array)).to eq Array
23
+ end
24
+ end
25
+
26
+ describe '#ensure_class' do
27
+ it_behaves_like 'class selector'
28
+
29
+ it 'returns nil for wrong classes' do
30
+ expect(call_for(10)).to be_nil
31
+ expect(call_for(Float, Integer)).to be_nil
32
+ end
33
+
34
+ it 'returns wrong option for wrong classs' do
35
+ expect(call_for(10, wrong: true)).to be_true
36
+ end
37
+ end
38
+
39
+ describe '#ensure_class!' do
40
+ it_behaves_like 'class selector'
41
+
42
+ it 'raises for non-classes' do
43
+ expect {
44
+ call_for(10)
45
+ }.to raise_error EnsureIt::Error, /should be a class\z/
46
+ end
47
+
48
+ it 'raises on wrong classes' do
49
+ expect {
50
+ call_for(Float, Integer)
51
+ }.to raise_error EnsureIt::Error, /should subclass or extend all of/
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ class Tester
4
+ using EnsureIt if ENSURE_IT_REFINES
5
+
6
+ def ensure_float(*args)
7
+ obj.ensure_float(*args)
8
+ end
9
+
10
+ def ensure_float!(*args)
11
+ obj.ensure_float!(*args)
12
+ end
13
+ end
14
+
15
+ describe EnsureIt do
16
+ shared_examples 'float numerizer' do
17
+ it 'and returns self for Float' do
18
+ obj = 0.1
19
+ expect(call_for(obj)).to eq obj
20
+ end
21
+
22
+ it 'and converts Rational' do
23
+ expect(call_for(Rational(1, 2))).to eq 0.5
24
+ end
25
+
26
+ it 'and converts Integers' do
27
+ expect(call_for(100)).to eq 100.0
28
+ expect(call_for(100)).to be_kind_of(Float)
29
+ end
30
+
31
+ it 'and converts decimal strings' do
32
+ expect(call_for('100')).to eq(100.0)
33
+ expect(call_for('100')).to be_kind_of(Float)
34
+ end
35
+
36
+ it 'and converts strings with dot' do
37
+ expect(call_for('0.1')).to eq(0.1)
38
+ end
39
+
40
+ it 'and converts scientific strings' do
41
+ expect(call_for('1e3')).to eq(1000.0)
42
+ expect(call_for('1e-3')).to eq(0.001)
43
+ expect(call_for('-1.5e+3')).to eq(-1500.0)
44
+ end
45
+ end
46
+
47
+ describe '#ensure_float' do
48
+ it_behaves_like 'float numerizer'
49
+ it_behaves_like(
50
+ 'niller for unmet objects',
51
+ '123test', :test123, :'0.1',
52
+ except: [String, Integer, Float, Rational]
53
+ )
54
+ end
55
+
56
+ describe '#ensure_float!' do
57
+ it_behaves_like 'float numerizer'
58
+ it_behaves_like(
59
+ 'banger for unmet objects',
60
+ '123test', :test123, :'0.1',
61
+ except: [String, Integer, Float, Rational],
62
+ message: /should be a float or be able to convert to it/
63
+ )
64
+ end
65
+ end