ensure_it 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +332 -0
- data/Rakefile +11 -0
- data/ensure_it.gemspec +39 -0
- data/lib/ensure_it/config.rb +23 -0
- data/lib/ensure_it/ensure_array.rb +67 -0
- data/lib/ensure_it/ensure_class.rb +30 -0
- data/lib/ensure_it/ensure_float.rb +48 -0
- data/lib/ensure_it/ensure_hash.rb +22 -0
- data/lib/ensure_it/ensure_instance_of.rb +27 -0
- data/lib/ensure_it/ensure_integer.rb +89 -0
- data/lib/ensure_it/ensure_string.rb +43 -0
- data/lib/ensure_it/ensure_symbol.rb +26 -0
- data/lib/ensure_it/errors.rb +173 -0
- data/lib/ensure_it/patch.rb +17 -0
- data/lib/ensure_it/version.rb +3 -0
- data/lib/ensure_it.rb +18 -0
- data/lib/ensure_it_refines.rb +8 -0
- data/spec/integration/refines_spec.rb +37 -0
- data/spec/lib/config_spec.rb +50 -0
- data/spec/lib/ensure_array_spec.rb +75 -0
- data/spec/lib/ensure_class_spec.rb +54 -0
- data/spec/lib/ensure_float_spec.rb +65 -0
- data/spec/lib/ensure_hash_spec.rb +45 -0
- data/spec/lib/ensure_instance_of_spec.rb +49 -0
- data/spec/lib/ensure_integer_spec.rb +89 -0
- data/spec/lib/ensure_string_spec.rb +53 -0
- data/spec/lib/ensure_symbol_spec.rb +39 -0
- data/spec/lib/errors_spec.rb +124 -0
- data/spec/lib/patch_spec.rb +31 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/support/example_groups/ensure_it_example_group.rb +66 -0
- data/spec/support/matchers/warn_matcher.rb +30 -0
- data/spec/support/shared_examples/unmet_objects.rb +60 -0
- 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
|
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,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
|