This commit is contained in:
Benoit Daloze 2020-07-27 21:41:08 +02:00
Родитель 7429841ab6
Коммит 126fd5f15c
38 изменённых файлов: 733 добавлений и 44 удалений

Просмотреть файл

@ -152,6 +152,7 @@ RegexpSpecsSubclassTwo
Reline Reline
RescueInClassExample RescueInClassExample
Resolv Resolv
Ripper
SHA1Constants SHA1Constants
SHA256Constants SHA256Constants
SHA384Constants SHA384Constants

Просмотреть файл

@ -92,6 +92,7 @@ Lint/UnreachableCode:
Exclude: Exclude:
- 'core/enumerator/lazy/fixtures/classes.rb' - 'core/enumerator/lazy/fixtures/classes.rb'
- 'core/kernel/catch_spec.rb' - 'core/kernel/catch_spec.rb'
- 'core/kernel/raise_spec.rb'
- 'core/kernel/throw_spec.rb' - 'core/kernel/throw_spec.rb'
- 'language/break_spec.rb' - 'language/break_spec.rb'
- 'language/fixtures/break.rb' - 'language/fixtures/break.rb'

Просмотреть файл

@ -59,6 +59,7 @@ Lint/InheritException:
- 'core/enumerator/lazy/fixtures/classes.rb' - 'core/enumerator/lazy/fixtures/classes.rb'
- 'core/exception/fixtures/common.rb' - 'core/exception/fixtures/common.rb'
- 'core/module/fixtures/autoload_ex1.rb' - 'core/module/fixtures/autoload_ex1.rb'
- 'shared/kernel/raise.rb'
# Offense count: 72 # Offense count: 72
# Cop supports --auto-correct. # Cop supports --auto-correct.
@ -115,6 +116,7 @@ Lint/RescueException:
- 'core/exception/cause_spec.rb' - 'core/exception/cause_spec.rb'
- 'core/exception/no_method_error_spec.rb' - 'core/exception/no_method_error_spec.rb'
- 'core/kernel/fixtures/autoload_frozen.rb' - 'core/kernel/fixtures/autoload_frozen.rb'
- 'core/kernel/raise_spec.rb'
- 'core/module/autoload_spec.rb' - 'core/module/autoload_spec.rb'
- 'core/mutex/sleep_spec.rb' - 'core/mutex/sleep_spec.rb'
- 'core/thread/abort_on_exception_spec.rb' - 'core/thread/abort_on_exception_spec.rb'

Просмотреть файл

@ -136,11 +136,11 @@ Here is a list of the most commonly-used guards:
#### Version guards #### Version guards
```ruby ```ruby
ruby_version_is ""..."2.6 do ruby_version_is ""..."2.6" do
# Specs for RUBY_VERSION < 2.6 # Specs for RUBY_VERSION < 2.6
end end
ruby_version_is "2.6 do ruby_version_is "2.6" do
# Specs for RUBY_VERSION >= 2.6 # Specs for RUBY_VERSION >= 2.6
end end
``` ```

Просмотреть файл

@ -7,7 +7,22 @@ describe "The -r command line option" do
end end
it "requires the specified file" do it "requires the specified file" do
result = ruby_exe(@script, options: "-r #{@test_file}") out = ruby_exe(@script, options: "-r #{@test_file}")
result.should include(@test_file + ".rb") out.should include("REQUIRED")
out.should include(@test_file + ".rb")
end
it "requires the file before parsing the main script" do
out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), options: "-r #{@test_file}", args: "2>&1")
$?.should_not.success?
out.should include("REQUIRED")
out.should include("syntax error")
end
it "does not require the file if the main script file does not exist" do
out = `#{ruby_exe.to_a.join(' ')} -r #{@test_file} #{fixture(__FILE__, "does_not_exist.rb")} 2>&1`
$?.should_not.success?
out.should_not.include?("REQUIRED")
out.should.include?("No such file or directory")
end end
end end

Просмотреть файл

@ -1 +1 @@
"test file" puts "REQUIRED"

Просмотреть файл

@ -207,8 +207,9 @@ describe "Array#fill with (filler, index, length)" do
not_supported_on :opal do not_supported_on :opal do
it "raises an ArgumentError or RangeError for too-large sizes" do it "raises an ArgumentError or RangeError for too-large sizes" do
error_types = [RangeError, ArgumentError]
arr = [1, 2, 3] arr = [1, 2, 3]
-> { arr.fill(10, 1, fixnum_max) }.should raise_error(ArgumentError) -> { arr.fill(10, 1, fixnum_max) }.should raise_error { |err| error_types.should include(err.class) }
-> { arr.fill(10, 1, bignum_value) }.should raise_error(RangeError) -> { arr.fill(10, 1, bignum_value) }.should raise_error(RangeError)
end end
end end

Просмотреть файл

@ -43,7 +43,7 @@ describe "Exception#backtrace" do
# This regexp is deliberately imprecise to account for the need to abstract out # This regexp is deliberately imprecise to account for the need to abstract out
# the paths of the included mspec files and the desire to avoid specifying in any # the paths of the included mspec files and the desire to avoid specifying in any
# detail what the in `...' portion looks like. # detail what the in `...' portion looks like.
line.should =~ /^[^ ]+\:\d+(:in `[^`]+')?$/ line.should =~ /^.+:\d+:in `[^`]+'$/
end end
end end

Просмотреть файл

@ -5,6 +5,13 @@ describe "Kernel#__dir__" do
__dir__.should == File.realpath(File.dirname(__FILE__)) __dir__.should == File.realpath(File.dirname(__FILE__))
end 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 context "when used in eval with a given filename" do
it "returns File.dirname(filename)" do it "returns File.dirname(filename)" do
eval("__dir__", nil, "foo.rb").should == "." eval("__dir__", nil, "foo.rb").should == "."

Просмотреть файл

@ -23,7 +23,7 @@ describe "Kernel.at_exit" do
it "gives access to the last raised exception" do it "gives access to the last raised exception" do
code = <<-EOC code = <<-EOC
at_exit do at_exit do
puts "The exception matches: \#{$! == $exception}" puts "The exception matches: \#{$! == $exception} (message=\#{$!.message})"
end end
begin begin
@ -33,10 +33,35 @@ describe "Kernel.at_exit" do
end end
EOC EOC
result = ruby_exe(code, args: "2>&1", escape: true) result = ruby_exe(code, args: "2>&1")
result.should =~ /The exception matches: true/ result.lines.should.include?("The exception matches: true (message=foo)\n")
end end
it "both exceptions in at_exit and in the main script are printed" do
result = ruby_exe('at_exit { raise "at_exit_error" }; raise "main_script_error"', args: "2>&1")
result.should.include?('at_exit_error (RuntimeError)')
result.should.include?('main_script_error (RuntimeError)')
end
it "decides the exit status if both at_exit and the main script raise SystemExit" do
ruby_exe('at_exit { exit 43 }; exit 42', args: "2>&1")
$?.exitstatus.should == 43
end
it "runs all at_exit even if some raise exceptions" do
code = 'at_exit { STDERR.puts "last" }; at_exit { exit 43 }; at_exit { STDERR.puts "first" }; exit 42'
result = ruby_exe(code, args: "2>&1")
result.should == "first\nlast\n"
$?.exitstatus.should == 43
end
it "runs at_exit handlers even if the main script fails to parse" do
script = fixture(__FILE__, "at_exit.rb")
result = ruby_exe('{', options: "-r#{script}", args: "2>&1")
$?.should_not.success?
result.should.include?("at_exit ran\n")
result.should.include?("syntax error")
end
end end
describe "Kernel#at_exit" do describe "Kernel#at_exit" do

Просмотреть файл

@ -0,0 +1,2 @@
puts __FILE__
puts __dir__

Просмотреть файл

@ -0,0 +1,3 @@
at_exit do
STDERR.puts "at_exit ran"
end

Просмотреть файл

@ -0,0 +1 @@
warn 'warn-require-warning', uplevel: 1

Просмотреть файл

@ -0,0 +1,2 @@
# Use a different line than just 1
require "#{__dir__}/warn_require"

Просмотреть файл

@ -6,6 +6,27 @@ describe "Kernel#raise" do
it "is a private method" do it "is a private method" do
Kernel.should have_private_instance_method(:raise) Kernel.should have_private_instance_method(:raise)
end 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
end end
describe "Kernel#raise" do describe "Kernel#raise" do

Просмотреть файл

@ -101,6 +101,19 @@ describe "Kernel#warn" do
-> { w.f4("foo", 3) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f3_call_lineno}: warning: foo|) -> { w.f4("foo", 3) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f3_call_lineno}: warning: foo|)
end 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
ruby_version_is "2.6" do
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
end
it "converts first arg using to_s" do it "converts first arg using to_s" do
w = KernelSpecs::WarnInNestedCall.new w = KernelSpecs::WarnInNestedCall.new

Просмотреть файл

@ -3,6 +3,10 @@ module ModuleSpecs
def foo; "foo" end def foo; "foo" end
end end
class ClassWithSuperFoo
def foo; [:C] end
end
module PrependedModule module PrependedModule
def foo; "foo from prepended module"; end def foo; "foo from prepended module"; end
end end
@ -11,7 +15,11 @@ module ModuleSpecs
def foo; "foo from included module"; end def foo; "foo from included module"; end
end end
def self.build_refined_class def self.build_refined_class(for_super: false)
if for_super
Class.new(ClassWithSuperFoo)
else
Class.new(ClassWithFoo) Class.new(ClassWithFoo)
end end
end end
end

Просмотреть файл

@ -731,16 +731,67 @@ describe "Module#refine" do
result.should == "foo" result.should == "foo"
end end
it "looks in the refined class from included module" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
a = Module.new do
def foo
[:A] + super
end
end
refinement = Module.new do
refine refined_class do
include a
end
end
result = nil
Module.new do
using refinement
result = refined_class.new.foo
end
result.should == [:A, :C]
end
it "looks in the refined ancestors from included module" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
subclass = Class.new(refined_class)
a = Module.new do
def foo
[:A] + super
end
end
refinement = Module.new do
refine refined_class do
include a
end
end
result = nil
Module.new do
using refinement
result = subclass.new.foo
end
result.should == [:A, :C]
end
# super in a method of a refinement invokes the method in the refined # super in a method of a refinement invokes the method in the refined
# class even if there is another refinement which has been activated # class even if there is another refinement which has been activated
# in the same context. # in the same context.
it "looks in the refined class even if there is another active refinement" do it "looks in the refined class first if called from refined method" do
refined_class = ModuleSpecs.build_refined_class refined_class = ModuleSpecs.build_refined_class(for_super: true)
refinement = Module.new do refinement = Module.new do
refine refined_class do refine refined_class do
def foo def foo
"foo from refinement" [:R1]
end end
end end
end end
@ -748,7 +799,7 @@ describe "Module#refine" do
refinement_with_super = Module.new do refinement_with_super = Module.new do
refine refined_class do refine refined_class do
def foo def foo
super [:R2] + super
end end
end end
end end
@ -760,7 +811,246 @@ describe "Module#refine" do
result = refined_class.new.foo result = refined_class.new.foo
end end
result.should == "foo" result.should == [:R2, :C]
end
it "looks only in the refined class even if there is another active refinement" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
refinement = Module.new do
refine refined_class do
def bar
"you cannot see me from super because I belong to another active R"
end
end
end
refinement_with_super = Module.new do
refine refined_class do
def bar
super
end
end
end
Module.new do
using refinement
using refinement_with_super
-> {
refined_class.new.bar
}.should raise_error(NoMethodError)
end
end
it "does't have access to active refinements for C from included module" do
refined_class = ModuleSpecs.build_refined_class
a = Module.new do
def foo
super + bar
end
end
refinement = Module.new do
refine refined_class do
include a
def bar
"bar is not seen from A methods"
end
end
end
Module.new do
using refinement
-> {
refined_class.new.foo
}.should raise_error(NameError) { |e| e.name.should == :bar }
end
end
it "does't have access to other active refinements from included module" do
refined_class = ModuleSpecs.build_refined_class
refinement_integer = Module.new do
refine Integer do
def bar
"bar is not seen from A methods"
end
end
end
a = Module.new do
def foo
super + 1.bar
end
end
refinement = Module.new do
refine refined_class do
include a
end
end
Module.new do
using refinement
using refinement_integer
-> {
refined_class.new.foo
}.should raise_error(NameError) { |e| e.name.should == :bar }
end
end
# https://bugs.ruby-lang.org/issues/16977
it "looks in the another active refinement if super called from included modules" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
a = Module.new do
def foo
[:A] + super
end
end
b = Module.new do
def foo
[:B] + super
end
end
refinement_a = Module.new do
refine refined_class do
include a
end
end
refinement_b = Module.new do
refine refined_class do
include b
end
end
result = nil
Module.new do
using refinement_a
using refinement_b
result = refined_class.new.foo
end
result.should == [:B, :A, :C]
end
it "looks in the current active refinement from included modules" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
a = Module.new do
def foo
[:A] + super
end
end
b = Module.new do
def foo
[:B] + super
end
end
refinement = Module.new do
refine refined_class do
def foo
[:LAST] + super
end
end
end
refinement_a_b = Module.new do
refine refined_class do
include a
include b
end
end
result = nil
Module.new do
using refinement
using refinement_a_b
result = refined_class.new.foo
end
result.should == [:B, :A, :LAST, :C]
end
ruby_version_is ""..."2.8" do
it "looks in the lexical scope refinements before other active refinements" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
refinement_local = Module.new do
refine refined_class do
def foo
[:LOCAL] + super
end
end
end
a = Module.new do
using refinement_local
def foo
[:A] + super
end
end
refinement = Module.new do
refine refined_class do
include a
end
end
result = nil
Module.new do
using refinement
result = refined_class.new.foo
end
result.should == [:A, :LOCAL, :C]
end
end
ruby_version_is "2.8" do
# https://bugs.ruby-lang.org/issues/17007
it "does not look in the lexical scope refinements before other active refinements" do
refined_class = ModuleSpecs.build_refined_class(for_super: true)
refinement_local = Module.new do
refine refined_class do
def foo
[:LOCAL] + super
end
end
end
a = Module.new do
using refinement_local
def foo
[:A] + super
end
end
refinement = Module.new do
refine refined_class do
include a
end
end
result = nil
Module.new do
using refinement
result = refined_class.new.foo
end
result.should == [:A, :C]
end
end end
end end

Просмотреть файл

@ -426,14 +426,72 @@ describe "String#split with Regexp" do
end end
ruby_version_is "2.6" do ruby_version_is "2.6" do
it "yields each split substrings if a block is given" do context "when a block is given" do
it "yields each split substring with default pattern" do
a = [] a = []
returned_object = "chunky bacon".split(" ") { |str| a << str.capitalize } returned_object = "chunky bacon".split { |str| a << str.capitalize }
returned_object.should == "chunky bacon" returned_object.should == "chunky bacon"
a.should == ["Chunky", "Bacon"] a.should == ["Chunky", "Bacon"]
end end
it "yields the string when limit is 1" do
a = []
returned_object = "chunky bacon".split("", 1) { |str| a << str.capitalize }
returned_object.should == "chunky bacon"
a.should == ["Chunky bacon"]
end
it "yields each split letter" do
a = []
returned_object = "chunky".split("", 0) { |str| a << str.capitalize }
returned_object.should == "chunky"
a.should == %w(C H U N K Y)
end
it "yields each split substring with a pattern" do
a = []
returned_object = "chunky-bacon".split("-", 0) { |str| a << str.capitalize }
returned_object.should == "chunky-bacon"
a.should == ["Chunky", "Bacon"]
end
it "yields each split substring with empty regexp pattern" do
a = []
returned_object = "chunky".split(//) { |str| a << str.capitalize }
returned_object.should == "chunky"
a.should == %w(C H U N K Y)
end
it "yields each split substring with empty regexp pattern and limit" do
a = []
returned_object = "chunky".split(//, 3) { |str| a << str.capitalize }
returned_object.should == "chunky"
a.should == %w(C H Unky)
end
it "yields each split substring with a regexp pattern" do
a = []
returned_object = "chunky:bacon".split(/:/) { |str| a << str.capitalize }
returned_object.should == "chunky:bacon"
a.should == ["Chunky", "Bacon"]
end
it "returns a string as is (and doesn't call block) if it is empty" do
a = []
returned_object = "".split { |str| a << str.capitalize }
returned_object.should == ""
a.should == []
end
end
describe "for a String subclass" do describe "for a String subclass" do
it "yields instances of the same subclass" do it "yields instances of the same subclass" do
a = [] a = []

Просмотреть файл

@ -10,6 +10,13 @@ describe 'Thread::Backtrace::Location#absolute_path' do
@frame.absolute_path.should == File.realpath(__FILE__) @frame.absolute_path.should == File.realpath(__FILE__)
end end
it 'returns an absolute path when using a relative main script path' do
script = fixture(__FILE__, 'absolute_path_main.rb')
Dir.chdir(File.dirname(script)) do
ruby_exe('absolute_path_main.rb').should == "absolute_path_main.rb\n#{script}\n"
end
end
context "when used in eval with a given filename" do context "when used in eval with a given filename" do
it "returns filename" do it "returns filename" do
code = "caller_locations(0)[0].absolute_path" code = "caller_locations(0)[0].absolute_path"

Просмотреть файл

@ -0,0 +1,2 @@
puts __FILE__
puts caller_locations(0)[0].absolute_path

Просмотреть файл

@ -10,4 +10,14 @@ describe 'Thread::Backtrace::Location#lineno' do
it 'returns the absolute path of the call frame' do it 'returns the absolute path of the call frame' do
@frame.lineno.should == @line @frame.lineno.should == @line
end end
it 'should be the same line number as in #to_s, including for core methods' do
# Get the caller_locations from a call made into a core library method
locations = [:non_empty].map { caller_locations }[0]
locations.each do |location|
line_number = location.to_s[/:(\d+):/, 1]
location.lineno.should == Integer(line_number)
end
end
end end

Просмотреть файл

@ -87,6 +87,18 @@ describe 'Thread::Backtrace::Location#path' do
end end
end end
it 'should be the same path as in #to_s, including for core methods' do
# Get the caller_locations from a call made into a core library method
locations = [:non_empty].map { caller_locations }[0]
locations.each do |location|
filename = location.to_s[/^(.+):\d+:/, 1]
path = location.path
path.should == filename
end
end
context "canonicalization" do context "canonicalization" do
platform_is_not :windows do platform_is_not :windows do
before :each do before :each do

Просмотреть файл

@ -203,6 +203,6 @@ describe "Thread#raise on same thread" do
Thread.current.raise Thread.current.raise
end end
end end
-> { t.value }.should raise_error(RuntimeError) -> { t.value }.should raise_error(RuntimeError, '')
end end
end end

Просмотреть файл

@ -362,4 +362,22 @@ describe "Executing break from within a block" do
bt2.three bt2.three
ScratchPad.recorded.should == [:two_ensure, :three_post, :three_ensure] ScratchPad.recorded.should == [:two_ensure, :three_post, :three_ensure]
end end
it "works when passing through a super call" do
cls1 = Class.new { def foo; yield; end }
cls2 = Class.new(cls1) { def foo; super { break 1 }; end }
-> do
cls2.new.foo.should == 1
end.should_not raise_error
end
it "raises LocalJumpError when converted into a proc during a a super call" do
cls1 = Class.new { def foo(&b); b; end }
cls2 = Class.new(cls1) { def foo; super { break 1 }.call; end }
-> do
cls2.new.foo
end.should raise_error(LocalJumpError)
end
end end

Просмотреть файл

@ -42,7 +42,7 @@ ruby_version_is "2.7" do
end end
end end
it "warns when numbered parameter is overriten with local variable" do it "warns when numbered parameter is overwritten with local variable" do
-> { -> {
eval("_1 = 0") eval("_1 = 0")
}.should complain(/warning: `_1' is reserved for numbered parameter; consider another name/) }.should complain(/warning: `_1' is reserved for numbered parameter; consider another name/)
@ -59,7 +59,7 @@ ruby_version_is "2.7" do
}.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/) }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
end end
it "errors when numbered parameter is overriten with local variable" do it "errors when numbered parameter is overwritten with local variable" do
-> { -> {
eval("_1 = 0") eval("_1 = 0")
}.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/) }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)

Просмотреть файл

@ -8,6 +8,11 @@ describe "BigDecimal#to_s" do
@bigneg_str = "-3.1415926535897932384626433832795028841971693993" @bigneg_str = "-3.1415926535897932384626433832795028841971693993"
@bigdec = BigDecimal(@bigdec_str) @bigdec = BigDecimal(@bigdec_str)
@bigneg = BigDecimal(@bigneg_str) @bigneg = BigDecimal(@bigneg_str)
@internal = Encoding.default_internal
end
after :each do
Encoding.default_internal = @internal
end end
it "return type is of class String" do it "return type is of class String" do
@ -78,4 +83,15 @@ describe "BigDecimal#to_s" do
end end
end end
ruby_version_is "2.8" do
it "returns a String in US-ASCII encoding when Encoding.default_internal is nil" do
Encoding.default_internal = nil
BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII)
end
it "returns a String in US-ASCII encoding when Encoding.default_internal is not nil" do
Encoding.default_internal = Encoding::IBM437
BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII)
end
end
end end

Просмотреть файл

@ -0,0 +1,19 @@
require_relative '../../../spec_helper'
require 'digest'
require_relative '../md5/shared/constants'
describe "Digest::Instance#new" do
it "returns a copy of the digest instance" do
digest = Digest::MD5.new
copy = digest.new
copy.should_not.equal?(digest)
end
it "calls reset" do
digest = Digest::MD5.new
digest << "test"
digest.hexdigest.should != MD5Constants::BlankHexdigest
copy = digest.new
copy.hexdigest.should == MD5Constants::BlankHexdigest
end
end

Просмотреть файл

@ -0,0 +1,23 @@
require_relative '../../spec_helper'
require 'ripper'
describe "Ripper.lex" do
it "lexes a simple method declaration" do
expected = [
[[1, 0], :on_kw, "def", 'FNAME'],
[[1, 3], :on_sp, " ", 'FNAME'],
[[1, 4], :on_ident, "m", 'ENDFN'],
[[1, 5], :on_lparen, "(", 'BEG|LABEL'],
[[1, 6], :on_ident, "a", 'ARG'],
[[1, 7], :on_rparen, ")", 'ENDFN'],
[[1, 8], :on_sp, " ", 'BEG'],
[[1, 9], :on_kw, "nil", 'END'],
[[1, 12], :on_sp, " ", 'END'],
[[1, 13], :on_kw, "end", 'END']
]
lexed = Ripper.lex("def m(a) nil end")
lexed.map { |e|
e[0...-1] + [e[-1].to_s.split('|').map { |s| s.sub(/^EXPR_/, '') }.join('|')]
}.should == expected
end
end

Просмотреть файл

@ -0,0 +1,13 @@
require_relative '../../spec_helper'
require 'ripper'
describe "Ripper.sexp" do
it "returns an s-expression for a method declaration" do
expected = [:program,
[[:def,
[:@ident, "hello", [1, 4]],
[:params, nil, nil, nil, nil, nil, nil, nil],
[:bodystmt, [[:@int, "42", [1, 11]]], nil, nil, nil]]]]
Ripper.sexp("def hello; 42; end").should == expected
end
end

Просмотреть файл

@ -58,6 +58,15 @@ describe "C-API Encoding function" do
end end
end end
describe "rb_enc_codelen" do
it "returns the correct length for the given codepoint" do
@s.rb_enc_codelen(0x24, Encoding::UTF_8).should == 1
@s.rb_enc_codelen(0xA2, Encoding::UTF_8).should == 2
@s.rb_enc_codelen(0x20AC, Encoding::UTF_8).should == 3
@s.rb_enc_codelen(0x24B62, Encoding::UTF_8).should == 4
end
end
describe "rb_enc_find" do describe "rb_enc_find" do
it "returns the encoding of an Encoding" do it "returns the encoding of an Encoding" do
@s.rb_enc_find("UTF-8").should == "UTF-8" @s.rb_enc_find("UTF-8").should == "UTF-8"
@ -130,6 +139,18 @@ describe "C-API Encoding function" do
end end
end end
describe "rb_enc_mbcput" do
it "writes the correct bytes to the buffer" do
@s.rb_enc_mbcput(0x24, Encoding::UTF_8).should == "$"
@s.rb_enc_mbcput(0xA2, Encoding::UTF_8).should == "¢"
@s.rb_enc_mbcput(0x20AC, Encoding::UTF_8).should == ""
@s.rb_enc_mbcput(0x24B62, Encoding::UTF_8).should == "𤭢"
@s.rb_enc_mbcput(0x24, Encoding::UTF_16BE).bytes.should == [0, 0x24]
@s.rb_enc_mbcput(0x24B62, Encoding::UTF_16LE).bytes.should == [82, 216, 98, 223]
end
end
describe "rb_usascii_encoding" do describe "rb_usascii_encoding" do
it "returns the encoding for Encoding::US_ASCII" do it "returns the encoding for Encoding::US_ASCII" do
@s.rb_usascii_encoding.should == "US-ASCII" @s.rb_usascii_encoding.should == "US-ASCII"
@ -610,4 +631,21 @@ describe "C-API Encoding function" do
end end
end end
end end
describe "ONIGENC_MBC_CASE_FOLD" do
it "returns the correct case fold for the given string" do
@s.ONIGENC_MBC_CASE_FOLD("lower").should == ["l", 1]
@s.ONIGENC_MBC_CASE_FOLD("Upper").should == ["u", 1]
end
it "works with other encodings" do
@s.ONIGENC_MBC_CASE_FOLD("lower".force_encoding("binary")).should == ["l", 1]
@s.ONIGENC_MBC_CASE_FOLD("Upper".force_encoding("binary")).should == ["u", 1]
@s.ONIGENC_MBC_CASE_FOLD("É").should == ["é", 2]
str, length = @s.ONIGENC_MBC_CASE_FOLD('$'.encode(Encoding::UTF_16BE))
length.should == 2
str.bytes.should == [0, 0x24]
end
end
end end

Просмотреть файл

@ -127,6 +127,18 @@ static VALUE encoding_spec_rb_enc_mbc_to_codepoint(VALUE self, VALUE str, VALUE
return INT2FIX(rb_enc_mbc_to_codepoint(p, e, rb_enc_get(str))); return INT2FIX(rb_enc_mbc_to_codepoint(p, e, rb_enc_get(str)));
} }
static VALUE encoding_spec_rb_enc_mbcput(VALUE self, VALUE code, VALUE encoding) {
unsigned int c = FIX2UINT(code);
rb_encoding *enc = rb_to_encoding(encoding);
char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
memset(buf, '\1', sizeof(buf));
int len = rb_enc_mbcput(c, buf, enc);
if (buf[len] != '\1') {
rb_raise(rb_eRuntimeError, "should not change bytes after len");
}
return rb_enc_str_new(buf, len, enc);
}
static VALUE encoding_spec_rb_enc_from_encoding(VALUE self, VALUE name) { static VALUE encoding_spec_rb_enc_from_encoding(VALUE self, VALUE name) {
return rb_enc_from_encoding(rb_enc_find(RSTRING_PTR(name))); return rb_enc_from_encoding(rb_enc_find(RSTRING_PTR(name)));
} }
@ -266,6 +278,28 @@ static VALUE encoding_spec_rb_uv_to_utf8(VALUE self, VALUE buf, VALUE num) {
return INT2NUM(rb_uv_to_utf8(RSTRING_PTR(buf), NUM2INT(num))); return INT2NUM(rb_uv_to_utf8(RSTRING_PTR(buf), NUM2INT(num)));
} }
static VALUE encoding_spec_ONIGENC_MBC_CASE_FOLD(VALUE self, VALUE str) {
char *beg = RSTRING_PTR(str);
char *beg_initial = beg;
char *end = beg + 2;
OnigUChar fold[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM];
memset(fold, '\1', sizeof(fold));
rb_encoding *enc = rb_enc_get(str);
int r = ONIGENC_MBC_CASE_FOLD(enc, ONIGENC_CASE_FOLD, &beg, (const OnigUChar *)end, fold);
if (r > 0 && fold[r] != '\1') {
rb_raise(rb_eRuntimeError, "should not change bytes after len");
}
VALUE str_result = r <= 0 ? Qnil : rb_enc_str_new((char *)fold, r, enc);
long bytes_used = beg - beg_initial;
return rb_ary_new3(2, str_result, INT2FIX(bytes_used));
}
static VALUE encoding_spec_rb_enc_codelen(VALUE self, VALUE code, VALUE encoding) {
unsigned int c = FIX2UINT(code);
rb_encoding *enc = rb_to_encoding(encoding);
return INT2FIX(rb_enc_codelen(c, enc));
}
void Init_encoding_spec(void) { void Init_encoding_spec(void) {
VALUE cls; VALUE cls;
native_rb_encoding_pointer = (rb_encoding**) malloc(sizeof(rb_encoding*)); native_rb_encoding_pointer = (rb_encoding**) malloc(sizeof(rb_encoding*));
@ -299,12 +333,14 @@ void Init_encoding_spec(void) {
rb_define_method(cls, "rb_enc_associate_index", encoding_spec_rb_enc_associate_index, 2); rb_define_method(cls, "rb_enc_associate_index", encoding_spec_rb_enc_associate_index, 2);
rb_define_method(cls, "rb_enc_compatible", encoding_spec_rb_enc_compatible, 2); rb_define_method(cls, "rb_enc_compatible", encoding_spec_rb_enc_compatible, 2);
rb_define_method(cls, "rb_enc_copy", encoding_spec_rb_enc_copy, 2); rb_define_method(cls, "rb_enc_copy", encoding_spec_rb_enc_copy, 2);
rb_define_method(cls, "rb_enc_codelen", encoding_spec_rb_enc_codelen, 2);
rb_define_method(cls, "rb_enc_find", encoding_spec_rb_enc_find, 1); rb_define_method(cls, "rb_enc_find", encoding_spec_rb_enc_find, 1);
rb_define_method(cls, "rb_enc_find_index", encoding_spec_rb_enc_find_index, 1); rb_define_method(cls, "rb_enc_find_index", encoding_spec_rb_enc_find_index, 1);
rb_define_method(cls, "rb_enc_isalnum", encoding_spec_rb_enc_isalnum, 2); rb_define_method(cls, "rb_enc_isalnum", encoding_spec_rb_enc_isalnum, 2);
rb_define_method(cls, "rb_enc_isspace", encoding_spec_rb_enc_isspace, 2); rb_define_method(cls, "rb_enc_isspace", encoding_spec_rb_enc_isspace, 2);
rb_define_method(cls, "rb_enc_from_index", encoding_spec_rb_enc_from_index, 1); rb_define_method(cls, "rb_enc_from_index", encoding_spec_rb_enc_from_index, 1);
rb_define_method(cls, "rb_enc_mbc_to_codepoint", encoding_spec_rb_enc_mbc_to_codepoint, 2); rb_define_method(cls, "rb_enc_mbc_to_codepoint", encoding_spec_rb_enc_mbc_to_codepoint, 2);
rb_define_method(cls, "rb_enc_mbcput", encoding_spec_rb_enc_mbcput, 2);
rb_define_method(cls, "rb_enc_from_encoding", encoding_spec_rb_enc_from_encoding, 1); rb_define_method(cls, "rb_enc_from_encoding", encoding_spec_rb_enc_from_encoding, 1);
rb_define_method(cls, "rb_enc_get", encoding_spec_rb_enc_get, 1); rb_define_method(cls, "rb_enc_get", encoding_spec_rb_enc_get, 1);
rb_define_method(cls, "rb_enc_precise_mbclen", encoding_spec_rb_enc_precise_mbclen, 2); rb_define_method(cls, "rb_enc_precise_mbclen", encoding_spec_rb_enc_precise_mbclen, 2);
@ -326,6 +362,7 @@ void Init_encoding_spec(void) {
rb_define_method(cls, "rb_enc_codepoint_len", encoding_spec_rb_enc_codepoint_len, 1); rb_define_method(cls, "rb_enc_codepoint_len", encoding_spec_rb_enc_codepoint_len, 1);
rb_define_method(cls, "rb_enc_str_asciionly_p", encoding_spec_rb_enc_str_asciionly_p, 1); rb_define_method(cls, "rb_enc_str_asciionly_p", encoding_spec_rb_enc_str_asciionly_p, 1);
rb_define_method(cls, "rb_uv_to_utf8", encoding_spec_rb_uv_to_utf8, 2); rb_define_method(cls, "rb_uv_to_utf8", encoding_spec_rb_uv_to_utf8, 2);
rb_define_method(cls, "ONIGENC_MBC_CASE_FOLD", encoding_spec_ONIGENC_MBC_CASE_FOLD, 1);
} }
#ifdef __cplusplus #ifdef __cplusplus

Просмотреть файл

@ -148,6 +148,18 @@ VALUE sws_typed_change_struct(VALUE self, VALUE obj, VALUE new_val) {
return Qnil; return Qnil;
} }
VALUE sws_typed_rb_check_typeddata_same_type(VALUE self, VALUE obj) {
return rb_check_typeddata(obj, &sample_typed_wrapped_struct_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse;
}
VALUE sws_typed_rb_check_typeddata_same_type_parent(VALUE self, VALUE obj) {
return rb_check_typeddata(obj, &sample_typed_wrapped_struct_parent_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse;
}
VALUE sws_typed_rb_check_typeddata_different_type(VALUE self, VALUE obj) {
return rb_check_typeddata(obj, &sample_typed_wrapped_struct_other_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse;
}
void Init_typed_data_spec(void) { void Init_typed_data_spec(void) {
VALUE cls = rb_define_class("CApiAllocTypedSpecs", rb_cObject); VALUE cls = rb_define_class("CApiAllocTypedSpecs", rb_cObject);
rb_define_alloc_func(cls, sdaf_alloc_typed_func); rb_define_alloc_func(cls, sdaf_alloc_typed_func);
@ -160,6 +172,9 @@ void Init_typed_data_spec(void) {
rb_define_method(cls, "typed_get_struct_rdata", sws_typed_get_struct_rdata, 1); rb_define_method(cls, "typed_get_struct_rdata", sws_typed_get_struct_rdata, 1);
rb_define_method(cls, "typed_get_struct_data_ptr", sws_typed_get_struct_data_ptr, 1); rb_define_method(cls, "typed_get_struct_data_ptr", sws_typed_get_struct_data_ptr, 1);
rb_define_method(cls, "typed_change_struct", sws_typed_change_struct, 2); rb_define_method(cls, "typed_change_struct", sws_typed_change_struct, 2);
rb_define_method(cls, "rb_check_typeddata_same_type", sws_typed_rb_check_typeddata_same_type, 1);
rb_define_method(cls, "rb_check_typeddata_same_type_parent", sws_typed_rb_check_typeddata_same_type_parent, 1);
rb_define_method(cls, "rb_check_typeddata_different_type", sws_typed_rb_check_typeddata_different_type, 1);
} }
#ifdef __cplusplus #ifdef __cplusplus

Просмотреть файл

@ -831,6 +831,7 @@ describe "CApiObject" do
it "returns nil if the instance variable has not been initialized and is not a valid Ruby name" do it "returns nil if the instance variable has not been initialized and is not a valid Ruby name" do
@o.rb_ivar_get(@test, :bar).should == nil @o.rb_ivar_get(@test, :bar).should == nil
@o.rb_ivar_get(@test, :mesg).should == nil
end end
it 'returns the instance variable when it is not a valid Ruby name' do it 'returns the instance variable when it is not a valid Ruby name' do
@ -866,6 +867,7 @@ describe "CApiObject" do
it "does not throw an error if the instance variable is not a valid Ruby name" do it "does not throw an error if the instance variable is not a valid Ruby name" do
@o.rb_ivar_defined(@test, :bar).should == false @o.rb_ivar_defined(@test, :bar).should == false
@o.rb_ivar_defined(@test, :mesg).should == false
end end
end end

Просмотреть файл

@ -76,6 +76,7 @@ def compile_extension(name)
$ruby = ENV.values_at('RUBY_EXE', 'RUBY_FLAGS').join(' ') $ruby = ENV.values_at('RUBY_EXE', 'RUBY_FLAGS').join(' ')
# MRI magic to consider building non-bundled extensions # MRI magic to consider building non-bundled extensions
$extout = nil $extout = nil
$warnflags << ' -Wno-declaration-after-statement'
create_makefile(#{ext.inspect}) create_makefile(#{ext.inspect})
RUBY RUBY
output = ruby_exe("extconf.rb") output = ruby_exe("extconf.rb")

Просмотреть файл

@ -57,4 +57,21 @@ describe "CApiWrappedTypedStruct" do
@s.typed_get_struct_data_ptr(a).should == 1024 @s.typed_get_struct_data_ptr(a).should == 1024
end end
end end
describe "rb_check_typeddata" do
it "returns data pointer when the struct has the given type" do
a = @s.typed_wrap_struct(1024)
@s.rb_check_typeddata_same_type(a).should == true
end
it "returns data pointer when the parent struct has the given type" do
a = @s.typed_wrap_struct(1024)
@s.rb_check_typeddata_same_type_parent(a).should == true
end
it "raises an error for different types" do
a = @s.typed_wrap_struct(1024)
-> { @s.rb_check_typeddata_different_type(a) }.should raise_error(TypeError)
end
end
end end

Просмотреть файл

@ -25,6 +25,14 @@ describe :kernel_raise, shared: true do
-> { @object.raise("a bad thing") }.should raise_error(RuntimeError) -> { @object.raise("a bad thing") }.should raise_error(RuntimeError)
end end
it "passes no arguments to the constructor when given only an exception class" do
klass = Class.new(Exception) do
def initialize
end
end
-> { @object.raise(klass) }.should raise_error(klass) { |e| e.message.should == klass.to_s }
end
it "raises a TypeError when passed a non-Exception object" do it "raises a TypeError when passed a non-Exception object" do
-> { @object.raise(Object.new) }.should raise_error(TypeError) -> { @object.raise(Object.new) }.should raise_error(TypeError)
end end
@ -41,25 +49,6 @@ describe :kernel_raise, shared: true do
-> { @object.raise(nil) }.should raise_error(TypeError) -> { @object.raise(nil) }.should raise_error(TypeError)
end end
it "re-raises the previously rescued exception if no exception is specified" do
-> do
begin
@object.raise Exception, "outer"
ScratchPad.record :no_abort
rescue
begin
@object.raise StandardError, "inner"
rescue
end
@object.raise
ScratchPad.record :no_reraise
end
end.should raise_error(Exception, "outer")
ScratchPad.recorded.should be_nil
end
it "re-raises a previously rescued exception without overwriting the backtrace" do it "re-raises a previously rescued exception without overwriting the backtrace" do
begin begin
initial_raise_line = __LINE__; @object.raise 'raised' initial_raise_line = __LINE__; @object.raise 'raised'

Просмотреть файл

@ -91,4 +91,24 @@ describe :process_exit!, shared: true do
out.should == "" out.should == ""
$?.exitstatus.should == 21 $?.exitstatus.should == 21
end end
it "skips at_exit handlers" do
out = ruby_exe("at_exit { STDERR.puts 'at_exit' }; #{@object}.send(:exit!, 21)", args: '2>&1')
out.should == ""
$?.exitstatus.should == 21
end
it "overrides the original exception and exit status when called from #at_exit" do
code = <<-RUBY
at_exit do
STDERR.puts 'in at_exit'
STDERR.puts "$! is \#{$!.class}:\#{$!.message}"
#{@object}.send(:exit!, 21)
end
raise 'original error'
RUBY
out = ruby_exe(code, args: '2>&1')
out.should == "in at_exit\n$! is RuntimeError:original error\n"
$?.exitstatus.should == 21
end
end end