Class-Usul
view release on metacpan or search on metacpan
lib/Class/Usul/Functions.pm view on Meta::CPAN
for (my $i = 0, my $j = 0; $len > 0; $len -= 3, $i += 3) {
my $c1 = ord $x[ $i ]; my $c2 = $len > 1 ? ord $x[ $i + 1 ] : 0;
$y[ $j++ ] = $basis->[ $c1 >> 2 ];
$y[ $j++ ] = $basis->[ (($c1 & 0x3) << 4) | (($c2 & 0xF0) >> 4) ];
if ($len > 2) {
my $c3 = ord $x[ $i + 2 ];
$y[ $j++ ] = $basis->[ (($c2 & 0xF) << 2) | (($c3 & 0xC0) >> 6) ];
$y[ $j++ ] = $basis->[ $c3 & 0x3F ];
}
elsif ($len == 2) {
$y[ $j++ ] = $basis->[ ($c2 & 0xF) << 2 ];
$y[ $j++ ] = $basis->[ 64 ];
}
else { # len == 1
$y[ $j++ ] = $basis->[ 64 ];
$y[ $j++ ] = $basis->[ 64 ];
}
}
return join q(), @y;
}
sub bsonid (;$) {
return unpack 'H*', $_bsonid->( $_[ 0 ] );
}
sub bsonid_time ($) {
return unpack 'N', substr hex2str( $_[ 0 ] ), 0, 4;
}
sub bson64id (;$) {
return base64_encode_ns( $_bsonid->( 2 ) );
}
sub bson64id_time ($) {
return unpack 'N', substr base64_decode_ns( $_[ 0 ] ), 2, 4;
}
sub canonicalise ($;$) {
my ($base, $relpath) = @_;
$base = is_arrayref( $base ) ? catdir( @{ $base } ) : $base;
$relpath or return canonpath( untaint_path( $base ) );
my @relpath = is_arrayref( $relpath ) ? @{ $relpath } : $relpath;
my $path = canonpath( untaint_path( catdir( $base, @relpath ) ) );
-d $path and return $path;
return canonpath( untaint_path( catfile( $base, @relpath ) ) );
}
sub class2appdir ($) {
return lc distname( $_[ 0 ] );
}
sub classdir ($) {
return catdir( split m{ :: }mx, $_[ 0 ] // q() );
}
sub classfile ($) {
return catfile( split m{ :: }mx, $_[ 0 ].'.pm' );
}
sub create_token (;$) {
return digest( $_[ 0 ] // urandom() )->hexdigest;
}
sub create_token64 (;$) {
return digest( $_[ 0 ] // urandom() )->b64digest;
}
sub cwdp () {
return abs_path( curdir );
}
sub dash2under (;$) {
(my $v = $_[ 0 ] // q()) =~ s{ [\-] }{_}gmx; return $v;
}
sub data_dumper (;@) {
_data_dumper( @_ ); return 1;
}
sub digest ($) {
my $seed = shift; my ($candidate, $digest);
if ($digest_cache) { $digest = Digest->new( $digest_cache ) }
else {
for (DIGEST_ALGORITHMS) {
$candidate = $_; $digest = eval { Digest->new( $candidate ) } and last;
}
$digest or throw( 'Digest algorithm not found' );
$digest_cache = $candidate;
}
$digest->add( $seed );
return $digest;
}
sub distname ($) {
(my $v = $_[ 0 ] // q()) =~ s{ :: }{-}gmx; return $v;
}
#head2 downgrade
# $sv_pv = downgrade $sv_pvgv;
#Horrendous Perl bug is promoting C<PV> and C<PVMG> type scalars to
#C<PVGV>. Serializing these values with L<Storable> throws a can't
#store SCALAR items error. This functions copies the string value of
#the input scalar to the output scalar but resets the output scalar
#type to C<PV>
#sub downgrade (;$) {
# my $x = shift // q(); my ($y) = $x =~ m{ (.*) }msx; return $y;
#}
sub elapsed () {
return time - $BASETIME;
}
sub emit (;@) {
lib/Class/Usul/Functions.pm view on Meta::CPAN
sub find_apphome ($;$$) {
my ($appclass, $default, $extns) = @_; my $path;
# 0. Pass the directory in (short circuit the search)
$path = assert_directory $default and return $path;
my $app_pref = app_prefix $appclass;
my $appdir = class2appdir $appclass;
my $classdir = classdir $appclass;
my $env_pref = env_prefix $appclass;
my $my_home = File::HomeDir->my_home;
# 1a. Environment variable - for application directory
$path = assert_directory $ENV{ "${env_pref}_HOME" } and return $path;
# 1b. Environment variable - for config file
$path = $_get_env_var_for_conf->( "${env_pref}_CONFIG" ) and return $path;
# 2a. Users XDG_DATA_HOME env variable or XDG default share directory
$path = $ENV{ 'XDG_DATA_HOME' } // catdir( $my_home, '.local', 'share' );
$path = assert_directory catdir( $path, $appdir ) and return $path;
# 2b. Users home directory - dot file containing shell env variable
$path = $_get_file_var->( $my_home, $app_pref, $classdir ) and return $path;
$path = $_get_file_var->( $my_home, $appdir, $classdir ) and return $path;
# 2c. Users home directory - dot directory is apphome
$path = catdir( $my_home, ".${app_pref}" );
$path = assert_directory $path and return $path;
$path = catdir( $my_home, ".${appdir}" );
$path = assert_directory $path and return $path;
# 3. Well known path containing shell env file
$path = $_get_known_file_var->( $appdir, $classdir ) and return $path;
# 4. Default install prefix
$path = catdir( @{ PREFIX() }, $appdir, 'default', 'lib', $classdir );
$path = assert_directory $path and return $path;
# 5a. Config file found in @INC - underscore as separator
$path = $_find_cfg_in_inc->( $classdir, $app_pref, $extns ) and return $path;
# 5b. Config file found in @INC - dash as separator
$path = $_find_cfg_in_inc->( $classdir, $appdir, $extns ) and return $path;
# 6. Default to /tmp
return untaint_path( DEFAULT_CONFHOME );
}
sub find_source ($) {
my $class = shift; my $file = classfile( $class ); my $path;
for (@INC) {
$path = abs_path( catfile( $_, $file ) ) and -f $path and return $path;
}
return;
}
sub first_char ($) {
return substr $_[ 0 ], 0, 1;
}
sub fqdn (;$) {
my $x = shift // hostname; return (gethostbyname( $x ))[ 0 ];
}
sub fullname () {
my $v = (split m{ \s* , \s * }msx, (get_user()->gecos // q()))[ 0 ];
$v //= q(); $v =~ s{ [\&] }{}gmx; # Coz af25e158-d0c7-11e3-bdcb-31d9eda79835
return untaint_cmdline( $v );
}
sub get_cfgfiles ($;$$) {
my ($appclass, $dirs, $extns) = @_;
$appclass // throw( Unspecified, [ 'application class' ], level => 2 );
is_arrayref( $dirs ) or $dirs = [ $dirs || curdir ];
my $app_pref = app_prefix $appclass;
my $appdir = class2appdir $appclass;
my $env_pref = env_prefix $appclass;
my $suffix = $ENV{ "${env_pref}_CONFIG_LOCAL_SUFFIX" } // '_local';
my @paths = ();
for my $dir (@{ $dirs }) {
for my $extn (@{ $extns // [ supported_extensions() ] }) {
for my $path (map { $_catpath->( $dir, $_ ) } "${app_pref}${extn}",
"${appdir}${extn}", "${app_pref}${suffix}${extn}",
"${appdir}${suffix}${extn}") {
-f $path and push @paths, $path;
}
}
}
return \@paths;
}
sub get_user (;$) {
my $user = shift; is_win32() and return Class::Null->new;
defined $user and $user !~ m{ \A \d+ \z }mx and return getpwnam( $user );
return getpwuid( $user // $UID );
}
sub hex2str (;$) {
my @a = split m{}mx, shift // q(); my $str = q();
while (my ($x, $y) = splice @a, 0, 2) { $str .= pack 'C', hex "${x}${y}" }
return $str;
}
sub home2appldir ($) {
$_[ 0 ] or return; my $dir = io( $_[ 0 ] );
$dir = $dir->parent while ($dir ne $dir->parent and $dir !~ m{ lib \z }mx);
return $dir ne $dir->parent ? $dir->parent : undef;
}
sub io (;@) {
return File::DataClass::IO->new( @_ );
}
sub is_arrayref (;$) {
return $_[ 0 ] && ref $_[ 0 ] eq 'ARRAY' ? 1 : 0;
}
sub is_coderef (;$) {
return $_[ 0 ] && ref $_[ 0 ] eq 'CODE' ? 1 : 0;
}
sub is_hashref (;$) {
return $_[ 0 ] && ref $_[ 0 ] eq 'HASH' ? 1 : 0;
}
sub is_member (;@) {
my ($candidate, @args) = @_; $candidate or return;
is_arrayref $args[ 0 ] and @args = @{ $args[ 0 ] };
return (first { $_ eq $candidate } @args) ? 1 : 0;
}
sub is_ntfs () {
return is_win32() || lc $OSNAME eq 'cygwin' ? 1 : 0;
}
sub is_win32 () {
return lc $OSNAME eq 'mswin32' ? 1 : 0;
}
sub list_attr_of ($;@) {
my ($obj, @except) = @_; my $class = blessed $obj;
ensure_class_loaded( 'Pod::Eventual::Simple' );
is_member 'new', @except or push @except, 'new';
return map { my $attr = $_->[0]; [ @{ $_ }, $obj->$attr ] }
map { [ $_->[1], $_->[0], $_get_pod_content_for_attr->( @{ $_ } ) ] }
grep { $_->[0] ne 'Moo::Object' and not is_member $_->[1], @except }
map { m{ \A (.+) \:\: ([^:]+) \z }mx; [ $1, $2 ] }
@{ Class::Inspector->methods( $class, 'full', 'public' ) };
}
lib/Class/Usul/Functions.pm view on Meta::CPAN
sub logname (;$) { # Deprecated use loginid
return untaint_cmdline( $ENV{USER} || $ENV{LOGNAME} || loginid( $_[ 0 ] ) );
}
sub merge_attributes ($@) {
my ($dest, @args) = @_;
my $attr = is_arrayref( $args[ -1 ] ) ? pop @args : [];
for my $k (grep { not exists $dest->{ $_ } or not defined $dest->{ $_ } }
@{ $attr }) {
my $i = 0; my $v;
while (not defined $v and defined( my $src = $args[ $i++ ] )) {
my $class = blessed $src;
$v = $class ? ($src->can( $k ) ? $src->$k() : undef) : $src->{ $k };
}
defined $v and $dest->{ $k } = $v;
}
return $dest;
}
sub my_prefix (;$) {
return split_on__( basename( $_[ 0 ] // q(), PERL_EXTNS ) );
}
sub nonblocking_write_pipe_pair () {
my ($r, $w); pipe $r, $w or throw( 'No pipe' );
fcntl $w, F_SETFL, O_NONBLOCK; $w->autoflush( 1 );
binmode $r; binmode $w;
return [ $r, $w ];
}
sub ns_environment ($$;$) {
my ($class, $k, $v) = @_; $k = (env_prefix $class).'_'.(uc $k);
return defined $v ? $ENV{ $k } = $v : $ENV{ $k };
}
sub pad ($$;$$) {
my ($v, $wanted, $str, $direction) = @_; my $len = $wanted - length $v;
$len > 0 or return $v; (defined $str and length $str) or $str = q( );
my $pad = substr( $str x $len, 0, $len );
(not $direction or $direction eq 'right') and return $v.$pad;
$direction eq 'left' and return $pad.$v;
return (substr $pad, 0, int( (length $pad) / 2 )).$v
.(substr $pad, 0, int( 0.99999999 + (length $pad) / 2 ));
}
sub prefix2class (;$) {
return join '::', map { ucfirst } split m{ - }mx, my_prefix( $_[ 0 ] );
}
sub socket_pair () {
my $rdr = gensym; my $wtr = gensym;
socketpair( $rdr, $wtr, AF_UNIX, SOCK_STREAM, PF_UNSPEC )
or throw( $EXTENDED_OS_ERROR );
shutdown ( $rdr, 1 ); # No more writing for reader
shutdown ( $wtr, 0 ); # No more reading for writer
return [ $rdr, $wtr ];
}
sub split_on__ (;$$) {
return (split m{ _ }mx, $_[ 0 ] // q())[ $_[ 1 ] // 0 ];
}
sub split_on_dash (;$$) {
return (split m{ \- }mx, $_[ 0 ] // q())[ $_[ 1 ] // 0 ];
}
sub squeeze (;$) {
(my $v = $_[ 0 ] // q()) =~ s{ \s+ }{ }gmx; return $v;
}
sub strip_leader (;$) {
(my $v = $_[ 0 ] // q()) =~ s{ \A [^:]+ [:] \s+ }{}msx; return $v;
}
sub sub_name (;$) {
my $frame = 1 + ($_[ 0 ] // 0);
return (split m{ :: }mx, ((caller $frame)[ 3 ]) // 'main')[ -1 ];
}
sub symlink (;$$$) {
my ($from, $to, $base) = @_;
defined $base and not CORE::length $base and $base = File::Spec->rootdir;
$from or throw( Unspecified, [ 'path from' ] );
$from = io( $from )->absolute( $base );
$from->exists or throw( PathNotFound, [ "${from}" ] );
$to or throw( Unspecified, [ 'path to' ] );
$to = io( $to )->absolute( $base ); $to->is_link and $to->unlink;
$to->exists and throw( PathAlreadyExists, [ "${to}" ] );
CORE::symlink "${from}", "${to}"
or throw( 'Symlink from [_1] to [_2] failed: [_3]',
[ "${from}", "${to}", $OS_ERROR ] );
return "Symlinked ${from} to ${to}";
}
sub thread_id () {
return exists $INC{ 'threads.pm' } ? threads->tid() : 0;
}
sub throw (;@) {
EXCEPTION_CLASS->throw( @_ );
}
sub throw_on_error (;@) {
EXCEPTION_CLASS->throw_on_error( @_ );
}
sub trim (;$$) {
my $chs = $_[ 1 ] // " \t"; (my $v = $_[ 0 ] // q()) =~ s{ \A [$chs]+ }{}mx;
chomp $v; $v =~ s{ [$chs]+ \z }{}mx; return $v;
}
sub unescape_TT (;$$) {
my $v = defined $_[ 0 ] ? $_[ 0 ] : q();
my $fl = ($_[ 1 ] && $_[ 1 ]->[ 0 ]) || '<';
my $fr = ($_[ 1 ] && $_[ 1 ]->[ 1 ]) || '>';
$v =~ s{ ${fl}\% }{[%}gmx; $v =~ s{ \%${fr} }{%]}gmx;
return $v;
}
sub untaint_cmdline (;$) {
return untaint_string( UNTAINT_CMDLINE, $_[ 0 ] );
}
sub untaint_identifier (;$) {
return untaint_string( UNTAINT_IDENTIFIER, $_[ 0 ] );
}
sub untaint_path (;$) {
return untaint_string( UNTAINT_PATH, $_[ 0 ] );
}
sub untaint_string ($;$) {
my ($regex, $string) = @_;
( run in 0.642 second using v1.01-cache-2.11-cpan-71847e10f99 )