corefines 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.adoc +198 -0
- data/Rakefile +23 -0
- data/lib/corefines/array.rb +30 -0
- data/lib/corefines/enumerable.rb +64 -0
- data/lib/corefines/hash.rb +164 -0
- data/lib/corefines/module.rb +95 -0
- data/lib/corefines/object.rb +389 -0
- data/lib/corefines/string.rb +211 -0
- data/lib/corefines/support/alias_submodules.rb +103 -0
- data/lib/corefines/support/classes_including_module.rb +27 -0
- data/lib/corefines/support/fake_refinements.rb +86 -0
- data/lib/corefines/symbol.rb +32 -0
- data/lib/corefines/version.rb +3 -0
- data/lib/corefines.rb +14 -0
- data/spec/array/second_spec.rb +10 -0
- data/spec/array/third_spec.rb +10 -0
- data/spec/enumerable/index_by_spec.rb +13 -0
- data/spec/enumerable/map_send_spec.rb +24 -0
- data/spec/hash/compact_spec.rb +48 -0
- data/spec/hash/op_plus_spec.rb +11 -0
- data/spec/hash/rekey_spec.rb +100 -0
- data/spec/hash/symbolize_keys_spec.rb +21 -0
- data/spec/module/alias_class_method_spec.rb +21 -0
- data/spec/module/alias_method_chain_spec.rb +76 -0
- data/spec/object/blank_spec.rb +128 -0
- data/spec/object/deep_dup_spec.rb +61 -0
- data/spec/object/else_spec.rb +24 -0
- data/spec/object/in_spec.rb +21 -0
- data/spec/object/instance_values_spec.rb +22 -0
- data/spec/object/then_if_spec.rb +64 -0
- data/spec/object/then_spec.rb +26 -0
- data/spec/object/try_spec.rb +47 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/string/color_spec.rb +82 -0
- data/spec/string/concat_spec.rb +36 -0
- data/spec/string/decolor_spec.rb +27 -0
- data/spec/string/remove_spec.rb +57 -0
- data/spec/string/unindent_spec.rb +66 -0
- data/spec/support/alias_submodules_spec.rb +83 -0
- data/spec/support/classes_including_module_spec.rb +35 -0
- data/spec/support/fake_refinements_spec.rb +118 -0
- data/spec/symbol/call_spec.rb +16 -0
- metadata +175 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
module Corefines
|
2
|
+
module Support
|
3
|
+
|
4
|
+
@classes_including_module = {}
|
5
|
+
|
6
|
+
##
|
7
|
+
# @private
|
8
|
+
# Finds all classes that includes the specified module.
|
9
|
+
# Results are cached to speed-up repeated calls.
|
10
|
+
#
|
11
|
+
# @param mod [Module] the module.
|
12
|
+
# @yield [Class] gives each class that includes the _mod_.
|
13
|
+
#
|
14
|
+
def self.classes_including_module(mod)
|
15
|
+
@classes_including_module[mod] ||=
|
16
|
+
::ObjectSpace.each_object(::Class).select do |klass|
|
17
|
+
begin
|
18
|
+
klass.included_modules.include?(mod)
|
19
|
+
rescue
|
20
|
+
# ignore errors
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
@classes_including_module[mod].each { |e| yield e }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Corefines
|
2
|
+
module Support
|
3
|
+
##
|
4
|
+
# @private
|
5
|
+
# Faked Refinements somehow mimics refinements on Ruby engines that doesn't
|
6
|
+
# support them yet. It provides the same interface, but actually does just
|
7
|
+
# plain monkey-patching; the changes are *not* scoped like when using real
|
8
|
+
# refinements.
|
9
|
+
#
|
10
|
+
# It's useful when you want to use refinements, but also need to support
|
11
|
+
# older versions of Ruby, at least limited.
|
12
|
+
#
|
13
|
+
module FakeRefinements
|
14
|
+
|
15
|
+
MUTEX = Mutex.new
|
16
|
+
private_constant :MUTEX
|
17
|
+
|
18
|
+
def self.define_refine(target)
|
19
|
+
target.send(:define_method, :refine) do |klass, &block|
|
20
|
+
fail TypeError, "wrong argument type #{klass.class} (expected Class)" unless klass.is_a? ::Class
|
21
|
+
fail ArgumentError, "no block given" unless block
|
22
|
+
|
23
|
+
MUTEX.synchronize do
|
24
|
+
(@__pending_refinements ||= []) << [klass, block]
|
25
|
+
end
|
26
|
+
__refine__(klass) { module_eval &block } if respond_to?(:__refine__, true)
|
27
|
+
|
28
|
+
self
|
29
|
+
end
|
30
|
+
target.send(:private, :refine)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.define_using(target)
|
34
|
+
target.send(:define_method, :using) do |mod|
|
35
|
+
refinements = mod.instance_variable_get(:@__pending_refinements)
|
36
|
+
|
37
|
+
if refinements && !refinements.empty?
|
38
|
+
MUTEX.synchronize do
|
39
|
+
refinements.delete_if do |klass, block|
|
40
|
+
klass.class_eval &block
|
41
|
+
true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Evaluate refinements from submodules recursively.
|
47
|
+
mod.included_modules.each do |submodule|
|
48
|
+
using submodule
|
49
|
+
end
|
50
|
+
|
51
|
+
self
|
52
|
+
end
|
53
|
+
target.send(:private, :using)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.alias_private_method(klass, new_name, old_name)
|
57
|
+
return if !klass.private_method_defined?(old_name) ||
|
58
|
+
klass.private_method_defined?(new_name)
|
59
|
+
|
60
|
+
klass.send(:alias_method, new_name, old_name)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
# If Module doesn't define method +using+, then refinements are apparently not
|
68
|
+
# supported on this platform, or running on MRI 2.0 that allows +using+ only on
|
69
|
+
# top-level. Since refinements in MRI 2.0 are experimental and behaves
|
70
|
+
# differently than in later versions, we use "faked refinements" even so.
|
71
|
+
unless Module.private_method_defined? :using
|
72
|
+
|
73
|
+
warn "corefines: Your Ruby doesn't support refinements, so I'll fake them \
|
74
|
+
using plain monkey-patching (not scoped!)."
|
75
|
+
|
76
|
+
m = Corefines::Support::FakeRefinements
|
77
|
+
|
78
|
+
# Define using on Module and the main object.
|
79
|
+
[Module, self.singleton_class].each do |klass|
|
80
|
+
m.alias_private_method(klass, :__using__, :using)
|
81
|
+
m.define_using(klass)
|
82
|
+
end
|
83
|
+
|
84
|
+
m.alias_private_method(Module, :__refine__, :refine)
|
85
|
+
m.define_refine(Module)
|
86
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'corefines/support/alias_submodules'
|
2
|
+
|
3
|
+
module Corefines
|
4
|
+
module Symbol
|
5
|
+
|
6
|
+
##
|
7
|
+
# @!method call(*args, &block)
|
8
|
+
# An useful extension for +&:symbol+ which makes it possible to pass
|
9
|
+
# arguments for method in a block
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# [1, 2, 3].map(&:to_s.(2)) #=> ['1', '10', '11']
|
13
|
+
# %w[Chloe Drew Uma].map(&:gsub.('e', 'E')) #=> %w[ChloE DrEw Uma]
|
14
|
+
#
|
15
|
+
# @param *args arguments being passed to the method.
|
16
|
+
# @param block a block being passed to the method.
|
17
|
+
# @return [Proc] a proc that invokes the method, identified by this
|
18
|
+
# symbol and passing it the given arguments, on an object passed to it.
|
19
|
+
#
|
20
|
+
module Call
|
21
|
+
refine ::Symbol do
|
22
|
+
def call(*args, &block)
|
23
|
+
proc do |recv|
|
24
|
+
recv.__send__(self, *args, &block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
include Support::AliasSubmodules
|
31
|
+
end
|
32
|
+
end
|
data/lib/corefines.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'corefines/version'
|
2
|
+
require 'corefines/support/fake_refinements'
|
3
|
+
|
4
|
+
# Refinements
|
5
|
+
require 'corefines/array'
|
6
|
+
require 'corefines/enumerable'
|
7
|
+
require 'corefines/hash'
|
8
|
+
require 'corefines/module'
|
9
|
+
require 'corefines/object'
|
10
|
+
require 'corefines/string'
|
11
|
+
require 'corefines/symbol'
|
12
|
+
|
13
|
+
# Provide an alternative, shorter, module name.
|
14
|
+
CF = Corefines unless defined? CF
|
@@ -0,0 +1,13 @@
|
|
1
|
+
describe Enumerable do
|
2
|
+
using Corefines::Enumerable::index_by
|
3
|
+
|
4
|
+
describe '#index_by' do
|
5
|
+
|
6
|
+
let(:input) { %w[alpha bee beta gamma] }
|
7
|
+
let(:expected) { {a: 'alpha', b: 'beta', g: 'gamma'} }
|
8
|
+
|
9
|
+
it "returns hash with the array's elements keyed be result of the block" do
|
10
|
+
expect(input.index_by { |s| s[0].to_sym }).to eq expected
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
describe Enumerable do
|
2
|
+
using Corefines::Enumerable::map_send
|
3
|
+
|
4
|
+
describe '#map_send' do
|
5
|
+
|
6
|
+
context Array do
|
7
|
+
it "sends a message to each element and collects the result" do
|
8
|
+
expect([1, 2, 3].map_send(:+, 3)).to eq [4, 5, 6]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context Hash do
|
13
|
+
it "sends a message to each element and collects the result" do
|
14
|
+
expect({a: 1, b: 2}.map_send(:at, 1)).to eq [1, 2]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context Set do
|
19
|
+
it "sends a message to each element and collects the result" do
|
20
|
+
expect(Set.new([1, 2, 3]).map_send(:+, 3)).to eq [4, 5, 6]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
describe Hash do
|
2
|
+
using Corefines::Hash::compact
|
3
|
+
|
4
|
+
let!(:original) { subject.dup }
|
5
|
+
|
6
|
+
describe '#compact' do
|
7
|
+
|
8
|
+
context "hash with some nil values" do
|
9
|
+
subject(:hash) { {a: true, b: false, c: nil, d: 'foo'} }
|
10
|
+
|
11
|
+
it "returns a new hash with no key-value pairs which value is nil" do
|
12
|
+
expect(hash.compact).to eq({a: true, b: false, d: 'foo'})
|
13
|
+
expect(hash).to eql original
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "hash with only nil values" do
|
18
|
+
subject(:hash) { {a: nil, b: nil} }
|
19
|
+
|
20
|
+
it "returns a new empty hash" do
|
21
|
+
expect(hash.compact).to be_empty
|
22
|
+
expect(hash).to eql original
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#compact!' do
|
28
|
+
|
29
|
+
context "hash with some nil values" do
|
30
|
+
subject(:hash) { {a: true, b: false, c: nil, d: 'foo'} }
|
31
|
+
let(:expected) { {a: true, b: false, d: 'foo'} }
|
32
|
+
|
33
|
+
it "removes key-value pairs which value is nil" do
|
34
|
+
expect(hash.compact!).to eq expected
|
35
|
+
expect(hash).to eq expected
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "hash with only nil values" do
|
40
|
+
subject(:hash) { {a: nil, b: nil} }
|
41
|
+
|
42
|
+
it "removes all key-value pairs" do
|
43
|
+
expect(hash.compact!).to be_empty
|
44
|
+
expect(hash).to be_empty
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
describe Hash do
|
2
|
+
using Corefines::Hash::rekey
|
3
|
+
|
4
|
+
let(:symbols) { {a: 1, b: 2, c: 3} }
|
5
|
+
let(:strings) { {'a' => 1, 'b' => 2, 'c' => 3} }
|
6
|
+
let(:mixed) { {'a' => 'foo', :b => 42, true => 66} }
|
7
|
+
let(:mixed_symbolized) { {:a => 'foo', :b => 42, true => 66} }
|
8
|
+
|
9
|
+
subject(:hash) { symbols }
|
10
|
+
let!(:original) { hash.dup }
|
11
|
+
|
12
|
+
|
13
|
+
describe '#rekey' do
|
14
|
+
|
15
|
+
context "with no arguments" do
|
16
|
+
subject(:hash) { mixed }
|
17
|
+
|
18
|
+
it "returns a new hash with symbolized keys" do
|
19
|
+
expect(hash.rekey).to eq mixed_symbolized
|
20
|
+
expect(hash).to eql original
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "with key_map" do
|
25
|
+
it "returns a new hash with translated keys" do
|
26
|
+
expect(hash.rekey(a: :x, c: 'y', d: 'z')).to eq({:x => 1, :b => 2, 'y' => 3})
|
27
|
+
expect(hash).to eql original
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "with block" do
|
32
|
+
it "yields key and value to the block" do
|
33
|
+
yielded = []
|
34
|
+
hash.rekey { |k, v| yielded << [k, v] }
|
35
|
+
expect(yielded).to eq [[:a, 1], [:b, 2], [:c, 3]]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "returns a new hash with transformed keys" do
|
39
|
+
expect(hash.rekey { |k| k.to_s }).to eq strings
|
40
|
+
expect(hash).to eql original
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "with symbol proc" do
|
45
|
+
it "returns a new hash with transformed keys" do
|
46
|
+
expect(hash.rekey(&:to_s)).to eq strings
|
47
|
+
expect(hash).to eql original
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "with both key_map and block" do
|
52
|
+
it { expect { hash.rekey(a: 'x') { |k| k.to_s } }.to raise_error ArgumentError }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
describe '#rekey!' do
|
58
|
+
|
59
|
+
context "with no arguments" do
|
60
|
+
subject(:hash) { mixed }
|
61
|
+
|
62
|
+
it "transforms keys to symbols and returns self" do
|
63
|
+
expect(hash.rekey!).to eq mixed_symbolized
|
64
|
+
expect(hash).to eq mixed_symbolized
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "with key_map" do
|
69
|
+
it "translates keys and returns self" do
|
70
|
+
expected = {:x => 1, :b => 2, 'y' => 3}
|
71
|
+
expect(hash.rekey!(a: :x, c: 'y', d: 'z')).to eq expected
|
72
|
+
expect(hash).to eq expected
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "with block" do
|
77
|
+
it "yields key and value to the block" do
|
78
|
+
yielded = []
|
79
|
+
hash.rekey! { |k, v| yielded << [k, v] }
|
80
|
+
expect(yielded).to eq [[:a, 1], [:b, 2], [:c, 3]]
|
81
|
+
end
|
82
|
+
|
83
|
+
it "transforms keys and returns self" do
|
84
|
+
expect(hash.rekey! { |k| k.to_s }).to eq strings
|
85
|
+
expect(hash).to eq strings
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "with symbol proc" do
|
90
|
+
it "transforms keys and returns self" do
|
91
|
+
expect(hash.rekey!(&:to_s)).to eq strings
|
92
|
+
expect(hash).to eq strings
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "with key_map and block" do
|
97
|
+
it { expect { hash.rekey!(a: 'x') { |k| k.to_s } }.to raise_error ArgumentError }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
describe Hash do
|
2
|
+
using Corefines::Hash::symbolize_keys
|
3
|
+
|
4
|
+
subject(:mixed) { {'a' => 'foo', :b => 42, true => 66} }
|
5
|
+
let(:symbolized) { {:a => 'foo', :b => 42, true => 66} }
|
6
|
+
let!(:original) { mixed.dup }
|
7
|
+
|
8
|
+
describe '#symbolize_keys' do
|
9
|
+
it "returns a new hash with keys converted to symbols" do
|
10
|
+
expect(mixed.symbolize_keys).to eq symbolized
|
11
|
+
expect(mixed).to eql original
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#symbolize_keys!' do
|
16
|
+
it "converts keys to symbols" do
|
17
|
+
expect(mixed.symbolize_keys!).to eq symbolized
|
18
|
+
expect(mixed).to eq symbolized
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
describe Module do
|
2
|
+
using Corefines::Module::alias_class_method
|
3
|
+
|
4
|
+
describe '#alias_class_method' do
|
5
|
+
|
6
|
+
subject :klass do
|
7
|
+
Class.new do
|
8
|
+
def self.salute
|
9
|
+
'Meow!'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it "defines new class method that calls the old class method" do
|
15
|
+
klass.alias_class_method :say_hello!, :salute
|
16
|
+
|
17
|
+
expect(klass).to respond_to :say_hello!
|
18
|
+
expect(klass.say_hello!).to eq klass.salute
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
describe Module do
|
2
|
+
using Corefines::Module::alias_method_chain
|
3
|
+
|
4
|
+
describe '#alias_method_chain' do
|
5
|
+
|
6
|
+
context "regular method" do
|
7
|
+
|
8
|
+
subject :obj do
|
9
|
+
Class.new {
|
10
|
+
def say; 'say' end
|
11
|
+
def say_with_accent; 'say_with_accent' end
|
12
|
+
alias_method_chain :say, :accent
|
13
|
+
}.new
|
14
|
+
end
|
15
|
+
|
16
|
+
it "defines method alias x_without_y -> x" do
|
17
|
+
expect(obj.say_without_accent).to eq 'say'
|
18
|
+
end
|
19
|
+
|
20
|
+
it "defines method alias x -> x_with_y" do
|
21
|
+
expect(obj.say).to eq 'say_with_accent'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "method with punctuation" do
|
26
|
+
|
27
|
+
subject :obj do
|
28
|
+
Class.new {
|
29
|
+
def say!; 'say!' end
|
30
|
+
def say_with_accent!; 'say_with_accent!' end
|
31
|
+
alias_method_chain :say!, :accent
|
32
|
+
}.new
|
33
|
+
end
|
34
|
+
|
35
|
+
it "defines method alias x_without_y! -> x!" do
|
36
|
+
expect(obj.say_without_accent!).to eq 'say!'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "defines method alias x! -> x_with_y!" do
|
40
|
+
expect(obj.say!).to eq 'say_with_accent!'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "feature with punctuation" do
|
45
|
+
|
46
|
+
subject :obj do
|
47
|
+
Class.new {
|
48
|
+
def say; 'say' end
|
49
|
+
def say_with_accent?; 'say_with_accent?' end
|
50
|
+
alias_method_chain :say, :accent?
|
51
|
+
}.new
|
52
|
+
end
|
53
|
+
|
54
|
+
it "defines method alias x_without_y? -> x" do
|
55
|
+
expect(obj.say_without_accent?).to eq 'say'
|
56
|
+
end
|
57
|
+
|
58
|
+
it "defines method alias x -> x_with_y?" do
|
59
|
+
expect(obj.say).to eq 'say_with_accent?'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
[:public, :protected, :private].each do |visibility|
|
65
|
+
it "preserves #{visibility} method visibility" do
|
66
|
+
klass = Class.new.class_eval <<-CLASS
|
67
|
+
def say; end
|
68
|
+
def say_with_accent; end
|
69
|
+
#{visibility} :say
|
70
|
+
alias_method_chain :say, :accent
|
71
|
+
CLASS
|
72
|
+
expect(klass.send("#{visibility}_method_defined?", :say)).to be true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
using Corefines::Object::blank?
|
3
|
+
|
4
|
+
describe Object do
|
5
|
+
let(:obj) { Object.new }
|
6
|
+
|
7
|
+
let :obj_empty do
|
8
|
+
Class.new { define_method(:empty?) { 0 } }.new
|
9
|
+
end
|
10
|
+
|
11
|
+
let :obj_not_empty do
|
12
|
+
Class.new { define_method(:empty?) { nil } }.new
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#blank?' do
|
16
|
+
it { expect(obj.blank?).to be false }
|
17
|
+
|
18
|
+
context "when object responds to #empty?" do
|
19
|
+
it "returns true when #empty? is truthy" do
|
20
|
+
expect(obj_empty.blank?).to be true
|
21
|
+
end
|
22
|
+
|
23
|
+
it "returns false when #empty? is falsy" do
|
24
|
+
expect(obj_not_empty.blank?).to be false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#presence' do
|
30
|
+
it { expect(obj.presence).to be obj }
|
31
|
+
|
32
|
+
context "when object responds to #empty?" do
|
33
|
+
it "returns nil when #empty? is truthy" do
|
34
|
+
expect(obj_empty.presence).to be nil
|
35
|
+
end
|
36
|
+
|
37
|
+
it "returns caller when #empty? is falsy" do
|
38
|
+
expect(obj_not_empty.presence).to be obj_not_empty
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe NilClass do
|
45
|
+
describe '#blank?' do
|
46
|
+
it { expect(nil.blank?).to be true }
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#presence' do
|
50
|
+
it { expect(nil.presence).to be_nil }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe FalseClass do
|
55
|
+
describe '#blank?' do
|
56
|
+
it { expect(false.blank?).to be true }
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#presence' do
|
60
|
+
it { expect(false.presence).to be_nil }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe TrueClass do
|
65
|
+
describe '#blank?' do
|
66
|
+
it { expect(true.blank?).to be false }
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#presence' do
|
70
|
+
it { expect(true.presence).to be true }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe Array do
|
75
|
+
describe '#blank?' do
|
76
|
+
it { expect([].blank?).to be true }
|
77
|
+
it { expect([1].blank?).to be false }
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '#presence' do
|
81
|
+
it { expect([].presence).to be_nil }
|
82
|
+
it { expect([1].presence).to eq [1] }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe Hash do
|
87
|
+
describe '#blank?' do
|
88
|
+
it { expect({}.blank?).to be true }
|
89
|
+
it { expect({x: 0}.blank?).to be false }
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#presence' do
|
93
|
+
it { expect({}.presence).to be_nil }
|
94
|
+
it { expect({x: 0}.presence).to eq({x: 0}) }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe Numeric do
|
99
|
+
[ 0, 1, 1.1 ].each do |val|
|
100
|
+
describe '#blank?' do
|
101
|
+
it { expect(val.blank?).to be false }
|
102
|
+
end
|
103
|
+
|
104
|
+
describe '#presence' do
|
105
|
+
it { expect(val.presence).to be val }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe String do
|
111
|
+
[ '', ' ', " \n\t \r ", ' ', "\u00a0" ].each do |val|
|
112
|
+
describe '#blank?' do
|
113
|
+
it { expect(val.blank?).to be true }
|
114
|
+
end
|
115
|
+
|
116
|
+
describe '#presence' do
|
117
|
+
it { expect(val.presence).to be_nil }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe '#blank?' do
|
122
|
+
it { expect('x'.blank?).to be false }
|
123
|
+
end
|
124
|
+
|
125
|
+
describe '#presence' do
|
126
|
+
it { expect('x'.presence).to eq 'x' }
|
127
|
+
end
|
128
|
+
end
|