Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin' into mcjit
Browse files Browse the repository at this point in the history
  • Loading branch information
brixen committed Feb 16, 2016
2 parents d1a452c + cdc89a9 commit a596063
Show file tree
Hide file tree
Showing 18 changed files with 183 additions and 17 deletions.
5 changes: 4 additions & 1 deletion core/basic_object.rb
Expand Up @@ -39,7 +39,10 @@ def __id__
end

def method_missing(meth, *args)
::Kernel.raise ::NoMethodError, "Unable to send '#{meth}' on instance of BasicObject"
error = ::NoMethodError
.new("Unable to send '#{meth}' on instance of BasicObject", receiver: self)

::Kernel.raise(error)
end
private :method_missing

Expand Down
16 changes: 13 additions & 3 deletions core/exception.rb
Expand Up @@ -237,18 +237,28 @@ class LocalJumpError < StandardError
class NameError < StandardError
attr_reader :name

def initialize(*args)
def initialize(*args, receiver: nil)
super(args.shift)

@name = args.shift
@receiver = receiver
end

def receiver
if @receiver
@receiver
else
raise ArgumentError, 'no receiver is available'
end
end
end

class NoMethodError < NameError
attr_reader :name
attr_reader :args

def initialize(*arguments)
super(arguments.shift)
def initialize(*arguments, **options)
super(arguments.shift, **options)
@name = arguments.shift
@args = arguments.shift
end
Expand Down
3 changes: 2 additions & 1 deletion core/object_space.rb
Expand Up @@ -6,11 +6,12 @@ def self.find_object(query, callable)

def self._id2ref(id)
ary = []

if find_object([:object_id, Integer(id)], ary) > 0
return ary.first
end

return nil
raise RangeError, "#{id} is not a valid ID value"
end

def self.find_references(obj)
Expand Down
8 changes: 8 additions & 0 deletions core/string.rb
Expand Up @@ -2680,4 +2680,12 @@ def dump
str += ".force_encoding(\"#{encoding}\")" unless encoding.ascii_compatible?
s.replace(str)
end

def -@
frozen? ? self : dup.freeze
end

def +@
frozen? ? dup : self
end
end
2 changes: 1 addition & 1 deletion core/zed.rb
Expand Up @@ -1367,7 +1367,7 @@ def method_missing(meth, *args)
msg << " on an instance of #{object_class}."
end

Kernel.raise cls.new(msg, meth, args)
Kernel.raise(cls.new(msg, meth, args, receiver: self))
end

private :method_missing
Expand Down
6 changes: 3 additions & 3 deletions gems_list.txt
Expand Up @@ -7,7 +7,7 @@ psych-2.0.17.gem
racc-1.4.14.gem
rake-10.5.0.gem
rb-readline-0.5.3.gem
rdoc-4.2.1.gem
rdoc-4.2.2.gem
redcard-1.1.0.gem
rubinius-ast-3.0.gem
rubinius-bridge-1.1.0.gem
Expand Down Expand Up @@ -71,9 +71,9 @@ rubysl-net-smtp-2.0.1.gem
rubysl-net-telnet-2.0.0.gem
rubysl-nkf-2.0.1.gem
rubysl-observer-2.0.0.gem
rubysl-open-uri-2.0.0.gem
rubysl-open3-2.0.0.gem
rubysl-openssl-2.8.0.gem
rubysl-open-uri-2.0.0.gem
rubysl-optparse-2.0.1.gem
rubysl-ostruct-2.1.0.gem
rubysl-pathname-2.1.0.gem
Expand All @@ -95,7 +95,7 @@ rubysl-set-2.0.1.gem
rubysl-shellwords-2.0.0.gem
rubysl-singleton-2.0.0.gem
rubysl-socket-2.1.1.gem
rubysl-stringio-2.0.0.gem
rubysl-stringio-2.1.0.gem
rubysl-strscan-2.0.0.gem
rubysl-sync-2.0.0.gem
rubysl-syslog-2.1.0.gem
Expand Down
18 changes: 18 additions & 0 deletions spec/ruby/core/exception/name_error_spec.rb
Expand Up @@ -11,3 +11,21 @@
NameError.new("msg","name").name.should == "name"
end
end

describe 'NameError#receiver' do
it 'returns the receiver if available' do
x = 'foo'

begin
x.foo
rescue NameError => error
error.receiver.should == x
end
end

it 'raises ArgumentError when no receiver is available' do
error = NameError.new('msg', 'name')

proc { error.receiver }.should raise_error(ArgumentError)
end
end
4 changes: 4 additions & 0 deletions spec/ruby/core/objectspace/_id2ref_spec.rb
Expand Up @@ -18,4 +18,8 @@
r = ObjectSpace._id2ref(s.object_id)
r.should == s
end

it 'raises RangeError when an object could not be found' do
proc { ObjectSpace._id2ref(1 << 60) }.should raise_error(RangeError)
end
end
19 changes: 19 additions & 0 deletions spec/ruby/core/string/minus_prefix_spec.rb
@@ -0,0 +1,19 @@
require File.expand_path('../../../spec_helper', __FILE__)

describe 'String#-@' do
it 'returns self if the String is frozen' do
input = 'foo'.freeze
output = -input

output.equal?(input).should == true
output.frozen?.should == true
end

it 'returns a frozen copy if the String is not frozen' do
input = 'foo'
output = -input

output.frozen?.should == true
output.should == 'foo'
end
end
18 changes: 18 additions & 0 deletions spec/ruby/core/string/plus_prefix_spec.rb
@@ -0,0 +1,18 @@
require File.expand_path('../../../spec_helper', __FILE__)

describe 'String#+@' do
it 'returns an unfrozen copy of a frozen String' do
input = 'foo'.freeze
output = +input

output.frozen?.should == false
output.should == 'foo'
end

it 'returns self if the String is not frozen' do
input = 'foo'
output = +input

output.equal?(input).should == true
end
end
12 changes: 10 additions & 2 deletions spec/ruby/language/send_spec.rb
Expand Up @@ -193,11 +193,19 @@ def foobar; 200; end
o.message.should == :not_there
o.args.should == [1,2]
end

it "raises NameError if invoked as a vcall" do
lambda { no_such_method }.should raise_error NameError
end


it 'adds the receiver to the raised exception' do
begin
no_such_method
rescue NameError => error
error.receiver.should == self
end
end

it "raises NoMethodError if invoked as an unambiguous method call" do
lambda { no_such_method() }.should raise_error NoMethodError
lambda { no_such_method(1,2,3) }.should raise_error NoMethodError
Expand Down
1 change: 1 addition & 0 deletions spec/ruby/optional/capi/ext/rubyspec.h
Expand Up @@ -639,6 +639,7 @@
#define HAVE_RB_TIME_INTERVAL 1
#define HAVE_RB_TIME_TIMEVAL 1
#define HAVE_RB_TIME_TIMESPEC 1
#define HAVE_RB_TIME_TIMESPEC_NEW 1
#endif

/* Util */
Expand Down
14 changes: 14 additions & 0 deletions spec/ruby/optional/capi/ext/time_spec.c
Expand Up @@ -63,6 +63,16 @@ static VALUE time_spec_rb_time_timespec(VALUE self, VALUE time) {
}
#endif

#ifdef HAVE_RB_TIME_TIMESPEC_NEW
static VALUE time_spec_rb_time_timespec_new(VALUE self, VALUE sec, VALUE nsec, VALUE offset) {
struct timespec ts;
ts.tv_sec = NUM2TIMET(sec);
ts.tv_nsec = NUM2LONG(nsec);

return rb_time_timespec_new(&ts, NUM2INT(offset));
}
#endif

#ifdef HAVE_TIMET2NUM
static VALUE time_spec_TIMET2NUM(VALUE self) {
time_t t = 10;
Expand Down Expand Up @@ -101,6 +111,10 @@ void Init_time_spec() {
#ifdef HAVE_RB_TIME_TIMESPEC
rb_define_method(cls, "rb_time_timespec", time_spec_rb_time_timespec, 1);
#endif

#ifdef HAVE_RB_TIME_TIMESPEC_NEW
rb_define_method(cls, "rb_time_timespec_new", time_spec_rb_time_timespec_new, 3);
#endif
}

#ifdef __cplusplus
Expand Down
30 changes: 30 additions & 0 deletions spec/ruby/optional/capi/time_spec.rb
Expand Up @@ -252,4 +252,34 @@
nsec.should == t.nsec
end
end

describe "rb_time_timespec_new" do
it "returns a time object with the given timespec and UTC offset" do
@s.rb_time_timespec_new(1447087832, 476451125, 32400).should == Time.at(1447087832, 476451.125).localtime(32400)
end

describe "when offset given is within range of -86400 and 86400 (exclusive)" do
it "sets time's is_gmt to false" do
@s.rb_time_timespec_new(1447087832, 476451125, 0).gmt?.should be_false
end

it "sets time's offset to the offset given" do
@s.rb_time_timespec_new(1447087832, 476451125, 86399).gmtoff.should == 86399
end
end

it "returns time object in UTC if offset given equals INT_MAX - 1" do
@s.rb_time_timespec_new(1447087832, 476451125, 0x7ffffffe).utc?.should be_true
end

it "returns time object in localtime if offset given equals INT_MAX" do
@s.rb_time_timespec_new(1447087832, 476451125, 0x7fffffff).should == Time.at(1447087832, 476451.125).localtime
@s.rb_time_timespec_new(1447087832, 476451125, 0x7fffffff).gmtoff.should == Time.now.gmtoff
end

it "raises an ArgumentError if offset passed is not within range of -86400 and 86400 (exclusive)" do
lambda { @s.rb_time_timespec_new(1447087832, 476451125, 86400) }.should raise_error(ArgumentError)
lambda { @s.rb_time_timespec_new(1447087832, 476451125, -86400) }.should raise_error(ArgumentError)
end
end
end
10 changes: 10 additions & 0 deletions spec/ruby/shared/kernel/method_missing.rb
Expand Up @@ -110,5 +110,15 @@
it "raises a NoMethodError when a private method is called" do
lambda { @object.new.method_private }.should raise_error(NoMethodError)
end

it 'sets the receiver of the raised NoMethodError' do
obj = @object.new

begin
obj.method_private
rescue NoMethodError => error
(error.receiver == obj).should == true
end
end
end
end
12 changes: 6 additions & 6 deletions vm/builtin/string.cpp
Expand Up @@ -602,7 +602,7 @@ namespace rubinius {
native_int String::char_size(STATE) {
if(num_chars_->nil_p()) {
OnigEncodingType* enc = encoding(state)->get_encoding();
if(byte_compatible_p(encoding_) || CBOOL(ascii_only_)) {
if(byte_compatible_p(encoding_) || CBOOL(ascii_only_p(state))) {
num_chars(state, num_bytes_);
} else if(fixed_width_p(encoding_)) {
num_chars(state, Fixnum::from((byte_size() + ONIGENC_MBC_MINLEN(enc) - 1) / ONIGENC_MBC_MINLEN(enc)));
Expand Down Expand Up @@ -1337,7 +1337,7 @@ namespace rubinius {
if(i >= byte_size() || i < 0) return cNil;

native_int len = char_size(state);
if(byte_compatible_p(encoding_) || CBOOL(ascii_only_)) {
if(byte_compatible_p(encoding_) || CBOOL(ascii_only_p(state))) {
return byte_substring(state, i, 1);
} else {
// Assumptions above about size are possibly invalid, recalculate.
Expand All @@ -1355,7 +1355,7 @@ namespace rubinius {
native_int String::find_character_byte_index(STATE, native_int index,
native_int start) {
OnigEncodingType* enc = encoding(state)->get_encoding();
if(byte_compatible_p(encoding_) || CBOOL(ascii_only_)) {
if(byte_compatible_p(encoding_) || CBOOL(ascii_only_p(state))) {
return start + index;
} else if(fixed_width_p(encoding_)) {
return start + index * ONIGENC_MBC_MINLEN(enc);
Expand Down Expand Up @@ -1391,7 +1391,7 @@ namespace rubinius {
native_int String::find_byte_character_index(STATE, native_int index,
native_int start) {
OnigEncodingType* enc = encoding(state)->get_encoding();
if(byte_compatible_p(encoding_) || CBOOL(ascii_only_)) {
if(byte_compatible_p(encoding_) || CBOOL(ascii_only_p(state))) {
return index;
} else if(fixed_width_p(encoding_)) {
return index / ONIGENC_MBC_MINLEN(enc);
Expand Down Expand Up @@ -1500,7 +1500,7 @@ namespace rubinius {
n = size - i;
}

if(n == 0 || byte_compatible_p(encoding_) || CBOOL(ascii_only_)) {
if(n == 0 || byte_compatible_p(encoding_) || CBOOL(ascii_only_p(state))) {
return byte_substring(state, i, n);
} else {
return char_substring(state, i, n);
Expand Down Expand Up @@ -1564,7 +1564,7 @@ namespace rubinius {
uint8_t* s;
uint8_t* ss;

if(byte_compatible_p(encoding()) || CBOOL(ascii_only_)) {
if(byte_compatible_p(encoding()) || CBOOL(ascii_only_p(state))) {
for(s = p += offset, ss = pp; p < e; s = ++p) {
if(*p != *pp) continue;

Expand Down
19 changes: 19 additions & 0 deletions vm/capi/time.cpp
Expand Up @@ -106,4 +106,23 @@ extern "C" {
struct timespec ts = capi_time_num_timespec(env, time);
return ts;
}

VALUE rb_time_timespec_new(const struct timespec *ts, int offset) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();

Time* time = Time::at(env->state(), ts->tv_sec, ts->tv_nsec);

if(-86400 < offset && offset < 86400) { /* fixed offset */
time->offset(env->state(), Fixnum::from(offset));
time->is_gmt(env->state(), cFalse);
time->zone(env->state(), cNil);
} else if(offset == INT_MAX) { /* localtime */
} else if(offset == INT_MAX - 1) { /* UTC */
time->is_gmt(env->state(), cTrue);
} else {
rb_raise(rb_eArgError, "utc_offset out of range");
}

return env->get_handle(time);
}
}
3 changes: 3 additions & 0 deletions vm/include/capi/ruby/ruby.h
Expand Up @@ -2148,6 +2148,9 @@ struct RTypedData {
struct timeval rb_time_timeval(VALUE time);
struct timespec rb_time_timespec(VALUE time);

/** Returns a time object with UTC/localtime/fixed offset */
VALUE rb_time_timespec_new(const struct timespec *ts, int offset);

#define HAVE_RB_TIME_NEW 1
#define HAVE_RB_TIME_NANO_NEW 1
#define HAVE_RB_TIME_NUM_NEW 1
Expand Down

0 comments on commit a596063

Please sign in to comment.