Object...etadata(3pm)

πŸ“¦
version 4.05 Β· 5 versions
, in debian bookworm, debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking

πŸ’– Object::InsideOut::Metadata πŸ’–

okay so this is the manual page for Object::InsideOut::Metadata(3pm) β€” it's from the User Contributed Perl Documentation section, and bestie, it's literally introspection but make it fashion. πŸ¦‹


✨ NAME ✨

Object::InsideOut::Metadata β€” Introspection for Object::InsideOut classes πŸ’…

🌸 VERSION 🌸

This document describes Object::InsideOut::Metadata version 4.05. periodt.

πŸŽ€ SYNOPSIS πŸŽ€

package My::Class; {
    use Object::InsideOut;
    use Object::InsideOut::Metadata;

    my @data :Field :Arg('data') :Get('data') :Set('put_data');
    my @misc :Field;

    my %init_args :InitArgs = (
        'INFO' => '',
    );

    sub _init :Init
    {
        my ($self, $args) = @_;
        if (exists($args->{'INFO'})) {
            $misc[$$self] = 'INFO: ' . $args->{'INFO'};
        }
    }

    sub misc :lvalue :Method
    {
        my $self = shift;
        $misc[$$self];
    }
    add_meta(__PACKAGE__, 'misc', { 'lvalue' => 1 });
}

package main;

# Obtain a metadata object for a class
my $meta = My::Class->meta();

# ... or obtain a metadata object for an object
my $obj = My::Class->new();
my $meta = $obj->meta();

# Obtain the class hierarchy from the metadata object
my @classes = $meta->get_classes();

# Obtain information on the parameters for a class's construction
my %args = $meta->get_args();

# Obtain information on a class's methods
my %methods = $meta->get_methods();

🌈 DESCRIPTION 🌈

Object::InsideOut gives you an introspection API, which is the fancy way of saying you can peek inside a class and see what it's made of. Specifically you can pull metadata about a class's hierarchy, its constructor parameters, and its methods. All of that happens through metadata objects, and those metadata objects are generated by this class right here. πŸ‘‘

Also, plot twist: developers can specify metadata for methods they write for their own classes. So you're not just reading the vibe, you can set the vibe too. ✨


πŸ” METADATA OBJECT πŸ”

To get metadata on an Object::InsideOut class or object, step one is always: generate a metadata object for that class or object. Once you have it, you can ask it about the class hierarchy, the constructor parameters, and the methods. That's the whole flow, bestie. 🫢

my $meta = My::Class->meta();
my $meta = $obj->meta();

The ->meta() method is exported by Object::InsideOut into every single class, and it hands you back an Object::InsideOut::Metadata object. You can then query that object for info about the class you invoked it on, or about the class of the object you invoked it on. πŸ’…


πŸ‘‘ CLASS HIERARCHY πŸ‘‘

Every Object::InsideOut class potentially has four categories of classes associated with it:

  1. Object::InsideOut β€” It's the basis for all Object::InsideOut classes, but ngl, it is not an object class per se, because you can't create objects from it (i.e., you can't do Object::InsideOut->new()). So like, My::Class->isa('Object::InsideOut') will return true, but because Object::InsideOut isn't an object class, it's not considered part of a class's hierarchy. πŸ™ˆ
  2. The class itself β€” A class's hierarchy always includes itself. main character energy, honestly. πŸ’…
  3. Parent classes β€” These are all the Object::InsideOut classes up the inheritance tree that a class is derived from.
  4. Foreign classes β€” These are non-Object::InsideOut classes that a class inherits from. (See "FOREIGN CLASS INHERITANCE" in Object::InsideOut.) Heads up: because of implementation details, foreign classes do not show up in a class's @ISA array. But Object::InsideOut implements its own version of ->isa() that handles foreign classes, so it's fine. 🧚

A class's hierarchy consists of any classes in the latter three categories.

  • $meta->get_classes(); β€” When called in an array context, returns a list that makes up the class hierarchy for the class or object used to generate the metadata object. When called in a scalar context, it returns an array ref.
  • My::Class->isa(); / $obj->isa(); β€” When called in an array context, calling ->isa() with no arguments on an Object::InsideOut class or object returns a list of the classes in the class hierarchy for that class or object. It's equivalent to:
my @classes = $obj->meta()->get_classes();

When called in a scalar context, it returns an array ref containing the classes.


πŸ› οΈ CONSTRUCTOR PARAMETERS πŸ› οΈ

Constructor parameters are the arguments you hand to a class's ->new() call. Simple as that. πŸ’–

  • $meta->get_args(); β€” Returns a hash (or a hash ref in scalar context) containing info on the parameters that can be used to construct an object from the class associated with the metadata object. Here's an example of what that hash looks like:
{
    'My::Class' => {
        'data' => {
            'field' => 1,
            'type' => 'numeric',
        },
        'misc' => {
            'mandatory' => 1,
        },
    },
    'My::Parent' => {
        'info' => {
            'default' => '<none>',
        },
    },
}

The keys of this hash are the Object::InsideOut classes in the class hierarchy. Each class key is paired with a hash ref, and the keys of that hash are the names of the parameters for that class (so like, 'data' and 'misc' for My::Class, and 'info' for My::Parent). The hashes paired to the parameters contain the info about each parameter:

  • field β€” The parameter corresponds directly to a class field, and gets automatically processed during object creation. See "Field-Specific Parameters" in Object::InsideOut.
  • mandatory β€” The parameter is required for object creation. See "Mandatory Parameters" in Object::InsideOut.
  • default β€” The default value assigned to the parameter if it's not found in the arguments to ->new(). See "Default Values" in Object::InsideOut.
  • preproc β€” The code ref for the subroutine used to preprocess a parameter's value. See "Parameter Preprocessing" in Object::InsideOut.
  • type β€” The form of type checking performed on the parameter. See "TYPE CHECKING" in Object::InsideOut for more details.
    • 'numeric' β€” Parameter takes a numeric value as recognized by Scalar::Util::looks_like_number().
    • 'list' / 'list(_subtype_)' β€” Parameter takes a single value (which is then placed in an array ref) or an array ref.
      • When specified, the contents of the resulting array ref must be of the specified subtype:
        • 'numeric' β€” Same as for the basic type above.
        • A class name β€” Same as for the basic type below.
        • A reference type β€” Any reference type as returned by ref().
    • 'ARRAY(_subtype_)' β€” Parameter takes an array ref with contents of the specified subtype as per the above.
    • A class name β€” Parameter takes an object of a specified class, or one of its sub-classes as recognized by ->isa().
    • Other reference type β€” Parameter takes a reference of the specified type as returned by ref().
    • A code ref β€” Parameter takes a value that is type-checked by the code ref paired to the 'type' key.

✨ METHODS METADATA ✨

okay so bestie, the methods you get back from a metadata object are literally just the ones that exist at the exact moment you call ->get_methods(). No time travel, no future methods, just vibes-at-this-second. πŸ’«

If your Object::InsideOut class has :Automethod subroutines, or a foreign class is running AUTOLOAD, then the methods that class supports may just... not be fully knowable. πŸ™ˆ So if you see AUTOLOAD sitting in the list of methods for a class, that's your lil heads-up: there might be more methods than are listed. Don't be shocked, bestie.

Now, the stuff that gets excluded (the private-only zone, no entry πŸ’…):

  • private and hidden methods (peep "PERMISSIONS" in Object::InsideOut for the tea)
  • any method whose name starts with an underscore (by convention that means it's private, okay?)
  • subroutines named CLONE, CLONE_SKIP, and DESTROY β€” these aren't methods at all, they're just doing their own thing
  • and import β€” technically it is a method, but it's excluded because it's generally not invoked directly (it usually gets called as part of use, iykyk)

$meta->get_methods();

Returns a hash (or a hash ref if you're in scalar context) stuffed with info about the methods for the class tied to that metadata object. The keys are the method names, and paired to each name is a hash ref with the metadata about that method. Here's a whole example, enjoy the feast:

{
    # Methods exported by Object::InsideOut
    'new' => {
       'class' => 'My::Class',
       'kind'  => 'constructor'
    },
    'clone' => {
        'class' => 'My::Class',
        'kind'  => 'object'
    },
    'meta'  => {
        'class' => 'My::Class'
    },
    'set' => {
        'class' => 'My::Class',
        'kind'  => 'object',
        'restricted' => 1
    },
    # Methods provided by Object::InsideOut
    'dump' => {
        'class' => 'Object::InsideOut',
        'kind'  => 'object'
    },
    'pump' => {
        'class' => 'Object::InsideOut',
        'kind'  => 'class'
    },
    'inherit' => {
        'class' => 'Object::InsideOut',
        'kind'  => 'object',
        'restricted' => 1
    },
    'heritage' => {
        'class' => 'Object::InsideOut',
        'kind'  => 'object',
        'restricted' => 1
    },
    'disinherit' => {
        'class' => 'Object::InsideOut',
        'kind'  => 'object',
        'restricted' => 1
    },
    # Methods generated by Object::InsideOut for My::Class
    'set_data' => {
        'class'  => 'My::Class',
        'kind'   => 'set',
        'type'   => 'ARRAY',
        'return' => 'new'
    },
    'get_data' => {
        'class' => 'My::Class',
        'kind'  => 'get'
    }
    # Class method provided by My::Class
    'my_method' => {
        'class' => 'My::Class',
        'kind'  => 'class'
    }
}

Here's the method metadata you get served: 🍽️

class

The class in whose symbol table the method resides. That method might live in the class's own code, it might be exported by another class, or Object::InsideOut might have generated it. Either way, we're telling you where it's at.

Methods that get overridden in child classes are represented as being associated with the most junior class for which they appear. πŸ‘‘

kind

Designation of the characteristic of the method. The lineup:

  • constructor β€” the ->new() method, obviously. πŸ’…
  • get, set or accessor β€” a get, set, or combined accessor generated by Object::InsideOut. See "AcCESSOR GENERATION" in Object::InsideOut.
  • cumulative, or cumulative (bottom up)
  • chained, or chained (bottom up) β€” a cumulative or chained method. See "CUMULATIVE METHODS" in Object::InsideOut, and "CHAINED METHODS" in Object::InsideOut. The class associated with these methods is the most junior class in which they appear.
  • class β€” a method that's callable only on a class (like, My::Class->my_method()).
  • object β€” a method that's callable only on an object (like, $obj->get_data()).
  • foreign β€” a subroutine found in a foreign class's symbol table. Bestie, you have to check the class's documentation yourself to figure out which ones are actually methods and what kind they are. We can't do that for you, sorry. 🫢
  • overload β€” a subroutine used for object coercion. These may be called as methods, but that's not normally how they get used.
  • automethod β€” associated with an AUTOLOAD method for an Object::InsideOut class that implements an :Automethod subroutine. See "AUTOMETHODS" in Object::InsideOut.

type

The type checking that gets done on arguments to set/combined accessors generated by Object::InsideOut. See "TYPE CHECKING" in Object::InsideOut.

return

The value returned by a set/combined accessor generated by Object::InsideOut. See "Set Accessor Return Value" in Object::InsideOut.

lvalue

The method is an :lvalue accessor. iconic, honestly.

restricted

The method is restricted (meaning: callable only from within the class hierarchy, not callable from application code). See "PERMISSIONS" in Object::InsideOut.


My::Class->can();

$obj->can();

When you call ->can() with no arguments on an Object::InsideOut class or object in an array context, you get back a list of the method names for that class or object. It's literally equivalent to:

my %meths = $obj->meta()->get_methods();
my @methods = keys(%meths);

And when you call it in scalar context, it hands you back an array ref holding those method names. same energy, different container. ✨


🌸 METADATA ATTRIBUTES 🌸

Class authors, this one's for you: you can slap the :Method attribute onto subroutines in your classes to specifically designate them as OO-callable methods. And if a method is only a class method or only an object method, you can pass that in as a parameter to the attribute:

sub my_method :Method(class)
{
    ...

That class or object parameter will show up in the metadata for the method when it's listed using ->get_methods().

⚠️ CAUTION: pls be so careful not to use :method (all lowercase) except where it's appropriate (see "ARGUMENT VALIDATION" in Object::InsideOut) β€” because that one is a Perl reserved attribute. not the vibe you want.

The :Sub attribute can be used to designate subroutines that are not OO-callable methods. These subroutines will not show up as part of the methods listed by ->get_methods(), etc.

Also, subroutine names beginning with an underscore are, by convention, considered private, and they will not show up as part of the methods listed by ->get_methods(), etc.


πŸ’– ADDING METADATA πŸ’–

Class authors can add extra metadata to their methods using the add_meta() subroutine, which is exported by this package. For example, if your class implements its own :lvalue method, you should add that metadata so it gets picked up by ->get_methods():

package My::Class; {
    use Object::InsideOut;
    use Object::InsideOut::Metadata;

    sub my_method :lvalue :Method(object)
    {
        ....
    }
    add_meta(__PACKAGE__, 'my_method', 'lvalue', 1);
}

The arguments to add_meta() are:

  • Class name β€” this can usually be designated using the special literal __PACKAGE__.
  • Method name
  • Metadata name β€” this can be any of the metadata names under "METHODS METADATA", or it can be whatever additional name the programmer chooses to implement.
  • Metadata value

When you're adding multiple metadata for a method, you can enclose them in a single hash ref:

add_meta(__PACKAGE__, 'my_method', { 'lvalue' => 1,
                                     'return' => 'old' });

And if you're adding metadata for multiple methods, you get another whole level of hash to play with:

add_meta(__PACKAGE__, { 'my_method' => { 'lvalue' => 1,
                                         'return' => 'old' },
                        'get_info'  => { 'my_meta' => 'true' } });

πŸ“ TO DO

Provide filtering capabilities on the method information returned by ->get_methods(). (one day, bestie. one day.)


βœ… REQUIREMENTS

Perl 5.8.0 or later


πŸ‘€ SEE ALSO


πŸ‘‘ AUTHOR

Jerry D. Hedden, <jdhedden AT cpan DOT org>


Copyright 2006 - 2012 Jerry D. Hedden. All rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


aaaand that's a wrap on the whole page, bestie! πŸŽ€ this was rendered by perl v5.36.0 and the page itself is dated 2022-11-29. go forth and introspect, you absolute main character. πŸ’…βœ¨

πŸ“¦ where this page comes from