Pod-Elemental-Transformer-Splint

 view release on metacpan or  search on metacpan

lib/Pod/Elemental/Transformer/Splint.pm  view on Meta::CPAN

);
has attribute_renderer => (
    is => 'rw',
    isa => ArrayRef[HashRef[Str]],
    traits => [qw/Array/],
    default => sub {
        [
            { for => 'HTML', class => 'HtmlDefault' },
            { for => 'markdown', class => 'HtmlDefault' },
        ],
    },
    handles => {
        all_attribute_renderers => 'elements',
    }
);
has method_renderer => (
    is => 'rw',
    isa => ArrayRef[HashRef[Str]],
    traits => [qw/Array/],
    default => sub {
        [
            { for => 'HTML', class => 'HtmlDefault' },
            { for => 'markdown', class => 'HtmlDefault' },
        ],
    },
    handles => {
        all_method_renderers => 'elements',
    }
);

around BUILDARGS => sub {
    my $orig = shift;
    my $class = shift;
    my $args = shift;

    my $type_libraries = {};

    if(exists $args->{'type_libraries'}) {
        my $lib = $args->{'type_libraries'};
        $lib =~ s{([^\h]+=)}{---$1}g;
        $lib =~ s{^---}{};
        $lib =~ s{\h}{}g;
        my @libraries = split /---/ => $lib;

        foreach my $librarydata (@libraries) {
            my($library, $typesdata) = split /=/ => $librarydata;
            my @types = split /,/ => $typesdata;

            foreach my $type (@types) {
                $type_libraries->{ $type } = $library;
            }
        }
    }
    $args->{'type_libraries'} = $type_libraries;

    my $attribute_renderers = [];
    my $method_renderers = [];


    if(exists $args->{'attribute_renderer'}) {
        my @renderers = split m{,\s+}, $args->{'attribute_renderer'};

        for my $renderer (@renderers) {
            my($format, $class) = split m/=/, $renderer;
            push @{ $attribute_renderers } => { for => $format, class => $class };
        }
        $args->{'attribute_renderer'} = $attribute_renderers;
    }
    if(exists $args->{'method_renderer'}) {
        my @renderers = split m{,\s+}, $args->{'method_renderer'};

        for my $renderer (@renderers) {
            my($format, $class) = split m/=/, $renderer;
            $renderer = { for => $format, class => $class };
            push @{ $method_renderers } => { for => $format, class => $class };
        }
        $args->{'method_renderer'} = $method_renderers;
    }
    $class->$orig($args);
};

sub BUILD {
    my $self = shift;

    my $base = 'Pod::Elemental::Transformer::Splint';

    TYPE:
    foreach my $type (qw/attribute method/) {
        my $all_method = sprintf 'all_%s_renderers', $type;

        RENDERER:
        foreach my $renderer ($self->$all_method) {
            my $role = sprintf '%s::%sRenderer', $base, ucfirst $type;
            my $classname = sprintf '%s::%s', $role, $renderer->{'class'};

            try {
                load $classname;
            }
            catch {
                die "Can't use $classname as renderer: $_";
            };

            if(!$classname->does($role)) {
                die "$classname doesn't do the $role role";
            }

            $renderer->{'renderer'} = $classname->new(for => $renderer->{'for'});
        }
    }
}

sub transform_node {
    my $self = shift;
    my $node = shift;

    CHILD:
    foreach my $child (@{ $node->children }) {

        my $line_start = substr($child->content, 0 => length ($self->command_name) + 1);
        next CHILD if $line_start ne sprintf '%s ', $self->command_name;

        my($prefix, $action, $param, $data) = split m/\h+/, $child->content, 4;

        if($action eq 'classname' && defined $param) {
            eval "use $param";
            die "Can't use $param: $@" if $@;

            $self->classmeta($param->meta);
            $child->content('');

            next CHILD;
        }
        next CHILD if !$self->has_classmeta;

        if($action eq 'attributes' && scalar $self->classmeta->get_attribute_list) {

            my @attributes = map { $self->classmeta->get_attribute($_) } $self->classmeta->get_attribute_list;

            my @unwanted = extract_by { $_->does('Documented') && !$_->documentation_order } @attributes;

            my @custom_sort_order_attrs   = sort { $a->documentation_order <=> $b->documentation_order || $a->name cmp $b->name } extract_by { $_->does('Documented') && $_->documentation_order < 1000 }  @attributes;
            my @docced_not_in_constr_attr = sort { $a->name cmp $b->name } extract_by { !defined $_->init_arg && $_->does('Documented') } @attributes;
            my @not_in_constructor_attrs  = sort { $a->name cmp $b->name } extract_by { !defined $_->init_arg }  @attributes;
            my @required_attrs            = sort { $a->name cmp $b->name } extract_by { $_->is_required }        @attributes;
            my @documented_attrs          = sort { $a->name cmp $b->name } extract_by { $_->does('Documented') } @attributes;
            my @the_rest                  = sort { $a->name cmp $b->name } @attributes;

            my @wanted_attributes = (@custom_sort_order_attrs, @required_attrs, @documented_attrs, @the_rest, @docced_not_in_constr_attr, @not_in_constructor_attrs);
            #* First attributes with documentation
            #* then attributes available in constructor
            #* then required attributes
            #* and then alphabetical
            #my @attribute_names = sort {
            #                             ($a->does('Documented') && $a->has_documentation_order ? $a->documentation_order : 1000) <=> ($b->does('Documented') && $b->has_documentation_order ? $b->documentation_order : 1000)
            #                          || ($b->init_arg // 0) <=> ($a->init_arg // 0)
            #                          || ($b->is_required || 0) <=> ($a->is_required || 0)
            #                          ||  $a->name cmp $b->name
            #                      }
            #                      map { $self->classmeta->get_attribute($_) }
            #                      $self->classmeta->get_attribute_list;
            my $content = '';

            ATTR:
            foreach my $attr (@wanted_attributes) {
                next ATTR if $attr->does('Documented') && $attr->has_documentation_order && $attr->documentation_order == 0;

                $content .= sprintf "\n=head2 %s\n", $attr->name;
                my $prepared_attr = $self->prepare_attr($attr);
                foreach my $attribute_renderer ($self->all_attribute_renderers) {
                    $content .= $attribute_renderer->{'renderer'}->render_attribute($prepared_attr);
                }

            }
            $child->content($content);
        }

        if($action eq 'method') {
            if(!$self->classmeta->has_method($param)) {
                $child->content('');
                return;
            }



( run in 0.611 second using v1.01-cache-2.11-cpan-71847e10f99 )