Skip to content
Permalink
Browse files

Merge bfab884 into 42c875e

  • Loading branch information
timfel committed Aug 15, 2013
2 parents 42c875e + bfab884 commit 47e6ca0a25beac3d7a05f2f45c5c41f2b23eb702
@@ -27,6 +27,7 @@
load_bootstrap.call("random.rb")
load_bootstrap.call("regexp.rb")
load_bootstrap.call("string.rb")
load_bootstrap.call("struct.rb")
load_bootstrap.call("symbol.rb")
load_bootstrap.call("thread.rb")
load_bootstrap.call("time.rb")
@@ -0,0 +1,227 @@
class Struct
include Enumerable

class << self
alias subclass_new new
end

def self.new(klass_name, *attrs, &block)
if klass_name
begin
klass_name = Topaz.convert_type(klass_name, String, :to_str)
rescue TypeError
attrs.unshift(klass_name)
klass_name = nil
end
end

attrs = attrs.map do |attr|
case attr
when String, Symbol
Topaz.convert_type(attr, Symbol, :to_sym)
else
raise TypeError.new("#{attr.inspect} is not a symbol")
end
end

klass = Class.new(self) do
attr_accessor(*attrs)

def self.new(*args, &block)
return subclass_new(*args, &block)
end

def self.[](*args)
return new(*args)
end

const_set(:STRUCT_ATTRS, attrs)
end

Struct.const_set(klass_name, klass) if klass_name
klass.module_eval(&block) if block
klass
end

def self.make_struct(name, attrs)
new(name, *attrs)
end

def instance_variables
# Hide the ivars used to store the struct fields
attr_syms = self.class::STRUCT_ATTRS.map { |a| "@#{a}".to_sym }
self.singleton_class.instance_variables - attr_syms
end

def initialize(*args)
attrs = self.class::STRUCT_ATTRS

unless args.length <= attrs.length
raise ArgumentError.new("Expected #{attrs.size}, got #{args.size}")
end

attrs.each_with_index do |attr, i|
instance_variable_set(:"@#{attr}", args[i])
end
end

private :initialize

def ==(other)
return false if self.class != other.class

Thread.current.recursion_guard(:==, self) do
return self.values == other.values
end
true
end

def eql?(other)
return true if equal?(other)
return false if self.class != other.class

Thread.current.recursion_guard(:eql?, self) do
self.class::STRUCT_ATTRS.each do |var|
mine = instance_variable_get(:"@#{var}")
theirs = other.instance_variable_get(:"@#{var}")
return false unless mine.eql?(theirs)
end
end
true
end

def [](var)
case var
when Symbol, String
unless self.class::STRUCT_ATTRS.include?(var.to_sym)
raise NameError.new("no member '#{var}' in struct")
end
else
var = Topaz.convert_type(var, Fixnum, :to_int)
a_len = self.class::STRUCT_ATTRS.length
if var > a_len - 1
raise IndexError.new("offset #{var} too large for struct(size:#{a_len})")
end
if var < -a_len
raise IndexError.new("offset #{var + a_len} too small for struct(size:#{a_len})")
end
var = self.class::STRUCT_ATTRS[var]
end

instance_variable_get(:"@#{var}")
end

def []=(var, obj)
case var
when Symbol, String
unless self.class::STRUCT_ATTRS.include?(var.to_sym)
raise NameError, "no member '#{var}' in struct"
end
else
var = Topaz.convert_type(var, Fixnum, :to_int)
a_len = self.class::STRUCT_ATTRS.length
if var > a_len - 1
raise IndexError, "offset #{var} too large for struct(size:#{a_len})"
end
if var < -a_len
raise IndexError, "offset #{var + a_len} too small for struct(size:#{a_len})"
end
var = self.class::STRUCT_ATTRS[var]
end

instance_variable_set(:"@#{var}", obj)
end

def each(&block)
return to_enum(:each) unless block
values.each(&block)
self
end

def each_pair(&block)
return to_enum(:each_pair) unless block
self.class::STRUCT_ATTRS.each do |var|
yield var, instance_variable_get(:"@#{var}")
end
self
end

def hash
hash_val = size

recursion = Thread.current.recursion_guard(:hash, self) do
self.class::STRUCT_ATTRS.each do |var|
hash_val ^= instance_variable_get(:"@#{var}").hash
end
end

hash_val
end

def length
self.class::STRUCT_ATTRS.length
end
alias size length

def self.length
self::STRUCT_ATTRS.size
end

class << self
alias size length
end

def self.members
self::STRUCT_ATTRS.dup
end

def members
self.class.members
end

def select(&block)
to_a.select(&block)
end

def to_a
self.class::STRUCT_ATTRS.map { |var| instance_variable_get :"@#{var}" }
end
alias values to_a

def values_at(*args)
to_a.values_at(*args)
end

def to_s
recursion = Thread.current.recursion_guard(:to_s, self) do
values = []

self.class::STRUCT_ATTRS.each do |var|
val = instance_variable_get :"@#{var}"
values << "#{var}=#{val.inspect}"
end

name = self.class.name

if name.nil? || name.empty?
return "#<struct #{values.join(', ')}>"
else
return "#<struct #{self.class.name} #{values.join(', ')}>"
end
end
return "[...]" if recursion
end
alias inspect to_s

Struct.new('Tms', :utime, :stime, :cutime, :cstime, :tutime, :tstime) do
def initialize(utime=nil, stime=nil, cutime=nil, cstime=nil,
tutime=nil, tstime=nil)
@utime = utime
@stime = stime
@cutime = cutime
@cstime = cstime
@tutime = tutime
@tstime = tstime
end
end
end

This file was deleted.

@@ -0,0 +1 @@
fails:Struct#eql? handles recursive structures by returning false if a difference can be found
@@ -0,0 +1 @@
fails:Struct#== handles recursive structures by returning false if a difference can be found
@@ -0,0 +1 @@
fails:Struct#hash returns the same hash for recursive structs
@@ -0,0 +1 @@
fails:Struct#initialize is private
@@ -0,0 +1,2 @@
fails:Struct#inspect returns a string representation of some kind
fails:Struct#inspect returns a string representation without the class name for anonymous structs
@@ -0,0 +1 @@
fails:Struct#instance_variables returns an array with one name if an instance variable is added
@@ -0,0 +1,4 @@
fails:Struct.new creates a constant in Struct namespace with string as first argument
fails:Struct.new calls to_str on its first argument (constant name)
fails:Struct.new creates reader methods
fails:Struct.new creates writer methods
@@ -0,0 +1 @@
fails:Struct#to_s returns a string representation without the class name for anonymous structs
@@ -8,7 +8,6 @@ class MSpecScript
core = [
"#{Rubyspec}/core/",
# Struct: ``Struct.new(:field)``
"^#{Rubyspec}/core/struct",
"^#{Rubyspec}/core/string/chomp_spec.rb",
# timeout: ``require 'timeout'``
"^#{Rubyspec}/core/process/detach_spec.rb",
@@ -80,6 +80,18 @@ def method_fork(self, space, block):
else:
return space.newint(pid)

@moduledef.function("times")
def method_times(self, space):
tms = space.find_const(
space.find_const(space.w_object, "Struct"),
"Tms"
)
return space.send(
tms,
"new",
[space.newfloat(t) for t in list(os.times()[0:4])]
)

@moduledef.function("kill")
def method_kill(self, space, w_signal, args_w):
if not args_w:
@@ -19,6 +19,11 @@ def __init__(self, varname):
W_FunctionObject.__init__(self, varname)
self.varname = varname

def __deepcopy__(self, memo):
obj = super(W_FunctionObject, self).__deepcopy__(memo)
obj.varname = self.varname
return obj

def call(self, space, w_obj, args_w, block):
return space.find_instance_var(w_obj, self.varname)

@@ -30,6 +35,11 @@ def __init__(self, varname):
W_FunctionObject.__init__(self, varname)
self.varname = varname

def __deepcopy__(self, memo):
obj = super(W_FunctionObject, self).__deepcopy__(memo)
obj.varname = self.varname
return obj

def call(self, space, w_obj, args_w, block):
[w_value] = args_w
space.set_instance_var(w_obj, self.varname, w_value)

0 comments on commit 47e6ca0

Please sign in to comment.