mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Update to ruby/spec@f8a2d54
This commit is contained in:
parent
ed377cc9aa
commit
809f0b8a13
76 changed files with 2451 additions and 224 deletions
|
@ -55,6 +55,7 @@ DefSpecsLambdaVisibility
|
||||||
DefineMethodByProcClass
|
DefineMethodByProcClass
|
||||||
DefineMethodSpecClass
|
DefineMethodSpecClass
|
||||||
DefineSingletonMethodSpecClass
|
DefineSingletonMethodSpecClass
|
||||||
|
Delegator
|
||||||
DescArray
|
DescArray
|
||||||
DescObjectTest
|
DescObjectTest
|
||||||
Digest
|
Digest
|
||||||
|
@ -148,6 +149,7 @@ Readline
|
||||||
ReceiverClass
|
ReceiverClass
|
||||||
RegexpSpecsSubclass
|
RegexpSpecsSubclass
|
||||||
RegexpSpecsSubclassTwo
|
RegexpSpecsSubclassTwo
|
||||||
|
Reline
|
||||||
RescueInClassExample
|
RescueInClassExample
|
||||||
Resolv
|
Resolv
|
||||||
SHA1Constants
|
SHA1Constants
|
||||||
|
@ -161,6 +163,7 @@ SecondClass
|
||||||
SecureRandom
|
SecureRandom
|
||||||
Set
|
Set
|
||||||
Shellwords
|
Shellwords
|
||||||
|
SimpleDelegator
|
||||||
SingleForwardable
|
SingleForwardable
|
||||||
Singleton
|
Singleton
|
||||||
Socket
|
Socket
|
||||||
|
@ -188,6 +191,7 @@ TimeoutError
|
||||||
UDPSocket
|
UDPSocket
|
||||||
UNIXServer
|
UNIXServer
|
||||||
UNIXSocket
|
UNIXSocket
|
||||||
|
URI
|
||||||
UnaryMinusTest
|
UnaryMinusTest
|
||||||
UnicodeNormalize
|
UnicodeNormalize
|
||||||
UnloadableDumpableDir
|
UnloadableDumpableDir
|
||||||
|
|
|
@ -114,6 +114,7 @@ Style/Lambda:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'language/lambda_spec.rb'
|
- 'language/lambda_spec.rb'
|
||||||
- 'language/proc_spec.rb'
|
- 'language/proc_spec.rb'
|
||||||
|
- 'language/numbered_parameters_spec.rb'
|
||||||
- 'core/kernel/lambda_spec.rb'
|
- 'core/kernel/lambda_spec.rb'
|
||||||
|
|
||||||
Style/EmptyLambdaParameter:
|
Style/EmptyLambdaParameter:
|
||||||
|
|
11
spec/ruby/core/array/deconstruct_spec.rb
Normal file
11
spec/ruby/core/array/deconstruct_spec.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
require_relative '../../spec_helper'
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
describe "Array#deconstruct" do
|
||||||
|
it "returns self" do
|
||||||
|
array = [1]
|
||||||
|
|
||||||
|
array.deconstruct.should equal array
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -396,6 +396,14 @@ describe "Array#[]= with [m..n]" do
|
||||||
a.should == [1, 2, 3, 8, 4, 5]
|
a.should == [1, 2, 3, 8, 4, 5]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "inserts at the end if m > the array size" do
|
||||||
|
a = [1, 2, 3]
|
||||||
|
a[3..3] = [4]
|
||||||
|
a.should == [1, 2, 3, 4]
|
||||||
|
a[5..7] = [6]
|
||||||
|
a.should == [1, 2, 3, 4, nil, 6]
|
||||||
|
end
|
||||||
|
|
||||||
describe "Range subclasses" do
|
describe "Range subclasses" do
|
||||||
before :each do
|
before :each do
|
||||||
@range_incl = ArraySpecs::MyRange.new(1, 2)
|
@range_incl = ArraySpecs::MyRange.new(1, 2)
|
||||||
|
@ -425,6 +433,45 @@ describe "Array#[]= with [m..n]" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
describe "Array#[]= with [m..]" do
|
||||||
|
|
||||||
|
it "just sets the section defined by range to nil even if the rhs is nil" do
|
||||||
|
a = [1, 2, 3, 4, 5]
|
||||||
|
a[eval("(2..)")] = nil
|
||||||
|
a.should == [1, 2, nil]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "just sets the section defined by range to nil if m and n < 0 and the rhs is nil" do
|
||||||
|
a = [1, 2, 3, 4, 5]
|
||||||
|
a[eval("(-3..)")] = nil
|
||||||
|
a.should == [1, 2, nil]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "replaces the section defined by range" do
|
||||||
|
a = [6, 5, 4, 3, 2, 1]
|
||||||
|
a[eval("(3...)")] = 9
|
||||||
|
a.should == [6, 5, 4, 9]
|
||||||
|
a[eval("(2..)")] = [7, 7, 7]
|
||||||
|
a.should == [6, 5, 7, 7, 7]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "replaces the section if m and n < 0" do
|
||||||
|
a = [1, 2, 3, 4, 5]
|
||||||
|
a[eval("(-3..)")] = [7, 8, 9]
|
||||||
|
a.should == [1, 2, 7, 8, 9]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "inserts at the end if m > the array size" do
|
||||||
|
a = [1, 2, 3]
|
||||||
|
a[eval("(3..)")] = [4]
|
||||||
|
a.should == [1, 2, 3, 4]
|
||||||
|
a[eval("(5..)")] = [6]
|
||||||
|
a.should == [1, 2, 3, 4, nil, 6]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "Array#[] after a shift" do
|
describe "Array#[] after a shift" do
|
||||||
it "works for insertion" do
|
it "works for insertion" do
|
||||||
a = [1,2]
|
a = [1,2]
|
||||||
|
|
|
@ -314,4 +314,13 @@ describe "Array#fill with (filler, range)" do
|
||||||
def obj.<=>(rhs); rhs == self ? 0 : nil end
|
def obj.<=>(rhs); rhs == self ? 0 : nil end
|
||||||
-> { [].fill('a', obj..obj) }.should raise_error(TypeError)
|
-> { [].fill('a', obj..obj) }.should raise_error(TypeError)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
it "works with endless ranges" do
|
||||||
|
[1, 2, 3, 4].fill('x', eval("(1..)")).should == [1, 'x', 'x', 'x']
|
||||||
|
[1, 2, 3, 4].fill('x', eval("(3...)")).should == [1, 2, 3, 'x']
|
||||||
|
[1, 2, 3, 4].fill(eval("(1..)")) { |x| x + 2 }.should == [1, 3, 4, 5]
|
||||||
|
[1, 2, 3, 4].fill(eval("(3...)")) { |x| x + 2 }.should == [1, 2, 3, 5]
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,87 +1,21 @@
|
||||||
require_relative '../../spec_helper'
|
require_relative '../../spec_helper'
|
||||||
require_relative 'fixtures/classes'
|
require_relative 'fixtures/classes'
|
||||||
|
require_relative 'shared/intersection'
|
||||||
|
|
||||||
describe "Array#&" do
|
describe "Array#&" do
|
||||||
it "creates an array with elements common to both arrays (intersection)" do
|
it_behaves_like :array_intersection, :&
|
||||||
([] & []).should == []
|
end
|
||||||
([1, 2] & []).should == []
|
|
||||||
([] & [1, 2]).should == []
|
|
||||||
([ 1, 3, 5 ] & [ 1, 2, 3 ]).should == [1, 3]
|
|
||||||
end
|
|
||||||
|
|
||||||
it "creates an array with no duplicates" do
|
ruby_version_is "2.7" do
|
||||||
([ 1, 1, 3, 5 ] & [ 1, 2, 3 ]).uniq!.should == nil
|
describe "Array#intersection" do
|
||||||
end
|
it_behaves_like :array_intersection, :intersection
|
||||||
|
|
||||||
it "creates an array with elements in order they are first encountered" do
|
it "accepts multiple arguments" do
|
||||||
([ 1, 2, 3, 2, 5 ] & [ 5, 2, 3, 4 ]).should == [2, 3, 5]
|
[1, 2, 3, 4].intersection([1, 2, 3], [2, 3, 4]).should == [2, 3]
|
||||||
end
|
|
||||||
|
|
||||||
it "does not modify the original Array" do
|
|
||||||
a = [1, 1, 3, 5]
|
|
||||||
(a & [1, 2, 3]).should == [1, 3]
|
|
||||||
a.should == [1, 1, 3, 5]
|
|
||||||
end
|
|
||||||
|
|
||||||
it "properly handles recursive arrays" do
|
|
||||||
empty = ArraySpecs.empty_recursive_array
|
|
||||||
(empty & empty).should == empty
|
|
||||||
|
|
||||||
(ArraySpecs.recursive_array & []).should == []
|
|
||||||
([] & ArraySpecs.recursive_array).should == []
|
|
||||||
|
|
||||||
(ArraySpecs.recursive_array & ArraySpecs.recursive_array).should == [1, 'two', 3.0, ArraySpecs.recursive_array]
|
|
||||||
end
|
|
||||||
|
|
||||||
it "tries to convert the passed argument to an Array using #to_ary" do
|
|
||||||
obj = mock('[1,2,3]')
|
|
||||||
obj.should_receive(:to_ary).and_return([1, 2, 3])
|
|
||||||
([1, 2] & obj).should == ([1, 2])
|
|
||||||
end
|
|
||||||
|
|
||||||
it "determines equivalence between elements in the sense of eql?" do
|
|
||||||
not_supported_on :opal do
|
|
||||||
([5.0, 4.0] & [5, 4]).should == []
|
|
||||||
end
|
end
|
||||||
|
|
||||||
str = "x"
|
it "preserves elements order from original array" do
|
||||||
([str] & [str.dup]).should == [str]
|
[1, 2, 3, 4].intersection([3, 2, 1]).should == [1, 2, 3]
|
||||||
|
end
|
||||||
obj1 = mock('1')
|
|
||||||
obj2 = mock('2')
|
|
||||||
obj1.stub!(:hash).and_return(0)
|
|
||||||
obj2.stub!(:hash).and_return(0)
|
|
||||||
obj1.should_receive(:eql?).at_least(1).and_return(true)
|
|
||||||
obj2.stub!(:eql?).and_return(true)
|
|
||||||
|
|
||||||
([obj1] & [obj2]).should == [obj1]
|
|
||||||
([obj1, obj1, obj2, obj2] & [obj2]).should == [obj1]
|
|
||||||
|
|
||||||
obj1 = mock('3')
|
|
||||||
obj2 = mock('4')
|
|
||||||
obj1.stub!(:hash).and_return(0)
|
|
||||||
obj2.stub!(:hash).and_return(0)
|
|
||||||
obj1.should_receive(:eql?).at_least(1).and_return(false)
|
|
||||||
|
|
||||||
([obj1] & [obj2]).should == []
|
|
||||||
([obj1, obj1, obj2, obj2] & [obj2]).should == [obj2]
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does return subclass instances for Array subclasses" do
|
|
||||||
(ArraySpecs::MyArray[1, 2, 3] & []).should be_an_instance_of(Array)
|
|
||||||
(ArraySpecs::MyArray[1, 2, 3] & ArraySpecs::MyArray[1, 2, 3]).should be_an_instance_of(Array)
|
|
||||||
([] & ArraySpecs::MyArray[1, 2, 3]).should be_an_instance_of(Array)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not call to_ary on array subclasses" do
|
|
||||||
([5, 6] & ArraySpecs::ToAryArray[1, 2, 5, 6]).should == [5, 6]
|
|
||||||
end
|
|
||||||
|
|
||||||
it "properly handles an identical item even when its #eql? isn't reflexive" do
|
|
||||||
x = mock('x')
|
|
||||||
x.stub!(:hash).and_return(42)
|
|
||||||
x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
|
|
||||||
|
|
||||||
([x] & [x]).should == [x]
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
84
spec/ruby/core/array/shared/intersection.rb
Normal file
84
spec/ruby/core/array/shared/intersection.rb
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
describe :array_intersection, shared: true do
|
||||||
|
it "creates an array with elements common to both arrays (intersection)" do
|
||||||
|
[].send(@method, []).should == []
|
||||||
|
[1, 2].send(@method, []).should == []
|
||||||
|
[].send(@method, [1, 2]).should == []
|
||||||
|
[ 1, 3, 5 ].send(@method, [ 1, 2, 3 ]).should == [1, 3]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "creates an array with no duplicates" do
|
||||||
|
[ 1, 1, 3, 5 ].send(@method, [ 1, 2, 3 ]).uniq!.should == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "creates an array with elements in order they are first encountered" do
|
||||||
|
[ 1, 2, 3, 2, 5 ].send(@method, [ 5, 2, 3, 4 ]).should == [2, 3, 5]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not modify the original Array" do
|
||||||
|
a = [1, 1, 3, 5]
|
||||||
|
a.send(@method, [1, 2, 3]).should == [1, 3]
|
||||||
|
a.should == [1, 1, 3, 5]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "properly handles recursive arrays" do
|
||||||
|
empty = ArraySpecs.empty_recursive_array
|
||||||
|
empty.send(@method, empty).should == empty
|
||||||
|
|
||||||
|
ArraySpecs.recursive_array.send(@method, []).should == []
|
||||||
|
[].send(@method, ArraySpecs.recursive_array).should == []
|
||||||
|
|
||||||
|
ArraySpecs.recursive_array.send(@method, ArraySpecs.recursive_array).should == [1, 'two', 3.0, ArraySpecs.recursive_array]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "tries to convert the passed argument to an Array using #to_ary" do
|
||||||
|
obj = mock('[1,2,3]')
|
||||||
|
obj.should_receive(:to_ary).and_return([1, 2, 3])
|
||||||
|
[1, 2].send(@method, obj).should == ([1, 2])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "determines equivalence between elements in the sense of eql?" do
|
||||||
|
not_supported_on :opal do
|
||||||
|
[5.0, 4.0].send(@method, [5, 4]).should == []
|
||||||
|
end
|
||||||
|
|
||||||
|
str = "x"
|
||||||
|
[str].send(@method, [str.dup]).should == [str]
|
||||||
|
|
||||||
|
obj1 = mock('1')
|
||||||
|
obj2 = mock('2')
|
||||||
|
obj1.stub!(:hash).and_return(0)
|
||||||
|
obj2.stub!(:hash).and_return(0)
|
||||||
|
obj1.should_receive(:eql?).at_least(1).and_return(true)
|
||||||
|
obj2.stub!(:eql?).and_return(true)
|
||||||
|
|
||||||
|
[obj1].send(@method, [obj2]).should == [obj1]
|
||||||
|
[obj1, obj1, obj2, obj2].send(@method, [obj2]).should == [obj1]
|
||||||
|
|
||||||
|
obj1 = mock('3')
|
||||||
|
obj2 = mock('4')
|
||||||
|
obj1.stub!(:hash).and_return(0)
|
||||||
|
obj2.stub!(:hash).and_return(0)
|
||||||
|
obj1.should_receive(:eql?).at_least(1).and_return(false)
|
||||||
|
|
||||||
|
[obj1].send(@method, [obj2]).should == []
|
||||||
|
[obj1, obj1, obj2, obj2].send(@method, [obj2]).should == [obj2]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does return subclass instances for Array subclasses" do
|
||||||
|
ArraySpecs::MyArray[1, 2, 3].send(@method, []).should be_an_instance_of(Array)
|
||||||
|
ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should be_an_instance_of(Array)
|
||||||
|
[].send(@method, ArraySpecs::MyArray[1, 2, 3]).should be_an_instance_of(Array)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not call to_ary on array subclasses" do
|
||||||
|
[5, 6].send(@method, ArraySpecs::ToAryArray[1, 2, 5, 6]).should == [5, 6]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "properly handles an identical item even when its #eql? isn't reflexive" do
|
||||||
|
x = mock('x')
|
||||||
|
x.stub!(:hash).and_return(42)
|
||||||
|
x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
|
||||||
|
|
||||||
|
[x].send(@method, [x]).should == [x]
|
||||||
|
end
|
||||||
|
end
|
|
@ -113,6 +113,20 @@ describe :array_join_with_default_separator, shared: true do
|
||||||
|
|
||||||
-> { ary_utf8_bad_binary.send(@method) }.should raise_error(EncodingError)
|
-> { ary_utf8_bad_binary.send(@method) }.should raise_error(EncodingError)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
context "when $, is not nil" do
|
||||||
|
before do
|
||||||
|
suppress_warning do
|
||||||
|
$, = '*'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "warns" do
|
||||||
|
-> { [].join }.should complain(/warning: \$, is set to non-nil value/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe :array_join_with_string_separator, shared: true do
|
describe :array_join_with_string_separator, shared: true do
|
||||||
|
|
|
@ -153,6 +153,18 @@ describe "Array#slice!" do
|
||||||
it "raises a #{frozen_error_class} on a frozen array" do
|
it "raises a #{frozen_error_class} on a frozen array" do
|
||||||
-> { ArraySpecs.frozen_array.slice!(0, 0) }.should raise_error(frozen_error_class)
|
-> { ArraySpecs.frozen_array.slice!(0, 0) }.should raise_error(frozen_error_class)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
it "works with endless ranges" do
|
||||||
|
a = [1, 2, 3]
|
||||||
|
a.slice!(eval("(1..)")).should == [2, 3]
|
||||||
|
a.should == [1]
|
||||||
|
|
||||||
|
a = [1, 2, 3]
|
||||||
|
a.slice!(eval("(2...)")).should == [3]
|
||||||
|
a.should == [1, 2]
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "Array#slice" do
|
describe "Array#slice" do
|
||||||
|
|
|
@ -60,4 +60,11 @@ describe "Array#values_at" do
|
||||||
it "does not return subclass instance on Array subclasses" do
|
it "does not return subclass instance on Array subclasses" do
|
||||||
ArraySpecs::MyArray[1, 2, 3].values_at(0, 1..2, 1).should be_an_instance_of(Array)
|
ArraySpecs::MyArray[1, 2, 3].values_at(0, 1..2, 1).should be_an_instance_of(Array)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
it "works when given endless ranges" do
|
||||||
|
[1, 2, 3, 4].values_at(eval("(1..)")).should == [2, 3, 4]
|
||||||
|
[1, 2, 3, 4].values_at(eval("(3...)")).should == [4]
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
require_relative '../../spec_helper'
|
require_relative '../../spec_helper'
|
||||||
|
|
||||||
describe "Complex#<=>" do
|
describe "Complex#<=>" do
|
||||||
ruby_version_is '2.7' do
|
ruby_version_is "2.7" do
|
||||||
it "returns nil if either self or argument has imaginary part" do
|
it "returns nil if either self or argument has imaginary part" do
|
||||||
(Complex(5, 1) <=> Complex(2)).should be_nil
|
(Complex(5, 1) <=> Complex(2)).should be_nil
|
||||||
(Complex(1) <=> Complex(2, 1)).should be_nil
|
(Complex(1) <=> Complex(2, 1)).should be_nil
|
|
@ -40,10 +40,10 @@ describe "Enumerator#each" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "calls the method given in the constructor until it's exhausted" do
|
it "calls the method given in the constructor until it's exhausted" do
|
||||||
each = mock('each')
|
each = mock('peach')
|
||||||
each.should_receive(:each).and_yield(1).and_yield(2).and_yield(3)
|
each.should_receive(:peach).and_yield(1).and_yield(2).and_yield(3)
|
||||||
acc = []
|
acc = []
|
||||||
each.to_enum.each {|e| acc << e }
|
each.to_enum(:peach).each {|e| acc << e }
|
||||||
acc.should == [1,2,3]
|
acc.should == [1,2,3]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
29
spec/ruby/core/enumerator/lazy/eager_spec.rb
Normal file
29
spec/ruby/core/enumerator/lazy/eager_spec.rb
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
require_relative '../../../spec_helper'
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
describe "Enumerator::Lazy#eager" do
|
||||||
|
it "returns a non-lazy Enumerator converted from the lazy enumerator" do
|
||||||
|
enum = [1, 2, 3].lazy
|
||||||
|
|
||||||
|
enum.class.should == Enumerator::Lazy
|
||||||
|
enum.eager.class.should == Enumerator
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not enumerate an enumerator" do
|
||||||
|
ScratchPad.record []
|
||||||
|
|
||||||
|
sequence = [1, 2, 3]
|
||||||
|
enum_lazy = Enumerator::Lazy.new(sequence) do |yielder, value|
|
||||||
|
yielder << value
|
||||||
|
ScratchPad << value
|
||||||
|
end
|
||||||
|
|
||||||
|
ScratchPad.recorded.should == []
|
||||||
|
enum = enum_lazy.eager
|
||||||
|
ScratchPad.recorded.should == []
|
||||||
|
|
||||||
|
enum.map { |i| i }.should == [1, 2, 3]
|
||||||
|
ScratchPad.recorded.should == [1, 2, 3]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -38,4 +38,42 @@ describe "Enumerator.new" do
|
||||||
end
|
end
|
||||||
enum.to_a.should == [:bar]
|
enum.to_a.should == [:bar]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "when passed a block" do
|
||||||
|
it "defines iteration with block, yielder argument and calling << method" do
|
||||||
|
enum = Enumerator.new do |yielder|
|
||||||
|
a = 1
|
||||||
|
|
||||||
|
loop do
|
||||||
|
yielder << a
|
||||||
|
a = a + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
enum.take(3).should == [1, 2, 3]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "defines iteration with block, yielder argument and calling yield method" do
|
||||||
|
enum = Enumerator.new do |yielder|
|
||||||
|
a = 1
|
||||||
|
|
||||||
|
loop do
|
||||||
|
yielder.yield(a)
|
||||||
|
a = a + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
enum.take(3).should == [1, 2, 3]
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
it "defines iteration with block, yielder argument and treating it as a proc" do
|
||||||
|
enum = Enumerator.new do |yielder|
|
||||||
|
"a\nb\nc".each_line(&yielder)
|
||||||
|
end
|
||||||
|
|
||||||
|
enum.to_a.should == ["a\n", "b\n", "c"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
36
spec/ruby/core/enumerator/produce_spec.rb
Normal file
36
spec/ruby/core/enumerator/produce_spec.rb
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
require_relative '../../spec_helper'
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
describe "Enumerator.produce" do
|
||||||
|
it "creates an infinite enumerator" do
|
||||||
|
enum = Enumerator.produce(0) { |prev| prev + 1 }
|
||||||
|
enum.take(5).should == [0, 1, 2, 3, 4]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "terminates iteration when block raises StopIteration exception" do
|
||||||
|
enum = Enumerator.produce(0) do | prev|
|
||||||
|
raise StopIteration if prev >= 2
|
||||||
|
prev + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
enum.to_a.should == [0, 1, 2]
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when initial value skipped" do
|
||||||
|
it "uses nil instead" do
|
||||||
|
ScratchPad.record []
|
||||||
|
enum = Enumerator.produce { |prev| ScratchPad << prev; (prev || 0) + 1 }
|
||||||
|
|
||||||
|
enum.take(3).should == [1, 2, 3]
|
||||||
|
ScratchPad.recorded.should == [nil, 1, 2]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "starts enumerable from result of first block call" do
|
||||||
|
array = "a\nb\nc\nd".lines
|
||||||
|
lines = Enumerator.produce { array.shift }.take_while { |s| s }
|
||||||
|
|
||||||
|
lines.should == ["a\n", "b\n", "c\n", "d"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
18
spec/ruby/core/enumerator/yielder/to_proc_spec.rb
Normal file
18
spec/ruby/core/enumerator/yielder/to_proc_spec.rb
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
require_relative '../../../spec_helper'
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
describe "Enumerator::Yielder#to_proc" do
|
||||||
|
it "returns a Proc object that takes an argument and yields it to the block" do
|
||||||
|
ScratchPad.record []
|
||||||
|
y = Enumerator::Yielder.new { |*args| ScratchPad << args; "foobar" }
|
||||||
|
|
||||||
|
callable = y.to_proc
|
||||||
|
callable.class.should == Proc
|
||||||
|
|
||||||
|
result = callable.call(1, 2)
|
||||||
|
ScratchPad.recorded.should == [[1, 2]]
|
||||||
|
|
||||||
|
result.should == "foobar"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,23 +0,0 @@
|
||||||
require_relative '../../spec_helper'
|
|
||||||
|
|
||||||
describe "Encoding::UndefinedConversionError#destination_encoding_name" do
|
|
||||||
it "returns the destination encoding name" do
|
|
||||||
ec = Encoding::Converter.new("ISO-8859-1", "EUC-JP")
|
|
||||||
begin
|
|
||||||
ec.convert("\xa0")
|
|
||||||
rescue Encoding::UndefinedConversionError => e
|
|
||||||
e.destination_encoding_name.should == "EUC-JP"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "Encoding::InvalidByteSequenceError#destination_encoding_name" do
|
|
||||||
it "returns the destination encoding name" do
|
|
||||||
ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
|
|
||||||
begin
|
|
||||||
ec.convert("\xa0")
|
|
||||||
rescue Encoding::InvalidByteSequenceError => e
|
|
||||||
e.destination_encoding_name.should == "UTF-8"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,23 +0,0 @@
|
||||||
require_relative '../../spec_helper'
|
|
||||||
|
|
||||||
describe "Encoding::UndefinedConversionError#destination_encoding" do
|
|
||||||
it "returns the destination encoding" do
|
|
||||||
ec = Encoding::Converter.new("ISO-8859-1", "EUC-JP")
|
|
||||||
begin
|
|
||||||
ec.convert("\xa0")
|
|
||||||
rescue Encoding::UndefinedConversionError => e
|
|
||||||
e.destination_encoding.should == Encoding::EUC_JP
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "Encoding::InvalidByteSequenceError#destination_encoding" do
|
|
||||||
it "returns the destination encoding" do
|
|
||||||
ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
|
|
||||||
begin
|
|
||||||
ec.convert("\xa0")
|
|
||||||
rescue Encoding::InvalidByteSequenceError => e
|
|
||||||
e.destination_encoding.should == Encoding::UTF_8
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,12 +0,0 @@
|
||||||
require_relative '../../spec_helper'
|
|
||||||
|
|
||||||
describe "Encoding::InvalidByteSequenceError#error_bytes" do
|
|
||||||
it "returns the error bytes" do
|
|
||||||
ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
|
|
||||||
begin
|
|
||||||
ec.convert("\xa0")
|
|
||||||
rescue Encoding::InvalidByteSequenceError => e
|
|
||||||
e.error_bytes.should == "\xA0".force_encoding("ASCII-8BIT")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,12 +0,0 @@
|
||||||
require_relative '../../spec_helper'
|
|
||||||
|
|
||||||
describe "Encoding::UndefinedConversionError#error_char" do
|
|
||||||
it "returns the error char" do
|
|
||||||
ec = Encoding::Converter.new("ISO-8859-1", "EUC-JP")
|
|
||||||
begin
|
|
||||||
ec.convert("\xa0")
|
|
||||||
rescue Encoding::UndefinedConversionError => e
|
|
||||||
e.error_char.should == "\u00A0"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1 +0,0 @@
|
||||||
require_relative '../../spec_helper'
|
|
|
@ -1,12 +0,0 @@
|
||||||
require_relative '../../spec_helper'
|
|
||||||
|
|
||||||
describe "Encoding::InvalidByteSequenceError#readagain_bytes" do
|
|
||||||
it "returns the next byte" do
|
|
||||||
begin
|
|
||||||
"abc\xa4def".encode("ISO-8859-1", "EUC-JP")
|
|
||||||
rescue Encoding::InvalidByteSequenceError => e
|
|
||||||
e.error_bytes.should == "\xA4".force_encoding("ASCII-8BIT")
|
|
||||||
e.readagain_bytes.should == 'd'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,23 +0,0 @@
|
||||||
require_relative '../../spec_helper'
|
|
||||||
|
|
||||||
describe "Encoding::UndefinedConversionError#source_encoding_name" do
|
|
||||||
it "returns the source encoding name" do
|
|
||||||
ec = Encoding::Converter.new("ISO-8859-1", "EUC-JP")
|
|
||||||
begin
|
|
||||||
ec.convert("\xa0")
|
|
||||||
rescue Encoding::UndefinedConversionError => e
|
|
||||||
e.source_encoding_name.should == "UTF-8"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "Encoding::InvalidByteSequenceError#source_encoding_name" do
|
|
||||||
it "returns the source encoding name" do
|
|
||||||
ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
|
|
||||||
begin
|
|
||||||
ec.convert("\xa0")
|
|
||||||
rescue Encoding::InvalidByteSequenceError => e
|
|
||||||
e.source_encoding_name.should == "EUC-JP"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,23 +0,0 @@
|
||||||
require_relative '../../spec_helper'
|
|
||||||
|
|
||||||
describe "Encoding::UndefinedConversionError#source_encoding" do
|
|
||||||
it "returns the source encoding" do
|
|
||||||
ec = Encoding::Converter.new("ISO-8859-1", "EUC-JP")
|
|
||||||
begin
|
|
||||||
ec.convert("\xa0")
|
|
||||||
rescue Encoding::UndefinedConversionError => e
|
|
||||||
e.source_encoding.should == Encoding::UTF_8
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "Encoding::InvalidByteSequenceError#source_encoding" do
|
|
||||||
it "returns the source encoding" do
|
|
||||||
ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
|
|
||||||
begin
|
|
||||||
ec.convert("\xa0")
|
|
||||||
rescue Encoding::InvalidByteSequenceError => e
|
|
||||||
e.source_encoding.should == Encoding::EUC_JP
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
25
spec/ruby/core/hash/deconstruct_keys_spec.rb
Normal file
25
spec/ruby/core/hash/deconstruct_keys_spec.rb
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
require_relative '../../spec_helper'
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
describe "Hash#deconstruct_keys" do
|
||||||
|
it "returns self" do
|
||||||
|
hash = {a: 1, b: 2}
|
||||||
|
|
||||||
|
hash.deconstruct_keys([:a, :b]).should equal hash
|
||||||
|
end
|
||||||
|
|
||||||
|
it "requires one argument" do
|
||||||
|
-> {
|
||||||
|
{a: 1}.deconstruct_keys
|
||||||
|
}.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "ignores argument" do
|
||||||
|
hash = {a: 1, b: 2}
|
||||||
|
|
||||||
|
hash.deconstruct_keys([:a]).should == {a: 1, b: 2}
|
||||||
|
hash.deconstruct_keys(0 ).should == {a: 1, b: 2}
|
||||||
|
hash.deconstruct_keys('' ).should == {a: 1, b: 2}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -78,6 +78,91 @@ describe "Integer#[]" do
|
||||||
it "returns 0 when passed a Float in the range of a Bignum" do
|
it "returns 0 when passed a Float in the range of a Bignum" do
|
||||||
3[bignum_value.to_f].should == 0
|
3[bignum_value.to_f].should == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
context "when index and length passed" do
|
||||||
|
it "returns specified number of bits from specified position" do
|
||||||
|
0b101001101[2, 4].should == 0b0011
|
||||||
|
0b101001101[2, 5].should == 0b10011
|
||||||
|
0b101001101[2, 7].should == 0b1010011
|
||||||
|
end
|
||||||
|
|
||||||
|
it "ensures n[i, len] equals to (n >> i) & ((1 << len) - 1)" do
|
||||||
|
n = 0b101001101; i = 2; len = 4
|
||||||
|
n[i, len].should == (n >> i) & ((1 << len) - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "moves start position to the most significant bits when negative index passed" do
|
||||||
|
0b000001[-1, 4].should == 0b10
|
||||||
|
0b000001[-2, 4].should == 0b100
|
||||||
|
0b000001[-3, 4].should == 0b1000
|
||||||
|
end
|
||||||
|
|
||||||
|
it "ignores negative length" do
|
||||||
|
0b101001101[1, -1].should == 0b10100110
|
||||||
|
0b101001101[2, -1].should == 0b1010011
|
||||||
|
0b101001101[3, -1].should == 0b101001
|
||||||
|
|
||||||
|
0b101001101[3, -5].should == 0b101001
|
||||||
|
0b101001101[3, -15].should == 0b101001
|
||||||
|
0b101001101[3, -125].should == 0b101001
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when range passed" do
|
||||||
|
it "returns bits specified by range" do
|
||||||
|
0b101001101[2..5].should == 0b0011
|
||||||
|
0b101001101[2..6].should == 0b10011
|
||||||
|
0b101001101[2..8].should == 0b1010011
|
||||||
|
end
|
||||||
|
|
||||||
|
it "ensures n[i..j] equals to (n >> i) & ((1 << (j - i + 1)) - 1)" do
|
||||||
|
n = 0b101001101; i = 2; j = 5
|
||||||
|
n[i..j].should == (n >> i) & ((1 << (j - i + 1)) - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "ensures n[i..] equals to (n >> i)" do
|
||||||
|
eval("0b101001101[3..]").should == 0b101001101 >> 3
|
||||||
|
end
|
||||||
|
|
||||||
|
it "moves lower boundary to the most significant bits when negative value passed" do
|
||||||
|
0b000001[-1, 4].should == 0b10
|
||||||
|
0b000001[-2, 4].should == 0b100
|
||||||
|
0b000001[-3, 4].should == 0b1000
|
||||||
|
end
|
||||||
|
|
||||||
|
it "ignores negative upper boundary" do
|
||||||
|
0b101001101[1..-1].should == 0b10100110
|
||||||
|
0b101001101[1..-2].should == 0b10100110
|
||||||
|
0b101001101[1..-3].should == 0b10100110
|
||||||
|
end
|
||||||
|
|
||||||
|
it "ignores upper boundary smaller than lower boundary" do
|
||||||
|
0b101001101[4..1].should == 0b10100
|
||||||
|
0b101001101[4..2].should == 0b10100
|
||||||
|
0b101001101[4..3].should == 0b10100
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises FloatDomainError if any boundary is infinity" do
|
||||||
|
-> { 0x0001[3..Float::INFINITY] }.should raise_error(FloatDomainError, /Infinity/)
|
||||||
|
-> { 0x0001[-Float::INFINITY..3] }.should raise_error(FloatDomainError, /-Infinity/)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when passed (..i)" do
|
||||||
|
it "returns 0 if all i bits equal 0" do
|
||||||
|
eval("0b10000[..1]").should == 0
|
||||||
|
eval("0b10000[..2]").should == 0
|
||||||
|
eval("0b10000[..3]").should == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises ArgumentError if any of i bit equals 1" do
|
||||||
|
-> {
|
||||||
|
eval("0b111110[..3]")
|
||||||
|
}.should raise_error(ArgumentError, /The beginless range for Integer#\[\] results in infinity/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "bignum" do
|
context "bignum" do
|
||||||
|
|
|
@ -22,6 +22,30 @@ describe 'Kernel#caller_locations' do
|
||||||
locations.length.should == 1
|
locations.length.should == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "can be called with a range" do
|
||||||
|
locations1 = caller_locations(0)
|
||||||
|
locations2 = caller_locations(2..4)
|
||||||
|
locations1[2..4].map(&:to_s).should == locations2.map(&:to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can be called with a range whose end is negative" do
|
||||||
|
locations1 = caller_locations(0)
|
||||||
|
locations2 = caller_locations(2..-1)
|
||||||
|
locations3 = caller_locations(2..-2)
|
||||||
|
locations1[2..-1].map(&:to_s).should == locations2.map(&:to_s)
|
||||||
|
locations1[2..-2].map(&:to_s).should == locations3.map(&:to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "must return nil if omitting more locations than available" do
|
||||||
|
caller_locations(100).should == nil
|
||||||
|
caller_locations(100..-1).should == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "must return [] if omitting exactly the number of locations available" do
|
||||||
|
omit = caller_locations(0).length
|
||||||
|
caller_locations(omit).should == []
|
||||||
|
end
|
||||||
|
|
||||||
it 'returns the locations as Thread::Backtrace::Location instances' do
|
it 'returns the locations as Thread::Backtrace::Location instances' do
|
||||||
locations = KernelSpecs::CallerLocationsTest.locations
|
locations = KernelSpecs::CallerLocationsTest.locations
|
||||||
|
|
||||||
|
@ -29,4 +53,8 @@ describe 'Kernel#caller_locations' do
|
||||||
location.kind_of?(Thread::Backtrace::Location).should == true
|
location.kind_of?(Thread::Backtrace::Location).should == true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "must return the same locations when called with 1..-1 and when called with no arguments" do
|
||||||
|
caller_locations.map(&:to_s).should == caller_locations(1..-1).map(&:to_s)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
require_relative '../../spec_helper'
|
require_relative '../../spec_helper'
|
||||||
require_relative 'fixtures/classes'
|
require_relative 'fixtures/classes'
|
||||||
require_relative 'shared/sprintf'
|
require_relative 'shared/sprintf'
|
||||||
require "stringio"
|
|
||||||
|
|
||||||
describe "Kernel#printf" do
|
describe "Kernel#printf" do
|
||||||
it "is a private method" do
|
it "is a private method" do
|
||||||
|
@ -32,8 +31,14 @@ describe "Kernel.printf" do
|
||||||
object.should_receive(:write).with("string")
|
object.should_receive(:write).with("string")
|
||||||
Kernel.printf(object, "%s", "string")
|
Kernel.printf(object, "%s", "string")
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Kernel.printf" do
|
||||||
describe "formatting" do
|
describe "formatting" do
|
||||||
|
before :each do
|
||||||
|
require "stringio"
|
||||||
|
end
|
||||||
|
|
||||||
context "io is specified" do
|
context "io is specified" do
|
||||||
it_behaves_like :kernel_sprintf, -> format, *args {
|
it_behaves_like :kernel_sprintf, -> format, *args {
|
||||||
io = StringIO.new
|
io = StringIO.new
|
||||||
|
@ -45,7 +50,6 @@ describe "Kernel.printf" do
|
||||||
context "io is not specified" do
|
context "io is not specified" do
|
||||||
it_behaves_like :kernel_sprintf, -> format, *args {
|
it_behaves_like :kernel_sprintf, -> format, *args {
|
||||||
stdout = $stdout
|
stdout = $stdout
|
||||||
|
|
||||||
begin
|
begin
|
||||||
$stdout = io = StringIO.new
|
$stdout = io = StringIO.new
|
||||||
Kernel.printf(format, *args)
|
Kernel.printf(format, *args)
|
||||||
|
|
|
@ -111,7 +111,7 @@ describe "Kernel#warn" do
|
||||||
-> { w.f4(obj, 2) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f2_call_lineno}: warning: to_s called|)
|
-> { w.f4(obj, 2) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f2_call_lineno}: warning: to_s called|)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not prepend caller information if line number is too big" do
|
it "does not prepend caller information if the uplevel argument is too large" do
|
||||||
w = KernelSpecs::WarnInNestedCall.new
|
w = KernelSpecs::WarnInNestedCall.new
|
||||||
-> { w.f4("foo", 100) }.should output(nil, "warning: foo\n")
|
-> { w.f4("foo", 100) }.should output(nil, "warning: foo\n")
|
||||||
end
|
end
|
||||||
|
|
|
@ -556,13 +556,10 @@ describe "Marshal.dump" do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "when passed a StringIO" do
|
describe "when passed a StringIO" do
|
||||||
|
|
||||||
it "should raise an error" do
|
it "should raise an error" do
|
||||||
require "stringio"
|
require "stringio"
|
||||||
|
|
||||||
-> { Marshal.dump(StringIO.new) }.should raise_error(TypeError)
|
-> { Marshal.dump(StringIO.new) }.should raise_error(TypeError)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises a TypeError if marshalling a Method instance" do
|
it "raises a TypeError if marshalling a Method instance" do
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
# -*- encoding: binary -*-
|
# -*- encoding: binary -*-
|
||||||
require_relative '../fixtures/marshal_data'
|
require_relative '../fixtures/marshal_data'
|
||||||
require 'stringio'
|
|
||||||
|
|
||||||
describe :marshal_load, shared: true do
|
describe :marshal_load, shared: true do
|
||||||
before :all do
|
before :all do
|
||||||
|
@ -410,8 +409,9 @@ describe :marshal_load, shared: true do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "loads a string through StringIO stream" do
|
it "loads a string through StringIO stream" do
|
||||||
obj = "This is a string which should be unmarshalled through StringIO stream!"
|
require 'stringio'
|
||||||
Marshal.send(@method, StringIO.new(Marshal.dump(obj))).should == obj
|
obj = "This is a string which should be unmarshalled through StringIO stream!"
|
||||||
|
Marshal.send(@method, StringIO.new(Marshal.dump(obj))).should == obj
|
||||||
end
|
end
|
||||||
|
|
||||||
it "loads a string with an ivar" do
|
it "loads a string with an ivar" do
|
||||||
|
|
|
@ -81,6 +81,19 @@ describe "Range#bsearch" do
|
||||||
[1, 2].should include(result)
|
[1, 2].should include(result)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns nil for empty ranges" do
|
||||||
|
(0...0).bsearch { true }.should == nil
|
||||||
|
(0...0).bsearch { false }.should == nil
|
||||||
|
(0...0).bsearch { 1 }.should == nil
|
||||||
|
(0...0).bsearch { 0 }.should == nil
|
||||||
|
(0...0).bsearch { -1 }.should == nil
|
||||||
|
|
||||||
|
(4..2).bsearch { true }.should == nil
|
||||||
|
(4..2).bsearch { 1 }.should == nil
|
||||||
|
(4..2).bsearch { 0 }.should == nil
|
||||||
|
(4..2).bsearch { -1 }.should == nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with Float values" do
|
context "with Float values" do
|
||||||
|
@ -94,13 +107,46 @@ describe "Range#bsearch" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns minimum element if the block returns true for every element" do
|
it "returns minimum element if the block returns true for every element" do
|
||||||
(-0.2..4.8).bsearch { |x| x < 4 }.should == -0.2
|
(-0.2..4.8).bsearch { |x| x < 5 }.should == -0.2
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns the smallest element for which block returns true" do
|
it "returns the smallest element for which block returns true" do
|
||||||
(0..4.2).bsearch { |x| x >= 2 }.should == 2
|
(0..4.2).bsearch { |x| x >= 2 }.should == 2
|
||||||
(-1.2..4.3).bsearch { |x| x >= 1 }.should == 1
|
(-1.2..4.3).bsearch { |x| x >= 1 }.should == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns a boundary element if appropriate" do
|
||||||
|
(1.0..3.0).bsearch { |x| x >= 3.0 }.should == 3.0
|
||||||
|
(1.0...3.0).bsearch { |x| x >= 3.0.prev_float }.should == 3.0.prev_float
|
||||||
|
(1.0..3.0).bsearch { |x| x >= 1.0 }.should == 1.0
|
||||||
|
(1.0...3.0).bsearch { |x| x >= 1.0 }.should == 1.0
|
||||||
|
end
|
||||||
|
|
||||||
|
it "works with infinity bounds" do
|
||||||
|
inf = Float::INFINITY
|
||||||
|
(0..inf).bsearch { |x| x == inf }.should == inf
|
||||||
|
(0...inf).bsearch { |x| x == inf }.should == nil
|
||||||
|
(-inf..0).bsearch { |x| x == -inf }.should == nil
|
||||||
|
(-inf...0).bsearch { |x| x == -inf }.should == nil
|
||||||
|
(inf..inf).bsearch { |x| true }.should == inf
|
||||||
|
(inf...inf).bsearch { |x| true }.should == nil
|
||||||
|
(-inf..-inf).bsearch { |x| true }.should == -inf
|
||||||
|
(-inf...-inf).bsearch { |x| true }.should == nil
|
||||||
|
(inf..0).bsearch { true }.should == nil
|
||||||
|
(inf...0).bsearch { true }.should == nil
|
||||||
|
(0..-inf).bsearch { true }.should == nil
|
||||||
|
(0...-inf).bsearch { true }.should == nil
|
||||||
|
(inf..-inf).bsearch { true }.should == nil
|
||||||
|
(inf...-inf).bsearch { true }.should == nil
|
||||||
|
(0..inf).bsearch { |x| x >= 3 }.should == 3.0
|
||||||
|
(0...inf).bsearch { |x| x >= 3 }.should == 3.0
|
||||||
|
(-inf..0).bsearch { |x| x >= -3 }.should == -3.0
|
||||||
|
(-inf...0).bsearch { |x| x >= -3 }.should == -3.0
|
||||||
|
(-inf..inf).bsearch { |x| x >= 3 }.should == 3.0
|
||||||
|
(-inf...inf).bsearch { |x| x >= 3 }.should == 3.0
|
||||||
|
(0..inf).bsearch { |x| x >= Float::MAX }.should == Float::MAX
|
||||||
|
(0...inf).bsearch { |x| x >= Float::MAX }.should == Float::MAX
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with a block returning negative, zero, positive numbers" do
|
context "with a block returning negative, zero, positive numbers" do
|
||||||
|
@ -130,7 +176,157 @@ describe "Range#bsearch" do
|
||||||
it "returns an element at an index for which block returns 0" do
|
it "returns an element at an index for which block returns 0" do
|
||||||
result = (0.1..4.9).bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
|
result = (0.1..4.9).bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
|
||||||
result.should >= 1
|
result.should >= 1
|
||||||
result.should <= 2
|
result.should <= 3
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns an element at an index for which block returns 0 (small numbers)" do
|
||||||
|
result = (0.1..0.3).bsearch { |x| x < 0.1 ? 1 : x > 0.3 ? -1 : 0 }
|
||||||
|
result.should >= 0.1
|
||||||
|
result.should <= 0.3
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a boundary element if appropriate" do
|
||||||
|
(1.0..3.0).bsearch { |x| 3.0 - x }.should == 3.0
|
||||||
|
(1.0...3.0).bsearch { |x| 3.0.prev_float - x }.should == 3.0.prev_float
|
||||||
|
(1.0..3.0).bsearch { |x| 1.0 - x }.should == 1.0
|
||||||
|
(1.0...3.0).bsearch { |x| 1.0 - x }.should == 1.0
|
||||||
|
end
|
||||||
|
|
||||||
|
it "works with infinity bounds" do
|
||||||
|
inf = Float::INFINITY
|
||||||
|
(0..inf).bsearch { |x| x == inf ? 0 : -1 }.should == nil
|
||||||
|
(0...inf).bsearch { |x| x == inf ? 0 : -1 }.should == nil
|
||||||
|
(-inf...0).bsearch { |x| x == -inf ? 0 : 1 }.should == nil
|
||||||
|
(-inf..0).bsearch { |x| x == -inf ? 0 : 1 }.should == nil
|
||||||
|
(inf..inf).bsearch { 0 }.should == inf
|
||||||
|
(inf...inf).bsearch { 0 }.should == nil
|
||||||
|
(-inf..-inf).bsearch { 0 }.should == -inf
|
||||||
|
(-inf...-inf).bsearch { 0 }.should == nil
|
||||||
|
(inf..0).bsearch { 0 }.should == nil
|
||||||
|
(inf...0).bsearch { 0 }.should == nil
|
||||||
|
(0..-inf).bsearch { 0 }.should == nil
|
||||||
|
(0...-inf).bsearch { 0 }.should == nil
|
||||||
|
(inf..-inf).bsearch { 0 }.should == nil
|
||||||
|
(inf...-inf).bsearch { 0 }.should == nil
|
||||||
|
(-inf..inf).bsearch { |x| 3 - x }.should == 3.0
|
||||||
|
(-inf...inf).bsearch { |x| 3 - x }.should == 3.0
|
||||||
|
(0...inf).bsearch { |x| x >= Float::MAX ? 0 : 1 }.should == Float::MAX
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
context "with endless ranges and Integer values" do
|
||||||
|
context "with a block returning true or false" do
|
||||||
|
it "returns minimum element if the block returns true for every element" do
|
||||||
|
eval("(-2..)").bsearch { |x| true }.should == -2
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the smallest element for which block returns true" do
|
||||||
|
eval("(0..)").bsearch { |x| x >= 2 }.should == 2
|
||||||
|
eval("(-1..)").bsearch { |x| x >= 1 }.should == 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with a block returning negative, zero, positive numbers" do
|
||||||
|
it "returns nil if the block returns less than zero for every element" do
|
||||||
|
eval("(0..)").bsearch { |x| -1 }.should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns nil if the block never returns zero" do
|
||||||
|
eval("(0..)").bsearch { |x| x > 5 ? -1 : 1 }.should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts -Float::INFINITY from the block" do
|
||||||
|
eval("(0..)").bsearch { |x| -Float::INFINITY }.should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns an element at an index for which block returns 0.0" do
|
||||||
|
result = eval("(0..)").bsearch { |x| x < 2 ? 1.0 : x > 2 ? -1.0 : 0.0 }
|
||||||
|
result.should == 2
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns an element at an index for which block returns 0" do
|
||||||
|
result = eval("(0..)").bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
|
||||||
|
[1, 2].should include(result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with endless ranges and Float values" do
|
||||||
|
context "with a block returning true or false" do
|
||||||
|
it "returns nil if the block returns false for every element" do
|
||||||
|
eval("(0.1..)").bsearch { |x| x < 0.0 }.should be_nil
|
||||||
|
eval("(0.1...)").bsearch { |x| x < 0.0 }.should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns nil if the block returns nil for every element" do
|
||||||
|
eval("(-0.0..)").bsearch { |x| nil }.should be_nil
|
||||||
|
eval("(-0.0...)").bsearch { |x| nil }.should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns minimum element if the block returns true for every element" do
|
||||||
|
eval("(-0.2..)").bsearch { |x| true }.should == -0.2
|
||||||
|
eval("(-0.2...)").bsearch { |x| true }.should == -0.2
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the smallest element for which block returns true" do
|
||||||
|
eval("(0..)").bsearch { |x| x >= 2 }.should == 2
|
||||||
|
eval("(-1.2..)").bsearch { |x| x >= 1 }.should == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
it "works with infinity bounds" do
|
||||||
|
inf = Float::INFINITY
|
||||||
|
eval("(inf..)").bsearch { |x| true }.should == inf
|
||||||
|
eval("(inf...)").bsearch { |x| true }.should == nil
|
||||||
|
eval("(-inf..)").bsearch { |x| true }.should == -inf
|
||||||
|
eval("(-inf...)").bsearch { |x| true }.should == -inf
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with a block returning negative, zero, positive numbers" do
|
||||||
|
it "returns nil if the block returns less than zero for every element" do
|
||||||
|
eval("(-2.0..)").bsearch { |x| -1 }.should be_nil
|
||||||
|
eval("(-2.0...)").bsearch { |x| -1 }.should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns nil if the block returns greater than zero for every element" do
|
||||||
|
eval("(0.3..)").bsearch { |x| 1 }.should be_nil
|
||||||
|
eval("(0.3...)").bsearch { |x| 1 }.should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns nil if the block never returns zero" do
|
||||||
|
eval("(0.2..)").bsearch { |x| x < 2 ? 1 : -1 }.should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts (+/-)Float::INFINITY from the block" do
|
||||||
|
eval("(0.1..)").bsearch { |x| Float::INFINITY }.should be_nil
|
||||||
|
eval("(-5.0..)").bsearch { |x| -Float::INFINITY }.should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns an element at an index for which block returns 0.0" do
|
||||||
|
result = eval("(0.0..)").bsearch { |x| x < 2 ? 1.0 : x > 2 ? -1.0 : 0.0 }
|
||||||
|
result.should == 2
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns an element at an index for which block returns 0" do
|
||||||
|
result = eval("(0.1..)").bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
|
||||||
|
result.should >= 1
|
||||||
|
result.should <= 3
|
||||||
|
end
|
||||||
|
|
||||||
|
it "works with infinity bounds" do
|
||||||
|
inf = Float::INFINITY
|
||||||
|
eval("(inf..)").bsearch { |x| 1 }.should == nil
|
||||||
|
eval("(inf...)").bsearch { |x| 1 }.should == nil
|
||||||
|
eval("(inf..)").bsearch { |x| x == inf ? 0 : 1 }.should == inf
|
||||||
|
eval("(inf...)").bsearch { |x| x == inf ? 0 : 1 }.should == nil
|
||||||
|
eval("(-inf..)").bsearch { |x| x == -inf ? 0 : -1 }.should == -inf
|
||||||
|
eval("(-inf...)").bsearch { |x| x == -inf ? 0 : -1 }.should == -inf
|
||||||
|
eval("(-inf..)").bsearch { |x| 3 - x }.should == 3
|
||||||
|
eval("(-inf...)").bsearch { |x| 3 - x }.should == 3
|
||||||
|
eval("(0.0...)").bsearch { 0 }.should != inf
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,6 +32,28 @@ describe "Range#each" do
|
||||||
a.should == [x, y]
|
a.should == [x, y]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
it "works with endless ranges" do
|
||||||
|
a = []
|
||||||
|
eval("(-2..)").each { |x| break if x > 2; a << x }
|
||||||
|
a.should == [-2, -1, 0, 1, 2]
|
||||||
|
|
||||||
|
a = []
|
||||||
|
eval("(-2...)").each { |x| break if x > 2; a << x }
|
||||||
|
a.should == [-2, -1, 0, 1, 2]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "works with String endless ranges" do
|
||||||
|
a = []
|
||||||
|
eval("('A'..)").each { |x| break if x > "D"; a << x }
|
||||||
|
a.should == ["A", "B", "C", "D"]
|
||||||
|
|
||||||
|
a = []
|
||||||
|
eval("('A'...)").each { |x| break if x > "D"; a << x }
|
||||||
|
a.should == ["A", "B", "C", "D"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "raises a TypeError if the first element does not respond to #succ" do
|
it "raises a TypeError if the first element does not respond to #succ" do
|
||||||
-> { (0.5..2.4).each { |i| i } }.should raise_error(TypeError)
|
-> { (0.5..2.4).each { |i| i } }.should raise_error(TypeError)
|
||||||
|
|
||||||
|
|
|
@ -7,4 +7,10 @@ describe "Range#==" do
|
||||||
it "returns true if the endpoints are ==" do
|
it "returns true if the endpoints are ==" do
|
||||||
(0..1).should == (0..1.0)
|
(0..1).should == (0..1.0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
it "returns true if the endpoints are == for endless ranges" do
|
||||||
|
eval("(1.0..)").should == eval("(1.0..)")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,6 +12,13 @@ describe "Range#inspect" do
|
||||||
(0.5..2.4).inspect.should == "0.5..2.4"
|
(0.5..2.4).inspect.should == "0.5..2.4"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
it "works for endless ranges" do
|
||||||
|
eval("(1..)").inspect.should == "1.."
|
||||||
|
eval("(0.1...)").inspect.should == "0.1..."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
ruby_version_is ''...'2.7' do
|
ruby_version_is ''...'2.7' do
|
||||||
it "returns a tainted string if either end is tainted" do
|
it "returns a tainted string if either end is tainted" do
|
||||||
(("a".taint)..."c").inspect.tainted?.should be_true
|
(("a".taint)..."c").inspect.tainted?.should be_true
|
||||||
|
|
|
@ -46,4 +46,10 @@ describe "Range#last" do
|
||||||
it "raises a TypeError when passed a String" do
|
it "raises a TypeError when passed a String" do
|
||||||
-> { (2..3).last("1") }.should raise_error(TypeError)
|
-> { (2..3).last("1") }.should raise_error(TypeError)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
it "raises a RangeError when called on an endless range" do
|
||||||
|
-> { eval("(1..)").last }.should raise_error(RangeError)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -45,6 +45,12 @@ describe "Range#max" do
|
||||||
time_end = Time.now + 1.0
|
time_end = Time.now + 1.0
|
||||||
-> { (time_start...time_end).max }.should raise_error(TypeError)
|
-> { (time_start...time_end).max }.should raise_error(TypeError)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
it "raises RangeError when called on an endless range" do
|
||||||
|
-> { eval("(1..)").max }.should raise_error(RangeError)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "Range#max given a block" do
|
describe "Range#max given a block" do
|
||||||
|
|
|
@ -72,4 +72,11 @@ describe "Range#min given a block" do
|
||||||
('z'..'l').min {|x,y| x <=> y}.should be_nil
|
('z'..'l').min {|x,y| x <=> y}.should be_nil
|
||||||
(7...7).min {|x,y| x <=> y}.should be_nil
|
(7...7).min {|x,y| x <=> y}.should be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
it "returns the start point for endless ranges" do
|
||||||
|
eval("(1..)").min.should == 1
|
||||||
|
eval("(1.0...)").min.should == 1.0
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,6 +19,13 @@ describe :range_cover_and_include, shared: true do
|
||||||
(0.5...2.4).send(@method, 2.4).should == false
|
(0.5...2.4).send(@method, 2.4).should == false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
it "returns true if other is an element of self for endless ranges" do
|
||||||
|
eval("(1..)").send(@method, 2.4).should == true
|
||||||
|
eval("(0.5...)").send(@method, 2.4).should == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "compares values using <=>" do
|
it "compares values using <=>" do
|
||||||
rng = (1..5)
|
rng = (1..5)
|
||||||
m = mock("int")
|
m = mock("int")
|
||||||
|
|
|
@ -42,4 +42,12 @@ describe :range_eql, shared: true do
|
||||||
b = RangeSpecs::MyRange.new(RangeSpecs::Xs.new(3), RangeSpecs::Xs.new(5))
|
b = RangeSpecs::MyRange.new(RangeSpecs::Xs.new(3), RangeSpecs::Xs.new(5))
|
||||||
a.send(@method, b).should == true
|
a.send(@method, b).should == true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
it "works for endless Ranges" do
|
||||||
|
eval("(1..)").send(@method, eval("(1..)")).should == true
|
||||||
|
eval("(0.5...)").send(@method, eval("(0.5...)")).should == true
|
||||||
|
eval("(1..)").send(@method, eval("(1...)")).should == false
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,6 +24,13 @@ describe "Range#size" do
|
||||||
(-Float::INFINITY..Float::INFINITY).size.should == Float::INFINITY
|
(-Float::INFINITY..Float::INFINITY).size.should == Float::INFINITY
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
it 'returns Float::INFINITY for endless ranges' do
|
||||||
|
eval("(1..)").size.should == Float::INFINITY
|
||||||
|
eval("(0.5...)").size.should == Float::INFINITY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "returns nil if first and last are not Numeric" do
|
it "returns nil if first and last are not Numeric" do
|
||||||
(:a..:z).size.should be_nil
|
(:a..:z).size.should be_nil
|
||||||
('a'..'z').size.should be_nil
|
('a'..'z').size.should be_nil
|
||||||
|
|
|
@ -274,6 +274,102 @@ describe "Range#step" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
describe "with an endless range" do
|
||||||
|
describe "and Integer values" do
|
||||||
|
it "yield Integer values incremented by 1 when not passed a step" do
|
||||||
|
eval("(-2..)").step { |x| break if x > 2; ScratchPad << x }
|
||||||
|
ScratchPad.recorded.should eql([-2, -1, 0, 1, 2])
|
||||||
|
|
||||||
|
ScratchPad.record []
|
||||||
|
eval("(-2...)").step { |x| break if x > 2; ScratchPad << x }
|
||||||
|
ScratchPad.recorded.should eql([-2, -1, 0, 1, 2])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "yields Integer values incremented by an Integer step" do
|
||||||
|
eval("(-5..)").step(2) { |x| break if x > 3; ScratchPad << x }
|
||||||
|
ScratchPad.recorded.should eql([-5, -3, -1, 1, 3])
|
||||||
|
|
||||||
|
ScratchPad.record []
|
||||||
|
eval("(-5...)").step(2) { |x| break if x > 3; ScratchPad << x }
|
||||||
|
ScratchPad.recorded.should eql([-5, -3, -1, 1, 3])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "yields Float values incremented by a Float step" do
|
||||||
|
eval("(-2..)").step(1.5) { |x| break if x > 1.0; ScratchPad << x }
|
||||||
|
ScratchPad.recorded.should eql([-2.0, -0.5, 1.0])\
|
||||||
|
|
||||||
|
ScratchPad.record []
|
||||||
|
eval("(-2..)").step(1.5) { |x| break if x > 1.0; ScratchPad << x }
|
||||||
|
ScratchPad.recorded.should eql([-2.0, -0.5, 1.0])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "and Float values" do
|
||||||
|
it "yields Float values incremented by 1 and less than end when not passed a step" do
|
||||||
|
eval("(-2.0..)").step { |x| break if x > 1.5; ScratchPad << x }
|
||||||
|
ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0])
|
||||||
|
|
||||||
|
ScratchPad.record []
|
||||||
|
eval("(-2.0...)").step { |x| break if x > 1.5; ScratchPad << x }
|
||||||
|
ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "yields Float values incremented by an Integer step" do
|
||||||
|
eval("(-5.0..)").step(2) { |x| break if x > 3.5; ScratchPad << x }
|
||||||
|
ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0])
|
||||||
|
|
||||||
|
ScratchPad.record []
|
||||||
|
eval("(-5.0...)").step(2) { |x| break if x > 3.5; ScratchPad << x }
|
||||||
|
ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "yields Float values incremented by a Float step" do
|
||||||
|
eval("(-1.0..)").step(0.5) { |x| break if x > 0.6; ScratchPad << x }
|
||||||
|
ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
|
||||||
|
|
||||||
|
ScratchPad.record []
|
||||||
|
eval("(-1.0...)").step(0.5) { |x| break if x > 0.6; ScratchPad << x }
|
||||||
|
ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "handles infinite values at the start" do
|
||||||
|
eval("(-Float::INFINITY..)").step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
|
||||||
|
ScratchPad.recorded.should eql([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
|
||||||
|
|
||||||
|
ScratchPad.record []
|
||||||
|
eval("(-Float::INFINITY...)").step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
|
||||||
|
ScratchPad.recorded.should eql([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "and String values" do
|
||||||
|
it "yields String values incremented by #succ and less than or equal to end when not passed a step" do
|
||||||
|
eval("('A'..)").step { |x| break if x > "D"; ScratchPad << x }
|
||||||
|
ScratchPad.recorded.should == ["A", "B", "C", "D"]
|
||||||
|
|
||||||
|
ScratchPad.record []
|
||||||
|
eval("('A'...)").step { |x| break if x > "D"; ScratchPad << x }
|
||||||
|
ScratchPad.recorded.should == ["A", "B", "C", "D"]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "yields String values incremented by #succ called Integer step times" do
|
||||||
|
eval("('A'..)").step(2) { |x| break if x > "F"; ScratchPad << x }
|
||||||
|
ScratchPad.recorded.should == ["A", "C", "E"]
|
||||||
|
|
||||||
|
ScratchPad.record []
|
||||||
|
eval("('A'...)").step(2) { |x| break if x > "F"; ScratchPad << x }
|
||||||
|
ScratchPad.recorded.should == ["A", "C", "E"]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises a TypeError when passed a Float step" do
|
||||||
|
-> { eval("('A'..)").step(2.0) { } }.should raise_error(TypeError)
|
||||||
|
-> { eval("('A'...)").step(2.0) { } }.should raise_error(TypeError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "when no block is given" do
|
describe "when no block is given" do
|
||||||
describe "returned Enumerator" do
|
describe "returned Enumerator" do
|
||||||
describe "size" do
|
describe "size" do
|
||||||
|
|
|
@ -19,4 +19,10 @@ describe "Range#to_a" do
|
||||||
it "works with Ranges of Symbols" do
|
it "works with Ranges of Symbols" do
|
||||||
(:A..:z).to_a.size.should == 58
|
(:A..:z).to_a.size.should == 58
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
it "throws an exception for endless ranges" do
|
||||||
|
-> { eval("(1..)").to_a }.should raise_error(RangeError)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,6 +11,13 @@ describe "Range#to_s" do
|
||||||
(0.5..2.4).to_s.should == "0.5..2.4"
|
(0.5..2.4).to_s.should == "0.5..2.4"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.6" do
|
||||||
|
it "can show endless ranges" do
|
||||||
|
eval("(1..)").to_s.should == "1.."
|
||||||
|
eval("(1.0...)").to_s.should == "1.0..."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
ruby_version_is ''...'2.7' do
|
ruby_version_is ''...'2.7' do
|
||||||
it "returns a tainted string if either end is tainted" do
|
it "returns a tainted string if either end is tainted" do
|
||||||
(("a".taint)..."c").to_s.tainted?.should be_true
|
(("a".taint)..."c").to_s.tainted?.should be_true
|
||||||
|
|
|
@ -93,6 +93,12 @@ describe "String#capitalize!" do
|
||||||
a.should == "Hello"
|
a.should == "Hello"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "modifies self in place for non-ascii-compatible encodings" do
|
||||||
|
a = "heLLo".encode("utf-16le")
|
||||||
|
a.capitalize!
|
||||||
|
a.should == "Hello".encode("utf-16le")
|
||||||
|
end
|
||||||
|
|
||||||
describe "full Unicode case mapping" do
|
describe "full Unicode case mapping" do
|
||||||
it "modifies self in place for all of Unicode with no option" do
|
it "modifies self in place for all of Unicode with no option" do
|
||||||
a = "äöÜ"
|
a = "äöÜ"
|
||||||
|
@ -106,6 +112,12 @@ describe "String#capitalize!" do
|
||||||
a.should == "Ss"
|
a.should == "Ss"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "works for non-ascii-compatible encodings" do
|
||||||
|
a = "äöü".encode("utf-16le")
|
||||||
|
a.capitalize!
|
||||||
|
a.should == "Äöü".encode("utf-16le")
|
||||||
|
end
|
||||||
|
|
||||||
it "updates string metadata" do
|
it "updates string metadata" do
|
||||||
capitalized = "ßeT"
|
capitalized = "ßeT"
|
||||||
capitalized.capitalize!
|
capitalized.capitalize!
|
||||||
|
@ -123,6 +135,12 @@ describe "String#capitalize!" do
|
||||||
a.capitalize!(:ascii)
|
a.capitalize!(:ascii)
|
||||||
a.should == "ßet"
|
a.should == "ßet"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "works for non-ascii-compatible encodings" do
|
||||||
|
a = "aBc".encode("utf-16le")
|
||||||
|
a.capitalize!(:ascii)
|
||||||
|
a.should == "Abc".encode("utf-16le")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "modifies self in place for full Unicode case mapping adapted for Turkic languages" do
|
describe "modifies self in place for full Unicode case mapping adapted for Turkic languages" do
|
||||||
|
|
|
@ -88,6 +88,12 @@ describe "String#downcase!" do
|
||||||
a.should == "hello"
|
a.should == "hello"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "modifies self in place for non-ascii-compatible encodings" do
|
||||||
|
a = "HeLlO".encode("utf-16le")
|
||||||
|
a.downcase!
|
||||||
|
a.should == "hello".encode("utf-16le")
|
||||||
|
end
|
||||||
|
|
||||||
describe "full Unicode case mapping" do
|
describe "full Unicode case mapping" do
|
||||||
it "modifies self in place for all of Unicode with no option" do
|
it "modifies self in place for all of Unicode with no option" do
|
||||||
a = "ÄÖÜ"
|
a = "ÄÖÜ"
|
||||||
|
@ -112,6 +118,12 @@ describe "String#downcase!" do
|
||||||
a.downcase!(:ascii)
|
a.downcase!(:ascii)
|
||||||
a.should == "cÅr"
|
a.should == "cÅr"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "works for non-ascii-compatible encodings" do
|
||||||
|
a = "ABC".encode("utf-16le")
|
||||||
|
a.downcase!(:ascii)
|
||||||
|
a.should == "abc".encode("utf-16le")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "full Unicode case mapping adapted for Turkic languages" do
|
describe "full Unicode case mapping adapted for Turkic languages" do
|
||||||
|
|
|
@ -23,4 +23,17 @@ describe :string_length, shared: true do
|
||||||
|
|
||||||
str.force_encoding('BINARY').send(@method).should == 12
|
str.force_encoding('BINARY').send(@method).should == 12
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns the correct length after force_encoding(BINARY)" do
|
||||||
|
utf8 = "あ"
|
||||||
|
ascii = "a"
|
||||||
|
concat = utf8 + ascii
|
||||||
|
|
||||||
|
concat.encoding.should == Encoding::UTF_8
|
||||||
|
concat.bytesize.should == 4
|
||||||
|
|
||||||
|
concat.size.should == 2
|
||||||
|
concat.force_encoding(Encoding::ASCII_8BIT)
|
||||||
|
concat.size.should == 4
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -84,6 +84,24 @@ describe "String#split with String" do
|
||||||
$; = old_fs
|
$; = old_fs
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
context "when $; is not nil" do
|
||||||
|
before do
|
||||||
|
suppress_warning do
|
||||||
|
@old_value, $; = $;, 'foobar'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
$; = @old_value
|
||||||
|
end
|
||||||
|
|
||||||
|
it "warns" do
|
||||||
|
-> { "".split }.should complain(/warning: \$; is set to non-nil value/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "ignores leading and continuous whitespace when string is a single space" do
|
it "ignores leading and continuous whitespace when string is a single space" do
|
||||||
|
|
|
@ -86,6 +86,12 @@ describe "String#swapcase!" do
|
||||||
a.should == "CyBeR_pUnK11"
|
a.should == "CyBeR_pUnK11"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "modifies self in place for non-ascii-compatible encodings" do
|
||||||
|
a = "cYbEr_PuNk11".encode("utf-16le")
|
||||||
|
a.swapcase!
|
||||||
|
a.should == "CyBeR_pUnK11".encode("utf-16le")
|
||||||
|
end
|
||||||
|
|
||||||
describe "full Unicode case mapping" do
|
describe "full Unicode case mapping" do
|
||||||
it "modifies self in place for all of Unicode with no option" do
|
it "modifies self in place for all of Unicode with no option" do
|
||||||
a = "äÖü"
|
a = "äÖü"
|
||||||
|
@ -93,6 +99,12 @@ describe "String#swapcase!" do
|
||||||
a.should == "ÄöÜ"
|
a.should == "ÄöÜ"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "works for non-ascii-compatible encodings" do
|
||||||
|
a = "äÖü".encode("utf-16le")
|
||||||
|
a.swapcase!
|
||||||
|
a.should == "ÄöÜ".encode("utf-16le")
|
||||||
|
end
|
||||||
|
|
||||||
it "updates string metadata" do
|
it "updates string metadata" do
|
||||||
swapcased = "Aßet"
|
swapcased = "Aßet"
|
||||||
swapcased.swapcase!
|
swapcased.swapcase!
|
||||||
|
@ -110,6 +122,12 @@ describe "String#swapcase!" do
|
||||||
a.swapcase!(:ascii)
|
a.swapcase!(:ascii)
|
||||||
a.should == "AßET"
|
a.should == "AßET"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "works for non-ascii-compatible encodings" do
|
||||||
|
a = "aBc".encode("utf-16le")
|
||||||
|
a.swapcase!(:ascii)
|
||||||
|
a.should == "AbC".encode("utf-16le")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "modifies self in place for full Unicode case mapping adapted for Turkic languages" do
|
describe "modifies self in place for full Unicode case mapping adapted for Turkic languages" do
|
||||||
|
|
|
@ -85,6 +85,12 @@ describe "String#upcase!" do
|
||||||
a.should == "HELLO"
|
a.should == "HELLO"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "modifies self in place for non-ascii-compatible encodings" do
|
||||||
|
a = "HeLlO".encode("utf-16le")
|
||||||
|
a.upcase!
|
||||||
|
a.should == "HELLO".encode("utf-16le")
|
||||||
|
end
|
||||||
|
|
||||||
describe "full Unicode case mapping" do
|
describe "full Unicode case mapping" do
|
||||||
it "modifies self in place for all of Unicode with no option" do
|
it "modifies self in place for all of Unicode with no option" do
|
||||||
a = "äöü"
|
a = "äöü"
|
||||||
|
@ -92,6 +98,12 @@ describe "String#upcase!" do
|
||||||
a.should == "ÄÖÜ"
|
a.should == "ÄÖÜ"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "works for non-ascii-compatible encodings" do
|
||||||
|
a = "äöü".encode("utf-16le")
|
||||||
|
a.upcase!
|
||||||
|
a.should == "ÄÖÜ".encode("utf-16le")
|
||||||
|
end
|
||||||
|
|
||||||
it "updates string metadata for self" do
|
it "updates string metadata for self" do
|
||||||
upcased = "aßet"
|
upcased = "aßet"
|
||||||
upcased.upcase!
|
upcased.upcase!
|
||||||
|
@ -109,6 +121,12 @@ describe "String#upcase!" do
|
||||||
a.upcase!(:ascii)
|
a.upcase!(:ascii)
|
||||||
a.should == "AßET"
|
a.should == "AßET"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "works for non-ascii-compatible encodings" do
|
||||||
|
a = "abc".encode("utf-16le")
|
||||||
|
a.upcase!(:ascii)
|
||||||
|
a.should == "ABC".encode("utf-16le")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "modifies self in place for full Unicode case mapping adapted for Turkic languages" do
|
describe "modifies self in place for full Unicode case mapping adapted for Turkic languages" do
|
||||||
|
|
70
spec/ruby/core/struct/deconstruct_keys_spec.rb
Normal file
70
spec/ruby/core/struct/deconstruct_keys_spec.rb
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
require_relative '../../spec_helper'
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
describe "Struct#deconstruct_keys" do
|
||||||
|
it "returns a hash of attributes" do
|
||||||
|
struct = Struct.new(:x, :y)
|
||||||
|
s = struct.new(1, 2)
|
||||||
|
|
||||||
|
s.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "requires one argument" do
|
||||||
|
struct = Struct.new(:x)
|
||||||
|
obj = struct.new(1)
|
||||||
|
|
||||||
|
-> {
|
||||||
|
obj.deconstruct_keys
|
||||||
|
}.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns only specified keys" do
|
||||||
|
struct = Struct.new(:x, :y, :z)
|
||||||
|
s = struct.new(1, 2, 3)
|
||||||
|
|
||||||
|
s.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
|
||||||
|
s.deconstruct_keys([:x] ).should == {x: 1}
|
||||||
|
s.deconstruct_keys([] ).should == {}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts string attribute names" do
|
||||||
|
struct = Struct.new(:x, :y)
|
||||||
|
s = struct.new(1, 2)
|
||||||
|
|
||||||
|
s.deconstruct_keys(['x', 'y']).should == {'x' => 1, 'y' => 2}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts argument position number as well but returns them as keys" do
|
||||||
|
struct = Struct.new(:x, :y, :z)
|
||||||
|
s = struct.new(10, 20, 30)
|
||||||
|
|
||||||
|
s.deconstruct_keys([0, 1, 2]).should == {0 => 10, 1 => 20, 2 => 30}
|
||||||
|
s.deconstruct_keys([0, 1] ).should == {0 => 10, 1 => 20}
|
||||||
|
s.deconstruct_keys([0] ).should == {0 => 10}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "ignores not existing attribute names" do
|
||||||
|
struct = Struct.new(:x, :y)
|
||||||
|
s = struct.new(1, 2)
|
||||||
|
|
||||||
|
s.deconstruct_keys([:a, :b, :c]).should == {}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts nil argument and return all the attributes" do
|
||||||
|
struct = Struct.new(:x, :y)
|
||||||
|
obj = struct.new(1, 2)
|
||||||
|
|
||||||
|
obj.deconstruct_keys(nil).should == {x: 1, y: 2}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raise TypeError if passed anything accept nil or array" do
|
||||||
|
struct = Struct.new(:x, :y)
|
||||||
|
s = struct.new(1, 2)
|
||||||
|
|
||||||
|
-> { s.deconstruct_keys('x') }.should raise_error(TypeError, /expected Array or nil/)
|
||||||
|
-> { s.deconstruct_keys(1) }.should raise_error(TypeError, /expected Array or nil/)
|
||||||
|
-> { s.deconstruct_keys(:x) }.should raise_error(TypeError, /expected Array or nil/)
|
||||||
|
-> { s.deconstruct_keys({}) }.should raise_error(TypeError, /expected Array or nil/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
12
spec/ruby/core/struct/deconstruct_spec.rb
Normal file
12
spec/ruby/core/struct/deconstruct_spec.rb
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
require_relative '../../spec_helper'
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
describe "Struct#deconstruct" do
|
||||||
|
it "returns an array of attribute values" do
|
||||||
|
struct = Struct.new(:x, :y)
|
||||||
|
s = struct.new(1, 2)
|
||||||
|
|
||||||
|
s.deconstruct.should == [1, 2]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -19,6 +19,22 @@ describe "Struct#hash" do
|
||||||
car.hash.should == similar_car.hash
|
car.hash.should == similar_car.hash
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns different hashes for structs with different values" do
|
||||||
|
s1 = StructClasses::Ruby.new('2.7.0', 'linux')
|
||||||
|
s2 = StructClasses::Ruby.new('2.7.0', 'macos')
|
||||||
|
s1.hash.should_not == s2.hash
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.5" do
|
||||||
|
it "returns different hashes for structs with different values when using keyword_init: true" do
|
||||||
|
key = :"1 non symbol member"
|
||||||
|
struct_class = Struct.new(key, keyword_init: true)
|
||||||
|
t1 = struct_class.new(key => 1)
|
||||||
|
t2 = struct_class.new(key => 2)
|
||||||
|
t1.hash.should_not == t2.hash
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "allows for overriding methods in an included module" do
|
it "allows for overriding methods in an included module" do
|
||||||
mod = Module.new do
|
mod = Module.new do
|
||||||
def hash
|
def hash
|
||||||
|
|
|
@ -19,6 +19,43 @@ describe "Thread#backtrace_locations" do
|
||||||
locations.each { |loc| loc.should be_an_instance_of(Thread::Backtrace::Location) }
|
locations.each { |loc| loc.should be_an_instance_of(Thread::Backtrace::Location) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "can be called with a number of locations to omit" do
|
||||||
|
locations1 = Thread.current.backtrace_locations
|
||||||
|
locations2 = Thread.current.backtrace_locations(2)
|
||||||
|
locations1[2..-1].length.should == locations2.length
|
||||||
|
locations1[2..-1].map(&:to_s).should == locations2.map(&:to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can be called with a maximum number of locations to return as second parameter" do
|
||||||
|
locations1 = Thread.current.backtrace_locations
|
||||||
|
locations2 = Thread.current.backtrace_locations(2, 3)
|
||||||
|
locations1[2..4].map(&:to_s).should == locations2.map(&:to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can be called with a range" do
|
||||||
|
locations1 = Thread.current.backtrace_locations
|
||||||
|
locations2 = Thread.current.backtrace_locations(2..4)
|
||||||
|
locations1[2..4].map(&:to_s).should == locations2.map(&:to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can be called with a range whose end is negative" do
|
||||||
|
locations1 = Thread.current.backtrace_locations
|
||||||
|
locations2 = Thread.current.backtrace_locations(2..-1)
|
||||||
|
locations3 = Thread.current.backtrace_locations(2..-2)
|
||||||
|
locations1[2..-1].map(&:to_s).should == locations2.map(&:to_s)
|
||||||
|
locations1[2..-2].map(&:to_s).should == locations3.map(&:to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns nil if omitting more locations than available" do
|
||||||
|
Thread.current.backtrace_locations(100).should == nil
|
||||||
|
Thread.current.backtrace_locations(100..-1).should == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns [] if omitting exactly the number of locations available" do
|
||||||
|
omit = Thread.current.backtrace_locations.length
|
||||||
|
Thread.current.backtrace_locations(omit).should == []
|
||||||
|
end
|
||||||
|
|
||||||
it "without argument is the same as showing all locations with 0..-1" do
|
it "without argument is the same as showing all locations with 0..-1" do
|
||||||
Thread.current.backtrace_locations.map(&:to_s).should == Thread.current.backtrace_locations(0..-1).map(&:to_s)
|
Thread.current.backtrace_locations.map(&:to_s).should == Thread.current.backtrace_locations(0..-1).map(&:to_s)
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,4 +3,19 @@ require_relative 'shared/inspect'
|
||||||
|
|
||||||
describe "Time#inspect" do
|
describe "Time#inspect" do
|
||||||
it_behaves_like :inspect, :inspect
|
it_behaves_like :inspect, :inspect
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
it "preserves milliseconds" do
|
||||||
|
t = Time.utc(2007, 11, 1, 15, 25, 0, 123456)
|
||||||
|
t.inspect.should == "2007-11-01 15:25:00.123456 UTC"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "formats nanoseconds as a Rational" do
|
||||||
|
t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789)
|
||||||
|
t.nsec.should == 123456789
|
||||||
|
t.strftime("%N").should == "123456789"
|
||||||
|
|
||||||
|
t.inspect.should == "2007-11-01 15:25:00 8483885939586761/68719476736000000 UTC"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -255,4 +255,9 @@ describe "The alias keyword" do
|
||||||
code = '$a = 1; $b = 2; alias $b $a; p [$a, $b]; $b = 3; p [$a, $b]'
|
code = '$a = 1; $b = 2; alias $b $a; p [$a, $b]; $b = 3; p [$a, $b]'
|
||||||
ruby_exe(code).should == "[1, 1]\n[3, 3]\n"
|
ruby_exe(code).should == "[1, 1]\n[3, 3]\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "supports aliasing twice the same global variables" do
|
||||||
|
code = '$a = 1; alias $b $a; alias $b $a; p [$a, $b]'
|
||||||
|
ruby_exe(code).should == "[1, 1]\n"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
15
spec/ruby/language/comment_spec.rb
Normal file
15
spec/ruby/language/comment_spec.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
require_relative '../spec_helper'
|
||||||
|
|
||||||
|
describe "The comment" do
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
it "can be placed between fluent dot now" do
|
||||||
|
code = <<~CODE
|
||||||
|
10
|
||||||
|
# some comment
|
||||||
|
.to_s
|
||||||
|
CODE
|
||||||
|
|
||||||
|
eval(code).should == '10'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
87
spec/ruby/language/numbered_parameters_spec.rb
Normal file
87
spec/ruby/language/numbered_parameters_spec.rb
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
require_relative '../spec_helper'
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
describe "Numbered parameters" do
|
||||||
|
it "provides default parameters _1, _2, ... in a block" do
|
||||||
|
-> { _1 }.call("a").should == "a"
|
||||||
|
proc { _1 }.call("a").should == "a"
|
||||||
|
lambda { _1 }.call("a").should == "a"
|
||||||
|
["a"].map { _1 }.should == ["a"]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "assigns nil to not passed parameters" do
|
||||||
|
proc { [_1, _2] }.call("a").should == ["a", nil]
|
||||||
|
proc { [_1, _2] }.call("a", "b").should == ["a", "b"]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports variables _1-_9 only for the first 9 passed parameters" do
|
||||||
|
block = proc { [_1, _2, _3, _4, _5, _6, _7, _8, _9] }
|
||||||
|
result = block.call(1, 2, 3, 4, 5, 6, 7, 8, 9)
|
||||||
|
result.should == [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not support more than 9 parameters" do
|
||||||
|
-> {
|
||||||
|
proc { [_10] }.call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
||||||
|
}.should raise_error(NameError, /undefined local variable or method `_10'/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can not be used in both outer and nested blocks at the same time" do
|
||||||
|
-> {
|
||||||
|
eval("-> { _1; -> { _2 } }")
|
||||||
|
}.should raise_error(SyntaxError, /numbered parameter is already used in.+ outer block here/m)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can be overwritten with local variable" do
|
||||||
|
suppress_warning do
|
||||||
|
eval <<~CODE
|
||||||
|
_1 = 0
|
||||||
|
proc { _1 }.call("a").should == 0
|
||||||
|
CODE
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "warns when numbered parameter is overriten with local variable" do
|
||||||
|
-> {
|
||||||
|
eval("_1 = 0")
|
||||||
|
}.should complain(/warning: `_1' is reserved for numbered parameter; consider another name/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises SyntaxError when block parameters are specified explicitly" do
|
||||||
|
-> { eval("-> () { _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
|
||||||
|
-> { eval("-> (x) { _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
|
||||||
|
|
||||||
|
-> { eval("proc { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
|
||||||
|
-> { eval("proc { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
|
||||||
|
|
||||||
|
-> { eval("lambda { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
|
||||||
|
-> { eval("lambda { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
|
||||||
|
|
||||||
|
-> { eval("['a'].map { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
|
||||||
|
-> { eval("['a'].map { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "affects block arity" do
|
||||||
|
-> { _1 }.arity.should == 1
|
||||||
|
-> { _2 }.arity.should == 2
|
||||||
|
-> { _3 }.arity.should == 3
|
||||||
|
-> { _4 }.arity.should == 4
|
||||||
|
-> { _5 }.arity.should == 5
|
||||||
|
-> { _6 }.arity.should == 6
|
||||||
|
-> { _7 }.arity.should == 7
|
||||||
|
-> { _8 }.arity.should == 8
|
||||||
|
-> { _9 }.arity.should == 9
|
||||||
|
|
||||||
|
-> { _9 }.arity.should == 9
|
||||||
|
proc { _9 }.arity.should == 9
|
||||||
|
lambda { _9 }.arity.should == 9
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not work in methods" do
|
||||||
|
obj = Object.new
|
||||||
|
def obj.foo; _1 end
|
||||||
|
|
||||||
|
-> { obj.foo("a") }.should raise_error(ArgumentError, /wrong number of arguments/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -45,6 +45,10 @@ describe "A number literal" do
|
||||||
eval('-3r').should == Rational(-3, 1)
|
eval('-3r').should == Rational(-3, 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "can be a float literal with trailing 'r' to represent a Rational" do
|
||||||
|
eval('0.0174532925199432957r').should == Rational(174532925199432957, 10000000000000000000)
|
||||||
|
end
|
||||||
|
|
||||||
it "can be an bignum literal with trailing 'r' to represent a Rational" do
|
it "can be an bignum literal with trailing 'r' to represent a Rational" do
|
||||||
eval('1111111111111111111111111111111111111111111111r').should == Rational(1111111111111111111111111111111111111111111111, 1)
|
eval('1111111111111111111111111111111111111111111111r').should == Rational(1111111111111111111111111111111111111111111111, 1)
|
||||||
eval('-1111111111111111111111111111111111111111111111r').should == Rational(-1111111111111111111111111111111111111111111111, 1)
|
eval('-1111111111111111111111111111111111111111111111r').should == Rational(-1111111111111111111111111111111111111111111111, 1)
|
||||||
|
|
966
spec/ruby/language/pattern_matching_spec.rb
Normal file
966
spec/ruby/language/pattern_matching_spec.rb
Normal file
|
@ -0,0 +1,966 @@
|
||||||
|
require_relative '../spec_helper'
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
describe "Pattern matching" do
|
||||||
|
# TODO: Remove excessive eval calls when support of previous version
|
||||||
|
# Ruby 2.6 will be dropped
|
||||||
|
|
||||||
|
before do
|
||||||
|
ScratchPad.record []
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can be standalone in operator that deconstructs value" do
|
||||||
|
eval(<<-RUBY).should == [0, 1]
|
||||||
|
[0, 1] in [a, b]
|
||||||
|
[a, b]
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "extends case expression with case/in construction" do
|
||||||
|
eval(<<~RUBY).should == :bar
|
||||||
|
case [0, 1]
|
||||||
|
in [0]
|
||||||
|
:foo
|
||||||
|
in [0, 1]
|
||||||
|
:bar
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "allows using then operator" do
|
||||||
|
eval(<<~RUBY).should == :bar
|
||||||
|
case [0, 1]
|
||||||
|
in [0] then :foo
|
||||||
|
in [0, 1] then :bar
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "warns about pattern matching is experimental feature" do
|
||||||
|
-> {
|
||||||
|
eval <<~RUBY
|
||||||
|
case 0
|
||||||
|
in 0
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
}.should complain(/warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby!/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "binds variables" do
|
||||||
|
eval(<<~RUBY).should == 1
|
||||||
|
case [0, 1]
|
||||||
|
in [0, a]
|
||||||
|
a
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "cannot mix in and when operators" do
|
||||||
|
-> {
|
||||||
|
eval <<~RUBY
|
||||||
|
case []
|
||||||
|
when 1 == 1
|
||||||
|
in []
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
}.should raise_error(SyntaxError, /syntax error, unexpected `in'/)
|
||||||
|
|
||||||
|
-> {
|
||||||
|
eval <<~RUBY
|
||||||
|
case []
|
||||||
|
in []
|
||||||
|
when 1 == 1
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
}.should raise_error(SyntaxError, /syntax error, unexpected `when'/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "checks patterns until the first matching" do
|
||||||
|
eval(<<~RUBY).should == :bar
|
||||||
|
case [0, 1]
|
||||||
|
in [0]
|
||||||
|
:foo
|
||||||
|
in [0, 1]
|
||||||
|
:bar
|
||||||
|
in [0, 1]
|
||||||
|
:baz
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "executes else clause if no pattern matches" do
|
||||||
|
eval(<<~RUBY).should == false
|
||||||
|
case [0, 1]
|
||||||
|
in [0]
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises NoMatchingPatternError if no pattern matches and no else clause" do
|
||||||
|
-> {
|
||||||
|
eval <<~RUBY
|
||||||
|
case [0, 1]
|
||||||
|
in [0]
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
}.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not allow calculation or method calls in a pattern" do
|
||||||
|
-> {
|
||||||
|
eval <<~RUBY
|
||||||
|
case 0
|
||||||
|
in 1 + 1
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
}.should raise_error(SyntaxError, /unexpected/)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "guards" do
|
||||||
|
it "supports if guard" do
|
||||||
|
eval(<<~RUBY).should == false
|
||||||
|
case 0
|
||||||
|
in 0 if false
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case 0
|
||||||
|
in 0 if true
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports unless guard" do
|
||||||
|
eval(<<~RUBY).should == false
|
||||||
|
case 0
|
||||||
|
in 0 unless true
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case 0
|
||||||
|
in 0 unless false
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "makes bound variables visible in guard" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case [0, 1]
|
||||||
|
in [a, 1] if a >= 0
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not evaluate guard if pattern does not match" do
|
||||||
|
eval <<~RUBY
|
||||||
|
case 0
|
||||||
|
in 1 if (ScratchPad << :foo) || true
|
||||||
|
else
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
ScratchPad.recorded.should == []
|
||||||
|
end
|
||||||
|
|
||||||
|
it "takes guards into account when there are several matching patterns" do
|
||||||
|
eval(<<~RUBY).should == :bar
|
||||||
|
case 0
|
||||||
|
in 0 if false
|
||||||
|
:foo
|
||||||
|
in 0 if true
|
||||||
|
:bar
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "executes else clause if no guarded pattern matches" do
|
||||||
|
eval(<<~RUBY).should == false
|
||||||
|
case 0
|
||||||
|
in 0 if false
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises NoMatchingPatternError if no guarded pattern matches and no else clause" do
|
||||||
|
-> {
|
||||||
|
eval <<~RUBY
|
||||||
|
case [0, 1]
|
||||||
|
in [0, 1] if false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
}.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "value pattern" do
|
||||||
|
it "matches an object such that pattern === object" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case 0
|
||||||
|
in 0
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case 0
|
||||||
|
in (-1..1)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case 0
|
||||||
|
in Integer
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case "0"
|
||||||
|
in /0/
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case "0"
|
||||||
|
in ->(s) { s == "0" }
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "allows string literal with interpolation" do
|
||||||
|
x = "x"
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case "x"
|
||||||
|
in "#{x + ""}"
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "variable pattern" do
|
||||||
|
it "matches a value and binds variable name to this value" do
|
||||||
|
eval(<<~RUBY).should == 0
|
||||||
|
case 0
|
||||||
|
in a
|
||||||
|
a
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "makes bounded variable visible outside a case statement scope" do
|
||||||
|
eval(<<~RUBY).should == 0
|
||||||
|
case 0
|
||||||
|
in a
|
||||||
|
end
|
||||||
|
|
||||||
|
a
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "create local variables even if a pattern doesn't match" do
|
||||||
|
eval(<<~RUBY).should == [0, nil, nil]
|
||||||
|
case 0
|
||||||
|
in a
|
||||||
|
in b
|
||||||
|
in c
|
||||||
|
end
|
||||||
|
|
||||||
|
[a, b, c]
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "allow using _ name to drop values" do
|
||||||
|
eval(<<~RUBY).should == 0
|
||||||
|
case [0, 1]
|
||||||
|
in [a, _]
|
||||||
|
a
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports using _ in a pattern several times" do
|
||||||
|
eval(<<~RUBY).should == 2
|
||||||
|
case [0, 1, 2]
|
||||||
|
in [0, _, _]
|
||||||
|
_
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports using any name with _ at the beginning in a pattern several times" do
|
||||||
|
eval(<<~RUBY).should == 2
|
||||||
|
case [0, 1, 2]
|
||||||
|
in [0, _x, _x]
|
||||||
|
_x
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == 2
|
||||||
|
case {a: 0, b: 1, c: 2}
|
||||||
|
in {a: 0, b: _x, c: _x}
|
||||||
|
_x
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not support using variable name (except _) several times" do
|
||||||
|
-> {
|
||||||
|
eval <<~RUBY
|
||||||
|
case [0]
|
||||||
|
in [a, a]
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
}.should raise_error(SyntaxError, /duplicated variable name/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports existing variables in a pattern specified with ^ operator" do
|
||||||
|
a = 0
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case 0
|
||||||
|
in ^a
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "allows applying ^ operator to bound variables" do
|
||||||
|
eval(<<~RUBY).should == 1
|
||||||
|
case [1, 1]
|
||||||
|
in [n, ^n]
|
||||||
|
n
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == false
|
||||||
|
case [1, 2]
|
||||||
|
in [n, ^n]
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "requires bound variable to be specified in a pattern before ^ operator when it relies on a bound variable" do
|
||||||
|
-> {
|
||||||
|
eval <<~RUBY
|
||||||
|
case [1, 2]
|
||||||
|
in [^n, n]
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
}.should raise_error(SyntaxError, /n: no such local variable/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "alternative pattern" do
|
||||||
|
it "matches if any of patterns matches" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case 0
|
||||||
|
in 0 | 1 | 2
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not support variable binding" do
|
||||||
|
-> {
|
||||||
|
eval <<~RUBY
|
||||||
|
case [0, 1]
|
||||||
|
in [0, 0] | [0, a]
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
}.should raise_error(SyntaxError, /illegal variable in alternative pattern/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "AS pattern" do
|
||||||
|
it "binds a variable to a value if pattern matches" do
|
||||||
|
eval(<<~RUBY).should == 0
|
||||||
|
case 0
|
||||||
|
in Integer => n
|
||||||
|
n
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can be used as a nested pattern" do
|
||||||
|
eval(<<~RUBY).should == [2, 3]
|
||||||
|
case [1, [2, 3]]
|
||||||
|
in [1, Array => ary]
|
||||||
|
ary
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Array pattern" do
|
||||||
|
it "supports form Constant(pat, pat, ...)" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case [0, 1, 2]
|
||||||
|
in Array(0, 1, 2)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports form Constant[pat, pat, ...]" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case [0, 1, 2]
|
||||||
|
in Array[0, 1, 2]
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports form [pat, pat, ...]" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case [0, 1, 2]
|
||||||
|
in [0, 1, 2]
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports form pat, pat, ..." do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case [0, 1, 2]
|
||||||
|
in 0, 1, 2
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == 1
|
||||||
|
case [0, 1, 2]
|
||||||
|
in 0, a, 2
|
||||||
|
a
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == [1, 2]
|
||||||
|
case [0, 1, 2]
|
||||||
|
in 0, *rest
|
||||||
|
rest
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "matches an object with #deconstruct method which returns an array and each element in array matches element in pattern" do
|
||||||
|
obj = Object.new
|
||||||
|
def obj.deconstruct; [0, 1] end
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case obj
|
||||||
|
in [Integer, Integer]
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not match object if Constant === object returns false" do
|
||||||
|
eval(<<~RUBY).should == false
|
||||||
|
case [0, 1, 2]
|
||||||
|
in String[0, 1, 2]
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not match object without #deconstruct method" do
|
||||||
|
obj = Object.new
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == false
|
||||||
|
case obj
|
||||||
|
in Object[]
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises TypeError if #deconstruct method does not return array" do
|
||||||
|
obj = Object.new
|
||||||
|
def obj.deconstruct; "" end
|
||||||
|
|
||||||
|
-> {
|
||||||
|
eval <<~RUBY
|
||||||
|
case obj
|
||||||
|
in Object[]
|
||||||
|
else
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
}.should raise_error(TypeError, /deconstruct must return Array/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not match object if elements of array returned by #deconstruct method does not match elements in pattern" do
|
||||||
|
obj = Object.new
|
||||||
|
def obj.deconstruct; [1] end
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == false
|
||||||
|
case obj
|
||||||
|
in Object[0]
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "binds variables" do
|
||||||
|
eval(<<~RUBY).should == [0, 1, 2]
|
||||||
|
case [0, 1, 2]
|
||||||
|
in [a, b, c]
|
||||||
|
[a, b, c]
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "binds variable even if patter matches only partially" do
|
||||||
|
a = nil
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == 0
|
||||||
|
case [0, 1, 2]
|
||||||
|
in [a, 1, 3]
|
||||||
|
else
|
||||||
|
end
|
||||||
|
|
||||||
|
a
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports splat operator *rest" do
|
||||||
|
eval(<<~RUBY).should == [1, 2]
|
||||||
|
case [0, 1, 2]
|
||||||
|
in [0, *rest]
|
||||||
|
rest
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not match partially by default" do
|
||||||
|
eval(<<~RUBY).should == false
|
||||||
|
case [0, 1, 2, 3]
|
||||||
|
in [1, 2]
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does match partially from the array beginning if list + , syntax used" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case [0, 1, 2, 3]
|
||||||
|
in [0, 1,]
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case [0, 1, 2, 3]
|
||||||
|
in 0, 1,;
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "matches [] with []" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case []
|
||||||
|
in []
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "matches anything with *" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case [0, 1]
|
||||||
|
in *;
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Hash pattern" do
|
||||||
|
it "supports form Constant(id: pat, id: pat, ...)" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case {a: 0, b: 1}
|
||||||
|
in Hash(a: 0, b: 1)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports form Constant[id: pat, id: pat, ...]" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case {a: 0, b: 1}
|
||||||
|
in Hash[a: 0, b: 1]
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports form {id: pat, id: pat, ...}" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case {a: 0, b: 1}
|
||||||
|
in {a: 0, b: 1}
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports form id: pat, id: pat, ..." do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case {a: 0, b: 1}
|
||||||
|
in a: 0, b: 1
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == [0, 1]
|
||||||
|
case {a: 0, b: 1}
|
||||||
|
in a: a, b: b
|
||||||
|
[a, b]
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == { b: 1, c: 2 }
|
||||||
|
case {a: 0, b: 1, c: 2}
|
||||||
|
in a: 0, **rest
|
||||||
|
rest
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports a: which means a: a" do
|
||||||
|
eval(<<~RUBY).should == [0, 1]
|
||||||
|
case {a: 0, b: 1}
|
||||||
|
in Hash(a:, b:)
|
||||||
|
[a, b]
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
a = b = nil
|
||||||
|
eval(<<~RUBY).should == [0, 1]
|
||||||
|
case {a: 0, b: 1}
|
||||||
|
in Hash[a:, b:]
|
||||||
|
[a, b]
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
a = b = nil
|
||||||
|
eval(<<~RUBY).should == [0, 1]
|
||||||
|
case {a: 0, b: 1}
|
||||||
|
in {a:, b:}
|
||||||
|
[a, b]
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
a = nil
|
||||||
|
eval(<<~RUBY).should == [0, {b: 1, c: 2}]
|
||||||
|
case {a: 0, b: 1, c: 2}
|
||||||
|
in {a:, **rest}
|
||||||
|
[a, rest]
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
a = b = nil
|
||||||
|
eval(<<~RUBY).should == [0, 1]
|
||||||
|
case {a: 0, b: 1}
|
||||||
|
in a:, b:
|
||||||
|
[a, b]
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can mix key (a:) and key-value (a: b) declarations" do
|
||||||
|
eval(<<~RUBY).should == [0, 1]
|
||||||
|
case {a: 0, b: 1}
|
||||||
|
in Hash(a:, b: x)
|
||||||
|
[a, x]
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports 'string': key literal" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case {a: 0}
|
||||||
|
in {"a": 0}
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not support non-symbol keys" do
|
||||||
|
-> {
|
||||||
|
eval <<~RUBY
|
||||||
|
case {a: 1}
|
||||||
|
in {"a" => 1}
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
}.should raise_error(SyntaxError, /unexpected/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not support string interpolation in keys" do
|
||||||
|
x = "a"
|
||||||
|
|
||||||
|
-> {
|
||||||
|
eval <<~'RUBY'
|
||||||
|
case {a: 1}
|
||||||
|
in {"#{x}": 1}
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
}.should raise_error(SyntaxError, /symbol literal with interpolation is not allowed/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raise SyntaxError when keys duplicate in pattern" do
|
||||||
|
-> {
|
||||||
|
eval <<~RUBY
|
||||||
|
case {a: 1}
|
||||||
|
in {a: 1, b: 2, a: 3}
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
}.should raise_error(SyntaxError, /duplicated key name/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "matches an object with #deconstruct_keys method which returns a Hash with equal keys and each value in Hash matches value in pattern" do
|
||||||
|
obj = Object.new
|
||||||
|
def obj.deconstruct_keys(*); {a: 1} end
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case obj
|
||||||
|
in {a: 1}
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not match object if Constant === object returns false" do
|
||||||
|
eval(<<~RUBY).should == false
|
||||||
|
case {a: 1}
|
||||||
|
in String[a: 1]
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not match object without #deconstruct_keys method" do
|
||||||
|
obj = Object.new
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == false
|
||||||
|
case obj
|
||||||
|
in Object[a: 1]
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not match object if #deconstruct_keys method does not return Hash" do
|
||||||
|
obj = Object.new
|
||||||
|
def obj.deconstruct_keys(*); "" end
|
||||||
|
|
||||||
|
-> {
|
||||||
|
eval <<~RUBY
|
||||||
|
case obj
|
||||||
|
in Object[a: 1]
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
}.should raise_error(TypeError, /deconstruct_keys must return Hash/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not match object if #deconstruct_keys method returns Hash with non-symbol keys" do
|
||||||
|
obj = Object.new
|
||||||
|
def obj.deconstruct_keys(*); {"a" => 1} end
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == false
|
||||||
|
case obj
|
||||||
|
in Object[a: 1]
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not match object if elements of Hash returned by #deconstruct_keys method does not match values in pattern" do
|
||||||
|
obj = Object.new
|
||||||
|
def obj.deconstruct_keys(*); {a: 1} end
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == false
|
||||||
|
case obj
|
||||||
|
in Object[a: 2]
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "passes keys specified in pattern as arguments to #deconstruct_keys method" do
|
||||||
|
obj = Object.new
|
||||||
|
|
||||||
|
def obj.deconstruct_keys(*args)
|
||||||
|
ScratchPad << args
|
||||||
|
{a: 1, b: 2, c: 3}
|
||||||
|
end
|
||||||
|
|
||||||
|
eval <<~RUBY
|
||||||
|
case obj
|
||||||
|
in Object[a: 1, b: 2, c: 3]
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
ScratchPad.recorded.should == [[[:a, :b, :c]]]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "passes keys specified in pattern to #deconstruct_keys method if pattern contains double splat operator **" do
|
||||||
|
obj = Object.new
|
||||||
|
|
||||||
|
def obj.deconstruct_keys(*args)
|
||||||
|
ScratchPad << args
|
||||||
|
{a: 1, b: 2, c: 3}
|
||||||
|
end
|
||||||
|
|
||||||
|
eval <<~RUBY
|
||||||
|
case obj
|
||||||
|
in Object[a: 1, b: 2, **]
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
ScratchPad.recorded.should == [[[:a, :b]]]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "passes nil to #deconstruct_keys method if pattern contains double splat operator **rest" do
|
||||||
|
obj = Object.new
|
||||||
|
|
||||||
|
def obj.deconstruct_keys(*args)
|
||||||
|
ScratchPad << args
|
||||||
|
{a: 1, b: 2}
|
||||||
|
end
|
||||||
|
|
||||||
|
eval <<~RUBY
|
||||||
|
case obj
|
||||||
|
in Object[a: 1, **rest]
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
ScratchPad.recorded.should == [[nil]]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "binds variables" do
|
||||||
|
eval(<<~RUBY).should == [0, 1, 2]
|
||||||
|
case {a: 0, b: 1, c: 2}
|
||||||
|
in {a: x, b: y, c: z}
|
||||||
|
[x, y, z]
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "binds variable even if pattern matches only partially" do
|
||||||
|
x = nil
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == 0
|
||||||
|
case {a: 0, b: 1}
|
||||||
|
in {a: x, b: 2}
|
||||||
|
else
|
||||||
|
end
|
||||||
|
|
||||||
|
x
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports double splat operator **rest" do
|
||||||
|
eval(<<~RUBY).should == {b: 1, c: 2}
|
||||||
|
case {a: 0, b: 1, c: 2}
|
||||||
|
in {a: 0, **rest}
|
||||||
|
rest
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "treats **nil like there should not be any other keys in a matched Hash" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case {a: 1, b: 2}
|
||||||
|
in {a: 1, b: 2, **nil}
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
eval(<<~RUBY).should == false
|
||||||
|
case {a: 1, b: 2}
|
||||||
|
in {a: 1, **nil}
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can match partially" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case {a: 1, b: 2}
|
||||||
|
in {a: 1}
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "matches {} with {}" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case {}
|
||||||
|
in {}
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
it "matches anything with **" do
|
||||||
|
eval(<<~RUBY).should == true
|
||||||
|
case {a: 1}
|
||||||
|
in **;
|
||||||
|
true
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -398,6 +398,19 @@ describe "Predefined global $!" do
|
||||||
$!.should == nil
|
$!.should == nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should be cleared when an exception is rescued even when a non-local return from block" do
|
||||||
|
[ 1 ].each do
|
||||||
|
begin
|
||||||
|
raise StandardError.new('err')
|
||||||
|
rescue => e
|
||||||
|
$!.should == e
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
$!.should == nil
|
||||||
|
end
|
||||||
|
|
||||||
it "should not be cleared when an exception is not rescued" do
|
it "should not be cleared when an exception is not rescued" do
|
||||||
e = StandardError.new
|
e = StandardError.new
|
||||||
begin
|
begin
|
||||||
|
@ -633,6 +646,12 @@ describe "Predefined global $," do
|
||||||
it "raises TypeError if assigned a non-String" do
|
it "raises TypeError if assigned a non-String" do
|
||||||
-> { $, = Object.new }.should raise_error(TypeError)
|
-> { $, = Object.new }.should raise_error(TypeError)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
it "warns if assigned non-nil" do
|
||||||
|
-> { $, = "_" }.should complain(/warning: `\$,' is deprecated/)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "Predefined global $." do
|
describe "Predefined global $." do
|
||||||
|
@ -662,6 +681,18 @@ describe "Predefined global $." do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "Predefined global $;" do
|
||||||
|
after :each do
|
||||||
|
$; = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
it "warns if assigned non-nil" do
|
||||||
|
-> { $; = "_" }.should complain(/warning: `\$;' is deprecated/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "Predefined global $_" do
|
describe "Predefined global $_" do
|
||||||
it "is set to the last line read by e.g. StringIO#gets" do
|
it "is set to the last line read by e.g. StringIO#gets" do
|
||||||
stdin = StringIO.new("foo\nbar\n", "r")
|
stdin = StringIO.new("foo\nbar\n", "r")
|
||||||
|
|
|
@ -16,4 +16,11 @@ describe "Literal Ranges" do
|
||||||
eval("(1...)").should == Range.new(1, nil, true)
|
eval("(1...)").should == Range.new(1, nil, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
it "creates beginless ranges" do
|
||||||
|
eval("(..1)").should == Range.new(nil, 1)
|
||||||
|
eval("(...1)").should == Range.new(nil, 1, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -481,5 +481,15 @@ describe "The rescue keyword" do
|
||||||
a = raise(Exception) rescue 1
|
a = raise(Exception) rescue 1
|
||||||
}.should raise_error(Exception)
|
}.should raise_error(Exception)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "2.7" do
|
||||||
|
it "rescues with multiple assignment" do
|
||||||
|
|
||||||
|
a, b = raise rescue [1, 2]
|
||||||
|
|
||||||
|
a.should == 1
|
||||||
|
b.should == 2
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
14
spec/ruby/library/English/alias_spec.rb
Normal file
14
spec/ruby/library/English/alias_spec.rb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
require_relative '../../spec_helper'
|
||||||
|
require 'English'
|
||||||
|
|
||||||
|
describe "English" do
|
||||||
|
it "aliases $! to $ERROR_INFO and $ERROR_INFO still returns an Exception with a backtrace" do
|
||||||
|
exception = (1 / 0 rescue $ERROR_INFO)
|
||||||
|
exception.should be_kind_of(Exception)
|
||||||
|
exception.backtrace.should be_kind_of(Array)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "aliases $@ to $ERROR_POSITION and $ERROR_POSITION still returns a backtrace" do
|
||||||
|
(1 / 0 rescue $ERROR_POSITION).should be_kind_of(Array)
|
||||||
|
end
|
||||||
|
end
|
|
@ -12,5 +12,6 @@ module MD5Constants
|
||||||
Digest = "\2473\267qw\276\364\343\345\320\304\350\313\314\217n"
|
Digest = "\2473\267qw\276\364\343\345\320\304\350\313\314\217n"
|
||||||
BlankHexdigest = "d41d8cd98f00b204e9800998ecf8427e"
|
BlankHexdigest = "d41d8cd98f00b204e9800998ecf8427e"
|
||||||
Hexdigest = "a733b77177bef4e3e5d0c4e8cbcc8f6e"
|
Hexdigest = "a733b77177bef4e3e5d0c4e8cbcc8f6e"
|
||||||
|
Base64digest = "pzO3cXe+9OPl0MToy8yPbg=="
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,6 +12,7 @@ module SHA1Constants
|
||||||
BlankDigest = "\3329\243\356^kK\r2U\277\357\225`\030\220\257\330\a\t"
|
BlankDigest = "\3329\243\356^kK\r2U\277\357\225`\030\220\257\330\a\t"
|
||||||
Digest = "X!\255b\323\035\352\314a|q\344+\376\317\361V9\324\343"
|
Digest = "X!\255b\323\035\352\314a|q\344+\376\317\361V9\324\343"
|
||||||
BlankHexdigest = "da39a3ee5e6b4b0d3255bfef95601890afd80709"
|
BlankHexdigest = "da39a3ee5e6b4b0d3255bfef95601890afd80709"
|
||||||
Hexdigest = "e907d2ba21c6c74bc0efd76e44d11fb9bbb7a75e"
|
Hexdigest = "5821ad62d31deacc617c71e42bfecff15639d4e3"
|
||||||
|
Base64digest = "WCGtYtMd6sxhfHHkK/7P8VY51OM="
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,5 +13,6 @@ module SHA256Constants
|
||||||
Digest = "\230b\265\344_\337\357\337\242\004\314\311A\211jb\350\373\254\370\365M\230B\002\372\020j\as\270\376"
|
Digest = "\230b\265\344_\337\357\337\242\004\314\311A\211jb\350\373\254\370\365M\230B\002\372\020j\as\270\376"
|
||||||
BlankHexdigest = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
BlankHexdigest = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||||
Hexdigest = "9862b5e45fdfefdfa204ccc941896a62e8fbacf8f54d984202fa106a0773b8fe"
|
Hexdigest = "9862b5e45fdfefdfa204ccc941896a62e8fbacf8f54d984202fa106a0773b8fe"
|
||||||
|
Base64digest = "mGK15F/f79+iBMzJQYlqYuj7rPj1TZhCAvoQagdzuP4="
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,5 +14,6 @@ module SHA384Constants
|
||||||
Digest = "B&\266:\314\216z\361!TD\001{`\355\323\320MW%\270\272\0034n\034\026g\a\217\"\333s\202\275\002Y*\217]\207u\f\034\244\231\266f"
|
Digest = "B&\266:\314\216z\361!TD\001{`\355\323\320MW%\270\272\0034n\034\026g\a\217\"\333s\202\275\002Y*\217]\207u\f\034\244\231\266f"
|
||||||
BlankHexdigest = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"
|
BlankHexdigest = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"
|
||||||
Hexdigest = "4226b63acc8e7af1215444017b60edd3d04d5725b8ba03346e1c1667078f22db7382bd02592a8f5d87750c1ca499b666"
|
Hexdigest = "4226b63acc8e7af1215444017b60edd3d04d5725b8ba03346e1c1667078f22db7382bd02592a8f5d87750c1ca499b666"
|
||||||
|
Base64digest = "Qia2OsyOevEhVEQBe2Dt09BNVyW4ugM0bhwWZwePIttzgr0CWSqPXYd1DBykmbZm"
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,5 +13,6 @@ module SHA512Constants
|
||||||
Digest = "\241\231\232\365\002z\241\331\242\310=\367F\272\004\326\331g\315n\251Q\222\250\374E\257\254=\325\225\003SM\350\244\234\220\233=\031\230A;\000\203\233\340\323t\333\271\222w\266\307\2678\344\255j\003\216\300"
|
Digest = "\241\231\232\365\002z\241\331\242\310=\367F\272\004\326\331g\315n\251Q\222\250\374E\257\254=\325\225\003SM\350\244\234\220\233=\031\230A;\000\203\233\340\323t\333\271\222w\266\307\2678\344\255j\003\216\300"
|
||||||
BlankHexdigest = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
|
BlankHexdigest = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
|
||||||
Hexdigest = "a1999af5027aa1d9a2c83df746ba04d6d967cd6ea95192a8fc45afac3dd59503534de8a49c909b3d1998413b00839be0d374dbb99277b6c7b738e4ad6a038ec0"
|
Hexdigest = "a1999af5027aa1d9a2c83df746ba04d6d967cd6ea95192a8fc45afac3dd59503534de8a49c909b3d1998413b00839be0d374dbb99277b6c7b738e4ad6a038ec0"
|
||||||
|
Base64digest = "oZma9QJ6odmiyD33RroE1tlnzW6pUZKo/EWvrD3VlQNTTeiknJCbPRmYQTsAg5vg03TbuZJ3tse3OOStagOOwA=="
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
63
spec/ruby/library/openssl/digest_spec.rb
Normal file
63
spec/ruby/library/openssl/digest_spec.rb
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
require_relative '../../spec_helper'
|
||||||
|
require_relative '../../library/digest/sha1/shared/constants'
|
||||||
|
require_relative '../../library/digest/sha256/shared/constants'
|
||||||
|
require_relative '../../library/digest/sha384/shared/constants'
|
||||||
|
require_relative '../../library/digest/sha512/shared/constants'
|
||||||
|
require 'openssl'
|
||||||
|
|
||||||
|
describe "OpenSSL::Digest" do
|
||||||
|
|
||||||
|
describe ".digest" do
|
||||||
|
it "returns a SHA1 digest" do
|
||||||
|
OpenSSL::Digest.digest('sha1', SHA1Constants::Contents).should == SHA1Constants::Digest
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a SHA256 digest" do
|
||||||
|
OpenSSL::Digest.digest('sha256', SHA256Constants::Contents).should == SHA256Constants::Digest
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a SHA384 digest" do
|
||||||
|
OpenSSL::Digest.digest('sha384', SHA384Constants::Contents).should == SHA384Constants::Digest
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a SHA512 digest" do
|
||||||
|
OpenSSL::Digest.digest('sha512', SHA512Constants::Contents).should == SHA512Constants::Digest
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe ".hexdigest" do
|
||||||
|
it "returns a SHA1 hexdigest" do
|
||||||
|
OpenSSL::Digest.hexdigest('sha1', SHA1Constants::Contents).should == SHA1Constants::Hexdigest
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a SHA256 hexdigest" do
|
||||||
|
OpenSSL::Digest.hexdigest('sha256', SHA256Constants::Contents).should == SHA256Constants::Hexdigest
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a SHA384 hexdigest" do
|
||||||
|
OpenSSL::Digest.hexdigest('sha384', SHA384Constants::Contents).should == SHA384Constants::Hexdigest
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a SHA512 hexdigest" do
|
||||||
|
OpenSSL::Digest.hexdigest('sha512', SHA512Constants::Contents).should == SHA512Constants::Hexdigest
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe ".base64digest" do
|
||||||
|
it "returns a SHA1 base64digest" do
|
||||||
|
OpenSSL::Digest.base64digest('sha1', SHA1Constants::Contents).should == SHA1Constants::Base64digest
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a SHA256 base64digest" do
|
||||||
|
OpenSSL::Digest.base64digest('sha256', SHA256Constants::Contents).should == SHA256Constants::Base64digest
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a SHA384 base64digest" do
|
||||||
|
OpenSSL::Digest.base64digest('sha384', SHA384Constants::Contents).should == SHA384Constants::Base64digest
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a SHA512 base64digest" do
|
||||||
|
OpenSSL::Digest.base64digest('sha512', SHA512Constants::Contents).should == SHA512Constants::Base64digest
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -40,4 +40,3 @@ ruby_version_is ''...'2.8' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -305,6 +305,13 @@ static VALUE kernel_spec_rb_funcall_with_block(VALUE self, VALUE obj, VALUE meth
|
||||||
return rb_funcall_with_block(obj, SYM2ID(method), 0, NULL, block);
|
return rb_funcall_with_block(obj, SYM2ID(method), 0, NULL, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE kernel_spec_rb_funcall_many_args(VALUE self, VALUE obj, VALUE method) {
|
||||||
|
return rb_funcall(obj, SYM2ID(method), 15,
|
||||||
|
INT2FIX(15), INT2FIX(14), INT2FIX(13), INT2FIX(12), INT2FIX(11),
|
||||||
|
INT2FIX(10), INT2FIX(9), INT2FIX(8), INT2FIX(7), INT2FIX(6),
|
||||||
|
INT2FIX(5), INT2FIX(4), INT2FIX(3), INT2FIX(2), INT2FIX(1));
|
||||||
|
}
|
||||||
|
|
||||||
void Init_kernel_spec(void) {
|
void Init_kernel_spec(void) {
|
||||||
VALUE cls = rb_define_class("CApiKernelSpecs", rb_cObject);
|
VALUE cls = rb_define_class("CApiKernelSpecs", rb_cObject);
|
||||||
rb_define_method(cls, "rb_block_given_p", kernel_spec_rb_block_given_p, 0);
|
rb_define_method(cls, "rb_block_given_p", kernel_spec_rb_block_given_p, 0);
|
||||||
|
@ -342,6 +349,7 @@ void Init_kernel_spec(void) {
|
||||||
rb_define_method(cls, "rb_make_backtrace", kernel_spec_rb_make_backtrace, 0);
|
rb_define_method(cls, "rb_make_backtrace", kernel_spec_rb_make_backtrace, 0);
|
||||||
rb_define_method(cls, "rb_obj_method", kernel_spec_rb_obj_method, 2);
|
rb_define_method(cls, "rb_obj_method", kernel_spec_rb_obj_method, 2);
|
||||||
rb_define_method(cls, "rb_funcall3", kernel_spec_rb_funcall3, 2);
|
rb_define_method(cls, "rb_funcall3", kernel_spec_rb_funcall3, 2);
|
||||||
|
rb_define_method(cls, "rb_funcall_many_args", kernel_spec_rb_funcall_many_args, 2);
|
||||||
rb_define_method(cls, "rb_funcall_with_block", kernel_spec_rb_funcall_with_block, 3);
|
rb_define_method(cls, "rb_funcall_with_block", kernel_spec_rb_funcall_with_block, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -345,6 +345,40 @@ static VALUE object_spec_rb_class_inherited_p(VALUE self, VALUE mod, VALUE arg)
|
||||||
return rb_class_inherited_p(mod, arg);
|
return rb_class_inherited_p(mod, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE speced_allocator(VALUE klass) {
|
||||||
|
VALUE flags = 0;
|
||||||
|
VALUE instance;
|
||||||
|
if (rb_class_inherited_p(klass, rb_cString)) {
|
||||||
|
flags = T_STRING;
|
||||||
|
} else if (rb_class_inherited_p(klass, rb_cArray)) {
|
||||||
|
flags = T_ARRAY;
|
||||||
|
} else {
|
||||||
|
flags = T_OBJECT;
|
||||||
|
}
|
||||||
|
instance = rb_newobj_of(klass, flags);
|
||||||
|
rb_iv_set(instance, "@from_custom_allocator", Qtrue);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE define_alloc_func(VALUE self, VALUE klass) {
|
||||||
|
rb_define_alloc_func(klass, speced_allocator);
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE undef_alloc_func(VALUE self, VALUE klass) {
|
||||||
|
rb_undef_alloc_func(klass);
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE speced_allocator_p(VALUE self, VALUE klass) {
|
||||||
|
rb_alloc_func_t allocator = rb_get_alloc_func(klass);
|
||||||
|
return (allocator == speced_allocator) ? Qtrue : Qfalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE custom_alloc_func_p(VALUE self, VALUE klass) {
|
||||||
|
rb_alloc_func_t allocator = rb_get_alloc_func(klass);
|
||||||
|
return allocator ? Qtrue : Qfalse;
|
||||||
|
}
|
||||||
|
|
||||||
void Init_object_spec(void) {
|
void Init_object_spec(void) {
|
||||||
VALUE cls = rb_define_class("CApiObjectSpecs", rb_cObject);
|
VALUE cls = rb_define_class("CApiObjectSpecs", rb_cObject);
|
||||||
|
@ -412,6 +446,10 @@ void Init_object_spec(void) {
|
||||||
rb_define_method(cls, "rb_ivar_defined", object_spec_rb_ivar_defined, 2);
|
rb_define_method(cls, "rb_ivar_defined", object_spec_rb_ivar_defined, 2);
|
||||||
rb_define_method(cls, "rb_copy_generic_ivar", object_spec_rb_copy_generic_ivar, 2);
|
rb_define_method(cls, "rb_copy_generic_ivar", object_spec_rb_copy_generic_ivar, 2);
|
||||||
rb_define_method(cls, "rb_free_generic_ivar", object_spec_rb_free_generic_ivar, 1);
|
rb_define_method(cls, "rb_free_generic_ivar", object_spec_rb_free_generic_ivar, 1);
|
||||||
|
rb_define_method(cls, "rb_define_alloc_func", define_alloc_func, 1);
|
||||||
|
rb_define_method(cls, "rb_undef_alloc_func", undef_alloc_func, 1);
|
||||||
|
rb_define_method(cls, "speced_allocator?", speced_allocator_p, 1);
|
||||||
|
rb_define_method(cls, "custom_alloc_func?", custom_alloc_func_p, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -260,7 +260,7 @@ describe "C-API Hash function" do
|
||||||
hash_code = @s.compute_a_hash_code(53)
|
hash_code = @s.compute_a_hash_code(53)
|
||||||
hash_code.should be_an_instance_of(Integer)
|
hash_code.should be_an_instance_of(Integer)
|
||||||
hash_code.should == @s.compute_a_hash_code(53)
|
hash_code.should == @s.compute_a_hash_code(53)
|
||||||
@s.compute_a_hash_code(90) == @s.compute_a_hash_code(90)
|
@s.compute_a_hash_code(90).should == @s.compute_a_hash_code(90)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -578,6 +578,20 @@ describe "C-API Kernel function" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'rb_funcall' do
|
||||||
|
before :each do
|
||||||
|
@obj = Object.new
|
||||||
|
class << @obj
|
||||||
|
def many_args(*args)
|
||||||
|
args
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can call a public method with 10 arguments" do
|
||||||
|
@s.rb_funcall_many_args(@obj, :many_args).should == 15.downto(1).to_a
|
||||||
|
end
|
||||||
|
end
|
||||||
describe 'rb_funcall_with_block' do
|
describe 'rb_funcall_with_block' do
|
||||||
before :each do
|
before :each do
|
||||||
@obj = Object.new
|
@obj = Object.new
|
||||||
|
|
|
@ -110,6 +110,11 @@ describe "CApiObject" do
|
||||||
@o.rb_respond_to(ObjectTest.new, :foo).should == true
|
@o.rb_respond_to(ObjectTest.new, :foo).should == true
|
||||||
@o.rb_respond_to(ObjectTest.new, :bar).should == false
|
@o.rb_respond_to(ObjectTest.new, :bar).should == false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "can be used with primitives" do
|
||||||
|
@o.rb_respond_to(true, :object_id).should == true
|
||||||
|
@o.rb_respond_to(14, :succ).should == true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "rb_obj_respond_to" do
|
describe "rb_obj_respond_to" do
|
||||||
|
@ -887,4 +892,78 @@ describe "CApiObject" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "allocator accessors" do
|
||||||
|
describe "rb_define_alloc_func" do
|
||||||
|
it "sets up the allocator" do
|
||||||
|
klass = Class.new
|
||||||
|
@o.rb_define_alloc_func(klass)
|
||||||
|
obj = klass.allocate
|
||||||
|
obj.class.should.equal?(klass)
|
||||||
|
obj.should have_instance_variable(:@from_custom_allocator)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets up the allocator for a subclass of String" do
|
||||||
|
klass = Class.new(String)
|
||||||
|
@o.rb_define_alloc_func(klass)
|
||||||
|
obj = klass.allocate
|
||||||
|
obj.class.should.equal?(klass)
|
||||||
|
obj.should have_instance_variable(:@from_custom_allocator)
|
||||||
|
obj.should == ""
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets up the allocator for a subclass of Array" do
|
||||||
|
klass = Class.new(Array)
|
||||||
|
@o.rb_define_alloc_func(klass)
|
||||||
|
obj = klass.allocate
|
||||||
|
obj.class.should.equal?(klass)
|
||||||
|
obj.should have_instance_variable(:@from_custom_allocator)
|
||||||
|
obj.should == []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "rb_get_alloc_func" do
|
||||||
|
it "gets the allocator that is defined directly on a class" do
|
||||||
|
klass = Class.new
|
||||||
|
@o.rb_define_alloc_func(klass)
|
||||||
|
@o.speced_allocator?(Object).should == false
|
||||||
|
@o.speced_allocator?(klass).should == true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "gets the allocator that is inherited" do
|
||||||
|
parent = Class.new
|
||||||
|
@o.rb_define_alloc_func(parent)
|
||||||
|
klass = Class.new(parent)
|
||||||
|
@o.speced_allocator?(Object).should == false
|
||||||
|
@o.speced_allocator?(klass).should == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "rb_undef_alloc_func" do
|
||||||
|
it "makes rb_get_alloc_func() return NULL for a class without a custom allocator" do
|
||||||
|
klass = Class.new
|
||||||
|
@o.rb_undef_alloc_func(klass)
|
||||||
|
@o.custom_alloc_func?(klass).should == false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "undefs the allocator for the class" do
|
||||||
|
klass = Class.new
|
||||||
|
@o.rb_define_alloc_func(klass)
|
||||||
|
@o.speced_allocator?(klass).should == true
|
||||||
|
@o.rb_undef_alloc_func(klass)
|
||||||
|
@o.custom_alloc_func?(klass).should == false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "undefs the allocator for a class that inherits a allocator" do
|
||||||
|
parent = Class.new
|
||||||
|
@o.rb_define_alloc_func(parent)
|
||||||
|
klass = Class.new(parent)
|
||||||
|
@o.speced_allocator?(klass).should == true
|
||||||
|
@o.rb_undef_alloc_func(klass)
|
||||||
|
@o.custom_alloc_func?(klass).should == false
|
||||||
|
|
||||||
|
@o.speced_allocator?(parent).should == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue