Exemple #1
0
 def __init__(self, space, name):
     self.name = name
     self.klass = None
     self.version = VersionTag()
     self.methods_w = {}
     self.constants_w = {}
     self.class_variables = CellDict()
     self.instance_variables = CellDict()
     self.included_modules = []
     self.descendants = []
Exemple #2
0
 def test_multi_set(self, space):
     c = CellDict()
     c.set(space, "a", 2)
     v = c.version
     c.set(space, "a", 3)
     assert isinstance(c._get_cell("a", c.version), Cell)
     assert c.version is not v
     v = c.version
     c.set(space, "a", 4)
     assert isinstance(c._get_cell("a", c.version), Cell)
     assert c.version is v
Exemple #3
0
 def __init__(self, space, name, klass=None):
     self.name = name
     self.klass = klass
     self.version = VersionTag()
     self.methods_w = {}
     self.constants_w = {}
     self.class_variables = CellDict()
     self.instance_variables = CellDict()
     self.flags = CellDict()
     self.included_modules = []
     self.descendants = []
Exemple #4
0
class W_ModuleObject(W_RootObject):
    _immutable_fields_ = ["version?", "included_modules?[*]", "klass?", "name?"]

    classdef = ClassDef("Module", W_RootObject.classdef)

    def __init__(self, space, name, klass=None):
        self.name = name
        self.klass = klass
        self.version = VersionTag()
        self.methods_w = {}
        self.constants_w = {}
        self.class_variables = CellDict()
        self.instance_variables = CellDict()
        self.flags = CellDict()
        self.included_modules = []
        self.descendants = []

    def __deepcopy__(self, memo):
        obj = super(W_ModuleObject, self).__deepcopy__(memo)
        obj.name = self.name
        obj.klass = copy.deepcopy(self.klass, memo)
        obj.version = copy.deepcopy(self.version, memo)
        obj.methods_w = copy.deepcopy(self.methods_w, memo)
        obj.constants_w = copy.deepcopy(self.constants_w, memo)
        obj.class_variables = copy.deepcopy(self.class_variables, memo)
        obj.instance_variables = copy.deepcopy(self.instance_variables, memo)
        obj.included_modules = copy.deepcopy(self.included_modules, memo)
        obj.descendants = copy.deepcopy(self.descendants, memo)
        return obj

    def getclass(self, space):
        if self.klass is not None:
            return jit.promote(self).klass
        return W_RootObject.getclass(self, space)

    def getsingletonclass(self, space):
        if self.klass is None or not self.klass.is_singleton:
            self.klass = space.newclass(
                "#<Class:%s>" % self.name, self.klass or space.w_module, is_singleton=True, attached=self
            )
        return self.klass

    def mutated(self):
        self.version = VersionTag()

    def define_method(self, space, name, method):
        self.mutated()
        self.methods_w[name] = method
        if not space.bootstrap:
            if isinstance(method, UndefMethod):
                self.method_undefined(space, space.newsymbol(name))
            else:
                self.method_added(space, space.newsymbol(name))

    @jit.unroll_safe
    def find_method(self, space, name):
        method = self._find_method_pure(space, name, self.version)
        if method is None:
            for module in self.included_modules:
                method = module.find_method(space, name)
                if method is not None:
                    return method
        return method

    @jit.unroll_safe
    def find_method_super(self, space, name):
        for module in self.included_modules:
            method = module.find_method(space, name)
            if method is not None:
                return method
        return None

    @jit.elidable
    def _find_method_pure(self, space, method, version):
        return self.methods_w.get(method, None)

    def set_const(self, space, name, w_obj):
        self.mutated()
        self.constants_w[name] = w_obj
        if isinstance(w_obj, W_ModuleObject) and w_obj.name is None and self.name is not None:
            w_obj.set_name_in_scope(space, name, self)

    def find_const(self, space, name):
        w_res = self.find_included_const(space, name)
        if w_res is None:
            return space.w_object.find_const(space, name)
        else:
            return w_res

    @jit.unroll_safe
    def find_included_const(self, space, name):
        w_res = self.find_local_const(space, name)
        if w_res is None:
            for w_mod in self.included_modules:
                w_res = w_mod.find_local_const(space, name)
                if w_res is not None:
                    break
        return w_res

    def included_constants(self, space):
        consts = {}
        for const in self.constants_w:
            consts[const] = None
        for w_mod in self.included_modules:
            for const in w_mod.included_constants(space):
                consts[const] = None
        return consts.keys()

    def lexical_constants(self, space):
        consts = {}
        frame = space.getexecutioncontext().gettoprubyframe()
        scope = frame.lexical_scope

        while scope is not None:
            assert isinstance(scope, W_ModuleObject)
            for const in scope.w_mod.constants_w:
                consts[const] = None
            scope = scope.backscope

        return consts.keys()

    def local_constants(self, space):
        return self.constants_w.keys()

    def inherited_constants(self, space):
        return self.local_constants(space)

    def find_local_const(self, space, name):
        return self._find_const_pure(name, self.version)

    @jit.elidable
    def _find_const_pure(self, name, version):
        return self.constants_w.get(name, None)

    @jit.unroll_safe
    def set_class_var(self, space, name, w_obj):
        for module in reversed(self.ancestors()):
            assert isinstance(module, W_ModuleObject)
            w_res = module.class_variables.get(space, name)
            if w_res is not None or module is self:
                module.class_variables.set(space, name, w_obj)
                if module is self:
                    for descendant in self.descendants:
                        descendant.remove_class_var(space, name)

    @jit.unroll_safe
    def find_class_var(self, space, name):
        w_res = self.class_variables.get(space, name)
        if w_res is None:
            ancestors = self.ancestors()
            for idx in xrange(1, len(ancestors)):
                module = ancestors[idx]
                assert isinstance(module, W_ModuleObject)
                w_res = module.class_variables.get(space, name)
                if w_res is not None:
                    break
        return w_res

    @jit.unroll_safe
    def remove_class_var(self, space, name):
        self.class_variables.delete(name)
        for descendant in self.descendants:
            descendant.remove_class_var(space, name)

    def set_instance_var(self, space, name, w_value):
        return self.instance_variables.set(space, name, w_value)

    def find_instance_var(self, space, name):
        return self.instance_variables.get(space, name) or space.w_nil

    def copy_instance_vars(self, space, w_other):
        assert isinstance(w_other, W_ModuleObject)
        for key in w_other.instance_variables:
            w_value = w_other.instance_variables.get(space, key)
            self.set_instance_var(space, key, w_value)

    def set_flag(self, space, name):
        self.flags.set(space, name, space.w_true)

    def unset_flag(self, space, name):
        self.flags.set(space, name, space.w_false)

    def get_flag(self, space, name):
        return self.flags.get(space, name) or space.w_false

    def ancestors(self, include_singleton=True, include_self=True):
        if include_self:
            return [self] + self.included_modules
        else:
            return self.included_modules[:]

    @jit.unroll_safe
    def is_ancestor_of(self, w_cls):
        if self is w_cls:
            return True
        for w_mod in w_cls.included_modules:
            if self is w_mod:
                return True
        if w_cls.superclass is not None:
            return self.is_ancestor_of(w_cls.superclass)
        return False

    def include_module(self, space, w_mod):
        assert isinstance(w_mod, W_ModuleObject)
        if w_mod not in self.ancestors():
            self.included_modules = [w_mod] + self.included_modules
            w_mod.included(space, self)

    def included(self, space, w_mod):
        self.descendants.append(w_mod)
        if space.respond_to(self, "included"):
            space.send(self, "included", [w_mod])

    def extend_object(self, space, w_mod):
        if self not in w_mod.ancestors():
            self.descendants.append(w_mod)
            w_mod.included_modules = [self] + w_mod.included_modules

    def set_visibility(self, space, names_w, visibility):
        names = [space.symbol_w(w_name) for w_name in names_w]
        if names:
            for name in names:
                self.set_method_visibility(space, name, visibility)
        else:
            self.set_default_visibility(space, visibility)

    def set_default_visibility(self, space, visibility):
        pass

    def set_method_visibility(self, space, name, visibility):
        pass

    def method_added(self, space, w_name):
        space.send(self, "method_added", [w_name])

    def method_undefined(self, space, w_name):
        space.send(self, "method_undefined", [w_name])

    def method_removed(self, space, w_name):
        space.send(self, "method_removed", [w_name])

    def set_name_in_scope(self, space, name, w_scope):
        self.name = space.buildname(name, w_scope)
        for name, w_const in self.constants_w.iteritems():
            if isinstance(w_const, W_ModuleObject):
                w_const.set_name_in_scope(space, name, self)

    @classdef.singleton_method("nesting")
    def singleton_method_nesting(self, space):
        frame = space.getexecutioncontext().gettoprubyframe()
        modules_w = []
        scope = frame.lexical_scope
        while scope is not None:
            modules_w.append(scope.w_mod)
            scope = scope.backscope
        return space.newarray(modules_w)

    @classdef.singleton_method("allocate")
    def method_allocate(self, space):
        return W_ModuleObject(space, None, self)

    @classdef.method("initialize")
    def method_initialize(self, space, block):
        if block is not None:
            space.send(self, "module_exec", [self], block)

    @classdef.method("to_s")
    def method_to_s(self, space):
        name = self.name
        if name is None:
            return space.newstr_fromstr(space.any_to_s(self))
        return space.newstr_fromstr(name)

    @classdef.method("include")
    def method_include(self, space, args_w):
        for w_mod in args_w:
            if type(w_mod) is not W_ModuleObject:
                raise space.error(
                    space.w_TypeError,
                    "wrong argument type %s (expected Module)" % space.obj_to_s(space.getclass(w_mod))
                )

        for w_mod in reversed(args_w):
            space.send(w_mod, "append_features", [self])

        return self

    @classdef.method("include?")
    def method_includep(self, space, w_mod):
        if type(w_mod) is not W_ModuleObject:
            raise space.error(
                space.w_TypeError,
                "wrong argument type %s (expected Module)" % space.obj_to_s(space.getclass(w_mod))
            )
        if w_mod is self:
            return space.w_false
        return space.newbool(w_mod in self.ancestors())

    @classdef.method("append_features")
    def method_append_features(self, space, w_mod):
        if w_mod in self.ancestors():
            raise space.error(space.w_ArgumentError, "cyclic include detected")
        for module in reversed(self.ancestors()):
            w_mod.include_module(space, module)

    @classdef.method("define_method", name="symbol")
    def method_define_method(self, space, name, w_method=None, block=None):
        if w_method is not None:
            if space.is_kind_of(w_method, space.w_method):
                w_method = space.send(w_method, "unbind")

            if space.is_kind_of(w_method, space.w_unbound_method):
                self.define_method(space, name, DefineMethodMethod(name, w_method))
            elif space.is_kind_of(w_method, space.w_proc):
                assert isinstance(w_method, W_ProcObject)
                self.define_method(space, name, DefineMethodBlock(name, w_method))
        elif block is not None:
            self.define_method(space, name, DefineMethodBlock(name, block))
        else:
            raise space.error(space.w_ArgumentError, "tried to create Proc object without a block")

    @classdef.method("attr_accessor")
    def method_attr_accessor(self, space, args_w):
        self.method_attr_reader(space, args_w)
        self.method_attr_writer(space, args_w)

    @classdef.method("attr_reader")
    def method_attr_reader(self, space, args_w):
        for w_arg in args_w:
            varname = Coerce.symbol(space, w_arg)
            self.define_method(space, varname, AttributeReader("@" + varname))

    @classdef.method("attr_writer")
    def method_attr_writer(self, space, args_w):
        for w_arg in args_w:
            varname = Coerce.symbol(space, w_arg)
            self.define_method(space, varname + "=", AttributeWriter("@" + varname))

    @classdef.method("attr")
    def method_attr(self, space, args_w):
        if len(args_w) == 2 and (args_w[1] is space.w_true or args_w[1] is space.w_false):
            [w_name, w_writable] = args_w
            if space.is_true(w_writable):
                self.method_attr_accessor(space, [w_name])
            else:
                self.method_attr_reader(space, [w_name])
        else:
            self.method_attr_reader(space, args_w)

    @classdef.method("module_function")
    def method_module_function(self, space, args_w):
        for w_arg in args_w:
            name = Coerce.symbol(space, w_arg)
            self.attach_method(space, name, self._find_method_pure(space, name, self.version))

    @classdef.method("private_class_method")
    def method_private_class_method(self, space, w_name):
        w_cls = self.getsingletonclass(space)
        return space.send(w_cls, "private", [w_name])

    @classdef.method("public_class_method")
    def method_public_class_method(self, space, w_name):
        w_cls = self.getsingletonclass(space)
        return space.send(w_cls, "public", [w_name])

    @classdef.method("alias_method", new_name="symbol", old_name="symbol")
    def method_alias_method(self, space, new_name, old_name):
        self.define_method(space, new_name, self.find_method(space, old_name))

    @classdef.method("ancestors")
    def method_ancestors(self, space):
        return space.newarray(self.ancestors(include_singleton=False))

    @classdef.method("included")
    def method_included(self, space, w_mod):
        # TODO: should be private
        pass

    @classdef.method("extended")
    def method_extended(self, space, w_mod):
        # TODO: should be private
        pass

    @classdef.method("extend_object")
    def method_extend_object(self, space, w_obj):
        self.extend_object(space, space.getsingletonclass(w_obj))

    @classdef.method("name")
    def method_name(self, space):
        if self.name is None:
            return space.w_nil
        return space.newstr_fromstr(self.name)

    @classdef.method("private")
    def method_private(self, space, args_w):
        self.set_visibility(space, args_w, "private")

    @classdef.method("public")
    def method_public(self, space, args_w):
        self.set_visibility(space, args_w, "public")

    @classdef.method("protected")
    def method_protected(self, space, args_w):
        self.set_visibility(space, args_w, "protected")

    @classdef.method("private_constant")
    def method_private_constant(self, space, args_w):
        pass

    @classdef.method("constants")
    def method_constants(self, space, w_inherit=None):
        if self is space.w_module and w_inherit is None:
            consts = {}
            for const in self.lexical_constants(space):
                consts[const] = None
            for const in self.inherited_constants(space):
                consts[const] = None
            return space.newarray([space.newsymbol(n) for n in consts])

        if w_inherit is None or space.is_true(w_inherit):
            return space.newarray([space.newsymbol(n) for n in self.included_constants(space)])
        else:
            return space.newarray([space.newsymbol(n) for n in self.constants_w])

    @classdef.method("const_missing", name="symbol")
    def method_const_missing(self, space, name):
        raise space.error(space.w_NameError, "uninitialized constant %s" % name)

    @classdef.method("class_eval", string="str", filename="str")
    @classdef.method("module_eval", string="str", filename="str")
    def method_module_eval(self, space, string=None, filename=None, w_lineno=None, block=None):
        if string is not None and block is not None:
            raise space.error(space.w_ArgumentError, "wrong number of arguments")
        if string is not None:
            if filename is None:
                filename = "module_eval"
            if w_lineno is not None:
                lineno = space.int_w(w_lineno)
            else:
                lineno = 1
            return space.execute(string, self, lexical_scope=StaticScope(self, None), filepath=filename, initial_lineno=lineno)
        elif block is None:
            raise space.error(space.w_ArgumentError, "block not supplied")
        else:
            return space.invoke_block(block.copy(space, w_self=self, lexical_scope=StaticScope(self, block.lexical_scope)), [])

    @classdef.method("const_defined?", const="str", inherit="bool")
    def method_const_definedp(self, space, const, inherit=True):
        space._check_const_name(const)
        if inherit:
            return space.newbool(self.find_const(space, const) is not None)
        else:
            return space.newbool(self.find_local_const(space, const) is not None)

    @classdef.method("const_get", const="symbol", inherit="bool")
    def method_const_get(self, space, const, inherit=True):
        space._check_const_name(const)
        if inherit:
            w_res = self.find_const(space, const)
        else:
            w_res = self.find_local_const(space, const)
        if w_res is None:
            name = space.obj_to_s(self)
            raise space.error(space.w_NameError,
                "uninitialized constant %s::%s" % (name, const)
            )
        return w_res

    @classdef.method("const_set", const="symbol")
    def method_const_set(self, space, const, w_value):
        space.set_const(self, const, w_value)
        return w_value

    @classdef.method("remove_const", name="str")
    def method_remove_const(self, space, name):
        space._check_const_name(name)
        w_res = self.find_local_const(space, name)
        if w_res is None:
            self_name = space.obj_to_s(self)
            raise space.error(space.w_NameError,
                "uninitialized constant %s::%s" % (self_name, name)
            )
        del self.constants_w[name]
        self.mutated()
        return w_res

    @classdef.method("class_variable_defined?", name="symbol")
    def method_class_variable_definedp(self, space, name):
        return space.newbool(self.find_class_var(space, name) is not None)

    @classdef.method("class_variable_get", name="symbol")
    def method_class_variable_get(self, space, name):
        return space.find_class_var(self, name)

    @classdef.method("class_variable_set", name="symbol")
    @check_frozen()
    def method_class_variable_set(self, space, name, w_value):
        self.set_class_var(space, name, w_value)
        return w_value

    @classdef.method("remove_class_variable", name="symbol")
    def method_remove_class_variable(self, space, name):
        w_value = self.class_variables.get(space, name)
        if w_value is not None:
            self.class_variables.delete(name)
            return w_value
        if self.find_class_var(space, name) is not None:
            raise space.error(space.w_NameError,
                "cannot remove %s for %s" % (name, space.obj_to_s(self))
            )
        raise space.error(space.w_NameError,
            "class variable %s not defined for %s" % (name, space.obj_to_s(self))
        )

    @classdef.method("method_defined?", name="str")
    def method_method_definedp(self, space, name):
        return space.newbool(self.find_method(space, name) is not None)

    @classdef.method("===")
    def method_eqeqeq(self, space, w_obj):
        return space.newbool(self.is_ancestor_of(space.getclass(w_obj)))

    @classdef.method("<=")
    def method_lte(self, space, w_other):
        if not isinstance(w_other, W_ModuleObject):
            raise space.error(space.w_TypeError, "compared with non class/module")
        for w_mod in self.ancestors():
            if w_other is w_mod:
                return space.w_true
        for w_mod in w_other.ancestors():
            if self is w_mod:
                return space.w_false
        return space.w_nil

    @classdef.method("<")
    def method_lt(self, space, w_other):
        if self is w_other:
            return space.w_false
        return space.send(self, "<=", [w_other])

    @classdef.method(">=")
    def method_gte(self, space, w_other):
        if not isinstance(w_other, W_ModuleObject):
            raise space.error(space.w_TypeError, "compared with non class/module")
        return space.send(w_other, "<=", [self])

    @classdef.method(">")
    def method_gt(self, space, w_other):
        if not isinstance(w_other, W_ModuleObject):
            raise space.error(space.w_TypeError, "compared with non class/module")
        if self is w_other:
            return space.w_false
        return space.send(w_other, "<=", [self])

    @classdef.method("<=>")
    def method_comparison(self, space, w_other):
        if not isinstance(w_other, W_ModuleObject):
            return space.w_nil

        if self is w_other:
            return space.newint(0)

        other_is_subclass = space.send(self, "<", [w_other])

        if space.is_true(other_is_subclass):
            return space.newint(-1)
        elif other_is_subclass is space.w_nil:
            return space.w_nil
        else:
            return space.newint(1)


    @classdef.method("instance_method", name="symbol")
    def method_instance_method(self, space, name):
        return space.newmethod(name, self)

    @classdef.method("undef_method", name="symbol")
    def method_undef_method(self, space, name):
        w_method = self.find_method(space, name)
        if w_method is None or isinstance(w_method, UndefMethod):
            cls_name = space.obj_to_s(self)
            raise space.error(space.w_NameError,
                "undefined method `%s' for class `%s'" % (name, cls_name)
            )
        self.define_method(space, name, UndefMethod(name))
        return self

    @classdef.method("remove_method", name="symbol")
    @check_frozen()
    def method_remove_method(self, space, name):
        w_method = self._find_method_pure(space, name, self.version)
        if w_method is None or isinstance(w_method, UndefMethod):
            cls_name = space.obj_to_s(self)
            raise space.error(space.w_NameError,
                "method `%s' not defined in %s" % (name, cls_name)
            )
        del self.methods_w[name]
        self.mutated()
        self.method_removed(space, space.newsymbol(name))
        return self

    @classdef.method("method_added")
    def method_method_added(self, space, w_name):
        return space.w_nil

    @classdef.method("method_undefined")
    def method_method_undefined(self, space, w_name):
        return space.w_nil

    @classdef.method("method_removed")
    def method_method_removed(self, space, w_name):
        return space.w_nil

    @classdef.method("class_exec")
    @classdef.method("module_exec")
    def method_module_exec(self, space, args_w, block):
        if block is None:
            raise space.error(space.w_LocalJumpError, "no block given")
        return space.invoke_block(
            block.copy(
                space,
                w_self=self,
                lexical_scope=StaticScope(self, None)
            ),
            args_w
        )
Exemple #5
0
class W_ModuleObject(W_RootObject):
    _immutable_fields_ = ["version?", "included_modules?[*]", "klass?", "name?"]

    classdef = ClassDef("Module", W_RootObject.classdef, filepath=__file__)

    def __init__(self, space, name):
        self.name = name
        self.klass = None
        self.version = VersionTag()
        self.methods_w = {}
        self.constants_w = {}
        self.class_variables = CellDict()
        self.instance_variables = CellDict()
        self.included_modules = []
        self.descendants = []

    def __deepcopy__(self, memo):
        obj = super(W_ModuleObject, self).__deepcopy__(memo)
        obj.name = self.name
        obj.klass = copy.deepcopy(self.klass, memo)
        obj.version = copy.deepcopy(self.version, memo)
        obj.methods_w = copy.deepcopy(self.methods_w, memo)
        obj.constants_w = copy.deepcopy(self.constants_w, memo)
        obj.class_variables = copy.deepcopy(self.class_variables, memo)
        obj.instance_variables = copy.deepcopy(self.instance_variables, memo)
        obj.included_modules = copy.deepcopy(self.included_modules, memo)
        obj.descendants = copy.deepcopy(self.descendants, memo)
        return obj

    def getclass(self, space):
        if self.klass is not None:
            return self.klass
        return W_RootObject.getclass(self, space)

    def getsingletonclass(self, space):
        if self.klass is None:
            self.klass = space.newclass(
                "#<Class:%s>" % self.name, space.w_module, is_singleton=True
            )
        return self.klass

    def mutated(self):
        self.version = VersionTag()

    def define_method(self, space, name, method):
        self.mutated()
        self.methods_w[name] = method

    @jit.unroll_safe
    def find_method(self, space, name):
        method = self._find_method_pure(space, name, self.version)
        if method is None:
            for module in self.included_modules:
                method = module.find_method(space, name)
                if method is not None:
                    return method
        return method

    @jit.unroll_safe
    def find_method_super(self, space, name):
        for module in self.included_modules:
            method = module.find_method(space, name)
            if method is not None:
                return method
        return None

    @jit.elidable
    def _find_method_pure(self, space, method, version):
        return self.methods_w.get(method, None)

    def set_const(self, space, name, w_obj):
        self.mutated()
        self.constants_w[name] = w_obj

    def find_const(self, space, name):
        w_res = self.find_included_const(space, name)
        if w_res is None:
            return space.w_object.find_const(space, name)
        else:
            return w_res

    @jit.unroll_safe
    def find_included_const(self, space, name):
        w_res = self.find_local_const(space, name)
        if w_res is None:
            for w_mod in self.included_modules:
                w_res = w_mod.find_local_const(space, name)
                if w_res is not None:
                    break
        return w_res

    def find_local_const(self, space, name):
        return self._find_const_pure(name, self.version)

    @jit.elidable
    def _find_const_pure(self, name, version):
        return self.constants_w.get(name, None)

    @jit.unroll_safe
    def set_class_var(self, space, name, w_obj):
        ancestors = self.ancestors()
        for idx in xrange(len(ancestors) - 1, -1, -1):
            module = ancestors[idx]
            assert isinstance(module, W_ModuleObject)
            w_res = module.class_variables.get(space, name)
            if w_res is not None or module is self:
                module.class_variables.set(space, name, w_obj)
                if module is self:
                    for descendant in self.descendants:
                        descendant.remove_class_var(space, name)

    @jit.unroll_safe
    def find_class_var(self, space, name):
        w_res = self.class_variables.get(space, name)
        if w_res is None:
            ancestors = self.ancestors()
            for idx in xrange(1, len(ancestors)):
                module = ancestors[idx]
                assert isinstance(module, W_ModuleObject)
                w_res = module.class_variables.get(space, name)
                if w_res is not None:
                    break
        return w_res

    @jit.unroll_safe
    def remove_class_var(self, space, name):
        self.class_variables.delete(name)
        for descendant in self.descendants:
            descendant.remove_class_var(space, name)

    def set_instance_var(self, space, name, w_value):
        return self.instance_variables.set(space, name, w_value)

    def find_instance_var(self, space, name):
        return self.instance_variables.get(space, name) or space.w_nil

    def ancestors(self, include_singleton=True, include_self=True):
        if include_self:
            return [self] + self.included_modules
        else:
            return self.included_modules[:]

    @jit.unroll_safe
    def is_ancestor_of(self, w_cls):
        if self is w_cls:
            return True
        for w_mod in w_cls.included_modules:
            if self is w_mod:
                return True
        if w_cls.superclass is not None:
            return self.is_ancestor_of(w_cls.superclass)
        return False

    def include_module(self, space, w_mod):
        assert isinstance(w_mod, W_ModuleObject)
        if w_mod not in self.ancestors():
            self.included_modules = [w_mod] + self.included_modules
            w_mod.included(space, self)

    def included(self, space, w_mod):
        self.descendants.append(w_mod)
        if space.respond_to(self, space.newsymbol("included")):
            space.send(self, space.newsymbol("included"), [w_mod])

    def extend_object(self, space, w_obj, w_mod):
        if w_mod not in self.ancestors():
            self.included_modules = [w_mod] + self.included_modules
            w_mod.extended(space, w_obj, self)

    def extended(self, space, w_obj, w_mod):
        self.descendants.append(w_mod)
        if space.respond_to(self, space.newsymbol("extended")):
            space.send(self, space.newsymbol("extended"), [w_obj])

    def set_visibility(self, space, names_w, visibility):
        names = [space.symbol_w(w_name) for w_name in names_w]
        if names:
            for name in names:
                self.set_method_visibility(space, name, visibility)
        else:
            self.set_default_visibility(space, visibility)

    def set_default_visibility(self, space, visibility):
        pass

    def set_method_visibility(self, space, name, visibility):
        pass

    @classdef.singleton_method("allocate")
    def method_allocate(self, space):
        # TODO: this should really store None for the name and all places
        # reading the name should handle None
        return W_ModuleObject(space, "")

    @classdef.method("to_s")
    def method_to_s(self, space):
        return space.newstr_fromstr(self.name)

    @classdef.method("include")
    def method_include(self, space, w_mod):
        space.send(w_mod, space.newsymbol("append_features"), [self])

    @classdef.method("append_features")
    def method_append_features(self, space, w_mod):
        ancestors = self.ancestors()
        for idx in xrange(len(ancestors) - 1, -1, -1):
            w_mod.include_module(space, ancestors[idx])

    @classdef.method("define_method", name="symbol")
    def method_define_method(self, space, name, w_method=None, block=None):
        if w_method is not None:
            if space.is_kind_of(w_method, space.w_method):
                w_method = space.send(w_method, space.newsymbol("unbind"))

            if space.is_kind_of(w_method, space.w_unbound_method):
                self.define_method(space, name, DefineMethodMethod(name, w_method))
            elif space.is_kind_of(w_method, space.w_proc):
                self.define_method(space, name, DefineMethodBlock(name, w_method.get_block()))
        elif block is not None:
            self.define_method(space, name, DefineMethodBlock(name, block))
        else:
            raise space.error(space.w_ArgumentError, "tried to create Proc object without a block")

    @classdef.method("attr_accessor")
    def method_attr_accessor(self, space, args_w):
        self.method_attr_reader(space, args_w)
        self.method_attr_writer(space, args_w)

    @classdef.method("attr_reader")
    def method_attr_reader(self, space, args_w):
        for w_arg in args_w:
            varname = space.symbol_w(w_arg)
            self.define_method(space, varname, AttributeReader("@" + varname))

    @classdef.method("attr_writer")
    def method_attr_writer(self, space, args_w):
        for w_arg in args_w:
            varname = space.symbol_w(w_arg)
            self.define_method(space, varname + "=", AttributeWriter("@" + varname))

    @classdef.method("attr")
    def method_attr(self, space, args_w):
        if len(args_w) == 2 and (args_w[1] is space.w_true or args_w[1] is space.w_false):
            [w_name, w_writable] = args_w
            if space.is_true(w_writable):
                self.method_attr_accessor(space, [w_name])
            else:
                self.method_attr_reader(space, [w_name])
        else:
            self.method_attr_reader(space, args_w)

    @classdef.method("module_function")
    def method_module_function(self, space, args_w):
        for w_arg in args_w:
            name = space.symbol_w(w_arg)
            self.attach_method(space, name, self._find_method_pure(space, name, self.version))

    @classdef.method("private_class_method")
    def method_private_class_method(self, space, w_name):
        w_cls = self.getsingletonclass(space)
        return space.send(w_cls, space.newsymbol("private"), [w_name])

    @classdef.method("public_class_method")
    def method_public_class_method(self, space, w_name):
        w_cls = self.getsingletonclass(space)
        return space.send(w_cls, space.newsymbol("public"), [w_name])

    @classdef.method("alias_method", new_name="symbol", old_name="symbol")
    def method_alias_method(self, space, new_name, old_name):
        self.define_method(space, new_name, self.find_method(space, old_name))

    @classdef.method("ancestors")
    def method_ancestors(self, space):
        return space.newarray(self.ancestors(include_singleton=False))

    @classdef.method("included")
    def method_included(self, space, w_mod):
        # TODO: should be private
        pass

    @classdef.method("extended")
    def method_included(self, space, w_mod):
        # TODO: should be private
        pass

    @classdef.method("name")
    def method_name(self, space):
        return space.newstr_fromstr(self.name)

    @classdef.method("private")
    def method_private(self, space, args_w):
        self.set_visibility(space, args_w, "private")

    @classdef.method("public")
    def method_public(self, space, args_w):
        self.set_visibility(space, args_w, "public")

    @classdef.method("protected")
    def method_protected(self, space, args_w):
        self.set_visibility(space, args_w, "protected")

    @classdef.method("constants")
    def method_constants(self, space):
        return space.newarray([space.newsymbol(n) for n in self.constants_w])

    @classdef.method("const_missing", name="symbol")
    def method_const_missing(self, space, name):
        raise space.error(space.w_NameError, "uninitialized constant %s" % name)

    @classdef.method("class_eval", string="str", filename="str")
    @classdef.method("module_eval", string="str", filename="str")
    def method_module_eval(self, space, string=None, filename=None, w_lineno=None, block=None):
        if string is not None:
            if filename is None:
                filename = "module_eval"
            if w_lineno is not None:
                lineno = space.int_w(w_lineno)
            else:
                lineno = 1
            return space.execute(string, self, lexical_scope=StaticScope(self, None), filepath=filename, initial_lineno=lineno)
        else:
            space.invoke_block(block.copy(w_self=self, lexical_scope=StaticScope(self, None)), [])

    @classdef.method("const_defined?", const="str", inherit="bool")
    def method_const_definedp(self, space, const, inherit=True):
        if inherit:
            return space.newbool(self.find_const(space, const) is not None)
        else:
            return space.newbool(self.find_local_const(space, const) is not None)

    @classdef.method("const_get", const="symbol", inherit="bool")
    def method_const_get(self, space, const, inherit=True):
        if inherit:
            w_res = self.find_const(space, const)
        else:
            w_res = self.find_local_const(space, const)
        if w_res is None:
            raise space.error(space.w_NameError,
                "uninitialized constant %s::%s" % (self.name, const)
            )
        return w_res

    @classdef.method("const_set", const="symbol")
    def method_const_set(self, space, const, w_value):
        space.set_const(self, const, w_value)
        return w_value

    @classdef.method("class_variable_defined?", name="symbol")
    def method_class_variable_definedp(self, space, name):
        return space.newbool(self.find_class_var(space, name) is not None)

    @classdef.method("method_defined?", name="str")
    def method_method_definedp(self, space, name):
        return space.newbool(self.find_method(space, name) is not None)

    @classdef.method("===")
    def method_eqeqeq(self, space, w_obj):
        return space.newbool(self.is_ancestor_of(space.getclass(w_obj)))

    @classdef.method("instance_method", name="symbol")
    def method_instance_method(self, space, name):
        return space.newmethod(name, self)

    @classdef.method("undef_method", name="symbol")
    def method_undef_method(self, space, name):
        w_method = self.find_method(space, name)
        if w_method is None or isinstance(w_method, UndefMethod):
            raise space.error(space.w_NameError,
                "undefined method `%s' for class `%s'" % (name, self.name)
            )
        self.define_method(space, name, UndefMethod(name))
        return self

    @classdef.method("remove_method", name="symbol")
    def method_remove_method(self, space, name):
        w_method = self._find_method_pure(space, name, self.version)
        if w_method is None or isinstance(w_method, UndefMethod):
            raise space.error(space.w_NameError,
                "method `%s' not defined in %s" % (name, self.name)
            )
        self.define_method(space, name, UndefMethod(name))
        return self
Exemple #6
0
class W_ModuleObject(W_RootObject):
    _immutable_fields_ = [
        "version?", "included_modules?[*]", "klass?", "name?"
    ]

    classdef = ClassDef("Module", W_RootObject.classdef)

    def __init__(self, space, name, klass=None):
        self.name = name
        self.klass = klass
        self.version = VersionTag()
        self.methods_w = {}
        self.constants_w = {}
        self.class_variables = CellDict()
        self.instance_variables = CellDict()
        self.flags = CellDict()
        self.included_modules = []
        self.descendants = []

    def __deepcopy__(self, memo):
        obj = super(W_ModuleObject, self).__deepcopy__(memo)
        obj.name = self.name
        obj.klass = copy.deepcopy(self.klass, memo)
        obj.version = copy.deepcopy(self.version, memo)
        obj.methods_w = copy.deepcopy(self.methods_w, memo)
        obj.constants_w = copy.deepcopy(self.constants_w, memo)
        obj.class_variables = copy.deepcopy(self.class_variables, memo)
        obj.instance_variables = copy.deepcopy(self.instance_variables, memo)
        obj.included_modules = copy.deepcopy(self.included_modules, memo)
        obj.descendants = copy.deepcopy(self.descendants, memo)
        return obj

    def getclass(self, space):
        if self.klass is not None:
            return jit.promote(self).klass
        return W_RootObject.getclass(self, space)

    def getsingletonclass(self, space):
        if self.klass is None or not self.klass.is_singleton:
            self.klass = space.newclass("#<Class:%s>" % self.name,
                                        self.klass or space.w_module,
                                        is_singleton=True,
                                        attached=self)
        return self.klass

    def mutated(self):
        self.version = VersionTag()

    def define_method(self, space, name, method):
        self.mutated()
        self.methods_w[name] = method
        if not space.bootstrap:
            if isinstance(method, UndefMethod):
                self.method_undefined(space, space.newsymbol(name))
            else:
                self.method_added(space, space.newsymbol(name))

    @jit.unroll_safe
    def find_method(self, space, name):
        method = self._find_method_pure(space, name, self.version)
        if method is None:
            for module in self.included_modules:
                method = module.find_method(space, name)
                if method is not None:
                    return method
        return method

    @jit.unroll_safe
    def find_method_super(self, space, name):
        for module in self.included_modules:
            method = module.find_method(space, name)
            if method is not None:
                return method
        return None

    @jit.elidable
    def _find_method_pure(self, space, method, version):
        return self.methods_w.get(method, None)

    def methods(self, space, inherit=True):
        methods = {}
        for name, method in self.methods_w.iteritems():
            if not isinstance(method, UndefMethod):
                methods[name] = None

        if inherit:
            for w_mod in self.included_modules:
                for name in w_mod.methods(space, inherit):
                    method = self._find_method_pure(space, name, self.version)
                    if method is None or not isinstance(method, UndefMethod):
                        methods[name] = None
        return methods.keys()

    def set_const(self, space, name, w_obj):
        self.mutated()
        self.constants_w[name] = w_obj
        if isinstance(w_obj, W_ModuleObject
                      ) and w_obj.name is None and self.name is not None:
            w_obj.set_name_in_scope(space, name, self)

    def find_const(self, space, name):
        w_res = self.find_included_const(space, name)
        if w_res is None:
            return space.w_object.find_const(space, name)
        else:
            return w_res

    @jit.unroll_safe
    def find_included_const(self, space, name):
        w_res = self.find_local_const(space, name)
        if w_res is None:
            for w_mod in self.included_modules:
                w_res = w_mod.find_local_const(space, name)
                if w_res is not None:
                    break
        return w_res

    def included_constants(self, space):
        consts = {}
        for const in self.constants_w:
            consts[const] = None
        for w_mod in self.included_modules:
            for const in w_mod.included_constants(space):
                consts[const] = None
        return consts.keys()

    def lexical_constants(self, space):
        consts = {}
        frame = space.getexecutioncontext().gettoprubyframe()
        scope = frame.lexical_scope

        while scope is not None:
            assert isinstance(scope, W_ModuleObject)
            for const in scope.w_mod.constants_w:
                consts[const] = None
            scope = scope.backscope

        return consts.keys()

    def local_constants(self, space):
        return self.constants_w.keys()

    def inherited_constants(self, space):
        return self.local_constants(space)

    def find_local_const(self, space, name):
        return self._find_const_pure(name, self.version)

    @jit.elidable
    def _find_const_pure(self, name, version):
        return self.constants_w.get(name, None)

    @jit.unroll_safe
    def set_class_var(self, space, name, w_obj):
        for module in reversed(self.ancestors()):
            assert isinstance(module, W_ModuleObject)
            w_res = module.class_variables.get(space, name)
            if w_res is not None or module is self:
                module.class_variables.set(space, name, w_obj)
                if module is self:
                    for descendant in self.descendants:
                        descendant.remove_class_var(space, name)

    @jit.unroll_safe
    def find_class_var(self, space, name):
        w_res = self.class_variables.get(space, name)
        if w_res is None:
            ancestors = self.ancestors()
            for idx in xrange(1, len(ancestors)):
                module = ancestors[idx]
                assert isinstance(module, W_ModuleObject)
                w_res = module.class_variables.get(space, name)
                if w_res is not None:
                    break
        return w_res

    @jit.unroll_safe
    def remove_class_var(self, space, name):
        self.class_variables.delete(name)
        for descendant in self.descendants:
            descendant.remove_class_var(space, name)

    def set_instance_var(self, space, name, w_value):
        return self.instance_variables.set(space, name, w_value)

    def find_instance_var(self, space, name):
        return self.instance_variables.get(space, name) or space.w_nil

    def copy_instance_vars(self, space, w_other):
        assert isinstance(w_other, W_ModuleObject)
        for key in w_other.instance_variables:
            w_value = w_other.instance_variables.get(space, key)
            self.set_instance_var(space, key, w_value)

    def set_flag(self, space, name):
        self.flags.set(space, name, space.w_true)

    def unset_flag(self, space, name):
        self.flags.set(space, name, space.w_false)

    def get_flag(self, space, name):
        return self.flags.get(space, name) or space.w_false

    def ancestors(self, include_singleton=True, include_self=True):
        if include_self:
            return [self] + self.included_modules
        else:
            return self.included_modules[:]

    @jit.unroll_safe
    def is_ancestor_of(self, w_cls):
        if self is w_cls:
            return True
        for w_mod in w_cls.included_modules:
            if self is w_mod:
                return True
        if w_cls.superclass is not None:
            return self.is_ancestor_of(w_cls.superclass)
        return False

    def include_module(self, space, w_mod):
        assert isinstance(w_mod, W_ModuleObject)
        if w_mod not in self.ancestors():
            self.included_modules = [w_mod] + self.included_modules
            w_mod.included(space, self)

    def included(self, space, w_mod):
        self.descendants.append(w_mod)
        if space.respond_to(self, "included"):
            space.send(self, "included", [w_mod])

    def extend_object(self, space, w_mod):
        if self not in w_mod.ancestors():
            self.descendants.append(w_mod)
            w_mod.included_modules = [self] + w_mod.included_modules

    def set_visibility(self, space, names_w, visibility):
        names = [space.symbol_w(w_name) for w_name in names_w]
        if names:
            for name in names:
                self.set_method_visibility(space, name, visibility)
        else:
            self.set_default_visibility(space, visibility)

    def set_default_visibility(self, space, visibility):
        pass

    def set_method_visibility(self, space, name, visibility):
        pass

    def method_added(self, space, w_name):
        space.send(self, "method_added", [w_name])

    def method_undefined(self, space, w_name):
        space.send(self, "method_undefined", [w_name])

    def method_removed(self, space, w_name):
        space.send(self, "method_removed", [w_name])

    def set_name_in_scope(self, space, name, w_scope):
        self.name = space.buildname(name, w_scope)
        for name, w_const in self.constants_w.iteritems():
            if isinstance(w_const, W_ModuleObject):
                w_const.set_name_in_scope(space, name, self)

    @classdef.singleton_method("nesting")
    def singleton_method_nesting(self, space):
        frame = space.getexecutioncontext().gettoprubyframe()
        modules_w = []
        scope = frame.lexical_scope
        while scope is not None:
            modules_w.append(scope.w_mod)
            scope = scope.backscope
        return space.newarray(modules_w)

    @classdef.singleton_method("allocate")
    def method_allocate(self, space):
        return W_ModuleObject(space, None, self)

    @classdef.method("initialize")
    def method_initialize(self, space, block):
        if block is not None:
            space.send(self, "module_exec", [self], block)

    @classdef.method("to_s")
    def method_to_s(self, space):
        name = self.name
        if name is None:
            return space.newstr_fromstr(space.any_to_s(self))
        return space.newstr_fromstr(name)

    @classdef.method("include")
    def method_include(self, space, args_w):
        for w_mod in args_w:
            if type(w_mod) is not W_ModuleObject:
                raise space.error(
                    space.w_TypeError,
                    "wrong argument type %s (expected Module)" %
                    space.obj_to_s(space.getclass(w_mod)))

        for w_mod in reversed(args_w):
            space.send(w_mod, "append_features", [self])

        return self

    @classdef.method("include?")
    def method_includep(self, space, w_mod):
        if type(w_mod) is not W_ModuleObject:
            raise space.error(
                space.w_TypeError, "wrong argument type %s (expected Module)" %
                space.obj_to_s(space.getclass(w_mod)))
        if w_mod is self:
            return space.w_false
        return space.newbool(w_mod in self.ancestors())

    @classdef.method("append_features")
    def method_append_features(self, space, w_mod):
        if w_mod in self.ancestors():
            raise space.error(space.w_ArgumentError, "cyclic include detected")
        for module in reversed(self.ancestors()):
            w_mod.include_module(space, module)

    @classdef.method("define_method", name="symbol")
    @check_frozen()
    def method_define_method(self, space, name, w_method=None, block=None):
        if w_method is not None:
            if space.is_kind_of(w_method, space.w_method):
                w_method = space.send(w_method, "unbind")

            if space.is_kind_of(w_method, space.w_unbound_method):
                self.define_method(space, name,
                                   DefineMethodMethod(name, w_method))
                return w_method
            elif space.is_kind_of(w_method, space.w_proc):
                assert isinstance(w_method, W_ProcObject)
                self.define_method(space, name,
                                   DefineMethodBlock(name, w_method))
                return w_method.copy(space, is_lambda=True)
            else:
                raise space.error(
                    space.w_TypeError,
                    "wrong argument type %s (expected Proc/Method)" %
                    space.obj_to_s(space.getclass(w_method)))
        elif block is not None:
            self.define_method(space, name, DefineMethodBlock(name, block))
            return block.copy(space, is_lambda=True)
        else:
            raise space.error(space.w_ArgumentError,
                              "tried to create Proc object without a block")

    @classdef.method("attr_accessor")
    def method_attr_accessor(self, space, args_w):
        self.method_attr_reader(space, args_w)
        self.method_attr_writer(space, args_w)

    @classdef.method("attr_reader")
    def method_attr_reader(self, space, args_w):
        for w_arg in args_w:
            varname = Coerce.symbol(space, w_arg)
            self.define_method(space, varname, AttributeReader("@" + varname))

    @classdef.method("attr_writer")
    def method_attr_writer(self, space, args_w):
        for w_arg in args_w:
            varname = Coerce.symbol(space, w_arg)
            self.define_method(space, varname + "=",
                               AttributeWriter("@" + varname))

    @classdef.method("attr")
    def method_attr(self, space, args_w):
        if len(args_w) == 2 and (args_w[1] is space.w_true
                                 or args_w[1] is space.w_false):
            [w_name, w_writable] = args_w
            if space.is_true(w_writable):
                self.method_attr_accessor(space, [w_name])
            else:
                self.method_attr_reader(space, [w_name])
        else:
            self.method_attr_reader(space, args_w)

    @classdef.method("module_function")
    def method_module_function(self, space, args_w):
        for w_arg in args_w:
            name = Coerce.symbol(space, w_arg)
            self.attach_method(
                space, name, self._find_method_pure(space, name, self.version))

    @classdef.method("private_class_method")
    def method_private_class_method(self, space, w_name):
        w_cls = self.getsingletonclass(space)
        return space.send(w_cls, "private", [w_name])

    @classdef.method("public_class_method")
    def method_public_class_method(self, space, w_name):
        w_cls = self.getsingletonclass(space)
        return space.send(w_cls, "public", [w_name])

    @classdef.method("alias_method", new_name="symbol", old_name="symbol")
    def method_alias_method(self, space, new_name, old_name):
        self.define_method(space, new_name, self.find_method(space, old_name))

    @classdef.method("ancestors")
    def method_ancestors(self, space):
        return space.newarray(self.ancestors(include_singleton=False))

    @classdef.method("included")
    def method_included(self, space, w_mod):
        # TODO: should be private
        pass

    @classdef.method("extended")
    def method_extended(self, space, w_mod):
        # TODO: should be private
        pass

    @classdef.method("extend_object")
    def method_extend_object(self, space, w_obj):
        self.extend_object(space, space.getsingletonclass(w_obj))

    @classdef.method("name")
    def method_name(self, space):
        if self.name is None:
            return space.w_nil
        return space.newstr_fromstr(self.name)

    @classdef.method("private")
    def method_private(self, space, args_w):
        self.set_visibility(space, args_w, "private")

    @classdef.method("public")
    def method_public(self, space, args_w):
        self.set_visibility(space, args_w, "public")

    @classdef.method("protected")
    def method_protected(self, space, args_w):
        self.set_visibility(space, args_w, "protected")

    @classdef.method("private_constant")
    def method_private_constant(self, space, args_w):
        pass

    @classdef.method("constants")
    def method_constants(self, space, w_inherit=None):
        if self is space.w_module and w_inherit is None:
            consts = {}
            for const in self.lexical_constants(space):
                consts[const] = None
            for const in self.inherited_constants(space):
                consts[const] = None
            return space.newarray([space.newsymbol(n) for n in consts])

        if w_inherit is None or space.is_true(w_inherit):
            return space.newarray(
                [space.newsymbol(n) for n in self.included_constants(space)])
        else:
            return space.newarray(
                [space.newsymbol(n) for n in self.constants_w])

    @classdef.method("const_missing", name="symbol")
    def method_const_missing(self, space, name):
        if self is space.w_object:
            raise space.error(space.w_NameError,
                              "uninitialized constant %s" % (name))
        else:
            self_name = space.obj_to_s(self)
            raise space.error(
                space.w_NameError,
                "uninitialized constant %s::%s" % (self_name, name))

    @classdef.method("class_eval", string="str", filename="str")
    @classdef.method("module_eval", string="str", filename="str")
    def method_module_eval(self,
                           space,
                           string=None,
                           filename=None,
                           w_lineno=None,
                           block=None):
        if string is not None and block is not None:
            raise space.error(space.w_ArgumentError,
                              "wrong number of arguments")
        if string is not None:
            if filename is None:
                filename = "module_eval"
            if w_lineno is not None:
                lineno = space.int_w(w_lineno)
            else:
                lineno = 1
            return space.execute(string,
                                 self,
                                 lexical_scope=StaticScope(self, None),
                                 filepath=filename,
                                 initial_lineno=lineno)
        elif block is None:
            raise space.error(space.w_ArgumentError, "block not supplied")
        else:
            return space.invoke_block(
                block.copy(space,
                           w_self=self,
                           lexical_scope=StaticScope(self,
                                                     block.lexical_scope)), [])

    @classdef.method("const_defined?", const="str", inherit="bool")
    def method_const_definedp(self, space, const, inherit=True):
        space._check_const_name(const)
        if inherit:
            return space.newbool(self.find_const(space, const) is not None)
        else:
            return space.newbool(
                self.find_local_const(space, const) is not None)

    @classdef.method("const_get", const="symbol", inherit="bool")
    def method_const_get(self, space, const, inherit=True):
        space._check_const_name(const)
        if inherit:
            w_res = self.find_const(space, const)
        else:
            w_res = self.find_local_const(space, const)
        if w_res is None:
            return space.send(self, "const_missing", [space.newsymbol(const)])
        return w_res

    @classdef.method("const_set", const="symbol")
    def method_const_set(self, space, const, w_value):
        space.set_const(self, const, w_value)
        return w_value

    @classdef.method("remove_const", name="str")
    def method_remove_const(self, space, name):
        space._check_const_name(name)
        w_res = self.find_local_const(space, name)
        if w_res is None:
            self_name = space.obj_to_s(self)
            raise space.error(
                space.w_NameError,
                "uninitialized constant %s::%s" % (self_name, name))
        del self.constants_w[name]
        self.mutated()
        return w_res

    @classdef.method("class_variable_defined?", name="symbol")
    def method_class_variable_definedp(self, space, name):
        return space.newbool(self.find_class_var(space, name) is not None)

    @classdef.method("class_variable_get", name="symbol")
    def method_class_variable_get(self, space, name):
        return space.find_class_var(self, name)

    @classdef.method("class_variable_set", name="symbol")
    @check_frozen()
    def method_class_variable_set(self, space, name, w_value):
        self.set_class_var(space, name, w_value)
        return w_value

    @classdef.method("remove_class_variable", name="symbol")
    def method_remove_class_variable(self, space, name):
        w_value = self.class_variables.get(space, name)
        if w_value is not None:
            self.class_variables.delete(name)
            return w_value
        if self.find_class_var(space, name) is not None:
            raise space.error(
                space.w_NameError,
                "cannot remove %s for %s" % (name, space.obj_to_s(self)))
        raise space.error(
            space.w_NameError, "class variable %s not defined for %s" %
            (name, space.obj_to_s(self)))

    @classdef.method("method_defined?", name="str")
    def method_method_definedp(self, space, name):
        return space.newbool(self.find_method(space, name) is not None)

    @classdef.method("===")
    def method_eqeqeq(self, space, w_obj):
        return space.newbool(self.is_ancestor_of(space.getclass(w_obj)))

    @classdef.method("<=")
    def method_lte(self, space, w_other):
        if not isinstance(w_other, W_ModuleObject):
            raise space.error(space.w_TypeError,
                              "compared with non class/module")
        for w_mod in self.ancestors():
            if w_other is w_mod:
                return space.w_true
        for w_mod in w_other.ancestors():
            if self is w_mod:
                return space.w_false
        return space.w_nil

    @classdef.method("<")
    def method_lt(self, space, w_other):
        if self is w_other:
            return space.w_false
        return space.send(self, "<=", [w_other])

    @classdef.method(">=")
    def method_gte(self, space, w_other):
        if not isinstance(w_other, W_ModuleObject):
            raise space.error(space.w_TypeError,
                              "compared with non class/module")
        return space.send(w_other, "<=", [self])

    @classdef.method(">")
    def method_gt(self, space, w_other):
        if not isinstance(w_other, W_ModuleObject):
            raise space.error(space.w_TypeError,
                              "compared with non class/module")
        if self is w_other:
            return space.w_false
        return space.send(w_other, "<=", [self])

    @classdef.method("<=>")
    def method_comparison(self, space, w_other):
        if not isinstance(w_other, W_ModuleObject):
            return space.w_nil

        if self is w_other:
            return space.newint(0)

        other_is_subclass = space.send(self, "<", [w_other])

        if space.is_true(other_is_subclass):
            return space.newint(-1)
        elif other_is_subclass is space.w_nil:
            return space.w_nil
        else:
            return space.newint(1)

    @classdef.method("instance_method", name="symbol")
    def method_instance_method(self, space, name):
        return space.newmethod(name, self)

    @classdef.method("undef_method", name="symbol")
    def method_undef_method(self, space, name):
        w_method = self.find_method(space, name)
        if w_method is None or isinstance(w_method, UndefMethod):
            cls_name = space.obj_to_s(self)
            raise space.error(
                space.w_NameError,
                "undefined method `%s' for class `%s'" % (name, cls_name))
        self.define_method(space, name, UndefMethod(name))
        return self

    @classdef.method("remove_method", name="symbol")
    @check_frozen()
    def method_remove_method(self, space, name):
        w_method = self._find_method_pure(space, name, self.version)
        if w_method is None or isinstance(w_method, UndefMethod):
            cls_name = space.obj_to_s(self)
            raise space.error(
                space.w_NameError,
                "method `%s' not defined in %s" % (name, cls_name))
        del self.methods_w[name]
        self.mutated()
        self.method_removed(space, space.newsymbol(name))
        return self

    @classdef.method("method_added")
    def method_method_added(self, space, w_name):
        return space.w_nil

    @classdef.method("method_undefined")
    def method_method_undefined(self, space, w_name):
        return space.w_nil

    @classdef.method("method_removed")
    def method_method_removed(self, space, w_name):
        return space.w_nil

    @classdef.method("class_exec")
    @classdef.method("module_exec")
    def method_module_exec(self, space, args_w, block):
        if block is None:
            raise space.error(space.w_LocalJumpError, "no block given")
        return space.invoke_block(
            block.copy(space,
                       w_self=self,
                       lexical_scope=StaticScope(self, None)), args_w)
Exemple #7
0
 def test_single_set(self, space):
     c = CellDict()
     v = c.version
     c.set(space, "a", 2)
     assert c.version is not v
     assert c._get_cell("a", c.version) == 2