Config-Resolver

 view release on metacpan or  search on metacpan

lib/Config/Resolver.pm  view on Meta::CPAN

      { debug         => $options->{debug},
        warning_level => $options->{warning_level},
        logger        => $logger,
        %{$plugin_specific_config},
      }
    );

    if ($logger) {
      $logger->level($log_level);
    }

    $plugin_handlers{$protocol} = $plugin_obj;
  }

  my $final_handler_map = { %base_handlers, %plugin_handlers, %{$user_handlers}, };

  $self->set_handler_map($final_handler_map);

  return $self;
}

########################################################################
sub resolve_value {
########################################################################
  my ( $self, $value, $parameters ) = @_;

  my $handlers = $self->get_handler_map;

  # It checks for the "protocol" pattern first.
  if ( $value =~ /^(\w+):\/\/(.+)$/xsm ) {
    my ( $prefix, $path ) = ( $1, $2 );  # $prefix is the 'xxx'

    if ( my $handler = $handlers->{$prefix} ) {

      my $resolved_val;

      if ( reftype($handler) eq 'CODE' ) {
        $resolved_val = $handler->( $path, $parameters );
      }
      elsif ( blessed($handler) && $handler->can('resolve') ) {
        $resolved_val = $handler->resolve( $path, $parameters );
      }
      else {
        croak "Invalid handler for protocol '$prefix': "
          . 'handler must be a coderef or a blessed object '
          . q{that implements a 'resolve' method.};
      }

      # Handle errors/undefs
      die "could not resolve [$value]\n"
        if !defined $resolved_val && $self->get_warning_level eq 'error';

      # Return the resolved value, defaulting undef to empty string
      return ( $resolved_val // $EMPTY, $parameters );
    }

    # If no backend plugin exists, we can either 'croak' or just
    # fall through and treat it as a literal string.
  }

  if ( $value =~ /\$[{]([\S]+?)[}]/xsm ) {
    my %vars;

    while ( $value =~ /\$[{]([\S]+?)[}]/xsmg ) {
      my $p = $1;

      my $v = $self->get_parameter( $parameters, $p );

      {
        local $SIG{__DIE__} = 'DEFAULT';

        die "could not resolve [$p]\n"
          if !defined $v && $self->get_warning_level eq 'error';
      }

      $vars{$p} = $v;
    }

    foreach my $k ( keys %vars ) {
      if ( !exists $vars{$k} || !defined $vars{$k} ) {
        $vars{$k} = q{};
        print {*STDERR} "WARNING: $k is undefined!\n";
      }

      $value =~ s/\$[{]\Q$k\E[}]/$vars{$k}/xsmg;
    }
    return ( $value, $parameters );
  }

  if ( $value =~ /\$[{]([\S]+?)\s+([\w!=><]+)\s+(.+?)\s+\?\s+(.+?)\s+\:\s+(.+?)\s*[}]/ ) {
    my %dispatch_ops = (
      # Numeric
      q{==} => sub { $_[0] == $_[1] },
      q{!=} => sub { $_[0] != $_[1] },
      q{>}  => sub { $_[0] > $_[1] },
      q{<}  => sub { $_[0] < $_[1] },
      q{>=} => sub { $_[0] >= $_[1] },
      q{<=} => sub { $_[0] <= $_[1] },

      # String
      q{eq} => sub { $_[0] eq $_[1] },
      q{ne} => sub { $_[0] ne $_[1] },
      q{gt} => sub { $_[0] gt $_[1] },
      q{lt} => sub { $_[0] lt $_[1] },
      q{ge} => sub { $_[0] ge $_[1] },
      q{le} => sub { $_[0] le $_[1] },
    );

    # ternary
    my $lhs       = $self->get_parameter( $parameters, $1 );
    my $rhs       = $self->eval_arg( $3, $parameters );
    my $op        = $2;
    my $alt_true  = $self->eval_arg( $4, $parameters );
    my $alt_false = $self->eval_arg( $5, $parameters );

    croak "Invalid operator $op in ternary"
      if !exists $dispatch_ops{$op};

    my $is_true = $dispatch_ops{$op}->( $lhs, $rhs );
    my $val     = $is_true ? $alt_true : $alt_false;

    $value =~ s/\$[{]([\S]+?)\s+([\w!=><]+)\s+(.+?)\s+\?\s+(.+?)\s+\:\s+(.+?)\s*[}]/$val/;

    return ( $value, $parameters );
  }

  return ( $value, $parameters );
}

########################################################################
sub eval_arg {
########################################################################
  my ( $self, $arg, $parameters ) = @_;

  # 1. Is it a number? (e.g., 123)
  if ( looks_like_number($arg) ) {
    return $arg;
  }

  # 2. Is it a quoted string? (e.g., "prod-db" or 'dev-db')
  if ( $arg =~ / ^ (["']) (.*?) \1 $ /xsm ) {
    my $val = $2;  # Get the captured content

    # Un-escape any backslashed quotes
    $val =~ s/ \\ (["']) /$1/gx;

    return $val;
  }

  # 3. If it's not a number or quoted string, it must be a
  #    variable path (e.g., database.dev).
  return $self->get_parameter( $parameters, $arg );
}

########################################################################
sub _resolve_array {
########################################################################
  my ( $self, $obj, $parameters ) = @_;

  foreach my $val ( @{$obj} ) {
    ( $val, $parameters ) = $self->finalize_parameters( $val, $parameters );
  }

  return ( $obj, $parameters );
}

########################################################################
sub _resolve_hash {
########################################################################
  my ( $self, $obj, $parameters ) = @_;

  foreach my $key ( keys %{$obj} ) {
    my $val;

    ( $val, $parameters ) = $self->finalize_parameters( $obj->{$key}, $parameters );

    $obj->{$key} = $val;
  }

  return ( $obj, $parameters );
}



( run in 0.739 second using v1.01-cache-2.11-cpan-5735350b133 )