DBIO
view release on metacpan or search on metacpan
lib/DBIO/Util.pm view on Meta::CPAN
package DBIO::Util;
# ABSTRACT: Internal utility functions for DBIO
use warnings;
use strict;
use Config;
# All configuration as lowercase functions â safe in quote_sub/eval contexts
# when called fully qualified (DBIO::Util::func_name())
sub spurious_version_check_warnings () {
( $ENV{DBIO_TEST_VERSION_WARNS_INDISCRIMINATELY} || $] < 5.010 ) ? 1 : 0
}
sub is_windows () { $^O eq 'MSWin32' ? 1 : 0 }
sub is_dev_release () { ($DBIO::VERSION || '') =~ /_/ ? 1 : 0 }
sub old_mro () { $] < 5.009_005 ? 1 : 0 }
sub has_ithreads () { $Config{useithreads} ? 1 : 0 }
sub unstable_dollar_at () { "$]" < 5.013002 ? 1 : 0 }
sub dbiotest () { $INC{"DBIO/Test.pm"} ? 1 : 0 }
sub peepeeness () { $INC{"DBIO/Test.pm"} && eval { DBIO::Test->is_smoker } && ($] >= 5.013005 and $] <= 5.013006) }
sub shuffle_unordered_resultsets () { $ENV{DBIO_SHUFFLE_UNORDERED_RESULTSETS} ? 1 : 0 }
sub assert_no_internal_wantarray () { $ENV{DBIO_ASSERT_NO_INTERNAL_WANTARRAY} ? 1 : 0 }
sub assert_no_internal_indirect_calls () { $ENV{DBIO_ASSERT_NO_INTERNAL_INDIRECT_CALLS} ? 1 : 0 }
sub stresstest_utf8_upgrade_generated_collapser_source () { $ENV{DBIO_STRESSTEST_UTF8_UPGRADE_GENERATED_COLLAPSER_SOURCE} ? 1 : 0 }
sub iv_size () { $Config{ivsize} }
sub os_name () { $^O }
sub help_url () { 'https://codeberg.org/dbio/dbio/issues' }
BEGIN {
if ($] < 5.009_005) {
require MRO::Compat;
}
else {
require mro;
}
}
# FIXME - this is not supposed to be here
# Carp::Skip to the rescue soon
use DBIO::Carp '^DBIO';
use B ();
use Carp 'croak';
use Storable 'nfreeze';
use Scalar::Util qw(weaken blessed reftype refaddr);
use Sub::Quote qw(qsub quote_sub);
use base 'Exporter';
our @EXPORT_OK = qw(
sigwarn_silencer modver_gt_or_eq modver_gt_or_eq_and_lt
fail_on_internal_wantarray fail_on_internal_call
refdesc refcount hrefaddr
scope_guard is_exception emit_loud_diag
quote_sub qsub perlstring serialize dump_value
UNRESOLVABLE_CONDITION
dir_path file_path parent_dir slurp_file slurp_file_utf8 write_file mkpath rmtree
split_name dumper_squashed eval_package_without_redefine_warnings class_path
firstidx uniq apply array_eq
foreignbuildargs is_access_broker
is_windows is_dev_release old_mro help_url unstable_dollar_at
has_ithreads dbiotest peepeeness shuffle_unordered_resultsets
iv_size os_name spurious_version_check_warnings
is_plain_value is_literal_value
assert_no_internal_wantarray assert_no_internal_indirect_calls
stresstest_utf8_upgrade_generated_collapser_source
);
use constant UNRESOLVABLE_CONDITION => \ '1 = 0';
sub sigwarn_silencer ($) {
my $pattern = shift;
croak "Expecting a regexp" if ref $pattern ne 'Regexp';
my $orig_sig_warn = $SIG{__WARN__} || sub { CORE::warn(@_) };
return sub { &$orig_sig_warn unless $_[0] =~ $pattern };
}
sub perlstring ($) { q{"}. quotemeta( shift ). q{"} };
sub hrefaddr ($) { sprintf '0x%x', &refaddr||0 }
sub refdesc ($) {
croak "Expecting a reference" if ! length ref $_[0];
# be careful not to trigger stringification,
# reuse @_ as a scratch-pad
sprintf '%s%s(0x%x)',
( defined( $_[1] = blessed $_[0]) ? "$_[1]=" : '' ),
reftype $_[0],
refaddr($_[0]),
;
}
sub refcount ($) {
croak "Expecting a reference" if ! length ref $_[0];
# No tempvars - must operate on $_[0], otherwise the pad
# will count as an extra ref
B::svref_2object($_[0])->REFCNT;
}
sub serialize ($) {
local $Storable::canonical = 1;
lib/DBIO/Util.pm view on Meta::CPAN
local $@;
eval { $mod->VERSION($ver) } ? 1 : 0;
}
sub modver_gt_or_eq_and_lt ($$$) {
my ($mod, $v_ge, $v_lt) = @_;
croak "Nonsensical maximum version supplied"
if ! defined $v_lt or $v_lt =~ /[^0-9\.\_]/;
return (
modver_gt_or_eq($mod, $v_ge)
and
! modver_gt_or_eq($mod, $v_lt)
) ? 1 : 0;
}
{
my $list_ctx_ok_stack_marker;
sub fail_on_internal_wantarray () {
return if $list_ctx_ok_stack_marker;
if (! defined wantarray) {
croak('fail_on_internal_wantarray() needs a tempvar to save the stack marker guard');
}
my $cf = 1;
while ( ( (caller($cf+1))[3] || '' ) =~ / :: (?:
# these are public API parts that alter behavior on wantarray
search | search_related | slice | search_literal
|
) $/x ) {
$cf++;
}
my ($fr, $want, $argdesc);
{
package DB;
$fr = [ caller($cf) ];
$want = ( caller($cf-1) )[5];
$argdesc = ref $DB::args[0]
? DBIO::Util::refdesc($DB::args[0])
: 'non '
;
};
if (
$want and $fr->[0] =~ /^(?:DBIO|DBICx::)/
) {
DBIO::Exception->throw( sprintf (
"Improper use of %s instance in list context at %s line %d\n\n Stacktrace starts",
$argdesc, @{$fr}[1,2]
), 'with_stacktrace');
}
my $mark = [];
weaken ( $list_ctx_ok_stack_marker = $mark );
$mark;
}
}
# --- Path helpers (replace Path::Class with core modules) ---
require File::Spec;
require File::Basename;
sub dir_path { File::Spec->catdir(@_) }
sub file_path { File::Spec->catfile(@_) }
sub parent_dir { File::Basename::dirname($_[0]) }
sub slurp_file {
open my $fh, '<', $_[0] or croak "Cannot read $_[0]: $!";
local $/;
<$fh>;
}
sub mkpath {
require File::Path;
File::Path::mkpath([@_]);
}
sub rmtree {
require File::Path;
File::Path::rmtree([@_]);
}
# --- End path helpers ---
# --- Loader utilities (merged from DBIO::Loader::Utils) ---
sub split_name {
require String::CamelCase;
my ($name, $v) = @_;
my $BY_NON_ALPHANUM = qr/[\W_]+/;
if ((not $v) || $v >= 8) {
return map split($BY_NON_ALPHANUM, $_), String::CamelCase::wordsplit($name);
}
my $BY_CASE_TRANSITION_V7 = qr/(?<=[[:lower:]\d])[\W_]*(?=[[:upper:]])|[\W_]+/;
my $is_camel_case = $name =~ /[[:upper:]]/ && $name =~ /[[:lower:]]/;
return split $is_camel_case ? $BY_CASE_TRANSITION_V7 : $BY_NON_ALPHANUM, $name;
}
sub dumper_squashed {
require Data::Dumper;
my $dd = Data::Dumper->new([]);
$dd->Terse(1)->Indent(0)->Useqq(1)->Deparse(1)->Quotekeys(0)->Sortkeys(1);
return $dd->Values([ $_[0] ])->Dump;
}
sub eval_package_without_redefine_warnings {
my ($pkg, $code) = @_;
local $SIG{__WARN__} = sigwarn_silencer(qr/^Subroutine \S+ redefined/);
my @delete_syms;
my $try_again = 1;
while ($try_again) {
eval $code;
if (my ($sym) = $@ =~ /^Subroutine (\S+) redefined/) {
( run in 1.033 second using v1.01-cache-2.11-cpan-995e09ba956 )