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,61 @@
|
|
1
|
+
describe Object do
|
2
|
+
using Corefines::Object::deep_dup
|
3
|
+
|
4
|
+
describe '#deep_dup' do
|
5
|
+
|
6
|
+
it "duplicates array and its values" do
|
7
|
+
ary = ['foo', 'bar']
|
8
|
+
dup = ary.deep_dup
|
9
|
+
dup[1].prepend('x')
|
10
|
+
|
11
|
+
expect(dup).to_not be ary
|
12
|
+
expect(ary[1]).to eq 'bar'
|
13
|
+
expect(dup[1]).to eq 'xbar'
|
14
|
+
end
|
15
|
+
|
16
|
+
it "duplicates values inside a nested array" do
|
17
|
+
ary = ['foo', ['bar', 'baz']]
|
18
|
+
dup = ary.deep_dup
|
19
|
+
dup[1][0].prepend('x')
|
20
|
+
|
21
|
+
expect(ary[1][0]).to eq 'bar'
|
22
|
+
expect(dup[1][0]).to eq 'xbar'
|
23
|
+
end
|
24
|
+
|
25
|
+
it "duplicates a nested hash" do
|
26
|
+
hash = {a: {b: 'b'}}
|
27
|
+
dup = hash.deep_dup
|
28
|
+
dup[:a][:c] = 'c'
|
29
|
+
|
30
|
+
expect(hash[:a][:c]).to be_nil
|
31
|
+
expect(dup[:a][:c]).to eq 'c'
|
32
|
+
end
|
33
|
+
|
34
|
+
it "duplicates an object" do
|
35
|
+
obj = ::Object.new
|
36
|
+
dup = obj.deep_dup
|
37
|
+
dup.instance_variable_set(:@a, 1)
|
38
|
+
|
39
|
+
expect(obj.instance_variable_defined? :@a).to be_falsy
|
40
|
+
expect(dup.instance_variable_defined? :@a).to be_truthy
|
41
|
+
end
|
42
|
+
|
43
|
+
it "calls #deep_dup on nested object when it responds to it" do
|
44
|
+
obj = Object.new.instance_eval do
|
45
|
+
def deep_dup; 'foo' end
|
46
|
+
self
|
47
|
+
end
|
48
|
+
ary = [1, obj]
|
49
|
+
dup = ary.deep_dup
|
50
|
+
|
51
|
+
expect(ary[1]).to eql obj
|
52
|
+
expect(dup[1]).to eq 'foo'
|
53
|
+
end
|
54
|
+
|
55
|
+
it "doesn't raise error for non-duplicable object" do
|
56
|
+
[nil, false, true, :foo, 1.0, method(:to_s)].each do |obj|
|
57
|
+
expect { obj.deep_dup }.to_not raise_error
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
describe Object do
|
2
|
+
using Corefines::Object::else
|
3
|
+
|
4
|
+
describe '#else' do
|
5
|
+
|
6
|
+
it "returns self without calling the block" do
|
7
|
+
obj = 'yay'
|
8
|
+
expect(obj.else { fail }).to eql obj
|
9
|
+
end
|
10
|
+
|
11
|
+
[ nil, false ].each do |val|
|
12
|
+
context "called on #{val.nil? ? 'nil' : val}" do
|
13
|
+
|
14
|
+
it "calls the block and returns result" do
|
15
|
+
expect(val.else { 42 }).to eq 42
|
16
|
+
end
|
17
|
+
|
18
|
+
it "passes self to the block" do
|
19
|
+
val.else { |x| expect(x).to eql val }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
describe Object do
|
2
|
+
using Corefines::Object::in?
|
3
|
+
|
4
|
+
describe '#in?' do
|
5
|
+
let(:other) { [] }
|
6
|
+
|
7
|
+
it "returns true when argument includes self" do
|
8
|
+
expect(other).to receive(:include?).with(42).and_return(true)
|
9
|
+
expect(42.in? other).to be true
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns false when argument doesn't include self" do
|
13
|
+
expect(other).to receive(:include?).with(66).and_return(false)
|
14
|
+
expect(66.in? other).to be false
|
15
|
+
end
|
16
|
+
|
17
|
+
it "raises ArgumentError when argument doesn't respond #include?" do
|
18
|
+
expect { 66.in? Object.new }.to raise_error ArgumentError
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
describe Object do
|
2
|
+
using Corefines::Object::instance_values
|
3
|
+
|
4
|
+
describe '#instance_values' do
|
5
|
+
let :obj do
|
6
|
+
Object.new.tap do |o|
|
7
|
+
o.instance_variable_set(:@foo, 'first')
|
8
|
+
o.instance_variable_set(:@bar, 'second')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns hash that maps instance variables to their values" do
|
13
|
+
expect(obj.instance_values).to eq({foo: 'first', bar: 'second'})
|
14
|
+
end
|
15
|
+
|
16
|
+
context "no instance variables" do
|
17
|
+
it "returns an empty array" do
|
18
|
+
expect(''.instance_values).to be_empty
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
describe Object do
|
2
|
+
using Corefines::Object::then_if
|
3
|
+
|
4
|
+
describe '#then_if' do
|
5
|
+
|
6
|
+
shared_examples 'conditions evaluates to true' do |*conditions|
|
7
|
+
it "yields self to the block and returns that block's value" do
|
8
|
+
expect('yay'.then_if(*conditions) { |x| x + '!' }).to eq 'yay!'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
shared_examples 'conditions evaluates to false' do |*conditions|
|
13
|
+
it "returns self without calling the block" do
|
14
|
+
obj = 'yay'
|
15
|
+
expect(obj.then_if(*conditions) { fail 'block should not be called' }).to eql obj
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
context "no conditions given" do
|
21
|
+
|
22
|
+
context "and self evaluates to true" do
|
23
|
+
it_behaves_like 'conditions evaluates to true'
|
24
|
+
end
|
25
|
+
|
26
|
+
context "and self evaluates to false" do
|
27
|
+
[ false, nil ].each do |val|
|
28
|
+
it "returns self without calling the block" do
|
29
|
+
expect(val.then_if { fail 'block should not be called' }).to eql val
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
[ :ascii_only?, [:start_with?, 'y'], ->(x) { x.start_with? 'y' },
|
36
|
+
:ascii_only?.to_proc, true, 'foo'
|
37
|
+
].each do |condition|
|
38
|
+
context "with #{condition.class} condition" do
|
39
|
+
include_examples 'conditions evaluates to true', condition
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
[ :empty?, [:start_with?, 'x'], ->(x) { x.start_with? 'x' },
|
44
|
+
:empty?.to_proc, false, nil
|
45
|
+
].each do |condition|
|
46
|
+
context "with #{condition.class} condition that evaluates to true" do
|
47
|
+
include_examples 'conditions evaluates to false', condition
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "with multiple conditions" do
|
52
|
+
|
53
|
+
context "all evaluates to true" do
|
54
|
+
conditions = [ true, [:start_with?, 'y'], :ascii_only? ]
|
55
|
+
include_examples 'conditions evaluates to true', *conditions
|
56
|
+
end
|
57
|
+
|
58
|
+
context "one evaluates to false" do
|
59
|
+
conditions = [ true, [:start_with?, 'y'], false, :ascii_only? ]
|
60
|
+
include_examples 'conditions evaluates to false', *conditions
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
describe Object do
|
2
|
+
using Corefines::Object::then
|
3
|
+
|
4
|
+
describe '#then' do
|
5
|
+
|
6
|
+
it "calls the block and returns result" do
|
7
|
+
expect('yay'.then { 42 }).to eq 42
|
8
|
+
end
|
9
|
+
|
10
|
+
it "passes self to the block" do
|
11
|
+
'yay'.then { |x| expect(x).to eq 'yay' }
|
12
|
+
end
|
13
|
+
|
14
|
+
context "called on nil" do
|
15
|
+
it "returns nil without calling the block" do
|
16
|
+
expect(nil.then { fail }).to be_nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "called on false" do
|
21
|
+
it "returns false without calling the block" do
|
22
|
+
expect(false.then { fail }).to be false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
describe Object do
|
2
|
+
using Corefines::Object::try
|
3
|
+
|
4
|
+
let(:str) { "allons-y!" }
|
5
|
+
|
6
|
+
describe '#try' do
|
7
|
+
context "non-existing method" do
|
8
|
+
it "returns nil" do
|
9
|
+
expect(str.try(:non_existing_method)).to be_nil
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context "valid method" do
|
14
|
+
it "calls and returns the result" do
|
15
|
+
expect(str.try(:upcase)).to eq "ALLONS-Y!"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "forwards arguments" do
|
19
|
+
expect(str.try(:sub, '!', '?')).to eq "allons-y?"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "forwards block" do
|
23
|
+
expect(str.try(:sub, '!') { |m| '?' }).to eq "allons-y?"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "on nil" do
|
28
|
+
it "returns nil" do
|
29
|
+
expect(nil.try(:upcase)).to be_nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "on false" do
|
34
|
+
it "calls and returns the result" do
|
35
|
+
expect(false.try(:to_s)).to eq 'false'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#try!' do
|
41
|
+
context "non-existing method" do
|
42
|
+
it "raises NoMethodError" do
|
43
|
+
expect { str.try!(:non_existing_method) }.to raise_error NoMethodError
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'corefines'
|
3
|
+
|
4
|
+
RSpec.configure do |config|
|
5
|
+
|
6
|
+
# rspec-expectations config
|
7
|
+
config.expect_with :rspec do |expects|
|
8
|
+
|
9
|
+
# This option disables deprecated 'should' syntax.
|
10
|
+
expects.syntax = :expect
|
11
|
+
|
12
|
+
# This option makes the +description+ and +failure_message+ of custom
|
13
|
+
# matchers include text for helper methods defined using +chain+, e.g.:
|
14
|
+
# be_bigger_than(2).and_smaller_than(4).description
|
15
|
+
# # => "be bigger than 2 and smaller than 4"
|
16
|
+
# ...rather than:
|
17
|
+
# # => "be bigger than 2"
|
18
|
+
expects.include_chain_clauses_in_custom_matcher_descriptions = true
|
19
|
+
end
|
20
|
+
|
21
|
+
# rspec-mocks config
|
22
|
+
config.mock_with :rspec do |mocks|
|
23
|
+
|
24
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
25
|
+
# a real object.
|
26
|
+
mocks.verify_partial_doubles = true
|
27
|
+
end
|
28
|
+
|
29
|
+
config.color = true
|
30
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
describe String do
|
2
|
+
using Corefines::String::color
|
3
|
+
|
4
|
+
describe '#color' do
|
5
|
+
|
6
|
+
shared_examples :defaults do |opts|
|
7
|
+
it "returns text with the default mode, foreground and background colors" do
|
8
|
+
expect(text.color(opts)).to eq "\e[0;39;49m#{text}\e[0m"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
subject(:text) { "This is\nsome text" }
|
13
|
+
|
14
|
+
context Symbol do
|
15
|
+
it "returns text with the specified foreground color" do
|
16
|
+
expect(text.color(:blue)).to eq "\e[0;34;49m#{text}\e[0m"
|
17
|
+
end
|
18
|
+
|
19
|
+
context "unknown color name" do
|
20
|
+
include_examples :defaults, :foo
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context Fixnum do
|
25
|
+
it "returns text with the specified foreground color" do
|
26
|
+
expect(text.color(7)).to eq "\e[0;37;49m#{text}\e[0m"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context Hash do
|
31
|
+
|
32
|
+
context "empty" do
|
33
|
+
include_examples :defaults, {}
|
34
|
+
end
|
35
|
+
|
36
|
+
context "with unknown mode and color names" do
|
37
|
+
include_examples :defaults, {mode: :foo, text: :foo, background: :foo}
|
38
|
+
end
|
39
|
+
|
40
|
+
context "with valid options" do
|
41
|
+
it "returns text with the specified mode" do
|
42
|
+
[:bold, 1].each do |mode|
|
43
|
+
expect(text.color(mode: mode)).to eq "\e[1;39;49m#{text}\e[0m"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "returns text with the specified foreground color" do
|
48
|
+
[:red, 1].each do |color|
|
49
|
+
expect(text.color(text: color)).to eq "\e[0;31;49m#{text}\e[0m"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it "returns text with the specified background color" do
|
54
|
+
[:green, 2].each do |color|
|
55
|
+
expect(text.color(background: color)).to eq "\e[0;39;42m#{text}\e[0m"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it "returns text with the specified mode, foreground and background colors" do
|
60
|
+
expect(text.color(mode: :bold, text: :blue, background: :yellow)).to eq "\e[1;34;43m#{text}\e[0m"
|
61
|
+
expect(text.color(mode: 1, text: 4, background: 3)).to eq "\e[1;34;43m#{text}\e[0m"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "already colored text" do
|
67
|
+
it "changes specified and preserves unspecified attributes" do
|
68
|
+
expect("\e[1;34;42m#{text}\e[0m".color(text: :red)).to eq "\e[1;31;42m#{text}\e[0m"
|
69
|
+
end
|
70
|
+
|
71
|
+
it "doesn't change invalidly specified attributes" do
|
72
|
+
expect("\e[1;34;42m#{text}\e[0m".color(text: :foo)).to eq "\e[1;34;42m#{text}\e[0m"
|
73
|
+
end
|
74
|
+
|
75
|
+
it "changes multiple escape sequences" do
|
76
|
+
text = 'none' + 'red'.color(:red) + 'none' + 'blue'.color(:blue) + 'none'
|
77
|
+
expected = "\e[0;39;42mnone\e[0m\e[0;31;42mred\e[0m\e[0;39;42mnone\e[0m\e[0;34;42mblue\e[0m\e[0;39;42mnone\e[0m"
|
78
|
+
expect(text.color(background: :green)).to eq expected
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
describe String do
|
2
|
+
using Corefines::String::concat!
|
3
|
+
|
4
|
+
describe '#concat!' do
|
5
|
+
|
6
|
+
context "without separator" do
|
7
|
+
subject { 'foo' }
|
8
|
+
|
9
|
+
it "appends the given string to self" do
|
10
|
+
subject.concat! 'bar'
|
11
|
+
is_expected.to eq 'foobar'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "with separator" do
|
16
|
+
|
17
|
+
context "when self is empty" do
|
18
|
+
subject { '' }
|
19
|
+
|
20
|
+
it "appends the given string to self" do
|
21
|
+
subject.concat! 'bar', "\n"
|
22
|
+
is_expected.to eq 'bar'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when self is not empty" do
|
27
|
+
subject { 'foo' }
|
28
|
+
|
29
|
+
it "appends the given separator and string to self" do
|
30
|
+
subject.concat! 'bar', "\n"
|
31
|
+
is_expected.to eq "foo\nbar"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
describe String do
|
2
|
+
using Corefines::String::decolor
|
3
|
+
|
4
|
+
describe '#decolor' do
|
5
|
+
|
6
|
+
subject(:text) { "This is\nsome text" }
|
7
|
+
|
8
|
+
context "colored text" do
|
9
|
+
it "strips ANSI escape sequence" do
|
10
|
+
expect("\e[1;34;42m#{text}\e[0m".decolor).to eq text
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "concatenated colored texts" do
|
15
|
+
it "strips all ANSI escape sequences" do
|
16
|
+
text = "\e[0;39;42mSome\ncolored\e[0m\e[0;31;42m text\e[0m"
|
17
|
+
expect(text.decolor).to eq "Some\ncolored text"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "plain string" do
|
22
|
+
it "passes without change" do
|
23
|
+
expect(text.decolor).to eq text
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
describe String do
|
2
|
+
using Corefines::String::remove
|
3
|
+
|
4
|
+
subject(:str) { "This is a good day to die" }
|
5
|
+
let!(:original) { str.dup }
|
6
|
+
|
7
|
+
describe '#remove' do
|
8
|
+
|
9
|
+
context "string" do
|
10
|
+
it "returns a new string with occurrences of the pattern removed" do
|
11
|
+
expect(str.remove(" to die")).to eq "This is a good day"
|
12
|
+
expect(str.remove("is")).to eq "Th a good day to die"
|
13
|
+
expect(str).to eq original
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "regexp" do
|
18
|
+
it "returns a new string with occurrences of the pattern removed" do
|
19
|
+
expect(str.remove(/\s*to.*$/)).to eq "This is a good day"
|
20
|
+
expect(str.remove(/\s/)).to eq "Thisisagooddaytodie"
|
21
|
+
expect(str).to eq original
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "multiple patterns" do
|
26
|
+
it "returns a new string with occurrences of the patterns removed" do
|
27
|
+
expect(str.remove("to die", /\s*$/)).to eq "This is a good day"
|
28
|
+
expect(str.remove("to", "die", /\s*/)).to eq "Thisisagoodday"
|
29
|
+
expect(str).to eq original
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#remove!' do
|
35
|
+
|
36
|
+
context "string" do
|
37
|
+
it "removes occurrences of the pattern and returns self" do
|
38
|
+
expect(str.remove!(" to die")).to eq "This is a good day"
|
39
|
+
expect(str.remove!("is")).to eq "Th a good day"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "regexp" do
|
44
|
+
it "removes occurrences of the pattern and returns self" do
|
45
|
+
expect(str.remove!(/\s*to.*$/)).to eq "This is a good day"
|
46
|
+
expect(str.remove!(/\s/)).to eq "Thisisagoodday"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "multiple patterns" do
|
51
|
+
it "removes occurrences of the patterns and returns self" do
|
52
|
+
expect(str.remove!("to die", /\s*$/)).to eq "This is a good day"
|
53
|
+
expect(str.remove!("to", "die", /\s*/)).to eq "Thisisagoodday"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
describe String do
|
2
|
+
using Corefines::String::unindent
|
3
|
+
|
4
|
+
describe '#unindent' do
|
5
|
+
|
6
|
+
context "single-line" do
|
7
|
+
|
8
|
+
it "removes space indentation" do
|
9
|
+
expect(" abc".unindent).to eq 'abc'
|
10
|
+
end
|
11
|
+
|
12
|
+
it "removes tab indentation" do
|
13
|
+
expect("\tabc".unindent).to eq 'abc'
|
14
|
+
end
|
15
|
+
|
16
|
+
it "removes mixed space and tab indentation" do
|
17
|
+
expect("\t\s\t\sabc".unindent).to eq 'abc'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "multi-line" do
|
22
|
+
|
23
|
+
it "removes indentation" do
|
24
|
+
expect(" abc\n abc".unindent).to eq "abc\nabc"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "keeps relative indentation" do
|
28
|
+
expect(" abc\n abc".unindent).to eq " abc\nabc"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "ignores blank lines for indent calculation" do
|
32
|
+
expect("\n\tabc\n\n\t\tabc\n".unindent).to eq "\nabc\n\n\tabc\n"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "unindents more complex input" do
|
36
|
+
input = <<-EOF
|
37
|
+
module WishScanner
|
38
|
+
|
39
|
+
def scan_for_a_wish
|
40
|
+
wish = self.read.detect do |thought|
|
41
|
+
thought.index('wish: ') == 0
|
42
|
+
end
|
43
|
+
|
44
|
+
wish.gsub('wish: ', '')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
EOF
|
48
|
+
|
49
|
+
expected = <<-EOF
|
50
|
+
module WishScanner
|
51
|
+
|
52
|
+
def scan_for_a_wish
|
53
|
+
wish = self.read.detect do |thought|
|
54
|
+
thought.index('wish: ') == 0
|
55
|
+
end
|
56
|
+
|
57
|
+
wish.gsub('wish: ', '')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
EOF
|
61
|
+
|
62
|
+
expect(input.unindent).to eq expected
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
describe Corefines::Support::AliasSubmodules do
|
2
|
+
|
3
|
+
before :context do
|
4
|
+
# Define dynamically to not pollute global context of other tests.
|
5
|
+
ModuleX = Module.new.tap do |m|
|
6
|
+
m.class_eval <<-CODE
|
7
|
+
Something = 66
|
8
|
+
module Indent end
|
9
|
+
module StripHeredoc end
|
10
|
+
module Blank end
|
11
|
+
include Corefines::Support::AliasSubmodules
|
12
|
+
CODE
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
after :context do
|
17
|
+
Object.send(:remove_const, :ModuleX)
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
describe '.included' do
|
22
|
+
|
23
|
+
subject(:target) { ModuleX }
|
24
|
+
|
25
|
+
it 'defines method-named "alias" for each submodule' do
|
26
|
+
expect(ModuleX.indent).to eql ModuleX::Indent
|
27
|
+
expect(ModuleX::strip_heredoc).to eql ModuleX::StripHeredoc
|
28
|
+
end
|
29
|
+
|
30
|
+
it "ignores constants that are not modules" do
|
31
|
+
is_expected.to_not respond_to :something
|
32
|
+
end
|
33
|
+
|
34
|
+
it "includes all submodules into the target" do
|
35
|
+
is_expected.to include ModuleX::Indent, ModuleX::StripHeredoc
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
describe '.[]' do
|
41
|
+
subject { ModuleX[:indent, :strip_heredoc] }
|
42
|
+
|
43
|
+
it "returns module that includes the named modules" do
|
44
|
+
is_expected.to be_instance_of ::Module
|
45
|
+
is_expected.to include ModuleX::Indent, ModuleX::StripHeredoc
|
46
|
+
is_expected.to_not include ModuleX::Blank
|
47
|
+
end
|
48
|
+
|
49
|
+
it "raises ArgumentError if any submodule alias doesn't exist" do
|
50
|
+
expect { ModuleX[:indent, :invalid] }.to raise_error ArgumentError
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
describe '.method_name' do
|
56
|
+
|
57
|
+
def method_name(str)
|
58
|
+
described_class.send(:method_name, str)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "string without any uppercase returns untouched" do
|
62
|
+
str = 'allonsy!'
|
63
|
+
expect(method_name str).to eql str
|
64
|
+
end
|
65
|
+
|
66
|
+
{
|
67
|
+
'Unindent' => 'unindent',
|
68
|
+
'StripHeredoc' => 'strip_heredoc',
|
69
|
+
'ToJSON' => 'to_json',
|
70
|
+
}.merge(described_class.const_get(:OPERATORS_MAP)).each do |input, expected|
|
71
|
+
|
72
|
+
it "converts '#{input}' to '#{expected}'" do
|
73
|
+
input_clone = input.to_s.dup
|
74
|
+
expect(method_name input).to eq expected
|
75
|
+
expect(input.to_s).to eql input_clone
|
76
|
+
end
|
77
|
+
|
78
|
+
it "converts :#{input} to '#{expected}'" do
|
79
|
+
expect(method_name input.to_sym).to eq expected
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'corefines/support/classes_including_module'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
describe Corefines::Support do
|
5
|
+
|
6
|
+
describe '.classes_including_module' do
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_delegator :described_class, :classes_including_module
|
10
|
+
|
11
|
+
before :context do
|
12
|
+
ModuleX, ModuleY = Module.new, Module.new
|
13
|
+
ClassA, ClassB = Class.new, Class.new(Array)
|
14
|
+
[ClassA, ClassB].each { |m| m.send(:include, ModuleX) }
|
15
|
+
end
|
16
|
+
|
17
|
+
after :context do
|
18
|
+
[:ModuleX, :ModuleY, :ClassA, :ClassB].each do |name|
|
19
|
+
Object.send(:remove_const, name)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "yields classes that includes the module" do
|
24
|
+
actual = []
|
25
|
+
classes_including_module(ModuleX) { |c| actual << c }
|
26
|
+
expect(actual).to contain_exactly ClassA, ClassB
|
27
|
+
end
|
28
|
+
|
29
|
+
it "yields nothing for module that isn't included anywhere" do
|
30
|
+
actual = []
|
31
|
+
classes_including_module(ModuleY) { |c| actual << c }
|
32
|
+
expect(actual).to be_empty
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|