NAME

IO::K8s::CRD::Emitter - Render generated IO::K8s classes as house-style Perl source

VERSION

version 1.108

SYNOPSIS

my $classes = IO::K8s::CRD->generate($crd, 'IO::K8s::_SUGGEST');
my $emitter = IO::K8s::CRD::Emitter->new(
    base  => 'IO::K8s::Traefik::V1alpha1',
    names => { "$root\::Spec::RateLimit" => 'RateLimit' },   # D6: upstream Go type names
);
my $files = $emitter->render($classes->{'traefik.io/v1alpha1'});
# { 'IO/K8s/Traefik/V1alpha1/Middleware.pm' => "package ...", ... }

DESCRIPTION

The source half of D10: what IO::K8s::CRD generates at runtime, rendered as checked-in, hand-maintained class files this distribution ships -- one output file per target path, the k8s DSL line per field with its options, the schema description as the field's =attr POD. Several generated classes may name the same target only when their functional declarations are identical; contextual # ABSTRACT and POD may differ, and one source is retained. A functional difference croaks before either class can overwrite the other. It reads nothing but the attribute registry of the generated classes, so it renders any AutoGen class set, and it never writes a file: callers get { path => source } and decide (maint/crd-drift-check.pl --suggest prints, --suggest-dir writes outside lib/).

Descriptions go into POD, not into the description field option: the house format documents every field once, in the =attr block.

For an is_int_or_string registry entry whose pattern is exactly Kubernetes' apimachinery Quantity pattern, rendering uses Quantity and removes only that redundant pattern from the emitted options; all other options and the dynamic AutoGen registry remain unchanged. Exact matching accepts either the pattern text or a regexp with only non-semantic u and p flags, so a near match or semantic flag stays IntOrStr. Consequently, numeric-looking '42' is a JSON string in emitted Quantity code, while the dynamic IntOrStr class still serializes it as a JSON number.

base

The package prefix of the rendered classes, e.g. IO::K8s::Traefik::V1alpha1. Required.

names

Hashref from a generated class name to the bare package name it should get under "base": { 'IO::K8s::_AUTOGEN_x::...::Middleware::Spec::RateLimit' => 'RateLimit' }. Classes not listed get their path joined: Middleware::Spec::RateLimit becomes MiddlewareSpecRateLimit. This is where the upstream Go type names (D6) come in. Checked before "overlay"'s own names map.

overlay

The per-Kind slice of a provider's maint/crd-render/<Provider>.yaml (the render-side counterpart of "names"): a hashref with with (arrayref of role class names composed on one with line), extra (arrayref of verbatim source lines rendered right after the with line) and names (a map from the LOGICAL class path below the Kind -- what "class_path" in IO::K8s::AutoGen returns, e.g. Spec, Spec::RateLimit -- to the bare Go type name), applied while rendering the root Kind passed to "render". with defaults to ['IO::K8s::Role::Namespaced'] when the root class composes that role and [] otherwise, when not given. This attribute holds one Kind's overlay, not the whole provider file -- slicing $provider_overlay->{kinds}{$kind} out of the YAML is the caller's job.

An names value carrying :: (k120) is an absolute target -- a fully-qualified package this render references but does not itself write a file for: a cross-version type another version directory of the same provider already ships (IO::K8s::ExternalSecrets::V1::AWSAuth named under a v1alpha1 Kind), or a core class the D5 reuse heuristic would not fold on its own (a single-key {name} that stays IO::K8s::Api::Core::V1::LocalObjectReference). See "package_for". The sibling no_reuse_core key of a provider overlay file is not read here: it is a generation-time concern the render driver passes to IO::K8s::AutoGen as reuse_core_except, so that a provider's own named type is generated for such a path before this overlay renames it.

version

The $VERSION line to write. Defaults to this distribution's.

package_for

my $package = $emitter->package_for($generated_class);

The package a generated class is rendered as: "names" when listed there by the generated class's own (possibly hash-shortened) Perl name, else "overlay"'s names when listed there by logical path, otherwise "base" plus the class's path segments below its Kind joined together (the Kind itself for the root).

An overlay names value that carries :: (k120) is used verbatim as an absolute package (a leading + is stripped) rather than joined below "base" -- the cross-version / core external targets described under "overlay". Such a class satisfies _is_external_ref: "render" neither recurses into it nor writes a file for it, and its reference is emitted the way a hand-written class writes that target package.

A class deep enough that IO::K8s::AutoGen had to shorten its own namespace-qualified Perl name (past its 251-character identifier limit -- see $MAX_CLASS_NAME there) is rendered from IO::K8s::AutoGen::class_path, the field path AutoGen records regardless of shortening, not from the class's own (possibly hashed) name -- this emitter's own base is normally much shorter than the AutoGen namespace prefix that forced the shortening, so the joined package name here often fits fine even when AutoGen's did not. That same logical path is what "overlay"'s names map is keyed by. Only when the joined name would itself run past $MAX_PACKAGE_SUFFIX characters, or base is itself long enough that the full package name would, does the emitted package fall back to <Kind>_<10 hex chars>, the hex digits a sha1_hex of the field path; give such a class a proper name via "names" or "overlay" instead of relying on that fallback.

render

my $files = $emitter->render($root_class);

Renders $root_class and every generated class reachable from its fields (objects, arrays of objects, maps of objects) into { 'Relative/Path.pm' => $source }. The result has one entry per target path, not necessarily per logical class: two classes mapped to the same path share it only when their executable declarations are identical after ignoring contextual # ABSTRACT and POD; otherwise render croaks naming the path and both logical classes. Stock classes referenced by a field (ObjectMeta, core types) are written by their short name and not rendered.

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/pplu/io-k8s-p5/issues.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHORS

  • Torsten Raudssus <getty@cpan.org>

  • Jose Luis Martinez Torres <jlmartin@cpan.org>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2018-2026 by Jose Luis Martinez Torres <jlmartin@cpan.org>.

This is free software, licensed under:

The Apache License, Version 2.0, January 2004