require File.expand_path('../../spec_helper', __FILE__)
require 'stringio'
describe "Predefined global $~" do
it "is set to contain the MatchData object of the last match if successful" do
md = /foo/.match 'foo'
$~.should be_kind_of(MatchData)
$~.object_id.should == md.object_id
/bar/ =~ 'bar'
$~.should be_kind_of(MatchData)
$~.object_id.should_not == md.object_id
end
it "is set to nil if the last match was unsuccessful" do
/foo/ =~ 'foo'
$~.nil?.should == false
/foo/ =~ 'bar'
$~.nil?.should == true
end
it "is set at the method-scoped level rather than block-scoped" do
obj = Object.new
def obj.foo; yield; end
def obj.foo2(&proc); proc.call; end
match = /foo/.match "foo"
obj.foo { match = /bar/.match("bar") }
$~.should == match
eval 'match = /baz/.match("baz")'
$~.should == match
obj.foo2 { match = /qux/.match("qux") }
$~.should == match
end
it "raises an error if assigned an object not nil or instanceof MatchData" do
$~ = nil
$~.should == nil
$~ = /foo/.match("foo")
$~.should be_an_instance_of(MatchData)
lambda { $~ = Object.new }.should raise_error(TypeError)
lambda { $~ = 1 }.should raise_error(TypeError)
end
it "changes the value of derived capture globals when assigned" do
"foo" =~ /(f)oo/
foo_match = $~
"bar" =~ /(b)ar/
$~ = foo_match
$1.should == "f"
end
it "changes the value of the derived preceding match global" do
"foo hello" =~ /hello/
foo_match = $~
"bar" =~ /(bar)/
$~ = foo_match
$`.should == "foo "
end
it "changes the value of the derived following match global" do
"foo hello" =~ /foo/
foo_match = $~
"bar" =~ /(bar)/
$~ = foo_match
$'.should == " hello"
end
it "changes the value of the derived full match global" do
"foo hello" =~ /foo/
foo_match = $~
"bar" =~ /(bar)/
$~ = foo_match
$&.should == "foo"
end
end
describe "Predefined global $&" do
it "is equivalent to MatchData#[0] on the last match $~" do
/foo/ =~ 'barfoobaz'
$&.should == $~[0]
$&.should == 'foo'
end
with_feature :encoding do
it "sets the encoding to the encoding of the source String" do
"abc".force_encoding(Encoding::EUC_JP) =~ /b/
$&.encoding.should equal(Encoding::EUC_JP)
end
end
end
describe "Predefined global $`" do
it "is equivalent to MatchData#pre_match on the last match $~" do
/foo/ =~ 'barfoobaz'
$`.should == $~.pre_match
$`.should == 'bar'
end
with_feature :encoding do
it "sets the encoding to the encoding of the source String" do
"abc".force_encoding(Encoding::EUC_JP) =~ /b/
$`.encoding.should equal(Encoding::EUC_JP)
end
it "sets an empty result to the encoding of the source String" do
"abc".force_encoding(Encoding::ISO_8859_1) =~ /a/
$`.encoding.should equal(Encoding::ISO_8859_1)
end
end
end
describe "Predefined global $'" do
it "is equivalent to MatchData#post_match on the last match $~" do
/foo/ =~ 'barfoobaz'
$'.should == $~.post_match
$'.should == 'baz'
end
with_feature :encoding do
it "sets the encoding to the encoding of the source String" do
"abc".force_encoding(Encoding::EUC_JP) =~ /b/
$'.encoding.should equal(Encoding::EUC_JP)
end
it "sets an empty result to the encoding of the source String" do
"abc".force_encoding(Encoding::ISO_8859_1) =~ /c/
$'.encoding.should equal(Encoding::ISO_8859_1)
end
end
end
describe "Predefined global $+" do
it "is equivalent to $~.captures.last" do
/(f(o)o)/ =~ 'barfoobaz'
$+.should == $~.captures.last
$+.should == 'o'
end
it "captures the last non nil capture" do
/(a)|(b)/ =~ 'a'
$+.should == 'a'
end
with_feature :encoding do
it "sets the encoding to the encoding of the source String" do
"abc".force_encoding(Encoding::EUC_JP) =~ /(b)/
$+.encoding.should equal(Encoding::EUC_JP)
end
end
end
describe "Predefined globals $1..N" do
it "are equivalent to $~[N]" do
/(f)(o)(o)/ =~ 'foo'
$1.should == $~[1]
$2.should == $~[2]
$3.should == $~[3]
$4.should == $~[4]
[$1, $2, $3, $4].should == ['f', 'o', 'o', nil]
end
it "are nil unless a match group occurs" do
def test(arg)
case arg
when /-(.)?/
$1
end
end
test("-").should == nil
end
with_feature :encoding do
it "sets the encoding to the encoding of the source String" do
"abc".force_encoding(Encoding::EUC_JP) =~ /(b)/
$1.encoding.should equal(Encoding::EUC_JP)
end
end
end
describe "Predefined global $stdout" do
before :each do
@old_stdout = $stdout
end
after :each do
$stdout = @old_stdout
end
it "raises TypeError error if assigned to nil" do
lambda { $stdout = nil }.should raise_error(TypeError)
end
it "raises TypeError error if assigned to object that doesn't respond to #write" do
obj = mock('object')
lambda { $stdout = obj }.should raise_error(TypeError)
obj.stub!(:write)
$stdout = obj
$stdout.should equal(obj)
end
end
describe "Predefined global $!" do
it "remains nil after a failed core class \"checked\" coercion against a class that defines method_missing" do
$!.should == nil
obj = Class.new do
def method_missing(*args)
super
end
end.new
[obj, 'foo'].join
$!.should == nil
end
it "should be set to the value of $! before the begin after a successful rescue" do
outer = StandardError.new 'outer'
inner = StandardError.new 'inner'
begin
raise outer
rescue
$!.should == outer
begin
$!.should == outer
raise inner
rescue
$!.should == inner
ensure
$!.should == outer
end
$!.should == outer
end
$!.should == nil
end
it "should be set to the value of $! before the begin after a rescue which returns" do
def foo
outer = StandardError.new 'outer'
inner = StandardError.new 'inner'
begin
raise outer
rescue
$!.should == outer
begin
$!.should == outer
raise inner
rescue
$!.should == inner
return
ensure
$!.should == outer
end
$!.should == outer
end
$!.should == nil
end
foo
end
it "should be set to the value of $! before the begin after a successful rescue within an ensure" do
outer = StandardError.new 'outer'
inner = StandardError.new 'inner'
begin
begin
raise outer
ensure
$!.should == outer
begin
$!.should == outer
raise inner
rescue
$!.should == inner
ensure
$!.should == outer
end
$!.should == outer
end
flunk "outer should be raised after the ensure"
rescue
$!.should == outer
end
$!.should == nil
end
it "should be set to the new exception after a throwing rescue" do
outer = StandardError.new 'outer'
inner = StandardError.new 'inner'
begin
raise outer
rescue
$!.should == outer
begin
begin
$!.should == outer
raise inner
rescue $!.should == inner
raise inner
ensure
$!.should == inner
end
rescue $!.should == inner
end
$!.should == outer
end
$!.should == nil
end
describe "in bodies without ensure" do
it "should be cleared when an exception is rescued" do
e = StandardError.new 'foo'
begin
raise e
rescue
$!.should == e
end
$!.should == nil
end
it "should be cleared when an exception is rescued even when a non-local return is present" do
def foo(e)
$!.should == e
yield
end
def bar
e = StandardError.new 'foo'
begin
raise e
rescue
$!.should == e
foo(e) { return }
end
end
bar
$!.should == nil
end
it "should not be cleared when an exception is not rescued" do
e = StandardError.new
begin
begin
begin
raise e
rescue TypeError
flunk
end
ensure
$!.should == e
end
rescue
$!.should == e
end
$!.should == nil
end
it "should not be cleared when an exception is rescued and rethrown" do
e = StandardError.new 'foo'
begin
begin
begin
raise e
rescue => e
$!.should == e
raise e
end
ensure
$!.should == e
end
rescue
$!.should == e
end
$!.should == nil
end
end
describe "in ensure-protected bodies" do
it "should be cleared when an exception is rescued" do
e = StandardError.new 'foo'
begin
raise e
rescue
$!.should == e
ensure
$!.should == nil
end
$!.should == nil
end
it "should not be cleared when an exception is not rescued" do
e = StandardError.new
begin
begin
begin
raise e
rescue TypeError
flunk
ensure
$!.should == e
end
ensure
$!.should == e
end
rescue
$!.should == e
end
end
it "should not be cleared when an exception is rescued and rethrown" do
e = StandardError.new
begin
begin
begin
raise e
rescue => e
$!.should == e
raise e
ensure
$!.should == e
end
ensure
$!.should == e
end
rescue
$!.should == e
end
end
end
end
describe "Predefined global $/" do
before :each do
@dollar_slash = $/
@dollar_dash_zero = $-0
end
after :each do
$/ = @dollar_slash
$-0 = @dollar_dash_zero
end
it "can be assigned a String" do
str = "abc"
$/ = str
$/.should equal(str)
end
it "can be assigned nil" do
$/ = nil
$/.should be_nil
end
it "returns the value assigned" do
($/ = "xyz").should == "xyz"
end
it "changes $-0" do
$/ = "xyz"
$-0.should equal($/)
end
it "does not call #to_str to convert the object to a String" do
obj = mock("$/ value")
obj.should_not_receive(:to_str)
lambda { $/ = obj }.should raise_error(TypeError)
end
it "raises a TypeError if assigned a Fixnum" do
lambda { $/ = 1 }.should raise_error(TypeError)
end
it "raises a TypeError if assigned a boolean" do
lambda { $/ = true }.should raise_error(TypeError)
end
end
describe "Predefined global $-0" do
before :each do
@dollar_slash = $/
@dollar_dash_zero = $-0
end
after :each do
$/ = @dollar_slash
$-0 = @dollar_dash_zero
end
it "can be assigned a String" do
str = "abc"
$-0 = str
$-0.should equal(str)
end
it "can be assigned nil" do
$-0 = nil
$-0.should be_nil
end
it "returns the value assigned" do
($-0 = "xyz").should == "xyz"
end
it "changes $/" do
$-0 = "xyz"
$/.should equal($-0)
end
it "does not call #to_str to convert the object to a String" do
obj = mock("$-0 value")
obj.should_not_receive(:to_str)
lambda { $-0 = obj }.should raise_error(TypeError)
end
it "raises a TypeError if assigned a Fixnum" do
lambda { $-0 = 1 }.should raise_error(TypeError)
end
it "raises a TypeError if assigned a boolean" do
lambda { $-0 = true }.should raise_error(TypeError)
end
end
describe "Predefined global $," do
after :each do
$, = nil
end
it "defaults to nil" do
$,.should be_nil
end
it "raises TypeError if assigned a non-String" do
lambda { $, = Object.new }.should raise_error(TypeError)
end
end
describe "Predefined global $_" do
it "is set to the last line read by e.g. StringIO#gets" do
stdin = StringIO.new("foo\nbar\n", "r")
read = stdin.gets
read.should == "foo\n"
$_.should == read
read = stdin.gets
read.should == "bar\n"
$_.should == read
read = stdin.gets
read.should == nil
$_.should == read
end
it "is set at the method-scoped level rather than block-scoped" do
obj = Object.new
def obj.foo; yield; end
def obj.foo2; yield; end
stdin = StringIO.new("foo\nbar\nbaz\nqux\n", "r")
match = stdin.gets
obj.foo { match = stdin.gets }
match.should == "bar\n"
$_.should == match
eval 'match = stdin.gets'
match.should == "baz\n"
$_.should == match
obj.foo2 { match = stdin.gets }
match.should == "qux\n"
$_.should == match
end
it "is Thread-local" do
$_ = nil
running = false
thr = Thread.new do
$_ = "last line"
running = true
end
Thread.pass until running
$_.should be_nil
thr.join
end
it "can be assigned any value" do
$_ = nil
$_.should == nil
$_ = "foo"
$_.should == "foo"
o = Object.new
$_ = o
$_.should == o
$_ = 1
$_.should == 1
end
end
describe "Execution variable $:" do
it "is initialized to an array of strings" do
$:.is_a?(Array).should == true
($:.length > 0).should == true
end
it "does not include the current directory" do
$:.should_not include(".")
end
it "is the same object as $LOAD_PATH and $-I" do
$:.__id__.should == $LOAD_PATH.__id__
$:.__id__.should == $-I.__id__
end
it "can be changed via <<" do
$: << "foo"
$:.should include("foo")
end
it "is read-only" do
lambda {
$: = []
}.should raise_error(NameError)
lambda {
$LOAD_PATH = []
}.should raise_error(NameError)
lambda {
$-I = []
}.should raise_error(NameError)
end
end
describe "Global variable $\"" do
it "is an alias for $LOADED_FEATURES" do
$".object_id.should == $LOADED_FEATURES.object_id
end
it "is read-only" do
lambda {
$" = []
}.should raise_error(NameError)
lambda {
$LOADED_FEATURES = []
}.should raise_error(NameError)
end
end
describe "Global variable $<" do
it "is read-only" do
lambda {
$< = nil
}.should raise_error(NameError)
end
end
describe "Global variable $FILENAME" do
it "is read-only" do
lambda {
$FILENAME = "-"
}.should raise_error(NameError)
end
end
describe "Global variable $?" do
it "is read-only" do
lambda {
$? = nil
}.should raise_error(NameError)
end
it "is thread-local" do
system("#{RUBY_EXE} -e 'exit 0'")
Thread.new { $?.should be_nil }.join
end
end
describe "Global variable $-a" do
it "is read-only" do
lambda { $-a = true }.should raise_error(NameError)
end
end
describe "Global variable $-l" do
it "is read-only" do
lambda { $-l = true }.should raise_error(NameError)
end
end
describe "Global variable $-p" do
it "is read-only" do
lambda { $-p = true }.should raise_error(NameError)
end
end
describe "Global variable $-d" do
before :each do
@debug = $DEBUG
end
after :each do
$DEBUG = @debug
end
it "is an alias of $DEBUG" do
$DEBUG = true
$-d.should be_true
$-d = false
$DEBUG.should be_false
end
end
describe :verbose_global_alias, shared: true do
before :each do
@verbose = $VERBOSE
end
after :each do
$VERBOSE = @verbose
end
it "is an alias of $VERBOSE" do
$VERBOSE = true
eval(@method).should be_true
eval("#{@method} = false")
$VERBOSE.should be_false
end
end
describe "Global variable $-v" do
it_behaves_like :verbose_global_alias, '$-v'
end
describe "Global variable $-w" do
it_behaves_like :verbose_global_alias, '$-w'
end
describe "Global variable $0" do
before :each do
@orig_program_name = $0
end
after :each do
$0 = @orig_program_name
end
it "returns the program name" do
$0 = "rbx"
$0.should == "rbx"
end
platform_is :linux, :darwin do
it "actually sets the program name" do
title = "rubyspec-dollar0-test"
$0 = title
`ps -ocommand= -p#{$$}`.should include(title)
end
end
it "returns the given value when set" do
($0 = "rbx").should == "rbx"
end
it "raises a TypeError when not given an object that can be coerced to a String" do
lambda { $0 = nil }.should raise_error(TypeError)
end
end
describe "The predefined standard objects" do
it "includes ARGF" do
Object.const_defined?(:ARGF).should == true
end
it "includes ARGV" do
Object.const_defined?(:ARGV).should == true
end
it "includes a hash-like object ENV" do
Object.const_defined?(:ENV).should == true
ENV.respond_to?(:[]).should == true
end
end
describe "The predefined standard object nil" do
it "is an instance of NilClass" do
nil.should be_kind_of(NilClass)
end
it "raises a SyntaxError if assigned to" do
lambda { eval("nil = true") }.should raise_error(SyntaxError)
end
end
describe "The predefined standard object true" do
it "is an instance of TrueClass" do
true.should be_kind_of(TrueClass)
end
it "raises a SyntaxError if assigned to" do
lambda { eval("true = false") }.should raise_error(SyntaxError)
end
end
describe "The predefined standard object false" do
it "is an instance of FalseClass" do
false.should be_kind_of(FalseClass)
end
it "raises a SyntaxError if assigned to" do
lambda { eval("false = nil") }.should raise_error(SyntaxError)
end
end
describe "The self pseudo-variable" do
it "raises a SyntaxError if assigned to" do
lambda { eval("self = 1") }.should raise_error(SyntaxError)
end
end
describe "The predefined global constants" do
it "includes TRUE" do
Object.const_defined?(:TRUE).should == true
TRUE.should equal(true)
end
it "includes FALSE" do
Object.const_defined?(:FALSE).should == true
FALSE.should equal(false)
end
it "includes NIL" do
Object.const_defined?(:NIL).should == true
NIL.should equal(nil)
end
it "includes STDIN" do
Object.const_defined?(:STDIN).should == true
end
it "includes STDOUT" do
Object.const_defined?(:STDOUT).should == true
end
it "includes STDERR" do
Object.const_defined?(:STDERR).should == true
end
it "includes RUBY_VERSION" do
Object.const_defined?(:RUBY_VERSION).should == true
end
it "includes RUBY_RELEASE_DATE" do
Object.const_defined?(:RUBY_RELEASE_DATE).should == true
end
it "includes RUBY_PLATFORM" do
Object.const_defined?(:RUBY_PLATFORM).should == true
end
it "includes TOPLEVEL_BINDING" do
Object.const_defined?(:TOPLEVEL_BINDING).should == true
end
end
with_feature :encoding do
describe "The predefined global constant" do
before :each do
@external = Encoding.default_external
@internal = Encoding.default_internal
end
after :each do
Encoding.default_external = @external
Encoding.default_internal = @internal
end
describe "STDIN" do
it "has the same external encoding as Encoding.default_external" do
STDIN.external_encoding.should equal(Encoding.default_external)
end
it "has the same external encoding as Encoding.default_external when that encoding is changed" do
Encoding.default_external = Encoding::ISO_8859_16
STDIN.external_encoding.should equal(Encoding::ISO_8859_16)
end
it "has the encodings set by #set_encoding"do
code = "STDIN.set_encoding Encoding::IBM775, Encoding::IBM866; " \
"p [STDIN.external_encoding.name, STDIN.internal_encoding.name]"
ruby_exe(code).chomp.should == %{["IBM775", "IBM866"]}
end
it "retains the encoding set by #set_encoding when Encoding.default_external is changed" do
code = "STDIN.set_encoding Encoding::IBM775, Encoding::IBM866; " \
"Encoding.default_external = Encoding::ISO_8859_16;" \
"p [STDIN.external_encoding.name, STDIN.internal_encoding.name]"
ruby_exe(code).chomp.should == %{["IBM775", "IBM866"]}
end
it "has nil for the internal encoding" do
STDIN.internal_encoding.should be_nil
end
it "has nil for the internal encoding despite Encoding.default_internal being changed" do
Encoding.default_internal = Encoding::IBM437
STDIN.internal_encoding.should be_nil
end
end
describe "STDOUT" do
it "has nil for the external encoding" do
STDOUT.external_encoding.should be_nil
end
it "has nil for the external encoding despite Encoding.default_external being changed" do
Encoding.default_external = Encoding::ISO_8859_1
STDOUT.external_encoding.should be_nil
end
it "has the encodings set by #set_encoding"do
code = "STDOUT.set_encoding Encoding::IBM775, Encoding::IBM866; " \
"p [STDOUT.external_encoding.name, STDOUT.internal_encoding.name]"
ruby_exe(code).chomp.should == %{["IBM775", "IBM866"]}
end
it "has nil for the internal encoding" do
STDOUT.internal_encoding.should be_nil
end
it "has nil for the internal encoding despite Encoding.default_internal being changed" do
Encoding.default_internal = Encoding::IBM437
STDOUT.internal_encoding.should be_nil
end
end
describe "STDERR" do
it "has nil for the external encoding" do
STDERR.external_encoding.should be_nil
end
it "has nil for the external encoding despite Encoding.default_external being changed" do
Encoding.default_external = Encoding::ISO_8859_1
STDERR.external_encoding.should be_nil
end
it "has the encodings set by #set_encoding"do
code = "STDERR.set_encoding Encoding::IBM775, Encoding::IBM866; " \
"p [STDERR.external_encoding.name, STDERR.internal_encoding.name]"
ruby_exe(code).chomp.should == %{["IBM775", "IBM866"]}
end
it "has nil for the internal encoding" do
STDERR.internal_encoding.should be_nil
end
it "has nil for the internal encoding despite Encoding.default_internal being changed" do
Encoding.default_internal = Encoding::IBM437
STDERR.internal_encoding.should be_nil
end
end
describe "ARGV" do
it "contains Strings encoded in locale Encoding" do
code = fixture __FILE__, "argv_encoding.rb"
result = ruby_exe(code, args: "a b")
encoding = Encoding.default_external
result.chomp.should == %{["#{encoding}", "#{encoding}"]}
end
end
end
end