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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.adoc +198 -0
  4. data/Rakefile +23 -0
  5. data/lib/corefines/array.rb +30 -0
  6. data/lib/corefines/enumerable.rb +64 -0
  7. data/lib/corefines/hash.rb +164 -0
  8. data/lib/corefines/module.rb +95 -0
  9. data/lib/corefines/object.rb +389 -0
  10. data/lib/corefines/string.rb +211 -0
  11. data/lib/corefines/support/alias_submodules.rb +103 -0
  12. data/lib/corefines/support/classes_including_module.rb +27 -0
  13. data/lib/corefines/support/fake_refinements.rb +86 -0
  14. data/lib/corefines/symbol.rb +32 -0
  15. data/lib/corefines/version.rb +3 -0
  16. data/lib/corefines.rb +14 -0
  17. data/spec/array/second_spec.rb +10 -0
  18. data/spec/array/third_spec.rb +10 -0
  19. data/spec/enumerable/index_by_spec.rb +13 -0
  20. data/spec/enumerable/map_send_spec.rb +24 -0
  21. data/spec/hash/compact_spec.rb +48 -0
  22. data/spec/hash/op_plus_spec.rb +11 -0
  23. data/spec/hash/rekey_spec.rb +100 -0
  24. data/spec/hash/symbolize_keys_spec.rb +21 -0
  25. data/spec/module/alias_class_method_spec.rb +21 -0
  26. data/spec/module/alias_method_chain_spec.rb +76 -0
  27. data/spec/object/blank_spec.rb +128 -0
  28. data/spec/object/deep_dup_spec.rb +61 -0
  29. data/spec/object/else_spec.rb +24 -0
  30. data/spec/object/in_spec.rb +21 -0
  31. data/spec/object/instance_values_spec.rb +22 -0
  32. data/spec/object/then_if_spec.rb +64 -0
  33. data/spec/object/then_spec.rb +26 -0
  34. data/spec/object/try_spec.rb +47 -0
  35. data/spec/spec_helper.rb +30 -0
  36. data/spec/string/color_spec.rb +82 -0
  37. data/spec/string/concat_spec.rb +36 -0
  38. data/spec/string/decolor_spec.rb +27 -0
  39. data/spec/string/remove_spec.rb +57 -0
  40. data/spec/string/unindent_spec.rb +66 -0
  41. data/spec/support/alias_submodules_spec.rb +83 -0
  42. data/spec/support/classes_including_module_spec.rb +35 -0
  43. data/spec/support/fake_refinements_spec.rb +118 -0
  44. data/spec/symbol/call_spec.rb +16 -0
  45. 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
@@ -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