219 lines
6.1 KiB
Elixir
219 lines
6.1 KiB
Elixir
object Object
|
|
module Methods
|
|
% Create a new object using the current object as parent
|
|
%
|
|
% ## Example
|
|
%
|
|
% obj = Object.new
|
|
% obj.__parent__ %=> 'Object
|
|
%
|
|
% ## Notes
|
|
%
|
|
% The new method is special cased by the compiler to receive
|
|
% all arguments wrapped into a single array.
|
|
def new(args)
|
|
Erlang.elixir_object_methods.new(self, args)
|
|
end
|
|
|
|
def mixin(module)
|
|
Erlang.elixir_object_methods.mixin(self, module)
|
|
end
|
|
|
|
def proto(module)
|
|
Erlang.elixir_object_methods.proto(self, module)
|
|
end
|
|
|
|
def __name__
|
|
Erlang.elixir_object_methods.name(self)
|
|
end
|
|
|
|
def __parent__
|
|
Erlang.elixir_object_methods.parent(self)
|
|
end
|
|
|
|
% Returns a list of atoms representing all mixins for the current object.
|
|
% The mixins chain is retrieved by getting the current object mixins and
|
|
% appending all protos from its parents.
|
|
%
|
|
% ## Example
|
|
%
|
|
% Imagine the following definition:
|
|
%
|
|
% object Foo
|
|
% mixin SomeMethods
|
|
% proto MoreMethods
|
|
% end
|
|
%
|
|
% The mixins chain for Foo is:
|
|
%
|
|
% Foo.__mixins__ % => ['SomeMethods, 'Object::Methods]
|
|
%
|
|
% Where `SomeMethods` is a module mixed into `Foo` and the `Object::Methods`
|
|
% is a module added as proto on `Foo` parent, which is the object `Object`:
|
|
%
|
|
% Foo.__parent__ % => 'Object
|
|
%
|
|
% The mixins for `Foo.new` are these:
|
|
%
|
|
% Foo.new.__mixins__ %=> ['MoreMethods, 'Object::Methods]
|
|
%
|
|
% Where `MoreMethods` is a module added as proto to `Foo.new` parent (which is `Foo`)
|
|
% and `Object::Methods` is a proto on `Foo.new` grandparent (which is `Object`).
|
|
%
|
|
% If we added a mixin to `Foo.new`, we would have the following result:
|
|
%
|
|
% Foo.new.mixin(MuchMoreMethods).__mixins__ %=> ['MuchMoreMethods, 'MoreMethods, 'Object::Methods]
|
|
%
|
|
% In other words, calculating the mixins chain is as simple as:
|
|
%
|
|
% [self.exclusive_mixins, self.parent.exclusive_protos, self.parent.parent.exclusive_protos, ...]
|
|
%
|
|
% Until parent becomes empty (`Object` is the only object that does not have a parent).
|
|
%
|
|
% Notice that we don't have methods called `exclusive_mixins` and `exclusive_protos`,
|
|
% they are mentioned just as examples.
|
|
%
|
|
% == Mixins inside object definitions
|
|
%
|
|
% In Elixir, all methods are carried in modules. Regular objects does not have methods per-se.
|
|
% However, for convenience, Elixir allows you to define methods inside the object definition:
|
|
%
|
|
% object Foo
|
|
% def bar
|
|
% 'baz
|
|
% end
|
|
% end
|
|
%
|
|
% What happens internally is that Elixir automatically creates a module named `Foo::Proto`
|
|
% and automatically adds it as `Foo` proto. In order for this to work properly, Elixir
|
|
% adds `Module::Methods` as mixin during the object definition, but it is removed from
|
|
% the mixins chain after the object is defined:
|
|
%
|
|
% object Foo
|
|
% __mixins__ % => ['Module::Methods, 'Object::Methods]
|
|
% end
|
|
%
|
|
% Foo.__mixins__ % => ['Object::Methods]
|
|
%
|
|
def __mixins__
|
|
Erlang.elixir_object_methods.mixins(self)
|
|
end
|
|
|
|
% Returns a list of atoms representing all proto for the current object.
|
|
% The mixins chain is retrieved by getting the current object protos and
|
|
% appending all protos from its parents.
|
|
%
|
|
% ## Example
|
|
%
|
|
% Imagine the following definition:
|
|
%
|
|
% object Foo
|
|
% mixin SomeMethods
|
|
% proto MoreMethods
|
|
% end
|
|
%
|
|
% The protos chain for Foo is:
|
|
%
|
|
% Foo.__protos__ % => ['MoreMethods, 'Object::Methods]
|
|
% Foo.new.__protos__ % => ['MoreMethods, 'Object::Methods]
|
|
%
|
|
% The lookup for protos happens in a similar fashion to mixins:
|
|
%
|
|
% [self.exclusive_protos, self.parent.exclusive_protos, self.parent.parent.exclusive_protos, ...]
|
|
%
|
|
% Read the documentation for `__mixins__` for more information.
|
|
def __protos__
|
|
Erlang.elixir_object_methods.protos(self)
|
|
end
|
|
|
|
% Returns a `Dict` with all variable names and values as its key-values.
|
|
%
|
|
% ## Example
|
|
%
|
|
% object Foo
|
|
% def constructor
|
|
% { 'bar: 1, 'baz: 2 }
|
|
% end
|
|
% end
|
|
%
|
|
% Foo.new.__ivars__ % => { 'bar: 1, 'baz: 2 }
|
|
%
|
|
def __ivars__
|
|
OrderedDict.new Erlang.elixir_object_methods.data(self)
|
|
end
|
|
|
|
def __ancestors__
|
|
Erlang.elixir_object_methods.ancestors(self)
|
|
end
|
|
|
|
def inspect
|
|
name = __name__
|
|
if name
|
|
name.to_s
|
|
else
|
|
"<#{__parent__} #{__ivars__.inspect}>"
|
|
end
|
|
end
|
|
|
|
def to_s
|
|
self.inspect
|
|
end
|
|
|
|
% We could mark the methods below as protected, but, as everything
|
|
% inherits from Object, the visibility would never take effect and
|
|
% would just affect performance instead.
|
|
% protected
|
|
|
|
def constructor
|
|
{:}
|
|
end
|
|
|
|
def get_ivar(name)
|
|
Erlang.elixir_object_methods.get_ivar(self, name)
|
|
end
|
|
|
|
def set_ivar(name, value)
|
|
Erlang.elixir_object_methods.set_ivar(self, name, value)
|
|
end
|
|
|
|
def __public_proto_methods__
|
|
Erlang.elixir_object_methods.public_proto_methods(self)
|
|
end
|
|
|
|
def send(method)
|
|
send(method, [])
|
|
end
|
|
|
|
def send(method, args)
|
|
Erlang.elixir_dispatch.dispatch(false, self, method, args)
|
|
end
|
|
|
|
def catch(function)
|
|
filter_stacktrace Erlang.elixir_object_methods.function_catch(function)
|
|
end
|
|
|
|
% Set the following methods to private.
|
|
Erlang.elixir_module_methods.set_visibility(self, 'private)
|
|
|
|
def filter_stacktrace({ 'EXIT, { reason, stacktrace } })
|
|
regexp = ~r(^[A-Z])
|
|
newtrace = stacktrace.foldr [], do ({module, function, arity}, acc)
|
|
if regexp.match?(module)
|
|
[{module, function, arity - 1}|acc]
|
|
else
|
|
acc
|
|
end
|
|
end
|
|
{ 'EXIT, { reason, newtrace } }
|
|
end
|
|
|
|
def filter_stacktrace(other)
|
|
other
|
|
end
|
|
end
|
|
|
|
% Object::Methods is automatically mixed and proto'd by Elixir
|
|
% runtime so we can bootstrap the object system.
|
|
% mixin Object::Methods
|
|
% proto Object::Methods
|
|
end |