corefines 1.0.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.
- 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
|