Mercurial > pub > Impl
view lib/IMPL/lang.pm @ 427:09e0086a82a7 ref20150831 tip
Merge
author | cin |
---|---|
date | Tue, 15 May 2018 00:51:33 +0300 |
parents | 7798345304bc |
children |
line wrap: on
line source
package IMPL::lang; use strict; use warnings; use parent qw(Exporter); use IMPL::clone qw(clone); use Scalar::Util qw(blessed); use POSIX; use Carp qw(carp); our @EXPORT = qw(&is &isclass &typeof &coarsen &coarsen_dt); our %EXPORT_TAGS = ( base => [ qw( &is &clone &isclass &typeof &ishash &isarray &isscalar &isglob ) ], compare => [ qw( &equals &equals_s &hashCompare ) ], hash => [ qw( &hashApply &hashMerge &hashDiff &hashCompare &hashParse &hashSave ) ] ); our @EXPORT_OK = keys %{ { map ( ( $_, 1 ), map ( @{$_}, values %EXPORT_TAGS ) ) } }; use IMPL::Const qw(:all); sub is { carp "A typename can't be undefined" unless $_[1]; blessed( $_[0] ) and $_[0]->isa( $_[1] ); } sub isclass { carp "A typename can't be undefined" unless $_[1]; local $@; eval { not ref $_[0] and $_[0]->isa( $_[1] ) }; } sub typeof(*) { blessed( $_[0] ); } sub isarray { not blessed( $_[0] ) and ref $_[0] eq 'ARRAY'; } sub ishash { not blessed( $_[0] ) and ref $_[0] eq 'HASH'; } sub isscalar { not blessed( $_[0] ) and ref $_[0] eq 'SCALAR'; } sub isglob { not blessed( $_[0] ) and ref $_[0] eq 'GLOB'; } sub coarsen { my ( $value, $resolution ) = @_; return $resolution ? ceil( $value / $resolution ) * $resolution : $value; } # datetime is DateTime object # resolution is DateTime::Duration object, the resulting time will be aligned to it sub coarsen_dt { my ( $datetime, $resolution ) = @_; return $datetime unless $resolution; my $date = $datetime->clone()->truncate( to => "day" ); return $date->add( minutes => coarsen( $datetime->subtract_datetime($date)->in_units('minutes'), $resolution->in_units('minutes') ) ); } sub equals { if ( defined $_[0] ) { return 0 if ( not defined $_[1] ); return $_[0] == $_[1]; } else { return 0 if defined $_[1]; return 1; } } sub equals_s { if ( defined $_[0] ) { return 0 if ( not defined $_[1] ); return $_[0] eq $_[1]; } else { return 0 if defined $_[1]; return 1; } } sub hashDiff { my ( $src, $dst ) = @_; $dst = $dst ? {%$dst} : {}; $src ||= {}; my %result; foreach my $key ( keys %$src ) { if ( exists $dst->{$key} ) { $result{"+$key"} = $dst->{$key} unless equals_s( $dst->{$key}, $src->{$key} ); delete $dst->{$key}; } else { $result{"-$key"} = 1; } } $result{"+$_"} = $dst->{$_} foreach keys %$dst; return \%result; } sub hashMerge { return hashApply( { %{ $_[0] || {} } }, $_[1] ); } sub hashApply { my ( $target, $diff ) = @_; return $target unless ref $diff eq 'HASH'; while ( my ( $key, $value ) = each %$diff ) { $key =~ /^(\+|-)?(.*)$/; my $op = $1 || '+'; $key = $2; if ( $op eq '-' ) { delete $target->{$key}; } else { $target->{$key} = $value; } } return $target; } sub hashCompare { my ( $l, $r, $cmp ) = @_; $cmp ||= \&equals_s; return 0 unless scalar keys %$l == scalar keys %$r; &$cmp( $l->{$_}, $r->{$_} ) || return 0 foreach keys %$l; return 1; } sub hashParse { my ( $s, $p, $d ) = @_; $p = $p ? qr/$p/ : qr/\n+/; $d = $d ? qr/$d/ : qr/\s*=\s*/; return { map split( $d, $_, 2 ), split( $p, $s ) }; } sub hashSave { my ( $hash, $p, $d ) = @_; return "" unless ref $hash eq 'HASH'; $p ||= "\n"; $d ||= " = "; return join( $p, map( join( $d, $_, $hash->{$_} ), keys %$hash ) ); } 1;