summaryrefslogtreecommitdiff
path: root/spec/ruby/core/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/core/kernel')
-rw-r--r--spec/ruby/core/kernel/Array_spec.rb8
-rw-r--r--spec/ruby/core/kernel/Complex_spec.rb276
-rw-r--r--spec/ruby/core/kernel/Float_spec.rb255
-rw-r--r--spec/ruby/core/kernel/Hash_spec.rb16
-rw-r--r--spec/ruby/core/kernel/Integer_spec.rb358
-rw-r--r--spec/ruby/core/kernel/Rational_spec.rb236
-rw-r--r--spec/ruby/core/kernel/String_spec.rb14
-rw-r--r--spec/ruby/core/kernel/__callee___spec.rb4
-rw-r--r--spec/ruby/core/kernel/__dir___spec.rb20
-rw-r--r--spec/ruby/core/kernel/__method___spec.rb4
-rw-r--r--spec/ruby/core/kernel/abort_spec.rb6
-rw-r--r--spec/ruby/core/kernel/at_exit_spec.rb39
-rw-r--r--spec/ruby/core/kernel/autoload_spec.rb73
-rw-r--r--spec/ruby/core/kernel/backtick_spec.rb36
-rw-r--r--spec/ruby/core/kernel/binding_spec.rb6
-rw-r--r--spec/ruby/core/kernel/block_given_spec.rb9
-rw-r--r--spec/ruby/core/kernel/caller_locations_spec.rb86
-rw-r--r--spec/ruby/core/kernel/caller_spec.rb78
-rw-r--r--spec/ruby/core/kernel/case_compare_spec.rb4
-rw-r--r--spec/ruby/core/kernel/catch_spec.rb10
-rw-r--r--spec/ruby/core/kernel/chomp_spec.rb40
-rw-r--r--spec/ruby/core/kernel/chop_spec.rb40
-rw-r--r--spec/ruby/core/kernel/class_spec.rb8
-rw-r--r--spec/ruby/core/kernel/clone_spec.rb101
-rw-r--r--spec/ruby/core/kernel/comparison_spec.rb2
-rw-r--r--spec/ruby/core/kernel/define_singleton_method_spec.rb55
-rw-r--r--spec/ruby/core/kernel/display_spec.rb4
-rw-r--r--spec/ruby/core/kernel/dup_spec.rb14
-rw-r--r--spec/ruby/core/kernel/enum_for_spec.rb2
-rw-r--r--spec/ruby/core/kernel/eql_spec.rb5
-rw-r--r--spec/ruby/core/kernel/equal_value_spec.rb4
-rw-r--r--spec/ruby/core/kernel/eval_spec.rb390
-rw-r--r--spec/ruby/core/kernel/exec_spec.rb8
-rw-r--r--spec/ruby/core/kernel/exit_spec.rb16
-rw-r--r--spec/ruby/core/kernel/extend_spec.rb30
-rw-r--r--spec/ruby/core/kernel/fail_spec.rb25
-rw-r--r--spec/ruby/core/kernel/fixtures/Complex.rb5
-rw-r--r--spec/ruby/core/kernel/fixtures/__dir__.rb2
-rw-r--r--spec/ruby/core/kernel/fixtures/autoload_c.rb5
-rw-r--r--spec/ruby/core/kernel/fixtures/autoload_from_included_module.rb9
-rw-r--r--spec/ruby/core/kernel/fixtures/autoload_from_included_module2.rb9
-rw-r--r--spec/ruby/core/kernel/fixtures/caller_at_exit.rb7
-rw-r--r--spec/ruby/core/kernel/fixtures/classes.rb181
-rw-r--r--spec/ruby/core/kernel/fixtures/eval_return_with_lambda.rb2
-rw-r--r--spec/ruby/core/kernel/fixtures/singleton_methods.rb13
-rw-r--r--spec/ruby/core/kernel/fixtures/warn_core_method.rb14
-rw-r--r--spec/ruby/core/kernel/fixtures/warn_require.rb1
-rw-r--r--spec/ruby/core/kernel/fixtures/warn_require_caller.rb2
-rw-r--r--spec/ruby/core/kernel/fork_spec.rb6
-rw-r--r--spec/ruby/core/kernel/format_spec.rb37
-rw-r--r--spec/ruby/core/kernel/freeze_spec.rb40
-rw-r--r--spec/ruby/core/kernel/frozen_spec.rb44
-rw-r--r--spec/ruby/core/kernel/gets_spec.rb4
-rw-r--r--spec/ruby/core/kernel/global_variables_spec.rb4
-rw-r--r--spec/ruby/core/kernel/gsub_spec.rb6
-rw-r--r--spec/ruby/core/kernel/initialize_clone_spec.rb26
-rw-r--r--spec/ruby/core/kernel/initialize_copy_spec.rb36
-rw-r--r--spec/ruby/core/kernel/initialize_dup_spec.rb20
-rw-r--r--spec/ruby/core/kernel/inspect_spec.rb79
-rw-r--r--spec/ruby/core/kernel/instance_of_spec.rb12
-rw-r--r--spec/ruby/core/kernel/instance_variable_defined_spec.rb6
-rw-r--r--spec/ruby/core/kernel/instance_variable_get_spec.rb36
-rw-r--r--spec/ruby/core/kernel/instance_variable_set_spec.rb56
-rw-r--r--spec/ruby/core/kernel/instance_variables_spec.rb21
-rw-r--r--spec/ruby/core/kernel/is_a_spec.rb6
-rw-r--r--spec/ruby/core/kernel/iterator_spec.rb12
-rw-r--r--spec/ruby/core/kernel/itself_spec.rb4
-rw-r--r--spec/ruby/core/kernel/kind_of_spec.rb6
-rw-r--r--spec/ruby/core/kernel/lambda_spec.rb92
-rw-r--r--spec/ruby/core/kernel/load_spec.rb8
-rw-r--r--spec/ruby/core/kernel/local_variables_spec.rb15
-rw-r--r--spec/ruby/core/kernel/loop_spec.rb22
-rw-r--r--spec/ruby/core/kernel/match_spec.rb13
-rw-r--r--spec/ruby/core/kernel/method_spec.rb53
-rw-r--r--spec/ruby/core/kernel/methods_spec.rb6
-rw-r--r--spec/ruby/core/kernel/nil_spec.rb14
-rw-r--r--spec/ruby/core/kernel/not_match_spec.rb8
-rw-r--r--spec/ruby/core/kernel/object_id_spec.rb4
-rw-r--r--spec/ruby/core/kernel/open_spec.rb128
-rw-r--r--spec/ruby/core/kernel/p_spec.rb44
-rw-r--r--spec/ruby/core/kernel/pp_spec.rb9
-rw-r--r--spec/ruby/core/kernel/print_spec.rb16
-rw-r--r--spec/ruby/core/kernel/printf_spec.rb35
-rw-r--r--spec/ruby/core/kernel/private_methods_spec.rb6
-rw-r--r--spec/ruby/core/kernel/proc_spec.rb26
-rw-r--r--spec/ruby/core/kernel/protected_methods_spec.rb6
-rw-r--r--spec/ruby/core/kernel/public_method_spec.rb14
-rw-r--r--spec/ruby/core/kernel/public_methods_spec.rb6
-rw-r--r--spec/ruby/core/kernel/public_send_spec.rb28
-rw-r--r--spec/ruby/core/kernel/putc_spec.rb6
-rw-r--r--spec/ruby/core/kernel/puts_spec.rb4
-rw-r--r--spec/ruby/core/kernel/raise_spec.rb281
-rw-r--r--spec/ruby/core/kernel/rand_spec.rb66
-rw-r--r--spec/ruby/core/kernel/readline_spec.rb4
-rw-r--r--spec/ruby/core/kernel/readlines_spec.rb4
-rw-r--r--spec/ruby/core/kernel/remove_instance_variable_spec.rb23
-rw-r--r--spec/ruby/core/kernel/require_relative_spec.rb142
-rw-r--r--spec/ruby/core/kernel/require_spec.rb34
-rw-r--r--spec/ruby/core/kernel/respond_to_missing_spec.rb4
-rw-r--r--spec/ruby/core/kernel/respond_to_spec.rb9
-rw-r--r--spec/ruby/core/kernel/select_spec.rb10
-rw-r--r--spec/ruby/core/kernel/send_spec.rb8
-rw-r--r--spec/ruby/core/kernel/set_trace_func_spec.rb4
-rw-r--r--spec/ruby/core/kernel/shared/dup_clone.rb94
-rw-r--r--spec/ruby/core/kernel/shared/kind_of.rb23
-rw-r--r--spec/ruby/core/kernel/shared/lambda.rb4
-rw-r--r--spec/ruby/core/kernel/shared/load.rb120
-rw-r--r--spec/ruby/core/kernel/shared/method.rb14
-rw-r--r--spec/ruby/core/kernel/shared/require.rb289
-rw-r--r--spec/ruby/core/kernel/shared/sprintf.rb1004
-rw-r--r--spec/ruby/core/kernel/shared/sprintf_encoding.rb59
-rw-r--r--spec/ruby/core/kernel/shared/then.rb20
-rw-r--r--spec/ruby/core/kernel/singleton_class_spec.rb53
-rw-r--r--spec/ruby/core/kernel/singleton_method_spec.rb48
-rw-r--r--spec/ruby/core/kernel/singleton_methods_spec.rb32
-rw-r--r--spec/ruby/core/kernel/sleep_spec.rb98
-rw-r--r--spec/ruby/core/kernel/spawn_spec.rb8
-rw-r--r--spec/ruby/core/kernel/sprintf_spec.rb64
-rw-r--r--spec/ruby/core/kernel/srand_spec.rb28
-rw-r--r--spec/ruby/core/kernel/sub_spec.rb4
-rw-r--r--spec/ruby/core/kernel/syscall_spec.rb4
-rw-r--r--spec/ruby/core/kernel/system_spec.rb51
-rw-r--r--spec/ruby/core/kernel/taint_spec.rb45
-rw-r--r--spec/ruby/core/kernel/tainted_spec.rb12
-rw-r--r--spec/ruby/core/kernel/tap_spec.rb6
-rw-r--r--spec/ruby/core/kernel/test_spec.rb8
-rw-r--r--spec/ruby/core/kernel/then_spec.rb6
-rw-r--r--spec/ruby/core/kernel/throw_spec.rb16
-rw-r--r--spec/ruby/core/kernel/to_enum_spec.rb2
-rw-r--r--spec/ruby/core/kernel/to_s_spec.rb12
-rw-r--r--spec/ruby/core/kernel/trace_var_spec.rb6
-rw-r--r--spec/ruby/core/kernel/trap_spec.rb7
-rw-r--r--spec/ruby/core/kernel/trust_spec.rb25
-rw-r--r--spec/ruby/core/kernel/untaint_spec.rb25
-rw-r--r--spec/ruby/core/kernel/untrace_var_spec.rb4
-rw-r--r--spec/ruby/core/kernel/untrust_spec.rb25
-rw-r--r--spec/ruby/core/kernel/untrusted_spec.rb28
-rw-r--r--spec/ruby/core/kernel/warn_spec.rb243
-rw-r--r--spec/ruby/core/kernel/yield_self_spec.rb28
139 files changed, 4897 insertions, 1763 deletions
diff --git a/spec/ruby/core/kernel/Array_spec.rb b/spec/ruby/core/kernel/Array_spec.rb
index 6031a828f6..b4a8bb7599 100644
--- a/spec/ruby/core/kernel/Array_spec.rb
+++ b/spec/ruby/core/kernel/Array_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel" do
it "has private instance method Array()" do
@@ -77,14 +77,14 @@ describe :kernel_Array, shared: true do
obj = mock("Array() string")
obj.should_receive(:to_ary).and_return("string")
- lambda { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should raise_error(TypeError)
end
it "raises a TypeError if #to_a does not return an Array" do
obj = mock("Array() string")
obj.should_receive(:to_a).and_return("string")
- lambda { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/core/kernel/Complex_spec.rb b/spec/ruby/core/kernel/Complex_spec.rb
index b156cc4549..346d50ab5e 100644
--- a/spec/ruby/core/kernel/Complex_spec.rb
+++ b/spec/ruby/core/kernel/Complex_spec.rb
@@ -1,6 +1,276 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../../../shared/complex/Complex', __FILE__)
+require_relative '../../spec_helper'
+require_relative '../../shared/kernel/complex'
+require_relative 'fixtures/Complex'
describe "Kernel.Complex()" do
- it_behaves_like :kernel_Complex, :Complex
+ describe "when passed [Complex, Complex]" do
+ it "returns a new Complex number based on the two given numbers" do
+ Complex(Complex(3, 4), Complex(5, 6)).should == Complex(3 - 6, 4 + 5)
+ Complex(Complex(1.5, 2), Complex(-5, 6.3)).should == Complex(1.5 - 6.3, 2 - 5)
+ end
+ end
+
+ describe "when passed [Complex]" do
+ it "returns the passed Complex number" do
+ Complex(Complex(1, 2)).should == Complex(1, 2)
+ Complex(Complex(-3.4, bignum_value)).should == Complex(-3.4, bignum_value)
+ end
+ end
+
+ describe "when passed [Integer, Integer]" do
+ it "returns a new Complex number" do
+ Complex(1, 2).should be_an_instance_of(Complex)
+ Complex(1, 2).real.should == 1
+ Complex(1, 2).imag.should == 2
+
+ Complex(-3, -5).should be_an_instance_of(Complex)
+ Complex(-3, -5).real.should == -3
+ Complex(-3, -5).imag.should == -5
+
+ Complex(3.5, -4.5).should be_an_instance_of(Complex)
+ Complex(3.5, -4.5).real.should == 3.5
+ Complex(3.5, -4.5).imag.should == -4.5
+
+ Complex(bignum_value, 30).should be_an_instance_of(Complex)
+ Complex(bignum_value, 30).real.should == bignum_value
+ Complex(bignum_value, 30).imag.should == 30
+ end
+ end
+
+ describe "when passed [Integer/Float]" do
+ it "returns a new Complex number with 0 as the imaginary component" do
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ Complex(1).should be_an_instance_of(Complex)
+ Complex(1).imag.should == 0
+ Complex(1).real.should == 1
+
+ Complex(-3).should be_an_instance_of(Complex)
+ Complex(-3).imag.should == 0
+ Complex(-3).real.should == -3
+
+ Complex(-4.5).should be_an_instance_of(Complex)
+ Complex(-4.5).imag.should == 0
+ Complex(-4.5).real.should == -4.5
+
+ Complex(bignum_value).should be_an_instance_of(Complex)
+ Complex(bignum_value).imag.should == 0
+ Complex(bignum_value).real.should == bignum_value
+ end
+ end
+ end
+
+ describe "when passed [String]" do
+ it_behaves_like :kernel_complex, :Complex_method, KernelSpecs
+
+ context "invalid argument" do
+ it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
+ -> {
+ Complex("79+4i".encode("UTF-16"))
+ }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ end
+
+ it "raises ArgumentError for unrecognised Strings" do
+ -> {
+ Complex("ruby")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "ruby"')
+ end
+
+ it "raises ArgumentError for trailing garbage" do
+ -> {
+ Complex("79+4iruby")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "79+4iruby"')
+ end
+
+ it "does not understand Float::INFINITY" do
+ -> {
+ Complex("Infinity")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "Infinity"')
+
+ -> {
+ Complex("-Infinity")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "-Infinity"')
+ end
+
+ it "does not understand Float::NAN" do
+ -> {
+ Complex("NaN")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "NaN"')
+ end
+
+ it "does not understand a sequence of _" do
+ -> {
+ Complex("7__9+4__0i")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "7__9+4__0i"')
+ end
+
+ it "does not allow null-byte" do
+ -> {
+ Complex("1-2i\0")
+ }.should raise_error(ArgumentError, "string contains null byte")
+ end
+ end
+
+ context "invalid argument and exception: false passed" do
+ it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
+ -> {
+ Complex("79+4i".encode("UTF-16"), exception: false)
+ }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ end
+
+ it "returns nil for unrecognised Strings" do
+ Complex("ruby", exception: false).should == nil
+ end
+
+ it "returns nil when trailing garbage" do
+ Complex("79+4iruby", exception: false).should == nil
+ end
+
+ it "returns nil for Float::INFINITY" do
+ Complex("Infinity", exception: false).should == nil
+ Complex("-Infinity", exception: false).should == nil
+ end
+
+ it "returns nil for Float::NAN" do
+ Complex("NaN", exception: false).should == nil
+ end
+
+ it "returns nil when there is a sequence of _" do
+ Complex("7__9+4__0i", exception: false).should == nil
+ end
+
+ it "returns nil when String contains null-byte" do
+ Complex("1-2i\0", exception: false).should == nil
+ end
+ end
+ end
+
+ describe "when passes [String, String]" do
+ it "needs to be reviewed for spec completeness"
+ end
+
+ describe "when passed an Object which responds to #to_c" do
+ it "returns the passed argument" do
+ obj = Object.new; def obj.to_c; 1i end
+ Complex(obj).should == Complex(0, 1)
+ end
+ end
+
+ describe "when passed a Numeric which responds to #real? with false" do
+ it "returns the passed argument" do
+ n = mock_numeric("unreal")
+ n.should_receive(:real?).any_number_of_times.and_return(false)
+ Complex(n).should equal(n)
+ end
+ end
+
+ describe "when passed a Numeric which responds to #real? with true" do
+ it "returns a Complex with the passed argument as the real component and 0 as the imaginary component" do
+ n = mock_numeric("real")
+ n.should_receive(:real?).any_number_of_times.and_return(true)
+ result = Complex(n)
+ result.real.should equal(n)
+ result.imag.should equal(0)
+ end
+ end
+
+ describe "when passed Numerics n1 and n2 and at least one responds to #real? with false" do
+ [[false, false], [false, true], [true, false]].each do |r1, r2|
+ it "returns n1 + n2 * Complex(0, 1)" do
+ n1 = mock_numeric("n1")
+ n2 = mock_numeric("n2")
+ n3 = mock_numeric("n3")
+ n4 = mock_numeric("n4")
+ n1.should_receive(:real?).any_number_of_times.and_return(r1)
+ n2.should_receive(:real?).any_number_of_times.and_return(r2)
+ n2.should_receive(:*).with(Complex(0, 1)).and_return(n3)
+ n1.should_receive(:+).with(n3).and_return(n4)
+ Complex(n1, n2).should equal(n4)
+ end
+ end
+ end
+
+ describe "when passed two Numerics and both respond to #real? with true" do
+ it "returns a Complex with the passed arguments as real and imaginary components respectively" do
+ n1 = mock_numeric("n1")
+ n2 = mock_numeric("n2")
+ n1.should_receive(:real?).any_number_of_times.and_return(true)
+ n2.should_receive(:real?).any_number_of_times.and_return(true)
+ result = Complex(n1, n2)
+ result.real.should equal(n1)
+ result.imag.should equal(n2)
+ end
+ end
+
+ describe "when passed a single non-Numeric" do
+ it "coerces the passed argument using #to_c" do
+ n = mock("n")
+ c = Complex(0, 0)
+ n.should_receive(:to_c).and_return(c)
+ Complex(n).should equal(c)
+ end
+ end
+
+ describe "when passed a non-Numeric second argument" do
+ it "raises TypeError" do
+ -> { Complex(:sym, :sym) }.should raise_error(TypeError)
+ -> { Complex(0, :sym) }.should raise_error(TypeError)
+ end
+ end
+
+ describe "when passed nil" do
+ it "raises TypeError" do
+ -> { Complex(nil) }.should raise_error(TypeError, "can't convert nil into Complex")
+ -> { Complex(0, nil) }.should raise_error(TypeError, "can't convert nil into Complex")
+ -> { Complex(nil, 0) }.should raise_error(TypeError, "can't convert nil into Complex")
+ end
+ end
+
+ describe "when passed exception: false" do
+ describe "and [Numeric]" do
+ it "returns a complex number" do
+ Complex("123", exception: false).should == Complex(123)
+ end
+ end
+
+ describe "and [non-Numeric]" do
+ it "swallows an error" do
+ Complex(:sym, exception: false).should == nil
+ end
+ end
+
+ describe "and [non-Numeric, Numeric] argument" do
+ it "throws a TypeError" do
+ -> { Complex(:sym, 0, exception: false) }.should raise_error(TypeError, "not a real")
+ end
+ end
+
+ describe "and [anything, non-Numeric] argument" do
+ it "swallows an error" do
+ Complex("a", :sym, exception: false).should == nil
+ Complex(:sym, :sym, exception: false).should == nil
+ Complex(0, :sym, exception: false).should == nil
+ end
+ end
+
+ describe "and non-numeric String arguments" do
+ it "swallows an error" do
+ Complex("a", "b", exception: false).should == nil
+ Complex("a", 0, exception: false).should == nil
+ Complex(0, "b", exception: false).should == nil
+ end
+ end
+
+ describe "and nil arguments" do
+ it "swallows an error" do
+ Complex(nil, exception: false).should == nil
+ Complex(0, nil, exception: false).should == nil
+ Complex(nil, 0, exception: false).should == nil
+ end
+ end
+ end
+
+ it "freezes its result" do
+ Complex(1).frozen?.should == true
+ end
end
diff --git a/spec/ruby/core/kernel/Float_spec.rb b/spec/ruby/core/kernel/Float_spec.rb
index ee20190094..9c436b05f7 100644
--- a/spec/ruby/core/kernel/Float_spec.rb
+++ b/spec/ruby/core/kernel/Float_spec.rb
@@ -1,12 +1,12 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe :kernel_float, shared: true do
it "returns the identical Float for numeric Floats" do
float = 1.12
float2 = @object.send(:Float, float)
float2.should == float
- float2.object_id.should == float.object_id
+ float2.should equal float
end
it "returns a Float for Fixnums" do
@@ -22,7 +22,7 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError for nil" do
- lambda { @object.send(:Float, nil) }.should raise_error(TypeError)
+ -> { @object.send(:Float, nil) }.should raise_error(TypeError)
end
it "returns the identical NaN for NaN" do
@@ -41,7 +41,7 @@ describe :kernel_float, shared: true do
end
it "converts Strings to floats without calling #to_f" do
- string = "10"
+ string = +"10"
string.should_not_receive(:to_f)
@object.send(:Float, string).should == 10.0
end
@@ -51,24 +51,30 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError for a String of word characters" do
- lambda { @object.send(:Float, "float") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "float") }.should raise_error(ArgumentError)
+ end
+
+ it "raises an ArgumentError for a String with string in error message" do
+ -> { @object.send(:Float, "foo") }.should raise_error(ArgumentError) { |e|
+ e.message.should == 'invalid value for Float(): "foo"'
+ }
end
it "raises an ArgumentError if there are two decimal points in the String" do
- lambda { @object.send(:Float, "10.0.0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "10.0.0") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError for a String of numbers followed by word characters" do
- lambda { @object.send(:Float, "10D") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "10D") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError for a String of word characters followed by numbers" do
- lambda { @object.send(:Float, "D10") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "D10") }.should raise_error(ArgumentError)
end
it "is strict about the string form even across newlines" do
- lambda { @object.send(:Float, "not a number\n10") }.should raise_error(ArgumentError)
- lambda { @object.send(:Float, "10\nnot a number") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "not a number\n10") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "10\nnot a number") }.should raise_error(ArgumentError)
end
it "converts String subclasses to floats without calling #to_f" do
@@ -90,17 +96,17 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError if a + or - is embedded in a String" do
- lambda { @object.send(:Float, "1+1") }.should raise_error(ArgumentError)
- lambda { @object.send(:Float, "1-1") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1+1") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1-1") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if a String has a trailing + or -" do
- lambda { @object.send(:Float, "11+") }.should raise_error(ArgumentError)
- lambda { @object.send(:Float, "11-") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "11+") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "11-") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError for a String with a leading _" do
- lambda { @object.send(:Float, "_1") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "_1") }.should raise_error(ArgumentError)
end
it "returns a value for a String with an embedded _" do
@@ -108,31 +114,31 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError for a String with a trailing _" do
- lambda { @object.send(:Float, "10_") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "10_") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError for a String of \\0" do
- lambda { @object.send(:Float, "\0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "\0") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError for a String with a leading \\0" do
- lambda { @object.send(:Float, "\01") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "\01") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError for a String with an embedded \\0" do
- lambda { @object.send(:Float, "1\01") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1\01") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError for a String with a trailing \\0" do
- lambda { @object.send(:Float, "1\0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1\0") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError for a String that is just an empty space" do
- lambda { @object.send(:Float, " ") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, " ") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError for a String that with an embedded space" do
- lambda { @object.send(:Float, "1 2") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1 2") }.should raise_error(ArgumentError)
end
it "returns a value for a String with a leading space" do
@@ -151,13 +157,33 @@ describe :kernel_float, shared: true do
@object.send(:Float, "1\t\n").should == 1.0
end
+ ruby_version_is ""..."3.4" do
+ it "raises ArgumentError if a fractional part is missing" do
+ -> { @object.send(:Float, "1.") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "+1.") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "-1.") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1.e+0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1.e-2") }.should raise_error(ArgumentError)
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "allows String representation without a fractional part" do
+ @object.send(:Float, "1.").should == 1.0
+ @object.send(:Float, "+1.").should == 1.0
+ @object.send(:Float, "-1.").should == -1.0
+ @object.send(:Float, "1.e+0").should == 1.0
+ @object.send(:Float, "1.e-2").should be_close(0.01, TOLERANCE)
+ end
+ end
+
%w(e E).each do |e|
it "raises an ArgumentError if #{e} is the trailing character" do
- lambda { @object.send(:Float, "2#{e}") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "2#{e}") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if #{e} is the leading character" do
- lambda { @object.send(:Float, "#{e}2") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "#{e}2") }.should raise_error(ArgumentError)
end
it "returns Infinity for '2#{e}1000'" do
@@ -175,18 +201,18 @@ describe :kernel_float, shared: true do
end
it "raises an exception if a space is embedded on either side of the '#{e}'" do
- lambda { @object.send(:Float, "2 0#{e}100") }.should raise_error(ArgumentError)
- lambda { @object.send(:Float, "20#{e}1 00") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "2 0#{e}100") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "20#{e}1 00") }.should raise_error(ArgumentError)
end
it "raises an exception if there's a leading _ on either side of the '#{e}'" do
- lambda { @object.send(:Float, "_20#{e}100") }.should raise_error(ArgumentError)
- lambda { @object.send(:Float, "20#{e}_100") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "_20#{e}100") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "20#{e}_100") }.should raise_error(ArgumentError)
end
it "raises an exception if there's a trailing _ on either side of the '#{e}'" do
- lambda { @object.send(:Float, "20_#{e}100") }.should raise_error(ArgumentError)
- lambda { @object.send(:Float, "20#{e}100_") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "20_#{e}100") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "20#{e}100_") }.should raise_error(ArgumentError)
end
it "allows decimal points on the left side of the '#{e}'" do
@@ -194,63 +220,111 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError if there's a decimal point on the right side of the '#{e}'" do
- lambda { @object.send(:Float, "20#{e}2.0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "20#{e}2.0") }.should raise_error(ArgumentError)
end
end
- describe "for hexadecimal literals with binary exponent" do
- %w(p P).each do |p|
- it "interprets the fractional part (on the left side of '#{p}') in hexadecimal" do
- @object.send(:Float, "0x10#{p}0").should == 16.0
- end
-
- it "interprets the exponent (on the right of '#{p}') in decimal" do
- @object.send(:Float, "0x1#{p}10").should == 1024.0
- end
-
- it "raises an ArgumentError if #{p} is the trailing character" do
- lambda { @object.send(:Float, "0x1#{p}") }.should raise_error(ArgumentError)
- end
-
- it "raises an ArgumentError if #{p} is the leading character" do
- lambda { @object.send(:Float, "0x#{p}1") }.should raise_error(ArgumentError)
- end
+ context "for hexadecimal literals" do
+ it "interprets the 0x prefix as hexadecimal" do
+ @object.send(:Float, "0x10").should == 16.0
+ @object.send(:Float, "0x0F").should == 15.0
+ @object.send(:Float, "0x0f").should == 15.0
+ end
- it "returns Infinity for '0x1#{p}10000'" do
- @object.send(:Float, "0x1#{p}10000").should == Float::INFINITY
- end
+ it "interprets negative hex value" do
+ @object.send(:Float, "-0x10").should == -16.0
+ end
- it "returns 0 for '0x1#{p}-10000'" do
- @object.send(:Float, "0x1#{p}-10000").should == 0
- end
+ it "accepts embedded _ if the number does not contain a-f" do
+ @object.send(:Float, "0x1_0").should == 16.0
+ end
- it "allows embedded _ in a number on either side of the #{p}" do
- @object.send(:Float, "0x1_0#{p}10").should == 16384.0
- @object.send(:Float, "0x10#{p}1_0").should == 16384.0
- @object.send(:Float, "0x1_0#{p}1_0").should == 16384.0
+ ruby_version_is ""..."3.4.3" do
+ it "does not accept embedded _ if the number contains a-f" do
+ -> { @object.send(:Float, "0x1_0a") }.should raise_error(ArgumentError)
+ @object.send(:Float, "0x1_0a", exception: false).should be_nil
end
+ end
- it "raises an exception if a space is embedded on either side of the '#{p}'" do
- lambda { @object.send(:Float, "0x1 0#{p}10") }.should raise_error(ArgumentError)
- lambda { @object.send(:Float, "0x10#{p}1 0") }.should raise_error(ArgumentError)
+ ruby_version_is "3.4.3" do
+ it "accepts embedded _ if the number contains a-f" do
+ @object.send(:Float, "0x1_0a").should == 0x10a.to_f
end
+ end
- it "raises an exception if there's a leading _ on either side of the '#{p}'" do
- lambda { @object.send(:Float, "0x_10#{p}10") }.should raise_error(ArgumentError)
- lambda { @object.send(:Float, "0x10#{p}_10") }.should raise_error(ArgumentError)
- end
+ it "does not accept _ before, after or inside the 0x prefix" do
+ -> { @object.send(:Float, "_0x10") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "0_x10") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "0x_10") }.should raise_error(ArgumentError)
+ @object.send(:Float, "_0x10", exception: false).should be_nil
+ @object.send(:Float, "0_x10", exception: false).should be_nil
+ @object.send(:Float, "0x_10", exception: false).should be_nil
+ end
- it "raises an exception if there's a trailing _ on either side of the '#{p}'" do
- lambda { @object.send(:Float, "0x10_#{p}10") }.should raise_error(ArgumentError)
- lambda { @object.send(:Float, "0x10#{p}10_") }.should raise_error(ArgumentError)
- end
+ it "parses negative hexadecimal string as negative float" do
+ @object.send(:Float, "-0x7b").should == -123.0
+ end
- it "allows hexadecimal points on the left side of the '#{p}'" do
- @object.send(:Float, "0x1.8#{p}0").should == 1.5
+ ruby_version_is "3.4" do
+ it "accepts a fractional part" do
+ @object.send(:Float, "0x0.8").should == 0.5
end
+ end
- it "raises an ArgumentError if there's a decimal point on the right side of the '#{p}'" do
- lambda { @object.send(:Float, "0x1#{p}1.0") }.should raise_error(ArgumentError)
+ describe "with binary exponent" do
+ %w(p P).each do |p|
+ it "interprets the fractional part (on the left side of '#{p}') in hexadecimal" do
+ @object.send(:Float, "0x10#{p}0").should == 16.0
+ end
+
+ it "interprets the exponent (on the right of '#{p}') in decimal" do
+ @object.send(:Float, "0x1#{p}10").should == 1024.0
+ end
+
+ it "raises an ArgumentError if #{p} is the trailing character" do
+ -> { @object.send(:Float, "0x1#{p}") }.should raise_error(ArgumentError)
+ end
+
+ it "raises an ArgumentError if #{p} is the leading character" do
+ -> { @object.send(:Float, "0x#{p}1") }.should raise_error(ArgumentError)
+ end
+
+ it "returns Infinity for '0x1#{p}10000'" do
+ @object.send(:Float, "0x1#{p}10000").should == Float::INFINITY
+ end
+
+ it "returns 0 for '0x1#{p}-10000'" do
+ @object.send(:Float, "0x1#{p}-10000").should == 0
+ end
+
+ it "allows embedded _ in a number on either side of the #{p}" do
+ @object.send(:Float, "0x1_0#{p}10").should == 16384.0
+ @object.send(:Float, "0x10#{p}1_0").should == 16384.0
+ @object.send(:Float, "0x1_0#{p}1_0").should == 16384.0
+ end
+
+ it "raises an exception if a space is embedded on either side of the '#{p}'" do
+ -> { @object.send(:Float, "0x1 0#{p}10") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "0x10#{p}1 0") }.should raise_error(ArgumentError)
+ end
+
+ it "raises an exception if there's a leading _ on either side of the '#{p}'" do
+ -> { @object.send(:Float, "0x_10#{p}10") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "0x10#{p}_10") }.should raise_error(ArgumentError)
+ end
+
+ it "raises an exception if there's a trailing _ on either side of the '#{p}'" do
+ -> { @object.send(:Float, "0x10_#{p}10") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "0x10#{p}10_") }.should raise_error(ArgumentError)
+ end
+
+ it "allows hexadecimal points on the left side of the '#{p}'" do
+ @object.send(:Float, "0x1.8#{p}0").should == 1.5
+ end
+
+ it "raises an ArgumentError if there's a decimal point on the right side of the '#{p}'" do
+ -> { @object.send(:Float, "0x1#{p}1.0") }.should raise_error(ArgumentError)
+ end
end
end
end
@@ -274,7 +348,7 @@ describe :kernel_float, shared: true do
nan2.should equal(nan)
end
- it "returns the identical Infinity if to_f is called and it returns Infinity" do
+ it "returns the identical Infinity if #to_f is called and it returns Infinity" do
infinity = infinity_value
(infinity_to_f = mock('Infinity')).should_receive(:to_f).once.and_return(infinity)
infinity2 = @object.send(:Float, infinity_to_f)
@@ -282,22 +356,45 @@ describe :kernel_float, shared: true do
end
it "raises a TypeError if #to_f is not provided" do
- lambda { @object.send(:Float, mock('x')) }.should raise_error(TypeError)
+ -> { @object.send(:Float, mock('x')) }.should raise_error(TypeError)
end
it "raises a TypeError if #to_f returns a String" do
(obj = mock('ha!')).should_receive(:to_f).once.and_return('ha!')
- lambda { @object.send(:Float, obj) }.should raise_error(TypeError)
+ -> { @object.send(:Float, obj) }.should raise_error(TypeError)
end
it "raises a TypeError if #to_f returns an Integer" do
(obj = mock('123')).should_receive(:to_f).once.and_return(123)
- lambda { @object.send(:Float, obj) }.should raise_error(TypeError)
+ -> { @object.send(:Float, obj) }.should raise_error(TypeError)
end
it "raises a RangeError when passed a Complex argument" do
c = Complex(2, 3)
- lambda { @object.send(:Float, c) }.should raise_error(RangeError)
+ -> { @object.send(:Float, c) }.should raise_error(RangeError)
+ end
+
+ describe "when passed exception: false" do
+ describe "and valid input" do
+ it "returns a Float number" do
+ @object.send(:Float, 1, exception: false).should == 1.0
+ @object.send(:Float, "1", exception: false).should == 1.0
+ @object.send(:Float, "1.23", exception: false).should == 1.23
+ end
+ end
+
+ describe "and invalid input" do
+ it "swallows an error" do
+ @object.send(:Float, "abc", exception: false).should == nil
+ @object.send(:Float, :sym, exception: false).should == nil
+ end
+ end
+
+ describe "and nil" do
+ it "swallows it" do
+ @object.send(:Float, nil, exception: false).should == nil
+ end
+ end
end
end
diff --git a/spec/ruby/core/kernel/Hash_spec.rb b/spec/ruby/core/kernel/Hash_spec.rb
index 8d51316c75..cbe098a8ac 100644
--- a/spec/ruby/core/kernel/Hash_spec.rb
+++ b/spec/ruby/core/kernel/Hash_spec.rb
@@ -1,8 +1,14 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#hash" do
- it "needs to be reviewed for spec completeness"
+ it "is provided" do
+ 1.respond_to?(:hash).should == true
+ end
+
+ it "is stable" do
+ 1.hash.should == 1.hash
+ end
end
describe "Kernel" do
@@ -37,14 +43,14 @@ describe :kernel_Hash, shared: true do
end
it "raises a TypeError if it doesn't respond to #to_hash" do
- lambda { @object.send(@method, mock("")) }.should raise_error(TypeError)
+ -> { @object.send(@method, mock("")) }.should raise_error(TypeError)
end
it "raises a TypeError if #to_hash does not return an Hash" do
obj = mock("Hash() string")
obj.should_receive(:to_hash).and_return("string")
- lambda { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/core/kernel/Integer_spec.rb b/spec/ruby/core/kernel/Integer_spec.rb
index 1e95fc9151..74dd3e0dd2 100644
--- a/spec/ruby/core/kernel/Integer_spec.rb
+++ b/spec/ruby/core/kernel/Integer_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe :kernel_integer, shared: true do
it "returns a Bignum for a Bignum" do
@@ -10,20 +10,27 @@ describe :kernel_integer, shared: true do
Integer(100).should == 100
end
- it "uncritically return the value of to_int even if it is not an Integer" do
+ it "raises a TypeError when to_int returns not-an-Integer object and to_i returns nil" do
obj = mock("object")
obj.should_receive(:to_int).and_return("1")
- obj.should_not_receive(:to_i)
- Integer(obj).should == "1"
+ obj.should_receive(:to_i).and_return(nil)
+ -> { Integer(obj) }.should raise_error(TypeError)
+ end
+
+ it "return a result of to_i when to_int does not return an Integer" do
+ obj = mock("object")
+ obj.should_receive(:to_int).and_return("1")
+ obj.should_receive(:to_i).and_return(42)
+ Integer(obj).should == 42
end
it "raises a TypeError when passed nil" do
- lambda { Integer(nil) }.should raise_error(TypeError)
+ -> { Integer(nil) }.should raise_error(TypeError)
end
- it "returns a Fixnum or Bignum object" do
- Integer(2).should be_an_instance_of(Fixnum)
- Integer(9**99).should be_an_instance_of(Bignum)
+ it "returns an Integer object" do
+ Integer(2).should be_an_instance_of(Integer)
+ Integer(9**99).should be_an_instance_of(Integer)
end
it "truncates Floats" do
@@ -45,9 +52,9 @@ describe :kernel_integer, shared: true do
it "returns the value of to_int if the result is a Bignum" do
obj = mock("object")
- obj.should_receive(:to_int).and_return(2e100)
+ obj.should_receive(:to_int).and_return(2 * 10**100)
obj.should_not_receive(:to_i)
- Integer(obj).should == 2e100
+ Integer(obj).should == 2 * 10**100
end
it "calls to_i on an object whose to_int returns nil" do
@@ -60,44 +67,99 @@ describe :kernel_integer, shared: true do
it "raises a TypeError if to_i returns a value that is not an Integer" do
obj = mock("object")
obj.should_receive(:to_i).and_return("1")
- lambda { Integer(obj) }.should raise_error(TypeError)
+ -> { Integer(obj) }.should raise_error(TypeError)
end
it "raises a TypeError if no to_int or to_i methods exist" do
obj = mock("object")
- lambda { Integer(obj) }.should raise_error(TypeError)
+ -> { Integer(obj) }.should raise_error(TypeError)
end
it "raises a TypeError if to_int returns nil and no to_i exists" do
obj = mock("object")
obj.should_receive(:to_i).and_return(nil)
- lambda { Integer(obj) }.should raise_error(TypeError)
+ -> { Integer(obj) }.should raise_error(TypeError)
end
it "raises a FloatDomainError when passed NaN" do
- lambda { Integer(nan_value) }.should raise_error(FloatDomainError)
+ -> { Integer(nan_value) }.should raise_error(FloatDomainError)
end
it "raises a FloatDomainError when passed Infinity" do
- lambda { Integer(infinity_value) }.should raise_error(FloatDomainError)
+ -> { Integer(infinity_value) }.should raise_error(FloatDomainError)
+ end
+
+ describe "when passed exception: false" do
+ describe "and to_i returns a value that is not an Integer" do
+ it "swallows an error" do
+ obj = mock("object")
+ obj.should_receive(:to_i).and_return("1")
+ Integer(obj, exception: false).should == nil
+ end
+ end
+
+ describe "and no to_int or to_i methods exist" do
+ it "swallows an error" do
+ obj = mock("object")
+ Integer(obj, exception: false).should == nil
+ end
+ end
+
+ describe "and to_int returns nil and no to_i exists" do
+ it "swallows an error" do
+ obj = mock("object")
+ obj.should_receive(:to_i).and_return(nil)
+ Integer(obj, exception: false).should == nil
+ end
+ end
+
+ describe "and passed NaN" do
+ it "swallows an error" do
+ Integer(nan_value, exception: false).should == nil
+ end
+ end
+
+ describe "and passed Infinity" do
+ it "swallows an error" do
+ Integer(infinity_value, exception: false).should == nil
+ end
+ end
+
+ describe "and passed nil" do
+ it "swallows an error" do
+ Integer(nil, exception: false).should == nil
+ end
+ end
+
+ describe "and passed a String that contains numbers" do
+ it "normally parses it and returns an Integer" do
+ Integer("42", exception: false).should == 42
+ end
+ end
+
+ describe "and passed a String that can't be converted to an Integer" do
+ it "swallows an error" do
+ Integer("abc", exception: false).should == nil
+ end
+ end
end
end
-describe "Integer() given a String", shared: true do
+describe :kernel_integer_string, shared: true do
it "raises an ArgumentError if the String is a null byte" do
- lambda { Integer("\0") }.should raise_error(ArgumentError)
+ -> { Integer("\0") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if the String starts with a null byte" do
- lambda { Integer("\01") }.should raise_error(ArgumentError)
+ -> { Integer("\01") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if the String ends with a null byte" do
- lambda { Integer("1\0") }.should raise_error(ArgumentError)
+ -> { Integer("1\0") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if the String contains a null byte" do
- lambda { Integer("1\01") }.should raise_error(ArgumentError)
+ -> { Integer("1\01") }.should raise_error(ArgumentError)
end
it "ignores leading whitespace" do
@@ -113,13 +175,13 @@ describe "Integer() given a String", shared: true do
end
it "raises an ArgumentError if there are leading _s" do
- lambda { Integer("_1") }.should raise_error(ArgumentError)
- lambda { Integer("___1") }.should raise_error(ArgumentError)
+ -> { Integer("_1") }.should raise_error(ArgumentError)
+ -> { Integer("___1") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if there are trailing _s" do
- lambda { Integer("1_") }.should raise_error(ArgumentError)
- lambda { Integer("1___") }.should raise_error(ArgumentError)
+ -> { Integer("1_") }.should raise_error(ArgumentError)
+ -> { Integer("1___") }.should raise_error(ArgumentError)
end
it "ignores an embedded _" do
@@ -127,8 +189,8 @@ describe "Integer() given a String", shared: true do
end
it "raises an ArgumentError if there are multiple embedded _s" do
- lambda { Integer("1__1") }.should raise_error(ArgumentError)
- lambda { Integer("1___1") }.should raise_error(ArgumentError)
+ -> { Integer("1__1") }.should raise_error(ArgumentError)
+ -> { Integer("1___1") }.should raise_error(ArgumentError)
end
it "ignores a single leading +" do
@@ -136,17 +198,17 @@ describe "Integer() given a String", shared: true do
end
it "raises an ArgumentError if there is a space between the + and number" do
- lambda { Integer("+ 1") }.should raise_error(ArgumentError)
+ -> { Integer("+ 1") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if there are multiple leading +s" do
- lambda { Integer("++1") }.should raise_error(ArgumentError)
- lambda { Integer("+++1") }.should raise_error(ArgumentError)
+ -> { Integer("++1") }.should raise_error(ArgumentError)
+ -> { Integer("+++1") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if there are trailing +s" do
- lambda { Integer("1+") }.should raise_error(ArgumentError)
- lambda { Integer("1+++") }.should raise_error(ArgumentError)
+ -> { Integer("1+") }.should raise_error(ArgumentError)
+ -> { Integer("1+++") }.should raise_error(ArgumentError)
end
it "makes the number negative if there's a leading -" do
@@ -154,21 +216,47 @@ describe "Integer() given a String", shared: true do
end
it "raises an ArgumentError if there are multiple leading -s" do
- lambda { Integer("--1") }.should raise_error(ArgumentError)
- lambda { Integer("---1") }.should raise_error(ArgumentError)
+ -> { Integer("--1") }.should raise_error(ArgumentError)
+ -> { Integer("---1") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if there are trailing -s" do
- lambda { Integer("1-") }.should raise_error(ArgumentError)
- lambda { Integer("1---") }.should raise_error(ArgumentError)
+ -> { Integer("1-") }.should raise_error(ArgumentError)
+ -> { Integer("1---") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if there is a period" do
- lambda { Integer("0.0") }.should raise_error(ArgumentError)
+ -> { Integer("0.0") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError for an empty String" do
- lambda { Integer("") }.should raise_error(ArgumentError)
+ -> { Integer("") }.should raise_error(ArgumentError)
+ end
+
+ describe "when passed exception: false" do
+ describe "and multiple leading -s" do
+ it "swallows an error" do
+ Integer("---1", exception: false).should == nil
+ end
+ end
+
+ describe "and multiple trailing -s" do
+ it "swallows an error" do
+ Integer("1---", exception: false).should == nil
+ end
+ end
+
+ describe "and an argument that contains a period" do
+ it "swallows an error" do
+ Integer("0.0", exception: false).should == nil
+ end
+ end
+
+ describe "and an empty string" do
+ it "swallows an error" do
+ Integer("", exception: false).should == nil
+ end
+ end
end
it "parses the value as 0 if the string consists of a single zero character" do
@@ -192,7 +280,7 @@ describe "Integer() given a String", shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as hex" do
- lambda { Integer("0#{x}g") }.should raise_error(ArgumentError)
+ -> { Integer("0#{x}g") }.should raise_error(ArgumentError)
end
end
@@ -213,7 +301,7 @@ describe "Integer() given a String", shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as binary" do
- lambda { Integer("0#{b}2") }.should raise_error(ArgumentError)
+ -> { Integer("0#{b}2") }.should raise_error(ArgumentError)
end
end
@@ -234,7 +322,7 @@ describe "Integer() given a String", shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as octal" do
- lambda { Integer("0#{o}9") }.should raise_error(ArgumentError)
+ -> { Integer("0#{o}9") }.should raise_error(ArgumentError)
end
end
@@ -255,26 +343,26 @@ describe "Integer() given a String", shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as decimal" do
- lambda { Integer("0#{d}a") }.should raise_error(ArgumentError)
+ -> { Integer("0#{d}a") }.should raise_error(ArgumentError)
end
end
end
-describe "Integer() given a String and base", shared: true do
+describe :kernel_integer_string_base, shared: true do
it "raises an ArgumentError if the String is a null byte" do
- lambda { Integer("\0", 2) }.should raise_error(ArgumentError)
+ -> { Integer("\0", 2) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if the String starts with a null byte" do
- lambda { Integer("\01", 3) }.should raise_error(ArgumentError)
+ -> { Integer("\01", 3) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if the String ends with a null byte" do
- lambda { Integer("1\0", 4) }.should raise_error(ArgumentError)
+ -> { Integer("1\0", 4) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if the String contains a null byte" do
- lambda { Integer("1\01", 5) }.should raise_error(ArgumentError)
+ -> { Integer("1\01", 5) }.should raise_error(ArgumentError)
end
it "ignores leading whitespace" do
@@ -290,13 +378,13 @@ describe "Integer() given a String and base", shared: true do
end
it "raises an ArgumentError if there are leading _s" do
- lambda { Integer("_1", 7) }.should raise_error(ArgumentError)
- lambda { Integer("___1", 7) }.should raise_error(ArgumentError)
+ -> { Integer("_1", 7) }.should raise_error(ArgumentError)
+ -> { Integer("___1", 7) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if there are trailing _s" do
- lambda { Integer("1_", 12) }.should raise_error(ArgumentError)
- lambda { Integer("1___", 12) }.should raise_error(ArgumentError)
+ -> { Integer("1_", 12) }.should raise_error(ArgumentError)
+ -> { Integer("1___", 12) }.should raise_error(ArgumentError)
end
it "ignores an embedded _" do
@@ -304,8 +392,8 @@ describe "Integer() given a String and base", shared: true do
end
it "raises an ArgumentError if there are multiple embedded _s" do
- lambda { Integer("1__1", 4) }.should raise_error(ArgumentError)
- lambda { Integer("1___1", 4) }.should raise_error(ArgumentError)
+ -> { Integer("1__1", 4) }.should raise_error(ArgumentError)
+ -> { Integer("1___1", 4) }.should raise_error(ArgumentError)
end
it "ignores a single leading +" do
@@ -313,17 +401,17 @@ describe "Integer() given a String and base", shared: true do
end
it "raises an ArgumentError if there is a space between the + and number" do
- lambda { Integer("+ 1", 3) }.should raise_error(ArgumentError)
+ -> { Integer("+ 1", 3) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if there are multiple leading +s" do
- lambda { Integer("++1", 3) }.should raise_error(ArgumentError)
- lambda { Integer("+++1", 3) }.should raise_error(ArgumentError)
+ -> { Integer("++1", 3) }.should raise_error(ArgumentError)
+ -> { Integer("+++1", 3) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if there are trailing +s" do
- lambda { Integer("1+", 3) }.should raise_error(ArgumentError)
- lambda { Integer("1+++", 12) }.should raise_error(ArgumentError)
+ -> { Integer("1+", 3) }.should raise_error(ArgumentError)
+ -> { Integer("1+++", 12) }.should raise_error(ArgumentError)
end
it "makes the number negative if there's a leading -" do
@@ -331,29 +419,29 @@ describe "Integer() given a String and base", shared: true do
end
it "raises an ArgumentError if there are multiple leading -s" do
- lambda { Integer("--1", 9) }.should raise_error(ArgumentError)
- lambda { Integer("---1", 9) }.should raise_error(ArgumentError)
+ -> { Integer("--1", 9) }.should raise_error(ArgumentError)
+ -> { Integer("---1", 9) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if there are trailing -s" do
- lambda { Integer("1-", 12) }.should raise_error(ArgumentError)
- lambda { Integer("1---", 12) }.should raise_error(ArgumentError)
+ -> { Integer("1-", 12) }.should raise_error(ArgumentError)
+ -> { Integer("1---", 12) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if there is a period" do
- lambda { Integer("0.0", 3) }.should raise_error(ArgumentError)
+ -> { Integer("0.0", 3) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError for an empty String" do
- lambda { Integer("", 12) }.should raise_error(ArgumentError)
+ -> { Integer("", 12) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError for a base of 1" do
- lambda { Integer("1", 1) }.should raise_error(ArgumentError)
+ -> { Integer("1", 1) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError for a base of 37" do
- lambda { Integer("1", 37) }.should raise_error(ArgumentError)
+ -> { Integer("1", 37) }.should raise_error(ArgumentError)
end
it "accepts wholly lowercase alphabetic strings for bases > 10" do
@@ -381,8 +469,8 @@ describe "Integer() given a String and base", shared: true do
end
it "raises an ArgumentError for letters invalid in the given base" do
- lambda { Integer('z',19) }.should raise_error(ArgumentError)
- lambda { Integer('c00o',2) }.should raise_error(ArgumentError)
+ -> { Integer('z',19) }.should raise_error(ArgumentError)
+ -> { Integer('c00o',2) }.should raise_error(ArgumentError)
end
%w(x X).each do |x|
@@ -403,12 +491,12 @@ describe "Integer() given a String and base", shared: true do
2.upto(15) do |base|
it "raises an ArgumentError if the number begins with 0#{x} and the base is #{base}" do
- lambda { Integer("0#{x}1", base) }.should raise_error(ArgumentError)
+ -> { Integer("0#{x}1", base) }.should raise_error(ArgumentError)
end
end
it "raises an ArgumentError if the number cannot be parsed as hex and the base is 16" do
- lambda { Integer("0#{x}g", 16) }.should raise_error(ArgumentError)
+ -> { Integer("0#{x}g", 16) }.should raise_error(ArgumentError)
end
end
@@ -429,7 +517,7 @@ describe "Integer() given a String and base", shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as binary and the base is 2" do
- lambda { Integer("0#{b}2", 2) }.should raise_error(ArgumentError)
+ -> { Integer("0#{b}2", 2) }.should raise_error(ArgumentError)
end
end
@@ -450,12 +538,12 @@ describe "Integer() given a String and base", shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as octal and the base is 8" do
- lambda { Integer("0#{o}9", 8) }.should raise_error(ArgumentError)
+ -> { Integer("0#{o}9", 8) }.should raise_error(ArgumentError)
end
2.upto(7) do |base|
it "raises an ArgumentError if the number begins with 0#{o} and the base is #{base}" do
- lambda { Integer("0#{o}1", base) }.should raise_error(ArgumentError)
+ -> { Integer("0#{o}1", base) }.should raise_error(ArgumentError)
end
end
end
@@ -477,17 +565,55 @@ describe "Integer() given a String and base", shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as decimal and the base is 10" do
- lambda { Integer("0#{d}a", 10) }.should raise_error(ArgumentError)
+ -> { Integer("0#{d}a", 10) }.should raise_error(ArgumentError)
end
2.upto(9) do |base|
it "raises an ArgumentError if the number begins with 0#{d} and the base is #{base}" do
- lambda { Integer("0#{d}1", base) }.should raise_error(ArgumentError)
+ -> { Integer("0#{d}1", base) }.should raise_error(ArgumentError)
+ end
+ end
+ end
+
+ it "raises an ArgumentError if a base is given for a non-String value" do
+ -> { Integer(98, 15) }.should raise_error(ArgumentError)
+ end
+
+ it "tries to convert the base to an integer using to_int" do
+ obj = mock('8')
+ obj.should_receive(:to_int).and_return(8)
+
+ Integer("777", obj).should == 0777
+ end
+
+ # https://bugs.ruby-lang.org/issues/19349
+ ruby_version_is ''...'3.3' do
+ it "ignores the base if it is not an integer and does not respond to #to_i" do
+ Integer("777", "8").should == 777
+ end
+ end
+
+ ruby_version_is '3.3' do
+ it "raises a TypeError if it is not an integer and does not respond to #to_i" do
+ -> {
+ Integer("777", "8")
+ }.should raise_error(TypeError, "no implicit conversion of String into Integer")
+ end
+ end
+
+ describe "when passed exception: false" do
+ describe "and valid argument" do
+ it "returns an Integer number" do
+ Integer("100", 10, exception: false).should == 100
+ Integer("100", 2, exception: false).should == 4
end
end
- it "raises an ArgumentError if a base is given for a non-String value" do
- lambda { Integer(98, 15) }.should raise_error(ArgumentError)
+ describe "and invalid argument" do
+ it "swallows an error" do
+ Integer("999", 2, exception: false).should == nil
+ Integer("abc", 10, exception: false).should == nil
+ end
end
end
end
@@ -495,176 +621,176 @@ end
describe :kernel_Integer, shared: true do
it "raises an ArgumentError when the String contains digits out of range of radix 2" do
str = "23456789abcdefghijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 2) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 2) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 3" do
str = "3456789abcdefghijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 3) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 3) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 4" do
str = "456789abcdefghijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 4) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 4) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 5" do
str = "56789abcdefghijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 5) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 5) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 6" do
str = "6789abcdefghijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 6) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 6) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 7" do
str = "789abcdefghijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 7) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 7) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 8" do
str = "89abcdefghijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 8) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 8) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 9" do
str = "9abcdefghijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 9) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 9) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 10" do
str = "abcdefghijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 10) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 10) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 11" do
str = "bcdefghijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 11) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 11) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 12" do
str = "cdefghijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 12) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 12) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 13" do
str = "defghijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 13) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 13) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 14" do
str = "efghijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 14) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 14) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 15" do
str = "fghijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 15) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 15) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 16" do
str = "ghijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 16) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 16) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 17" do
str = "hijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 17) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 17) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 18" do
str = "ijklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 18) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 18) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 19" do
str = "jklmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 19) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 19) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 20" do
str = "klmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 20) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 20) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 21" do
str = "lmnopqrstuvwxyz"
- lambda { @object.send(@method, str, 21) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 21) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 22" do
str = "mnopqrstuvwxyz"
- lambda { @object.send(@method, str, 22) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 22) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 23" do
str = "nopqrstuvwxyz"
- lambda { @object.send(@method, str, 23) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 23) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 24" do
str = "opqrstuvwxyz"
- lambda { @object.send(@method, str, 24) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 24) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 25" do
str = "pqrstuvwxyz"
- lambda { @object.send(@method, str, 25) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 25) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 26" do
str = "qrstuvwxyz"
- lambda { @object.send(@method, str, 26) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 26) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 27" do
str = "rstuvwxyz"
- lambda { @object.send(@method, str, 27) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 27) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 28" do
str = "stuvwxyz"
- lambda { @object.send(@method, str, 28) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 28) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 29" do
str = "tuvwxyz"
- lambda { @object.send(@method, str, 29) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 29) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 30" do
str = "uvwxyz"
- lambda { @object.send(@method, str, 30) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 30) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 31" do
str = "vwxyz"
- lambda { @object.send(@method, str, 31) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 31) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 32" do
str = "wxyz"
- lambda { @object.send(@method, str, 32) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 32) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 33" do
str = "xyz"
- lambda { @object.send(@method, str, 33) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 33) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 34" do
str = "yz"
- lambda { @object.send(@method, str, 34) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 34) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 35" do
str = "z"
- lambda { @object.send(@method, str, 35) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 35) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 36" do
- lambda { @object.send(@method, "{", 36) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, "{", 36) }.should raise_error(ArgumentError)
end
end
@@ -673,9 +799,9 @@ describe "Kernel.Integer" do
# TODO: fix these specs
it_behaves_like :kernel_integer, :Integer, Kernel
- it_behaves_like "Integer() given a String", :Integer
+ it_behaves_like :kernel_integer_string, :Integer
- it_behaves_like "Integer() given a String and base", :Integer
+ it_behaves_like :kernel_integer_string_base, :Integer
it "is a public method" do
Kernel.Integer(10).should == 10
@@ -687,9 +813,9 @@ describe "Kernel#Integer" do
# TODO: fix these specs
it_behaves_like :kernel_integer, :Integer, Object.new
- it_behaves_like "Integer() given a String", :Integer
+ it_behaves_like :kernel_integer_string, :Integer
- it_behaves_like "Integer() given a String and base", :Integer
+ it_behaves_like :kernel_integer_string_base, :Integer
it "is a private method" do
Kernel.should have_private_instance_method(:Integer)
diff --git a/spec/ruby/core/kernel/Rational_spec.rb b/spec/ruby/core/kernel/Rational_spec.rb
index 38f1da6333..cc11a35451 100644
--- a/spec/ruby/core/kernel/Rational_spec.rb
+++ b/spec/ruby/core/kernel/Rational_spec.rb
@@ -1,6 +1,236 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../../../shared/rational/Rational', __FILE__)
+require_relative '../../spec_helper'
+require_relative '../rational/fixtures/rational'
describe "Kernel.Rational" do
- it_behaves_like :kernel_Rational, :Rational
+ describe "passed Integer" do
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ it "returns a new Rational number with 1 as the denominator" do
+ Rational(1).should eql(Rational(1, 1))
+ Rational(-3).should eql(Rational(-3, 1))
+ Rational(bignum_value).should eql(Rational(bignum_value, 1))
+ end
+ end
+ end
+
+ describe "passed two integers" do
+ it "returns a new Rational number" do
+ rat = Rational(1, 2)
+ rat.numerator.should == 1
+ rat.denominator.should == 2
+ rat.should be_an_instance_of(Rational)
+
+ rat = Rational(-3, -5)
+ rat.numerator.should == 3
+ rat.denominator.should == 5
+ rat.should be_an_instance_of(Rational)
+
+ rat = Rational(bignum_value, 3)
+ rat.numerator.should == bignum_value
+ rat.denominator.should == 3
+ rat.should be_an_instance_of(Rational)
+ end
+
+ it "reduces the Rational" do
+ rat = Rational(2, 4)
+ rat.numerator.should == 1
+ rat.denominator.should == 2
+
+ rat = Rational(3, 9)
+ rat.numerator.should == 1
+ rat.denominator.should == 3
+ end
+ end
+
+ describe "when passed a String" do
+ it "converts the String to a Rational using the same method as String#to_r" do
+ r = Rational(13, 25)
+ s_r = ".52".to_r
+ r_s = Rational(".52")
+
+ r_s.should == r
+ r_s.should == s_r
+ end
+
+ it "scales the Rational value of the first argument by the Rational value of the second" do
+ Rational(".52", ".6").should == Rational(13, 15)
+ Rational(".52", "1.6").should == Rational(13, 40)
+ end
+
+ it "does not use the same method as Float#to_r" do
+ r = Rational(3, 5)
+ f_r = 0.6.to_r
+ r_s = Rational("0.6")
+
+ r_s.should == r
+ r_s.should_not == f_r
+ end
+ end
+
+ describe "when passed a Numeric" do
+ it "calls #to_r to convert the first argument to a Rational" do
+ num = RationalSpecs::SubNumeric.new(2)
+
+ Rational(num).should == Rational(2)
+ end
+ end
+
+ describe "when passed a Complex" do
+ context "[Complex]" do
+ it "returns a Rational from the real part if the imaginary part is 0" do
+ Rational(Complex(1, 0)).should == Rational(1)
+ end
+
+ it "raises a RangeError if the imaginary part is not 0" do
+ -> { Rational(Complex(1, 2)) }.should raise_error(RangeError, "can't convert 1+2i into Rational")
+ end
+ end
+
+ context "[Numeric, Complex]" do
+ it "uses the real part if the imaginary part is 0" do
+ Rational(1, Complex(2, 0)).should == Rational(1, 2)
+ end
+
+ it "divides a numerator by the Complex denominator if the imaginary part is not 0" do
+ Rational(1, Complex(2, 1)).should == Complex(2/5r, -1/5r)
+ end
+ end
+ end
+
+ context "when passed neither a Numeric nor a String" do
+ it "converts to Rational with #to_r method" do
+ obj = Object.new
+ def obj.to_r; 1/2r; end
+
+ Rational(obj).should == 1/2r
+ end
+
+ it "tries to convert to Integer with #to_int method if it does not respond to #to_r" do
+ obj = Object.new
+ def obj.to_int; 1; end
+
+ Rational(obj).should == 1r
+ end
+
+ it "raises TypeError if it neither responds to #to_r nor #to_int method" do
+ -> { Rational([]) }.should raise_error(TypeError, "can't convert Array into Rational")
+ -> { Rational({}) }.should raise_error(TypeError, "can't convert Hash into Rational")
+ -> { Rational(nil) }.should raise_error(TypeError, "can't convert nil into Rational")
+ end
+
+ it "swallows exception raised in #to_int method" do
+ object = Object.new
+ def object.to_int() raise NoMethodError; end
+
+ -> { Rational(object) }.should raise_error(TypeError)
+ -> { Rational(object, 1) }.should raise_error(TypeError)
+ -> { Rational(1, object) }.should raise_error(TypeError)
+ end
+
+ it "raises TypeError if #to_r does not return Rational" do
+ obj = Object.new
+ def obj.to_r; []; end
+
+ -> { Rational(obj) }.should raise_error(TypeError, "can't convert Object to Rational (Object#to_r gives Array)")
+ end
+ end
+
+ it "raises a ZeroDivisionError if the second argument is 0" do
+ -> { Rational(1, 0) }.should raise_error(ZeroDivisionError, "divided by 0")
+ -> { Rational(1, 0.0) }.should raise_error(ZeroDivisionError, "divided by 0")
+ end
+
+ it "raises a TypeError if the first argument is nil" do
+ -> { Rational(nil) }.should raise_error(TypeError, "can't convert nil into Rational")
+ end
+
+ it "raises a TypeError if the second argument is nil" do
+ -> { Rational(1, nil) }.should raise_error(TypeError, "can't convert nil into Rational")
+ end
+
+ it "raises a TypeError if the first argument is a Symbol" do
+ -> { Rational(:sym) }.should raise_error(TypeError)
+ end
+
+ it "raises a TypeError if the second argument is a Symbol" do
+ -> { Rational(1, :sym) }.should raise_error(TypeError)
+ end
+
+ describe "when passed exception: false" do
+ describe "and [non-Numeric]" do
+ it "swallows an error" do
+ Rational(:sym, exception: false).should == nil
+ Rational("abc", exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_r" do
+ obj = Object.new
+ def obj.to_r; raise; end
+ Rational(obj, exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_int" do
+ obj = Object.new
+ def obj.to_int; raise; end
+ Rational(obj, exception: false).should == nil
+ end
+ end
+
+ describe "and [non-Numeric, Numeric]" do
+ it "swallows an error" do
+ Rational(:sym, 1, exception: false).should == nil
+ Rational("abc", 1, exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_r" do
+ obj = Object.new
+ def obj.to_r; raise; end
+ Rational(obj, 1, exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_int" do
+ obj = Object.new
+ def obj.to_int; raise; end
+ Rational(obj, 1, exception: false).should == nil
+ end
+ end
+
+ describe "and [anything, non-Numeric]" do
+ it "swallows an error" do
+ Rational(:sym, :sym, exception: false).should == nil
+ Rational("abc", :sym, exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_r" do
+ obj = Object.new
+ def obj.to_r; raise; end
+ Rational(obj, obj, exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_int" do
+ obj = Object.new
+ def obj.to_int; raise; end
+ Rational(obj, obj, exception: false).should == nil
+ end
+ end
+
+ describe "and non-Numeric String arguments" do
+ it "swallows an error" do
+ Rational("a", "b", exception: false).should == nil
+ Rational("a", 0, exception: false).should == nil
+ Rational(0, "b", exception: false).should == nil
+ end
+ end
+
+ describe "and nil arguments" do
+ it "swallows an error" do
+ Rational(nil, exception: false).should == nil
+ Rational(nil, nil, exception: false).should == nil
+ end
+ end
+ end
+
+ it "freezes its result" do
+ Rational(1).frozen?.should == true
+ end
end
diff --git a/spec/ruby/core/kernel/String_spec.rb b/spec/ruby/core/kernel/String_spec.rb
index b24bc798e5..7caec6eda5 100644
--- a/spec/ruby/core/kernel/String_spec.rb
+++ b/spec/ruby/core/kernel/String_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe :kernel_String, shared: true do
it "converts nil to a String" do
@@ -32,7 +32,7 @@ describe :kernel_String, shared: true do
undef_method :to_s
end
- lambda { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should raise_error(TypeError)
end
# #5158
@@ -44,7 +44,7 @@ describe :kernel_String, shared: true do
end
end
- lambda { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should raise_error(TypeError)
end
it "raises a TypeError if #to_s is not defined, even though #respond_to?(:to_s) returns true" do
@@ -57,7 +57,7 @@ describe :kernel_String, shared: true do
end
end
- lambda { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should raise_error(TypeError)
end
it "calls #to_s if #respond_to?(:to_s) returns true" do
@@ -74,11 +74,11 @@ describe :kernel_String, shared: true do
it "raises a TypeError if #to_s does not return a String" do
(obj = mock('123')).should_receive(:to_s).and_return(123)
- lambda { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should raise_error(TypeError)
end
it "returns the same object if it is already a String" do
- string = "Hello"
+ string = +"Hello"
string.should_not_receive(:to_s)
string2 = @object.send(@method, string)
string.should equal(string2)
diff --git a/spec/ruby/core/kernel/__callee___spec.rb b/spec/ruby/core/kernel/__callee___spec.rb
index 91cc4cdafa..3059ea8b57 100644
--- a/spec/ruby/core/kernel/__callee___spec.rb
+++ b/spec/ruby/core/kernel/__callee___spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/__callee__', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/__callee__'
describe "Kernel.__callee__" do
it "returns the current method, even when aliased" do
diff --git a/spec/ruby/core/kernel/__dir___spec.rb b/spec/ruby/core/kernel/__dir___spec.rb
index 395d30f494..242adbf48b 100644
--- a/spec/ruby/core/kernel/__dir___spec.rb
+++ b/spec/ruby/core/kernel/__dir___spec.rb
@@ -1,13 +1,27 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Kernel#__dir__" do
it "returns the real name of the directory containing the currently-executing file" do
__dir__.should == File.realpath(File.dirname(__FILE__))
end
+ it "returns the expanded path of the directory when used in the main script" do
+ fixtures_dir = File.dirname(fixture(__FILE__, '__dir__.rb'))
+ Dir.chdir(fixtures_dir) do
+ ruby_exe("__dir__.rb").should == "__dir__.rb\n#{fixtures_dir}\n"
+ end
+ end
+
+ context "when used in eval with a given filename" do
+ it "returns File.dirname(filename)" do
+ eval("__dir__", nil, "foo.rb").should == "."
+ eval("__dir__", nil, "foo/bar.rb").should == "foo"
+ end
+ end
+
context "when used in eval with top level binding" do
- it "returns the real name of the directory containing the currently-executing file" do
- eval("__dir__", binding).should == File.realpath(File.dirname(__FILE__))
+ it "returns nil" do
+ eval("__dir__", binding).should == nil
end
end
end
diff --git a/spec/ruby/core/kernel/__method___spec.rb b/spec/ruby/core/kernel/__method___spec.rb
index 936a6b2f00..578d25640d 100644
--- a/spec/ruby/core/kernel/__method___spec.rb
+++ b/spec/ruby/core/kernel/__method___spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/__method__', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/__method__'
describe "Kernel.__method__" do
it "returns the current method, even when aliased" do
diff --git a/spec/ruby/core/kernel/abort_spec.rb b/spec/ruby/core/kernel/abort_spec.rb
index eb9c1c30c7..f8152718c5 100644
--- a/spec/ruby/core/kernel/abort_spec.rb
+++ b/spec/ruby/core/kernel/abort_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../../../shared/process/abort', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative '../../shared/process/abort'
describe "Kernel#abort" do
it "is a private method" do
diff --git a/spec/ruby/core/kernel/at_exit_spec.rb b/spec/ruby/core/kernel/at_exit_spec.rb
index 9fcb99148c..ebd9a71d15 100644
--- a/spec/ruby/core/kernel/at_exit_spec.rb
+++ b/spec/ruby/core/kernel/at_exit_spec.rb
@@ -1,42 +1,17 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative '../../shared/kernel/at_exit'
describe "Kernel.at_exit" do
+ it_behaves_like :kernel_at_exit, :at_exit
+
it "is a private method" do
Kernel.should have_private_instance_method(:at_exit)
end
- it "runs after all other code" do
- ruby_exe("at_exit {print 5}; print 6").should == "65"
- end
-
- it "runs in reverse order of registration" do
- code = "at_exit {print 4};at_exit {print 5}; print 6; at_exit {print 7}"
- ruby_exe(code).should == "6754"
- end
-
- it "allows calling exit inside at_exit handler" do
- code = "at_exit {print 3}; at_exit {print 4; exit; print 5}; at_exit {print 6}"
- ruby_exe(code).should == "643"
+ it "raises ArgumentError if called without a block" do
+ -> { at_exit }.should raise_error(ArgumentError, "called without a block")
end
-
- it "gives access to the last raised exception" do
- code = <<-EOC
- at_exit do
- puts "The exception matches: \#{$! == $exception}"
- end
-
- begin
- raise "foo"
- rescue => $exception
- raise
- end
- EOC
-
- result = ruby_exe(code, args: "2>&1", escape: true)
- result.should =~ /The exception matches: true/
- end
-
end
describe "Kernel#at_exit" do
diff --git a/spec/ruby/core/kernel/autoload_spec.rb b/spec/ruby/core/kernel/autoload_spec.rb
index b2aab5a895..5edb70541d 100644
--- a/spec/ruby/core/kernel/autoload_spec.rb
+++ b/spec/ruby/core/kernel/autoload_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
# These specs only illustrate the basic autoload cases
# and where toplevel autoload behaves differently from
@@ -7,7 +7,9 @@ require File.expand_path('../fixtures/classes', __FILE__)
autoload :KSAutoloadA, "autoload_a.rb"
autoload :KSAutoloadB, fixture(__FILE__, "autoload_b.rb")
-autoload :KSAutoloadC, fixture(__FILE__, "autoload_c.rb")
+define_autoload_KSAutoloadCallsRequire = -> {
+ autoload :KSAutoloadCallsRequire, "main_autoload_not_exist.rb"
+}
def check_autoload(const)
autoload? const
@@ -42,10 +44,12 @@ describe "Kernel#autoload" do
KSAutoloadB.loaded.should == :ksautoload_b
end
- it "does not call Kernel.require or Kernel.load to load the file" do
- Kernel.should_not_receive(:require)
- Kernel.should_not_receive(:load)
- KSAutoloadC.loaded.should == :ksautoload_c
+ it "calls main.require(path) to load the file" do
+ define_autoload_KSAutoloadCallsRequire.call
+ main = TOPLEVEL_BINDING.eval("self")
+ main.should_receive(:require).with("main_autoload_not_exist.rb")
+ # The constant won't be defined since require is mocked to do nothing
+ -> { KSAutoloadCallsRequire }.should raise_error(NameError)
end
it "can autoload in instance_eval" do
@@ -55,9 +59,43 @@ describe "Kernel#autoload" do
end
end
+ describe "inside a Class.new method body" do
+ # NOTE: this spec is being discussed in https://github.com/ruby/spec/pull/839
+ it "should define on the new anonymous class" do
+ cls = Class.new do
+ def go
+ autoload :Object, 'bogus'
+ autoload? :Object
+ end
+ end
+
+ cls.new.go.should == 'bogus'
+ cls.autoload?(:Object).should == 'bogus'
+ end
+ end
+
describe "when Object is frozen" do
it "raises a FrozenError before defining the constant" do
- ruby_exe(fixture(__FILE__, "autoload_frozen.rb")).should == "#{frozen_error_class} - nil"
+ ruby_exe(fixture(__FILE__, "autoload_frozen.rb")).should == "FrozenError - nil"
+ end
+ end
+
+ describe "when called from included module's method" do
+ before :all do
+ @path = fixture(__FILE__, "autoload_from_included_module.rb")
+ KernelSpecs::AutoloadMethodIncluder.new.setup_autoload(@path)
+ end
+
+ it "setups the autoload on the included module" do
+ KernelSpecs::AutoloadMethod.autoload?(:AutoloadFromIncludedModule).should == @path
+ end
+
+ it "the autoload is reachable from the class too" do
+ KernelSpecs::AutoloadMethodIncluder.autoload?(:AutoloadFromIncludedModule).should == @path
+ end
+
+ it "the autoload relative to the included module works" do
+ KernelSpecs::AutoloadMethod::AutoloadFromIncludedModule.loaded.should == :autoload_from_included_module
end
end
end
@@ -107,6 +145,25 @@ describe "Kernel.autoload" do
p.should_receive(:to_path).and_return @non_existent
Kernel.autoload :KSAutoloadAA, p
end
+
+ describe "when called from included module's method" do
+ before :all do
+ @path = fixture(__FILE__, "autoload_from_included_module2.rb")
+ KernelSpecs::AutoloadMethodIncluder2.new.setup_autoload(@path)
+ end
+
+ it "setups the autoload on the included module" do
+ KernelSpecs::AutoloadMethod2.autoload?(:AutoloadFromIncludedModule2).should == @path
+ end
+
+ it "the autoload is reachable from the class too" do
+ KernelSpecs::AutoloadMethodIncluder2.autoload?(:AutoloadFromIncludedModule2).should == @path
+ end
+
+ it "the autoload relative to the included module works" do
+ KernelSpecs::AutoloadMethod2::AutoloadFromIncludedModule2.loaded.should == :autoload_from_included_module2
+ end
+ end
end
describe "Kernel.autoload?" do
diff --git a/spec/ruby/core/kernel/backtick_spec.rb b/spec/ruby/core/kernel/backtick_spec.rb
index eb25750bc2..834d5636c1 100644
--- a/spec/ruby/core/kernel/backtick_spec.rb
+++ b/spec/ruby/core/kernel/backtick_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#`" do
before :each do
@@ -21,7 +21,7 @@ describe "Kernel#`" do
it "lets the standard error stream pass through to the inherited stderr" do
cmd = ruby_cmd('STDERR.print "error stream"')
- lambda {
+ -> {
`#{cmd}`.should == ""
}.should output_to_fd("error stream", STDERR)
end
@@ -32,24 +32,28 @@ describe "Kernel#`" do
end
it "raises an Errno::ENOENT if the command is not executable" do
- lambda { `nonexistent_command` }.should raise_error(Errno::ENOENT)
+ -> { `nonexistent_command` }.should raise_error(Errno::ENOENT)
end
platform_is_not :windows do
+ it "handles invalid UTF-8 bytes in command" do
+ `echo "testing\xC2 a non UTF-8 string"`.b.should == "testing\xC2 a non UTF-8 string\n".b
+ end
+
it "sets $? to the exit status of the executed sub-process" do
ip = 'world'
`echo disc #{ip}`
$?.should be_kind_of(Process::Status)
- $?.stopped?.should == false
- $?.exited?.should == true
+ $?.should_not.stopped?
+ $?.should.exited?
$?.exitstatus.should == 0
- $?.success?.should == true
+ $?.should.success?
`echo disc #{ip}; exit 99`
$?.should be_kind_of(Process::Status)
- $?.stopped?.should == false
- $?.exited?.should == true
+ $?.should_not.stopped?
+ $?.should.exited?
$?.exitstatus.should == 99
- $?.success?.should == false
+ $?.should_not.success?
end
end
@@ -58,16 +62,16 @@ describe "Kernel#`" do
ip = 'world'
`echo disc #{ip}`
$?.should be_kind_of(Process::Status)
- $?.stopped?.should == false
- $?.exited?.should == true
+ $?.should_not.stopped?
+ $?.should.exited?
$?.exitstatus.should == 0
- $?.success?.should == true
+ $?.should.success?
`echo disc #{ip}& exit 99`
$?.should be_kind_of(Process::Status)
- $?.stopped?.should == false
- $?.exited?.should == true
+ $?.should_not.stopped?
+ $?.should.exited?
$?.exitstatus.should == 99
- $?.success?.should == false
+ $?.should_not.success?
end
end
end
diff --git a/spec/ruby/core/kernel/binding_spec.rb b/spec/ruby/core/kernel/binding_spec.rb
index 0b33c86d3c..f1c9c6ec9f 100644
--- a/spec/ruby/core/kernel/binding_spec.rb
+++ b/spec/ruby/core/kernel/binding_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel.binding" do
it "returns a binding for the caller" do
@@ -35,7 +35,7 @@ describe "Kernel#binding" do
end
it "raises a NameError on undefined variable" do
- lambda { eval("a_fake_variable", @b1) }.should raise_error(NameError)
+ -> { eval("a_fake_variable", @b1) }.should raise_error(NameError)
end
it "uses the closure's self as self in the binding" do
diff --git a/spec/ruby/core/kernel/block_given_spec.rb b/spec/ruby/core/kernel/block_given_spec.rb
index 9454c938ae..aece4c821d 100644
--- a/spec/ruby/core/kernel/block_given_spec.rb
+++ b/spec/ruby/core/kernel/block_given_spec.rb
@@ -1,19 +1,24 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe :kernel_block_given, shared: true do
it "returns true if and only if a block is supplied" do
@object.accept_block {}.should == true
@object.accept_block_as_argument {}.should == true
+ @object.accept_block_inside_block {}.should == true
+ @object.accept_block_as_argument_inside_block {}.should == true
@object.accept_block.should == false
@object.accept_block_as_argument.should == false
+ @object.accept_block_inside_block.should == false
+ @object.accept_block_as_argument_inside_block.should == false
end
# Clarify: Based on http://www.ruby-forum.com/topic/137822 it appears
# that Matz wanted this to be true in 1.9.
it "returns false when a method defined by define_method is called with a block" do
@object.defined_block {}.should == false
+ @object.defined_block_inside_block {}.should == false
end
end
diff --git a/spec/ruby/core/kernel/caller_locations_spec.rb b/spec/ruby/core/kernel/caller_locations_spec.rb
index 69993c3ec0..a917dba504 100644
--- a/spec/ruby/core/kernel/caller_locations_spec.rb
+++ b/spec/ruby/core/kernel/caller_locations_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/caller_locations', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/caller_locations'
describe 'Kernel#caller_locations' do
it 'is a private method' do
@@ -7,13 +7,13 @@ describe 'Kernel#caller_locations' do
end
it 'returns an Array of caller locations' do
- KernelSpecs::CallerLocationsTest.locations.empty?.should == false
+ KernelSpecs::CallerLocationsTest.locations.should_not.empty?
end
it 'returns an Array of caller locations using a custom offset' do
locations = KernelSpecs::CallerLocationsTest.locations(2)
- locations[0].absolute_path.end_with?('mspec.rb').should == true
+ locations[0].absolute_path.should.end_with?('mspec.rb')
end
it 'returns an Array of caller locations using a custom limit' do
@@ -22,6 +22,42 @@ describe 'Kernel#caller_locations' do
locations.length.should == 1
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 "works with endless ranges" do
+ locations1 = caller_locations(0)
+ locations2 = caller_locations(eval("(2..)"))
+ locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s)
+ end
+
+ it "works with beginless ranges" do
+ locations1 = caller_locations(0)
+ locations2 = caller_locations((...5))
+ locations2.map(&:to_s)[eval("(2..)")].should == locations1[(...5)].map(&:to_s)[eval("(2..)")]
+ 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
locations = KernelSpecs::CallerLocationsTest.locations
@@ -29,4 +65,46 @@ describe 'Kernel#caller_locations' do
location.kind_of?(Thread::Backtrace::Location).should == true
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
+
+ guard -> { Kernel.instance_method(:tap).source_location } do
+ ruby_version_is ""..."3.4" do
+ it "includes core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
+
+ loc = nil
+ tap { loc = caller_locations(1, 1)[0] }
+ loc.label.should == "tap"
+ loc.path.should.start_with? "<internal:"
+ end
+ end
+
+ ruby_version_is "3.4"..."4.0" do
+ it "includes core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
+
+ loc = nil
+ tap { loc = caller_locations(1, 1)[0] }
+ loc.label.should == "Kernel#tap"
+ loc.path.should.start_with? "<internal:"
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "does not include core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
+
+ loc = nil
+ tap { loc = caller_locations(1, 1)[0] }
+ loc.label.should == "Kernel#tap"
+ loc.path.should == __FILE__
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/caller_spec.rb b/spec/ruby/core/kernel/caller_spec.rb
index d9be29a8db..7cd703de5a 100644
--- a/spec/ruby/core/kernel/caller_spec.rb
+++ b/spec/ruby/core/kernel/caller_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/caller', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/caller'
describe 'Kernel#caller' do
it 'is a private method' do
@@ -7,7 +7,7 @@ describe 'Kernel#caller' do
end
it 'returns an Array of caller locations' do
- KernelSpecs::CallerTest.locations.empty?.should == false
+ KernelSpecs::CallerTest.locations.should_not.empty?
end
it 'returns an Array of caller locations using a custom offset' do
@@ -34,4 +34,76 @@ describe 'Kernel#caller' do
locations[0].should include("#{__FILE__}:#{line}:in")
end
+
+ it "returns an Array with the block given to #at_exit at the base of the stack" do
+ path = fixture(__FILE__, "caller_at_exit.rb")
+ lines = ruby_exe(path).lines
+ lines.size.should == 2
+ lines[0].should =~ /\A#{path}:6:in [`'](?:Object#)?foo'\n\z/
+ lines[1].should =~ /\A#{path}:2:in [`']block in <main>'\n\z/
+ end
+
+ it "can be called with a range" do
+ locations1 = caller(0)
+ locations2 = caller(2..4)
+ locations1[2..4].should == locations2
+ end
+
+ it "works with endless ranges" do
+ locations1 = KernelSpecs::CallerTest.locations(0)
+ locations2 = KernelSpecs::CallerTest.locations(eval("(2..)"))
+ locations2.should == locations1[2..-1]
+ end
+
+ it "works with beginless ranges" do
+ locations1 = KernelSpecs::CallerTest.locations(0)
+ locations2 = KernelSpecs::CallerTest.locations((..5))
+ locations2[eval("(2..)")].should == locations1[(..5)][eval("(2..)")]
+ end
+
+ it "can be called with a range whose end is negative" do
+ locations1 = caller(0)
+ locations2 = caller(2..-1)
+ locations3 = caller(2..-2)
+ locations1[2..-1].should == locations2
+ locations1[2..-2].should == locations3
+ end
+
+ it "must return nil if omitting more locations than available" do
+ caller(100).should == nil
+ caller(100..-1).should == nil
+ end
+
+ it "must return [] if omitting exactly the number of locations available" do
+ omit = caller(0).length
+ caller(omit).should == []
+ end
+
+ it "must return the same locations when called with 1..-1 and when called with no arguments" do
+ caller.should == caller(1..-1)
+ end
+
+ guard -> { Kernel.instance_method(:tap).source_location } do
+ ruby_version_is ""..."4.0" do
+ it "includes core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
+
+ loc = nil
+ tap { loc = caller(1, 1)[0] }
+ loc.should =~ /\A<internal:.*in [`'](?:Kernel#)?tap'\z/
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "includes core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
+
+ loc = nil
+ tap { loc = caller(1, 1)[0] }
+ loc.should =~ /\A#{ __FILE__ }:.*in [`'](?:Kernel#)?tap'\z/
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/case_compare_spec.rb b/spec/ruby/core/kernel/case_compare_spec.rb
index 5332aa7647..b8d30960e8 100644
--- a/spec/ruby/core/kernel/case_compare_spec.rb
+++ b/spec/ruby/core/kernel/case_compare_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
module Specs
diff --git a/spec/ruby/core/kernel/catch_spec.rb b/spec/ruby/core/kernel/catch_spec.rb
index 35a4860f38..9f59d3b384 100644
--- a/spec/ruby/core/kernel/catch_spec.rb
+++ b/spec/ruby/core/kernel/catch_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel.catch" do
before :each do
@@ -31,11 +31,11 @@ describe "Kernel.catch" do
end
it "raises an ArgumentError if a Symbol is thrown for a String catch value" do
- lambda { catch("exit") { throw :exit } }.should raise_error(ArgumentError)
+ -> { catch("exit") { throw :exit } }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if a String with different identity is thrown" do
- lambda { catch("exit") { throw "exit" } }.should raise_error(ArgumentError)
+ -> { catch("exit".dup) { throw "exit".dup } }.should raise_error(ArgumentError)
end
it "catches a Symbol when thrown a matching Symbol" do
@@ -116,7 +116,7 @@ describe "Kernel.catch" do
end
it "raises LocalJumpError if no block is given" do
- lambda { catch :blah }.should raise_error(LocalJumpError)
+ -> { catch :blah }.should raise_error(LocalJumpError)
end
end
diff --git a/spec/ruby/core/kernel/chomp_spec.rb b/spec/ruby/core/kernel/chomp_spec.rb
index 524a4c8b1d..d30e77c35a 100644
--- a/spec/ruby/core/kernel/chomp_spec.rb
+++ b/spec/ruby/core/kernel/chomp_spec.rb
@@ -1,6 +1,6 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe :kernel_chomp, shared: true do
it "removes the final newline of $_" do
@@ -40,28 +40,26 @@ describe "Kernel#chomp" do
it_behaves_like :kernel_chomp_private, :chomp
end
-with_feature :encoding do
- describe :kernel_chomp_encoded, shared: true do
- before :each do
- @external = Encoding.default_external
- Encoding.default_external = Encoding::UTF_8
- end
-
- after :each do
- Encoding.default_external = @external
- end
-
- it "removes the final carriage return, newline from a multi-byte $_" do
- script = fixture __FILE__, "#{@method}.rb"
- KernelSpecs.run_with_dash_n(script).should == "あれ"
- end
+describe :kernel_chomp_encoded, shared: true do
+ before :each do
+ @external = Encoding.default_external
+ Encoding.default_external = Encoding::UTF_8
end
- describe "Kernel.chomp" do
- it_behaves_like :kernel_chomp_encoded, "chomp"
+ after :each do
+ Encoding.default_external = @external
end
- describe "Kernel#chomp" do
- it_behaves_like :kernel_chomp_encoded, "chomp_f"
+ it "removes the final carriage return, newline from a multi-byte $_" do
+ script = fixture __FILE__, "#{@method}.rb"
+ KernelSpecs.run_with_dash_n(script).should == "あれ"
end
end
+
+describe "Kernel.chomp" do
+ it_behaves_like :kernel_chomp_encoded, "chomp"
+end
+
+describe "Kernel#chomp" do
+ it_behaves_like :kernel_chomp_encoded, "chomp_f"
+end
diff --git a/spec/ruby/core/kernel/chop_spec.rb b/spec/ruby/core/kernel/chop_spec.rb
index 5106fefee8..9b91c011bc 100644
--- a/spec/ruby/core/kernel/chop_spec.rb
+++ b/spec/ruby/core/kernel/chop_spec.rb
@@ -1,6 +1,6 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe :kernel_chop, shared: true do
it "removes the final character of $_" do
@@ -28,28 +28,26 @@ describe "Kernel#chop" do
it_behaves_like :kernel_chop, "chop"
end
-with_feature :encoding do
- describe :kernel_chop_encoded, shared: true do
- before :each do
- @external = Encoding.default_external
- Encoding.default_external = Encoding::UTF_8
- end
-
- after :each do
- Encoding.default_external = @external
- end
-
- it "removes the final multi-byte character from $_" do
- script = fixture __FILE__, "#{@method}.rb"
- KernelSpecs.run_with_dash_n(script).should == "あ"
- end
+describe :kernel_chop_encoded, shared: true do
+ before :each do
+ @external = Encoding.default_external
+ Encoding.default_external = Encoding::UTF_8
end
- describe "Kernel.chop" do
- it_behaves_like :kernel_chop_encoded, "chop"
+ after :each do
+ Encoding.default_external = @external
end
- describe "Kernel#chop" do
- it_behaves_like :kernel_chop_encoded, "chop_f"
+ it "removes the final multi-byte character from $_" do
+ script = fixture __FILE__, "#{@method}.rb"
+ KernelSpecs.run_with_dash_n(script).should == "あ"
end
end
+
+describe "Kernel.chop" do
+ it_behaves_like :kernel_chop_encoded, "chop"
+end
+
+describe "Kernel#chop" do
+ it_behaves_like :kernel_chop_encoded, "chop_f"
+end
diff --git a/spec/ruby/core/kernel/class_spec.rb b/spec/ruby/core/kernel/class_spec.rb
index 0d7b40c366..b1d9df1671 100644
--- a/spec/ruby/core/kernel/class_spec.rb
+++ b/spec/ruby/core/kernel/class_spec.rb
@@ -1,11 +1,11 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#class" do
it "returns the class of the object" do
Object.new.class.should equal(Object)
- 1.class.should equal(Fixnum)
+ 1.class.should equal(Integer)
3.14.class.should equal(Float)
:hello.class.should equal(Symbol)
"hello".class.should equal(String)
@@ -19,7 +19,7 @@ describe "Kernel#class" do
end
it "returns the first non-singleton class" do
- a = "hello"
+ a = +"hello"
def a.my_singleton_method; end
a.class.should equal(String)
end
diff --git a/spec/ruby/core/kernel/clone_spec.rb b/spec/ruby/core/kernel/clone_spec.rb
index 48b3c24c7f..5adcbbe603 100644
--- a/spec/ruby/core/kernel/clone_spec.rb
+++ b/spec/ruby/core/kernel/clone_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../shared/dup_clone', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/dup_clone'
describe "Kernel#clone" do
it_behaves_like :kernel_dup_clone, :clone
@@ -28,22 +28,87 @@ describe "Kernel#clone" do
clone.class.should equal klass
end
- it "copies frozen state from the original" do
- o2 = @obj.clone
- @obj.freeze
- o3 = @obj.clone
+ describe "with no arguments" do
+ it "copies frozen state from the original" do
+ o2 = @obj.clone
+ o2.should_not.frozen?
- o2.frozen?.should == false
- o3.frozen?.should == true
+ @obj.freeze
+ o3 = @obj.clone
+ o3.should.frozen?
+ end
+
+ it 'copies frozen?' do
+ o = ''.freeze.clone
+ o.frozen?.should be_true
+ end
+ end
+
+ describe "with freeze: nil" do
+ it "copies frozen state from the original, like #clone without arguments" do
+ o2 = @obj.clone(freeze: nil)
+ o2.should_not.frozen?
+
+ @obj.freeze
+ o3 = @obj.clone(freeze: nil)
+ o3.should.frozen?
+ end
+
+ it "copies frozen?" do
+ o = "".freeze.clone(freeze: nil)
+ o.frozen?.should be_true
+ end
+ end
+
+ describe "with freeze: true" do
+ it 'makes a frozen copy if the original is frozen' do
+ @obj.freeze
+ @obj.clone(freeze: true).should.frozen?
+ end
+
+ it 'freezes the copy even if the original was not frozen' do
+ @obj.clone(freeze: true).should.frozen?
+ end
+
+ it "calls #initialize_clone with kwargs freeze: true" do
+ obj = KernelSpecs::CloneFreeze.new
+ obj.clone(freeze: true)
+ ScratchPad.recorded.should == [obj, { freeze: true }]
+ end
+
+ it "calls #initialize_clone with kwargs freeze: true even if #initialize_clone only takes a single argument" do
+ obj = KernelSpecs::Clone.new
+ -> { obj.clone(freeze: true) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
+ end
end
- ruby_version_is '2.4' do
- it 'takes an option to copy freeze state or not' do
- @obj.clone(freeze: true).frozen?.should == false
- @obj.clone(freeze: false).frozen?.should == false
+ describe "with freeze: false" do
+ it 'does not freeze the copy if the original is frozen' do
@obj.freeze
- @obj.clone(freeze: true).frozen?.should == true
- @obj.clone(freeze: false).frozen?.should == false
+ @obj.clone(freeze: false).should_not.frozen?
+ end
+
+ it 'does not freeze the copy if the original is not frozen' do
+ @obj.clone(freeze: false).should_not.frozen?
+ end
+
+ it "calls #initialize_clone with kwargs freeze: false" do
+ obj = KernelSpecs::CloneFreeze.new
+ obj.clone(freeze: false)
+ ScratchPad.recorded.should == [obj, { freeze: false }]
+ end
+
+ it "calls #initialize_clone with kwargs freeze: false even if #initialize_clone only takes a single argument" do
+ obj = KernelSpecs::Clone.new
+ -> { obj.clone(freeze: false) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
+ end
+ end
+
+ describe "with freeze: anything else" do
+ it 'raises ArgumentError when passed not true/false/nil' do
+ -> { @obj.clone(freeze: 1) }.should raise_error(ArgumentError, /unexpected value for freeze: Integer/)
+ -> { @obj.clone(freeze: "") }.should raise_error(ArgumentError, /unexpected value for freeze: String/)
+ -> { @obj.clone(freeze: Object.new) }.should raise_error(ArgumentError, /unexpected value for freeze: Object/)
end
end
@@ -109,10 +174,4 @@ describe "Kernel#clone" do
cloned.bar.should == ['a']
end
-
- it 'copies frozen? and tainted?' do
- o = ''.taint.freeze.clone
- o.frozen?.should be_true
- o.tainted?.should be_true
- end
end
diff --git a/spec/ruby/core/kernel/comparison_spec.rb b/spec/ruby/core/kernel/comparison_spec.rb
index 2aa4358600..affdc5c00d 100644
--- a/spec/ruby/core/kernel/comparison_spec.rb
+++ b/spec/ruby/core/kernel/comparison_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Kernel#<=>" do
it "returns 0 if self" do
diff --git a/spec/ruby/core/kernel/define_singleton_method_spec.rb b/spec/ruby/core/kernel/define_singleton_method_spec.rb
index de6f7fc286..24acec84f5 100644
--- a/spec/ruby/core/kernel/define_singleton_method_spec.rb
+++ b/spec/ruby/core/kernel/define_singleton_method_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#define_singleton_method" do
describe "when given an UnboundMethod" do
@@ -21,7 +21,7 @@ describe "Kernel#define_singleton_method" do
um = KernelSpecs::Parent.method(:parent_class_method).unbind
KernelSpecs::Child.send :define_singleton_method, :child_class_method, um
KernelSpecs::Child.child_class_method.should == :foo
- lambda{KernelSpecs::Parent.child_class_method}.should raise_error(NoMethodError)
+ ->{KernelSpecs::Parent.child_class_method}.should raise_error(NoMethodError)
end
it "will raise when attempting to define an object's singleton method from another object's singleton method" do
@@ -33,7 +33,7 @@ describe "Kernel#define_singleton_method" do
end
end
um = p.method(:singleton_method).unbind
- lambda{ other.send :define_singleton_method, :other_singleton_method, um }.should raise_error(TypeError)
+ ->{ other.send :define_singleton_method, :other_singleton_method, um }.should raise_error(TypeError)
end
end
@@ -41,7 +41,7 @@ describe "Kernel#define_singleton_method" do
it "defines a new method with the given name and the given block as body in self" do
class DefineSingletonMethodSpecClass
define_singleton_method(:block_test1) { self }
- define_singleton_method(:block_test2, &lambda { self })
+ define_singleton_method(:block_test2, &-> { self })
end
o = DefineSingletonMethodSpecClass
@@ -50,11 +50,11 @@ describe "Kernel#define_singleton_method" do
end
it "raises a TypeError when the given method is no Method/Proc" do
- lambda {
+ -> {
Class.new { define_singleton_method(:test, "self") }
}.should raise_error(TypeError)
- lambda {
+ -> {
Class.new { define_singleton_method(:test, 1234) }
}.should raise_error(TypeError)
end
@@ -63,7 +63,7 @@ describe "Kernel#define_singleton_method" do
obj = Object.new
obj.define_singleton_method(:test) { "world!" }
obj.test.should == "world!"
- lambda {
+ -> {
Object.new.test
}.should raise_error(NoMethodError)
end
@@ -81,21 +81,40 @@ describe "Kernel#define_singleton_method" do
it "raises an ArgumentError when no block is given" do
obj = Object.new
- lambda {
+ -> {
obj.define_singleton_method(:test)
}.should raise_error(ArgumentError)
end
- ruby_version_is "2.3" do
- it "does not use the caller block when no block is given" do
- o = Object.new
- def o.define(name)
- define_singleton_method(name)
- end
+ it "does not use the caller block when no block is given" do
+ o = Object.new
+ def o.define(name)
+ define_singleton_method(name)
+ end
+
+ -> {
+ o.define(:foo) { raise "not used" }
+ }.should raise_error(ArgumentError)
+ end
- lambda {
- o.define(:foo) { raise "not used" }
- }.should raise_error(ArgumentError)
+ it "always defines the method with public visibility" do
+ cls = Class.new
+ def cls.define(name, &block)
+ private
+ define_singleton_method(name, &block)
end
+
+ -> {
+ suppress_warning do
+ cls.define(:foo) { :ok }
+ end
+ cls.foo.should == :ok
+ }.should_not raise_error(NoMethodError)
+ end
+
+ it "cannot define a singleton method with a frozen singleton class" do
+ o = Object.new
+ o.freeze
+ -> { o.define_singleton_method(:foo) { 1 } }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/kernel/display_spec.rb b/spec/ruby/core/kernel/display_spec.rb
index e771e14cdb..9d429a9fac 100644
--- a/spec/ruby/core/kernel/display_spec.rb
+++ b/spec/ruby/core/kernel/display_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#display" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/kernel/dup_spec.rb b/spec/ruby/core/kernel/dup_spec.rb
index af7e924a66..70198abdb7 100644
--- a/spec/ruby/core/kernel/dup_spec.rb
+++ b/spec/ruby/core/kernel/dup_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../shared/dup_clone', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/dup_clone'
describe "Kernel#dup" do
it_behaves_like :kernel_dup_clone, :dup
@@ -32,7 +32,7 @@ describe "Kernel#dup" do
@obj.freeze
dup = @obj.dup
- dup.frozen?.should == false
+ dup.should_not.frozen?
end
it "copies instance variables" do
@@ -44,7 +44,7 @@ describe "Kernel#dup" do
it "does not copy singleton methods" do
def @obj.special() :the_one end
dup = @obj.dup
- lambda { dup.special }.should raise_error(NameError)
+ -> { dup.special }.should raise_error(NameError)
end
it "does not copy modules included in the singleton class" do
@@ -53,7 +53,7 @@ describe "Kernel#dup" do
end
dup = @obj.dup
- lambda { dup.repr }.should raise_error(NameError)
+ -> { dup.repr }.should raise_error(NameError)
end
it "does not copy constants defined in the singleton class" do
@@ -62,6 +62,6 @@ describe "Kernel#dup" do
end
dup = @obj.dup
- lambda { class << dup; CLONE; end }.should raise_error(NameError)
+ -> { class << dup; CLONE; end }.should raise_error(NameError)
end
end
diff --git a/spec/ruby/core/kernel/enum_for_spec.rb b/spec/ruby/core/kernel/enum_for_spec.rb
index 819140e0e4..0092e20468 100644
--- a/spec/ruby/core/kernel/enum_for_spec.rb
+++ b/spec/ruby/core/kernel/enum_for_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Kernel#enum_for" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/kernel/eql_spec.rb b/spec/ruby/core/kernel/eql_spec.rb
index 39c9fea7eb..e62a601a79 100644
--- a/spec/ruby/core/kernel/eql_spec.rb
+++ b/spec/ruby/core/kernel/eql_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../../../shared/kernel/equal', __FILE__)
+require_relative '../../spec_helper'
+require_relative '../../shared/kernel/equal'
describe "Kernel#eql?" do
it "is a public instance method" do
@@ -8,4 +8,3 @@ describe "Kernel#eql?" do
it_behaves_like :object_equal, :eql?
end
-
diff --git a/spec/ruby/core/kernel/equal_value_spec.rb b/spec/ruby/core/kernel/equal_value_spec.rb
index a66493f283..2be151263d 100644
--- a/spec/ruby/core/kernel/equal_value_spec.rb
+++ b/spec/ruby/core/kernel/equal_value_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#==" do
it "returns true only if obj and other are the same object" do
diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb
index 96fc0f5b71..e027294347 100644
--- a/spec/ruby/core/kernel/eval_spec.rb
+++ b/spec/ruby/core/kernel/eval_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
EvalSpecs::A.new.c
@@ -24,7 +24,7 @@ describe "Kernel#eval" do
EvalSpecs::A::B.name.should == "EvalSpecs::A::B"
end
- it "evaluates such that consts are scoped to the class of the eval" do
+ it "evaluates such that constants are scoped to the class of the eval" do
EvalSpecs::A::C.name.should == "EvalSpecs::A::C"
end
@@ -76,12 +76,12 @@ describe "Kernel#eval" do
x = 1
bind = proc {}
- lambda { eval("x", bind) }.should raise_error(TypeError)
+ -> { eval("x", bind) }.should raise_error(TypeError)
end
it "does not make Proc locals visible to evaluated code" do
bind = proc { inner = 4 }
- lambda { eval("inner", bind.binding) }.should raise_error(NameError)
+ -> { eval("inner", bind.binding) }.should raise_error(NameError)
end
# REWRITE ME: This obscures the real behavior of where locals are stored
@@ -134,8 +134,8 @@ describe "Kernel#eval" do
it "includes file and line information in syntax error" do
expected = 'speccing.rb'
- lambda {
- eval('if true',TOPLEVEL_BINDING, expected)
+ -> {
+ eval('if true', TOPLEVEL_BINDING, expected)
}.should raise_error(SyntaxError) { |e|
e.message.should =~ /#{expected}:1:.+/
}
@@ -143,8 +143,8 @@ describe "Kernel#eval" do
it "evaluates string with given filename and negative linenumber" do
expected_file = 'speccing.rb'
- lambda {
- eval('if true',TOPLEVEL_BINDING, expected_file, -100)
+ -> {
+ eval('if true', TOPLEVEL_BINDING, expected_file, -100)
}.should raise_error(SyntaxError) { |e|
e.message.should =~ /#{expected_file}:-100:.+/
}
@@ -159,15 +159,106 @@ describe "Kernel#eval" do
end
end
- it "uses the filename of the binding if none is provided" do
- eval("__FILE__").should == "(eval)"
- eval("__FILE__", binding).should == __FILE__
- eval("__FILE__", binding, "success").should == "success"
- eval("eval '__FILE__', binding").should == "(eval)"
- eval("eval '__FILE__', binding", binding).should == __FILE__
- eval("eval '__FILE__', binding", binding, 'success').should == 'success'
+ ruby_version_is ""..."3.3" do
+ it "uses (eval) filename if none is provided" do
+ eval("__FILE__").should == "(eval)"
+ eval("__FILE__", binding).should == "(eval)"
+ eval("__FILE__", binding, "success").should == "success"
+ eval("eval '__FILE__', binding").should == "(eval)"
+ eval("eval '__FILE__', binding", binding).should == "(eval)"
+ eval("eval '__FILE__', binding", binding, 'success').should == '(eval)'
+ eval("eval '__FILE__', binding, 'success'", binding).should == 'success'
+ end
+
+ it 'uses (eval) for __FILE__ and 1 for __LINE__ with a binding argument' do
+ eval("[__FILE__, __LINE__]", binding).should == ["(eval)", 1]
+ end
end
+ context "parameter forwarding" do
+ it "allows anonymous rest parameter forwarding" do
+ object = Object.new
+ def object.foo(a, b, c)
+ [a, b, c]
+ end
+ def object.bar(*)
+ eval "foo(*)"
+ end
+
+ object.bar(1, 2, 3).should == [1, 2, 3]
+ end
+
+ it "allows anonymous keyword parameters forwarding" do
+ object = Object.new
+ def object.foo(a:, b:, c:)
+ [a, b, c]
+ end
+ def object.bar(**)
+ eval "foo(**)"
+ end
+
+ object.bar(a: 1, b: 2, c: 3).should == [1, 2, 3]
+ end
+
+ it "allows anonymous block parameter forwarding" do
+ object = Object.new
+ def object.foo(&block)
+ block.call
+ end
+ def object.bar(&)
+ eval "foo(&)"
+ end
+
+ object.bar { :foobar }.should == :foobar
+ end
+
+ it "allows ... forwarding" do
+ object = Object.new
+ def object.foo(a, b:, &block)
+ [a, b, block.call]
+ end
+ def object.bar(...)
+ eval "foo(...)"
+ end
+
+ object.bar(1, b: 2) { 3 }.should == [1, 2, 3]
+ end
+
+ it "allows parameter forwarding to super" do
+ m = Module.new do
+ def foo(a, b:, &block)
+ [a, b, block.call]
+ end
+ end
+
+ c = Class.new do
+ include m
+
+ def foo(a, b:, &block)
+ eval "super"
+ end
+ end
+
+ object = c.new
+ object.foo(1, b: 2) { 3 }.should == [1, 2, 3]
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "uses (eval at __FILE__:__LINE__) if none is provided" do
+ eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})"
+ eval("__FILE__", binding).should == "(eval at #{__FILE__}:#{__LINE__})"
+ eval("__FILE__", binding, "success").should == "success"
+ eval("eval '__FILE__', binding").should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)"
+ eval("eval '__FILE__', binding", binding).should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)"
+ eval("eval '__FILE__', binding", binding, 'success').should == "(eval at success:1)"
+ eval("eval '__FILE__', binding, 'success'", binding).should == 'success'
+ end
+
+ it 'uses (eval at __FILE__:__LINE__) for __FILE__ and 1 for __LINE__ with a binding argument' do
+ eval("[__FILE__, __LINE__]", binding).should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
+ end
+ end
# Found via Rubinius bug github:#149
it "does not alter the value of __FILE__ in the binding" do
first_time = EvalSpecs.call_eval
@@ -195,13 +286,27 @@ describe "Kernel#eval" do
end
it "does not pass the block to the method being eval'ed" do
- lambda {
+ -> {
eval('KernelSpecs::EvalTest.call_yield') { "content" }
}.should raise_error(LocalJumpError)
end
it "returns from the scope calling #eval when evaluating 'return'" do
- lambda { eval("return :eval") }.call.should == :eval
+ -> { eval("return :eval") }.call.should == :eval
+ end
+
+ it "returns from the method calling #eval when evaluating 'return'" do
+ def eval_return(n)
+ eval("return n*2")
+ end
+ -> { eval_return(3) }.call.should == 6
+ end
+
+ it "returns from the method calling #eval when evaluating 'return' in BEGIN" do
+ def eval_return(n)
+ eval("BEGIN {return n*3}")
+ end
+ -> { eval_return(4) }.call.should == 12
end
it "unwinds through a Proc-style closure and returns from a lambda-style closure in the closure chain" do
@@ -213,4 +318,253 @@ describe "Kernel#eval" do
code = fixture __FILE__, "eval_return_without_lambda.rb"
ruby_exe(code).chomp.should == "a,b,c,e,LocalJumpError,f"
end
+
+ it "can be called with Method#call" do
+ method(:eval).call("2 * 3").should == 6
+ end
+
+ it "has the correct default definee when called through Method#call" do
+ class EvalSpecs
+ method(:eval).call("def eval_spec_method_call; end")
+ EvalSpecs.should have_instance_method(:eval_spec_method_call)
+ end
+ end
+
+ it "makes flip-flop operator work correctly" do
+ ScratchPad.record []
+
+ eval "10.times { |i| ScratchPad << i if (i == 4)...(i == 4) }"
+ ScratchPad.recorded.should == [4, 5, 6, 7, 8, 9]
+
+ ScratchPad.clear
+ end
+
+ it "returns nil if given an empty string" do
+ eval("").should == nil
+ end
+
+ context "with shebang" do
+ it "ignores shebang with ruby interpreter" do
+ pid = eval(<<~CODE.b)
+ #!/usr/bin/env ruby
+ Process.pid
+ CODE
+
+ pid.should == Process.pid
+ end
+
+ it "ignores shebang with non-ruby interpreter" do
+ pid = eval(<<~CODE.b)
+ #!/usr/bin/env puma
+ Process.pid
+ CODE
+
+ pid.should == Process.pid
+ end
+ end
+
+ # See language/magic_comment_spec.rb for more magic comments specs
+ describe "with a magic encoding comment" do
+ it "uses the magic comment encoding for the encoding of literal strings" do
+ code = "# encoding: UTF-8\n'é'.encoding".b
+ code.encoding.should == Encoding::BINARY
+ eval(code).should == Encoding::UTF_8
+ end
+
+ it "uses the magic comment encoding for parsing constants" do
+ code = <<CODE.b
+# encoding: UTF-8
+class EvalSpecs
+ Vπ = 3.14
+end
+CODE
+ code.encoding.should == Encoding::BINARY
+ eval(code)
+ EvalSpecs.constants(false).should include(:"Vπ")
+ EvalSpecs::Vπ.should == 3.14
+ ensure
+ EvalSpecs.send(:remove_const, :Vπ)
+ end
+
+ it "allows an emacs-style magic comment encoding" do
+ code = <<CODE.b
+# -*- encoding: UTF-8 -*-
+class EvalSpecs
+Vπemacs = 3.14
+end
+CODE
+ code.encoding.should == Encoding::BINARY
+ eval(code)
+ EvalSpecs.constants(false).should include(:"Vπemacs")
+ EvalSpecs::Vπemacs.should == 3.14
+ ensure
+ EvalSpecs.send(:remove_const, :Vπemacs)
+ end
+
+ it "allows spaces before the magic encoding comment" do
+ code = <<CODE.b
+\t \t # encoding: UTF-8
+class EvalSpecs
+ Vπspaces = 3.14
+end
+CODE
+ code.encoding.should == Encoding::BINARY
+ eval(code)
+ EvalSpecs.constants(false).should include(:"Vπspaces")
+ EvalSpecs::Vπspaces.should == 3.14
+ ensure
+ EvalSpecs.send(:remove_const, :Vπspaces)
+ end
+
+ it "allows a shebang line before the magic encoding comment" do
+ code = <<CODE.b
+#!/usr/bin/env ruby
+# encoding: UTF-8
+class EvalSpecs
+ Vπshebang = 3.14
+end
+CODE
+ code.encoding.should == Encoding::BINARY
+ eval(code)
+ EvalSpecs.constants(false).should include(:"Vπshebang")
+ EvalSpecs::Vπshebang.should == 3.14
+ ensure
+ EvalSpecs.send(:remove_const, :Vπshebang)
+ end
+
+ it "allows a shebang line and some spaces before the magic encoding comment" do
+ code = <<CODE.b
+#!/usr/bin/env ruby
+ # encoding: UTF-8
+class EvalSpecs
+ Vπshebang_spaces = 3.14
+end
+CODE
+ code.encoding.should == Encoding::BINARY
+ eval(code)
+ EvalSpecs.constants(false).should include(:"Vπshebang_spaces")
+ EvalSpecs::Vπshebang_spaces.should == 3.14
+ ensure
+ EvalSpecs.send(:remove_const, :Vπshebang_spaces)
+ end
+
+ it "allows a magic encoding comment and a subsequent frozen_string_literal magic comment" do
+ frozen_string_default = "test".frozen?
+
+ code = <<CODE.b
+# encoding: UTF-8
+# frozen_string_literal: #{!frozen_string_default}
+class EvalSpecs
+ Vπstring = "frozen"
+end
+CODE
+ code.encoding.should == Encoding::BINARY
+ eval(code)
+ EvalSpecs.constants(false).should include(:"Vπstring")
+ EvalSpecs::Vπstring.should == "frozen"
+ EvalSpecs::Vπstring.encoding.should == Encoding::UTF_8
+ EvalSpecs::Vπstring.frozen?.should == !frozen_string_default
+ ensure
+ EvalSpecs.send(:remove_const, :Vπstring)
+ end
+
+ it "allows a magic encoding comment and a frozen_string_literal magic comment on the same line in emacs style" do
+ code = <<CODE.b
+# -*- encoding: UTF-8; frozen_string_literal: true -*-
+class EvalSpecs
+Vπsame_line = "frozen"
+end
+CODE
+ code.encoding.should == Encoding::BINARY
+ eval(code)
+ EvalSpecs.constants(false).should include(:"Vπsame_line")
+ EvalSpecs::Vπsame_line.should == "frozen"
+ EvalSpecs::Vπsame_line.encoding.should == Encoding::UTF_8
+ EvalSpecs::Vπsame_line.frozen?.should be_true
+ ensure
+ EvalSpecs.send(:remove_const, :Vπsame_line)
+ end
+
+ it "ignores the magic encoding comment if it is after a frozen_string_literal magic comment" do
+ frozen_string_default = "test".frozen?
+ code = <<CODE.b
+# frozen_string_literal: #{!frozen_string_default}
+# encoding: UTF-8
+class EvalSpecs
+ Vπfrozen_first = "frozen"
+end
+CODE
+ code.encoding.should == Encoding::BINARY
+ eval(code)
+ EvalSpecs.constants(false).should_not include(:"Vπfrozen_first")
+ binary_constant = "Vπfrozen_first".b.to_sym
+ EvalSpecs.constants(false).should include(binary_constant)
+ value = EvalSpecs.const_get(binary_constant)
+ value.should == "frozen"
+ value.encoding.should == Encoding::BINARY
+ value.frozen?.should == !frozen_string_default
+ ensure
+ EvalSpecs.send(:remove_const, binary_constant)
+ end
+
+ it "ignores the frozen_string_literal magic comment if it appears after a token and warns if $VERBOSE is true" do
+ frozen_string_default = "test".frozen?
+ code = <<CODE
+some_token_before_magic_comment = :anything
+# frozen_string_literal: #{!frozen_string_default}
+class EvalSpecs
+ Vπstring_not_frozen = "not frozen"
+end
+CODE
+ -> { eval(code) }.should complain(/warning: [`']frozen_string_literal' is ignored after any tokens/, verbose: true)
+ EvalSpecs::Vπstring_not_frozen.frozen?.should == frozen_string_default
+ EvalSpecs.send :remove_const, :Vπstring_not_frozen
+
+ -> { eval(code) }.should_not complain(verbose: false)
+ EvalSpecs::Vπstring_not_frozen.frozen?.should == frozen_string_default
+ EvalSpecs.send :remove_const, :Vπstring_not_frozen
+ end
+ end
+
+ describe 'with refinements' do
+ it "activates refinements from the eval scope" do
+ refinery = Module.new do
+ refine EvalSpecs::A do
+ def foo
+ "bar"
+ end
+ end
+ end
+
+ result = nil
+
+ Module.new do
+ using refinery
+
+ result = eval "EvalSpecs::A.new.foo"
+ end
+
+ result.should == "bar"
+ end
+
+ it "activates refinements from the binding" do
+ refinery = Module.new do
+ refine EvalSpecs::A do
+ def foo
+ "bar"
+ end
+ end
+ end
+
+ b = nil
+ m = Module.new do
+ using refinery
+ b = binding
+ end
+
+ result = eval "EvalSpecs::A.new.foo", b
+
+ result.should == "bar"
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/exec_spec.rb b/spec/ruby/core/kernel/exec_spec.rb
index 3a7b656914..3d9520ad67 100644
--- a/spec/ruby/core/kernel/exec_spec.rb
+++ b/spec/ruby/core/kernel/exec_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#exec" do
it "is a private method" do
@@ -7,12 +7,12 @@ describe "Kernel#exec" do
end
it "runs the specified command, replacing current process" do
- ruby_exe('exec "echo hello"; puts "fail"', escape: true).should == "hello\n"
+ ruby_exe('exec "echo hello"; puts "fail"').should == "hello\n"
end
end
describe "Kernel.exec" do
it "runs the specified command, replacing current process" do
- ruby_exe('Kernel.exec "echo hello"; puts "fail"', escape: true).should == "hello\n"
+ ruby_exe('Kernel.exec "echo hello"; puts "fail"').should == "hello\n"
end
end
diff --git a/spec/ruby/core/kernel/exit_spec.rb b/spec/ruby/core/kernel/exit_spec.rb
index 61a6670cfd..93cec3fee5 100644
--- a/spec/ruby/core/kernel/exit_spec.rb
+++ b/spec/ruby/core/kernel/exit_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../../../shared/process/exit', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative '../../shared/process/exit'
describe "Kernel#exit" do
it "is a private method" do
@@ -10,6 +10,10 @@ describe "Kernel#exit" do
it_behaves_like :process_exit, :exit, KernelSpecs::Method.new
end
+describe "Kernel.exit" do
+ it_behaves_like :process_exit, :exit, Kernel
+end
+
describe "Kernel#exit!" do
it "is a private method" do
Kernel.should have_private_instance_method(:exit!)
@@ -18,10 +22,6 @@ describe "Kernel#exit!" do
it_behaves_like :process_exit!, :exit!, "self"
end
-describe "Kernel.exit" do
- it_behaves_like :process_exit, :exit, Kernel
-end
-
describe "Kernel.exit!" do
- it_behaves_like :process_exit!, :exit!, Kernel
+ it_behaves_like :process_exit!, :exit!, "Kernel"
end
diff --git a/spec/ruby/core/kernel/extend_spec.rb b/spec/ruby/core/kernel/extend_spec.rb
index 482eef32e9..6342d8cae1 100644
--- a/spec/ruby/core/kernel/extend_spec.rb
+++ b/spec/ruby/core/kernel/extend_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
module KernelSpecs::M
def self.extend_object(o)
@@ -46,20 +46,20 @@ describe "Kernel#extend" do
end
it "makes the class a kind_of? the argument" do
- class C
+ c = Class.new do
extend KernelSpecs::M
end
- (C.kind_of? KernelSpecs::M).should == true
+ (c.kind_of? KernelSpecs::M).should == true
end
it "raises an ArgumentError when no arguments given" do
- lambda { Object.new.extend }.should raise_error(ArgumentError)
+ -> { Object.new.extend }.should raise_error(ArgumentError)
end
it "raises a TypeError when the argument is not a Module" do
o = mock('o')
klass = Class.new
- lambda { o.extend(klass) }.should raise_error(TypeError)
+ -> { o.extend(klass) }.should raise_error(TypeError)
end
describe "on frozen instance" do
@@ -69,11 +69,23 @@ describe "Kernel#extend" do
end
it "raises an ArgumentError when no arguments given" do
- lambda { @frozen.extend }.should raise_error(ArgumentError)
+ -> { @frozen.extend }.should raise_error(ArgumentError)
end
- it "raises a RuntimeError" do
- lambda { @frozen.extend @module }.should raise_error(RuntimeError)
+ it "raises a FrozenError" do
+ -> { @frozen.extend @module }.should raise_error(FrozenError)
end
end
+
+ it "updated class methods of a module when it extends self and includes another module" do
+ a = Module.new do
+ extend self
+ end
+ b = Module.new do
+ def foo; :foo; end
+ end
+
+ a.include b
+ a.foo.should == :foo
+ end
end
diff --git a/spec/ruby/core/kernel/fail_spec.rb b/spec/ruby/core/kernel/fail_spec.rb
index 9f3601c233..fab622037e 100644
--- a/spec/ruby/core/kernel/fail_spec.rb
+++ b/spec/ruby/core/kernel/fail_spec.rb
@@ -1,31 +1,30 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
-describe "Kernel.fail" do
+describe "Kernel#fail" do
it "is a private method" do
Kernel.should have_private_instance_method(:fail)
end
it "raises a RuntimeError" do
- lambda { fail }.should raise_error(RuntimeError)
+ -> { fail }.should raise_error(RuntimeError)
end
it "accepts an Object with an exception method returning an Exception" do
- class Boring
- def self.exception(msg)
- StandardError.new msg
- end
+ obj = Object.new
+ def obj.exception(msg)
+ StandardError.new msg
end
- lambda { fail Boring, "..." }.should raise_error(StandardError)
+ -> { fail obj, "..." }.should raise_error(StandardError, "...")
end
it "instantiates the specified exception class" do
- class LittleBunnyFooFoo < RuntimeError; end
- lambda { fail LittleBunnyFooFoo }.should raise_error(LittleBunnyFooFoo)
+ error_class = Class.new(RuntimeError)
+ -> { fail error_class }.should raise_error(error_class)
end
it "uses the specified message" do
- lambda {
+ -> {
begin
fail "the duck is not irish."
rescue => e
@@ -38,6 +37,6 @@ describe "Kernel.fail" do
end
end
-describe "Kernel#fail" do
+describe "Kernel.fail" do
it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/core/kernel/fixtures/Complex.rb b/spec/ruby/core/kernel/fixtures/Complex.rb
new file mode 100644
index 0000000000..bf14d55ad5
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/Complex.rb
@@ -0,0 +1,5 @@
+module KernelSpecs
+ def self.Complex_method(string)
+ Complex(string)
+ end
+end
diff --git a/spec/ruby/core/kernel/fixtures/__dir__.rb b/spec/ruby/core/kernel/fixtures/__dir__.rb
new file mode 100644
index 0000000000..bf9a15e3c8
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/__dir__.rb
@@ -0,0 +1,2 @@
+puts __FILE__
+puts __dir__
diff --git a/spec/ruby/core/kernel/fixtures/autoload_c.rb b/spec/ruby/core/kernel/fixtures/autoload_c.rb
deleted file mode 100644
index 4569b23669..0000000000
--- a/spec/ruby/core/kernel/fixtures/autoload_c.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-module KSAutoloadC
- def self.loaded
- :ksautoload_c
- end
-end
diff --git a/spec/ruby/core/kernel/fixtures/autoload_from_included_module.rb b/spec/ruby/core/kernel/fixtures/autoload_from_included_module.rb
new file mode 100644
index 0000000000..f5bedc6992
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/autoload_from_included_module.rb
@@ -0,0 +1,9 @@
+module KernelSpecs
+ module AutoloadMethod
+ module AutoloadFromIncludedModule
+ def self.loaded
+ :autoload_from_included_module
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/kernel/fixtures/autoload_from_included_module2.rb b/spec/ruby/core/kernel/fixtures/autoload_from_included_module2.rb
new file mode 100644
index 0000000000..f4f1cfbf7c
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/autoload_from_included_module2.rb
@@ -0,0 +1,9 @@
+module KernelSpecs
+ module AutoloadMethod2
+ module AutoloadFromIncludedModule2
+ def self.loaded
+ :autoload_from_included_module2
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/kernel/fixtures/caller_at_exit.rb b/spec/ruby/core/kernel/fixtures/caller_at_exit.rb
new file mode 100644
index 0000000000..ca9d808597
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/caller_at_exit.rb
@@ -0,0 +1,7 @@
+at_exit {
+ foo
+}
+
+def foo
+ puts caller(0)
+end
diff --git a/spec/ruby/core/kernel/fixtures/classes.rb b/spec/ruby/core/kernel/fixtures/classes.rb
index afa2bec12f..0e2b81988f 100644
--- a/spec/ruby/core/kernel/fixtures/classes.rb
+++ b/spec/ruby/core/kernel/fixtures/classes.rb
@@ -49,7 +49,7 @@ module KernelSpecs
def self.chomp(str, method, sep="\n")
code = "$_ = #{str.inspect}; $/ = #{sep.inspect}; #{method}; print $_"
- IO.popen([*ruby_exe, "-n", "-e", code], "r+") do |io|
+ IO.popen([*ruby_exe, "-W0", "-n", "-e", code], "r+") do |io|
io.puts
io.close_write
io.read
@@ -68,6 +68,7 @@ module KernelSpecs
module SomeOtherModule; end
module AncestorModule; end
module MyModule; end
+ module MyPrependedModule; end
module MyExtensionModule; end
class AncestorClass < String
@@ -80,6 +81,8 @@ module KernelSpecs
class KindaClass < AncestorClass
include MyModule
+ prepend MyPrependedModule
+
def initialize
self.extend MyExtensionModule
end
@@ -216,10 +219,28 @@ module KernelSpecs
block_given?
end
+ def self.accept_block_inside_block()
+ yield_self {
+ block_given?
+ }
+ end
+
+ def self.accept_block_as_argument_inside_block(&block)
+ yield_self {
+ block_given?
+ }
+ end
+
class << self
define_method(:defined_block) do
block_given?
end
+
+ define_method(:defined_block_inside_block) do
+ yield_self {
+ block_given?
+ }
+ end
end
end
@@ -232,10 +253,28 @@ module KernelSpecs
self.send(:block_given?)
end
+ def self.accept_block_inside_block
+ yield_self {
+ self.send(:block_given?)
+ }
+ end
+
+ def self.accept_block_as_argument_inside_block(&block)
+ yield_self {
+ self.send(:block_given?)
+ }
+ end
+
class << self
define_method(:defined_block) do
self.send(:block_given?)
end
+
+ define_method(:defined_block_inside_block) do
+ yield_self {
+ self.send(:block_given?)
+ }
+ end
end
end
@@ -248,10 +287,28 @@ module KernelSpecs
Kernel.block_given?
end
+ def self.accept_block_inside_block
+ yield_self {
+ Kernel.block_given?
+ }
+ end
+
+ def self.accept_block_as_argument_inside_block(&block)
+ yield_self {
+ Kernel.block_given?
+ }
+ end
+
class << self
define_method(:defined_block) do
Kernel.block_given?
end
+
+ define_method(:defined_block_inside_block) do
+ yield_self {
+ Kernel.block_given?
+ }
+ end
end
end
@@ -278,14 +335,25 @@ module KernelSpecs
@two = two
end
- def initialize_copy(other)
+ def initialize_copy(other, **kw)
ScratchPad.record object_id
end
+
+ # define to support calling #clone with optional :freeze keyword argument
+ def initialize_clone(other, **kw)
+ super(other) # to call #initialize_copy
+ end
end
class Clone
def initialize_clone(other)
- ScratchPad.record other.object_id
+ ScratchPad.record other
+ end
+ end
+
+ class CloneFreeze
+ def initialize_clone(other, **kwargs)
+ ScratchPad.record([other, kwargs])
end
end
@@ -325,7 +393,7 @@ module KernelSpecs
def inner
b = mp { return :good }
- pr = lambda { |x| x.call }
+ pr = -> x { x.call }
pr.call(b)
@@ -334,21 +402,44 @@ module KernelSpecs
end
end
+ module LambdaSpecs
+ module ZSuper
+ def lambda
+ super
+ end
+ end
+
+ class ForwardBlockWithZSuper
+ prepend(ZSuper)
+ end
+
+ module Ampersand
+ def lambda(&block)
+ suppress_warning {super(&block)}
+ end
+ end
+
+ class SuperAmpersand
+ prepend(Ampersand)
+ end
+ end
+
class RespondViaMissing
def respond_to_missing?(method, priv=false)
case method
- when :handled_publicly
- true
- when :handled_privately
- priv
- when :not_handled
- false
- else
- raise "Typo in method name"
+ when :handled_publicly
+ true
+ when :handled_privately
+ priv
+ when :not_handled
+ false
+ else
+ raise "Typo in method name: #{method.inspect}"
end
end
def method_missing(method, *args)
+ raise "the method name should be a Symbol" unless Symbol === method
"Done #{method}(#{args})"
end
end
@@ -378,6 +469,63 @@ module KernelSpecs
[3, 4]
end
end
+
+ module AutoloadMethod
+ def setup_autoload(file)
+ autoload :AutoloadFromIncludedModule, file
+ end
+ end
+
+ class AutoloadMethodIncluder
+ include AutoloadMethod
+ end
+
+ module AutoloadMethod2
+ def setup_autoload(file)
+ Kernel.autoload :AutoloadFromIncludedModule2, file
+ end
+ end
+
+ class AutoloadMethodIncluder2
+ include AutoloadMethod2
+ end
+
+ class WarnInNestedCall
+ def f4(s = "", n)
+ f3(s, n)
+ end
+
+ def f3(s, n)
+ f2(s, n)
+ end
+
+ def f2(s, n)
+ f1(s, n)
+ end
+
+ def f1(s, n)
+ warn(s, uplevel: n)
+ end
+
+ def warn_call_lineno; method(:f1).source_location[1] + 1; end
+ def f1_call_lineno; method(:f2).source_location[1] + 1; end
+ def f2_call_lineno; method(:f3).source_location[1] + 1; end
+ def f3_call_lineno; method(:f4).source_location[1] + 1; end
+ end
+
+ CustomRangeInteger = Struct.new(:value) do
+ def to_int; value; end
+ def <=>(other); to_int <=> other.to_int; end
+ def -(other); self.class.new(to_int - other.to_int); end
+ def +(other); self.class.new(to_int + other.to_int); end
+ end
+
+ CustomRangeFloat = Struct.new(:value) do
+ def to_f; value; end
+ def <=>(other); to_f <=> other.to_f; end
+ def -(other); to_f - other.to_f; end
+ def +(other); self.class.new(to_f + other.to_f); end
+ end
end
class EvalSpecs
@@ -408,12 +556,3 @@ class EvalSpecs
return f
end
end
-
-# for Kernel#sleep to have Channel in it's specs
-# TODO: switch directly to queue for both Kernel#sleep and Thread specs?
-unless defined? Channel
- require 'thread'
- class Channel < Queue
- alias receive shift
- end
-end
diff --git a/spec/ruby/core/kernel/fixtures/eval_return_with_lambda.rb b/spec/ruby/core/kernel/fixtures/eval_return_with_lambda.rb
index a48b5685f3..9e2d045bf3 100644
--- a/spec/ruby/core/kernel/fixtures/eval_return_with_lambda.rb
+++ b/spec/ruby/core/kernel/fixtures/eval_return_with_lambda.rb
@@ -1,5 +1,5 @@
print "a,"
-x = lambda do
+x = -> do
print "b,"
Proc.new do
print "c,"
diff --git a/spec/ruby/core/kernel/fixtures/singleton_methods.rb b/spec/ruby/core/kernel/fixtures/singleton_methods.rb
new file mode 100644
index 0000000000..32ea0adf89
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/singleton_methods.rb
@@ -0,0 +1,13 @@
+module SingletonMethodsSpecs
+ module Prepended
+ def mspec_test_kernel_singleton_methods
+ end
+ public :mspec_test_kernel_singleton_methods
+ end
+
+ ::Module.prepend Prepended
+
+ module SelfExtending
+ extend self
+ end
+end
diff --git a/spec/ruby/core/kernel/fixtures/warn_core_method.rb b/spec/ruby/core/kernel/fixtures/warn_core_method.rb
new file mode 100644
index 0000000000..fd82562404
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/warn_core_method.rb
@@ -0,0 +1,14 @@
+raise 'should be run without RubyGems' if defined?(Gem)
+
+public def deprecated(n=1)
+ # puts nil, caller(0), nil
+ warn "use X instead", uplevel: n
+end
+
+1.times do # to test with a non-empty stack above the reported locations
+ deprecated
+ tap(&:deprecated)
+ tap { deprecated(2) }
+ # eval sources with a <internal: file are also ignored
+ eval "tap(&:deprecated)", nil, "<internal:should-be-skipped-by-warn-uplevel>"
+end
diff --git a/spec/ruby/core/kernel/fixtures/warn_require.rb b/spec/ruby/core/kernel/fixtures/warn_require.rb
new file mode 100644
index 0000000000..c4b0733233
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/warn_require.rb
@@ -0,0 +1 @@
+warn 'warn-require-warning', uplevel: 1
diff --git a/spec/ruby/core/kernel/fixtures/warn_require_caller.rb b/spec/ruby/core/kernel/fixtures/warn_require_caller.rb
new file mode 100644
index 0000000000..35a0f969f9
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/warn_require_caller.rb
@@ -0,0 +1,2 @@
+# Use a different line than just 1
+require "#{__dir__}/warn_require"
diff --git a/spec/ruby/core/kernel/fork_spec.rb b/spec/ruby/core/kernel/fork_spec.rb
index 8919d0914d..b37f9980e0 100644
--- a/spec/ruby/core/kernel/fork_spec.rb
+++ b/spec/ruby/core/kernel/fork_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../../../shared/process/fork', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative '../../shared/process/fork'
describe "Kernel#fork" do
it "is a private method" do
diff --git a/spec/ruby/core/kernel/format_spec.rb b/spec/ruby/core/kernel/format_spec.rb
index c73d5f0efb..1d0c000c15 100644
--- a/spec/ruby/core/kernel/format_spec.rb
+++ b/spec/ruby/core/kernel/format_spec.rb
@@ -1,6 +1,7 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+# NOTE: most specs are in sprintf_spec.rb, this is just an alias
describe "Kernel#format" do
it "is a private method" do
Kernel.should have_private_instance_method(:format)
@@ -11,4 +12,36 @@ describe "Kernel.format" do
it "is accessible as a module function" do
Kernel.format("%s", "hello").should == "hello"
end
+
+ describe "when $VERBOSE is true" do
+ it "warns if too many arguments are passed" do
+ code = <<~RUBY
+ $VERBOSE = true
+ format("test", 1)
+ RUBY
+
+ ruby_exe(code, args: "2>&1").should include("warning: too many arguments for format string")
+ end
+
+ it "does not warns if too many keyword arguments are passed" do
+ code = <<~RUBY
+ $VERBOSE = true
+ format("test %{test}", test: 1, unused: 2)
+ RUBY
+
+ ruby_exe(code, args: "2>&1").should_not include("warning")
+ end
+
+ ruby_bug "#20593", ""..."3.4" do
+ it "doesn't warns if keyword arguments are passed and none are used" do
+ code = <<~RUBY
+ $VERBOSE = true
+ format("test", test: 1)
+ format("test", {})
+ RUBY
+
+ ruby_exe(code, args: "2>&1").should_not include("warning")
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/freeze_spec.rb b/spec/ruby/core/kernel/freeze_spec.rb
index cf16512094..fa32d321cf 100644
--- a/spec/ruby/core/kernel/freeze_spec.rb
+++ b/spec/ruby/core/kernel/freeze_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#freeze" do
it "prevents self from being further modified" do
@@ -51,21 +51,19 @@ describe "Kernel#freeze" do
end
end
- ruby_version_is "2.5" do
- describe "on a Complex" do
- it "has no effect since it is already frozen" do
- c = Complex(1.3, 3.1)
- c.frozen?.should be_true
- c.freeze
- end
+ describe "on a Complex" do
+ it "has no effect since it is already frozen" do
+ c = Complex(1.3, 3.1)
+ c.frozen?.should be_true
+ c.freeze
end
+ end
- describe "on a Rational" do
- it "has no effect since it is already frozen" do
- r = Rational(1, 3)
- r.frozen?.should be_true
- r.freeze
- end
+ describe "on a Rational" do
+ it "has no effect since it is already frozen" do
+ r = Rational(1, 3)
+ r.frozen?.should be_true
+ r.freeze
end
end
@@ -74,12 +72,20 @@ describe "Kernel#freeze" do
def mutate; @foo = 1; end
end.new
o.freeze
- lambda {o.mutate}.should raise_error(RuntimeError)
+ -> {o.mutate}.should raise_error(RuntimeError)
end
it "causes instance_variable_set to raise RuntimeError" do
o = Object.new
o.freeze
- lambda {o.instance_variable_set(:@foo, 1)}.should raise_error(RuntimeError)
+ -> {o.instance_variable_set(:@foo, 1)}.should raise_error(RuntimeError)
+ end
+
+ it "freezes an object's singleton class" do
+ o = Object.new
+ c = o.singleton_class
+ c.frozen?.should == false
+ o.freeze
+ c.frozen?.should == true
end
end
diff --git a/spec/ruby/core/kernel/frozen_spec.rb b/spec/ruby/core/kernel/frozen_spec.rb
index fad1971985..a4cec4263d 100644
--- a/spec/ruby/core/kernel/frozen_spec.rb
+++ b/spec/ruby/core/kernel/frozen_spec.rb
@@ -1,13 +1,13 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#frozen?" do
it "returns true if self is frozen" do
o = mock('o')
p = mock('p')
p.freeze
- o.frozen?.should == false
- p.frozen?.should == true
+ o.should_not.frozen?
+ p.should.frozen?
end
describe "on true, false and nil" do
@@ -50,29 +50,27 @@ describe "Kernel#frozen?" do
end
end
- ruby_version_is "2.5" do
- describe "on a Complex" do
- it "returns true" do
- c = Complex(1.3, 3.1)
- c.frozen?.should be_true
- end
+ describe "on a Complex" do
+ it "returns true" do
+ c = Complex(1.3, 3.1)
+ c.frozen?.should be_true
+ end
- it "literal returns true" do
- c = eval "1.3i"
- c.frozen?.should be_true
- end
+ it "literal returns true" do
+ c = eval "1.3i"
+ c.frozen?.should be_true
end
+ end
- describe "on a Rational" do
- it "returns true" do
- r = Rational(1, 3)
- r.frozen?.should be_true
- end
+ describe "on a Rational" do
+ it "returns true" do
+ r = Rational(1, 3)
+ r.frozen?.should be_true
+ end
- it "literal returns true" do
- r = eval "1/3r"
- r.frozen?.should be_true
- end
+ it "literal returns true" do
+ r = eval "1/3r"
+ r.frozen?.should be_true
end
end
end
diff --git a/spec/ruby/core/kernel/gets_spec.rb b/spec/ruby/core/kernel/gets_spec.rb
index c775b2b7a4..104613dbfa 100644
--- a/spec/ruby/core/kernel/gets_spec.rb
+++ b/spec/ruby/core/kernel/gets_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#gets" do
it "is a private method" do
diff --git a/spec/ruby/core/kernel/global_variables_spec.rb b/spec/ruby/core/kernel/global_variables_spec.rb
index 739b800938..8bce8e25b7 100644
--- a/spec/ruby/core/kernel/global_variables_spec.rb
+++ b/spec/ruby/core/kernel/global_variables_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel.global_variables" do
it "is a private method" do
diff --git a/spec/ruby/core/kernel/gsub_spec.rb b/spec/ruby/core/kernel/gsub_spec.rb
index 005ed0063d..a0cb9f2a70 100644
--- a/spec/ruby/core/kernel/gsub_spec.rb
+++ b/spec/ruby/core/kernel/gsub_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
# FIXME: These methods exist only when the -n or -p option is passed to
# ruby, but we currently don't have a way of specifying that.
@@ -10,7 +10,7 @@ ruby_version_is ""..."1.9" do
end
it "raises a TypeError if $_ is not a String" do
- lambda {
+ -> {
$_ = 123
gsub(/./, "!")
}.should raise_error(TypeError)
diff --git a/spec/ruby/core/kernel/initialize_clone_spec.rb b/spec/ruby/core/kernel/initialize_clone_spec.rb
new file mode 100644
index 0000000000..21a90c19f0
--- /dev/null
+++ b/spec/ruby/core/kernel/initialize_clone_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../spec_helper'
+
+describe "Kernel#initialize_clone" do
+ it "is a private instance method" do
+ Kernel.should have_private_instance_method(:initialize_clone)
+ end
+
+ it "returns the receiver" do
+ a = Object.new
+ b = Object.new
+ a.send(:initialize_clone, b).should == a
+ end
+
+ it "calls #initialize_copy" do
+ a = Object.new
+ b = Object.new
+ a.should_receive(:initialize_copy).with(b)
+ a.send(:initialize_clone, b)
+ end
+
+ it "accepts a :freeze keyword argument for obj.clone(freeze: value)" do
+ a = Object.new
+ b = Object.new
+ a.send(:initialize_clone, b, freeze: true).should == a
+ end
+end
diff --git a/spec/ruby/core/kernel/initialize_copy_spec.rb b/spec/ruby/core/kernel/initialize_copy_spec.rb
new file mode 100644
index 0000000000..d71ca9f60f
--- /dev/null
+++ b/spec/ruby/core/kernel/initialize_copy_spec.rb
@@ -0,0 +1,36 @@
+require_relative '../../spec_helper'
+
+describe "Kernel#initialize_copy" do
+ it "returns self" do
+ obj = Object.new
+ obj.send(:initialize_copy, obj).should.equal?(obj)
+ end
+
+ it "does nothing if the argument is the same as the receiver" do
+ obj = Object.new
+ obj.send(:initialize_copy, obj).should.equal?(obj)
+
+ obj = Object.new.freeze
+ obj.send(:initialize_copy, obj).should.equal?(obj)
+
+ 1.send(:initialize_copy, 1).should.equal?(1)
+ end
+
+ it "raises FrozenError if the receiver is frozen" do
+ -> { Object.new.freeze.send(:initialize_copy, Object.new) }.should raise_error(FrozenError)
+ -> { 1.send(:initialize_copy, Object.new) }.should raise_error(FrozenError)
+ end
+
+ it "raises TypeError if the objects are of different class" do
+ klass = Class.new
+ sub = Class.new(klass)
+ a = klass.new
+ b = sub.new
+ message = 'initialize_copy should take same class object'
+ -> { a.send(:initialize_copy, b) }.should raise_error(TypeError, message)
+ -> { b.send(:initialize_copy, a) }.should raise_error(TypeError, message)
+
+ -> { a.send(:initialize_copy, 1) }.should raise_error(TypeError, message)
+ -> { a.send(:initialize_copy, 1.0) }.should raise_error(TypeError, message)
+ end
+end
diff --git a/spec/ruby/core/kernel/initialize_dup_spec.rb b/spec/ruby/core/kernel/initialize_dup_spec.rb
new file mode 100644
index 0000000000..6dff34b7ad
--- /dev/null
+++ b/spec/ruby/core/kernel/initialize_dup_spec.rb
@@ -0,0 +1,20 @@
+require_relative '../../spec_helper'
+
+describe "Kernel#initialize_dup" do
+ it "is a private instance method" do
+ Kernel.should have_private_instance_method(:initialize_dup)
+ end
+
+ it "returns the receiver" do
+ a = Object.new
+ b = Object.new
+ a.send(:initialize_dup, b).should == a
+ end
+
+ it "calls #initialize_copy" do
+ a = Object.new
+ b = Object.new
+ a.should_receive(:initialize_copy).with(b)
+ a.send(:initialize_dup, b)
+ end
+end
diff --git a/spec/ruby/core/kernel/inspect_spec.rb b/spec/ruby/core/kernel/inspect_spec.rb
index 92129ebbc5..1fa66cab98 100644
--- a/spec/ruby/core/kernel/inspect_spec.rb
+++ b/spec/ruby/core/kernel/inspect_spec.rb
@@ -1,19 +1,11 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#inspect" do
it "returns a String" do
Object.new.inspect.should be_an_instance_of(String)
end
- it "returns a tainted string if self is tainted" do
- Object.new.taint.inspect.tainted?.should be_true
- end
-
- it "returns an untrusted string if self is untrusted" do
- Object.new.untrust.inspect.untrusted?.should be_true
- end
-
it "does not call #to_s if it is defined" do
# We must use a bare Object here
obj = Object.new
@@ -28,4 +20,71 @@ describe "Kernel#inspect" do
obj = Object.new
obj.inspect.should =~ /^#<Object:0x[0-9a-f]+>$/
end
+
+ it "returns a String for an object without #class method" do
+ obj = Object.new
+ class << obj
+ undef_method :class
+ end
+ obj.inspect.should be_kind_of(String)
+ end
+
+ ruby_version_is "4.0" do
+ it "calls #instance_variables_to_inspect private method to know which variables to display" do
+ obj = Object.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ obj.singleton_class.class_eval do
+ private def instance_variables_to_inspect = %i[@host @user @does_not_exist]
+ end
+
+ inspected = obj.inspect.sub(/^#<Object:0x[0-9a-f]+/, '#<Object:0x00')
+ inspected.should == '#<Object:0x00 @host="localhost", @user="root">'
+
+ obj = Object.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ obj.singleton_class.class_eval do
+ private def instance_variables_to_inspect = []
+ end
+
+ inspected = obj.inspect.sub(/^#<Object:0x[0-9a-f]+/, '#<Object:0x00')
+ inspected.should == "#<Object:0x00>"
+ end
+
+ it "displays all instance variables if #instance_variables_to_inspect returns nil" do
+ obj = Object.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ obj.singleton_class.class_eval do
+ private def instance_variables_to_inspect = nil
+ end
+
+ inspected = obj.inspect.sub(/^#<Object:0x[0-9a-f]+/, '#<Object:0x00')
+ inspected.should == %{#<Object:0x00 @host="localhost", @user="root", @password="hunter2">}
+ end
+
+ it "raises an error if #instance_variables_to_inspect returns an invalid value" do
+ obj = Object.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ obj.singleton_class.class_eval do
+ private def instance_variables_to_inspect = {}
+ end
+
+ ->{ obj.inspect }.should raise_error(TypeError, "Expected #instance_variables_to_inspect to return an Array or nil, but it returned Hash")
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/instance_of_spec.rb b/spec/ruby/core/kernel/instance_of_spec.rb
index 4801a1ff96..d1170d5047 100644
--- a/spec/ruby/core/kernel/instance_of_spec.rb
+++ b/spec/ruby/core/kernel/instance_of_spec.rb
@@ -1,7 +1,7 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
-describe Kernel, "#instance_of?" do
+describe "Kernel#instance_of?" do
before :each do
@o = KernelSpecs::InstanceClass.new
end
@@ -33,8 +33,8 @@ describe Kernel, "#instance_of?" do
end
it "raises a TypeError if given an object that is not a Class nor a Module" do
- lambda { @o.instance_of?(Object.new) }.should raise_error(TypeError)
- lambda { @o.instance_of?('KernelSpecs::InstanceClass') }.should raise_error(TypeError)
- lambda { @o.instance_of?(1) }.should raise_error(TypeError)
+ -> { @o.instance_of?(Object.new) }.should raise_error(TypeError)
+ -> { @o.instance_of?('KernelSpecs::InstanceClass') }.should raise_error(TypeError)
+ -> { @o.instance_of?(1) }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/core/kernel/instance_variable_defined_spec.rb b/spec/ruby/core/kernel/instance_variable_defined_spec.rb
index 969d36c731..2ebb582b43 100644
--- a/spec/ruby/core/kernel/instance_variable_defined_spec.rb
+++ b/spec/ruby/core/kernel/instance_variable_defined_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#instance_variable_defined?" do
before do
@@ -27,7 +27,7 @@ describe "Kernel#instance_variable_defined?" do
end
it "raises a TypeError if passed an Object not defining #to_str" do
- lambda do
+ -> do
obj = mock("kernel instance_variable_defined?")
@instance.instance_variable_defined? obj
end.should raise_error(TypeError)
diff --git a/spec/ruby/core/kernel/instance_variable_get_spec.rb b/spec/ruby/core/kernel/instance_variable_get_spec.rb
index 0c564f11b6..f1d2a45df8 100644
--- a/spec/ruby/core/kernel/instance_variable_get_spec.rb
+++ b/spec/ruby/core/kernel/instance_variable_get_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#instance_variable_get" do
before :each do
@@ -24,25 +24,25 @@ describe "Kernel#instance_variable_get" do
end
it "raises a TypeError when the passed argument does not respond to #to_str" do
- lambda { @obj.instance_variable_get(Object.new) }.should raise_error(TypeError)
+ -> { @obj.instance_variable_get(Object.new) }.should raise_error(TypeError)
end
it "raises a TypeError when the passed argument can't be converted to a String" do
obj = mock("to_str")
obj.stub!(:to_str).and_return(123)
- lambda { @obj.instance_variable_get(obj) }.should raise_error(TypeError)
+ -> { @obj.instance_variable_get(obj) }.should raise_error(TypeError)
end
it "raises a NameError when the conversion result does not start with an '@'" do
obj = mock("to_str")
obj.stub!(:to_str).and_return("test")
- lambda { @obj.instance_variable_get(obj) }.should raise_error(NameError)
+ -> { @obj.instance_variable_get(obj) }.should raise_error(NameError)
end
it "raises a NameError when passed just '@'" do
obj = mock("to_str")
obj.stub!(:to_str).and_return('@')
- lambda { @obj.instance_variable_get(obj) }.should raise_error(NameError)
+ -> { @obj.instance_variable_get(obj) }.should raise_error(NameError)
end
end
@@ -57,15 +57,21 @@ describe "Kernel#instance_variable_get when passed Symbol" do
end
it "raises a NameError when passed :@ as an instance variable name" do
- lambda { @obj.instance_variable_get(:"@") }.should raise_error(NameError)
+ -> { @obj.instance_variable_get(:"@") }.should raise_error(NameError)
end
it "raises a NameError when the passed Symbol does not start with an '@'" do
- lambda { @obj.instance_variable_get(:test) }.should raise_error(NameError)
+ -> { @obj.instance_variable_get(:test) }.should raise_error(NameError)
end
it "raises a NameError when the passed Symbol is an invalid instance variable name" do
- lambda { @obj.instance_variable_get(:"@0") }.should raise_error(NameError)
+ -> { @obj.instance_variable_get(:"@0") }.should raise_error(NameError)
+ end
+
+ it "returns nil or raises for frozen objects" do
+ nil.instance_variable_get(:@foo).should == nil
+ -> { nil.instance_variable_get(:foo) }.should raise_error(NameError)
+ :foo.instance_variable_get(:@foo).should == nil
end
end
@@ -80,26 +86,26 @@ describe "Kernel#instance_variable_get when passed String" do
end
it "raises a NameError when the passed String does not start with an '@'" do
- lambda { @obj.instance_variable_get("test") }.should raise_error(NameError)
+ -> { @obj.instance_variable_get("test") }.should raise_error(NameError)
end
it "raises a NameError when the passed String is an invalid instance variable name" do
- lambda { @obj.instance_variable_get("@0") }.should raise_error(NameError)
+ -> { @obj.instance_variable_get("@0") }.should raise_error(NameError)
end
it "raises a NameError when passed '@' as an instance variable name" do
- lambda { @obj.instance_variable_get("@") }.should raise_error(NameError)
+ -> { @obj.instance_variable_get("@") }.should raise_error(NameError)
end
end
-describe "Kernel#instance_variable_get when passed Fixnum" do
+describe "Kernel#instance_variable_get when passed Integer" do
before :each do
@obj = Object.new
@obj.instance_variable_set("@test", :test)
end
it "raises a TypeError" do
- lambda { @obj.instance_variable_get(10) }.should raise_error(TypeError)
- lambda { @obj.instance_variable_get(-10) }.should raise_error(TypeError)
+ -> { @obj.instance_variable_get(10) }.should raise_error(TypeError)
+ -> { @obj.instance_variable_get(-10) }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/core/kernel/instance_variable_set_spec.rb b/spec/ruby/core/kernel/instance_variable_set_spec.rb
index bac1bb5f99..2c25f4366f 100644
--- a/spec/ruby/core/kernel/instance_variable_set_spec.rb
+++ b/spec/ruby/core/kernel/instance_variable_set_spec.rb
@@ -1,43 +1,43 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#instance_variable_set" do
it "sets the value of the specified instance variable" do
- class Dog
+ dog = Class.new do
def initialize(p1, p2)
@a, @b = p1, p2
end
end
- Dog.new('cat', 99).instance_variable_set(:@a, 'dog').should == "dog"
+ dog.new('cat', 99).instance_variable_set(:@a, 'dog').should == "dog"
end
it "sets the value of the instance variable when no instance variables exist yet" do
- class NoVariables; end
- NoVariables.new.instance_variable_set(:@a, "new").should == "new"
+ no_variables = Class.new
+ no_variables.new.instance_variable_set(:@a, "new").should == "new"
end
it "raises a NameError exception if the argument is not of form '@x'" do
- class NoDog; end
- lambda { NoDog.new.instance_variable_set(:c, "cat") }.should raise_error(NameError)
+ no_dog = Class.new
+ -> { no_dog.new.instance_variable_set(:c, "cat") }.should raise_error(NameError)
end
it "raises a NameError exception if the argument is an invalid instance variable name" do
- class DigitDog; end
- lambda { DigitDog.new.instance_variable_set(:"@0", "cat") }.should raise_error(NameError)
+ digit_dog = Class.new
+ -> { digit_dog.new.instance_variable_set(:"@0", "cat") }.should raise_error(NameError)
end
it "raises a NameError when the argument is '@'" do
- class DogAt; end
- lambda { DogAt.new.instance_variable_set(:"@", "cat") }.should raise_error(NameError)
+ dog_at = Class.new
+ -> { dog_at.new.instance_variable_set(:"@", "cat") }.should raise_error(NameError)
end
- it "raises a TypeError if the instance variable name is a Fixnum" do
- lambda { "".instance_variable_set(1, 2) }.should raise_error(TypeError)
+ it "raises a TypeError if the instance variable name is an Integer" do
+ -> { "".instance_variable_set(1, 2) }.should raise_error(TypeError)
end
it "raises a TypeError if the instance variable name is an object that does not respond to to_str" do
class KernelSpecs::A; end
- lambda { "".instance_variable_set(KernelSpecs::A.new, 3) }.should raise_error(TypeError)
+ -> { "".instance_variable_set(KernelSpecs::A.new, 3) }.should raise_error(TypeError)
end
it "raises a NameError if the passed object, when coerced with to_str, does not start with @" do
@@ -46,11 +46,11 @@ describe "Kernel#instance_variable_set" do
":c"
end
end
- lambda { "".instance_variable_set(KernelSpecs::B.new, 4) }.should raise_error(NameError)
+ -> { "".instance_variable_set(KernelSpecs::B.new, 4) }.should raise_error(NameError)
end
it "raises a NameError if pass an object that cannot be a symbol" do
- lambda { "".instance_variable_set(:c, 1) }.should raise_error(NameError)
+ -> { "".instance_variable_set(:c, 1) }.should raise_error(NameError)
end
it "accepts as instance variable name any instance of a class that responds to to_str" do
@@ -78,16 +78,28 @@ describe "Kernel#instance_variable_set" do
end
it "keeps stored object after any exceptions" do
- lambda { @frozen.instance_variable_set(:@ivar, :replacement) }.should raise_error(Exception)
+ -> { @frozen.instance_variable_set(:@ivar, :replacement) }.should raise_error(Exception)
@frozen.ivar.should equal(:origin)
end
- it "raises a RuntimeError when passed replacement is identical to stored object" do
- lambda { @frozen.instance_variable_set(:@ivar, :origin) }.should raise_error(RuntimeError)
+ it "raises a FrozenError when passed replacement is identical to stored object" do
+ -> { @frozen.instance_variable_set(:@ivar, :origin) }.should raise_error(FrozenError)
end
- it "raises a RuntimeError when passed replacement is different from stored object" do
- lambda { @frozen.instance_variable_set(:@ivar, :replacement) }.should raise_error(RuntimeError)
+ it "raises a FrozenError when passed replacement is different from stored object" do
+ -> { @frozen.instance_variable_set(:@ivar, :replacement) }.should raise_error(FrozenError)
+ end
+
+ it "accepts unicode instance variable names" do
+ o = Object.new
+ o.instance_variable_set(:@💙, 42)
+ o.instance_variable_get(:@💙).should == 42
+ end
+
+ it "raises for frozen objects" do
+ -> { nil.instance_variable_set(:@foo, 42) }.should raise_error(FrozenError)
+ -> { nil.instance_variable_set(:foo, 42) }.should raise_error(NameError)
+ -> { :foo.instance_variable_set(:@foo, 42) }.should raise_error(FrozenError)
end
end
end
diff --git a/spec/ruby/core/kernel/instance_variables_spec.rb b/spec/ruby/core/kernel/instance_variables_spec.rb
index f744ee3c7a..677d8bb7b2 100644
--- a/spec/ruby/core/kernel/instance_variables_spec.rb
+++ b/spec/ruby/core/kernel/instance_variables_spec.rb
@@ -1,15 +1,17 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#instance_variables" do
describe "immediate values" do
it "returns an empty array if no instance variables are defined" do
- 0.instance_variables.should == []
+ [0, 0.5, true, false, nil].each do |value|
+ value.instance_variables.should == []
+ end
end
it "returns the correct array if an instance variable is added" do
a = 0
- lambda{ a.instance_variable_set("@test", 1) }.should raise_error(RuntimeError)
+ ->{ a.instance_variable_set("@test", 1) }.should raise_error(RuntimeError)
end
end
@@ -23,5 +25,16 @@ describe "Kernel#instance_variables" do
a.instance_variable_set("@test", 1)
a.instance_variables.should == [:@test]
end
+
+ it "returns the instances variables in the order declared" do
+ c = Class.new do
+ def initialize
+ @c = 1
+ @a = 2
+ @b = 3
+ end
+ end
+ c.new.instance_variables.should == [:@c, :@a, :@b]
+ end
end
end
diff --git a/spec/ruby/core/kernel/is_a_spec.rb b/spec/ruby/core/kernel/is_a_spec.rb
index c67c6552a0..bd8c96529a 100644
--- a/spec/ruby/core/kernel/is_a_spec.rb
+++ b/spec/ruby/core/kernel/is_a_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../shared/kind_of', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'shared/kind_of'
describe "Kernel#is_a?" do
- it_behaves_like(:kernel_kind_of , :is_a?)
+ it_behaves_like :kernel_kind_of, :is_a?
end
diff --git a/spec/ruby/core/kernel/iterator_spec.rb b/spec/ruby/core/kernel/iterator_spec.rb
deleted file mode 100644
index e85f0dc612..0000000000
--- a/spec/ruby/core/kernel/iterator_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-
-describe "Kernel#iterator?" do
- it "is a private method" do
- Kernel.should have_private_instance_method(:iterator?)
- end
-end
-
-describe "Kernel.iterator?" do
- it "needs to be reviewed for spec completeness"
-end
diff --git a/spec/ruby/core/kernel/itself_spec.rb b/spec/ruby/core/kernel/itself_spec.rb
index 722d75d718..c906d7c3e8 100644
--- a/spec/ruby/core/kernel/itself_spec.rb
+++ b/spec/ruby/core/kernel/itself_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#itself" do
it "returns the receiver itself" do
diff --git a/spec/ruby/core/kernel/kind_of_spec.rb b/spec/ruby/core/kernel/kind_of_spec.rb
index 56a54ec859..c988edccb5 100644
--- a/spec/ruby/core/kernel/kind_of_spec.rb
+++ b/spec/ruby/core/kernel/kind_of_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../shared/kind_of', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'shared/kind_of'
describe "Kernel#kind_of?" do
- it_behaves_like(:kernel_kind_of , :kind_of?)
+ it_behaves_like :kernel_kind_of, :kind_of?
end
diff --git a/spec/ruby/core/kernel/lambda_spec.rb b/spec/ruby/core/kernel/lambda_spec.rb
index 8fa0075675..565536ac0d 100644
--- a/spec/ruby/core/kernel/lambda_spec.rb
+++ b/spec/ruby/core/kernel/lambda_spec.rb
@@ -1,11 +1,11 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../shared/lambda', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/lambda'
# The functionality of lambdas is specified in core/proc
describe "Kernel.lambda" do
- it_behaves_like(:kernel_lambda, :lambda)
+ it_behaves_like :kernel_lambda, :lambda
it "is a private method" do
Kernel.should have_private_instance_method(:lambda)
@@ -16,11 +16,54 @@ describe "Kernel.lambda" do
l.lambda?.should be_true
end
- it "returned the passed Proc if given an existing Proc" do
- some_proc = proc {}
- l = lambda(&some_proc)
- l.should equal(some_proc)
- l.lambda?.should be_false
+ it "creates a lambda-style Proc if given a literal block via #send" do
+ l = send(:lambda) { 42 }
+ l.lambda?.should be_true
+ end
+
+ it "creates a lambda-style Proc if given a literal block via #__send__" do
+ l = __send__(:lambda) { 42 }
+ l.lambda?.should be_true
+ end
+
+ ruby_version_is ""..."3.3" do
+ it "creates a lambda-style Proc if given a literal block via Kernel.public_send" do
+ suppress_warning do
+ l = Kernel.public_send(:lambda) { 42 }
+ l.lambda?.should be_true
+ end
+ end
+
+ it "returns the passed Proc if given an existing Proc" do
+ some_proc = proc {}
+ l = suppress_warning {lambda(&some_proc)}
+ l.should equal(some_proc)
+ l.lambda?.should be_false
+ end
+
+ it "creates a lambda-style Proc when called with zsuper" do
+ suppress_warning do
+ l = KernelSpecs::LambdaSpecs::ForwardBlockWithZSuper.new.lambda { 42 }
+ l.lambda?.should be_true
+ l.call.should == 42
+
+ lambda { l.call(:extra) }.should raise_error(ArgumentError)
+ end
+ end
+
+ it "returns the passed Proc if given an existing Proc through super" do
+ some_proc = proc { }
+ l = KernelSpecs::LambdaSpecs::SuperAmpersand.new.lambda(&some_proc)
+ l.should equal(some_proc)
+ l.lambda?.should be_false
+ end
+
+ it "does not create lambda-style Procs when captured with #method" do
+ kernel_lambda = method(:lambda)
+ l = suppress_warning {kernel_lambda.call { 42 }}
+ l.lambda?.should be_false
+ l.call(:extra).should == 42
+ end
end
it "checks the arity of the call when no args are specified" do
@@ -82,5 +125,34 @@ describe "Kernel.lambda" do
it "allows long returns to flow through it" do
KernelSpecs::Lambda.new.outer.should == :good
end
-end
+ it "treats the block as a Proc when lambda is re-defined" do
+ klass = Class.new do
+ def lambda (&block); block; end
+ def ret
+ lambda { return 1 }.call
+ 2
+ end
+ end
+ klass.new.lambda { 42 }.should be_an_instance_of Proc
+ klass.new.ret.should == 1
+ end
+
+ context "when called without a literal block" do
+ ruby_version_is ""..."3.3" do
+ it "warns when proc isn't a lambda" do
+ -> { lambda(&proc{}) }.should complain("#{__FILE__}:#{__LINE__}: warning: lambda without a literal block is deprecated; use the proc without lambda instead\n")
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raises when proc isn't a lambda" do
+ -> { lambda(&proc{}) }.should raise_error(ArgumentError, /the lambda method requires a literal block/)
+ end
+ end
+
+ it "doesn't warn when proc is lambda" do
+ -> { lambda(&lambda{}) }.should_not complain(verbose: true)
+ end
+ end
+end
diff --git a/spec/ruby/core/kernel/load_spec.rb b/spec/ruby/core/kernel/load_spec.rb
index 36cc07e38a..a165cc4acd 100644
--- a/spec/ruby/core/kernel/load_spec.rb
+++ b/spec/ruby/core/kernel/load_spec.rb
@@ -1,7 +1,7 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../../../fixtures/code_loading', __FILE__)
-require File.expand_path('../shared/load', __FILE__)
-require File.expand_path('../shared/require', __FILE__)
+require_relative '../../spec_helper'
+require_relative '../../fixtures/code_loading'
+require_relative 'shared/load'
+require_relative 'shared/require'
describe "Kernel#load" do
before :each do
diff --git a/spec/ruby/core/kernel/local_variables_spec.rb b/spec/ruby/core/kernel/local_variables_spec.rb
index 7e8b364b4f..f6f1e15f52 100644
--- a/spec/ruby/core/kernel/local_variables_spec.rb
+++ b/spec/ruby/core/kernel/local_variables_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#local_variables" do
after :each do
@@ -34,4 +34,15 @@ describe "Kernel#local_variables" do
ScratchPad.recorded.should include(:a, :b)
ScratchPad.recorded.length.should == 2
end
+
+ it "includes only unique variable names" do
+ def local_var_method
+ a = 1
+ 1.times do |;a|
+ return local_variables
+ end
+ end
+
+ local_var_method.should == [:a]
+ end
end
diff --git a/spec/ruby/core/kernel/loop_spec.rb b/spec/ruby/core/kernel/loop_spec.rb
index f23e3afb02..7c76c7d28e 100644
--- a/spec/ruby/core/kernel/loop_spec.rb
+++ b/spec/ruby/core/kernel/loop_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel.loop" do
it "is a private method" do
@@ -55,18 +55,16 @@ describe "Kernel.loop" do
end
it "does not rescue other errors" do
- lambda{ loop do raise StandardError end }.should raise_error( StandardError )
+ ->{ loop do raise StandardError end }.should raise_error( StandardError )
end
- ruby_version_is "2.3" do
- it "returns StopIteration#result, the result value of a finished iterator" do
- e = Enumerator.new { |y|
- y << 1
- y << 2
- :stopped
- }
- loop { e.next }.should == :stopped
- end
+ it "returns StopIteration#result, the result value of a finished iterator" do
+ e = Enumerator.new { |y|
+ y << 1
+ y << 2
+ :stopped
+ }
+ loop { e.next }.should == :stopped
end
describe "when no block is given" do
diff --git a/spec/ruby/core/kernel/match_spec.rb b/spec/ruby/core/kernel/match_spec.rb
index 8a117ed497..cd6330fe91 100644
--- a/spec/ruby/core/kernel/match_spec.rb
+++ b/spec/ruby/core/kernel/match_spec.rb
@@ -1,14 +1,7 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Kernel#=~" do
- it "returns nil matching any object" do
- o = Object.new
-
- (o =~ /Object/).should be_nil
- (o =~ 'Object').should be_nil
- (o =~ Object).should be_nil
- (o =~ Object.new).should be_nil
- (o =~ nil).should be_nil
- (o =~ true).should be_nil
+ it "is no longer defined" do
+ Object.new.should_not.respond_to?(:=~)
end
end
diff --git a/spec/ruby/core/kernel/method_spec.rb b/spec/ruby/core/kernel/method_spec.rb
index 09a3f940ca..3fc566d6a6 100644
--- a/spec/ruby/core/kernel/method_spec.rb
+++ b/spec/ruby/core/kernel/method_spec.rb
@@ -1,9 +1,9 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../shared/method', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'shared/method'
+require_relative 'fixtures/classes'
describe "Kernel#method" do
- it_behaves_like(:kernel_method, :method)
+ it_behaves_like :kernel_method, :method
before :each do
@obj = KernelSpecs::A.new
@@ -29,9 +29,52 @@ describe "Kernel#method" do
m.call.should == :defined
end
- it "can be called even if we only repond_to_missing? method, true" do
+ it "can be called even if we only respond_to_missing? method, true" do
m = KernelSpecs::RespondViaMissing.new.method(:handled_privately)
m.should be_an_instance_of(Method)
m.call(1, 2, 3).should == "Done handled_privately([1, 2, 3])"
end
+
+ it "can call a #method_missing accepting zero or one arguments" do
+ cls = Class.new do
+ def respond_to_missing?(name, *)
+ name == :foo or super
+ end
+ def method_missing
+ :no_args
+ end
+ end
+ m = cls.new.method(:foo)
+ -> { m.call }.should raise_error(ArgumentError)
+
+ cls = Class.new do
+ def respond_to_missing?(name, *)
+ name == :bar or super
+ end
+ def method_missing(m)
+ m
+ end
+ end
+ m = cls.new.method(:bar)
+ m.call.should == :bar
+ end
+
+ describe "converts the given name to a String using #to_str" do
+ it "calls #to_str to convert the given name to a String" do
+ name = mock("method-name")
+ name.should_receive(:to_str).and_return("hash")
+ Object.method(name).should == Object.method(:hash)
+ end
+
+ it "raises a TypeError if the given name can't be converted to a String" do
+ -> { Object.method(nil) }.should raise_error(TypeError)
+ -> { Object.method([]) }.should raise_error(TypeError)
+ end
+
+ it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do
+ name = mock("method-name")
+ name.should_receive(:to_str).and_raise(NoMethodError)
+ -> { Object.method(name) }.should raise_error(NoMethodError)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/methods_spec.rb b/spec/ruby/core/kernel/methods_spec.rb
index 5dfb17d4cb..fb7a7e8be9 100644
--- a/spec/ruby/core/kernel/methods_spec.rb
+++ b/spec/ruby/core/kernel/methods_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../../../fixtures/reflection', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative '../../fixtures/reflection'
# TODO: rewrite
describe "Kernel#methods" do
diff --git a/spec/ruby/core/kernel/nil_spec.rb b/spec/ruby/core/kernel/nil_spec.rb
index 0b5e34f7f1..7418245f26 100644
--- a/spec/ruby/core/kernel/nil_spec.rb
+++ b/spec/ruby/core/kernel/nil_spec.rb
@@ -1,6 +1,12 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
-describe "Kernel#nil?" do
- it "needs to be reviewed for spec completeness"
+describe 'Kernel#nil?' do
+ it 'returns false' do
+ Object.should_not.nil?
+ Object.new.should_not.nil?
+ ''.should_not.nil?
+ [].should_not.nil?
+ {}.should_not.nil?
+ end
end
diff --git a/spec/ruby/core/kernel/not_match_spec.rb b/spec/ruby/core/kernel/not_match_spec.rb
index 42bd45c106..082e56fed7 100644
--- a/spec/ruby/core/kernel/not_match_spec.rb
+++ b/spec/ruby/core/kernel/not_match_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#!~" do
class KernelSpecs::NotMatch
@@ -14,6 +14,10 @@ describe "Kernel#!~" do
(obj !~ :foo).should == false
end
+ it "raises NoMethodError if self does not respond to #=~" do
+ -> { Object.new !~ :foo }.should raise_error(NoMethodError)
+ end
+
it 'can be overridden in subclasses' do
obj = KernelSpecs::NotMatch.new
(obj !~ :bar).should == :foo
diff --git a/spec/ruby/core/kernel/object_id_spec.rb b/spec/ruby/core/kernel/object_id_spec.rb
index 0a12415a40..ef9e80c831 100644
--- a/spec/ruby/core/kernel/object_id_spec.rb
+++ b/spec/ruby/core/kernel/object_id_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../../../shared/kernel/object_id', __FILE__)
+require_relative '../../spec_helper'
+require_relative '../../shared/kernel/object_id'
describe "Kernel#object_id" do
it_behaves_like :object_id, :object_id, Object
diff --git a/spec/ruby/core/kernel/open_spec.rb b/spec/ruby/core/kernel/open_spec.rb
index ff56dfa03b..b967d5044b 100644
--- a/spec/ruby/core/kernel/open_spec.rb
+++ b/spec/ruby/core/kernel/open_spec.rb
@@ -1,8 +1,7 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#open" do
-
before :each do
@name = tmp("kernel_open.txt")
@content = "This is a test"
@@ -28,47 +27,80 @@ describe "Kernel#open" do
open(@name, "r") { |f| f.gets }.should == @content
end
- platform_is_not :windows do
- it "opens an io when path starts with a pipe" do
- @io = open("|date")
- begin
- @io.should be_kind_of(IO)
- @io.read
- ensure
- @io.close
+ ruby_version_is ""..."4.0" do
+ platform_is_not :windows, :wasi do
+ it "opens an io when path starts with a pipe" do
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @io = open("|date")
+ end
+ begin
+ @io.should be_kind_of(IO)
+ @io.read
+ ensure
+ @io.close
+ end
end
- end
- it "opens an io when called with a block" do
- @output = open("|date") { |f| f.read }
- @output.should_not == ''
- end
+ it "opens an io when called with a block" do
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @output = open("|date") { |f| f.read }
+ end
+ @output.should_not == ''
+ end
- it "opens an io for writing" do
- bytes = open("|cat", "w") { |io| io.write(".") }
- bytes.should == 1
+ it "opens an io for writing" do
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ -> {
+ bytes = open("|cat", "w") { |io| io.write(".") }
+ bytes.should == 1
+ }.should output_to_fd(".")
+ end
+ end
end
- end
- platform_is :windows do
- it "opens an io when path starts with a pipe" do
- @io = open("|date /t")
- begin
- @io.should be_kind_of(IO)
- @io.read
- ensure
- @io.close
+ platform_is :windows do
+ it "opens an io when path starts with a pipe" do
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @io = open("|date /t")
+ end
+ begin
+ @io.should be_kind_of(IO)
+ @io.read
+ ensure
+ @io.close
+ end
+ end
+
+ it "opens an io when called with a block" do
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @output = open("|date /t") { |f| f.read }
+ end
+ @output.should_not == ''
end
end
- it "opens an io when called with a block" do
- @output = open("|date /t") { |f| f.read }
- @output.should_not == ''
+ ruby_version_is "3.3" do
+ # https://bugs.ruby-lang.org/issues/19630
+ it "warns about deprecation given a path with a pipe" do
+ cmd = "|echo ok"
+ -> {
+ open(cmd) { |f| f.read }
+ }.should complain(/Kernel#open with a leading '\|'/)
+ end
end
end
it "raises an ArgumentError if not passed one argument" do
- lambda { open }.should raise_error(ArgumentError)
+ -> { open }.should raise_error(ArgumentError)
+ end
+
+ it "accepts options as keyword arguments" do
+ @file = open(@name, "r", 0666, flags: File::CREAT)
+ @file.should be_kind_of(File)
+
+ -> {
+ open(@name, "r", 0666, {flags: File::CREAT})
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
end
describe "when given an object that responds to to_open" do
@@ -76,7 +108,7 @@ describe "Kernel#open" do
ScratchPad.clear
end
- it "calls #to_path to covert the argument to a String before calling #to_str" do
+ it "calls #to_path to convert the argument to a String before calling #to_str" do
obj = mock("open to_path")
obj.should_receive(:to_path).at_least(1).times.and_return(@name)
obj.should_not_receive(:to_str)
@@ -108,11 +140,21 @@ describe "Kernel#open" do
it "passes its arguments onto #to_open" do
obj = mock('to_open')
- obj.should_receive(:to_open).with(1,2,3)
-
+ obj.should_receive(:to_open).with(1, 2, 3)
open(obj, 1, 2, 3)
end
+ it "passes keyword arguments onto #to_open as keyword arguments if to_open accepts them" do
+ obj = Object.new
+ def obj.to_open(*args, **kw)
+ ScratchPad << {args: args, kw: kw}
+ end
+
+ ScratchPad.record []
+ open(obj, 1, 2, 3, a: "b")
+ ScratchPad.recorded.should == [args: [1, 2, 3], kw: {a: "b"}]
+ end
+
it "passes the return value from #to_open to a block" do
obj = mock('to_open')
obj.should_receive(:to_open).and_return(:value)
@@ -127,14 +169,24 @@ describe "Kernel#open" do
it "raises a TypeError if passed a non-String that does not respond to #to_open" do
obj = mock('non-fileish')
- lambda { open(obj) }.should raise_error(TypeError)
- lambda { open(nil) }.should raise_error(TypeError)
- lambda { open(7) }.should raise_error(TypeError)
+ -> { open(obj) }.should raise_error(TypeError)
+ -> { open(nil) }.should raise_error(TypeError)
+ -> { open(7) }.should raise_error(TypeError)
end
it "accepts nil for mode and permission" do
open(@name, nil, nil) { |f| f.gets }.should == @content
end
+
+ it "is not redefined by open-uri" do
+ code = <<~RUBY
+ before = Kernel.instance_method(:open)
+ require 'open-uri'
+ after = Kernel.instance_method(:open)
+ p before == after
+ RUBY
+ ruby_exe(code, args: "2>&1").should == "true\n"
+ end
end
describe "Kernel.open" do
diff --git a/spec/ruby/core/kernel/p_spec.rb b/spec/ruby/core/kernel/p_spec.rb
index c451f5952a..eae191aa54 100644
--- a/spec/ruby/core/kernel/p_spec.rb
+++ b/spec/ruby/core/kernel/p_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#p" do
before :all do
@@ -7,7 +7,9 @@ describe "Kernel#p" do
end
after :each do
- $/, $\, $, = @rs_f, @rs_b, @rs_c
+ suppress_warning {
+ $/, $\, $, = @rs_f, @rs_b, @rs_c
+ }
end
it "is a private method" do
@@ -40,38 +42,42 @@ describe "Kernel#p" do
o = mock("Inspector Gadget")
o.should_receive(:inspect).any_number_of_times.and_return "Next time, Gadget, NEXT TIME!"
- lambda { p(o) }.should output("Next time, Gadget, NEXT TIME!\n")
- lambda { p(*[o]) }.should output("Next time, Gadget, NEXT TIME!\n")
- lambda { p(*[o, o]) }.should output("Next time, Gadget, NEXT TIME!\nNext time, Gadget, NEXT TIME!\n")
- lambda { p([o])}.should output("[#{o.inspect}]\n")
+ -> { p(o) }.should output("Next time, Gadget, NEXT TIME!\n")
+ -> { p(*[o]) }.should output("Next time, Gadget, NEXT TIME!\n")
+ -> { p(*[o, o]) }.should output("Next time, Gadget, NEXT TIME!\nNext time, Gadget, NEXT TIME!\n")
+ -> { p([o])}.should output("[#{o.inspect}]\n")
end
it "is not affected by setting $\\, $/ or $," do
o = mock("Inspector Gadget")
o.should_receive(:inspect).any_number_of_times.and_return "Next time, Gadget, NEXT TIME!"
- $, = " *helicopter sound*\n"
- lambda { p(o) }.should output_to_fd("Next time, Gadget, NEXT TIME!\n")
+ suppress_warning {
+ $, = " *helicopter sound*\n"
+ }
+ -> { p(o) }.should output_to_fd("Next time, Gadget, NEXT TIME!\n")
- $\ = " *helicopter sound*\n"
- lambda { p(o) }.should output_to_fd("Next time, Gadget, NEXT TIME!\n")
+ suppress_warning {
+ $\ = " *helicopter sound*\n"
+ }
+ -> { p(o) }.should output_to_fd("Next time, Gadget, NEXT TIME!\n")
- $/ = " *helicopter sound*\n"
- lambda { p(o) }.should output_to_fd("Next time, Gadget, NEXT TIME!\n")
+ suppress_warning {
+ $/ = " *helicopter sound*\n"
+ }
+ -> { p(o) }.should output_to_fd("Next time, Gadget, NEXT TIME!\n")
end
it "prints nothing if no argument is given" do
- lambda { p }.should output("")
+ -> { p }.should output("")
end
it "prints nothing if called splatting an empty Array" do
- lambda { p(*[]) }.should output("")
+ -> { p(*[]) }.should output("")
end
-=begin Not sure how to spec this, but wanted to note the behavior here
- it "does not flush if receiver is not a TTY or a File" do
- end
-=end
+ # Not sure how to spec this, but wanted to note the behavior here
+ it "does not flush if receiver is not a TTY or a File"
end
describe "Kernel.p" do
diff --git a/spec/ruby/core/kernel/pp_spec.rb b/spec/ruby/core/kernel/pp_spec.rb
new file mode 100644
index 0000000000..b5b1c98d38
--- /dev/null
+++ b/spec/ruby/core/kernel/pp_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../spec_helper'
+
+describe "Kernel#pp" do
+ it "lazily loads the 'pp' library and delegates the call to that library" do
+ # Run in child process to ensure 'pp' hasn't been loaded yet.
+ output = ruby_exe("pp [1, 2, 3]")
+ output.should == "[1, 2, 3]\n"
+ end
+end
diff --git a/spec/ruby/core/kernel/print_spec.rb b/spec/ruby/core/kernel/print_spec.rb
index 3b642538cb..7e7c9b822d 100644
--- a/spec/ruby/core/kernel/print_spec.rb
+++ b/spec/ruby/core/kernel/print_spec.rb
@@ -1,10 +1,22 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#print" do
it "is a private method" do
Kernel.should have_private_instance_method(:print)
end
+
+ it "delegates to $stdout" do
+ -> { print :arg }.should output("arg")
+ end
+
+ it "prints $_ when no arguments are given" do
+ orig_value = $_
+ $_ = 'foo'
+ -> { print }.should output("foo")
+ ensure
+ $_ = orig_value
+ end
end
describe "Kernel.print" do
diff --git a/spec/ruby/core/kernel/printf_spec.rb b/spec/ruby/core/kernel/printf_spec.rb
index ed134027c0..61bf955c25 100644
--- a/spec/ruby/core/kernel/printf_spec.rb
+++ b/spec/ruby/core/kernel/printf_spec.rb
@@ -1,7 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../shared/sprintf', __FILE__)
-require "stringio"
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/sprintf'
describe "Kernel#printf" do
it "is a private method" do
@@ -10,7 +9,6 @@ describe "Kernel#printf" do
end
describe "Kernel.printf" do
-
before :each do
@stdout = $stdout
@name = tmp("kernel_puts.txt")
@@ -34,22 +32,34 @@ describe "Kernel.printf" do
Kernel.printf(object, "%s", "string")
end
+ it "calls #to_str to convert the format object to a String" do
+ object = mock('format string')
+ object.should_receive(:to_str).and_return("to_str: %i")
+ $stdout.should_receive(:write).with("to_str: 42")
+ Kernel.printf($stdout, object, 42)
+ end
+end
+
+describe "Kernel.printf" do
describe "formatting" do
+ before :each do
+ require "stringio"
+ end
+
context "io is specified" do
- it_behaves_like :kernel_sprintf, -> (format, *args) {
- io = StringIO.new
- printf(io, format, *args)
+ it_behaves_like :kernel_sprintf, -> format, *args {
+ io = StringIO.new(+"")
+ Kernel.printf(io, format, *args)
io.string
}
end
context "io is not specified" do
- it_behaves_like :kernel_sprintf, -> (format, *args) {
+ it_behaves_like :kernel_sprintf, -> format, *args {
stdout = $stdout
-
begin
- $stdout = io = StringIO.new
- printf(format, *args)
+ $stdout = io = StringIO.new(+"")
+ Kernel.printf(format, *args)
io.string
ensure
$stdout = stdout
@@ -58,4 +68,3 @@ describe "Kernel.printf" do
end
end
end
-
diff --git a/spec/ruby/core/kernel/private_methods_spec.rb b/spec/ruby/core/kernel/private_methods_spec.rb
index d0603c72b8..041634d1e5 100644
--- a/spec/ruby/core/kernel/private_methods_spec.rb
+++ b/spec/ruby/core/kernel/private_methods_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../../../fixtures/reflection', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative '../../fixtures/reflection'
# TODO: rewrite
describe "Kernel#private_methods" do
diff --git a/spec/ruby/core/kernel/proc_spec.rb b/spec/ruby/core/kernel/proc_spec.rb
index 4e4854f97d..6553b8fd04 100644
--- a/spec/ruby/core/kernel/proc_spec.rb
+++ b/spec/ruby/core/kernel/proc_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../shared/lambda', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/lambda'
# The functionality of Proc objects is specified in core/proc
@@ -15,14 +15,14 @@ describe "Kernel.proc" do
end
it "returned the passed Proc if given an existing Proc" do
- some_lambda = lambda {}
+ some_lambda = -> {}
some_lambda.lambda?.should be_true
l = proc(&some_lambda)
l.should equal(some_lambda)
l.lambda?.should be_true
end
- it_behaves_like(:kernel_lambda, :proc)
+ it_behaves_like :kernel_lambda, :proc
it "returns from the creation site of the proc, not just the proc itself" do
@reached_end_of_method = nil
@@ -36,15 +36,13 @@ describe "Kernel.proc" do
end
describe "Kernel#proc" do
- it "uses the implicit block from an enclosing method" do
- def some_method
- proc
- end
-
- prc = some_method { "hello" }
-
- prc.call.should == "hello"
+ def some_method
+ proc
end
- it "needs to be reviewed for spec completeness"
+ it "raises an ArgumentError when passed no block" do
+ -> {
+ some_method { "hello" }
+ }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
+ end
end
diff --git a/spec/ruby/core/kernel/protected_methods_spec.rb b/spec/ruby/core/kernel/protected_methods_spec.rb
index 2e09cead53..d3334e886b 100644
--- a/spec/ruby/core/kernel/protected_methods_spec.rb
+++ b/spec/ruby/core/kernel/protected_methods_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../../../fixtures/reflection', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative '../../fixtures/reflection'
# TODO: rewrite
diff --git a/spec/ruby/core/kernel/public_method_spec.rb b/spec/ruby/core/kernel/public_method_spec.rb
index f1cc168420..c5d54c777e 100644
--- a/spec/ruby/core/kernel/public_method_spec.rb
+++ b/spec/ruby/core/kernel/public_method_spec.rb
@@ -1,9 +1,9 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../shared/method', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/method'
describe "Kernel#public_method" do
- it_behaves_like(:kernel_method, :public_method)
+ it_behaves_like :kernel_method, :public_method
before :each do
@obj = KernelSpecs::A.new
@@ -11,21 +11,21 @@ describe "Kernel#public_method" do
it "raises a NameError when called on a private method" do
@obj.send(:private_method).should == :private_method
- lambda do
+ -> do
@obj.public_method(:private_method)
end.should raise_error(NameError)
end
it "raises a NameError when called on a protected method" do
@obj.send(:protected_method).should == :protected_method
- lambda {
+ -> {
@obj.public_method(:protected_method)
}.should raise_error(NameError)
end
it "raises a NameError if we only repond_to_missing? method, true" do
obj = KernelSpecs::RespondViaMissing.new
- lambda do
+ -> do
obj.public_method(:handled_privately)
end.should raise_error(NameError)
end
diff --git a/spec/ruby/core/kernel/public_methods_spec.rb b/spec/ruby/core/kernel/public_methods_spec.rb
index b72775483c..a5512784fb 100644
--- a/spec/ruby/core/kernel/public_methods_spec.rb
+++ b/spec/ruby/core/kernel/public_methods_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../../../fixtures/reflection', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative '../../fixtures/reflection'
# TODO: rewrite
describe "Kernel#public_methods" do
diff --git a/spec/ruby/core/kernel/public_send_spec.rb b/spec/ruby/core/kernel/public_send_spec.rb
index 2eabbc7dc9..b684b1729c 100644
--- a/spec/ruby/core/kernel/public_send_spec.rb
+++ b/spec/ruby/core/kernel/public_send_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../../../shared/basicobject/send', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative '../../shared/basicobject/send'
describe "Kernel#public_send" do
it "invokes the named public method" do
@@ -29,7 +29,7 @@ describe "Kernel#public_send" do
'done'
end
end
- lambda { KernelSpecs::Foo.new.public_send(:bar)}.should raise_error(NoMethodError)
+ -> { KernelSpecs::Foo.new.public_send(:bar)}.should raise_error(NoMethodError)
end
it "raises a NoMethodError if the named method is private" do
@@ -39,7 +39,7 @@ describe "Kernel#public_send" do
'done2'
end
end
- lambda {
+ -> {
KernelSpecs::Foo.new.public_send(:bar)
}.should raise_error(NoMethodError)
end
@@ -70,11 +70,11 @@ describe "Kernel#public_send" do
end
it "raises a NoMethodError if the method is protected" do
- lambda { @receiver.call_protected_method }.should raise_error(NoMethodError)
+ -> { @receiver.call_protected_method }.should raise_error(NoMethodError)
end
it "raises a NoMethodError if the method is private" do
- lambda { @receiver.call_private_method }.should raise_error(NoMethodError)
+ -> { @receiver.call_private_method }.should raise_error(NoMethodError)
end
end
@@ -86,7 +86,7 @@ describe "Kernel#public_send" do
end
alias :aka :bar
end
- lambda {
+ -> {
KernelSpecs::Foo.new.public_send(:aka)
}.should raise_error(NoMethodError)
end
@@ -99,10 +99,18 @@ describe "Kernel#public_send" do
end
alias :aka :bar
end
- lambda {
+ -> {
KernelSpecs::Foo.new.public_send(:aka)
}.should raise_error(NoMethodError)
end
- it_behaves_like(:basicobject_send, :public_send)
+ it "includes `public_send` in the backtrace when passed not enough arguments" do
+ -> { public_send() }.should raise_error(ArgumentError) { |e| e.backtrace[0].should =~ /[`'](?:Kernel#)?public_send'/ }
+ end
+
+ it "includes `public_send` in the backtrace when passed a single incorrect argument" do
+ -> { public_send(Object.new) }.should raise_error(TypeError) { |e| e.backtrace[0].should =~ /[`'](?:Kernel#)?public_send'/ }
+ end
+
+ it_behaves_like :basicobject_send, :public_send
end
diff --git a/spec/ruby/core/kernel/putc_spec.rb b/spec/ruby/core/kernel/putc_spec.rb
index 1f5e9b6d63..74bd3765db 100644
--- a/spec/ruby/core/kernel/putc_spec.rb
+++ b/spec/ruby/core/kernel/putc_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../../../shared/io/putc', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative '../../shared/io/putc'
describe "Kernel#putc" do
it "is a private instance method" do
diff --git a/spec/ruby/core/kernel/puts_spec.rb b/spec/ruby/core/kernel/puts_spec.rb
index c5297f1cb2..6eb38e8fcf 100644
--- a/spec/ruby/core/kernel/puts_spec.rb
+++ b/spec/ruby/core/kernel/puts_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#puts" do
before :each do
diff --git a/spec/ruby/core/kernel/raise_spec.rb b/spec/ruby/core/kernel/raise_spec.rb
index 6efffd9366..fcd011d4e6 100644
--- a/spec/ruby/core/kernel/raise_spec.rb
+++ b/spec/ruby/core/kernel/raise_spec.rb
@@ -1,11 +1,286 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../../../shared/kernel/raise', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative '../../shared/kernel/raise'
describe "Kernel#raise" do
it "is a private method" do
Kernel.should have_private_instance_method(:raise)
end
+
+ it "re-raises the previously rescued exception if no exception is specified" do
+ ScratchPad.record nil
+
+ -> do
+ begin
+ raise Exception, "outer"
+ ScratchPad.record :no_abort
+ rescue Exception
+ begin
+ raise StandardError, "inner"
+ rescue StandardError
+ end
+
+ raise
+ ScratchPad.record :no_reraise
+ end
+ end.should raise_error(Exception, "outer")
+
+ ScratchPad.recorded.should be_nil
+ end
+
+ it "accepts a cause keyword argument that sets the cause" do
+ cause = StandardError.new
+ -> { raise("error", cause: cause) }.should raise_error(RuntimeError) { |e| e.cause.should == cause }
+ end
+
+ it "accepts a cause keyword argument that overrides the last exception" do
+ begin
+ raise "first raise"
+ rescue => ignored
+ cause = StandardError.new
+ -> { raise("error", cause: cause) }.should raise_error(RuntimeError) { |e| e.cause.should == cause }
+ end
+ end
+
+ it "raises an ArgumentError when only cause is given" do
+ cause = StandardError.new
+ -> { raise(cause: cause) }.should raise_error(ArgumentError, "only cause is given with no arguments")
+ end
+
+ it "raises an ArgumentError when only cause is given even if it has nil value" do
+ -> { raise(cause: nil) }.should raise_error(ArgumentError, "only cause is given with no arguments")
+ end
+
+ it "raises a TypeError when given cause is not an instance of Exception" do
+ -> { raise "message", cause: Object.new }.should raise_error(TypeError, "exception object expected")
+ end
+
+ it "doesn't raise a TypeError when given cause is nil" do
+ -> { raise "message", cause: nil }.should raise_error(RuntimeError, "message")
+ end
+
+ it "allows cause equal an exception" do
+ e = RuntimeError.new("message")
+ -> { raise e, cause: e }.should raise_error(e)
+ end
+
+ it "doesn't set given cause when it equals an exception" do
+ e = RuntimeError.new("message")
+
+ begin
+ raise e, cause: e
+ rescue
+ end
+
+ e.cause.should == nil
+ end
+
+ it "raises ArgumentError when exception is part of the cause chain" do
+ -> {
+ begin
+ raise "Error 1"
+ rescue => e1
+ begin
+ raise "Error 2"
+ rescue => e2
+ begin
+ raise "Error 3"
+ rescue => e3
+ raise e1, cause: e3
+ end
+ end
+ end
+ }.should raise_error(ArgumentError, "circular causes")
+ end
+
+ it "re-raises a rescued exception" do
+ -> do
+ begin
+ raise StandardError, "aaa"
+ rescue Exception
+ begin
+ raise ArgumentError
+ rescue ArgumentError
+ end
+
+ # should raise StandardError "aaa"
+ raise
+ end
+ end.should raise_error(StandardError, "aaa")
+ end
+
+ it "re-raises a previously rescued exception without overwriting the cause" do
+ begin
+ begin
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ raise "Error 2"
+ end
+ rescue => e2
+ raise "Error 3"
+ end
+ rescue
+ e2.cause.should == e1
+ raise e2
+ end
+ rescue => e
+ e.cause.should == e1
+ end
+ end
+
+ it "re-raises a previously rescued exception with overwriting the cause when it's explicitly specified with :cause option" do
+ e4 = RuntimeError.new("Error 4")
+
+ begin
+ begin
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ raise "Error 2"
+ end
+ rescue => e2
+ raise "Error 3"
+ end
+ rescue
+ e2.cause.should == e1
+ raise e2, cause: e4
+ end
+ rescue => e
+ e.cause.should == e4
+ end
+ end
+
+ it "re-raises a previously rescued exception without overwriting the cause when it's explicitly specified with :cause option and has nil value" do
+ begin
+ begin
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ raise "Error 2"
+ end
+ rescue => e2
+ raise "Error 3"
+ end
+ rescue
+ e2.cause.should == e1
+ raise e2, cause: nil
+ end
+ rescue => e
+ e.cause.should == e1
+ end
+ end
+
+ it "re-raises a previously rescued exception without setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ raise
+ end
+ rescue => e
+ e.should == e1
+ e.cause.should == nil
+ end
+ end
+
+ it "re-raises a previously rescued exception that has a cause without setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ begin
+ raise "Error 2"
+ rescue => e2
+ raise
+ end
+ end
+ rescue => e
+ e.should == e2
+ e.cause.should == e1
+ end
+ end
+
+ it "re-raises a previously rescued exception that doesn't have a cause and isn't a cause of any other exception with setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ begin
+ raise "Error 2"
+ rescue => e2
+ raise "Error 3"
+ end
+ end
+ rescue => e
+ e.message.should == "Error 3"
+ e.cause.should == e2
+ end
+ end
+
+ it "re-raises a previously rescued exception that doesn't have a cause and is a cause of other exception without setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ begin
+ raise "Error 2"
+ rescue => e2
+ e1.cause.should == nil
+ e2.cause.should == e1
+ raise e1
+ end
+ end
+ rescue => e
+ e.should == e1
+ e.cause.should == nil
+ end
+ end
+
+ it "re-raises a previously rescued exception that doesn't have a cause and is a cause of other exception (that wasn't raised explicitly) without setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ begin
+ foo # raises NameError
+ rescue => e2
+ e1.cause.should == nil
+ e2.cause.should == e1
+ raise e1
+ end
+ end
+ rescue => e
+ e.should == e1
+ e.cause.should == nil
+ end
+ end
+
+ it "re-raises a previously rescued exception that has a cause but isn't a cause of any other exception without setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ begin
+ raise "Error 2"
+ rescue => e2
+ begin
+ raise "Error 3", cause: RuntimeError.new("Error 4")
+ rescue => e3
+ e2.cause.should == e1
+ e3.cause.should_not == e2
+ raise e2
+ end
+ end
+ end
+ rescue => e
+ e.should == e2
+ e.cause.should == e1
+ end
+ end
end
describe "Kernel#raise" do
diff --git a/spec/ruby/core/kernel/rand_spec.rb b/spec/ruby/core/kernel/rand_spec.rb
index f52b5f75b5..355e425792 100644
--- a/spec/ruby/core/kernel/rand_spec.rb
+++ b/spec/ruby/core/kernel/rand_spec.rb
@@ -1,7 +1,7 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
-describe "Kernel.rand" do
+describe "Kernel#rand" do
it "is a private method" do
Kernel.should have_private_instance_method(:rand)
end
@@ -117,6 +117,48 @@ describe "Kernel.rand" do
end
end
+ context "given an inclusive range between 0 and 1" do
+ it "returns an Integer between the two Integers" do
+ x = rand(0..1)
+ x.should be_kind_of(Integer)
+ (0..1).should include(x)
+ end
+
+ it "returns a Float if at least one side is Float" do
+ seed = 42
+ x1 = Random.new(seed).rand(0..1.0)
+ x2 = Random.new(seed).rand(0.0..1.0)
+ x3 = Random.new(seed).rand(0.0..1)
+
+ x3.should be_kind_of(Float)
+ x1.should eql(x3)
+ x2.should eql(x3)
+
+ (0.0..1.0).should include(x3)
+ end
+ end
+
+ context "given an exclusive range between 0 and 1" do
+ it "returns zero as an Integer" do
+ x = rand(0...1)
+ x.should be_kind_of(Integer)
+ x.should eql(0)
+ end
+
+ it "returns a Float if at least one side is Float" do
+ seed = 42
+ x1 = Random.new(seed).rand(0...1.0)
+ x2 = Random.new(seed).rand(0.0...1.0)
+ x3 = Random.new(seed).rand(0.0...1)
+
+ x3.should be_kind_of(Float)
+ x1.should eql(x3)
+ x2.should eql(x3)
+
+ (0.0...1.0).should include(x3)
+ end
+ end
+
it "returns a numeric for an range argument where max is < 1" do
rand(0.25..0.75).should be_kind_of(Numeric)
end
@@ -132,8 +174,24 @@ describe "Kernel.rand" do
it "returns the range start/end when Integer range is 0" do
rand(42..42).should eql(42)
end
+
+ it "supports custom object types" do
+ rand(KernelSpecs::CustomRangeInteger.new(1)..KernelSpecs::CustomRangeInteger.new(42)).should be_an_instance_of(KernelSpecs::CustomRangeInteger)
+ rand(KernelSpecs::CustomRangeFloat.new(1.0)..KernelSpecs::CustomRangeFloat.new(42.0)).should be_an_instance_of(KernelSpecs::CustomRangeFloat)
+ rand(Time.now..Time.now).should be_an_instance_of(Time)
+ end
+
+ it "is random on boot" do
+ results = 2.times.map {
+ out = ruby_exe('p rand', options: '--disable-gems')
+ Float(out)
+ }
+ results.size.should == 2
+ # this is technically flaky, but very unlikely in a good distribution
+ results[0].should_not == results[1]
+ end
end
-describe "Kernel#rand" do
+describe "Kernel.rand" do
it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/core/kernel/readline_spec.rb b/spec/ruby/core/kernel/readline_spec.rb
index c69eee0726..dce7b03dc8 100644
--- a/spec/ruby/core/kernel/readline_spec.rb
+++ b/spec/ruby/core/kernel/readline_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#readline" do
it "is a private method" do
diff --git a/spec/ruby/core/kernel/readlines_spec.rb b/spec/ruby/core/kernel/readlines_spec.rb
index d5e07f8f75..2b6d65fff2 100644
--- a/spec/ruby/core/kernel/readlines_spec.rb
+++ b/spec/ruby/core/kernel/readlines_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#readlines" do
it "is a private method" do
diff --git a/spec/ruby/core/kernel/remove_instance_variable_spec.rb b/spec/ruby/core/kernel/remove_instance_variable_spec.rb
index 6a9f78b9bc..4e5ba5e018 100644
--- a/spec/ruby/core/kernel/remove_instance_variable_spec.rb
+++ b/spec/ruby/core/kernel/remove_instance_variable_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe :kernel_remove_instance_variable, shared: true do
it "returns the instance variable's value" do
@@ -23,24 +23,37 @@ describe "Kernel#remove_instance_variable" do
end
it "raises a NameError if the instance variable is not defined" do
- lambda do
+ -> do
@instance.send :remove_instance_variable, :@unknown
end.should raise_error(NameError)
end
it "raises a NameError if the argument is not a valid instance variable name" do
- lambda do
+ -> do
@instance.send :remove_instance_variable, :"@0"
end.should raise_error(NameError)
end
it "raises a TypeError if passed an Object not defining #to_str" do
- lambda do
+ -> do
obj = mock("kernel remove_instance_variable")
@instance.send :remove_instance_variable, obj
end.should raise_error(TypeError)
end
+ it "raises a FrozenError if self is frozen" do
+ o = Object.new
+ o.freeze
+ -> { o.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
+ -> { o.remove_instance_variable(:foo) }.should raise_error(NameError)
+ end
+
+ it "raises for frozen objects" do
+ -> { nil.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
+ -> { nil.remove_instance_variable(:foo) }.should raise_error(NameError)
+ -> { :foo.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
+ end
+
describe "when passed a String" do
it_behaves_like :kernel_remove_instance_variable, nil, "@greeting"
end
diff --git a/spec/ruby/core/kernel/require_relative_spec.rb b/spec/ruby/core/kernel/require_relative_spec.rb
index 04cf5444d2..6188d13a4e 100644
--- a/spec/ruby/core/kernel/require_relative_spec.rb
+++ b/spec/ruby/core/kernel/require_relative_spec.rb
@@ -1,15 +1,13 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../../../fixtures/code_loading', __FILE__)
+require_relative '../../spec_helper'
+require_relative '../../fixtures/code_loading'
describe "Kernel#require_relative with a relative path" do
- it "needs to be reviewed for spec completeness"
-
before :each do
CodeLoadingSpecs.spec_setup
@dir = "../../fixtures/code"
- @abs_dir = File.realpath(@dir, File.dirname(__FILE__))
+ @abs_dir = File.realpath(@dir, __dir__)
@path = "#{@dir}/load_fixture.rb"
- @abs_path = File.realpath(@path, File.dirname(__FILE__))
+ @abs_path = File.realpath(@path, __dir__)
end
after :each do
@@ -40,24 +38,76 @@ describe "Kernel#require_relative with a relative path" do
ScratchPad.recorded.should == [:loaded]
end
+ describe "in an #instance_eval with a" do
+
+ it "synthetic file base name loads a file base name relative to the working directory" do
+ Dir.chdir @abs_dir do
+ Object.new.instance_eval("require_relative(#{File.basename(@path).inspect})", "foo.rb").should be_true
+ end
+ ScratchPad.recorded.should == [:loaded]
+ end
+
+ it "synthetic file path loads a relative path relative to the working directory plus the directory of the synthetic path" do
+ Dir.chdir @abs_dir do
+ Object.new.instance_eval("require_relative(File.join('..', #{File.basename(@path).inspect}))", "bar/foo.rb").should be_true
+ end
+ ScratchPad.recorded.should == [:loaded]
+ end
+
+ platform_is_not :windows do
+ it "synthetic relative file path with a Windows path separator specified loads a relative path relative to the working directory" do
+ Dir.chdir @abs_dir do
+ Object.new.instance_eval("require_relative(#{File.basename(@path).inspect})", "bar\\foo.rb").should be_true
+ end
+ ScratchPad.recorded.should == [:loaded]
+ end
+ end
+
+ it "absolute file path loads a path relative to the absolute path" do
+ Object.new.instance_eval("require_relative(#{@path.inspect})", __FILE__).should be_true
+ ScratchPad.recorded.should == [:loaded]
+ end
+
+ it "absolute file path loads a path relative to the root directory" do
+ root = @abs_path
+ until File.dirname(root) == root
+ root = File.dirname(root)
+ end
+ root_relative = @abs_path[root.size..-1]
+ Object.new.instance_eval("require_relative(#{root_relative.inspect})", "/").should be_true
+ ScratchPad.recorded.should == [:loaded]
+ end
+
+ end
+
it "loads a file defining many methods" do
require_relative("#{@dir}/methods_fixture.rb").should be_true
ScratchPad.recorded.should == [:loaded]
end
it "raises a LoadError if the file does not exist" do
- lambda { require_relative("#{@dir}/nonexistent.rb") }.should raise_error(LoadError)
+ -> { require_relative("#{@dir}/nonexistent.rb") }.should raise_error(LoadError)
+ ScratchPad.recorded.should == []
+ end
+
+ it "raises a LoadError that includes the missing path" do
+ missing_path = "#{@dir}/nonexistent.rb"
+ expanded_missing_path = File.expand_path(missing_path, __dir__)
+ -> { require_relative(missing_path) }.should raise_error(LoadError) { |e|
+ e.message.should include(expanded_missing_path)
+ e.path.should == expanded_missing_path
+ }
ScratchPad.recorded.should == []
end
it "raises a LoadError if basepath does not exist" do
- lambda { eval("require_relative('#{@dir}/nonexistent.rb')") }.should raise_error(LoadError)
+ -> { eval("require_relative('#{@dir}/nonexistent.rb')") }.should raise_error(LoadError)
end
it "stores the missing path in a LoadError object" do
path = "#{@dir}/nonexistent.rb"
- lambda {
+ -> {
require_relative(path)
}.should(raise_error(LoadError) { |e|
e.path.should == File.expand_path(path, @abs_dir)
@@ -72,9 +122,9 @@ describe "Kernel#require_relative with a relative path" do
end
it "raises a TypeError if argument does not respond to #to_str" do
- lambda { require_relative(nil) }.should raise_error(TypeError)
- lambda { require_relative(42) }.should raise_error(TypeError)
- lambda {
+ -> { require_relative(nil) }.should raise_error(TypeError)
+ -> { require_relative(42) }.should raise_error(TypeError)
+ -> {
require_relative([@path,@path])
}.should raise_error(TypeError)
end
@@ -82,13 +132,13 @@ describe "Kernel#require_relative with a relative path" do
it "raises a TypeError if passed an object that has #to_s but not #to_str" do
name = mock("load_fixture.rb mock")
name.stub!(:to_s).and_return(@path)
- lambda { require_relative(name) }.should raise_error(TypeError)
+ -> { require_relative(name) }.should raise_error(TypeError)
end
it "raises a TypeError if #to_str does not return a String" do
name = mock("#to_str returns nil")
name.should_receive(:to_str).at_least(1).times.and_return(nil)
- lambda { require_relative(name) }.should raise_error(TypeError)
+ -> { require_relative(name) }.should raise_error(TypeError)
end
it "calls #to_path on non-String objects" do
@@ -157,9 +207,49 @@ describe "Kernel#require_relative with a relative path" do
$LOADED_FEATURES.should include(@abs_path)
end
+ platform_is_not :windows, :wasi do
+ describe "with symlinks" do
+ before :each do
+ @symlink_to_code_dir = tmp("codesymlink")
+ File.symlink(CODE_LOADING_DIR, @symlink_to_code_dir)
+ @symlink_basename = File.basename(@symlink_to_code_dir)
+ @requiring_file = tmp("requiring")
+ end
+
+ after :each do
+ rm_r @symlink_to_code_dir, @requiring_file
+ end
+
+ it "does not canonicalize the path and stores a path with symlinks" do
+ symlink_path = "#{@symlink_basename}/load_fixture.rb"
+ absolute_path = "#{tmp("")}#{symlink_path}"
+ canonical_path = "#{CODE_LOADING_DIR}/load_fixture.rb"
+ touch(@requiring_file) { |f|
+ f.puts "require_relative #{symlink_path.inspect}"
+ }
+ load(@requiring_file)
+ ScratchPad.recorded.should == [:loaded]
+
+ features = $LOADED_FEATURES.select { |path| path.end_with?('load_fixture.rb') }
+ features.should include(absolute_path)
+ features.should_not include(canonical_path)
+ end
+
+ it "stores the same path that __FILE__ returns in the required file" do
+ symlink_path = "#{@symlink_basename}/load_fixture_and__FILE__.rb"
+ touch(@requiring_file) { |f|
+ f.puts "require_relative #{symlink_path.inspect}"
+ }
+ load(@requiring_file)
+ loaded_feature = $LOADED_FEATURES.last
+ ScratchPad.recorded.should == [loaded_feature]
+ end
+ end
+ end
+
it "does not store the path if the load fails" do
saved_loaded_features = $LOADED_FEATURES.dup
- lambda { require_relative("#{@dir}/raise_fixture.rb") }.should raise_error(RuntimeError)
+ -> { require_relative("#{@dir}/raise_fixture.rb") }.should raise_error(RuntimeError)
$LOADED_FEATURES.should == saved_loaded_features
end
@@ -185,11 +275,9 @@ describe "Kernel#require_relative with a relative path" do
end
describe "Kernel#require_relative with an absolute path" do
- it "needs to be reviewed for spec completeness"
-
before :each do
CodeLoadingSpecs.spec_setup
- @dir = File.expand_path "../../fixtures/code", File.dirname(__FILE__)
+ @dir = File.expand_path "../../fixtures/code", __dir__
@abs_dir = @dir
@path = File.join @dir, "load_fixture.rb"
@abs_path = @path
@@ -210,18 +298,18 @@ describe "Kernel#require_relative with an absolute path" do
end
it "raises a LoadError if the file does not exist" do
- lambda { require_relative("#{@dir}/nonexistent.rb") }.should raise_error(LoadError)
+ -> { require_relative("#{@dir}/nonexistent.rb") }.should raise_error(LoadError)
ScratchPad.recorded.should == []
end
it "raises a LoadError if basepath does not exist" do
- lambda { eval("require_relative('#{@dir}/nonexistent.rb')") }.should raise_error(LoadError)
+ -> { eval("require_relative('#{@dir}/nonexistent.rb')") }.should raise_error(LoadError)
end
it "stores the missing path in a LoadError object" do
path = "#{@dir}/nonexistent.rb"
- lambda {
+ -> {
require_relative(path)
}.should(raise_error(LoadError) { |e|
e.path.should == File.expand_path(path, @abs_dir)
@@ -236,9 +324,9 @@ describe "Kernel#require_relative with an absolute path" do
end
it "raises a TypeError if argument does not respond to #to_str" do
- lambda { require_relative(nil) }.should raise_error(TypeError)
- lambda { require_relative(42) }.should raise_error(TypeError)
- lambda {
+ -> { require_relative(nil) }.should raise_error(TypeError)
+ -> { require_relative(42) }.should raise_error(TypeError)
+ -> {
require_relative([@path,@path])
}.should raise_error(TypeError)
end
@@ -246,13 +334,13 @@ describe "Kernel#require_relative with an absolute path" do
it "raises a TypeError if passed an object that has #to_s but not #to_str" do
name = mock("load_fixture.rb mock")
name.stub!(:to_s).and_return(@path)
- lambda { require_relative(name) }.should raise_error(TypeError)
+ -> { require_relative(name) }.should raise_error(TypeError)
end
it "raises a TypeError if #to_str does not return a String" do
name = mock("#to_str returns nil")
name.should_receive(:to_str).at_least(1).times.and_return(nil)
- lambda { require_relative(name) }.should raise_error(TypeError)
+ -> { require_relative(name) }.should raise_error(TypeError)
end
it "calls #to_path on non-String objects" do
@@ -323,7 +411,7 @@ describe "Kernel#require_relative with an absolute path" do
it "does not store the path if the load fails" do
saved_loaded_features = $LOADED_FEATURES.dup
- lambda { require_relative("#{@dir}/raise_fixture.rb") }.should raise_error(RuntimeError)
+ -> { require_relative("#{@dir}/raise_fixture.rb") }.should raise_error(RuntimeError)
$LOADED_FEATURES.should == saved_loaded_features
end
diff --git a/spec/ruby/core/kernel/require_spec.rb b/spec/ruby/core/kernel/require_spec.rb
index 75cea7565e..60d17242fe 100644
--- a/spec/ruby/core/kernel/require_spec.rb
+++ b/spec/ruby/core/kernel/require_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../../../fixtures/code_loading', __FILE__)
-require File.expand_path('../shared/require', __FILE__)
+require_relative '../../spec_helper'
+require_relative '../../fixtures/code_loading'
+require_relative 'shared/require'
describe "Kernel#require" do
before :each do
@@ -16,8 +16,33 @@ describe "Kernel#require" do
Kernel.should have_private_instance_method(:require)
end
- it_behaves_like :kernel_require_basic, :require, CodeLoadingSpecs::Method.new
+ provided = %w[complex enumerator fiber rational thread ruby2_keywords]
+ ruby_version_is "4.0" do
+ provided << "set"
+ provided << "pathname"
+ end
+
+ it "#{provided.join(', ')} are already required" do
+ out = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems --disable-did-you-mean')
+ features = out.lines.map { |line| File.basename(line.chomp, '.*') }
+
+ # Ignore CRuby internals
+ features -= %w[encdb transdb windows_1252 windows_31j]
+ features.reject! { |feature| feature.end_with?('-fake') }
+
+ features.sort.should == provided.sort
+ requires = provided
+ ruby_version_is "4.0" do
+ requires = requires.map { |f| f == "pathname" ? "pathname.so" : f }
+ end
+
+ code = requires.map { |f| "puts require #{f.inspect}\n" }.join
+ required = ruby_exe(code, options: '--disable-gems')
+ required.should == "false\n" * requires.size
+ end
+
+ it_behaves_like :kernel_require_basic, :require, CodeLoadingSpecs::Method.new
it_behaves_like :kernel_require, :require, CodeLoadingSpecs::Method.new
end
@@ -31,6 +56,5 @@ describe "Kernel.require" do
end
it_behaves_like :kernel_require_basic, :require, Kernel
-
it_behaves_like :kernel_require, :require, Kernel
end
diff --git a/spec/ruby/core/kernel/respond_to_missing_spec.rb b/spec/ruby/core/kernel/respond_to_missing_spec.rb
index f116f19dbd..cc82031e26 100644
--- a/spec/ruby/core/kernel/respond_to_missing_spec.rb
+++ b/spec/ruby/core/kernel/respond_to_missing_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#respond_to_missing?" do
before :each do
diff --git a/spec/ruby/core/kernel/respond_to_spec.rb b/spec/ruby/core/kernel/respond_to_spec.rb
index aa4379277b..5b3ea3f651 100644
--- a/spec/ruby/core/kernel/respond_to_spec.rb
+++ b/spec/ruby/core/kernel/respond_to_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#respond_to?" do
before :each do
@@ -25,7 +25,7 @@ describe "Kernel#respond_to?" do
end
it "throws a type error if argument can't be coerced into a Symbol" do
- lambda { @a.respond_to?(Object.new) }.should raise_error(TypeError)
+ -> { @a.respond_to?(Object.new) }.should raise_error(TypeError, /is not a symbol nor a string/)
end
it "returns false if obj responds to the given protected method" do
@@ -61,7 +61,7 @@ describe "Kernel#respond_to?" do
it "does not change method visibility when finding private method" do
KernelSpecs::VisibilityChange.respond_to?(:new, false).should == false
KernelSpecs::VisibilityChange.respond_to?(:new, true).should == true
- lambda { KernelSpecs::VisibilityChange.new }.should raise_error(NoMethodError)
+ -> { KernelSpecs::VisibilityChange.new }.should raise_error(NoMethodError)
end
it "indicates if an object responds to a particular message" do
@@ -69,5 +69,4 @@ describe "Kernel#respond_to?" do
KernelSpecs::Foo.new.respond_to?(:bar).should == true
KernelSpecs::Foo.new.respond_to?(:invalid_and_silly_method_name).should == false
end
-
end
diff --git a/spec/ruby/core/kernel/select_spec.rb b/spec/ruby/core/kernel/select_spec.rb
index c37c621ae7..df23414b28 100644
--- a/spec/ruby/core/kernel/select_spec.rb
+++ b/spec/ruby/core/kernel/select_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#select" do
it "is a private method" do
@@ -8,13 +8,11 @@ describe "Kernel#select" do
end
describe "Kernel.select" do
- it "needs to be reviewed for spec completeness"
-
it 'does not block when timeout is 0' do
IO.pipe do |read, write|
- IO.select([read], [], [], 0).should == nil
+ select([read], [], [], 0).should == nil
write.write 'data'
- IO.select([read], [], [], 0).should == [[read], [], []]
+ select([read], [], [], 0).should == [[read], [], []]
end
end
end
diff --git a/spec/ruby/core/kernel/send_spec.rb b/spec/ruby/core/kernel/send_spec.rb
index 8afd16e97c..9a4d261964 100644
--- a/spec/ruby/core/kernel/send_spec.rb
+++ b/spec/ruby/core/kernel/send_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../../../shared/basicobject/send', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative '../../shared/basicobject/send'
describe "Kernel#send" do
it "invokes the named public method" do
@@ -64,5 +64,5 @@ describe "Kernel#send" do
KernelSpecs::Foo.new.send(:aka).should == 'done2'
end
- it_behaves_like(:basicobject_send, :send)
+ it_behaves_like :basicobject_send, :send
end
diff --git a/spec/ruby/core/kernel/set_trace_func_spec.rb b/spec/ruby/core/kernel/set_trace_func_spec.rb
index 5dafa8b5d3..1f43e7a009 100644
--- a/spec/ruby/core/kernel/set_trace_func_spec.rb
+++ b/spec/ruby/core/kernel/set_trace_func_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#set_trace_func" do
it "is a private method" do
diff --git a/spec/ruby/core/kernel/shared/dup_clone.rb b/spec/ruby/core/kernel/shared/dup_clone.rb
index 116989958b..4fac6006e1 100644
--- a/spec/ruby/core/kernel/shared/dup_clone.rb
+++ b/spec/ruby/core/kernel/shared/dup_clone.rb
@@ -52,16 +52,6 @@ describe :kernel_dup_clone, shared: true do
o2.original.should equal(o)
end
- it "preserves tainted state from the original" do
- o = ObjectSpecDupInitCopy.new
- o2 = o.send(@method)
- o.taint
- o3 = o.send(@method)
-
- o2.tainted?.should == false
- o3.tainted?.should == true
- end
-
it "does not preserve the object_id" do
o1 = ObjectSpecDupInitCopy.new
old_object_id = o1.object_id
@@ -69,81 +59,33 @@ describe :kernel_dup_clone, shared: true do
o2.object_id.should_not == old_object_id
end
- it "preserves untrusted state from the original" do
- o = ObjectSpecDupInitCopy.new
- o2 = o.send(@method)
- o.untrust
- o3 = o.send(@method)
-
- o2.untrusted?.should == false
- o3.untrusted?.should == true
+ it "returns nil for NilClass" do
+ nil.send(@method).should == nil
end
- ruby_version_is ''...'2.4' do
- it "raises a TypeError for NilClass" do
- lambda { nil.send(@method) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError for TrueClass" do
- lambda { true.send(@method) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError for FalseClass" do
- lambda { false.send(@method) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError for Fixnum" do
- lambda { 1.send(@method) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError for Symbol" do
- lambda { :my_symbol.send(@method) }.should raise_error(TypeError)
- end
+ it "returns true for TrueClass" do
+ true.send(@method).should == true
end
- ruby_version_is '2.4' do
- it "returns nil for NilClass" do
- nil.send(@method).should == nil
- end
-
- it "returns true for TrueClass" do
- true.send(@method).should == true
- end
-
- it "returns false for FalseClass" do
- false.send(@method).should == false
- end
-
- it "returns the same Integer for Integer" do
- 1.send(@method).should == 1
- end
-
- it "returns the same Symbol for Symbol" do
- :my_symbol.send(@method).should == :my_symbol
- end
+ it "returns false for FalseClass" do
+ false.send(@method).should == false
end
- ruby_version_is ''...'2.5' do
- it "raises a TypeError for Complex" do
- c = Complex(1.3, 3.1)
- lambda { c.send(@method) }.should raise_error(TypeError)
- end
+ it "returns the same Integer for Integer" do
+ 1.send(@method).should == 1
+ end
- it "raises a TypeError for Rational" do
- r = Rational(1, 3)
- lambda { r.send(@method) }.should raise_error(TypeError)
- end
+ it "returns the same Symbol for Symbol" do
+ :my_symbol.send(@method).should == :my_symbol
end
- ruby_version_is '2.5' do
- it "returns self for Complex" do
- c = Complex(1.3, 3.1)
- c.send(@method).should equal c
- end
+ it "returns self for Complex" do
+ c = Complex(1.3, 3.1)
+ c.send(@method).should equal c
+ end
- it "returns self for Rational" do
- r = Rational(1, 3)
- r.send(@method).should equal r
- end
+ it "returns self for Rational" do
+ r = Rational(1, 3)
+ r.send(@method).should equal r
end
end
diff --git a/spec/ruby/core/kernel/shared/kind_of.rb b/spec/ruby/core/kernel/shared/kind_of.rb
index e99f46aa14..aef6f1c1d8 100644
--- a/spec/ruby/core/kernel/shared/kind_of.rb
+++ b/spec/ruby/core/kernel/shared/kind_of.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../fixtures/classes', __FILE__)
+require_relative '../fixtures/classes'
describe :kernel_kind_of, shared: true do
before :each do
@@ -31,14 +31,25 @@ describe :kernel_kind_of, shared: true do
@o.send(@method, KernelSpecs::MyExtensionModule).should == true
end
- it "returns false if given a Module not included in object's class nor ancestors" do
+ it "returns true if given a Module that object has been prepended with" do
+ @o.send(@method, KernelSpecs::MyPrependedModule).should == true
+ end
+
+ it "returns false if given a Module not included nor prepended in object's class nor ancestors" do
@o.send(@method, KernelSpecs::SomeOtherModule).should == false
end
it "raises a TypeError if given an object that is not a Class nor a Module" do
- lambda { @o.send(@method, 1) }.should raise_error(TypeError)
- lambda { @o.send(@method, 'KindaClass') }.should raise_error(TypeError)
- lambda { @o.send(@method, :KindaClass) }.should raise_error(TypeError)
- lambda { @o.send(@method, Object.new) }.should raise_error(TypeError)
+ -> { @o.send(@method, 1) }.should raise_error(TypeError)
+ -> { @o.send(@method, 'KindaClass') }.should raise_error(TypeError)
+ -> { @o.send(@method, :KindaClass) }.should raise_error(TypeError)
+ -> { @o.send(@method, Object.new) }.should raise_error(TypeError)
+ end
+
+ it "does not take into account `class` method overriding" do
+ def @o.class; Integer; end
+
+ @o.send(@method, Integer).should == false
+ @o.send(@method, KernelSpecs::KindaClass).should == true
end
end
diff --git a/spec/ruby/core/kernel/shared/lambda.rb b/spec/ruby/core/kernel/shared/lambda.rb
index bebb111c43..c70640082a 100644
--- a/spec/ruby/core/kernel/shared/lambda.rb
+++ b/spec/ruby/core/kernel/shared/lambda.rb
@@ -4,6 +4,8 @@ describe :kernel_lambda, shared: true do
end
it "raises an ArgumentError when no block is given" do
- lambda { send(@method) }.should raise_error(ArgumentError)
+ suppress_warning do
+ -> { send(@method) }.should raise_error(ArgumentError)
+ end
end
end
diff --git a/spec/ruby/core/kernel/shared/load.rb b/spec/ruby/core/kernel/shared/load.rb
index 0ce7d58d2c..62c5c7be9b 100644
--- a/spec/ruby/core/kernel/shared/load.rb
+++ b/spec/ruby/core/kernel/shared/load.rb
@@ -1,3 +1,6 @@
+main = self
+
+# The big difference is Kernel#load does not attempt to add an extension to the passed path, unlike Kernel#require
describe :kernel_load, shared: true do
before :each do
CodeLoadingSpecs.spec_setup
@@ -8,31 +11,39 @@ describe :kernel_load, shared: true do
CodeLoadingSpecs.spec_cleanup
end
- it "loads a non-extensioned file as a Ruby source file" do
- path = File.expand_path "load_fixture", CODE_LOADING_DIR
- @object.load(path).should be_true
- ScratchPad.recorded.should == [:no_ext]
- end
+ describe "(path resolution)" do
+ # This behavior is specific to Kernel#load, it differs for Kernel#require
+ it "loads a non-extensioned file as a Ruby source file" do
+ path = File.expand_path "load_fixture", CODE_LOADING_DIR
+ @object.load(path).should be_true
+ ScratchPad.recorded.should == [:no_ext]
+ end
- it "loads a non .rb extensioned file as a Ruby source file" do
- path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
- @object.load(path).should be_true
- ScratchPad.recorded.should == [:no_rb_ext]
- end
+ it "loads a non .rb extensioned file as a Ruby source file" do
+ path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
+ @object.load(path).should be_true
+ ScratchPad.recorded.should == [:no_rb_ext]
+ end
- it "loads from the current working directory" do
- Dir.chdir CODE_LOADING_DIR do
- @object.load("load_fixture.rb").should be_true
- ScratchPad.recorded.should == [:loaded]
+ it "loads from the current working directory" do
+ Dir.chdir CODE_LOADING_DIR do
+ @object.load("load_fixture.rb").should be_true
+ ScratchPad.recorded.should == [:loaded]
+ end
+ end
+
+ # This behavior is specific to Kernel#load, it differs for Kernel#require
+ it "does not look for a c-extension file when passed a path without extension (when no .rb is present)" do
+ path = File.join CODE_LOADING_DIR, "a", "load_fixture"
+ -> { @object.send(@method, path) }.should raise_error(LoadError)
end
end
it "loads a file that recursively requires itself" do
path = File.expand_path "recursive_require_fixture.rb", CODE_LOADING_DIR
-> {
- $VERBOSE = true
@object.load(path).should be_true
- }.should complain(/circular require considered harmful/)
+ }.should complain(/circular require considered harmful/, verbose: true)
ScratchPad.recorded.should == [:loaded, :loaded]
end
@@ -82,27 +93,59 @@ describe :kernel_load, shared: true do
it "raises a LoadError if passed a non-extensioned path that does not exist but a .rb extensioned path does exist" do
path = File.expand_path "load_ext_fixture", CODE_LOADING_DIR
- lambda { @object.load(path) }.should raise_error(LoadError)
+ -> { @object.load(path) }.should raise_error(LoadError)
end
describe "when passed true for 'wrap'" do
it "loads from an existing path" do
- path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true).should be_true
end
it "sets the enclosing scope to an anonymous module" do
- path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
Object.const_defined?(:LoadSpecWrap).should be_false
+
+ wrap_module = ScratchPad.recorded[1]
+ wrap_module.should be_an_instance_of(Module)
end
it "allows referencing outside namespaces" do
- path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
- ScratchPad.recorded.first.should be_an_instance_of(Class)
+ ScratchPad.recorded[0].should equal(String)
+ end
+
+ it "sets self as a copy of the top-level main" do
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
+ @object.load(path, true)
+
+ top_level = ScratchPad.recorded[2]
+ top_level.to_s.should == "main"
+ top_level.method(:to_s).owner.should == top_level.singleton_class
+ top_level.should_not equal(main)
+ top_level.should be_an_instance_of(Object)
+ end
+
+ it "includes modules included in main's singleton class in self's class" do
+ mod = Module.new
+ main.extend(mod)
+
+ main_ancestors = main.singleton_class.ancestors[1..-1]
+ main_ancestors.first.should == mod
+
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
+ @object.load(path, true)
+
+ top_level = ScratchPad.recorded[2]
+ top_level_ancestors = top_level.singleton_class.ancestors[-main_ancestors.size..-1]
+ top_level_ancestors.should == main_ancestors
+
+ wrap_module = ScratchPad.recorded[1]
+ top_level.singleton_class.ancestors.should == [top_level.singleton_class, wrap_module, *main_ancestors]
end
describe "with top-level methods" do
@@ -116,11 +159,44 @@ describe :kernel_load, shared: true do
end
it "does not pollute the receiver" do
- lambda { @object.send(:top_level_method) }.should raise_error(NameError)
+ -> { @object.send(:top_level_method) }.should raise_error(NameError)
end
end
end
+ describe "when passed a module for 'wrap'" do
+ it "sets the enclosing scope to the supplied module" do
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
+ mod = Module.new
+ @object.load(path, mod)
+
+ Object.const_defined?(:LoadSpecWrap).should be_false
+ mod.const_defined?(:LoadSpecWrap).should be_true
+
+ wrap_module = ScratchPad.recorded[1]
+ wrap_module.should == mod
+ end
+
+ it "makes constants and instance methods in the source file reachable with the supplied module" do
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
+ mod = Module.new
+ @object.load(path, mod)
+
+ mod::LOAD_WRAP_SPECS_TOP_LEVEL_CONSTANT.should == 1
+ obj = Object.new
+ obj.extend(mod)
+ obj.send(:load_wrap_specs_top_level_method).should == :load_wrap_specs_top_level_method
+ end
+
+ it "makes instance methods in the source file private" do
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
+ mod = Module.new
+ @object.load(path, mod)
+
+ mod.private_instance_methods.include?(:load_wrap_specs_top_level_method).should == true
+ end
+ end
+
describe "(shell expansion)" do
before :each do
@env_home = ENV["HOME"]
diff --git a/spec/ruby/core/kernel/shared/method.rb b/spec/ruby/core/kernel/shared/method.rb
index 1566c6ab09..8b6ab23fd3 100644
--- a/spec/ruby/core/kernel/shared/method.rb
+++ b/spec/ruby/core/kernel/shared/method.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe :kernel_method, shared: true do
it "returns a method object for a valid method" do
@@ -15,22 +15,28 @@ describe :kernel_method, shared: true do
m.call.should == 'class done'
end
- it "returns a method object if we repond_to_missing? method" do
+ it "returns a method object if respond_to_missing?(method) is true" do
m = KernelSpecs::RespondViaMissing.new.send(@method, :handled_publicly)
m.should be_an_instance_of Method
m.call(42).should == "Done handled_publicly([42])"
end
+ it "the returned method object if respond_to_missing?(method) calls #method_missing with a Symbol name" do
+ m = KernelSpecs::RespondViaMissing.new.send(@method, "handled_publicly")
+ m.should be_an_instance_of Method
+ m.call(42).should == "Done handled_publicly([42])"
+ end
+
it "raises a NameError for an invalid method name" do
class KernelSpecs::Foo; def bar; 'done'; end; end
- lambda {
+ -> {
KernelSpecs::Foo.new.send(@method, :invalid_and_silly_method_name)
}.should raise_error(NameError)
end
it "raises a NameError for an invalid singleton method name" do
class KernelSpecs::Foo; def self.bar; 'done'; end; end
- lambda { KernelSpecs::Foo.send(@method, :baz) }.should raise_error(NameError)
+ -> { KernelSpecs::Foo.send(@method, :baz) }.should raise_error(NameError)
end
it "changes the method called for super on a target aliased method" do
diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb
index 3296c7f42a..52f86f73e5 100644
--- a/spec/ruby/core/kernel/shared/require.rb
+++ b/spec/ruby/core/kernel/shared/require.rb
@@ -20,28 +20,30 @@ describe :kernel_require_basic, shared: true do
it "raises a LoadError if the file does not exist" do
path = File.expand_path "nonexistent.rb", CODE_LOADING_DIR
- File.exist?(path).should be_false
- lambda { @object.send(@method, path) }.should raise_error(LoadError)
+ File.should_not.exist?(path)
+ -> { @object.send(@method, path) }.should raise_error(LoadError)
ScratchPad.recorded.should == []
end
# Can't make a file unreadable on these platforms
platform_is_not :windows, :cygwin do
- describe "with an unreadable file" do
- before :each do
- @path = tmp("unreadable_file.rb")
- touch @path
- File.chmod 0000, @path
- end
-
- after :each do
- File.chmod 0666, @path
- rm_r @path
- end
-
- it "raises a LoadError" do
- File.exist?(@path).should be_true
- lambda { @object.send(@method, @path) }.should raise_error(LoadError)
+ as_user do
+ describe "with an unreadable file" do
+ before :each do
+ @path = tmp("unreadable_file.rb")
+ touch @path
+ File.chmod 0000, @path
+ end
+
+ after :each do
+ File.chmod 0666, @path
+ rm_r @path
+ end
+
+ it "raises a LoadError" do
+ File.should.exist?(@path)
+ -> { @object.send(@method, @path) }.should raise_error(LoadError)
+ end
end
end
end
@@ -55,19 +57,19 @@ describe :kernel_require_basic, shared: true do
end
it "raises a TypeError if passed nil" do
- lambda { @object.send(@method, nil) }.should raise_error(TypeError)
+ -> { @object.send(@method, nil) }.should raise_error(TypeError)
end
- it "raises a TypeError if passed a Fixnum" do
- lambda { @object.send(@method, 42) }.should raise_error(TypeError)
+ it "raises a TypeError if passed an Integer" do
+ -> { @object.send(@method, 42) }.should raise_error(TypeError)
end
it "raises a TypeError if passed an Array" do
- lambda { @object.send(@method, []) }.should raise_error(TypeError)
+ -> { @object.send(@method, []) }.should raise_error(TypeError)
end
it "raises a TypeError if passed an object that does not provide #to_str" do
- lambda { @object.send(@method, mock("not a filename")) }.should raise_error(TypeError)
+ -> { @object.send(@method, mock("not a filename")) }.should raise_error(TypeError)
end
it "raises a TypeError if passed an object that has #to_s but not #to_str" do
@@ -75,14 +77,14 @@ describe :kernel_require_basic, shared: true do
name.stub!(:to_s).and_return("load_fixture.rb")
$LOAD_PATH << "."
Dir.chdir CODE_LOADING_DIR do
- lambda { @object.send(@method, name) }.should raise_error(TypeError)
+ -> { @object.send(@method, name) }.should raise_error(TypeError)
end
end
it "raises a TypeError if #to_str does not return a String" do
name = mock("#to_str returns nil")
name.should_receive(:to_str).at_least(1).times.and_return(nil)
- lambda { @object.send(@method, name) }.should raise_error(TypeError)
+ -> { @object.send(@method, name) }.should raise_error(TypeError)
end
it "calls #to_path on non-String objects" do
@@ -158,17 +160,25 @@ describe :kernel_require_basic, shared: true do
ScratchPad.recorded.should == [:loaded]
end
+ it "accepts an Object with #to_path in $LOAD_PATH" do
+ obj = mock("to_path")
+ obj.should_receive(:to_path).at_least(:once).and_return(CODE_LOADING_DIR)
+ $LOAD_PATH << obj
+ @object.send(@method, "load_fixture.rb").should be_true
+ ScratchPad.recorded.should == [:loaded]
+ end
+
it "does not require file twice after $LOAD_PATH change" do
$LOAD_PATH << CODE_LOADING_DIR
@object.require("load_fixture.rb").should be_true
- $LOAD_PATH.unshift CODE_LOADING_DIR + "/gem"
+ $LOAD_PATH.push CODE_LOADING_DIR + "/gem"
@object.require("load_fixture.rb").should be_false
ScratchPad.recorded.should == [:loaded]
end
it "does not resolve a ./ relative path against $LOAD_PATH entries" do
$LOAD_PATH << CODE_LOADING_DIR
- lambda do
+ -> do
@object.send(@method, "./load_fixture.rb")
end.should raise_error(LoadError)
ScratchPad.recorded.should == []
@@ -176,7 +186,7 @@ describe :kernel_require_basic, shared: true do
it "does not resolve a ../ relative path against $LOAD_PATH entries" do
$LOAD_PATH << CODE_LOADING_DIR
- lambda do
+ -> do
@object.send(@method, "../code/load_fixture.rb")
end.should raise_error(LoadError)
ScratchPad.recorded.should == []
@@ -202,18 +212,46 @@ end
describe :kernel_require, shared: true do
describe "(path resolution)" do
+ it "loads .rb file when passed absolute path without extension" do
+ path = File.expand_path "load_fixture", CODE_LOADING_DIR
+ @object.send(@method, path).should be_true
+ # This should _not_ be [:no_ext]
+ ScratchPad.recorded.should == [:loaded]
+ end
+
+ platform_is :linux, :darwin do
+ it "loads c-extension file when passed absolute path without extension when no .rb is present" do
+ # the error message is specific to what dlerror() returns
+ path = File.join CODE_LOADING_DIR, "a", "load_fixture"
+ -> { @object.send(@method, path) }.should raise_error(LoadError)
+ end
+ end
+
+ platform_is :darwin do
+ it "loads .bundle file when passed absolute path with .so" do
+ # the error message is specific to what dlerror() returns
+ path = File.join CODE_LOADING_DIR, "a", "load_fixture.so"
+ -> { @object.send(@method, path) }.should raise_error(LoadError)
+ end
+ end
+
+ it "does not try an extra .rb if the path already ends in .rb" do
+ path = File.join CODE_LOADING_DIR, "d", "load_fixture.rb"
+ -> { @object.send(@method, path) }.should raise_error(LoadError)
+ end
+
# For reference see [ruby-core:24155] in which matz confirms this feature is
# intentional for security reasons.
it "does not load a bare filename unless the current working directory is in $LOAD_PATH" do
Dir.chdir CODE_LOADING_DIR do
- lambda { @object.require("load_fixture.rb") }.should raise_error(LoadError)
+ -> { @object.require("load_fixture.rb") }.should raise_error(LoadError)
ScratchPad.recorded.should == []
end
end
it "does not load a relative path unless the current working directory is in $LOAD_PATH" do
Dir.chdir File.dirname(CODE_LOADING_DIR) do
- lambda do
+ -> do
@object.require("code/load_fixture.rb")
end.should raise_error(LoadError)
ScratchPad.recorded.should == []
@@ -223,11 +261,21 @@ describe :kernel_require, shared: true do
it "loads a file that recursively requires itself" do
path = File.expand_path "recursive_require_fixture.rb", CODE_LOADING_DIR
-> {
- $VERBOSE = true
@object.require(path).should be_true
- }.should complain(/circular require considered harmful/)
+ }.should complain(/circular require considered harmful/, verbose: true)
ScratchPad.recorded.should == [:loaded]
end
+
+ ruby_bug "#17340", ''...'3.3' do
+ it "loads a file concurrently" do
+ path = File.expand_path "concurrent_require_fixture.rb", CODE_LOADING_DIR
+ ScratchPad.record(@object)
+ -> {
+ @object.require(path)
+ }.should_not complain(/circular require considered harmful/, verbose: true)
+ ScratchPad.recorded.join
+ end
+ end
end
describe "(non-extensioned path)" do
@@ -241,12 +289,29 @@ describe :kernel_require, shared: true do
@object.require("load_fixture").should be_true
ScratchPad.recorded.should == [:loaded]
end
+
+ it "does not load a feature twice when $LOAD_PATH has been modified" do
+ $LOAD_PATH.replace [CODE_LOADING_DIR]
+ @object.require("load_fixture").should be_true
+ $LOAD_PATH.replace [File.expand_path("b", CODE_LOADING_DIR), CODE_LOADING_DIR]
+ @object.require("load_fixture").should be_false
+ end
+
+ it "stores the missing path in a LoadError object" do
+ path = "abcd1234"
+
+ -> {
+ @object.send(@method, path)
+ }.should raise_error(LoadError) { |e|
+ e.path.should == path
+ }
+ end
end
describe "(file extensions)" do
it "loads a .rb extensioned file when passed a non-extensioned path" do
path = File.expand_path "load_fixture", CODE_LOADING_DIR
- File.exist?(path).should be_true
+ File.should.exist?(path)
@object.require(path).should be_true
ScratchPad.recorded.should == [:loaded]
end
@@ -270,7 +335,7 @@ describe :kernel_require, shared: true do
it "loads a .rb extensioned file when passed a non-.rb extensioned path" do
path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
- File.exist?(path).should be_true
+ File.should.exist?(path)
@object.require(path).should be_true
ScratchPad.recorded.should == [:loaded]
end
@@ -303,10 +368,86 @@ describe :kernel_require, shared: true do
$LOADED_FEATURES.should include(@path)
end
+ platform_is_not :windows do
+ describe "with symlinks" do
+ before :each do
+ @symlink_to_code_dir = tmp("codesymlink")
+ File.symlink(CODE_LOADING_DIR, @symlink_to_code_dir)
+
+ $LOAD_PATH.delete(CODE_LOADING_DIR)
+ $LOAD_PATH.unshift(@symlink_to_code_dir)
+ end
+
+ after :each do
+ rm_r @symlink_to_code_dir
+ end
+
+ it "does not canonicalize the path and stores a path with symlinks" do
+ symlink_path = "#{@symlink_to_code_dir}/load_fixture.rb"
+ canonical_path = "#{CODE_LOADING_DIR}/load_fixture.rb"
+ @object.require(symlink_path).should be_true
+ ScratchPad.recorded.should == [:loaded]
+
+ features = $LOADED_FEATURES.select { |path| path.end_with?('load_fixture.rb') }
+ features.should include(symlink_path)
+ features.should_not include(canonical_path)
+ end
+
+ it "stores the same path that __FILE__ returns in the required file" do
+ symlink_path = "#{@symlink_to_code_dir}/load_fixture_and__FILE__.rb"
+ @object.require(symlink_path).should be_true
+ loaded_feature = $LOADED_FEATURES.last
+ ScratchPad.recorded.should == [loaded_feature]
+ end
+
+ it "requires only once when a new matching file added to path" do
+ @object.require('load_fixture').should be_true
+ ScratchPad.recorded.should == [:loaded]
+
+ symlink_to_code_dir_two = tmp("codesymlinktwo")
+ File.symlink("#{CODE_LOADING_DIR}/b", symlink_to_code_dir_two)
+ begin
+ $LOAD_PATH.unshift(symlink_to_code_dir_two)
+
+ @object.require('load_fixture').should be_false
+ ensure
+ rm_r symlink_to_code_dir_two
+ end
+ end
+ end
+
+ describe "with symlinks in the required feature and $LOAD_PATH" do
+ before :each do
+ @dir = tmp("realdir")
+ mkdir_p @dir
+ @file = "#{@dir}/realfile.rb"
+ touch(@file) { |f| f.puts 'ScratchPad << __FILE__' }
+
+ @symlink_to_dir = tmp("symdir").freeze
+ File.symlink(@dir, @symlink_to_dir)
+ @symlink_to_file = "#{@dir}/symfile.rb"
+ File.symlink("realfile.rb", @symlink_to_file)
+ end
+
+ after :each do
+ rm_r @dir, @symlink_to_dir
+ end
+
+ it "canonicalizes the entry in $LOAD_PATH but not the filename passed to #require" do
+ $LOAD_PATH.unshift(@symlink_to_dir)
+ @object.require("symfile").should be_true
+ loaded_feature = "#{@dir}/symfile.rb"
+ ScratchPad.recorded.should == [loaded_feature]
+ $".last.should == loaded_feature
+ $LOAD_PATH[0].should == @symlink_to_dir
+ end
+ end
+ end
+
it "does not store the path if the load fails" do
$LOAD_PATH << CODE_LOADING_DIR
saved_loaded_features = $LOADED_FEATURES.dup
- lambda { @object.require("raise_fixture.rb") }.should raise_error(RuntimeError)
+ -> { @object.require("raise_fixture.rb") }.should raise_error(RuntimeError)
$LOADED_FEATURES.should == saved_loaded_features
end
@@ -415,7 +556,7 @@ describe :kernel_require, shared: true do
$LOADED_FEATURES.should include(@path)
end
- it "canonicalizes non-unique absolute paths" do
+ it "expands absolute paths containing .." do
path = File.join CODE_LOADING_DIR, "..", "code", "load_fixture.rb"
@object.require(path).should be_true
$LOADED_FEATURES.should include(@path)
@@ -452,46 +593,30 @@ describe :kernel_require, shared: true do
ScratchPad.recorded.should == []
end
- ruby_version_is "2.2"..."2.3" do
- it "complex, enumerator, rational and unicode_normalize are already required" do
- provided = %w[complex enumerator rational unicode_normalize]
- features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems')
- provided.each { |feature|
- features.should =~ /\b#{feature}\.(rb|so)$/
- }
+ it "unicode_normalize is part of core and not $LOADED_FEATURES" do
+ features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems')
+ features.lines.each { |feature|
+ feature.should_not include("unicode_normalize")
+ }
- code = provided.map { |f| "puts require #{f.inspect}\n" }.join
- required = ruby_exe(code, options: '--disable-gems')
- required.should == "false\n" * provided.size
- end
+ -> { @object.require("unicode_normalize") }.should raise_error(LoadError)
end
- ruby_version_is "2.3"..."2.5" do
- it "complex, enumerator, rational, thread and unicode_normalize are already required" do
- provided = %w[complex enumerator rational thread unicode_normalize]
- features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems')
- provided.each { |feature|
- features.should =~ /\b#{feature}\.(rb|so|jar)$/
- }
-
- code = provided.map { |f| "puts require #{f.inspect}\n" }.join
- required = ruby_exe(code, options: '--disable-gems')
- required.should == "false\n" * provided.size
+ it "does not load a file earlier on the $LOAD_PATH when other similar features were already loaded" do
+ Dir.chdir CODE_LOADING_DIR do
+ @object.send(@method, "../code/load_fixture").should be_true
end
- end
+ ScratchPad.recorded.should == [:loaded]
- ruby_version_is "2.5" do
- it "complex, enumerator, rational and thread are already required" do
- provided = %w[complex enumerator rational thread]
- features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems')
- provided.each { |feature|
- features.should =~ /\b#{feature}\.(rb|so|jar)$/
- }
+ $LOAD_PATH.unshift "#{CODE_LOADING_DIR}/b"
+ # This loads because the above load was not on the $LOAD_PATH
+ @object.send(@method, "load_fixture").should be_true
+ ScratchPad.recorded.should == [:loaded, :loaded]
- code = provided.map { |f| "puts require #{f.inspect}\n" }.join
- required = ruby_exe(code, options: '--disable-gems')
- required.should == "false\n" * provided.size
- end
+ $LOAD_PATH.unshift "#{CODE_LOADING_DIR}/c"
+ # This does not load because the above load was on the $LOAD_PATH
+ @object.send(@method, "load_fixture").should be_false
+ ScratchPad.recorded.should == [:loaded, :loaded]
end
end
@@ -613,7 +738,7 @@ describe :kernel_require, shared: true do
Thread.current[:wait_for] = t2
Thread.current[:con_raise] = true
- lambda {
+ -> {
@object.require(@path)
}.should raise_error(RuntimeError)
@@ -654,7 +779,7 @@ describe :kernel_require, shared: true do
t1 = Thread.new do
Thread.current[:con_raise] = true
- lambda {
+ -> {
@object.require(@path)
}.should raise_error(RuntimeError)
@@ -694,10 +819,30 @@ describe :kernel_require, shared: true do
it "stores the missing path in a LoadError object" do
path = "abcd1234"
- lambda {
+ -> {
@object.send(@method, path)
}.should raise_error(LoadError) { |e|
e.path.should == path
}
end
+
+ platform_is :linux, :darwin do
+ it "does not store the missing path in a LoadError object when c-extension file exists but loading fails and passed absolute path without extension" do
+ # the error message is specific to what dlerror() returns
+ path = File.join CODE_LOADING_DIR, "a", "load_fixture"
+ -> { @object.send(@method, path) }.should raise_error(LoadError) { |e|
+ e.path.should == nil
+ }
+ end
+ end
+
+ platform_is :darwin do
+ it "does not store the missing path in a LoadError object when c-extension file exists but loading fails and passed absolute path with extension" do
+ # the error message is specific to what dlerror() returns
+ path = File.join CODE_LOADING_DIR, "a", "load_fixture.bundle"
+ -> { @object.send(@method, path) }.should raise_error(LoadError) { |e|
+ e.path.should == nil
+ }
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/shared/sprintf.rb b/spec/ruby/core/kernel/shared/sprintf.rb
index e595a06640..2b2c6c9b63 100644
--- a/spec/ruby/core/kernel/shared/sprintf.rb
+++ b/spec/ruby/core/kernel/shared/sprintf.rb
@@ -1,8 +1,4 @@
describe :kernel_sprintf, shared: true do
- def format(*args)
- @method.call(*args)
- end
-
describe "integer formats" do
it "converts argument into Integer with to_int" do
obj = Object.new
@@ -10,7 +6,7 @@ describe :kernel_sprintf, shared: true do
def obj.to_int; 10; end
obj.should_receive(:to_int).and_return(10)
- format("%b", obj).should == "1010"
+ @method.call("%b", obj).should == "1010"
end
it "converts argument into Integer with to_i if to_int isn't available" do
@@ -18,35 +14,36 @@ describe :kernel_sprintf, shared: true do
def obj.to_i; 10; end
obj.should_receive(:to_i).and_return(10)
- format("%b", obj).should == "1010"
+ @method.call("%b", obj).should == "1010"
end
it "converts String argument with Kernel#Integer" do
- format("%d", "0b1010").should == "10"
- format("%d", "112").should == "112"
- format("%d", "0127").should == "87"
- format("%d", "0xc4").should == "196"
+ @method.call("%d", "0b1010").should == "10"
+ @method.call("%d", "112").should == "112"
+ @method.call("%d", "0127").should == "87"
+ @method.call("%d", "0xc4").should == "196"
+ @method.call("%d", "0").should == "0"
end
it "raises TypeError exception if cannot convert to Integer" do
- -> () {
- format("%b", Object.new)
+ -> {
+ @method.call("%b", Object.new)
}.should raise_error(TypeError)
end
["b", "B"].each do |f|
describe f do
it "converts argument as a binary number" do
- format("%#{f}", 10).should == "1010"
+ @method.call("%#{f}", 10).should == "1010"
end
it "displays negative number as a two's complement prefixed with '..1'" do
- format("%#{f}", -10).should == "..1" + "0110"
+ @method.call("%#{f}", -10).should == "..1" + "0110"
end
it "collapse negative number representation if it equals 1" do
- format("%#{f}", -1).should_not == "..11"
- format("%#{f}", -1).should == "..1"
+ @method.call("%#{f}", -1).should_not == "..11"
+ @method.call("%#{f}", -1).should == "..1"
end
end
end
@@ -54,58 +51,63 @@ describe :kernel_sprintf, shared: true do
["d", "i", "u"].each do |f|
describe f do
it "converts argument as a decimal number" do
- format("%#{f}", 112).should == "112"
- format("%#{f}", -112).should == "-112"
+ @method.call("%#{f}", 112).should == "112"
+ @method.call("%#{f}", -112).should == "-112"
end
it "works well with large numbers" do
- format("%#{f}", 1234567890987654321).should == "1234567890987654321"
+ @method.call("%#{f}", 1234567890987654321).should == "1234567890987654321"
+ end
+
+ it "converts to the empty string if precision is 0 and value is 0" do
+ @method.call("%.#{f}", 0).should == ""
+ @method.call("%.0#{f}", 0).should == ""
end
end
end
describe "o" do
it "converts argument as an octal number" do
- format("%o", 87).should == "127"
+ @method.call("%o", 87).should == "127"
end
it "displays negative number as a two's complement prefixed with '..7'" do
- format("%o", -87).should == "..7" + "651"
+ @method.call("%o", -87).should == "..7" + "651"
end
it "collapse negative number representation if it equals 7" do
- format("%o", -1).should_not == "..77"
- format("%o", -1).should == "..7"
+ @method.call("%o", -1).should_not == "..77"
+ @method.call("%o", -1).should == "..7"
end
end
describe "x" do
it "converts argument as a hexadecimal number" do
- format("%x", 196).should == "c4"
+ @method.call("%x", 196).should == "c4"
end
it "displays negative number as a two's complement prefixed with '..f'" do
- format("%x", -196).should == "..f" + "3c"
+ @method.call("%x", -196).should == "..f" + "3c"
end
it "collapse negative number representation if it equals f" do
- format("%x", -1).should_not == "..ff"
- format("%x", -1).should == "..f"
+ @method.call("%x", -1).should_not == "..ff"
+ @method.call("%x", -1).should == "..f"
end
end
describe "X" do
it "converts argument as a hexadecimal number with uppercase letters" do
- format("%X", 196).should == "C4"
+ @method.call("%X", 196).should == "C4"
end
it "displays negative number as a two's complement prefixed with '..f'" do
- format("%X", -196).should == "..F" + "3C"
+ @method.call("%X", -196).should == "..F" + "3C"
end
it "collapse negative number representation if it equals F" do
- format("%X", -1).should_not == "..FF"
- format("%X", -1).should == "..F"
+ @method.call("%X", -1).should_not == "..FF"
+ @method.call("%X", -1).should == "..F"
end
end
end
@@ -114,70 +116,70 @@ describe :kernel_sprintf, shared: true do
it "converts argument into Float" do
obj = mock("float")
obj.should_receive(:to_f).and_return(9.6)
- format("%f", obj).should == "9.600000"
+ @method.call("%f", obj).should == "9.600000"
end
it "raises TypeError exception if cannot convert to Float" do
- -> () {
- format("%f", Object.new)
+ -> {
+ @method.call("%f", Object.new)
}.should raise_error(TypeError)
end
{"e" => "e", "E" => "E"}.each_pair do |f, exp|
describe f do
it "converts argument into exponential notation [-]d.dddddde[+-]dd" do
- format("%#{f}", 109.52).should == "1.095200#{exp}+02"
- format("%#{f}", -109.52).should == "-1.095200#{exp}+02"
- format("%#{f}", 0.10952).should == "1.095200#{exp}-01"
- format("%#{f}", -0.10952).should == "-1.095200#{exp}-01"
+ @method.call("%#{f}", 109.52).should == "1.095200#{exp}+02"
+ @method.call("%#{f}", -109.52).should == "-1.095200#{exp}+02"
+ @method.call("%#{f}", 0.10952).should == "1.095200#{exp}-01"
+ @method.call("%#{f}", -0.10952).should == "-1.095200#{exp}-01"
end
it "cuts excessive digits and keeps only 6 ones" do
- format("%#{f}", 1.123456789).should == "1.123457#{exp}+00"
+ @method.call("%#{f}", 1.123456789).should == "1.123457#{exp}+00"
end
it "rounds the last significant digit to the closest one" do
- format("%#{f}", 1.555555555).should == "1.555556#{exp}+00"
- format("%#{f}", -1.555555555).should == "-1.555556#{exp}+00"
- format("%#{f}", 1.444444444).should == "1.444444#{exp}+00"
+ @method.call("%#{f}", 1.555555555).should == "1.555556#{exp}+00"
+ @method.call("%#{f}", -1.555555555).should == "-1.555556#{exp}+00"
+ @method.call("%#{f}", 1.444444444).should == "1.444444#{exp}+00"
end
it "displays Float::INFINITY as Inf" do
- format("%#{f}", Float::INFINITY).should == "Inf"
- format("%#{f}", -Float::INFINITY).should == "-Inf"
+ @method.call("%#{f}", Float::INFINITY).should == "Inf"
+ @method.call("%#{f}", -Float::INFINITY).should == "-Inf"
end
it "displays Float::NAN as NaN" do
- format("%#{f}", Float::NAN).should == "NaN"
- format("%#{f}", -Float::NAN).should == "NaN"
+ @method.call("%#{f}", Float::NAN).should == "NaN"
+ @method.call("%#{f}", -Float::NAN).should == "NaN"
end
end
end
describe "f" do
it "converts floating point argument as [-]ddd.dddddd" do
- format("%f", 10.952).should == "10.952000"
- format("%f", -10.952).should == "-10.952000"
+ @method.call("%f", 10.952).should == "10.952000"
+ @method.call("%f", -10.952).should == "-10.952000"
end
it "cuts excessive digits and keeps only 6 ones" do
- format("%f", 1.123456789).should == "1.123457"
+ @method.call("%f", 1.123456789).should == "1.123457"
end
it "rounds the last significant digit to the closest one" do
- format("%f", 1.555555555).should == "1.555556"
- format("%f", -1.555555555).should == "-1.555556"
- format("%f", 1.444444444).should == "1.444444"
+ @method.call("%f", 1.555555555).should == "1.555556"
+ @method.call("%f", -1.555555555).should == "-1.555556"
+ @method.call("%f", 1.444444444).should == "1.444444"
end
it "displays Float::INFINITY as Inf" do
- format("%f", Float::INFINITY).should == "Inf"
- format("%f", -Float::INFINITY).should == "-Inf"
+ @method.call("%f", Float::INFINITY).should == "Inf"
+ @method.call("%f", -Float::INFINITY).should == "-Inf"
end
it "displays Float::NAN as NaN" do
- format("%f", Float::NAN).should == "NaN"
- format("%f", -Float::NAN).should == "NaN"
+ @method.call("%f", Float::NAN).should == "NaN"
+ @method.call("%f", -Float::NAN).should == "NaN"
end
end
@@ -185,100 +187,100 @@ describe :kernel_sprintf, shared: true do
describe f do
context "the exponent is less than -4" do
it "converts a floating point number using exponential form" do
- format("%#{f}", 0.0000123456).should == "1.23456#{exp}-05"
- format("%#{f}", -0.0000123456).should == "-1.23456#{exp}-05"
+ @method.call("%#{f}", 0.0000123456).should == "1.23456#{exp}-05"
+ @method.call("%#{f}", -0.0000123456).should == "-1.23456#{exp}-05"
- format("%#{f}", 0.000000000123456).should == "1.23456#{exp}-10"
- format("%#{f}", -0.000000000123456).should == "-1.23456#{exp}-10"
+ @method.call("%#{f}", 0.000000000123456).should == "1.23456#{exp}-10"
+ @method.call("%#{f}", -0.000000000123456).should == "-1.23456#{exp}-10"
end
end
context "the exponent is greater than or equal to the precision (6 by default)" do
it "converts a floating point number using exponential form" do
- format("%#{f}", 1234567).should == "1.23457#{exp}+06"
- format("%#{f}", 1234567890123).should == "1.23457#{exp}+12"
- format("%#{f}", -1234567).should == "-1.23457#{exp}+06"
+ @method.call("%#{f}", 1234567).should == "1.23457#{exp}+06"
+ @method.call("%#{f}", 1234567890123).should == "1.23457#{exp}+12"
+ @method.call("%#{f}", -1234567).should == "-1.23457#{exp}+06"
end
end
context "otherwise" do
it "converts a floating point number in dd.dddd form" do
- format("%#{f}", 0.0001).should == "0.0001"
- format("%#{f}", -0.0001).should == "-0.0001"
- format("%#{f}", 123456).should == "123456"
- format("%#{f}", -123456).should == "-123456"
+ @method.call("%#{f}", 0.0001).should == "0.0001"
+ @method.call("%#{f}", -0.0001).should == "-0.0001"
+ @method.call("%#{f}", 123456).should == "123456"
+ @method.call("%#{f}", -123456).should == "-123456"
end
it "cuts excessive digits in fractional part and keeps only 4 ones" do
- format("%#{f}", 12.12341111).should == "12.1234"
- format("%#{f}", -12.12341111).should == "-12.1234"
+ @method.call("%#{f}", 12.12341111).should == "12.1234"
+ @method.call("%#{f}", -12.12341111).should == "-12.1234"
end
it "rounds the last significant digit to the closest one in fractional part" do
- format("%#{f}", 1.555555555).should == "1.55556"
- format("%#{f}", -1.555555555).should == "-1.55556"
- format("%#{f}", 1.444444444).should == "1.44444"
+ @method.call("%#{f}", 1.555555555).should == "1.55556"
+ @method.call("%#{f}", -1.555555555).should == "-1.55556"
+ @method.call("%#{f}", 1.444444444).should == "1.44444"
end
it "cuts fraction part to have only 6 digits at all" do
- format("%#{f}", 1.1234567).should == "1.12346"
- format("%#{f}", 12.1234567).should == "12.1235"
- format("%#{f}", 123.1234567).should == "123.123"
- format("%#{f}", 1234.1234567).should == "1234.12"
- format("%#{f}", 12345.1234567).should == "12345.1"
- format("%#{f}", 123456.1234567).should == "123456"
+ @method.call("%#{f}", 1.1234567).should == "1.12346"
+ @method.call("%#{f}", 12.1234567).should == "12.1235"
+ @method.call("%#{f}", 123.1234567).should == "123.123"
+ @method.call("%#{f}", 1234.1234567).should == "1234.12"
+ @method.call("%#{f}", 12345.1234567).should == "12345.1"
+ @method.call("%#{f}", 123456.1234567).should == "123456"
end
end
it "displays Float::INFINITY as Inf" do
- format("%#{f}", Float::INFINITY).should == "Inf"
- format("%#{f}", -Float::INFINITY).should == "-Inf"
+ @method.call("%#{f}", Float::INFINITY).should == "Inf"
+ @method.call("%#{f}", -Float::INFINITY).should == "-Inf"
end
it "displays Float::NAN as NaN" do
- format("%#{f}", Float::NAN).should == "NaN"
- format("%#{f}", -Float::NAN).should == "NaN"
+ @method.call("%#{f}", Float::NAN).should == "NaN"
+ @method.call("%#{f}", -Float::NAN).should == "NaN"
end
end
end
describe "a" do
it "converts floating point argument as [-]0xh.hhhhp[+-]dd" do
- format("%a", 196).should == "0x1.88p+7"
- format("%a", -196).should == "-0x1.88p+7"
- format("%a", 196.1).should == "0x1.8833333333333p+7"
- format("%a", 0.01).should == "0x1.47ae147ae147bp-7"
- format("%a", -0.01).should == "-0x1.47ae147ae147bp-7"
+ @method.call("%a", 196).should == "0x1.88p+7"
+ @method.call("%a", -196).should == "-0x1.88p+7"
+ @method.call("%a", 196.1).should == "0x1.8833333333333p+7"
+ @method.call("%a", 0.01).should == "0x1.47ae147ae147bp-7"
+ @method.call("%a", -0.01).should == "-0x1.47ae147ae147bp-7"
end
it "displays Float::INFINITY as Inf" do
- format("%a", Float::INFINITY).should == "Inf"
- format("%a", -Float::INFINITY).should == "-Inf"
+ @method.call("%a", Float::INFINITY).should == "Inf"
+ @method.call("%a", -Float::INFINITY).should == "-Inf"
end
it "displays Float::NAN as NaN" do
- format("%a", Float::NAN).should == "NaN"
- format("%a", -Float::NAN).should == "NaN"
+ @method.call("%a", Float::NAN).should == "NaN"
+ @method.call("%a", -Float::NAN).should == "NaN"
end
end
describe "A" do
it "converts floating point argument as [-]0xh.hhhhp[+-]dd and use uppercase X and P" do
- format("%A", 196).should == "0X1.88P+7"
- format("%A", -196).should == "-0X1.88P+7"
- format("%A", 196.1).should == "0X1.8833333333333P+7"
- format("%A", 0.01).should == "0X1.47AE147AE147BP-7"
- format("%A", -0.01).should == "-0X1.47AE147AE147BP-7"
+ @method.call("%A", 196).should == "0X1.88P+7"
+ @method.call("%A", -196).should == "-0X1.88P+7"
+ @method.call("%A", 196.1).should == "0X1.8833333333333P+7"
+ @method.call("%A", 0.01).should == "0X1.47AE147AE147BP-7"
+ @method.call("%A", -0.01).should == "-0X1.47AE147AE147BP-7"
end
it "displays Float::INFINITY as Inf" do
- format("%A", Float::INFINITY).should == "Inf"
- format("%A", -Float::INFINITY).should == "-Inf"
+ @method.call("%A", Float::INFINITY).should == "Inf"
+ @method.call("%A", -Float::INFINITY).should == "-Inf"
end
it "displays Float::NAN as NaN" do
- format("%A", Float::NAN).should == "NaN"
- format("%A", -Float::NAN).should == "NaN"
+ @method.call("%A", Float::NAN).should == "NaN"
+ @method.call("%A", -Float::NAN).should == "NaN"
end
end
end
@@ -286,28 +288,71 @@ describe :kernel_sprintf, shared: true do
describe "other formats" do
describe "c" do
it "displays character if argument is a numeric code of character" do
- format("%c", 97).should == "a"
+ @method.call("%c", 97).should == "a"
end
it "displays character if argument is a single character string" do
- format("%c", "a").should == "a"
+ @method.call("%c", "a").should == "a"
end
- it "raises ArgumentError if argument is a string of several characters" do
- -> () {
- format("%c", "abc")
- }.should raise_error(ArgumentError)
+ it "displays only the first character if argument is a string of several characters" do
+ @method.call("%c", "abc").should == "a"
end
- it "raises ArgumentError if argument is an empty string" do
- -> () {
- format("%c", "")
- }.should raise_error(ArgumentError)
+ it "displays no characters if argument is an empty string" do
+ @method.call("%c", "").should == ""
+ end
+
+ it "raises TypeError if argument is not String or Integer and cannot be converted to them" do
+ -> {
+ @method.call("%c", [])
+ }.should raise_error(TypeError, /no implicit conversion of Array into Integer/)
+ end
+
+ it "raises TypeError if argument is nil" do
+ -> {
+ @method.call("%c", nil)
+ }.should raise_error(TypeError, /no implicit conversion from nil to integer/)
end
- it "supports Unicode characters" do
- format("%c", 1286).should == "Ԇ"
- format("%c", "ش").should == "ش"
+ it "tries to convert argument to String with to_str" do
+ obj = BasicObject.new
+ def obj.to_str
+ "a"
+ end
+
+ @method.call("%c", obj).should == "a"
+ end
+
+ it "tries to convert argument to Integer with to_int" do
+ obj = BasicObject.new
+ def obj.to_int
+ 90
+ end
+
+ @method.call("%c", obj).should == "Z"
+ end
+
+ it "raises TypeError if converting to String with to_str returns non-String" do
+ obj = BasicObject.new
+ def obj.to_str
+ :foo
+ end
+
+ -> {
+ @method.call("%c", obj)
+ }.should raise_error(TypeError, /can't convert BasicObject to String/)
+ end
+
+ it "raises TypeError if converting to Integer with to_int returns non-Integer" do
+ obj = BasicObject.new
+ def obj.to_int
+ :foo
+ end
+
+ -> {
+ @method.call("%c", obj)
+ }.should raise_error(TypeError, /can't convert BasicObject to Integer/)
end
end
@@ -315,19 +360,27 @@ describe :kernel_sprintf, shared: true do
it "displays argument.inspect value" do
obj = mock("object")
obj.should_receive(:inspect).and_return("<inspect-result>")
- format("%p", obj).should == "<inspect-result>"
+ @method.call("%p", obj).should == "<inspect-result>"
+ end
+
+ it "substitutes 'nil' for nil" do
+ @method.call("%p", nil).should == "nil"
end
end
describe "s" do
it "substitute argument passes as a string" do
- format("%s", "abc").should == "abc"
+ @method.call("%s", "abc").should == "abc"
+ end
+
+ it "substitutes '' for nil" do
+ @method.call("%s", nil).should == ""
end
it "converts argument to string with to_s" do
obj = mock("string")
obj.should_receive(:to_s).and_return("abc")
- format("%s", obj).should == "abc"
+ @method.call("%s", obj).should == "abc"
end
it "does not try to convert with to_str" do
@@ -336,30 +389,67 @@ describe :kernel_sprintf, shared: true do
"abc"
end
- -> () {
- format("%s", obj)
+ -> {
+ @method.call("%s", obj)
}.should raise_error(NoMethodError)
end
- end
- describe "%" do
- ruby_version_is ""..."2.5" do
- it "alone displays the percent sign" do
- format("%").should == "%"
- end
+ it "formats a partial substring without including omitted characters" do
+ long_string = "aabbccddhelloddccbbaa"
+ sub_string = long_string[8, 5]
+ sprintf("%.#{1 * 3}s", sub_string).should == "hel"
end
- ruby_version_is "2.5" do
- it "alone raises an ArgumentError" do
- -> {
- format("%")
- }.should raise_error(ArgumentError)
- end
+ it "formats string with precision" do
+ Kernel.format("%.3s", "hello").should == "hel"
+ Kernel.format("%-3.3s", "hello").should == "hel"
+ end
+
+ it "formats string with width" do
+ @method.call("%6s", "abc").should == " abc"
+ @method.call("%6s", "abcdefg").should == "abcdefg"
+ end
+
+ it "formats string with width and precision" do
+ @method.call("%4.6s", "abc").should == " abc"
+ @method.call("%4.6s", "abcdefg").should == "abcdef"
+ end
+
+ it "formats nil with width" do
+ @method.call("%6s", nil).should == " "
+ end
+
+ it "formats nil with precision" do
+ @method.call("%.6s", nil).should == ""
+ end
+
+ it "formats nil with width and precision" do
+ @method.call("%4.6s", nil).should == " "
+ end
+
+ it "formats multibyte string with precision" do
+ Kernel.format("%.2s", "été").should == "ét"
+ end
+
+ it "preserves encoding of the format string" do
+ str = format('%s'.encode(Encoding::UTF_8), 'foobar')
+ str.encoding.should == Encoding::UTF_8
+
+ str = format('%s'.encode(Encoding::US_ASCII), 'foobar')
+ str.encoding.should == Encoding::US_ASCII
+ end
+ end
+
+ describe "%" do
+ it "alone raises an ArgumentError" do
+ -> {
+ @method.call("%")
+ }.should raise_error(ArgumentError)
end
it "is escaped by %" do
- format("%%").should == "%"
- format("%%d", 10).should == "%d"
+ @method.call("%%").should == "%"
+ @method.call("%%d").should == "%d"
end
end
end
@@ -368,110 +458,110 @@ describe :kernel_sprintf, shared: true do
describe "space" do
context "applies to numeric formats bBdiouxXeEfgGaA" do
it "leaves a space at the start of non-negative numbers" do
- format("% b", 10).should == " 1010"
- format("% B", 10).should == " 1010"
- format("% d", 112).should == " 112"
- format("% i", 112).should == " 112"
- format("% o", 87).should == " 127"
- format("% u", 112).should == " 112"
- format("% x", 196).should == " c4"
- format("% X", 196).should == " C4"
-
- format("% e", 109.52).should == " 1.095200e+02"
- format("% E", 109.52).should == " 1.095200E+02"
- format("% f", 10.952).should == " 10.952000"
- format("% g", 12.1234).should == " 12.1234"
- format("% G", 12.1234).should == " 12.1234"
- format("% a", 196).should == " 0x1.88p+7"
- format("% A", 196).should == " 0X1.88P+7"
+ @method.call("% b", 10).should == " 1010"
+ @method.call("% B", 10).should == " 1010"
+ @method.call("% d", 112).should == " 112"
+ @method.call("% i", 112).should == " 112"
+ @method.call("% o", 87).should == " 127"
+ @method.call("% u", 112).should == " 112"
+ @method.call("% x", 196).should == " c4"
+ @method.call("% X", 196).should == " C4"
+
+ @method.call("% e", 109.52).should == " 1.095200e+02"
+ @method.call("% E", 109.52).should == " 1.095200E+02"
+ @method.call("% f", 10.952).should == " 10.952000"
+ @method.call("% g", 12.1234).should == " 12.1234"
+ @method.call("% G", 12.1234).should == " 12.1234"
+ @method.call("% a", 196).should == " 0x1.88p+7"
+ @method.call("% A", 196).should == " 0X1.88P+7"
end
it "does not leave a space at the start of negative numbers" do
- format("% b", -10).should == "-1010"
- format("% B", -10).should == "-1010"
- format("% d", -112).should == "-112"
- format("% i", -112).should == "-112"
- format("% o", -87).should == "-127"
- format("% u", -112).should == "-112"
- format("% x", -196).should == "-c4"
- format("% X", -196).should == "-C4"
-
- format("% e", -109.52).should == "-1.095200e+02"
- format("% E", -109.52).should == "-1.095200E+02"
- format("% f", -10.952).should == "-10.952000"
- format("% g", -12.1234).should == "-12.1234"
- format("% G", -12.1234).should == "-12.1234"
- format("% a", -196).should == "-0x1.88p+7"
- format("% A", -196).should == "-0X1.88P+7"
+ @method.call("% b", -10).should == "-1010"
+ @method.call("% B", -10).should == "-1010"
+ @method.call("% d", -112).should == "-112"
+ @method.call("% i", -112).should == "-112"
+ @method.call("% o", -87).should == "-127"
+ @method.call("% u", -112).should == "-112"
+ @method.call("% x", -196).should == "-c4"
+ @method.call("% X", -196).should == "-C4"
+
+ @method.call("% e", -109.52).should == "-1.095200e+02"
+ @method.call("% E", -109.52).should == "-1.095200E+02"
+ @method.call("% f", -10.952).should == "-10.952000"
+ @method.call("% g", -12.1234).should == "-12.1234"
+ @method.call("% G", -12.1234).should == "-12.1234"
+ @method.call("% a", -196).should == "-0x1.88p+7"
+ @method.call("% A", -196).should == "-0X1.88P+7"
end
it "prevents converting negative argument to two's complement form" do
- format("% b", -10).should == "-1010"
- format("% B", -10).should == "-1010"
- format("% o", -87).should == "-127"
- format("% x", -196).should == "-c4"
- format("% X", -196).should == "-C4"
+ @method.call("% b", -10).should == "-1010"
+ @method.call("% B", -10).should == "-1010"
+ @method.call("% o", -87).should == "-127"
+ @method.call("% x", -196).should == "-c4"
+ @method.call("% X", -196).should == "-C4"
end
it "treats several white spaces as one" do
- format("% b", 10).should == " 1010"
- format("% B", 10).should == " 1010"
- format("% d", 112).should == " 112"
- format("% i", 112).should == " 112"
- format("% o", 87).should == " 127"
- format("% u", 112).should == " 112"
- format("% x", 196).should == " c4"
- format("% X", 196).should == " C4"
+ @method.call("% b", 10).should == " 1010"
+ @method.call("% B", 10).should == " 1010"
+ @method.call("% d", 112).should == " 112"
+ @method.call("% i", 112).should == " 112"
+ @method.call("% o", 87).should == " 127"
+ @method.call("% u", 112).should == " 112"
+ @method.call("% x", 196).should == " c4"
+ @method.call("% X", 196).should == " C4"
- format("% e", 109.52).should == " 1.095200e+02"
- format("% E", 109.52).should == " 1.095200E+02"
- format("% f", 10.952).should == " 10.952000"
- format("% g", 12.1234).should == " 12.1234"
- format("% G", 12.1234).should == " 12.1234"
- format("% a", 196).should == " 0x1.88p+7"
- format("% A", 196).should == " 0X1.88P+7"
+ @method.call("% e", 109.52).should == " 1.095200e+02"
+ @method.call("% E", 109.52).should == " 1.095200E+02"
+ @method.call("% f", 10.952).should == " 10.952000"
+ @method.call("% g", 12.1234).should == " 12.1234"
+ @method.call("% G", 12.1234).should == " 12.1234"
+ @method.call("% a", 196).should == " 0x1.88p+7"
+ @method.call("% A", 196).should == " 0X1.88P+7"
end
end
end
describe "(digit)$" do
it "specifies the absolute argument number for this field" do
- format("%2$b", 0, 10).should == "1010"
- format("%2$B", 0, 10).should == "1010"
- format("%2$d", 0, 112).should == "112"
- format("%2$i", 0, 112).should == "112"
- format("%2$o", 0, 87).should == "127"
- format("%2$u", 0, 112).should == "112"
- format("%2$x", 0, 196).should == "c4"
- format("%2$X", 0, 196).should == "C4"
-
- format("%2$e", 0, 109.52).should == "1.095200e+02"
- format("%2$E", 0, 109.52).should == "1.095200E+02"
- format("%2$f", 0, 10.952).should == "10.952000"
- format("%2$g", 0, 12.1234).should == "12.1234"
- format("%2$G", 0, 12.1234).should == "12.1234"
- format("%2$a", 0, 196).should == "0x1.88p+7"
- format("%2$A", 0, 196).should == "0X1.88P+7"
-
- format("%2$c", 1, 97).should == "a"
- format("%2$p", "a", []).should == "[]"
- format("%2$s", "-", "abc").should == "abc"
+ @method.call("%2$b", 0, 10).should == "1010"
+ @method.call("%2$B", 0, 10).should == "1010"
+ @method.call("%2$d", 0, 112).should == "112"
+ @method.call("%2$i", 0, 112).should == "112"
+ @method.call("%2$o", 0, 87).should == "127"
+ @method.call("%2$u", 0, 112).should == "112"
+ @method.call("%2$x", 0, 196).should == "c4"
+ @method.call("%2$X", 0, 196).should == "C4"
+
+ @method.call("%2$e", 0, 109.52).should == "1.095200e+02"
+ @method.call("%2$E", 0, 109.52).should == "1.095200E+02"
+ @method.call("%2$f", 0, 10.952).should == "10.952000"
+ @method.call("%2$g", 0, 12.1234).should == "12.1234"
+ @method.call("%2$G", 0, 12.1234).should == "12.1234"
+ @method.call("%2$a", 0, 196).should == "0x1.88p+7"
+ @method.call("%2$A", 0, 196).should == "0X1.88P+7"
+
+ @method.call("%2$c", 1, 97).should == "a"
+ @method.call("%2$p", "a", []).should == "[]"
+ @method.call("%2$s", "-", "abc").should == "abc"
end
it "raises exception if argument number is bigger than actual arguments list" do
- -> () {
- format("%4$d", 1, 2, 3)
+ -> {
+ @method.call("%4$d", 1, 2, 3)
}.should raise_error(ArgumentError)
end
it "ignores '-' sign" do
- format("%2$d", 1, 2, 3).should == "2"
- format("%-2$d", 1, 2, 3).should == "2"
+ @method.call("%2$d", 1, 2, 3).should == "2"
+ @method.call("%-2$d", 1, 2, 3).should == "2"
end
it "raises ArgumentError exception when absolute and relative argument numbers are mixed" do
- -> () {
- format("%1$d %d", 1, 2)
+ -> {
+ @method.call("%1$d %d", 1, 2)
}.should raise_error(ArgumentError)
end
end
@@ -479,62 +569,62 @@ describe :kernel_sprintf, shared: true do
describe "#" do
context "applies to format o" do
it "increases the precision until the first digit will be `0' if it is not formatted as complements" do
- format("%#o", 87).should == "0127"
+ @method.call("%#o", 87).should == "0127"
end
it "does nothing for negative argument" do
- format("%#o", -87).should == "..7651"
+ @method.call("%#o", -87).should == "..7651"
end
end
context "applies to formats bBxX" do
it "prefixes the result with 0x, 0X, 0b and 0B respectively for non-zero argument" do
- format("%#b", 10).should == "0b1010"
- format("%#b", -10).should == "0b..10110"
- format("%#B", 10).should == "0B1010"
- format("%#B", -10).should == "0B..10110"
+ @method.call("%#b", 10).should == "0b1010"
+ @method.call("%#b", -10).should == "0b..10110"
+ @method.call("%#B", 10).should == "0B1010"
+ @method.call("%#B", -10).should == "0B..10110"
- format("%#x", 196).should == "0xc4"
- format("%#x", -196).should == "0x..f3c"
- format("%#X", 196).should == "0XC4"
- format("%#X", -196).should == "0X..F3C"
+ @method.call("%#x", 196).should == "0xc4"
+ @method.call("%#x", -196).should == "0x..f3c"
+ @method.call("%#X", 196).should == "0XC4"
+ @method.call("%#X", -196).should == "0X..F3C"
end
it "does nothing for zero argument" do
- format("%#b", 0).should == "0"
- format("%#B", 0).should == "0"
+ @method.call("%#b", 0).should == "0"
+ @method.call("%#B", 0).should == "0"
- format("%#o", 0).should == "0"
+ @method.call("%#o", 0).should == "0"
- format("%#x", 0).should == "0"
- format("%#X", 0).should == "0"
+ @method.call("%#x", 0).should == "0"
+ @method.call("%#X", 0).should == "0"
end
end
context "applies to formats aAeEfgG" do
it "forces a decimal point to be added, even if no digits follow" do
- format("%#.0a", 16.25).should == "0x1.p+4"
- format("%#.0A", 16.25).should == "0X1.P+4"
+ @method.call("%#.0a", 16.25).should == "0x1.p+4"
+ @method.call("%#.0A", 16.25).should == "0X1.P+4"
- format("%#.0e", 100).should == "1.e+02"
- format("%#.0E", 100).should == "1.E+02"
+ @method.call("%#.0e", 100).should == "1.e+02"
+ @method.call("%#.0E", 100).should == "1.E+02"
- format("%#.0f", 123.4).should == "123."
+ @method.call("%#.0f", 123.4).should == "123."
- format("%#g", 123456).should == "123456."
- format("%#G", 123456).should == "123456."
+ @method.call("%#g", 123456).should == "123456."
+ @method.call("%#G", 123456).should == "123456."
end
it "changes format from dd.dddd to exponential form for gG" do
- format("%#.0g", 123.4).should_not == "123."
- format("%#.0g", 123.4).should == "1.e+02"
+ @method.call("%#.0g", 123.4).should_not == "123."
+ @method.call("%#.0g", 123.4).should == "1.e+02"
end
end
context "applies to gG" do
it "does not remove trailing zeros" do
- format("%#g", 123.4).should == "123.400"
- format("%#g", 123.4).should == "123.400"
+ @method.call("%#g", 123.4).should == "123.400"
+ @method.call("%#g", 123.4).should == "123.400"
end
end
end
@@ -542,186 +632,186 @@ describe :kernel_sprintf, shared: true do
describe "+" do
context "applies to numeric formats bBdiouxXaAeEfgG" do
it "adds a leading plus sign to non-negative numbers" do
- format("%+b", 10).should == "+1010"
- format("%+B", 10).should == "+1010"
- format("%+d", 112).should == "+112"
- format("%+i", 112).should == "+112"
- format("%+o", 87).should == "+127"
- format("%+u", 112).should == "+112"
- format("%+x", 196).should == "+c4"
- format("%+X", 196).should == "+C4"
-
- format("%+e", 109.52).should == "+1.095200e+02"
- format("%+E", 109.52).should == "+1.095200E+02"
- format("%+f", 10.952).should == "+10.952000"
- format("%+g", 12.1234).should == "+12.1234"
- format("%+G", 12.1234).should == "+12.1234"
- format("%+a", 196).should == "+0x1.88p+7"
- format("%+A", 196).should == "+0X1.88P+7"
+ @method.call("%+b", 10).should == "+1010"
+ @method.call("%+B", 10).should == "+1010"
+ @method.call("%+d", 112).should == "+112"
+ @method.call("%+i", 112).should == "+112"
+ @method.call("%+o", 87).should == "+127"
+ @method.call("%+u", 112).should == "+112"
+ @method.call("%+x", 196).should == "+c4"
+ @method.call("%+X", 196).should == "+C4"
+
+ @method.call("%+e", 109.52).should == "+1.095200e+02"
+ @method.call("%+E", 109.52).should == "+1.095200E+02"
+ @method.call("%+f", 10.952).should == "+10.952000"
+ @method.call("%+g", 12.1234).should == "+12.1234"
+ @method.call("%+G", 12.1234).should == "+12.1234"
+ @method.call("%+a", 196).should == "+0x1.88p+7"
+ @method.call("%+A", 196).should == "+0X1.88P+7"
end
it "does not use two's complement form for negative numbers for formats bBoxX" do
- format("%+b", -10).should == "-1010"
- format("%+B", -10).should == "-1010"
- format("%+o", -87).should == "-127"
- format("%+x", -196).should == "-c4"
- format("%+X", -196).should == "-C4"
+ @method.call("%+b", -10).should == "-1010"
+ @method.call("%+B", -10).should == "-1010"
+ @method.call("%+o", -87).should == "-127"
+ @method.call("%+x", -196).should == "-c4"
+ @method.call("%+X", -196).should == "-C4"
end
end
end
describe "-" do
it "left-justifies the result of conversion if width is specified" do
- format("%-10b", 10).should == "1010 "
- format("%-10B", 10).should == "1010 "
- format("%-10d", 112).should == "112 "
- format("%-10i", 112).should == "112 "
- format("%-10o", 87).should == "127 "
- format("%-10u", 112).should == "112 "
- format("%-10x", 196).should == "c4 "
- format("%-10X", 196).should == "C4 "
+ @method.call("%-10b", 10).should == "1010 "
+ @method.call("%-10B", 10).should == "1010 "
+ @method.call("%-10d", 112).should == "112 "
+ @method.call("%-10i", 112).should == "112 "
+ @method.call("%-10o", 87).should == "127 "
+ @method.call("%-10u", 112).should == "112 "
+ @method.call("%-10x", 196).should == "c4 "
+ @method.call("%-10X", 196).should == "C4 "
- format("%-20e", 109.52).should == "1.095200e+02 "
- format("%-20E", 109.52).should == "1.095200E+02 "
- format("%-20f", 10.952).should == "10.952000 "
- format("%-20g", 12.1234).should == "12.1234 "
- format("%-20G", 12.1234).should == "12.1234 "
- format("%-20a", 196).should == "0x1.88p+7 "
- format("%-20A", 196).should == "0X1.88P+7 "
+ @method.call("%-20e", 109.52).should == "1.095200e+02 "
+ @method.call("%-20E", 109.52).should == "1.095200E+02 "
+ @method.call("%-20f", 10.952).should == "10.952000 "
+ @method.call("%-20g", 12.1234).should == "12.1234 "
+ @method.call("%-20G", 12.1234).should == "12.1234 "
+ @method.call("%-20a", 196).should == "0x1.88p+7 "
+ @method.call("%-20A", 196).should == "0X1.88P+7 "
- format("%-10c", 97).should == "a "
- format("%-10p", []).should == "[] "
- format("%-10s", "abc").should == "abc "
+ @method.call("%-10c", 97).should == "a "
+ @method.call("%-10p", []).should == "[] "
+ @method.call("%-10s", "abc").should == "abc "
end
end
describe "0 (zero)" do
context "applies to numeric formats bBdiouxXaAeEfgG and width is specified" do
it "pads with zeros, not spaces" do
- format("%010b", 10).should == "0000001010"
- format("%010B", 10).should == "0000001010"
- format("%010d", 112).should == "0000000112"
- format("%010i", 112).should == "0000000112"
- format("%010o", 87).should == "0000000127"
- format("%010u", 112).should == "0000000112"
- format("%010x", 196).should == "00000000c4"
- format("%010X", 196).should == "00000000C4"
-
- format("%020e", 109.52).should == "000000001.095200e+02"
- format("%020E", 109.52).should == "000000001.095200E+02"
- format("%020f", 10.952).should == "0000000000010.952000"
- format("%020g", 12.1234).should == "000000000000012.1234"
- format("%020G", 12.1234).should == "000000000000012.1234"
- format("%020a", 196).should == "0x000000000001.88p+7"
- format("%020A", 196).should == "0X000000000001.88P+7"
+ @method.call("%010b", 10).should == "0000001010"
+ @method.call("%010B", 10).should == "0000001010"
+ @method.call("%010d", 112).should == "0000000112"
+ @method.call("%010i", 112).should == "0000000112"
+ @method.call("%010o", 87).should == "0000000127"
+ @method.call("%010u", 112).should == "0000000112"
+ @method.call("%010x", 196).should == "00000000c4"
+ @method.call("%010X", 196).should == "00000000C4"
+
+ @method.call("%020e", 109.52).should == "000000001.095200e+02"
+ @method.call("%020E", 109.52).should == "000000001.095200E+02"
+ @method.call("%020f", 10.952).should == "0000000000010.952000"
+ @method.call("%020g", 12.1234).should == "000000000000012.1234"
+ @method.call("%020G", 12.1234).should == "000000000000012.1234"
+ @method.call("%020a", 196).should == "0x000000000001.88p+7"
+ @method.call("%020A", 196).should == "0X000000000001.88P+7"
end
it "uses radix-1 when displays negative argument as a two's complement" do
- format("%010b", -10).should == "..11110110"
- format("%010B", -10).should == "..11110110"
- format("%010o", -87).should == "..77777651"
- format("%010x", -196).should == "..ffffff3c"
- format("%010X", -196).should == "..FFFFFF3C"
+ @method.call("%010b", -10).should == "..11110110"
+ @method.call("%010B", -10).should == "..11110110"
+ @method.call("%010o", -87).should == "..77777651"
+ @method.call("%010x", -196).should == "..ffffff3c"
+ @method.call("%010X", -196).should == "..FFFFFF3C"
end
end
end
describe "*" do
it "uses the previous argument as the field width" do
- format("%*b", 10, 10).should == " 1010"
- format("%*B", 10, 10).should == " 1010"
- format("%*d", 10, 112).should == " 112"
- format("%*i", 10, 112).should == " 112"
- format("%*o", 10, 87).should == " 127"
- format("%*u", 10, 112).should == " 112"
- format("%*x", 10, 196).should == " c4"
- format("%*X", 10, 196).should == " C4"
-
- format("%*e", 20, 109.52).should == " 1.095200e+02"
- format("%*E", 20, 109.52).should == " 1.095200E+02"
- format("%*f", 20, 10.952).should == " 10.952000"
- format("%*g", 20, 12.1234).should == " 12.1234"
- format("%*G", 20, 12.1234).should == " 12.1234"
- format("%*a", 20, 196).should == " 0x1.88p+7"
- format("%*A", 20, 196).should == " 0X1.88P+7"
-
- format("%*c", 10, 97).should == " a"
- format("%*p", 10, []).should == " []"
- format("%*s", 10, "abc").should == " abc"
+ @method.call("%*b", 10, 10).should == " 1010"
+ @method.call("%*B", 10, 10).should == " 1010"
+ @method.call("%*d", 10, 112).should == " 112"
+ @method.call("%*i", 10, 112).should == " 112"
+ @method.call("%*o", 10, 87).should == " 127"
+ @method.call("%*u", 10, 112).should == " 112"
+ @method.call("%*x", 10, 196).should == " c4"
+ @method.call("%*X", 10, 196).should == " C4"
+
+ @method.call("%*e", 20, 109.52).should == " 1.095200e+02"
+ @method.call("%*E", 20, 109.52).should == " 1.095200E+02"
+ @method.call("%*f", 20, 10.952).should == " 10.952000"
+ @method.call("%*g", 20, 12.1234).should == " 12.1234"
+ @method.call("%*G", 20, 12.1234).should == " 12.1234"
+ @method.call("%*a", 20, 196).should == " 0x1.88p+7"
+ @method.call("%*A", 20, 196).should == " 0X1.88P+7"
+
+ @method.call("%*c", 10, 97).should == " a"
+ @method.call("%*p", 10, []).should == " []"
+ @method.call("%*s", 10, "abc").should == " abc"
end
it "left-justifies the result if width is negative" do
- format("%*b", -10, 10).should == "1010 "
- format("%*B", -10, 10).should == "1010 "
- format("%*d", -10, 112).should == "112 "
- format("%*i", -10, 112).should == "112 "
- format("%*o", -10, 87).should == "127 "
- format("%*u", -10, 112).should == "112 "
- format("%*x", -10, 196).should == "c4 "
- format("%*X", -10, 196).should == "C4 "
-
- format("%*e", -20, 109.52).should == "1.095200e+02 "
- format("%*E", -20, 109.52).should == "1.095200E+02 "
- format("%*f", -20, 10.952).should == "10.952000 "
- format("%*g", -20, 12.1234).should == "12.1234 "
- format("%*G", -20, 12.1234).should == "12.1234 "
- format("%*a", -20, 196).should == "0x1.88p+7 "
- format("%*A", -20, 196).should == "0X1.88P+7 "
-
- format("%*c", -10, 97).should == "a "
- format("%*p", -10, []).should == "[] "
- format("%*s", -10, "abc").should == "abc "
+ @method.call("%*b", -10, 10).should == "1010 "
+ @method.call("%*B", -10, 10).should == "1010 "
+ @method.call("%*d", -10, 112).should == "112 "
+ @method.call("%*i", -10, 112).should == "112 "
+ @method.call("%*o", -10, 87).should == "127 "
+ @method.call("%*u", -10, 112).should == "112 "
+ @method.call("%*x", -10, 196).should == "c4 "
+ @method.call("%*X", -10, 196).should == "C4 "
+
+ @method.call("%*e", -20, 109.52).should == "1.095200e+02 "
+ @method.call("%*E", -20, 109.52).should == "1.095200E+02 "
+ @method.call("%*f", -20, 10.952).should == "10.952000 "
+ @method.call("%*g", -20, 12.1234).should == "12.1234 "
+ @method.call("%*G", -20, 12.1234).should == "12.1234 "
+ @method.call("%*a", -20, 196).should == "0x1.88p+7 "
+ @method.call("%*A", -20, 196).should == "0X1.88P+7 "
+
+ @method.call("%*c", -10, 97).should == "a "
+ @method.call("%*p", -10, []).should == "[] "
+ @method.call("%*s", -10, "abc").should == "abc "
end
it "uses the specified argument as the width if * is followed by a number and $" do
- format("%1$*2$b", 10, 10).should == " 1010"
- format("%1$*2$B", 10, 10).should == " 1010"
- format("%1$*2$d", 112, 10).should == " 112"
- format("%1$*2$i", 112, 10).should == " 112"
- format("%1$*2$o", 87, 10).should == " 127"
- format("%1$*2$u", 112, 10).should == " 112"
- format("%1$*2$x", 196, 10).should == " c4"
- format("%1$*2$X", 196, 10).should == " C4"
-
- format("%1$*2$e", 109.52, 20).should == " 1.095200e+02"
- format("%1$*2$E", 109.52, 20).should == " 1.095200E+02"
- format("%1$*2$f", 10.952, 20).should == " 10.952000"
- format("%1$*2$g", 12.1234, 20).should == " 12.1234"
- format("%1$*2$G", 12.1234, 20).should == " 12.1234"
- format("%1$*2$a", 196, 20).should == " 0x1.88p+7"
- format("%1$*2$A", 196, 20).should == " 0X1.88P+7"
-
- format("%1$*2$c", 97, 10).should == " a"
- format("%1$*2$p", [], 10).should == " []"
- format("%1$*2$s", "abc", 10).should == " abc"
+ @method.call("%1$*2$b", 10, 10).should == " 1010"
+ @method.call("%1$*2$B", 10, 10).should == " 1010"
+ @method.call("%1$*2$d", 112, 10).should == " 112"
+ @method.call("%1$*2$i", 112, 10).should == " 112"
+ @method.call("%1$*2$o", 87, 10).should == " 127"
+ @method.call("%1$*2$u", 112, 10).should == " 112"
+ @method.call("%1$*2$x", 196, 10).should == " c4"
+ @method.call("%1$*2$X", 196, 10).should == " C4"
+
+ @method.call("%1$*2$e", 109.52, 20).should == " 1.095200e+02"
+ @method.call("%1$*2$E", 109.52, 20).should == " 1.095200E+02"
+ @method.call("%1$*2$f", 10.952, 20).should == " 10.952000"
+ @method.call("%1$*2$g", 12.1234, 20).should == " 12.1234"
+ @method.call("%1$*2$G", 12.1234, 20).should == " 12.1234"
+ @method.call("%1$*2$a", 196, 20).should == " 0x1.88p+7"
+ @method.call("%1$*2$A", 196, 20).should == " 0X1.88P+7"
+
+ @method.call("%1$*2$c", 97, 10).should == " a"
+ @method.call("%1$*2$p", [], 10).should == " []"
+ @method.call("%1$*2$s", "abc", 10).should == " abc"
end
it "left-justifies the result if specified with $ argument is negative" do
- format("%1$*2$b", 10, -10).should == "1010 "
- format("%1$*2$B", 10, -10).should == "1010 "
- format("%1$*2$d", 112, -10).should == "112 "
- format("%1$*2$i", 112, -10).should == "112 "
- format("%1$*2$o", 87, -10).should == "127 "
- format("%1$*2$u", 112, -10).should == "112 "
- format("%1$*2$x", 196, -10).should == "c4 "
- format("%1$*2$X", 196, -10).should == "C4 "
-
- format("%1$*2$e", 109.52, -20).should == "1.095200e+02 "
- format("%1$*2$E", 109.52, -20).should == "1.095200E+02 "
- format("%1$*2$f", 10.952, -20).should == "10.952000 "
- format("%1$*2$g", 12.1234, -20).should == "12.1234 "
- format("%1$*2$G", 12.1234, -20).should == "12.1234 "
- format("%1$*2$a", 196, -20).should == "0x1.88p+7 "
- format("%1$*2$A", 196, -20).should == "0X1.88P+7 "
-
- format("%1$*2$c", 97, -10).should == "a "
- format("%1$*2$p", [], -10).should == "[] "
- format("%1$*2$s", "abc", -10).should == "abc "
+ @method.call("%1$*2$b", 10, -10).should == "1010 "
+ @method.call("%1$*2$B", 10, -10).should == "1010 "
+ @method.call("%1$*2$d", 112, -10).should == "112 "
+ @method.call("%1$*2$i", 112, -10).should == "112 "
+ @method.call("%1$*2$o", 87, -10).should == "127 "
+ @method.call("%1$*2$u", 112, -10).should == "112 "
+ @method.call("%1$*2$x", 196, -10).should == "c4 "
+ @method.call("%1$*2$X", 196, -10).should == "C4 "
+
+ @method.call("%1$*2$e", 109.52, -20).should == "1.095200e+02 "
+ @method.call("%1$*2$E", 109.52, -20).should == "1.095200E+02 "
+ @method.call("%1$*2$f", 10.952, -20).should == "10.952000 "
+ @method.call("%1$*2$g", 12.1234, -20).should == "12.1234 "
+ @method.call("%1$*2$G", 12.1234, -20).should == "12.1234 "
+ @method.call("%1$*2$a", 196, -20).should == "0x1.88p+7 "
+ @method.call("%1$*2$A", 196, -20).should == "0X1.88P+7 "
+
+ @method.call("%1$*2$c", 97, -10).should == "a "
+ @method.call("%1$*2$p", [], -10).should == "[] "
+ @method.call("%1$*2$s", "abc", -10).should == "abc "
end
it "raises ArgumentError when is mixed with width" do
- -> () {
- format("%*10d", 10, 112)
+ -> {
+ @method.call("%*10d", 10, 112)
}.should raise_error(ArgumentError)
end
end
@@ -729,74 +819,74 @@ describe :kernel_sprintf, shared: true do
describe "width" do
it "specifies the minimum number of characters that will be written to the result" do
- format("%10b", 10).should == " 1010"
- format("%10B", 10).should == " 1010"
- format("%10d", 112).should == " 112"
- format("%10i", 112).should == " 112"
- format("%10o", 87).should == " 127"
- format("%10u", 112).should == " 112"
- format("%10x", 196).should == " c4"
- format("%10X", 196).should == " C4"
-
- format("%20e", 109.52).should == " 1.095200e+02"
- format("%20E", 109.52).should == " 1.095200E+02"
- format("%20f", 10.952).should == " 10.952000"
- format("%20g", 12.1234).should == " 12.1234"
- format("%20G", 12.1234).should == " 12.1234"
- format("%20a", 196).should == " 0x1.88p+7"
- format("%20A", 196).should == " 0X1.88P+7"
-
- format("%10c", 97).should == " a"
- format("%10p", []).should == " []"
- format("%10s", "abc").should == " abc"
+ @method.call("%10b", 10).should == " 1010"
+ @method.call("%10B", 10).should == " 1010"
+ @method.call("%10d", 112).should == " 112"
+ @method.call("%10i", 112).should == " 112"
+ @method.call("%10o", 87).should == " 127"
+ @method.call("%10u", 112).should == " 112"
+ @method.call("%10x", 196).should == " c4"
+ @method.call("%10X", 196).should == " C4"
+
+ @method.call("%20e", 109.52).should == " 1.095200e+02"
+ @method.call("%20E", 109.52).should == " 1.095200E+02"
+ @method.call("%20f", 10.952).should == " 10.952000"
+ @method.call("%20g", 12.1234).should == " 12.1234"
+ @method.call("%20G", 12.1234).should == " 12.1234"
+ @method.call("%20a", 196).should == " 0x1.88p+7"
+ @method.call("%20A", 196).should == " 0X1.88P+7"
+
+ @method.call("%10c", 97).should == " a"
+ @method.call("%10p", []).should == " []"
+ @method.call("%10s", "abc").should == " abc"
end
it "is ignored if argument's actual length is greater" do
- format("%5d", 1234567890).should == "1234567890"
+ @method.call("%5d", 1234567890).should == "1234567890"
end
end
describe "precision" do
context "integer types" do
it "controls the number of decimal places displayed" do
- format("%.6b", 10).should == "001010"
- format("%.6B", 10).should == "001010"
- format("%.5d", 112).should == "00112"
- format("%.5i", 112).should == "00112"
- format("%.5o", 87).should == "00127"
- format("%.5u", 112).should == "00112"
+ @method.call("%.6b", 10).should == "001010"
+ @method.call("%.6B", 10).should == "001010"
+ @method.call("%.5d", 112).should == "00112"
+ @method.call("%.5i", 112).should == "00112"
+ @method.call("%.5o", 87).should == "00127"
+ @method.call("%.5u", 112).should == "00112"
- format("%.5x", 196).should == "000c4"
- format("%.5X", 196).should == "000C4"
+ @method.call("%.5x", 196).should == "000c4"
+ @method.call("%.5X", 196).should == "000C4"
end
end
context "float types" do
it "controls the number of decimal places displayed in fraction part" do
- format("%.10e", 109.52).should == "1.0952000000e+02"
- format("%.10E", 109.52).should == "1.0952000000E+02"
- format("%.10f", 10.952).should == "10.9520000000"
- format("%.10a", 196).should == "0x1.8800000000p+7"
- format("%.10A", 196).should == "0X1.8800000000P+7"
+ @method.call("%.10e", 109.52).should == "1.0952000000e+02"
+ @method.call("%.10E", 109.52).should == "1.0952000000E+02"
+ @method.call("%.10f", 10.952).should == "10.9520000000"
+ @method.call("%.10a", 196).should == "0x1.8800000000p+7"
+ @method.call("%.10A", 196).should == "0X1.8800000000P+7"
end
it "does not affect G format" do
- format("%.10g", 12.1234).should == "12.1234"
- format("%.10g", 123456789).should == "123456789"
+ @method.call("%.10g", 12.1234).should == "12.1234"
+ @method.call("%.10g", 123456789).should == "123456789"
end
end
context "string formats" do
it "determines the maximum number of characters to be copied from the string" do
- format("%.1p", [1]).should == "["
- format("%.2p", [1]).should == "[1"
- format("%.10p", [1]).should == "[1]"
- format("%.0p", [1]).should == ""
+ @method.call("%.1p", [1]).should == "["
+ @method.call("%.2p", [1]).should == "[1"
+ @method.call("%.10p", [1]).should == "[1]"
+ @method.call("%.0p", [1]).should == ""
- format("%.1s", "abc").should == "a"
- format("%.2s", "abc").should == "ab"
- format("%.10s", "abc").should == "abc"
- format("%.0s", "abc").should == ""
+ @method.call("%.1s", "abc").should == "a"
+ @method.call("%.2s", "abc").should == "ab"
+ @method.call("%.10s", "abc").should == "abc"
+ @method.call("%.0s", "abc").should == ""
end
end
end
@@ -804,55 +894,49 @@ describe :kernel_sprintf, shared: true do
describe "reference by name" do
describe "%<name>s style" do
it "uses value passed in a hash argument" do
- format("%<foo>d", foo: 123).should == "123"
+ @method.call("%<foo>d", foo: 123).should == "123"
end
it "supports flags, width, precision and type" do
- format("%+20.10<foo>f", foo: 10.952).should == " +10.9520000000"
+ @method.call("%+20.10<foo>f", foo: 10.952).should == " +10.9520000000"
end
it "allows to place name in any position" do
- format("%+15.5<foo>f", foo: 10.952).should == " +10.95200"
- format("%+15<foo>.5f", foo: 10.952).should == " +10.95200"
- format("%+<foo>15.5f", foo: 10.952).should == " +10.95200"
- format("%<foo>+15.5f", foo: 10.952).should == " +10.95200"
+ @method.call("%+15.5<foo>f", foo: 10.952).should == " +10.95200"
+ @method.call("%+15<foo>.5f", foo: 10.952).should == " +10.95200"
+ @method.call("%+<foo>15.5f", foo: 10.952).should == " +10.95200"
+ @method.call("%<foo>+15.5f", foo: 10.952).should == " +10.95200"
end
it "cannot be mixed with unnamed style" do
- -> () {
- format("%d %<foo>d", 1, foo: "123")
+ -> {
+ @method.call("%d %<foo>d", 1, foo: "123")
}.should raise_error(ArgumentError)
end
-
- it "raises KeyError when there is no matching key" do
- -> () {
- format("%<foo>s", {})
- }.should raise_error(KeyError)
- end
end
describe "%{name} style" do
it "uses value passed in a hash argument" do
- format("%{foo}", foo: 123).should == "123"
+ @method.call("%{foo}", foo: 123).should == "123"
end
it "does not support type style" do
- format("%{foo}d", foo: 123).should == "123d"
+ @method.call("%{foo}d", foo: 123).should == "123d"
end
it "supports flags, width and precision" do
- format("%-20.5{foo}", foo: "123456789").should == "12345 "
+ @method.call("%-20.5{foo}", foo: "123456789").should == "12345 "
end
it "cannot be mixed with unnamed style" do
- -> () {
- format("%d %{foo}", 1, foo: "123")
+ -> {
+ @method.call("%d %{foo}", 1, foo: "123")
}.should raise_error(ArgumentError)
end
it "raises KeyError when there is no matching key" do
- -> () {
- format("%{foo}", {})
+ -> {
+ @method.call("%{foo}", {})
}.should raise_error(KeyError)
end
@@ -864,8 +948,40 @@ describe :kernel_sprintf, shared: true do
obj.should_receive(:to_s).and_return("42")
obj.should_not_receive(:to_str)
- format("%{foo}", foo: obj).should == "42"
+ @method.call("%{foo}", foo: obj).should == "42"
end
end
end
+
+ describe "faulty key" do
+ before :each do
+ @object = { foooo: 1 }
+ end
+
+ it "raises a KeyError" do
+ -> {
+ @method.call("%<foo>s", @object)
+ }.should raise_error(KeyError)
+ end
+
+ it "sets the Hash as the receiver of KeyError" do
+ -> {
+ @method.call("%<foo>s", @object)
+ }.should raise_error(KeyError) { |err|
+ err.receiver.should equal(@object)
+ }
+ end
+
+ it "sets the unmatched key as the key of KeyError" do
+ -> {
+ @method.call("%<foo>s", @object)
+ }.should raise_error(KeyError) { |err|
+ err.key.to_s.should == 'foo'
+ }
+ end
+ end
+
+ it "does not raise error when passed more arguments than needed" do
+ sprintf("%s %d %c", "string", 2, "c", []).should == "string 2 c"
+ end
end
diff --git a/spec/ruby/core/kernel/shared/sprintf_encoding.rb b/spec/ruby/core/kernel/shared/sprintf_encoding.rb
index a92f3c10cd..7ec0fe4c48 100644
--- a/spec/ruby/core/kernel/shared/sprintf_encoding.rb
+++ b/spec/ruby/core/kernel/shared/sprintf_encoding.rb
@@ -1,28 +1,67 @@
+# Keep encoding-related specs in a separate shared example to be able to skip them in IO/File/StringIO specs.
+# It's difficult to check result's encoding in the test after writing to a file/io buffer.
describe :kernel_sprintf_encoding, shared: true do
- def format(*args)
- @method.call(*args)
+ it "can produce a string with valid encoding" do
+ string = @method.call("good day %{valid}", valid: "e")
+ string.encoding.should == Encoding::UTF_8
+ string.valid_encoding?.should be_true
+ end
+
+ it "can produce a string with invalid encoding" do
+ string = @method.call("good day %{invalid}", invalid: "\x80")
+ string.encoding.should == Encoding::UTF_8
+ string.valid_encoding?.should be_false
end
it "returns a String in the same encoding as the format String if compatible" do
- string = "%s".force_encoding(Encoding::KOI8_U)
- result = format(string, "dogs")
+ string = "%s".dup.force_encoding(Encoding::KOI8_U)
+ result = @method.call(string, "dogs")
result.encoding.should equal(Encoding::KOI8_U)
end
it "returns a String in the argument's encoding if format encoding is more restrictive" do
- string = "foo %s".force_encoding(Encoding::US_ASCII)
- argument = "b\303\274r".force_encoding(Encoding::UTF_8)
+ string = "foo %s".dup.force_encoding(Encoding::US_ASCII)
+ argument = "b\303\274r".dup.force_encoding(Encoding::UTF_8)
- result = format(string, argument)
+ result = @method.call(string, argument)
result.encoding.should equal(Encoding::UTF_8)
end
- it "raises Encoding::CompatibilityError if both encodings are ASCII compatible and there ano not ASCII characters" do
+ it "raises Encoding::CompatibilityError if both encodings are ASCII compatible and there are not ASCII characters" do
string = "Ä %s".encode('windows-1252')
argument = "Ђ".encode('windows-1251')
- -> () {
- format(string, argument)
+ -> {
+ @method.call(string, argument)
}.should raise_error(Encoding::CompatibilityError)
end
+
+ describe "%c" do
+ it "supports Unicode characters" do
+ result = @method.call("%c", 1286)
+ result.should == "Ԇ"
+ result.bytes.should == [212, 134]
+
+ result = @method.call("%c", "ش")
+ result.should == "ش"
+ result.bytes.should == [216, 180]
+ end
+
+ it "raises error when a codepoint isn't representable in an encoding of a format string" do
+ format = "%c".encode("ASCII")
+
+ -> {
+ @method.call(format, 1286)
+ }.should raise_error(RangeError, /out of char range/)
+ end
+
+ it "uses the encoding of the format string to interpret codepoints" do
+ format = "%c".dup.force_encoding("euc-jp")
+ result = @method.call(format, 9415601)
+
+ result.encoding.should == Encoding::EUC_JP
+ result.should == "é".encode(Encoding::EUC_JP)
+ result.bytes.should == [143, 171, 177]
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/shared/then.rb b/spec/ruby/core/kernel/shared/then.rb
new file mode 100644
index 0000000000..b52075371f
--- /dev/null
+++ b/spec/ruby/core/kernel/shared/then.rb
@@ -0,0 +1,20 @@
+describe :kernel_then, shared: true do
+ it "yields self" do
+ object = Object.new
+ object.send(@method) { |o| o.should equal object }
+ end
+
+ it "returns the block return value" do
+ object = Object.new
+ object.send(@method) { 42 }.should equal 42
+ end
+
+ it "returns a sized Enumerator when no block given" do
+ object = Object.new
+ enum = object.send(@method)
+ enum.should be_an_instance_of Enumerator
+ enum.size.should equal 1
+ enum.peek.should equal object
+ enum.first.should equal object
+ end
+end
diff --git a/spec/ruby/core/kernel/singleton_class_spec.rb b/spec/ruby/core/kernel/singleton_class_spec.rb
index b5e0703905..23c400f9bd 100644
--- a/spec/ruby/core/kernel/singleton_class_spec.rb
+++ b/spec/ruby/core/kernel/singleton_class_spec.rb
@@ -1,3 +1,6 @@
+# truffleruby_primitives: true
+require_relative '../../spec_helper'
+
describe "Kernel#singleton_class" do
it "returns class extended from an object" do
x = Object.new
@@ -17,11 +20,55 @@ describe "Kernel#singleton_class" do
false.singleton_class.should == FalseClass
end
- it "raises TypeError for Fixnum" do
- lambda { 123.singleton_class }.should raise_error(TypeError)
+ it "raises TypeError for Integer" do
+ -> { 123.singleton_class }.should raise_error(TypeError, "can't define singleton")
+ end
+
+ it "raises TypeError for Float" do
+ -> { 3.14.singleton_class }.should raise_error(TypeError, "can't define singleton")
end
it "raises TypeError for Symbol" do
- lambda { :foo.singleton_class }.should raise_error(TypeError)
+ -> { :foo.singleton_class }.should raise_error(TypeError, "can't define singleton")
+ end
+
+ it "raises TypeError for a frozen deduplicated String" do
+ -> { (-"string").singleton_class }.should raise_error(TypeError, "can't define singleton")
+ -> { a = -"string"; a.singleton_class }.should raise_error(TypeError, "can't define singleton")
+ -> { a = "string"; (-a).singleton_class }.should raise_error(TypeError, "can't define singleton")
+ end
+
+ it "returns a frozen singleton class if object is frozen" do
+ obj = Object.new
+ obj.freeze
+ obj.singleton_class.frozen?.should be_true
+ end
+
+ context "for an IO object with a replaced singleton class" do
+ it "looks up singleton methods from the fresh singleton class after an object instance got a new one" do
+ proxy = -> io { io.foo }
+ if RUBY_ENGINE == 'truffleruby'
+ # We need an inline cache with only this object seen, the best way to do that is to use a Primitive
+ sclass = -> io { Primitive.singleton_class(io) }
+ else
+ sclass = -> io { io.singleton_class }
+ end
+
+ io = File.new(__FILE__)
+ io.define_singleton_method(:foo) { "old" }
+ sclass1 = sclass.call(io)
+ proxy.call(io).should == "old"
+
+ # IO#reopen is the only method which can replace an object's singleton class
+ io2 = File.new(__FILE__)
+ io.reopen(io2)
+ io.define_singleton_method(:foo) { "new" }
+ sclass2 = sclass.call(io)
+ sclass2.should_not.equal?(sclass1)
+ proxy.call(io).should == "new"
+ ensure
+ io2.close
+ io.close
+ end
end
end
diff --git a/spec/ruby/core/kernel/singleton_method_spec.rb b/spec/ruby/core/kernel/singleton_method_spec.rb
index 77022b40c2..7d63fa7cc6 100644
--- a/spec/ruby/core/kernel/singleton_method_spec.rb
+++ b/spec/ruby/core/kernel/singleton_method_spec.rb
@@ -1,7 +1,7 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Kernel#singleton_method" do
- it "find a method defined on the singleton class" do
+ it "finds a method defined on the singleton class" do
obj = Object.new
def obj.foo; end
obj.singleton_method(:foo).should be_an_instance_of(Method)
@@ -38,4 +38,48 @@ describe "Kernel#singleton_method" do
e.class.should == NameError
}
end
+
+ ruby_bug "#20620", ""..."3.4" do
+ it "finds a method defined in a module included in the singleton class" do
+ m = Module.new do
+ def foo
+ :foo
+ end
+ end
+
+ obj = Object.new
+ obj.singleton_class.include(m)
+
+ obj.singleton_method(:foo).should be_an_instance_of(Method)
+ obj.singleton_method(:foo).call.should == :foo
+ end
+
+ it "finds a method defined in a module prepended in the singleton class" do
+ m = Module.new do
+ def foo
+ :foo
+ end
+ end
+
+ obj = Object.new
+ obj.singleton_class.prepend(m)
+
+ obj.singleton_method(:foo).should be_an_instance_of(Method)
+ obj.singleton_method(:foo).call.should == :foo
+ end
+
+ it "finds a method defined in a module that an object is extended with" do
+ m = Module.new do
+ def foo
+ :foo
+ end
+ end
+
+ obj = Object.new
+ obj.extend(m)
+
+ obj.singleton_method(:foo).should be_an_instance_of(Method)
+ obj.singleton_method(:foo).call.should == :foo
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/singleton_methods_spec.rb b/spec/ruby/core/kernel/singleton_methods_spec.rb
index 596e5ddad2..a127a439de 100644
--- a/spec/ruby/core/kernel/singleton_methods_spec.rb
+++ b/spec/ruby/core/kernel/singleton_methods_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../../../fixtures/reflection', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative '../../fixtures/reflection'
+require_relative 'fixtures/classes'
describe :kernel_singleton_methods, shared: true do
it "returns an empty Array for an object with no singleton methods" do
@@ -36,10 +36,23 @@ describe :kernel_singleton_methods_modules, shared: true do
it "does not return any included methods for a class including a module" do
ReflectSpecs::D.singleton_methods(*@object).should include(:ds_pro, :ds_pub)
end
+
+ it "for a module does not return methods in a module prepended to Module itself" do
+ require_relative 'fixtures/singleton_methods'
+ mod = SingletonMethodsSpecs::SelfExtending
+ mod.method(:mspec_test_kernel_singleton_methods).owner.should == SingletonMethodsSpecs::Prepended
+
+ ancestors = mod.singleton_class.ancestors
+ ancestors[0...2].should == [ mod.singleton_class, mod ]
+ ancestors.should include(SingletonMethodsSpecs::Prepended)
+
+ # Do not search prepended modules of `Module`, as that's a non-singleton class
+ mod.singleton_methods.should == []
+ end
end
describe :kernel_singleton_methods_supers, shared: true do
- it "returns the names of singleton methods for an object extented with a module" do
+ it "returns the names of singleton methods for an object extended with a module" do
ReflectSpecs.oe.singleton_methods(*@object).should include(:m_pro, :m_pub)
end
@@ -49,11 +62,11 @@ describe :kernel_singleton_methods_supers, shared: true do
r.should == [:pro, :pub]
end
- it "returns the names of singleton methods for an object extented with two modules" do
+ it "returns the names of singleton methods for an object extended with two modules" do
ReflectSpecs.oee.singleton_methods(*@object).should include(:m_pro, :m_pub, :n_pro, :n_pub)
end
- it "returns the names of singleton methods for an object extented with a module including a module" do
+ it "returns the names of singleton methods for an object extended with a module including a module" do
ReflectSpecs.oei.singleton_methods(*@object).should include(:n_pro, :n_pub, :m_pro, :m_pub)
end
@@ -99,7 +112,7 @@ describe :kernel_singleton_methods_private_supers, shared: true do
ReflectSpecs.oee.singleton_methods(*@object).should_not include(:m_pri)
end
- it "does not return private singleton methods for an object extented with a module including a module" do
+ it "does not return private singleton methods for an object extended with a module including a module" do
ReflectSpecs.oei.singleton_methods(*@object).should_not include(:n_pri, :m_pri)
end
@@ -145,7 +158,6 @@ describe "Kernel#singleton_methods" do
it_behaves_like :kernel_singleton_methods_supers, nil, true
it_behaves_like :kernel_singleton_methods_modules, nil, true
it_behaves_like :kernel_singleton_methods_private_supers, nil, true
-
end
describe "when passed false" do
@@ -153,11 +165,11 @@ describe "Kernel#singleton_methods" do
it_behaves_like :kernel_singleton_methods_modules, nil, false
it_behaves_like :kernel_singleton_methods_private_supers, nil, false
- it "returns an empty Array for an object extented with a module" do
+ it "returns an empty Array for an object extended with a module" do
ReflectSpecs.oe.singleton_methods(false).should == []
end
- it "returns an empty Array for an object extented with two modules" do
+ it "returns an empty Array for an object extended with two modules" do
ReflectSpecs.oee.singleton_methods(false).should == []
end
diff --git a/spec/ruby/core/kernel/sleep_spec.rb b/spec/ruby/core/kernel/sleep_spec.rb
index bcb0060aa3..e9c600aac4 100644
--- a/spec/ruby/core/kernel/sleep_spec.rb
+++ b/spec/ruby/core/kernel/sleep_spec.rb
@@ -1,34 +1,40 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative '../fiber/fixtures/scheduler'
describe "Kernel#sleep" do
it "is a private method" do
Kernel.should have_private_instance_method(:sleep)
end
+ it "returns an Integer" do
+ sleep(0.001).should be_kind_of(Integer)
+ end
+
it "accepts a Float" do
- sleep(0.1).should be_close(0, 2)
+ sleep(0.001).should >= 0
end
- it "accepts a Fixnum" do
- sleep(0).should be_close(0, 2)
+ it "accepts an Integer" do
+ sleep(0).should >= 0
end
it "accepts a Rational" do
- sleep(Rational(1, 9)).should be_close(0, 2)
+ sleep(Rational(1, 999)).should >= 0
end
- it "raises an ArgumentError when passed a negative duration" do
- lambda { sleep(-0.1) }.should raise_error(ArgumentError)
- lambda { sleep(-1) }.should raise_error(ArgumentError)
+ it "accepts any Object that responds to divmod" do
+ o = Object.new
+ def o.divmod(*); [0, 0.001]; end
+ sleep(o).should >= 0
end
- it "raises a TypeError when passed nil" do
- lambda { sleep(nil) }.should raise_error(TypeError)
+ it "raises an ArgumentError when passed a negative duration" do
+ -> { sleep(-0.1) }.should raise_error(ArgumentError)
+ -> { sleep(-1) }.should raise_error(ArgumentError)
end
it "raises a TypeError when passed a String" do
- lambda { sleep('2') }.should raise_error(TypeError)
+ -> { sleep('2') }.should raise_error(TypeError)
end
it "pauses execution indefinitely if not given a duration" do
@@ -45,6 +51,74 @@ describe "Kernel#sleep" do
t.wakeup
t.value.should == 5
end
+
+ it "sleeps with nanosecond precision" do
+ start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ 100.times do
+ sleep(0.0001)
+ end
+ end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+
+ actual_duration = end_time - start_time
+ actual_duration.should > 0.01 # 100 * 0.0001 => 0.01
+ end
+
+ ruby_version_is ""..."3.3" do
+ it "raises a TypeError when passed nil" do
+ -> { sleep(nil) }.should raise_error(TypeError)
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "accepts a nil duration" do
+ running = false
+ t = Thread.new do
+ running = true
+ sleep(nil)
+ 5
+ end
+
+ Thread.pass until running
+ Thread.pass while t.status and t.status != "sleep"
+
+ t.wakeup
+ t.value.should == 5
+ end
+ end
+
+ context "Kernel.sleep with Fiber scheduler" do
+ before :each do
+ Fiber.set_scheduler(FiberSpecs::LoggingScheduler.new)
+ end
+
+ after :each do
+ Fiber.set_scheduler(nil)
+ end
+
+ it "calls the scheduler without arguments when no duration is given" do
+ sleeper = Fiber.new(blocking: false) do
+ sleep
+ end
+ sleeper.resume
+ Fiber.scheduler.events.should == [{ event: :kernel_sleep, fiber: sleeper, args: [] }]
+ end
+
+ it "calls the scheduler with the given duration" do
+ sleeper = Fiber.new(blocking: false) do
+ sleep(0.01)
+ end
+ sleeper.resume
+ Fiber.scheduler.events.should == [{ event: :kernel_sleep, fiber: sleeper, args: [0.01] }]
+ end
+
+ it "does not call the scheduler if the fiber is blocking" do
+ sleeper = Fiber.new(blocking: true) do
+ sleep(0.01)
+ end
+ sleeper.resume
+ Fiber.scheduler.events.should == []
+ end
+ end
end
describe "Kernel.sleep" do
diff --git a/spec/ruby/core/kernel/spawn_spec.rb b/spec/ruby/core/kernel/spawn_spec.rb
index ad937b17dd..ba05b629d5 100644
--- a/spec/ruby/core/kernel/spawn_spec.rb
+++ b/spec/ruby/core/kernel/spawn_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
# These specs only run a basic usage of #spawn.
# Process.spawn has more complete specs and they are not
@@ -10,7 +10,7 @@ describe "Kernel#spawn" do
end
it "executes the given command" do
- lambda {
+ -> {
Process.wait spawn("echo spawn")
}.should output_to_fd("spawn\n")
end
@@ -18,7 +18,7 @@ end
describe "Kernel.spawn" do
it "executes the given command" do
- lambda {
+ -> {
Process.wait Kernel.spawn("echo spawn")
}.should output_to_fd("spawn\n")
end
diff --git a/spec/ruby/core/kernel/sprintf_spec.rb b/spec/ruby/core/kernel/sprintf_spec.rb
index a89b253803..5a4a90ff7a 100644
--- a/spec/ruby/core/kernel/sprintf_spec.rb
+++ b/spec/ruby/core/kernel/sprintf_spec.rb
@@ -1,24 +1,64 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../shared/sprintf', __FILE__)
-require File.expand_path('../shared/sprintf_encoding', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/sprintf'
+require_relative 'shared/sprintf_encoding'
+
+describe :kernel_sprintf_to_str, shared: true do
+ it "calls #to_str to convert the format object to a String" do
+ obj = mock('format string')
+ obj.should_receive(:to_str).and_return("to_str: %i")
+ @method.call(obj, 42).should == "to_str: 42"
+ end
+end
describe "Kernel#sprintf" do
- it_behaves_like :kernel_sprintf, -> (format, *args) {
- sprintf(format, *args)
+ it_behaves_like :kernel_sprintf, -> format, *args {
+ r = nil
+ -> {
+ r = sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
+ }
+
+ it_behaves_like :kernel_sprintf_encoding, -> format, *args {
+ r = nil
+ -> {
+ r = sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
- it_behaves_like :kernel_sprintf_encoding, -> (format, *args) {
- sprintf(format, *args)
+ it_behaves_like :kernel_sprintf_to_str, -> format, *args {
+ r = nil
+ -> {
+ r = sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
end
describe "Kernel.sprintf" do
- it_behaves_like :kernel_sprintf, -> (format, *args) {
- Kernel.sprintf(format, *args)
+ it_behaves_like :kernel_sprintf, -> format, *args {
+ r = nil
+ -> {
+ r = Kernel.sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
+ }
+
+ it_behaves_like :kernel_sprintf_encoding, -> format, *args {
+ r = nil
+ -> {
+ r = Kernel.sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
- it_behaves_like :kernel_sprintf_encoding, -> (format, *args) {
- Kernel.sprintf(format, *args)
+ it_behaves_like :kernel_sprintf_to_str, -> format, *args {
+ r = nil
+ -> {
+ r = Kernel.sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
end
diff --git a/spec/ruby/core/kernel/srand_spec.rb b/spec/ruby/core/kernel/srand_spec.rb
index 33f99f5ac4..95bb406f46 100644
--- a/spec/ruby/core/kernel/srand_spec.rb
+++ b/spec/ruby/core/kernel/srand_spec.rb
@@ -1,7 +1,15 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "Kernel#srand" do
+ before :each do
+ @seed = srand
+ end
+
+ after :each do
+ srand(@seed)
+ end
-describe "Kernel.srand" do
it "is a private method" do
Kernel.should have_private_instance_method(:srand)
end
@@ -11,6 +19,10 @@ describe "Kernel.srand" do
srand(20).should == 10
end
+ it "returns the system-initialized seed value on the first call" do
+ ruby_exe('print srand(10)', options: '--disable-gems').should =~ /\A\d+\z/
+ end
+
it "seeds the RNG correctly and repeatably" do
srand(10)
x = rand
@@ -19,7 +31,7 @@ describe "Kernel.srand" do
end
it "defaults number to a random value" do
- lambda { srand }.should_not raise_error
+ -> { srand }.should_not raise_error
srand.should_not == 0
end
@@ -33,7 +45,7 @@ describe "Kernel.srand" do
srand.should == -17
end
- it "accepts a Bignum as a seed" do
+ it "accepts an Integer as a seed" do
srand(0x12345678901234567890)
srand.should == 0x12345678901234567890
end
@@ -48,14 +60,14 @@ describe "Kernel.srand" do
end
it "raises a TypeError when passed nil" do
- lambda { srand(nil) }.should raise_error(TypeError)
+ -> { srand(nil) }.should raise_error(TypeError)
end
it "raises a TypeError when passed a String" do
- lambda { srand("7") }.should raise_error(TypeError)
+ -> { srand("7") }.should raise_error(TypeError)
end
end
-describe "Kernel#srand" do
+describe "Kernel.srand" do
it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/core/kernel/sub_spec.rb b/spec/ruby/core/kernel/sub_spec.rb
index 78e5eec4a8..9130bd159c 100644
--- a/spec/ruby/core/kernel/sub_spec.rb
+++ b/spec/ruby/core/kernel/sub_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
# FIXME: These methods exist only when the -n or -p option is passed to
# ruby, but we currently don't have a way of specifying that.
diff --git a/spec/ruby/core/kernel/syscall_spec.rb b/spec/ruby/core/kernel/syscall_spec.rb
index bcea833f1f..32d07b3ae2 100644
--- a/spec/ruby/core/kernel/syscall_spec.rb
+++ b/spec/ruby/core/kernel/syscall_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#syscall" do
it "is a private method" do
diff --git a/spec/ruby/core/kernel/system_spec.rb b/spec/ruby/core/kernel/system_spec.rb
index aee75441a2..9bc03924dd 100644
--- a/spec/ruby/core/kernel/system_spec.rb
+++ b/spec/ruby/core/kernel/system_spec.rb
@@ -1,19 +1,19 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe :kernel_system, shared: true do
it "executes the specified command in a subprocess" do
- lambda { @object.system("echo a") }.should output_to_fd("a\n")
+ -> { @object.system("echo a") }.should output_to_fd("a\n")
$?.should be_an_instance_of Process::Status
- $?.success?.should == true
+ $?.should.success?
end
it "returns true when the command exits with a zero exit status" do
@object.system(ruby_cmd('exit 0')).should == true
$?.should be_an_instance_of Process::Status
- $?.success?.should == true
+ $?.should.success?
$?.exitstatus.should == 0
end
@@ -21,20 +21,28 @@ describe :kernel_system, shared: true do
@object.system(ruby_cmd('exit 1')).should == false
$?.should be_an_instance_of Process::Status
- $?.success?.should == false
+ $?.should_not.success?
$?.exitstatus.should == 1
end
+ it "raises RuntimeError when `exception: true` is given and the command exits with a non-zero exit status" do
+ -> { @object.system(ruby_cmd('exit 1'), exception: true) }.should raise_error(RuntimeError)
+ end
+
+ it "raises Errno::ENOENT when `exception: true` is given and the specified command does not exist" do
+ -> { @object.system('feature_14386', exception: true) }.should raise_error(Errno::ENOENT)
+ end
+
it "returns nil when command execution fails" do
@object.system("sad").should be_nil
$?.should be_an_instance_of Process::Status
$?.pid.should be_kind_of(Integer)
- $?.exitstatus.should == 127
+ $?.should_not.success?
end
it "does not write to stderr when command execution fails" do
- lambda { @object.system("sad") }.should output_to_fd("", STDERR)
+ -> { @object.system("sad") }.should output_to_fd("", STDERR)
end
platform_is_not :windows do
@@ -47,12 +55,29 @@ describe :kernel_system, shared: true do
end
it "executes with `sh` if the command contains shell characters" do
- lambda { @object.system("echo $0") }.should output_to_fd("sh\n")
+ -> { @object.system("echo $0") }.should output_to_fd("sh\n")
end
it "ignores SHELL env var and always uses `sh`" do
ENV['SHELL'] = "/bin/fakeshell"
- lambda { @object.system("echo $0") }.should output_to_fd("sh\n")
+ -> { @object.system("echo $0") }.should output_to_fd("sh\n")
+ end
+ end
+
+ platform_is_not :windows do
+ before :each do
+ require 'tmpdir'
+ @shell_command = File.join(Dir.mktmpdir, "noshebang.cmd")
+ File.write(@shell_command, %[echo "$PATH"\n], perm: 0o700)
+ end
+
+ after :each do
+ File.unlink(@shell_command)
+ Dir.rmdir(File.dirname(@shell_command))
+ end
+
+ it "executes with `sh` if the command is executable but not binary and there is no shebang" do
+ -> { @object.system(@shell_command) }.should output_to_fd(ENV['PATH'] + "\n")
end
end
@@ -69,19 +94,19 @@ describe :kernel_system, shared: true do
end
it "expands shell variables when given a single string argument" do
- lambda { @object.system("echo #{@shell_var}") }.should output_to_fd("foo\n")
+ -> { @object.system("echo #{@shell_var}") }.should output_to_fd("foo\n")
end
platform_is_not :windows do
it "does not expand shell variables when given multiples arguments" do
- lambda { @object.system("echo", @shell_var) }.should output_to_fd("#{@shell_var}\n")
+ -> { @object.system("echo", @shell_var) }.should output_to_fd("#{@shell_var}\n")
end
end
platform_is :windows do
it "does expand shell variables when given multiples arguments" do
# See https://bugs.ruby-lang.org/issues/12231
- lambda { @object.system("echo", @shell_var) }.should output_to_fd("foo\n")
+ -> { @object.system("echo", @shell_var) }.should output_to_fd("foo\n")
end
end
diff --git a/spec/ruby/core/kernel/taint_spec.rb b/spec/ruby/core/kernel/taint_spec.rb
index 0c2fb3286b..9a2efbaea0 100644
--- a/spec/ruby/core/kernel/taint_spec.rb
+++ b/spec/ruby/core/kernel/taint_spec.rb
@@ -1,45 +1,8 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#taint" do
- it "returns self" do
- o = Object.new
- o.taint.should equal(o)
- end
-
- it "sets the tainted bit" do
- o = Object.new
- o.taint
- o.tainted?.should == true
- end
-
- it "raises RuntimeError on an untainted, frozen object" do
- o = Object.new.freeze
- lambda { o.taint }.should raise_error(RuntimeError)
- end
-
- it "does not raise an error on a tainted, frozen object" do
- o = Object.new.taint.freeze
- o.taint.should equal(o)
- end
-
- it "has no effect on immediate values" do
- [nil, true, false].each do |v|
- v.taint
- v.tainted?.should == false
- end
- end
-
- it "no raises a RuntimeError on symbols" do
- v = :sym
- lambda { v.taint }.should_not raise_error(RuntimeError)
- v.tainted?.should == false
- end
-
- it "no raises error on fixnum values" do
- [1].each do |v|
- lambda { v.taint }.should_not raise_error(RuntimeError)
- v.tainted?.should == false
- end
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:taint)
end
end
diff --git a/spec/ruby/core/kernel/tainted_spec.rb b/spec/ruby/core/kernel/tainted_spec.rb
index efb31be9d8..837eb1dafb 100644
--- a/spec/ruby/core/kernel/tainted_spec.rb
+++ b/spec/ruby/core/kernel/tainted_spec.rb
@@ -1,12 +1,8 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#tainted?" do
- it "returns true if Object is tainted" do
- o = mock('o')
- p = mock('p')
- p.taint
- o.tainted?.should == false
- p.tainted?.should == true
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:tainted?)
end
end
diff --git a/spec/ruby/core/kernel/tap_spec.rb b/spec/ruby/core/kernel/tap_spec.rb
index 312a34426c..f7720a6dc7 100644
--- a/spec/ruby/core/kernel/tap_spec.rb
+++ b/spec/ruby/core/kernel/tap_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#tap" do
it "always yields self and returns self" do
@@ -8,6 +8,6 @@ describe "Kernel#tap" do
end
it "raises a LocalJumpError when no block given" do
- lambda { 3.tap }.should raise_error(LocalJumpError)
+ -> { 3.tap }.should raise_error(LocalJumpError)
end
end
diff --git a/spec/ruby/core/kernel/test_spec.rb b/spec/ruby/core/kernel/test_spec.rb
index 43e3a963e3..d26dc06361 100644
--- a/spec/ruby/core/kernel/test_spec.rb
+++ b/spec/ruby/core/kernel/test_spec.rb
@@ -1,10 +1,10 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#test" do
before :all do
- @file = File.dirname(__FILE__) + '/fixtures/classes.rb'
- @dir = File.dirname(__FILE__) + '/fixtures'
+ @file = __dir__ + '/fixtures/classes.rb'
+ @dir = __dir__ + '/fixtures'
end
it "is a private method" do
diff --git a/spec/ruby/core/kernel/then_spec.rb b/spec/ruby/core/kernel/then_spec.rb
new file mode 100644
index 0000000000..8109a2960a
--- /dev/null
+++ b/spec/ruby/core/kernel/then_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/then'
+
+describe "Kernel#then" do
+ it_behaves_like :kernel_then, :then
+end
diff --git a/spec/ruby/core/kernel/throw_spec.rb b/spec/ruby/core/kernel/throw_spec.rb
index 3f8d272d6d..64bfccb413 100644
--- a/spec/ruby/core/kernel/throw_spec.rb
+++ b/spec/ruby/core/kernel/throw_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel.throw" do
it "transfers control to the end of the active catch block waiting for symbol" do
@@ -10,7 +10,7 @@ describe "Kernel.throw" do
end.should be_nil
end
- it "transfers control to the innermost catch block waiting for the same sympol" do
+ it "transfers control to the innermost catch block waiting for the same symbol" do
one = two = three = 0
catch :duplicate do
catch :duplicate do
@@ -42,21 +42,21 @@ describe "Kernel.throw" do
end
it "raises an ArgumentError if there is no catch block for the symbol" do
- lambda { throw :blah }.should raise_error(ArgumentError)
+ -> { throw :blah }.should raise_error(ArgumentError)
end
it "raises an UncaughtThrowError if there is no catch block for the symbol" do
- lambda { throw :blah }.should raise_error(UncaughtThrowError)
+ -> { throw :blah }.should raise_error(UncaughtThrowError)
end
it "raises ArgumentError if 3 or more arguments provided" do
- lambda {
+ -> {
catch :blah do
throw :blah, :return_value, 2
end
}.should raise_error(ArgumentError)
- lambda {
+ -> {
catch :blah do
throw :blah, :return_value, 2, 3, 4, 5
end
@@ -64,7 +64,7 @@ describe "Kernel.throw" do
end
it "can throw an object" do
- lambda {
+ -> {
obj = Object.new
catch obj do
throw obj
diff --git a/spec/ruby/core/kernel/to_enum_spec.rb b/spec/ruby/core/kernel/to_enum_spec.rb
index 9fb228f318..9d9945450f 100644
--- a/spec/ruby/core/kernel/to_enum_spec.rb
+++ b/spec/ruby/core/kernel/to_enum_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Kernel#to_enum" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/kernel/to_s_spec.rb b/spec/ruby/core/kernel/to_s_spec.rb
index c6fcca54a2..ea4b00151e 100644
--- a/spec/ruby/core/kernel/to_s_spec.rb
+++ b/spec/ruby/core/kernel/to_s_spec.rb
@@ -1,16 +1,8 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#to_s" do
it "returns a String containing the name of self's class" do
Object.new.to_s.should =~ /Object/
end
-
- it "returns a tainted result if self is tainted" do
- Object.new.taint.to_s.tainted?.should be_true
- end
-
- it "returns an untrusted result if self is untrusted" do
- Object.new.untrust.to_s.untrusted?.should be_true
- end
end
diff --git a/spec/ruby/core/kernel/trace_var_spec.rb b/spec/ruby/core/kernel/trace_var_spec.rb
index 07e02feb72..3c84aa5e60 100644
--- a/spec/ruby/core/kernel/trace_var_spec.rb
+++ b/spec/ruby/core/kernel/trace_var_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#trace_var" do
before :each do
@@ -47,7 +47,7 @@ describe "Kernel#trace_var" do
end
it "raises ArgumentError if no block or proc is provided" do
- lambda do
+ -> do
trace_var :$Kernel_trace_var_global
end.should raise_error(ArgumentError)
end
diff --git a/spec/ruby/core/kernel/trap_spec.rb b/spec/ruby/core/kernel/trap_spec.rb
index 98f386dc85..4c801a7215 100644
--- a/spec/ruby/core/kernel/trap_spec.rb
+++ b/spec/ruby/core/kernel/trap_spec.rb
@@ -1,12 +1,9 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
describe "Kernel#trap" do
it "is a private method" do
Kernel.should have_private_instance_method(:trap)
end
-end
-describe "Kernel.trap" do
- it "needs to be reviewed for spec completeness"
+ # Behaviour is specified for Signal.trap
end
diff --git a/spec/ruby/core/kernel/trust_spec.rb b/spec/ruby/core/kernel/trust_spec.rb
index a9fda5c5c6..ef3fa9a3e1 100644
--- a/spec/ruby/core/kernel/trust_spec.rb
+++ b/spec/ruby/core/kernel/trust_spec.rb
@@ -1,25 +1,8 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#trust" do
- it "returns self" do
- o = Object.new
- o.trust.should equal(o)
- end
-
- it "clears the untrusted bit" do
- o = Object.new.untrust
- o.trust
- o.untrusted?.should == false
- end
-
- it "raises RuntimeError on an untrusted, frozen object" do
- o = Object.new.untrust.freeze
- lambda { o.trust }.should raise_error(RuntimeError)
- end
-
- it "does not raise an error on a trusted, frozen object" do
- o = Object.new.freeze
- o.trust.should equal(o)
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:trust)
end
end
diff --git a/spec/ruby/core/kernel/untaint_spec.rb b/spec/ruby/core/kernel/untaint_spec.rb
index 5abe5d63fc..47e8544bd4 100644
--- a/spec/ruby/core/kernel/untaint_spec.rb
+++ b/spec/ruby/core/kernel/untaint_spec.rb
@@ -1,25 +1,8 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#untaint" do
- it "returns self" do
- o = Object.new
- o.untaint.should equal(o)
- end
-
- it "clears the tainted bit" do
- o = Object.new.taint
- o.untaint
- o.tainted?.should == false
- end
-
- it "raises RuntimeError on a tainted, frozen object" do
- o = Object.new.taint.freeze
- lambda { o.untaint }.should raise_error(RuntimeError)
- end
-
- it "does not raise an error on an untainted, frozen object" do
- o = Object.new.freeze
- o.untaint.should equal(o)
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untaint)
end
end
diff --git a/spec/ruby/core/kernel/untrace_var_spec.rb b/spec/ruby/core/kernel/untrace_var_spec.rb
index 3af1348ffd..1925a3a836 100644
--- a/spec/ruby/core/kernel/untrace_var_spec.rb
+++ b/spec/ruby/core/kernel/untrace_var_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#untrace_var" do
it "is a private method" do
diff --git a/spec/ruby/core/kernel/untrust_spec.rb b/spec/ruby/core/kernel/untrust_spec.rb
index 280a465807..8787ab3fc9 100644
--- a/spec/ruby/core/kernel/untrust_spec.rb
+++ b/spec/ruby/core/kernel/untrust_spec.rb
@@ -1,25 +1,8 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#untrust" do
- it "returns self" do
- o = Object.new
- o.untrust.should equal(o)
- end
-
- it "sets the untrusted bit" do
- o = Object.new
- o.untrust
- o.untrusted?.should == true
- end
-
- it "raises RuntimeError on a trusted, frozen object" do
- o = Object.new.freeze
- lambda { o.untrust }.should raise_error(RuntimeError)
- end
-
- it "does not raise an error on an untrusted, frozen object" do
- o = Object.new.untrust.freeze
- o.untrust.should equal(o)
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untrust)
end
end
diff --git a/spec/ruby/core/kernel/untrusted_spec.rb b/spec/ruby/core/kernel/untrusted_spec.rb
index 43c4c0aa18..29261be9c4 100644
--- a/spec/ruby/core/kernel/untrusted_spec.rb
+++ b/spec/ruby/core/kernel/untrusted_spec.rb
@@ -1,28 +1,8 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#untrusted?" do
- it "returns the untrusted status of an object" do
- o = mock('o')
- o.untrusted?.should == false
- o.untrust
- o.untrusted?.should == true
- end
-
- it "has no effect on immediate values" do
- a = nil
- b = true
- c = false
- a.untrust
- b.untrust
- c.untrust
- a.untrusted?.should == false
- b.untrusted?.should == false
- c.untrusted?.should == false
- end
-
- it "has effect on immediate values" do
- d = 1
- lambda { d.untrust }.should_not raise_error(RuntimeError)
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untrusted?)
end
end
diff --git a/spec/ruby/core/kernel/warn_spec.rb b/spec/ruby/core/kernel/warn_spec.rb
index c44116dc21..e03498c6dc 100644
--- a/spec/ruby/core/kernel/warn_spec.rb
+++ b/spec/ruby/core/kernel/warn_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#warn" do
before :each do
@@ -8,72 +8,291 @@ describe "Kernel#warn" do
end
after :each do
- $VERBOSE = @before_verbose
+ $VERBOSE = nil
$/ = @before_separator
+ $VERBOSE = @before_verbose
end
it "is a private method" do
Kernel.should have_private_instance_method(:warn)
end
- it "requires multiple arguments" do
+ it "accepts multiple arguments" do
Kernel.method(:warn).arity.should < 0
end
it "does not append line-end if last character is line-end" do
- lambda {
+ -> {
$VERBOSE = true
warn("this is some simple text with line-end\n")
}.should output(nil, "this is some simple text with line-end\n")
end
it "calls #write on $stderr if $VERBOSE is true" do
- lambda {
+ -> {
$VERBOSE = true
warn("this is some simple text")
}.should output(nil, "this is some simple text\n")
end
it "calls #write on $stderr if $VERBOSE is false" do
- lambda {
+ -> {
$VERBOSE = false
warn("this is some simple text")
}.should output(nil, "this is some simple text\n")
end
it "does not call #write on $stderr if $VERBOSE is nil" do
- lambda {
+ -> {
$VERBOSE = nil
warn("this is some simple text")
}.should output(nil, "")
end
it "writes each argument on a line when passed multiple arguments" do
- lambda {
+ -> {
$VERBOSE = true
warn("line 1", "line 2")
}.should output(nil, "line 1\nline 2\n")
end
it "writes each array element on a line when passes an array" do
- lambda {
+ -> {
$VERBOSE = true
warn(["line 1", "line 2"])
}.should output(nil, "line 1\nline 2\n")
end
it "does not write strings when passed no arguments" do
- lambda {
+ -> {
$VERBOSE = true
warn
}.should output("", "")
end
it "writes the default record separator and NOT $/ to $stderr after the warning message" do
- lambda {
+ -> {
$VERBOSE = true
$/ = 'rs'
warn("")
}.should output(nil, /\n/)
end
+
+ it "writes to_s representation if passed a non-string" do
+ obj = mock("obj")
+ obj.should_receive(:to_s).and_return("to_s called")
+ -> {
+ $VERBOSE = true
+ warn(obj)
+ }.should output(nil, "to_s called\n")
+ end
+
+ describe ":uplevel keyword argument" do
+ before :each do
+ $VERBOSE = true
+ end
+
+ it "prepends a message with specified line from the backtrace" do
+ w = KernelSpecs::WarnInNestedCall.new
+
+ -> { w.f4("foo", 0) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.warn_call_lineno}: warning: foo|)
+ -> { w.f4("foo", 1) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f1_call_lineno}: warning: foo|)
+ -> { w.f4("foo", 2) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f2_call_lineno}: warning: foo|)
+ -> { w.f4("foo", 3) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f3_call_lineno}: warning: foo|)
+ end
+
+ # Test both explicitly without and with RubyGems as RubyGems overrides Kernel#warn
+ it "shows the caller of #require and not #require itself without RubyGems" do
+ file = fixture(__FILE__ , "warn_require_caller.rb")
+ ruby_exe(file, options: "--disable-gems", args: "2>&1").should == "#{file}:2: warning: warn-require-warning\n"
+ end
+
+ it "shows the caller of #require and not #require itself with RubyGems loaded" do
+ file = fixture(__FILE__ , "warn_require_caller.rb")
+ ruby_exe(file, options: "-rrubygems", args: "2>&1").should == "#{file}:2: warning: warn-require-warning\n"
+ end
+
+ it "doesn't show the caller when the uplevel is `nil`" do
+ w = KernelSpecs::WarnInNestedCall.new
+
+ -> { w.f4("foo", nil) }.should output(nil, "foo\n")
+ end
+
+ guard -> { Kernel.instance_method(:tap).source_location } do
+ it "skips <internal: core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
+
+ file = fixture(__FILE__ , "warn_core_method.rb")
+ n = 9
+ ruby_exe(file, options: "--disable-gems", args: "2>&1").lines.should == [
+ "#{file}:#{n+0}: warning: use X instead\n",
+ "#{file}:#{n+1}: warning: use X instead\n",
+ "#{file}:#{n+2}: warning: use X instead\n",
+ "#{file}:#{n+4}: warning: use X instead\n",
+ ]
+ end
+ end
+
+ it "accepts :category keyword with a symbol" do
+ -> {
+ $VERBOSE = true
+ warn("message", category: :deprecated)
+ }.should output(nil, "message\n")
+ end
+
+ it "accepts :category keyword with nil" do
+ -> {
+ $VERBOSE = true
+ warn("message", category: nil)
+ }.should output(nil, "message\n")
+ end
+
+ it "accepts :category keyword with object convertible to symbol" do
+ o = Object.new
+ def o.to_sym; :deprecated; end
+ -> {
+ $VERBOSE = true
+ warn("message", category: o)
+ }.should output(nil, "message\n")
+ end
+
+ it "raises if :category keyword is not nil and not convertible to symbol" do
+ -> {
+ $VERBOSE = true
+ warn("message", category: Object.new)
+ }.should raise_error(TypeError)
+ end
+
+ it "converts first arg using to_s" do
+ w = KernelSpecs::WarnInNestedCall.new
+
+ -> { w.f4(false, 0) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.warn_call_lineno}: warning: false|)
+ -> { w.f4(nil, 1) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f1_call_lineno}: warning: |)
+ obj = mock("obj")
+ obj.should_receive(:to_s).and_return("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
+
+ it "does not prepend caller information if the uplevel argument is too large" do
+ w = KernelSpecs::WarnInNestedCall.new
+ -> { w.f4("foo", 100) }.should output(nil, "warning: foo\n")
+ end
+
+ it "prepends even if a message is empty or nil" do
+ w = KernelSpecs::WarnInNestedCall.new
+
+ -> { w.f4("", 0) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.warn_call_lineno}: warning: \n$|)
+ -> { w.f4(nil, 0) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.warn_call_lineno}: warning: \n$|)
+ end
+
+ it "converts value to Integer" do
+ w = KernelSpecs::WarnInNestedCall.new
+
+ -> { w.f4(0.1) }.should output(nil, %r|classes.rb:#{w.warn_call_lineno}:|)
+ -> { w.f4(Rational(1, 2)) }.should output(nil, %r|classes.rb:#{w.warn_call_lineno}:|)
+ end
+
+ it "raises ArgumentError if passed negative value" do
+ -> { warn "", uplevel: -2 }.should raise_error(ArgumentError)
+ -> { warn "", uplevel: -100 }.should raise_error(ArgumentError)
+ end
+
+ it "raises ArgumentError if passed -1" do
+ -> { warn "", uplevel: -1 }.should raise_error(ArgumentError)
+ end
+
+ it "raises TypeError if passed not Integer" do
+ -> { warn "", uplevel: "" }.should raise_error(TypeError)
+ -> { warn "", uplevel: [] }.should raise_error(TypeError)
+ -> { warn "", uplevel: {} }.should raise_error(TypeError)
+ -> { warn "", uplevel: Object.new }.should raise_error(TypeError)
+ end
+ end
+
+ it "treats empty hash as no keyword argument" do
+ h = {}
+ -> { warn(**h) }.should_not complain(verbose: true)
+ -> { warn('foo', **h) }.should complain("foo\n")
+ end
+
+ it "calls Warning.warn without keyword arguments if Warning.warn does not accept keyword arguments" do
+ verbose = $VERBOSE
+ $VERBOSE = false
+ class << Warning
+ alias_method :_warn, :warn
+ def warn(message)
+ ScratchPad.record(message)
+ end
+ end
+
+ begin
+ ScratchPad.clear
+ Kernel.warn("Chunky bacon!")
+ ScratchPad.recorded.should == "Chunky bacon!\n"
+
+ Kernel.warn("Deprecated bacon!", category: :deprecated)
+ ScratchPad.recorded.should == "Deprecated bacon!\n"
+ ensure
+ class << Warning
+ remove_method :warn
+ alias_method :warn, :_warn
+ remove_method :_warn
+ end
+ $VERBOSE = verbose
+ end
+ end
+
+ it "calls Warning.warn with category: nil if Warning.warn accepts keyword arguments" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil)
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ Kernel.warn("Chunky bacon!")
+ ensure
+ $VERBOSE = verbose
+ end
+ end
+
+ it "calls Warning.warn with given category keyword converted to a symbol" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated)
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ Kernel.warn("Chunky bacon!", category: 'deprecated')
+ ensure
+ $VERBOSE = verbose
+ end
+ end
+
+ it "does not call Warning.warn if self is the Warning module" do
+ # RubyGems redefines Kernel#warn so we need to use a subprocess and disable RubyGems here
+ code = <<-RUBY
+ def Warning.warn(*args, **kwargs)
+ raise 'should not be called'
+ end
+ Kernel.instance_method(:warn).bind(Warning).call('Kernel#warn spec edge case')
+ RUBY
+ out = ruby_exe(code, args: "2>&1", options: "--disable-gems")
+ out.should == "Kernel#warn spec edge case\n"
+ $?.should.success?
+ end
+
+ it "avoids recursion if Warning#warn is redefined and calls super" do
+ # This works because of the spec above, which is the workaround for it.
+ # Note that redefining Warning#warn is a mistake which would naturally end in infinite recursion,
+ # Warning.extend Module.new { def warn } should be used instead.
+ # RubyGems redefines Kernel#warn so we need to use a subprocess and disable RubyGems here
+ code = <<-RUBY
+ module Warning
+ def warn(*args, **kwargs)
+ super
+ end
+ end
+ warn "avoid infinite recursion"
+ RUBY
+ out = ruby_exe(code, args: "2>&1", options: "--disable-gems")
+ out.should == "avoid infinite recursion\n"
+ $?.should.success?
+ end
end
diff --git a/spec/ruby/core/kernel/yield_self_spec.rb b/spec/ruby/core/kernel/yield_self_spec.rb
index 817c01f288..e311dcee47 100644
--- a/spec/ruby/core/kernel/yield_self_spec.rb
+++ b/spec/ruby/core/kernel/yield_self_spec.rb
@@ -1,26 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'shared/then'
-has_yield_self = VersionGuard.new("2.5").match? || PlatformGuard.implementation?(:truffleruby)
-
-if has_yield_self
- describe "Kernel#yield_self" do
- it "yields self" do
- object = Object.new
- object.yield_self { |o| o.should equal object }
- end
-
- it "returns the block return value" do
- object = Object.new
- object.yield_self { 42 }.should equal 42
- end
-
- it "returns a sized Enumerator when no block given" do
- object = Object.new
- enum = object.yield_self
- enum.should be_an_instance_of Enumerator
- enum.size.should equal 1
- enum.peek.should equal object
- enum.first.should equal object
- end
- end
+describe "Kernel#yield_self" do
+ it_behaves_like :kernel_then, :yield_self
end