mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Update to ruby/spec@a6b8805
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60525 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
6530b14cee
commit
8c5b60eb22
218 changed files with 4069 additions and 328 deletions
|
@ -7,13 +7,28 @@ AllCops:
|
||||||
- command_line/fixtures/bad_syntax.rb
|
- command_line/fixtures/bad_syntax.rb
|
||||||
DisabledByDefault: true
|
DisabledByDefault: true
|
||||||
|
|
||||||
|
Layout/TrailingWhitespace:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
Lint:
|
Lint:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
|
|
||||||
Lint/AssignmentInCondition:
|
Lint/AssignmentInCondition:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Lint/LiteralInCondition:
|
Lint/BooleanSymbol:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Lint/InterpolationCheck:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Lint/LiteralAsCondition:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Lint/UnneededRequireStatement:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Lint/RescueWithoutErrorClass:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Lint/UnifiedInteger:
|
Lint/UnifiedInteger:
|
||||||
|
@ -38,3 +53,7 @@ Lint/Void:
|
||||||
Lint/EmptyExpression:
|
Lint/EmptyExpression:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'language/**/*.rb'
|
- 'language/**/*.rb'
|
||||||
|
|
||||||
|
Lint/UriRegexp:
|
||||||
|
Exclude:
|
||||||
|
- 'library/uri/regexp_spec.rb'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# This configuration was generated by
|
# This configuration was generated by
|
||||||
# `rubocop --auto-gen-config`
|
# `rubocop --auto-gen-config`
|
||||||
# on 2017-06-18 19:12:38 +0200 using RuboCop version 0.49.1.
|
# on 2017-10-09 20:22:01 +0200 using RuboCop version 0.50.0.
|
||||||
# The point is for the user to remove these configuration records
|
# The point is for the user to remove these configuration records
|
||||||
# one by one as the offenses are removed from the code base.
|
# one by one as the offenses are removed from the code base.
|
||||||
# Note that changes in the inspected code, or installation of new
|
# Note that changes in the inspected code, or installation of new
|
||||||
|
@ -52,7 +52,7 @@ Lint/FloatOutOfRange:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'core/string/modulo_spec.rb'
|
- 'core/string/modulo_spec.rb'
|
||||||
|
|
||||||
# Offense count: 46
|
# Offense count: 43
|
||||||
Lint/FormatParameterMismatch:
|
Lint/FormatParameterMismatch:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'core/kernel/sprintf_spec.rb'
|
- 'core/kernel/sprintf_spec.rb'
|
||||||
|
@ -137,6 +137,7 @@ Lint/RescueException:
|
||||||
- 'library/erb/filename_spec.rb'
|
- 'library/erb/filename_spec.rb'
|
||||||
|
|
||||||
# Offense count: 1
|
# Offense count: 1
|
||||||
|
# Cop supports --auto-correct.
|
||||||
Lint/ScriptPermission:
|
Lint/ScriptPermission:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'command_line/fixtures/bin/launcher.rb'
|
- 'command_line/fixtures/bin/launcher.rb'
|
||||||
|
@ -181,7 +182,7 @@ Lint/UnneededSplatExpansion:
|
||||||
- 'language/send_spec.rb'
|
- 'language/send_spec.rb'
|
||||||
- 'language/variables_spec.rb'
|
- 'language/variables_spec.rb'
|
||||||
|
|
||||||
# Offense count: 53
|
# Offense count: 55
|
||||||
Lint/UnreachableCode:
|
Lint/UnreachableCode:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'core/enumerator/lazy/fixtures/classes.rb'
|
- 'core/enumerator/lazy/fixtures/classes.rb'
|
||||||
|
@ -198,7 +199,7 @@ Lint/UnreachableCode:
|
||||||
- 'optional/capi/kernel_spec.rb'
|
- 'optional/capi/kernel_spec.rb'
|
||||||
- 'shared/kernel/raise.rb'
|
- 'shared/kernel/raise.rb'
|
||||||
|
|
||||||
# Offense count: 9
|
# Offense count: 7
|
||||||
# Configuration parameters: ContextCreatingMethods, MethodCreatingMethods.
|
# Configuration parameters: ContextCreatingMethods, MethodCreatingMethods.
|
||||||
Lint/UselessAccessModifier:
|
Lint/UselessAccessModifier:
|
||||||
Exclude:
|
Exclude:
|
||||||
|
@ -206,6 +207,4 @@ Lint/UselessAccessModifier:
|
||||||
- 'core/module/fixtures/classes.rb'
|
- 'core/module/fixtures/classes.rb'
|
||||||
- 'core/module/module_function_spec.rb'
|
- 'core/module/module_function_spec.rb'
|
||||||
- 'core/module/private_class_method_spec.rb'
|
- 'core/module/private_class_method_spec.rb'
|
||||||
- 'core/module/private_spec.rb'
|
- 'language/fixtures/send.rb'
|
||||||
- 'core/module/protected_spec.rb'
|
|
||||||
- 'core/module/public_spec.rb'
|
|
||||||
|
|
|
@ -3,21 +3,23 @@ language: ruby
|
||||||
install:
|
install:
|
||||||
- git clone https://github.com/ruby/mspec.git ../mspec
|
- git clone https://github.com/ruby/mspec.git ../mspec
|
||||||
script:
|
script:
|
||||||
- if [ -n "$RUBOCOP" ]; then gem install rubocop -v 0.49.1 && rubocop; fi
|
- if [ -n "$RUBOCOP" ]; then gem install rubocop -v 0.51.0 && rubocop; fi
|
||||||
- ../mspec/bin/mspec $MSPEC_OPTS
|
- ../mspec/bin/mspec $MSPEC_OPTS
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: osx
|
- os: osx
|
||||||
rvm: 2.4.0
|
osx_image: xcode9
|
||||||
|
rvm: 2.4.2
|
||||||
|
env: CHECK_LEAKS=true
|
||||||
- os: linux
|
- os: linux
|
||||||
rvm: 2.4.1
|
rvm: 2.4.2
|
||||||
env: MSPEC_OPTS="-R2 -ff"
|
env: MSPEC_OPTS="-R2 -ff"
|
||||||
- os: linux
|
- os: linux
|
||||||
rvm: 2.2.7
|
rvm: 2.2.8
|
||||||
- os: linux
|
- os: linux
|
||||||
rvm: 2.3.4
|
rvm: 2.3.5
|
||||||
- os: linux
|
- os: linux
|
||||||
rvm: 2.4.1
|
rvm: 2.4.2
|
||||||
env: CHECK_LEAKS=true RUBOCOP=true
|
env: CHECK_LEAKS=true RUBOCOP=true
|
||||||
- os: linux
|
- os: linux
|
||||||
rvm: ruby-head
|
rvm: ruby-head
|
||||||
|
|
|
@ -48,9 +48,116 @@ You might also want to search for:
|
||||||
|
|
||||||
which indicates the file was generated but the method unspecified.
|
which indicates the file was generated but the method unspecified.
|
||||||
|
|
||||||
|
### Matchers and expectations
|
||||||
|
|
||||||
|
Here is a list of frequently-used matchers, which should be enough for most specs.
|
||||||
|
There are a few extra specific matchers used in the couple specs that need it.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
(1 + 2).should == 3 # Calls #==
|
||||||
|
(1 + 2).should_not == 5
|
||||||
|
|
||||||
|
File.should equal(File) # Calls #equal? (tests identity)
|
||||||
|
(1 + 2).should eql(3) # Calls #eql? (Hash equality)
|
||||||
|
|
||||||
|
1.should < 2
|
||||||
|
2.should <= 2
|
||||||
|
3.should >= 3
|
||||||
|
4.should > 3
|
||||||
|
|
||||||
|
"Hello".should =~ /l{2}/ # Calls #=~ (Regexp match)
|
||||||
|
|
||||||
|
[].should be_empty # Calls #empty?
|
||||||
|
[1,2,3].should include(2) # Calls #include?
|
||||||
|
|
||||||
|
(0.1 + 0.2).should be_close(0.3, TOLERANCE) # (0.2-0.1).abs < TOLERANCE
|
||||||
|
(0.0/0.0).should be_nan # Calls Float#nan?
|
||||||
|
(1.0/0.0).should be_positive_infinity
|
||||||
|
(-1.0/0.0).should be_negative_infinity
|
||||||
|
|
||||||
|
3.14.should be_an_instance_of(Float) # Calls #instance_of?
|
||||||
|
3.14.should be_kind_of(Numeric) # Calls #is_a?
|
||||||
|
Numeric.should be_ancestor_of(Float) # Float.ancestors.include?(Numeric)
|
||||||
|
|
||||||
|
3.14.should respond_to(:to_i) # Calls #respond_to?
|
||||||
|
Fixnum.should have_instance_method(:+)
|
||||||
|
Array.should have_method(:new)
|
||||||
|
# Also have_constant, have_private_instance_method, have_singleton_method, etc
|
||||||
|
|
||||||
|
-> {
|
||||||
|
raise "oops"
|
||||||
|
}.should raise_error(RuntimeError, /oops/)
|
||||||
|
|
||||||
|
# To avoid! Instead, use an expectation testing what the code in the lambda does.
|
||||||
|
# If an exception is raised, it will fail the example anyway.
|
||||||
|
-> { ... }.should_not raise_error
|
||||||
|
|
||||||
|
-> {
|
||||||
|
Fixnum
|
||||||
|
}.should complain(/constant ::Fixnum is deprecated/) # Expect a warning
|
||||||
|
```
|
||||||
|
|
||||||
### Guards
|
### Guards
|
||||||
|
|
||||||
Different guards are available as defined by mspec.
|
Different guards are available as defined by mspec.
|
||||||
|
Here is a list of the most commonly-used guards:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
ruby_version_is ""..."2.4" do
|
||||||
|
# Specs for RUBY_VERSION < 2.4
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
# Specs for RUBY_VERSION >= 2.4
|
||||||
|
end
|
||||||
|
|
||||||
|
platform_is :windows do
|
||||||
|
# Specs only valid on Windows
|
||||||
|
end
|
||||||
|
|
||||||
|
platform_is_not :windows do
|
||||||
|
# Specs valid on platforms other than Windows
|
||||||
|
end
|
||||||
|
|
||||||
|
platform_is :linux, :darwin do # OR
|
||||||
|
end
|
||||||
|
|
||||||
|
platform_is_not :linux, :darwin do # Not Linux and not Darwin
|
||||||
|
end
|
||||||
|
|
||||||
|
platform_is wordsize: 64 do
|
||||||
|
# 64-bit platform
|
||||||
|
end
|
||||||
|
|
||||||
|
big_endian do
|
||||||
|
# Big-endian platform
|
||||||
|
end
|
||||||
|
|
||||||
|
# In case there is a bug in MRI but the expected behavior is obvious
|
||||||
|
# First file a bug at https://bugs.ruby-lang.org/
|
||||||
|
# It is better to use a ruby_version_is guard if there was a release with the fix
|
||||||
|
ruby_bug '#13669', ''...'2.5' do
|
||||||
|
it "works like this" do
|
||||||
|
# Specify the expected behavior here, not the bug
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Combining guards
|
||||||
|
guard -> { platform_is :windows and ruby_version_is ""..."2.3" } do
|
||||||
|
# Windows and RUBY_VERSION < 2.3
|
||||||
|
end
|
||||||
|
|
||||||
|
guard_not -> { platform_is :windows and ruby_version_is ""..."2.3" } do
|
||||||
|
# The opposite
|
||||||
|
end
|
||||||
|
|
||||||
|
# Custom guard
|
||||||
|
max_uint = (1 << 32) - 1
|
||||||
|
guard -> { max_uint <= fixnum_max } do
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
In general, the usage of guards should be minimized as possible.
|
In general, the usage of guards should be minimized as possible.
|
||||||
|
|
||||||
There are no guards to define implementation-specific behavior because
|
There are no guards to define implementation-specific behavior because
|
||||||
|
|
|
@ -15,7 +15,7 @@ describe "Array#at" do
|
||||||
a.at(7).should == nil
|
a.at(7).should == nil
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns the (-n)'th elemet from the last, for the given negative index n" do
|
it "returns the (-n)'th element from the last, for the given negative index n" do
|
||||||
a = [1, 2, 3, 4, 5, 6]
|
a = [1, 2, 3, 4, 5, 6]
|
||||||
a.at(-1).should == 6
|
a.at(-1).should == 6
|
||||||
a.at(-2).should == 5
|
a.at(-2).should == 5
|
||||||
|
@ -50,7 +50,7 @@ describe "Array#at" do
|
||||||
lambda { [].at("cat") }.should raise_error(TypeError)
|
lambda { [].at("cat") }.should raise_error(TypeError)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises an ArgumentError when 2 or more arguments is passed" do
|
it "raises an ArgumentError when 2 or more arguments are passed" do
|
||||||
lambda { [:a, :b].at(0,1) }.should raise_error(ArgumentError)
|
lambda { [:a, :b].at(0,1) }.should raise_error(ArgumentError)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,7 +19,7 @@ describe "Array#&" do
|
||||||
|
|
||||||
it "does not modify the original Array" do
|
it "does not modify the original Array" do
|
||||||
a = [1, 1, 3, 5]
|
a = [1, 1, 3, 5]
|
||||||
a & [1, 2, 3]
|
(a & [1, 2, 3]).should == [1, 3]
|
||||||
a.should == [1, 1, 3, 5]
|
a.should == [1, 1, 3, 5]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ describe "Array#&" do
|
||||||
obj1.stub!(:hash).and_return(0)
|
obj1.stub!(:hash).and_return(0)
|
||||||
obj2.stub!(:hash).and_return(0)
|
obj2.stub!(:hash).and_return(0)
|
||||||
obj1.should_receive(:eql?).at_least(1).and_return(true)
|
obj1.should_receive(:eql?).at_least(1).and_return(true)
|
||||||
obj2.should_receive(:eql?).at_least(1).and_return(true)
|
obj2.stub!(:eql?).and_return(true)
|
||||||
|
|
||||||
([obj1] & [obj2]).should == [obj1]
|
([obj1] & [obj2]).should == [obj1]
|
||||||
([obj1, obj1, obj2, obj2] & [obj2]).should == [obj1]
|
([obj1, obj1, obj2, obj2] & [obj2]).should == [obj1]
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
require File.expand_path('../../../spec_helper', __FILE__)
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
describe "Array#max" do
|
describe "Array#max" do
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
it "is defined on Array" do
|
||||||
|
[1].method(:max).owner.should equal Array
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "returns nil with no values" do
|
it "returns nil with no values" do
|
||||||
[].max.should == nil
|
[].max.should == nil
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
require File.expand_path('../../../spec_helper', __FILE__)
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
describe "Array#min" do
|
describe "Array#min" do
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
it "is defined on Array" do
|
||||||
|
[1].method(:max).owner.should equal Array
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "returns nil with no values" do
|
it "returns nil with no values" do
|
||||||
[].min.should == nil
|
[].min.should == nil
|
||||||
end
|
end
|
||||||
|
|
52
spec/ruby/core/array/pack/buffer_spec.rb
Normal file
52
spec/ruby/core/array/pack/buffer_spec.rb
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
# encoding: ascii-8bit
|
||||||
|
|
||||||
|
require File.expand_path('../../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
describe "Aray#pack with `buffer` option" do
|
||||||
|
it "returns specified buffer" do
|
||||||
|
n = [ 65, 66, 67 ]
|
||||||
|
buffer = " "*3
|
||||||
|
result = n.pack("ccc", buffer: buffer) #=> "ABC"
|
||||||
|
result.should equal(buffer)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "adds result at the end of buffer content" do
|
||||||
|
n = [ 65, 66, 67 ] # result without buffer is "ABC"
|
||||||
|
|
||||||
|
buffer = ""
|
||||||
|
n.pack("ccc", buffer: buffer).should == "ABC"
|
||||||
|
|
||||||
|
buffer = "123"
|
||||||
|
n.pack("ccc", buffer: buffer).should == "123ABC"
|
||||||
|
|
||||||
|
buffer = "12345"
|
||||||
|
n.pack("ccc", buffer: buffer).should == "12345ABC"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises TypeError exception if buffer is not String" do
|
||||||
|
lambda { [65].pack("ccc", buffer: []) }.should raise_error(
|
||||||
|
TypeError, "buffer must be String, not Array")
|
||||||
|
end
|
||||||
|
|
||||||
|
context "offset (@) is specified" do
|
||||||
|
it 'keeps buffer content if it is longer than offset' do
|
||||||
|
n = [ 65, 66, 67 ]
|
||||||
|
buffer = "123456"
|
||||||
|
n.pack("@3ccc", buffer: buffer).should == "123ABC"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fills the gap with \0 if buffer content is shorter than offset" do
|
||||||
|
n = [ 65, 66, 67 ]
|
||||||
|
buffer = "123"
|
||||||
|
n.pack("@6ccc", buffer: buffer).should == "123\0\0\0ABC"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not keep buffer content if it is longer than offset + result' do
|
||||||
|
n = [ 65, 66, 67 ]
|
||||||
|
buffer = "1234567890"
|
||||||
|
n.pack("@3ccc", buffer: buffer).should == "123ABC"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -52,7 +52,7 @@ describe "Array#permutation" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns no permutations when the given length has no permutations" do
|
it "returns no permutations when the given length has no permutations" do
|
||||||
@numbers.permutation(9).entries.size == 0
|
@numbers.permutation(9).entries.size.should == 0
|
||||||
@numbers.permutation(9) { |n| @yielded << n }
|
@numbers.permutation(9) { |n| @yielded << n }
|
||||||
@yielded.should == []
|
@yielded.should == []
|
||||||
end
|
end
|
||||||
|
|
|
@ -119,7 +119,7 @@ describe "Array#pop" do
|
||||||
a.should == []
|
a.should == []
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises a TypeError when the passed n can be coerced to Integer" do
|
it "raises a TypeError when the passed n cannot be coerced to Integer" do
|
||||||
lambda{ [1, 2].pop("cat") }.should raise_error(TypeError)
|
lambda{ [1, 2].pop("cat") }.should raise_error(TypeError)
|
||||||
lambda{ [1, 2].pop(nil) }.should raise_error(TypeError)
|
lambda{ [1, 2].pop(nil) }.should raise_error(TypeError)
|
||||||
end
|
end
|
||||||
|
|
|
@ -104,7 +104,7 @@ describe "Array#shift" do
|
||||||
a.should == []
|
a.should == []
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises a TypeError when the passed n can be coerced to Integer" do
|
it "raises a TypeError when the passed n cannot be coerced to Integer" do
|
||||||
lambda{ [1, 2].shift("cat") }.should raise_error(TypeError)
|
lambda{ [1, 2].shift("cat") }.should raise_error(TypeError)
|
||||||
lambda{ [1, 2].shift(nil) }.should raise_error(TypeError)
|
lambda{ [1, 2].shift(nil) }.should raise_error(TypeError)
|
||||||
end
|
end
|
||||||
|
|
44
spec/ruby/core/array/sum_spec.rb
Normal file
44
spec/ruby/core/array/sum_spec.rb
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
describe "Array#sum" do
|
||||||
|
it "returns the sum of elements" do
|
||||||
|
[1, 2, 3].sum.should == 6
|
||||||
|
end
|
||||||
|
|
||||||
|
it "applies a block to each element before adding if it's given" do
|
||||||
|
[1, 2, 3].sum { |i| i * 10 }.should == 60
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns init value if array is empty" do
|
||||||
|
[].sum(-1).should == -1
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns 0 if array is empty and init is omitted" do
|
||||||
|
[].sum.should == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
it "adds init value to the sum of elemens" do
|
||||||
|
[1, 2, 3].sum(10).should == 16
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can be used for non-numeric objects by providing init value" do
|
||||||
|
["a", "b", "c"].sum("").should == "abc"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'raises TypeError if any element are not numeric' do
|
||||||
|
lambda { ["a"].sum }.should raise_error(TypeError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'raises TypeError if any element cannot be added to init value' do
|
||||||
|
lambda { [1].sum([]) }.should raise_error(TypeError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "calls + to sum the elements" do
|
||||||
|
a = mock("a")
|
||||||
|
b = mock("b")
|
||||||
|
a.should_receive(:+).with(b).and_return(42)
|
||||||
|
[b].sum(a).should == 42
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -16,4 +16,16 @@ describe "Bignum" do
|
||||||
Bignum.new
|
Bignum.new
|
||||||
end.should raise_error(NoMethodError)
|
end.should raise_error(NoMethodError)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
it "unified into Integer" do
|
||||||
|
Bignum.should equal(Integer)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is deprecated" do
|
||||||
|
-> {
|
||||||
|
Bignum
|
||||||
|
}.should complain(/constant ::Bignum is deprecated/)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
36
spec/ruby/core/complex/finite_spec.rb
Normal file
36
spec/ruby/core/complex/finite_spec.rb
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
describe "Complex#finite?" do
|
||||||
|
it "returns true if magnitude is finite" do
|
||||||
|
(1+1i).finite?.should == true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false for positive infinity" do
|
||||||
|
value = Complex(Float::INFINITY, 42)
|
||||||
|
value.finite?.should == false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false for positive complex with infinite imaginary" do
|
||||||
|
value = Complex(1, Float::INFINITY)
|
||||||
|
value.finite?.should == false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false for negative infinity" do
|
||||||
|
value = -Complex(Float::INFINITY, 42)
|
||||||
|
value.finite?.should == false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false for negative complex with infinite imaginary" do
|
||||||
|
value = -Complex(1, Float::INFINITY)
|
||||||
|
value.finite?.should == false
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_bug "#14014", "2.4"..."2.5" do
|
||||||
|
it "returns false for NaN" do
|
||||||
|
value = Complex(Float::NAN, Float::NAN)
|
||||||
|
value.finite?.should == false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
34
spec/ruby/core/complex/infinite_spec.rb
Normal file
34
spec/ruby/core/complex/infinite_spec.rb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
describe "Complex#infinite?" do
|
||||||
|
it "returns nil if magnitude is finite" do
|
||||||
|
(1+1i).infinite?.should == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns 1 for positive infinity" do
|
||||||
|
value = Complex(Float::INFINITY, 42).infinite?
|
||||||
|
value.should == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns 1 for positive complex with infinite imaginary" do
|
||||||
|
value = Complex(1, Float::INFINITY).infinite?
|
||||||
|
value.should == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns -1 for negative infinity" do
|
||||||
|
value = -Complex(Float::INFINITY, 42).infinite?
|
||||||
|
value.should == -1
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns -1 for negative complex with infinite imaginary" do
|
||||||
|
value = -Complex(1, Float::INFINITY).infinite?
|
||||||
|
value.should == -1
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns nil for NaN" do
|
||||||
|
value = Complex(0, Float::NAN).infinite?
|
||||||
|
value.should == nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
33
spec/ruby/core/dir/empty_spec.rb
Normal file
33
spec/ruby/core/dir/empty_spec.rb
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
describe "Dir.empty?" do
|
||||||
|
before :all do
|
||||||
|
@empty_dir = tmp("empty_dir")
|
||||||
|
mkdir_p @empty_dir
|
||||||
|
end
|
||||||
|
|
||||||
|
after :all do
|
||||||
|
rm_r @empty_dir
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns true for empty directories" do
|
||||||
|
result = Dir.empty? @empty_dir
|
||||||
|
result.should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false for non-empty directories" do
|
||||||
|
result = Dir.empty? __dir__
|
||||||
|
result.should be_false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false for a non-directory" do
|
||||||
|
result = Dir.empty? __FILE__
|
||||||
|
result.should be_false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises ENOENT for nonexistent directories" do
|
||||||
|
lambda { Dir.empty? tmp("nonexistent") }.should raise_error(Errno::ENOENT)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -68,7 +68,7 @@ describe "Dir.glob" do
|
||||||
Dir.glob('**/', File::FNM_DOTMATCH).sort.should == expected
|
Dir.glob('**/', File::FNM_DOTMATCH).sort.should == expected
|
||||||
end
|
end
|
||||||
|
|
||||||
# This is a seperate case to check **/ coming after a constant
|
# This is a separate case to check **/ coming after a constant
|
||||||
# directory as well.
|
# directory as well.
|
||||||
it "recursively matches any subdirectories except './' or '../' with '**/' and option File::FNM_DOTMATCH" do
|
it "recursively matches any subdirectories except './' or '../' with '**/' and option File::FNM_DOTMATCH" do
|
||||||
expected = %w[
|
expected = %w[
|
||||||
|
|
|
@ -89,7 +89,7 @@ with_feature :encoding do
|
||||||
@ec.primitive_convert("","",nil,nil, {after_output: true}).should == :finished
|
@ec.primitive_convert("","",nil,nil, {after_output: true}).should == :finished
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sets the destination buffer's encoding to the destination encoding if the conversion suceeded" do
|
it "sets the destination buffer's encoding to the destination encoding if the conversion succeeded" do
|
||||||
dest = "".force_encoding('utf-8')
|
dest = "".force_encoding('utf-8')
|
||||||
dest.encoding.should == Encoding::UTF_8
|
dest.encoding.should == Encoding::UTF_8
|
||||||
@ec.primitive_convert("\u{98}",dest).should == :finished
|
@ec.primitive_convert("\u{98}",dest).should == :finished
|
||||||
|
|
|
@ -16,15 +16,13 @@ with_feature :encoding do
|
||||||
|
|
||||||
it "returns [:source_buffer_empty,nil,nil,nil, nil] when #convert last succeeded" do
|
it "returns [:source_buffer_empty,nil,nil,nil, nil] when #convert last succeeded" do
|
||||||
ec = Encoding::Converter.new('ascii','utf-8')
|
ec = Encoding::Converter.new('ascii','utf-8')
|
||||||
ec.convert("a".force_encoding('ascii')).should == "a".\
|
ec.convert("a".force_encoding('ascii')).should == "a".force_encoding('utf-8')
|
||||||
force_encoding('utf-8')
|
|
||||||
ec.primitive_errinfo.should == [:source_buffer_empty, nil, nil, nil, nil]
|
ec.primitive_errinfo.should == [:source_buffer_empty, nil, nil, nil, nil]
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns [:destination_buffer_full,nil,nil,nil,nil] when #primitive_convert last returned :destination_buffer_full" do
|
it "returns [:destination_buffer_full,nil,nil,nil,nil] when #primitive_convert last returned :destination_buffer_full" do
|
||||||
ec = Encoding::Converter.new("utf-8", "iso-2022-jp")
|
ec = Encoding::Converter.new("utf-8", "iso-2022-jp")
|
||||||
ec.primitive_convert("\u{9999}", "", 0, 0, partial_input: false) \
|
ec.primitive_convert("\u{9999}", "", 0, 0, partial_input: false).should == :destination_buffer_full
|
||||||
.should == :destination_buffer_full
|
|
||||||
ec.primitive_errinfo.should == [:destination_buffer_full, nil, nil, nil, nil]
|
ec.primitive_errinfo.should == [:destination_buffer_full, nil, nil, nil, nil]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,7 @@ with_feature :encoding do
|
||||||
src = "\x00\xd8\x61\x00"
|
src = "\x00\xd8\x61\x00"
|
||||||
dst = ""
|
dst = ""
|
||||||
ec.primitive_convert(src, dst).should == :invalid_byte_sequence
|
ec.primitive_convert(src, dst).should == :invalid_byte_sequence
|
||||||
ec.primitive_errinfo.should ==
|
ec.primitive_errinfo.should == [:invalid_byte_sequence, "UTF-16LE", "UTF-8", "\x00\xD8", "a\x00"]
|
||||||
[:invalid_byte_sequence, "UTF-16LE", "UTF-8", "\x00\xD8", "a\x00"]
|
|
||||||
ec.putback(1).should == "\x00".force_encoding("utf-16le")
|
ec.putback(1).should == "\x00".force_encoding("utf-16le")
|
||||||
ec.putback.should == "a".force_encoding("utf-16le")
|
ec.putback.should == "a".force_encoding("utf-16le")
|
||||||
ec.putback.should == ""
|
ec.putback.should == ""
|
||||||
|
|
|
@ -23,7 +23,7 @@ with_feature :encoding do
|
||||||
# conversion from ISO-8859-1 -> UTF-8 succeeded, but the conversion from
|
# conversion from ISO-8859-1 -> UTF-8 succeeded, but the conversion from
|
||||||
# UTF-8 to EUC-JP failed. IOW, it failed when the source encoding was
|
# UTF-8 to EUC-JP failed. IOW, it failed when the source encoding was
|
||||||
# UTF-8, so UTF-8 is regarded as the source encoding.
|
# UTF-8, so UTF-8 is regarded as the source encoding.
|
||||||
it "is equal to the source encoding at the stage of the conversion path where the error occured" do
|
it "is equal to the source encoding at the stage of the conversion path where the error occurred" do
|
||||||
@exception2.source_encoding_name.should == 'UTF-8'
|
@exception2.source_encoding_name.should == 'UTF-8'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -28,7 +28,7 @@ with_feature :encoding do
|
||||||
|
|
||||||
# FIXME: Derive example where the failure occurs at the UTF-8 ->
|
# FIXME: Derive example where the failure occurs at the UTF-8 ->
|
||||||
# ISO-8859-1 case so as to better illustrate the issue
|
# ISO-8859-1 case so as to better illustrate the issue
|
||||||
it "is equal to the source encoding at the stage of the conversion path where the error occured" do
|
it "is equal to the source encoding at the stage of the conversion path where the error occurred" do
|
||||||
@exception2.source_encoding.should == Encoding::EUC_JP
|
@exception2.source_encoding.should == Encoding::EUC_JP
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,7 +23,7 @@ with_feature :encoding do
|
||||||
# conversion from ISO-8859-1 -> UTF-8 succeeded, but the conversion from
|
# conversion from ISO-8859-1 -> UTF-8 succeeded, but the conversion from
|
||||||
# UTF-8 to EUC-JP failed. IOW, it failed when the source encoding was
|
# UTF-8 to EUC-JP failed. IOW, it failed when the source encoding was
|
||||||
# UTF-8, so UTF-8 is regarded as the source encoding.
|
# UTF-8, so UTF-8 is regarded as the source encoding.
|
||||||
it "is equal to the source encoding at the stage of the conversion path where the error occured" do
|
it "is equal to the source encoding at the stage of the conversion path where the error occurred" do
|
||||||
@exception2.source_encoding_name.should == 'UTF-8'
|
@exception2.source_encoding_name.should == 'UTF-8'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,7 +24,7 @@ with_feature :encoding do
|
||||||
# conversion from ISO-8859-1 -> UTF-8 succeeded, but the conversion from
|
# conversion from ISO-8859-1 -> UTF-8 succeeded, but the conversion from
|
||||||
# UTF-8 to EUC-JP failed. IOW, it failed when the source encoding was
|
# UTF-8 to EUC-JP failed. IOW, it failed when the source encoding was
|
||||||
# UTF-8, so UTF-8 is regarded as the source encoding.
|
# UTF-8, so UTF-8 is regarded as the source encoding.
|
||||||
it "is equal to the source encoding at the stage of the conversion path where the error occured" do
|
it "is equal to the source encoding at the stage of the conversion path where the error occurred" do
|
||||||
@exception2.source_encoding.should == Encoding::UTF_8
|
@exception2.source_encoding.should == Encoding::UTF_8
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -68,11 +68,11 @@ describe "Enumerable#any?" do
|
||||||
|
|
||||||
describe "with block" do
|
describe "with block" do
|
||||||
it "returns true if the block ever returns other than false or nil" do
|
it "returns true if the block ever returns other than false or nil" do
|
||||||
@enum.any? { true } == true
|
@enum.any? { true }.should == true
|
||||||
@enum.any? { 0 } == true
|
@enum.any? { 0 }.should == true
|
||||||
@enum.any? { 1 } == true
|
@enum.any? { 1 }.should == true
|
||||||
|
|
||||||
@enum1.any? { Object.new } == true
|
@enum1.any? { Object.new }.should == true
|
||||||
@enum1.any?{ |o| o < 1 }.should == true
|
@enum1.any?{ |o| o < 1 }.should == true
|
||||||
@enum1.any?{ |o| 5 }.should == true
|
@enum1.any?{ |o| 5 }.should == true
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ describe "Enumerable#cycle" do
|
||||||
enum.cycle(obj).to_a.should == [3, 2, 1, 3, 2, 1]
|
enum.cycle(obj).to_a.should == [3, 2, 1, 3, 2, 1]
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises a TypeError when the passed n can be coerced to Integer" do
|
it "raises a TypeError when the passed n cannot be coerced to Integer" do
|
||||||
enum = EnumerableSpecs::Numerous.new
|
enum = EnumerableSpecs::Numerous.new
|
||||||
lambda{ enum.cycle("cat"){} }.should raise_error(TypeError)
|
lambda{ enum.cycle("cat"){} }.should raise_error(TypeError)
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,7 +34,7 @@ describe "Enumerable#drop" do
|
||||||
EnumerableSpecs::Numerous.new(3, 2, 1, :go).drop(4).should == []
|
EnumerableSpecs::Numerous.new(3, 2, 1, :go).drop(4).should == []
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises a TypeError when the passed n can be coerced to Integer" do
|
it "raises a TypeError when the passed n cannot be coerced to Integer" do
|
||||||
lambda{ @enum.drop("hat") }.should raise_error(TypeError)
|
lambda{ @enum.drop("hat") }.should raise_error(TypeError)
|
||||||
lambda{ @enum.drop(nil) }.should raise_error(TypeError)
|
lambda{ @enum.drop(nil) }.should raise_error(TypeError)
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,71 @@ ruby_version_is '2.4' do
|
||||||
[0, 1, 2, 3].to_enum.uniq { |n| n.even? }.should == [0, 1]
|
[0, 1, 2, 3].to_enum.uniq { |n| n.even? }.should == [0, 1]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "uses eql? semantics" do
|
||||||
|
[1.0, 1].to_enum.uniq.should == [1.0, 1]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "compares elements first with hash" do
|
||||||
|
x = mock('0')
|
||||||
|
x.should_receive(:hash).at_least(1).and_return(0)
|
||||||
|
y = mock('0')
|
||||||
|
y.should_receive(:hash).at_least(1).and_return(0)
|
||||||
|
|
||||||
|
[x, y].to_enum.uniq.should == [x, y]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not compare elements with different hash codes via eql?" do
|
||||||
|
x = mock('0')
|
||||||
|
x.should_not_receive(:eql?)
|
||||||
|
y = mock('1')
|
||||||
|
y.should_not_receive(:eql?)
|
||||||
|
|
||||||
|
x.should_receive(:hash).at_least(1).and_return(0)
|
||||||
|
y.should_receive(:hash).at_least(1).and_return(1)
|
||||||
|
|
||||||
|
[x, y].to_enum.uniq.should == [x, y]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "compares elements with matching hash codes with #eql?" do
|
||||||
|
a = Array.new(2) do
|
||||||
|
obj = mock('0')
|
||||||
|
obj.should_receive(:hash).at_least(1).and_return(0)
|
||||||
|
|
||||||
|
def obj.eql?(o)
|
||||||
|
# It's undefined whether the impl does a[0].eql?(a[1]) or
|
||||||
|
# a[1].eql?(a[0]) so we taint both.
|
||||||
|
taint
|
||||||
|
o.taint
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
obj
|
||||||
|
end
|
||||||
|
|
||||||
|
a.uniq.should == a
|
||||||
|
a[0].tainted?.should == true
|
||||||
|
a[1].tainted?.should == true
|
||||||
|
|
||||||
|
a = Array.new(2) do
|
||||||
|
obj = mock('0')
|
||||||
|
obj.should_receive(:hash).at_least(1).and_return(0)
|
||||||
|
|
||||||
|
def obj.eql?(o)
|
||||||
|
# It's undefined whether the impl does a[0].eql?(a[1]) or
|
||||||
|
# a[1].eql?(a[0]) so we taint both.
|
||||||
|
taint
|
||||||
|
o.taint
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
obj
|
||||||
|
end
|
||||||
|
|
||||||
|
a.to_enum.uniq.size.should == 1
|
||||||
|
a[0].tainted?.should == true
|
||||||
|
a[1].tainted?.should == true
|
||||||
|
end
|
||||||
|
|
||||||
context 'when yielded with multiple arguments' do
|
context 'when yielded with multiple arguments' do
|
||||||
before :each do
|
before :each do
|
||||||
@enum = Object.new.to_enum
|
@enum = Object.new.to_enum
|
||||||
|
|
|
@ -24,7 +24,7 @@ describe "Enumerator::Lazy#force" do
|
||||||
(0..Float::INFINITY).lazy.map(&:succ).take(2).force.should == [1, 2]
|
(0..Float::INFINITY).lazy.map(&:succ).take(2).force.should == [1, 2]
|
||||||
|
|
||||||
@eventsmixed.take(1).map(&:succ).force.should == [1]
|
@eventsmixed.take(1).map(&:succ).force.should == [1]
|
||||||
ScratchPad.recorded == [:after_yields]
|
ScratchPad.recorded.should == [:before_yield]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
9
spec/ruby/core/false/dup_spec.rb
Normal file
9
spec/ruby/core/false/dup_spec.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
describe "FalseClass#dup" do
|
||||||
|
it "returns self" do
|
||||||
|
false.dup.should equal(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
15
spec/ruby/core/file/empty_spec.rb
Normal file
15
spec/ruby/core/file/empty_spec.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
require File.expand_path('../../../shared/file/zero', __FILE__)
|
||||||
|
|
||||||
|
describe "File.empty?" do
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
it_behaves_like :file_zero, :empty?, File
|
||||||
|
it_behaves_like :file_zero_missing, :empty?, File
|
||||||
|
|
||||||
|
platform_is :solaris do
|
||||||
|
it "returns false for /dev/null" do
|
||||||
|
File.empty?('/dev/null').should == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,7 +3,7 @@ require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
describe "File.readlink" do
|
describe "File.readlink" do
|
||||||
# symlink/readlink are not supported on Windows
|
# symlink/readlink are not supported on Windows
|
||||||
platform_is_not :windows do
|
platform_is_not :windows do
|
||||||
describe "File.readlink with absolute paths" do
|
describe "with absolute paths" do
|
||||||
before :each do
|
before :each do
|
||||||
@file = tmp('file_readlink.txt')
|
@file = tmp('file_readlink.txt')
|
||||||
@link = tmp('file_readlink.lnk')
|
@link = tmp('file_readlink.lnk')
|
||||||
|
@ -35,7 +35,26 @@ describe "File.readlink" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "File.readlink when changing the working directory" do
|
describe "with paths containing unicode characters" do
|
||||||
|
before :each do
|
||||||
|
@file = tmp('tàrget.txt')
|
||||||
|
@link = tmp('lïnk.lnk')
|
||||||
|
File.symlink(@file, @link)
|
||||||
|
end
|
||||||
|
|
||||||
|
after :each do
|
||||||
|
rm_r @file, @link
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the name of the file referenced by the given link" do
|
||||||
|
touch @file
|
||||||
|
result = File.readlink(@link)
|
||||||
|
result.encoding.should equal Encoding.find('filesystem')
|
||||||
|
result.should == @file.dup.force_encoding(Encoding.find('filesystem'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "when changing the working directory" do
|
||||||
before :each do
|
before :each do
|
||||||
@cwd = Dir.pwd
|
@cwd = Dir.pwd
|
||||||
@tmpdir = tmp("/readlink")
|
@tmpdir = tmp("/readlink")
|
||||||
|
|
|
@ -75,11 +75,11 @@ describe :file_fnmatch, shared: true do
|
||||||
File.send(@method, 'c*t', 'c/a/b/t').should == true
|
File.send(@method, 'c*t', 'c/a/b/t').should == true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "matches ranges of characters using bracket expresions (e.g. [a-z])" do
|
it "matches ranges of characters using bracket expression (e.g. [a-z])" do
|
||||||
File.send(@method, 'ca[a-z]', 'cat').should == true
|
File.send(@method, 'ca[a-z]', 'cat').should == true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "matches ranges of characters using bracket expresions, taking case into account" do
|
it "matches ranges of characters using bracket expression, taking case into account" do
|
||||||
File.send(@method, '[a-z]', 'D').should == false
|
File.send(@method, '[a-z]', 'D').should == false
|
||||||
File.send(@method, '[^a-z]', 'D').should == true
|
File.send(@method, '[^a-z]', 'D').should == true
|
||||||
File.send(@method, '[A-Z]', 'd').should == false
|
File.send(@method, '[A-Z]', 'd').should == false
|
||||||
|
@ -92,7 +92,7 @@ describe :file_fnmatch, shared: true do
|
||||||
File.send(@method, '/ca[s][s-t]/rul[a-b]/[z]he/[x-Z]orld', '/cats/rule/the/World').should == false
|
File.send(@method, '/ca[s][s-t]/rul[a-b]/[z]he/[x-Z]orld', '/cats/rule/the/World').should == false
|
||||||
end
|
end
|
||||||
|
|
||||||
it "matches ranges of characters using exclusive bracket expresions (e.g. [^t] or [!t])" do
|
it "matches ranges of characters using exclusive bracket expression (e.g. [^t] or [!t])" do
|
||||||
File.send(@method, 'ca[^t]', 'cat').should == false
|
File.send(@method, 'ca[^t]', 'cat').should == false
|
||||||
File.send(@method, 'ca[!t]', 'cat').should == false
|
File.send(@method, 'ca[!t]', 'cat').should == false
|
||||||
end
|
end
|
||||||
|
@ -106,13 +106,13 @@ describe :file_fnmatch, shared: true do
|
||||||
end
|
end
|
||||||
|
|
||||||
platform_is_not :windows do
|
platform_is_not :windows do
|
||||||
it "doesn't match case sensitive characters on platfroms with case sensitive paths, when flags include FNM_SYSCASE" do
|
it "doesn't match case sensitive characters on platforms with case sensitive paths, when flags include FNM_SYSCASE" do
|
||||||
File.send(@method, 'cat', 'CAT', File::FNM_SYSCASE).should == false
|
File.send(@method, 'cat', 'CAT', File::FNM_SYSCASE).should == false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
platform_is :windows do
|
platform_is :windows do
|
||||||
it "matches case sensitive characters on platfroms with case insensitive paths, when flags include FNM_SYSCASE" do
|
it "matches case sensitive characters on platforms with case insensitive paths, when flags include FNM_SYSCASE" do
|
||||||
File.send(@method, 'cat', 'CAT', File::FNM_SYSCASE).should == true
|
File.send(@method, 'cat', 'CAT', File::FNM_SYSCASE).should == true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,4 +16,16 @@ describe "Fixnum" do
|
||||||
Fixnum.new
|
Fixnum.new
|
||||||
end.should raise_error(NoMethodError)
|
end.should raise_error(NoMethodError)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
it "is unified into Integer" do
|
||||||
|
Fixnum.should equal(Integer)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is deprecated" do
|
||||||
|
-> {
|
||||||
|
Fixnum
|
||||||
|
}.should complain(/constant ::Fixnum is deprecated/)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,4 +10,14 @@ describe "Float#ceil" do
|
||||||
-9223372036854775808.1.ceil.should eql(-9223372036854775808)
|
-9223372036854775808.1.ceil.should eql(-9223372036854775808)
|
||||||
+9223372036854775808.1.ceil.should eql(+9223372036854775808)
|
+9223372036854775808.1.ceil.should eql(+9223372036854775808)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
it "returns the smallest number greater than or equal to self with an optionally given precision" do
|
||||||
|
2.1679.ceil(0).should eql(3)
|
||||||
|
214.94.ceil(-1).should eql(220)
|
||||||
|
7.0.ceil(1).should eql(7.0)
|
||||||
|
-1.234.ceil(2).should eql(-1.23)
|
||||||
|
5.123812.ceil(4).should eql(5.1239)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
10
spec/ruby/core/float/dup_spec.rb
Normal file
10
spec/ruby/core/float/dup_spec.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
describe "Float#dup" do
|
||||||
|
it "returns self" do
|
||||||
|
float = 2.4
|
||||||
|
float.dup.should equal(float)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,4 +10,14 @@ describe "Float#floor" do
|
||||||
-9223372036854775808.1.floor.should eql(-9223372036854775808)
|
-9223372036854775808.1.floor.should eql(-9223372036854775808)
|
||||||
+9223372036854775808.1.floor.should eql(+9223372036854775808)
|
+9223372036854775808.1.floor.should eql(+9223372036854775808)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
it "returns the largest number less than or equal to self with an optionally given precision" do
|
||||||
|
2.1679.floor(0).should eql(2)
|
||||||
|
214.94.floor(-1).should eql(210)
|
||||||
|
7.0.floor(1).should eql(7.0)
|
||||||
|
-1.234.floor(2).should eql(-1.24)
|
||||||
|
5.123812.floor(4).should eql(5.1238)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -84,4 +84,18 @@ describe "Float#round" do
|
||||||
-2.5e200.round(-200).should eql( -3 * 10 ** 200 )
|
-2.5e200.round(-200).should eql( -3 * 10 ** 200 )
|
||||||
-2.4e200.round(-200).should eql( -2 * 10 ** 200 )
|
-2.4e200.round(-200).should eql( -2 * 10 ** 200 )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
it "returns different rounded values depending on the half option" do
|
||||||
|
2.5.round(half: :up).should eql(3)
|
||||||
|
2.5.round(half: :down).should eql(2)
|
||||||
|
2.5.round(half: :even).should eql(2)
|
||||||
|
3.5.round(half: :up).should eql(4)
|
||||||
|
3.5.round(half: :down).should eql(3)
|
||||||
|
3.5.round(half: :even).should eql(4)
|
||||||
|
(-2.5).round(half: :up).should eql(-3)
|
||||||
|
(-2.5).round(half: :down).should eql(-2)
|
||||||
|
(-2.5).round(half: :even).should eql(-2)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,4 +3,14 @@ require File.expand_path('../shared/to_i', __FILE__)
|
||||||
|
|
||||||
describe "Float#truncate" do
|
describe "Float#truncate" do
|
||||||
it_behaves_like(:float_to_i, :truncate)
|
it_behaves_like(:float_to_i, :truncate)
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
it "returns self truncated to an optionally given precision" do
|
||||||
|
2.1679.truncate(0).should eql(2)
|
||||||
|
7.1.truncate(1).should eql(7.1)
|
||||||
|
214.94.truncate(-1).should eql(210)
|
||||||
|
-1.234.truncate(2).should eql(-1.23)
|
||||||
|
5.123812.truncate(4).should eql(5.1238)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,13 +11,13 @@ describe "Hash#delete" do
|
||||||
it "calls supplied block if the key is not found" do
|
it "calls supplied block if the key is not found" do
|
||||||
{ a: 1, b: 10, c: 100 }.delete(:d) { 5 }.should == 5
|
{ a: 1, b: 10, c: 100 }.delete(:d) { 5 }.should == 5
|
||||||
Hash.new(:default).delete(:d) { 5 }.should == 5
|
Hash.new(:default).delete(:d) { 5 }.should == 5
|
||||||
Hash.new { :defualt }.delete(:d) { 5 }.should == 5
|
Hash.new { :default }.delete(:d) { 5 }.should == 5
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns nil if the key is not found when no block is given" do
|
it "returns nil if the key is not found when no block is given" do
|
||||||
{ a: 1, b: 10, c: 100 }.delete(:d).should == nil
|
{ a: 1, b: 10, c: 100 }.delete(:d).should == nil
|
||||||
Hash.new(:default).delete(:d).should == nil
|
Hash.new(:default).delete(:d).should == nil
|
||||||
Hash.new { :defualt }.delete(:d).should == nil
|
Hash.new { :default }.delete(:d).should == nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# MRI explicitly implements this behavior
|
# MRI explicitly implements this behavior
|
||||||
|
|
|
@ -24,6 +24,15 @@ ruby_version_is "2.4" do
|
||||||
enumerator.each(&:succ).should == { a: 2, b: 3, c: 4 }
|
enumerator.each(&:succ).should == { a: 2, b: 3, c: 4 }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns a Hash instance, even on subclasses" do
|
||||||
|
klass = Class.new(Hash)
|
||||||
|
h = klass.new
|
||||||
|
h[:foo] = 42
|
||||||
|
r = h.transform_values{|v| 2 * v}
|
||||||
|
r[:foo].should == 84
|
||||||
|
r.class.should == Hash
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "Hash#transform_values!" do
|
describe "Hash#transform_values!" do
|
||||||
|
@ -41,6 +50,14 @@ ruby_version_is "2.4" do
|
||||||
@hash.should == { a: 2, b: 3, c: 4 }
|
@hash.should == { a: 2, b: 3, c: 4 }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "partially modifies the contents if we broke from the block" do
|
||||||
|
@hash.transform_values! do |v|
|
||||||
|
break if v == 3
|
||||||
|
100 + v
|
||||||
|
end
|
||||||
|
@hash.should == { a: 101, b: 102, c: 3}
|
||||||
|
end
|
||||||
|
|
||||||
context "when no block is given" do
|
context "when no block is given" do
|
||||||
it "returns a sized Enumerator" do
|
it "returns a sized Enumerator" do
|
||||||
enumerator = @hash.transform_values!
|
enumerator = @hash.transform_values!
|
||||||
|
@ -56,6 +73,10 @@ ruby_version_is "2.4" do
|
||||||
@hash.freeze
|
@hash.freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "raises a RuntimeError on an empty hash" do
|
||||||
|
->{ {}.freeze.transform_values!(&:succ) }.should raise_error(RuntimeError)
|
||||||
|
end
|
||||||
|
|
||||||
it "keeps pairs and raises a RuntimeError" do
|
it "keeps pairs and raises a RuntimeError" do
|
||||||
->{ @hash.transform_values!(&:succ) }.should raise_error(RuntimeError)
|
->{ @hash.transform_values!(&:succ) }.should raise_error(RuntimeError)
|
||||||
@hash.should == @initial_pairs
|
@hash.should == @initial_pairs
|
||||||
|
|
|
@ -1,6 +1,21 @@
|
||||||
require File.expand_path('../../../spec_helper', __FILE__)
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
require File.expand_path('../shared/to_i', __FILE__)
|
require File.expand_path('../shared/to_i', __FILE__)
|
||||||
|
require File.expand_path('../shared/integer_rounding', __FILE__)
|
||||||
|
|
||||||
describe "Integer#ceil" do
|
describe "Integer#ceil" do
|
||||||
it_behaves_like(:integer_to_i, :ceil)
|
it_behaves_like(:integer_to_i, :ceil)
|
||||||
|
it_behaves_like(:integer_rounding_positive_precision, :ceil)
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
context "precision argument specified as part of the ceil method is negative" do
|
||||||
|
it "returns the smallest integer greater than self with at least precision.abs trailing zeros" do
|
||||||
|
18.ceil(-1).should eql(20)
|
||||||
|
18.ceil(-2).should eql(100)
|
||||||
|
18.ceil(-3).should eql(1000)
|
||||||
|
-1832.ceil(-1).should eql(-1830)
|
||||||
|
-1832.ceil(-2).should eql(-1800)
|
||||||
|
-1832.ceil(-3).should eql(-1000)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
34
spec/ruby/core/integer/digits_spec.rb
Normal file
34
spec/ruby/core/integer/digits_spec.rb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
describe "Integer#digits" do
|
||||||
|
it "returns an array of place values in base-10 by default" do
|
||||||
|
12345.digits.should == [5,4,3,2,1]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns digits by place value of a given radix" do
|
||||||
|
12345.digits(7).should == [4,6,6,0,5]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "converts the radix with #to_int" do
|
||||||
|
12345.digits(mock_int(2)).should == [1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns [0] when called on 0, regardless of base" do
|
||||||
|
0.digits.should == [0]
|
||||||
|
0.digits(7).should == [0]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises ArgumentError when calling with a radix less than 2" do
|
||||||
|
lambda { 12345.digits(1) }.should raise_error(ArgumentError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises ArgumentError when calling with a negative radix" do
|
||||||
|
lambda { 12345.digits(-2) }.should raise_error(ArgumentError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises Math::DomainError when calling digits on a negative number" do
|
||||||
|
lambda { -12345.digits(7) }.should raise_error(Math::DomainError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
10
spec/ruby/core/integer/dup_spec.rb
Normal file
10
spec/ruby/core/integer/dup_spec.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
describe "Integer#dup" do
|
||||||
|
it "returns self" do
|
||||||
|
int = 2
|
||||||
|
int.dup.should equal(int)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,21 @@
|
||||||
require File.expand_path('../../../spec_helper', __FILE__)
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
require File.expand_path('../shared/to_i', __FILE__)
|
require File.expand_path('../shared/to_i', __FILE__)
|
||||||
|
require File.expand_path('../shared/integer_rounding', __FILE__)
|
||||||
|
|
||||||
describe "Integer#floor" do
|
describe "Integer#floor" do
|
||||||
it_behaves_like(:integer_to_i, :floor)
|
it_behaves_like(:integer_to_i, :floor)
|
||||||
|
it_behaves_like(:integer_rounding_positive_precision, :floor)
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
context "precision argument specified as part of the floor method is negative" do
|
||||||
|
it "returns the largest integer less than self with at least precision.abs trailing zeros" do
|
||||||
|
1832.floor(-1).should eql(1830)
|
||||||
|
1832.floor(-2).should eql(1800)
|
||||||
|
1832.floor(-3).should eql(1000)
|
||||||
|
-1832.floor(-1).should eql(-1840)
|
||||||
|
-1832.floor(-2).should eql(-1900)
|
||||||
|
-1832.floor(-3).should eql(-2000)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,13 @@ describe "Integer" do
|
||||||
it "includes Comparable" do
|
it "includes Comparable" do
|
||||||
Integer.include?(Comparable).should == true
|
Integer.include?(Comparable).should == true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
it "is the class of both small and large integers" do
|
||||||
|
42.class.should equal(Integer)
|
||||||
|
bignum_value.class.should equal(Integer)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "Integer#integer?" do
|
describe "Integer#integer?" do
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
require File.expand_path('../../../spec_helper', __FILE__)
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
require File.expand_path('../shared/to_i', __FILE__)
|
require File.expand_path('../shared/to_i', __FILE__)
|
||||||
|
require File.expand_path('../shared/integer_rounding', __FILE__)
|
||||||
|
|
||||||
describe "Integer#round" do
|
describe "Integer#round" do
|
||||||
it_behaves_like(:integer_to_i, :round)
|
it_behaves_like(:integer_to_i, :round)
|
||||||
|
it_behaves_like(:integer_rounding_positive_precision, :round)
|
||||||
|
|
||||||
ruby_version_is ""..."2.5" do
|
ruby_version_is ""..."2.5" do # Not just since 2.4
|
||||||
it "rounds itself as a float if passed a positive precision" do
|
it "rounds itself as a float if passed a positive precision" do
|
||||||
[2, -4, 10**70, -10**100].each do |v|
|
[2, -4, 10**70, -10**100].each do |v|
|
||||||
v.round(42).should eql(v.to_f)
|
v.round(42).should eql(v.to_f)
|
||||||
|
@ -12,20 +14,6 @@ describe "Integer#round" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
ruby_version_is "2.5" do
|
|
||||||
it "returns itself if passed a positive precision" do
|
|
||||||
[2, -4, 10**70, -10**100].each do |v|
|
|
||||||
v.round(42).should eql(v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns itself if passed zero" do
|
|
||||||
[2, -4, 10**70, -10**100].each do |v|
|
|
||||||
v.round(0).should eql(v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# redmine:5228
|
# redmine:5228
|
||||||
it "returns itself rounded if passed a negative value" do
|
it "returns itself rounded if passed a negative value" do
|
||||||
+249.round(-2).should eql(+200)
|
+249.round(-2).should eql(+200)
|
||||||
|
@ -74,4 +62,34 @@ describe "Integer#round" do
|
||||||
obj.stub!(:to_int).and_return([])
|
obj.stub!(:to_int).and_return([])
|
||||||
lambda { 42.round(obj) }.should raise_error(TypeError)
|
lambda { 42.round(obj) }.should raise_error(TypeError)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
it "returns different rounded values depending on the half option" do
|
||||||
|
25.round(-1, half: :up).should eql(30)
|
||||||
|
25.round(-1, half: :down).should eql(20)
|
||||||
|
25.round(-1, half: :even).should eql(20)
|
||||||
|
35.round(-1, half: :up).should eql(40)
|
||||||
|
35.round(-1, half: :down).should eql(30)
|
||||||
|
35.round(-1, half: :even).should eql(40)
|
||||||
|
(-25).round(-1, half: :up).should eql(-30)
|
||||||
|
(-25).round(-1, half: :down).should eql(-20)
|
||||||
|
(-25).round(-1, half: :even).should eql(-20)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4"..."2.5" do
|
||||||
|
it "returns itself as a float if passed a positive precision and the half option" do
|
||||||
|
35.round(1, half: :up).should eql(35.0)
|
||||||
|
35.round(1, half: :down).should eql(35.0)
|
||||||
|
35.round(1, half: :even).should eql(35.0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.5" do
|
||||||
|
it "returns itself if passed a positive precision and the half option" do
|
||||||
|
35.round(1, half: :up).should eql(35)
|
||||||
|
35.round(1, half: :down).should eql(35)
|
||||||
|
35.round(1, half: :even).should eql(35)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
31
spec/ruby/core/integer/shared/integer_rounding.rb
Normal file
31
spec/ruby/core/integer/shared/integer_rounding.rb
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
describe :integer_rounding_positive_precision, shared: true do
|
||||||
|
it "returns self if not passed a precision" do
|
||||||
|
[2, -4, 10**70, -10**100].each do |v|
|
||||||
|
v.send(@method).should eql(v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
it "returns self if passed a precision of zero" do
|
||||||
|
[2, -4, 10**70, -10**100].each do |v|
|
||||||
|
v.send(@method, 0).should eql(v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4"..."2.5" do
|
||||||
|
it "returns itself as a float if passed a positive precision" do
|
||||||
|
[2, -4, 10**70, -10**100].each do |v|
|
||||||
|
v.send(@method, 42).should eql(v.to_f)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.5" do
|
||||||
|
it "returns itself if passed a positive precision" do
|
||||||
|
[2, -4, 10**70, -10**100].each do |v|
|
||||||
|
v.send(@method, 42).should eql(v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
33
spec/ruby/core/integer/sqrt_spec.rb
Normal file
33
spec/ruby/core/integer/sqrt_spec.rb
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is "2.5" do
|
||||||
|
describe "Integer.sqrt" do
|
||||||
|
it "returns an integer" do
|
||||||
|
Integer.sqrt(10).should be_kind_of(Integer)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the integer square root of the argument" do
|
||||||
|
Integer.sqrt(0).should == 0
|
||||||
|
Integer.sqrt(1).should == 1
|
||||||
|
Integer.sqrt(24).should == 4
|
||||||
|
Integer.sqrt(25).should == 5
|
||||||
|
Integer.sqrt(10**400).should == 10**200
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises a Math::DomainError if the argument is negative" do
|
||||||
|
lambda { Integer.sqrt(-4) }.should raise_error(Math::DomainError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts any argument that can be coerced to Integer" do
|
||||||
|
Integer.sqrt(10.0).should == 3
|
||||||
|
end
|
||||||
|
|
||||||
|
it "converts the argument with #to_int" do
|
||||||
|
Integer.sqrt(mock_int(10)).should == 3
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises a TypeError if the argument cannot be coerced to Integer" do
|
||||||
|
lambda { Integer.sqrt("test") }.should raise_error(TypeError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,21 @@
|
||||||
require File.expand_path('../../../spec_helper', __FILE__)
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
require File.expand_path('../shared/to_i', __FILE__)
|
require File.expand_path('../shared/to_i', __FILE__)
|
||||||
|
require File.expand_path('../shared/integer_rounding', __FILE__)
|
||||||
|
|
||||||
describe "Integer#truncate" do
|
describe "Integer#truncate" do
|
||||||
it_behaves_like(:integer_to_i, :truncate)
|
it_behaves_like(:integer_to_i, :truncate)
|
||||||
|
it_behaves_like(:integer_rounding_positive_precision, :truncate)
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
context "precision argument specified as part of the truncate method is negative" do
|
||||||
|
it "returns an integer with at least precision.abs trailing zeros" do
|
||||||
|
1832.truncate(-1).should eql(1830)
|
||||||
|
1832.truncate(-2).should eql(1800)
|
||||||
|
1832.truncate(-3).should eql(1000)
|
||||||
|
-1832.truncate(-1).should eql(-1830)
|
||||||
|
-1832.truncate(-2).should eql(-1800)
|
||||||
|
-1832.truncate(-3).should eql(-1000)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,7 +17,7 @@ describe "IO#advise" do
|
||||||
}.should raise_error(TypeError)
|
}.should raise_error(TypeError)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises a TypeError if offsert cannot be coerced to an Integer" do
|
it "raises a TypeError if offset cannot be coerced to an Integer" do
|
||||||
lambda {
|
lambda {
|
||||||
@io.advise(:normal, "wat")
|
@io.advise(:normal, "wat")
|
||||||
}.should raise_error(TypeError)
|
}.should raise_error(TypeError)
|
||||||
|
|
|
@ -20,6 +20,18 @@ module IOSpecs
|
||||||
"Here is line six.\n" ]
|
"Here is line six.\n" ]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.lines_without_newline_characters
|
||||||
|
[ "Voici la ligne une.",
|
||||||
|
"Qui \303\250 la linea due.",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"Aqu\303\255 est\303\241 la l\303\255nea tres.",
|
||||||
|
"Hier ist Zeile vier.",
|
||||||
|
"",
|
||||||
|
"Est\303\241 aqui a linha cinco.",
|
||||||
|
"Here is line six." ]
|
||||||
|
end
|
||||||
|
|
||||||
def self.lines_limit
|
def self.lines_limit
|
||||||
[ "Voici la l",
|
[ "Voici la l",
|
||||||
"igne une.\n",
|
"igne une.\n",
|
||||||
|
|
|
@ -138,6 +138,14 @@ describe "IO#gets" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
describe "when passed chomp" do
|
||||||
|
it "returns the first line without a trailing newline character" do
|
||||||
|
@io.gets(chomp: true).should == IOSpecs.lines_without_newline_characters[0]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "IO#gets" do
|
describe "IO#gets" do
|
||||||
|
@ -191,7 +199,7 @@ describe "IO#gets" do
|
||||||
@io.gets(obj, 5).should == "one\n"
|
@io.gets(obj, 5).should == "one\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "reads to the default seperator when passed a single argument greater than the number of bytes to the separator" do
|
it "reads to the default separator when passed a single argument greater than the number of bytes to the separator" do
|
||||||
@io.gets(6).should == "one\n"
|
@io.gets(6).should == "one\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -42,4 +42,12 @@ describe "IO#readline" do
|
||||||
$_.should == line
|
$_.should == line
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
describe "when passed chomp" do
|
||||||
|
it "returns the first line without a trailing newline character" do
|
||||||
|
@io.readline(chomp: true).should == IOSpecs.lines_without_newline_characters[0]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -114,6 +114,15 @@ describe :io_each, shared: true do
|
||||||
ScratchPad.recorded.should == IOSpecs.paragraphs
|
ScratchPad.recorded.should == IOSpecs.paragraphs
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
describe "when passed chomp" do
|
||||||
|
it "yields each line without trailing newline characters to the passed block" do
|
||||||
|
@io.send(@method, chomp: true) { |s| ScratchPad << s }
|
||||||
|
ScratchPad.recorded.should == IOSpecs.lines_without_newline_characters
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe :io_each_default_separator, shared: true do
|
describe :io_each_default_separator, shared: true do
|
||||||
|
|
|
@ -17,6 +17,13 @@ describe :io_readlines, shared: true do
|
||||||
result = IO.send(@method, @name, "", &@object)
|
result = IO.send(@method, @name, "", &@object)
|
||||||
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_empty_separator
|
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_empty_separator
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
it "yields a sequence of lines without trailing newline characters when chomp is passed" do
|
||||||
|
result = IO.send(@method, @name, chomp: true, &@object)
|
||||||
|
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_without_newline_characters
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe :io_readlines_options_19, shared: true do
|
describe :io_readlines_options_19, shared: true do
|
||||||
|
|
|
@ -7,9 +7,9 @@ describe "Kernel#==" do
|
||||||
o2 = mock('o2')
|
o2 = mock('o2')
|
||||||
(o1 == o1).should == true
|
(o1 == o1).should == true
|
||||||
(o2 == o2).should == true
|
(o2 == o2).should == true
|
||||||
(o1 == o2).should== false
|
(o1 == o2).should == false
|
||||||
(nil == nil).should == true
|
(nil == nil).should == true
|
||||||
(o1 == nil).should== false
|
(o1 == nil).should == false
|
||||||
(nil == o2).should== false
|
(nil == o2).should == false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,8 +4,11 @@ module MainSpecs
|
||||||
|
|
||||||
module WrapIncludeModule
|
module WrapIncludeModule
|
||||||
end
|
end
|
||||||
|
|
||||||
|
DATA = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def main_public_method
|
def main_public_method
|
||||||
end
|
end
|
||||||
public :main_public_method
|
public :main_public_method
|
||||||
|
|
7
spec/ruby/core/main/fixtures/string_refinement.rb
Normal file
7
spec/ruby/core/main/fixtures/string_refinement.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
module StringRefinement
|
||||||
|
refine(String) do
|
||||||
|
def foo
|
||||||
|
'foo'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
11
spec/ruby/core/main/fixtures/string_refinement_user.rb
Normal file
11
spec/ruby/core/main/fixtures/string_refinement_user.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using StringRefinement
|
||||||
|
|
||||||
|
module MainSpecs
|
||||||
|
DATA[:in_module] = 'hello'.foo
|
||||||
|
|
||||||
|
def self.call_foo(x)
|
||||||
|
x.foo
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
MainSpecs::DATA[:toplevel] = 'hello'.foo
|
134
spec/ruby/core/main/using_spec.rb
Normal file
134
spec/ruby/core/main/using_spec.rb
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is "2.0.0" do
|
||||||
|
require File.expand_path('../fixtures/classes', __FILE__)
|
||||||
|
require File.expand_path('../fixtures/string_refinement', __FILE__)
|
||||||
|
|
||||||
|
describe "main.using" do
|
||||||
|
it "requires one Module argument" do
|
||||||
|
lambda do
|
||||||
|
eval('using', TOPLEVEL_BINDING)
|
||||||
|
end.should raise_error(ArgumentError)
|
||||||
|
|
||||||
|
lambda do
|
||||||
|
eval('using "foo"', TOPLEVEL_BINDING)
|
||||||
|
end.should raise_error(TypeError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "uses refinements from the given module only in the target file" do
|
||||||
|
load File.expand_path('../fixtures/string_refinement_user.rb', __FILE__)
|
||||||
|
MainSpecs::DATA[:in_module].should == 'foo'
|
||||||
|
MainSpecs::DATA[:toplevel].should == 'foo'
|
||||||
|
lambda do
|
||||||
|
'hello'.foo
|
||||||
|
end.should raise_error(NoMethodError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "uses refinements from the given module for method calls in the target file" do
|
||||||
|
load File.expand_path('../fixtures/string_refinement_user.rb', __FILE__)
|
||||||
|
lambda do
|
||||||
|
'hello'.foo
|
||||||
|
end.should raise_error(NoMethodError)
|
||||||
|
MainSpecs.call_foo('hello').should == 'foo'
|
||||||
|
end
|
||||||
|
|
||||||
|
it "uses refinements from the given module in the eval string" do
|
||||||
|
cls = MainSpecs::DATA[:cls] = Class.new {def foo; 'foo'; end}
|
||||||
|
MainSpecs::DATA[:mod] = Module.new do
|
||||||
|
refine(cls) do
|
||||||
|
def foo; 'bar'; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
eval(<<-EOS, TOPLEVEL_BINDING).should == 'bar'
|
||||||
|
using MainSpecs::DATA[:mod]
|
||||||
|
MainSpecs::DATA[:cls].new.foo
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not affect methods defined before it is called" do
|
||||||
|
cls = Class.new {def foo; 'foo'; end}
|
||||||
|
MainSpecs::DATA[:mod] = Module.new do
|
||||||
|
refine(cls) do
|
||||||
|
def foo; 'bar'; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
x = MainSpecs::DATA[:x] = Object.new
|
||||||
|
eval <<-EOS, TOPLEVEL_BINDING
|
||||||
|
x = MainSpecs::DATA[:x]
|
||||||
|
def x.before_using(obj)
|
||||||
|
obj.foo
|
||||||
|
end
|
||||||
|
using MainSpecs::DATA[:mod]
|
||||||
|
def x.after_using(obj)
|
||||||
|
obj.foo
|
||||||
|
end
|
||||||
|
EOS
|
||||||
|
|
||||||
|
obj = cls.new
|
||||||
|
x.before_using(obj).should == 'foo'
|
||||||
|
x.after_using(obj).should == 'bar'
|
||||||
|
end
|
||||||
|
|
||||||
|
it "propagates refinements added to existing modules after it is called" do
|
||||||
|
cls = Class.new {def foo; 'foo'; end}
|
||||||
|
mod = MainSpecs::DATA[:mod] = Module.new do
|
||||||
|
refine(cls) do
|
||||||
|
def foo; 'quux'; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
x = MainSpecs::DATA[:x] = Object.new
|
||||||
|
eval <<-EOS, TOPLEVEL_BINDING
|
||||||
|
using MainSpecs::DATA[:mod]
|
||||||
|
x = MainSpecs::DATA[:x]
|
||||||
|
def x.call_foo(obj)
|
||||||
|
obj.foo
|
||||||
|
end
|
||||||
|
def x.call_bar(obj)
|
||||||
|
obj.bar
|
||||||
|
end
|
||||||
|
EOS
|
||||||
|
|
||||||
|
obj = cls.new
|
||||||
|
x.call_foo(obj).should == 'quux'
|
||||||
|
|
||||||
|
mod.module_eval do
|
||||||
|
refine(cls) do
|
||||||
|
def bar; 'quux'; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
x.call_bar(obj).should == 'quux'
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not propagate refinements of new modules added after it is called" do
|
||||||
|
cls = Class.new {def foo; 'foo'; end}
|
||||||
|
cls2 = Class.new {def bar; 'bar'; end}
|
||||||
|
mod = MainSpecs::DATA[:mod] = Module.new do
|
||||||
|
refine(cls) do
|
||||||
|
def foo; 'quux'; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
x = MainSpecs::DATA[:x] = Object.new
|
||||||
|
eval <<-EOS, TOPLEVEL_BINDING
|
||||||
|
using MainSpecs::DATA[:mod]
|
||||||
|
x = MainSpecs::DATA[:x]
|
||||||
|
def x.call_foo(obj)
|
||||||
|
obj.foo
|
||||||
|
end
|
||||||
|
def x.call_bar(obj)
|
||||||
|
obj.bar
|
||||||
|
end
|
||||||
|
EOS
|
||||||
|
|
||||||
|
x.call_foo(cls.new).should == 'quux'
|
||||||
|
|
||||||
|
mod.module_eval do
|
||||||
|
refine(cls2) do
|
||||||
|
def bar; 'quux'; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
x.call_bar(cls2.new).should == 'bar'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
13
spec/ruby/core/module/fixtures/refine.rb
Normal file
13
spec/ruby/core/module/fixtures/refine.rb
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
module ModuleSpecs
|
||||||
|
class ClassWithFoo
|
||||||
|
def foo; "foo" end
|
||||||
|
end
|
||||||
|
|
||||||
|
module PrependedModule
|
||||||
|
def foo; "foo from prepended module"; end
|
||||||
|
end
|
||||||
|
|
||||||
|
module IncludedModule
|
||||||
|
def foo; "foo from included module"; end
|
||||||
|
end
|
||||||
|
end
|
10
spec/ruby/core/module/fixtures/using.rb
Normal file
10
spec/ruby/core/module/fixtures/using.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
module ModuleSpecs
|
||||||
|
module EmptyRefinement
|
||||||
|
end
|
||||||
|
|
||||||
|
module RefinementForStringToS
|
||||||
|
refine String do
|
||||||
|
def to_s; "hello from refinement"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
616
spec/ruby/core/module/refine_spec.rb
Normal file
616
spec/ruby/core/module/refine_spec.rb
Normal file
|
@ -0,0 +1,616 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
require File.expand_path('../fixtures/refine', __FILE__)
|
||||||
|
|
||||||
|
describe "Module#refine" do
|
||||||
|
it "runs its block in an anonymous module" do
|
||||||
|
inner_self = nil
|
||||||
|
mod = Module.new do
|
||||||
|
refine String do
|
||||||
|
inner_self = self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mod.should_not == inner_self
|
||||||
|
inner_self.should be_kind_of(Module)
|
||||||
|
inner_self.name.should == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "uses the same anonymous module for future refines of the same class" do
|
||||||
|
selves = []
|
||||||
|
mod = Module.new do
|
||||||
|
refine String do
|
||||||
|
selves << self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mod.module_eval do
|
||||||
|
refine String do
|
||||||
|
selves << self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
selves[0].should == selves[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "adds methods defined in its block to the anonymous module's public instance methods" do
|
||||||
|
inner_self = nil
|
||||||
|
mod = Module.new do
|
||||||
|
refine String do
|
||||||
|
def blah
|
||||||
|
"blah"
|
||||||
|
end
|
||||||
|
inner_self = self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
inner_self.public_instance_methods.should include(:blah)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns created anonymous module" do
|
||||||
|
inner_self = nil
|
||||||
|
result = nil
|
||||||
|
mod = Module.new do
|
||||||
|
result = refine String do
|
||||||
|
inner_self = self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == inner_self
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises ArgumentError if not passed an argument" do
|
||||||
|
lambda do
|
||||||
|
Module.new do
|
||||||
|
refine {}
|
||||||
|
end
|
||||||
|
end.should raise_error(ArgumentError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises TypeError if not passed a class" do
|
||||||
|
lambda do
|
||||||
|
Module.new do
|
||||||
|
refine("foo") {}
|
||||||
|
end
|
||||||
|
end.should raise_error(TypeError)
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_version_is "" ... "2.4" do
|
||||||
|
it "raises TypeError if passed a module" do
|
||||||
|
lambda do
|
||||||
|
Module.new do
|
||||||
|
refine(Enumerable) {}
|
||||||
|
end
|
||||||
|
end.should raise_error(TypeError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
it "accepts a module as argument" do
|
||||||
|
inner_self = nil
|
||||||
|
Module.new do
|
||||||
|
refine(Enumerable) do
|
||||||
|
def blah
|
||||||
|
end
|
||||||
|
inner_self = self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
inner_self.public_instance_methods.should include(:blah)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises ArgumentError if not given a block" do
|
||||||
|
lambda do
|
||||||
|
Module.new do
|
||||||
|
refine String
|
||||||
|
end
|
||||||
|
end.should raise_error(ArgumentError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "applies refinements to calls in the refine block" do
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
refine(String) do
|
||||||
|
def foo; "foo"; end
|
||||||
|
result = "hello".foo
|
||||||
|
end
|
||||||
|
end
|
||||||
|
result.should == "foo"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't apply refinements outside the refine block" do
|
||||||
|
Module.new do
|
||||||
|
refine(String) {def foo; "foo"; end}
|
||||||
|
-> () {
|
||||||
|
"hello".foo
|
||||||
|
}.should raise_error(NoMethodError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not apply refinements to external scopes not using the module" do
|
||||||
|
Module.new do
|
||||||
|
refine(String) {def foo; 'foo'; end}
|
||||||
|
end
|
||||||
|
|
||||||
|
lambda {"hello".foo}.should raise_error(NoMethodError)
|
||||||
|
end
|
||||||
|
|
||||||
|
# When defining multiple refinements in the same module,
|
||||||
|
# inside a refine block all refinements from the same
|
||||||
|
# module are active when a refined method is called
|
||||||
|
it "makes available all refinements from the same module" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine Integer do
|
||||||
|
def to_json_format
|
||||||
|
to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
refine Array do
|
||||||
|
def to_json_format
|
||||||
|
"[" + map { |i| i.to_json_format }.join(", ") + "]"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
refine Hash do
|
||||||
|
def to_json_format
|
||||||
|
"{" + map { |k, v| k.to_s.dump + ": " + v.to_json_format }.join(", ") + "}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
|
||||||
|
result = [{1 => 2}, {3 => 4}].to_json_format
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == '[{"1": 2}, {"3": 4}]'
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not make available methods from another refinement module" do
|
||||||
|
refinery_integer = Module.new do
|
||||||
|
refine Integer do
|
||||||
|
def to_json_format
|
||||||
|
to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
refinery_array = Module.new do
|
||||||
|
refine Array do
|
||||||
|
def to_json_format
|
||||||
|
"[" + map { |i| i.to_json_format }.join(",") + "]"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
|
||||||
|
-> () {
|
||||||
|
Module.new do
|
||||||
|
using refinery_integer
|
||||||
|
using refinery_array
|
||||||
|
|
||||||
|
[1, 2].to_json_format
|
||||||
|
end
|
||||||
|
}.should raise_error(NoMethodError)
|
||||||
|
end
|
||||||
|
|
||||||
|
# method lookup:
|
||||||
|
# * The prepended modules from the refinement for C
|
||||||
|
# * The refinement for C
|
||||||
|
# * The included modules from the refinement for C
|
||||||
|
# * The prepended modules of C
|
||||||
|
# * C
|
||||||
|
# * The included modules of C
|
||||||
|
describe "method lookup" do
|
||||||
|
it "looks in the object singleton class first" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine ModuleSpecs::ClassWithFoo do
|
||||||
|
def foo; "foo from refinement"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
|
||||||
|
obj = ModuleSpecs::ClassWithFoo.new
|
||||||
|
class << obj
|
||||||
|
def foo; "foo from singleton class"; end
|
||||||
|
end
|
||||||
|
result = obj.foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo from singleton class"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "looks in prepended modules from the refinement first" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine ModuleSpecs::ClassWithFoo do
|
||||||
|
include ModuleSpecs::IncludedModule
|
||||||
|
prepend ModuleSpecs::PrependedModule
|
||||||
|
|
||||||
|
def foo; "foo from refinement"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = ModuleSpecs::ClassWithFoo.new.foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo from prepended module"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "looks in refinement then" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine(ModuleSpecs::ClassWithFoo) do
|
||||||
|
include ModuleSpecs::IncludedModule
|
||||||
|
|
||||||
|
def foo; "foo from refinement"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = ModuleSpecs::ClassWithFoo.new.foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo from refinement"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "looks in included modules from the refinement then" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine ModuleSpecs::ClassWithFoo do
|
||||||
|
include ModuleSpecs::IncludedModule
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = ModuleSpecs::ClassWithFoo.new.foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo from included module"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "looks in the class then" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine(ModuleSpecs::ClassWithFoo) { }
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = ModuleSpecs::ClassWithFoo.new.foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# methods in a subclass have priority over refinements in a superclass
|
||||||
|
it "does not override methods in subclasses" do
|
||||||
|
subclass = Class.new(ModuleSpecs::ClassWithFoo) do
|
||||||
|
def foo; "foo from subclass"; end
|
||||||
|
end
|
||||||
|
|
||||||
|
refinement = Module.new do
|
||||||
|
refine ModuleSpecs::ClassWithFoo do
|
||||||
|
def foo; "foo from refinement"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = subclass.new.foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo from subclass"
|
||||||
|
end
|
||||||
|
|
||||||
|
context "for methods accesses indirectly" do
|
||||||
|
ruby_version_is "" ... "2.4" do
|
||||||
|
it "is not honored by Kernel#send" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine ModuleSpecs::ClassWithFoo do
|
||||||
|
def foo; "foo from refinement"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = ModuleSpecs::ClassWithFoo.new.send :foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not honored by BasicObject#__send__" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine ModuleSpecs::ClassWithFoo do
|
||||||
|
def foo; "foo from refinement"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = ModuleSpecs::ClassWithFoo.new.__send__ :foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not honored by Symbol#to_proc" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine Integer do
|
||||||
|
def to_s
|
||||||
|
"(#{super})"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = [1, 2, 3].map(&:to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == ["1", "2", "3"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
it "is honored by Kernel#send" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine ModuleSpecs::ClassWithFoo do
|
||||||
|
def foo; "foo from refinement"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = ModuleSpecs::ClassWithFoo.new.send :foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo from refinement"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is honored by BasicObject#__send__" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine ModuleSpecs::ClassWithFoo do
|
||||||
|
def foo; "foo from refinement"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = ModuleSpecs::ClassWithFoo.new.__send__ :foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo from refinement"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is honored by Symbol#to_proc" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine Integer do
|
||||||
|
def to_s
|
||||||
|
"(#{super})"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = [1, 2, 3].map(&:to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == ["(1)", "(2)", "(3)"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is honored by Kernel#binding" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine String do
|
||||||
|
def to_s
|
||||||
|
"hello from refinement"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
klass = Class.new do
|
||||||
|
using refinement
|
||||||
|
|
||||||
|
def foo
|
||||||
|
"foo".to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_binding
|
||||||
|
binding
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = Kernel.eval("self.foo()", klass.new.get_binding)
|
||||||
|
result.should == "hello from refinement"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not honored by Kernel#method" do
|
||||||
|
klass = Class.new
|
||||||
|
refinement = Module.new do
|
||||||
|
refine klass do
|
||||||
|
def foo; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-> {
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
klass.new.method(:foo)
|
||||||
|
end
|
||||||
|
}.should raise_error(NameError, /undefined method `foo'/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not honored by Kernel#respond_to?" do
|
||||||
|
klass = Class.new
|
||||||
|
refinement = Module.new do
|
||||||
|
refine klass do
|
||||||
|
def foo; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = klass.new.respond_to?(:foo)
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when super is called in a refinement" do
|
||||||
|
it "looks in the included to refinery module" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine ModuleSpecs::ClassWithFoo do
|
||||||
|
include ModuleSpecs::IncludedModule
|
||||||
|
|
||||||
|
def foo
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = ModuleSpecs::ClassWithFoo.new.foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo from included module"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "looks in the refined class" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine ModuleSpecs::ClassWithFoo do
|
||||||
|
def foo
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = ModuleSpecs::ClassWithFoo.new.foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo"
|
||||||
|
end
|
||||||
|
|
||||||
|
# super in a method of a refinement invokes the method in the refined
|
||||||
|
# class even if there is another refinement which has been activated
|
||||||
|
# in the same context.
|
||||||
|
it "looks in the refined class even if there is another active refinement" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine ModuleSpecs::ClassWithFoo do
|
||||||
|
def foo
|
||||||
|
"foo from refinement"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
refinement_with_super = Module.new do
|
||||||
|
refine ModuleSpecs::ClassWithFoo do
|
||||||
|
def foo
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
using refinement_with_super
|
||||||
|
result = ModuleSpecs::ClassWithFoo.new.foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Refinements are inherited by module inclusion.
|
||||||
|
# That is, using activates all refinements in the ancestors of the specified module.
|
||||||
|
# Refinements in a descendant have priority over refinements in an ancestor.
|
||||||
|
context "module inclusion" do
|
||||||
|
it "activates all refinements from all ancestors" do
|
||||||
|
refinement_included = Module.new do
|
||||||
|
refine Integer do
|
||||||
|
def to_json_format
|
||||||
|
to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
refinement = Module.new do
|
||||||
|
include refinement_included
|
||||||
|
|
||||||
|
refine Array do
|
||||||
|
def to_json_format
|
||||||
|
"[" + map { |i| i.to_s }.join(", ") + "]"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = [5.to_json_format, [1, 2, 3].to_json_format]
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == ["5", "[1, 2, 3]"]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "overrides methods of ancestors by methods in descendants" do
|
||||||
|
refinement_included = Module.new do
|
||||||
|
refine Integer do
|
||||||
|
def to_json_format
|
||||||
|
to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
refinement = Module.new do
|
||||||
|
include refinement_included
|
||||||
|
|
||||||
|
refine Integer do
|
||||||
|
def to_json_format
|
||||||
|
"hello from refinement"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = 5.to_json_format
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "hello from refinement"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
276
spec/ruby/core/module/using_spec.rb
Normal file
276
spec/ruby/core/module/using_spec.rb
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
require File.expand_path('../fixtures/using', __FILE__)
|
||||||
|
|
||||||
|
describe "Module#using" do
|
||||||
|
it "imports class refinements from module into the current class/module" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine Integer do
|
||||||
|
def foo; "foo"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
result = 1.foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts module as argument" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine Integer do
|
||||||
|
def foo; "foo"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-> () {
|
||||||
|
Module.new do
|
||||||
|
using refinement
|
||||||
|
end
|
||||||
|
}.should_not raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts module without refinements" do
|
||||||
|
mod = Module.new
|
||||||
|
|
||||||
|
-> () {
|
||||||
|
Module.new do
|
||||||
|
using mod
|
||||||
|
end
|
||||||
|
}.should_not raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not accept class" do
|
||||||
|
klass = Class.new
|
||||||
|
|
||||||
|
-> () {
|
||||||
|
Module.new do
|
||||||
|
using klass
|
||||||
|
end
|
||||||
|
}.should raise_error(TypeError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises TypeError if passed something other than module" do
|
||||||
|
-> () {
|
||||||
|
Module.new do
|
||||||
|
using "foo"
|
||||||
|
end
|
||||||
|
}.should raise_error(TypeError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns self" do
|
||||||
|
refinement = Module.new
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
mod = Module.new do
|
||||||
|
result = using refinement
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should equal(mod)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "works in classes too" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine Integer do
|
||||||
|
def foo; "foo"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
Class.new do
|
||||||
|
using refinement
|
||||||
|
result = 1.foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises error in method scope" do
|
||||||
|
mod = Module.new do
|
||||||
|
def self.foo
|
||||||
|
using ModuleSpecs::EmptyRefinement
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-> () {
|
||||||
|
mod.foo
|
||||||
|
}.should raise_error(RuntimeError, /Module#using is not permitted in methods/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "activates refinement even for existed objects" do
|
||||||
|
result = nil
|
||||||
|
|
||||||
|
Module.new do
|
||||||
|
klass = Class.new do
|
||||||
|
def foo; "foo"; end
|
||||||
|
end
|
||||||
|
|
||||||
|
refinement = Module.new do
|
||||||
|
refine klass do
|
||||||
|
def foo; "foo from refinement"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
obj = klass.new
|
||||||
|
using refinement
|
||||||
|
result = obj.foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo from refinement"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "activates updates when refinement reopens later" do
|
||||||
|
result = nil
|
||||||
|
|
||||||
|
Module.new do
|
||||||
|
klass = Class.new do
|
||||||
|
def foo; "foo"; end
|
||||||
|
end
|
||||||
|
|
||||||
|
refinement = Module.new do
|
||||||
|
refine klass do
|
||||||
|
def foo; "foo from refinement"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
using refinement
|
||||||
|
|
||||||
|
refinement.class_eval do
|
||||||
|
refine klass do
|
||||||
|
def foo; "foo from reopened refinement"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
obj = klass.new
|
||||||
|
result = obj.foo
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo from reopened refinement"
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "scope of refinement" do
|
||||||
|
it "is active until the end of current class/module" do
|
||||||
|
ScratchPad.record []
|
||||||
|
|
||||||
|
Module.new do
|
||||||
|
Class.new do
|
||||||
|
using ModuleSpecs::RefinementForStringToS
|
||||||
|
ScratchPad << "1".to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
ScratchPad << "1".to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
ScratchPad.recorded.should == ["hello from refinement", "1"]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Refinements are lexical in scope.
|
||||||
|
# Refinements are only active within a scope after the call to using.
|
||||||
|
# Any code before the using statement will not have the refinement activated.
|
||||||
|
it "is not active before the `using` call" do
|
||||||
|
ScratchPad.record []
|
||||||
|
|
||||||
|
Module.new do
|
||||||
|
Class.new do
|
||||||
|
ScratchPad << "1".to_s
|
||||||
|
using ModuleSpecs::RefinementForStringToS
|
||||||
|
ScratchPad << "1".to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ScratchPad.recorded.should == ["1", "hello from refinement"]
|
||||||
|
end
|
||||||
|
|
||||||
|
# If you call a method that is defined outside the current scope
|
||||||
|
# the refinement will be deactivated
|
||||||
|
it "is not active for code defined outside the current scope" do
|
||||||
|
result = nil
|
||||||
|
|
||||||
|
Module.new do
|
||||||
|
klass = Class.new do
|
||||||
|
def foo; "foo"; end
|
||||||
|
end
|
||||||
|
|
||||||
|
refinement = Module.new do
|
||||||
|
refine klass do
|
||||||
|
def foo; "foo from refinement"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.call_foo(c)
|
||||||
|
c.foo
|
||||||
|
end
|
||||||
|
|
||||||
|
using refinement
|
||||||
|
|
||||||
|
result = call_foo(klass.new)
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "foo"
|
||||||
|
end
|
||||||
|
|
||||||
|
# If a method is defined in a scope where a refinement is active
|
||||||
|
# the refinement will be active when the method is called.
|
||||||
|
it "is active for method defined in a scope wherever it's called" do
|
||||||
|
klass = Class.new do
|
||||||
|
def foo; "foo"; end
|
||||||
|
end
|
||||||
|
|
||||||
|
mod = Module.new do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine klass do
|
||||||
|
def foo; "foo from refinement"; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
using refinement
|
||||||
|
|
||||||
|
def self.call_foo(c)
|
||||||
|
c.foo
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
c = klass.new
|
||||||
|
mod.call_foo(c).should == "foo from refinement"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not active if `using` call is not evaluated" do
|
||||||
|
result = nil
|
||||||
|
|
||||||
|
Module.new do
|
||||||
|
if false
|
||||||
|
using ModuleSpecs::RefinementForStringToS
|
||||||
|
end
|
||||||
|
result = "1".to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == "1"
|
||||||
|
end
|
||||||
|
|
||||||
|
# The refinements in module are not activated automatically
|
||||||
|
# if the class is reopened later
|
||||||
|
it "is not active when class/module reopens" do
|
||||||
|
refinement = Module.new do
|
||||||
|
refine String do
|
||||||
|
def to_s
|
||||||
|
"hello from refinement"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = []
|
||||||
|
klass = Class.new do
|
||||||
|
using refinement
|
||||||
|
result << "1".to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
klass.class_eval do
|
||||||
|
result << "1".to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == ["hello from refinement", "1"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -33,14 +33,9 @@ describe "Mutex#lock" do
|
||||||
# related to this ML thread.
|
# related to this ML thread.
|
||||||
it "raises a ThreadError when used recursively" do
|
it "raises a ThreadError when used recursively" do
|
||||||
m = Mutex.new
|
m = Mutex.new
|
||||||
|
m.lock
|
||||||
th = Thread.new do
|
-> {
|
||||||
m.lock
|
m.lock
|
||||||
m.lock
|
}.should raise_error(ThreadError)
|
||||||
end
|
|
||||||
|
|
||||||
lambda do
|
|
||||||
th.join
|
|
||||||
end.should raise_error(ThreadError)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
9
spec/ruby/core/nil/dup_spec.rb
Normal file
9
spec/ruby/core/nil/dup_spec.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
describe "NilClass#dup" do
|
||||||
|
it "returns self" do
|
||||||
|
nil.dup.should equal(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -17,7 +17,7 @@ describe "Numeric#coerce" do
|
||||||
# I (emp) think that this behavior is actually a bug in MRI. It's here as documentation
|
# I (emp) think that this behavior is actually a bug in MRI. It's here as documentation
|
||||||
# of the behavior until we find out if it's a bug.
|
# of the behavior until we find out if it's a bug.
|
||||||
quarantine! do
|
quarantine! do
|
||||||
it "considers the presense of a metaclass when checking the class of the objects" do
|
it "considers the presence of a metaclass when checking the class of the objects" do
|
||||||
a = NumericSpecs::Subclass.new
|
a = NumericSpecs::Subclass.new
|
||||||
b = NumericSpecs::Subclass.new
|
b = NumericSpecs::Subclass.new
|
||||||
|
|
||||||
|
|
10
spec/ruby/core/numeric/finite_spec.rb
Normal file
10
spec/ruby/core/numeric/finite_spec.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
describe "Numeric#finite?" do
|
||||||
|
it "returns true by default" do
|
||||||
|
o = mock_numeric("finite")
|
||||||
|
o.finite?.should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
10
spec/ruby/core/numeric/infinite_spec.rb
Normal file
10
spec/ruby/core/numeric/infinite_spec.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
describe "Numeric#infinite?" do
|
||||||
|
it "returns nil by default" do
|
||||||
|
o = mock_numeric("infinite")
|
||||||
|
o.infinite?.should == nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,8 +5,11 @@ describe "Process.wait2" do
|
||||||
# HACK: this kludge is temporarily necessary because some
|
# HACK: this kludge is temporarily necessary because some
|
||||||
# misbehaving spec somewhere else does not clear processes
|
# misbehaving spec somewhere else does not clear processes
|
||||||
begin
|
begin
|
||||||
|
Process.wait(-1, Process::WNOHANG)
|
||||||
|
$stderr.puts "Leaked process before wait2 specs! Waiting for it"
|
||||||
leaked = Process.waitall
|
leaked = Process.waitall
|
||||||
puts "leaked before wait2 specs: #{leaked}" unless leaked.empty?
|
$stderr.puts "leaked before wait2 specs: #{leaked}"
|
||||||
|
rescue Errno::ECHILD # No child processes
|
||||||
rescue NotImplementedError
|
rescue NotImplementedError
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,14 +19,14 @@ describe "Random#bytes" do
|
||||||
end
|
end
|
||||||
|
|
||||||
# Should double check this is official spec
|
# Should double check this is official spec
|
||||||
it "returns the same numeric output for a given seed accross all implementations and platforms" do
|
it "returns the same numeric output for a given seed across all implementations and platforms" do
|
||||||
rnd = Random.new(33)
|
rnd = Random.new(33)
|
||||||
rnd.bytes(2).should == "\x14\\"
|
rnd.bytes(2).should == "\x14\\"
|
||||||
rnd.bytes(1000) # skip some
|
rnd.bytes(1000) # skip some
|
||||||
rnd.bytes(2).should == "\xA1p"
|
rnd.bytes(2).should == "\xA1p"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns the same numeric output for a given huge seed accross all implementations and platforms" do
|
it "returns the same numeric output for a given huge seed across all implementations and platforms" do
|
||||||
rnd = Random.new(bignum_value ** 4)
|
rnd = Random.new(bignum_value ** 4)
|
||||||
rnd.bytes(2).should == "_\x91"
|
rnd.bytes(2).should == "_\x91"
|
||||||
rnd.bytes(1000) # skip some
|
rnd.bytes(1000) # skip some
|
||||||
|
|
|
@ -44,6 +44,14 @@ describe "String#capitalize!" do
|
||||||
a.should == "Hello"
|
a.should == "Hello"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
it "capitalizes self in place for all of Unicode" do
|
||||||
|
a = "äöü"
|
||||||
|
a.capitalize!.should equal(a)
|
||||||
|
a.should == "Äöü"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "returns nil when no changes are made" do
|
it "returns nil when no changes are made" do
|
||||||
a = "Hello"
|
a = "Hello"
|
||||||
a.capitalize!.should == nil
|
a.capitalize!.should == nil
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# -*- encoding: ascii-8bit -*-
|
# -*- encoding: utf-8 -*-
|
||||||
require File.expand_path('../../../spec_helper', __FILE__)
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||||
|
|
||||||
|
@ -40,10 +40,10 @@ describe "String#casecmp independent of case" do
|
||||||
describe "in UTF-8 mode" do
|
describe "in UTF-8 mode" do
|
||||||
describe "for non-ASCII characters" do
|
describe "for non-ASCII characters" do
|
||||||
before :each do
|
before :each do
|
||||||
@upper_a_tilde = "\xc3\x83"
|
@upper_a_tilde = "Ã"
|
||||||
@lower_a_tilde = "\xc3\xa3"
|
@lower_a_tilde = "ã"
|
||||||
@upper_a_umlaut = "\xc3\x84"
|
@upper_a_umlaut = "Ä"
|
||||||
@lower_a_umlaut = "\xc3\xa4"
|
@lower_a_umlaut = "ä"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns -1 when numerically less than other" do
|
it "returns -1 when numerically less than other" do
|
||||||
|
@ -118,3 +118,67 @@ describe "String#casecmp independent of case" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
describe 'String#casecmp? independent of case' do
|
||||||
|
it 'returns true when equal to other' do
|
||||||
|
'abc'.casecmp?('abc').should == true
|
||||||
|
'abc'.casecmp?('ABC').should == true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns false when not equal to other' do
|
||||||
|
'abc'.casecmp?('DEF').should == false
|
||||||
|
'abc'.casecmp?('def').should == false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "tries to convert other to string using to_str" do
|
||||||
|
other = mock('x')
|
||||||
|
other.should_receive(:to_str).and_return("abc")
|
||||||
|
|
||||||
|
"abc".casecmp?(other).should == true
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'for UNICODE characters' do
|
||||||
|
it 'returns true when downcase(:fold) on unicode' do
|
||||||
|
'äöü'.casecmp?('ÄÖÜ').should == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "when comparing a subclass instance" do
|
||||||
|
it 'returns true when equal to other' do
|
||||||
|
a = StringSpecs::MyString.new "a"
|
||||||
|
'a'.casecmp?(a).should == true
|
||||||
|
'A'.casecmp?(a).should == true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns false when not equal to other' do
|
||||||
|
b = StringSpecs::MyString.new "a"
|
||||||
|
'b'.casecmp?(b).should == false
|
||||||
|
'B'.casecmp?(b).should == false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "in UTF-8 mode" do
|
||||||
|
describe "for non-ASCII characters" do
|
||||||
|
before :each do
|
||||||
|
@upper_a_tilde = "Ã"
|
||||||
|
@lower_a_tilde = "ã"
|
||||||
|
@upper_a_umlaut = "Ä"
|
||||||
|
@lower_a_umlaut = "ä"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns true when they are the same with normalized case" do
|
||||||
|
@upper_a_tilde.casecmp?(@lower_a_tilde).should == true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false when they are unrelated" do
|
||||||
|
@upper_a_tilde.casecmp?(@upper_a_umlaut).should == false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns true when they have the same bytes" do
|
||||||
|
@upper_a_tilde.casecmp?(@upper_a_tilde).should == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -46,6 +46,14 @@ describe "String#downcase!" do
|
||||||
a.should == "hello"
|
a.should == "hello"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
it "modifies self in place for all of Unicode" do
|
||||||
|
a = "ÄÖÜ"
|
||||||
|
a.downcase!.should equal(a)
|
||||||
|
a.should == "äöü"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "returns nil if no modifications were made" do
|
it "returns nil if no modifications were made" do
|
||||||
a = "hello"
|
a = "hello"
|
||||||
a.downcase!.should == nil
|
a.downcase!.should == nil
|
||||||
|
|
|
@ -10,4 +10,13 @@ describe "String#lines" do
|
||||||
ary = "hello world".send(@method, ' ')
|
ary = "hello world".send(@method, ' ')
|
||||||
ary.should == ["hello ", "world"]
|
ary.should == ["hello ", "world"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
context "when `chomp` keyword argument is passed" do
|
||||||
|
it "removes new line characters" do
|
||||||
|
"hello \nworld\n".lines(chomp: true).should == ["hello ", "world"]
|
||||||
|
"hello \r\nworld\r\n".lines(chomp: true).should == ["hello ", "world"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,6 +15,13 @@ describe "String.new" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
it "accepts a capacity argument" do
|
||||||
|
String.new("", capacity: 100_000).should == ""
|
||||||
|
String.new("abc", capacity: 100_000).should == "abc"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "returns a fully-formed String" do
|
it "returns a fully-formed String" do
|
||||||
str = String.new
|
str = String.new
|
||||||
str.size.should == 0
|
str.size.should == 0
|
||||||
|
|
|
@ -42,10 +42,8 @@ describe :string_chars, shared: true do
|
||||||
it "returns a different character if the String is transcoded" do
|
it "returns a different character if the String is transcoded" do
|
||||||
s = "\u{20AC}".force_encoding('UTF-8')
|
s = "\u{20AC}".force_encoding('UTF-8')
|
||||||
s.encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".force_encoding('UTF-8')]
|
s.encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".force_encoding('UTF-8')]
|
||||||
s.encode('iso-8859-15').send(@method).to_a.should == [
|
s.encode('iso-8859-15').send(@method).to_a.should == [[0xA4].pack('C').force_encoding('iso-8859-15')]
|
||||||
[0xA4].pack('C').force_encoding('iso-8859-15')]
|
s.encode('iso-8859-15').encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".force_encoding('UTF-8')]
|
||||||
s.encode('iso-8859-15').encode('UTF-8').send(@method).to_a.should == [
|
|
||||||
"\u{20AC}".force_encoding('UTF-8')]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "uses the String's encoding to determine what characters it contains" do
|
it "uses the String's encoding to determine what characters it contains" do
|
||||||
|
|
|
@ -48,7 +48,7 @@ describe :string_codepoints, shared: true do
|
||||||
s.should == s2
|
s.should == s2
|
||||||
end
|
end
|
||||||
|
|
||||||
it "is synonomous with #bytes for Strings which are single-byte optimisable" do
|
it "is synonymous with #bytes for Strings which are single-byte optimisable" do
|
||||||
s = "(){}".encode('ascii')
|
s = "(){}".encode('ascii')
|
||||||
s.ascii_only?.should be_true
|
s.ascii_only?.should be_true
|
||||||
s.send(@method).to_a.should == s.bytes.to_a
|
s.send(@method).to_a.should == s.bytes.to_a
|
||||||
|
|
|
@ -133,4 +133,18 @@ end
|
||||||
it "raises a TypeError when the separator is a symbol" do
|
it "raises a TypeError when the separator is a symbol" do
|
||||||
lambda { "hello world".send(@method, :o).to_a }.should raise_error(TypeError)
|
lambda { "hello world".send(@method, :o).to_a }.should raise_error(TypeError)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
context "when `chomp` keyword argument is passed" do
|
||||||
|
it "removes new line characters" do
|
||||||
|
a = []
|
||||||
|
"hello \nworld\n".send(@method, chomp: true) { |s| a << s }
|
||||||
|
a.should == ["hello ", "world"]
|
||||||
|
|
||||||
|
a = []
|
||||||
|
"hello \r\nworld\r\n".send(@method, chomp: true) { |s| a << s }
|
||||||
|
a.should == ["hello ", "world"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,24 +1,63 @@
|
||||||
describe :string_to_sym, shared: true do
|
describe :string_to_sym, shared: true do
|
||||||
it "returns the symbol corresponding to self" do
|
it "returns the symbol corresponding to self" do
|
||||||
"Koala".send(@method).should == :Koala
|
"Koala".send(@method).should equal :Koala
|
||||||
'cat'.send(@method).should == :cat
|
'cat'.send(@method).should equal :cat
|
||||||
'@cat'.send(@method).should == :@cat
|
'@cat'.send(@method).should equal :@cat
|
||||||
'cat and dog'.send(@method).should == :"cat and dog"
|
'cat and dog'.send(@method).should equal :"cat and dog"
|
||||||
"abc=".send(@method).should == :abc=
|
"abc=".send(@method).should equal :abc=
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not special case +(binary) and -(binary)" do
|
it "does not special case +(binary) and -(binary)" do
|
||||||
"+(binary)".send(@method).should == :"+(binary)"
|
"+(binary)".send(@method).should equal :"+(binary)"
|
||||||
"-(binary)".send(@method).should == :"-(binary)"
|
"-(binary)".send(@method).should equal :"-(binary)"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not special case certain operators" do
|
it "does not special case certain operators" do
|
||||||
[ ["!@", :"!@"],
|
"!@".send(@method).should equal :"!@"
|
||||||
["~@", :"~@"],
|
"~@".send(@method).should equal :"~@"
|
||||||
["!(unary)", :"!(unary)"],
|
"!(unary)".send(@method).should equal :"!(unary)"
|
||||||
["~(unary)", :"~(unary)"],
|
"~(unary)".send(@method).should equal :"~(unary)"
|
||||||
["+(unary)", :"+(unary)"],
|
"+(unary)".send(@method).should equal :"+(unary)"
|
||||||
["-(unary)", :"-(unary)"]
|
"-(unary)".send(@method).should equal :"-(unary)"
|
||||||
].should be_computed_by(@method)
|
end
|
||||||
|
|
||||||
|
it "returns a US-ASCII Symbol for a UTF-8 String containing only US-ASCII characters" do
|
||||||
|
sym = "foobar".send(@method)
|
||||||
|
sym.encoding.should == Encoding::US_ASCII
|
||||||
|
sym.should equal :"foobar"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a US-ASCII Symbol for a binary String containing only US-ASCII characters" do
|
||||||
|
sym = "foobar".b.send(@method)
|
||||||
|
sym.encoding.should == Encoding::US_ASCII
|
||||||
|
sym.should equal :"foobar"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a UTF-8 Symbol for a UTF-8 String containing non US-ASCII characters" do
|
||||||
|
sym = "il était une fois".send(@method)
|
||||||
|
sym.encoding.should == Encoding::UTF_8
|
||||||
|
sym.should equal :"il était une #{'fois'}"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a UTF-16LE Symbol for a UTF-16LE String containing non US-ASCII characters" do
|
||||||
|
utf16_str = "UtéF16".encode(Encoding::UTF_16LE)
|
||||||
|
sym = utf16_str.send(@method)
|
||||||
|
sym.encoding.should == Encoding::UTF_16LE
|
||||||
|
sym.to_s.should == utf16_str
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a binary Symbol for a binary String containing non US-ASCII characters" do
|
||||||
|
binary_string = "binarí".b
|
||||||
|
sym = binary_string.send(@method)
|
||||||
|
sym.encoding.should == Encoding::BINARY
|
||||||
|
sym.to_s.should == binary_string
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises an EncodingError for UTF-8 String containing invalid bytes" do
|
||||||
|
invalid_utf8 = "\xC3"
|
||||||
|
invalid_utf8.valid_encoding?.should == false
|
||||||
|
-> {
|
||||||
|
invalid_utf8.send(@method)
|
||||||
|
}.should raise_error(EncodingError, /invalid/)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,6 +41,14 @@ describe "String#swapcase!" do
|
||||||
a.should == "CyBeR_pUnK11"
|
a.should == "CyBeR_pUnK11"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
it "modifies self in place for all of Unicode" do
|
||||||
|
a = "äÖü"
|
||||||
|
a.swapcase!.should equal(a)
|
||||||
|
a.should == "ÄöÜ"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "returns nil if no modifications were made" do
|
it "returns nil if no modifications were made" do
|
||||||
a = "+++---111222???"
|
a = "+++---111222???"
|
||||||
a.swapcase!.should == nil
|
a.swapcase!.should == nil
|
||||||
|
|
12
spec/ruby/core/string/unpack1_spec.rb
Normal file
12
spec/ruby/core/string/unpack1_spec.rb
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
describe "String#unpack1" do
|
||||||
|
it "returns the first value of #unpack" do
|
||||||
|
"ABCD".unpack1('x3C').should == "ABCD".unpack('x3C')[0]
|
||||||
|
"\u{3042 3044 3046}".unpack1("U*").should == 0x3042
|
||||||
|
"aG9nZWZ1Z2E=".unpack1("m").should == "hogefuga"
|
||||||
|
"A".unpack1("B*").should == "01000001"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -46,6 +46,15 @@ describe "String#upcase!" do
|
||||||
a.should == "HELLO"
|
a.should == "HELLO"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
it "modifies self in place for all of Unicode" do
|
||||||
|
a = "äöü"
|
||||||
|
a.upcase!.should equal(a)
|
||||||
|
a.should == "ÄÖÜ"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "returns nil if no modifications were made" do
|
it "returns nil if no modifications were made" do
|
||||||
a = "HELLO"
|
a = "HELLO"
|
||||||
a.upcase!.should == nil
|
a.upcase!.should == nil
|
||||||
|
|
|
@ -37,7 +37,7 @@ describe "Struct#initialize" do
|
||||||
car.make.should == nil # still nil despite override in Honda#initialize b/c of super order
|
car.make.should == nil # still nil despite override in Honda#initialize b/c of super order
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can be overriden" do
|
it "can be overridden" do
|
||||||
StructClasses::SubclassX.new(:y).new.key.should == :value
|
StructClasses::SubclassX.new(:y).new.key.should == :value
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,6 +21,13 @@ describe "Symbol#capitalize" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
it "capitalizes the first character if it is Unicode" do
|
||||||
|
:"äöü".capitalize.should == :"Äöü"
|
||||||
|
:"aou".capitalize.should == :"Aou"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "converts subsequent uppercase ASCII characters to their lowercase equivalents" do
|
it "converts subsequent uppercase ASCII characters to their lowercase equivalents" do
|
||||||
:lOWER.capitalize.should == :Lower
|
:lOWER.capitalize.should == :Lower
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# -*- encoding: binary -*-
|
# -*- encoding: utf-8 -*-
|
||||||
require File.expand_path('../../../spec_helper', __FILE__)
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
describe "Symbol#casecmp with Symbol" do
|
describe "Symbol#casecmp with Symbol" do
|
||||||
|
@ -11,10 +11,10 @@ describe "Symbol#casecmp with Symbol" do
|
||||||
|
|
||||||
it "doesn't consider non-ascii characters equal that aren't" do
|
it "doesn't consider non-ascii characters equal that aren't" do
|
||||||
# -- Latin-1 --
|
# -- Latin-1 --
|
||||||
upper_a_tilde = :"\xC3"
|
upper_a_tilde = "\xC3".b.to_sym
|
||||||
upper_a_umlaut = :"\xC4"
|
upper_a_umlaut = "\xC4".b.to_sym
|
||||||
lower_a_tilde = :"\xE3"
|
lower_a_tilde = "\xE3".b.to_sym
|
||||||
lower_a_umlaut = :"\xE4"
|
lower_a_umlaut = "\xE4".b.to_sym
|
||||||
|
|
||||||
lower_a_tilde.casecmp(lower_a_umlaut).should_not == 0
|
lower_a_tilde.casecmp(lower_a_umlaut).should_not == 0
|
||||||
lower_a_umlaut.casecmp(lower_a_tilde).should_not == 0
|
lower_a_umlaut.casecmp(lower_a_tilde).should_not == 0
|
||||||
|
@ -22,10 +22,10 @@ describe "Symbol#casecmp with Symbol" do
|
||||||
upper_a_umlaut.casecmp(upper_a_tilde).should_not == 0
|
upper_a_umlaut.casecmp(upper_a_tilde).should_not == 0
|
||||||
|
|
||||||
# -- UTF-8 --
|
# -- UTF-8 --
|
||||||
upper_a_tilde = :"\xC3\x83"
|
upper_a_tilde = :"Ã"
|
||||||
upper_a_umlaut = :"\xC3\x84"
|
lower_a_tilde = :"ã"
|
||||||
lower_a_tilde = :"\xC3\xA3"
|
upper_a_umlaut = :"Ä"
|
||||||
lower_a_umlaut = :"\xC3\xA4"
|
lower_a_umlaut = :"ä"
|
||||||
|
|
||||||
lower_a_tilde.casecmp(lower_a_umlaut).should_not == 0
|
lower_a_tilde.casecmp(lower_a_umlaut).should_not == 0
|
||||||
lower_a_umlaut.casecmp(lower_a_tilde).should_not == 0
|
lower_a_umlaut.casecmp(lower_a_tilde).should_not == 0
|
||||||
|
@ -35,10 +35,10 @@ describe "Symbol#casecmp with Symbol" do
|
||||||
|
|
||||||
it "doesn't do case mapping for non-ascii characters" do
|
it "doesn't do case mapping for non-ascii characters" do
|
||||||
# -- Latin-1 --
|
# -- Latin-1 --
|
||||||
upper_a_tilde = :"\xC3"
|
upper_a_tilde = "\xC3".b.to_sym
|
||||||
upper_a_umlaut = :"\xC4"
|
upper_a_umlaut = "\xC4".b.to_sym
|
||||||
lower_a_tilde = :"\xE3"
|
lower_a_tilde = "\xE3".b.to_sym
|
||||||
lower_a_umlaut = :"\xE4"
|
lower_a_umlaut = "\xE4".b.to_sym
|
||||||
|
|
||||||
upper_a_tilde.casecmp(lower_a_tilde).should == -1
|
upper_a_tilde.casecmp(lower_a_tilde).should == -1
|
||||||
upper_a_umlaut.casecmp(lower_a_umlaut).should == -1
|
upper_a_umlaut.casecmp(lower_a_umlaut).should == -1
|
||||||
|
@ -46,10 +46,10 @@ describe "Symbol#casecmp with Symbol" do
|
||||||
lower_a_umlaut.casecmp(upper_a_umlaut).should == 1
|
lower_a_umlaut.casecmp(upper_a_umlaut).should == 1
|
||||||
|
|
||||||
# -- UTF-8 --
|
# -- UTF-8 --
|
||||||
upper_a_tilde = :"\xC3\x83"
|
upper_a_tilde = :"Ã"
|
||||||
upper_a_umlaut = :"\xC3\x84"
|
lower_a_tilde = :"ã"
|
||||||
lower_a_tilde = :"\xC3\xA3"
|
upper_a_umlaut = :"Ä"
|
||||||
lower_a_umlaut = :"\xC3\xA4"
|
lower_a_umlaut = :"ä"
|
||||||
|
|
||||||
upper_a_tilde.casecmp(lower_a_tilde).should == -1
|
upper_a_tilde.casecmp(lower_a_tilde).should == -1
|
||||||
upper_a_umlaut.casecmp(lower_a_umlaut).should == -1
|
upper_a_umlaut.casecmp(lower_a_umlaut).should == -1
|
||||||
|
@ -72,3 +72,75 @@ describe "Symbol#casecmp" do
|
||||||
:abc.casecmp(obj).should be_nil
|
:abc.casecmp(obj).should be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
describe 'Symbol#casecmp?' do
|
||||||
|
it "compares symbols without regard to case" do
|
||||||
|
:abcdef.casecmp?(:abcde).should == false
|
||||||
|
:aBcDeF.casecmp?(:abcdef).should == true
|
||||||
|
:abcdef.casecmp?(:abcdefg).should == false
|
||||||
|
:abcdef.casecmp?(:ABCDEF).should == true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't consider non-ascii characters equal that aren't" do
|
||||||
|
# -- Latin-1 --
|
||||||
|
upper_a_tilde = "\xC3".b.to_sym
|
||||||
|
upper_a_umlaut = "\xC4".b.to_sym
|
||||||
|
lower_a_tilde = "\xE3".b.to_sym
|
||||||
|
lower_a_umlaut = "\xE4".b.to_sym
|
||||||
|
|
||||||
|
lower_a_tilde.casecmp?(lower_a_umlaut).should_not == true
|
||||||
|
lower_a_umlaut.casecmp?(lower_a_tilde).should_not == true
|
||||||
|
upper_a_tilde.casecmp?(upper_a_umlaut).should_not == true
|
||||||
|
upper_a_umlaut.casecmp?(upper_a_tilde).should_not == true
|
||||||
|
|
||||||
|
# -- UTF-8 --
|
||||||
|
upper_a_tilde = :"Ã"
|
||||||
|
lower_a_tilde = :"ã"
|
||||||
|
upper_a_umlaut = :"Ä"
|
||||||
|
lower_a_umlaut = :"ä"
|
||||||
|
|
||||||
|
lower_a_tilde.casecmp?(lower_a_umlaut).should_not == true
|
||||||
|
lower_a_umlaut.casecmp?(lower_a_tilde).should_not == true
|
||||||
|
upper_a_tilde.casecmp?(upper_a_umlaut).should_not == true
|
||||||
|
upper_a_umlaut.casecmp?(upper_a_tilde).should_not == true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't do case mapping for non-ascii and non-unicode characters" do
|
||||||
|
# -- Latin-1 --
|
||||||
|
upper_a_tilde = "\xC3".b.to_sym
|
||||||
|
upper_a_umlaut = "\xC4".b.to_sym
|
||||||
|
lower_a_tilde = "\xE3".b.to_sym
|
||||||
|
lower_a_umlaut = "\xE4".b.to_sym
|
||||||
|
|
||||||
|
upper_a_tilde.casecmp?(lower_a_tilde).should == false
|
||||||
|
upper_a_umlaut.casecmp?(lower_a_umlaut).should == false
|
||||||
|
lower_a_tilde.casecmp?(upper_a_tilde).should == false
|
||||||
|
lower_a_umlaut.casecmp?(upper_a_umlaut).should == false
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does case mapping for unicode characters' do
|
||||||
|
# -- UTF-8 --
|
||||||
|
upper_a_tilde = :"Ã"
|
||||||
|
lower_a_tilde = :"ã"
|
||||||
|
upper_a_umlaut = :"Ä"
|
||||||
|
lower_a_umlaut = :"ä"
|
||||||
|
|
||||||
|
upper_a_tilde.casecmp?(lower_a_tilde).should == true
|
||||||
|
upper_a_umlaut.casecmp?(lower_a_umlaut).should == true
|
||||||
|
lower_a_tilde.casecmp?(upper_a_tilde).should == true
|
||||||
|
lower_a_umlaut.casecmp?(upper_a_umlaut).should == true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns nil when comparing characters with different encodings' do
|
||||||
|
# -- Latin-1 --
|
||||||
|
upper_a_tilde = "\xC3".b.to_sym
|
||||||
|
|
||||||
|
# -- UTF-8 --
|
||||||
|
lower_a_tilde = :"ã"
|
||||||
|
|
||||||
|
upper_a_tilde.casecmp?(lower_a_tilde).should == nil
|
||||||
|
lower_a_tilde.casecmp?(upper_a_tilde).should == nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -20,6 +20,13 @@ describe "Symbol#downcase" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
it "uncapitalizes all Unicode characters" do
|
||||||
|
"ÄÖÜ".to_sym.downcase.should == :"äöü"
|
||||||
|
"AOU".to_sym.downcase.should == :"aou"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "leaves non-alphabetic ASCII characters as they were" do
|
it "leaves non-alphabetic ASCII characters as they were" do
|
||||||
"Glark?!?".to_sym.downcase.should == :"glark?!?"
|
"Glark?!?".to_sym.downcase.should == :"glark?!?"
|
||||||
end
|
end
|
||||||
|
|
9
spec/ruby/core/symbol/dup_spec.rb
Normal file
9
spec/ruby/core/symbol/dup_spec.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
describe "Symbol#dup" do
|
||||||
|
it "returns self" do
|
||||||
|
:a_symbol.dup.should equal(:a_symbol)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -28,6 +28,13 @@ describe "Symbol#swapcase" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
it "swaps the case for Unicode characters" do
|
||||||
|
"äÖü".to_sym.swapcase.should == :"ÄöÜ"
|
||||||
|
"aOu".to_sym.swapcase.should == :"AoU"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "leaves non-alphabetic ASCII characters as they were" do
|
it "leaves non-alphabetic ASCII characters as they were" do
|
||||||
"Glark?!?".to_sym.swapcase.should == :"gLARK?!?"
|
"Glark?!?".to_sym.swapcase.should == :"gLARK?!?"
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,6 +16,13 @@ describe "Symbol#upcase" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is '2.4' do
|
||||||
|
it "capitalizes all Unicode characters" do
|
||||||
|
"äöü".to_sym.upcase.should == :"ÄÖÜ"
|
||||||
|
"aou".to_sym.upcase.should == :"AOU"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "leaves non-alphabetic ASCII characters as they were" do
|
it "leaves non-alphabetic ASCII characters as they were" do
|
||||||
"Glark?!?".to_sym.upcase.should == :"GLARK?!?"
|
"Glark?!?".to_sym.upcase.should == :"GLARK?!?"
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,12 +9,12 @@ describe "Thread#[]=" do
|
||||||
it "raises a RuntimeError if the thread is frozen" do
|
it "raises a RuntimeError if the thread is frozen" do
|
||||||
running = false
|
running = false
|
||||||
t = Thread.new do
|
t = Thread.new do
|
||||||
Thread.pass until running
|
|
||||||
t.freeze
|
t.freeze
|
||||||
t[:foo] = "bar"
|
-> {
|
||||||
|
t[:foo] = "bar"
|
||||||
|
}.should raise_error(RuntimeError, /frozen/)
|
||||||
end
|
end
|
||||||
running = true
|
t.join
|
||||||
lambda { t.join }.should raise_error(RuntimeError)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises exceptions on the wrong type of keys" do
|
it "raises exceptions on the wrong type of keys" do
|
||||||
|
|
|
@ -120,7 +120,10 @@ module ThreadSpecs
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.status_of_thread_with_uncaught_exception
|
def self.status_of_thread_with_uncaught_exception
|
||||||
t = Thread.new { raise "error" }
|
t = Thread.new {
|
||||||
|
Thread.current.report_on_exception = false
|
||||||
|
raise "error"
|
||||||
|
}
|
||||||
begin
|
begin
|
||||||
t.join
|
t.join
|
||||||
rescue RuntimeError
|
rescue RuntimeError
|
||||||
|
@ -159,6 +162,7 @@ module ThreadSpecs
|
||||||
|
|
||||||
def self.dying_thread_ensures(kill_method_name=:kill)
|
def self.dying_thread_ensures(kill_method_name=:kill)
|
||||||
Thread.new do
|
Thread.new do
|
||||||
|
Thread.current.report_on_exception = false
|
||||||
begin
|
begin
|
||||||
Thread.current.send(kill_method_name)
|
Thread.current.send(kill_method_name)
|
||||||
ensure
|
ensure
|
||||||
|
@ -169,6 +173,7 @@ module ThreadSpecs
|
||||||
|
|
||||||
def self.dying_thread_with_outer_ensure(kill_method_name=:kill)
|
def self.dying_thread_with_outer_ensure(kill_method_name=:kill)
|
||||||
Thread.new do
|
Thread.new do
|
||||||
|
Thread.current.report_on_exception = false
|
||||||
begin
|
begin
|
||||||
begin
|
begin
|
||||||
Thread.current.send(kill_method_name)
|
Thread.current.send(kill_method_name)
|
||||||
|
|
|
@ -46,7 +46,10 @@ describe "Thread#join" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises any exceptions encountered in the thread body" do
|
it "raises any exceptions encountered in the thread body" do
|
||||||
t = Thread.new { raise NotImplementedError.new("Just kidding") }
|
t = Thread.new {
|
||||||
|
Thread.current.report_on_exception = false
|
||||||
|
raise NotImplementedError.new("Just kidding")
|
||||||
|
}
|
||||||
lambda { t.join }.should raise_error(NotImplementedError)
|
lambda { t.join }.should raise_error(NotImplementedError)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ describe "Thread#key?" do
|
||||||
@th.join
|
@th.join
|
||||||
end
|
end
|
||||||
|
|
||||||
it "tests for existance of thread local variables using symbols or strings" do
|
it "tests for existence of thread local variables using symbols or strings" do
|
||||||
@th.key?(:oliver).should == true
|
@th.key?(:oliver).should == true
|
||||||
@th.key?("oliver").should == true
|
@th.key?("oliver").should == true
|
||||||
@th.key?(:stanley).should == false
|
@th.key?(:stanley).should == false
|
||||||
|
|
|
@ -51,6 +51,7 @@ describe "Thread#raise on a sleeping thread" do
|
||||||
|
|
||||||
it "is captured and raised by Thread#value" do
|
it "is captured and raised by Thread#value" do
|
||||||
t = Thread.new do
|
t = Thread.new do
|
||||||
|
Thread.current.report_on_exception = false
|
||||||
sleep
|
sleep
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -62,6 +63,7 @@ describe "Thread#raise on a sleeping thread" do
|
||||||
|
|
||||||
it "raises a RuntimeError when called with no arguments inside rescue" do
|
it "raises a RuntimeError when called with no arguments inside rescue" do
|
||||||
t = Thread.new do
|
t = Thread.new do
|
||||||
|
Thread.current.report_on_exception = false
|
||||||
begin
|
begin
|
||||||
1/0
|
1/0
|
||||||
rescue ZeroDivisionError
|
rescue ZeroDivisionError
|
||||||
|
@ -113,6 +115,7 @@ describe "Thread#raise on a running thread" do
|
||||||
|
|
||||||
it "can go unhandled" do
|
it "can go unhandled" do
|
||||||
t = Thread.new do
|
t = Thread.new do
|
||||||
|
Thread.current.report_on_exception = false
|
||||||
loop { Thread.pass }
|
loop { Thread.pass }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -123,6 +126,7 @@ describe "Thread#raise on a running thread" do
|
||||||
it "raises the given argument even when there is an active exception" do
|
it "raises the given argument even when there is an active exception" do
|
||||||
raised = false
|
raised = false
|
||||||
t = Thread.new do
|
t = Thread.new do
|
||||||
|
Thread.current.report_on_exception = false
|
||||||
begin
|
begin
|
||||||
1/0
|
1/0
|
||||||
rescue ZeroDivisionError
|
rescue ZeroDivisionError
|
||||||
|
@ -142,6 +146,7 @@ describe "Thread#raise on a running thread" do
|
||||||
it "raises a RuntimeError when called with no arguments inside rescue" do
|
it "raises a RuntimeError when called with no arguments inside rescue" do
|
||||||
raised = false
|
raised = false
|
||||||
t = Thread.new do
|
t = Thread.new do
|
||||||
|
Thread.current.report_on_exception = false
|
||||||
begin
|
begin
|
||||||
1/0
|
1/0
|
||||||
rescue ZeroDivisionError
|
rescue ZeroDivisionError
|
||||||
|
@ -164,6 +169,7 @@ describe "Thread#raise on same thread" do
|
||||||
|
|
||||||
it "raises a RuntimeError when called with no arguments inside rescue" do
|
it "raises a RuntimeError when called with no arguments inside rescue" do
|
||||||
t = Thread.new do
|
t = Thread.new do
|
||||||
|
Thread.current.report_on_exception = false
|
||||||
begin
|
begin
|
||||||
1/0
|
1/0
|
||||||
rescue ZeroDivisionError
|
rescue ZeroDivisionError
|
||||||
|
|
102
spec/ruby/core/thread/report_on_exception_spec.rb
Normal file
102
spec/ruby/core/thread/report_on_exception_spec.rb
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
ruby_version_is "2.4" do
|
||||||
|
describe "Thread.report_on_exception" do
|
||||||
|
it "defaults to false" do
|
||||||
|
ruby_exe("p Thread.report_on_exception").should == "false\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Thread.report_on_exception=" do
|
||||||
|
before :each do
|
||||||
|
@report_on_exception = Thread.report_on_exception
|
||||||
|
end
|
||||||
|
|
||||||
|
after :each do
|
||||||
|
Thread.report_on_exception = @report_on_exception
|
||||||
|
end
|
||||||
|
|
||||||
|
it "changes the default value for new threads" do
|
||||||
|
Thread.report_on_exception = true
|
||||||
|
Thread.report_on_exception.should == true
|
||||||
|
t = Thread.new {}
|
||||||
|
t.join
|
||||||
|
t.report_on_exception.should == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Thread#report_on_exception" do
|
||||||
|
it "returns whether the Thread will print a backtrace if it exits with an exception" do
|
||||||
|
t = Thread.new { Thread.current.report_on_exception = true }
|
||||||
|
t.join
|
||||||
|
t.report_on_exception.should == true
|
||||||
|
|
||||||
|
t = Thread.new { Thread.current.report_on_exception = false }
|
||||||
|
t.join
|
||||||
|
t.report_on_exception.should == false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Thread#report_on_exception=" do
|
||||||
|
describe "when set to true" do
|
||||||
|
it "prints a backtrace on $stderr if it terminates with an exception" do
|
||||||
|
t = nil
|
||||||
|
-> {
|
||||||
|
t = Thread.new {
|
||||||
|
Thread.current.report_on_exception = true
|
||||||
|
raise RuntimeError, "Thread#report_on_exception specs"
|
||||||
|
}
|
||||||
|
Thread.pass while t.alive?
|
||||||
|
}.should output("", /Thread.+terminated with exception.+Thread#report_on_exception specs/m)
|
||||||
|
|
||||||
|
-> {
|
||||||
|
t.join
|
||||||
|
}.should raise_error(RuntimeError, "Thread#report_on_exception specs")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "when set to false" do
|
||||||
|
it "lets the thread terminates silently with an exception" do
|
||||||
|
t = nil
|
||||||
|
-> {
|
||||||
|
t = Thread.new {
|
||||||
|
Thread.current.report_on_exception = false
|
||||||
|
raise RuntimeError, "Thread#report_on_exception specs"
|
||||||
|
}
|
||||||
|
Thread.pass while t.alive?
|
||||||
|
}.should output("", "")
|
||||||
|
|
||||||
|
-> {
|
||||||
|
t.join
|
||||||
|
}.should raise_error(RuntimeError, "Thread#report_on_exception specs")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_bug "#13163", "2.4"..."2.5" do
|
||||||
|
describe "when used in conjunction with Thread#abort_on_exception" do
|
||||||
|
it "first reports then send the exception back to the main Thread" do
|
||||||
|
t = nil
|
||||||
|
mutex = Mutex.new
|
||||||
|
mutex.lock
|
||||||
|
-> {
|
||||||
|
t = Thread.new {
|
||||||
|
Thread.current.abort_on_exception = true
|
||||||
|
Thread.current.report_on_exception = true
|
||||||
|
mutex.lock
|
||||||
|
mutex.unlock
|
||||||
|
raise RuntimeError, "Thread#report_on_exception specs"
|
||||||
|
}
|
||||||
|
|
||||||
|
-> {
|
||||||
|
mutex.sleep(5)
|
||||||
|
}.should raise_error(RuntimeError, "Thread#report_on_exception specs")
|
||||||
|
}.should output("", /Thread.+terminated with exception.+Thread#report_on_exception specs/m)
|
||||||
|
|
||||||
|
-> {
|
||||||
|
t.join
|
||||||
|
}.should raise_error(RuntimeError, "Thread#report_on_exception specs")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -112,7 +112,7 @@ describe :thread_exit, shared: true do
|
||||||
|
|
||||||
quarantine! do
|
quarantine! do
|
||||||
|
|
||||||
it "propogates inner exception to Thread.join if there is an outer ensure clause" do
|
it "propagates inner exception to Thread.join if there is an outer ensure clause" do
|
||||||
thread = ThreadSpecs.dying_thread_with_outer_ensure(@method) { }
|
thread = ThreadSpecs.dying_thread_with_outer_ensure(@method) { }
|
||||||
lambda { thread.join }.should raise_error(RuntimeError, "In dying thread")
|
lambda { thread.join }.should raise_error(RuntimeError, "In dying thread")
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,7 +7,10 @@ describe "Thread#value" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "re-raises an error for an uncaught exception" do
|
it "re-raises an error for an uncaught exception" do
|
||||||
t = Thread.new { raise "Hello" }
|
t = Thread.new {
|
||||||
|
Thread.current.report_on_exception = false
|
||||||
|
raise "Hello"
|
||||||
|
}
|
||||||
lambda { t.value }.should raise_error(RuntimeError, "Hello")
|
lambda { t.value }.should raise_error(RuntimeError, "Hello")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue