CONTRIBUTING000644001750001750 5213601673061 14174 0ustar00taitai000000000000Type-Tiny-1.008001See lib/Type/Tiny/Manual/Contributing.pod COPYRIGHT000644001750001750 3670613601673167 13743 0ustar00taitai000000000000Type-Tiny-1.008001Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: Type-Tiny Upstream-Contact: Toby Inkster (TOBYINK) Source: http://typetiny.toby.ink/ Files: lib/Devel/TypeTiny/Perl56Compat.pm lib/Devel/TypeTiny/Perl58Compat.pm lib/Error/TypeTiny.pm lib/Error/TypeTiny/Assertion.pm lib/Error/TypeTiny/Compilation.pm lib/Error/TypeTiny/WrongNumberOfParameters.pm lib/Eval/TypeTiny.pm lib/Reply/Plugin/TypeTiny.pm lib/Test/TypeTiny.pm lib/Type/Coercion.pm lib/Type/Coercion/FromMoose.pm lib/Type/Coercion/Union.pm lib/Type/Library.pm lib/Type/Params.pm lib/Type/Parser.pm lib/Type/Registry.pm lib/Type/Tiny.pm lib/Type/Tiny/Class.pm lib/Type/Tiny/Duck.pm lib/Type/Tiny/Enum.pm lib/Type/Tiny/Intersection.pm lib/Type/Tiny/Manual.pod lib/Type/Tiny/Manual/AllTypes.pod lib/Type/Tiny/Manual/Coercions.pod lib/Type/Tiny/Manual/Contributing.pod lib/Type/Tiny/Manual/Installation.pod lib/Type/Tiny/Manual/Libraries.pod lib/Type/Tiny/Manual/NonOO.pod lib/Type/Tiny/Manual/Optimization.pod lib/Type/Tiny/Manual/Params.pod lib/Type/Tiny/Manual/Policies.pod lib/Type/Tiny/Manual/UsingWithClassTiny.pod lib/Type/Tiny/Manual/UsingWithMoo.pod lib/Type/Tiny/Manual/UsingWithMoo2.pod lib/Type/Tiny/Manual/UsingWithMoo3.pod lib/Type/Tiny/Manual/UsingWithMoose.pod lib/Type/Tiny/Manual/UsingWithMouse.pod lib/Type/Tiny/Manual/UsingWithOther.pod lib/Type/Tiny/Manual/UsingWithTestMore.pod lib/Type/Tiny/Role.pm lib/Type/Tiny/Union.pm lib/Type/Utils.pm lib/Types/Common/Numeric.pm lib/Types/Common/String.pm lib/Types/Standard.pm lib/Types/Standard/ArrayRef.pm lib/Types/Standard/Dict.pm lib/Types/Standard/HashRef.pm lib/Types/Standard/Map.pm lib/Types/Standard/ScalarRef.pm lib/Types/Standard/StrMatch.pm lib/Types/Standard/Tied.pm lib/Types/Standard/Tuple.pm lib/Types/TypeTiny.pm t/00-begin.t t/01-compile.t t/02-api.t t/03-leak.t t/20-unit/Error-TypeTiny-Assertion/basic.t t/20-unit/Error-TypeTiny-Compilation/basic.t t/20-unit/Error-TypeTiny-WrongNumberOfParameters/basic.t t/20-unit/Error-TypeTiny/basic.t t/20-unit/Error-TypeTiny/stacktrace.t t/20-unit/Eval-TypeTiny/aliases-devel-lexalias.t t/20-unit/Eval-TypeTiny/aliases-native.t t/20-unit/Eval-TypeTiny/aliases-padwalker.t t/20-unit/Eval-TypeTiny/aliases-tie.t t/20-unit/Eval-TypeTiny/basic.t t/20-unit/Eval-TypeTiny/lexical-subs.t t/20-unit/Type-Coercion-Union/basic.t t/20-unit/Type-Coercion/basic.t t/20-unit/Type-Coercion/frozen.t t/20-unit/Type-Coercion/inlining.t t/20-unit/Type-Coercion/parameterized.t t/20-unit/Type-Library/assert.t t/20-unit/Type-Library/errors.t t/20-unit/Type-Library/inheritance.t t/20-unit/Type-Library/is.t t/20-unit/Type-Library/to.t t/20-unit/Type-Library/types.t t/20-unit/Type-Params/badsigs.t t/20-unit/Type-Params/carping.t t/20-unit/Type-Params/coerce.t t/20-unit/Type-Params/compile-named-bless.t t/20-unit/Type-Params/compile-named.t t/20-unit/Type-Params/hashorder.t t/20-unit/Type-Params/methods.t t/20-unit/Type-Params/mixednamed.t t/20-unit/Type-Params/multisig.t t/20-unit/Type-Params/named.t t/20-unit/Type-Params/noninline.t t/20-unit/Type-Params/optional.t t/20-unit/Type-Params/positional.t t/20-unit/Type-Params/slurpy.t t/20-unit/Type-Parser/basic.t t/20-unit/Type-Parser/moosextypes.t t/20-unit/Type-Registry/basic.t t/20-unit/Type-Registry/moosextypes.t t/20-unit/Type-Registry/mousextypes.t t/20-unit/Type-Tiny-Class/basic.t t/20-unit/Type-Tiny-Class/errors.t t/20-unit/Type-Tiny-Class/plus-constructors.t t/20-unit/Type-Tiny-Duck/basic.t t/20-unit/Type-Tiny-Enum/basic.t t/20-unit/Type-Tiny-Intersection/basic.t t/20-unit/Type-Tiny-Role/basic.t t/20-unit/Type-Tiny-Role/errors.t t/20-unit/Type-Tiny-Union/basic.t t/20-unit/Type-Tiny-Union/relationships.t t/20-unit/Type-Tiny/arithmetic.t t/20-unit/Type-Tiny/basic.t t/20-unit/Type-Tiny/coercion-modifiers.t t/20-unit/Type-Tiny/parameterization.t t/20-unit/Type-Tiny/syntax.t t/20-unit/Type-Utils/dwim-moose.t t/20-unit/Type-Utils/dwim-mouse.t t/20-unit/Type-Utils/match-on-type.t t/20-unit/Types-Standard/basic.t t/20-unit/Types-Standard/deep-coercions.t t/20-unit/Types-Standard/mxtmlb-alike.t t/20-unit/Types-Standard/optlist.t t/20-unit/Types-Standard/overload.t t/20-unit/Types-Standard/strmatch.t t/20-unit/Types-Standard/structured.t t/20-unit/Types-Standard/tied.t t/30-integration/Exporter-Tiny/basic.t t/30-integration/Exporter-Tiny/installer.t t/30-integration/Exporter-Tiny/role-conflict.t t/30-integration/Function-Parameters/basic.t t/30-integration/Kavorka/80returntype.t t/30-integration/Moo/basic.t t/30-integration/Moo/coercion.t t/30-integration/Moo/exceptions.t t/30-integration/Moo/inflation.t t/30-integration/Moo/inflation2.t t/30-integration/Moops/basic.t t/30-integration/Moops/library-keyword.t t/30-integration/Moose/accept-moose-types.t t/30-integration/Moose/basic.t t/30-integration/Moose/coercion-more.t t/30-integration/Moose/coercion.t t/30-integration/Moose/native-attribute-traits.t t/30-integration/MooseX-Types/basic.t t/30-integration/MooseX-Types/extending.t t/30-integration/MooseX-Types/more.t t/30-integration/Mouse/basic.t t/30-integration/Mouse/coercion.t t/30-integration/MouseX-Types/basic.t t/30-integration/MouseX-Types/extending.t t/30-integration/Object-Accessor/basic.t t/30-integration/Sub-Quote/basic.t t/30-integration/Validation-Class-Simple/archaic.t t/30-integration/Validation-Class-Simple/basic.t t/lib/BiggerLib.pm t/lib/DemoLib.pm Copyright: This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. License: GPL-1.0+ or Artistic-1.0 Files: lib/Type/Tiny/ConstrainedObject.pm t/20-unit/Type-Library/import-params.t t/20-unit/Type-Params/named-to-list.t t/20-unit/Type-Params/wrap.t t/20-unit/Type-Tiny-ConstrainedObject/basic.t t/20-unit/Type-Tiny-Intersection/cmp.t t/20-unit/Type-Tiny-Intersection/constrainedobject.t t/20-unit/Type-Tiny-Union/constrainedobject.t t/20-unit/Type-Tiny/inline-assert.t t/20-unit/Types-Standard/strmatch-allow-callbacks.t t/20-unit/Types-Standard/strmatch-avoid-callbacks.t t/21-types/Any.t t/21-types/ArrayLike.t t/21-types/ArrayRef.t t/21-types/Bool.t t/21-types/ClassName.t t/21-types/CodeLike.t t/21-types/CodeRef.t t/21-types/ConsumerOf.t t/21-types/CycleTuple.t t/21-types/Defined.t t/21-types/Dict.t t/21-types/Enum.t t/21-types/FileHandle.t t/21-types/GlobRef.t t/21-types/HasMethods.t t/21-types/HashLike.t t/21-types/HashRef.t t/21-types/InstanceOf.t t/21-types/Int.t t/21-types/IntRange.t t/21-types/Item.t t/21-types/LaxNum.t t/21-types/LowerCaseSimpleStr.t t/21-types/LowerCaseStr.t t/21-types/Map.t t/21-types/Maybe.t t/21-types/NegativeInt.t t/21-types/NegativeNum.t t/21-types/NegativeOrZeroInt.t t/21-types/NegativeOrZeroNum.t t/21-types/NonEmptySimpleStr.t t/21-types/NonEmptyStr.t t/21-types/Num.t t/21-types/NumRange.t t/21-types/NumericCode.t t/21-types/Object.t t/21-types/OptList.t t/21-types/Optional.t t/21-types/Overload.t t/21-types/Password.t t/21-types/PositiveInt.t t/21-types/PositiveNum.t t/21-types/PositiveOrZeroInt.t t/21-types/PositiveOrZeroNum.t t/21-types/Ref.t t/21-types/RegexpRef.t t/21-types/RoleName.t t/21-types/ScalarRef.t t/21-types/SimpleStr.t t/21-types/SingleDigit.t t/21-types/Str.t t/21-types/StrLength.t t/21-types/StrMatch.t t/21-types/StrictNum.t t/21-types/StringLike.t t/21-types/StrongPassword.t t/21-types/Tied.t t/21-types/Tuple.t t/21-types/TypeTiny.t t/21-types/Undef.t t/21-types/UpperCaseSimpleStr.t t/21-types/UpperCaseStr.t t/21-types/Value.t t/30-integration/Moose/parameterized.t t/30-integration/Mouse/parameterized.t t/30-integration/Specio/basic.t t/30-integration/Specio/library.t t/30-integration/Types-ReadOnly/basic.t t/40-regression/rt102748.t t/40-regression/rt104154.t t/40-regression/rt121763.t t/40-regression/rt129729.t t/40-regression/rt130823.t t/98-param-eg-from-docs.t Copyright: This software is copyright (c) 2019 by Toby Inkster. License: GPL-1.0+ or Artistic-1.0 Files: t/20-unit/Devel-TypeTiny-Perl56Compat/basic.t t/20-unit/Devel-TypeTiny-Perl58Compat/basic.t t/20-unit/Test-TypeTiny/basic.t t/20-unit/Test-TypeTiny/extended.t t/20-unit/Test-TypeTiny/matchfor.t t/20-unit/Type-Coercion-FromMoose/basic.t t/20-unit/Type-Coercion-FromMoose/errors.t t/20-unit/Type-Coercion/esoteric.t t/20-unit/Type-Coercion/smartmatch.t t/20-unit/Type-Coercion/typetiny-constructor.t t/20-unit/Type-Registry/automagic.t t/20-unit/Type-Registry/methods.t t/20-unit/Type-Tiny-Duck/errors.t t/20-unit/Type-Tiny-Enum/errors.t t/20-unit/Type-Tiny-Intersection/errors.t t/20-unit/Type-Tiny-Union/errors.t t/20-unit/Type-Tiny/esoteric.t t/20-unit/Type-Tiny/my-methods.t t/20-unit/Type-Tiny/shortcuts.t t/20-unit/Type-Tiny/smartmatch.t t/20-unit/Type-Tiny/to-moose.t t/20-unit/Type-Tiny/to-mouse.t t/20-unit/Type-Utils/classifier.t t/20-unit/Type-Utils/dwim-both.t t/20-unit/Type-Utils/warnings.t t/20-unit/Types-Standard/lockdown.t t/20-unit/Types-TypeTiny/basic.t t/20-unit/Types-TypeTiny/coercion.t t/20-unit/Types-TypeTiny/meta.t t/20-unit/Types-TypeTiny/moosemouse.t t/30-integration/Kavorka/basic.t t/30-integration/Moo/coercion-inlining-avoidance.t t/30-integration/Moose/inflate-then-inline.t t/30-integration/Return-Type/basic.t t/30-integration/Sub-Quote/unquote-coercions.t t/30-integration/Sub-Quote/unquote-constraints.t t/30-integration/Switcheroo/basic.t t/30-integration/Type-Tie/basic.t t/30-integration/match-simple/basic.t Copyright: This software is copyright (c) 2014, 2017-2019 by Toby Inkster. License: GPL-1.0+ or Artistic-1.0 Files: t/20-unit/Type-Library/deprecation.t t/20-unit/Type-Params/compile-named-oo.t t/20-unit/Type-Params/defaults.t t/20-unit/Type-Tiny-Duck/cmp.t t/20-unit/Type-Tiny-Enum/cmp.t t/20-unit/Type-Tiny/cmp.t t/20-unit/Type-Tiny/deprecation.t t/20-unit/Types-Common-Numeric/ranges.t t/20-unit/Types-Common-String/strlength.t t/20-unit/Types-Standard/arrayreflength.t t/20-unit/Types-Standard/filehandle.t t/20-unit/Types-TypeTiny/progressiveexporter.t t/30-integration/Sub-Quote/delayed-quoting.t Copyright: This software is copyright (c) 2018-2019 by Toby Inkster. License: GPL-1.0+ or Artistic-1.0 Files: INSTALL inc/archaic/Test/Builder/Module.pm inc/archaic/Test/Builder/Tester.pm inc/archaic/Test/Builder/Tester/Color.pm t/README t/TODO t/mk-test-manifest.pl t/not-covered.pl Copyright: Unknown License: Unknown Files: examples/benchmarking/benchmark-constraints.pl examples/benchmarking/benchmark-named-param-validation.pl examples/benchmarking/versus-scalar-validation.pl examples/datetime-coercions.pl examples/nonempty.pl examples/page-numbers.pl Copyright: Copyright 2017 Toby Inkster. License: GPL-1.0+ or Artistic-1.0 Files: t/40-regression/rt92571-2.t t/40-regression/rt92571.t t/40-regression/rt92591.t t/40-regression/rt94196.t t/40-regression/rt97684.t Copyright: This software is copyright (c) 2014, 2017-2019 by Diab Jerius. License: GPL-1.0+ or Artistic-1.0 Files: CREDITS Changes LICENSE Makefile.PL README Copyright: Copyright 1970 Toby Inkster. License: GPL-1.0+ or Artistic-1.0 Files: CONTRIBUTING META.json META.yml NEWS doap.ttl Copyright: Copyright 2019 Toby Inkster. License: GPL-1.0+ or Artistic-1.0 Files: lib/Types/Standard/CycleTuple.pm t/20-unit/Type-Tiny-_HalfOp/double-union.t t/20-unit/Type-Tiny/constraint-strings.t t/20-unit/Types-Standard/cycletuple.t t/40-regression/gh14.t Copyright: This software is copyright (c) 2017-2019 by Toby Inkster. License: GPL-1.0+ or Artistic-1.0 Files: t/20-unit/Types-Common-Numeric/basic.t t/20-unit/Types-Common-String/basic.t t/20-unit/Types-Common-String/coerce.t t/20-unit/Types-Common-String/unicode.t Copyright: This software is copyright (c) 2013-2014, 2017-2019 by Matt S Trout - mst (at) shadowcatsystems.co.uk (L). License: GPL-1.0+ or Artistic-1.0 Files: lib/Type/Tiny/_HalfOp.pm t/20-unit/Type-Tiny-_HalfOp/overload-precedence.t t/40-regression/73f51e2d.pl t/40-regression/73f51e2d.t Copyright: This software is copyright (c) 2014, 2017-2019 by Graham Knop. License: GPL-1.0+ or Artistic-1.0 Files: t/40-regression/rt85911.t t/40-regression/rt86004.t t/40-regression/rt90096-2.t Copyright: This software is copyright (c) 2013-2014, 2017-2019 by Diab Jerius. License: GPL-1.0+ or Artistic-1.0 Files: inc/archaic/Test/More.pm inc/archaic/Test/Simple.pm Copyright: Copyright 2001-2008 by Michael G Schwern . License: GPL-1.0+ or Artistic-1.0 Files: t/40-regression/rt86233.t t/40-regression/rt86239.t Copyright: This software is copyright (c) 2013-2014, 2017-2019 by Vyacheslav Matyukhin. License: GPL-1.0+ or Artistic-1.0 Files: COPYRIGHT SIGNATURE Copyright: None License: public-domain Files: inc/archaic/Test/Builder/IO/Scalar.pm Copyright: Copyright (c) 1996 by Eryq. All rights reserved. Copyright (c) 1999,2001 by ZeeGee Software Inc. All rights reserved. License: GPL-1.0+ or Artistic-1.0 Files: examples/benchmarking/benchmark-coercions.pl Copyright: This software is copyright (c) 2013-2014, 2017 by Toby Inkster. License: GPL-1.0+ or Artistic-1.0 Files: t/40-regression/gh1.t Copyright: This software is copyright (c) 2013-2014, 2017-2019 by Richard Simões. License: GPL-1.0+ or Artistic-1.0 Files: t/30-integration/Class-InsideOut/basic.t Copyright: This software is copyright (c) 2013-2014, 2017-2019 by David Golden, Toby Inkster. License: GPL-1.0+ or Artistic-1.0 Files: t/40-regression/rt90096.t Copyright: This software is copyright (c) 2013-2014, 2017-2019 by Samuel Kaufman. License: GPL-1.0+ or Artistic-1.0 Files: inc/Test/Fatal.pm Copyright: Copyright 2014 Ricardo Signes. License: GPL-1.0+ or Artistic-1.0 Files: t/40-regression/rt125765.t Copyright: This software is copyright (c) 2018-2019 by KB Jørgensen. License: GPL-1.0+ or Artistic-1.0 Files: t/40-regression/ttxs-gh1.t Copyright: This software is copyright (c) 2014, 2017-2019 by Jed Lund. License: GPL-1.0+ or Artistic-1.0 Files: t/20-unit/Type-Params/multisig-custom-message.t Copyright: This software is copyright (c) 2018-2019 by Benct Philip Jonsson. License: GPL-1.0+ or Artistic-1.0 Files: dist.ini Copyright: Copyright 2014 Toby Inkster. License: GPL-1.0+ or Artistic-1.0 Files: inc/Test/Requires.pm Copyright: Copyright 2019 MATSUNO Tokuhiro. License: GPL-1.0+ or Artistic-1.0 Files: inc/Try/Tiny.pm Copyright: Copyright 2014 Yuval Kogman. License: GPL-1.0+ or Artistic-1.0 Files: examples/benchmarking/benchmark-param-validation.pl Copyright: Copyright 2018 Toby Inkster. License: GPL-1.0+ or Artistic-1.0 Files: t/99-moose-std-types-test.t Copyright: This software is copyright (c) 2013-2014, 2017-2019 by Infinity Interactive, Inc.. License: GPL-1.0+ or Artistic-1.0 Files: inc/archaic/Test/Builder.pm Copyright: Copyright 2002-2008 by chromatic and. License: GPL-1.0+ or Artistic-1.0 Files: t/30-integration/MooseX-Getopt/coercion.t Copyright: This software is copyright (c) 2014, 2017-2019 by Alexander Hartmaier. License: GPL-1.0+ or Artistic-1.0 Files: t/40-regression/rt98113.t Copyright: This software is copyright (c) 2014, 2017-2019 by Dagfinn Ilmari MannsÃ¥ker. License: GPL-1.0+ or Artistic-1.0 Files: t/40-regression/rt125132.t Copyright: This software is copyright (c) 2018-2019 by Marc Ballarin. License: GPL-1.0+ or Artistic-1.0 License: Artistic-1.0 This software is Copyright (c) 2019 by the copyright holder(s). This is free software, licensed under: The Artistic License 1.0 License: GPL-1.0 This software is Copyright (c) 2019 by the copyright holder(s). This is free software, licensed under: The GNU General Public License, Version 1, February 1989 CREDITS000644001750001750 400213601673064 13424 0ustar00taitai000000000000Type-Tiny-1.008001Maintainer: - Toby Inkster (TOBYINK) Contributor: - Alexander Hartmaier (ABRAXXA) - Alexandr Ciornii - Benct Philip Jonsson - Dagfinn Ilmari Mannsåker (ILMARI) - David Steinbrunner - Denis Ibaev - Diab Jerius (DJERIUS) - Gianni Ceccarelli (DAKKAR) - Graham Knop (HAARG) - Jonas B Nielsen (JONASBN) - Karen Etheridge (ETHER) - Lucas Buchala (LSBUCHALA) - Mark Stosberg (MARKSTOS) - Nelo Onyiah - Peter Flanigan (PJFL) - Peter Karman (KARMAN) - Peter Valdemar Mørch - Philippe Bruhat (BOOK) - Pierre Masci - Robert Rothenberg (RRWO) - Samuel Kaufman (SKAUFMAN) - Thomas Sibley (TSIBLEY) - Vyacheslav Matyukhin (MMCLERIC) - Zoffix Znet Thanks: - Andreas J König (ANDK) - André Walker - Aran Clary Deltac (BLUEFEET) - Brendan Byrd (BBYRD) - Caleb Cushing (XENO) - Daniel Schröer (SCHROEER) - David Golden (DAGOLDEN) - Ivanov Anton - JPLINDSTROM - Jason R Mash (JRMASH) - Jon Portnoy (AVENJ) - KB Jørgensen - Kevin Dawson (BOWTIE) - Marcel Montes (SPICEMAN) - Marcel Timmerman (MARTIMM) - Matt Phillips (MATTP) - Matt S Trout (MSTROUT) - Michael G Schwern (MSCHWERN) - OMEGA - Peter Rabbitson (RIBASUSHI) - Richard Simões (RSIMOES) - Shlomi Fish (SHLOMIF) - Slaven Rezić (SREZIC) - Steven Lee (STEVENL) - Tim Bunce (TIMB) Changes000644001750001750 24540613601673064 13756 0ustar00taitai000000000000Type-Tiny-1.008001Type-Tiny ========= Created: 2013-03-23 Home page: Home page: Bug tracker: Maintainer: Toby Inkster (TOBYINK) 1.008001 2019-12-28 - Types::TypeTiny honours $Type::Tiny::AvoidCallbacks. - Types::TypeTiny now better mocks Type::Library, offering is_* and assert_* functions for export. - Use improved inline_assert when building the coderef for &{$type} overloading. 1.008000 2019-12-11 [ Packaging ] - Repackage as stable. 1.007_015 2019-12-10 [ Documentation ] - Minor formatting changes. - No longer suggest that Type::Tiny::Manual needs rewriting in Contributing.pod. 1.007_014 2019-12-10 [ Documentation ] - Mostly formatting changes. 1.007_013 2019-12-10 [ Documentation ] - Add links to homepage in pod. [ Packaging ] - Rebuild with newer RDF::DOAP. 1.007_012 2019-12-10 [ Bug Fixes ] - Fix tr/// stuff on $Type::Tiny::VERSION. [ Documentation ] - Minor tweaks to Type::Tiny::Manual. [ Packaging ] - Metadata updates. [ Other ] - Updated: Type::Tiny will stop trying to use very old versions of Type::Tiny::XS. (It already recommended newer versions in META.json.) 1.007_011 2019-12-09 [ Documentation ] - Make the Moo parts of the manual use less Moo-specific syntax, so it is more applicable to Moose and Mouse. - Rewrite Type::Tiny::Manual::Coercions. 1.007_010 2019-12-08 [ Bug Fixes ] - Avoid undef warnings from Type::Tiny::_failed_check when the type has become undefined before the error message can be generated. [ Test Suite ] - Minor improvements to the test suite. 1.007_009 2019-12-06 [ Documentation ] - Document some undocumented files in the test suite. [ Other ] - Obscure changes to Error::TypeTiny::Assertion. - Type::Tiny's inline_assert method has been overhauled. 1.007_008 2019-12-05 [ Documentation ] - Expand per-type tests of bundled type libraries. - More work on the Type::Tiny manual. 1.007_007 2019-12-03 [ Documentation ] - Expand per-type tests of bundled type libraries. - More work on the Type::Tiny manual. 1.007_006 2019-12-02 [ Documentation ] - Expand per-type tests of bundled type libraries. 1.007_005 2019-12-01 [ Bug Fixes ] - Fixes for inlining Tuples which have a combination of Optional and slurpy slots. [ Documentation ] - Expand per-type tests of bundled type libraries. [ Other ] - Improvements to deep coercions for Tuples. 1.007_004 2019-11-30 [ Bug Fixes ] - Fixes for some edge cases in the overidden `can` method on old Perl 5.8.x versions for types with the secret `is_object` parameter set to true. (There were problems in 5.8.1 but 5.8.9 was okay; not sure the exact version where the delta was that affected it. Either way, fixed now.) [ Documentation ] - Expand per-type tests of bundled type libraries. [ Test Suite ] - Clean up some warnings and stuff from test output. [ Other ] - Improvements to $AvoidCallbacks support for Types::Standard::Maybe. 1.007_003 2019-11-27 [ Documentation ] - Expand per-type tests of bundled type libraries. - More work on the Type::Tiny manual. jplindstrom++ 1.007_002 2019-11-26 [ Documentation ] - Expand per-type tests of bundled type libraries. - Fix various documentation typos. - Improve Type::Params SYNOPSIS. - Improve Type::Tiny SYNOPSIS. - More work on the Type::Tiny manual. - Move CONTRIBUTING.pod into the manual. - Types::Standard now has a SYNOPSIS. [ Other ] - (~Types::Standard::Any)->name is now 'None' - Control over whether types are allowed to make callbacks in inlined code is now via a package variable instead of an environment variable and can be toggled at runtime. 1.007_001 2019-11-23 [ Bug Fixes ] - ClassName/RoleName no longer accepts a glob. - Fix the 'my variable $base masks earlier declaration' warning caused by IntRange/NumRange. - The `Tied` type no longer assumes that any reference which isn't a HASH or ARRAY must be a SCALAR. [ Documentation ] - Add a huge amount of tests for the built-in type constraints, intended as documentation as well as tests. - Complete rewrite of the Type::Tiny manual. [ Other ] - Added: The `extends` function is now able to extend Specio::Exporter libraries. - Added: Type::Params now has `wrap_subs` and `wrap_methods` functions. - Returning a list of strings from an inlining coderef is now officially supported and no longer experimental. - Type::Tiny::XS integration is now officially supported and no longer experimental. 1.007_000 2019-11-17 [ Bug Fixes ] - Strip underscores in version numbers for dev releases. Fixes RT#125839. - Type::Params will now keep a reference to all type constraints passed to it; this may use more memory in some cases, but will improve exceptions thrown. Fixes RT#121763. - Type::Tiny better mimics the Moose::Meta::TypeConstraint::Parameterized API, adding `parameterized_from` and `has_parameterized_from` methods. Fixes RT#114915. - Type::Tiny::Enum will now avoid triggering a Type::Tiny::XS bug involving hyphens in strings. Fixes RT#129729. - When extending a MooseX::Types library, be more careful checking to see if types have coercions, because a Moose::Meta::TypeCoercion object may be an empty list of coercions. Fixes RT#102748. [ Test Suite ] - Add a test that Specio type constraints can be converted to Type::Tiny types, and inlining works. - Bundle some tests for Types::ReadOnly because it does interesting stuff with coercions and parameterizable types. - Bundle test from RT#104154, which turned out to not be a bug. - More tests for extending MooseX::Types libraries. [ Packaging ] - Dropped the TODO file from the repo and distribution because it was mostly out of date. Use RT instead. [ Other ] - Added: Many type constraints now support `stringifies_to`, `numifies_to`, and `with_attribute_values` methods. Type::Tiny 1.006000 accidentally included an undocumented early implementation of these with some differences. - Added: Provide a control over whether types are allowed to make callbacks in inlined code. - Added: Type::Tiny::ConstrainedObject exists as a superclass for Type::Tiny::Class, Type::Tiny::Role, and Type::Tiny::Duck. - Added: When Types::TypesTiny::to_TypeTiny converts a Moose/Mouse type to a Type::Tiny type, the returned type will now be parameterizable if they original type was parameterizable. - Added: When importing type constraints from non-Moose/non-Mouse blessed type constraint systems (Specio, Types::Nano, others?), support inlining. - Smarter caching and reuse of parameterized types. 1.006000 2019-11-12 [ Documentation ] - Links to Type::Tiny on GitHub/Travis/AppVeyor/Coveralls in Type::Tiny pod. - Minor correction to POD header for Type::Params Jonas B Nielsen++ - Types::Standard documentation fix. Lucas Buchala++ [ Test Suite ] - Improve test coverage. [ Packaging ] - Bump minimum required version of Exporter::Tiny to 1.000000. - Type::Tiny::XS 0.016 is recommended. [ Other ] - Added: Type::Library now supports `of` and `where` options when importing type constraints. - Added: Type::Params multisig function now supports custom error messages. Benct Philip Jonsson++ - Added: Type::Params named_to_list feature. - Added: Type::Params signatures with slurpy hashrefs now allow true hashrefs to be passed to them. - Added: Type::Tiny::Enum now has a `unique_values` method. - Added: Types::Standard ArrayRef parameterized type can now take a second parameter, the minimum array length. - Better implementation of is_subtype_of/is_supertype_of and related functions. - Don't use Int from Type::Tiny::XS unless version 0.016 is available. - Eliminate memory cycles created by coderef overloading in Type::Tiny and Type::Coercion. Fixes RT#130823. Ivanov Anton++ - Eval::TypeTiny's API is now considered to be stable. - Fix Types::Standard's LazyLoad implementation. - The `values` attribute of Type::Tiny::Enum now preserves order. Fixes RT#129650. Daniel Schröer++ - Tidy up Type::Tiny namespace a little by fully-referencing some functions instead of importing them. - Tweaks to Type::Tiny and Type::Coercion to avoid unnecessarily loading overload.pm and overloading.pm. - Types::TypeTiny::TypeTiny->has_coercion is now true. 1.005_004 2019-11-11 1.005_003 2019-02-26 1.005_002 2019-01-29 1.005_001 2019-01-23 1.005_000 2019-01-20 1.004004 2019-01-08 [ Bug Fixes ] - Depend on Exporter::Tiny 0.040; older versions don't provide all the functions Type::Library needs. 1.004003 2019-01-08 [ Bug Fixes ] - Fix spelling in error message for Types::Common::String LowerCaseSimpleStr. Robert Rothenberg++ [ Documentation ] - Fix Type::Params documentation error. Nelo Onyiah++ - Fix Types::Standard documentation error: incorrect third-party module name. Nelo Onyiah++ 1.004002 2018-07-29 [ Bug Fixes ] - Skip one particular test on old versions of Moo because it relies on a feature introduced in Moo 1.004000. Fixes RT#125948. 1.004001 2018-07-28 [ Bug Fixes ] - Add Eval::TypeTiny::Sandbox to the list of packages which should be skipped as internal by Error::TypeTiny, as it was mistakenly removed in 1.003_008. Fixes RT#125942. [ Documentation ] - Correct release date of 1.004000 in change log. 1.004000 2018-07-27 [ Documentation ] - Update NEWS. - Update TODO. [ Packaging ] - Repackage as a stable release. No functional changes since 1.003_010. 1.003_010 2018-07-25 [ Test Suite ] - Improve test coverage for Type::Utils, Type::Coercion, Types::Standard::Tuple, Eval::TypeTiny, Type::Registry, Type::Tiny::Class, and Types::Standard::Tied. 1.003_009 2018-07-24 [ Documentation ] - Better documentation of parameterization API. [ Test Suite ] - Improve testing of Test::TypeTiny itself; the matchfor() function in particular. - Test bad parameters to NumRange and IntRange. - Test late loading of Sub::Quote. [ Other ] - Types::Standard::Defined->complementary_type will now return Types::Standard::Undef, and vice versa. 1.003_008 2018-07-16 [ REGRESSIONS ] - Make Error::TypeTiny aware of some newer internal modules. [ Bug Fixes ] - Fix error messages generating deep explanations of some parameterized types. Fixes RT#125765. KB Jørgensen++ [ Test Suite ] - Improve test coverage. - Test Type::Utils' match_on_type's support for wantarray on strings of code. [ Other ] - Improve processing of parameters to Types::Standard's parameterized type constraints - Simplify how Type::Registry generates the `t()` function. - Split out some code from Types::Standard into autoloaded modules to speed up loading. - Types::Common::Numeric's IntRange and NumRange do better checking of parameters. - Types::Common::String's StrLength does better checking of parameters. 1.003_007 2018-07-12 [ Test Suite ] - Add tests for deep coercions in Tuples. - Better tests for Eval::TypeTiny's implementations of alias=>1. - Improve coverage. - Restructure Types::TypeTiny test cases so more of them run when Moose and Mouse aren't available. [ Other ] - Added: Eval::TypeTiny now supports PadWalker as a fallback implementation of alias => 1. - Added: Eval::TypeTiny provides a collection of constants to indicate the current implementation of alias => 1. - Eval::TypeTiny will now throw errors when it detects a mismatch between sigils and reference types in the environment hashref but only if EXTENDED_TESTING environment variable is true. Perl will probably give you its own error message for this later on anyway. - Improve progressive exporter in Types::TypeTiny to avoid loading Exporter::TypeTiny more often. - Removed: Eval::TypeTiny::HAS_LEXICAL_VARS constant is no longer documented and will be removed at a later date. - Types::Standard does better at checking the parameters of parameterized types are valid. - Updated: Eval::TypeTiny now supports Perl 5.22 refaliasing as the preferred implementation of alias => 1. 1.003_006 2018-07-08 [ Bug Fixes ] - Fix issues with arrayref and hashref defaults in Type::Params. - Workaround for Regexp-based check for Int clobbering $1 sometimes (this will sometimes slow down Int checks a little, but is needed for correctness). Fixes RT#125132. [ Documentation ] - Better documentation of environment variables. - Type::Params caller_level option is now documented. [ Test Suite ] - Improve coverage. [ Other ] - Added: PERL_TYPE_PARAMS_XS environment variable. - Added: Type::Params compile/compile_named now have subname and description options. 1.003_005 2018-07-05 [ Documentation ] - Type::Tiny::Manual::Coercions improvements. Fixes RT#122305. [ Other ] - Added: Allow type libraries to mark certain type constraints as deprecated. Fixes RT#124728. 1.003_004 2018-06-12 [ Bug Fixes ] - Load modules with `use` instead of `require` in 00-begin.t. Fixes RT#124067. Andreas J König++ Slaven Rezić++ 1.003_003 2018-06-10 [ BACK COMPAT ] - Bool (Types::Standard) is stricter, no longer allowing blessed objects that overload stringification because that's weird. [ Other ] - Added: Bool now allows coercion from Any. 1.003_002 2018-05-28 - Added: Types::Common::Numeric now has NumRange and IntRange types. - Added: Types::Common::String now has a StrLength type. 1.003_001 2018-05-22 [ Test Suite ] - Tests for coercions to CycleTuple from Types::Standard with non-inlineable type constraints. [ Other ] - Don't use Type::Tiny::XS's implementation of Bool in Types::Standard unless Type::Tiny::XS >= 0.014. - Looser definition of FileHandle in Types::Standard. Fixes RT#121762. 1.003_000 2018-05-20 [ Bug Fixes ] - Compatibility with constants and with CV-in-stash optimisation. Fixes RT#123408. [ Documentation ] - Add a new CONTRIBUTING.pod file. - Document Type::Library's :coercion export tag. Diab Jerius++ - Fix typo. Philippe Bruhat++ - Improvements to Type::Params documentation. [ Test Suite ] - Skip t/30-integration/Moose/native-attribute-traits.t on older Moose because Test::Moose is broken. [ Packaging ] - Ref::Util::XS 0.100 should be recommended, not 0.200 (which doesn't exist yet). Fixes RT#121981. [ Other ] - Added: Allow Type::Coercion's add_type_coercion to accept a Type::Coercion object, which was already documented as working. Diab Jerius++ - Added: Type::Params compile_named now supports bless/class/constructor options. - Added: Type::Params now exports a compile_named_oo function which returns a parameters object. - Added: Type::Params now supports parameter defaults. - Don't use Type::Tiny::XS's implementation of PositiveInt in Types::Common::Numeric unless Type::Tiny::XS >= 0.013. 1.002001 2017-06-08 [ Test Suite ] - Skip t/30-integration/Moose/native-attribute-traits.t on older Moose because Test::Moose is broken. [ Packaging ] - Ref::Util::XS 0.100 should be recommended, not 0.200 (which doesn't exist yet). Fixes RT#121981. 1.002000 2017-06-01 [ Packaging ] - Stable version number. 1.001_016 2017-05-30 [ Documentation ] - Include page-numbers.pl example 1.001_015 2017-05-20 [ Bug Fixes ] - Fix HashRef[Str]|Undef|Str parsing on Perl < 5.14. Fixes RT#121764. Aran Clary Deltac++ Graham Knop++ 1.001_014 2017-05-19 - Include trailing line break at the end of stringified version of some exceptions. Peter Valdemar Mørch++ 1.001_013 2017-05-18 Kittiversary [ Bug Fixes ] - Fixed crazy amount of UTF-8 warnings from Type::Params on Perl 5.6.x and Perl 5.8.x. Fixes RT#101582. André Walker++ - StrMatch changes in previous release broke the ability to check type equality between two parameterized StrMatch types under some circumstances. Changed how the hash key for stashing regexp references gets built — is now closer to the old way. This doesn't revert the change in 1.001_012 where regexp checks can be inlined better, but only applies to those regexp references that can't easily be inlined. 1.001_012 2017-05-17 [ BACK COMPAT ] - RegexpRef now accepts blessed objects if $object->isa('Regexp') returns true. [ Other ] - StrMatch will use Regexp::Util (if available) to inline regular expressions more sensibly. 1.001_011 2017-05-17 [ Bug Fixes ] - Type constraints like Tuple[Int] shouldn't report they have a coercion if Int doesn't have a coercion. [ Other ] - Added: Types::Standard now has a CycleTuple type. 1.001_010 2017-05-16 Puppiversary [ Test Suite ] - t/00-begin.t will now work around ANDK's apparently broken XS testing environment. 1.001_009 2017-05-13 - Rewrite some benchmarking scripts to use Benchmark::Featureset::ParamCheck. - Use Ref::Util::XS (if it's installed) to speed up certain type checks. 1.001_008 2017-05-10 [ Bug Fixes ] - Type::Params should make sure Type::Utils is loaded before calling english_list(). [ Documentation ] - Rearrange the examples directory in the distribution. [ Other ] - Added: Named parameter validation benchmarking script. - Added: Reduce scope of local $SIG{__DIE__} in Type::Registry. Graham Knop++ 1.001_007 2017-05-04 May the fourth be with you [ Documentation ] - Comparison of Type::Params with new(ish) CPAN module Params::ValidationCompiler. - Show example of how to set defaults for parameters with Type::Params. [ Other ] - Added: Type::Params' `multisig` function now sets a variable `${^TYPE_PARAMS_MULTISIG}` to indicate which signature succeeded. - Optimization of Type::Params positional parameter checking for simple cases with no slurpy parameter and no coercions. - Optimizations for Tuple and StrMatch type constraints from Types::Standard. 1.001_006 2017-04-30 - Allow Type::Tiny's `constraint` parameter to be a string of Perl code. - Localize $SIG{__DIE__} in Type::Registry. Fixes RT#100780. 1.001_005 2017-04-19 [ Bug Fixes ] - 02-api.t should check version of Moose available. - 20-unit/Type-Utils/warnings.t should check version of Test::Warnings. Alexandr Ciornii++ - Fix minor typos in documentation for Types::Standard. Zoffix Znet++ - Fix variable name typo in documentation for Type::Params. Lucas Buchala++ [ Documentation ] - Include projected release date for Type::Tiny 1.002000 in NEWS. [ Test Suite ] - Bundle a test case for GH issue 14. [ Other ] - Improved error location reporting for Moo Peter Valdemar Mørch++ - Updated: NumericCode now coerces from strings with whitespace in them, like MooseX::Types::Common::Numeric. Denis Ibaev++ 1.001_004 2017-02-06 - Attempting ArrayRef[Int, Int] or similar now throws an exception. Fixes RT#105299. Thomas Sibley++ 1.001_003 2017-02-02 - Updated: Merge fixes from stable Type-Tiny 1.000006. 1.001_002 2014-10-25 [ Bug Fixes ] - Fix short-circuiting optimizations for parameterized HashRef, ArrayRef, ScalarRef, and Map type constraints. Fixes RT#99312. Marcel Timmerman++ - Inlined version of Types::Standard::Int should check that the value is not a reference. [ Test Suite ] - Fix annoying warning message in test suite with recent versions of Exporter::Tiny. [ Other ] - Make equals/is_a_type_of/is_subtype_of/is_supertype_of in Type::Tiny::Union work more like Moose::Meta::TypeConstraint::Union. 1.001_001 2014-09-19 - Lazy-load Text::Balanced in Type::Parser. (Many parses don't even need it.) - Lazy-load Type::Tiny::Union in Type::Params. - Updated: Prefer Sub::Util over Sub::Name. (The former is smaller.) 1.001_000 2014-09-07 [ Bug Fixes ] - Fix for Type::Registry::DWIM. Fixes RT#98458. Marcel Montes++ - Fix issues with coercions and native attribute traits with some oldish versions of Moose on oldish versions of Perl. Fixes RT#98159. Peter Flanigan++ [ Documentation ] - Updated NEWS file. - Updated TODO file. - Updates to Type::Tiny::Manual::UsingWithMoose, Type::Tiny::Manual::UsingWithMoo, and Type::Tiny::Manual::UsingWithMouse. [ Test Suite ] - Make some of the test case skip_all bits more ambitious; test older versions of Moose and Moo than we were testing before. [ Other ] - Added: Type::Params now provides `compile_named` and `validate_named` functions which do the same thing as `compile` and `validate` but are better for named arguments. - Updated: If Sub::Name is unavailable, but the shiny new core Sub::Util is available, then use it instead. - Updated: Want Type::Tiny::XS 0.011. - `Type::Utils::dwim_type` now allows more control over fallback behaviours. 1.000006 2017-01-30 [ Bug Fixes ] - Fix escaping within q{...} in a test case. Fixes RT#114386. Karen Etheridge++ 1.000005 2014-10-25 [ Bug Fixes ] - Fix short-circuiting optimizations for parameterized HashRef, ArrayRef, ScalarRef, and Map type constraints. Fixes RT#99312. Marcel Timmerman++ [ Test Suite ] - Fix annoying warning message in test suite with recent versions of Exporter::Tiny. 1.000004 2014-09-02 [ Bug Fixes ] - Fix for Type::Registry::DWIM. Fixes RT#98458. Marcel Montes++ - Fix issues with coercions and native attribute traits with some oldish versions of Moose on oldish versions of Perl. Fixes RT#98159. Peter Flanigan++ 1.000003 2014-08-28 [ Bug Fixes ] - Fix for coercions to parameterized Dict including a mixture of inlineable and non-inlineable optional values. Fixes RT#98362. Gianni Ceccarelli++ 1.000002 2014-08-18 [ Bug Fixes ] - Fix for overloaded operation fallback on Perl 5.10.x. Fixes RT#98113. Dagfinn Ilmari Mannsåker++ Peter Flanigan++ 1.000001 2014-08-18 [ Bug Fixes ] - Changes to dwim_type() in 0.047_09 broke the fallback to creating class types in some circumstances. This broke the MooX::late test suite, and some usages of MooX::late. Shlomi Fish++ 1.000000 2014-08-16 Happy CPAN Day! [ Documentation ] - Document the Type::Tiny versioning policy. - Updated NEWS file. - Updated TODO file. 0.047_09 2014-08-12 [ Bug Fixes ] - Fix documentation typo. Benct Philip Jonsson++ [ Documentation ] - Improvements and clarifications to Type::Coercion documentation. [ Test Suite ] - Add tests for Error::TypeTiny::Assertion's predicate methods. - Add tests for Type::Coercion's i_really_want_to_unfreeze method. [ Other ] - Better integration between Type::Library and Type::Registry. If you import a type constraint from a Type::Library-based module, it will automatically be inserted into your modules' type registry. - The to_Foo functions exported by Type::Library-based modules are now significantly faster. (But only if the type's coercion is frozen.) - Type::Utils::dwim_type now takes into account what OO framework the caller is using (Moose or Mouse) if it needs to fall back to asking the OO framework about a type constraint. 0.047_08 2014-08-05 Sanity++ [ Bug Fixes ] - Fix non-inlined version of NegativeOrZeroInt. [ Documentation ] - Document the remaining RT#93345-related issues - see "Deep Caveat" in Type::Tiny::Manual::Coercions. [ Test Suite ] - Alter the Types::Common::* test cases to use Test::TypeTiny. - Test to avoid the "too few arguments for type constraint check functions" error. Diab Jerius++ - Update t/30-integration/Moose/coercion.t to Moose 2.1200 which throws an exception rather than printing a warning when coerce=>1 is used on a type constraint with no coercions. [ Other ] - Prevent inlining of coercions if they've not been frozen. 0.047_07 2014-08-04 [ Bug Fixes ] - The extract_type function was missing from Type::Parser's @EXPORT_OK list. [ Test Suite ] - Test cases for Type::Parser::extract_type. [ Other ] - Parameterized Maybe constraints are now XS-accelerated. 0.047_06 2014-07-31 What made the Queen go all ice crazy? [ Bug Fixes ] - Bugfix in coercion inheritance where the child's type_coercion_map arrayref would end up as a reference to the parent's type_coercion_map. (Which was not good.) [ Test Suite ] - More Type::Registry test cases. [ Other ] - Added: Type::Coercion now has a i_really_want_to_unfreeze method. - Added: Type::Library now has a make_immutable method. - Coercions for the types defined in Types::Common::Numeric are now frozen. - Coercions for the types defined in Types::Common::String are now frozen. - Coercions for the types defined in Types::Standard are now frozen. - Parameterized types now have their coercions frozen automatically, so you can no longer add coercions to, say, ArrayRef[Int]. However, you can create a subtype of ArrayRef[Int] and add coercions to that. Michael G Schwern++ - Type::Registry now has methods for creating union/intersection/class/role type constraints. Type::Parser delegates to these, making it potentially reusable outside Type::Tiny by simply passing it an alternative type registry object. - Type::Registry/Type::Parser will now auto-load MouseX::Types libraries. 0.047_05 2014-07-29 Sanity++ [ REGRESSIONS ] - Introduced bug concerning coercions to parameterized Dicts with a mixture of inlineable and non-inlineable optional values. [ Documentation ] - Improve the documentation of Optional[] and slurpy. [ Other ] - A far saner implementation of Optional[]. - A slightly saner implementation of Types::TypeTiny's meta methods. - Optimizations for slurpy Any. - When slurping the tail of a Tuple into a hashref, check it's an even number of elements. 0.047_04 2014-07-28 The 98% Coverage Release [ Documentation ] - Type::Utils does not export english_list() and classifier() by default. [ Test Suite ] - Check that Mouse type converted to Type::Tiny objects keep their original error messages. - Improve test coverage for Type::Registry. - Improve test coverage for Type::Utils' match_on_type and compile_match_on_type. - Test code from SYNOPSIS sections (only in xt). - Test exceptions thrown by Types::Standard::ScalarRef. - Test that Sub::Quote-enabled coderefs generated by Type::Tiny and Type::Coercion can actually be retrieved by Sub::Quote. - Test the Type::Coercion overloading of ~~. - Test warnings raised by Type::Utils::declare(). - Tests for Test::TypeTiny::matchfor(). - Tests for dynamically delegated Type::Tiny an Type::Coercion methods. - Tests for introspection methods of Type::Coercion. - Tests for introspection methods of Types::TypeTiny. [ Other ] - Straighten out the relationships between Type::Coercion and its subclasses. - Type:Utils::match_on_type no longer automatically loads Types::Standard. 0.047_03 2014-07-26 The 96% Coverage Release [ Bug Fixes ] - Fix for slurpy Map within a Tuple. - Types::TypeTiny->has_type was incorrectly returning whether Types::TypeTiny contained the named *coercion* instead of a named *type*. [ Test Suite ] - Check Type::Library-based type libraries can extend MouseX::Types-based type libraries. - Check that Type::Registry works in conjunction with MouseX::Types. (There's some TODO stuff there.) - Checks for more Error::TypeTiny::Assertion explanations (Tuple, Duck, Intersection, Union, Dicts containing slurpy things). - Checks non-inlineable deep coercions for Tuple. - Fake a very old Validation::Class::Simple for a certain test by overriding $Validation::Class::Simple::VERSION. - Improved type constraint constructor tests (exceptions thrown for bad parameters, coercion=>ARRAY|CODE parameter). - Improved type introspection method tests (find_parent/is_supertype_of/is_subtype_of/is_strictly_supertype_of/is_s trictly_subtype_of). - Test the immutability of Type::Coercion::Union. - Tests for `isa`. - Tests for non-inlineable type constraints in `match_on_type` and `compile_match_on_type`. - Tests for various little methods which were added for Moose/Mouse-compatibility. [ Packaging ] - Bundle my TODO file. [ Other ] - Better `isa` faking - returns true to Class::MOP::Object. 0.047_02 2014-07-23 The 92% Coverage Release [ Documentation ] - Type::Tiny::Manual no longer says that Perl 5.6.x support is at risk. [ Test Suite ] - Add tests explicitly testing Type::Tiny objects conversion to Moose::Meta::TypeConstraint and Mouse::Meta::TypeConstraint objects. - Include test case relating to Type::Tiny::XS GitHub issue #1. - Stop using base.pm. - Test exceptions thrown by Type::Tiny::Class. - Test exceptions thrown by Type::Tiny::Enum. - Test exceptions thrown by Type::Tiny::Role. - Test the Error::TypeTiny::Compilation exception class. - Test the Error::TypeTiny::WrongNumberOfParameters exception class. [ Other ] - Allow Enums containing hyphens to be accelerated by Type::Tiny::XS. - Type::Tiny::Class should stop using Class::ISA. Instead, if mro.pm is not available, use a private sub stolen from MRO::Compat. - Type::Tiny::Intersection is now XS-accelerated. - Type::Tiny::Union is now XS-accelerated. 0.047_01 2014-07-21 The 87% Coverage Release [ Bug Fixes ] - Fix a silly test case that was relying on Exporter::Tiny to always load B.pm. (Current versions of Exporter::Tiny do load B.pm, but future versions might not.) [ Documentation ] - Better document which type constraints will be accelerated by Type::Tiny::XS and Mouse. [ Other ] - Type::Tiny::Enum is now XS-accelerated. - Types::Common::Numeric::PositiveInt is now XS-accelerated. - Types::Common::Numeric::PositiveOrZeroInt is now XS-accelerated. - Types::Common::String::NonEmptyStr is now XS-accelerated. - Types::Standard::Map is now XS-accelerated. - Types::Standard::Tuple is now XS-accelerated. - Unify _USE_XS/_USE_MOUSE logic in Type::Tiny. (It was previously scattered across Types::Standard and various other modules.) 0.046 2014-07-18 [ Bug Fixes ] - Fix for Types::TypeTiny::to_TypeTiny($coderef) when Sub::Quote is loaded but not used. - Undef no longer passes the Types::TypeTiny::StringLike type constraint. [ Test Suite ] - Add test cases for Types::TypeTiny (the library of type constraints used internally by Type::Tiny). [ Other ] - Minor optimizations to Types::TypeTiny::to_TypeTiny. 0.045_05 2014-07-18 [ Bug Fixes ] - More sensible use of Sub::Name in Type::Library. [ Documentation ] - Added a Type::Tiny::Manual::Optimization perldoc page. [ Other ] - Added: Type::Tiny now has a `where` method which is a shortcut for creating a child type with a constraint coderef. - Added: Type::Tiny now has an `of` method which is a shortcut for `parameterize` which I can never spell properly. - Restore and improve Mouse XS stuff dropped in Type-Tiny 0.045_03. 0.045_04 2014-07-15 [ Bug Fixes ] - Type::Params was warning about additional arguments passed to sprintf under Perl blead. The additional argument has been removed. [ Documentation ] - Updated NEWS file. [ Test Suite ] - Cope with changes to Type::Tie error messages introduced in Type::Tie 0.008. - Fix warnings in 30-integration/Moose/native-attribute-traits.t when run under perl -w. Peter Karman++ - Generally stop testing the contents of error messages produced by external modules! 0.045_03 2014-07-11 [ REGRESSIONS ] - The Mouse XS stuff introduced in Type-Tiny 0.003_09 has been partially removed. (I do plan on restoring it, and improving it.) [ Documentation ] - Update benchmark scripts, showing results with/without Type::Tiny::XS. [ Test Suite ] - When testing equivalence between Types::Standard types and core Moose types, don't test `Num` because Types::Standard provides two different implementations for it. [ Other ] - Type::Tiny::XS is now used (if available) to speed up some of the Types::Standard type constraints, plus Type::Tiny::Class and Type::Tiny::Duck. 0.045_02 2014-07-10 [ Bug Fixes ] - Remove outdated references to the overloaded + operator from Types::Standard documentation. Fixes RT#96379. Diab Jerius++ [ Documentation ] - Include benchmark/example of Type::Params versus Scalar::Validation. 0.045_01 2014-06-30 [ Bug Fixes ] - Ensure that when a Type::Tiny object is inflated into a Moose::Meta::TypeConstraint, inlining still happens via Type::Tiny. omega++ - Workaround strange behaviour of exists() function when applied to @_ on Perl older than 5.20 which caused some uses of Optional[Foo] to accept an explicit undef. Caleb Cushing++ 0.044 2014-06-03 [ Documentation ] - Updated NEWS file. 0.043_05 2014-05-21 [ Bug Fixes ] - Fix inflation of Type::Coercion objects to Moose::Meta::TypeCoercion when some of the coercion routines are given as strings. [ Documentation ] - Document the is_*, to_*, and assert_* functions in Type::Tiny::Manual::Libraries. Alexander Hartmaier++ - Mention coercion=>1 and why it is useful in Type::Tiny::Manual::Coercions. Alexander Hartmaier++ [ Test Suite ] - Integration tests for MooseX::Getopt. Alexander Hartmaier++ [ Other ] - Detect missing comma in declaration of type constraints using Type::Utils a la `declare Foo as Bar`, and print a warning. Tim Bunce++ - No longer need to inflate a Type::Tiny object to Moose::Meta::TypeConstraint in order to give an answer to $type->isa('Moose::Meta::TypeConstraint::Union'). 0.043_04 2014-05-21 [ Test Suite ] - Improve test cases for integration with Moose native attribute traits. 0.043_03 2014-05-06 [ Documentation ] - Rename Types::Datetime to Example::Types because there is now really a Types::DateTime on CPAN. - Type::Tiny::Manual::Libraries add example of using the custom types library. Peter Karman++ [ Test Suite ] - Add some test cases for the Error::TypeTiny class. - Improve Eval::TypeTiny test cases. - Tests for Type::Library error messages. [ Packaging ] - Updated bundled version of Try::Tiny. [ Other ] - Added: Extremely experimental and mostly undocumented my_method stuff. - Added: Type::Utils::classifier 0.043_02 2014-04-11 - Added: Experimental my_methods attribute so that type constraints can offer additional methods. - Added: Type::Tiny now has a find_parent method. 0.043_01 2014-04-06 - Sub::Quote quoted coderefs passed to to_TypeTiny() now result in inlinable type constraints. 0.042 2014-04-02 [ Documentation ] - Include more recent results in benchmarking example scripts. - List currently unstable/experimental parts of the distribution in Type::Tiny::Manual::Policies. 0.041_04 2014-03-31 [ Test Suite ] - Add tests for given/when matching against type constraints. 0.041_03 2014-03-28 [ Documentation ] - Improve documentation for the Type::Coercion class; especially its constructors, attributes and methods. - Improve documentation for the Type::Tiny class; especially its constructor, attributes and methods. 0.041_02 2014-03-26 [ Bug Fixes ] - Fix Type::Tiny::Duck's inlining of code when given the variable name `$_`. Fixes RT#94196. Diab Jerius++ [ Documentation ] - Type::Tiny::Manual links to various parts of the test suite to document concepts. These links had grown stale and have now been updated. - Updated NEWS file. [ Test Suite ] - Prevent 20-unit/Type-Registry/moosextypes.t from failing due to too old MooseX::Types::Common - just skip the test script if MXTC is older than 0.001004. 0.041_01 2014-03-17 [ BACK COMPAT ] - Type::Tiny and Type::Coercion no longer overload addition. This feature never really worked very well with regard to precendence, requiring lot of parentheses to use. The overload also made solving the parameterizable type coercion problem very difficult. [ Other ] - Parameterizable coercions are now passed a reference to the type constraint they should target. 0.040 2014-03-17 [ Documentation ] - Refreshed SEE ALSO section of Type::Tiny::Manual::Libraries. - Updated NEWS file. 0.039_13 2014-03-15 [ Bug Fixes ] - Fix occasional segfaults on threaded Perl 5.18.x. Graham Knop++ [ Test Suite ] - Test for occasional segfaults on threaded Perl 5.18.x. Graham Knop++ 0.039_12 2014-03-12 [ Bug Fixes ] - Various Type::Utils functions were trying to dereference undef as a hash or array in certain circumstances. Matt Phillips++ [ Other ] - Type::Utils' class_type and role_type functions will $name =~ s/:://g. Matt Phillips++ 0.039_11 2014-03-11 [ Test Suite ] - Because of changes to Data::Dumper in Perl 5.19.x, the test suite was previously skipping some Dumper-based test cases depending on Perl version. However, Dumper is dual-lifed, so older versions of Perl may have shiny, new Dumpers. Skip test cases based on Data::Dumper version instead. 0.039_10 2014-03-10 [ Documentation ] - Document the benefits of freezing coercions, and of defining coercions either within the type library, or via $type->plus_coercions. [ Other ] - $type->plus_coercions and friends now return objects with frozen coercions. 0.039_09 2014-02-25 [ Documentation ] - Update Type::Tiny::Manual::Params to mention Kavorka, and newer features of Function::Parameters. [ Test Suite ] - Test integration with Moops. - Test integration with Switcheroo. - Test that coercions attached to Moose type constraints get inherited by Type::Tiny when they are inhaled. - Unit tests for Devel::TypeTiny::Perl56Compat. - Unit tests for Devel::TypeTiny::Perl58Compat. 0.039_08 2014-02-24 [ Test Suite ] - Test integration with Kavorka. 0.039_07 2014-02-17 [ Bug Fixes ] - Fix hash ordering bug in Return::Type integration tests. 0.039_06 2014-02-17 [ Bug Fixes ] - Type::Tiny's SUPPORT_SMARTMATCH constant was broken; fixed now. - Type::Tiny's TIEARRAY and TIEHASH methods were broken; fixed now. [ Test Suite ] - Enable some old tests that had been disabled as not-yet-implemented for parameterized type constraints; the feature they test was implemented ages ago. - Test integration with Return::Type. - Test integration with Type::Tie. - Test integration with match::simple. 0.039_05 2014-02-15 - Apply the Type::Tiny::_HalfOp trick to overloaded addition too. 0.039_04 2014-02-05 - Make overloaded ops on parameterized type constraints work more consistently between Perl above and below 5.14, reducing the need for parenthesizing complex type constraint expresssions. Graham Knop++ 0.039_03 2014-02-05 [ Bug Fixes ] - Make Type::Utils::declare_coercion work outside type libraries. Fixes RT#92591. Diab Jerius++ - Weak reference from Type::Coercion objects to target type constraint caused bad behaviour in some cases. This has been fixed by retaining enough information within the Type::Coercion to be able to reconstruct its type constraint if it disappears due to the reference count falling to zero. Fixes RT#92571. Diab Jerius++ 0.039_02 2014-01-25 [ Test Suite ] - Add tests for Test::TypeTiny. 0.039_01 2014-01-21 [ Documentation ] - The preferred IRC channel for support is now #moops. [ Test Suite ] - Restructure the 't' directory. [ Other ] - Removed: Exporter::TypeTiny. 0.038 2014-01-01 [ Documentation ] - Copyright 2014. - Updated NEWS file. 0.037_03 2013-12-30 [ Bug Fixes ] - Fix problems with Moo::HandleMoose integration on threaded Perls. Graham Knop++ Kevin Dawson++ Matt S Trout++ [ Test Suite ] - Skip leak.t on threaded Perls (for now). 0.037_02 2013-12-29 [ Documentation ] - Link to the Type::Tiny stability policy from the pod of each module it covers. 0.037_01 2013-12-24 [ Bug Fixes ] - Fix a Type::Params/B problem on Perl 5.6.x. 0.036 2013-12-21 [ Documentation ] - Updated NEWS file. 0.035_01 2013-12-17 - Make Type::Parser work with newer versions of MooseX::Types::Common which uses namespace::autoclean. Fixes RT#91468. David Steinbrunner++ - Make parameterized Dict and Map type constraints work with Moose native hash attribute trait. Jason R Mash++ 0.034 2013-12-09 [ Documentation ] - Updated NEWS file. 0.033_04 2013-12-06 [ Test Suite ] - Further tests related to RT#90096. Diab Jerius++ [ Other ] - Implement coercion_names, get_coercion, has_coercion, and has_type methods for Types::TypeTiny, to make it more like a real Type::Library type library. - The `extends` function from Type::Utils now allows inheritance of coercions, not just types. Fixes RT#91153. Jason R Mash++ 0.033_03 2013-11-26 [ Bug Fixes ] - Fix bug in Type::Params::multisig with regard to slurpy parameters. Fixes RT#90865. Diab Jerius++ [ Documentation ] - Make Error::TypeTiny::Assertion's explain method act more according to documentation. Fixes RT#90867. Diab Jerius++ [ Packaging ] - Recommend Sub::Name in META.json. 0.033_02 2013-11-26 - Split out some of the longer parts of Types::Standard into other modules that will be loaded on demand; this shaves about 20% off the load time of Types::Standard. 0.033_01 2013-11-07 [ Bug Fixes ] - Type::Params now localizes $_ before trying to assign anything to it. Fixes RT#90096. Samuel Kaufman++ [ Test Suite ] - Test case using a Type::Params compiled check within the scope of a read-only $_ variable. Samuel Kaufman++ [ Other ] - Added: Types::Common::Numeric - Added: Types::Common::String 0.032 2013-11-05 Remember, remember the fifth of November [ Bug Fixes ] - Eliminate a warning under Perl 5.6.x. [ Documentation ] - Updated NEWS file. 0.031_05 2013-11-04 [ Documentation ] - Fix minor typo. David Steinbrunner++ [ Other ] - Allow Dict to take a slurpy parameter - a la Dict[foo => Int, slurpy HashRef[Num]]. Matt S Trout++ 0.031_04 2013-11-03 [ Bug Fixes ] - Type::Parser 0.031_02 introduced a bug under Perl 5.6.x where we relied on the existence (or not) of a hash item being affected by `local`; this was implemented in Perl 5.8.0. Work around this problem by checking definedness instead. 0.031_03 2013-11-03 - Added: Deep coercions for Maybe[`a]. Fixes RT#89936. Brendan Byrd++ 0.031_02 2013-11-03 - Type::Parser now differentiates between Tuple[] and Tuple too. - Type::Parser only treats a comma as an operator within a parameterization now, and is thus now able to parse types from the head of a string which is a comma-separated list of types. 0.031_01 2013-10-28 [ Bug Fixes ] - Differentiate Tuple[] vs Tuple, and Dict[] vs Dict. Fixes RT#89696. Benct Philip Jonsson++ [ Documentation ] - Improved documentation for Types::TypeTiny. [ Test Suite ] - Adjustments to cope with newer Moose is-class-loaded heuristics. - Check Moose exception objects with isa rather than regexp matching. 0.030 2013-10-18 [ Documentation ] - Updated NEWS file. [ Test Suite ] - Skip leak.t on Perl < 5.10.1. Type-Tiny does have some memory leaks in particular older versions of Perl: 5.8.8 and 5.10.0 are known to be problematic, but 5.8.9 seems fine. Ultimately it would be nice to get these fixed, but in the mean time skipping the test case makes the distribution easier to install. 0.029_04 2013-10-17 [ Bug Fixes ] - Fix inlining of type checks in Moo which was broken around about version 0.027_09. - Fix validate_explain error messages in Type::Tiny::Union. Fixes RT#89279. Brendan Byrd++ [ Other ] - $Type::Tiny::DD can be set numerically. Fixes RT#89251. Tim Bunce++ - Improve error messages under Moo. Fixes RT#89234. Graham Knop++ 0.029_03 2013-10-17 [ Bug Fixes ] - Fix segfault on Perl 5.8.1 to 5.8.3. (And possibly some other 5.8.x Perls.) Caused by the combination of eval and goto. Dagfinn Ilmari Mannsåker++ Graham Knop++ Peter Rabbitson++ - Older versions of Scalar::Util::looks_like_number return true for undef; work around them. 0.029_02 2013-10-11 [ BACK COMPAT ] - Renamed the Type::Exception modules to Error::TypeTiny. Fixes RT#89280. Brendan Byrd++ [ Documentation ] - Fix typos in documentation of Error::TypeTiny package variables. [ Other ] - $Type::Tiny::DD package variable can now be used for a pluggable data dumper coderef. Fixes RT#89251. Tim Bunce++ - Type::Tiny::Enum type constraints are now subtypes of Types::Standard::Str; not Types::Standard::Defined. David Golden++ - Types::Standard::Item is now a subtype of not Types::Standard::Any. David Golden++ 0.029_01 2013-09-26 - Replace Exporter::TypeTiny with Exporter::Tiny (an external dependency). 0.028 2013-09-26 [ Documentation ] - Note in documentation for Type::Tiny::Union, etc that constraint/inlining coderefs not only should not be provided to the constructor, but cannot! Fixes RT#88655. Brendan Byrd++ - Updated NEWS file. 0.027_09 2013-09-20 [ REGRESSIONS ] - Inlining of type checks in Moo broken in this release, or hereabouts. Fixed in 0.029_04. [ Bug Fixes ] - Fix whitespace in error messages. [ Test Suite ] - Skip leak.t on Perl 5.10.0. 0.027_08 2013-09-19 [ Bug Fixes ] - Fix typo in Type::Utils for coerce=>1 --> coercion=>1. Fixes RT#88798. Diab Jerius++ - Fix typo in changelog for previous developer release. - Type::Exception::Assertion changes from 0.027_05 are now conditional upon Perl version; only take effect on Perl 5.8+; they just weren't working on Perl 5.6. [ Test Suite ] - More changes to version numbers reported by 00-begin.t. [ Other ] - Explicitly overload boolification (always true!) in Type::Exception. 0.027_07 2013-09-18 [ Bug Fixes ] - Fix missing version number in Type::Coercion::FromMoose [ Test Suite ] - Changes to version numbers reported by 00-begin.t. [ Other ] - Also ensure Mouse type constraints converted to Type::Tiny constraints retain their coercions. 0.027_06 2013-09-18 [ Documentation ] - Add a draft Stability Policy to Type::Tiny::Manual. [ Other ] - Added: Override `validate_explain` in all the bundled subclasses of Type::Tiny. - Added: Type::Coercion::FromMoose - Added: Type::Tiny::Union now provides a `find_type_for` method which should be compatible with Moose's equivalent method. - Added: Type::Utils now provides an `english_list` function like Moose::Util does. This was useful internally for implementing `validate_explain` methods. - Loosen the rules for Type::Tiny and Type::Coercion name attributes; allow them to begin with one or two leading underscores. - Memoize Types::TypeTiny::to_TypeTiny. - Stop using base.pm. - Type::Tiny::Union's compiled checks no longer close over the type constraints which are in the union. - Types::TypeTiny::to_TypeTiny now uses Type::Coercion::FromMoose to ensure Moose type constraints converted to Type::Tiny constraints retain their coercions. 0.027_05 2013-09-15 - Added: Provide a `validate_explain` method as part of Type::Tiny's public API. - Include a detailed explanation in the stringification of Type::Exception::Assertion. - Refactor the explanation generation mechanism. 0.027_04 2013-09-09 [ Test Suite ] - The file t/moose-coercion.t was checking a particular Moose warning message. In Moose 2.1100, this warning has been upgraded to an exception. For now, disable that particular check. 0.027_03 2013-09-09 [ Bug Fixes ] - Prevent Eval::TypeTiny from leaking stashes by recycling the sandbox. [ Test Suite ] - Fix the ultra-finicky t/02-api.t to cope with changes to Moose::Meta::TypeConstraint API in Moose 2.1100. 0.027_02 2013-09-08 [ Bug Fixes ] - Restore Type::Tiny -> Moose -> Type::Tiny round-tripping broken in previous release. [ Documentation ] - In Type::Tiny::Manual::Coercions, explain how to chain coercions. 0.027_01 2013-09-07 [ REGRESSIONS ] - Weakening various references to fix memory leaks led to breaking Type::Tiny -> Moose -> Type::Tiny round-tripping via Types::TypeTiny::to_TypeTiny. Test cases for this marked TODO. [ Bug Fixes ] - Fixed some memory leaks. Still some work to do in this area. [ Other ] - Added `coercibles` method to Type::Tiny. Diab Jerius++ 0.026 2013-09-05 [ Documentation ] - Updated NEWS file. 0.025_03 2013-09-04 [ Documentation ] - Document that multisig() accepts coderefs. [ Packaging ] - Use a newer version of RDF::DOAP to process this changelog. 0.025_02 2013-09-02 [ Bug Fixes ] - functionparameters.t now requires Moo or Moose and is skipped otherwise. [ Other ] - Added: Type::Params now provides a multisig() function, allowing you to define multiple function signatures, and attempt to validate @_ against them each in turn. Fixes RT#88291. Diab Jerius++ 0.025_01 2013-09-02 [ Bug Fixes ] - The Tuple structured type was treating arrays with missing required elements as if they were present but undef. Fixes RT#88277. Steven Lee++ [ Documentation ] - Document the internals of Exporter::TypeTiny. [ Packaging ] - Take advantage of dynamic_config to ask automated testers to test Type::Tiny with Moose present, but only if the Type::Tiny version number includes an underscore. - use Dist-Inkt [ Other ] - Exporter::TypeTiny will now use method-style resolution when searching for a sub to export. - Make Exporter::TypeTiny support generators with less internals-hacking. 0.024 2013-08-27 [ Documentation ] - Updated NEWS file. 0.023_03 2013-08-23 [ Bug Fixes ] - Constructors for some subclasses of Type::Tiny rejected hashrefs of paramaters. Fixes RT#88064. Brendan Byrd++ - Stop considering the empty string to be a valid package name. [ Test Suite ] - Include additional test cases stolen from Moose. [ Other ] - Implementation of RegexpRef in Types::Standard is now closer to Moose's implementation (accepts blessed Regexps). 0.023_02 2013-08-23 [ Bug Fixes ] - Fix quoting in error messages which caused Type::Params to be unable to compile some coderefs. Fixes RT#87846. Tim Bunce++ - Improve ugly type assertion failure messages when given structures of nested references. Fixes RT#87999. Tim Bunce++ [ Other ] - Added: Type::Registry now has an `add_type` method, for adding a single type constraint to a registry. - Type::Registry's `add_types` method now supports importing MooseX::Types and MouseX::Types libraries. - Type::Utils' `extend` function now supports extending MooseX::Types and MouseX::Types libraries. 0.023_01 2013-08-16 [ Bug Fixes ] - Fix Moo -> Moose type inflation issue. Matt Phillips++ 0.022 2013-08-06 [ Documentation ] - Updated NEWS file. [ Other ] - Improved implementations of is_subtype_of/is_strictly_subtype_of; better for subclassing. - In Devel::TypeTiny::Perl56Compat, `use strict` and `use warnings`. 0.021_04 2013-07-30 [ Bug Fixes ] - Fix Type::Parser's handling of numeric parameters; they shouldn't need quoting. - Fix Types::Standard::Dict differentiating between undef and not exists. Fixes RT#87443. Tim Bunce++ [ Packaging ] - Add dependency on Exporter 5.57 for older versions of Perl. 0.021_03 2013-07-30 - Improve compatibility between Type::Tiny and Moose attribute native traits. - Restore Eval::TypeTiny's pre-0.019_01 behaviour re closing over lexicals, but enable the 0.021_02 behaviour if alias=>1 option is passed in. 0.021_02 2013-07-26 - Use real lexicals again for Eval::TypeTiny; this requires Devel::LexAlias, but there's a fallback to using tied variables. 0.021_01 2013-07-24 - Added: Type::Tiny is_strictly_a_type_of method. - Added: Type::Tiny is_strictly_subtype_of method. - Added: Type::Tiny is_strictly_supertype_of method. - Added: Type::Tiny strictly_equals method. 0.020 2013-07-23 [ Documentation ] - Updated NEWS file. 0.019_01 2013-07-23 [ Bug Fixes ] - Eval::TypeTiny now closes over variables properly. - Work around lack of B::perlstring() function in Perl 5.6.x in test suite. 0.018 2013-07-21 [ Documentation ] - Updated NEWS file. 0.017_02 2013-07-20 [ Bug Fixes ] - Further changes for Perl 5.6.x support. [ Other ] - Hopefully improved workaround for missing B::perlstring() using Data::Dumper instead of quotemeta(). Peter Rabbitson++ 0.017_01 2013-07-19 [ Bug Fixes ] - Work around lack of B::perlstring() function in Perl 5.6.x. [ Documentation ] - Fix typo in Types::Standard 'regular exception' -> 'regular expression'. Mark Stosberg++ - Give an example of the default error messages thrown by Type::Tiny. - Improve examples of custom type constraint error message in Type::Utils and Type::Tiny::Manual::Libraries. Fixes RT#86892. Tim Bunce++ [ Other ] - Updated: Eval::TypeTiny now supports lexical subs under Perl 5.18. 0.016 2013-07-16 [ Documentation ] - Add some pod links. - Updated NEWS file. 0.015_05 2013-07-15 [ Packaging ] - Experimentally drop required version of Perl from 5.8.1 to 5.6.1. I've not been able to extensively test Type-Tiny on Perl 5.6.x, but I believe it should mostly work. (The only feature that seems unlikely to work is non-ASCII names for type constraints and coercions.) [ Other ] - Stop monkey-patching Moose::Meta::TypeContraint; it's not necessary and has never been documented. 0.015_04 2013-07-13 [ Documentation ] - Clarify when inlining via Sub::Quote may be less efficient than hand-written inlining. Fixes RT#86893. Tim Bunce++ - Mention in Type::Tiny::Manual::Libraries that the `extends` function is no longer exported by default; update example code. Fixes RT#86813. Pierre Masci++ [ Other ] - Allow an inline_as block to return a list of strings (which are implictly joined with &&); allow the first item on the list to be undef, which is treated as the inlined parent type constraint. Fixes RT#86891. Tim Bunce++ 0.015_03 2013-07-08 - Added: Implement TIESCALAR, TIEARRAY and TIEHASH methods for Type::Tiny; this improves Type::Tie integration. - Slight speed improvements for `compile_match_on_type`. - The `dwim_type` function now prioritizes lookups within the caller class' type registry over Types::Standard's built-in types. 0.015_02 2013-07-06 - Better test cases for `dwim_type`. - Improvements to DWIMness of Type::Parser for the benefit of `dwim_type`. 0.015_01 2013-07-05 - Added: Type::Utils now provides a `dwim_type` function; this is powered by a hidden Type::Registry::DWIM package. - Type::Parser can now pull in types from MooseX::Types libraries properly. 0.014 2013-06-28 [ Documentation ] - Updated NEWS file. 0.013_01 2013-06-27 [ BACK COMPAT ] - Type::Parser functions no longer accept an arrayref of tokens, as they expect to pull tokens from a stream as required. - Type::Parser no longer provides a `tokens` function as it no longer pre-emptively tokenizes the whole string it is given. [ Other ] - Added: Type::Parser now provides a `extract_type` function which parses a type constraint expression from the head of a string and returns a Type::Tiny object, plus the tail of the string. (This is designed to make it easier to use Type::Parser to parse things like function signatures.) - Type::Parser's tokenization is now done on a pull basis, allowing one-pass building of the AST. 0.012 2013-06-25 [ Documentation ] - Updated NEWS file. 0.011_03 2013-06-25 [ Bug Fixes ] - Type::Tiny now overloads `cmp`. Necessary because Mouse does a sort on type constraints in a union, and overload's fallback doesn't seem to cover `cmp` on Perl prior to 5.12. 0.011_02 2013-06-25 [ Bug Fixes ] - Types::Standard 0.009_02 stopped including 'library' attribute in its types, and thus broke MooX::late. Type::Library modified to make 'library' attribute more automatic, and less reliant on Type::Utils to do the right thing. Graham Knop++ 0.011_01 2013-06-25 [ Bug Fixes ] - B::SPECIAL-related fix. Fixes RT#86383. Peter Flanigan++ - Unions of Type::Tiny and Mouse::Meta::TypeConstraints now work properly. This makes Type::Tiny and MouseX::Types play nice together (much like Type::Tiny already plays nice with MooseX::Types). [ Other ] - Cleanups within Type::Coercion. Necessary because in some places the entire type_coercion_map (including conversion coderefs) was passed through Types::Standard::to_TypeTiny, when really only the type constraints should have been. - Types::Standard::to_TypeTiny now accepts any object implementing the Type::API::Constraint or Type::API::Constraint::Coercion interfaces. As Mouse::Meta::TypeConstraint implements this interface, specific support for importing Mouse types has been dropped; the generic Type::API import 'just works' for Mouse types. - Types::Standard::to_TypeTiny now accepts unblessed coderefs and converts them to type constraints. This allows things like `Int & sub { $_ < 10 }` to work. 0.010 2013-06-24 [ Documentation ] - Updated NEWS file. 0.009_07 2013-06-24 [ Test Suite ] - Make rt86172.t an 'xt' test case because it's causing random CPAN testers failures unrelated to the feature it's supposed to be testing. - More test cases for interacting with MooseX::Types type constraints. [ Other ] - If a Type::Tiny object is instantiated with a Sub::Quote quoted constraint coderef, and no inlined coderef, then Type::Tiny will use Sub::Quote to make an inlined coderef. - Subclasses of Type::Tiny reject 'inlined' coderef, just like they already reject 'constraint' coderef. - Type::Params no longer uses Type::Utils. - Types::Standard::to_TypeTiny now sets 'display_name' instead of 'name' on generated type constraints. 0.009_06 2013-06-23 [ Bug Fixes ] - Careful calling the DOES method (it doesn't exist in Perl 5.8). 0.009_05 2013-06-23 [ Bug Fixes ] - Type::Registry does the AUTOLOAD thing, so ought to provide a DESTROY method. 0.009_04 2013-06-23 [ Bug Fixes ] - Type::Tiny::Class shouldn't completely trust @ISA when establishing parent class heirarchies. [ Other ] - Constructors for Type::Tiny subclasses no longer accept the 'constraint' parameter; it doesn't make sense. - Updated: Support Type::API interfaces. 0.009_03 2013-06-22 [ Bug Fixes ] - Fix Types::Standard compilation errors under Perl 5.8.x. 0.009_02 2013-06-22 [ REGRESSIONS ] - Types::Standard types no longer have 'library' attribute set; this subtly breaks Moo type inflation, and breaks the MooX::late test suite which relies on type inflation working correctly. [ Bug Fixes ] - Fix for compiled_checks for type constraints inheriting from Type::Tiny::Class, etc. Richard Simões++ [ Other ] - Types::Standard no longer uses Type::Utils. - Various minor optimizations for Eval::TypeTiny, Type::Tiny, etc. 0.009_01 2013-06-21 [ Bug Fixes ] - Fix error messages from type constraints with null constraint coderefs. [ Other ] - Added: Reply::Plugin::TypeTiny. 0.008 2013-06-21 [ Documentation ] - Updated NEWS file. 0.007_10 2013-06-21 [ Bug Fixes ] - Fixed many small parsing bugs in Type::Parser. - MooseX::Types objects used in Type::Tiny::Union, Type::Tiny::Intersection and parameterized Type::Tiny type constraints would break in some circumstances, as Types::TypeTiny::to_TypeTiny was failing to convert them to native Type::Tiny type constraints. Fixes RT#86303. [ Documentation ] - Document status of Type::Registry. [ Test Suite ] - Add test cases for Type::Parser. - Better test cases for Type::Registry. [ Other ] - Added: Type::Parser now exports a _std_eval function useful for testing. - Improved error messages from Type::Parser. - Type::Parser now supports parentheses in its DSL. 0.007_09 2013-06-18 [ Bug Fixes ] - Fix problems inlining Dict deep coercions where the target constraint could not be inlined. Fixes RT#86233. Vyacheslav Matyukhin++ - Fix unintuitive Dict deep coercions. Fixes RT#86239. Vyacheslav Matyukhin++ [ Test Suite ] - Bundle various tests for deep Dict coercions. Vyacheslav Matyukhin++ 0.007_08 2013-06-17 [ Bug Fixes ] - Fix problem with interaction between constraints, coercions, and Moose classes that inherit from Moo classes. Fixes RT#86172. Peter Flanigan++ [ Test Suite ] - Bundle test for interaction between constraints, coercions, and Moose classes that inherit from Moo classes. Peter Flanigan++ 0.007_07 2013-06-16 [ Bug Fixes ] - Partly roll back prototype changes. Now we use `;$` for Perl since 5.14, but `;@`, for older Perls that don't support `;$` so well. 0.007_06 2013-06-16 [ BACK COMPAT ] - Better prototypes (was `;@`, now `;$`) for parameterizable type 'constants' exported by type libraries. Matt S Trout++ - Type::Utils no longer exports 'extends' by default. [ Documentation ] - Document the evaluation environment used by Eval::TypeTiny. - Rearranged documentation for Type::Utils, avoiding previous split into Moose-like and non-Moose-like functions. [ Other ] - Added: Type::Exception is now capable of supplying stack traces (requires Devel::StackTrace). - Exceptions thrown for Moo isa/coerce now indicate which attribute was involved. 0.007_05 2013-06-12 [ Documentation ] - Mention Scalar::Does and Type::Tie in manual. - Vastly improved documentation for Type::Utils. - Vastly improved documentation for Types::Standard. [ Test Suite ] - Added test cases for InstanceOf, ConsumerOf, HasMethods and Enum types defined by Types::Standard. [ Other ] - Added: Add match_on_type and compile_match_on_type to Type::Utils. - Support '0' and '1' as shortcuts for Optional[Any] and Any in Type::Params. (Not documented yet.) 0.007_04 2013-06-09 [ Bug Fixes ] - Overloading of `$type eq $type` now works in Perl 5.8. Fixes RT#85895. Vyacheslav Matyukhin++ - The combination of Dict, Optional and coercions seems to have been broken in certain circumstances. Fixes RT#86001. Diab Jerius++ 0.007_03 2013-06-08 [ Bug Fixes ] - Inlining of certain deep Dict, Tuple and Map coercions was broken, but Type::Params attempted to inline them anyway, leading to death. Fixes RT#85911. Diab Jerius++ [ Documentation ] - Better document Type::Tiny's 'parents' method which differs from the Moose method of the same name. 0.007_02 2013-06-04 [ Documentation ] - Improvements to Type::Tiny::Manual. - Improvements to Type::Tiny::Manual::Params, including rewritten manual processing section, and processing type constraints in function signatures via Function::Parameters/Attribute::Constract. [ Test Suite ] - Test cases for usage with Function::Parameters. [ Other ] - Added: New constraints added to Types::Standard: InstanceOf, ConsumerOf, HasMethods and Enum. Graham Knop++ - Allow constraint_generators (for parameterizable type constraints) to return full Type::Tiny objects instead of plain coderefs. - Drop use of Carp in Type::Parser. - Type::Tiny::Class types now have an automatically calculated parent type constraint based on @ISA. - Type::Tiny::Duck types now have a parent type constraint of Types::Standard::Object. - Type::Tiny::Enum types now have a parent type constraint of Types::Standard::Str. - Type::Tiny::Intersection types now have an arbitrary parent type constraint. - Type::Tiny::Role types now have a parent type constraint of Types::Standard::Object. - Type::Tiny::Union types now have an automatically calculated parent type constraint based on the most specific common parent type constraint. 0.007_01 2013-06-01 Happy birthday to me... [ BACK COMPAT ] - Types::Standard's Num constraint is now a subtype of either LaxNum and StrictNum (depending on environment). [ Bug Fixes ] - Fix $VERSION defined in Type::Library. [ Packaging ] - Generate README from Type::Tiny::Manual instead of Type::Tiny. [ Other ] - Added: Type::Parser. - Added: Types::Standard now has LaxNum/StrictNum type constraints. - Implemented Types::TypeTiny->meta->get_type. - Re-introduce Type::Registry, with improved parsing thanks to Type::Parser. 0.006 2013-05-28 [ Bug Fixes ] - Exporter::TypeTiny::mkopt_hash now works. 0.005_08 2013-05-28 [ Test Suite ] - Add 00-begin.t. - Rearrange test cases - Use JSON::PP instead of JSON in test cases, because JSON::PP is a core module since Perl 5.14. 0.005_07 2013-05-28 [ Bug Fixes ] - Assertions using the assert_return pattern were triggering FATAL warnings when inlined with Sub::Quote. Inlined assertions are now prefixed with 'no warnings "void";'. [ Documentation ] - Add pure-Perl Mouse to examples/benchmark-constraints.pl. 0.005_06 2013-05-26 [ Bug Fixes ] - Fix StrMatch to properly support regexps containing slashes. [ Other ] - Fold Types::Standard::DeepCoercion into Types::Standard. 0.005_05 2013-05-24 [ Documentation ] - Suggest newer version of Validation::Class. [ Other ] - Added: Type::Tiny now has an assert_return method, which is used in most places in preference to assert_valid. - Fix warnings under Perl 5.18. - Removed: Removed Type::Registry from the release; it will return at a later date. 0.005_04 2013-05-17 [ Bug Fixes ] - Fixed bug in non-inlined code for Types::Standard::MkOpt. [ Other ] - Added: Type::Exception::Compilation. - All error conditions now throw exception objects instead of string error messages. - Allow the slurpy tail of a Types::Standard::Tuple to be a treated as a hashref rather than an arrayref. - Deep explanations for Types::Standard::{Map,Maybe,Ref,Dict,Tuple} type constraint assertion failures. - Improved deep explanations for Types::Standard::{ArrayRef,HashRef,ScalarRef}. - Test::TypeTiny performs more thorough testing if EXTENDED_TESTING environment variable is set. - Throw exception if people attempt to set parent types for Type::Tiny::{Class,Role,Duck,Enum,Union,Intersection}. 0.005_03 2013-05-14 - Many error conditions now throw exception objects instead of string error messages. - Removed: Bytes and Chars type constraints removed from Types::Standard. - Removed: Decode and Encode coercions removed from Types::Standard. 0.005_02 2013-05-14 [ Documentation ] - Fix a typo in declare_coercion in Type::Tiny::Manual::Coercions. Vyacheslav Matyukhin++ - Link to Type::Tiny::Manual::Libraries instead of non-existing Type::Tiny::Intro. Vyacheslav Matyukhin++ 0.005_01 2013-05-07 [ Bug Fixes ] - Type::Library should require Perl 5.8.1, not 5.8.3. [ Other ] - Added: ArrayLike type added to Types::TypeTiny. - Added: Type::Registry. 0.004 2013-05-06 [ Bug Fixes ] - Eval::Closure now strips line breaks and other unsavoury characters from descriptions. [ Other ] - Minor updates to to_TypeTiny following Validation::Class 7.900048 release. 0.003_16 2013-05-05 [ Documentation ] - Document that Map[`k,`v] has a deep coercion. - Improve Type::Coercion documentation. [ Other ] - Minor updates to coderef overloading following Moo 1.002000 release. - Rename Types::Standard::AutomaticCoercion -> Types::Standard::DeepCoercion. - Type::Params produces nicer error messages. 0.003_15 2013-05-03 - Improvements to to_TypeTiny function, including accepting Validation::Class::Simple objects. 0.003_14 2013-05-03 0.003_13 2013-05-03 [ Bug Fixes ] - Don't crash in old versions of Moose that have no Class::MOP::_definition_context() function. [ Documentation ] - Fix typo in Type::Params documentation. Diab Jerius++ [ Test Suite ] - BAIL_OUT in test suite if 00-compile.t or 01-api.t fail. [ Other ] - Better documentation and tests of Moose/Mouse-compatible API. 0.003_12 2013-05-01 [ Bug Fixes ] - Sane behaviour for Types::Standard's 'slurpy' function when it appears mid-list. [ Other ] - Allow people to use Carp::{confess,cluck,carp} with Type::Params validators; default is still croak. - Improved Type::Params documentation. - Type::Params validators now explicitly check the number of arguments passed to them. Vyacheslav Matyukhin++ 0.003_11 2013-04-30 [ Test Suite ] - Test cases for Eval::TypeTiny. [ Other ] - Automatic coercion for parameterized Dict will no longer drop key/value pairs to force a coercion. Vyacheslav Matyukhin++ - Automatic coercion for parameterized Tuple will no longer drop values to force a coercion. Vyacheslav Matyukhin++ 0.003_10 2013-04-29 [ Documentation ] - Improve Exporter::TypeTiny documentation. - Improve advice on inlining type constraints and coercions. [ Packaging ] - Bump version of Test::More dependency fom 0.88 to 0.96. [ Other ] - Added: Bundle Type::Params, which had previously appeared on CPAN in a separate developer release. - Added: New module, Eval::TypeTiny - Added: Type::Tiny::SUPPORT_SMARTMATCH constant. - General code tidy-up. - Much of the stringy eval stuff has been factored out into Eval::TypeTiny. 0.003_09 2013-04-28 [ Documentation ] - Document usage with Params::Check and Object::Accessor. [ Other ] - Added: 'Tied' type constraint added to Types::Standard. - If Mouse is already in memory, Type::Tiny will use its super-fast XS subs to validate values when possible. 0.003_08 2013-04-26 [ Documentation ] - More Exporter::TypeTiny docs, including usage with Sub::Exporter::Lexical. [ Test Suite ] - Add test case using Exporter::TypeTiny with Sub::Exporter::Lexical. [ Other ] - ASCII-only strings are now accepted by the Chars constraint in Types::Standard. - Type::Tiny, Type::Coercion and their subclasses no longer call Types::TypeTiny->import method. - Types::TypeTiny lazily loads Exporter::TypeTiny - i.e. it loads Exporter::TypeTiny when Types::TypeTiny->import is first called. 0.003_07 2013-04-26 [ Bug Fixes ] - Fix method conflicts when exporting type constraints to roles. Kevin Dawson++ [ Documentation ] - Document usage with Class::InsideOut. - Minor improvements to manual. 0.003_06 2013-04-25 [ Documentation ] - Add lots of stuff to Type::Tiny::Manual::UsingWithMouse. - Document deep coercions (feature added in 0.003_01). [ Other ] - Add a bunch of stub methods to Type::Tiny and Type::Coercion in order to make it less necessary to inflate to Moose/Mouse meta objects. - No longer need to add '-mouse' when importing types into Mouse libraries. (Same change as what we did for Moose in 0.000_11.) - Types::TypeTiny::to_TypeTiny can now coerce from a Mouse::Meta::TypeConstraint. - Various minor changes to Exporter::TypeTiny to make it more Sub::Exporter compatible. 0.003_05 2013-04-19 [ Bug Fixes ] - Prevent warnings (about 'my $val' masking a previously declared variable) when several Str checks are being inlined in close proximity, such as Tuple[Str,Str] [ Documentation ] - Create a new manual page Type::Tiny::Manual::Coercions. - Document Exporter::TypeTiny. [ Other ] - Added: Chars and Bytes types added to Types::Standard. - Added: Encode, Decode, Join and Split coercions added to Types::Standard. - Added: Type::Tiny::Class now has a plus_constructors method. - Allow coercions to accept parameters. 0.003_04 2013-04-18 - Factor out the sub exporting code scattered around (in Type::Utils, Types::TypeTiny and Type::Library) into a single module, Exporter::TypeTiny. 0.003_03 2013-04-17 - Added: Add OptList data type to Types::Standard, plus MkOpt coercion. - Make Type::Tiny's has_coercion method more DWIM. - When inflating Moo type constraints to Moose, don't unnecessarily call 'moose_type' method. 0.003_02 2013-04-16 [ Documentation ] - Document how to process sub parameters with Type::Tiny, and point people towards Type::Params. [ Other ] - Avoid unnecessarily regenerating parameterized type constraints. 0.003_01 2013-04-16 [ Documentation ] - Link from Test::TypeTiny to Test::Deep::Type. [ Other ] - Allow a Type::Tiny object to "freeze" its coercions. This prevents a Type::Tiny object from becoming out of sync with its equivalent Mouse or Moose constraint objects. - Allow subtypes to inherit coercions from their parent type constraint. (They do not by default.) - Build coercions automatically for certain type parameterized constraints. Say there's a Num->Int coercion defined; then we should be able to coerce ArrayRef[Num]->ArrayRef[Int]. - Overload "+" operator for Type::Coercion and Type::Tiny allows coercions to be added to each other, and added to type constraints. - Type::Library packages can now include "standalone" Type::Coercion objects, not attached to a type constraint. These can be exported on request. 0.002 2013-04-26 [ Bug Fixes ] - Fix method conflicts when exporting type constraints to roles. Kevin Dawson++ - Prevent warnings (about 'my $val' masking a previously declared variable) when several Str checks are being inlined in close proximity, such as Tuple[Str,Str] [ Documentation ] - Link from Test::TypeTiny to Test::Deep::Type. [ Other ] - Added: Chars and Bytes types added to Types::Standard. - Avoid unnecessarily regenerating parameterized type constraints. - Make Type::Tiny's has_coercion method more DWIM. 0.001 2013-04-15 First public release [ Bug Fixes ] - Some inline code assumed that it would be compiled in a package that had 'blessed' imported. - Some inline code wasn't wrapped in parentheses. [ Documentation ] - Minor improvements. [ Test Suite ] - More test cases for Optional[`a] within Dict[`a]. [ Other ] - Improve test names generated by Test::TypeTiny; allow test scripts to provide test names. - Parameterized type constraints in Types::Standard now do some sanity checking on their arguments. - Weaken the reference from a Moose::Meta::TypeConstraint object to its Type::Tiny origin. 0.000_12 2013-04-12 [ Documentation ] - Fix minor typo. 0.000_11 2013-04-11 [ Bug Fixes ] - Fix prototype for Type::Utils::as. [ Other ] - No longer need to pass '-moose' parameter when importing a library into a Moose class; only Mouse needs that treatment now. 0.000_10 2013-04-09 [ Bug Fixes ] - Fix incorrect Test::Requires line in 'mouse-coercion.t'. [ Other ] - Improvements to has_coercion_for_{type,value} from Type::Coercion. 0.000_09 2013-04-08 [ Documentation ] - Bundle benchmarking scripts. - Fill in the Usage with Moose section of the fine manual. [ Packaging ] - Tidy up the 'examples' directory. [ Other ] - When generating Moose/Mouse constraints from Type::Tiny objects, prefer to generate anonymous ones. 0.000_08 2013-04-07 - Most parts of the API that accept Type::Tiny objects (e.g. Type::Utils::from()) now also accept Moose::Meta::TypeConstraint objects. - Rewrite most of the functions exported by Type::Library-based type libraries to cope better with being used mid-list. - Types::TypeTiny::to_TypeTiny can be used to coerce a Moose type constraint object to Type::Tiny. 0.000_07 2013-04-06 [ Bug Fixes ] - Fix inlining for Type::Tiny::Intersection. - Fix inlining of certain conditionals into coercion code. - Types within libraries, if accessed directly rather than exported, did not accept parameters. [ Documentation ] - Document constructor for Type::Tiny::Class. [ Test Suite ] - More test cases. [ Other ] - Added: New module Type::Coercion::Union automatically handles coercion to union types. 0.000_06 2013-04-05 [ Documentation ] - Improved documentation of parameterization attributes. - Section in manual comparing Type::Tiny with various other type library frameworks. - Using Type::Tiny with Moo added to manual. [ Test Suite ] - More test cases. [ Other ] - Added: Type::Tiny now has an 'inline_assert' function. - Footprint reduction: Type::Tiny and Type::Coercion no longer use if.pm. - Footprint reduction: Type::Tiny no longer triggers Perl to load its Unicode tables (unless you create a type constraint with a non-ASCII type name). - Footprint reduction: Type::Tiny, Type::Library and Type::Coerce no longer automatically load Types::Standard and Type::Utils. - In Moo, type assertions and coercions are now inlined. Matt S Trout++ - Monkey patch Moose::Meta::TypeConstraint to be able to retrieve Type::Tiny constraints from inflated Moose constraints. 0.000_05 2013-04-04 [ BACK COMPAT ] - Rename Type::Standard module to Types::Standard. [ Bug Fixes ] - Fix is_parameterized method. - Get Mouse coercions working. [ Test Suite ] - Factor out some functions from test suite into a new module: Test::TypeTiny. - Rearrange test suite slightly. [ Other ] - Allow null type constraints with no parent type (e.g. 'Any' in Types::Standard) to be inlined. - Don't die with full stack trace. - Sanity checks for type constraint names. - Types::TypeTiny bootstrapping library now takes care of vaious internal type checking requirements. 0.000_04 2013-04-03 - Added: Finally implement Type::Coercion's has_coercion_for_type method. - Added: Type::Tiny equals/is_subtype_of/is_supertype_of/is_a_type_of methods for type constraint comparisons. - Added: Type::Tiny plus_coercions/minus_coercions/no_coercions methods for creating subtypes with different sets of coercions. - Allow coercion code to be expressed as a string; quite a bit faster. - Create and use compiled coercions; somewhat faster. 0.000_03 2013-04-03 [ Bug Fixes ] - Fix the crashing t/moo-inflation.t test case. [ Documentation ] - Document Type::Coercion's overloading. [ Test Suite ] - Add test cases for ScalarRef[`a]. [ Other ] - All of Type::Standard cannow be inlined. - Create and use compiled type constraint checks; much faster! - Make sure Type::Standard's Moose-like built-ins get inflated to real Moose built-in types. - Use more unique stringification for %Moo::HandleMoose::TYPE_MAP keys. 0.000_02 2013-04-02 [ Bug Fixes ] - Anchor enum regexps to beginning and end of string. [ Documentation ] - Beginnings of Type::Tiny::Manual. [ Other ] - Added: StrMatch added to Type::Standard. - use Type::Library -base - use Type::Library -declare 0.000_01 2013-04-02 Developer preview INSTALL000644001750001750 165313601673061 13443 0ustar00taitai000000000000Type-Tiny-1.008001 Installing Type-Tiny should be straightforward. INSTALLATION WITH CPANMINUS If you have cpanm, you only need one line: % cpanm Type::Tiny If you are installing into a system-wide directory, you may need to pass the "-S" flag to cpanm, which uses sudo to install the module: % cpanm -S Type::Tiny INSTALLATION WITH THE CPAN SHELL Alternatively, if your CPAN shell is set up, you should just be able to do: % cpan Type::Tiny MANUAL INSTALLATION As a last resort, you can manually install it. Download the tarball and unpack it. Consult the file META.json for a list of pre-requisites. Install these first. To build Type-Tiny: % perl Makefile.PL % make && make test Then install it: % make install If you are installing into a system-wide directory, you may need to run: % sudo make install LICENSE000644001750001750 4365513601673061 13447 0ustar00taitai000000000000Type-Tiny-1.008001This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- This software is Copyright (c) 2019 by Toby Inkster. This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! --- The Artistic License 1.0 --- This software is Copyright (c) 2019 by Toby Inkster. This is free software, licensed under: The Artistic License 1.0 The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: - "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. - "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. - "Copyright Holder" is whoever is named in the copyright or copyrights for the package. - "You" is you, if you're thinking about copying or distributing this Package. - "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) - "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End MANIFEST000644001750001750 2570313601673167 13574 0ustar00taitai000000000000Type-Tiny-1.008001CONTRIBUTING COPYRIGHT CREDITS Changes INSTALL LICENSE MANIFEST META.json META.yml Makefile.PL NEWS README SIGNATURE dist.ini doap.ttl examples/benchmarking/benchmark-coercions.pl examples/benchmarking/benchmark-constraints.pl examples/benchmarking/benchmark-named-param-validation.pl examples/benchmarking/benchmark-param-validation.pl examples/benchmarking/versus-scalar-validation.pl examples/datetime-coercions.pl examples/nonempty.pl examples/page-numbers.pl inc/Test/Fatal.pm inc/Test/Requires.pm inc/Try/Tiny.pm inc/archaic/Test/Builder.pm inc/archaic/Test/Builder/IO/Scalar.pm inc/archaic/Test/Builder/Module.pm inc/archaic/Test/Builder/Tester.pm inc/archaic/Test/Builder/Tester/Color.pm inc/archaic/Test/More.pm inc/archaic/Test/Simple.pm lib/Devel/TypeTiny/Perl56Compat.pm lib/Devel/TypeTiny/Perl58Compat.pm lib/Error/TypeTiny.pm lib/Error/TypeTiny/Assertion.pm lib/Error/TypeTiny/Compilation.pm lib/Error/TypeTiny/WrongNumberOfParameters.pm lib/Eval/TypeTiny.pm lib/Reply/Plugin/TypeTiny.pm lib/Test/TypeTiny.pm lib/Type/Coercion.pm lib/Type/Coercion/FromMoose.pm lib/Type/Coercion/Union.pm lib/Type/Library.pm lib/Type/Params.pm lib/Type/Parser.pm lib/Type/Registry.pm lib/Type/Tiny.pm lib/Type/Tiny/Class.pm lib/Type/Tiny/ConstrainedObject.pm lib/Type/Tiny/Duck.pm lib/Type/Tiny/Enum.pm lib/Type/Tiny/Intersection.pm lib/Type/Tiny/Manual.pod lib/Type/Tiny/Manual/AllTypes.pod lib/Type/Tiny/Manual/Coercions.pod lib/Type/Tiny/Manual/Contributing.pod lib/Type/Tiny/Manual/Installation.pod lib/Type/Tiny/Manual/Libraries.pod lib/Type/Tiny/Manual/NonOO.pod lib/Type/Tiny/Manual/Optimization.pod lib/Type/Tiny/Manual/Params.pod lib/Type/Tiny/Manual/Policies.pod lib/Type/Tiny/Manual/UsingWithClassTiny.pod lib/Type/Tiny/Manual/UsingWithMoo.pod lib/Type/Tiny/Manual/UsingWithMoo2.pod lib/Type/Tiny/Manual/UsingWithMoo3.pod lib/Type/Tiny/Manual/UsingWithMoose.pod lib/Type/Tiny/Manual/UsingWithMouse.pod lib/Type/Tiny/Manual/UsingWithOther.pod lib/Type/Tiny/Manual/UsingWithTestMore.pod lib/Type/Tiny/Role.pm lib/Type/Tiny/Union.pm lib/Type/Tiny/_HalfOp.pm lib/Type/Utils.pm lib/Types/Common/Numeric.pm lib/Types/Common/String.pm lib/Types/Standard.pm lib/Types/Standard/ArrayRef.pm lib/Types/Standard/CycleTuple.pm lib/Types/Standard/Dict.pm lib/Types/Standard/HashRef.pm lib/Types/Standard/Map.pm lib/Types/Standard/ScalarRef.pm lib/Types/Standard/StrMatch.pm lib/Types/Standard/Tied.pm lib/Types/Standard/Tuple.pm lib/Types/TypeTiny.pm t/00-begin.t t/01-compile.t t/02-api.t t/03-leak.t t/20-unit/Devel-TypeTiny-Perl56Compat/basic.t t/20-unit/Devel-TypeTiny-Perl58Compat/basic.t t/20-unit/Error-TypeTiny-Assertion/basic.t t/20-unit/Error-TypeTiny-Compilation/basic.t t/20-unit/Error-TypeTiny-WrongNumberOfParameters/basic.t t/20-unit/Error-TypeTiny/basic.t t/20-unit/Error-TypeTiny/stacktrace.t t/20-unit/Eval-TypeTiny/aliases-devel-lexalias.t t/20-unit/Eval-TypeTiny/aliases-native.t t/20-unit/Eval-TypeTiny/aliases-padwalker.t t/20-unit/Eval-TypeTiny/aliases-tie.t t/20-unit/Eval-TypeTiny/basic.t t/20-unit/Eval-TypeTiny/lexical-subs.t t/20-unit/Test-TypeTiny/basic.t t/20-unit/Test-TypeTiny/extended.t t/20-unit/Test-TypeTiny/matchfor.t t/20-unit/Type-Coercion-FromMoose/basic.t t/20-unit/Type-Coercion-FromMoose/errors.t t/20-unit/Type-Coercion-Union/basic.t t/20-unit/Type-Coercion/basic.t t/20-unit/Type-Coercion/esoteric.t t/20-unit/Type-Coercion/frozen.t t/20-unit/Type-Coercion/inlining.t t/20-unit/Type-Coercion/parameterized.t t/20-unit/Type-Coercion/smartmatch.t t/20-unit/Type-Coercion/typetiny-constructor.t t/20-unit/Type-Library/assert.t t/20-unit/Type-Library/deprecation.t t/20-unit/Type-Library/errors.t t/20-unit/Type-Library/import-params.t t/20-unit/Type-Library/inheritance.t t/20-unit/Type-Library/is.t t/20-unit/Type-Library/to.t t/20-unit/Type-Library/types.t t/20-unit/Type-Params/badsigs.t t/20-unit/Type-Params/carping.t t/20-unit/Type-Params/coerce.t t/20-unit/Type-Params/compile-named-bless.t t/20-unit/Type-Params/compile-named-oo.t t/20-unit/Type-Params/compile-named.t t/20-unit/Type-Params/defaults.t t/20-unit/Type-Params/hashorder.t t/20-unit/Type-Params/methods.t t/20-unit/Type-Params/mixednamed.t t/20-unit/Type-Params/multisig-custom-message.t t/20-unit/Type-Params/multisig.t t/20-unit/Type-Params/named-to-list.t t/20-unit/Type-Params/named.t t/20-unit/Type-Params/noninline.t t/20-unit/Type-Params/optional.t t/20-unit/Type-Params/positional.t t/20-unit/Type-Params/slurpy.t t/20-unit/Type-Params/wrap.t t/20-unit/Type-Parser/basic.t t/20-unit/Type-Parser/moosextypes.t t/20-unit/Type-Registry/automagic.t t/20-unit/Type-Registry/basic.t t/20-unit/Type-Registry/methods.t t/20-unit/Type-Registry/moosextypes.t t/20-unit/Type-Registry/mousextypes.t t/20-unit/Type-Tiny-Class/basic.t t/20-unit/Type-Tiny-Class/errors.t t/20-unit/Type-Tiny-Class/plus-constructors.t t/20-unit/Type-Tiny-ConstrainedObject/basic.t t/20-unit/Type-Tiny-Duck/basic.t t/20-unit/Type-Tiny-Duck/cmp.t t/20-unit/Type-Tiny-Duck/errors.t t/20-unit/Type-Tiny-Enum/basic.t t/20-unit/Type-Tiny-Enum/cmp.t t/20-unit/Type-Tiny-Enum/errors.t t/20-unit/Type-Tiny-Intersection/basic.t t/20-unit/Type-Tiny-Intersection/cmp.t t/20-unit/Type-Tiny-Intersection/constrainedobject.t t/20-unit/Type-Tiny-Intersection/errors.t t/20-unit/Type-Tiny-Role/basic.t t/20-unit/Type-Tiny-Role/errors.t t/20-unit/Type-Tiny-Union/basic.t t/20-unit/Type-Tiny-Union/constrainedobject.t t/20-unit/Type-Tiny-Union/errors.t t/20-unit/Type-Tiny-Union/relationships.t t/20-unit/Type-Tiny-_HalfOp/double-union.t t/20-unit/Type-Tiny-_HalfOp/overload-precedence.t t/20-unit/Type-Tiny/arithmetic.t t/20-unit/Type-Tiny/basic.t t/20-unit/Type-Tiny/cmp.t t/20-unit/Type-Tiny/coercion-modifiers.t t/20-unit/Type-Tiny/constraint-strings.t t/20-unit/Type-Tiny/deprecation.t t/20-unit/Type-Tiny/esoteric.t t/20-unit/Type-Tiny/inline-assert.t t/20-unit/Type-Tiny/my-methods.t t/20-unit/Type-Tiny/parameterization.t t/20-unit/Type-Tiny/shortcuts.t t/20-unit/Type-Tiny/smartmatch.t t/20-unit/Type-Tiny/syntax.t t/20-unit/Type-Tiny/to-moose.t t/20-unit/Type-Tiny/to-mouse.t t/20-unit/Type-Utils/classifier.t t/20-unit/Type-Utils/dwim-both.t t/20-unit/Type-Utils/dwim-moose.t t/20-unit/Type-Utils/dwim-mouse.t t/20-unit/Type-Utils/match-on-type.t t/20-unit/Type-Utils/warnings.t t/20-unit/Types-Common-Numeric/basic.t t/20-unit/Types-Common-Numeric/ranges.t t/20-unit/Types-Common-String/basic.t t/20-unit/Types-Common-String/coerce.t t/20-unit/Types-Common-String/strlength.t t/20-unit/Types-Common-String/unicode.t t/20-unit/Types-Standard/arrayreflength.t t/20-unit/Types-Standard/basic.t t/20-unit/Types-Standard/cycletuple.t t/20-unit/Types-Standard/deep-coercions.t t/20-unit/Types-Standard/filehandle.t t/20-unit/Types-Standard/lockdown.t t/20-unit/Types-Standard/mxtmlb-alike.t t/20-unit/Types-Standard/optlist.t t/20-unit/Types-Standard/overload.t t/20-unit/Types-Standard/strmatch-allow-callbacks.t t/20-unit/Types-Standard/strmatch-avoid-callbacks.t t/20-unit/Types-Standard/strmatch.t t/20-unit/Types-Standard/structured.t t/20-unit/Types-Standard/tied.t t/20-unit/Types-TypeTiny/basic.t t/20-unit/Types-TypeTiny/coercion.t t/20-unit/Types-TypeTiny/meta.t t/20-unit/Types-TypeTiny/moosemouse.t t/20-unit/Types-TypeTiny/progressiveexporter.t t/21-types/Any.t t/21-types/ArrayLike.t t/21-types/ArrayRef.t t/21-types/Bool.t t/21-types/ClassName.t t/21-types/CodeLike.t t/21-types/CodeRef.t t/21-types/ConsumerOf.t t/21-types/CycleTuple.t t/21-types/Defined.t t/21-types/Dict.t t/21-types/Enum.t t/21-types/FileHandle.t t/21-types/GlobRef.t t/21-types/HasMethods.t t/21-types/HashLike.t t/21-types/HashRef.t t/21-types/InstanceOf.t t/21-types/Int.t t/21-types/IntRange.t t/21-types/Item.t t/21-types/LaxNum.t t/21-types/LowerCaseSimpleStr.t t/21-types/LowerCaseStr.t t/21-types/Map.t t/21-types/Maybe.t t/21-types/NegativeInt.t t/21-types/NegativeNum.t t/21-types/NegativeOrZeroInt.t t/21-types/NegativeOrZeroNum.t t/21-types/NonEmptySimpleStr.t t/21-types/NonEmptyStr.t t/21-types/Num.t t/21-types/NumRange.t t/21-types/NumericCode.t t/21-types/Object.t t/21-types/OptList.t t/21-types/Optional.t t/21-types/Overload.t t/21-types/Password.t t/21-types/PositiveInt.t t/21-types/PositiveNum.t t/21-types/PositiveOrZeroInt.t t/21-types/PositiveOrZeroNum.t t/21-types/Ref.t t/21-types/RegexpRef.t t/21-types/RoleName.t t/21-types/ScalarRef.t t/21-types/SimpleStr.t t/21-types/SingleDigit.t t/21-types/Str.t t/21-types/StrLength.t t/21-types/StrMatch.t t/21-types/StrictNum.t t/21-types/StringLike.t t/21-types/StrongPassword.t t/21-types/Tied.t t/21-types/Tuple.t t/21-types/TypeTiny.t t/21-types/Undef.t t/21-types/UpperCaseSimpleStr.t t/21-types/UpperCaseStr.t t/21-types/Value.t t/30-integration/Class-InsideOut/basic.t t/30-integration/Exporter-Tiny/basic.t t/30-integration/Exporter-Tiny/installer.t t/30-integration/Exporter-Tiny/role-conflict.t t/30-integration/Function-Parameters/basic.t t/30-integration/Kavorka/80returntype.t t/30-integration/Kavorka/basic.t t/30-integration/Moo/basic.t t/30-integration/Moo/coercion-inlining-avoidance.t t/30-integration/Moo/coercion.t t/30-integration/Moo/exceptions.t t/30-integration/Moo/inflation.t t/30-integration/Moo/inflation2.t t/30-integration/Moops/basic.t t/30-integration/Moops/library-keyword.t t/30-integration/Moose/accept-moose-types.t t/30-integration/Moose/basic.t t/30-integration/Moose/coercion-more.t t/30-integration/Moose/coercion.t t/30-integration/Moose/inflate-then-inline.t t/30-integration/Moose/native-attribute-traits.t t/30-integration/Moose/parameterized.t t/30-integration/MooseX-Getopt/coercion.t t/30-integration/MooseX-Types/basic.t t/30-integration/MooseX-Types/extending.t t/30-integration/MooseX-Types/more.t t/30-integration/Mouse/basic.t t/30-integration/Mouse/coercion.t t/30-integration/Mouse/parameterized.t t/30-integration/MouseX-Types/basic.t t/30-integration/MouseX-Types/extending.t t/30-integration/Object-Accessor/basic.t t/30-integration/Return-Type/basic.t t/30-integration/Specio/basic.t t/30-integration/Specio/library.t t/30-integration/Sub-Quote/basic.t t/30-integration/Sub-Quote/delayed-quoting.t t/30-integration/Sub-Quote/unquote-coercions.t t/30-integration/Sub-Quote/unquote-constraints.t t/30-integration/Switcheroo/basic.t t/30-integration/Type-Tie/basic.t t/30-integration/Types-ReadOnly/basic.t t/30-integration/Validation-Class-Simple/archaic.t t/30-integration/Validation-Class-Simple/basic.t t/30-integration/match-simple/basic.t t/40-regression/73f51e2d.pl t/40-regression/73f51e2d.t t/40-regression/gh1.t t/40-regression/gh14.t t/40-regression/rt102748.t t/40-regression/rt104154.t t/40-regression/rt121763.t t/40-regression/rt125132.t t/40-regression/rt125765.t t/40-regression/rt129729.t t/40-regression/rt130823.t t/40-regression/rt85911.t t/40-regression/rt86004.t t/40-regression/rt86233.t t/40-regression/rt86239.t t/40-regression/rt90096-2.t t/40-regression/rt90096.t t/40-regression/rt92571-2.t t/40-regression/rt92571.t t/40-regression/rt92591.t t/40-regression/rt94196.t t/40-regression/rt97684.t t/40-regression/rt98113.t t/40-regression/ttxs-gh1.t t/98-param-eg-from-docs.t t/99-moose-std-types-test.t t/README t/TODO t/lib/BiggerLib.pm t/lib/DemoLib.pm t/mk-test-manifest.pl t/not-covered.pl META.json000644001750001750 2126513601673167 14063 0ustar00taitai000000000000Type-Tiny-1.008001{ "abstract" : "tiny, yet Moo(se)-compatible type constraint", "author" : [ "Toby Inkster (TOBYINK) " ], "dynamic_config" : 1, "generated_by" : "Dist::Inkt::Profile::TOBYINK version 0.024, CPAN::Meta::Converter version 2.150010", "keywords" : [ "Argument Checking", "Argument Validation", "Moo", "Moose", "Mouse", "Parameter Checking", "Parameter Validation", "Schema", "Type Coercion", "Type Constraint", "Type Library", "Validation" ], "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Type-Tiny", "no_index" : { "directory" : [ "eg", "examples", "inc", "t", "xt" ] }, "optional_features" : {}, "prereqs" : { "configure" : { "recommends" : { "CPAN::Meta::Requirements" : "2.000" }, "requires" : { "ExtUtils::MakeMaker" : "6.17" } }, "develop" : { "recommends" : { "Test::Memory::Cycle" : "0" }, "suggests" : { "Dist::Inkt::Profile::TOBYINK" : "0" } }, "runtime" : { "conflicts" : { "Kavorka" : "<= 0.013", "Types::ReadOnly" : "<= 0.001" }, "recommends" : { "Devel::LexAlias" : "0.05", "Devel::StackTrace" : "0", "Ref::Util::XS" : "0.100", "Regexp::Util" : "0.003", "Sub::Util" : "0", "Type::Tie" : "0", "Type::Tiny::XS" : "0.016", "perl" : "5.010001" }, "requires" : { "Exporter::Tiny" : "1.000000", "perl" : "5.006001" }, "suggests" : { "Moo" : "1.006000", "Moose" : "2.0000", "Mouse" : "1.00", "Reply" : "0" } }, "test" : { "recommends" : { "Test::Tester" : "0.109", "Test::Warnings" : "0" }, "requires" : { "Test::More" : "0.96" }, "suggests" : { "Test::Memory::Cycle" : "0" } } }, "provides" : { "Devel::TypeTiny::Perl56Compat" : { "file" : "lib/Devel/TypeTiny/Perl56Compat.pm", "version" : "1.008001" }, "Devel::TypeTiny::Perl58Compat" : { "file" : "lib/Devel/TypeTiny/Perl58Compat.pm", "version" : "1.008001" }, "Error::TypeTiny" : { "file" : "lib/Error/TypeTiny.pm", "version" : "1.008001" }, "Error::TypeTiny::Assertion" : { "file" : "lib/Error/TypeTiny/Assertion.pm", "version" : "1.008001" }, "Error::TypeTiny::Compilation" : { "file" : "lib/Error/TypeTiny/Compilation.pm", "version" : "1.008001" }, "Error::TypeTiny::WrongNumberOfParameters" : { "file" : "lib/Error/TypeTiny/WrongNumberOfParameters.pm", "version" : "1.008001" }, "Eval::TypeTiny" : { "file" : "lib/Eval/TypeTiny.pm", "version" : "1.008001" }, "Reply::Plugin::TypeTiny" : { "file" : "lib/Reply/Plugin/TypeTiny.pm", "version" : "1.008001" }, "Test::TypeTiny" : { "file" : "lib/Test/TypeTiny.pm", "version" : "1.008001" }, "Type::Coercion" : { "file" : "lib/Type/Coercion.pm", "version" : "1.008001" }, "Type::Coercion::FromMoose" : { "file" : "lib/Type/Coercion/FromMoose.pm", "version" : "1.008001" }, "Type::Coercion::Union" : { "file" : "lib/Type/Coercion/Union.pm", "version" : "1.008001" }, "Type::Library" : { "file" : "lib/Type/Library.pm", "version" : "1.008001" }, "Type::Params" : { "file" : "lib/Type/Params.pm", "version" : "1.008001" }, "Type::Parser" : { "file" : "lib/Type/Parser.pm", "version" : "1.008001" }, "Type::Registry" : { "file" : "lib/Type/Registry.pm", "version" : "1.008001" }, "Type::Tiny" : { "file" : "lib/Type/Tiny.pm", "version" : "1.008001" }, "Type::Tiny::Class" : { "file" : "lib/Type/Tiny/Class.pm", "version" : "1.008001" }, "Type::Tiny::ConstrainedObject" : { "file" : "lib/Type/Tiny/ConstrainedObject.pm", "version" : "1.008001" }, "Type::Tiny::Duck" : { "file" : "lib/Type/Tiny/Duck.pm", "version" : "1.008001" }, "Type::Tiny::Enum" : { "file" : "lib/Type/Tiny/Enum.pm", "version" : "1.008001" }, "Type::Tiny::Intersection" : { "file" : "lib/Type/Tiny/Intersection.pm", "version" : "1.008001" }, "Type::Tiny::Role" : { "file" : "lib/Type/Tiny/Role.pm", "version" : "1.008001" }, "Type::Tiny::Union" : { "file" : "lib/Type/Tiny/Union.pm", "version" : "1.008001" }, "Type::Utils" : { "file" : "lib/Type/Utils.pm", "version" : "1.008001" }, "Types::Common::Numeric" : { "file" : "lib/Types/Common/Numeric.pm", "version" : "1.008001" }, "Types::Common::String" : { "file" : "lib/Types/Common/String.pm", "version" : "1.008001" }, "Types::Standard" : { "file" : "lib/Types/Standard.pm", "version" : "1.008001" }, "Types::Standard::ArrayRef" : { "file" : "lib/Types/Standard/ArrayRef.pm", "version" : "1.008001" }, "Types::Standard::CycleTuple" : { "file" : "lib/Types/Standard/CycleTuple.pm", "version" : "1.008001" }, "Types::Standard::Dict" : { "file" : "lib/Types/Standard/Dict.pm", "version" : "1.008001" }, "Types::Standard::HashRef" : { "file" : "lib/Types/Standard/HashRef.pm", "version" : "1.008001" }, "Types::Standard::Map" : { "file" : "lib/Types/Standard/Map.pm", "version" : "1.008001" }, "Types::Standard::ScalarRef" : { "file" : "lib/Types/Standard/ScalarRef.pm", "version" : "1.008001" }, "Types::Standard::StrMatch" : { "file" : "lib/Types/Standard/StrMatch.pm", "version" : "1.008001" }, "Types::Standard::Tied" : { "file" : "lib/Types/Standard/Tied.pm", "version" : "1.008001" }, "Types::Standard::Tuple" : { "file" : "lib/Types/Standard/Tuple.pm", "version" : "1.008001" }, "Types::TypeTiny" : { "file" : "lib/Types/TypeTiny.pm", "version" : "1.008001" } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "http://rt.cpan.org/Dist/Display.html?Queue=Type-Tiny" }, "homepage" : "http://typetiny.toby.ink/", "license" : [ "http://dev.perl.org/licenses/" ], "repository" : { "type" : "git", "url" : "git://github.com/tobyink/p5-type-tiny.git", "web" : "https://github.com/tobyink/p5-type-tiny" }, "x_identifier" : "http://purl.org/NET/cpan-uri/dist/Type-Tiny/project" }, "version" : "1.008001", "x_breaks" : { "Kavorka" : "<= 0.013", "Types::ReadOnly" : "<= 0.001" }, "x_contributors" : [ "Diab Jerius (DJERIUS) ", "Vyacheslav Matyukhin (MMCLERIC) ", "Peter Flanigan (PJFL) ", "Pierre Masci", "Mark Stosberg (MARKSTOS) ", "David Steinbrunner ", "Samuel Kaufman (SKAUFMAN) ", "Graham Knop (HAARG) ", "Peter Karman (KARMAN) ", "Alexander Hartmaier (ABRAXXA) ", "Dagfinn Ilmari Mannsåker (ILMARI) ", "Gianni Ceccarelli (DAKKAR) ", "Karen Etheridge (ETHER) ", "Thomas Sibley (TSIBLEY) ", "Peter Valdemar Mørch ", "Zoffix Znet ", "Denis Ibaev ", "Lucas Buchala (LSBUCHALA) ", "Alexandr Ciornii ", "Philippe Bruhat (BOOK) ", "Robert Rothenberg (RRWO) ", "Nelo Onyiah", "Jonas B Nielsen (JONASBN) ", "Benct Philip Jonsson " ], "x_serialization_backend" : "JSON::PP version 2.27400_02" } META.yml000644001750001750 1331713601673167 13712 0ustar00taitai000000000000Type-Tiny-1.008001--- abstract: 'tiny, yet Moo(se)-compatible type constraint' author: - 'Toby Inkster (TOBYINK) ' build_requires: Test::More: '0.96' configure_requires: ExtUtils::MakeMaker: '6.17' conflicts: Kavorka: '<= 0.013' Types::ReadOnly: '<= 0.001' dynamic_config: 1 generated_by: 'Dist::Inkt::Profile::TOBYINK version 0.024, CPAN::Meta::Converter version 2.150010' keywords: - 'Argument Checking' - 'Argument Validation' - Moo - Moose - Mouse - 'Parameter Checking' - 'Parameter Validation' - Schema - 'Type Coercion' - 'Type Constraint' - 'Type Library' - Validation license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Type-Tiny no_index: directory: - eg - examples - inc - t - xt optional_features: {} provides: Devel::TypeTiny::Perl56Compat: file: lib/Devel/TypeTiny/Perl56Compat.pm version: '1.008001' Devel::TypeTiny::Perl58Compat: file: lib/Devel/TypeTiny/Perl58Compat.pm version: '1.008001' Error::TypeTiny: file: lib/Error/TypeTiny.pm version: '1.008001' Error::TypeTiny::Assertion: file: lib/Error/TypeTiny/Assertion.pm version: '1.008001' Error::TypeTiny::Compilation: file: lib/Error/TypeTiny/Compilation.pm version: '1.008001' Error::TypeTiny::WrongNumberOfParameters: file: lib/Error/TypeTiny/WrongNumberOfParameters.pm version: '1.008001' Eval::TypeTiny: file: lib/Eval/TypeTiny.pm version: '1.008001' Reply::Plugin::TypeTiny: file: lib/Reply/Plugin/TypeTiny.pm version: '1.008001' Test::TypeTiny: file: lib/Test/TypeTiny.pm version: '1.008001' Type::Coercion: file: lib/Type/Coercion.pm version: '1.008001' Type::Coercion::FromMoose: file: lib/Type/Coercion/FromMoose.pm version: '1.008001' Type::Coercion::Union: file: lib/Type/Coercion/Union.pm version: '1.008001' Type::Library: file: lib/Type/Library.pm version: '1.008001' Type::Params: file: lib/Type/Params.pm version: '1.008001' Type::Parser: file: lib/Type/Parser.pm version: '1.008001' Type::Registry: file: lib/Type/Registry.pm version: '1.008001' Type::Tiny: file: lib/Type/Tiny.pm version: '1.008001' Type::Tiny::Class: file: lib/Type/Tiny/Class.pm version: '1.008001' Type::Tiny::ConstrainedObject: file: lib/Type/Tiny/ConstrainedObject.pm version: '1.008001' Type::Tiny::Duck: file: lib/Type/Tiny/Duck.pm version: '1.008001' Type::Tiny::Enum: file: lib/Type/Tiny/Enum.pm version: '1.008001' Type::Tiny::Intersection: file: lib/Type/Tiny/Intersection.pm version: '1.008001' Type::Tiny::Role: file: lib/Type/Tiny/Role.pm version: '1.008001' Type::Tiny::Union: file: lib/Type/Tiny/Union.pm version: '1.008001' Type::Utils: file: lib/Type/Utils.pm version: '1.008001' Types::Common::Numeric: file: lib/Types/Common/Numeric.pm version: '1.008001' Types::Common::String: file: lib/Types/Common/String.pm version: '1.008001' Types::Standard: file: lib/Types/Standard.pm version: '1.008001' Types::Standard::ArrayRef: file: lib/Types/Standard/ArrayRef.pm version: '1.008001' Types::Standard::CycleTuple: file: lib/Types/Standard/CycleTuple.pm version: '1.008001' Types::Standard::Dict: file: lib/Types/Standard/Dict.pm version: '1.008001' Types::Standard::HashRef: file: lib/Types/Standard/HashRef.pm version: '1.008001' Types::Standard::Map: file: lib/Types/Standard/Map.pm version: '1.008001' Types::Standard::ScalarRef: file: lib/Types/Standard/ScalarRef.pm version: '1.008001' Types::Standard::StrMatch: file: lib/Types/Standard/StrMatch.pm version: '1.008001' Types::Standard::Tied: file: lib/Types/Standard/Tied.pm version: '1.008001' Types::Standard::Tuple: file: lib/Types/Standard/Tuple.pm version: '1.008001' Types::TypeTiny: file: lib/Types/TypeTiny.pm version: '1.008001' recommends: Devel::LexAlias: '0.05' Devel::StackTrace: '0' Ref::Util::XS: '0.100' Regexp::Util: '0.003' Sub::Util: '0' Type::Tie: '0' Type::Tiny::XS: '0.016' perl: '5.010001' requires: Exporter::Tiny: '1.000000' perl: '5.006001' resources: Identifier: http://purl.org/NET/cpan-uri/dist/Type-Tiny/project bugtracker: http://rt.cpan.org/Dist/Display.html?Queue=Type-Tiny homepage: http://typetiny.toby.ink/ license: http://dev.perl.org/licenses/ repository: git://github.com/tobyink/p5-type-tiny.git version: '1.008001' x_breaks: Kavorka: '<= 0.013' Types::ReadOnly: '<= 0.001' x_contributors: - 'Diab Jerius (DJERIUS) ' - 'Vyacheslav Matyukhin (MMCLERIC) ' - 'Peter Flanigan (PJFL) ' - 'Pierre Masci' - 'Mark Stosberg (MARKSTOS) ' - 'David Steinbrunner ' - 'Samuel Kaufman (SKAUFMAN) ' - 'Graham Knop (HAARG) ' - 'Peter Karman (KARMAN) ' - 'Alexander Hartmaier (ABRAXXA) ' - 'Dagfinn Ilmari Mannsåker (ILMARI) ' - 'Gianni Ceccarelli (DAKKAR) ' - 'Karen Etheridge (ETHER) ' - 'Thomas Sibley (TSIBLEY) ' - 'Peter Valdemar Mørch ' - 'Zoffix Znet ' - 'Denis Ibaev ' - 'Lucas Buchala (LSBUCHALA) ' - 'Alexandr Ciornii ' - 'Philippe Bruhat (BOOK) ' - 'Robert Rothenberg (RRWO) ' - 'Nelo Onyiah' - 'Jonas B Nielsen (JONASBN) ' - 'Benct Philip Jonsson ' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Makefile.PL000644001750001750 4070713601673167 14416 0ustar00taitai000000000000Type-Tiny-1.008001use strict; use ExtUtils::MakeMaker 6.17; my $EUMM = eval( $ExtUtils::MakeMaker::VERSION ); my $meta = { "abstract" => "tiny, yet Moo(se)-compatible type constraint", "author" => ["Toby Inkster (TOBYINK) "], "dynamic_config" => 1, "generated_by" => "Dist::Inkt::Profile::TOBYINK version 0.024, CPAN::Meta::Converter version 2.150010", "keywords" => [ "Argument Checking", "Argument Validation", "Moo", "Moose", "Mouse", "Parameter Checking", "Parameter Validation", "Schema", "Type Coercion", "Type Constraint", "Type Library", "Validation", ], "license" => ["perl_5"], "meta-spec" => { url => "http://search.cpan.org/perldoc?CPAN::Meta::Spec", version => 2, }, "name" => "Type-Tiny", "no_index" => { directory => ["eg", "examples", "inc", "t", "xt"] }, "prereqs" => { configure => { recommends => { "CPAN::Meta::Requirements" => "2.000" }, requires => { "ExtUtils::MakeMaker" => 6.17 }, }, develop => { recommends => { "Test::Memory::Cycle" => 0 }, suggests => { "Dist::Inkt::Profile::TOBYINK" => 0 }, }, runtime => { conflicts => { "Kavorka" => "<= 0.013", "Types::ReadOnly" => "<= 0.001" }, recommends => { "Devel::LexAlias" => 0.05, "Devel::StackTrace" => 0, "perl" => 5.010001, "Ref::Util::XS" => "0.100", "Regexp::Util" => 0.003, "Sub::Util" => 0, "Type::Tie" => 0, "Type::Tiny::XS" => 0.016, }, requires => { "Exporter::Tiny" => "1.000000", "perl" => 5.006001 }, suggests => { Moo => "1.006000", Moose => "2.0000", Mouse => "1.00", Reply => 0 }, }, test => { recommends => { "Test::Tester" => 0.109, "Test::Warnings" => 0 }, requires => { "Test::More" => 0.96 }, suggests => { "Test::Memory::Cycle" => 0 }, }, }, "provides" => { "Devel::TypeTiny::Perl56Compat" => { file => "lib/Devel/TypeTiny/Perl56Compat.pm", version => 1.008001 }, "Devel::TypeTiny::Perl58Compat" => { file => "lib/Devel/TypeTiny/Perl58Compat.pm", version => 1.008001 }, "Error::TypeTiny" => { file => "lib/Error/TypeTiny.pm", version => 1.008001 }, "Error::TypeTiny::Assertion" => { file => "lib/Error/TypeTiny/Assertion.pm", version => 1.008001 }, "Error::TypeTiny::Compilation" => { file => "lib/Error/TypeTiny/Compilation.pm", version => 1.008001 }, "Error::TypeTiny::WrongNumberOfParameters" => { file => "lib/Error/TypeTiny/WrongNumberOfParameters.pm", version => 1.008001, }, "Eval::TypeTiny" => { file => "lib/Eval/TypeTiny.pm", version => 1.008001 }, "Reply::Plugin::TypeTiny" => { file => "lib/Reply/Plugin/TypeTiny.pm", version => 1.008001 }, "Test::TypeTiny" => { file => "lib/Test/TypeTiny.pm", version => 1.008001 }, "Type::Coercion" => { file => "lib/Type/Coercion.pm", version => 1.008001 }, "Type::Coercion::FromMoose" => { file => "lib/Type/Coercion/FromMoose.pm", version => 1.008001 }, "Type::Coercion::Union" => { file => "lib/Type/Coercion/Union.pm", version => 1.008001 }, "Type::Library" => { file => "lib/Type/Library.pm", version => 1.008001 }, "Type::Params" => { file => "lib/Type/Params.pm", version => 1.008001 }, "Type::Parser" => { file => "lib/Type/Parser.pm", version => 1.008001 }, "Type::Registry" => { file => "lib/Type/Registry.pm", version => 1.008001 }, "Type::Tiny" => { file => "lib/Type/Tiny.pm", version => 1.008001 }, "Type::Tiny::Class" => { file => "lib/Type/Tiny/Class.pm", version => 1.008001 }, "Type::Tiny::ConstrainedObject" => { file => "lib/Type/Tiny/ConstrainedObject.pm", version => 1.008001 }, "Type::Tiny::Duck" => { file => "lib/Type/Tiny/Duck.pm", version => 1.008001 }, "Type::Tiny::Enum" => { file => "lib/Type/Tiny/Enum.pm", version => 1.008001 }, "Type::Tiny::Intersection" => { file => "lib/Type/Tiny/Intersection.pm", version => 1.008001 }, "Type::Tiny::Role" => { file => "lib/Type/Tiny/Role.pm", version => 1.008001 }, "Type::Tiny::Union" => { file => "lib/Type/Tiny/Union.pm", version => 1.008001 }, "Type::Utils" => { file => "lib/Type/Utils.pm", version => 1.008001 }, "Types::Common::Numeric" => { file => "lib/Types/Common/Numeric.pm", version => 1.008001 }, "Types::Common::String" => { file => "lib/Types/Common/String.pm", version => 1.008001 }, "Types::Standard" => { file => "lib/Types/Standard.pm", version => 1.008001 }, "Types::Standard::ArrayRef" => { file => "lib/Types/Standard/ArrayRef.pm", version => 1.008001 }, "Types::Standard::CycleTuple" => { file => "lib/Types/Standard/CycleTuple.pm", version => 1.008001 }, "Types::Standard::Dict" => { file => "lib/Types/Standard/Dict.pm", version => 1.008001 }, "Types::Standard::HashRef" => { file => "lib/Types/Standard/HashRef.pm", version => 1.008001 }, "Types::Standard::Map" => { file => "lib/Types/Standard/Map.pm", version => 1.008001 }, "Types::Standard::ScalarRef" => { file => "lib/Types/Standard/ScalarRef.pm", version => 1.008001 }, "Types::Standard::StrMatch" => { file => "lib/Types/Standard/StrMatch.pm", version => 1.008001 }, "Types::Standard::Tied" => { file => "lib/Types/Standard/Tied.pm", version => 1.008001 }, "Types::Standard::Tuple" => { file => "lib/Types/Standard/Tuple.pm", version => 1.008001 }, "Types::TypeTiny" => { file => "lib/Types/TypeTiny.pm", version => 1.008001 }, }, "release_status" => "stable", "resources" => { bugtracker => { web => "http://rt.cpan.org/Dist/Display.html?Queue=Type-Tiny" }, homepage => "http://typetiny.toby.ink/", license => ["http://dev.perl.org/licenses/"], repository => { type => "git", url => "git://github.com/tobyink/p5-type-tiny.git", web => "https://github.com/tobyink/p5-type-tiny", }, x_identifier => "http://purl.org/NET/cpan-uri/dist/Type-Tiny/project", }, "version" => 1.008001, "x_breaks" => { "Kavorka" => "<= 0.013", "Types::ReadOnly" => "<= 0.001" }, "x_contributors" => [ "Diab Jerius (DJERIUS) ", "Vyacheslav Matyukhin (MMCLERIC) ", "Peter Flanigan (PJFL) ", "Pierre Masci", "Mark Stosberg (MARKSTOS) ", "David Steinbrunner ", "Samuel Kaufman (SKAUFMAN) ", "Graham Knop (HAARG) ", "Peter Karman (KARMAN) ", "Alexander Hartmaier (ABRAXXA) ", "Dagfinn Ilmari Manns\xE5ker (ILMARI) ", "Gianni Ceccarelli (DAKKAR) ", "Karen Etheridge (ETHER) ", "Thomas Sibley (TSIBLEY) ", "Peter Valdemar M\xF8rch ", "Zoffix Znet ", "Denis Ibaev ", "Lucas Buchala (LSBUCHALA) ", "Alexandr Ciornii ", "Philippe Bruhat (BOOK) ", "Robert Rothenberg (RRWO) ", "Nelo Onyiah", "Jonas B Nielsen (JONASBN) ", "Benct Philip Jonsson ", ], }; my %dynamic_config; do { $meta->{prereqs}{runtime}{requires}{'Scalar::Util'} = '1.13' if $] < 5.007003; $meta->{prereqs}{runtime}{requires}{'Data::Dumper'} = '1.121' if $] < 5.008001; $meta->{prereqs}{runtime}{requires}{'Text::Balanced'} = '1.95' if $] < 5.007003; $meta->{prereqs}{runtime}{requires}{'Exporter'} = '5.57' if $] < 5.009001; if ($ENV{EXTENDED_TESTING} and $meta->{version} =~ /_/) { $meta->{prereqs}{test}{requires}{'Moose'} = '2.0600'; } }; for my $stage (keys %{$meta->{prereqs}}) { my $conflicts = $meta->{prereqs}{$stage}{conflicts} or next; eval { require CPAN::Meta::Requirements } or last; $conflicts = 'CPAN::Meta::Requirements'->from_string_hash($conflicts); for my $module ($conflicts->required_modules) { eval "require $module" or next; my $installed = eval(sprintf('$%s::VERSION', $module)); $conflicts->accepts_module($module, $installed) or next; my $message = "\n". "** This version of $meta->{name} conflicts with the version of\n". "** module $module ($installed) you have installed.\n"; die($message . "\n" . "Bailing out") if $stage eq 'build' || $stage eq 'configure'; $message .= "**\n". "** It's strongly recommended that you update it after\n". "** installing this version of $meta->{name}.\n"; warn("$message\n"); } } my %WriteMakefileArgs = ( ABSTRACT => $meta->{abstract}, AUTHOR => ($EUMM >= 6.5702 ? $meta->{author} : $meta->{author}[0]), DISTNAME => $meta->{name}, VERSION => $meta->{version}, EXE_FILES => [ map $_->{file}, values %{ $meta->{x_provides_scripts} || {} } ], NAME => do { my $n = $meta->{name}; $n =~ s/-/::/g; $n }, test => { TESTS => "t/*.t t/20-unit/Devel-TypeTiny-Perl56Compat/*.t t/20-unit/Devel-TypeTiny-Perl58Compat/*.t t/20-unit/Error-TypeTiny-Assertion/*.t t/20-unit/Error-TypeTiny-Compilation/*.t t/20-unit/Error-TypeTiny-WrongNumberOfParameters/*.t t/20-unit/Error-TypeTiny/*.t t/20-unit/Eval-TypeTiny/*.t t/20-unit/Test-TypeTiny/*.t t/20-unit/Type-Coercion-FromMoose/*.t t/20-unit/Type-Coercion-Union/*.t t/20-unit/Type-Coercion/*.t t/20-unit/Type-Library/*.t t/20-unit/Type-Params/*.t t/20-unit/Type-Parser/*.t t/20-unit/Type-Registry/*.t t/20-unit/Type-Tiny-Class/*.t t/20-unit/Type-Tiny-ConstrainedObject/*.t t/20-unit/Type-Tiny-Duck/*.t t/20-unit/Type-Tiny-Enum/*.t t/20-unit/Type-Tiny-Intersection/*.t t/20-unit/Type-Tiny-Role/*.t t/20-unit/Type-Tiny-Union/*.t t/20-unit/Type-Tiny-_HalfOp/*.t t/20-unit/Type-Tiny/*.t t/20-unit/Type-Utils/*.t t/20-unit/Types-Common-Numeric/*.t t/20-unit/Types-Common-String/*.t t/20-unit/Types-Standard/*.t t/20-unit/Types-TypeTiny/*.t t/21-types/*.t t/30-integration/Class-InsideOut/*.t t/30-integration/Exporter-Tiny/*.t t/30-integration/Function-Parameters/*.t t/30-integration/Kavorka/*.t t/30-integration/Moo/*.t t/30-integration/Moops/*.t t/30-integration/Moose/*.t t/30-integration/MooseX-Getopt/*.t t/30-integration/MooseX-Types/*.t t/30-integration/Mouse/*.t t/30-integration/MouseX-Types/*.t t/30-integration/Object-Accessor/*.t t/30-integration/Return-Type/*.t t/30-integration/Specio/*.t t/30-integration/Sub-Quote/*.t t/30-integration/Switcheroo/*.t t/30-integration/Type-Tie/*.t t/30-integration/Types-ReadOnly/*.t t/30-integration/Validation-Class-Simple/*.t t/30-integration/match-simple/*.t t/40-regression/*.t" }, %dynamic_config, ); $WriteMakefileArgs{LICENSE} = $meta->{license}[0] if $EUMM >= 6.3001; sub deps { my %r; for my $stage (@_) { for my $dep (keys %{$meta->{prereqs}{$stage}{requires}}) { next if $dep eq 'perl'; my $ver = $meta->{prereqs}{$stage}{requires}{$dep}; $r{$dep} = $ver if !exists($r{$dep}) || $ver >= $r{$dep}; } } \%r; } my ($build_requires, $configure_requires, $runtime_requires, $test_requires); if ($EUMM >= 6.6303) { $WriteMakefileArgs{BUILD_REQUIRES} ||= deps('build'); $WriteMakefileArgs{CONFIGURE_REQUIRES} ||= deps('configure'); $WriteMakefileArgs{TEST_REQUIRES} ||= deps('test'); $WriteMakefileArgs{PREREQ_PM} ||= deps('runtime'); } elsif ($EUMM >= 6.5503) { $WriteMakefileArgs{BUILD_REQUIRES} ||= deps('build', 'test'); $WriteMakefileArgs{CONFIGURE_REQUIRES} ||= deps('configure'); $WriteMakefileArgs{PREREQ_PM} ||= deps('runtime'); } elsif ($EUMM >= 6.52) { $WriteMakefileArgs{CONFIGURE_REQUIRES} ||= deps('configure'); $WriteMakefileArgs{PREREQ_PM} ||= deps('runtime', 'build', 'test'); } else { $WriteMakefileArgs{PREREQ_PM} ||= deps('configure', 'build', 'test', 'runtime'); } { my ($minperl) = reverse sort( grep defined && /^[0-9]+(\.[0-9]+)?$/, map $meta->{prereqs}{$_}{requires}{perl}, qw( configure build runtime ) ); if (defined($minperl)) { die "Installing $meta->{name} requires Perl >= $minperl" unless $] >= $minperl; $WriteMakefileArgs{MIN_PERL_VERSION} ||= $minperl if $EUMM >= 6.48; } } sub FixMakefile { return unless -d 'inc'; my $file = shift; local *MAKEFILE; open MAKEFILE, "< $file" or die "FixMakefile: Couldn't open $file: $!; bailing out"; my $makefile = do { local $/; }; close MAKEFILE or die $!; $makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /; $makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g; $makefile =~ s/( "-I\$\(INST_LIB\)")/ "-Iinc"$1/g; $makefile =~ s/^(FULLPERL = .*)/$1 "-Iinc"/m; $makefile =~ s/^(PERL = .*)/$1 "-Iinc"/m; open MAKEFILE, "> $file" or die "FixMakefile: Couldn't open $file: $!; bailing out"; print MAKEFILE $makefile or die $!; close MAKEFILE or die $!; } my $mm = WriteMakefile(%WriteMakefileArgs); FixMakefile($mm->{FIRST_MAKEFILE} || 'Makefile'); exit(0); NEWS000644001750001750 172313601673061 13107 0ustar00taitai000000000000Type-Tiny-1.008001======================================================================= This file contains a high-level summary of changes between recent stable releases of Type-Tiny. For a more detailed list, including changes in development releases, see the "Changes" file instead. ======================================================================= 2019-11-12 Type-Tiny version 1.006000 released! - Improved is_subtype_of/is_supertype_of support. - ArrayRef array length parameter. - Eval::TypeTiny's API is now considered to be stable. - Slurpy HashRefs passed to coderefs returned by Type::Params can now be true hashrefs. - More import options for Type::Library 2019-12-11 Type-Tiny version 1.008000 released! - Type::Tiny has a website. - Resolved all bugs from RT. - Completed everything on TODO. - Rewrite of the manual. - Lots more test cases. (Now almost 14,000 test cases total!) - wrap_methods/wrap_subs in Type::Params. README000644001750001750 1532113601673061 13307 0ustar00taitai000000000000Type-Tiny-1.008001NAME Type::Tiny::Manual - an overview of Type::Tiny SYNOPSIS Type::Tiny is a small Perl class for writing type constraints, inspired by Moose's type constraint API and MooseX::Types. It has only one non-core dependency (and even that is simply a module that was previously distributed as part of Type::Tiny but has since been spun off), and can be used with Moose, Mouse, or Moo (or none of the above). Type::Tiny is used by over 800 Perl distributions on the CPAN (Comprehensive Perl Archive Network) and can be considered a stable and mature framework for efficiently and reliably enforcing data types. Type::Tiny is bundled with Type::Library a framework for organizing type constraints into collections. Also bundled is Types::Standard, a Moose-inspired library of useful type constraints. Type::Params is also provided, to allow very fast checking and coercion of function and method parameters. The following example gives you an idea of some of the features of these modules. If you don't understand it all, that's fine; that's what the rest of the manual is for. Although the example uses Moo, the `use Moo` could be changed to `use Moose` or `use Mouse` and it would still work. use v5.12; use strict; use warnings; package Horse { use Moo; use Types::Standard qw( Str Int Enum ArrayRef InstanceOf ); use Type::Params qw( compile ); use namespace::autoclean; has name => ( is => 'ro', isa => Str, required => 1, ); has gender => ( is => 'ro', isa => Enum[qw( f m )], ); has age => ( is => 'rw', isa => Int->where( '$_ >= 0' ), ); has children => ( is => 'ro', isa => ArrayRef[ InstanceOf['Horse'] ], default => sub { return [] }, ); sub add_child { # method signature state $check = compile( InstanceOf['Horse'], InstanceOf['Horse'] ); my ($self, $child) = $check->(@_); # unpack @_ push @{ $self->children }, $child; return $self; } } package main; my $boldruler = Horse->new( name => "Bold Ruler", gender => 'm', age => 16, ); my $secretariat = Horse->new( name => "Secretariat", gender => 'm', age => 0, ); $boldruler->add_child( $secretariat ); use Types::Standard qw( is_Object assert_Object ); # is_Object will return a boolean # if ( is_Object($boldruler) ) { say $boldruler->name; } # assert_Object will return $secretariat or die # say assert_Object($secretariat)->name; MANUAL Even if you are using Type::Tiny with other object-oriented programming toolkits (such as Moose or Mouse), you should start with the Moo sections of the manual. Most of the information is directly transferrable and the Moose and Mouse sections of the manual list the minor differences between using Type::Tiny with Moo and with them. In general, this manual assumes you use Perl 5.12 or above and may use examples that do not work on older versions of Perl. Type::Tiny does work on earlier versions of Perl, but not all the examples and features in the manual will run without adjustment. (For instance, you may need to replace `state` variables with lexical variables, avoid the `package NAME { BLOCK }` syntax, etc.) * Type::Tiny::Manual::Installation How to install Type::Tiny. If Type::Tiny is already installed, you can skip this. * Type::Tiny::Manual::UsingWithMoo Basic use of Type::Tiny with Moo, including attribute type constraints, parameterized type constraints, coercions, and method parameter checking. * Type::Tiny::Manual::UsingWithMoo2 Advanced use of Type::Tiny with Moo, including unions and intersections, `stringifies_to`, `numifies_to`, `with_attribute_values`, and `where`. * Type::Tiny::Manual::UsingWithMoo3 There's more than one way to do it! Alternative ways of using Type::Tiny, including type registries, exported functions, and `dwim_type`. * Type::Tiny::Manual::Libraries Defining your own type libraries, including extending existing libraries, defining new types, adding coercions, defining parameterizable types, and the declarative style. * Type::Tiny::Manual::UsingWithMoose How to use Type::Tiny with Moose, including the advantages of Type::Tiny over built-in type constraints, and Moose-specific features. * Type::Tiny::Manual::UsingWithMouse How to use Type::Tiny with Mouse, including the advantages of Type::Tiny over built-in type constraints, and Mouse-specific features. * Type::Tiny::Manual::UsingWithClassTiny Including how to Type::Tiny in your object's `BUILD` method, and third-party shims between Type::Tiny and Class::Tiny. * Type::Tiny::Manual::UsingWithOther Using Type::Tiny with Class::InsideOut, Params::Check, and Object::Accessor. * Type::Tiny::Manual::UsingWithTestMore Type::Tiny for test suites. * Type::Tiny::Manual::Params Advanced information on Type::Params, and using Type::Tiny with other signature modules like Function::Parameters and Kavorka. * Type::Tiny::Manual::NonOO Type::Tiny in non-object-oriented code. * Type::Tiny::Manual::Optimization Squeeze the most out of your CPU. * Type::Tiny::Manual::Coercions Advanced information on coercions. * Type::Tiny::Manual::AllTypes An alphabetical list of all type constraints bundled with Type::Tiny. * Type::Tiny::Manual::Policies Policies related to Type::Tiny development. * Type::Tiny::Manual::Contributing Contributing to Type::Tiny development. BUGS Please report any bugs to . SEE ALSO The Type::Tiny homepage . AUTHOR Toby Inkster . COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. SIGNATURE000644001750001750 11203213601673167 13737 0ustar00taitai000000000000Type-Tiny-1.008001This file contains message digests of all files listed in MANIFEST, signed via the Module::Signature module, version 0.83. To verify the content in this distribution, first make sure you have Module::Signature installed, then type: % cpansign -v It will check each file's integrity, as well as the signature's validity. If "==> Signature verified OK! <==" is not displayed, the distribution may already have been compromised, and you should not run its Makefile.PL or Build.PL. -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 SHA256 b995288fb503b0a64dd55a8caedd80e031e5b8f5a40b82aa884c81f72b2d069c CONTRIBUTING SHA256 15a51532efbe83245dfee2140847a95acb07bf211570f188ec1229feb5f9bf09 COPYRIGHT SHA256 e20e14c05140ed64948a9c80683d147a3b6d75d8a941e6f2a4748e1bc31c0434 CREDITS SHA256 eb21fa04bbddd45595bf3b074cb82ae8024bffc4bbad3f91add144066ee3e25f Changes SHA256 6a5ab06a68802a98172274d878229173c11a5229cdf14feaa4b88498cb3c05d7 INSTALL SHA256 5c791221f0dde289392a38a5921b66d4a1be8248cc64ee6de15f3c2426892673 LICENSE SHA256 fe56eb748dd9154971abbcb2e7c6ce6723e45143a04f1c67f9514bb90a37094f MANIFEST SHA256 6eeee5c117b795dd84b5dad158f07cd2a2568b4905efa25d92beb5695be1c0b4 META.json SHA256 b4a2aafa141af12104dc1920fbb6a558842f44e0c95de39781729f04508c18dc META.yml SHA256 ae19b89970603e6d6e0655ade961c6698e90ed019adfdd8311f05a1cc55a41c9 Makefile.PL SHA256 8d042b843bc4314da62056703fe8026b3664236d624edfc03515933c0dcdf951 NEWS SHA256 3e22936ed59c44e385fcb73441be191fc3f49294c7d8c5964a938a2a7facdc53 README SHA256 cd8759458860e09c13d2be9509cef61689d8ee9738ef9d38ee1ca8add64312ba dist.ini SHA256 199a16e92168ba4fbbdd18cbffc3db971000ae3b75bdd1e11f33703369294f55 doap.ttl SHA256 31e0f1c020ff3c80fdae25c8013945acab50ad80772f795ba12378d1ed9adb0b examples/benchmarking/benchmark-coercions.pl SHA256 6fd4023f0ce061619303e0b252c4c2dd25593384bc1ab2815743acd6c5789a9b examples/benchmarking/benchmark-constraints.pl SHA256 5a6468b557e0bfd9b248e6e773b4a0864c331158a87783d968283980f9c57dea examples/benchmarking/benchmark-named-param-validation.pl SHA256 afce7c0fbe7183e06aa06be924aeaea4cd337bc081ff64ddd9f26fa09f889735 examples/benchmarking/benchmark-param-validation.pl SHA256 734e61080079b084143d6305d0f5dc8c56a1acddcf4a777ab42b79637adb9df0 examples/benchmarking/versus-scalar-validation.pl SHA256 daf7b5c3345147ad7cbd337137f031f765428a3dcb87a92bf35e4f50c13ed035 examples/datetime-coercions.pl SHA256 6660315664c9b5678d91e273f1d9f3631563226883be0ba3482305d3dbdfe0e3 examples/nonempty.pl SHA256 18261dcc61931290c0e92a7a93f33b7ac2a1e2ff2c0b15579f64f5ab1998e905 examples/page-numbers.pl SHA256 c361b86d13c8fdfbe75840d11dbe6af488e44af27b0edb80fd1eea28c8e935d4 inc/Test/Fatal.pm SHA256 fe1cb3feb9e6892c5796e5883e63abd052b388dab44b9b2103e23828e7dd4db4 inc/Test/Requires.pm SHA256 083292e0cefc5cd41c82975f7b9aadc6893065d4297dc153b7f13356c0c0a44c inc/Try/Tiny.pm SHA256 a93c5c677f44f7b00a7c414afeafaaa15ee7c7b72a47083936e1a8d37f0970b9 inc/archaic/Test/Builder.pm SHA256 fea307eee1d65187effaaaaf85663e55f1a23c2a25cd6a4963bada80c440075d inc/archaic/Test/Builder/IO/Scalar.pm SHA256 4da2ad5c38d41eb389393f111f01f8e3c885f3ae5c027e540f662ddf44d2895c inc/archaic/Test/Builder/Module.pm SHA256 71d019f6ac3467615dbec9c17aa85eec0f32a4cfd8824f25fda7176e0890de44 inc/archaic/Test/Builder/Tester.pm SHA256 ae528d9fc2962793e98af13f4d4e802fbf8d78b17b1c27a860728a16e8bf4a3a inc/archaic/Test/Builder/Tester/Color.pm SHA256 764f3ed1e0a314e7e9f8d803dff3d894e8c572e2a128d7ce14f2a80268e50543 inc/archaic/Test/More.pm SHA256 c4fd1410a9bd85a0e7700de08c1614fc5928c0d02151ba1ec7d06bd56407e0d5 inc/archaic/Test/Simple.pm SHA256 6fdae553a4a6bbfbc024a53153aa71e080e55ae466e44d4cf11f041f5e3a3fb3 lib/Devel/TypeTiny/Perl56Compat.pm SHA256 151e7ef21acac7a1dff84c7bff90c5c002dd2e4896fb6867c46283b0e0c46e84 lib/Devel/TypeTiny/Perl58Compat.pm SHA256 5627cf0fa52b1c31646bc260fdf238b6cf4586fb043bdeddf310a1d20236b159 lib/Error/TypeTiny.pm SHA256 82a8821a4ebca08827869eeed27782e39a61922a5b611bfb923eff4de0e0501c lib/Error/TypeTiny/Assertion.pm SHA256 4dde78d449e9bf45f187b9e260e75472559ee130896686bd71e5c9ea2c519857 lib/Error/TypeTiny/Compilation.pm SHA256 66adf085c9561dac4d4034a6615e1494cd380fd7c5bee987bbe6b475c7fad168 lib/Error/TypeTiny/WrongNumberOfParameters.pm SHA256 ecf9ca7726864cdef7d1cb1b8dd0b20ba55c0453b82850d2e064670b7ed3b9f7 lib/Eval/TypeTiny.pm SHA256 0f3143e08248fabda5072fc9b5aa57d6ac718c9a59a52423bb7501d392992e24 lib/Reply/Plugin/TypeTiny.pm SHA256 d4f10c09d67bd190b7ef8850ffc9f47419d597730c6beb9feaa1a4c11371c638 lib/Test/TypeTiny.pm SHA256 d6247d924ae2377c4672314db5bf9f69808a3fab06b50def3616e19fe045cb05 lib/Type/Coercion.pm SHA256 0c536f5a377830fce4ca9b1b572e979e1890980e7919db55054eaf4422712a19 lib/Type/Coercion/FromMoose.pm SHA256 ed4ae1b4c75f08b8254f45dd679f526640012e20300e7968d988cab8421ea865 lib/Type/Coercion/Union.pm SHA256 d452957a8076c9336756224004b96d0e121d2040f4691cf434d82ed4130cd809 lib/Type/Library.pm SHA256 e9a8224d57f959853046d54903875b9a387efdf605e608167092d135850d1dad lib/Type/Params.pm SHA256 6b1f8dda5900a0c3e6ba32cd39eaa83cfa187d7ac8693edd8eee21a559cf693f lib/Type/Parser.pm SHA256 94aca3b60605d1b6a57bc91e851c33c1554f4551cbf950c7e333cd49264a0d4e lib/Type/Registry.pm SHA256 f1764b0bb6cb1dd43539754d0c468020e3676a837ea099c8b1ea71d582a9ecf9 lib/Type/Tiny.pm SHA256 fd836734b5c0c4a740f1c22f1aa3c14300c18442f1e05fca837b4ab6bf07c0af lib/Type/Tiny/Class.pm SHA256 ff4806fcd17dc2b972c272b9a2f9d04dc6dea565ebb84673791c74af6b73ca4a lib/Type/Tiny/ConstrainedObject.pm SHA256 e64e4fbfecb33e7da890b3c52fab8703ee7174aed83ef0f1bf03d16e71b6296b lib/Type/Tiny/Duck.pm SHA256 57c89867d924ef663dfb5a0530e7217b4808874d2cb030c021a40ca4faa830a3 lib/Type/Tiny/Enum.pm SHA256 78a48c873cb562f9a3126fd3fdbd80e6542b2ad2d852d72d7c5444098af99767 lib/Type/Tiny/Intersection.pm SHA256 4de8fc35c4ec8bb61fd8834edd0abd9ce1bf8c132b7c07c6147fbd03b86f59da lib/Type/Tiny/Manual.pod SHA256 04e1da8570aff621a11285722e39c4b415e81fa8155f7db94aa661b1641f2e61 lib/Type/Tiny/Manual/AllTypes.pod SHA256 adcc2d17abb6b6e19a3a4040514a8368572ccf42221b62ed027c72ea8de430d1 lib/Type/Tiny/Manual/Coercions.pod SHA256 50054a48b5bcb4b27095b1188e004e0c944416e7a31653fcf00f1e969aa1e9a4 lib/Type/Tiny/Manual/Contributing.pod SHA256 569bfe1685f943766d2cd6d2c847e4356f885134a50fecffc09d860ae500116d lib/Type/Tiny/Manual/Installation.pod SHA256 8e43d02c8b0ce0b8bc26062b680b8d8dc7028245bc88b1a97aa514ab26831d31 lib/Type/Tiny/Manual/Libraries.pod SHA256 6ebd4d06ebb1ff398427217c037cc8150794a12b6aebc17ffb9c281eb7fa9fa3 lib/Type/Tiny/Manual/NonOO.pod SHA256 119aae3b68d42bb732574d7bc9ff7875322a0f20f8ed4ec4f2be1819a5c1cf3b lib/Type/Tiny/Manual/Optimization.pod SHA256 3766fe7be7923bc68522ebb96dac9947832a0e88c92386aa76f4775da1a0effd lib/Type/Tiny/Manual/Params.pod SHA256 6ba24a5ae47089716aa53ea86cb345a839a22fd0bd39f41e4ecd49277c1a6d94 lib/Type/Tiny/Manual/Policies.pod SHA256 fc03295a4d808ed5cfad2eddb76408e1833360be88374c89d918b37b6a0860fa lib/Type/Tiny/Manual/UsingWithClassTiny.pod SHA256 f8764f0fe1a612f095da62b480fb05bda3b1343ae73098c2bc41078ed055dacd lib/Type/Tiny/Manual/UsingWithMoo.pod SHA256 907c2bb0cec05ee6b219225070b7e266e550ef0370b4b1f5af23c4c52e587e9c lib/Type/Tiny/Manual/UsingWithMoo2.pod SHA256 d5d12bbf10cffea104b97377b14ae8652ea4bea7e8e8ce236b64d0718021e7ae lib/Type/Tiny/Manual/UsingWithMoo3.pod SHA256 60aa34cb584da16e9c5bd8b77c1e2592052dc72f65eda498ae3bd2d5b4d5c4cd lib/Type/Tiny/Manual/UsingWithMoose.pod SHA256 898cccd2c1f89f3fee07998952202d962eeed8fa793f06ece05359d81bdf97ef lib/Type/Tiny/Manual/UsingWithMouse.pod SHA256 255ddb860d5eb9749b5ada6a5158eb5fe1657b76ce077505995b5574b33aae7a lib/Type/Tiny/Manual/UsingWithOther.pod SHA256 0b2511c105a42a15a6d058d02cbdea14388db947b8d563ebc94d4db511e74730 lib/Type/Tiny/Manual/UsingWithTestMore.pod SHA256 c8de5a7b5647ae75beda15ae5b79bfe7999a603b70969f8718a3272ece5929e5 lib/Type/Tiny/Role.pm SHA256 084462743155174f4ff3bb51b9bf1ba0f98b7b67fb90a3683d5d1fadcfea638c lib/Type/Tiny/Union.pm SHA256 44cf2c9a28f3414414f0739b90d30b341ba15c1722dc567696d63e647d4ca04c lib/Type/Tiny/_HalfOp.pm SHA256 0836f0b6e52cd32d6cee8898af3d7c3e127c2a12eafb4ebab3ef739f7551b30f lib/Type/Utils.pm SHA256 be7769913be442a2537774c07531c36a148c4e5241cfd243fa4b06b0a62b5f21 lib/Types/Common/Numeric.pm SHA256 6efc0809559c3b8afb4c0f8d195ccacbe220531ee9fd53f28f1d4f53f21a9e1b lib/Types/Common/String.pm SHA256 6fd98624f4863affc6afebb6652a1589243e7374bc49a2c8bfd65f2ffde9ee45 lib/Types/Standard.pm SHA256 184a2c59b23c7caada8a1cd1da35956e21db3f9bdb8e67a8f539a8c086374a8f lib/Types/Standard/ArrayRef.pm SHA256 4e7e42e66c6f63c0ffe1f43a7d89e5ef35b9c7106bbc6d6df36d318c1cfd164e lib/Types/Standard/CycleTuple.pm SHA256 8d9527bacf816967dac8b27d15a392a9b25500c682c8ce830085064aa89783a5 lib/Types/Standard/Dict.pm SHA256 b4807341e5d855513127e6570ba2c4144b4d4b8059186669259e91a76cf3f103 lib/Types/Standard/HashRef.pm SHA256 6d612be70ab916d96133aeeba5694253f9d95811ccf141fd548a00b14d8eb110 lib/Types/Standard/Map.pm SHA256 e55d9a8178179bd6390f05b65e45b76fa678605ed8bb8311cbfb3115a977a175 lib/Types/Standard/ScalarRef.pm SHA256 b9271424b254faf68cfd13d4c892c0c1369bdd4cf03396b67279291f28a33edc lib/Types/Standard/StrMatch.pm SHA256 d344fdfaa447d79daf93cbcabe7ea7a0b70c21408baad73944fe2a864f7553b6 lib/Types/Standard/Tied.pm SHA256 78ae477c2e7fc5657379b106d3b6fc284b0dfc8a71b89ae2fdf0e6ad6a31b7d6 lib/Types/Standard/Tuple.pm SHA256 d52702022e3c373071844809f6a5a768ae6eb7e7bf816158c0610da21ed4efb0 lib/Types/TypeTiny.pm SHA256 a410c255b1c433646b2e77d956d01cac987f27b2646e187b8e120e322808d68c t/00-begin.t SHA256 afbc41a276242ac22acaff4ca5570d62c7488a4a97c87a247b2863d270ef05e4 t/01-compile.t SHA256 554b46e2a88186a4401a39522511cf150b901dc67b896464c0734eb037375880 t/02-api.t SHA256 60aa092a1e37339bf2eb35aa20acbe86fac37d31d73a07dd1fe33a13113b3fe0 t/03-leak.t SHA256 d2946477a35b8c7115c94db4b1e5b6a43210583d55a4c586d04449f66b7938fb t/20-unit/Devel-TypeTiny-Perl56Compat/basic.t SHA256 29cbb29c765bd959ad702c088ee052d6d6ba6150dcbd6871f33dfbeeaab623f5 t/20-unit/Devel-TypeTiny-Perl58Compat/basic.t SHA256 3244f96aa3526dd31eff1db637dd784b54f30130b01f74906e7eb441d91b8114 t/20-unit/Error-TypeTiny-Assertion/basic.t SHA256 3b1c6130cdaad137e4c0c83463326f76fd6a5bf4958b54e64a730f161980debb t/20-unit/Error-TypeTiny-Compilation/basic.t SHA256 65b9a24d5b04a68425f5bac9dde89bed41d52f48668715224bd630aab1e2b139 t/20-unit/Error-TypeTiny-WrongNumberOfParameters/basic.t SHA256 1e85705144181800dfd858c9bbc81322a26e7f982fbf6de6261d55c19b223c84 t/20-unit/Error-TypeTiny/basic.t SHA256 75d0897aa82856d83fd0fa5f22d646acde00a5bb286737b289a02ba56f33b003 t/20-unit/Error-TypeTiny/stacktrace.t SHA256 d522fdb2153b33bc8d574cb96c52b7f47e116abffa57db0837edf08045e31672 t/20-unit/Eval-TypeTiny/aliases-devel-lexalias.t SHA256 3596284e97da7fc36d1f7e3f0416280b7f48d6e0b2b0478dab225a96531ce3f4 t/20-unit/Eval-TypeTiny/aliases-native.t SHA256 2a9d634b3576927b83815f5c5441d5b5f6b87c49f16f409323fc90155cca1a01 t/20-unit/Eval-TypeTiny/aliases-padwalker.t SHA256 9a3ff40ecc8c3a9bf944cf06128a866a19a9ec05d9accdab178a733e9d7387d0 t/20-unit/Eval-TypeTiny/aliases-tie.t SHA256 50fb5377425767c347b9eb896fbf7669076a38aa5ef6042f68b8709a17f0bc6d t/20-unit/Eval-TypeTiny/basic.t SHA256 589b745c755a5c531022d10aa7847aef660f11d95cc44d8da50e51d904ebb365 t/20-unit/Eval-TypeTiny/lexical-subs.t SHA256 c5bdeb512b6dffb07ec5042cfad698752bfe7a9e795c6a5a585deb84a1c622e4 t/20-unit/Test-TypeTiny/basic.t SHA256 e7f238297ca97bfb7ff21494b7afe0b305c7aabd5050171081833f76b7f5f147 t/20-unit/Test-TypeTiny/extended.t SHA256 ab8df9a052736679141fedc15b0b9b3c636080b87f79994135eb973818bad87f t/20-unit/Test-TypeTiny/matchfor.t SHA256 448013cf4485fdbf7aa9812f0317c3b1b908284c04e0e41bb5282ab931fc4615 t/20-unit/Type-Coercion-FromMoose/basic.t SHA256 b582503088701f674985a496fe5318937002cd304c183709cb45fb702c49d389 t/20-unit/Type-Coercion-FromMoose/errors.t SHA256 71d2046affcb017c18b09e704ce38ff2ac380fabfede52e0a46f6ad75ad4c79e t/20-unit/Type-Coercion-Union/basic.t SHA256 3ca689653ed447e42d96d270c3d27f16265925b5f2691c92e9f457df8963d907 t/20-unit/Type-Coercion/basic.t SHA256 a58a90d0f4681bf00f92010295b37dd57ecf67b1aa253bb2cde2de6f7d695060 t/20-unit/Type-Coercion/esoteric.t SHA256 efea4face90f5baf3e8c8c6e6ae8a16f407a27a390a6c9c81f6118a787e01a6b t/20-unit/Type-Coercion/frozen.t SHA256 9043adb4a8f9cffc6e5964e6bd9fea318daf322ba2d3a5aa0a075b5a6488bc97 t/20-unit/Type-Coercion/inlining.t SHA256 3be22084ef50dee39df5715cb926627141fe91049b4500ce1a94975ece02901e t/20-unit/Type-Coercion/parameterized.t SHA256 4ca80f23e377c479c2dfa0baa9a7c9a668c5e161035fe65d77b85eaf926f92d0 t/20-unit/Type-Coercion/smartmatch.t SHA256 ac97b5bce4dd561c2a887fe5741bed401695417b1fe1dfbc33bce51c2ca06773 t/20-unit/Type-Coercion/typetiny-constructor.t SHA256 a222ea402776b52f568f8779d7d1286e1993f5bb0c754474d4dbeadbc26f6d1b t/20-unit/Type-Library/assert.t SHA256 c46e4b114699a11ce6a268d3c848e2aa289686b1aa2408ee2859605ecff6349e t/20-unit/Type-Library/deprecation.t SHA256 bccab6f90046696c25a89a19d18c12461f4a6ee4df3127670d5b270c87d86ae4 t/20-unit/Type-Library/errors.t SHA256 1e757bfb13dc7d802fae3f497723069f9b7738bcb4ea9bfae5b16068f23b871e t/20-unit/Type-Library/import-params.t SHA256 faa1a7a6516f3d07012548573a6d93ce989a2f7e7125091a142cb8faa2924f76 t/20-unit/Type-Library/inheritance.t SHA256 382170ae7698ef65763476be64f371fae2e0de8620c9bc4aa9d3f43d82c39a97 t/20-unit/Type-Library/is.t SHA256 7050a3025e268968b88f50323ad825a4a9d3c506e6e64ead894102f606cc4679 t/20-unit/Type-Library/to.t SHA256 3c9d3d83840c11da2d2eda8a00b6c4d9693ad26a004d0ac310fd1d182bbd2603 t/20-unit/Type-Library/types.t SHA256 71a738f4aa9f0e949d3b25c2c9b2bc611252a1371b91275e4329c9f562c79761 t/20-unit/Type-Params/badsigs.t SHA256 28581f018b34522e3e369315d41f1725ae0ecb41c6b1972e563a37d344f0d2a8 t/20-unit/Type-Params/carping.t SHA256 a643f4fb5802698ef922508fb3f932e2b97e17adf39387cfbccf58e763fcd6c1 t/20-unit/Type-Params/coerce.t SHA256 34ffd2316f26f08060e0e62319a92eb0e97a8fb6482c6f4e2ffb93b1a57824a7 t/20-unit/Type-Params/compile-named-bless.t SHA256 18ff9a668494b75ff337fc5c50dccca1eb1379e73178b7834c60bb1d345352f2 t/20-unit/Type-Params/compile-named-oo.t SHA256 b638b4fcf22bfd1077e3e600b2090e6cfe2d78cf68994e2d6e20a106ba4e3959 t/20-unit/Type-Params/compile-named.t SHA256 5a7322daa8ad20656b1d7bb45da54166a92115a54805b468a7c67c6a329ab4ce t/20-unit/Type-Params/defaults.t SHA256 a9833a7ca31dcf73540cb46ead0d63909c34e1565b1d573419edd9506262ebd5 t/20-unit/Type-Params/hashorder.t SHA256 f57a6980ccdab2f88fac625054afb7f24439ffdd663ff8d48ad9ad2e172408ca t/20-unit/Type-Params/methods.t SHA256 346190985a1fb9ce310d740e654f96b241c2d844d32e688efaf1397f36c10a83 t/20-unit/Type-Params/mixednamed.t SHA256 b8888baa9fec67a82709ce122aab1e66362b4b09da4132232eb057b6022f5a5a t/20-unit/Type-Params/multisig-custom-message.t SHA256 cfc23d0c4aee82c4b22c67f119630dcb9e8421cd2c2636445c85ab2d5195a09c t/20-unit/Type-Params/multisig.t SHA256 c71f3be4221431ae01f6873498b870025b614b2c6003a9345753cc12190e56b2 t/20-unit/Type-Params/named-to-list.t SHA256 41a67d24e10418751f59b9961db1fd0347242a3c5c656fba28dccd9578748519 t/20-unit/Type-Params/named.t SHA256 f4fc5c5d78eea032fac977db34136842286e89831dccc53a804e286a798a5e16 t/20-unit/Type-Params/noninline.t SHA256 75248e4e537a8b39cfacf63165a191a07c9b3f04924dbc27e4a516f25aa44dc4 t/20-unit/Type-Params/optional.t SHA256 1a264a87a9f1c22ad9cbd6ec23f4027638a61ef768b45c1465d0b96fc7b3e1b5 t/20-unit/Type-Params/positional.t SHA256 53fb3878c0703915b6c322b01e5ab3ce4231e4ec114db2da968438957bce2a16 t/20-unit/Type-Params/slurpy.t SHA256 bd13093f57f329852fb052ae654d252724532000cb36f8cb5ef585e09ed32e02 t/20-unit/Type-Params/wrap.t SHA256 bdd1e6b8fbedf845a1cc3dae858df529c992a77372d993f5bf7c9ce9f59e8dc8 t/20-unit/Type-Parser/basic.t SHA256 d39bc95789bf42d74f7b456605a03ea95a9aad0a5fbbfae27627b36207a34684 t/20-unit/Type-Parser/moosextypes.t SHA256 b0aef3ce5fcbe805e6849b9ffc1c672156a67260657ef7314fc4e2c8d0f3f3de t/20-unit/Type-Registry/automagic.t SHA256 3237ed87a6976f8704d50db0874d5c093a7e5cf498095c3eb244dc8fc6cbd24f t/20-unit/Type-Registry/basic.t SHA256 c56affdb24c096be4fca1cbf095ab8f7b11ecb10ceca060061601277f4c86235 t/20-unit/Type-Registry/methods.t SHA256 4fa3399717074fb73624a734992d282ac47e0da1062d654ca1b1e17ecfb38f53 t/20-unit/Type-Registry/moosextypes.t SHA256 33e5d7540b6d347027a95c8b3f1068e11bb2d54d2a4527a8f86adf471d8e978e t/20-unit/Type-Registry/mousextypes.t SHA256 88dd079b2e604dd08ec4dd3854029a3dbe5ec1903cf2d7cf60cacb7de6e3d641 t/20-unit/Type-Tiny-Class/basic.t SHA256 2ba2160cdceb399febcdd56e3ccc93da678eac40f7be7f9be5864584193e7e1d t/20-unit/Type-Tiny-Class/errors.t SHA256 141e29e570a074ba1dd3cc635e7acd8cfbc7c26c43d8ded81cb693f789af5342 t/20-unit/Type-Tiny-Class/plus-constructors.t SHA256 cc2fd78c148f7e4bdb836be1555b7da5a5e9acb4037651d679a9d1d448e9b732 t/20-unit/Type-Tiny-ConstrainedObject/basic.t SHA256 36f7eeaacbcef8d4c315333cddf0f424afdc81b2a54b4f5b7386a33104c03278 t/20-unit/Type-Tiny-Duck/basic.t SHA256 17ca5f4606bd797ee9987889723e575cbc02f90000b06154737b76c9dbafa2a6 t/20-unit/Type-Tiny-Duck/cmp.t SHA256 bdc4df16ee39dd2b1fc1ade321d0c77a2a98c1b7f2b8d5bc97f756a423e74a53 t/20-unit/Type-Tiny-Duck/errors.t SHA256 cc4b2a846935031766a670eb0667f1ba08414cbab0664154c2949808df11e05b t/20-unit/Type-Tiny-Enum/basic.t SHA256 3feaf76a5dafa2207426fed301ec132bfdcf516e80abb502f7799d5d68fdc8c7 t/20-unit/Type-Tiny-Enum/cmp.t SHA256 35846517da197aacab16da30e2feb1be65e1b2c325bb8630a818ead39e34110e t/20-unit/Type-Tiny-Enum/errors.t SHA256 a00e7bcebded655216648ed8f2c4902af79851f3cf203682ea4a295af1e3e63d t/20-unit/Type-Tiny-Intersection/basic.t SHA256 8bddf1d50f1b550309009efe359275b5acd649323183a176642af1878f8907a2 t/20-unit/Type-Tiny-Intersection/cmp.t SHA256 4d27e89ba39e0438be3f2b2732af648d3cab55b881dc3a7e2de5d828f5af9e7f t/20-unit/Type-Tiny-Intersection/constrainedobject.t SHA256 0537de3396b41b7192ed13a581ba95cdc8b5f9e19c4793d5c7400bfeee1e1b8d t/20-unit/Type-Tiny-Intersection/errors.t SHA256 3cd25775a788922665e46053f39f52e8f19fa81ba798ad408fee1ae8b312364c t/20-unit/Type-Tiny-Role/basic.t SHA256 1dc9f0a9ff802b68f46f722b33254ab7c1840d6b7bfd81269dbf43f5d0037e9d t/20-unit/Type-Tiny-Role/errors.t SHA256 22d11143d06213133f600a74ce7d271ccfb0211cb23463efa7d951d4c8e1071f t/20-unit/Type-Tiny-Union/basic.t SHA256 710d25079f67464d6ddb2f56964f09d2c7a5ab3d8fa9bd5cf276b91bd5f044ea t/20-unit/Type-Tiny-Union/constrainedobject.t SHA256 0e0fdc2b87d7af92de12184431e65102328e5c6667d944f2670f358aaf7637e6 t/20-unit/Type-Tiny-Union/errors.t SHA256 beb5ca6b517e946c08a71917ea76f8428be22dc029449ebb7339e6ba4e009df9 t/20-unit/Type-Tiny-Union/relationships.t SHA256 de9d44ba9182b81ba6ce1c6b8f77ff8b5d9439716a4fa80a92942e9f11021fb7 t/20-unit/Type-Tiny-_HalfOp/double-union.t SHA256 a13ecea2c1c4d97a2e2e00538a186d0bed691b0421fa046fdbf4e46a4015469f t/20-unit/Type-Tiny-_HalfOp/overload-precedence.t SHA256 c0f0398380486d500f5fbec7f934c3cd9e77707d4e9d396786c3966e01d88cd8 t/20-unit/Type-Tiny/arithmetic.t SHA256 06fd88d5d616f85bd8d75f4ecb5a85ab41930a4cd2ef02ebb853cc8fd6d2522a t/20-unit/Type-Tiny/basic.t SHA256 9cb70b353002adffb7d0e75be041f6239a008094d4027ef71c264e5e403f1a4e t/20-unit/Type-Tiny/cmp.t SHA256 9dba47290eb73534e7ec3639d4ecf7b374881f1459083281277cf46346e3a4e7 t/20-unit/Type-Tiny/coercion-modifiers.t SHA256 463d1a201e7888150742d17fa4c18601abc03688218b9e4098693c81763cb55d t/20-unit/Type-Tiny/constraint-strings.t SHA256 ce6f37a6cab71cd8c1af4e668e956bb0654d2304ff283e52a52afeda08d6321e t/20-unit/Type-Tiny/deprecation.t SHA256 68ca8892d0c089ce5daf620a7b780ebbe0f217b4151d1efe6155651421068c70 t/20-unit/Type-Tiny/esoteric.t SHA256 dc266f9699fdad436805ffd4a3cf6486a0fa19bc07e6703d34edc9c7b589d135 t/20-unit/Type-Tiny/inline-assert.t SHA256 d5b9f7c245dbad64d00f529feade87b6925951ae0ac5ae21fb4ec1a3324438a4 t/20-unit/Type-Tiny/my-methods.t SHA256 403f744b44ff84040a57c12ee603801ffdf404e972e5a221ed6406754fad7324 t/20-unit/Type-Tiny/parameterization.t SHA256 414b354e711fcf48ea5ec286e7d06bbc3f6da3982b935af97a304f7f1541ac44 t/20-unit/Type-Tiny/shortcuts.t SHA256 c0fb3fd90e61cd5e257cf05c833c83d78bd432d46559fd50dcba6d25e2cc03f8 t/20-unit/Type-Tiny/smartmatch.t SHA256 b08c0c829927e9d222b29c5add175db1e52642ffd26ea2cb34e8237c7fcc5668 t/20-unit/Type-Tiny/syntax.t SHA256 8978a9bd7ae514fd289be0da8694c48af10e5b37fadaded5c651787af008442f t/20-unit/Type-Tiny/to-moose.t SHA256 041f544b0c8e92d28956b6be7ab8a88348e693084ade4b74688cd46654bcba67 t/20-unit/Type-Tiny/to-mouse.t SHA256 f0270117223e8136d3a5256cd77dc74905893d479c7ff0b07cf2379c0009e9be t/20-unit/Type-Utils/classifier.t SHA256 e0e90dba8d096f1b7c3755c135b36c801a7cc817a17464614694854628e6ef9c t/20-unit/Type-Utils/dwim-both.t SHA256 27f2aef2cb42f34476e8eac0dbd1fe20b4f8cefed526c735257b2edcb4c9e733 t/20-unit/Type-Utils/dwim-moose.t SHA256 7f3358f373010dab6a5ab821a9547d76ea2a66b1c139c0496504f8657a467dba t/20-unit/Type-Utils/dwim-mouse.t SHA256 b77fd7304d899ad784665300f257d21dc81e235122aa5b3fc7e76bf9d541a673 t/20-unit/Type-Utils/match-on-type.t SHA256 517787c91311ef1d1680b1948ded2b24e57513f4f488c7a39f7b9a1e7a9ba82d t/20-unit/Type-Utils/warnings.t SHA256 c09447501ee489735f7dfafcc9bb9c3ecdd34ba4e2f11e1adf56fa5de6b45b20 t/20-unit/Types-Common-Numeric/basic.t SHA256 aebe482c4f035c31d9ac18f72a3bd000d3c7ec8fae000be8dfe2a301dd3f4601 t/20-unit/Types-Common-Numeric/ranges.t SHA256 233426a37f29be9fc7003e758a29f0db33792429f9e9847d1c69cccdec3de223 t/20-unit/Types-Common-String/basic.t SHA256 a56bee95a92622504cd12f001cfad5a978828e7f436cec0339cf8d646a75803e t/20-unit/Types-Common-String/coerce.t SHA256 ad2da1432f87fee4d254633757cf3451807ac9f7a22fd501f9bd443b104c822a t/20-unit/Types-Common-String/strlength.t SHA256 b39496949f6ff39e130a341359c17b22560057c83b409e80e1cbc315fb8d5fdf t/20-unit/Types-Common-String/unicode.t SHA256 8031ec529e5b3d184743941170c470431c45c079eb3fa498b83683bb0f6ec31c t/20-unit/Types-Standard/arrayreflength.t SHA256 c80f64b323ba23e88da335eab67f124cb1fa863e841bcea32a4d8003df94aac0 t/20-unit/Types-Standard/basic.t SHA256 524e926dd09c764e9eb6f86673818225cec6195ecceb6598b51bea0909fb153c t/20-unit/Types-Standard/cycletuple.t SHA256 161344daf8784ef7b6a403d373c3dc19bff0821e4948df1807adeef0555db4ea t/20-unit/Types-Standard/deep-coercions.t SHA256 c0299a9b84ffe583c26f2a0d731603976e26cc729bef6915974c6295587b643c t/20-unit/Types-Standard/filehandle.t SHA256 f58b443199442876ee43235fd8760b4b8952d11c01f5a1d5bba83cc3516219bf t/20-unit/Types-Standard/lockdown.t SHA256 4fdeb81eeadc009c7abd9e4b62b56b035bc3358a2a2e2678af77e944720dfe34 t/20-unit/Types-Standard/mxtmlb-alike.t SHA256 f1911c2e2c9d9dec99877b9f19d8b3d3d8274b187d7f6abd91b10f5e7dce336a t/20-unit/Types-Standard/optlist.t SHA256 9512484bbd3e06441e3eb8d7ca744e318d24822c6c27b943f33bbc0eec56cbbd t/20-unit/Types-Standard/overload.t SHA256 c3430e498d4a475efe82a24f03babff5158e1fde3d8b10adefe33725db9aca45 t/20-unit/Types-Standard/strmatch-allow-callbacks.t SHA256 1edd9c207424da06675745ee1facd93a6a92a6f2c9576ae48573b8e556f30f2e t/20-unit/Types-Standard/strmatch-avoid-callbacks.t SHA256 8b88bbd0c98dcea6bac6f6fa56e37749be60aa688270a6206464ffcb255d22ad t/20-unit/Types-Standard/strmatch.t SHA256 d722cb38622a8d4af10d29179e95be70ca523ebe51d2e1ae3342f68f9740e734 t/20-unit/Types-Standard/structured.t SHA256 7a1a8300bf660e0cb0c60448f849435f9d880feeae743e5e709f6aae8ef48e20 t/20-unit/Types-Standard/tied.t SHA256 ed1c804319f24d3d37ddb07a1d99d0d70db156b970c9ef9a3c53e2c7209249bc t/20-unit/Types-TypeTiny/basic.t SHA256 a74b672eb03bf288c37a6cdd50518ce1a3057156577286ffc3201a1f8f79c4ed t/20-unit/Types-TypeTiny/coercion.t SHA256 ec75787d7d978edfce378c186cde034ce9f243b6b828a14c1485ee4a0c02fe69 t/20-unit/Types-TypeTiny/meta.t SHA256 f8346b4c5896185b71a0a2a6dbcfdd1e78a233a3d4e7045e8f49257faf322760 t/20-unit/Types-TypeTiny/moosemouse.t SHA256 41fdb181bb13aa29ac9a4a45b3c3fca6d337b4f757b94a08686f2956c3cc6fe7 t/20-unit/Types-TypeTiny/progressiveexporter.t SHA256 b70c67f5edefcedcc7abfc5da2a2b050ec225bfb5507e74ab22465bae5862b7c t/21-types/Any.t SHA256 99453ad0544dd2ed1c1dbaf860a7e9e22d15bc59edd55d666df778c8ec467bbd t/21-types/ArrayLike.t SHA256 6653d702a9ae4e425f3e312d983f4fd119cd7d05e53794129f66c072466895f2 t/21-types/ArrayRef.t SHA256 427df1eda893b5050ccc7f28a687ef63825d1e13fe3da42bf11ee8128f6c48f9 t/21-types/Bool.t SHA256 056efdeb07da23c1e936b7303d12003b3b9afa542063a865f5fc74e68faa162b t/21-types/ClassName.t SHA256 ee1141b9eef343bdcb37cae767eaf7894bafad6496555f7db08a33aadb6a957a t/21-types/CodeLike.t SHA256 c2124a1326693db7a78f915bf4e789b90397cf8523d8ddf91835cc5b0921e201 t/21-types/CodeRef.t SHA256 430446411f6280ec7a76ccc082ca56f7092b73e1900718d5cdfd3376eeb5f9b6 t/21-types/ConsumerOf.t SHA256 1d21e37a9a659eaa3707e6162237d688c7c574d1e905f3bac5d4fcbc12aaf127 t/21-types/CycleTuple.t SHA256 372fe2eb6bcb8bc72a286a17bce287caade40e3767a1050ffec01bef760ddd3f t/21-types/Defined.t SHA256 b08bd28d915ecdaf0b67a6201f0f60c484935537f6657aa876478049903e2d2f t/21-types/Dict.t SHA256 860e8a0bd25688bf2d06ba3592e969586e303c4af6d09c8be1ca81261cade660 t/21-types/Enum.t SHA256 ea455ec9d7ce96c3e2b60712b177d2bd7d24597deb49764d3b1787bc13caff1c t/21-types/FileHandle.t SHA256 4d8a268c2aa5954992bfc5611f7be49f86cb8ab023e26467078fc158ed59a998 t/21-types/GlobRef.t SHA256 a8dc561fec2e132243d6be759624a1c184b6003ec9fcfcce54b277e480162089 t/21-types/HasMethods.t SHA256 ce0a3386978e55f3fe9a0f9bd3e09678abb422090e8b042f54466105a725dc5e t/21-types/HashLike.t SHA256 f95997b8860129a4edb0175ea359d827bebcd127cc524f0e9ffe4d28a8bd88f9 t/21-types/HashRef.t SHA256 cbcccda1a59dc59294388f65b44515cfb4e7ee76a35e78e77ff1ade741829d48 t/21-types/InstanceOf.t SHA256 c74810e064e13984ae69860119721f62f62b22df1b15673008215d407d8064d6 t/21-types/Int.t SHA256 fbc7222e257f60f0a7481f70ea13aeb70ebcfc1666051595a7764bd2ae476c5c t/21-types/IntRange.t SHA256 029f0cd69f7a39b2bb7394ca509049105617d7bbc1d321883cf259a85de95376 t/21-types/Item.t SHA256 91d2197d33764a62cf187db3660eb0a9456686e1a68b3fc2510a5b2ae577dae2 t/21-types/LaxNum.t SHA256 dfe898a0ce5f768708be719463f550256b656c4dcd89760521a33dd0a08d631f t/21-types/LowerCaseSimpleStr.t SHA256 e306262a064c65a6a700f1d961c165771dd01d752c38ae57b7822bb3cf187a7b t/21-types/LowerCaseStr.t SHA256 e6ef4db21bdabf98173f9788f0fefb002c4e69b7fd057350dbed89cd6865dc94 t/21-types/Map.t SHA256 511c7150a9a6728529a66e1dc64aae69fbb9ca71167a8dd9a39a885f6cea20a1 t/21-types/Maybe.t SHA256 188c93ac04e2f2923873bbb1abc29349f2cff1400f5d591616ca9c55b366681f t/21-types/NegativeInt.t SHA256 918f38ac5aa8ece67ab84f51f38c53cc9bb0afde56760526425568b63e65be81 t/21-types/NegativeNum.t SHA256 36027b9e2836f84f9f65dd92598c4d4883f83347d389199af19a2cdfd37758ed t/21-types/NegativeOrZeroInt.t SHA256 40cb80e8b0e497716ab5641bebc5fe5192e9569a90ba40d73ac64073a1216cb6 t/21-types/NegativeOrZeroNum.t SHA256 3288e7288fcdc147a28bf570aaea4e43556a6890364bd6fa947beec0eaa62cc0 t/21-types/NonEmptySimpleStr.t SHA256 c8e7286640740e8757bf3438bc1b8fa2bb1b423ecfbe6b2824cbe83f9abd15cb t/21-types/NonEmptyStr.t SHA256 509dae8814d78a59d5e3bb1e79edf28c0139098aa48a4806a9338def5ea492c5 t/21-types/Num.t SHA256 cba74e990905516b58ca90cee9e6ed4148602bdfc0e992f5a72ed6eb5d150016 t/21-types/NumRange.t SHA256 e39e6dba6a78890f19193be91745dfc109f3f01c5f83031049b208a9f39d04cd t/21-types/NumericCode.t SHA256 d8120dae07717a6cc44bbc462faa9e7108e0779a27b9bea1bda027ec6be9e250 t/21-types/Object.t SHA256 66e0501ab584f019b661aa4c75f41e37ed7603154264da4e7a29f0d31410fea2 t/21-types/OptList.t SHA256 1db505b4e1dc083b50b1130559891b893c2430454e1bb94f74b0948df973fafd t/21-types/Optional.t SHA256 91360445a7a781fcba20838b460e0682de4110727aa8385b094b61c72e07074c t/21-types/Overload.t SHA256 083987a5e2da2150eab3ab58fdcf455a51818515f975044d7ab1651c9c58e7d2 t/21-types/Password.t SHA256 caa39fbb07074c7496739249be81db8d65c1db2938c832b070b493d5882a77de t/21-types/PositiveInt.t SHA256 498003ad060a8b54dc22676e8c4ed47fc4ab42ce5fb419da163b4eaeed6d17df t/21-types/PositiveNum.t SHA256 97ceceffead1141234b5f5bab2d4f8c4b68d589511aa100b3f0472766b29531e t/21-types/PositiveOrZeroInt.t SHA256 5dc018f8aa09678344a09f2fae3706513ff39bfb39fcff93f49f15d7519a6539 t/21-types/PositiveOrZeroNum.t SHA256 5fa1827d1a486a936cbcc529fc779131c7026d6a1bb2bc71019c5f29112750f0 t/21-types/Ref.t SHA256 2b1094214e29c0472f300d1cf0e2b8e1fafb134a98e6765faf04a8ec2ead7334 t/21-types/RegexpRef.t SHA256 68645205a5345fc2bccfc0b3c67758504e499f498f3480b872ba79511b366d98 t/21-types/RoleName.t SHA256 870ffef86b2119f87f4b74a6afa3cbf158afb3eaf15397d4ed0de0905b2cb079 t/21-types/ScalarRef.t SHA256 569b4220dfea4c12eba8cdc1406574b28c0320817aae5e1d8b07e431462d0455 t/21-types/SimpleStr.t SHA256 726ba1fb5342f49dfa6dd35273fbd9beced2d3d371c2c6f00d06603a5a439889 t/21-types/SingleDigit.t SHA256 23ebfe461dfa6159e5c2f10e2a000a5f4550b43bf8b2e415f69e1341ef099a26 t/21-types/Str.t SHA256 2ed08b937a173125b5aac6e88008d20400c2eea2fb0bd4b827906b6affd81cee t/21-types/StrLength.t SHA256 35ed1f1ad3349e5ec12ce65d976b51bb9ed30b69640b593ae7c509a21f94c7da t/21-types/StrMatch.t SHA256 caf4fc7b69abceb61db3f6546c2fc90edc5db9c4e36bdc70156d27c564498bf3 t/21-types/StrictNum.t SHA256 0690a6d48470670bb2551ef2e28c8bba3f94458600c8f470d8c09084cb127d49 t/21-types/StringLike.t SHA256 2f218ad8291ebea316119680126236477315c7068b23e1c8cf27b6b6b0d1de51 t/21-types/StrongPassword.t SHA256 06db19531295acb251aab29d7f1dc24d830d0dbbcd0d07ece11fe3747fb77aaf t/21-types/Tied.t SHA256 8a32f669c49bd7a3503fedbf46bc74a713ecbacb70143792c29d272ebc2af819 t/21-types/Tuple.t SHA256 da491d3a878949f4132e07ba61376988792aa0675f743632db109b7c2fbd10bc t/21-types/TypeTiny.t SHA256 a0b19c900fb318d5035951e709907472e272b010facf54080e3b60b8137b8043 t/21-types/Undef.t SHA256 92ae4c078222a3ed0794df92dec61c2bcce96602eee919376a0f9d4dc2b08225 t/21-types/UpperCaseSimpleStr.t SHA256 3249e84cec6a091a5f2cf649d0922223e2376d4916ec427e44201054d0f606b3 t/21-types/UpperCaseStr.t SHA256 47775b0457c309d7d313b78282b5730a31deab58d3df2569fc5a97699def9526 t/21-types/Value.t SHA256 126accef6f1610da783c70f34279971ca947a4712baed8866bfe6fbeee8f1255 t/30-integration/Class-InsideOut/basic.t SHA256 c8c658fc5fa0657da862b59ff2d5edb66f4b3d0f613b91c4617c314319df9707 t/30-integration/Exporter-Tiny/basic.t SHA256 94ade5910830db8d8f73b32a479ce671ac29990bf62499430e555fc585e96d25 t/30-integration/Exporter-Tiny/installer.t SHA256 ec5bf9ba00ab7bfc87948306e33bf04e67c4166626b829a0553439a6ff94c003 t/30-integration/Exporter-Tiny/role-conflict.t SHA256 fda2bef5f9341a89c682069baf09d615bba94ce3b257296a4f7f4d97dfe25fd8 t/30-integration/Function-Parameters/basic.t SHA256 aed9a6d42aca610e892701416de3fe48f51cdab8aa6a69b16fff2e92314dcdfa t/30-integration/Kavorka/80returntype.t SHA256 0573d8df1b480fef509b32b88884be6ebc967795a71bcf6207017a833a50b9cf t/30-integration/Kavorka/basic.t SHA256 b5d359650920852af59de7af3dbbd9f8d2fcc121613c46755a334d7d49015b7d t/30-integration/Moo/basic.t SHA256 8f51a93b71377a22c273b6918c11f3c7872f9d1c82430f5597994e27130f5c36 t/30-integration/Moo/coercion-inlining-avoidance.t SHA256 42b4e26ac2d33497d49128d3fd79d5592164ef5893378d58aaa310fcbb36fe12 t/30-integration/Moo/coercion.t SHA256 17e83273d91347d532eee553e69a676ec93575fb0edd8b2c0ec8bdf964dd45f6 t/30-integration/Moo/exceptions.t SHA256 d63f2a5d56582911de13ac0ac46fc9886a0e3000d6fdedb5ca0dbd6c18e260c1 t/30-integration/Moo/inflation.t SHA256 1a39abee308fe61e7caabff08890ee55d46b58c81128f787a5c12251de85a344 t/30-integration/Moo/inflation2.t SHA256 c574c45aa7c98f6156f77fc8d9ca26cd6b1133e7c50233f8ee6287bb8785dd0f t/30-integration/Moops/basic.t SHA256 371deb00a671dbbd76ed863f7076d92ed8233b2af7cd1caacc220dc21e2e9dee t/30-integration/Moops/library-keyword.t SHA256 c24c740083a2f5762b34ead266dcecaf7a35b28527a6c33e53075d505ecade3c t/30-integration/Moose/accept-moose-types.t SHA256 17e3ad039b16547e612082378a8ee1202ea0f4481312dc9878171bbef5f2b42b t/30-integration/Moose/basic.t SHA256 d639a490ee1601d90f08219a6545937b883e2b7dfbda6eb268405c2108af1436 t/30-integration/Moose/coercion-more.t SHA256 09978af362fd48ecc7deb32122f230fefa6a27e4575b9147837d1a5d8fe33de1 t/30-integration/Moose/coercion.t SHA256 34a110a9083728ce57d2ffce0d0d0d1abb62e81050df36e39b093f9542d622dc t/30-integration/Moose/inflate-then-inline.t SHA256 8b7209157ba88935322b3ad85548e5df3e5d2f2c2a334148011e35bb1a378ecb t/30-integration/Moose/native-attribute-traits.t SHA256 7d65a73487416b26e2b6f5dbdc6a53f41d410b6ada04ba3faf068a84ebd7b42a t/30-integration/Moose/parameterized.t SHA256 df02b2d6cdf0b866dcb672fc00b601981c7141c355c0070355c421e7b3acbaa4 t/30-integration/MooseX-Getopt/coercion.t SHA256 e086d85923abc20c755247b0081c858a6d8555176e967e9deeb84a4e97b2cb31 t/30-integration/MooseX-Types/basic.t SHA256 94490d66d0a4ea46f82f204c99bb88bec938fa92cda57a3398feb3c705e84826 t/30-integration/MooseX-Types/extending.t SHA256 04de033915dbbe788bf0ed40f6b1e4d60a24ecf8c28b89d787287d8ecb1d70ae t/30-integration/MooseX-Types/more.t SHA256 3e389a31463d31a27c630db5842e1625eb623eb6832679c2e649c9bb82d9c574 t/30-integration/Mouse/basic.t SHA256 8657f6b52db6c6684bb1b51da84a25b83cb66f5239a334253985624f16a49789 t/30-integration/Mouse/coercion.t SHA256 de28878cdde23b8e2277f1300c56269ed23481c7b07b392100bffb857915c428 t/30-integration/Mouse/parameterized.t SHA256 4bb5b6ff8e63108e14c9f81d798dfdd4a0d72a30a2f126e68a665e29051fa5dc t/30-integration/MouseX-Types/basic.t SHA256 65f5678b06796780f9b1a09ed2c27aa3f18e1fbbef810f7815dfa2bd9b9c63e9 t/30-integration/MouseX-Types/extending.t SHA256 8ff1bbbd76cf7c9d0c62b2dd4b6a69a191a4c650627634343bf72c12fa7b308c t/30-integration/Object-Accessor/basic.t SHA256 c6f3c3ec9a156ed4f00c230c1f2250678cd01f8a5be2e59927c57945acde8bbf t/30-integration/Return-Type/basic.t SHA256 4c2b44c79e72b17bb4b5e595b14cb708857f31274dee5dbc15e85dfa6eac628f t/30-integration/Specio/basic.t SHA256 469d63c1037538202b31b66800fca717499c66f08db116103a257724499df5eb t/30-integration/Specio/library.t SHA256 89628bef00076baa65345487af5a052c943a193d16697712e157a82abd48db30 t/30-integration/Sub-Quote/basic.t SHA256 d58fa42eee09544a9d4aa17cdc3fe973586472799058866ffbd57d54a231fee1 t/30-integration/Sub-Quote/delayed-quoting.t SHA256 6de4dd648fec68fe6ecd15ce25ba93bdf55d03c468137ad23f234f5ebdb1b4f2 t/30-integration/Sub-Quote/unquote-coercions.t SHA256 d144a22245c12cdb2155fd218bd157c2e1e16f44f08d67569cc25dcf7a71abdb t/30-integration/Sub-Quote/unquote-constraints.t SHA256 e230b22538c4de05909c8bfbd6d0672369dde09094c50c14478d925d1da633e3 t/30-integration/Switcheroo/basic.t SHA256 0a37472a0f562761ed2bc296c41539b7ffef9ed040c60f4fc690703bf94622fd t/30-integration/Type-Tie/basic.t SHA256 aa0e240646b96b52ba49178dc90158dc49f97771eaaf1b3962a2dca8af0f37b4 t/30-integration/Types-ReadOnly/basic.t SHA256 3e047c91d49dbc499d3a89822ce92e173be2d06f1d0d2a4843e0baf0c892be42 t/30-integration/Validation-Class-Simple/archaic.t SHA256 38cc56766005bedc42c3613ba70a7afb27081a55868306315be3ebe1f9118296 t/30-integration/Validation-Class-Simple/basic.t SHA256 d5bcdb3f1216fd47afc2cd33f05cf8a21c05a0b0eb274789958164ce459313e8 t/30-integration/match-simple/basic.t SHA256 f533b199b75930aa5dc5d3ad0961de3daa8b8538275eb38e6a162851b2e281f1 t/40-regression/73f51e2d.pl SHA256 dbdf5bf27d81d7ac4f4dcca98d1aada1346dbb4d59810e3b93fd128f5b48c61b t/40-regression/73f51e2d.t SHA256 abe5f7c7b4faed8ea88a7c2e049e9cfe80a17e4d6acf725ec8b0ddf9845cd66d t/40-regression/gh1.t SHA256 db4249a023d06faeda2677dddd943055e49c2a0ee5953d55daddb315a59fd519 t/40-regression/gh14.t SHA256 fe447d317df680d5b99554e99a4c976af10399c92117785b5be229a636f061ab t/40-regression/rt102748.t SHA256 8242a0d123028ae4378391de24f8170052bbe6a32abdab24528e5e5b8a663cf6 t/40-regression/rt104154.t SHA256 015ebf526001cacb8f60ba7d5b88ac31ebde9c579613671a907d83f94e1ce128 t/40-regression/rt121763.t SHA256 4edfb2e98438dcab560cb011510f373574bb91afd52661db7c46f9b1d128ff05 t/40-regression/rt125132.t SHA256 4a4452d7f4e386eae37c700bf5286a519cef9308ed0f265d5ea0d9790ef353ae t/40-regression/rt125765.t SHA256 89268caa2f73f064e618a486d1cd24a3a0571a2327e3de32ffabdee0e26902b3 t/40-regression/rt129729.t SHA256 0ecf9f72dbd3e05846d0ee64fed0407ad544f92e4680af8c3d04328992975c9a t/40-regression/rt130823.t SHA256 eb1ebd839c811d57ad8df8a2028fa2822b72dc311e65d600b3785f9060d597bb t/40-regression/rt85911.t SHA256 a9d90fd4de4ec2257d0c24815d43e796d643217e81c29b15d4d0ce6c031114b1 t/40-regression/rt86004.t SHA256 bef272fab15947e0d8084890a2999a3f2c6fa0c2a9e360a587152aeeeb4de8b4 t/40-regression/rt86233.t SHA256 f63016d3d168163b006f7b06076e9b2754c74acf859a1d1168ab0c48129e925e t/40-regression/rt86239.t SHA256 717ee43f352d7dd84a0d7aa9dfda31611501dd4717255636d58e7e9d1430a563 t/40-regression/rt90096-2.t SHA256 6a1d6f7e73fab9ebe43094cd7ce28e9ea59ad2a183ba79a96a417077d97b09a6 t/40-regression/rt90096.t SHA256 49874c94710ac7db378ba4a4a47b132fc642fe14f6315e1d52ee7b315bde414c t/40-regression/rt92571-2.t SHA256 ad4ee81cb06b8c2282a43f2682a1d13223c3654e6230b12649cdb3ac90ad7340 t/40-regression/rt92571.t SHA256 b01b4b8d3ea57a25e18f924689b17e97cd7c88c1e6c77bf5895c782b0e6c5d77 t/40-regression/rt92591.t SHA256 101e24342c6371cf01e1301331a29c47da848ac3b9c2294790511f17ac2522c9 t/40-regression/rt94196.t SHA256 22adbc04a55cb0ac4d336f1aef0aedc2509454c176e60e35d04face325fb323f t/40-regression/rt97684.t SHA256 fe4d8749964a7b44b5213a9729e06c362005b094cc0107bb98282c451e2685b1 t/40-regression/rt98113.t SHA256 1a1d78fd15ef7663f0103d0b833ace08752e8efa17df1089f8a2941bf6b8fa48 t/40-regression/ttxs-gh1.t SHA256 38416bdd46d8618a87423ed8edf3cae7f4ea205f8044d1a17fe125635e3bea7f t/98-param-eg-from-docs.t SHA256 51aa07997086542237c60ba532fbde28eb1c1d6f3a21e593bd2c221ef3a99b80 t/99-moose-std-types-test.t SHA256 aa0083e57c250d894855b3360eabacd1c5a8e7f0e72965585a7bf69e3442637b t/README SHA256 e589d42a1c1d3a891b0f7d9877679c3e00c82d514b0d7e6cbde66d4d6e6202bb t/TODO SHA256 5bad3388159e3553231b64f3e83d2a2dbaa90e98b0c98cb9021d8e172d261205 t/lib/BiggerLib.pm SHA256 3e3b8c96a27e98d96f14a3201438616ad29074e4bf247a82f2ae6c42e0da3eb1 t/lib/DemoLib.pm SHA256 ae3b960a903b5d1fe99ac8d22fef623c435d438223dd2a76404fcfd85fb787f2 t/mk-test-manifest.pl SHA256 f139bc177170bb9155072e1f92b6009b17498a45907a2def9f35fbb6cdaafb4b t/not-covered.pl -----BEGIN PGP SIGNATURE----- iF0EARECAB0WIQRVJKj/4+s6z4WzNujOv4Eoaip9OQUCXgd2dwAKCRDOv4Eoaip9 OR9YAKCQFRCq55MMVZ1is1OZni+61NjjcQCeJLoO1r5h1RIswHbXuGziNEBbVaA= =wjoG -----END PGP SIGNATURE----- dist.ini000644001750001750 16213601673061 14030 0ustar00taitai000000000000Type-Tiny-1.008001;; class = 'Dist::Inkt::Profile::TOBYINK' ;; name = 'Type-Tiny' ;; source_for_readme = 'lib/Type/Tiny/Manual.pod' doap.ttl000644001750001750 147652713601673167 14172 0ustar00taitai000000000000Type-Tiny-1.008001@prefix cpan-uri: . @prefix dc: . @prefix doap: . @prefix doap-bugs: . @prefix doap-changeset: . @prefix doap-deps: . @prefix doap-tests: . @prefix foaf: . @prefix nfo: . @prefix rdfs: . @prefix xsd: . dc:title "the same terms as the perl 5 programming language system itself". a doap:Project; doap:developer ; doap:download-page ; doap:homepage ; doap:name "Acme-Types-NonStandard"; doap:programming-language "Perl". a doap:Project; doap:developer ; doap:download-page ; doap:homepage ; doap:name "List-Objects-Types"; doap:programming-language "Perl". a doap:Project; dc:contributor ; doap-bugs:issue , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ; doap-deps:develop-recommendation [ doap-deps:on "Test::Memory::Cycle"^^doap-deps:CpanId; ]; doap-deps:develop-suggestion [ doap-deps:on "Dist::Inkt::Profile::TOBYINK"^^doap-deps:CpanId; rdfs:comment "This is used for building the release tarball."@en; ]; doap-deps:runtime-conflict [ doap-deps:on "Kavorka <= 0.013"^^doap-deps:CpanId; rdfs:comment "Theoretically broken by changes to parameterization of Dict to allow it to accept a slurpy."@en; ], [ doap-deps:on "Types::ReadOnly <= 0.001"^^doap-deps:CpanId; rdfs:comment "Theoretically broken by changes to parameterization of Dict to allow it to accept a slurpy."@en; ]; doap-deps:runtime-recommendation [ doap-deps:on "perl 5.010001"^^doap-deps:CpanId; rdfs:comment "For smartmatch operator overloading; and to avoid some pre-5.10 hacks."@en; ], [ doap-deps:on "Type::Tie"^^doap-deps:CpanId; rdfs:comment "Type::Tie is needed if you want to constrain the type of a scalar, array or hash variable."@en; ], [ doap-deps:on "Devel::StackTrace"^^doap-deps:CpanId; rdfs:comment "Type::Exception can use Devel::StackTrace for stack traces."@en; ], [ doap-deps:on "Devel::LexAlias 0.05"^^doap-deps:CpanId; rdfs:comment "Devel::LexAlias is useful for some Eval::TypeTiny features."@en; ], [ doap-deps:on "Type::Tiny::XS 0.016"^^doap-deps:CpanId; rdfs:comment "Makes a lot of stuff faster."@en; ], [ doap-deps:on "Ref::Util::XS 0.100"^^doap-deps:CpanId; rdfs:comment "Makes some stuff faster."@en; ], [ doap-deps:on "Regexp::Util 0.003"^^doap-deps:CpanId; rdfs:comment "Saner serialization of StrMatch type constraints."@en; ], [ doap-deps:on "Sub::Util"^^doap-deps:CpanId; rdfs:comment "This allows Type::Library to name subs nicely."@en; ]; doap-deps:runtime-requirement [ doap-deps:on "perl 5.006001"^^doap-deps:CpanId ], [ doap-deps:on "Exporter::Tiny 1.000000"^^doap-deps:CpanId; rdfs:comment "This module was spun off from the Type-Tiny distribution."@en; ]; doap-deps:runtime-suggestion [ doap-deps:on "Moose 2.0000"^^doap-deps:CpanId; rdfs:comment "Type::Tiny works nicely with Moose."@en; ], [ doap-deps:on "Mouse 1.00"^^doap-deps:CpanId; rdfs:comment "Type::Tiny works nicely with Mouse."@en; ], [ doap-deps:on "Moo 1.006000"^^doap-deps:CpanId; rdfs:comment "Type::Tiny works nicely with Moo. Use Moo 1.006000 or above for best results."@en; ], [ doap-deps:on "Reply"^^doap-deps:CpanId; rdfs:comment "Type::Tiny bundles a plugin for Reply."@en; ]; doap-deps:test-recommendation [ doap-deps:on "Test::Tester 0.109"^^doap-deps:CpanId; rdfs:comment "For testing Test::TypeTiny."@en; ], [ doap-deps:on "Test::Warnings"^^doap-deps:CpanId; rdfs:comment "For testing Type::Utils."@en; ]; doap-deps:test-requirement [ doap-deps:on "Test::More 0.96"^^doap-deps:CpanId; rdfs:comment "I don't have the patience to maintain a test suite that runs on ancient versions of Test::More."@en; ]; doap-deps:test-suggestion [ doap-deps:on "Test::Memory::Cycle"^^doap-deps:CpanId; ]; doap:bug-database ; doap:category [ rdfs:label "Moo" ], [ rdfs:label "Argument Validation" ], [ rdfs:label "Argument Checking" ], [ rdfs:label "Validation" ], [ rdfs:label "Moose" ], [ rdfs:label "Mouse" ], [ rdfs:label "Type Constraint" ], [ rdfs:label "Type Coercion" ], [ rdfs:label "Type Library" ], [ rdfs:label "Schema" ], [ rdfs:label "Parameter Validation" ], [ rdfs:label "Parameter Checking" ]; doap:created "2013-03-23"^^xsd:date; doap:developer ; doap:download-page ; doap:homepage , ; doap:license ; doap:maintainer ; doap:name "Type-Tiny"; doap:programming-language "Perl"; doap:release , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ; doap:repository [ a doap:GitRepository; doap:browse ; ]; doap:shortdesc "tiny, yet Moo(se)-compatible type constraint"; doap:tester ; foaf:page , , , , , , . a cpan-uri:DeveloperRelease, doap:Version; rdfs:label "Developer preview"; dc:identifier "Type-Tiny-0.000_01"^^xsd:string; dc:issued "2013-04-02"^^xsd:date; doap-changeset:released-by ; doap:file-release ; doap:revision "0.000_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.000_02"^^xsd:string; dc:issued "2013-04-02"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Beginnings of Type::Tiny::Manual."; ], [ a doap-changeset:Bugfix; rdfs:label "Anchor enum regexps to beginning and end of string."; ], [ a doap-changeset:Addition; rdfs:label "StrMatch added to Type::Standard."; ], [ a doap-changeset:Change; rdfs:label "use Type::Library -base"; ], [ a doap-changeset:Change; rdfs:label "use Type::Library -declare"; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.000_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.000_03"^^xsd:string; dc:issued "2013-04-03"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Document Type::Coercion's overloading."; ], [ a doap-changeset:Change; rdfs:label "Create and use compiled type constraint checks; much faster!"; ], [ a doap-changeset:Change; rdfs:label "All of Type::Standard cannow be inlined."; ], [ a doap-changeset:Tests; rdfs:label "Add test cases for ScalarRef[`a]."; ], [ a doap-changeset:Change; rdfs:label "Use more unique stringification for %Moo::HandleMoose::TYPE_MAP keys."; ], [ a doap-changeset:Change; rdfs:label "Make sure Type::Standard's Moose-like built-ins get inflated to real Moose built-in types."; ], [ a doap-changeset:Bugfix, doap-changeset:Tests; rdfs:label "Fix the crashing t/moo-inflation.t test case."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.000_03"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.000_04"^^xsd:string; dc:issued "2013-04-03"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Create and use compiled coercions; somewhat faster."; ], [ a doap-changeset:Addition; rdfs:label "Type::Tiny plus_coercions/minus_coercions/no_coercions methods for creating subtypes with different sets of coercions."; ], [ a doap-changeset:Addition; rdfs:label "Type::Tiny equals/is_subtype_of/is_supertype_of/is_a_type_of methods for type constraint comparisons."; ], [ a doap-changeset:Addition; rdfs:label "Finally implement Type::Coercion's has_coercion_for_type method."; ], [ a doap-changeset:Change; rdfs:label "Allow coercion code to be expressed as a string; quite a bit faster."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.000_04"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.000_05"^^xsd:string; dc:issued "2013-04-04"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Factor out some functions from test suite into a new module: Test::TypeTiny."; ], [ a doap-changeset:Tests; rdfs:label "Rearrange test suite slightly."; ], [ a doap-changeset:BackCompat; rdfs:label "Rename Type::Standard module to Types::Standard."; ], [ a doap-changeset:Change; rdfs:label "Types::TypeTiny bootstrapping library now takes care of vaious internal type checking requirements."; ], [ a doap-changeset:Change; rdfs:label "Sanity checks for type constraint names."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix is_parameterized method."; ], [ a doap-changeset:Change; rdfs:label "Allow null type constraints with no parent type (e.g. 'Any' in Types::Standard) to be inlined."; ], [ a doap-changeset:Change; rdfs:label "Don't die with full stack trace."; ], [ a doap-changeset:Bugfix; rdfs:label "Get Mouse coercions working."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.000_05"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.000_06"^^xsd:string; dc:issued "2013-04-05"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Monkey patch Moose::Meta::TypeConstraint to be able to retrieve Type::Tiny constraints from inflated Moose constraints."; ], [ a doap-changeset:Tests; rdfs:label "More test cases."; ], [ a doap-changeset:Documentation; rdfs:label "Improved documentation of parameterization attributes."; ], [ a doap-changeset:Change; rdfs:label "Footprint reduction: Type::Tiny, Type::Library and Type::Coerce no longer automatically load Types::Standard and Type::Utils."; ], [ a doap-changeset:Change; rdfs:label "Footprint reduction: Type::Tiny and Type::Coercion no longer use if.pm."; ], [ a doap-changeset:Change; rdfs:label "Footprint reduction: Type::Tiny no longer triggers Perl to load its Unicode tables (unless you create a type constraint with a non-ASCII type name)."; ], [ a doap-changeset:Addition; rdfs:label "Type::Tiny now has an 'inline_assert' function."; ], [ a doap-changeset:Documentation; rdfs:label "Using Type::Tiny with Moo added to manual."; ], [ a doap-changeset:Documentation; rdfs:label "Section in manual comparing Type::Tiny with various other type library frameworks."; ], [ a doap-changeset:Change; rdfs:label "In Moo, type assertions and coercions are now inlined."; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.000_06"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.000_07"^^xsd:string; dc:issued "2013-04-06"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "More test cases."; ], [ a doap-changeset:Documentation; rdfs:label "Document constructor for Type::Tiny::Class."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix inlining for Type::Tiny::Intersection."; ], [ a doap-changeset:Bugfix; rdfs:label "Types within libraries, if accessed directly rather than exported, did not accept parameters."; ], [ a doap-changeset:Addition; rdfs:label "New module Type::Coercion::Union automatically handles coercion to union types."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix inlining of certain conditionals into coercion code."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.000_07"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.000_08"^^xsd:string; dc:issued "2013-04-07"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Rewrite most of the functions exported by Type::Library-based type libraries to cope better with being used mid-list."; ], [ a doap-changeset:Change; rdfs:label "Most parts of the API that accept Type::Tiny objects (e.g. Type::Utils::from()) now also accept Moose::Meta::TypeConstraint objects."; ], [ a doap-changeset:Change; rdfs:label "Types::TypeTiny::to_TypeTiny can be used to coerce a Moose type constraint object to Type::Tiny."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.000_08"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.000_09"^^xsd:string; dc:issued "2013-04-08"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Bundle benchmarking scripts."; ], [ a doap-changeset:Packaging; rdfs:label "Tidy up the 'examples' directory."; ], [ a doap-changeset:Change; rdfs:label "When generating Moose/Mouse constraints from Type::Tiny objects, prefer to generate anonymous ones."; ], [ a doap-changeset:Documentation; rdfs:label "Fill in the Usage with Moose section of the fine manual."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.000_09"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.000_10"^^xsd:string; dc:issued "2013-04-09"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Improvements to has_coercion_for_{type,value} from Type::Coercion."; ], [ a doap-changeset:Bugfix, doap-changeset:Tests; rdfs:label "Fix incorrect Test::Requires line in 'mouse-coercion.t'."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.000_10"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.000_11"^^xsd:string; dc:issued "2013-04-11"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix prototype for Type::Utils::as."; ], [ a doap-changeset:Change; rdfs:label "No longer need to pass '-moose' parameter when importing a library into a Moose class; only Mouse needs that treatment now."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.000_11"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.000_12"^^xsd:string; dc:issued "2013-04-12"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Fix minor typo."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.000_12"^^xsd:string. a doap:Version; rdfs:label "First public release"; dc:identifier "Type-Tiny-0.001"^^xsd:string; dc:issued "2013-04-15"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Minor improvements."; ], [ a doap-changeset:Bugfix; rdfs:label "Some inline code assumed that it would be compiled in a package that had 'blessed' imported."; ], [ a doap-changeset:Bugfix; rdfs:label "Some inline code wasn't wrapped in parentheses."; ], [ a doap-changeset:Tests; rdfs:label "More test cases for Optional[`a] within Dict[`a]."; ], [ a doap-changeset:Change; rdfs:label "Weaken the reference from a Moose::Meta::TypeConstraint object to its Type::Tiny origin."; ], [ a doap-changeset:Change; rdfs:label "Parameterized type constraints in Types::Standard now do some sanity checking on their arguments."; ], [ a doap-changeset:Change; rdfs:label "Improve test names generated by Test::TypeTiny; allow test scripts to provide test names."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.001"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.002"^^xsd:string; dc:issued "2013-04-26"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Link from Test::TypeTiny to Test::Deep::Type."; ], [ a doap-changeset:Change; rdfs:label "Avoid unnecessarily regenerating parameterized type constraints."; ], [ a doap-changeset:Change; rdfs:label "Make Type::Tiny's has_coercion method more DWIM."; ], [ a doap-changeset:Addition; rdfs:label "Chars and Bytes types added to Types::Standard."; ], [ a doap-changeset:Bugfix; rdfs:label "Prevent warnings (about 'my $val' masking a previously declared variable) when several Str checks are being inlined in close proximity, such as Tuple[Str,Str]"; ], [ a doap-changeset:Bugfix; rdfs:label "Fix method conflicts when exporting type constraints to roles."; doap-changeset:fixes [ doap-bugs:reporter ; ]; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.002"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.003_01"^^xsd:string; dc:issued "2013-04-16"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Link from Test::TypeTiny to Test::Deep::Type."; ], [ a doap-changeset:Change; rdfs:label "Allow a Type::Tiny object to \"freeze\" its coercions. This prevents a Type::Tiny object from becoming out of sync with its equivalent Mouse or Moose constraint objects."; ], [ a doap-changeset:Change; rdfs:label "Type::Library packages can now include \"standalone\" Type::Coercion objects, not attached to a type constraint. These can be exported on request."; ], [ a doap-changeset:Change; rdfs:label "Overload \"+\" operator for Type::Coercion and Type::Tiny allows coercions to be added to each other, and added to type constraints."; ], [ a doap-changeset:Change; rdfs:label "Build coercions automatically for certain type parameterized constraints. Say there's a Num->Int coercion defined; then we should be able to coerce ArrayRef[Num]->ArrayRef[Int]."; ], [ a doap-changeset:Change; rdfs:label "Allow subtypes to inherit coercions from their parent type constraint. (They do not by default.)"; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.003_02"^^xsd:string; dc:issued "2013-04-16"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Document how to process sub parameters with Type::Tiny, and point people towards Type::Params."; ], [ a doap-changeset:Change; rdfs:label "Avoid unnecessarily regenerating parameterized type constraints."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.003_03"^^xsd:string; dc:issued "2013-04-17"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Add OptList data type to Types::Standard, plus MkOpt coercion."; ], [ a doap-changeset:Change; rdfs:label "When inflating Moo type constraints to Moose, don't unnecessarily call 'moose_type' method."; ], [ a doap-changeset:Change; rdfs:label "Make Type::Tiny's has_coercion method more DWIM."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003_03"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.003_04"^^xsd:string; dc:issued "2013-04-18"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Factor out the sub exporting code scattered around (in Type::Utils, Types::TypeTiny and Type::Library) into a single module, Exporter::TypeTiny."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003_04"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.003_05"^^xsd:string; dc:issued "2013-04-19"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Chars and Bytes types added to Types::Standard."; ], [ a doap-changeset:Change; rdfs:label "Allow coercions to accept parameters."; ], [ a doap-changeset:Addition; rdfs:label "Encode, Decode, Join and Split coercions added to Types::Standard."; ], [ a doap-changeset:Bugfix; rdfs:label "Prevent warnings (about 'my $val' masking a previously declared variable) when several Str checks are being inlined in close proximity, such as Tuple[Str,Str]"; ], [ a doap-changeset:Addition; rdfs:label "Type::Tiny::Class now has a plus_constructors method."; ], [ a doap-changeset:Documentation; rdfs:label "Create a new manual page Type::Tiny::Manual::Coercions."; ], [ a doap-changeset:Documentation; rdfs:label "Document Exporter::TypeTiny."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003_05"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.003_06"^^xsd:string; dc:issued "2013-04-25"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "No longer need to add '-mouse' when importing types into Mouse libraries. (Same change as what we did for Moose in 0.000_11.)"; ], [ a doap-changeset:Documentation; rdfs:label "Add lots of stuff to Type::Tiny::Manual::UsingWithMouse."; ], [ a doap-changeset:Documentation; rdfs:label "Document deep coercions (feature added in 0.003_01)."; ], [ a doap-changeset:Change; rdfs:label "Add a bunch of stub methods to Type::Tiny and Type::Coercion in order to make it less necessary to inflate to Moose/Mouse meta objects."; ], [ a doap-changeset:Change; rdfs:label "Various minor changes to Exporter::TypeTiny to make it more Sub::Exporter compatible."; ], [ a doap-changeset:Change; rdfs:label "Types::TypeTiny::to_TypeTiny can now coerce from a Mouse::Meta::TypeConstraint."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003_06"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.003_07"^^xsd:string; dc:issued "2013-04-26"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Document usage with Class::InsideOut."; ], [ a doap-changeset:Documentation; rdfs:label "Minor improvements to manual."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix method conflicts when exporting type constraints to roles."; doap-changeset:fixes [ doap-bugs:reporter ; ]; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003_07"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.003_08"^^xsd:string; dc:issued "2013-04-26"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "ASCII-only strings are now accepted by the Chars constraint in Types::Standard."; ], [ a doap-changeset:Documentation; rdfs:label "More Exporter::TypeTiny docs, including usage with Sub::Exporter::Lexical."; ], [ a doap-changeset:Tests; rdfs:label "Add test case using Exporter::TypeTiny with Sub::Exporter::Lexical."; ], [ a doap-changeset:Change; rdfs:label "Type::Tiny, Type::Coercion and their subclasses no longer call Types::TypeTiny->import method."; ], [ a doap-changeset:Change; rdfs:label "Types::TypeTiny lazily loads Exporter::TypeTiny - i.e. it loads Exporter::TypeTiny when Types::TypeTiny->import is first called."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003_08"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.003_09"^^xsd:string; dc:issued "2013-04-28"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Document usage with Params::Check and Object::Accessor."; ], [ a doap-changeset:Addition; rdfs:label "'Tied' type constraint added to Types::Standard."; ], [ a doap-changeset:Change; rdfs:label "If Mouse is already in memory, Type::Tiny will use its super-fast XS subs to validate values when possible."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003_09"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.003_10"^^xsd:string; dc:issued "2013-04-29"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Improve Exporter::TypeTiny documentation."; ], [ a doap-changeset:Documentation; rdfs:label "Improve advice on inlining type constraints and coercions."; ], [ a doap-changeset:Packaging; rdfs:label "Bump version of Test::More dependency fom 0.88 to 0.96."; ], [ a doap-changeset:Change; rdfs:label "General code tidy-up."; ], [ a doap-changeset:Addition; rdfs:label "Type::Tiny::SUPPORT_SMARTMATCH constant."; ], [ a doap-changeset:Addition; rdfs:label "New module, Eval::TypeTiny"; ], [ a doap-changeset:Change; rdfs:label "Much of the stringy eval stuff has been factored out into Eval::TypeTiny."; ], [ a doap-changeset:Addition; rdfs:label "Bundle Type::Params, which had previously appeared on CPAN in a separate developer release."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003_10"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.003_11"^^xsd:string; dc:issued "2013-04-30"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Test cases for Eval::TypeTiny."; ], [ rdfs:label "Automatic coercion for parameterized Dict will no longer drop key/value pairs to force a coercion."; doap-changeset:thanks ; rdfs:seeAlso ; ], [ rdfs:label "Automatic coercion for parameterized Tuple will no longer drop values to force a coercion."; doap-changeset:thanks ; rdfs:seeAlso ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003_11"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.003_12"^^xsd:string; dc:issued "2013-05-01"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Allow people to use Carp::{confess,cluck,carp} with Type::Params validators; default is still croak."; ], [ a doap-changeset:Change; rdfs:label "Improved Type::Params documentation."; ], [ a doap-changeset:Bugfix; rdfs:label "Sane behaviour for Types::Standard's 'slurpy' function when it appears mid-list."; ], [ rdfs:label "Type::Params validators now explicitly check the number of arguments passed to them."; doap-changeset:thanks ; rdfs:seeAlso ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003_12"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.003_13"^^xsd:string; dc:issued "2013-05-03"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Don't crash in old versions of Moose that have no Class::MOP::_definition_context() function."; ], [ a doap-changeset:Change; rdfs:label "Better documentation and tests of Moose/Mouse-compatible API."; ], [ a doap-changeset:Tests; rdfs:label "BAIL_OUT in test suite if 00-compile.t or 01-api.t fail."; ], [ a doap-changeset:Documentation; rdfs:label "Fix typo in Type::Params documentation."; doap-changeset:blame ; rdfs:seeAlso ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003_13"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.003_14"^^xsd:string; dc:issued "2013-05-03"^^xsd:date; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003_14"^^xsd:string; rdfs:comment "No functional changes.". a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.003_15"^^xsd:string; dc:issued "2013-05-03"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Improvements to to_TypeTiny function, including accepting Validation::Class::Simple objects."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003_15"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.003_16"^^xsd:string; dc:issued "2013-05-05"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Rename Types::Standard::AutomaticCoercion -> Types::Standard::DeepCoercion."; ], [ a doap-changeset:Change; rdfs:label "Type::Params produces nicer error messages."; ], [ a doap-changeset:Documentation; rdfs:label "Document that Map[`k,`v] has a deep coercion."; ], [ a doap-changeset:Documentation; rdfs:label "Improve Type::Coercion documentation."; ], [ a doap-changeset:Change; rdfs:label "Minor updates to coderef overloading following Moo 1.002000 release."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003_16"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.004"^^xsd:string; dc:issued "2013-05-06"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Minor updates to to_TypeTiny following Validation::Class 7.900048 release."; ], [ a doap-changeset:Bugfix; rdfs:label "Eval::Closure now strips line breaks and other unsavoury characters from descriptions."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.004"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.005_01"^^xsd:string; dc:issued "2013-05-07"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Type::Library should require Perl 5.8.1, not 5.8.3."; ], [ a doap-changeset:Addition; rdfs:label "ArrayLike type added to Types::TypeTiny."; ], [ a doap-changeset:Addition; rdfs:label "Type::Registry."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.005_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.005_02"^^xsd:string; dc:issued "2013-05-14"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Fix a typo in declare_coercion in Type::Tiny::Manual::Coercions."; doap-changeset:blame ; ], [ a doap-changeset:Documentation; rdfs:label "Link to Type::Tiny::Manual::Libraries instead of non-existing Type::Tiny::Intro."; doap-changeset:blame ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.005_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.005_03"^^xsd:string; dc:issued "2013-05-14"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Many error conditions now throw exception objects instead of string error messages."; ], [ a doap-changeset:Removal; rdfs:label "Bytes and Chars type constraints removed from Types::Standard."; ], [ a doap-changeset:Removal; rdfs:label "Decode and Encode coercions removed from Types::Standard."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.005_03"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.005_04"^^xsd:string; dc:issued "2013-05-17"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "All error conditions now throw exception objects instead of string error messages."; ], [ a doap-changeset:Change; rdfs:label "Deep explanations for Types::Standard::{Map,Maybe,Ref,Dict,Tuple} type constraint assertion failures."; ], [ a doap-changeset:Change; rdfs:label "Test::TypeTiny performs more thorough testing if EXTENDED_TESTING environment variable is set."; ], [ a doap-changeset:Bugfix; rdfs:label "Fixed bug in non-inlined code for Types::Standard::MkOpt."; ], [ a doap-changeset:Change; rdfs:label "Improved deep explanations for Types::Standard::{ArrayRef,HashRef,ScalarRef}."; ], [ a doap-changeset:Change; rdfs:label "Throw exception if people attempt to set parent types for Type::Tiny::{Class,Role,Duck,Enum,Union,Intersection}."; ], [ a doap-changeset:Addition; rdfs:label "Type::Exception::Compilation."; ], [ a doap-changeset:Change; rdfs:label "Allow the slurpy tail of a Types::Standard::Tuple to be a treated as a hashref rather than an arrayref."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.005_04"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.005_05"^^xsd:string; dc:issued "2013-05-24"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Fix warnings under Perl 5.18."; ], [ a doap-changeset:Documentation; rdfs:label "Suggest newer version of Validation::Class."; ], [ a doap-changeset:Addition; rdfs:label "Type::Tiny now has an assert_return method, which is used in most places in preference to assert_valid."; ], [ a doap-changeset:Removal; rdfs:label "Removed Type::Registry from the release; it will return at a later date."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.005_05"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.005_06"^^xsd:string; dc:issued "2013-05-26"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Fold Types::Standard::DeepCoercion into Types::Standard."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix StrMatch to properly support regexps containing slashes."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.005_06"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.005_07"^^xsd:string; dc:issued "2013-05-28"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Add pure-Perl Mouse to examples/benchmark-constraints.pl."; ], [ a doap-changeset:Bugfix; rdfs:label "Assertions using the assert_return pattern were triggering FATAL warnings when inlined with Sub::Quote. Inlined assertions are now prefixed with 'no warnings \"void\";'."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.005_07"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.005_08"^^xsd:string; dc:issued "2013-05-28"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Use JSON::PP instead of JSON in test cases, because JSON::PP is a core module since Perl 5.14."; ], [ a doap-changeset:Tests; rdfs:label "Rearrange test cases"; ], [ a doap-changeset:Tests; rdfs:label "Add 00-begin.t."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.005_08"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.006"^^xsd:string; dc:issued "2013-05-28"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Exporter::TypeTiny::mkopt_hash now works."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.006"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; rdfs:label "Happy birthday to me..."; dc:identifier "Type-Tiny-0.007_01"^^xsd:string; dc:issued "2013-06-01"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix $VERSION defined in Type::Library."; ], [ a doap-changeset:Change; rdfs:label "Re-introduce Type::Registry, with improved parsing thanks to Type::Parser."; ], [ a doap-changeset:Addition; rdfs:label "Type::Parser."; ], [ a doap-changeset:Addition; rdfs:label "Types::Standard now has LaxNum/StrictNum type constraints."; ], [ a doap-changeset:BackCompat; rdfs:label "Types::Standard's Num constraint is now a subtype of either LaxNum and StrictNum (depending on environment)."; ], [ a doap-changeset:Change; rdfs:label "Implemented Types::TypeTiny->meta->get_type."; ], [ a doap-changeset:Packaging; rdfs:label "Generate README from Type::Tiny::Manual instead of Type::Tiny."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.007_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.007_02"^^xsd:string; dc:issued "2013-06-04"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Drop use of Carp in Type::Parser."; ], [ a doap-changeset:Documentation; rdfs:label "Improvements to Type::Tiny::Manual."; ], [ a doap-changeset:Documentation; rdfs:label "Improvements to Type::Tiny::Manual::Params, including rewritten manual processing section, and processing type constraints in function signatures via Function::Parameters/Attribute::Constract."; ], [ a doap-changeset:Tests; rdfs:label "Test cases for usage with Function::Parameters."; ], [ a doap-changeset:Change; rdfs:label "Allow constraint_generators (for parameterizable type constraints) to return full Type::Tiny objects instead of plain coderefs."; ], [ a doap-changeset:Change; rdfs:label "Type::Tiny::Duck types now have a parent type constraint of Types::Standard::Object."; ], [ a doap-changeset:Change; rdfs:label "Type::Tiny::Role types now have a parent type constraint of Types::Standard::Object."; ], [ a doap-changeset:Change; rdfs:label "Type::Tiny::Enum types now have a parent type constraint of Types::Standard::Str."; ], [ a doap-changeset:Change; rdfs:label "Type::Tiny::Class types now have an automatically calculated parent type constraint based on @ISA."; ], [ a doap-changeset:Change; rdfs:label "Type::Tiny::Union types now have an automatically calculated parent type constraint based on the most specific common parent type constraint."; ], [ a doap-changeset:Change; rdfs:label "Type::Tiny::Intersection types now have an arbitrary parent type constraint."; ], [ a doap-changeset:Addition; rdfs:label "New constraints added to Types::Standard: InstanceOf, ConsumerOf, HasMethods and Enum."; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.007_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.007_03"^^xsd:string; dc:issued "2013-06-08"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Better document Type::Tiny's 'parents' method which differs from the Moose method of the same name."; ], [ a doap-changeset:Bugfix; rdfs:label "Inlining of certain deep Dict, Tuple and Map coercions was broken, but Type::Params attempted to inline them anyway, leading to death."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.007_03"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.007_04"^^xsd:string; dc:issued "2013-06-09"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "The combination of Dict, Optional and coercions seems to have been broken in certain circumstances."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Bugfix; rdfs:label "Overloading of `$type eq $type` now works in Perl 5.8."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.007_04"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.007_05"^^xsd:string; dc:issued "2013-06-12"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Add match_on_type and compile_match_on_type to Type::Utils."; ], [ a doap-changeset:Documentation; rdfs:label "Vastly improved documentation for Type::Utils."; ], [ a doap-changeset:Documentation; rdfs:label "Vastly improved documentation for Types::Standard."; ], [ a doap-changeset:Documentation; rdfs:label "Mention Scalar::Does and Type::Tie in manual."; ], [ a doap-changeset:Tests; rdfs:label "Added test cases for InstanceOf, ConsumerOf, HasMethods and Enum types defined by Types::Standard."; ], [ a doap-changeset:Change; rdfs:label "Support '0' and '1' as shortcuts for Optional[Any] and Any in Type::Params. (Not documented yet.)"; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.007_05"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.007_06"^^xsd:string; dc:issued "2013-06-16"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Rearranged documentation for Type::Utils, avoiding previous split into Moose-like and non-Moose-like functions."; ], [ a doap-changeset:Documentation; rdfs:label "Document the evaluation environment used by Eval::TypeTiny."; ], [ a doap-changeset:Addition; rdfs:label "Type::Exception is now capable of supplying stack traces (requires Devel::StackTrace)."; ], [ a doap-changeset:Change; rdfs:label "Exceptions thrown for Moo isa/coerce now indicate which attribute was involved."; ], [ a doap-changeset:BackCompat; rdfs:label "Type::Utils no longer exports 'extends' by default."; ], [ a doap-changeset:BackCompat; rdfs:label "Better prototypes (was `;@`, now `;$`) for parameterizable type 'constants' exported by type libraries."; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.007_06"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.007_07"^^xsd:string; dc:issued "2013-06-16"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Partly roll back prototype changes. Now we use `;$` for Perl since 5.14, but `;@`, for older Perls that don't support `;$` so well."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.007_07"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.007_08"^^xsd:string; dc:issued "2013-06-17"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix problem with interaction between constraints, coercions, and Moose classes that inherit from Moo classes."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Tests; rdfs:label "Bundle test for interaction between constraints, coercions, and Moose classes that inherit from Moo classes."; doap-changeset:blame ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.007_08"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.007_09"^^xsd:string; dc:issued "2013-06-18"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix problems inlining Dict deep coercions where the target constraint could not be inlined."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Bugfix; rdfs:label "Fix unintuitive Dict deep coercions."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Tests; rdfs:label "Bundle various tests for deep Dict coercions."; doap-changeset:blame ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.007_09"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.007_10"^^xsd:string; dc:issued "2013-06-21"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Type::Parser now supports parentheses in its DSL."; ], [ a doap-changeset:Addition; rdfs:label "Type::Parser now exports a _std_eval function useful for testing."; ], [ a doap-changeset:Bugfix; rdfs:label "Fixed many small parsing bugs in Type::Parser."; ], [ a doap-changeset:Change; rdfs:label "Improved error messages from Type::Parser."; ], [ a doap-changeset:Tests; rdfs:label "Add test cases for Type::Parser."; ], [ a doap-changeset:Tests; rdfs:label "Better test cases for Type::Registry."; ], [ a doap-changeset:Documentation; rdfs:label "Document status of Type::Registry."; ], [ a doap-changeset:Bugfix; rdfs:label "MooseX::Types objects used in Type::Tiny::Union, Type::Tiny::Intersection and parameterized Type::Tiny type constraints would break in some circumstances, as Types::TypeTiny::to_TypeTiny was failing to convert them to native Type::Tiny type constraints."; doap-changeset:fixes ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.007_10"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.008"^^xsd:string; dc:issued "2013-06-21"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.008"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.009_01"^^xsd:string; dc:issued "2013-06-21"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix error messages from type constraints with null constraint coderefs."; ], [ a doap-changeset:Addition; rdfs:label "Reply::Plugin::TypeTiny."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.009_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.009_02"^^xsd:string; dc:issued "2013-06-22"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Various minor optimizations for Eval::TypeTiny, Type::Tiny, etc."; ], [ a doap-changeset:Change; rdfs:label "Types::Standard no longer uses Type::Utils."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix for compiled_checks for type constraints inheriting from Type::Tiny::Class, etc."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Regression; rdfs:label "Types::Standard types no longer have 'library' attribute set; this subtly breaks Moo type inflation, and breaks the MooX::late test suite which relies on type inflation working correctly."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.009_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.009_03"^^xsd:string; dc:issued "2013-06-22"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix Types::Standard compilation errors under Perl 5.8.x."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.009_03"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.009_04"^^xsd:string; dc:issued "2013-06-23"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Type::Tiny::Class shouldn't completely trust @ISA when establishing parent class heirarchies."; ], [ a doap-changeset:Change; rdfs:label "Constructors for Type::Tiny subclasses no longer accept the 'constraint' parameter; it doesn't make sense."; ], [ a doap-changeset:Update; rdfs:label "Support Type::API interfaces."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.009_04"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.009_05"^^xsd:string; dc:issued "2013-06-23"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Type::Registry does the AUTOLOAD thing, so ought to provide a DESTROY method."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.009_05"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.009_06"^^xsd:string; dc:issued "2013-06-23"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Careful calling the DOES method (it doesn't exist in Perl 5.8)."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.009_06"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.009_07"^^xsd:string; dc:issued "2013-06-24"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Types::Standard::to_TypeTiny now sets 'display_name' instead of 'name' on generated type constraints."; ], [ a doap-changeset:Tests; rdfs:label "More test cases for interacting with MooseX::Types type constraints."; ], [ a doap-changeset:Change; rdfs:label "Type::Params no longer uses Type::Utils."; ], [ a doap-changeset:Change; rdfs:label "Subclasses of Type::Tiny reject 'inlined' coderef, just like they already reject 'constraint' coderef."; ], [ a doap-changeset:Change; rdfs:label "If a Type::Tiny object is instantiated with a Sub::Quote quoted constraint coderef, and no inlined coderef, then Type::Tiny will use Sub::Quote to make an inlined coderef."; ], [ a doap-changeset:Tests; rdfs:label "Make rt86172.t an 'xt' test case because it's causing random CPAN testers failures unrelated to the feature it's supposed to be testing."; rdfs:seeAlso ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.009_07"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.010"^^xsd:string; dc:issued "2013-06-24"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.010"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.011_01"^^xsd:string; dc:issued "2013-06-25"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Unions of Type::Tiny and Mouse::Meta::TypeConstraints now work properly. This makes Type::Tiny and MouseX::Types play nice together (much like Type::Tiny already plays nice with MooseX::Types)."; ], [ a doap-changeset:Change; rdfs:label "Cleanups within Type::Coercion. Necessary because in some places the entire type_coercion_map (including conversion coderefs) was passed through Types::Standard::to_TypeTiny, when really only the type constraints should have been."; ], [ a doap-changeset:Change; rdfs:label "Types::Standard::to_TypeTiny now accepts any object implementing the Type::API::Constraint or Type::API::Constraint::Coercion interfaces. As Mouse::Meta::TypeConstraint implements this interface, specific support for importing Mouse types has been dropped; the generic Type::API import 'just works' for Mouse types."; ], [ a doap-changeset:Change; rdfs:label "Types::Standard::to_TypeTiny now accepts unblessed coderefs and converts them to type constraints. This allows things like `Int & sub { $_ < 10 }` to work."; ], [ a doap-changeset:Bugfix; rdfs:label "B::SPECIAL-related fix."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.011_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.011_02"^^xsd:string; dc:issued "2013-06-25"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Types::Standard 0.009_02 stopped including 'library' attribute in its types, and thus broke MooX::late. Type::Library modified to make 'library' attribute more automatic, and less reliant on Type::Utils to do the right thing."; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.011_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.011_03"^^xsd:string; dc:issued "2013-06-25"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Type::Tiny now overloads `cmp`. Necessary because Mouse does a sort on type constraints in a union, and overload's fallback doesn't seem to cover `cmp` on Perl prior to 5.12."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.011_03"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.012"^^xsd:string; dc:issued "2013-06-25"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.012"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.013_01"^^xsd:string; dc:issued "2013-06-27"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Type::Parser's tokenization is now done on a pull basis, allowing one-pass building of the AST."; ], [ a doap-changeset:BackCompat; rdfs:label "Type::Parser no longer provides a `tokens` function as it no longer pre-emptively tokenizes the whole string it is given."; ], [ a doap-changeset:BackCompat; rdfs:label "Type::Parser functions no longer accept an arrayref of tokens, as they expect to pull tokens from a stream as required."; ], [ a doap-changeset:Addition; rdfs:label "Type::Parser now provides a `extract_type` function which parses a type constraint expression from the head of a string and returns a Type::Tiny object, plus the tail of the string. (This is designed to make it easier to use Type::Parser to parse things like function signatures.)"; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.013_01"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.014"^^xsd:string; dc:issued "2013-06-28"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.014"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.015_01"^^xsd:string; dc:issued "2013-07-05"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Type::Parser can now pull in types from MooseX::Types libraries properly."; ], [ a doap-changeset:Addition; rdfs:label "Type::Utils now provides a `dwim_type` function; this is powered by a hidden Type::Registry::DWIM package."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.015_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.015_02"^^xsd:string; dc:issued "2013-07-06"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Improvements to DWIMness of Type::Parser for the benefit of `dwim_type`."; ], [ a doap-changeset:Change; rdfs:label "Better test cases for `dwim_type`."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.015_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.015_03"^^xsd:string; dc:issued "2013-07-08"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "The `dwim_type` function now prioritizes lookups within the caller class' type registry over Types::Standard's built-in types."; ], [ a doap-changeset:Change; rdfs:label "Slight speed improvements for `compile_match_on_type`."; ], [ a doap-changeset:Addition; rdfs:label "Implement TIESCALAR, TIEARRAY and TIEHASH methods for Type::Tiny; this improves Type::Tie integration."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.015_03"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.015_04"^^xsd:string; dc:issued "2013-07-13"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Mention in Type::Tiny::Manual::Libraries that the `extends` function is no longer exported by default; update example code."; doap-changeset:blame ; doap-changeset:fixes , ; rdfs:seeAlso ; ], [ rdfs:label "Allow an inline_as block to return a list of strings (which are implictly joined with &&); allow the first item on the list to be undef, which is treated as the inlined parent type constraint."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Documentation; rdfs:label "Clarify when inlining via Sub::Quote may be less efficient than hand-written inlining."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.015_04"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.015_05"^^xsd:string; dc:issued "2013-07-15"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Packaging; rdfs:label "Experimentally drop required version of Perl from 5.8.1 to 5.6.1. I've not been able to extensively test Type-Tiny on Perl 5.6.x, but I believe it should mostly work. (The only feature that seems unlikely to work is non-ASCII names for type constraints and coercions.)"; ], [ a doap-changeset:Change; rdfs:label "Stop monkey-patching Moose::Meta::TypeContraint; it's not necessary and has never been documented."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.015_05"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.016"^^xsd:string; dc:issued "2013-07-16"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Add some pod links."; ], [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.016"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.017_01"^^xsd:string; dc:issued "2013-07-19"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Update; rdfs:label "Eval::TypeTiny now supports lexical subs under Perl 5.18."; ], [ a doap-changeset:Documentation; rdfs:label "Give an example of the default error messages thrown by Type::Tiny."; ], [ a doap-changeset:Bugfix; rdfs:label "Work around lack of B::perlstring() function in Perl 5.6.x."; ], [ a doap-changeset:Documentation; rdfs:label "Improve examples of custom type constraint error message in Type::Utils and Type::Tiny::Manual::Libraries."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Documentation; rdfs:label "Fix typo in Types::Standard 'regular exception' -> 'regular expression'."; doap-changeset:blame ; doap-changeset:fixes ; rdfs:seeAlso ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.017_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.017_02"^^xsd:string; dc:issued "2013-07-20"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Hopefully improved workaround for missing B::perlstring() using Data::Dumper instead of quotemeta()."; doap-changeset:thanks ; ], [ a doap-changeset:Bugfix; rdfs:label "Further changes for Perl 5.6.x support."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.017_02"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.018"^^xsd:string; dc:issued "2013-07-21"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.018"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.019_01"^^xsd:string; dc:issued "2013-07-23"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Work around lack of B::perlstring() function in Perl 5.6.x in test suite."; ], [ a doap-changeset:Bugfix; rdfs:label "Eval::TypeTiny now closes over variables properly."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.019_01"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.020"^^xsd:string; dc:issued "2013-07-23"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.020"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.021_01"^^xsd:string; dc:issued "2013-07-24"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Type::Tiny strictly_equals method."; ], [ a doap-changeset:Addition; rdfs:label "Type::Tiny is_strictly_subtype_of method."; ], [ a doap-changeset:Addition; rdfs:label "Type::Tiny is_strictly_supertype_of method."; ], [ a doap-changeset:Addition; rdfs:label "Type::Tiny is_strictly_a_type_of method."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.021_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.021_02"^^xsd:string; dc:issued "2013-07-26"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Use real lexicals again for Eval::TypeTiny; this requires Devel::LexAlias, but there's a fallback to using tied variables."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.021_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.021_03"^^xsd:string; dc:issued "2013-07-30"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Restore Eval::TypeTiny's pre-0.019_01 behaviour re closing over lexicals, but enable the 0.021_02 behaviour if alias=>1 option is passed in."; ], [ a doap-changeset:Change; rdfs:label "Improve compatibility between Type::Tiny and Moose attribute native traits."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.021_03"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.021_04"^^xsd:string; dc:issued "2013-07-30"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix Type::Parser's handling of numeric parameters; they shouldn't need quoting."; ], [ a doap-changeset:Packaging; rdfs:label "Add dependency on Exporter 5.57 for older versions of Perl."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix Types::Standard::Dict differentiating between undef and not exists."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.021_04"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.022"^^xsd:string; dc:issued "2013-08-06"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "In Devel::TypeTiny::Perl56Compat, `use strict` and `use warnings`."; ], [ a doap-changeset:Change; rdfs:label "Improved implementations of is_subtype_of/is_strictly_subtype_of; better for subclassing."; ], [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.022"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.023_01"^^xsd:string; dc:issued "2013-08-16"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix Moo -> Moose type inflation issue."; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.023_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.023_02"^^xsd:string; dc:issued "2013-08-23"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Type::Registry now has an `add_type` method, for adding a single type constraint to a registry."; ], [ a doap-changeset:Change; rdfs:label "Type::Registry's `add_types` method now supports importing MooseX::Types and MouseX::Types libraries."; ], [ a doap-changeset:Change; rdfs:label "Type::Utils' `extend` function now supports extending MooseX::Types and MouseX::Types libraries."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix quoting in error messages which caused Type::Params to be unable to compile some coderefs."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Bugfix; rdfs:label "Improve ugly type assertion failure messages when given structures of nested references."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.023_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.023_03"^^xsd:string; dc:issued "2013-08-23"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Constructors for some subclasses of Type::Tiny rejected hashrefs of paramaters."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Change; rdfs:label "Implementation of RegexpRef in Types::Standard is now closer to Moose's implementation (accepts blessed Regexps)."; ], [ a doap-changeset:Bugfix; rdfs:label "Stop considering the empty string to be a valid package name."; ], [ a doap-changeset:Tests; rdfs:label "Include additional test cases stolen from Moose."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.023_03"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.024"^^xsd:string; dc:issued "2013-08-27"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.024"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.025_01"^^xsd:string; dc:issued "2013-09-02"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "The Tuple structured type was treating arrays with missing required elements as if they were present but undef."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Change; rdfs:label "Make Exporter::TypeTiny support generators with less internals-hacking."; ], [ a doap-changeset:Documentation; rdfs:label "Document the internals of Exporter::TypeTiny."; ], [ a doap-changeset:Change; rdfs:label "Exporter::TypeTiny will now use method-style resolution when searching for a sub to export."; ], [ a doap-changeset:Packaging; rdfs:label "use Dist-Inkt"; ], [ a doap-changeset:Packaging; rdfs:label "Take advantage of dynamic_config to ask automated testers to test Type::Tiny with Moose present, but only if the Type::Tiny version number includes an underscore."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.025_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.025_02"^^xsd:string; dc:issued "2013-09-02"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Type::Params now provides a multisig() function, allowing you to define multiple function signatures, and attempt to validate @_ against them each in turn."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Bugfix, doap-changeset:Tests; rdfs:label "functionparameters.t now requires Moo or Moose and is skipped otherwise."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.025_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.025_03"^^xsd:string; dc:issued "2013-09-04"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Document that multisig() accepts coderefs."; ], [ a doap-changeset:Packaging; rdfs:label "Use a newer version of RDF::DOAP to process this changelog."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.025_03"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.026"^^xsd:string; dc:issued "2013-09-05"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.026"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.027_01"^^xsd:string; dc:issued "2013-09-07"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fixed some memory leaks. Still some work to do in this area."; ], [ a doap-changeset:Regression; rdfs:label "Weakening various references to fix memory leaks led to breaking Type::Tiny -> Moose -> Type::Tiny round-tripping via Types::TypeTiny::to_TypeTiny. Test cases for this marked TODO."; ], [ rdfs:label "Added `coercibles` method to Type::Tiny."; doap-changeset:thanks ; rdfs:seeAlso ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.027_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.027_02"^^xsd:string; dc:issued "2013-09-08"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Restore Type::Tiny -> Moose -> Type::Tiny round-tripping broken in previous release."; ], [ a doap-changeset:Documentation; rdfs:label "In Type::Tiny::Manual::Coercions, explain how to chain coercions."; rdfs:seeAlso ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.027_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.027_03"^^xsd:string; dc:issued "2013-09-09"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests, doap-changeset:Update; rdfs:label "Fix the ultra-finicky t/02-api.t to cope with changes to Moose::Meta::TypeConstraint API in Moose 2.1100."; ], [ a doap-changeset:Bugfix; rdfs:label "Prevent Eval::TypeTiny from leaking stashes by recycling the sandbox."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.027_03"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.027_04"^^xsd:string; dc:issued "2013-09-09"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests, doap-changeset:Update; rdfs:label "The file t/moose-coercion.t was checking a particular Moose warning message. In Moose 2.1100, this warning has been upgraded to an exception. For now, disable that particular check."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.027_04"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.027_05"^^xsd:string; dc:issued "2013-09-15"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Include a detailed explanation in the stringification of Type::Exception::Assertion."; ], [ a doap-changeset:Change; rdfs:label "Refactor the explanation generation mechanism."; ], [ a doap-changeset:Addition; rdfs:label "Provide a `validate_explain` method as part of Type::Tiny's public API."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.027_05"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.027_06"^^xsd:string; dc:issued "2013-09-18"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Override `validate_explain` in all the bundled subclasses of Type::Tiny."; ], [ a doap-changeset:Change; rdfs:label "Memoize Types::TypeTiny::to_TypeTiny."; ], [ a doap-changeset:Addition; rdfs:label "Type::Tiny::Union now provides a `find_type_for` method which should be compatible with Moose's equivalent method."; ], [ a doap-changeset:Change; rdfs:label "Type::Tiny::Union's compiled checks no longer close over the type constraints which are in the union."; ], [ a doap-changeset:Addition; rdfs:label "Type::Utils now provides an `english_list` function like Moose::Util does. This was useful internally for implementing `validate_explain` methods."; ], [ a doap-changeset:Documentation; rdfs:label "Add a draft Stability Policy to Type::Tiny::Manual."; ], [ a doap-changeset:Change; rdfs:label "Loosen the rules for Type::Tiny and Type::Coercion name attributes; allow them to begin with one or two leading underscores."; ], [ a doap-changeset:Change; rdfs:label "Types::TypeTiny::to_TypeTiny now uses Type::Coercion::FromMoose to ensure Moose type constraints converted to Type::Tiny constraints retain their coercions."; ], [ a doap-changeset:Addition; rdfs:label "Type::Coercion::FromMoose"; ], [ a doap-changeset:Change; rdfs:label "Stop using base.pm."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.027_06"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.027_07"^^xsd:string; dc:issued "2013-09-18"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Also ensure Mouse type constraints converted to Type::Tiny constraints retain their coercions."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix missing version number in Type::Coercion::FromMoose"; ], [ a doap-changeset:Tests; rdfs:label "Changes to version numbers reported by 00-begin.t."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.027_07"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.027_08"^^xsd:string; dc:issued "2013-09-19"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Explicitly overload boolification (always true!) in Type::Exception."; ], [ a doap-changeset:Bugfix; rdfs:label "Type::Exception::Assertion changes from 0.027_05 are now conditional upon Perl version; only take effect on Perl 5.8+; they just weren't working on Perl 5.6."; ], [ a doap-changeset:Tests; rdfs:label "More changes to version numbers reported by 00-begin.t."; ], [ a doap-changeset:Bugfix, doap-changeset:Documentation; rdfs:label "Fix typo in changelog for previous developer release."; ], [ a doap-changeset:Bugfix, doap-changeset:Documentation; rdfs:label "Fix typo in Type::Utils for coerce=>1 --> coercion=>1."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.027_08"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.027_09"^^xsd:string; dc:issued "2013-09-20"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix whitespace in error messages."; ], [ a doap-changeset:Tests; rdfs:label "Skip leak.t on Perl 5.10.0."; ], [ a doap-changeset:Regression; rdfs:label "Inlining of type checks in Moo broken in this release, or hereabouts. Fixed in 0.029_04."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.027_09"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.028"^^xsd:string; dc:issued "2013-09-26"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ], [ a doap-changeset:Documentation; rdfs:label "Note in documentation for Type::Tiny::Union, etc that constraint/inlining coderefs not only should not be provided to the constructor, but cannot!"; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.028"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.029_01"^^xsd:string; dc:issued "2013-09-26"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Replace Exporter::TypeTiny with Exporter::Tiny (an external dependency)."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:branch "exporter-tiny"; doap:file-release ; doap:revision "0.029_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.029_02"^^xsd:string; dc:issued "2013-10-11"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:BackCompat; rdfs:label "Renamed the Type::Exception modules to Error::TypeTiny."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ rdfs:label "Type::Tiny::Enum type constraints are now subtypes of Types::Standard::Str; not Types::Standard::Defined."; doap-changeset:thanks ; ], [ rdfs:label "Types::Standard::Item is now a subtype of not Types::Standard::Any."; doap-changeset:thanks ; ], [ a doap-changeset:Documentation; rdfs:label "Fix typos in documentation of Error::TypeTiny package variables."; ], [ rdfs:label "$Type::Tiny::DD package variable can now be used for a pluggable data dumper coderef."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:branch "master"; doap:file-release ; doap:revision "0.029_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.029_03"^^xsd:string; dc:issued "2013-10-17"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Older versions of Scalar::Util::looks_like_number return true for undef; work around them."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix segfault on Perl 5.8.1 to 5.8.3. (And possibly some other 5.8.x Perls.) Caused by the combination of eval and goto."; doap-changeset:thanks , , ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.029_03"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.029_04"^^xsd:string; dc:issued "2013-10-17"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix validate_explain error messages in Type::Tiny::Union."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ rdfs:label "$Type::Tiny::DD can be set numerically."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Bugfix; rdfs:label "Fix inlining of type checks in Moo which was broken around about version 0.027_09."; ], [ rdfs:label "Improve error messages under Moo."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.029_04"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.030"^^xsd:string; dc:issued "2013-10-18"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Skip leak.t on Perl < 5.10.1. Type-Tiny does have some memory leaks in particular older versions of Perl: 5.8.8 and 5.10.0 are known to be problematic, but 5.8.9 seems fine. Ultimately it would be nice to get these fixed, but in the mean time skipping the test case makes the distribution easier to install."; ], [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.030"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.031_01"^^xsd:string; dc:issued "2013-10-28"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Adjustments to cope with newer Moose is-class-loaded heuristics."; ], [ a doap-changeset:Tests; rdfs:label "Check Moose exception objects with isa rather than regexp matching."; ], [ a doap-changeset:Documentation; rdfs:label "Improved documentation for Types::TypeTiny."; ], [ a doap-changeset:Bugfix; rdfs:label "Differentiate Tuple[] vs Tuple, and Dict[] vs Dict."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.031_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.031_02"^^xsd:string; dc:issued "2013-11-03"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Type::Parser now differentiates between Tuple[] and Tuple too."; ], [ a doap-changeset:Change; rdfs:label "Type::Parser only treats a comma as an operator within a parameterization now, and is thus now able to parse types from the head of a string which is a comma-separated list of types."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.031_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.031_03"^^xsd:string; dc:issued "2013-11-03"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Deep coercions for Maybe[`a]."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.031_03"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.031_04"^^xsd:string; dc:issued "2013-11-03"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Type::Parser 0.031_02 introduced a bug under Perl 5.6.x where we relied on the existence (or not) of a hash item being affected by `local`; this was implemented in Perl 5.8.0. Work around this problem by checking definedness instead."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.031_04"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.031_05"^^xsd:string; dc:issued "2013-11-04"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Fix minor typo."; doap-changeset:blame ; ], [ a doap-changeset:Change; rdfs:label "Allow Dict to take a slurpy parameter - a la Dict[foo => Int, slurpy HashRef[Num]]."; doap-changeset:thanks ; rdfs:comment "This was Matt S Trout's idea."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.031_05"^^xsd:string. a doap:Version; rdfs:label "Remember, remember the fifth of November"; dc:identifier "Type-Tiny-0.032"^^xsd:string; dc:issued "2013-11-05"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ], [ a doap-changeset:Bugfix; rdfs:label "Eliminate a warning under Perl 5.6.x."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.032"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.033_01"^^xsd:string; dc:issued "2013-11-07"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Types::Common::Numeric"; ], [ a doap-changeset:Addition; rdfs:label "Types::Common::String"; ], [ a doap-changeset:Tests; rdfs:label "Test case using a Type::Params compiled check within the scope of a read-only $_ variable."; doap-changeset:blame ; ], [ a doap-changeset:Bugfix; rdfs:label "Type::Params now localizes $_ before trying to assign anything to it."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.033_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.033_02"^^xsd:string; dc:issued "2013-11-26"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Split out some of the longer parts of Types::Standard into other modules that will be loaded on demand; this shaves about 20% off the load time of Types::Standard."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:branch "ts-optimization"; doap:file-release ; doap:revision "0.033_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.033_03"^^xsd:string; dc:issued "2013-11-26"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Packaging; rdfs:label "Recommend Sub::Name in META.json."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix bug in Type::Params::multisig with regard to slurpy parameters."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Documentation; rdfs:label "Make Error::TypeTiny::Assertion's explain method act more according to documentation."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.033_03"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.033_04"^^xsd:string; dc:issued "2013-12-06"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Implement coercion_names, get_coercion, has_coercion, and has_type methods for Types::TypeTiny, to make it more like a real Type::Library type library."; ], [ rdfs:label "The `extends` function from Type::Utils now allows inheritance of coercions, not just types."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Tests; rdfs:label "Further tests related to RT#90096."; doap-changeset:thanks ; rdfs:seeAlso ; ]; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.033_04"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.034"^^xsd:string; dc:issued "2013-12-09"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.034"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.035_01"^^xsd:string; dc:issued "2013-12-17"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ rdfs:label "Make parameterized Dict and Map type constraints work with Moose native hash attribute trait."; doap-changeset:thanks ; ], [ rdfs:label "Make Type::Parser work with newer versions of MooseX::Types::Common which uses namespace::autoclean."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.035_01"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.036"^^xsd:string; dc:issued "2013-12-21"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.036"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.037_01"^^xsd:string; dc:issued "2013-12-24"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix a Type::Params/B problem on Perl 5.6.x."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.037_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.037_02"^^xsd:string; dc:issued "2013-12-29"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Link to the Type::Tiny stability policy from the pod of each module it covers."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.037_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.037_03"^^xsd:string; dc:issued "2013-12-30"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Skip leak.t on threaded Perls (for now)."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix problems with Moo::HandleMoose integration on threaded Perls."; doap-changeset:thanks , , ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.037_03"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.038"^^xsd:string; dc:issued "2014-01-01"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ], [ a doap-changeset:Documentation; rdfs:label "Copyright 2014."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.038"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.039_01"^^xsd:string; dc:issued "2014-01-21"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "The preferred IRC channel for support is now #moops."; ], [ a doap-changeset:Removal; rdfs:label "Exporter::TypeTiny."; ], [ a doap-changeset:Tests; rdfs:label "Restructure the 't' directory."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.039_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.039_02"^^xsd:string; dc:issued "2014-01-25"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Add tests for Test::TypeTiny."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.039_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.039_03"^^xsd:string; dc:issued "2014-02-05"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Make Type::Utils::declare_coercion work outside type libraries."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Bugfix; rdfs:label "Weak reference from Type::Coercion objects to target type constraint caused bad behaviour in some cases. This has been fixed by retaining enough information within the Type::Coercion to be able to reconstruct its type constraint if it disappears due to the reference count falling to zero."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.039_03"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.039_04"^^xsd:string; dc:issued "2014-02-05"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ rdfs:label "Make overloaded ops on parameterized type constraints work more consistently between Perl above and below 5.14, reducing the need for parenthesizing complex type constraint expresssions."; doap-changeset:blame ; rdfs:seeAlso ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.039_04"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.039_05"^^xsd:string; dc:issued "2014-02-15"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Apply the Type::Tiny::_HalfOp trick to overloaded addition too."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.039_05"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.039_06"^^xsd:string; dc:issued "2014-02-17"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Type::Tiny's TIEARRAY and TIEHASH methods were broken; fixed now."; ], [ a doap-changeset:Bugfix; rdfs:label "Type::Tiny's SUPPORT_SMARTMATCH constant was broken; fixed now."; ], [ a doap-changeset:Tests; rdfs:label "Test integration with match::simple."; ], [ a doap-changeset:Tests; rdfs:label "Test integration with Type::Tie."; ], [ a doap-changeset:Tests; rdfs:label "Test integration with Return::Type."; ], [ a doap-changeset:Tests; rdfs:label "Enable some old tests that had been disabled as not-yet-implemented for parameterized type constraints; the feature they test was implemented ages ago."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.039_06"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.039_07"^^xsd:string; dc:issued "2014-02-17"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix, doap-changeset:Tests; rdfs:label "Fix hash ordering bug in Return::Type integration tests."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.039_07"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.039_08"^^xsd:string; dc:issued "2014-02-24"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Test integration with Kavorka."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.039_08"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.039_09"^^xsd:string; dc:issued "2014-02-25"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Update Type::Tiny::Manual::Params to mention Kavorka, and newer features of Function::Parameters."; ], [ a doap-changeset:Tests; rdfs:label "Test integration with Moops."; ], [ a doap-changeset:Tests; rdfs:label "Test integration with Switcheroo."; ], [ a doap-changeset:Tests; rdfs:label "Test that coercions attached to Moose type constraints get inherited by Type::Tiny when they are inhaled."; ], [ a doap-changeset:Tests; rdfs:label "Unit tests for Devel::TypeTiny::Perl56Compat."; ], [ a doap-changeset:Tests; rdfs:label "Unit tests for Devel::TypeTiny::Perl58Compat."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.039_09"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.039_10"^^xsd:string; dc:issued "2014-03-10"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Document the benefits of freezing coercions, and of defining coercions either within the type library, or via $type->plus_coercions."; ], [ a doap-changeset:Change; rdfs:label "$type->plus_coercions and friends now return objects with frozen coercions."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.039_10"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.039_11"^^xsd:string; dc:issued "2014-03-11"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Because of changes to Data::Dumper in Perl 5.19.x, the test suite was previously skipping some Dumper-based test cases depending on Perl version. However, Dumper is dual-lifed, so older versions of Perl may have shiny, new Dumpers. Skip test cases based on Data::Dumper version instead."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.039_11"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.039_12"^^xsd:string; dc:issued "2014-03-12"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Various Type::Utils functions were trying to dereference undef as a hash or array in certain circumstances."; doap-changeset:thanks ; ], [ a doap-changeset:Change; rdfs:label "Type::Utils' class_type and role_type functions will $name =~ s/:://g."; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.039_12"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.039_13"^^xsd:string; dc:issued "2014-03-15"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Test for occasional segfaults on threaded Perl 5.18.x."; doap-changeset:blame ; ], [ a doap-changeset:Bugfix; rdfs:label "Fix occasional segfaults on threaded Perl 5.18.x."; doap-changeset:blame ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.039_13"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.040"^^xsd:string; dc:issued "2014-03-17"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ], [ a doap-changeset:Documentation; rdfs:label "Refreshed SEE ALSO section of Type::Tiny::Manual::Libraries."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.040"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.041_01"^^xsd:string; dc:issued "2014-03-17"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:BackCompat; rdfs:label "Type::Tiny and Type::Coercion no longer overload addition. This feature never really worked very well with regard to precendence, requiring lot of parentheses to use. The overload also made solving the parameterizable type coercion problem very difficult."; ], [ a doap-changeset:Change; rdfs:label "Parameterizable coercions are now passed a reference to the type constraint they should target."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.041_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.041_02"^^xsd:string; dc:issued "2014-03-26"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Type::Tiny::Manual links to various parts of the test suite to document concepts. These links had grown stale and have now been updated."; ], [ a doap-changeset:Tests; rdfs:label "Prevent 20-unit/Type-Registry/moosextypes.t from failing due to too old MooseX::Types::Common - just skip the test script if MXTC is older than 0.001004."; ], [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix Type::Tiny::Duck's inlining of code when given the variable name `$_`."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.041_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.041_03"^^xsd:string; dc:issued "2014-03-28"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Improve documentation for the Type::Tiny class; especially its constructor, attributes and methods."; ], [ a doap-changeset:Documentation; rdfs:label "Improve documentation for the Type::Coercion class; especially its constructors, attributes and methods."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.041_03"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.041_04"^^xsd:string; dc:issued "2014-03-31"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Add tests for given/when matching against type constraints."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.041_04"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.042"^^xsd:string; dc:issued "2014-04-02"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "List currently unstable/experimental parts of the distribution in Type::Tiny::Manual::Policies."; ], [ a doap-changeset:Documentation; rdfs:label "Include more recent results in benchmarking example scripts."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.042"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.043_01"^^xsd:string; dc:issued "2014-04-06"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Sub::Quote quoted coderefs passed to to_TypeTiny() now result in inlinable type constraints."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.043_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.043_02"^^xsd:string; dc:issued "2014-04-11"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Experimental my_methods attribute so that type constraints can offer additional methods."; ], [ a doap-changeset:Addition; rdfs:label "Type::Tiny now has a find_parent method."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.043_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.043_03"^^xsd:string; dc:issued "2014-05-06"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Type::Utils::classifier"; ], [ a doap-changeset:Documentation; rdfs:label "Rename Types::Datetime to Example::Types because there is now really a Types::DateTime on CPAN."; ], [ a doap-changeset:Addition; rdfs:label "Extremely experimental and mostly undocumented my_method stuff."; ], [ a doap-changeset:Tests; rdfs:label "Improve Eval::TypeTiny test cases."; ], [ a doap-changeset:Packaging; rdfs:label "Updated bundled version of Try::Tiny."; ], [ a doap-changeset:Tests; rdfs:label "Tests for Type::Library error messages."; ], [ a doap-changeset:Tests; rdfs:label "Add some test cases for the Error::TypeTiny class."; ], [ a doap-changeset:Documentation; rdfs:label "Type::Tiny::Manual::Libraries add example of using the custom types library."; doap-changeset:blame ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.043_03"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.043_04"^^xsd:string; dc:issued "2014-05-21"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Improve test cases for integration with Moose native attribute traits."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.043_04"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.043_05"^^xsd:string; dc:issued "2014-05-21"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Integration tests for MooseX::Getopt."; doap-changeset:blame ; ], [ a doap-changeset:Bugfix; rdfs:label "Fix inflation of Type::Coercion objects to Moose::Meta::TypeCoercion when some of the coercion routines are given as strings."; doap-changeset:fixes [ a doap-bugs:Issue; rdfs:label "Inflation of Type::Coercion objects to Moose::Meta::TypeCoercion is sometimes broken."; doap-bugs:reporter ; ]; ], [ a doap-changeset:Change; rdfs:label "No longer need to inflate a Type::Tiny object to Moose::Meta::TypeConstraint in order to give an answer to $type->isa('Moose::Meta::TypeConstraint::Union')."; rdfs:comment "Inflation to Moose::Meta::TypeConstraint is a last resort."; ], [ a doap-changeset:Change; rdfs:label "Detect missing comma in declaration of type constraints using Type::Utils a la `declare Foo as Bar`, and print a warning."; doap-changeset:thanks ; ], [ a doap-changeset:Documentation; rdfs:label "Document the is_*, to_*, and assert_* functions in Type::Tiny::Manual::Libraries."; doap-changeset:thanks ; rdfs:comment "They were already mentioned in Type::Library."; ], [ a doap-changeset:Documentation; rdfs:label "Mention coercion=>1 and why it is useful in Type::Tiny::Manual::Coercions."; doap-changeset:thanks ; rdfs:comment "It was already mentioned in Type::Tiny."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.043_05"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.044"^^xsd:string; dc:issued "2014-06-03"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.044"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.045_01"^^xsd:string; dc:issued "2014-06-30"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Ensure that when a Type::Tiny object is inflated into a Moose::Meta::TypeConstraint, inlining still happens via Type::Tiny."; doap-changeset:thanks [ a foaf:Person; foaf:nick "omega" ]; rdfs:comment "This was causing some obscure problems with MooseX::Getopt."; ], [ a doap-changeset:Bugfix; rdfs:label "Workaround strange behaviour of exists() function when applied to @_ on Perl older than 5.20 which caused some uses of Optional[Foo] to accept an explicit undef."; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.045_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.045_02"^^xsd:string; dc:issued "2014-07-10"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Include benchmark/example of Type::Params versus Scalar::Validation."; ], [ a doap-changeset:Bugfix, doap-changeset:Documentation; rdfs:label "Remove outdated references to the overloaded + operator from Types::Standard documentation."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.045_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.045_03"^^xsd:string; dc:issued "2014-07-11"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Type::Tiny::XS is now used (if available) to speed up some of the Types::Standard type constraints, plus Type::Tiny::Class and Type::Tiny::Duck."; ], [ a doap-changeset:Regression; rdfs:label "The Mouse XS stuff introduced in Type-Tiny 0.003_09 has been partially removed. (I do plan on restoring it, and improving it.)"; ], [ a doap-changeset:Tests; rdfs:label "When testing equivalence between Types::Standard types and core Moose types, don't test `Num` because Types::Standard provides two different implementations for it."; ], [ a doap-changeset:Documentation; rdfs:label "Update benchmark scripts, showing results with/without Type::Tiny::XS."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.045_03"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.045_04"^^xsd:string; dc:issued "2014-07-15"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Cope with changes to Type::Tie error messages introduced in Type::Tie 0.008."; ], [ a doap-changeset:Tests; rdfs:label "Generally stop testing the contents of error messages produced by external modules!"; ], [ a doap-changeset:Bugfix; rdfs:label "Type::Params was warning about additional arguments passed to sprintf under Perl blead. The additional argument has been removed."; ], [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ], [ a doap-changeset:Tests; rdfs:label "Fix warnings in 30-integration/Moose/native-attribute-traits.t when run under perl -w."; doap-changeset:blame ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.045_04"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.045_05"^^xsd:string; dc:issued "2014-07-18"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Type::Tiny now has an `of` method which is a shortcut for `parameterize` which I can never spell properly."; ], [ a doap-changeset:Addition; rdfs:label "Type::Tiny now has a `where` method which is a shortcut for creating a child type with a constraint coderef."; ], [ a doap-changeset:Documentation; rdfs:label "Added a Type::Tiny::Manual::Optimization perldoc page."; ], [ a doap-changeset:Bugfix; rdfs:label "More sensible use of Sub::Name in Type::Library."; ], [ a doap-changeset:Change; rdfs:label "Restore and improve Mouse XS stuff dropped in Type-Tiny 0.045_03."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.045_05"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-0.046"^^xsd:string; dc:issued "2014-07-18"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Add test cases for Types::TypeTiny (the library of type constraints used internally by Type::Tiny)."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix for Types::TypeTiny::to_TypeTiny($coderef) when Sub::Quote is loaded but not used."; ], [ a doap-changeset:Bugfix; rdfs:label "Undef no longer passes the Types::TypeTiny::StringLike type constraint."; ], [ a doap-changeset:Change; rdfs:label "Minor optimizations to Types::TypeTiny::to_TypeTiny."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.046"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; rdfs:label "The 87% Coverage Release"; dc:identifier "Type-Tiny-0.047_01"^^xsd:string; dc:issued "2014-07-21"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ rdfs:label "Types::Standard::Map is now XS-accelerated."; rdfs:seeAlso ; ], [ rdfs:label "Types::Standard::Tuple is now XS-accelerated."; rdfs:seeAlso ; ], [ rdfs:label "Type::Tiny::Enum is now XS-accelerated."; rdfs:seeAlso ; ], [ rdfs:label "Types::Common::Numeric::PositiveInt is now XS-accelerated."; rdfs:seeAlso ; ], [ rdfs:label "Types::Common::Numeric::PositiveOrZeroInt is now XS-accelerated."; rdfs:seeAlso ; ], [ rdfs:label "Types::Common::String::NonEmptyStr is now XS-accelerated."; rdfs:seeAlso ; ], [ rdfs:label "Unify _USE_XS/_USE_MOUSE logic in Type::Tiny. (It was previously scattered across Types::Standard and various other modules.)"; ], [ a doap-changeset:Documentation; rdfs:label "Better document which type constraints will be accelerated by Type::Tiny::XS and Mouse."; ], [ a doap-changeset:Bugfix, doap-changeset:Tests; rdfs:label "Fix a silly test case that was relying on Exporter::Tiny to always load B.pm. (Current versions of Exporter::Tiny do load B.pm, but future versions might not.)"; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.047_01"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; rdfs:label "The 92% Coverage Release"; dc:identifier "Type-Tiny-0.047_02"^^xsd:string; dc:issued "2014-07-23"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Allow Enums containing hyphens to be accelerated by Type::Tiny::XS."; ], [ a doap-changeset:Tests; rdfs:label "Test the Error::TypeTiny::Compilation exception class."; ], [ a doap-changeset:Tests; rdfs:label "Test exceptions thrown by Type::Tiny::Enum."; ], [ a doap-changeset:Tests; rdfs:label "Test the Error::TypeTiny::WrongNumberOfParameters exception class."; ], [ a doap-changeset:Tests; rdfs:label "Test exceptions thrown by Type::Tiny::Class."; ], [ a doap-changeset:Tests; rdfs:label "Test exceptions thrown by Type::Tiny::Role."; ], [ a doap-changeset:Tests; rdfs:label "Add tests explicitly testing Type::Tiny objects conversion to Moose::Meta::TypeConstraint and Mouse::Meta::TypeConstraint objects."; ], [ a doap-changeset:Change; rdfs:label "Type::Tiny::Class should stop using Class::ISA. Instead, if mro.pm is not available, use a private sub stolen from MRO::Compat."; ], [ a doap-changeset:Tests; rdfs:label "Stop using base.pm."; ], [ a doap-changeset:Documentation; rdfs:label "Type::Tiny::Manual no longer says that Perl 5.6.x support is at risk."; ], [ rdfs:label "Type::Tiny::Union is now XS-accelerated."; rdfs:seeAlso ; ], [ rdfs:label "Type::Tiny::Intersection is now XS-accelerated."; rdfs:seeAlso ; ], [ a doap-changeset:Tests; rdfs:label "Include test case relating to Type::Tiny::XS GitHub issue #1."; rdfs:seeAlso ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.047_02"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; rdfs:label "The 96% Coverage Release"; dc:identifier "Type-Tiny-0.047_03"^^xsd:string; dc:issued "2014-07-26"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Improved type introspection method tests (find_parent/is_supertype_of/is_subtype_of/is_strictly_supertype_of/is_strictly_subtype_of)."; ], [ a doap-changeset:Tests; rdfs:label "Improved type constraint constructor tests (exceptions thrown for bad parameters, coercion=>ARRAY|CODE parameter)."; ], [ a doap-changeset:Tests; rdfs:label "Checks for more Error::TypeTiny::Assertion explanations (Tuple, Duck, Intersection, Union, Dicts containing slurpy things)."; ], [ a doap-changeset:Tests; rdfs:label "Checks non-inlineable deep coercions for Tuple."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix for slurpy Map within a Tuple."; ], [ a doap-changeset:Bugfix; rdfs:label "Types::TypeTiny->has_type was incorrectly returning whether Types::TypeTiny contained the named *coercion* instead of a named *type*."; ], [ a doap-changeset:Tests; rdfs:label "Test the immutability of Type::Coercion::Union."; ], [ a doap-changeset:Tests; rdfs:label "Fake a very old Validation::Class::Simple for a certain test by overriding $Validation::Class::Simple::VERSION."; ], [ a doap-changeset:Tests; rdfs:label "Check that Type::Registry works in conjunction with MouseX::Types. (There's some TODO stuff there.)"; ], [ a doap-changeset:Packaging; rdfs:label "Bundle my TODO file."; ], [ a doap-changeset:Change; rdfs:label "Better `isa` faking - returns true to Class::MOP::Object."; ], [ a doap-changeset:Tests; rdfs:label "Tests for `isa`."; ], [ a doap-changeset:Tests; rdfs:label "Tests for various little methods which were added for Moose/Mouse-compatibility."; ], [ a doap-changeset:Tests; rdfs:label "Tests for non-inlineable type constraints in `match_on_type` and `compile_match_on_type`."; ], [ a doap-changeset:Tests; rdfs:label "Check Type::Library-based type libraries can extend MouseX::Types-based type libraries."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.047_03"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; rdfs:label "The 98% Coverage Release"; dc:identifier "Type-Tiny-0.047_04"^^xsd:string; dc:issued "2014-07-28"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Tests for introspection methods of Types::TypeTiny."; ], [ a doap-changeset:Tests; rdfs:label "Check that Mouse type converted to Type::Tiny objects keep their original error messages."; ], [ a doap-changeset:Tests; rdfs:label "Tests for Test::TypeTiny::matchfor()."; ], [ a doap-changeset:Tests; rdfs:label "Improve test coverage for Type::Registry."; ], [ a doap-changeset:Tests; rdfs:label "Tests for dynamically delegated Type::Tiny an Type::Coercion methods."; ], [ a doap-changeset:Documentation; rdfs:label "Type::Utils does not export english_list() and classifier() by default."; ], [ a doap-changeset:Tests; rdfs:label "Test that Sub::Quote-enabled coderefs generated by Type::Tiny and Type::Coercion can actually be retrieved by Sub::Quote."; ], [ a doap-changeset:Tests; rdfs:label "Test the Type::Coercion overloading of ~~."; ], [ a doap-changeset:Change; rdfs:label "Straighten out the relationships between Type::Coercion and its subclasses."; ], [ a doap-changeset:Tests; rdfs:label "Tests for introspection methods of Type::Coercion."; ], [ a doap-changeset:Tests; rdfs:label "Test exceptions thrown by Types::Standard::ScalarRef."; ], [ a doap-changeset:Tests; rdfs:label "Improve test coverage for Type::Utils' match_on_type and compile_match_on_type."; ], [ a doap-changeset:Change; rdfs:label "Type:Utils::match_on_type no longer automatically loads Types::Standard."; ], [ a doap-changeset:Tests; rdfs:label "Test warnings raised by Type::Utils::declare()."; ], [ a doap-changeset:Tests; rdfs:label "Test code from SYNOPSIS sections (only in xt)."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.047_04"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; rdfs:label "Sanity++"; dc:identifier "Type-Tiny-0.047_05"^^xsd:string; dc:issued "2014-07-29"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "A far saner implementation of Optional[]."; ], [ a doap-changeset:Documentation; rdfs:label "Improve the documentation of Optional[] and slurpy."; ], [ a doap-changeset:Change; rdfs:label "Optimizations for slurpy Any."; ], [ a doap-changeset:Change; rdfs:label "When slurping the tail of a Tuple into a hashref, check it's an even number of elements."; ], [ a doap-changeset:Change; rdfs:label "A slightly saner implementation of Types::TypeTiny's meta methods."; ], [ a doap-changeset:Regression; rdfs:label "Introduced bug concerning coercions to parameterized Dicts with a mixture of inlineable and non-inlineable optional values."; rdfs:seeAlso ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.047_05"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; rdfs:label "What made the Queen go all ice crazy?"; dc:identifier "Type-Tiny-0.047_06"^^xsd:string; dc:issued "2014-07-31"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Type::Registry/Type::Parser will now auto-load MouseX::Types libraries."; ], [ a doap-changeset:Change; rdfs:label "Type::Registry now has methods for creating union/intersection/class/role type constraints. Type::Parser delegates to these, making it potentially reusable outside Type::Tiny by simply passing it an alternative type registry object."; ], [ a doap-changeset:Tests; rdfs:label "More Type::Registry test cases."; ], [ a doap-changeset:Bugfix; rdfs:label "Bugfix in coercion inheritance where the child's type_coercion_map arrayref would end up as a reference to the parent's type_coercion_map. (Which was not good.)"; ], [ a doap-changeset:Change; rdfs:label "Coercions for the types defined in Types::Standard are now frozen."; ], [ a doap-changeset:Change; rdfs:label "Coercions for the types defined in Types::Common::Numeric are now frozen."; ], [ a doap-changeset:Change; rdfs:label "Coercions for the types defined in Types::Common::String are now frozen."; ], [ a doap-changeset:Addition; rdfs:label "Type::Coercion now has a i_really_want_to_unfreeze method."; ], [ a doap-changeset:Addition; rdfs:label "Type::Library now has a make_immutable method."; ], [ rdfs:label "Parameterized types now have their coercions frozen automatically, so you can no longer add coercions to, say, ArrayRef[Int]. However, you can create a subtype of ArrayRef[Int] and add coercions to that."; doap-changeset:thanks ; rdfs:seeAlso ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.047_06"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.047_07"^^xsd:string; dc:issued "2014-08-04"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "The extract_type function was missing from Type::Parser's @EXPORT_OK list."; ], [ a doap-changeset:Tests; rdfs:label "Test cases for Type::Parser::extract_type."; ], [ a doap-changeset:Change; rdfs:label "Parameterized Maybe constraints are now XS-accelerated."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.047_07"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; rdfs:label "Sanity++"; dc:identifier "Type-Tiny-0.047_08"^^xsd:string; dc:issued "2014-08-05"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Test to avoid the \"too few arguments for type constraint check functions\" error."; doap-changeset:thanks ; rdfs:seeAlso ; ], [ rdfs:label "Prevent inlining of coercions if they've not been frozen."; rdfs:seeAlso ; ], [ a doap-changeset:Documentation; rdfs:label "Document the remaining RT#93345-related issues - see \"Deep Caveat\" in Type::Tiny::Manual::Coercions."; rdfs:seeAlso ; ], [ a doap-changeset:Tests; rdfs:label "Update t/30-integration/Moose/coercion.t to Moose 2.1200 which throws an exception rather than printing a warning when coerce=>1 is used on a type constraint with no coercions."; ], [ a doap-changeset:Tests; rdfs:label "Alter the Types::Common::* test cases to use Test::TypeTiny."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix non-inlined version of NegativeOrZeroInt."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.047_08"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-0.047_09"^^xsd:string; dc:issued "2014-08-12"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Improvements and clarifications to Type::Coercion documentation."; ], [ a doap-changeset:Change; rdfs:label "The to_Foo functions exported by Type::Library-based modules are now significantly faster. (But only if the type's coercion is frozen.)"; ], [ a doap-changeset:Tests; rdfs:label "Add tests for Error::TypeTiny::Assertion's predicate methods."; ], [ a doap-changeset:Tests; rdfs:label "Add tests for Type::Coercion's i_really_want_to_unfreeze method."; ], [ a doap-changeset:Change; rdfs:label "Better integration between Type::Library and Type::Registry. If you import a type constraint from a Type::Library-based module, it will automatically be inserted into your modules' type registry."; ], [ a doap-changeset:Change; rdfs:label "Type::Utils::dwim_type now takes into account what OO framework the caller is using (Moose or Mouse) if it needs to fall back to asking the OO framework about a type constraint."; ], [ a doap-changeset:Bugfix, doap-changeset:Documentation; rdfs:label "Fix documentation typo."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.047_09"^^xsd:string. a doap:Version; rdfs:label "Happy CPAN Day!"; dc:identifier "Type-Tiny-1.000000"^^xsd:string; dc:issued "2014-08-16"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ], [ a doap-changeset:Documentation; rdfs:label "Updated TODO file."; ], [ a doap-changeset:Documentation; rdfs:label "Document the Type::Tiny versioning policy."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.000000"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-1.000001"^^xsd:string; dc:issued "2014-08-18"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Changes to dwim_type() in 0.047_09 broke the fallback to creating class types in some circumstances. This broke the MooX::late test suite, and some usages of MooX::late."; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.000001"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-1.000002"^^xsd:string; dc:issued "2014-08-18"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix for overloaded operation fallback on Perl 5.10.x."; doap-changeset:blame ; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.000002"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-1.000003"^^xsd:string; dc:issued "2014-08-28"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix for coercions to parameterized Dict including a mixture of inlineable and non-inlineable optional values."; doap-changeset:blame ; doap-changeset:fixes ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.000003"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-1.000004"^^xsd:string; dc:issued "2014-09-02"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix issues with coercions and native attribute traits with some oldish versions of Moose on oldish versions of Perl."; doap-changeset:fixes ; doap-changeset:thanks ; rdfs:comment "Backported fix from 1.001_000."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix for Type::Registry::DWIM."; doap-changeset:fixes ; doap-changeset:thanks ; rdfs:comment "Backported fix from 1.001_000."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.000004"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-1.000005"^^xsd:string; dc:issued "2014-10-25"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix short-circuiting optimizations for parameterized HashRef, ArrayRef, ScalarRef, and Map type constraints."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Tests; rdfs:label "Fix annoying warning message in test suite with recent versions of Exporter::Tiny."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.000005"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-1.000006"^^xsd:string; dc:issued "2017-01-30"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix, doap-changeset:Tests, doap-changeset:Update; rdfs:label "Fix escaping within q{...} in a test case."; doap-changeset:blame ; doap-changeset:fixes ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.000006"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.001_000"^^xsd:string; dc:issued "2014-09-07"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Updated NEWS file."; ], [ a doap-changeset:Documentation; rdfs:label "Updated TODO file."; ], [ a doap-changeset:Update; rdfs:label "Want Type::Tiny::XS 0.011."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix issues with coercions and native attribute traits with some oldish versions of Moose on oldish versions of Perl."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Tests; rdfs:label "Make some of the test case skip_all bits more ambitious; test older versions of Moose and Moo than we were testing before."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix for Type::Registry::DWIM."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Update; rdfs:label "If Sub::Name is unavailable, but the shiny new core Sub::Util is available, then use it instead."; ], [ a doap-changeset:Addition; rdfs:label "Type::Params now provides `compile_named` and `validate_named` functions which do the same thing as `compile` and `validate` but are better for named arguments."; rdfs:comment "Several people have requested this."; ], [ a doap-changeset:Change; rdfs:label "`Type::Utils::dwim_type` now allows more control over fallback behaviours."; ], [ a doap-changeset:Documentation; rdfs:label "Updates to Type::Tiny::Manual::UsingWithMoose, Type::Tiny::Manual::UsingWithMoo, and Type::Tiny::Manual::UsingWithMouse."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_000"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.001_001"^^xsd:string; dc:issued "2014-09-19"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Update; rdfs:label "Prefer Sub::Util over Sub::Name. (The former is smaller.)"; ], [ a doap-changeset:Change; rdfs:label "Lazy-load Text::Balanced in Type::Parser. (Many parses don't even need it.)"; ], [ a doap-changeset:Change; rdfs:label "Lazy-load Type::Tiny::Union in Type::Params."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_001"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.001_002"^^xsd:string; dc:issued "2014-10-25"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix short-circuiting optimizations for parameterized HashRef, ArrayRef, ScalarRef, and Map type constraints."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Tests; rdfs:label "Fix annoying warning message in test suite with recent versions of Exporter::Tiny."; ], [ a doap-changeset:Bugfix; rdfs:label "Inlined version of Types::Standard::Int should check that the value is not a reference."; ], [ a doap-changeset:Change; rdfs:label "Make equals/is_a_type_of/is_subtype_of/is_supertype_of in Type::Tiny::Union work more like Moose::Meta::TypeConstraint::Union."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_002"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.001_003"^^xsd:string; dc:issued "2017-02-02"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Update; rdfs:label "Merge fixes from stable Type-Tiny 1.000006."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_003"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.001_004"^^xsd:string; dc:issued "2017-02-06"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Attempting ArrayRef[Int, Int] or similar now throws an exception."; doap-changeset:blame ; doap-changeset:fixes ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_004"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.001_005"^^xsd:string; dc:issued "2017-04-19"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Bundle a test case for GH issue 14."; rdfs:seeAlso ; ], [ a doap-changeset:Change; rdfs:label "Improved error location reporting for Moo"; doap-changeset:blame ; rdfs:seeAlso ; ], [ a doap-changeset:Bugfix, doap-changeset:Tests; rdfs:label "02-api.t should check version of Moose available."; rdfs:seeAlso ; ], [ a doap-changeset:Bugfix, doap-changeset:Documentation; rdfs:label "Fix minor typos in documentation for Types::Standard."; doap-changeset:blame ; rdfs:seeAlso ; ], [ a doap-changeset:Update; rdfs:label "NumericCode now coerces from strings with whitespace in them, like MooseX::Types::Common::Numeric."; doap-changeset:blame ; rdfs:seeAlso ; ], [ a doap-changeset:Bugfix, doap-changeset:Documentation; rdfs:label "Fix variable name typo in documentation for Type::Params."; doap-changeset:blame ; rdfs:seeAlso ; ], [ a doap-changeset:Bugfix, doap-changeset:Tests; rdfs:label "20-unit/Type-Utils/warnings.t should check version of Test::Warnings."; doap-changeset:blame ; rdfs:seeAlso ; ], [ a doap-changeset:Documentation; rdfs:label "Include projected release date for Type::Tiny 1.002000 in NEWS."; rdfs:comment "It's my birthday!"; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_005"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.001_006"^^xsd:string; dc:issued "2017-04-30"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Localize $SIG{__DIE__} in Type::Registry."; doap-changeset:fixes ; ], [ a doap-changeset:Change; rdfs:label "Allow Type::Tiny's `constraint` parameter to be a string of Perl code."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_006"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; rdfs:label "May the fourth be with you"; dc:identifier "Type-Tiny-1.001_007"^^xsd:string; dc:issued "2017-05-04"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Optimizations for Tuple and StrMatch type constraints from Types::Standard."; ], [ a doap-changeset:Change; rdfs:label "Optimization of Type::Params positional parameter checking for simple cases with no slurpy parameter and no coercions."; ], [ a doap-changeset:Addition; rdfs:label "Type::Params' `multisig` function now sets a variable `${^TYPE_PARAMS_MULTISIG}` to indicate which signature succeeded."; ], [ a doap-changeset:Documentation; rdfs:label "Comparison of Type::Params with new(ish) CPAN module Params::ValidationCompiler."; ], [ a doap-changeset:Documentation; rdfs:label "Show example of how to set defaults for parameters with Type::Params."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_007"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.001_008"^^xsd:string; dc:issued "2017-05-10"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Rearrange the examples directory in the distribution."; ], [ a doap-changeset:Addition; rdfs:label "Named parameter validation benchmarking script."; ], [ a doap-changeset:Addition; rdfs:label "Reduce scope of local $SIG{__DIE__} in Type::Registry."; doap-changeset:thanks ; ], [ a doap-changeset:Bugfix; rdfs:label "Type::Params should make sure Type::Utils is loaded before calling english_list()."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_008"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.001_009"^^xsd:string; dc:issued "2017-05-13"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Use Ref::Util::XS (if it's installed) to speed up certain type checks."; ], [ a doap-changeset:Change; rdfs:label "Rewrite some benchmarking scripts to use Benchmark::Featureset::ParamCheck."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_009"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; rdfs:label "Puppiversary"; dc:identifier "Type-Tiny-1.001_010"^^xsd:string; dc:issued "2017-05-16"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "t/00-begin.t will now work around ANDK's apparently broken XS testing environment."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_010"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.001_011"^^xsd:string; dc:issued "2017-05-17"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Type constraints like Tuple[Int] shouldn't report they have a coercion if Int doesn't have a coercion."; ], [ a doap-changeset:Addition; rdfs:label "Types::Standard now has a CycleTuple type."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_011"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.001_012"^^xsd:string; dc:issued "2017-05-17"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:BackCompat, doap-changeset:Change; rdfs:label "RegexpRef now accepts blessed objects if $object->isa('Regexp') returns true."; rdfs:comment "For compatibility with re::engine::RE2 and similar modules."; ], [ a doap-changeset:Change; rdfs:label "StrMatch will use Regexp::Util (if available) to inline regular expressions more sensibly."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_012"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; rdfs:label "Kittiversary"; dc:identifier "Type-Tiny-1.001_013"^^xsd:string; dc:issued "2017-05-18"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "StrMatch changes in previous release broke the ability to check type equality between two parameterized StrMatch types under some circumstances. Changed how the hash key for stashing regexp references gets built — is now closer to the old way. This doesn't revert the change in 1.001_012 where regexp checks can be inlined better, but only applies to those regexp references that can't easily be inlined."; ], [ a doap-changeset:Bugfix; rdfs:label "Fixed crazy amount of UTF-8 warnings from Type::Params on Perl 5.6.x and Perl 5.8.x."; doap-changeset:fixes ; doap-changeset:thanks ; rdfs:seeAlso ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_013"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.001_014"^^xsd:string; dc:issued "2017-05-19"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Include trailing line break at the end of stringified version of some exceptions."; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_014"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.001_015"^^xsd:string; dc:issued "2017-05-20"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix HashRef[Str]|Undef|Str parsing on Perl < 5.14."; doap-changeset:fixes ; doap-changeset:thanks , ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_015"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.001_016"^^xsd:string; dc:issued "2017-05-30"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Include page-numbers.pl example"; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.001_016"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-1.002000"^^xsd:string; dc:issued "2017-06-01"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Packaging; rdfs:label "Stable version number."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.002000"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-1.002001"^^xsd:string; dc:issued "2017-06-08"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Packaging; rdfs:label "Ref::Util::XS 0.100 should be recommended, not 0.200 (which doesn't exist yet)."; doap-changeset:fixes ; ], [ a doap-changeset:Tests; rdfs:label "Skip t/30-integration/Moose/native-attribute-traits.t on older Moose because Test::Moose is broken."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.002001"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.003_000"^^xsd:string; dc:issued "2018-05-20"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Packaging; rdfs:label "Ref::Util::XS 0.100 should be recommended, not 0.200 (which doesn't exist yet)."; doap-changeset:fixes ; ], [ a doap-changeset:Tests; rdfs:label "Skip t/30-integration/Moose/native-attribute-traits.t on older Moose because Test::Moose is broken."; ], [ a doap-changeset:Bugfix; rdfs:label "Compatibility with constants and with CV-in-stash optimisation."; doap-changeset:fixes ; ], [ a doap-changeset:Addition; rdfs:label "Type::Params now exports a compile_named_oo function which returns a parameters object."; ], [ a doap-changeset:Documentation; rdfs:label "Improvements to Type::Params documentation."; ], [ a doap-changeset:Addition; rdfs:label "Type::Params now supports parameter defaults."; ], [ a doap-changeset:Addition; rdfs:label "Type::Params compile_named now supports bless/class/constructor options."; ], [ a doap-changeset:Change; rdfs:label "Don't use Type::Tiny::XS's implementation of PositiveInt in Types::Common::Numeric unless Type::Tiny::XS >= 0.013."; ], [ a doap-changeset:Documentation; rdfs:label "Document Type::Library's :coercion export tag."; doap-changeset:blame ; ], [ a doap-changeset:Addition; rdfs:label "Allow Type::Coercion's add_type_coercion to accept a Type::Coercion object, which was already documented as working."; doap-changeset:blame ; ], [ a doap-changeset:Documentation; rdfs:label "Fix typo."; doap-changeset:blame ; ], [ a doap-changeset:Documentation; rdfs:label "Add a new CONTRIBUTING.pod file."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.003_000"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.003_001"^^xsd:string; dc:issued "2018-05-22"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Don't use Type::Tiny::XS's implementation of Bool in Types::Standard unless Type::Tiny::XS >= 0.014."; ], [ a doap-changeset:Change; rdfs:label "Looser definition of FileHandle in Types::Standard."; doap-changeset:fixes ; ], [ a doap-changeset:Tests; rdfs:label "Tests for coercions to CycleTuple from Types::Standard with non-inlineable type constraints."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.003_001"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.003_002"^^xsd:string; dc:issued "2018-05-28"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Types::Common::Numeric now has NumRange and IntRange types."; ], [ a doap-changeset:Addition; rdfs:label "Types::Common::String now has a StrLength type."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.003_002"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.003_003"^^xsd:string; dc:issued "2018-06-10"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:BackCompat, doap-changeset:Change; rdfs:label "Bool (Types::Standard) is stricter, no longer allowing blessed objects that overload stringification because that's weird."; ], [ a doap-changeset:Addition; rdfs:label "Bool now allows coercion from Any."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.003_003"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.003_004"^^xsd:string; dc:issued "2018-06-12"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix, doap-changeset:Tests; rdfs:label "Load modules with `use` instead of `require` in 00-begin.t."; doap-changeset:fixes ; doap-changeset:thanks , ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.003_004"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.003_005"^^xsd:string; dc:issued "2018-07-05"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Allow type libraries to mark certain type constraints as deprecated."; doap-changeset:fixes ; ], [ a doap-changeset:Documentation; rdfs:label "Type::Tiny::Manual::Coercions improvements."; doap-changeset:fixes ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.003_005"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.003_006"^^xsd:string; dc:issued "2018-07-08"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Improve coverage."; ], [ a doap-changeset:Addition; rdfs:label "Type::Params compile/compile_named now have subname and description options."; ], [ a doap-changeset:Documentation; rdfs:label "Type::Params caller_level option is now documented."; ], [ a doap-changeset:Bugfix; rdfs:label "Workaround for Regexp-based check for Int clobbering $1 sometimes (this will sometimes slow down Int checks a little, but is needed for correctness)."; doap-changeset:fixes ; ], [ a doap-changeset:Bugfix; rdfs:label "Fix issues with arrayref and hashref defaults in Type::Params."; ], [ a doap-changeset:Addition; rdfs:label "PERL_TYPE_PARAMS_XS environment variable."; ], [ a doap-changeset:Documentation; rdfs:label "Better documentation of environment variables."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.003_006"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.003_007"^^xsd:string; dc:issued "2018-07-12"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Improve coverage."; ], [ a doap-changeset:Tests; rdfs:label "Add tests for deep coercions in Tuples."; ], [ a doap-changeset:Tests; rdfs:label "Restructure Types::TypeTiny test cases so more of them run when Moose and Mouse aren't available."; ], [ a doap-changeset:Change; rdfs:label "Improve progressive exporter in Types::TypeTiny to avoid loading Exporter::TypeTiny more often."; ], [ a doap-changeset:Change; rdfs:label "Types::Standard does better at checking the parameters of parameterized types are valid."; ], [ a doap-changeset:Tests; rdfs:label "Better tests for Eval::TypeTiny's implementations of alias=>1."; ], [ a doap-changeset:Update; rdfs:label "Eval::TypeTiny now supports Perl 5.22 refaliasing as the preferred implementation of alias => 1."; ], [ a doap-changeset:Addition; rdfs:label "Eval::TypeTiny now supports PadWalker as a fallback implementation of alias => 1."; ], [ a doap-changeset:Change; rdfs:label "Eval::TypeTiny will now throw errors when it detects a mismatch between sigils and reference types in the environment hashref but only if EXTENDED_TESTING environment variable is true. Perl will probably give you its own error message for this later on anyway."; ], [ a doap-changeset:Removal; rdfs:label "Eval::TypeTiny::HAS_LEXICAL_VARS constant is no longer documented and will be removed at a later date."; ], [ a doap-changeset:Addition; rdfs:label "Eval::TypeTiny provides a collection of constants to indicate the current implementation of alias => 1."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.003_007"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.003_008"^^xsd:string; dc:issued "2018-07-16"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Improve test coverage."; ], [ a doap-changeset:Regression, doap-changeset:Update; rdfs:label "Make Error::TypeTiny aware of some newer internal modules."; ], [ rdfs:label "Improve processing of parameters to Types::Standard's parameterized type constraints"; ], [ a doap-changeset:Change; rdfs:label "Types::Common::Numeric's IntRange and NumRange do better checking of parameters."; ], [ a doap-changeset:Change; rdfs:label "Types::Common::String's StrLength does better checking of parameters."; ], [ a doap-changeset:Tests; rdfs:label "Test Type::Utils' match_on_type's support for wantarray on strings of code."; ], [ a doap-changeset:Change; rdfs:label "Simplify how Type::Registry generates the `t()` function."; ], [ a doap-changeset:Change; rdfs:label "Split out some code from Types::Standard into autoloaded modules to speed up loading."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix error messages generating deep explanations of some parameterized types."; doap-changeset:fixes ; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.003_008"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.003_009"^^xsd:string; dc:issued "2018-07-24"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Improve testing of Test::TypeTiny itself; the matchfor() function in particular."; ], [ a doap-changeset:Tests; rdfs:label "Test bad parameters to NumRange and IntRange."; ], [ a doap-changeset:Tests; rdfs:label "Test late loading of Sub::Quote."; ], [ a doap-changeset:Documentation; rdfs:label "Better documentation of parameterization API."; ], [ a doap-changeset:Change; rdfs:label "Types::Standard::Defined->complementary_type will now return Types::Standard::Undef, and vice versa."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.003_009"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.003_010"^^xsd:string; dc:issued "2018-07-25"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Improve test coverage for Type::Utils, Type::Coercion, Types::Standard::Tuple, Eval::TypeTiny, Type::Registry, Type::Tiny::Class, and Types::Standard::Tied."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.003_010"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-1.004000"^^xsd:string; dc:issued "2018-07-27"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Packaging; rdfs:label "Repackage as a stable release. No functional changes since 1.003_010."; ], [ a doap-changeset:Documentation; rdfs:label "Update TODO."; ], [ a doap-changeset:Documentation; rdfs:label "Update NEWS."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.004000"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-1.004001"^^xsd:string; dc:issued "2018-07-28"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Add Eval::TypeTiny::Sandbox to the list of packages which should be skipped as internal by Error::TypeTiny, as it was mistakenly removed in 1.003_008."; doap-changeset:fixes ; ], [ a doap-changeset:Documentation; rdfs:label "Correct release date of 1.004000 in change log."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.004001"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-1.004002"^^xsd:string; dc:issued "2018-07-29"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix, doap-changeset:Tests; rdfs:label "Skip one particular test on old versions of Moo because it relies on a feature introduced in Moo 1.004000."; doap-changeset:fixes ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.004002"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-1.004003"^^xsd:string; dc:issued "2019-01-08"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix spelling in error message for Types::Common::String LowerCaseSimpleStr."; doap-changeset:blame ; rdfs:seeAlso ; ], [ a doap-changeset:Documentation; rdfs:label "Fix Types::Standard documentation error: incorrect third-party module name."; doap-changeset:blame ; rdfs:seeAlso ; ], [ a doap-changeset:Documentation; rdfs:label "Fix Type::Params documentation error."; doap-changeset:blame ; rdfs:seeAlso ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.004003"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-1.004004"^^xsd:string; dc:issued "2019-01-08"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix, doap-changeset:Packaging; rdfs:label "Depend on Exporter::Tiny 0.040; older versions don't provide all the functions Type::Library needs."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.004004"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.005_000"^^xsd:string; dc:issued "2019-01-20"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fix spelling in error message for Types::Common::String LowerCaseSimpleStr."; doap-changeset:blame ; rdfs:seeAlso ; ], [ a doap-changeset:Documentation; rdfs:label "Fix Types::Standard documentation error: incorrect third-party module name."; doap-changeset:blame ; rdfs:seeAlso ; ], [ a doap-changeset:Documentation; rdfs:label "Fix Type::Params documentation error."; doap-changeset:blame ; rdfs:seeAlso ; ], [ a doap-changeset:Documentation; rdfs:label "Minor correction to POD header for Type::Params"; doap-changeset:blame ; rdfs:seeAlso ; ], [ a doap-changeset:Addition; rdfs:label "Types::Standard ArrayRef parameterized type can now take a second parameter, the minimum array length."; ], [ rdfs:label "Tidy up Type::Tiny namespace a little by fully-referencing some functions instead of importing them."; ], [ a doap-changeset:Packaging; rdfs:label "Bump minimum required version of Exporter::Tiny to 1.000000."; ], [ rdfs:label "Eval::TypeTiny's API is now considered to be stable."; ], [ rdfs:label "Tweaks to Type::Tiny and Type::Coercion to avoid unnecessarily loading overload.pm and overloading.pm."; ], [ a doap-changeset:Addition; rdfs:label "Type::Params multisig function now supports custom error messages."; doap-changeset:blame ; rdfs:seeAlso ; ], [ rdfs:label "Types::TypeTiny::TypeTiny->has_coercion is now true."; ], [ rdfs:label "Type::Params signatures with slurpy hashrefs now allow true hashrefs to be passed to them."; ], [ rdfs:label "Better implementation of is_subtype_of/is_supertype_of and related functions."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.005_000"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.005_001"^^xsd:string; dc:issued "2019-01-23"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Type::Library now supports `of` and `where` options when importing type constraints."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.005_001"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.005_002"^^xsd:string; dc:issued "2019-01-29"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Type::Params named_to_list feature."; rdfs:seeAlso ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.005_002"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.005_003"^^xsd:string; dc:issued "2019-02-26"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Improve test coverage."; ], [ rdfs:label "Fix Types::Standard's LazyLoad implementation."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.005_003"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.005_004"^^xsd:string; dc:issued "2019-11-11"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ rdfs:label "Eliminate memory cycles created by coderef overloading in Type::Tiny and Type::Coercion."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Addition; rdfs:label "Type::Tiny::Enum now has a `unique_values` method."; rdfs:seeAlso ; ], [ rdfs:label "The `values` attribute of Type::Tiny::Enum now preserves order."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Documentation; rdfs:label "Types::Standard documentation fix."; doap-changeset:blame ; rdfs:seeAlso ; ], [ rdfs:label "Don't use Int from Type::Tiny::XS unless version 0.016 is available."; rdfs:seeAlso ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.005_004"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-1.006000"^^xsd:string; dc:issued "2019-11-12"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Minor correction to POD header for Type::Params"; doap-changeset:blame ; rdfs:seeAlso ; ], [ a doap-changeset:Addition; rdfs:label "Types::Standard ArrayRef parameterized type can now take a second parameter, the minimum array length."; ], [ rdfs:label "Tidy up Type::Tiny namespace a little by fully-referencing some functions instead of importing them."; ], [ a doap-changeset:Packaging; rdfs:label "Bump minimum required version of Exporter::Tiny to 1.000000."; ], [ rdfs:label "Eval::TypeTiny's API is now considered to be stable."; ], [ rdfs:label "Tweaks to Type::Tiny and Type::Coercion to avoid unnecessarily loading overload.pm and overloading.pm."; ], [ a doap-changeset:Addition; rdfs:label "Type::Params multisig function now supports custom error messages."; doap-changeset:blame ; rdfs:seeAlso ; ], [ rdfs:label "Types::TypeTiny::TypeTiny->has_coercion is now true."; ], [ a doap-changeset:Addition; rdfs:label "Type::Params signatures with slurpy hashrefs now allow true hashrefs to be passed to them."; ], [ rdfs:label "Better implementation of is_subtype_of/is_supertype_of and related functions."; ], [ a doap-changeset:Addition; rdfs:label "Type::Library now supports `of` and `where` options when importing type constraints."; ], [ a doap-changeset:Addition; rdfs:label "Type::Params named_to_list feature."; rdfs:seeAlso ; ], [ a doap-changeset:Tests; rdfs:label "Improve test coverage."; ], [ rdfs:label "Fix Types::Standard's LazyLoad implementation."; ], [ rdfs:label "Eliminate memory cycles created by coderef overloading in Type::Tiny and Type::Coercion."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Addition; rdfs:label "Type::Tiny::Enum now has a `unique_values` method."; rdfs:seeAlso ; ], [ rdfs:label "The `values` attribute of Type::Tiny::Enum now preserves order."; doap-changeset:fixes ; doap-changeset:thanks ; ], [ a doap-changeset:Documentation; rdfs:label "Types::Standard documentation fix."; doap-changeset:blame ; rdfs:seeAlso ; ], [ rdfs:label "Don't use Int from Type::Tiny::XS unless version 0.016 is available."; rdfs:seeAlso ; ], [ a doap-changeset:Packaging; rdfs:label "Type::Tiny::XS 0.016 is recommended."; ], [ a doap-changeset:Documentation; rdfs:label "Links to Type::Tiny on GitHub/Travis/AppVeyor/Coveralls in Type::Tiny pod."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.006000"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.007_000"^^xsd:string; dc:issued "2019-11-17"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Tests; rdfs:label "Bundle some tests for Types::ReadOnly because it does interesting stuff with coercions and parameterizable types."; ], [ a doap-changeset:Bugfix; rdfs:label "When extending a MooseX::Types library, be more careful checking to see if types have coercions, because a Moose::Meta::TypeCoercion object may be an empty list of coercions."; doap-changeset:fixes ; ], [ a doap-changeset:Tests; rdfs:label "More tests for extending MooseX::Types libraries."; ], [ a doap-changeset:Addition; rdfs:label "When Types::TypesTiny::to_TypeTiny converts a Moose/Mouse type to a Type::Tiny type, the returned type will now be parameterizable if they original type was parameterizable."; ], [ a doap-changeset:Addition; rdfs:label "When importing type constraints from non-Moose/non-Mouse blessed type constraint systems (Specio, Types::Nano, others?), support inlining."; ], [ a doap-changeset:Addition; rdfs:label "Type::Tiny::ConstrainedObject exists as a superclass for Type::Tiny::Class, Type::Tiny::Role, and Type::Tiny::Duck."; ], [ a doap-changeset:Addition; rdfs:label "Many type constraints now support `stringifies_to`, `numifies_to`, and `with_attribute_values` methods. Type::Tiny 1.006000 accidentally included an undocumented early implementation of these with some differences."; ], [ a doap-changeset:Tests; rdfs:label "Add a test that Specio type constraints can be converted to Type::Tiny types, and inlining works."; ], [ a doap-changeset:Bugfix; rdfs:label "Type::Params will now keep a reference to all type constraints passed to it; this may use more memory in some cases, but will improve exceptions thrown."; doap-changeset:fixes ; ], [ a doap-changeset:Tests; rdfs:label "Bundle test from RT#104154, which turned out to not be a bug."; rdfs:seeAlso ; ], [ rdfs:label "Smarter caching and reuse of parameterized types."; ], [ a doap-changeset:Bugfix, doap-changeset:Packaging; rdfs:label "Strip underscores in version numbers for dev releases."; doap-changeset:fixes ; ], [ a doap-changeset:Addition; rdfs:label "Provide a control over whether types are allowed to make callbacks in inlined code."; ], [ a doap-changeset:Bugfix; rdfs:label "Type::Tiny::Enum will now avoid triggering a Type::Tiny::XS bug involving hyphens in strings."; doap-changeset:fixes ; ], [ a doap-changeset:Bugfix; rdfs:label "Type::Tiny better mimics the Moose::Meta::TypeConstraint::Parameterized API, adding `parameterized_from` and `has_parameterized_from` methods."; doap-changeset:fixes ; ], [ a doap-changeset:Packaging, doap-changeset:Removal; rdfs:label "Dropped the TODO file from the repo and distribution because it was mostly out of date. Use RT instead."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.007_000"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.007_001"^^xsd:string; dc:issued "2019-11-23"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Complete rewrite of the Type::Tiny manual."; ], [ a doap-changeset:Addition, doap-changeset:Documentation, doap-changeset:Tests; rdfs:label "Add a huge amount of tests for the built-in type constraints, intended as documentation as well as tests."; ], [ a doap-changeset:Addition; rdfs:label "The `extends` function is now able to extend Specio::Exporter libraries."; ], [ a doap-changeset:Addition; rdfs:label "Type::Params now has `wrap_subs` and `wrap_methods` functions."; ], [ a doap-changeset:Bugfix; rdfs:label "The `Tied` type no longer assumes that any reference which isn't a HASH or ARRAY must be a SCALAR."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix the 'my variable $base masks earlier declaration' warning caused by IntRange/NumRange."; ], [ a doap-changeset:Bugfix; rdfs:label "ClassName/RoleName no longer accepts a glob."; ], [ rdfs:label "Returning a list of strings from an inlining coderef is now officially supported and no longer experimental."; ], [ rdfs:label "Type::Tiny::XS integration is now officially supported and no longer experimental."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.007_001"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.007_002"^^xsd:string; dc:issued "2019-11-26"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "More work on the Type::Tiny manual."; ], [ a doap-changeset:Documentation, doap-changeset:Tests; rdfs:label "Expand per-type tests of bundled type libraries."; ], [ rdfs:label "Control over whether types are allowed to make callbacks in inlined code is now via a package variable instead of an environment variable and can be toggled at runtime."; ], [ a doap-changeset:Documentation; rdfs:label "Move CONTRIBUTING.pod into the manual."; ], [ a doap-changeset:Change; rdfs:label "(~Types::Standard::Any)->name is now 'None'"; ], [ a doap-changeset:Documentation; rdfs:label "Fix various documentation typos."; ], [ a doap-changeset:Documentation; rdfs:label "Improve Type::Tiny SYNOPSIS."; ], [ a doap-changeset:Documentation; rdfs:label "Improve Type::Params SYNOPSIS."; ], [ a doap-changeset:Documentation; rdfs:label "Types::Standard now has a SYNOPSIS."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.007_002"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.007_003"^^xsd:string; dc:issued "2019-11-27"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "More work on the Type::Tiny manual."; doap-changeset:thanks [ foaf:nick "jplindstrom"; foaf:page ; ]; ], [ a doap-changeset:Documentation, doap-changeset:Tests; rdfs:label "Expand per-type tests of bundled type libraries."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.007_003"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.007_004"^^xsd:string; dc:issued "2019-11-30"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ rdfs:label "Improvements to $AvoidCallbacks support for Types::Standard::Maybe."; ], [ a doap-changeset:Bugfix; rdfs:label "Fixes for some edge cases in the overidden `can` method on old Perl 5.8.x versions for types with the secret `is_object` parameter set to true. (There were problems in 5.8.1 but 5.8.9 was okay; not sure the exact version where the delta was that affected it. Either way, fixed now.)"; ], [ a doap-changeset:Tests; rdfs:label "Clean up some warnings and stuff from test output."; ], [ a doap-changeset:Documentation, doap-changeset:Tests; rdfs:label "Expand per-type tests of bundled type libraries."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.007_004"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.007_005"^^xsd:string; dc:issued "2019-12-01"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Fixes for inlining Tuples which have a combination of Optional and slurpy slots."; ], [ rdfs:label "Improvements to deep coercions for Tuples."; ], [ a doap-changeset:Documentation, doap-changeset:Tests; rdfs:label "Expand per-type tests of bundled type libraries."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.007_005"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.007_006"^^xsd:string; dc:issued "2019-12-02"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation, doap-changeset:Tests; rdfs:label "Expand per-type tests of bundled type libraries."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.007_006"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.007_007"^^xsd:string; dc:issued "2019-12-03"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "More work on the Type::Tiny manual."; ], [ a doap-changeset:Documentation, doap-changeset:Tests; rdfs:label "Expand per-type tests of bundled type libraries."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.007_007"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.007_008"^^xsd:string; dc:issued "2019-12-05"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "More work on the Type::Tiny manual."; ], [ a doap-changeset:Documentation, doap-changeset:Tests; rdfs:label "Expand per-type tests of bundled type libraries."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.007_008"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.007_009"^^xsd:string; dc:issued "2019-12-06"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ rdfs:label "Type::Tiny's inline_assert method has been overhauled."; ], [ rdfs:label "Obscure changes to Error::TypeTiny::Assertion."; ], [ a doap-changeset:Documentation, doap-changeset:Tests; rdfs:label "Document some undocumented files in the test suite."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.007_009"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.007_010"^^xsd:string; dc:issued "2019-12-08"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Avoid undef warnings from Type::Tiny::_failed_check when the type has become undefined before the error message can be generated."; ], [ a doap-changeset:Tests; rdfs:label "Minor improvements to the test suite."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.007_010"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.007_011"^^xsd:string; dc:issued "2019-12-09"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Rewrite Type::Tiny::Manual::Coercions."; ], [ a doap-changeset:Documentation; rdfs:label "Make the Moo parts of the manual use less Moo-specific syntax, so it is more applicable to Moose and Mouse."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.007_011"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.007_012"^^xsd:string; dc:issued "2019-12-10"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Minor tweaks to Type::Tiny::Manual."; ], [ a doap-changeset:Bugfix; rdfs:label "Fix tr/// stuff on $Type::Tiny::VERSION."; ], [ a doap-changeset:Update; rdfs:label "Type::Tiny will stop trying to use very old versions of Type::Tiny::XS. (It already recommended newer versions in META.json.)"; ], [ a doap-changeset:Packaging; rdfs:label "Metadata updates."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.007_012"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.007_013"^^xsd:string; dc:issued "2019-12-10"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Add links to homepage in pod."; ], [ a doap-changeset:Packaging; rdfs:label "Rebuild with newer RDF::DOAP."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.007_013"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.007_014"^^xsd:string; dc:issued "2019-12-10"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Mostly formatting changes."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.007_014"^^xsd:string. a cpan-uri:DeveloperRelease, doap:Version; dc:identifier "Type-Tiny-1.007_015"^^xsd:string; dc:issued "2019-12-10"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Documentation; rdfs:label "Minor formatting changes."; ], [ a doap-changeset:Documentation; rdfs:label "No longer suggest that Type::Tiny::Manual needs rewriting in Contributing.pod."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.007_015"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-1.008000"^^xsd:string; dc:issued "2019-12-11"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Packaging; rdfs:label "Repackage as stable."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.008000"^^xsd:string. a doap:Version; dc:identifier "Type-Tiny-1.008001"^^xsd:string; dc:issued "2019-12-28"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Use improved inline_assert when building the coderef for &{$type} overloading."; ], [ a doap-changeset:Change; rdfs:label "Types::TypeTiny now better mocks Type::Library, offering is_* and assert_* functions for export."; ], [ a doap-changeset:Change; rdfs:label "Types::TypeTiny honours $Type::Tiny::AvoidCallbacks."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "1.008001"^^xsd:string. a foaf:Agent; foaf:mbox_sha1sum "cbd91ef3fd54c52cae34a5aaaed67dbf2da2b222". a foaf:Agent; foaf:mbox_sha1sum "2df4a653a57f2b27e8de55ebc0376974cdd60687". a foaf:Agent; foaf:mbox_sha1sum "860965460650325643501bf4e96aae390839b15d". a foaf:Agent; foaf:mbox_sha1sum "6c23833ac4a0b3ff955b4bc44976286eb1b15406". a foaf:Agent; foaf:mbox_sha1sum "e33976c4f7181cf955bd615e23814efb48545a3b". a foaf:Agent; foaf:mbox_sha1sum "fccaf03a90fdc927c8fcb3f0f8d4f5969c827b77". a foaf:Agent; foaf:mbox_sha1sum "943afe1e2148176ac8ba1c73bf2973580ad5b430". a foaf:Agent; foaf:mbox_sha1sum "eed2e225c2bb8a6b16179ac7dda75c6c59944cb0". a foaf:Agent; foaf:mbox_sha1sum "81750d13fe3e08dcbab06cebd34a9fe4fabd946f". a foaf:Agent; foaf:mbox_sha1sum "e6fb72dd0e31375b4c8626469a9a4ae195a6969e". a foaf:Agent; foaf:mbox_sha1sum "955e33f1b3b76c38043d3cb7d726fb4a93abf72a". a foaf:Agent; foaf:mbox_sha1sum "7699492dc595c10d65b72468627cb6bd0cd6536f". a foaf:Agent; foaf:mbox_sha1sum "00f47fd749128f7a4b60b9a9266a3f7dfd3d5f8e". a foaf:Agent; foaf:mbox_sha1sum "726bf25858db97a4640f0eb479d341e3c13c69fe". a foaf:Agent; foaf:mbox_sha1sum "68bb6d7424e2fe1bb9612197430db87f84a8b6d7". a foaf:Agent; foaf:mbox_sha1sum "a3bb054f532b528948e94b81574f172b9eaca03c". a foaf:Agent; foaf:mbox_sha1sum "339d855871c015a11cff4d97513ab012ecccb2ea". a foaf:Agent; foaf:mbox_sha1sum "ea2515cb691aed3a376aaff9e3272a81a0f17c5f". a foaf:Agent; foaf:mbox_sha1sum "0a6ed89ab18aed06a0df071c64be174e13fde53c". a foaf:Agent; foaf:mbox_sha1sum "01353d2d1cc7cb31f847fdc07ff0dee7024b34c9". a foaf:Agent; foaf:mbox_sha1sum "f30f17582ef9f59c6d0070b7624ea8062ef3f1ce". a foaf:Agent; foaf:mbox_sha1sum "5cfb9529eb9d18c8083a378c2697245ba8f2ee65". a foaf:Agent; foaf:mbox_sha1sum "01f1833f79d2ed448399911d7c175c2602ae168a". a foaf:Agent; foaf:mbox_sha1sum "ed010f54c43079761d1e89fe3160a14f07bd5311". a foaf:Agent; foaf:mbox_sha1sum "d182f0d5e392756c7df07f84047fcc7b52b5de90". a foaf:Agent; foaf:mbox_sha1sum "8e5fc889879f63ab979882081793ca857fb8ead5". a foaf:Agent; foaf:mbox_sha1sum "5c4419a9f32d74564c6fa40f2d8b57489b8b5233". a foaf:Agent; foaf:mbox_sha1sum "d9cd7d7db8c561cc55fc8194b6b6ad0a9e180def". a foaf:Person; foaf:name "Alexander Hartmaier"; foaf:nick "ABRAXXA"; foaf:page . a foaf:Person; foaf:name "Andreas J König"; foaf:nick "ANDK"; foaf:page . a foaf:Person; foaf:name "Jon Portnoy"; foaf:nick "AVENJ"; foaf:page . a foaf:Person; foaf:name "Brendan Byrd"; foaf:nick "BBYRD"; foaf:page . a foaf:Person; foaf:name "Aran Clary Deltac"; foaf:nick "BLUEFEET"; foaf:page . a foaf:Person; foaf:name "Philippe Bruhat"; foaf:nick "BOOK"; foaf:page . a foaf:Person; foaf:name "Kevin Dawson"; foaf:nick "BOWTIE"; foaf:page . a foaf:Person; foaf:name "David Golden"; foaf:nick "DAGOLDEN"; foaf:page . a foaf:Person; foaf:name "Gianni Ceccarelli"; foaf:nick "DAKKAR"; foaf:page . a foaf:Person; foaf:name "Diab Jerius"; foaf:nick "DJERIUS"; foaf:page . a foaf:Person; foaf:name "Karen Etheridge"; foaf:nick "ETHER"; foaf:page . a foaf:Person; foaf:name "Graham Knop"; foaf:nick "HAARG"; foaf:page . a foaf:Person; foaf:name "Dagfinn Ilmari Mannsåker"; foaf:nick "ILMARI"; foaf:page . a foaf:Person; foaf:name "Ingy döt Net"; foaf:nick "INGY"; foaf:page . a foaf:Person; foaf:name "Jonas B Nielsen"; foaf:nick "JONASBN"; foaf:page . a foaf:Person; foaf:name "Jason R Mash"; foaf:nick "JRMASH"; foaf:page . a foaf:Person; foaf:name "Peter Karman"; foaf:nick "KARMAN"; foaf:page . a foaf:Person; foaf:name "Lucas Buchala"; foaf:nick "LSBUCHALA"; foaf:page , . a foaf:Person; foaf:name "Mark Stosberg"; foaf:nick "MARKSTOS"; foaf:page . a foaf:Person; foaf:name "Marcel Timmerman"; foaf:nick "MARTIMM"; foaf:page . a foaf:Person; foaf:name "Matt Phillips"; foaf:nick "MATTP"; foaf:page . a foaf:Person; foaf:name "Vyacheslav Matyukhin"; foaf:nick "MMCLERIC"; foaf:page . a foaf:Person; foaf:name "Michael G Schwern"; foaf:nick "MSCHWERN"; foaf:page . a foaf:Person; foaf:name "Matt S Trout"; foaf:nick "MSTROUT"; foaf:page . a foaf:Person; foaf:name "Yuval Kogman"; foaf:nick "NUFFIN"; foaf:page . a foaf:Person; foaf:name "Peter Flanigan"; foaf:nick "PJFL"; foaf:page . a foaf:Person; foaf:name "Peter Rabbitson"; foaf:nick "RIBASUSHI"; foaf:page . a foaf:Person; foaf:name "Ricardo Signes"; foaf:nick "RJBS"; foaf:page . a foaf:Person; foaf:name "Robert Rothenberg"; foaf:nick "RRWO"; foaf:page . a foaf:Person; foaf:name "Richard Simões"; foaf:nick "RSIMOES"; foaf:page . a foaf:Person; foaf:name "Daniel Schröer"; foaf:nick "SCHROEER"; foaf:page . a foaf:Person; foaf:name "Shlomi Fish"; foaf:nick "SHLOMIF"; foaf:page . a foaf:Person; foaf:name "Samuel Kaufman"; foaf:nick "SKAUFMAN"; foaf:page . a foaf:Person; foaf:name "Marcel Montes"; foaf:nick "SPICEMAN"; foaf:page . a foaf:Person; foaf:name "Slaven Rezić"; foaf:nick "SREZIC"; foaf:page . a foaf:Person; foaf:name "Steven Lee"; foaf:nick "STEVENL"; foaf:page . a foaf:Person; foaf:name "Tim Bunce"; foaf:nick "TIMB"; foaf:page . a foaf:Person; foaf:mbox ; foaf:name "Toby Inkster"; foaf:nick "TOBYINK"; foaf:page . a foaf:Person; foaf:name "MATSUNO Tokuhiro"; foaf:nick "TOKUHIROM"; foaf:page . a foaf:Person; foaf:name "Thomas Sibley"; foaf:nick "TSIBLEY"; foaf:page , . a foaf:Person; foaf:name "Caleb Cushing"; foaf:nick "XENO"; foaf:page . a doap-bugs:Issue; rdfs:label "check and coerce arguments not being passed to parameterized types"; dc:created "2014-11-04T09:22:03Z"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "170b4944cacd3cffb9f5a27ab96a099d8650cc38"; ]; doap-bugs:id "100014"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "localize SIG DIE"; dc:created "2014-12-08T15:12:04Z"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "2b16b2ce13b2165be6ff6908b31276fbbe805630"; ]; doap-bugs:id "100780", "100780"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Malformed UTF-8 character warnings in Perl 5.10 with utf8 pragma on"; dc:created "2015-01-17T02:44:33Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "101582", "101582"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Test suite fails with perl 5.21.8"; dc:created "2015-01-20T22:18:42Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "101639"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Document that compile needs to be called from within the subroutine"; dc:created "2015-03-02T19:51:30Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "102457"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "\"Default\" type constraint for using with Dict and Tuple"; dc:created "2015-03-08T13:14:04Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "102638"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Types serialization / deserialization"; dc:created "2015-03-08T13:15:18Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "102639"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Type::Library can't consume MooseX::Types::DBIx::Class"; dc:created "2015-03-13T17:55:43Z"^^xsd:dateTime; dc:reporter _:B1; doap-bugs:id "102748", "102748"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "Tests inheriting from a MooseX::Types library that uses MooseX::Types::Parameterizable and MooseX::Meta::TypeCoercion::Parameterizable."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt102748.t"; ]; ]. a doap-bugs:Issue; rdfs:label "\"used only once\" warnings from test suite"; dc:created "2015-03-18T13:55:53Z"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "fca375f12085d4a03a2606da02bd0d6b346ee4d3"; ]; doap-bugs:id "102864"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "\"deep_explanation\" never called for some types"; dc:created "2015-05-01T21:11:02+01:00"^^xsd:dateTime; dc:reporter _:B1; doap-bugs:id "104154", "104154"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "Tests for deep coercion."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt104154.t"; ]; ]. a doap-bugs:Issue; rdfs:label "Tests fail on old Perl and old Moose"; dc:created "2015-06-01T17:56:58+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "7dbda2121338302f841f71d891a5b7a20af08056"; ]; doap-bugs:id "104848"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "coercions fail to be executed on uncompiled type checks"; dc:created "2015-06-06T19:05:28+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "105022"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "documentation on coerce methods needs more details"; dc:created "2015-06-07T14:27:46+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "105034"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "[PATCH] Croak when a parameterized ArrayRef is used like a Tuple"; dc:created "2015-06-17T17:28:14+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "3c261d7474c1dbb3f73460d61d84f80fb0f4111c"; ]; doap-bugs:id "105299", "105299"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Strawberry perl x32 5.22.0 crashes"; dc:created "2015-06-26T14:37:14+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "105505"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Type::Library messages lost when used with named parameters in Type::Params"; dc:created "2015-06-29T20:18:48+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "c9913d208967575ac8ec0e160f734609a3d240c5"; ]; doap-bugs:id "105561"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Make Type::Tiny assertions compatible with Carp::Always and/or Carp::Verbose"; dc:created "2015-11-30T02:26:19Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "109940"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Unescaped literal \"{\" characters in regular expression patterns are no longer permissible"; dc:created "2016-05-15T05:32:54+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "114386", "114386"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Mismatch in isa vs can for parameterized types"; dc:created "2016-05-31T19:50:58+01:00"^^xsd:dateTime; dc:reporter _:B2; doap-bugs:id "114915", "114915"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Bug in coercions for parameterized types"; dc:created "2016-09-14T19:47:29+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "4d06cb14e5ce9dc1558c4e9c48d7058203c1a18e"; ]; doap-bugs:id "117838"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Provide method to inline an attribute type check"; dc:created "2017-02-13T11:13:56Z"^^xsd:dateTime; dc:reporter _:B2; doap-bugs:id "120226"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "1.001_006 breaks SHLOMIF/AI-Pathfinding-OptimizeMultiple-0.0.13.tar.gz"; dc:created "2017-05-01T08:52:48+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "121478"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Comparison to Params::ValidationCompiler isn't really accurate"; dc:created "2017-05-04T18:52:41+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "121529"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "FileHandle behaviour is different between Type::Tiny and Type::Tiny::XS"; dc:created "2017-05-18T10:19:45+01:00"^^xsd:dateTime; dc:reporter _:B3; doap-bugs:id "121762", "121762"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Sometimes \"explain\" is missing from Error::TypeTiny::Assertion"; dc:created "2017-05-18T10:21:25+01:00"^^xsd:dateTime; dc:reporter _:B3; doap-bugs:id "121763", "121763"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "Test to make sure 'compile' keeps a reference to all the types that get compiled, to avoid them going away before exceptions can be thrown for them."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt121763.t"; ]; ]. a doap-bugs:Issue; rdfs:label "Weird Perl <5.14 error with Union Types"; dc:created "2017-05-18T10:24:46+01:00"^^xsd:dateTime; dc:reporter _:B3; doap-bugs:id "121764", "121764"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Document the options hash to `compile` and `compile_named` and provide some more useful options."; dc:created "2017-05-23T23:45:33+01:00"^^xsd:dateTime; dc:reporter _:B3; doap-bugs:id "121840"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Support `any_of`, `all_of`, `one_of`, and `none_of` in options hash to `compile_named`"; dc:created "2017-05-24T00:05:56+01:00"^^xsd:dateTime; dc:reporter _:B3; doap-bugs:id "121841"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Depends on Ref::Util::XS 0.200.0 which doesn't exist yet"; dc:created "2017-06-04T09:07:45+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "121981", "121981"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "1.002001 fails to install in docker"; dc:created "2017-06-09T01:44:32+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "56ca9233eaa3ac431a6588ed72aefec65a07316a"; ]; doap-bugs:id "122054"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Documented code using class_type with plus_coercions doesn’t work"; dc:created "2017-07-01T22:26:24+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "ba2fc0575516e4553efc73b60344d4dc30d5e758"; ]; doap-bugs:id "122305", "122305"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Circular reference on Type::Coercion"; dc:created "2017-08-31T01:40:52+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "122931"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "typo: Params::ValidateCompiler → Params::ValidationCompiler"; dc:created "2017-09-14T10:51:38+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "8fb5238859d200bb4e1de91964c58d779f04a913"; ]; doap-bugs:id "123041"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Code from Type::Utils synopsis doesn't work"; dc:created "2017-10-11T09:14:04+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "123243"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "[PATCH] Compatibility with constants and with CV-in-stash optimisation"; dc:created "2017-10-27T18:56:31+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "de3f4914b6898a5e74e0642110ee39086fe9aff2"; ]; doap-bugs:id "123408", "123408"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "00-begin.t fails with -DDEBUGGING perls"; dc:created "2018-01-13T07:33:26Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "124067", "124067"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "warning: \"Found = in conditional, should be == at temporary compiled converter from 'Dict' line 1\""; dc:created "2018-01-17T23:25:54Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "124121"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Type::Library::_mksub generates a new sub when importing types from another library"; dc:created "2018-03-08T18:40:43Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "124728", "124728"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Nasty interaction between compile() and $1"; dc:created "2018-04-19T14:51:32+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "78e234e70caad29b81a6eb58bc71d278e10bf76e"; ]; doap-bugs:id "125132", "125132"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "Test inlined Int type check clobbering '$1'."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt125132.t"; ]; ]. a doap-bugs:Issue; rdfs:label "Error when generating explanation"; dc:created "2018-07-06T09:31:57+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "18d9c920110a0a23e4a3d0e284d3e9ef4731a553"; ]; doap-bugs:id "125765", "125765"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "Check weird error doesn't happen with deep explain."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt125765.t"; ]; ]. a doap-bugs:Issue; rdfs:label "dev releases are not removing _ from their versions"; dc:created "2018-07-13T00:03:06+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "125839", "125839"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Error::TypeTiny not correctly reporting line number of error"; dc:created "2018-07-27T18:59:51+01:00"^^xsd:dateTime; dc:reporter _:B3; doap-bugs:id "125942", "125942"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "t/30-integration/Moo/exceptions.t fails with really old Moo"; dc:created "2018-07-28T14:58:22+01:00"^^xsd:dateTime; dc:reporter _:B3; doap-bugs:id "125948", "125948"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label ""; dc:created "2018-08-31T08:59:32+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "2974f68d48930089dcf73edb575a06ed34a5679b"; ]; doap-bugs:id "127005"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Bool type check fails on JSON::PP::Boolean"; dc:created "2018-09-11T08:24:49+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "127090"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Test Errors while trying to install Type-Tiny 1.004002"; dc:created "2018-10-10T09:21:55+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "b16438b6db2b156bced63c1cf47a1761d3a2df01"; ]; doap-bugs:id "127327"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Ambiguous exceptions where used with Params::ValidationCompiler"; dc:created "2018-10-28T19:39:59Z"^^xsd:dateTime; dc:reporter _:B4; doap-bugs:id "127504"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Test::TypeTiny should_pass fails but check works"; dc:created "2018-11-13T19:47:37Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "127635"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Predicate for complementary_type"; dc:created "2018-12-10T17:10:38Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "127986"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "allow IntRange and NumRange to only have upper bounds"; dc:created "2018-12-17T20:56:56Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "128039"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Bool type not properly validated via Type::Params::validate"; dc:created "2018-12-18T15:16:08Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "128046"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Support something similar to Params::ValidationCompiler#named_to_list"; dc:created "2019-01-23T19:43:53Z"^^xsd:dateTime; dc:reporter _:B5; doap-bugs:id "128337"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Char type in Types::Common::String"; dc:created "2019-02-13T04:49:05Z"^^xsd:dateTime; dc:reporter _:B5; doap-bugs:id "128493"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Add NumberLike to Types::TypeTiny"; dc:created "2019-03-17T14:57:17Z"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "2e7830c8d1fcbba54d43210e32819ec90fe9a45a"; ]; doap-bugs:id "128867"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Allowable value of Type::Tiny::Enum should maintain order"; dc:created "2019-05-22T11:18:33+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "129650", "129650"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Union with Enum with a value containing a '-' character fails"; dc:created "2019-06-02T02:30:22+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "129729", "129729"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "Test that Enum types containing hyphens work."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt129729.t"; ]; ]. a doap-bugs:Issue; rdfs:label "Consider documenting other styles of employing Type::Params"; dc:created "2019-08-21T07:14:17+01:00"^^xsd:dateTime; dc:reporter _:B4; doap-bugs:id "130353"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "is_Int sometimes gives false positives"; dc:created "2019-08-29T13:11:07+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "5ce5571608e34e0602196c86d87d1c0e7695f425"; ]; doap-bugs:id "130411"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Cycle references"; dc:created "2019-10-26T11:37:51+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "217b5f4f500428733491a7b87d5830252d372a79"; ]; doap-bugs:id "130823", "130823"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "Check for memory cycles."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt130823.t"; ]; ]. a doap-bugs:Issue; rdfs:label "Request: Types::TypeTiny::to_TypeTiny: add support for Specio::Constraint::Simple "; dc:created "2019-11-18T01:52:22Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "131011"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Why do you quote module names?"; dc:created "2019-11-19T18:48:00Z"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "81e3dfd9a09872c0b11985dbce425a247a702a3c"; ]; doap-bugs:id "131032"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Confusing error message if required slurpy Dict not present in parameter list"; dc:created "2013-05-05T03:35:42+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "85054"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "exception objects"; dc:created "2013-05-09T04:52:37+01:00"^^xsd:dateTime; dc:reporter _:B6; doap-bugs:id "85149"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Type::Library has wrong VERSION variable"; dc:created "2013-05-30T03:53:03+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "85720"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "support for optional arguments"; dc:created "2013-05-30T14:11:03+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "85732"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Type comparison not working on 5.8"; dc:created "2013-06-05T18:39:56+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "a0b2c81a1ab31a33a19293431d21804ea3bd09ac"; ]; doap-bugs:id "85895", "85895"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "\"coercion cannot be inlined\" error w/ Type::Params::compile & Dict"; dc:created "2013-06-06T04:00:30+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "85911", "85911"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "Test Type::Params with deep Dict coercion."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt85911.t"; ]; ]. a doap-bugs:Issue; doap-bugs:id "86001"^^xsd:string; doap-bugs:page . a doap-bugs:Issue; rdfs:label "type constraint fails after coercion if too many elements in Dict"; dc:created "2013-06-08T23:03:45+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "86004", "86004"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "Test Type::Params with more complex Dict coercion."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt86004.t"; ]; ]. a doap-bugs:Issue; rdfs:label "Missing coercion with Moose and Type::Tiny"; dc:created "2013-06-15T22:30:28+01:00"^^xsd:dateTime; dc:reporter _:B7; doap-bugs:id "86172", "86172"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "\"Cannot inline type constraint check\" erro with compile and Dict"; dc:created "2013-06-18T15:23:52+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "86233", "86233"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "Fix: \"Cannot inline type constraint check\" error with compile and Dict."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt86233.t"; ]; ]. a doap-bugs:Issue; rdfs:label "Optional constraints ignored if wrapped in Dict"; dc:created "2013-06-18T16:34:37+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "86239", "86239"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "Fix: Optional constraints ignored if wrapped in Dict."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt86239.t"; ]; ]. a doap-bugs:Issue; doap-bugs:id "86303"^^xsd:string; doap-bugs:page . a doap-bugs:Issue; rdfs:label "Can't locate object method \"NAME\" via package \"B::SPECIAL\""; dc:created "2013-06-24T14:48:37+01:00"^^xsd:dateTime; dc:reporter _:B7; doap-bugs:id "86383", "86383"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "'extends' is not declared"; dc:created "2013-07-09T18:53:01+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "1fa560e9f30b9c4621aad0c3ffca750ba9e3abae"; ]; doap-bugs:id "86813", "86813"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Reduce boilerplate for inline_as"; dc:created "2013-07-12T14:29:19+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "86891", "86891"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Reduce boilerplate for message"; dc:created "2013-07-12T14:45:49+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "86892", "86892"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Clarify \"may\" in the docs in relation to using constraint => quote_sub q{...}"; dc:created "2013-07-12T15:08:16+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "86893", "86893"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "I was bitten by equals() being looser than expected (ie structural) which impacts is_subtype_of()"; dc:created "2013-07-24T18:20:27+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "87264"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "PackageName type"; dc:created "2013-07-26T23:18:08+01:00"^^xsd:dateTime; dc:reporter _:B6; doap-bugs:id "87366"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Dict type doesn't notice missing Bool elements"; dc:created "2013-07-30T15:09:13+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "87443", "87443"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "slurpy Dict[ foo => InstanceOf[\"bar\"] ] fails (due to unescaped quotes in throw?)"; dc:created "2013-08-14T11:59:43+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "87846", "87846"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Make constraint failure errors look less like data dumps"; dc:created "2013-08-21T13:22:54+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "87999", "87999"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Several subclasses of Type::Tiny don't accept a hashref to the constructor"; dc:created "2013-08-23T17:00:11+01:00"^^xsd:dateTime; dc:reporter _:B3; doap-bugs:id "88064", "88064"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Tuple validation unexpectedly successful"; dc:created "2013-08-29T19:42:31+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "88277", "88277"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Grouped alternatives"; dc:created "2013-08-30T18:33:23+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "88291", "88291"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Coercion Hierarchies"; dc:created "2013-09-06T00:09:56+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "88452", "88452"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Type::Tiny::Union could better mock Moose::Meta::TypeConstraint::Union"; dc:created "2013-09-13T09:21:08+01:00"^^xsd:dateTime; dc:reporter _:B3; doap-bugs:id "88648"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Better messsages for type constraint failures"; dc:created "2013-09-13T13:52:03+01:00"^^xsd:dateTime; dc:reporter _:B3; doap-bugs:id "88655", "88655"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Typo in Type::Utils documentation"; dc:created "2013-09-19T03:52:25+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "88798", "88798"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Union and Intersection should still allow constraint/inlined attributes"; dc:created "2013-09-25T01:13:06+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "88951"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Fwd: Union?"; dc:created "2013-09-30T17:42:42+01:00"^^xsd:dateTime; dc:reporter _:B6; doap-bugs:id "89073"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Moo attribute information not included in exception messages"; dc:created "2013-10-03T17:09:02+01:00"^^xsd:dateTime; dc:reporter _:B2; doap-bugs:id "89234", "89234"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Make truncation length in Type::Tiny::_dd (currently 72) configurable"; dc:created "2013-10-04T12:41:25+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "89251", "89251"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "validate_explain and Intersections"; dc:created "2013-10-06T16:21:31+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "89279", "89279"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Types::Exception not being indexed properly"; dc:created "2013-10-06T16:24:38+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "89280", "89280"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Item should be a subtype of Any"; dc:created "2013-10-08T01:51:05+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "89317"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Gazetteer type constraint"; dc:created "2013-10-08T21:20:35+01:00"^^xsd:dateTime; dc:reporter _:B3; doap-bugs:id "89352"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Types::Standard: please add StrLen (string with length) type"; dc:created "2013-10-22T11:42:15+01:00"^^xsd:dateTime; dc:reporter _:B8; doap-bugs:id "89691"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Types::Standard: is it possible to check for an empty ArrayRef/HashRef?"; dc:created "2013-10-22T13:22:36+01:00"^^xsd:dateTime; dc:reporter _:B8; doap-bugs:id "89696", "89696"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Maybe[Foo] should better emulate Foo|Undef for constraints"; dc:created "2013-11-01T00:43:36Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "89936", "89936"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Modification of a read-only value attempted at parameter validation for '__ANON__'"; dc:created "2013-11-06T15:24:29Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "90096", "90096"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "Additional tests related to RT#90096. Make sure that Type::Params localizes '$_'."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt90096-2.t"; ]; ], [ a doap-tests:RegressionTest; doap-tests:purpose "Make sure that Type::Params localizes '$_'."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt90096.t"; ]; ]. a doap-bugs:Issue; rdfs:label "Type::Params::multisig fails to validate when presented with a slurpy Dict"; dc:created "2013-11-28T00:53:07Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "90865", "90865"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "possible documentation error in Error::TypeTiny::Assertion"; dc:created "2013-11-28T02:25:01Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "90867", "90867"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Type::Utils::extends does not handle named type coercions"; dc:created "2013-12-03T17:44:14Z"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "be10c65554cd95cd10b3305311f8cfb45bf39499"; ]; doap-bugs:id "91153", "91153"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "test failure"; dc:created "2013-12-17T12:39:50Z"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "e808ede8c60c2fe4c802fed08b9b7745f122515d"; ]; doap-bugs:id "91468", "91468"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Types::Standard: please add $class->DOES(...), $class->isa(...) and $class =~ /$valid_class_re/ constraints."; dc:created "2014-01-02T19:49:31Z"^^xsd:dateTime; dc:reporter _:B8; doap-bugs:id "91802"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "unexpected error from on-the-fly type union coercions, e.g. ( Str | Str )->coercion"; dc:created "2014-01-30T05:56:04Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "92571", "92571"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "Make sure that the weakening of the reference from a Type::Coercion::Union object back to its \"owner\" type constraint does not break functionality."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt92571-2.t"; ]; ], [ a doap-tests:RegressionTest; doap-tests:purpose "Make sure that the weakening of the reference from a Type::Coercion object back to its \"owner\" type constraint does not break functionality."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt92571.t"; ]; ]. a doap-bugs:Issue; rdfs:label "anonymous coercions (via declare_coercion) ignore passed coercion maps if not in a Type::Library"; dc:created "2014-01-30T22:24:22Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "92591", "92591"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "Make sure that 'declare_coercion' works outside type libraries."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt92591.t"; ]; ]. a doap-bugs:Issue; rdfs:label "Inlining/compiling of coercions which haven't been frozen"; dc:created "2014-02-25T14:13:36Z"^^xsd:dateTime; dc:reporter _:B3; doap-bugs:id "93345", "93345"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Type::Params; slurpy Dict breaks HasMethods"; dc:created "2014-03-26T04:18:03Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "94196", "94196"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "Problematic inlining using '$_'."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt94196.t"; ]; ]. a doap-bugs:Issue; rdfs:label "Type::Tiny and when()"; dc:created "2014-03-28T15:35:36Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "94286"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "documentation error in Types::Standard vis-à-vis coercions"; dc:created "2014-06-11T17:20:17+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "96379", "96379"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "5.20+ fails compile( Optional ) if passing explicit undef"; dc:created "2014-06-19T04:42:06+01:00"^^xsd:dateTime; dc:reporter _:B6; doap-bugs:id "96545"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "InstanceOf[Class::Name] is not cached, makes declaring coercion inconsistent"; dc:created "2014-07-25T23:50:47+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "97516", "97516"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Strange breakage with Mouse"; dc:created "2014-08-01T22:03:06+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "97684", "97684"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "The \"too few arguments for type constraint check functions\" error."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt97684.t"; ]; ]. a doap-bugs:Issue; rdfs:label "incorrect argument fingered in validate w/ optional coerced arg and bogus extra arg"; dc:created "2014-08-07T19:25:02+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "97840"; doap-bugs:page ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Overload fallback gets clobbered on 5.10"; dc:created "2014-08-17T18:41:34+01:00"^^xsd:dateTime; dc:reporter _:B7; doap-bugs:id "98113", "98113"^^xsd:string; doap-bugs:page , ; doap-bugs:status ; doap-tests:regression_test [ a doap-tests:RegressionTest; doap-tests:purpose "Test overload fallback"; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/rt98113.t"; ]; ]. a doap-bugs:Issue; rdfs:label "Install failed with older Moose"; dc:created "2014-08-18T23:18:09+01:00"^^xsd:dateTime; dc:reporter _:B7; doap-bugs:id "98159", "98159"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "a Dict with optional values and custom coercions can fail to validate"; dc:created "2014-08-27T17:06:50+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "98362", "98362"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "Type constraint parsing fails when using a classname in the fun/method arguments"; dc:created "2014-08-30T03:25:27+01:00"^^xsd:dateTime; dc:reporter ; doap-bugs:id "98458", "98458"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "inline_check code generation flaw/bug"; dc:created "2014-10-05T11:05:32+01:00"^^xsd:dateTime; dc:reporter [ a foaf:Agent; foaf:mbox_sha1sum "4adbbbbb2b570e8761bc411981ae5c1daad25184"; ]; doap-bugs:id "99312", "99312"^^xsd:string; doap-bugs:page , ; doap-bugs:status . a doap-bugs:Issue; rdfs:label "In Type::Params please throw exception showing caller"; dc:created "2014-10-29T15:03:49Z"^^xsd:dateTime; dc:reporter ; doap-bugs:id "99889"; doap-bugs:page ; doap-bugs:status . foaf:mbox ; foaf:name "David Steinbrunner". foaf:name "Pierre Masci"; foaf:page . foaf:mbox ; foaf:name "Benct Philip Jonsson". foaf:mbox ; foaf:name "Peter Valdemar Mørch". foaf:mbox ; foaf:name "Ivanov Anton". foaf:homepage ; foaf:name "André Walker"; foaf:page . foaf:mbox ; foaf:name "Alexandr Ciornii"; foaf:page . foaf:mbox ; foaf:name "Zoffix Znet". foaf:mbox ; foaf:name "Denis Ibaev"; foaf:page . foaf:name "Nelo Onyiah"; foaf:page . foaf:name "KB Jørgensen". _:B1 a foaf:Agent; foaf:mbox_sha1sum "a1ea66ab424d54745bcff0459ccedc34810b6698". _:B2 a foaf:Agent; foaf:mbox_sha1sum "b07d8ccbdad5ade6520ad7d8b42c5b0784604ff8". _:B3 a foaf:Agent; foaf:mbox_sha1sum "7ed2c97d6b43f439d14fb072af1c0ce3a2e83d9d". _:B4 a foaf:Agent; foaf:mbox_sha1sum "4489b6413868d5d58fb4c3fcbd9488bde196f7fc". _:B5 a foaf:Agent; foaf:mbox_sha1sum "73bf7b6cff88b2a42dc321f8d660290f47e5708c". _:B6 a foaf:Agent; foaf:mbox_sha1sum "fb673bc745f8b8bc65c33bc4700155dcba13dd5d". _:B7 a foaf:Agent; foaf:mbox_sha1sum "773c118edc593a4272b888498829f9ef4fb0a55c". _:B8 a foaf:Agent; foaf:mbox_sha1sum "11285309b4bb0908c954155cfa81c1027c7a146e". [] a nfo:FileDataObject; dc:license ; dc:rightsHolder ; nfo:fileName "CONTRIBUTING". [] a nfo:FileDataObject; dc:license ; dc:rightsHolder ; nfo:fileName "CREDITS". [] a nfo:FileDataObject, nfo:SourceCode; dc:license ; dc:rightsHolder ; nfo:fileName "examples/benchmarking/benchmark-coercion.pl"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; dc:license ; dc:rightsHolder ; nfo:fileName "examples/benchmarking/benchmark-constraints.pl"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; dc:license ; dc:rightsHolder ; nfo:fileName "examples/benchmarking/benchmark-param-validation.pl"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; dc:license ; dc:rightsHolder ; nfo:fileName "examples/benchmarking/benchmark-named-param-validation.pl"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; dc:license ; dc:rightsHolder ; nfo:fileName "examples/benchmarking/versus-scalar-validation.pl"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; dc:license ; dc:rightsHolder ; nfo:fileName "examples/nonempty.pl"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; dc:license ; dc:rightsHolder ; nfo:fileName "examples/page-numbers.pl"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; dc:license ; dc:rightsHolder ; nfo:fileName "examples/datetime-coercions.pl"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject; dc:license ; dc:rightsHolder ; nfo:fileName "meta/changes.pret". [] a nfo:FileDataObject; dc:license ; dc:rightsHolder ; nfo:fileName "meta/doap.pret". [] a nfo:FileDataObject, nfo:TextDocument; dc:license ; dc:rightsHolder ; nfo:fileName "Changes". [] a nfo:FileDataObject; dc:license ; dc:rightsHolder ; nfo:fileName "meta/makefile.pret". [] a nfo:FileDataObject; dc:license ; dc:rightsHolder ; nfo:fileName "meta/people.pret". [] a nfo:FileDataObject; dc:license ; dc:rightsHolder ; nfo:fileName "meta/rights.pret". [] a nfo:FileDataObject, nfo:SourceCode; dc:license ; dc:rightsHolder ; nfo:fileName "inc/Test/Fatal.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; dc:license ; dc:rightsHolder ; nfo:fileName "inc/Test/Requires.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; dc:license ; dc:rightsHolder ; nfo:fileName "inc/Try/Tiny.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject; dc:license ; dc:rightsHolder ; nfo:fileName "MANIFEST.SKIP". [] a nfo:FileDataObject, nfo:TextDocument; dc:license ; dc:rightsHolder ; nfo:fileName "LICENSE". [] a nfo:FileDataObject; dc:license ; dc:rightsHolder ; nfo:fileName "META.ttl". [] a nfo:FileDataObject, nfo:SourceCode; dc:license ; dc:rightsHolder ; nfo:fileName "Makefile.PL"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:TextDocument; dc:license ; dc:rightsHolder ; nfo:fileName "NEWS". [] a nfo:FileDataObject, nfo:TextDocument; dc:license ; dc:rightsHolder ; nfo:fileName "README". [] a nfo:FileDataObject, nfo:TextDocument; dc:license ; dc:rightsHolder ; nfo:fileName "TODO". [] a nfo:FileDataObject; dc:license ; dc:rightsHolder ; nfo:fileName "TODO.mm". _:B9 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/00-begin.t". _:B10 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/01-compile.t". _:B11 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/02-api.t". _:B12 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/03-leak.t". _:B13 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/98-param-eg-from-docs.t". _:B14 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/99-moose-std-types-test.t". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Devel::TypeTiny::Perl56Compat"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Checks 'B::perlstring()' works."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Devel-TypeTiny-Perl56Compat/basic.t"; ]; ]; nfo:fileName "lib/Devel/TypeTiny/Perl56Compat.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Devel::TypeTiny::Perl58Compat"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Checks 're::is_regexp()' works."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Devel-TypeTiny-Perl58Compat/basic.t"; ]; ]; nfo:fileName "lib/Devel/TypeTiny/Perl58Compat.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Error::TypeTiny"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Tests for basic Error::TypeTiny functionality."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Error-TypeTiny/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Tests that Error::TypeTiny is capable of providing stack traces."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Error-TypeTiny/stacktrace.t"; ]; ]; nfo:fileName "lib/Error/TypeTiny.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Error::TypeTiny::Assertion"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Tests Error::TypeTiny::Assertion."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Error-TypeTiny-Assertion/basic.t"; ]; ]; nfo:fileName "lib/Error/TypeTiny/Assertion.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Error::TypeTiny::Compilation"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Tests for Error::TypeTiny::Compilation, mostly by triggering compilation errors using Eval::TypeTiny."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Error-TypeTiny-Compilation/basic.t"; ]; ]; nfo:fileName "lib/Error/TypeTiny/Compilation.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Error::TypeTiny::WrongNumberOfParameters"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Test Error::TypeTiny::WrongNumberOfParameters."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Error-TypeTiny-WrongNumberOfParameters/basic.t"; ]; ]; nfo:fileName "lib/Error/TypeTiny/WrongNumberOfParameters.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Eval::TypeTiny"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Tests Eval::TypeTiny supports alias=>1 using Devel::LexAlias implementation."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Eval-TypeTiny/aliases-devel-lexalias.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Tests Eval::TypeTiny supports alias=>1 using Perl refaliasing."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Eval-TypeTiny/aliases-native.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Tests Eval::TypeTiny supports alias=>1 using PadWalker implementation."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Eval-TypeTiny/aliases-padwalker.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Tests Eval::TypeTiny supports alias=>1 using 'tie()' implementation."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Eval-TypeTiny/aliases-tie.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Tests Eval::TypeTiny."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Eval-TypeTiny/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Tests Eval::TypeTiny with experimental lexical subs."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Eval-TypeTiny/lexical-subs.t"; ]; ]; nfo:fileName "lib/Eval/TypeTiny.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Test::TypeTiny"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Tests Test::TypeTiny (which is somewhat important because Test::TypeTiny is itself used for the majority of the type constraint tests). In particular, this tests that everything works when the '$EXTENDED_TESTING' environment variable is false."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Test-TypeTiny/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Tests Test::TypeTiny works when the '$EXTENDED_TESTING' environment variable is true. Note that Test::Tester appears to have issues with subtests, so currently 'should_pass' and 'should_fail' are not tested."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Test-TypeTiny/extended.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Tests Test::TypeTiny (which is somewhat important because Test::TypeTiny is itself used for the majority of the type constraint tests). In particular, this tests that everything works when the '$EXTENDED_TESTING' environment variable is false."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Test-TypeTiny/matchfor.t"; ]; ]; nfo:fileName "lib/Test/TypeTiny.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Coercion"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Coercion works."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Coercion/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks various undocumented Type::Coercion methods. The fact that these are tested here should not be construed to mean tht they are any any way a stable, supported part of the Type::Coercion API."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Coercion/esoteric.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Type::Coercion objects are mutable, unlike Type::Tiny objects. However, they can be frozen, making them immutable. (And Type::Tiny will freeze them occasionally, if it feels it has to.)"; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Coercion/frozen.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Coercion can be inlined."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Coercion/inlining.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks the 'Split' and 'Join' parameterized coercions from Types::Standard."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Coercion/parameterized.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Coercion overload of '~~'."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Coercion/smartmatch.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks proper Type::Coercion objects are automatically created by the Type::Tiny constructor."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Coercion/typetiny-constructor.t"; ]; ]; nfo:fileName "lib/Type/Coercion.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Coercion::FromMoose"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Checks the types adopted from Moose still have a coercion which works."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Coercion-FromMoose/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks crazy Type::Coercion::FromMoose errors."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Coercion-FromMoose/errors.t"; ]; ]; nfo:fileName "lib/Type/Coercion/FromMoose.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Coercion::Union"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Coercion::Union works."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Coercion-Union/basic.t"; ]; ]; nfo:fileName "lib/Type/Coercion/Union.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Library"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Checks that the assertion functions exported by a type library work as expected."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Library/assert.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Library warns about deprecated types."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Library/deprecation.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Tests errors thrown by Type::Library."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Library/errors.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks 'of' and 'where' import options works."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Library/import-params.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks that it's possible to extend existing type libraries."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Library/inheritance.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks that the check functions exported by a type library work as expected."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Library/is.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks that the coercion functions exported by a type library work as expected."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Library/to.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks that the type functions exported by a type library work as expected."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Library/types.t"; ]; ]; nfo:fileName "lib/Type/Library.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Params"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Check that people doing silly things with Test::Params get"; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/badsigs.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Params' interaction with Carp: use Type::Params compile => { confess => 1 };"; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/carping.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Params usage of types with coercions."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/coerce.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Params' brand spanking new 'compile_named' function."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/compile-named-bless.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Params 'compile_named_oo' function."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/compile-named-oo.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Params' brand spanking new 'compile_named' function."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/compile-named.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test 'compile' and 'compile_named' support defaults for parameters."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/defaults.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Params' brand spanking new 'compile_named' function."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/hashorder.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Params usage for method calls."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/methods.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Params usage with mix of positional and named parameters."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/mixednamed.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Make sure that custom 'multisig()' messages work."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/multisig-custom-message.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Params 'multisig' function."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/multisig.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Params usage with named parameters and 'named_to_list'."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/named-to-list.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Params usage with named parameters."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/named.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Params with type constraints that cannot be inlined."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/noninline.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Params usage with optional parameters."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/optional.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Params positional parameters, a la the example in the documentation: sub nth_root { state $check = compile( Num, Num ); my ($x, $n) = $check->(@_); return $x ** (1 / $n); }"; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/positional.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Params usage with slurpy parameters."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/slurpy.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test 'wrap_subs' and 'wrap_methods' from Type::Params."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Params/wrap.t"; ]; ]; nfo:fileName "lib/Type/Params.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Parser"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Parser works."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Parser/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Parser can pick up MooseX::Types type constraints."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Parser/moosextypes.t"; ]; ]; nfo:fileName "lib/Type/Parser.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Registry"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Registry->for_class is automagically populated."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Registry/automagic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Registry works."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Registry/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks various newish Type::Registry method calls."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Registry/methods.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Registry works with MooseX::Types."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Registry/moosextypes.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Registry works with MouseX::Types."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Registry/mousextypes.t"; ]; ]; nfo:fileName "lib/Type/Registry.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Tiny"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Tests overloading of bitwise operators and numeric comparison operators for Type::Tiny."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny/arithmetic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Tiny works."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test new type comparison stuff with Type::Tiny objects."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny/cmp.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks 'plus_coercions', 'minus_coercions' and 'no_coercions' methods work."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny/coercion-modifiers.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Tiny works accepts strings of Perl code as constraints."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny/constraint-strings.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Tiny's 'deprecated' attribute works."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny/deprecation.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks various undocumented Type::Tiny methods. The fact that these are tested here should not be construed to mean tht they are any any way a stable, supported part of the Type::Tiny API."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny/esoteric.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Tests for Type::Tiny's 'inline_assert' method."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny/inline-assert.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Tiny's 'my_methods' attribute."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny/my-methods.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "There are loads of tests for parameterization in 'stdlib.t', 'stdlib-overload.t', 'stdlib-strmatch.t', 'stdlib-structures.t', 'syntax.t', 'stdlib-automatic.t', etc. This file includes a handful of other parameterization-related tests that didn't fit anywhere else."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny/parameterization.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test the '->of' and '->where' shortcut methods."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny/shortcuts.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Tiny works with the smartmatch operator."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny/smartmatch.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks that all this Type[Param] syntactic sugar works. In particular, the following three type constraints are expected to be equivalent to each other: use Types::Standard qw( ArrayRef Int Num Str ); use Type::Utils qw( union intersection ); my $type1 = ArrayRef[Int] | ArrayRef[Num & ~Int] | ArrayRef[Str & ~Num]; my $type2 = union [ ArrayRef[Int], ArrayRef[Num & ~Int], ArrayRef[Str & ~Num], ]; my $type3 = union([ ArrayRef->parameterize(Int), ArrayRef->parameterize( intersection([ Num, Int->complementary_type, ]), ), ArrayRef->parameterize( intersection([ Str, Num->complementary_type, ]), ), ]);"; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny/syntax.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Tiny objects can be converted to Moose type constraint objects."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny/to-moose.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks Type::Tiny objects can be converted to Mouse type constraint objects."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny/to-mouse.t"; ]; ]; nfo:fileName "lib/Type/Tiny.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Tiny::Class"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Checks class type constraints work."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Class/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks class type constraints throw sane error messages."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Class/errors.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks the 'Type::Tiny::Class''s 'plus_constructors' method."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Class/plus-constructors.t"; ]; ]; nfo:fileName "lib/Type/Tiny/Class.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Tiny::ConstrainedObject"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Check 'stringifies_to', 'numifies_to', and 'with_attribute_values' work for Type::Tiny::Class, Type::Tiny::Role, and Type::Tiny::Duck."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-ConstrainedObject/basic.t"; ]; ]; nfo:fileName "lib/Type/Tiny/ConstrainedObject.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Tiny::Duck"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Checks duck type constraints work."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Duck/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test new type comparison stuff with Type::Tiny::Duck objects."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Duck/cmp.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks duck type constraints throw sane error messages."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Duck/errors.t"; ]; ]; nfo:fileName "lib/Type/Tiny/Duck.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Tiny::Enum"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Checks enum type constraints work."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Enum/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test new type comparison stuff with Type::Tiny::Enum."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Enum/cmp.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks enum type constraints throw sane error messages."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Enum/errors.t"; ]; ]; nfo:fileName "lib/Type/Tiny/Enum.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Tiny::Intersection"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Checks intersection type constraints work."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Intersection/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Check cmp for Type::Tiny::Intersection."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Intersection/cmp.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Check 'stringifies_to', 'numifies_to', and 'with_attribute_values' work for Type::Tiny::Intersection."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Intersection/constrainedobject.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks intersection type constraints throw sane error messages."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Intersection/errors.t"; ]; ]; nfo:fileName "lib/Type/Tiny/Intersection.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Tiny::Role"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Checks role type constraints work."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Role/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks role type constraints throw sane error messages."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Role/errors.t"; ]; ]; nfo:fileName "lib/Type/Tiny/Role.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Tiny::Union"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Checks union type constraint subtype/supertype relationships."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Union/relationships.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks union type constraints work."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Union/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Check 'stringifies_to', 'numifies_to', and 'with_attribute_values' work for Type::Tiny::Union."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Union/constrainedobject.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks union type constraints throw sane error messages."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-Union/errors.t"; ]; ]; nfo:fileName "lib/Type/Tiny/Union.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Tiny::_HalfOp"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Ensure that the following works: ArrayRef[Str] | Undef | Str"; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-_HalfOp/double-union.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Ensure that the following works consistently on all supported Perls: ArrayRef[Int] | HashRef[Int]"; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Tiny-_HalfOp/overload-precedence.t"; ]; ]; nfo:fileName "lib/Type/Tiny/_HalfOp.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Type::Utils"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Utils 'classifier' function."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Utils/classifier.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks sane behaviour of 'dwim_type' from Type::Utils when both Moose and Mouse are loaded."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Utils/dwim-both.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks Moose type constraints, and MooseX::Types type constraints are picked up by 'dwim_type' from Type::Utils."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Utils/dwim-moose.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks Mouse type constraints, and MouseX::Types type constraints are picked up by 'dwim_type' from Type::Utils."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Utils/dwim-mouse.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Type::Utils 'match_on_type' and 'compile_match_on_type' functions."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Utils/match-on-type.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Tests warnings raised by Type::Utils."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Type-Utils/warnings.t"; ]; ]; nfo:fileName "lib/Type/Utils.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Types::Common::Numeric"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Tests constraints for Types::Common::Numeric. These tests are based on tests from MooseX::Types::Common."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Common-Numeric/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Tests constraints for Types::Common::Numeric's 'IntRange' and 'NumRange'."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Common-Numeric/ranges.t"; ]; ]; nfo:fileName "lib/Types/Common/Numeric.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Types::Common::String"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Tests constraints for Types::Common::String. These tests are based on tests from MooseX::Types::Common."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Common-String/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Tests coercions for Types::Common::String. These tests are based on tests from MooseX::Types::Common."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Common-String/coerce.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Tests constraints for Types::Common::String's 'StrLength'tring"; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Common-String/strlength.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Tests Unicode support for Types::Common::String. These tests are based on tests from MooseX::Types::Common."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Common-String/unicode.t"; ]; ]; nfo:fileName "lib/Types/Common/String.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Types::Standard"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Checks the new ArrayRef[$type, $min, $max] from Types::Standard."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Standard/arrayreflength.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks various values against the type constraints from Types::Standard."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Standard/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks various values against 'CycleTuple' from Types::Standard."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Standard/cycletuple.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "If a coercion exists for type 'Foo', then Type::Tiny should be able to auto-generate a coercion for type 'ArrayRef[Foo]', etc."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Standard/deep-coercions.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks various values against 'FileHandle' from Types::Standard."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Standard/filehandle.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "OK, we need to bite the bullet and lock down coercions on core type constraints and parameterized type constraints."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Standard/lockdown.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test the following types from Types::Standard which were inspired by MooX::Types::MooseLike::Base. * 'InstanceOf' * 'ConsumerOf' * 'HasMethods' * 'Enum' Rather than checking they work directy, we check they are equivalent to known (and well-tested) type constraints generated using Type::Utils."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Standard/mxtmlb-alike.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks various values against 'OptList' from Types::Standard. Checks the standalone 'MkOpt' coercion."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Standard/optlist.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks various values against 'Overload' from Types::Standard."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Standard/overload.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks various values against 'StrMatch' from Types::Standard when '$Type::Tiny::AvoidCallbacks' is false."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Standard/strmatch-allow-callbacks.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks various values against 'StrMatch' from Types::Standard when '$Type::Tiny::AvoidCallbacks' is true."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Standard/strmatch-avoid-callbacks.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks various values against 'StrMatch' from Types::Standard."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Standard/strmatch.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks various values against structured types from Types::Standard."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Standard/structured.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks various values against 'Tied' from Types::Standard."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-Standard/tied.t"; ]; ]; nfo:fileName "lib/Types/Standard.pm"; nfo:programmingLanguage "Perl". [] a nfo:FileDataObject, nfo:SourceCode; rdfs:label "Types::TypeTiny"; doap-tests:unit_test [ a doap-tests:UnitTest; doap-tests:purpose "Test the Types::TypeTiny bootstrap library. (That is, type constraints used by Type::Tiny internally.)"; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-TypeTiny/basic.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test Types::TypeTiny::to_TypeTiny pseudo-coercion and the Types::TypeTiny::_ForeignTypeConstraint type."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-TypeTiny/coercion.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Test the Types::TypeTiny introspection methods. Types::TypeTiny doesn't inherit from Type::Library (because bootstrapping), so provides independent re-implementations of the most important introspection stuff."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-TypeTiny/meta.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Stuff that was originally in basic.t but was split out to avoid basic.t requiring Moose and Mouse."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-TypeTiny/moosemouse.t"; ]; ], [ a doap-tests:UnitTest; doap-tests:purpose "Checks that Types::TypeTiny avoids loading Exporter::Tiny."; doap-tests:test_script [ a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/20-unit/Types-TypeTiny/progressiveexporter.t"; ]; ]; nfo:fileName "lib/Types/TypeTiny.pm"; nfo:programmingLanguage "Perl". _:B15 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Class-InsideOut/basic.t". _:B16 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Exporter-Tiny/basic.t". _:B17 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Exporter-Tiny/installer.t". _:B18 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Exporter-Tiny/role-conflict.t". _:B19 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Function-Parameters/basic.t". _:B20 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Kavorka/80returntype.t". _:B21 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Kavorka/basic.t". _:B22 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Moo/basic.t". _:B23 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Moo/coercion-inlining-avoidance.t". _:B24 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Moo/coercion.t". _:B25 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Moo/exceptions.t". _:B26 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Moo/inflation.t". _:B27 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Moo/inflation2.t". _:B28 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Moops/basic.t". _:B29 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Moops/library-keyword.t". _:B30 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Moose/accept-moose-types.t". _:B31 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Moose/basic.t". _:B32 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Moose/coercion-more.t". _:B33 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Moose/coercion.t". _:B34 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Moose/inflate-then-inline.t". _:B35 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Moose/native-attribute-traits.t". _:B36 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Moose/parameterized.t". _:B37 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/MooseX-Getopt/coercion.t". _:B38 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/MooseX-Types/basic.t". _:B39 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/MooseX-Types/extending.t". _:B40 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/MooseX-Types/more.t". _:B41 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Mouse/basic.t". _:B42 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Mouse/coercion.t". _:B43 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Mouse/parameterized.t". _:B44 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/MouseX-Types/basic.t". _:B45 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/MouseX-Types/extending.t". _:B46 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Object-Accessor/basic.t". _:B47 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Return-Type/basic.t". _:B48 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Specio/basic.t". _:B49 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Specio/library.t". _:B50 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Sub-Quote/basic.t". _:B51 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Sub-Quote/delayed-quoting.t". _:B52 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Sub-Quote/unquote-coercions.t". _:B53 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Sub-Quote/unquote-constraints.t". _:B54 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Switcheroo/basic.t". _:B55 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Type-Tie/basic.t". _:B56 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Types-ReadOnly/basic.t". _:B57 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Validation-Class-Simple/archaic.t". _:B58 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/Validation-Class-Simple/basic.t". _:B59 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/30-integration/match-simple/basic.t". _:B60 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/73f51e2d.t". _:B61 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/gh1.t". _:B62 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/gh14.t". _:B63 a nfo:FileDataObject, nfo:SourceCode; nfo:fileName "t/40-regression/ttxs-gh1.t". [] a doap-tests:Test; doap-tests:purpose "Print some standard diagnostics before beginning testing."; doap-tests:test_script _:B9. [] a doap-tests:Test; doap-tests:purpose "Test that Type::Tiny, Type::Library, etc compile."; doap-tests:test_script _:B10. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check type constraints work with Class::InsideOut."; doap-tests:test_script _:B15. [] a doap-tests:IntegrationTest; doap-tests:purpose "Tests Exporter::Tiny has the features Type::Tiny needs."; doap-tests:test_script _:B16. [] a doap-tests:IntegrationTest; doap-tests:purpose "Tests Type::Library libraries work with Sub::Exporter plugins."; doap-tests:test_script _:B17. [] a doap-tests:IntegrationTest; doap-tests:purpose "Tests exporting to two roles; tries to avoid reporting conflicts."; doap-tests:test_script _:B18. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check type constraints work with Function::Parameters."; doap-tests:test_script _:B19. [] a doap-tests:IntegrationTest; doap-tests:purpose "Adopted test from Kavorka test suite."; doap-tests:test_script _:B20. [] a doap-tests:IntegrationTest; doap-tests:purpose "Checks Type::Tiny works with Kavorka."; doap-tests:test_script _:B21. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check type constraints work with Moo. Checks values that should pass and should fail; checks error messages."; doap-tests:test_script _:B22. [] a doap-tests:IntegrationTest; doap-tests:purpose "A rather complex case of defining an attribute with a type coercion in Moo; and only then adding coercion definitions to it. Does Moo pick up on the changes? It should."; doap-tests:test_script _:B23. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check coercions work with Moo."; doap-tests:test_script _:B24. [] a doap-tests:IntegrationTest; doap-tests:purpose "Tests Error::TypeTiny interaction with Moo."; doap-tests:test_script _:B25. [] a doap-tests:IntegrationTest; doap-tests:purpose "Checks that type constraints continue to work when a Moo class is inflated to a Moose class. Checks that Moo::HandleMoose correctly calls back to Type::Tiny to build Moose type constraints."; doap-tests:test_script _:B26. [] a doap-tests:IntegrationTest; doap-tests:purpose "A test for type constraint inflation from Moo to Moose."; doap-tests:test_script _:B27. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check that type constraints work in Moops. This file is borrowed from the Moops test suite, where it is called '31types.t'."; doap-tests:test_script _:B28. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check that type libraries can be declared with Moops. This file is borrowed from the Moops test suite, where it is called '71library.t'."; doap-tests:test_script _:B29. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check that Moose type constraints can be passed into the Type::Tiny API where a Type::Tiny constraint might usually be expected."; doap-tests:test_script _:B30. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check type constraints work with Moose. Checks values that should pass and should fail; checks error messages."; doap-tests:test_script _:B31. [] a doap-tests:IntegrationTest; doap-tests:purpose "Test for the good old \"You cannot coerce an attribute unless its type has a coercion\" error."; doap-tests:test_script _:B32. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check coercions work with Moose; both mutable and immutable classes."; doap-tests:test_script _:B33. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check type constraint inlining works with Moose in strange edge cases where we need to inflate Type::Tiny constraints into full Moose::Meta::TypeConstraint objects."; doap-tests:test_script _:B34. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check type constraints and coercions work with Moose native attibute traits."; doap-tests:test_script _:B35. [] a doap-tests:IntegrationTest; doap-tests:purpose "Test that parameterizable Moose types are still parameterizable when they are converted to Type::Tiny."; doap-tests:test_script _:B36. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check coercions work with MooseX::Getopt; both mutable and immutable classes."; doap-tests:test_script _:B37. [] a doap-tests:IntegrationTest; doap-tests:purpose "Complex checks between Type::Tiny and MooseX::Types."; doap-tests:test_script _:B38. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check that Type::Library can extend an existing MooseX::Types type constraint library."; doap-tests:test_script _:B39. [] a doap-tests:IntegrationTest; doap-tests:purpose "More checks between Type::Tiny and MooseX::Types. This started out as an example of making a parameterized 'Not[]' type constraint, but worked out as a nice test case."; doap-tests:test_script _:B40. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check type constraints work with Mouse. Checks values that should pass and should fail; checks error messages."; doap-tests:test_script _:B41. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check coercions work with Mouse; both mutable and immutable classes."; doap-tests:test_script _:B42. [] a doap-tests:IntegrationTest; doap-tests:purpose "Test that parameterizable Mouse types are still parameterizable when they are converted to Type::Tiny."; doap-tests:test_script _:B43. [] a doap-tests:IntegrationTest; doap-tests:purpose "Complex checks between Type::Tiny and MouseX::Types."; doap-tests:test_script _:B44. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check that Type::Library can extend an existing MooseX::Types type constraint library."; doap-tests:test_script _:B45. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check type constraints work with Object::Accessor."; doap-tests:test_script _:B46. [] a doap-tests:IntegrationTest; doap-tests:purpose "Test that this sort of thing works: sub foo :ReturnType(Int) { ...; }"; doap-tests:test_script _:B47. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check that Specio type constraints can be converted to Type::Tiny with inlining support."; doap-tests:test_script _:B48. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check that Specio type libraries can be extended by Type::Library."; doap-tests:test_script _:B49. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check type constraints can be made inlinable using Sub::Quote."; doap-tests:test_script _:B50. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check type constraints can be made inlinable using Sub::Quote even if Sub::Quote is loaded late."; doap-tests:test_script _:B51. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check type coercions can be unquoted Sub::Quote."; doap-tests:test_script _:B52. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check type constraints can be unquoted Sub::Quote."; doap-tests:test_script _:B53. [] a doap-tests:IntegrationTest; doap-tests:purpose "Checks Type::Tiny works with Switcheroo."; doap-tests:test_script _:B54. [] a doap-tests:IntegrationTest; doap-tests:purpose "Test that this sort of thing works: tie my $var, Int;"; doap-tests:test_script _:B55. [] a doap-tests:IntegrationTest; doap-tests:purpose "Types::ReadOnly does some frickin weird stuff with parameterization. Check it all works!"; doap-tests:test_script _:B56. [] a doap-tests:IntegrationTest; doap-tests:purpose "Fake Validation::Class::Simple 7.900017 by overriding '$VERSION' variable. (There is a reason for this... 'Types::TypeTiny::to_TypeTiny' follows two different code paths depending on the version of the Validation::Class::Simple object passed to it.)"; doap-tests:test_script _:B57. [] a doap-tests:IntegrationTest; doap-tests:purpose "Check type constraints Validation::Class::Simple objects can be used as type constraints."; doap-tests:test_script _:B58. [] a doap-tests:IntegrationTest; doap-tests:purpose "Checks Type::Tiny works with match::simple."; doap-tests:test_script _:B59. [] a doap-tests:RegressionTest; doap-tests:purpose "Possible issue causing segfaults on threaded Perl 5.18.x."; doap-tests:test_script _:B60. [] a doap-tests:RegressionTest; doap-tests:purpose "Test that subtypes of Type::Tiny::Class work."; doap-tests:test_script _:B61. [] a doap-tests:RegressionTest; doap-tests:purpose "Test for non-inlined coercions in Moo. The issue that prompted this test was actually invalid, caused by a typo in the bug reporter's code. But I wrote the test case, so I might as well include it."; doap-tests:test_script _:B62. [] a doap-tests:RegressionTest; doap-tests:purpose "Test that was failing with Type::Tiny::XS prior to 0.009."; doap-tests:test_script _:B63. [] a doap-tests:Test; doap-tests:purpose "Test that Type::Tiny and Type::Coercion provide a Moose/Mouse-compatible API."; doap-tests:test_script _:B11. [] a doap-tests:Test; doap-tests:purpose "Check for memory leaks. These tests are not comprehensive; chances are that there are still memory leaks lurking somewhere in Type::Tiny. If you have any concrete suggestions for things to test, or fixes for identified memory leaks, please file a bug report. https://rt.cpan.org/Ticket/Create.html?Queue=Type-Tiny."; doap-tests:test_script _:B12. [] a doap-tests:Test; doap-tests:purpose "An example of parameterized types from Type::Tiny::Manual::Libraries. The example uses Type::Tiny, Type::Library, and Type::Coercion, and makes use of inlining and parameterization, so is a good canary to check everything is working."; doap-tests:test_script _:B13. [] a doap-tests:Test; doap-tests:purpose "Type constraint tests pilfered from the Moose test suite."; doap-tests:test_script _:B14. datetime-coercions.pl000644001750001750 525113601673061 20341 0ustar00taitai000000000000Type-Tiny-1.008001/examples=pod =encoding utf-8 =head1 PURPOSE This example expands upon the Example::Types library defined in L. It defines class types for L and L and some structured types for hashes that can be used to instantiate DateTime objects. It defines some coercions for the C class type. A simple L class is provided using some of these types and coercions. The class also defines a couple of extra coercions inline. See the source code of this file for the actual example code. =head1 DEPENDENCIES L, L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib "lib", "../lib"; BEGIN { package Example::Types; use Type::Library -base, -declare => qw( Datetime DatetimeHash Duration EpochHash ); use Type::Utils; use Types::Standard -types; require DateTime; require DateTime::Duration; class_type Datetime, { class => "DateTime" }; class_type Duration, { class => "DateTime::Duration" }; declare DatetimeHash, as Dict[ year => Int, month => Optional[ Int ], day => Optional[ Int ], hour => Optional[ Int ], minute => Optional[ Int ], second => Optional[ Int ], nanosecond => Optional[ Int ], time_zone => Optional[ Str ], ]; declare EpochHash, as Dict[ epoch => Int, time_zone => Optional[ Str ], ]; coerce Datetime, from Int, via { "DateTime"->from_epoch(epoch => $_) }, from Undef, via { "DateTime"->now }, from DatetimeHash, via { "DateTime"->new(%$_) }, from EpochHash, via { "DateTime"->from_epoch(%$_) }; $INC{"Example/Types.pm"} = __FILE__; }; BEGIN { package Person; use Moose; use Types::Standard qw( Str Int Num ); use Example::Types qw( Datetime Duration ); has name => ( is => "ro", isa => Str, required => 1, ); has age => ( is => "ro", isa => Int->plus_coercions(Num, 'int($_)', Duration, '$_->years'), coerce => 1, init_arg => undef, lazy => 1, builder => "_build_age", ); has date_of_birth => ( is => "ro", isa => Datetime, coerce => 1, required => 1, ); sub _build_age { my $self = shift; return Datetime->class->now - $self->date_of_birth; } }; my $me = Person->new( name => "Toby Inkster", date_of_birth => { epoch => 328646500, time_zone => "Asia/Tokyo" }, ); printf("%s is %d years old.\n", $me->name, $me->age); nonempty.pl000644001750001750 205013601673061 16426 0ustar00taitai000000000000Type-Tiny-1.008001/examplesuse v5.14; use strict; use warnings; package Example1 { use Moo; use Sub::Quote 'quote_sub'; use Types::Standard -types; has my_string => ( is => 'ro', isa => Str->where( 'length($_) > 0' ), ); has my_array => ( is => 'ro', isa => ArrayRef->where( '@$_ > 0' ), ); has my_hash => ( is => 'ro', isa => HashRef->where( 'keys(%$_) > 0' ), ); } use Test::More; use Test::Fatal; is( exception { Example1::->new( my_string => 'u' ) }, undef, 'non-empty string, okay', ); isa_ok( exception { Example1::->new( my_string => '' ) }, 'Error::TypeTiny', 'result of empty string', ); is( exception { Example1::->new( my_array => [undef] ) }, undef, 'non-empty arrayref, okay', ); isa_ok( exception { Example1::->new( my_array => [] ) }, 'Error::TypeTiny', 'result of empty arrayref', ); is( exception { Example1::->new( my_hash => { '' => undef } ) }, undef, 'non-empty hashref, okay', ); isa_ok( exception { Example1::->new( my_hash => +{} ) }, 'Error::TypeTiny', 'result of empty hashref', ); done_testing; page-numbers.pl000644001750001750 342313601673061 17147 0ustar00taitai000000000000Type-Tiny-1.008001/examplesuse strict; use warnings; # Type constraint library… BEGIN { package Types::Bookish; $INC{'Types/Bookish.pm'} = __FILE__; use Type::Library -base, -declare => qw( PageNumber PageRangeArray PageRange PageSeriesArray PageSeries ); use Types::Standard qw( Str StrMatch Tuple ArrayRef ); use Types::Common::Numeric qw( PositiveInt ); use Type::Utils -all; declare PageNumber, as PositiveInt, ; declare PageRangeArray, as Tuple[ PageNumber, PageNumber ], constraint => '$_->[0] < $_->[1]', ; declare PageRange, as StrMatch[ qr/\A([0-9]+)-([0-9]+)\z/, PageRangeArray ], ; coerce PageRangeArray from PageRange, q{ [ split /-/, $_ ] }, ; coerce PageRange from PageRangeArray, q{ join q/-/, @$_ }, ; declare PageSeriesArray, as ArrayRef[ PageNumber | PageRange ], constraint => ( # This constraint prevents page series arrays from being in # the wrong order, like [ 20, '4-16', 12 ]. 'my $J = join q/-/, @$_; '. 'my $S = join q/-/, sort { $a <=> $b } split /-/, $J; '. '$S eq $J' ), ; declare PageSeries, as Str, constraint => ( 'my $tmp = [split /\s*,\s*/]; '. PageSeriesArray->inline_check('$tmp') ), ; coerce PageSeriesArray from PageSeries, q{ [ split /\s*,\s*/, $_ ] }, from PageRange, q{ [ $_ ] }, from PageNumber, q{ [ $_ ] }, ; coerce PageSeries from PageSeriesArray, q{ join q[,], @$_ }, ; __PACKAGE__->meta->make_immutable; } use Types::Bookish -types; use Perl::Tidy; PageNumber->assert_valid('4'); PageRangeArray->assert_valid([4, 16]); PageRange->assert_valid('4-16'); PageSeriesArray->assert_valid([ '4-16', 18, 20 ]); PageSeries->assert_valid('4-16, 18, 20'); Perl::Tidy::perltidy( source => \( PageSeries->inline_check('$DATA') ), destination => \( my $tidied ), ); print $tidied; 00-begin.t000644001750001750 421213601673061 14335 0ustar00taitai000000000000Type-Tiny-1.008001/t=pod =encoding utf-8 =head1 PURPOSE Print some standard diagnostics before beginning testing. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; sub diag_version { my ($module, $version, $return) = @_; if ($module =~ /\//) { my @modules = split /\s*\/\s*/, $module; my @versions = map diag_version($_, undef, 1), @modules; return @versions if $return; return diag sprintf(' %-43s %s', join("/", @modules), join("/", @versions)); } unless (defined $version) { eval "use $module ()"; $version = $module->VERSION; } if (!defined $version) { return 'undef' if $return; return diag sprintf(' %-40s undef', $module); } my ($major, $rest) = split /\./, $version; $major =~ s/^v//; return "$major\.$rest" if $return; return diag sprintf(' %-40s % 4d.%s', $module, $major, $rest); } sub diag_env { require B; require Devel::TypeTiny::Perl56Compat; my $var = shift; return diag sprintf(' $%-40s %s', $var, exists $ENV{$var} ? B::perlstring($ENV{$var}) : "undef"); } while () { chomp; if (/^#\s*(.*)$/ or /^$/) { diag($1 || ""); next; } if (/^\$(.+)$/) { diag_env($1); next; } if (/^perl$/) { diag_version("Perl", $]); next; } diag_version($_) if /\S/; } require Types::Standard; diag(""); diag( !Types::Standard::Str()->_has_xsub ? ">>>> Type::Tiny is not using XS" : $INC{'Type/Tiny/XS.pm'} ? ">>>> Type::Tiny is using Type::Tiny::XS" : ">>>> Type::Tiny is using Mouse::XS" ); diag(""); ok 1; done_testing; __END__ perl Exporter::Tiny Type::Tie Type::Tiny::XS Scalar::Util/Sub::Util Ref::Util/Ref::Util::XS Regexp::Util Class::XSAccessor Devel::LexAlias/PadWalker Devel::StackTrace Class::Tiny Moo Moose/MooseX::Types Mouse/MouseX::Types $AUTOMATED_TESTING $NONINTERACTIVE_TESTING $EXTENDED_TESTING $AUTHOR_TESTING $RELEASE_TESTING $PERL_TYPE_TINY_XS $PERL_TYPES_STANDARD_STRICTNUM $PERL_ONLY 01-compile.t000644001750001750 216613601673061 14710 0ustar00taitai000000000000Type-Tiny-1.008001/t=pod =encoding utf-8 =head1 PURPOSE Test that Type::Tiny, Type::Library, etc compile. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use_ok("Eval::TypeTiny"); use_ok("Test::TypeTiny"); use_ok("Type::Coercion"); use_ok("Type::Coercion::Union"); use_ok("Error::TypeTiny"); use_ok("Error::TypeTiny::Assertion"); use_ok("Error::TypeTiny::Compilation"); use_ok("Error::TypeTiny::WrongNumberOfParameters"); use_ok("Type::Library"); use_ok("Types::Standard"); use_ok("Types::TypeTiny"); use_ok("Type::Tiny"); use_ok("Type::Tiny::Class"); use_ok("Type::Tiny::Duck"); use_ok("Type::Tiny::Enum"); use_ok("Type::Tiny::Intersection"); use_ok("Type::Tiny::Role"); use_ok("Type::Tiny::Union"); use_ok("Type::Utils"); use_ok("Type::Params"); BAIL_OUT("Further tests rely on all modules compiling.") unless "Test::Builder"->new->is_passing; done_testing; 02-api.t000644001750001750 473413601673061 14035 0ustar00taitai000000000000Type-Tiny-1.008001/t=pod =encoding utf-8 =head1 PURPOSE Test that Type::Tiny and Type::Coercion provide a Moose/Mouse-compatible API. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; my $HAVE_MOOSE = eval { require Moose; Moose->VERSION('2.000'); 1; # return true }; my @MOOSE_WANTS = qw( _actually_compile_type_constraint _collect_all_parents _compile_subtype _compile_type _compiled_type_constraint _default_message _has_compiled_type_constraint _inline_check _new _package_defined_in _set_constraint assert_coerce assert_valid can_be_inlined check coerce coercion compile_type_constraint constraint create_child_type equals get_message has_coercion has_message has_parent inline_environment inlined is_a_type_of is_subtype_of message meta name new parent parents validate ); my $HAVE_MOUSE = eval { require Mouse }; my @MOUSE_WANTS = qw( __is_parameterized _add_type_coercions _as_string _compiled_type_coercion _compiled_type_constraint _identity _unite assert_valid check coerce compile_type_constraint create_child_type get_message has_coercion is_a_type_of message name new parameterize parent type_parameter ); require Type::Tiny; my $type = "Type::Tiny"->new(name => "TestType"); for (@MOOSE_WANTS) { SKIP: { skip "Moose::Meta::TypeConstraint PRIVATE API: '$_'", 1 if /^_/ && !$HAVE_MOOSE; ok($type->can($_), "Moose::Meta::TypeConstraint API: $type->can('$_')"); } } for (@MOUSE_WANTS) { SKIP: { skip "Mouse::Meta::TypeConstraint PRIVATE API: '$_'", 1 if /^_/ && !$HAVE_MOUSE; ok($type->can($_), "Mouse::Meta::TypeConstraint API: $type->can('$_')"); } } my @MOOSE_WANTS_COERCE = qw( _compiled_type_coercion _new add_type_coercions coerce compile_type_coercion has_coercion_for_type meta new type_coercion_map type_constraint ); require Type::Coercion; my $coerce = "Type::Coercion"->new(name => "TestCoercion"); for (@MOOSE_WANTS_COERCE) { SKIP: { skip "Moose::Meta::TypeCoercion PRIVATE API: '$_'", 1 if /^_/ && !$HAVE_MOOSE; ok($coerce->can($_), "Moose::Meta::TypeCoercion API: $coerce->can('$_')"); } } BAIL_OUT("Further tests rely on the Type::Tiny and Type::Coercion APIs.") unless "Test::Builder"->new->is_passing; done_testing; 03-leak.t000644001750001750 417513601673061 14200 0ustar00taitai000000000000Type-Tiny-1.008001/t=pod =encoding utf-8 =head1 PURPOSE Check for memory leaks. These tests are not comprehensive; chances are that there are still memory leaks lurking somewhere in Type::Tiny. If you have any concrete suggestions for things to test, or fixes for identified memory leaks, please file a bug report. L. =head1 DEPENDENCIES L. This test is skipped on Perl < 5.10.1 because I'm not interested in jumping through hoops for ancient versions of Perl. =head1 MISC ATTRIBUTE DECORATION If Perl has been compiled with Misc Attribute Decoration (MAD) enabled, then this test may fail. If you don't know what MAD is, then don't worry: you probably don't have it enabled. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Config; BEGIN { plan skip_all => 'Devel::Cover' if $INC{'Devel/Cover.pm'} }; BEGIN { plan skip_all => 'Perl < 5.10.1' if $] < 5.010001 }; BEGIN { plan skip_all => 'useithreads' if $Config{'useithreads'} }; use Test::Requires 'Test::LeakTrace'; use Test::LeakTrace; use Types::Standard qw( ArrayRef HashRef ); eval { require Moo }; no_leaks_ok { my $x = Type::Tiny->new; undef($x); } 'Type::Tiny->new'; no_leaks_ok { my $x = Type::Tiny->new->coercibles; undef($x); } 'Type::Tiny->new->coercible'; no_leaks_ok { my $x = ArrayRef | HashRef; my $y = HashRef | ArrayRef; undef($_) for $x, $y; } 'ArrayRef | HashRef'; no_leaks_ok { my $x = ArrayRef[HashRef]; my $y = HashRef[ArrayRef]; undef($_) for $x, $y; } 'ArrayRef[HashRef]'; no_leaks_ok { my $x = Type::Tiny->new; $x->check(1); undef($x); } 'Type::Tiny->new->check'; no_leaks_ok { my $x = ArrayRef->plus_coercions(HashRef, sub { [sort keys %$_] }); my $a = $x->coerce({bar => 1, baz => 2}); undef($_) for $x, $a; } 'ArrayRef->plus_coercions->coerce'; done_testing; 98-param-eg-from-docs.t000644001750001750 442013601673061 16653 0ustar00taitai000000000000Type-Tiny-1.008001/t=pod =encoding utf-8 =head1 PURPOSE An example of parameterized types from L. The example uses L, L, and L, and makes use of inlining and parameterization, so is a good canary to check everything is working. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::TypeTiny; use Test::More; BEGIN { package My::Types; use Type::Library -base; use Type::Utils 'extends'; BEGIN { extends 'Types::Standard' }; __PACKAGE__->add_type( name => 'MultipleOf', parent => Int, constraint_generator => sub { my $i = assert_Int(shift); return sub { $_ % $i == 0 }; }, inline_generator => sub { my $i = shift; return sub { my $varname = pop; return (undef, "($varname % $i == 0)"); }; }, coercion_generator => sub { my $i = $_[2]; require Type::Coercion; return Type::Coercion->new( type_coercion_map => [ Num, qq{ int($i * int(\$_/$i)) } ], ); }, ); __PACKAGE__->make_immutable; $INC{'My/Types.pm'} = __FILE__; }; use My::Types 'MultipleOf'; my $MultipleOfThree = MultipleOf->of(3); should_pass(0, $MultipleOfThree); should_fail(1, $MultipleOfThree); should_fail(2, $MultipleOfThree); should_pass(3, $MultipleOfThree); should_fail(4, $MultipleOfThree); should_fail(5, $MultipleOfThree); should_pass(6, $MultipleOfThree); should_fail(7, $MultipleOfThree); should_fail(-1, $MultipleOfThree); should_pass(-3, $MultipleOfThree); should_fail(0.1, $MultipleOfThree); should_fail([], $MultipleOfThree); should_fail(undef, $MultipleOfThree); subtest 'coercion' => sub { is($MultipleOfThree->coerce(0), 0); is($MultipleOfThree->coerce(1), 0); is($MultipleOfThree->coerce(2), 0); is($MultipleOfThree->coerce(3), 3); is($MultipleOfThree->coerce(4), 3); is($MultipleOfThree->coerce(5), 3); is($MultipleOfThree->coerce(6), 6); is($MultipleOfThree->coerce(7), 6); is($MultipleOfThree->coerce(8), 6); is($MultipleOfThree->coerce(8.9), 6); }; #diag( $MultipleOfThree->inline_check('$VALUE') ); done_testing; 99-moose-std-types-test.t000644001750001750 4662513601673061 17362 0ustar00taitai000000000000Type-Tiny-1.008001/t=pod =encoding utf-8 =head1 PURPOSE Type constraint tests pilfered from the L test suite. =head1 DEPENDENCIES Test is skipped if Moose 2.0000 is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE, but largely derived from the Moose test suite. Moose is maintained by the Moose Cabal, along with the help of many contributors. See "CABAL" in Moose and "CONTRIBUTORS" in Moose for details. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Infinity Interactive, Inc.. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut #!/usr/bin/perl use Test::More; BEGIN { $ENV{PERL_TYPES_STANDARD_STRICTNUM} = 1; }; BEGIN { $ENV{AUTOMATED_TESTING} or $ENV{EXTENDED_TESTING} or $ENV{AUTHOR_TESTING} or $ENV{RELEASE_TESTING} or plan skip_all => 'EXTENDED_TESTING' }; use strict; use warnings; use Test::Fatal; use Test::Requires { 'Moose' => '2.0000' }; use Eval::TypeTiny; use IO::File; use Scalar::Util qw( blessed openhandle ); use Type::Utils { replace => 1 }, -all; use Types::Standard; my $ZERO = 0; my $ONE = 1; my $INT = 100; my $NEG_INT = -100; my $NUM = 42.42; my $NEG_NUM = -42.42; my $EMPTY_STRING = q{}; my $STRING = 'foo'; my $NUM_IN_STRING = 'has 42 in it'; my $INT_WITH_NL1 = "1\n"; my $INT_WITH_NL2 = "\n1"; my $SCALAR_REF = \( my $var ); my $SCALAR_REF_REF = \$SCALAR_REF; my $ARRAY_REF = []; my $HASH_REF = {}; my $CODE_REF = sub { }; my $GLOB = do { no warnings 'once'; *GLOB_REF }; my $GLOB_REF = \$GLOB; open my $FH, '<', $0 or die "Could not open $0 for the test"; my $FH_OBJECT = IO::File->new( $0, 'r' ) or die "Could not open $0 for the test"; my $REGEX = qr/../; my $REGEX_OBJ = bless qr/../, 'BlessedQR'; my $FAKE_REGEX = bless {}, 'Regexp'; my $OBJECT = bless {}, 'Foo'; my $UNDEF = undef; { package Thing; sub new { } sub foo { } } my $CLASS_NAME = 'Thing'; { package Role; use Moose::Role; sub foo { } } my $ROLE_NAME = 'Role'; my %tests = ( Any => { accept => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $UNDEF, ], }, Item => { accept => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $UNDEF, ], }, Defined => { accept => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, ], reject => [ $UNDEF, ], }, Undef => { accept => [ $UNDEF, ], reject => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, ], }, Bool => { accept => [ $ZERO, $ONE, $EMPTY_STRING, $UNDEF, ], reject => [ $INT, $NEG_INT, $NUM, $NEG_NUM, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, ], }, Maybe => { accept => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $UNDEF, ], }, Value => { accept => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $GLOB, ], reject => [ $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $UNDEF, ], }, Ref => { accept => [ $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, ], reject => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $GLOB, $UNDEF, ], }, Num => { accept => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, ], reject => [ $EMPTY_STRING, $STRING, $NUM_IN_STRING, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $UNDEF, $INT_WITH_NL1, $INT_WITH_NL2, ], }, Int => { accept => [ $ZERO, $ONE, $INT, $NEG_INT, ], reject => [ $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $UNDEF, ], }, Str => { accept => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, ], reject => [ $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $UNDEF, ], }, ScalarRef => { accept => [ $SCALAR_REF, $SCALAR_REF_REF, ], reject => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $UNDEF, ], }, ArrayRef => { accept => [ $ARRAY_REF, ], reject => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $UNDEF, ], }, HashRef => { accept => [ $HASH_REF, ], reject => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $UNDEF, ], }, CodeRef => { accept => [ $CODE_REF, ], reject => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $UNDEF, ], }, RegexpRef => { accept => [ $REGEX, $REGEX_OBJ, $FAKE_REGEX, ], reject => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $OBJECT, $UNDEF, ], }, GlobRef => { accept => [ $GLOB_REF, $FH, ], reject => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $FH_OBJECT, $OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $UNDEF, ], }, FileHandle => { accept => [ $FH, $FH_OBJECT, ], reject => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $UNDEF, ], }, Object => { accept => [ $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, ], reject => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $UNDEF, ], }, ClassName => { accept => [ $CLASS_NAME, $ROLE_NAME, ], reject => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $UNDEF, ], }, RoleName => { accept => [ $ROLE_NAME, ], reject => [ $CLASS_NAME, $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $UNDEF, ], }, ); for my $name ( sort keys %tests ) { test_constraint( 'Types::Standard'->get_type($name), $tests{$name} ); test_constraint( dwim_type("$name|$name"), $tests{$name} ); } my %substr_test_str = ( ClassName => 'x' . $CLASS_NAME, RoleName => 'x' . $ROLE_NAME, ); # We need to test that the Str constraint (and types that derive from it) # accept the return val of substr() - which means passing that return val # directly to the checking code foreach my $type_name (qw(Str Num Int ClassName RoleName)) { my $str = $substr_test_str{$type_name} || '123456789'; my $type = 'Types::Standard'->get_type($type_name); my $unoptimized = $type->parent->create_child_type(constraint => $type->constraint)->compiled_check; my $inlined; { $inlined = eval_closure( source => 'sub { ( ' . $type->_inline_check('$_[0]') . ' ) }', ); } ok( $type->check( substr( $str, 1, 5 ) ), $type_name . ' accepts return val from substr using ->check' ); ok( $unoptimized->( substr( $str, 1, 5 ) ), $type_name . ' accepts return val from substr using unoptimized constraint' ); ok( $inlined->( substr( $str, 1, 5 ) ), $type_name . ' accepts return val from substr using inlined constraint' ); # only Str accepts empty strings. next unless $type_name eq 'Str'; ok( $type->check( substr( $str, 0, 0 ) ), $type_name . ' accepts empty return val from substr using ->check' ); ok( $unoptimized->( substr( $str, 0, 0 ) ), $type_name . ' accepts empty return val from substr using unoptimized constraint' ); ok( $inlined->( substr( $str, 0, 0 ) ), $type_name . ' accepts empty return val from substr using inlined constraint' ); } { my $class_tc = class_type {class => 'Thing'}; test_constraint( $class_tc, { accept => [ ( bless {}, 'Thing' ), ], reject => [ 'Thing', $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $UNDEF, ], } ); } { package Duck; sub new { } sub quack { } sub flap { } } { package DuckLike; sub new { } sub quack { } sub flap { } } { package Bird; sub new { } sub flap { } } { my @methods = qw( quack flap ); my $duck = duck_type 'Duck' => [@methods]; test_constraint( $duck, { accept => [ ( bless {}, 'Duck' ), ( bless {}, 'DuckLike' ), ], reject => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, ( bless {}, 'Bird' ), $UNDEF, ], } ); } { my @allowed = qw( bar baz quux ); my $enum = enum 'Enumerated' => [@allowed]; test_constraint( $enum, { accept => \@allowed, reject => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $UNDEF, ], } ); } { require Type::Tiny::Union; my $union = 'Type::Tiny::Union'->new( type_constraints => [ Types::Standard::Int, Types::Standard::Object, ], ); test_constraint( $union, { accept => [ $ZERO, $ONE, $INT, $NEG_INT, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, ], reject => [ $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $UNDEF, ], } ); } { note 'Anonymous Union Test'; my $union = union[ Types::Standard::Int, Types::Standard::Object ]; test_constraint( $union, { accept => [ $ZERO, $ONE, $INT, $NEG_INT, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, ], reject => [ $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $UNDEF, ], } ); } { note 'Named Union Test'; my $union = union 'NamedUnion' => [ Types::Standard::Int, Types::Standard::Object ]; test_constraint( $union, { accept => [ $ZERO, $ONE, $INT, $NEG_INT, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, ], reject => [ $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $UNDEF, ], } ); } { note 'Combined Union Test'; my $union = union( [ Types::Standard::Int, enum [qw[ red green blue ]] ] ); test_constraint( $union, { accept => [ $ZERO, $ONE, $INT, $NEG_INT, 'red', 'green', 'blue', ], reject => [ 'yellow', 'pink', $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $UNDEF, ], } ); } { my $enum1 = enum 'Enum1' => ['a', 'b']; my $enum2 = enum 'Enum2' => ['x', 'y']; my $union = subtype 'EnumUnion', as ($enum1|$enum2); test_constraint( $union, { accept => [qw( a b x y )], reject => [ $ZERO, $ONE, $INT, $NEG_INT, $NUM, $NEG_NUM, $EMPTY_STRING, $STRING, $NUM_IN_STRING, $INT_WITH_NL1, $INT_WITH_NL2, $SCALAR_REF, $SCALAR_REF_REF, $ARRAY_REF, $HASH_REF, $CODE_REF, $GLOB, $GLOB_REF, $FH, $FH_OBJECT, $REGEX, $REGEX_OBJ, $FAKE_REGEX, $OBJECT, $UNDEF, ], } ); } { package DoesRole; use Moose; with 'Role'; } close $FH or warn "Could not close the filehandle $0 for test"; $FH_OBJECT->close or warn "Could not close the filehandle $0 for test"; done_testing; sub test_constraint { my $type = shift; my $tests = shift; local $Test::Builder::Level = $Test::Builder::Level + 1; unless ( blessed $type ) { BAIL_OUT("TYPE STRING!!! $type!"); } my $name = $type->name; note "TYPE: $name"; my $unoptimized = $type->has_parent ? $type->parent->create_child_type(constraint => $type->constraint)->compiled_check : 'Type::Tiny'->new( constraint => $type->constraint )->compiled_check; my $inlined; if ( $type->can_be_inlined ) { $inlined = eval_closure( source => 'sub { ( ' . $type->_inline_check('$_[0]') . ' ) }', environment => $type->inline_environment, ); } require Moose; my $class = Moose::Meta::Class->create_anon( superclasses => ['Moose::Object'], ); $class->add_attribute( simple => ( is => 'ro', isa => $type, ) ); $class->add_attribute( collection => ( traits => ['Array'], isa => Types::Standard::ArrayRef()->parameterize($type), default => sub { [] }, handles => { add_to_collection => 'push' }, ) ); my $anon_class = $class->name; for my $accept ( @{ $tests->{accept} || [] } ) { my $described = describe($accept); ok( $type->check($accept), "$name accepts $described using ->check" ); ok( $unoptimized->($accept), "$name accepts $described using unoptimized constraint" ); if ($inlined) { ok( $inlined->($accept), "$name accepts $described using inlined constraint" ); } is( exception { $anon_class->new( simple => $accept ); }, undef, "no exception passing $described to constructor with $name" ); is( exception { $anon_class->new()->add_to_collection($accept); }, undef, "no exception passing $described to native trait push method with $name" ); } for my $reject ( @{ $tests->{reject} || [] } ) { my $described = describe($reject); ok( !$type->check($reject), "$name rejects $described using ->check" ); ok( !$unoptimized->($reject), "$name rejects $described using unoptimized constraint" ); if ($inlined) { ok( !$inlined->($reject), "$name rejects $described using inlined constraint" ); } ok( exception { $anon_class->new( simple => $reject ); }, "got exception passing $described to constructor with $name" ); ok( exception { $anon_class->new()->add_to_collection($reject); }, "got exception passing $described to native trait push method with $name" ); } } sub describe { my $val = shift; return 'undef' unless defined $val; if ( !ref $val ) { return q{''} if $val eq q{}; $val =~ s/\n/\\n/g; return $val; } return 'open filehandle' if openhandle $val && !blessed $val; return blessed $val ? ( ref $val ) . ' object' : ( ref $val ) . ' reference'; } README000644001750001750 124413601673061 13531 0ustar00taitai000000000000Type-Tiny-1.008001/tRunning the test suite ====================== In the main directory for the distribution (i.e. the directory containing dist.ini), run the following command: prove -lr "t" Test suite structure ==================== Each test should contain its own documentation in pod format. t/20-unit/ - unit tests for each module in the distribution t/30-integration/ - integration tests for using Type-Tiny with other software - these should be skipped if the other software is not available t/40-regression/ - tests related to specific bug reports t/lib/ - support files for test cases. t/*.t - miscellaneous other tests t/*.pl - support files for managing test cases TODO000644001750001750 6513601673061 13301 0ustar00taitai000000000000Type-Tiny-1.008001/t- full module coverage (according to not-covered.pl) mk-test-manifest.pl000644001750001750 515413601673061 16402 0ustar00taitai000000000000Type-Tiny-1.008001/t#!/usr/bin/env perl use v5.014; use Path::Tiny; use Path::Iterator::Rule; use Pod::POM; use constant PROJ_NAME => 'Type-Tiny'; use constant PROJ_DIR => path(path(__FILE__)->absolute->dirname)->parent; use constant LIB_DIR => PROJ_DIR->child('lib'); use constant TEST_DIR => PROJ_DIR->child('t'); my $rule = Path::Iterator::Rule->new->file->name('*.t'); package Local::View { use parent 'Pod::POM::View::Text'; sub view_seq_link { my ($self, $link) = @_; $link =~ s/^.*?\|//; return $link; } } sub podpurpose { my $pod = Pod::POM->new->parse_file($_[0]->openr_raw); my ($purpose) = grep $_->title eq 'PURPOSE', $pod->head1; my $content = eval { $purpose->content->present('Local::View') } || "(Unknown.)"; my $trimmed = ($content =~ s/(\A\s+)|(\s+\z)//rms); $trimmed =~ s/\s+/ /g; $trimmed =~ s/"/\\"/g if $_[1]; return $trimmed; } say '@prefix : .'; MISC_TESTS: { my $iter = $rule->clone->max_depth(1)->iter( TEST_DIR ); while (my $file = $iter->()) { my $test = path($file); say "[] a :Test; :test_script f`${\ $test->relative(PROJ_DIR) } ${\ PROJ_NAME }`; :purpose \"${\ podpurpose($test,1) }\"."; } } UNIT_TESTS: { my $iter = $rule->iter( TEST_DIR->child('20-unit') ); my %mods; while (my $file = $iter->()) { my $test = path($file); my ($module) = ($test =~ m(t/20-unit/([^/]+)/)); $module =~ s{-}{::}g; push @{ $mods{$module} ||= [] }, $test; } for my $mod (sort keys %mods) { say "m`$mod ${\ PROJ_NAME }`"; for my $test (sort @{ $mods{$mod} }) { say "\t:unit_test [ a :UnitTest; :test_script f`${\ $test->relative(PROJ_DIR) } ${\ PROJ_NAME }`; :purpose \"${\ podpurpose($test,1) }\" ];"; } say "\t."; } } INTEGRATION_TESTS: { my $iter = $rule->iter( TEST_DIR->child('30-integration') ); while (my $file = $iter->()) { my $test = path($file); say "[] a :IntegrationTest; :test_script f`${\ $test->relative(PROJ_DIR) } ${\ PROJ_NAME }`; :purpose \"${\ podpurpose($test,1) }\"."; } } REGRESSION_TESTS: { my $iter = $rule->iter( TEST_DIR->child('40-regression') ); my %bugs; while (my $file = $iter->()) { my $test = path($file); if ($test =~ m/rt([0-9]+)/) { push @{ $bugs{$1} ||= [] }, $test; next; } say "[] a :RegressionTest; :test_script f`${\ $test->relative(PROJ_DIR) } ${\ PROJ_NAME }`; :purpose \"${\ podpurpose($test,1) }\"."; } for my $rt (sort { $a <=> $b } keys %bugs) { say "RT#$rt"; for my $test (@{$bugs{$rt}}) { say "\t:regression_test [ a :RegressionTest; :test_script f`${\ $test->relative(PROJ_DIR) } ${\ PROJ_NAME }`; :purpose \"${\ podpurpose($test,1) }\"];"; } say "\t."; } } not-covered.pl000644001750001750 113013601673061 15425 0ustar00taitai000000000000Type-Tiny-1.008001/t#!/usr/bin/env perl use v5.014; use Path::Tiny; use Path::Iterator::Rule; use constant LIB_DIR => path(path(__FILE__)->absolute->dirname)->parent->child('lib'); use constant TEST_DIR => path(path(__FILE__)->absolute->dirname)->parent->child('t/20-unit'); my $rule = Path::Iterator::Rule->new->file->perl_module; my $iter = $rule->iter( LIB_DIR ); while (my $file = $iter->()) { my $module = path($file)->relative(LIB_DIR); $module =~ s{.pm$}{}; $module =~ s{/}{::}g; TEST_DIR->child($module =~ s/::/-/gr)->exists or ($module =~ /^Types::Standard::/) # helper module or say $module; } benchmark-coercions.pl000644001750001750 674013601673061 23133 0ustar00taitai000000000000Type-Tiny-1.008001/examples/benchmarking=pod =encoding utf-8 =head1 PURPOSE Compares the speed of the constructor in four equivalent classes built using different tools: =over =item B L with L types and non-L coderef coercions. =item B L with L types and coercions. =item B L with L type constraints and coderef coercions. Class is made immutable. =item B L with L type constraints and coercions. Class is made immutable. =back =head1 RESULTS For both Moose and Moo, L type constraints are clearly faster than the conventional approach. B<< With Type::Tiny::XS: >> Rate Moo_MXTML Moose Moo_TT Moose_TT Moo_MXTML 3040/s -- -44% -64% -83% Moose 5463/s 80% -- -35% -69% Moo_TT 8373/s 175% 53% -- -52% Moose_TT 17612/s 479% 222% 110% -- B<< Without Type::Tiny::XS: >> Rate Moo_MXTML Moo_TT Moose Moose_TT Moo_MXTML 3140/s -- -41% -50% -63% Moo_TT 5288/s 68% -- -16% -38% Moose 6305/s 101% 19% -- -26% Moose_TT 8574/s 173% 62% 36% -- (Tested versions: Type::Tiny 0.045_03, Type::Tiny::XS 0.004, Moose 2.1207, Moo 1.005000, and MooX::Types::MooseLike 0.25.) =head1 DEPENDENCIES To run this script, you will need: L, L, L, L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Benchmark ':all'; { package Local::Moo_MXTML; use Moo; use MooX::Types::MooseLike::Base qw(HashRef ArrayRef Int is_Int); has attr1 => ( is => "ro", isa => ArrayRef[Int], coerce => sub { is_Int($_[0]) ? [ $_[0] ] : $_[0] }, ); has attr2 => ( is => "ro", isa => HashRef[ArrayRef[Int]], ); } { package Local::Moo_TT; use Moo; use Types::Standard qw(HashRef ArrayRef Int); my $AofI = (ArrayRef[Int])->plus_coercions(Int, '[$_]'); has attr1 => ( is => "ro", isa => $AofI, coerce => $AofI->coercion, ); has attr2 => ( is => "ro", isa => HashRef[ArrayRef[Int]], ); } { package Local::Moose; use Moose; use Moose::Util::TypeConstraints qw(subtype as coerce from via); subtype "AofI", as "ArrayRef[Int]"; coerce "AofI", from "Int", via { [$_] }; has attr1 => ( is => "ro", isa => "AofI", coerce => 1, ); has attr2 => ( is => "ro", isa => "HashRef[ArrayRef[Int]]", ); __PACKAGE__->meta->make_immutable; } { package Local::Moose_TT; use Moose; use Types::Standard qw(HashRef ArrayRef Int); use Sub::Quote; my $AofI = (ArrayRef[Int])->plus_coercions(Int, '[$_]'); has attr1 => ( is => "ro", isa => $AofI, coerce => 1, ); has attr2 => ( is => "ro", isa => HashRef[ArrayRef[Int]], ); __PACKAGE__->meta->make_immutable; } our %data = ( attr1 => 4, attr2 => { one => [0 .. 1], two => [0 .. 2], three => [0 .. 3], }, ); cmpthese(-1, { Moo_MXTML => q{ Local::Moo_MXTML->new(%::data) }, Moo_TT => q{ Local::Moo_TT->new(%::data) }, Moose_TT => q{ Local::Moose_TT->new(%::data) }, Moose => q{ Local::Moose->new(%::data) }, }); benchmark-constraints.pl000644001750001750 1144613601673061 23535 0ustar00taitai000000000000Type-Tiny-1.008001/examples/benchmarking=pod =encoding utf-8 =head1 PURPOSE Compares the speed of the constructor in six equivalent classes built using different tools: =over =item B L with L types. =item B L with L types. =item B L with L type constraints. Class is made immutable. =item B L with L type constraints. Class is made immutable. =item B L with L type constraints. Class is made immutable. B<< XS is switched off using C environment variable. >> =item B L with L type constraints. Class is made immutable. B<< XS is switched off using C environment variable. >> =back Each tool is used to define a class like the following: { package Local::Class; use Whatever::Tool; use Types::Standard qw(HashRef ArrayRef Int); has attr1 => (is => "ro", isa => ArrayRef[Int]); has attr2 => (is => "ro", isa => HashRef[ArrayRef[Int]]); } Then we benchmark the following object instantiation: Local::Class->new( attr1 => [1..10], attr2 => { one => [0 .. 1], two => [0 .. 2], three => [0 .. 3], }, ); =head1 RESULTS In all cases, L type constraints are clearly faster than the conventional approach. B<< With Type::Tiny::XS: >> Rate Moo_MXTML Mouse Moose Moo_TT Moose_TT Mouse_TT Moo_MXTML 2428/s -- -35% -57% -82% -90% -91% Mouse 3759/s 55% -- -33% -72% -85% -86% Moose 5607/s 131% 49% -- -58% -78% -79% Moo_TT 13274/s 447% 253% 137% -- -48% -51% Moose_TT 25358/s 945% 575% 352% 91% -- -7% Mouse_TT 27306/s 1025% 626% 387% 106% 8% -- B<< Without Type::Tiny::XS: >> Rate Moo_MXTML Mouse Moo_TT Moose Moose_TT Mouse_TT Moo_MXTML 2610/s -- -31% -56% -56% -67% -67% Mouse 3759/s 44% -- -36% -37% -52% -52% Moo_TT 5894/s 126% 57% -- -1% -24% -25% Moose 5925/s 127% 58% 1% -- -24% -25% Moose_TT 7802/s 199% 108% 32% 32% -- -1% Mouse_TT 7876/s 202% 110% 34% 33% 1% -- (Tested versions: Type::Tiny 0.045_03, Type::Tiny::XS 0.004, Moose 2.1207, Moo 1.005000, MooX::Types::MooseLike 0.25, and Mouse 2.3.0) =head1 DEPENDENCIES To run this script, you will need: L, L, L, L, L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Benchmark ':all'; BEGIN { $ENV{MOUSE_PUREPERL} = 1 }; { package Local::Moo_MXTML; use Moo; use MooX::Types::MooseLike::Base qw(HashRef ArrayRef Int); has attr1 => (is => "ro", isa => ArrayRef[Int]); has attr2 => (is => "ro", isa => HashRef[ArrayRef[Int]]); } { package Local::Moo_TT; use Moo; use Types::Standard qw(HashRef ArrayRef Int); has attr1 => (is => "ro", isa => ArrayRef[Int]); has attr2 => (is => "ro", isa => HashRef[ArrayRef[Int]]); } { package Local::Moose; use Moose; has attr1 => (is => "ro", isa => "ArrayRef[Int]"); has attr2 => (is => "ro", isa => "HashRef[ArrayRef[Int]]"); __PACKAGE__->meta->make_immutable; } { package Local::Moose_TT; use Moose; use Types::Standard qw(HashRef ArrayRef Int); has attr1 => (is => "ro", isa => ArrayRef[Int]); has attr2 => (is => "ro", isa => HashRef[ArrayRef[Int]]); __PACKAGE__->meta->make_immutable; } { package Local::Mouse; use Mouse; has attr1 => (is => "ro", isa => "ArrayRef[Int]"); has attr2 => (is => "ro", isa => "HashRef[ArrayRef[Int]]"); __PACKAGE__->meta->make_immutable; } { package Local::Mouse_TT; use Mouse; use Types::Standard qw(HashRef ArrayRef Int); has attr1 => (is => "ro", isa => ArrayRef[Int]); has attr2 => (is => "ro", isa => HashRef[ArrayRef[Int]]); __PACKAGE__->meta->make_immutable; } our %data = ( attr1 => [1..10], attr2 => { one => [0 .. 1], two => [0 .. 2], three => [0 .. 3], }, ); cmpthese(-1, { Moo_MXTML => q{ Local::Moo_MXTML->new(%::data) }, Moose => q{ Local::Moose->new(%::data) }, Mouse => q{ Local::Mouse->new(%::data) }, Moo_TT => q{ Local::Moo_TT->new(%::data) }, Moose_TT => q{ Local::Moose_TT->new(%::data) }, Mouse_TT => q{ Local::Mouse_TT->new(%::data) }, }); benchmark-named-param-validation.pl000644001750001750 776113601673061 25465 0ustar00taitai000000000000Type-Tiny-1.008001/examples/benchmarking=pod =encoding utf-8 =head1 DESCRIPTION Let's use L to see how fast L is compared with other modules for validating named parameters. (Hint: very fast.) =head1 RESULTS The results of running the script on a fairly low-powered laptop. Each parameter checking implementation is called 250,000 times. The table below displays the average time taken for each call in nanoseconds. =head2 With Type::Tiny::XS Type::Params .................................... 5079 ns (196850/s) Params::ValidateCompiler with Type::Tiny ........ 6599 ns (151515/s) Pure Perl Implementation with Ref::Util::XS ..... 7000 ns (142857/s) Naive Pure Perl Implementation .................. 7560 ns (132275/s) Data::Validator with Mouse ...................... 8440 ns (118483/s) Data::Validator with Type::Tiny ................. 9840 ns (101626/s) Params::ValidateCompiler with Moose ............. 11279 ns (88652/s) Params::ValidateCompiler with Specio ............ 11320 ns (88339/s) Data::Validator with Moose ...................... 18319 ns (54585/s) Params::Check with Type::Tiny ................... 21639 ns (46210/s) Params::Check with coderefs ..................... 28079 ns (35612/s) MooseX::Params::Validate with Moose ............. 48559 ns (20593/s) MooseX::Params::Validate with Type::Tiny ........ 54079 ns (18491/s) =head2 Without Type::Tiny::XS Pure Perl Implementation with Ref::Util::XS ..... 7120 ns (140449/s) Naive Pure Perl Implementation .................. 7520 ns (132978/s) Type::Params .................................... 7960 ns (125628/s) Data::Validator with Mouse ...................... 9000 ns (111111/s) Params::ValidateCompiler with Type::Tiny ........ 9159 ns (109170/s) Params::ValidateCompiler with Moose ............. 10159 ns (98425/s) Params::ValidateCompiler with Specio ............ 11240 ns (88967/s) Data::Validator with Type::Tiny ................. 14240 ns (70224/s) Data::Validator with Moose ...................... 18159 ns (55066/s) Params::Check with Type::Tiny ................... 22039 ns (45372/s) Params::Check with coderefs ..................... 22479 ns (44483/s) MooseX::Params::Validate with Moose ............. 42920 ns (23299/s) MooseX::Params::Validate with Type::Tiny ........ 43360 ns (23062/s) =head1 ANALYSIS Type::Params (using Type::Tiny type constraints) provides the fastest way of checking named parameters for a function, whether or not Type::Tiny::XS is available. Params::ValidationCompiler (also using Type::Tiny type constraints) is very nearly as fast. Params::ValidationCompiler using other type constraints is also quite fast, and when Type::Tiny::XS is not available, Moose and Specio constraints run almost as fast as Type::Tiny constraints. Data::Validator is acceptably fast. Params::Check is fairly slow, and MooseX::Params::Validate very slow. Type::Tiny::XS seems to slow down MooseX::Params::Validate for some strange reason. =head1 DEPENDENCIES To run this script, you will need: L, L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2017 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use v5.12; use strict; use warnings; use Benchmark qw(:hireswallclock timeit); use Benchmark::Featureset::ParamCheck 0.002; use Module::Runtime qw(use_module); my $data = 'Benchmark::Featureset::ParamCheck'->trivial_named_data; my @impl = 'Benchmark::Featureset::ParamCheck'->implementations; my $iter = 250_000; say for map { sprintf( '%s %s %6d ns (%d/s)', $_->[0]->long_name, '.' x (48 - length($_->[0]->long_name)), 1_000_000_000 * $_->[1]->cpu_a / $iter, $iter / $_->[1]->cpu_a, ); } sort { $a->[1]->cpu_a <=> $b->[1]->cpu_a; } map { my $pkg = use_module($_); [ $pkg, timeit 1, sub { $pkg->run_named_check($iter, $data) } ]; } @impl; benchmark-param-validation.pl000644001750001750 750613601673061 24400 0ustar00taitai000000000000Type-Tiny-1.008001/examples/benchmarking=pod =encoding utf-8 =head1 DESCRIPTION Let's use L to see how fast L is compared with other modules for validating positional parameters. (Hint: very fast.) =head1 RESULTS The results of running the script on a fairly low-powered laptop. Each parameter checking implementation is called 250,000 times. The table below displays the average time taken for each call in nanoseconds. =head2 With Type::Tiny::XS Type::Params .................................... 2640 ns (378787/s) Params::ValidationCompiler with Type::Tiny ...... 3120 ns (320512/s) Pure Perl Implementation with Ref::Util::XS ..... 3639 ns (274725/s) Naive Pure Perl Implementation .................. 4600 ns (217391/s) Params::ValidationCompiler with Specio .......... 11719 ns (85324/s) Params::ValidationCompiler with Moose ........... 12079 ns (82781/s) Data::Validator with Mouse ...................... 51760 ns (19319/s) Data::Validator with Type::Tiny ................. 51920 ns (19260/s) Data::Validator with Moose ...................... 52120 ns (19186/s) MooseX::Params::Validate with Moose ............. 83080 ns (12036/s) MooseX::Params::Validate with Type::Tiny ........ 84839 ns (11786/s) =head2 Without Type::Tiny::XS Pure Perl Implementation with Ref::Util::XS ..... 3560 ns (280898/s) Naive Pure Perl Implementation .................. 4479 ns (223214/s) Type::Params .................................... 7879 ns (126903/s) Params::ValidationCompiler with Type::Tiny ...... 8319 ns (120192/s) Params::ValidationCompiler with Specio .......... 11800 ns (84745/s) Params::ValidationCompiler with Moose ........... 12159 ns (82236/s) Data::Validator with Type::Tiny ................. 51039 ns (19592/s) Data::Validator with Moose ...................... 51559 ns (19394/s) Data::Validator with Mouse ...................... 51760 ns (19319/s) MooseX::Params::Validate with Type::Tiny ........ 82800 ns (12077/s) MooseX::Params::Validate with Moose ............. 93160 ns (10734/s) =head1 ANALYSIS Type::Params (using Type::Tiny type constraints) provides the fastest convenient way of checking positional parameters for a function, whether or not Type::Tiny::XS is available. The only way to beat it is to write your own type checking in longhand, but if Type::Tiny::XS is installed, you probably still won't be able to match Type::Params' speed. Params::ValidationCompiler (also using Type::Tiny type constraints) is very nearly as fast. Params::ValidationCompiler using other type constraints is also quite fast, and when Type::Tiny::XS is not available, Moose and Specio constraints run almost as fast as Type::Tiny constraints. Data::Validator and MooseX::Params::Validate are far slower. =head1 DEPENDENCIES To run this script, you will need: L, L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use v5.12; use strict; use warnings; use Benchmark qw(:hireswallclock timeit); use Benchmark::Featureset::ParamCheck 0.002; use Module::Runtime qw(use_module); my $data = 'Benchmark::Featureset::ParamCheck'->trivial_positional_data; my @impl = 'Benchmark::Featureset::ParamCheck'->implementations; my $iter = 250_000; say for map { sprintf( '%s %s %6d ns (%d/s)', $_->[0]->long_name, '.' x (48 - length($_->[0]->long_name)), 1_000_000_000 * $_->[1]->cpu_a / $iter, $iter / $_->[1]->cpu_a, ); } sort { $a->[1]->cpu_a <=> $b->[1]->cpu_a; } map { my $pkg = use_module($_); $pkg->accept_array ? [ $pkg, timeit 1, sub { $pkg->run_positional_check($iter, @$data) } ] : () } @impl; versus-scalar-validation.pl000644001750001750 400313601673061 24127 0ustar00taitai000000000000Type-Tiny-1.008001/examples/benchmarkinguse strict; use warnings; use Test::More; use Test::Fatal; use Test::Benchmark; use Benchmark qw(timethis); $Test::Benchmark::VERBOSE = 1; { package UseSV; use Scalar::Validation qw(:all); sub test { my $p_bool = par p_bool => -Enum => [0 => '1'] => shift; my $p_123 = par p_123 => -Enum => {1 => 1, 2 => 1, 3 => 1} => shift; my $p_free = par p_free => sub { $_ > 5 } => shift, sub { "$_ is not larger than 5" }; p_end \@_; return $p_bool + $p_123 + $p_free; } } { package UseTP; use Type::Params qw(compile); use Types::Standard qw(Enum); use Types::XSD::Lite qw(Integer); my $_check = compile Enum[0,1], Enum[1..3], Integer[minExclusive => 5]; sub test { my ($p_bool, $p_123, $p_free) = $_check->(@_); return $p_bool + $p_123 + $p_free; } } subtest "Scalar::Validation works ok" => sub { is( UseSV::test(1,2,7), 10 ); like( exception { UseSV::test(2,2,2) }, qr/^Error/, ); }; subtest "Type::Params works ok" => sub { is( UseTP::test(1,2,7), 10 ); like( exception { UseTP::test(2,2,2) }, qr/did not pass type constraint/, ); }; is_fastest('TP', -1, { SV => q[ UseSV::test(1,2,7) ], TP => q[ UseTP::test(1,2,7) ], }, 'Type::Params is fastest at passing validations'); is_fastest('TP', -1, { SV => q[ eval { UseSV::test(1,2,3) } ], TP => q[ eval { UseTP::test(1,2,3) } ], }, 'Type::Params is fastest at failing validations'); done_testing; __END__ # Subtest: Scalar::Validation works ok ok 1 ok 2 1..2 ok 1 - Scalar::Validation works ok # Subtest: Type::Params works ok ok 1 ok 2 1..2 ok 2 - Type::Params works ok ok 3 - Type::Params is fastest at passing validations # TP - 2 wallclock secs ( 1.17 usr + 0.00 sys = 1.17 CPU) @ 6564.10/s (n=7680) # SV - 1 wallclock secs ( 1.03 usr + 0.00 sys = 1.03 CPU) @ 4744.66/s (n=4887) ok 4 - Type::Params is fastest at failing validations # TP - 1 wallclock secs ( 1.05 usr + 0.00 sys = 1.05 CPU) @ 3412.38/s (n=3583) # SV - 1 wallclock secs ( 1.07 usr + 0.03 sys = 1.10 CPU) @ 1285.45/s (n=1414) 1..4 Fatal.pm000644001750001750 245513601673061 15470 0ustar00taitai000000000000Type-Tiny-1.008001/inc/Test#line 1 use strict; use warnings; package Test::Fatal; { $Test::Fatal::VERSION = '0.010'; } # ABSTRACT: incredibly simple helpers for testing code with exceptions use Carp (); use Try::Tiny 0.07; use base 'Exporter'; our @EXPORT = qw(exception); our @EXPORT_OK = qw(exception success dies_ok lives_ok); sub exception (&) { my $code = shift; return try { $code->(); return undef; } catch { return $_ if $_; my $problem = defined $_ ? 'false' : 'undef'; Carp::confess("$problem exception caught by Test::Fatal::exception"); }; } sub success (&;@) { my $code = shift; return finally( sub { return if @_; # <-- only run on success $code->(); }, @_ ); } my $Tester; # Signature should match that of Test::Exception sub dies_ok (&;$) { my $code = shift; my $name = shift; require Test::Builder; $Tester ||= Test::Builder->new; my $ok = $Tester->ok( exception( \&$code ), $name ); $ok or $Tester->diag( "expected an exception but none was raised" ); return $ok; } sub lives_ok (&;$) { my $code = shift; my $name = shift; require Test::Builder; $Tester ||= Test::Builder->new; my $ok = $Tester->ok( !exception( \&$code ), $name ); $ok or $Tester->diag( "expected return but an exception was raised" ); return $ok; } 1; __END__ #line 212 Requires.pm000644001750001750 337213601673061 16237 0ustar00taitai000000000000Type-Tiny-1.008001/inc/Test#line 1 package Test::Requires; use strict; use warnings; our $VERSION = '0.06'; use base 'Test::Builder::Module'; use 5.006000; sub import { my $class = shift; my $caller = caller(0); # export methods { no strict 'refs'; *{"$caller\::test_requires"} = \&test_requires; } # test arguments if (@_ == 1 && ref $_[0] && ref $_[0] eq 'HASH') { while (my ($mod, $ver) = each %{$_[0]}) { test_requires($mod, $ver, $caller); } } else { for my $mod (@_) { test_requires($mod, undef, $caller); } } } sub test_requires { my ( $mod, $ver, $caller ) = @_; return if $mod eq __PACKAGE__; if (@_ != 3) { $caller = caller(0); } $ver ||= ''; eval qq{package $caller; use $mod $ver}; ## no critic. if (my $e = $@) { my $skip_all = sub { my $builder = __PACKAGE__->builder; if (not defined $builder->has_plan) { $builder->skip_all(@_); } elsif ($builder->has_plan eq 'no_plan') { $builder->skip(@_); if ( $builder->can('parent') && $builder->parent ) { die bless {} => 'Test::Builder::Exception'; } exit 0; } else { for (1..$builder->has_plan) { $builder->skip(@_); } if ( $builder->can('parent') && $builder->parent ) { die bless {} => 'Test::Builder::Exception'; } exit 0; } }; if ( $e =~ /^Can't locate/ ) { $skip_all->("requires $mod"); } else { $skip_all->("$e"); } } } 1; __END__ #line 128 Tiny.pm000644001750001750 4332513601673061 15244 0ustar00taitai000000000000Type-Tiny-1.008001/inc/Trypackage Try::Tiny; BEGIN { $Try::Tiny::AUTHORITY = 'cpan:NUFFIN'; } $Try::Tiny::VERSION = '0.21'; use 5.006; # ABSTRACT: minimal try/catch with proper preservation of $@ use strict; use warnings; use Exporter (); our @ISA = qw( Exporter ); our @EXPORT = our @EXPORT_OK = qw(try catch finally); use Carp; $Carp::Internal{+__PACKAGE__}++; BEGIN { eval "use Sub::Name; 1" or *{subname} = sub {1} } # Need to prototype as @ not $$ because of the way Perl evaluates the prototype. # Keeping it at $$ means you only ever get 1 sub because we need to eval in a list # context & not a scalar one sub try (&;@) { my ( $try, @code_refs ) = @_; # we need to save this here, the eval block will be in scalar context due # to $failed my $wantarray = wantarray; # work around perl bug by explicitly initializing these, due to the likelyhood # this will be used in global destruction (perl rt#119311) my ( $catch, @finally ) = (); # find labeled blocks in the argument list. # catch and finally tag the blocks by blessing a scalar reference to them. foreach my $code_ref (@code_refs) { if ( ref($code_ref) eq 'Try::Tiny::Catch' ) { croak 'A try() may not be followed by multiple catch() blocks' if $catch; $catch = ${$code_ref}; } elsif ( ref($code_ref) eq 'Try::Tiny::Finally' ) { push @finally, ${$code_ref}; } else { croak( 'try() encountered an unexpected argument (' . ( defined $code_ref ? $code_ref : 'undef' ) . ') - perhaps a missing semi-colon before or' ); } } # FIXME consider using local $SIG{__DIE__} to accumulate all errors. It's # not perfect, but we could provide a list of additional errors for # $catch->(); # name the blocks if we have Sub::Name installed my $caller = caller; subname("${caller}::try {...} " => $try); subname("${caller}::catch {...} " => $catch) if $catch; subname("${caller}::finally {...} " => $_) foreach @finally; # save the value of $@ so we can set $@ back to it in the beginning of the eval # and restore $@ after the eval finishes my $prev_error = $@; my ( @ret, $error ); # failed will be true if the eval dies, because 1 will not be returned # from the eval body my $failed = not eval { $@ = $prev_error; # evaluate the try block in the correct context if ( $wantarray ) { @ret = $try->(); } elsif ( defined $wantarray ) { $ret[0] = $try->(); } else { $try->(); }; return 1; # properly set $fail to false }; # preserve the current error and reset the original value of $@ $error = $@; $@ = $prev_error; # set up a scope guard to invoke the finally block at the end my @guards = map { Try::Tiny::ScopeGuard->_new($_, $failed ? $error : ()) } @finally; # at this point $failed contains a true value if the eval died, even if some # destructor overwrote $@ as the eval was unwinding. if ( $failed ) { # if we got an error, invoke the catch block. if ( $catch ) { # This works like given($error), but is backwards compatible and # sets $_ in the dynamic scope for the body of C<$catch> for ($error) { return $catch->($error); } # in case when() was used without an explicit return, the C # loop will be aborted and there's no useful return value } return; } else { # no failure, $@ is back to what it was, everything is fine return $wantarray ? @ret : $ret[0]; } } sub catch (&;@) { my ( $block, @rest ) = @_; croak 'Useless bare catch()' unless wantarray; return ( bless(\$block, 'Try::Tiny::Catch'), @rest, ); } sub finally (&;@) { my ( $block, @rest ) = @_; croak 'Useless bare finally()' unless wantarray; return ( bless(\$block, 'Try::Tiny::Finally'), @rest, ); } { package # hide from PAUSE Try::Tiny::ScopeGuard; use constant UNSTABLE_DOLLARAT => ($] < '5.013002') ? 1 : 0; sub _new { shift; bless [ @_ ]; } sub DESTROY { my ($code, @args) = @{ $_[0] }; local $@ if UNSTABLE_DOLLARAT; eval { $code->(@args); 1; } or do { warn "Execution of finally() block $code resulted in an exception, which " . '*CAN NOT BE PROPAGATED* due to fundamental limitations of Perl. ' . 'Your program will continue as if this event never took place. ' . "Original exception text follows:\n\n" . (defined $@ ? $@ : '$@ left undefined...') . "\n" ; } } } __PACKAGE__ __END__ =pod =encoding UTF-8 =head1 NAME Try::Tiny - minimal try/catch with proper preservation of $@ =head1 VERSION version 0.21 =head1 SYNOPSIS You can use Try::Tiny's C and C to expect and handle exceptional conditions, avoiding quirks in Perl and common mistakes: # handle errors with a catch handler try { die "foo"; } catch { warn "caught error: $_"; # not $@ }; You can also use it like a standalone C to catch and ignore any error conditions. Obviously, this is an extreme measure not to be undertaken lightly: # just silence errors try { die "foo"; }; =head1 DESCRIPTION This module provides bare bones C/C/C statements that are designed to minimize common mistakes with eval blocks, and NOTHING else. This is unlike L which provides a nice syntax and avoids adding another call stack layer, and supports calling C from the C block to return from the parent subroutine. These extra features come at a cost of a few dependencies, namely L and L which are occasionally problematic, and the additional catch filtering uses L type constraints which may not be desirable either. The main focus of this module is to provide simple and reliable error handling for those having a hard time installing L, but who still want to write correct C blocks without 5 lines of boilerplate each time. It's designed to work as correctly as possible in light of the various pathological edge cases (see L) and to be compatible with any style of error values (simple strings, references, objects, overloaded objects, etc). If the C block dies, it returns the value of the last statement executed in the C block, if there is one. Otherwise, it returns C in scalar context or the empty list in list context. The following examples all assign C<"bar"> to C<$x>: my $x = try { die "foo" } catch { "bar" }; my $x = try { die "foo" } || { "bar" }; my $x = (try { die "foo" }) // { "bar" }; my $x = eval { die "foo" } || "bar"; You can add C blocks, yielding the following: my $x; try { die 'foo' } finally { $x = 'bar' }; try { die 'foo' } catch { warn "Got a die: $_" } finally { $x = 'bar' }; C blocks are always executed making them suitable for cleanup code which cannot be handled using local. You can add as many C blocks to a given C block as you like. Note that adding a C block without a preceding C block suppresses any errors. This behaviour is consistent with using a standalone C, but it is not consistent with C/C patterns found in other programming languages, such as Java, Python, Javascript or C#. If you learnt the C/C pattern from one of these languages, watch out for this. =head1 EXPORTS All functions are exported by default using L. If you need to rename the C, C or C keyword consider using L to get L's flexibility. =over 4 =item try (&;@) Takes one mandatory C subroutine, an optional C subroutine and C subroutine. The mandatory subroutine is evaluated in the context of an C block. If no error occurred the value from the first block is returned, preserving list/scalar context. If there was an error and the second subroutine was given it will be invoked with the error in C<$_> (localized) and as that block's first and only argument. C<$@> does B contain the error. Inside the C block it has the same value it had before the C block was executed. Note that the error may be false, but if that happens the C block will still be invoked. Once all execution is finished then the C block, if given, will execute. =item catch (&;@) Intended to be used in the second argument position of C. Returns a reference to the subroutine it was given but blessed as C which allows try to decode correctly what to do with this code reference. catch { ... } Inside the C block the caught error is stored in C<$_>, while previous value of C<$@> is still available for use. This value may or may not be meaningful depending on what happened before the C, but it might be a good idea to preserve it in an error stack. For code that captures C<$@> when throwing new errors (i.e. L), you'll need to do: local $@ = $_; =item finally (&;@) try { ... } catch { ... } finally { ... }; Or try { ... } finally { ... }; Or even try { ... } finally { ... } catch { ... }; Intended to be the second or third element of C. C blocks are always executed in the event of a successful C or if C is run. This allows you to locate cleanup code which cannot be done via C e.g. closing a file handle. When invoked, the C block is passed the error that was caught. If no error was caught, it is passed nothing. (Note that the C block does not localize C<$_> with the error, since unlike in a C block, there is no way to know if C<$_ == undef> implies that there were no errors.) In other words, the following code does just what you would expect: try { die_sometimes(); } catch { # ...code run in case of error } finally { if (@_) { print "The try block died with: @_\n"; } else { print "The try block ran without error.\n"; } }; B block>. C will not do anything about handling possible errors coming from code located in these blocks. Furthermore B blocks are not trappable and are unable to influence the execution of your program>. This is due to limitation of C-based scope guards, which C is implemented on top of. This may change in a future version of Try::Tiny. In the same way C blesses the code reference this subroutine does the same except it bless them as C. =back =head1 BACKGROUND There are a number of issues with C. =head2 Clobbering $@ When you run an C block and it succeeds, C<$@> will be cleared, potentially clobbering an error that is currently being caught. This causes action at a distance, clearing previous errors your caller may have not yet handled. C<$@> must be properly localized before invoking C in order to avoid this issue. More specifically, C<$@> is clobbered at the beginning of the C, which also makes it impossible to capture the previous error before you die (for instance when making exception objects with error stacks). For this reason C will actually set C<$@> to its previous value (the one available before entering the C block) in the beginning of the C block. =head2 Localizing $@ silently masks errors Inside an C block, C behaves sort of like: sub die { $@ = $_[0]; return_undef_from_eval(); } This means that if you were polite and localized C<$@> you can't die in that scope, or your error will be discarded (printing "Something's wrong" instead). The workaround is very ugly: my $error = do { local $@; eval { ... }; $@; }; ... die $error; =head2 $@ might not be a true value This code is wrong: if ( $@ ) { ... } because due to the previous caveats it may have been unset. C<$@> could also be an overloaded error object that evaluates to false, but that's asking for trouble anyway. The classic failure mode is: sub Object::DESTROY { eval { ... } } eval { my $obj = Object->new; die "foo"; }; if ( $@ ) { } In this case since C is not localizing C<$@> but still uses C, it will set C<$@> to C<"">. The destructor is called when the stack is unwound, after C sets C<$@> to C<"foo at Foo.pm line 42\n">, so by the time C is evaluated it has been cleared by C in the destructor. The workaround for this is even uglier than the previous ones. Even though we can't save the value of C<$@> from code that doesn't localize, we can at least be sure the C was aborted due to an error: my $failed = not eval { ... return 1; }; This is because an C that caught a C will always return a false value. =head1 SHINY SYNTAX Using Perl 5.10 you can use L. The C block is invoked in a topicalizer context (like a C block), but note that you can't return a useful value from C using the C blocks without an explicit C. This is somewhat similar to Perl 6's C blocks. You can use it to concisely match errors: try { require Foo; } catch { when (/^Can't locate .*?\.pm in \@INC/) { } # ignore default { die $_ } }; =head1 CAVEATS =over 4 =item * C<@_> is not available within the C block, so you need to copy your arglist. In case you want to work with argument values directly via C<@_> aliasing (i.e. allow C<$_[1] = "foo">), you need to pass C<@_> by reference: sub foo { my ( $self, @args ) = @_; try { $self->bar(@args) } } or sub bar_in_place { my $self = shift; my $args = \@_; try { $_ = $self->bar($_) for @$args } } =item * C returns from the C block, not from the parent sub (note that this is also how C works, but not how L works): sub parent_sub { try { die; } catch { return; }; say "this text WILL be displayed, even though an exception is thrown"; } Instead, you should capture the return value: sub parent_sub { my $success = try { die; 1; }; return unless $success; say "This text WILL NEVER appear!"; } # OR sub parent_sub_with_catch { my $success = try { die; 1; } catch { # do something with $_ return undef; #see note }; return unless $success; say "This text WILL NEVER appear!"; } Note that if you have a C block, it must return C for this to work, since if a C block exists, its return value is returned in place of C when an exception is thrown. =item * C introduces another caller stack frame. L is not used. L will not report this when using full stack traces, though, because C<%Carp::Internal> is used. This lack of magic is considered a feature. =item * The value of C<$_> in the C block is not guaranteed to be the value of the exception thrown (C<$@>) in the C block. There is no safe way to ensure this, since C may be used unhygenically in destructors. The only guarantee is that the C will be called if an exception is thrown. =item * The return value of the C block is not ignored, so if testing the result of the expression for truth on success, be sure to return a false value from the C block: my $obj = try { MightFail->new; } catch { ... return; # avoid returning a true value; }; return unless $obj; =item * C<$SIG{__DIE__}> is still in effect. Though it can be argued that C<$SIG{__DIE__}> should be disabled inside of C blocks, since it isn't people have grown to rely on it. Therefore in the interests of compatibility, C does not disable C<$SIG{__DIE__}> for the scope of the error throwing code. =item * Lexical C<$_> may override the one set by C. For example Perl 5.10's C form uses a lexical C<$_>, creating some confusing behavior: given ($foo) { when (...) { try { ... } catch { warn $_; # will print $foo, not the error warn $_[0]; # instead, get the error like this } } } Note that this behavior was changed once again in L. However, since the entirety of lexical C<$_> is now L, it is unclear whether the new version 18 behavior is final. =back =head1 SEE ALSO =over 4 =item L Much more feature complete, more convenient semantics, but at the cost of implementation complexity. =item L Automatic error throwing for builtin functions and more. Also designed to work well with C/C. =item L A lightweight role for rolling your own exception classes. =item L Exception object implementation with a C statement. Does not localize C<$@>. =item L Provides a C statement, but properly calling C is your responsibility. The C keyword pushes C<$@> onto an error stack, avoiding some of the issues with C<$@>, but you still need to localize to prevent clobbering. =back =head1 LIGHTNING TALK I gave a lightning talk about this module, you can see the slides (Firefox only): L Or read the source: L =head1 VERSION CONTROL L =head1 AUTHORS =over 4 =item * Yuval Kogman =item * Jesse Luehrs =back =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2014 by Yuval Kogman. This is free software, licensed under: The MIT (X11) License =cut TypeTiny.pm000644001750001750 1412513601673061 16412 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Errorpackage Error::TypeTiny; use 5.006001; use strict; use warnings; BEGIN { $Error::TypeTiny::AUTHORITY = 'cpan:TOBYINK'; $Error::TypeTiny::VERSION = '1.008001'; } $Error::TypeTiny::VERSION =~ tr/_//d; require Type::Tiny; __PACKAGE__->Type::Tiny::_install_overloads( q[""] => sub { $_[0]->to_string }, q[bool] => sub { 1 }, ); our %CarpInternal; $CarpInternal{$_}++ for qw( Types::Standard::_Stringable Exporter::Tiny Eval::TypeTiny::Sandbox Devel::TypeTiny::Perl56Compat Devel::TypeTiny::Perl58Compat Error::TypeTiny Error::TypeTiny::Assertion Error::TypeTiny::Compilation Error::TypeTiny::WrongNumberOfParameters Eval::TypeTiny Reply::Plugin::TypeTiny Test::TypeTiny Type::Coercion Type::Coercion::FromMoose Type::Coercion::Union Type::Library Type::Params Type::Parser Type::Registry Types::Common::Numeric Types::Common::String Types::Standard Types::Standard::ArrayRef Types::Standard::CycleTuple Types::Standard::Dict Types::Standard::HashRef Types::Standard::Map Types::Standard::ScalarRef Types::Standard::StrMatch Types::Standard::Tied Types::Standard::Tuple Types::TypeTiny Type::Tiny Type::Tiny::Class Type::Tiny::Duck Type::Tiny::Enum Type::Tiny::_HalfOp Type::Tiny::Intersection Type::Tiny::Role Type::Tiny::Union Type::Utils ); sub new { my $class = shift; my %params = (@_==1) ? %{$_[0]} : @_; return bless \%params, $class; } sub throw { my $class = shift; my ($level, @caller, %ctxt) = 0; while (do { my $caller = caller $level; defined $caller and $CarpInternal{$caller}; }) { $level++ }; if ( ((caller($level - 1))[1]||"") =~ /^(?:parameter validation for|exportable function) '(.+?)'$/ ) { my ($pkg, $func) = ($1 =~ m{^(.+)::(\w+)$}); $level++ if caller($level) eq ($pkg||""); } # Moo's Method::Generate::Constructor puts an eval in the stack trace, # that is useless for debugging, so show the stack frame one above. $level++ if ( (caller($level))[1] =~ /^\(eval \d+\)$/ and (caller($level))[3] eq '(eval)' # (caller())[3] is $subroutine ); @ctxt{qw/ package file line /} = caller($level); my $stack = undef; if (our $StackTrace) { require Devel::StackTrace; $stack = "Devel::StackTrace"->new( ignore_package => [ keys %CarpInternal ], ); } die( our $LastError = $class->new( context => \%ctxt, stack_trace => $stack, @_, ) ); } sub message { $_[0]{message} ||= $_[0]->_build_message }; sub context { $_[0]{context} }; sub stack_trace { $_[0]{stack_trace} }; sub to_string { my $e = shift; my $c = $e->context; my $m = $e->message; $m =~ /\n\z/s ? $m : $c ? sprintf("%s at %s line %s.\n", $m, $c->{file}||'file?', $c->{line}||'NaN') : sprintf("%s\n", $m); } sub _build_message { return 'An exception has occurred'; } sub croak { my ($fmt, @args) = @_; @_ = ( __PACKAGE__, message => sprintf($fmt, @args), ); goto \&throw; } 1; __END__ =pod =encoding utf-8 =head1 NAME Error::TypeTiny - exceptions for Type::Tiny and friends =head1 SYNOPSIS use Data::Dumper; use Try::Tiny; use Types::Standard qw(Str); try { Str->assert_valid(undef); } catch { my $exception = shift; warn "Encountered Error: $exception"; warn Dumper($exception->explain) if $exception->isa("Error::TypeTiny::Assertion"); }; =head1 STATUS This module is covered by the L. =head1 DESCRIPTION When Type::Tiny and its related modules encounter an error, they throw an exception object. These exception objects inherit from Error::TypeTiny. =head2 Constructors =over =item C<< new(%attributes) >> Moose-style constructor function. =item C<< throw(%attributes) >> Constructs an exception and passes it to C. Automatically populates C and C if appropriate. =back =head2 Attributes =over =item C The error message. =item C Hashref containing the package, file and line that generated the error. =item C A more complete stack trace. This feature requires L; use the C<< $StackTrace >> package variable to switch it on. =back =head2 Methods =over =item C Returns the message, followed by the context if it is set. =back =head2 Functions =over =item C<< Error::TypeTiny::croak($format, @args) >> Functional-style shortcut to C method. Takes an C-style format string and optional arguments to construct the C. =back =head2 Overloading =over =item * Stringification is overloaded to call C. =back =head2 Package Variables =over =item C<< %Error::TypeTiny::CarpInternal >> Serves a similar purpose to C<< %Carp::CarpInternal >>. =item C<< $Error::TypeTiny::StackTrace >> Boolean to toggle stack trace generation. =item C<< $Error::TypeTiny::LastError >> A reference to the last exception object thrown. =back =head1 CAVEATS Although Error::TypeTiny objects are thrown for errors produced by Type::Tiny, that doesn't mean every time you use Type::Tiny you'll get Error::TypeTinys whenever you want. For example, if you use a Type::Tiny type constraint in a Moose attribute, Moose will not call the constraint's C method (which throws an exception). Instead it will call C and C (which do not), and will C an error message of its own. (The C<< $LastError >> package variable may save your bacon.) =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L, L. L, L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. TypeTiny.pm000644001750001750 2644213601673061 16215 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Evalpackage Eval::TypeTiny; use strict; sub _clean_eval { local $@; local $SIG{__DIE__}; my $r = eval $_[0]; my $e = $@; return ($r, $e); } use warnings; BEGIN { *HAS_LEXICAL_SUBS = ($] >= 5.018) ? sub(){!!1} : sub(){!!0}; }; { # this is unused now and will be removed in a future version of Eval::TypeTiny my $hlv; sub HAS_LEXICAL_VARS () { $hlv = !! eval { require Devel::LexAlias; exists(&Devel::LexAlias::lexalias); } unless defined $hlv; $hlv; } } BEGIN { sub IMPLEMENTATION_DEVEL_LEXALIAS () { 'Devel::LexAlias' } sub IMPLEMENTATION_PADWALKER () { 'PadWalker' } sub IMPLEMENTATION_TIE () { 'tie' } sub IMPLEMENTATION_NATIVE () { 'perl' } my $implementation; sub ALIAS_IMPLEMENTATION () { $implementation ||= do { do { $] ge '5.022' } ? IMPLEMENTATION_NATIVE : eval { require Devel::LexAlias } ? IMPLEMENTATION_DEVEL_LEXALIAS : eval { require PadWalker } ? IMPLEMENTATION_PADWALKER : IMPLEMENTATION_TIE }; } sub _force_implementation { $implementation = shift; } } BEGIN { *_EXTENDED_TESTING = ($ENV{EXTENDED_TESTING}) ? sub(){!!1} : sub(){!!0}; }; our $AUTHORITY = 'cpan:TOBYINK'; our $VERSION = '1.008001'; our @EXPORT = qw( eval_closure ); our @EXPORT_OK = qw( HAS_LEXICAL_SUBS HAS_LEXICAL_VARS ALIAS_IMPLEMENTATION IMPLEMENTATION_DEVEL_LEXALIAS IMPLEMENTATION_PADWALKER IMPLEMENTATION_NATIVE IMPLEMENTATION_TIE ); $VERSION =~ tr/_//d; # See Types::TypeTiny for an explanation of this import method. # sub import { # uncoverable subroutine no warnings "redefine"; # uncoverable statement our @ISA = qw( Exporter::Tiny ); # uncoverable statement require Exporter::Tiny; # uncoverable statement my $next = \&Exporter::Tiny::import; # uncoverable statement *import = $next; # uncoverable statement my $class = shift; # uncoverable statement my $opts = { ref($_[0]) ? %{+shift} : () }; # uncoverable statement $opts->{into} ||= scalar(caller); # uncoverable statement return $class->$next($opts, @_); # uncoverable statement } sub eval_closure { my (%args) = @_; my $src = ref $args{source} eq "ARRAY" ? join("\n", @{$args{source}}) : $args{source}; $args{alias} = 0 unless defined $args{alias}; $args{line} = 1 unless defined $args{line}; $args{description} =~ s/[^\w .:-\[\]\(\)\{\}\']//g if defined $args{description}; $src = qq{#line $args{line} "$args{description}"\n$src} if defined $args{description} && !($^P & 0x10); $args{environment} ||= {}; if (_EXTENDED_TESTING) { require Scalar::Util; for my $k (sort keys %{$args{environment}}) { next if $k =~ /^\$/ && Scalar::Util::reftype($args{environment}{$k}) =~ /^(SCALAR|REF)$/; next if $k =~ /^\@/ && Scalar::Util::reftype($args{environment}{$k}) eq q(ARRAY); next if $k =~ /^\%/ && Scalar::Util::reftype($args{environment}{$k}) eq q(HASH); next if $k =~ /^\&/ && Scalar::Util::reftype($args{environment}{$k}) eq q(CODE); require Error::TypeTiny; Error::TypeTiny::croak("Expected a variable name and ref; got %s => %s", $k, $args{environment}{$k}); } } my $sandpkg = 'Eval::TypeTiny::Sandbox'; my $alias = exists($args{alias}) ? $args{alias} : 0; my @keys = sort keys %{$args{environment}}; my $i = 0; my $source = join "\n" => ( "package $sandpkg;", "sub {", map(_make_lexical_assignment($_, $i++, $alias), @keys), $src, "}", ); if ($alias and ALIAS_IMPLEMENTATION eq IMPLEMENTATION_TIE) { _manufacture_ties(); } my ($compiler, $e) = _clean_eval($source); if ($e) { chomp $e; require Error::TypeTiny::Compilation; "Error::TypeTiny::Compilation"->throw( code => (ref $args{source} eq "ARRAY" ? join("\n", @{$args{source}}) : $args{source}), errstr => $e, environment => $args{environment}, ); } my $code = $compiler->(@{$args{environment}}{@keys}); undef($compiler); if ($alias and ALIAS_IMPLEMENTATION eq IMPLEMENTATION_DEVEL_LEXALIAS) { require Devel::LexAlias; Devel::LexAlias::lexalias($code, $_ => $args{environment}{$_}) for grep !/^\&/, @keys; } if ($alias and ALIAS_IMPLEMENTATION eq IMPLEMENTATION_PADWALKER) { require PadWalker; my %env = map +($_ => $args{environment}{$_}), grep !/^\&/, @keys; PadWalker::set_closed_over($code, \%env); } return $code; } my $tmp; sub _make_lexical_assignment { my ($key, $index, $alias) = @_; my $name = substr($key, 1); if (HAS_LEXICAL_SUBS and $key =~ /^\&/) { $tmp++; my $tmpname = '$__LEXICAL_SUB__'.$tmp; return "no warnings 'experimental::lexical_subs';". "use feature 'lexical_subs';". "my $tmpname = \$_[$index];". "my sub $name { goto $tmpname };"; } if (!$alias) { my $sigil = substr($key, 0, 1); return "my $key = $sigil\{ \$_[$index] };"; } elsif (ALIAS_IMPLEMENTATION eq IMPLEMENTATION_NATIVE) { return "no warnings 'experimental::refaliasing';". "use feature 'refaliasing';". "my $key; \\$key = \$_[$index];" } elsif (ALIAS_IMPLEMENTATION eq IMPLEMENTATION_DEVEL_LEXALIAS) { return "my $key;"; } elsif (ALIAS_IMPLEMENTATION eq IMPLEMENTATION_PADWALKER) { return "my $key;"; } else { my $tieclass = { '@' => 'Eval::TypeTiny::_TieArray', '%' => 'Eval::TypeTiny::_TieHash', '$' => 'Eval::TypeTiny::_TieScalar', }->{ substr($key, 0, 1) }; return sprintf( 'tie(my(%s), "%s", $_[%d]);', $key, $tieclass, $index, ); } } { my $tie; sub _manufacture_ties { $tie ||= eval <<'FALLBACK'; } } no warnings qw(void once uninitialized numeric); use Type::Tiny (); { package # Eval::TypeTiny::_TieArray; require Tie::Array; our @ISA = qw( Tie::StdArray ); sub TIEARRAY { my $class = shift; bless $_[0] => $class; } sub AUTOLOAD { my $self = shift; my ($method) = (our $AUTOLOAD =~ /(\w+)$/); defined tied(@$self) and return tied(@$self)->$method(@_); require Carp; Carp::croak(qq[Can't call method "$method" on an undefined value]) unless $method eq 'DESTROY'; } sub can { my $self = shift; my $code = $self->SUPER::can(@_) || (defined tied(@$self) and tied(@$self)->can(@_)); return $code; } __PACKAGE__->Type::Tiny::_install_overloads( q[bool] => sub { !! tied @{$_[0]} }, q[""] => sub { '' . tied @{$_[0]} }, q[0+] => sub { 0 + tied @{$_[0]} }, ); } { package # Eval::TypeTiny::_TieHash; require Tie::Hash; our @ISA = qw( Tie::StdHash ); sub TIEHASH { my $class = shift; bless $_[0] => $class; } sub AUTOLOAD { my $self = shift; my ($method) = (our $AUTOLOAD =~ /(\w+)$/); defined tied(%$self) and return tied(%$self)->$method(@_); require Carp; Carp::croak(qq[Can't call method "$method" on an undefined value]) unless $method eq 'DESTROY'; } sub can { my $self = shift; my $code = $self->SUPER::can(@_) || (defined tied(%$self) and tied(%$self)->can(@_)); return $code; } __PACKAGE__->Type::Tiny::_install_overloads( q[bool] => sub { !! tied %{$_[0]} }, q[""] => sub { '' . tied %{$_[0]} }, q[0+] => sub { 0 + tied %{$_[0]} }, ); } { package # Eval::TypeTiny::_TieScalar; require Tie::Scalar; our @ISA = qw( Tie::StdScalar ); sub TIESCALAR { my $class = shift; bless $_[0] => $class; } sub AUTOLOAD { my $self = shift; my ($method) = (our $AUTOLOAD =~ /(\w+)$/); defined tied($$self) and return tied($$self)->$method(@_); require Carp; Carp::croak(qq[Can't call method "$method" on an undefined value]) unless $method eq 'DESTROY'; } sub can { my $self = shift; my $code = $self->SUPER::can(@_) || (defined tied($$self) and tied($$self)->can(@_)); return $code; } __PACKAGE__->Type::Tiny::_install_overloads( q[bool] => sub { !! tied ${$_[0]} }, q[""] => sub { '' . tied ${$_[0]} }, q[0+] => sub { 0 + tied ${$_[0]} }, ); } 1; FALLBACK 1; __END__ =pod =encoding utf-8 =for stopwords pragmas coderefs =head1 NAME Eval::TypeTiny - utility to evaluate a string of Perl code in a clean environment =head1 STATUS This module is covered by the L. =head1 DESCRIPTION This module is used by Type::Tiny to compile coderefs from strings of Perl code, and hashrefs of variables to close over. =head2 Functions This module exports one function, which works much like the similarly named function from L: =over =item C<< eval_closure(source => $source, environment => \%env, %opt) >> =back =head2 Constants The following constants may be exported, but are not by default. =over =item C<< HAS_LEXICAL_SUBS >> Boolean indicating whether Eval::TypeTiny has support for lexical subs. (This feature requires Perl 5.18.) =item C<< ALIAS_IMPLEMENTATION >> Returns a string indicating what implementation of C<< alias => 1 >> is being used. Eval::TypeTiny will automatically choose the best implementation. This constant can be matched against the C<< IMPLEMENTAION_* >> constants. =item C<< IMPLEMENTATION_NATIVE >> If C<< ALIAS_IMPLEMENTATION eq IMPLEMENTATION_NATIVE >> then Eval::TypeTiny is currently using Perl 5.22's native alias feature. This requires Perl 5.22. =item C<< IMPLEMENTATION_DEVEL_LEXALIAS >> If C<< ALIAS_IMPLEMENTATION eq IMPLEMENTATION_DEVEL_LEXALIAS >> then Eval::TypeTiny is currently using L to provide aliases. =item C<< IMPLEMENTATION_PADWALKER >> If C<< ALIAS_IMPLEMENTATION eq IMPLEMENTATION_PADWALKER >> then Eval::TypeTiny is currently using L to provide aliases. =item C<< IMPLEMENTATION_TIE >> If C<< ALIAS_IMPLEMENTATION eq IMPLEMENTATION_TIE >> then Eval::TypeTiny is using the fallback implementation of aliases using C. This is the slowest implementation, and may cause problems in certain edge cases, like trying to alias already-tied variables, but it's the only way to implement C<< alias => 1 >> without a recent version of Perl or one of the two optional modules mentioned above. =back =head1 EVALUATION ENVIRONMENT The evaluation is performed in the presence of L, but the absence of L. (This is different to L which enables warnings for compiled closures.) The L pragma is not active in the evaluation environment, so the following will not work: use feature qw(say); use Eval::TypeTiny qw(eval_closure); my $say_all = eval_closure( source => 'sub { say for @_ }', ); $say_all->("Hello", "World"); The L pragma does not "carry over" into the stringy eval. It is of course possible to import pragmas into the evaluated string as part of the string itself: use Eval::TypeTiny qw(eval_closure); my $say_all = eval_closure( source => 'sub { use feature qw(say); say for @_ }', ); $say_all->("Hello", "World"); =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L, L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. TypeTiny.pm000644001750001750 1304013601673061 16233 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Testpackage Test::TypeTiny; use strict; use warnings; use Test::More qw(); use Scalar::Util qw(blessed); use Types::TypeTiny qw(to_TypeTiny); use Type::Tiny (); require Exporter::Tiny; our @ISA = 'Exporter::Tiny'; BEGIN { *EXTENDED_TESTING = $ENV{EXTENDED_TESTING} ? sub(){!!1} : sub(){!!0}; }; our $AUTHORITY = 'cpan:TOBYINK'; our $VERSION = '1.008001'; our @EXPORT = qw( should_pass should_fail ok_subtype ); our @EXPORT_OK = qw( EXTENDED_TESTING matchfor ); $VERSION =~ tr/_//d; my $overloads_installed = 0; sub matchfor { my @matchers = @_; bless \@matchers, do { package # Test::TypeTiny::Internal::MATCHFOR; Test::TypeTiny::Internal::MATCHFOR->Type::Tiny::_install_overloads( q[==] => 'match', q[eq] => 'match', q[""] => 'to_string', ) unless $overloads_installed++; sub to_string { $_[0][0] } sub match { my ($self, $e) = @_; my $does = Scalar::Util::blessed($e) ? ($e->can('DOES') || $e->can('isa')) : undef; for my $s (@$self) { return 1 if ref($s) && $e =~ $s; return 1 if !ref($s) && $does && $e->$does($s); } return; } __PACKAGE__; }; } sub _mk_message { require Type::Tiny; my ($template, $value) = @_; sprintf($template, Type::Tiny::_dd($value)); } sub ok_subtype { my ($type, @s) = @_; @_ = ( not(scalar grep !$_->is_subtype_of($type), @s), sprintf("%s subtype: %s", $type, join q[, ], @s), ); goto \&Test::More::ok; } eval(EXTENDED_TESTING ? <<'SLOW' : <<'FAST'); sub should_pass { my ($value, $type, $message) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; $type = to_TypeTiny($type) unless blessed($type) && $type->can("check"); my $strictures = $type->can("_strict_check"); my $test = "Test::Builder"->new->child( $message || _mk_message("%s passes type constraint $type", $value), ); $test->plan(tests => ($strictures ? 2 : 1)); $test->ok(!!$type->check($value), '->check'); $test->ok(!!$type->_strict_check($value), '->_strict_check') if $strictures; $test->finalize; return $test->is_passing; } sub should_fail { my ($value, $type, $message) = @_; $type = to_TypeTiny($type) unless blessed($type) && $type->can("check"); local $Test::Builder::Level = $Test::Builder::Level + 1; my $strictures = $type->can("_strict_check"); my $test = "Test::Builder"->new->child( $message || _mk_message("%s fails type constraint $type", $value), ); $test->plan(tests => ($strictures ? 2 : 1)); $test->ok(!$type->check($value), '->check'); $test->ok(!$type->_strict_check($value), '->_strict_check') if $strictures; $test->finalize; return $test->is_passing; } SLOW sub should_pass { my ($value, $type, $message) = @_; $type = to_TypeTiny($type) unless blessed($type) && $type->can("check"); @_ = ( !!$type->check($value), $message || _mk_message("%s passes type constraint $type", $value), ); goto \&Test::More::ok; } sub should_fail { my ($value, $type, $message) = @_; $type = to_TypeTiny($type) unless blessed($type) && $type->can("check"); @_ = ( !$type->check($value), $message || _mk_message("%s fails type constraint $type", $value), ); goto \&Test::More::ok; } FAST 1; __END__ =pod =encoding utf-8 =head1 NAME Test::TypeTiny - useful functions for testing the efficacy of type constraints =head1 SYNOPSIS =for test_synopsis BEGIN { die "SKIP: uses a module that doesn't exist as an example" }; use strict; use warnings; use Test::More; use Test::TypeTiny; use Types::Mine qw(Integer Number); should_pass(1, Integer); should_pass(-1, Integer); should_pass(0, Integer); should_fail(2.5, Integer); ok_subtype(Number, Integer); done_testing; =head1 STATUS This module is covered by the L. =head1 DESCRIPTION L provides a few handy functions for testing type constraints. =head2 Functions =over =item C<< should_pass($value, $type, $test_name) >> =item C<< should_pass($value, $type) >> Test that passes iff C<< $value >> passes C<< $type->check >>. =item C<< should_fail($value, $type, $test_name) >> =item C<< should_fail($value, $type) >> Test that passes iff C<< $value >> fails C<< $type->check >>. =item C<< ok_subtype($type, @subtypes) >> Test that passes iff all C<< @subtypes >> are subtypes of C<< $type >>. =item C<< EXTENDED_TESTING >> Exportable boolean constant. =item C<< matchfor(@things) >> Assistant for matching exceptions. Not exported by default. See also L. =back =head1 ENVIRONMENT If the C environment variable is set to true, this module will promote each C or C test into a subtest block and test the type constraint in both an inlined and non-inlined manner. This variable must be set at compile time (i.e. before this module is loaded). =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. For an alternative to C, see L which will happily accept a Type::Tiny type constraint instead of a MooseX::Types one. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Coercion.pm000644001750001750 5404713601673061 16225 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Typepackage Type::Coercion; use 5.006001; use strict; use warnings; BEGIN { $Type::Coercion::AUTHORITY = 'cpan:TOBYINK'; $Type::Coercion::VERSION = '1.008001'; } $Type::Coercion::VERSION =~ tr/_//d; use Eval::TypeTiny qw<>; use Scalar::Util qw< blessed >; use Types::TypeTiny qw<>; sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } require Type::Tiny; __PACKAGE__->Type::Tiny::_install_overloads( q("") => sub { caller =~ m{^(Moo::HandleMoose|Sub::Quote)} ? $_[0]->_stringify_no_magic : $_[0]->display_name }, q(bool) => sub { 1 }, q(&{}) => "_overload_coderef", ); __PACKAGE__->Type::Tiny::_install_overloads( q(~~) => sub { $_[0]->has_coercion_for_value($_[1]) }, ) if Type::Tiny::SUPPORT_SMARTMATCH(); sub _overload_coderef { my $self = shift; if ("Sub::Quote"->can("quote_sub") && $self->can_be_inlined) { $self->{_overload_coderef} = Sub::Quote::quote_sub($self->inline_coercion('$_[0]')) if !$self->{_overload_coderef} || !$self->{_sub_quoted}++; } else { Scalar::Util::weaken(my $weak = $self); $self->{_overload_coderef} ||= sub { $weak->coerce(@_) }; } $self->{_overload_coderef}; } sub new { my $class = shift; my %params = (@_==1) ? %{$_[0]} : @_; $params{name} = '__ANON__' unless exists($params{name}); my $C = delete($params{type_coercion_map}) || []; my $F = delete($params{frozen}); my $self = bless \%params, $class; $self->add_type_coercions(@$C) if @$C; $self->_preserve_type_constraint; Scalar::Util::weaken($self->{type_constraint}); # break ref cycle $self->{frozen} = $F if $F; unless ($self->is_anon) { # First try a fast ASCII-only expression, but fall back to Unicode $self->name =~ /^_{0,2}[A-Z][A-Za-z0-9_]+$/sm or eval q( use 5.008; $self->name =~ /^_{0,2}\p{Lu}[\p{L}0-9_]+$/sm ) or _croak '"%s" is not a valid coercion name', $self->name; } return $self; } sub _stringify_no_magic { sprintf('%s=%s(0x%08x)', blessed($_[0]), Scalar::Util::reftype($_[0]), Scalar::Util::refaddr($_[0])); } sub name { $_[0]{name} } sub display_name { $_[0]{display_name} ||= $_[0]->_build_display_name } sub library { $_[0]{library} } sub type_constraint { $_[0]{type_constraint} ||= $_[0]->_maybe_restore_type_constraint } sub type_coercion_map { $_[0]{type_coercion_map} ||= [] } sub moose_coercion { $_[0]{moose_coercion} ||= $_[0]->_build_moose_coercion } sub compiled_coercion { $_[0]{compiled_coercion} ||= $_[0]->_build_compiled_coercion } sub frozen { $_[0]{frozen} ||= 0 } sub coercion_generator { $_[0]{coercion_generator} } sub parameters { $_[0]{parameters} } sub parameterized_from { $_[0]{parameterized_from} } sub has_library { exists $_[0]{library} } sub has_type_constraint { defined $_[0]->type_constraint } # sic sub has_coercion_generator { exists $_[0]{coercion_generator} } sub has_parameters { exists $_[0]{parameters} } sub _preserve_type_constraint { my $self = shift; $self->{_compiled_type_constraint_check} = $self->{type_constraint}->compiled_check if $self->{type_constraint}; } sub _maybe_restore_type_constraint { my $self = shift; if ( my $check = $self->{_compiled_type_constraint_check} ) { return Type::Tiny->new(constraint => $check); } return; # uncoverable statement } sub add { my $class = shift; my ($x, $y, $swap) = @_; Types::TypeTiny::TypeTiny->check($x) and return $x->plus_fallback_coercions($y); Types::TypeTiny::TypeTiny->check($y) and return $y->plus_coercions($x); _croak "Attempt to add $class to something that is not a $class" unless blessed($x) && blessed($y) && $x->isa($class) && $y->isa($class); ($y, $x) = ($x, $y) if $swap; my %opts; if ($x->has_type_constraint and $y->has_type_constraint and $x->type_constraint == $y->type_constraint) { $opts{type_constraint} = $x->type_constraint; } elsif ($x->has_type_constraint and $y->has_type_constraint) { # require Type::Tiny::Union; # $opts{type_constraint} = "Type::Tiny::Union"->new( # type_constraints => [ $x->type_constraint, $y->type_constraint ], # ); } $opts{display_name} ||= "$x+$y"; delete $opts{display_name} if $opts{display_name} eq '__ANON__+__ANON__'; my $new = $class->new(%opts); $new->add_type_coercions( @{$x->type_coercion_map} ); $new->add_type_coercions( @{$y->type_coercion_map} ); return $new; } sub _build_display_name { shift->name; } sub qualified_name { my $self = shift; if ($self->has_library and not $self->is_anon) { return sprintf("%s::%s", $self->library, $self->name); } return $self->name; } sub is_anon { my $self = shift; $self->name eq "__ANON__"; } sub _clear_compiled_coercion { delete $_[0]{_overload_coderef}; delete $_[0]{compiled_coercion}; } sub freeze { $_[0]{frozen} = 1; $_[0] } sub i_really_want_to_unfreeze { $_[0]{frozen} = 0; $_[0] } sub coerce { my $self = shift; return $self->compiled_coercion->(@_); } sub assert_coerce { my $self = shift; my $r = $self->coerce(@_); $self->type_constraint->assert_valid($r) if $self->has_type_constraint; return $r; } sub has_coercion_for_type { my $self = shift; my $type = Types::TypeTiny::to_TypeTiny($_[0]); return "0 but true" if $self->has_type_constraint && $type->is_a_type_of($self->type_constraint); my $c = $self->type_coercion_map; for (my $i = 0; $i <= $#$c; $i += 2) { return !!1 if $type->is_a_type_of($c->[$i]); } return; } sub has_coercion_for_value { my $self = shift; local $_ = $_[0]; return "0 but true" if $self->has_type_constraint && $self->type_constraint->check(@_); my $c = $self->type_coercion_map; for (my $i = 0; $i <= $#$c; $i += 2) { return !!1 if $c->[$i]->check(@_); } return; } sub add_type_coercions { my $self = shift; my @args = @_; _croak "Attempt to add coercion code to a Type::Coercion which has been frozen" if $self->frozen; while (@args) { my $type = Types::TypeTiny::to_TypeTiny(shift @args); if (blessed $type and my $method = $type->can('type_coercion_map')) { push @{$self->type_coercion_map}, @{$method->($type)}; } else { my $coercion = shift @args; _croak "Types must be blessed Type::Tiny objects" unless Types::TypeTiny::TypeTiny->check($type); _croak "Coercions must be code references or strings" unless Types::TypeTiny::StringLike->check($coercion) || Types::TypeTiny::CodeLike->check($coercion); push @{$self->type_coercion_map}, $type, $coercion; } } $self->_clear_compiled_coercion; return $self; } sub _build_compiled_coercion { my $self = shift; my @mishmash = @{$self->type_coercion_map}; return sub { $_[0] } unless @mishmash; if ($self->can_be_inlined) { return Eval::TypeTiny::eval_closure( source => sprintf('sub ($) { %s }', $self->inline_coercion('$_[0]')), description => sprintf("compiled coercion '%s'", $self), ); } # These arrays will be closed over. my (@types, @codes); while (@mishmash) { push @types, shift @mishmash; push @codes, shift @mishmash; } if ($self->has_type_constraint) { unshift @types, $self->type_constraint; unshift @codes, undef; } my @sub; for my $i (0..$#types) { push @sub, $types[$i]->can_be_inlined ? sprintf('if (%s)', $types[$i]->inline_check('$_[0]')) : sprintf('if ($checks[%d]->(@_))', $i); push @sub, !defined($codes[$i]) ? sprintf(' { return $_[0] }') : Types::TypeTiny::StringLike->check($codes[$i]) ? sprintf(' { local $_ = $_[0]; return scalar(%s); }', $codes[$i]) : sprintf(' { local $_ = $_[0]; return scalar($codes[%d]->(@_)) }', $i); } push @sub, 'return $_[0];'; return Eval::TypeTiny::eval_closure( source => sprintf('sub ($) { %s }', join qq[\n], @sub), description => sprintf("compiled coercion '%s'", $self), environment => { '@checks' => [ map $_->compiled_check, @types ], '@codes' => \@codes, }, ); } sub can_be_inlined { my $self = shift; return unless $self->frozen; return if $self->has_type_constraint && !$self->type_constraint->can_be_inlined; my @mishmash = @{$self->type_coercion_map}; while (@mishmash) { my ($type, $converter) = splice(@mishmash, 0, 2); return unless $type->can_be_inlined; return unless Types::TypeTiny::StringLike->check($converter); } return !!1; } sub _source_type_union { my $self = shift; my @r; push @r, $self->type_constraint if $self->has_type_constraint; my @mishmash = @{$self->type_coercion_map}; while (@mishmash) { my ($type) = splice(@mishmash, 0, 2); push @r, $type; } require Type::Tiny::Union; return "Type::Tiny::Union"->new(type_constraints => \@r, tmp => 1); } sub inline_coercion { my $self = shift; my $varname = $_[0]; _croak "This coercion cannot be inlined" unless $self->can_be_inlined; my @mishmash = @{$self->type_coercion_map}; return "($varname)" unless @mishmash; my (@types, @codes); while (@mishmash) { push @types, shift @mishmash; push @codes, shift @mishmash; } if ($self->has_type_constraint) { unshift @types, $self->type_constraint; unshift @codes, undef; } my @sub; for my $i (0..$#types) { push @sub, sprintf('(%s) ?', $types[$i]->inline_check($varname)); push @sub, (defined($codes[$i]) && ($varname eq '$_')) ? sprintf('scalar(do { %s }) :', $codes[$i]) : defined($codes[$i]) ? sprintf('scalar(do { local $_ = %s; %s }) :', $varname, $codes[$i]) : sprintf('%s :', $varname); } push @sub, "$varname"; "@sub"; } sub _build_moose_coercion { my $self = shift; my %options = (); $options{type_coercion_map} = [ $self->freeze->_codelike_type_coercion_map('moose_type') ]; $options{type_constraint} = $self->type_constraint if $self->has_type_constraint; require Moose::Meta::TypeCoercion; my $r = "Moose::Meta::TypeCoercion"->new(%options); return $r; } sub _codelike_type_coercion_map { my $self = shift; my $modifier = $_[0]; my @orig = @{ $self->type_coercion_map }; my @new; while (@orig) { my ($type, $converter) = splice(@orig, 0, 2); push @new, $modifier ? $type->$modifier : $type; if (Types::TypeTiny::CodeLike->check($converter)) { push @new, $converter; } else { push @new, Eval::TypeTiny::eval_closure( source => sprintf('sub { local $_ = $_[0]; %s }', $converter), description => sprintf("temporary compiled converter from '%s'", $type), ); } } return @new; } sub is_parameterizable { shift->has_coercion_generator; } sub is_parameterized { shift->has_parameters; } sub parameterize { my $self = shift; return $self unless @_; $self->is_parameterizable or _croak "Constraint '%s' does not accept parameters", "$self"; @_ = map Types::TypeTiny::to_TypeTiny($_), @_; return ref($self)->new( type_constraint => $self->type_constraint, type_coercion_map => [ $self->coercion_generator->($self, $self->type_constraint, @_) ], parameters => \@_, frozen => 1, parameterized_from => $self, ); } sub _reparameterize { my $self = shift; my ($target_type) = @_; $self->is_parameterized or return $self; my $parent = $self->parameterized_from; return ref($self)->new( type_constraint => $target_type, type_coercion_map => [ $parent->coercion_generator->($parent, $target_type, @{$self->parameters}) ], parameters => \@_, frozen => 1, parameterized_from => $parent, ); } sub isa { my $self = shift; if ($INC{"Moose.pm"} and blessed($self) and $_[0] eq 'Moose::Meta::TypeCoercion') { return !!1; } if ($INC{"Moose.pm"} and blessed($self) and $_[0] =~ /^(Class::MOP|MooseX?)::/) { my $r = $self->moose_coercion->isa(@_); return $r if $r; } $self->SUPER::isa(@_); } sub can { my $self = shift; my $can = $self->SUPER::can(@_); return $can if $can; if ($INC{"Moose.pm"} and blessed($self) and my $method = $self->moose_coercion->can(@_)) { return sub { $method->(shift->moose_coercion, @_) }; } return; } sub AUTOLOAD { my $self = shift; my ($m) = (our $AUTOLOAD =~ /::(\w+)$/); return if $m eq 'DESTROY'; if ($INC{"Moose.pm"} and blessed($self) and my $method = $self->moose_coercion->can($m)) { return $method->($self->moose_coercion, @_); } _croak q[Can't locate object method "%s" via package "%s"], $m, ref($self)||$self; } # Private Moose method, but Moo uses this... sub _compiled_type_coercion { my $self = shift; if (@_) { my $thing = $_[0]; if (blessed($thing) and $thing->isa("Type::Coercion")) { $self->add_type_coercions(@{$thing->type_coercion_map}); } elsif (Types::TypeTiny::CodeLike->check($thing)) { require Types::Standard; $self->add_type_coercions(Types::Standard::Any(), $thing); } } $self->compiled_coercion; } *compile_type_coercion = \&compiled_coercion; sub meta { _croak("Not really a Moose::Meta::TypeCoercion. Sorry!") } 1; __END__ =pod =encoding utf-8 =head1 NAME Type::Coercion - a set of coercions to a particular target type constraint =head1 STATUS This module is covered by the L. =head1 DESCRIPTION =head2 Constructors =over =item C<< new(%attributes) >> Moose-style constructor function. =item C<< add($c1, $c2) >> Create a Type::Coercion from two existing Type::Coercion objects. =back =head2 Attributes Attributes are named values that may be passed to the constructor. For each attribute, there is a corresponding reader method. For example: my $c = Type::Coercion->new( type_constraint => Int ); my $t = $c->type_constraint; # Int =head3 Important attributes These are the attributes you are likely to be most interested in providing when creating your own type coercions, and most interested in reading when dealing with coercion objects. =over =item C Weak reference to the target type constraint (i.e. the type constraint which the output of coercion coderefs is expected to conform to). =item C Arrayref of source-type/code pairs. =item C Boolean; default false. A frozen coercion cannot have C called upon it. =item C A name for the coercion. These need to conform to certain naming rules (they must begin with an uppercase letter and continue using only letters, digits 0-9 and underscores). Optional; if not supplied will be an anonymous coercion. =item C A name to display for the coercion when stringified. These don't have to conform to any naming rules. Optional; a default name will be calculated from the C. =item C The package name of the type library this coercion is associated with. Optional. Informational only: setting this attribute does not install the coercion into the package. =back =head3 Attributes related to parameterizable and parameterized coercions The following attributes are used for parameterized coercions, but are not fully documented because they may change in the near future: =over =item C<< coercion_generator >> =item C<< parameters >> =item C<< parameterized_from >> =back =head3 Lazy generated attributes The following attributes should not be usually passed to the constructor; unless you're doing something especially unusual, you should rely on the default lazily-built return values. =over =item C<< compiled_coercion >> Coderef to coerce a value (C<< $_[0] >>). The general point of this attribute is that you should not set it, but rely on the lazily-built default. Type::Coerce will usually generate a pretty fast coderef, inlining all type constraint checks, etc. =item C A L object equivalent to this one. Don't set this manually; rely on the default built one. =back =head2 Methods =head3 Predicate methods These methods return booleans indicating information about the coercion. They are each tightly associated with a particular attribute. (See L.) =over =item C, C Simple Moose-style predicate methods indicating the presence or absence of an attribute. =item C Returns true iff the coercion does not have a C. =back The following predicates are used for parameterized coercions, but are not fully documented because they may change in the near future: =over =item C<< has_coercion_generator >> =item C<< has_parameters >> =item C<< is_parameterizable >> =item C<< is_parameterized >> =back =head3 Coercion The following methods are used for coercing values to a type constraint: =over =item C<< coerce($value) >> Coerce the value to the target type. Returns the coerced value, or the original value if no coercion was possible. =item C<< assert_coerce($value) >> Coerce the value to the target type, and throw an exception if the result does not validate against the target type constraint. Returns the coerced value. =back =head3 Coercion code definition methods These methods all return C<< $self >> so are suitable for chaining. =over =item C<< add_type_coercions($type1, $code1, ...) >> Takes one or more pairs of L constraints and coercion code, creating an ordered list of source types and coercion codes. Coercion codes can be expressed as either a string of Perl code (this includes objects which overload stringification), or a coderef (or object that overloads coderefification). In either case, the value to be coerced is C<< $_ >>. C<< add_type_coercions($coercion_object) >> also works, and can be used to copy coercions from another type constraint: $type->coercion->add_type_coercions($othertype->coercion)->freeze; =item C<< freeze >> Sets the C attribute to true. Called automatically by L sometimes. =item C<< i_really_want_to_unfreeze >> If you really want to unfreeze a coercion, call this method. Don't call this method. It will potentially lead to subtle bugs. This method is considered unstable; future versions of Type::Tiny may alter its behaviour (e.g. to throw an exception if it has been detected that unfreezing this particular coercion will cause bugs). =back =head3 Parameterization The following method is used for parameterized coercions, but is not fully documented because it may change in the near future: =over =item C<< parameterize(@params) >> =back =head3 Type coercion introspection methods These methods allow you to determine a coercion's relationship to type constraints: =over =item C<< has_coercion_for_type($source_type) >> Returns true iff this coercion has a coercion from the source type. Returns the special string C<< "0 but true" >> if no coercion should actually be necessary for this type. (For example, if a coercion coerces to a theoretical "Number" type, there is probably no coercion necessary for values that already conform to the "Integer" type.) =item C<< has_coercion_for_value($value) >> Returns true iff the value could be coerced by this coercion. Returns the special string C<< "0 but true" >> if no coercion would be actually be necessary for this value (due to it already meeting the target type constraint). =back The C attribute provides a type constraint object for the target type constraint of the coercion. See L. =head3 Inlining methods =for stopwords uated The following methods are used to generate strings of Perl code which may be pasted into stringy Cuated subs to perform type coercions: =over =item C<< can_be_inlined >> Returns true iff the coercion can be inlined. =item C<< inline_coercion($varname) >> Much like C from L. =back =head3 Other methods =over =item C<< qualified_name >> For non-anonymous coercions that have a library, returns a qualified C<< "MyLib::MyCoercion" >> sort of name. Otherwise, returns the same as C. =item C<< isa($class) >>, C<< can($method) >>, C<< AUTOLOAD(@args) >> If Moose is loaded, then the combination of these methods is used to mock a Moose::Meta::TypeCoercion. =back The following methods exist for Moose/Mouse compatibility, but do not do anything useful. =over =item C<< compile_type_coercion >> =item C<< meta >> =back =head2 Overloading =over =item * Boolification is overloaded to always return true. =item * Coderefification is overloaded to call C. =item * On Perl 5.10.1 and above, smart match is overloaded to call C. =back Previous versions of Type::Coercion would overload the C<< + >> operator to call C. Support for this was dropped after 0.040. =head1 DIAGNOSTICS =over =item I<< Attempt to add coercion code to a Type::Coercion which has been frozen >> Type::Tiny type constraints are designed as immutable objects. Once you've created a constraint, rather than modifying it you generally create child constraints to do what you need. Type::Coercion objects, on the other hand, are mutable. Coercion routines can be added at any time during the object's lifetime. Sometimes Type::Tiny needs to freeze a Type::Coercion object to prevent this. In L and L code this is likely to happen as soon as you use a type constraint in an attribute. Workarounds: =over =item * Define as many of your coercions as possible within type libraries, not within the code that uses the type libraries. The type library will be evaluated relatively early, likely before there is any reason to freeze a coercion. =item * If you do need to add coercions to a type within application code outside the type library, instead create a subtype and add coercions to that. The C method provided by L should make this simple. =back =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. L, L, L, L. L. L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Library.pm000644001750001750 3604413601673061 16065 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Typepackage Type::Library; use 5.006001; use strict; use warnings; BEGIN { $Type::Library::AUTHORITY = 'cpan:TOBYINK'; $Type::Library::VERSION = '1.008001'; } $Type::Library::VERSION =~ tr/_//d; use Eval::TypeTiny qw< eval_closure >; use Scalar::Util qw< blessed refaddr >; use Type::Tiny; use Types::TypeTiny qw< TypeTiny to_TypeTiny >; require Exporter::Tiny; our @ISA = 'Exporter::Tiny'; BEGIN { *NICE_PROTOTYPES = ($] >= 5.014) ? sub () { !!1 } : sub () { !!0 } }; sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } { my $subname; my %already; # prevent renaming established functions sub _subname ($$) { $subname = eval { require Sub::Util } ? \&Sub::Util::set_subname : eval { require Sub::Name } ? \&Sub::Name::subname : 0 if not defined $subname; !$already{refaddr($_[1])}++ and return($subname->(@_)) if $subname; return $_[1]; } } sub _exporter_validate_opts { my $class = shift; no strict "refs"; my $into = $_[0]{into}; push @{"$into\::ISA"}, $class if $_[0]{base}; return $class->SUPER::_exporter_validate_opts(@_); } sub _exporter_expand_tag { my $class = shift; my ($name, $value, $globals) = @_; $name eq 'types' and return map [ "$_" => $value ], $class->type_names; $name eq 'is' and return map [ "is_$_" => $value ], $class->type_names; $name eq 'assert' and return map [ "assert_$_" => $value ], $class->type_names; $name eq 'to' and return map [ "to_$_" => $value ], $class->type_names; $name eq 'coercions' and return map [ "$_" => $value ], $class->coercion_names; if ($name eq 'all') { no strict "refs"; return ( map( [ "+$_" => $value ], $class->type_names, ), map( [ $_ => $value ], $class->coercion_names, @{"$class\::EXPORT"}, @{"$class\::EXPORT_OK"}, ), ); } return $class->SUPER::_exporter_expand_tag(@_); } sub _mksub { my $class = shift; my ($type, $post_method) = @_; $post_method ||= q(); my $source = $type->is_parameterizable ? sprintf( q{ sub (%s) { return $_[0]->complete($type) if ref($_[0]) eq 'Type::Tiny::_HalfOp'; my $params; $params = shift if ref($_[0]) eq q(ARRAY); my $t = $params ? $type->parameterize(@$params) : $type; @_ && wantarray ? return($t%s, @_) : return $t%s; } }, NICE_PROTOTYPES ? q(;$) : q(;@), $post_method, $post_method, ) : sprintf( q{ sub () { $type%s if $] } }, $post_method, ); return _subname( $type->qualified_name, eval_closure( source => $source, description => sprintf("exportable function '%s::%s'", $class, $type), environment => {'$type' => \$type}, ), ); } sub _exporter_permitted_regexp { my $class = shift; my $inherited = $class->SUPER::_exporter_permitted_regexp(@_); my $types = join "|", map quotemeta, sort { length($b) <=> length($a) or $a cmp $b } $class->type_names; my $coercions = join "|", map quotemeta, sort { length($b) <=> length($a) or $a cmp $b } $class->coercion_names; qr{^(?: $inherited | (?: (?:is_|to_|assert_)? (?:$types) ) | (?:$coercions) )$}xms; } sub _exporter_expand_sub { my $class = shift; my ($name, $value, $globals) = @_; if ($name =~ /^\+(.+)/ and $class->has_type($1)) { my $type = $1; my $value2 = +{%{$value||{}}}; return map $class->_exporter_expand_sub($_, $value2, $globals), $type, "is_$type", "assert_$type", "to_$type"; } my $typename = $name; my $thingy = undef; if ($name =~ /^(is|assert|to)_(.+)$/) { $thingy = $1; $typename = $2; } if (my $type = $class->get_type($typename)) { my $custom_type = 0; for my $param (qw/ of where /) { exists $value->{$param} or next; defined $value->{-as} or _croak("Parameter '-as' not supplied"); $type = $type->$param($value->{$param}); $name = $value->{-as}; ++$custom_type; } if (!defined $thingy) { my $post_method = q(); $post_method = '->mouse_type' if $globals->{mouse}; $post_method = '->moose_type' if $globals->{moose}; return ($name => $class->_mksub($type, $post_method)) if $post_method || $custom_type; } elsif ($thingy eq 'is') { return ($value->{-as} || "is_$typename" => $type->compiled_check) if $custom_type; } elsif ($thingy eq 'assert') { return ($value->{-as} || "assert_$typename" => $type->_overload_coderef) if $custom_type; } elsif ($thingy eq 'to') { my $to_type = $type->has_coercion && $type->coercion->frozen ? $type->coercion->compiled_coercion : sub ($) { $type->coerce($_[0]) }; return ($value->{-as} || "to_$typename" => $to_type) if $custom_type; } } return $class->SUPER::_exporter_expand_sub(@_); } sub _exporter_install_sub { my $class = shift; my ($name, $value, $globals, $sym) = @_; my $package = $globals->{into}; my $type = $class->get_type($name); Exporter::Tiny::_carp( "Exporting deprecated type %s to %s", $type->qualified_name, ref($package) ? "reference" : "package $package", ) if (defined $type and $type->deprecated and not $globals->{allow_deprecated}); if (!ref $package and defined $type) { my ($prefix) = grep defined, $value->{-prefix}, $globals->{prefix}, q(); my ($suffix) = grep defined, $value->{-suffix}, $globals->{suffix}, q(); my $as = $prefix . ($value->{-as} || $name) . $suffix; $INC{'Type/Registry.pm'} ? 'Type::Registry'->for_class($package)->add_type($type, $as) : ($Type::Registry::DELAYED{$package}{$as} = $type); } $class->SUPER::_exporter_install_sub(@_); } sub _exporter_fail { my $class = shift; my ($name, $value, $globals) = @_; my $into = $globals->{into} or _croak("Parameter 'into' not supplied"); if ($globals->{declare}) { my $declared = sub (;$) { my $params; $params = shift if ref($_[0]) eq "ARRAY"; my $type = $into->get_type($name); unless ($type) { _croak "Cannot parameterize a non-existant type" if $params; $type = $name; } my $t = $params ? $type->parameterize(@$params) : $type; @_ && wantarray ? return($t, @_) : return $t; }; return( $name, _subname( "$class\::$name", NICE_PROTOTYPES ? sub (;$) { goto $declared } : sub (;@) { goto $declared }, ), ); } return $class->SUPER::_exporter_fail(@_); } sub meta { no strict "refs"; no warnings "once"; return $_[0] if blessed $_[0]; ${"$_[0]\::META"} ||= bless {}, $_[0]; } sub add_type { my $meta = shift->meta; my $class = blessed($meta); my $type = ref($_[0]) =~ /^Type::Tiny\b/ ? $_[0] : blessed($_[0]) ? to_TypeTiny($_[0]) : ref($_[0]) eq q(HASH) ? "Type::Tiny"->new(library => $class, %{$_[0]}) : "Type::Tiny"->new(library => $class, @_); my $name = $type->{name}; $meta->{types} ||= {}; _croak 'Type %s already exists in this library', $name if $meta->has_type($name); _croak 'Type %s conflicts with coercion of same name', $name if $meta->has_coercion($name); _croak 'Cannot add anonymous type to a library' if $type->is_anon; $meta->{types}{$name} = $type; no strict "refs"; no warnings "redefine", "prototype"; my $to_type = $type->has_coercion && $type->coercion->frozen ? $type->coercion->compiled_coercion : sub ($) { $type->coerce($_[0]) }; *{"$class\::$name"} = $class->_mksub($type); *{"$class\::is_$name"} = _subname "$class\::is_$name", $type->compiled_check; *{"$class\::to_$name"} = _subname "$class\::to_$name", $to_type; *{"$class\::assert_$name"} = _subname "$class\::assert_$name", $type->_overload_coderef; return $type; } sub get_type { my $meta = shift->meta; $meta->{types}{$_[0]}; } sub has_type { my $meta = shift->meta; exists $meta->{types}{$_[0]}; } sub type_names { my $meta = shift->meta; keys %{ $meta->{types} }; } sub add_coercion { require Type::Coercion; my $meta = shift->meta; my $c = blessed($_[0]) ? $_[0] : "Type::Coercion"->new(@_); my $name = $c->name; $meta->{coercions} ||= {}; _croak 'Coercion %s already exists in this library', $name if $meta->has_coercion($name); _croak 'Coercion %s conflicts with type of same name', $name if $meta->has_type($name); _croak 'Cannot add anonymous type to a library' if $c->is_anon; $meta->{coercions}{$name} = $c; no strict "refs"; no warnings "redefine", "prototype"; my $class = blessed($meta); *{"$class\::$name"} = $class->_mksub($c); return $c; } sub get_coercion { my $meta = shift->meta; $meta->{coercions}{$_[0]}; } sub has_coercion { my $meta = shift->meta; exists $meta->{coercions}{$_[0]}; } sub coercion_names { my $meta = shift->meta; keys %{ $meta->{coercions} }; } sub make_immutable { my $meta = shift->meta; my $class = ref($meta); for my $type (values %{$meta->{types}}) { $type->coercion->freeze; no strict "refs"; no warnings "redefine", "prototype"; my $to_type = $type->has_coercion && $type->coercion->frozen ? $type->coercion->compiled_coercion : sub ($) { $type->coerce($_[0]) }; my $name = $type->name; *{"$class\::to_$name"} = _subname "$class\::to_$name", $to_type; } 1; } 1; __END__ =pod =encoding utf-8 =for stopwords Moo(se)-compatible MooseX::Types-like =head1 NAME Type::Library - tiny, yet Moo(se)-compatible type libraries =head1 SYNOPSIS =for test_synopsis BEGIN { die "SKIP: crams multiple modules into single example" }; package Types::Mine { use Scalar::Util qw(looks_like_number); use Type::Library -base; use Type::Tiny; my $NUM = "Type::Tiny"->new( name => "Number", constraint => sub { looks_like_number($_) }, message => sub { "$_ ain't a number" }, ); __PACKAGE__->meta->add_type($NUM); __PACKAGE__->meta->make_immutable; } package Ermintrude { use Moo; use Types::Mine qw(Number); has favourite_number => (is => "ro", isa => Number); } package Bullwinkle { use Moose; use Types::Mine qw(Number); has favourite_number => (is => "ro", isa => Number); } package Maisy { use Mouse; use Types::Mine qw(Number); has favourite_number => (is => "ro", isa => Number); } =head1 STATUS This module is covered by the L. =head1 DESCRIPTION L is a tiny class for creating MooseX::Types-like type libraries which are compatible with Moo, Moose and Mouse. If you're reading this because you want to create a type library, then you're probably better off reading L. =head2 Methods A type library is a singleton class. Use the C method to get a blessed object which other methods can get called on. For example: Types::Mine->meta->add_type($foo); =begin trustme =item meta =end trustme =over =item C<< add_type($type) >> or C<< add_type(%opts) >> Add a type to the library. If C<< %opts >> is given, then this method calls C<< Type::Tiny->new(%opts) >> first, and adds the resultant type. Adding a type named "Foo" to the library will automatically define four functions in the library's namespace: =over =item C<< Foo >> Returns the Type::Tiny object. =item C<< is_Foo($value) >> Returns true iff $value passes the type constraint. =item C<< assert_Foo($value) >> Returns $value iff $value passes the type constraint. Dies otherwise. =item C<< to_Foo($value) >> Coerces the value to the type. =back =item C<< get_type($name) >> Gets the C object corresponding to the name. =item C<< has_type($name) >> Boolean; returns true if the type exists in the library. =item C<< type_names >> List all types defined by the library. =item C<< add_coercion($c) >> or C<< add_coercion(%opts) >> Add a standalone coercion to the library. If C<< %opts >> is given, then this method calls C<< Type::Coercion->new(%opts) >> first, and adds the resultant coercion. Adding a coercion named "FooFromBar" to the library will automatically define a function in the library's namespace: =over =item C<< FooFromBar >> Returns the Type::Coercion object. =back =item C<< get_coercion($name) >> Gets the C object corresponding to the name. =item C<< has_coercion($name) >> Boolean; returns true if the coercion exists in the library. =item C<< coercion_names >> List all standalone coercions defined by the library. =item C<< import(@args) >> Type::Library-based libraries are exporters. =item C<< make_immutable >> A shortcut for calling C<< $type->coercion->freeze >> on every type constraint in the library. =back =head2 Constants =over =item C<< NICE_PROTOTYPES >> If this is true, then Type::Library will give parameterizable type constraints slightly the nicer prototype of C<< (;$) >> instead of the default C<< (;@) >>. This allows constructs like: ArrayRef[Int] | HashRef[Int] ... to "just work". =back =head2 Export Type libraries are exporters. For the purposes of the following examples, assume that the C library defines types C and C. # Exports nothing. # use Types::Mine; # Exports a function "String" which is a constant returning # the String type constraint. # use Types::Mine qw( String ); # Exports both String and Number as above. # use Types::Mine qw( String Number ); # Same. # use Types::Mine qw( :types ); # Exports "coerce_String" and "coerce_Number", as well as any other # coercions # use Types::Mine qw( :coercions ); # Exports a sub "is_String" so that "is_String($foo)" is equivalent # to "String->check($foo)". # use Types::Mine qw( is_String ); # Exports "is_String" and "is_Number". # use Types::Mine qw( :is ); # Exports a sub "assert_String" so that "assert_String($foo)" is # equivalent to "String->assert_return($foo)". # use Types::Mine qw( assert_String ); # Exports "assert_String" and "assert_Number". # use Types::Mine qw( :assert ); # Exports a sub "to_String" so that "to_String($foo)" is equivalent # to "String->coerce($foo)". # use Types::Mine qw( to_String ); # Exports "to_String" and "to_Number". # use Types::Mine qw( :to ); # Exports "String", "is_String", "assert_String" and "coerce_String". # use Types::Mine qw( +String ); # Exports everything. # use Types::Mine qw( :all ); Type libraries automatically inherit from L; see the documentation of that module for tips and tricks importing from libraries. =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. L, L, L, L. L, L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Params.pm000644001750001750 11711113601673061 15717 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Typepackage Type::Params; use 5.006001; use strict; use warnings; BEGIN { if ($] < 5.008) { require Devel::TypeTiny::Perl56Compat }; } BEGIN { $Type::Params::AUTHORITY = 'cpan:TOBYINK'; $Type::Params::VERSION = '1.008001'; } $Type::Params::VERSION =~ tr/_//d; use B qw(); use Eval::TypeTiny; use Scalar::Util qw(refaddr); use Error::TypeTiny; use Error::TypeTiny::Assertion; use Error::TypeTiny::WrongNumberOfParameters; use Types::Standard -types; use Types::TypeTiny qw(CodeLike TypeTiny ArrayLike StringLike to_TypeTiny); require Exporter::Tiny; our @ISA = 'Exporter::Tiny'; our @EXPORT = qw( compile compile_named ); our @EXPORT_OK = qw( multisig validate validate_named compile_named_oo Invocant wrap_subs wrap_methods ); sub english_list { require Type::Utils; goto \&Type::Utils::english_list; } my $QUOTE = ($^V < 5.010 && exists(&B::cstring)) ? \&B::cstring : \&B::perlstring; # is buggy on Perl 5.8 { my $Invocant; sub Invocant () { $Invocant ||= do { require Type::Tiny::Union; require Types::Standard; 'Type::Tiny::Union'->new( name => 'Invocant', type_constraints => [ Types::Standard::Object(), Types::Standard::ClassName(), ], ); }; } } sub _mkslurpy { my ($name, $type, $tc, $i) = @_; $name = 'local $_' if $name eq '$_'; $type eq '@' ? sprintf( '%s = [ @_[%d..$#_] ];', $name, $i, ) : sprintf( '%s = (@_==%d and ref $_[%d] eq "HASH") ? +{ %%{$_[%d]} } : (($#_-%d)%%2)==0 ? "Error::TypeTiny::WrongNumberOfParameters"->throw(message => sprintf("Odd number of elements in %%s", %s)) : +{ @_[%d..$#_] };', $name, $i + 1, $i, $i, $i, $QUOTE->("$tc"), $i, ); } sub _mkdefault { my $param_options = shift; my $default; if (exists $param_options->{default}) { $default = $param_options->{default}; if (ArrayRef->check($default) and not @$default) { $default = '[]'; } elsif (HashRef->check($default) and not %$default) { $default = '{}'; } elsif (Str->check($default)) { $default = $QUOTE->($default); } elsif (Undef->check($default)) { $default = 'undef'; } elsif (not CodeLike->check($default)) { Error::TypeTiny::croak("Default expected to be string, coderef, undef, or reference to an empty hash or array"); } } $default; } sub compile { my (@code, %env); push @code, '#placeholder', '#placeholder'; # @code[0,1] my %options; while (ref($_[0]) eq "HASH" && !$_[0]{slurpy}) { %options = (%options, %{+shift}); } my $arg = -1; my $saw_slurpy = 0; my $min_args = 0; my $max_args = 0; my $saw_opt = 0; my $return_default_list = !!1; $code[0] = 'my (%tmp, $tmp);'; PARAM: for my $param (@_) { if (HashRef->check($param)) { $code[0] = 'my (@R, %tmp, $tmp, $dtmp);'; $return_default_list = !!0; last PARAM; } elsif (not Bool->check($param)) { if ($param->has_coercion) { $code[0] = 'my (@R, %tmp, $tmp, $dtmp);'; $return_default_list = !!0; last PARAM; } } } my @default_indices; my @default_values; while (@_) { ++$arg; my $constraint = shift; my $is_optional; my $really_optional; my $is_slurpy; my $varname; my $param_options = {}; $param_options = shift if HashRef->check($_[0]) && !exists $_[0]{slurpy}; my $default = _mkdefault($param_options); if ($param_options->{optional} or defined $default) { $is_optional = 1; } if (Bool->check($constraint)) { $constraint = $constraint ? Any : Optional[Any]; } if (HashRef->check($constraint) and exists $constraint->{slurpy}) { $constraint = to_TypeTiny( $constraint->{slurpy} or Error::TypeTiny::croak("Slurpy parameter malformed") ); push @code, $constraint->is_a_type_of(Dict) ? _mkslurpy('$_', '%', $constraint => $arg) : $constraint->is_a_type_of(Map) ? _mkslurpy('$_', '%', $constraint => $arg) : $constraint->is_a_type_of(Tuple) ? _mkslurpy('$_', '@', $constraint => $arg) : $constraint->is_a_type_of(HashRef) ? _mkslurpy('$_', '%', $constraint => $arg) : $constraint->is_a_type_of(ArrayRef) ? _mkslurpy('$_', '@', $constraint => $arg) : Error::TypeTiny::croak("Slurpy parameter not of type HashRef or ArrayRef"); $varname = '$_'; $is_slurpy++; $saw_slurpy++; } else { Error::TypeTiny::croak("Parameter following slurpy parameter") if $saw_slurpy; $is_optional += grep $_->{uniq} == Optional->{uniq}, $constraint->parents; $really_optional = $is_optional && $constraint->parent && $constraint->parent->{uniq} eq Optional->{uniq} && $constraint->type_parameter; if (ref $default) { $env{'@default'}[$arg] = $default; push @code, sprintf( '$dtmp = ($#_ < %d) ? $default[%d]->() : $_[%d];', $arg, $arg, $arg, ); $saw_opt++; $max_args++; $varname = '$dtmp'; } elsif (defined $default) { push @code, sprintf( '$dtmp = ($#_ < %d) ? %s : $_[%d];', $arg, $default, $arg, ); $saw_opt++; $max_args++; $varname = '$dtmp'; } elsif ($is_optional) { push @code, sprintf( 'return %s if $#_ < %d;', $return_default_list ? '@_' : '@R', $arg, ); $saw_opt++; $max_args++; $varname = sprintf '$_[%d]', $arg; } else { Error::TypeTiny::croak("Non-Optional parameter following Optional parameter") if $saw_opt; $min_args++; $max_args++; $varname = sprintf '$_[%d]', $arg; } } if ($constraint->has_coercion and $constraint->coercion->can_be_inlined) { push @code, sprintf( '$tmp%s = %s;', ($is_optional ? '{x}' : ''), $constraint->coercion->inline_coercion($varname) ); $varname = '$tmp'.($is_optional ? '{x}' : ''); } elsif ($constraint->has_coercion) { $env{'@coerce'}[$arg] = $constraint->coercion->compiled_coercion; push @code, sprintf( '$tmp%s = $coerce[%d]->(%s);', ($is_optional ? '{x}' : ''), $arg, $varname, ); $varname = '$tmp'.($is_optional ? '{x}' : ''); } # unweaken the constraint in the cache undef $Type::Tiny::ALL_TYPES{ $constraint->{uniq} }; $Type::Tiny::ALL_TYPES{ $constraint->{uniq} } = $constraint; if ($constraint->can_be_inlined) { push @code, sprintf( '(%s) or Type::Tiny::_failed_check(%d, %s, %s, varname => %s);', $really_optional ? $constraint->type_parameter->inline_check($varname) : $constraint->inline_check($varname), $constraint->{uniq}, $QUOTE->($constraint), $varname, $is_slurpy ? 'q{$SLURPY}' : sprintf('q{$_[%d]}', $arg), ); } else { $env{'@check'}[$arg] = $really_optional ? $constraint->type_parameter->compiled_check : $constraint->compiled_check; push @code, sprintf( '%s or Type::Tiny::_failed_check(%d, %s, %s, varname => %s);', sprintf(sprintf '$check[%d]->(%s)', $arg, $varname), $constraint->{uniq}, $QUOTE->($constraint), $varname, $is_slurpy ? 'q{$SLURPY}' : sprintf('q{$_[%d]}', $arg), ); } unless ($return_default_list) { push @code, sprintf 'push @R, %s;', $varname; } } if ($min_args == $max_args and not $saw_slurpy) { $code[1] = sprintf( '"Error::TypeTiny::WrongNumberOfParameters"->throw(got => scalar(@_), minimum => %d, maximum => %d) if @_ != %d;', $min_args, $max_args, $min_args, ); } elsif ($min_args < $max_args and not $saw_slurpy) { $code[1] = sprintf( '"Error::TypeTiny::WrongNumberOfParameters"->throw(got => scalar(@_), minimum => %d, maximum => %d) if @_ < %d || @_ > %d;', $min_args, $max_args, $min_args, $max_args, ); } elsif ($min_args and $saw_slurpy) { $code[1] = sprintf( '"Error::TypeTiny::WrongNumberOfParameters"->throw(got => scalar(@_), minimum => %d) if @_ < %d;', $min_args, $min_args, ); } if ($return_default_list) { push @code, '@_;'; } else { push @code, '@R;'; } my $source = "sub { no warnings; ".join("\n", @code)." };"; return $source if $options{want_source}; my $closure = eval_closure( source => $source, description => $options{description}||sprintf("parameter validation for '%s'", $options{subname}||[caller(1+($options{caller_level}||0))]->[3] || '__ANON__'), environment => \%env, ); return { min_args => $min_args, max_args => $saw_slurpy ? undef : $max_args, closure => $closure, source => $source, environment => \%env, } if $options{want_details}; return $closure; } sub compile_named { my (@code, %env); @code = 'my (%R, %tmp, $tmp);'; push @code, '#placeholder'; # $code[1] my %options; while (ref($_[0]) eq "HASH" && !$_[0]{slurpy}) { %options = (%options, %{+shift}); } my $arg = -1; my $had_slurpy; push @code, 'my %in = ((@_==1) && ref($_[0]) eq "HASH") ? %{$_[0]} : (@_ % 2) ? "Error::TypeTiny::WrongNumberOfParameters"->throw(message => "Odd number of elements in hash") : @_;'; my @names; while (@_) { ++$arg; my ($name, $constraint) = splice(@_, 0, 2); push @names, $name; my $is_optional; my $really_optional; my $is_slurpy; my $varname; my $default; Str->check($name) or Error::TypeTiny::croak("Expected parameter name as string, got $name"); my $param_options = {}; $param_options = shift @_ if HashRef->check($_[0]) && !exists $_[0]{slurpy}; $default = _mkdefault($param_options); if ($param_options->{optional} or defined $default) { $is_optional = 1; } if (Bool->check($constraint)) { $constraint = $constraint ? Any : Optional[Any]; } if (HashRef->check($constraint) and exists $constraint->{slurpy}) { $constraint = to_TypeTiny($constraint->{slurpy}); ++$is_slurpy; ++$had_slurpy; } else { $is_optional += grep $_->{uniq} == Optional->{uniq}, $constraint->parents; $really_optional = $is_optional && $constraint->parent && $constraint->parent->{uniq} eq Optional->{uniq} && $constraint->type_parameter; $constraint = $constraint->type_parameter if $really_optional; } if (ref $default) { $env{'@default'}[$arg] = $default; push @code, sprintf( 'exists($in{%s}) or $in{%s} = $default[%d]->();', $QUOTE->($name), $QUOTE->($name), $arg, ); } elsif (defined $default) { push @code, sprintf( 'exists($in{%s}) or $in{%s} = %s;', $QUOTE->($name), $QUOTE->($name), $default, ); } elsif (not $is_optional||$is_slurpy) { push @code, sprintf( 'exists($in{%s}) or "Error::TypeTiny::WrongNumberOfParameters"->throw(message => sprintf "Missing required parameter: %%s", %s);', $QUOTE->($name), $QUOTE->($name), ); } my $need_to_close_if = 0; if ($is_slurpy) { $varname = '\\%in'; } elsif ($is_optional) { push @code, sprintf('if (exists($in{%s})) {', $QUOTE->($name)); push @code, sprintf('$tmp = delete($in{%s});', $QUOTE->($name)); $varname = '$tmp'; ++$need_to_close_if; } else { push @code, sprintf('$tmp = delete($in{%s});', $QUOTE->($name)); $varname = '$tmp'; } if ($constraint->has_coercion) { if ($constraint->coercion->can_be_inlined) { push @code, sprintf( '$tmp = %s;', $constraint->coercion->inline_coercion($varname) ); } else { $env{'@coerce'}[$arg] = $constraint->coercion->compiled_coercion; push @code, sprintf( '$tmp = $coerce[%d]->(%s);', $arg, $varname, ); } $varname = '$tmp'; } if ($constraint->can_be_inlined) { push @code, sprintf( '(%s) or Type::Tiny::_failed_check(%d, %s, %s, varname => %s);', $constraint->inline_check($varname), $constraint->{uniq}, $QUOTE->($constraint), $varname, $is_slurpy ? 'q{$SLURPY}' : sprintf('q{$_{%s}}', $QUOTE->($name)), ); } else { $env{'@check'}[$arg] = $constraint->compiled_check; push @code, sprintf( '%s or Type::Tiny::_failed_check(%d, %s, %s, varname => %s);', sprintf(sprintf '$check[%d]->(%s)', $arg, $varname), $constraint->{uniq}, $QUOTE->($constraint), $varname, $is_slurpy ? 'q{$SLURPY}' : sprintf('q{$_{%s}}', $QUOTE->($name)), ); } push @code, sprintf('$R{%s} = %s;', $QUOTE->($name), $varname); push @code, '}' if $need_to_close_if; } if (!$had_slurpy) { push @code, 'keys(%in) and "Error::TypeTiny"->throw(message => sprintf "Unrecognized parameter%s: %s", keys(%in)>1?"s":"", Type::Params::english_list(sort keys %in));' } if ($options{named_to_list}) { Error::TypeTiny::croak("named_to_list option cannot be used with slurpy") if $had_slurpy; my @order = ref $options{named_to_list} ? @{$options{named_to_list}} : @names; push @code, sprintf('@R{%s}', join ",", map $QUOTE->($_), @order); } elsif ($options{bless}) { push @code, sprintf('bless \\%%R, %s;', $QUOTE->($options{bless})); } elsif (ArrayRef->check($options{class})) { push @code, sprintf('(%s)->%s(\\%%R);', $QUOTE->($options{class}[0]), $options{class}[1]||'new'); } elsif ($options{class}) { push @code, sprintf('(%s)->%s(\\%%R);', $QUOTE->($options{class}), $options{constructor}||'new'); } else { push @code, '\\%R;'; } my $source = "sub { no warnings; ".join("\n", @code)." };"; return $source if $options{want_source}; my $closure = eval_closure( source => $source, description => $options{description}||sprintf("parameter validation for '%s'", $options{subname}||[caller(1+($options{caller_level}||0))]->[3] || '__ANON__'), environment => \%env, ); return { min_args => undef, # always going to be 1 or 0 max_args => undef, # should be possible to figure out if no slurpy param closure => $closure, source => $source, environment => \%env, } if $options{want_details}; return $closure; } my %klasses; my $kls_id = 0; my $has_cxsa; my $want_cxsa; sub _mkklass { my $klass = sprintf('%s::OO::Klass%d', __PACKAGE__, ++$kls_id); if (!defined $has_cxsa or !defined $want_cxsa) { $has_cxsa = !! eval { require Class::XSAccessor; 'Class::XSAccessor'->VERSION('1.17'); # exists_predicates, June 2013 1; }; $want_cxsa = $ENV{PERL_TYPE_PARAMS_XS} ? 'XS' : exists($ENV{PERL_TYPE_PARAMS_XS}) ? 'PP' : $has_cxsa ? 'XS' : 'PP'; if ($want_cxsa eq 'XS' and not $has_cxsa) { Error::TypeTiny::croak("Cannot load Class::XSAccessor"); # uncoverable statement } } if ($want_cxsa eq 'XS') { eval { 'Class::XSAccessor'->import( redefine => 1, class => $klass, getters => { map { defined($_->{getter}) ? ($_->{getter} => $_->{slot}) : () } values %{$_[0]} }, exists_predicates => { map { defined($_->{predicate}) ? ($_->{predicate} => $_->{slot}) : () } values %{$_[0]} }, ); 1; } ? return($klass) : die($@); } for my $attr (values %{$_[0]}) { defined($attr->{getter}) and eval sprintf( 'package %s; sub %s { $_[0]{%s} }; 1', $klass, $attr->{getter}, $attr->{slot}, ) || die($@); defined($attr->{predicate}) and eval sprintf( 'package %s; sub %s { exists $_[0]{%s} }; 1', $klass, $attr->{predicate}, $attr->{slot}, ) || die($@); } $klass; } sub compile_named_oo { my %options; while (ref($_[0]) eq "HASH" && !$_[0]{slurpy}) { %options = (%options, %{+shift}); } my @rest = @_; my %attribs; while (@_) { my ($name, $type) = splice(@_, 0, 2); my $opts = (HashRef->check($_[0]) && !exists $_[0]{slurpy}) ? shift(@_) : {}; my $is_optional = 0+!! $opts->{optional}; $is_optional += grep $_->{uniq} == Optional->{uniq}, $type->parents; my $getter = exists($opts->{getter}) ? $opts->{getter} : $name; Error::TypeTiny::croak("Bad accessor name: $getter") unless $getter =~ /\A[A-Za-z][A-Za-z0-9_]*\z/; my $predicate = exists($opts->{predicate}) ? ($opts->{predicate} eq '1' ? "has_$getter" : $opts->{predicate} eq '0' ? undef : $opts->{predicate}) : ($is_optional ? "has_$getter" : undef); $attribs{$name} = { slot => $name, getter => $getter, predicate => $predicate, }; } my $kls = join '//', map sprintf('%s*%s*%s', $attribs{$_}{slot}, $attribs{$_}{getter}, $attribs{$_}{predicate}||'0'), sort keys %attribs; $klasses{$kls} ||= _mkklass(\%attribs); compile_named({ %options, bless => $klasses{$kls} }, @rest); } # Would be faster to inline this into validate and validate_named, but # that would complicate them. :/ sub _mk_key { local $_; join ':', map { HashRef->check($_) ? do { my %h = %$_; sprintf('{%s}', _mk_key(map {; $_ => $h{$_} } sort keys %h)) } : TypeTiny->check($_) ? sprintf('TYPE=%s', $_->{uniq}) : Ref->check($_) ? sprintf('REF=%s', refaddr($_)) : Undef->check($_) ? sprintf('UNDEF') : $QUOTE->($_) } @_; } my %compiled; sub validate { my $arg = shift; my $sub = ($compiled{_mk_key(@_)} ||= compile( { caller_level => 1, %{ref($_[0])eq'HASH'?shift(@_):+{}} }, @_, )); @_ = @$arg; goto $sub; } my %compiled_named; sub validate_named { my $arg = shift; my $sub = ($compiled_named{_mk_key(@_)} ||= compile_named( { caller_level => 1, %{ref($_[0])eq'HASH'?shift(@_):+{}} }, @_, )); @_ = @$arg; goto $sub; } sub multisig { my %options = (ref($_[0]) eq "HASH" && !$_[0]{slurpy}) ? %{+shift} : (); $options{message} ||= "Parameter validation failed"; $options{description} ||= sprintf("parameter validation for '%s'", [caller(1+($options{caller_level}||0))]->[3] || '__ANON__'); for my $key ( qw[ message description ] ) { StringLike->check($options{$key}) or Error::TypeTiny::croak("Option '$key' expected to be string or stringifiable object"); } my @multi = map { CodeLike->check($_) ? { closure => $_ } : ArrayLike->check($_) ? compile({ want_details => 1 }, @$_) : $_; } @_; my @code = 'sub { my $r; '; for my $i (0 .. $#multi) { my $flag = sprintf('${^TYPE_PARAMS_MULTISIG} = %d', $i); my $sig = $multi[$i]; my @cond; push @cond, sprintf('@_ >= %s', $sig->{min_args}) if defined $sig->{min_args}; push @cond, sprintf('@_ <= %s', $sig->{max_args}) if defined $sig->{max_args}; if (defined $sig->{max_args} and defined $sig->{min_args}) { @cond = sprintf('@_ == %s', $sig->{min_args}) if $sig->{max_args} == $sig->{min_args}; } push @code, sprintf('if (%s){', join(' and ', @cond)) if @cond; push @code, sprintf('eval { $r = [ $multi[%d]{closure}->(@_) ]; %s };', $i, $flag); push @code, 'return(@$r) if $r;'; push @code, '}' if @cond; } push @code, sprintf('"Error::TypeTiny"->throw(message => "%s");', quotemeta("$options{message}")); push @code, '}'; eval_closure( source => \@code, description => $options{description}, environment => { '@multi' => \@multi }, ); } sub wrap_methods { my $opts = ref($_[0]) eq 'HASH' ? shift : {}; $opts->{caller} ||= caller; $opts->{skip_invocant} = 1; $opts->{use_can} = 1; unshift @_, $opts; goto \&_wrap_subs; } sub wrap_subs { my $opts = ref($_[0]) eq 'HASH' ? shift : {}; $opts->{caller} ||= caller; $opts->{skip_invocant} = 0; $opts->{use_can} = 0; unshift @_, $opts; goto \&_wrap_subs; } sub _wrap_subs { my $opts = shift; my $subname = eval { require Sub::Util } ? \&Sub::Util::set_subname : eval { require Sub::Name } ? \&Sub::Name::subname : 0; while (@_) { my ($name, $proto) = splice @_, 0, 2; my $fullname = ($name =~ /::/) ? $name : sprintf('%s::%s', $opts->{caller}, $name); my $orig = do { no strict 'refs'; exists &$fullname ? \&$fullname : $opts->{use_can} ? ($opts->{caller}->can($name)||sub{}) : sub {} }; my $check = ref($proto) eq 'CODE' ? $proto : undef; my $co = { description => "parameter validation for '$name'" }; my $new = $opts->{skip_invocant} ? sub { my $s = shift; $check ||= compile($co, @$proto); @_ = ($s, &$check); goto $orig } : sub { $check ||= compile($co, @$proto); @_ = (&$check); goto $orig }; $new = $subname->($fullname, $new) if $subname; no strict 'refs'; no warnings 'redefine'; *$fullname = $new; } 1; } 1; __END__ =pod =encoding utf-8 =for stopwords evals invocant =head1 NAME Type::Params - Params::Validate-like parameter validation using Type::Tiny type constraints and coercions =head1 SYNOPSIS use v5.12; use strict; use warnings; package Horse { use Moo; use Types::Standard qw( Object ); use Type::Params qw( compile ); use namespace::autoclean; ...; # define attributes, etc sub add_child { state $check = compile( Object, Object ); # method signature my ($self, $child) = $check->(@_); # unpack @_ push @{ $self->children }, $child; return $self; } } package main; my $boldruler = Horse->new; $boldruler->add_child( Horse->new ); $boldruler->add_child( 123 ); # dies (123 is not an Object!) =head1 STATUS This module is covered by the L. =head1 DESCRIPTION This documents the details of the L package. L is a better starting place if you're new. Type::Params uses L constraints to validate the parameters to a sub. It takes the slightly unorthodox approach of separating validation into two stages: =over =item 1. Compiling the parameter specification into a coderef; then =item 2. Using the coderef to validate parameters. =back The first stage is slow (it might take a couple of milliseconds), but you only need to do it the first time the sub is called. The second stage is fast; according to my benchmarks faster even than the XS version of L. If you're using a modern version of Perl, you can use the C keyword which was a feature added to Perl in 5.10. If you're stuck on Perl 5.8, the example from the SYNOPSIS could be rewritten as: my $add_child_check; sub add_child { $add_child_check ||= compile( Object, Object ); my ($self, $child) = $add_child_check->(@_); # unpack @_ push @{ $self->children }, $child; return $self; } Not quite as neat, but not awful either. If you don't like the two step, there's a shortcut reducing it to one step: use Type::Params qw( validate ); sub add_child { my ($self, $child) = validate(\@_, Object, Object); push @{ $self->children }, $child; return $self; } Type::Params has a few tricks up its sleeve to make sure performance doesn't suffer too much with the shortcut, but it's never going to be as fast as the two stage compile/execute. =head2 Functions =head3 C<< compile(@spec) >> Given specifications for positional parameters, compiles a coderef that can check against them. The generalized form of specifications for positional parameters is: state $check = compile( \%general_opts, $type_for_arg_1, \%opts_for_arg_1, $type_for_arg_2, \%opts_for_arg_2, $type_for_arg_3, \%opts_for_arg_3, ..., slurpy($slurpy_type), ); If a hashref of options is empty, it can simply be omitted. Much of the time, you won't need to specify any options. # In this example, we omit all the hashrefs # my $check = compile( Str, Int, Optional[ArrayRef], ); my ($str, $int, $arr) = $check->("Hello", 42, []); # ok my ($str, $int, $arr) = $check->("", -1); # ok my ($str, $int, $arr) = $check->("", -1, "bleh"); # dies The coderef returned (i.e. C<< $check >>) will check the arguments passed to it conform to the spec (coercing them if appropriate), and return them as a list if they do. If they don't, it will throw an exception. The first hashref, before any type constraints, is for general options which affect the entire compiled coderef. Currently supported general options are: =over =item C<< want_source >> B<< Bool >> Instead of returning a coderef, return Perl source code string. Handy for debugging. =item C<< want_details >> B<< Bool >> Instead of returning a coderef, return a hashref of stuff including the coderef. This is mostly for people extending Type::Params and I won't go into too many details about what else this hashref contains. =item C<< description >> B<< Str >> Description of the coderef that will show up in stack traces. Defaults to "parameter validation for X" where X is the caller sub name. =item C<< subname >> B<< Str >> If you wish to use the default description, but need to change the sub name, use this. =item C<< caller_level >> B<< Int >> If you wish to use the default description, but need to change the caller level for detecting the sub name, use this. =back The types for each parameter may be any L type constraint, or anything that Type::Tiny knows how to coerce into a Type::Tiny type constraint, such as a MooseX::Types type constraint or a coderef. Type coercions are automatically applied for all types that have coercions. If you wish to avoid coercions for a type, use Type::Tiny's C method. my $check = compile( Int, ArrayRef->of(Bool)->no_coercions, ); Note that having any coercions in a specification, even if they're not used in a particular check, will slightly slow down C<< $check >> because it means that C<< $check >> can't just check C<< @_ >> and return it unaltered if it's valid — it needs to build a new array to return. Optional parameters can be given using the B<< Optional[] >> type constraint. In the example above, the third parameter is optional. If it's present, it's required to be an arrayref, but if it's absent, it is ignored. Optional parameters need to be I required parameters in the spec. An alternative way to specify optional parameters is using a parameter options hashref. my $check = compile( Str, Int, ArrayRef, { optional => 1 }, ); The following parameter options are supported: =over =item C<< optional >> B<< Bool >> This is an alternative way of indicating that a parameter is optional. state $check = compile( Int, Int, { optional => 1 }, Optional[Int], ); The two are not I equivalent. The exceptions thrown will differ in the type name they mention. (B versus B<< Optional[Int] >>.) =item C<< default >> B<< CodeRef|Ref|Str|Undef >> A default may be provided for a parameter. state $check = compile( Int, Int, { default => "666" }, Int, { default => "999" }, ); Supported defaults are any strings (including numerical ones), C, and empty hashrefs and arrayrefs. Non-empty hashrefs and arrayrefs are I<< not allowed as defaults >>. Alternatively, you may provide a coderef to generate a default value: state $check = named( Int, Int, { default => sub { 6 * 111 } }, Int, { default => sub { 9 * 111 } }, ); That coderef may generate any value, including non-empty arrayrefs and non-empty hashrefs. For undef, simple strings, numbers, and empty structures, avoiding using a coderef will make your parameter processing faster. The default I be validated against the type constraint, and potentially coerced. Note that having any defaults in a specification, even if they're not used in a particular check, will slightly slow down C<< $check >> because it means that C<< $check >> can't just check C<< @_ >> and return it unaltered if it's valid — it needs to build a new array to return. =back As a special case, the numbers 0 and 1 may be used as shortcuts for B<< Optional[Any] >> and B<< Any >>. # Positional parameters state $check = compile(1, 0, 0); my ($foo, $bar, $baz) = $check->(@_); # $bar and $baz are optional After any required and optional parameters may be a slurpy parameter. Any additional arguments passed to C<< $check >> will be slurped into an arrayref or hashref and checked against the slurpy parameter. Defaults are not supported for slurpy parameters. Example with a slurpy ArrayRef: sub xyz { state $check = compile(Int, Int, slurpy ArrayRef[Int]); my ($foo, $bar, $baz) = $check->(@_); } xyz(1..5); # $foo = 1 # $bar = 2 # $baz = [ 3, 4, 5 ] Example with a slurpy HashRef: my $check = compile( Int, Optional[Str], slurpy HashRef[Int], ); my ($x, $y, $z) = $check->(1, "y", foo => 666, bar => 999); # $x is 1 # $y is "y" # $z is { foo => 666, bar => 999 } Any type constraints derived from B or B should work, but a type does need to inherit from one of those because otherwise Type::Params cannot know what kind of structure to slurp the remaining arguments into. B<< slurpy Any >> is also allowed as a special case, and is treated as B<< slurpy ArrayRef >>. From Type::Params 1.005000 onwards, slurpy hashrefs can be passed in as a true hashref (which will be shallow cloned) rather than key-value pairs. sub xyz { state $check = compile(Int, slurpy HashRef); my ($num, $hr) = $check->(@_); ... } xyz( 5, foo => 1, bar => 2 ); # works xyz( 5, { foo => 1, bar => 2 } ); # works from 1.005000 This feature is only implemented for slurpy hashrefs, not slurpy arrayrefs. Note that having a slurpy parameter will slightly slow down C<< $check >> because it means that C<< $check >> can't just check C<< @_ >> and return it unaltered if it's valid — it needs to build a new array to return. =head3 C<< validate(\@_, @spec) >> This example of C: sub foo { state $check = compile(@spec); my @args = $check->(@_); ...; } Can be written using C as: sub foo { my @args = validate(\@_, @spec); ...; } Performance using C will I beat C though. =head3 C<< compile_named(@spec) >> C is a variant of C for named parameters instead of positional parameters. The format of the specification is changed to include names for each parameter: state $check = compile_named( \%general_opts, foo => $type_for_foo, \%opts_for_foo, bar => $type_for_bar, \%opts_for_bar, baz => $type_for_baz, \%opts_for_baz, ..., slurpy($slurpy_type), ); The C<< $check >> coderef will return a hashref. my $check = compile_named( foo => Int, bar => Str, { default => "hello" }, ); my $args = $check->(foo => 42); # $args->{foo} is 42 # $args->{bar} is "hello" The C<< %general_opts >> hash supports the same options as C plus a few additional options: =over =item C<< class >> B<< ClassName >> The check coderef will, instead of returning a simple hashref, call C<< $class->new($hashref) >> and return the result. =item C<< constructor >> B<< Str >> Specifies an alternative method name instead of C for the C option described above. =item C<< class >> B<< Tuple[ClassName, Str] >> Shortcut for declaring both the C and C options at once. =item C<< bless >> B<< ClassName >> Like C, but bypass the constructor and directly bless the hashref. =item C<< named_to_list >> B<< Bool >> Instead of returning a hashref, return a hash slice. myfunc(bar => "x", foo => "y"); sub myfunc { state $check = compile_named( { named_to_list => 1 }, foo => Str, { optional => 1 }, bar => Str, { optional => 1 }, ); my ($foo, $bar) = $check->(@_); ...; ## $foo is "y" and $bar is "x" } The order of keys for the hash slice is the same as the order of the names passed to C. For missing named parameters, C is returned in the list. Basically in the above example, C takes named parameters, but receieves positional parameters. =item C<< named_to_list >> B<< ArrayRef[Str] >> As above, but explicitly specify the keys of the hash slice. =back Like C, the numbers 0 and 1 may be used as shortcuts for B<< Optional[Any] >> and B<< Any >>. state $check = compile_named(foo => 1, bar => 0, baz => 0); my $args = $check->(@_); # $args->{bar} and $args->{baz} are optional Slurpy parameters are supported as you'd expect. B<< slurpy Any >> is treated as B<< slurpy HashRef >>. =head3 C<< validate_named(\@_, @spec) >> Like C has C, C has C. Just like C, it's the slower way to do things, so stick with C. =head3 C<< compile_named_oo(@spec) >> Here's a quick example function: sub add_contact_to_database { state $check = compile_named( dbh => Object, id => Int, name => Str, ); my $arg = $check->(@_); my $sth = $arg->{db}->prepare('INSERT INTO contacts VALUES (?, ?)'); $sth->execute($arg->{id}, $arg->{name}); } Looks simple, right? Did you spot that it will always die with an error message I<< Can't call method "prepare" on an undefined value >>? This is because we defined a parameter called 'dbh' but later tried to refer to it as C<< $arg{db} >>. Here, Perl gives us a pretty clear error, but sometimes the failures will be far more subtle. Wouldn't it be nice if instead we could do this? sub add_contact_to_database { state $check = compile_named_oo( dbh => Object, id => Int, name => Str, ); my $arg = $check->(@_); my $sth = $arg->dbh->prepare('INSERT INTO contacts VALUES (?, ?)'); $sth->execute($arg->id, $arg->name); } If we tried to call C<< $arg->db >>, it would fail because there was no such method. Well, that's exactly what C does. As well as giving you nice protection against mistyped parameter names, It also looks kinda pretty, I think. Hash lookups are a little faster than method calls, of course (though Type::Params creates the methods using L if it's installed, so they're still pretty fast). An optional parameter C will also get a nifty C<< $arg->has_foo >> predicate method. Yay! C gives you some extra options for parameters. sub add_contact_to_database { state $check = compile_named_oo( dbh => Object, id => Int, { default => '0', getter => 'identifier' }, name => Str, { optional => 1, predicate => 'has_name' }, ); my $arg = $check->(@_); my $sth = $arg->dbh->prepare('INSERT INTO contacts VALUES (?, ?)'); $sth->execute($arg->identifier, $arg->name) if $arg->has_name; } =over =item C<< getter >> B<< Str >> The C option lets you choose the method name for getting the argument value. =item C<< predicate >> B<< Str >> The C option lets you choose the method name for checking the existence of an argument. By setting an explicit predicate method name, you can force a predicate method to be generated for non-optional arguments. =back The objects returned by C are blessed into lightweight classes which have been generated on the fly. Don't expect the names of the classes to be stable or predictable. It's probably a bad idea to be checking C, C, or C on any of these objects. If you're doing that, you've missed the point of them. They don't have any constructor (C method). The C<< $check >> coderef effectively I the constructor. =head3 C<< validate_named_oo(\@_, @spec) >> This function doesn't even exist. :D =head3 C<< multisig(@alternatives) >> Type::Params can export a C function that compiles multiple alternative signatures into one, and uses the first one that works: state $check = multisig( [ Int, ArrayRef ], [ HashRef, Num ], [ CodeRef ], ); my ($int, $arrayref) = $check->( 1, [] ); # okay my ($hashref, $num) = $check->( {}, 1.1 ); # okay my ($code) = $check->( sub { 1 } ); # okay $check->( sub { 1 }, 1.1 ); # throws an exception Coercions, slurpy parameters, etc still work. The magic global C<< ${^TYPE_PARAMS_MULTISIG} >> is set to the index of the first signature which succeeded. The present implementation involves compiling each signature independently, and trying them each (in their given order!) in an C block. The only slightly intelligent part is that it checks if C<< scalar(@_) >> fits into the signature properly (taking into account optional and slurpy parameters), and skips evals which couldn't possibly succeed. It's also possible to list coderefs as alternatives in C: state $check = multisig( [ Int, ArrayRef ], sub { ... }, [ HashRef, Num ], [ CodeRef ], compile_named( needle => Value, haystack => Ref ), ); The coderef is expected to die if that alternative should be abandoned (and the next alternative tried), or return the list of accepted parameters. Here's a full example: sub get_from { state $check = multisig( [ Int, ArrayRef ], [ Str, HashRef ], sub { my ($meth, $obj); die unless is_Object($obj); die unless $obj->can($meth); return ($meth, $obj); }, ); my ($needle, $haystack) = $check->(@_); for (${^TYPE_PARAMS_MULTISIG}) { return $haystack->[$needle] if $_ == 0; return $haystack->{$needle} if $_ == 1; return $haystack->$needle if $_ == 2; } } get_from(0, \@array); # returns $array[0] get_from('foo', \%hash); # returns $hash{foo} get_from('foo', $obj); # returns $obj->foo The default error message is just C<"Parameter validation failed">. You can pass an option hashref as the first argument with an informative message string: sub foo { state $OptionsDict = Dict[...]; state $check = multisig( { message => 'USAGE: $object->foo(\%options?, $string)' }, [ Object, $OptionsDict, StringLike ], [ Object, StringLike ], ); my ($self, @args) = $check->(@_); my ($opts, $str) = ${^TYPE_PARAMS_MULTISIG} ? ({}, @args) : @_; ...; } $obj->foo(\%opts, "Hello"); $obj->foo("World"); =head3 C<< wrap_subs( $subname1, $wrapper1, ... ) >> It's possible to turn the check inside-out and instead of the sub calling the check, the check can call the original sub. Normal way: use Type::Param qw(compile); use Types::Standard qw(Int Str); sub foobar { state $check = compile(Int, Str); my ($foo, $bar) = @_; ...; } Inside-out way: use Type::Param qw(wrap_subs); use Types::Standard qw(Int Str); sub foobar { my ($foo, $bar) = @_; ...; } wrap_subs foobar => [Int, Str]; C takes a hash of subs to wrap. The keys are the sub names and the values are either arrayrefs of arguments to pass to C to make a check, or coderefs that have already been built by C, C, or C. =head3 C<< wrap_methods( $subname1, $wrapper1, ... ) >> C also exists, which shifts off the invocant from C<< @_ >> before the check, but unshifts it before calling the original sub. use Type::Param qw(wrap_subs); use Types::Standard qw(Int Str); sub foobar { my ($self, $foo, $bar) = @_; ...; } wrap_subs foobar => [Int, Str]; =head3 B Type::Params exports a type B on request. This gives you a type constraint which accepts classnames I blessed objects. use Type::Params qw( compile Invocant ); sub my_method { state $check = compile(Invocant, ArrayRef, Int); my ($self_or_class, $arr, $ix) = $check->(@_); return $arr->[ $ix ]; } =head1 ENVIRONMENT =over =item C Affects the building of accessors for C. If set to true, will use L. If set to false, will use pure Perl. If this environment variable does not exist, will use L if it is available. =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. L, L, L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Parser.pm000644001750001750 3242313601673061 15712 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Typepackage Type::Parser; use strict; use warnings; sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } our $AUTHORITY = 'cpan:TOBYINK'; our $VERSION = '1.008001'; $VERSION =~ tr/_//d; # Token types # sub TYPE () { "TYPE" }; sub QUOTELIKE () { "QUOTELIKE" }; sub STRING () { "STRING" }; sub CLASS () { "CLASS" }; sub L_BRACKET () { "L_BRACKET" }; sub R_BRACKET () { "R_BRACKET" }; sub COMMA () { "COMMA" }; sub SLURPY () { "SLURPY" }; sub UNION () { "UNION" }; sub INTERSECT () { "INTERSECT" }; sub NOT () { "NOT" }; sub L_PAREN () { "L_PAREN" }; sub R_PAREN () { "R_PAREN" }; sub MYSTERY () { "MYSTERY" }; our @EXPORT_OK = qw( eval_type _std_eval parse extract_type ); require Exporter::Tiny; our @ISA = 'Exporter::Tiny'; Evaluate: { sub parse { my $str = $_[0]; my $parser = "Type::Parser::AstBuilder"->new(input => $str); $parser->build; wantarray ? ($parser->ast, $parser->remainder) : $parser->ast; } sub extract_type { my ($str, $reg) = @_; my ($parsed, $tail) = parse($str); wantarray ? (_eval_type($parsed, $reg), $tail) : _eval_type($parsed, $reg); } sub eval_type { my ($str, $reg) = @_; my ($parsed, $tail) = parse($str); _croak("Unexpected tail on type expression: $tail") if $tail =~ /\S/sm; return _eval_type($parsed, $reg); } my $std; sub _std_eval { require Type::Registry; unless ($std) { $std = "Type::Registry"->new; $std->add_types(-Standard); } eval_type($_[0], $std); } sub _eval_type { my ($node, $reg) = @_; $node = _simplify_expression($node); if ($node->{type} eq "list") { return map _eval_type($_, $reg), @{$node->{list}}; } if ($node->{type} eq "union") { return $reg->make_union( map _eval_type($_, $reg), @{$node->{union}} ); } if ($node->{type} eq "intersect") { return $reg->make_intersection( map _eval_type($_, $reg), @{$node->{intersect}} ); } if ($node->{type} eq "slurpy") { return +{ slurpy => _eval_type($node->{of}, $reg) }; } if ($node->{type} eq "complement") { return _eval_type($node->{of}, $reg)->complementary_type; } if ($node->{type} eq "parameterized") { my $base = _eval_type($node->{base}, $reg); return $base unless $base->is_parameterizable || $node->{params}; return $base->parameterize($node->{params} ? _eval_type($node->{params}, $reg) : ()); } if ($node->{type} eq "primary" and $node->{token}->type eq CLASS) { my $class = substr( $node->{token}->spelling, 0, length($node->{token}->spelling) - 2 ); return $reg->make_class_type($class); } if ($node->{type} eq "primary" and $node->{token}->type eq QUOTELIKE) { return eval($node->{token}->spelling); #ARGH } if ($node->{type} eq "primary" and $node->{token}->type eq STRING) { return $node->{token}->spelling; } if ($node->{type} eq "primary" and $node->{token}->type eq TYPE) { my $t = $node->{token}->spelling; my $r = ($t =~ /^(.+)::(\w+)$/) ? $reg->foreign_lookup($t, 1) : $reg->simple_lookup($t, 1); $r or _croak("%s is not a known type constraint", $node->{token}->spelling); return $r; } } sub _simplify_expression { my $expr = shift; if ($expr->{type} eq "expression" and $expr->{op}[0] eq COMMA) { return _simplify("list", COMMA, $expr); } if ($expr->{type} eq "expression" and $expr->{op}[0] eq UNION) { return _simplify("union", UNION, $expr); } if ($expr->{type} eq "expression" and $expr->{op}[0] eq INTERSECT) { return _simplify("intersect", INTERSECT, $expr); } return $expr; } sub _simplify { my $type = shift; my $op = shift; my @list; for my $expr ($_[0]{lhs}, $_[0]{rhs}) { if ($expr->{type} eq "expression" and $expr->{op}[0] eq $op) { my $simple = _simplify($type, $op, $expr); push @list, @{ $simple->{$type} }; } else { push @list, $expr; } } return { type => $type, $type => \@list }; } } { package # hide from CPAN Type::Parser::AstBuilder; sub new { my $class = shift; bless { @_ }, $class; } our %precedence = ( # Type::Parser::COMMA() , 1 , Type::Parser::UNION() , 2 , Type::Parser::INTERSECT() , 3 , Type::Parser::NOT() , 4 , ); sub _parse_primary { my $self = shift; my $tokens = $self->{tokens}; $tokens->assert_not_empty; if ($tokens->peek(0)->type eq Type::Parser::NOT) { $tokens->eat(Type::Parser::NOT); $tokens->assert_not_empty; return { type => "complement", of => $self->_parse_primary, }; } if ($tokens->peek(0)->type eq Type::Parser::SLURPY) { $tokens->eat(Type::Parser::SLURPY); $tokens->assert_not_empty; return { type => "slurpy", of => $self->_parse_primary, }; } if ($tokens->peek(0)->type eq Type::Parser::L_PAREN) { $tokens->eat(Type::Parser::L_PAREN); my $r = $self->_parse_expression; $tokens->eat(Type::Parser::R_PAREN); return $r; } if ($tokens->peek(1) and $tokens->peek(0)->type eq Type::Parser::TYPE and $tokens->peek(1)->type eq Type::Parser::L_BRACKET) { my $base = { type => "primary", token => $tokens->eat(Type::Parser::TYPE) }; $tokens->eat(Type::Parser::L_BRACKET); $tokens->assert_not_empty; local $precedence{ Type::Parser::COMMA() } = 1; my $params = undef; if ($tokens->peek(0)->type eq Type::Parser::R_BRACKET) { $tokens->eat(Type::Parser::R_BRACKET); } else { $params = $self->_parse_expression; $params = { type => "list", list => [$params] } unless $params->{type} eq "list"; $tokens->eat(Type::Parser::R_BRACKET); } return { type => "parameterized", base => $base, params => $params, }; } my $type = $tokens->peek(0)->type; if ($type eq Type::Parser::TYPE or $type eq Type::Parser::QUOTELIKE or $type eq Type::Parser::STRING or $type eq Type::Parser::CLASS) { return { type => "primary", token => $tokens->eat }; } Type::Parser::_croak("Unexpected token in primary type expression; got '%s'", $tokens->peek(0)->spelling); } sub _parse_expression_1 { my $self = shift; my $tokens = $self->{tokens}; my ($lhs, $min_p) = @_; while (!$tokens->empty and defined($precedence{$tokens->peek(0)->type}) and $precedence{$tokens->peek(0)->type} >= $min_p) { my $op = $tokens->eat; my $rhs = $self->_parse_primary; while (!$tokens->empty and defined($precedence{$tokens->peek(0)->type}) and $precedence{$tokens->peek(0)->type} > $precedence{$op->type}) { my $lookahead = $tokens->peek(0); $rhs = $self->_parse_expression_1($rhs, $precedence{$lookahead->type}); } $lhs = { type => "expression", op => $op, lhs => $lhs, rhs => $rhs, }; } return $lhs; } sub _parse_expression { my $self = shift; my $tokens = $self->{tokens}; return $self->_parse_expression_1($self->_parse_primary, 0); } sub build { my $self = shift; $self->{tokens} = "Type::Parser::TokenStream"->new(remaining => $self->{input}); $self->{ast} = $self->_parse_expression; } sub ast { $_[0]{ast}; } sub remainder { $_[0]{tokens}->remainder; } } { package # hide from CPAN Type::Parser::Token; sub type { $_[0][0] } sub spelling { $_[0][1] } } { package # hide from CPAN Type::Parser::TokenStream; use Scalar::Util qw(looks_like_number); sub new { my $class = shift; bless { stack => [], done => [], @_ }, $class; } sub peek { my $self = shift; my $ahead = $_[0]; while ($self->_stack_size <= $ahead and length $self->{remaining}) { $self->_stack_extend; } my @tokens = grep ref, @{ $self->{stack} }; return $tokens[$ahead]; } sub empty { my $self = shift; not $self->peek(0); } sub eat { my $self = shift; $self->_stack_extend unless $self->_stack_size; my $r; while (defined(my $item = shift @{$self->{stack}})) { push @{ $self->{done} }, $item; if (ref $item) { $r = $item; last; } } if (@_ and $_[0] ne $r->type) { unshift @{$self->{stack}}, pop @{$self->{done}}; # uncoverable statement Type::Parser::_croak("Expected $_[0]; got ".$r->type); # uncoverable statement } return $r; } sub assert_not_empty { my $self = shift; Type::Parser::_croak("Expected token; got empty string") if $self->empty; } sub _stack_size { my $self = shift; scalar grep ref, @{ $self->{stack} }; } sub _stack_extend { my $self = shift; push @{ $self->{stack} }, $self->_read_token; my ($space) = ($self->{remaining} =~ m/^([\s\n\r]*)/sm); return unless length $space; push @{ $self->{stack} }, $space; substr($self->{remaining}, 0, length $space) = ""; } sub remainder { my $self = shift; return join "", map { ref($_) ? $_->spelling : $_ } (@{$self->{stack}}, $self->{remaining}) } my %punctuation = ( '[' => bless([ Type::Parser::L_BRACKET, "[" ], "Type::Parser::Token"), ']' => bless([ Type::Parser::R_BRACKET, "]" ], "Type::Parser::Token"), '(' => bless([ Type::Parser::L_PAREN, "[" ], "Type::Parser::Token"), ')' => bless([ Type::Parser::R_PAREN, "]" ], "Type::Parser::Token"), ',' => bless([ Type::Parser::COMMA, "," ], "Type::Parser::Token"), '=>' => bless([ Type::Parser::COMMA, "=>" ], "Type::Parser::Token"), 'slurpy' => bless([ Type::Parser::SLURPY, "slurpy" ], "Type::Parser::Token"), '|' => bless([ Type::Parser::UNION, "|" ], "Type::Parser::Token"), '&' => bless([ Type::Parser::INTERSECT, "&" ], "Type::Parser::Token"), '~' => bless([ Type::Parser::NOT, "~" ], "Type::Parser::Token"), ); sub _read_token { my $self = shift; return if $self->{remaining} eq ""; # Punctuation # if ($self->{remaining} =~ /^( => | [()\]\[|&~,] )/xsm) { my $spelling = $1; substr($self->{remaining}, 0, length $spelling) = ""; return $punctuation{$spelling}; } if ($self->{remaining} =~ /\A\s*[q'"]/sm) { require Text::Balanced; if (my $quotelike = Text::Balanced::extract_quotelike($self->{remaining})) { return bless([ Type::Parser::QUOTELIKE, $quotelike ], "Type::Parser::Token"),; } } if ($self->{remaining} =~ /^([+-]?[\w:.+]+)/sm) { my $spelling = $1; substr($self->{remaining}, 0, length $spelling) = ""; if ($spelling =~ /::$/sm) { return bless([ Type::Parser::CLASS, $spelling ], "Type::Parser::Token"),; } elsif (looks_like_number($spelling)) { return bless([ Type::Parser::STRING, $spelling ], "Type::Parser::Token"),; } elsif ($self->{remaining} =~ /^\s*=>/sm) # peek ahead { return bless([ Type::Parser::STRING, $spelling ], "Type::Parser::Token"),; } elsif ($spelling eq "slurpy") { return $punctuation{$spelling}; } return bless([ Type::Parser::TYPE, $spelling ], "Type::Parser::Token"); } my $rest = $self->{remaining}; $self->{remaining} = ""; return bless([ Type::Parser::MYSTERY, $rest ], "Type::Parser::Token"); } } 1; __END__ =pod =encoding utf-8 =for stopwords non-whitespace =head1 NAME Type::Parser - parse type constraint strings =head1 SYNOPSIS use v5.10; use strict; use warnings; use Type::Parser qw( eval_type ); use Type::Registry; my $reg = Type::Registry->for_me; $reg->add_types("Types::Standard"); my $type = eval_type("Int | ArrayRef[Int]", $reg); $type->check(10); # true $type->check([1..4]); # true $type->check({foo=>1}); # false =head1 STATUS This module is covered by the L. =head1 DESCRIPTION Generally speaking, you probably don't want to be using this module directly. Instead use the C<< lookup >> method from L which wraps it. =head2 Functions =over =item C<< parse($string) >> Parse the type constraint string into something like an AST. If called in list context, also returns any "tail" found on the original string. =item C<< extract_type($string, $registry) >> Compile a type constraint string into a L object. If called in list context, also returns any "tail" found on the original string. =item C<< eval_type($string, $registry) >> Compile a type constraint string into a L object. Throws an error if the "tail" contains any non-whitespace character. =back =head2 Constants The following constants correspond to values returned by C<< $token->type >>. =over =item C<< TYPE >> =item C<< QUOTELIKE >> =item C<< STRING >> =item C<< CLASS >> =item C<< L_BRACKET >> =item C<< R_BRACKET >> =item C<< COMMA >> =item C<< SLURPY >> =item C<< UNION >> =item C<< INTERSECT >> =item C<< NOT >> =item C<< L_PAREN >> =item C<< R_PAREN >> =item C<< MYSTERY >> =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Registry.pm000644001750001750 2562113601673061 16270 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Typepackage Type::Registry; use 5.006001; use strict; use warnings; BEGIN { $Type::Registry::AUTHORITY = 'cpan:TOBYINK'; $Type::Registry::VERSION = '1.008001'; } $Type::Registry::VERSION =~ tr/_//d; use Exporter::Tiny qw( mkopt ); use Scalar::Util qw( refaddr ); use Type::Parser qw( eval_type ); use Types::TypeTiny qw( CodeLike ArrayLike to_TypeTiny ); our @ISA = 'Exporter::Tiny'; our @EXPORT_OK = qw(t); sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } sub _generate_t { my $class = shift; my ($name, $value, $globals) = @_; my $caller = $globals->{into}; my $reg = $class->for_class( ref($caller) ? sprintf('HASH(0x%08X)', refaddr($caller)) : $caller ); sub (;$) { @_ ? $reg->lookup(@_) : $reg }; } sub new { my $class = shift; ref($class) and _croak("Not an object method"); bless {}, $class; } { my %registries; sub for_class { my $class = shift; my ($for) = @_; $registries{$for} ||= $class->new; } sub for_me { my $class = shift; my $for = caller; $registries{$for} ||= $class->new; } } sub add_types { my $self = shift; my $opts = mkopt(\@_); for my $opt (@$opts) { my ($library, $types) = @_; $library =~ s/^-/Types::/; { local $SIG{__DIE__} = sub {}; eval "require $library"; }; my %hash; if ($library->isa("Type::Library") or $library eq 'Types::TypeTiny') { $types ||= [qw/-types/]; ArrayLike->check($types) or _croak("Expected arrayref following '%s'; got %s", $library, $types); $library->import({into => \%hash}, @$types); $hash{$_} = &{$hash{$_}}() for keys %hash; } elsif ($library->isa("MooseX::Types::Base")) { $types ||= []; ArrayLike->check($types) && (@$types == 0) or _croak("Library '%s' is a MooseX::Types type constraint library. No import options currently supported", $library); require Moose::Util::TypeConstraints; my $moosextypes = $library->type_storage; for my $name (sort keys %$moosextypes) { my $tt = to_TypeTiny( Moose::Util::TypeConstraints::find_type_constraint($moosextypes->{$name}) ); $hash{$name} = $tt; } } elsif ($library->isa("MouseX::Types::Base")) { $types ||= []; ArrayLike->check($types) && (@$types == 0) or _croak("Library '%s' is a MouseX::Types type constraint library. No import options currently supported", $library); require Mouse::Util::TypeConstraints; my $moosextypes = $library->type_storage; for my $name (sort keys %$moosextypes) { my $tt = to_TypeTiny( Mouse::Util::TypeConstraints::find_type_constraint($moosextypes->{$name}) ); $hash{$name} = $tt; } } else { _croak("%s is not a type library", $library); } for my $key (sort keys %hash) { exists($self->{$key}) and $self->{$key}{uniq} != $hash{$key}{uniq} and _croak("Duplicate type name: %s", $key); $self->{$key} = $hash{$key}; } } $self; } sub add_type { my $self = shift; my ($type, $name) = @_; $type = to_TypeTiny($type); $name ||= do { $type->is_anon and _croak("Expected named type constraint; got anonymous type constraint"); $type->name; }; exists($self->{$name}) and $self->{$name}{uniq} != $type->{uniq} and _croak("Duplicate type name: %s", $name); $self->{$name} = $type; $self; } sub alias_type { my $self = shift; my ($old, @new) = @_; my $lookup = eval { $self->lookup($old) } or _croak("Expected existing type constraint name; got '$old'"); $self->{$_} = $lookup for @new; $self; } sub simple_lookup { my $self = shift; my ($tc) = @_; $tc =~ s/(^\s+|\s+$)//g; if (exists $self->{$tc}) { return $self->{$tc}; } return; } sub foreign_lookup { my $self = shift; return $_[1] ? () : $self->simple_lookup($_[0], 1) unless $_[0] =~ /^(.+)::(\w+)$/; my $library = $1; my $typename = $2; { local $SIG{__DIE__} = sub {}; eval "require $library;"; }; if ( $library->isa('MooseX::Types::Base') ) { require Moose::Util::TypeConstraints; my $type = Moose::Util::TypeConstraints::find_type_constraint( $library->get_type($typename) ) or return; return to_TypeTiny($type); } if ( $library->isa('MouseX::Types::Base') ) { require Mouse::Util::TypeConstraints; my $sub = $library->can($typename) or return; my $type = Mouse::Util::TypeConstraints::find_type_constraint($sub->()) or return; return to_TypeTiny($type); } if ( $library->can("get_type") ) { my $type = $library->get_type($typename); return to_TypeTiny($type); } return; } sub lookup { my $self = shift; $self->simple_lookup(@_) or eval_type($_[0], $self); } sub make_union { my $self = shift; my (@types) = @_; require Type::Tiny::Union; return "Type::Tiny::Union"->new(type_constraints => \@types); } sub make_intersection { my $self = shift; my (@types) = @_; require Type::Tiny::Intersection; return "Type::Tiny::Intersection"->new(type_constraints => \@types); } sub make_class_type { my $self = shift; my ($class) = @_; require Type::Tiny::Class; return "Type::Tiny::Class"->new(class => $class); } sub make_role_type { my $self = shift; my ($role) = @_; require Type::Tiny::Role; return "Type::Tiny::Role"->new(role => $role); } sub AUTOLOAD { my $self = shift; my ($method) = (our $AUTOLOAD =~ /(\w+)$/); my $type = $self->simple_lookup($method); return $type if $type; _croak(q[Can't locate object method "%s" via package "%s"], $method, ref($self)); } # Prevent AUTOLOAD being called for DESTROY! sub DESTROY { return; } DELAYED: { our %DELAYED; for my $package (sort keys %DELAYED) { my $reg = __PACKAGE__->for_class($package); my $types = $DELAYED{$package}; for my $name (sort keys %$types) { $reg->add_type($types->{$name}, $name); } } } 1; __END__ =pod =encoding utf-8 =for stopwords optlist =head1 NAME Type::Registry - a glorified hashref for looking up type constraints =head1 SYNOPSIS =for test_synopsis no warnings qw(misc); package Foo::Bar; use Type::Registry; my $reg = "Type::Registry"->for_me; # a registry for Foo::Bar # Register all types from Types::Standard $reg->add_types(-Standard); # Register just one type from Types::XSD $reg->add_types(-XSD => ["NonNegativeInteger"]); # Register all types from MyApp::Types $reg->add_types("MyApp::Types"); # Create a type alias $reg->alias_type("NonNegativeInteger" => "Count"); # Look up a type constraint my $type = $reg->lookup("ArrayRef[Count]"); $type->check([1, 2, 3.14159]); # croaks Alternatively: package Foo::Bar; use Type::Registry qw( t ); # Register all types from Types::Standard t->add_types(-Standard); # Register just one type from Types::XSD t->add_types(-XSD => ["NonNegativeInteger"]); # Register all types from MyApp::Types t->add_types("MyApp::Types"); # Create a type alias t->alias_type("NonNegativeInteger" => "Count"); # Look up a type constraint my $type = t("ArrayRef[Count]"); $type->check([1, 2, 3.14159]); # croaks =head1 STATUS This module is covered by the L. =head1 DESCRIPTION A type registry is basically just a hashref mapping type names to type constraint objects. =head2 Constructors =over =item C<< new >> Create a new glorified hashref. =item C<< for_class($class) >> Create or return the existing glorified hashref associated with the given class. Note that any type constraint you have imported from Type::Library-based type libraries will be automatically available in your class' registry. =item C<< for_me >> Create or return the existing glorified hashref associated with the caller. =back =head2 Methods =over =item C<< add_types(@libraries) >> The libraries list is treated as an "optlist" (a la L). Strings are the names of type libraries; if the first character is a hyphen, it is expanded to the "Types::" prefix. If followed by an arrayref, this is the list of types to import from that library. Otherwise, imports all types from the library. use Type::Registry qw(t); t->add_types(-Standard); # OR: t->add_types("Types::Standard"); t->add_types( -TypeTiny => ['HashLike'], -Standard => ['HashRef' => { -as => 'RealHash' }], ); L (and experimentally, L) libraries can also be added this way, but I<< cannot be followed by an arrayref of types to import >>. =item C<< add_type($type, $name) >> The long-awaited singular form of C. Given a type constraint object, adds it to the registry with a given name. The name may be omitted, in which case C<< $type->name >> is called, and Type::Registry will throw an error if C<< $type >> is anonymous. If a name is explicitly given, Type::Registry cares not one wit whether the type constraint is anonymous. This method can even add L and L type constraints; indeed anything that can be handled by L's C function. (Bear in mind that to_TypeTiny I results in an anonymous type constraint, so C<< $name >> will be required.) =item C<< alias_type($oldname, $newname) >> Create an alias for an existing type. =item C<< simple_lookup($name) >> Look up a type in the registry by name. Returns undef if not found. =item C<< foreign_lookup($name) >> Like C, but if the type name contains "::", will attempt to load it from a type library. (And will attempt to load that module.) =item C<< lookup($name) >> Look up by name, with a DSL. t->lookup("Int|ArrayRef[Int]") The DSL can be summed up as: X type from this registry My::Lib::X type from a type library ~X complementary type X | Y union X & Y intersection X[...] parameterized type slurpy X slurpy type Foo::Bar:: class type Croaks if not found. =item C<< make_union(@constraints) >>, C<< make_intersection(@constraints) >>, C<< make_class_type($class) >>, C<< make_role_type($role) >> Convenience methods for creating certain common type constraints. =item C<< AUTOLOAD >> Overloaded to call C. $registry->Str; # like $registry->lookup("Str") =back =head2 Functions =over =item C<< t >> This class can export a function C<< t >> which acts like C<< "Type::Registry"->for_class($importing_class) >>. =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Tiny.pm000644001750001750 17337213601673061 15432 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Typepackage Type::Tiny; use 5.006001; use strict; use warnings; BEGIN { if ($] < 5.008) { require Devel::TypeTiny::Perl56Compat }; if ($] < 5.010) { require Devel::TypeTiny::Perl58Compat }; } BEGIN { $Type::Tiny::AUTHORITY = 'cpan:TOBYINK'; $Type::Tiny::VERSION = '1.008001'; $Type::Tiny::XS_VERSION = '0.016'; } $Type::Tiny::VERSION =~ tr/_//d; $Type::Tiny::XS_VERSION =~ tr/_//d; use Scalar::Util qw( blessed ); use Types::TypeTiny (); sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } sub _swap { $_[2] ? @_[1,0] : @_[0,1] } BEGIN { # uncoverable statement ($] < 5.010001) # uncoverable statement ? eval q{ sub SUPPORT_SMARTMATCH () { !!0 } } # uncoverable statement : eval q{ sub SUPPORT_SMARTMATCH () { !!1 } }; # uncoverable statement ($] >= 5.014) # uncoverable statement ? eval q{ sub _FIXED_PRECEDENCE () { !!1 } } # uncoverable statement : eval q{ sub _FIXED_PRECEDENCE () { !!0 } }; # uncoverable statement }; # uncoverable statement BEGIN { my $try_xs = # uncoverable statement exists($ENV{PERL_TYPE_TINY_XS}) ? !!$ENV{PERL_TYPE_TINY_XS} : # uncoverable statement exists($ENV{PERL_ONLY}) ? !$ENV{PERL_ONLY} : # uncoverable statement 1; # uncoverable statement my $use_xs = 0; $try_xs and eval { require Type::Tiny::XS; 'Type::Tiny::XS'->VERSION($Type::Tiny::XS_VERSION); $use_xs++; }; *_USE_XS = $use_xs ? sub () { !!1 } : sub () { !!0 }; *_USE_MOUSE = $try_xs ? sub () { $INC{'Mouse/Util.pm'} and Mouse::Util::MOUSE_XS() } : sub () { !!0 }; }; { my $nil = sub {}; sub _install_overloads { no strict 'refs'; no warnings 'redefine', 'once'; # Coverage is checked on Perl 5.26 if ($] < 5.010) { # uncoverable statement require overload; # uncoverable statement push @_, fallback => 1; # uncoverable statement goto \&overload::OVERLOAD; # uncoverable statement }; # uncoverable statement my $class = shift; *{$class . '::(('} = sub {}; *{$class . '::()'} = sub {}; *{$class . '::()'} = do { my $x = 1; \$x }; while (@_) { my $f = shift; *{$class . '::(' . $f} = ref $_[0] ? shift : do { my $m = shift; sub { shift->$m(@_) } }; } } } __PACKAGE__->_install_overloads( q("") => sub { caller =~ m{^(Moo::HandleMoose|Sub::Quote)} ? $_[0]->_stringify_no_magic : $_[0]->display_name }, q(bool) => sub { 1 }, q(&{}) => "_overload_coderef", q(|) => sub { my @tc = _swap @_; if (!_FIXED_PRECEDENCE && $_[2]) { if (blessed $tc[0]) { if (blessed $tc[0] eq "Type::Tiny::_HalfOp") { my $type = $tc[0]->{type}; my $param = $tc[0]->{param}; my $op = $tc[0]->{op}; require Type::Tiny::Union; return "Type::Tiny::_HalfOp"->new( $op, $param, "Type::Tiny::Union"->new(type_constraints => [$type, $tc[1]]), ); } } elsif (ref $tc[0] eq 'ARRAY') { require Type::Tiny::_HalfOp; return "Type::Tiny::_HalfOp"->new('|', @tc); } } require Type::Tiny::Union; return "Type::Tiny::Union"->new(type_constraints => \@tc) }, q(&) => sub { my @tc = _swap @_; if (!_FIXED_PRECEDENCE && $_[2]) { if (blessed $tc[0]) { if (blessed $tc[0] eq "Type::Tiny::_HalfOp") { my $type = $tc[0]->{type}; my $param = $tc[0]->{param}; my $op = $tc[0]->{op}; require Type::Tiny::Intersection; return "Type::Tiny::_HalfOp"->new( $op, $param, "Type::Tiny::Intersection"->new(type_constraints => [$type, $tc[1]]), ); } } elsif (ref $tc[0] eq 'ARRAY') { require Type::Tiny::_HalfOp; return "Type::Tiny::_HalfOp"->new('&', @tc); } } require Type::Tiny::Intersection; "Type::Tiny::Intersection"->new(type_constraints => \@tc) }, q(~) => sub { shift->complementary_type }, q(==) => sub { $_[0]->equals($_[1]) }, q(!=) => sub { not $_[0]->equals($_[1]) }, q(<) => sub { my $m = $_[0]->can('is_subtype_of'); $m->(_swap @_) }, q(>) => sub { my $m = $_[0]->can('is_subtype_of'); $m->(reverse _swap @_) }, q(<=) => sub { my $m = $_[0]->can('is_a_type_of'); $m->(_swap @_) }, q(>=) => sub { my $m = $_[0]->can('is_a_type_of'); $m->(reverse _swap @_) }, q(eq) => sub { "$_[0]" eq "$_[1]" }, q(cmp) => sub { $_[2] ? ("$_[1]" cmp "$_[0]") : ("$_[0]" cmp "$_[1]") }, ); __PACKAGE__->_install_overloads( q(~~) => sub { $_[0]->check($_[1]) }, ) if Type::Tiny::SUPPORT_SMARTMATCH; # Would be easy to just return sub { $self->assert_return(@_) } # but try to build a more efficient coderef whenever possible. # sub _overload_coderef { my $self = shift; # Bypass generating a coderef if we've already got the best possible one. # return $self->{_overload_coderef} if $self->{_overload_coderef_no_rebuild}; # Subclasses of Type::Tiny might override assert_return to do some kind # of interesting thing. In that case, we can't rely on it having identical # behaviour to Type::Tiny::inline_assert. # $self->{_overrides_assert_return} = ($self->can('assert_return') != \&assert_return) unless exists $self->{_overrides_assert_return}; if ($self->{_overrides_assert_return}) { $self->{_overload_coderef} ||= do { Scalar::Util::weaken(my $weak = $self); sub { $weak->assert_return(@_) }; }; ++ $self->{_overload_coderef_no_rebuild}; } elsif (exists(&Sub::Quote::quote_sub)) { # Use `=` instead of `||=` because we want to overwrite non-Sub::Quote # coderef if possible. $self->{_overload_coderef} = $self->can_be_inlined ? Sub::Quote::quote_sub( $self->inline_assert('$_[0]'), ) : Sub::Quote::quote_sub( $self->inline_assert('$_[0]', '$type'), { '$type' => \$self }, ); ++ $self->{_overload_coderef_no_rebuild}; } else { require Eval::TypeTiny; $self->{_overload_coderef} ||= $self->can_be_inlined ? Eval::TypeTiny::eval_closure( source => sprintf('sub { %s }', $self->inline_assert('$_[0]', undef, no_wrapper => 1)), description => sprintf("compiled assertion 'assert_%s'", $self), ) : Eval::TypeTiny::eval_closure( source => sprintf('sub { %s }', $self->inline_assert('$_[0]', '$type', no_wrapper => 1)), description => sprintf("compiled assertion 'assert_%s'", $self), environment => { '$type' => \$self }, ); } $self->{_overload_coderef}; } our %ALL_TYPES; my $QFS; my $uniq = 1; my $subname; sub new { my $class = shift; my %params = (@_==1) ? %{$_[0]} : @_; if (exists $params{constraint} and not ref $params{constraint} and not exists $params{constraint_generator} and not exists $params{inline_generator}) { require Eval::TypeTiny; my $code = $params{constraint}; $params{constraint} = Eval::TypeTiny::eval_closure( source => sprintf('sub ($) { %s }', $code), description => "anonymous check", ); $params{inlined} ||= sub { my ($type) = @_; my $inlined = $_ eq '$_' ? "do { $code }" : "do { local \$_ = $_; $code }"; $type->has_parent ? (undef, $inlined) : $inlined; }; } if (exists $params{parent}) { $params{parent} = ref($params{parent}) =~ /^Type::Tiny\b/ ? $params{parent} : Types::TypeTiny::to_TypeTiny($params{parent}); _croak "Parent must be an instance of %s", __PACKAGE__ unless blessed($params{parent}) && $params{parent}->isa(__PACKAGE__); if ($params{parent}->deprecated and not exists $params{deprecated}) { $params{deprecated} = 1; } } # canonicalize to a boolean $params{deprecated} = !!$params{deprecated}; $params{name} = "__ANON__" unless exists $params{name}; $params{uniq} = $uniq++; if ($params{name} ne "__ANON__") { # First try a fast ASCII-only expression, but fall back to Unicode $params{name} =~ /^_{0,2}[A-Z][A-Za-z0-9_]+$/sm or eval q( use 5.008; $params{name} =~ /^_{0,2}\p{Lu}[\p{L}0-9_]+$/sm ) or _croak '"%s" is not a valid type name', $params{name}; } if (exists $params{coercion} and !ref $params{coercion} and $params{coercion}) { $params{parent}->has_coercion or _croak "coercion => 1 requires type to have a direct parent with a coercion"; $params{coercion} = $params{parent}->coercion->type_coercion_map; } if (!exists $params{inlined} and exists $params{constraint} and ( !exists $params{parent} or $params{parent}->can_be_inlined ) and $QFS ||= "Sub::Quote"->can("quoted_from_sub")) { my (undef, $perlstring, $captures) = @{ $QFS->($params{constraint}) || [] }; $params{inlined} = sub { my ($self, $var) = @_; my $code = Sub::Quote::inlinify( $perlstring, $var, $var eq q($_) ? '' : "local \$_ = $var;", 1, ); $code = sprintf('%s and %s', $self->parent->inline_check($var), $code) if $self->has_parent; return $code; } if $perlstring && !$captures; } my $self = bless \%params, $class; unless ($params{tmp}) { my $uniq = $self->{uniq}; $ALL_TYPES{$uniq} = $self; Scalar::Util::weaken( $ALL_TYPES{$uniq} ); my $tmp = $self; Scalar::Util::weaken($tmp); $Moo::HandleMoose::TYPE_MAP{$self->_stringify_no_magic} = sub { $tmp }; } if (ref($params{coercion}) eq q(CODE)) { require Types::Standard; my $code = delete($params{coercion}); $self->{coercion} = $self->_build_coercion; $self->coercion->add_type_coercions(Types::Standard::Any(), $code); } elsif (ref($params{coercion}) eq q(ARRAY)) { my $arr = delete($params{coercion}); $self->{coercion} = $self->_build_coercion; $self->coercion->add_type_coercions(@$arr); } # Documenting this here because it's too weird to be in the pod. # There's a secret attribute called "_build_coercion" which takes a # coderef. If present, then when $type->coercion is lazy built, # the blank Type::Coercion object gets passed to the coderef, # allowing the coderef to manipulate it a little. This is used by # Types::TypeTiny to allow it to build a coercion for the TypeTiny # type constraint without needing to load Type::Coercion yet. if ($params{my_methods}) { $subname = eval { require Sub::Util } ? \&Sub::Util::set_subname : eval { require Sub::Name } ? \&Sub::Name::subname : 0 if not defined $subname; if ($subname) { (Scalar::Util::reftype($params{my_methods}{$_}) eq 'CODE') && $subname->( sprintf("%s::my_%s", $self->qualified_name, $_), $params{my_methods}{$_}, ) for keys %{$params{my_methods}}; } } return $self; } sub DESTROY { my $self = shift; delete( $ALL_TYPES{$self->{uniq}} ); delete( $Moo::HandleMoose::TYPE_MAP{$self->_stringify_no_magic} ); return; } sub _clone { my $self = shift; my %opts; $opts{$_} = $self->{$_} for qw< name display_name message >; $self->create_child_type(%opts); } sub _stringify_no_magic { sprintf('%s=%s(0x%08x)', blessed($_[0]), Scalar::Util::reftype($_[0]), Scalar::Util::refaddr($_[0])); } our $DD; sub _dd { @_ = $_ unless @_; my ($value) = @_; goto $DD if ref($DD) eq q(CODE); require B; !defined $value ? 'Undef' : !ref $value ? sprintf('Value %s', B::perlstring($value)) : do { my $N = 0 + (defined($DD) ? $DD : 72); require Data::Dumper; local $Data::Dumper::Indent = 0; local $Data::Dumper::Useqq = 1; local $Data::Dumper::Terse = 1; local $Data::Dumper::Sortkeys = 1; local $Data::Dumper::Maxdepth = 2; my $str = Data::Dumper::Dumper($value); $str = substr($str, 0, $N - 12).'...'.substr($str, -1, 1) if length($str) >= $N; "Reference $str"; } } sub _loose_to_TypeTiny { map +( ref($_) ? Types::TypeTiny::to_TypeTiny($_) : do { require Type::Utils; Type::Utils::dwim_type($_) } ), @_; } sub name { $_[0]{name} } sub display_name { $_[0]{display_name} ||= $_[0]->_build_display_name } sub parent { $_[0]{parent} } sub constraint { $_[0]{constraint} ||= $_[0]->_build_constraint } sub compiled_check { $_[0]{compiled_type_constraint} ||= $_[0]->_build_compiled_check } sub coercion { $_[0]{coercion} ||= $_[0]->_build_coercion } sub message { $_[0]{message} } sub library { $_[0]{library} } sub inlined { $_[0]{inlined} } sub deprecated { $_[0]{deprecated} } sub constraint_generator { $_[0]{constraint_generator} } sub inline_generator { $_[0]{inline_generator} } sub name_generator { $_[0]{name_generator} ||= $_[0]->_build_name_generator } sub coercion_generator { $_[0]{coercion_generator} } sub parameters { $_[0]{parameters} } sub moose_type { $_[0]{moose_type} ||= $_[0]->_build_moose_type } sub mouse_type { $_[0]{mouse_type} ||= $_[0]->_build_mouse_type } sub deep_explanation { $_[0]{deep_explanation} } sub my_methods { $_[0]{my_methods} ||= $_[0]->_build_my_methods } sub has_parent { exists $_[0]{parent} } sub has_library { exists $_[0]{library} } sub has_inlined { exists $_[0]{inlined} } sub has_constraint_generator { exists $_[0]{constraint_generator} } sub has_inline_generator { exists $_[0]{inline_generator} } sub has_coercion_generator { exists $_[0]{coercion_generator} } sub has_parameters { exists $_[0]{parameters} } sub has_message { defined $_[0]{message} } sub has_deep_explanation { exists $_[0]{deep_explanation} } sub _default_message { $_[0]{_default_message} ||= $_[0]->_build_default_message } sub has_coercion { $_[0]->coercion if $_[0]{_build_coercion}; # trigger auto build thing $_[0]{coercion} and !!@{ $_[0]{coercion}->type_coercion_map } } sub _assert_coercion { my $self = shift; return $self->coercion if $self->{_build_coercion}; # trigger auto build thing _croak "No coercion for this type constraint" unless $self->has_coercion && @{$self->coercion->type_coercion_map}; $self->coercion; } my $null_constraint = sub { !!1 }; sub _build_display_name { shift->name; } sub _build_constraint { return $null_constraint; } sub _is_null_constraint { shift->constraint == $null_constraint; } sub _build_coercion { require Type::Coercion; my $self = shift; my %opts = (type_constraint => $self); $opts{display_name} = "to_$self" unless $self->is_anon; my $coercion = "Type::Coercion"->new(%opts); $self->{_build_coercion}->($coercion) if ref $self->{_build_coercion}; $coercion; } sub _build_default_message { my $self = shift; $self->{is_using_default_message} = 1; return sub { sprintf '%s did not pass type constraint', _dd($_[0]) } if "$self" eq "__ANON__"; my $name = "$self"; return sub { sprintf '%s did not pass type constraint "%s"', _dd($_[0]), $name }; } sub _build_name_generator { my $self = shift; return sub { my ($s, @a) = @_; sprintf('%s[%s]', $s, join q[,], @a); }; } sub _build_compiled_check { my $self = shift; local our $AvoidCallbacks = 0; if ($self->_is_null_constraint and $self->has_parent) { return $self->parent->compiled_check; } require Eval::TypeTiny; return Eval::TypeTiny::eval_closure( source => sprintf('sub ($) { %s }', $self->inline_check('$_[0]')), description => sprintf("compiled check '%s'", $self), ) if $self->can_be_inlined; my @constraints; push @constraints, $self->parent->compiled_check if $self->has_parent; push @constraints, $self->constraint if !$self->_is_null_constraint; return $null_constraint unless @constraints; return sub ($) { local $_ = $_[0]; for my $c (@constraints) { return unless $c->(@_); } return !!1; }; } sub find_constraining_type { my $self = shift; if ($self->_is_null_constraint and $self->has_parent) { return $self->parent->find_constraining_type; } $self; } our @CMP; sub CMP_SUPERTYPE () { -1 } sub CMP_EQUAL () { 0 } sub CMP_EQUIVALENT () { '0E0' } sub CMP_SUBTYPE () { 1 } sub CMP_UNKNOWN () { ''; } # avoid getting mixed up with cmp operator at compile time *cmp = sub { my ($A, $B) = _loose_to_TypeTiny($_[0], $_[1]); return unless blessed($A) && $A->isa("Type::Tiny"); return unless blessed($B) && $B->isa("Type::Tiny"); for my $comparator (@CMP) { my $result = $comparator->($A, $B); next if $result eq CMP_UNKNOWN; if ($result eq CMP_EQUIVALENT) { my $prefer = @_==3 ? $_[2] : CMP_EQUAL; return $prefer; } return $result; } return CMP_UNKNOWN; }; push @CMP, sub { my ($A, $B) = @_; return CMP_EQUAL if Scalar::Util::refaddr($A) == Scalar::Util::refaddr($B); return CMP_EQUIVALENT if Scalar::Util::refaddr($A->compiled_check) == Scalar::Util::refaddr($B->compiled_check); my $A_stem = $A->find_constraining_type; my $B_stem = $B->find_constraining_type; return CMP_EQUIVALENT if Scalar::Util::refaddr($A_stem) == Scalar::Util::refaddr($B_stem); return CMP_EQUIVALENT if Scalar::Util::refaddr($A_stem->compiled_check) == Scalar::Util::refaddr($B_stem->compiled_check); if ($A_stem->can_be_inlined and $B_stem->can_be_inlined) { return 0 if $A_stem->inline_check('$WOLFIE') eq $B_stem->inline_check('$WOLFIE'); } A_IS_SUBTYPE: { my $A_prime = $A_stem; while ($A_prime->has_parent) { $A_prime = $A_prime->parent; return CMP_SUBTYPE if Scalar::Util::refaddr($A_prime) == Scalar::Util::refaddr($B_stem); return CMP_SUBTYPE if Scalar::Util::refaddr($A_prime->compiled_check) == Scalar::Util::refaddr($B_stem->compiled_check); if ($A_prime->can_be_inlined and $B_stem->can_be_inlined) { return CMP_SUBTYPE if $A_prime->inline_check('$WOLFIE') eq $B_stem->inline_check('$WOLFIE'); } } } B_IS_SUBTYPE: { my $B_prime = $B_stem; while ($B_prime->has_parent) { $B_prime = $B_prime->parent; return CMP_SUPERTYPE if Scalar::Util::refaddr($B_prime) == Scalar::Util::refaddr($A_stem); return CMP_SUPERTYPE if Scalar::Util::refaddr($B_prime->compiled_check) == Scalar::Util::refaddr($A_stem->compiled_check); if ($A_stem->can_be_inlined and $B_prime->can_be_inlined) { return CMP_SUPERTYPE if $B_prime->inline_check('$WOLFIE') eq $A_stem->inline_check('$WOLFIE'); } } } return CMP_UNKNOWN; }; sub equals { my $result = Type::Tiny::cmp($_[0], $_[1]); return unless defined $result; $result eq CMP_EQUAL; } sub is_subtype_of { my $result = Type::Tiny::cmp($_[0], $_[1], CMP_SUBTYPE); return unless defined $result; $result eq CMP_SUBTYPE; } sub is_supertype_of { my $result = Type::Tiny::cmp($_[0], $_[1], CMP_SUBTYPE); return unless defined $result; $result eq CMP_SUPERTYPE; } sub is_a_type_of { my $result = Type::Tiny::cmp($_[0], $_[1]); return unless defined $result; $result eq CMP_SUBTYPE or $result eq CMP_EQUAL or $result eq CMP_EQUIVALENT; } sub strictly_equals { my ($self, $other) = _loose_to_TypeTiny(@_); return unless blessed($self) && $self->isa("Type::Tiny"); return unless blessed($other) && $other->isa("Type::Tiny"); $self->{uniq} == $other->{uniq}; } sub is_strictly_subtype_of { my ($self, $other) = _loose_to_TypeTiny(@_); return unless blessed($self) && $self->isa("Type::Tiny"); return unless blessed($other) && $other->isa("Type::Tiny"); return unless $self->has_parent; $self->parent->strictly_equals($other) or $self->parent->is_strictly_subtype_of($other); } sub is_strictly_supertype_of { my ($self, $other) = _loose_to_TypeTiny(@_); return unless blessed($self) && $self->isa("Type::Tiny"); return unless blessed($other) && $other->isa("Type::Tiny"); $other->is_strictly_subtype_of($self); } sub is_strictly_a_type_of { my ($self, $other) = _loose_to_TypeTiny(@_); return unless blessed($self) && $self->isa("Type::Tiny"); return unless blessed($other) && $other->isa("Type::Tiny"); $self->strictly_equals($other) or $self->is_strictly_subtype_of($other); } sub qualified_name { my $self = shift; (exists $self->{library} and $self->name ne "__ANON__") ? "$self->{library}::$self->{name}" : $self->{name}; } sub is_anon { my $self = shift; $self->name eq "__ANON__"; } sub parents { my $self = shift; return unless $self->has_parent; return ($self->parent, $self->parent->parents); } sub find_parent { my $self = shift; my ($test) = @_; local ($_, $.); my $type = $self; my $count = 0; while ($type) { if ($test->($_=$type, $.=$count)) { return wantarray ? ($type, $count) : $type; } else { $type = $type->parent; $count++; } } return; } sub check { my $self = shift; ($self->{compiled_type_constraint} ||= $self->_build_compiled_check)->(@_); } sub _strict_check { my $self = shift; local $_ = $_[0]; my @constraints = reverse map { $_->constraint } grep { not $_->_is_null_constraint } ($self, $self->parents); for my $c (@constraints) { return unless $c->(@_); } return !!1; } sub get_message { my $self = shift; local $_ = $_[0]; $self->has_message ? $self->message->(@_) : $self->_default_message->(@_); } sub validate { my $self = shift; return undef if ($self->{compiled_type_constraint} ||= $self->_build_compiled_check)->(@_); local $_ = $_[0]; return $self->get_message(@_); } sub validate_explain { my $self = shift; my ($value, $varname) = @_; $varname = '$_' unless defined $varname; return undef if $self->check($value); if ($self->has_parent) { my $parent = $self->parent->validate_explain($value, $varname); return [ sprintf('"%s" is a subtype of "%s"', $self, $self->parent), @$parent ] if $parent; } my $message = sprintf( '%s%s', $self->get_message($value), $varname eq q{$_} ? '' : sprintf(' (in %s)', $varname), ); if ($self->is_parameterized and $self->parent->has_deep_explanation) { my $deep = $self->parent->deep_explanation->($self, $value, $varname); return [ $message, @$deep ] if $deep; } return [ $message, sprintf('"%s" is defined as: %s', $self, $self->_perlcode) ]; } my $b; sub _perlcode { my $self = shift; local our $AvoidCallbacks = 1; return $self->inline_check('$_') if $self->can_be_inlined; $b ||= do { require B::Deparse; my $tmp = "B::Deparse"->new; $tmp->ambient_pragmas(strict => "all", warnings => "all") if $tmp->can('ambient_pragmas'); $tmp; }; my $code = $b->coderef2text($self->constraint); $code =~ s/\s+/ /g; return "sub $code"; } sub assert_valid { my $self = shift; return !!1 if ($self->{compiled_type_constraint} ||= $self->_build_compiled_check)->(@_); local $_ = $_[0]; $self->_failed_check("$self", $_); } sub assert_return { my $self = shift; return $_[0] if ($self->{compiled_type_constraint} ||= $self->_build_compiled_check)->(@_); local $_ = $_[0]; $self->_failed_check("$self", $_); } sub can_be_inlined { my $self = shift; return $self->parent->can_be_inlined if $self->has_parent && $self->_is_null_constraint; return !!1 if !$self->has_parent && $self->_is_null_constraint; return $self->has_inlined; } sub inline_check { my $self = shift; _croak 'Cannot inline type constraint check for "%s"', $self unless $self->can_be_inlined; return $self->parent->inline_check(@_) if $self->has_parent && $self->_is_null_constraint; return '(!!1)' if !$self->has_parent && $self->_is_null_constraint; local $_ = $_[0]; my @r = $self->inlined->($self, @_); if (@r and not defined $r[0]) { _croak 'Inlining type constraint check for "%s" returned undef!', $self unless $self->has_parent; $r[0] = $self->parent->inline_check(@_); } my $r = join " && " => map { /[;{}]/ && !/\Ado \{.+\}\z/ ? "do { $_ }" : "($_)" } @r; return @r==1 ? $r : "($r)"; } sub inline_assert { require B; my $self = shift; my ($varname, $typevarname, %extras) = @_; my $inline_check; if ($self->can_be_inlined) { $inline_check = sprintf('(%s)', $self->inline_check($varname)); } elsif ($typevarname) { $inline_check = sprintf('%s->check(%s)', $typevarname, $varname); } else { _croak 'Cannot inline type constraint check for "%s"', $self; } my $do_wrapper = !delete $extras{no_wrapper}; my $inline_throw; if ($typevarname) { $inline_throw = sprintf( 'Type::Tiny::_failed_check(%s, %s, %s, %s)', $typevarname, B::perlstring("$self"), $varname, join(',', map +(B::perlstring($_) => B::perlstring($extras{$_})), sort keys %extras), ); } else { $inline_throw = sprintf( 'Type::Tiny::_failed_check(%s, %s, %s, %s)', $self->{uniq}, B::perlstring("$self"), $varname, join(',', map +(B::perlstring($_) => B::perlstring($extras{$_})), sort keys %extras), ); } $do_wrapper ? qq[do { no warnings "void"; $inline_check or $inline_throw; $varname };] : qq[ no warnings "void"; $inline_check or $inline_throw; $varname ] } sub _failed_check { require Error::TypeTiny::Assertion; my ($self, $name, $value, %attrs) = @_; $self = $ALL_TYPES{$self} if defined $self && !ref $self; my $exception_class = delete($attrs{exception_class}) || "Error::TypeTiny::Assertion"; if ($self) { $exception_class->throw( message => $self->get_message($value), type => $self, value => $value, %attrs, ); } else { $exception_class->throw( message => sprintf('%s did not pass type constraint "%s"', _dd($value), $name), value => $value, %attrs, ); } } sub coerce { my $self = shift; $self->_assert_coercion->coerce(@_); } sub assert_coerce { my $self = shift; $self->_assert_coercion->assert_coerce(@_); } sub is_parameterizable { shift->has_constraint_generator; } sub is_parameterized { shift->has_parameters; } { my %seen; sub ____make_key { join ',', map { Types::TypeTiny::TypeTiny->check($_) ? sprintf('$Type::Tiny::ALL_TYPES{%d}', $_->{uniq}) : ref() eq 'ARRAY' ? do { $seen{$_}++ ? '____CANNOT_KEY____' : sprintf('[%s]', ____make_key(@$_)) } : ref() eq 'HASH' ? do { $seen{$_}++ ? '____CANNOT_KEY____' : sprintf('{%s}', ____make_key(%$_)) } : ref() eq 'SCALAR' || ref() eq 'REF' ? do { $seen{$_}++ ? '____CANNOT_KEY____' : sprintf('do { my $x = %s; \\$x }', ____make_key($$_)) } : !defined() ? 'undef' : !ref() ? do { require B; B::perlstring($_) } : '____CANNOT_KEY____'; } @_; } my %param_cache; sub parameterize { my $self = shift; $self->is_parameterizable or @_ ? _croak("Type '%s' does not accept parameters", "$self") : return($self); @_ = map Types::TypeTiny::to_TypeTiny($_), @_; # Generate a key for caching parameterized type constraints, # but only if all the parameters are strings or type constraints. %seen = (); my $key = $self->____make_key(@_); undef($key) if $key =~ /____CANNOT_KEY____/; return $param_cache{$key} if defined $key && defined $param_cache{$key}; local $Type::Tiny::parameterize_type = $self; local $_ = $_[0]; my $P; my ($constraint, $compiled) = $self->constraint_generator->(@_); if (Types::TypeTiny::TypeTiny->check($constraint)) { $P = $constraint; } else { my %options = ( constraint => $constraint, display_name => $self->name_generator->($self, @_), parameters => [@_], ); $options{compiled_type_constraint} = $compiled if $compiled; $options{inlined} = $self->inline_generator->(@_) if $self->has_inline_generator; exists $options{$_} && !defined $options{$_} && delete $options{$_} for keys %options; $P = $self->create_child_type(%options); my $coercion; $coercion = $self->coercion_generator->($self, $P, @_) if $self->has_coercion_generator; $P->coercion->add_type_coercions( @{$coercion->type_coercion_map} ) if $coercion; } if (defined $key) { $param_cache{$key} = $P; Scalar::Util::weaken($param_cache{$key}); } $P->coercion->freeze; return $P; } } sub child_type_class { __PACKAGE__; } sub create_child_type { my $self = shift; my %moreopts; $moreopts{is_object} = 1 if $self->{is_object}; return $self->child_type_class->new(parent => $self, %moreopts, @_); } sub complementary_type { my $self = shift; my $r = ($self->{complementary_type} ||= $self->_build_complementary_type); Scalar::Util::weaken($self->{complementary_type}) unless Scalar::Util::isweak($self->{complementary_type}); return $r; } sub _build_complementary_type { my $self = shift; my %opts = ( constraint => sub { not $self->check($_) }, display_name => sprintf("~%s", $self), ); $opts{display_name} =~ s/^\~{2}//; $opts{inlined} = sub { shift; "not(".$self->inline_check(@_).")" } if $self->can_be_inlined; $opts{display_name} = $opts{name} = $self->{complement_name} if $self->{complement_name}; return "Type::Tiny"->new(%opts); } sub _instantiate_moose_type { my $self = shift; my %opts = @_; require Moose::Meta::TypeConstraint; return "Moose::Meta::TypeConstraint"->new(%opts); } sub _build_moose_type { my $self = shift; my $r; if ($self->{_is_core}) { require Moose::Util::TypeConstraints; $r = Moose::Util::TypeConstraints::find_type_constraint($self->name); $r->{"Types::TypeTiny::to_TypeTiny"} = $self; Scalar::Util::weaken($r->{"Types::TypeTiny::to_TypeTiny"}); } else { # Type::Tiny is more flexible than Moose, allowing # inlined to return a list. So we need to wrap the # inlined coderef to make sure Moose gets a single # string. # my $wrapped_inlined = sub { shift; $self->inline_check(@_); }; my %opts; $opts{name} = $self->qualified_name if $self->has_library && !$self->is_anon; $opts{parent} = $self->parent->moose_type if $self->has_parent; $opts{constraint} = $self->constraint unless $self->_is_null_constraint; $opts{message} = $self->message if $self->has_message; $opts{inlined} = $wrapped_inlined if $self->has_inlined; $r = $self->_instantiate_moose_type(%opts); $r->{"Types::TypeTiny::to_TypeTiny"} = $self; $self->{moose_type} = $r; # prevent recursion $r->coercion($self->coercion->moose_coercion) if $self->has_coercion; } return $r; } sub _build_mouse_type { my $self = shift; my %options; $options{name} = $self->qualified_name if $self->has_library && !$self->is_anon; $options{parent} = $self->parent->mouse_type if $self->has_parent; $options{constraint} = $self->constraint unless $self->_is_null_constraint; $options{message} = $self->message if $self->has_message; require Mouse::Meta::TypeConstraint; my $r = "Mouse::Meta::TypeConstraint"->new(%options); $self->{mouse_type} = $r; # prevent recursion $r->_add_type_coercions( $self->coercion->freeze->_codelike_type_coercion_map('mouse_type') ) if $self->has_coercion; return $r; } sub _process_coercion_list { my $self = shift; my @pairs; while (@_) { my $next = shift; if (blessed($next) and $next->isa('Type::Coercion') and $next->is_parameterized) { push @pairs => ( @{ $next->_reparameterize($self)->type_coercion_map } ); } elsif (blessed($next) and $next->can('type_coercion_map')) { push @pairs => ( @{ $next->type_coercion_map }, ); } elsif (ref($next) eq q(ARRAY)) { unshift @_, @$next; } else { push @pairs => ( Types::TypeTiny::to_TypeTiny($next), shift, ); } } return @pairs; } sub plus_coercions { my $self = shift; my $new = $self->_clone; $new->coercion->add_type_coercions( $self->_process_coercion_list(@_), @{$self->coercion->type_coercion_map}, ); $new->coercion->freeze; return $new; } sub plus_fallback_coercions { my $self = shift; my $new = $self->_clone; $new->coercion->add_type_coercions( @{$self->coercion->type_coercion_map}, $self->_process_coercion_list(@_), ); $new->coercion->freeze; return $new; } sub minus_coercions { my $self = shift; my $new = $self->_clone; my @not = grep Types::TypeTiny::TypeTiny->check($_), $self->_process_coercion_list($new, @_); my @keep; my $c = $self->coercion->type_coercion_map; for (my $i = 0; $i <= $#$c; $i += 2) { my $keep_this = 1; NOT: for my $n (@not) { if ($c->[$i] == $n) { $keep_this = 0; last NOT; } } push @keep, $c->[$i], $c->[$i+1] if $keep_this; } $new->coercion->add_type_coercions(@keep); $new->coercion->freeze; return $new; } sub no_coercions { my $new = shift->_clone; $new->coercion->freeze; $new; } sub coercibles { my $self = shift; $self->has_coercion ? $self->coercion->_source_type_union : $self; } sub isa { my $self = shift; if ($INC{"Moose.pm"} and ref($self) and $_[0] =~ /^(?:Class::MOP|MooseX?::Meta)::(.+)$/) { my $meta = $1; return !!1 if $meta eq 'TypeConstraint'; return $self->is_parameterized if $meta eq 'TypeConstraint::Parameterized'; return $self->is_parameterizable if $meta eq 'TypeConstraint::Parameterizable'; return $self->isa('Type::Tiny::Union') if $meta eq 'TypeConstraint::Union'; my $inflate = $self->moose_type; return $inflate->isa(@_); } if ($INC{"Mouse.pm"} and ref($self) and $_[0] eq 'Mouse::Meta::TypeConstraint') { return !!1; } $self->SUPER::isa(@_); } sub _build_my_methods { return {}; } sub _lookup_my_method { my $self = shift; my ($name) = @_; if ($self->my_methods->{$name}) { return $self->my_methods->{$name}; } if ($self->has_parent) { return $self->parent->_lookup_my_method(@_); } return; } my %object_methods = (with_attribute_values => 1, stringifies_to => 1, numifies_to => 1); sub can { my $self = shift; return !!0 if $_[0] eq 'type_parameter' && blessed($_[0]) && $_[0]->has_parameters; my $can = $self->SUPER::can(@_); return $can if $can; if (ref($self)) { if ($INC{"Moose.pm"}) { my $method = $self->moose_type->can(@_); return sub { shift->moose_type->$method(@_) } if $method; } if ($_[0] =~ /\Amy_(.+)\z/) { my $method = $self->_lookup_my_method($1); return $method if $method; } } if ($self->{is_object} && $object_methods{$_[0]}) { require Type::Tiny::ConstrainedObject; return Type::Tiny::ConstrainedObject->can($_[0]); } return; } sub AUTOLOAD { my $self = shift; my ($m) = (our $AUTOLOAD =~ /::(\w+)$/); return if $m eq 'DESTROY'; if (ref($self)) { if ($INC{"Moose.pm"}) { my $method = $self->moose_type->can($m); return $self->moose_type->$method(@_) if $method; } if ($m =~ /\Amy_(.+)\z/) { my $method = $self->_lookup_my_method($1); return &$method($self, @_) if $method; } } if ($self->{is_object} && $object_methods{$m}) { require Type::Tiny::ConstrainedObject; unshift @_, $self; no strict 'refs'; goto \&{"Type::Tiny::ConstrainedObject::$m"}; } _croak q[Can't locate object method "%s" via package "%s"], $m, ref($self)||$self; } sub DOES { my $self = shift; return !!1 if ref($self) && $_[0] =~ m{^ Type::API::Constraint (?: ::Coercible | ::Inlinable )? $}x; return !!1 if !ref($self) && $_[0] eq 'Type::API::Constraint::Constructor'; "UNIVERSAL"->can("DOES") ? $self->SUPER::DOES(@_) : $self->isa(@_); } sub _has_xsub { require B; !!B::svref_2object( shift->compiled_check )->XSUB; } sub of { shift->parameterize(@_) } sub where { shift->create_child_type(constraint => @_) } # fill out Moose-compatible API sub inline_environment { +{} } sub _inline_check { shift->inline_check(@_) } sub _compiled_type_constraint { shift->compiled_check(@_) } sub meta { _croak("Not really a Moose::Meta::TypeConstraint. Sorry!") } sub compile_type_constraint { shift->compiled_check } sub _actually_compile_type_constraint { shift->_build_compiled_check } sub hand_optimized_type_constraint { shift->{hand_optimized_type_constraint} } sub has_hand_optimized_type_constraint { exists(shift->{hand_optimized_type_constraint}) } sub type_parameter { (shift->parameters || [])->[0] } sub parameterized_from { $_[0]->is_parameterized ? shift->parent : _croak("Not a parameterized type") } sub has_parameterized_from { $_[0]->is_parameterized } # some stuff for Mouse-compatible API sub __is_parameterized { shift->is_parameterized(@_) } sub _add_type_coercions { shift->coercion->add_type_coercions(@_) }; sub _as_string { shift->qualified_name(@_) } sub _compiled_type_coercion { shift->coercion->compiled_coercion(@_) }; sub _identity { Scalar::Util::refaddr(shift) }; sub _unite { require Type::Tiny::Union; "Type::Tiny::Union"->new(type_constraints => \@_) }; # Hooks for Type::Tie sub TIESCALAR { require Type::Tie; unshift @_, 'Type::Tie::SCALAR'; goto \&Type::Tie::SCALAR::TIESCALAR }; sub TIEARRAY { require Type::Tie; unshift @_, 'Type::Tie::ARRAY'; goto \&Type::Tie::ARRAY::TIEARRAY }; sub TIEHASH { require Type::Tie; unshift @_, 'Type::Tie::HASH'; goto \&Type::Tie::HASH::TIEHASH }; 1; __END__ =pod =encoding utf-8 =for stopwords Moo(se)-compatible MooseX MouseX MooX Moose-compat invocant =head1 NAME Type::Tiny - tiny, yet Moo(se)-compatible type constraint =head1 SYNOPSIS use v5.12; use strict; use warnings; package Horse { use Moo; use Types::Standard qw( Str Int Enum ArrayRef Object ); use Type::Params qw( compile ); use namespace::autoclean; has name => ( is => 'ro', isa => Str, required => 1, ); has gender => ( is => 'ro', isa => Enum[qw( f m )], ); has age => ( is => 'rw', isa => Int->where( '$_ >= 0' ), ); has children => ( is => 'ro', isa => ArrayRef[Object], default => sub { return [] }, ); sub add_child { state $check = compile( Object, Object ); # method signature my ($self, $child) = $check->(@_); # unpack @_ push @{ $self->children }, $child; return $self; } } package main; my $boldruler = Horse->new( name => "Bold Ruler", gender => 'm', age => 16, ); my $secretariat = Horse->new( name => "Secretariat", gender => 'm', age => 0, ); $boldruler->add_child( $secretariat ); =head1 STATUS This module is covered by the L. =head1 DESCRIPTION This documents the internals of the L class. L is a better starting place if you're new. L is a small class for creating Moose-like type constraint objects which are compatible with Moo, Moose and Mouse. use Scalar::Util qw(looks_like_number); use Type::Tiny; my $NUM = "Type::Tiny"->new( name => "Number", constraint => sub { looks_like_number($_) }, message => sub { "$_ ain't a number" }, ); package Ermintrude { use Moo; has favourite_number => (is => "ro", isa => $NUM); } package Bullwinkle { use Moose; has favourite_number => (is => "ro", isa => $NUM); } package Maisy { use Mouse; has favourite_number => (is => "ro", isa => $NUM); } Maybe now we won't need to have separate MooseX, MouseX and MooX versions of everything? We can but hope... =head2 Constructor =over =item C<< new(%attributes) >> Moose-style constructor function. =back =head2 Attributes Attributes are named values that may be passed to the constructor. For each attribute, there is a corresponding reader method. For example: my $type = Type::Tiny->new( name => "Foo" ); print $type->name, "\n"; # says "Foo" =head3 Important attributes These are the attributes you are likely to be most interested in providing when creating your own type constraints, and most interested in reading when dealing with type constraint objects. =over =item C<< constraint >> Coderef to validate a value (C<< $_ >>) against the type constraint. The coderef will not be called unless the value is known to pass any parent type constraint (see C below). Alternatively, a string of Perl code checking C<< $_ >> can be passed as a parameter to the constructor, and will be converted to a coderef. Defaults to C<< sub { 1 } >> - i.e. a coderef that passes all values. =item C<< parent >> Optional attribute; parent type constraint. For example, an "Integer" type constraint might have a parent "Number". If provided, must be a Type::Tiny object. =item C<< inlined >> A coderef which returns a string of Perl code suitable for inlining this type. Optional. (The coderef will be called in list context and can actually return a list of strings which will be joined with C<< && >>. If the first item on the list is undef, it will be substituted with the type's parent's inline check.) If C (above) is a coderef generated via L, then Type::Tiny I be able to automatically generate C for you. If C (above) is a string, it will be able to. =item C<< name >> The name of the type constraint. These need to conform to certain naming rules (they must begin with an uppercase letter and continue using only letters, digits 0-9 and underscores). Optional; if not supplied will be an anonymous type constraint. =item C<< display_name >> A name to display for the type constraint when stringified. These don't have to conform to any naming rules. Optional; a default name will be calculated from the C. =item C<< library >> The package name of the type library this type is associated with. Optional. Informational only: setting this attribute does not install the type into the package. =item C<< deprecated >> Optional boolean indicating whether a type constraint is deprecated. L will issue a warning if you attempt to import a deprecated type constraint, but otherwise the type will continue to function as normal. There will not be deprecation warnings every time you validate a value, for instance. If omitted, defaults to the parent's deprecation status (or false if there's no parent). =item C<< message >> Coderef that returns an error message when C<< $_ >> does not validate against the type constraint. Optional (there's a vaguely sensible default.) =item C<< coercion >> A L object associated with this type. Generally speaking this attribute should not be passed to the constructor; you should rely on the default lazily-built coercion object. You may pass C<< coercion => 1 >> to the constructor to inherit coercions from the constraint's parent. (This requires the parent constraint to have a coercion.) =item C<< my_methods >> Experimenal hashref of additional methods that can be called on the type constraint object. =back =head3 Attributes related to parameterizable and parameterized types The following additional attributes are used for parameterizable (e.g. C) and parameterized (e.g. C<< ArrayRef[Int] >>) type constraints. Unlike Moose, these aren't handled by separate subclasses. =over =item C<< constraint_generator >> Coderef that is called when a type constraint is parameterized. When called, it is passed the list of parameters, though any parameter which looks like a foreign type constraint (Moose type constraints, Mouse type constraints, etc, I<< and coderefs(!!!) >>) is first coerced to a native Type::Tiny object. Note that for compatibility with the Moose API, the base type is I passed to the constraint generator, but can be found in the package variable C<< $Type::Tiny::parameterize_type >>. The first parameter is also available as C<< $_ >>. Types I be parameterized with an empty parameter list. For example, in L, C is just an alias for C but C<< Tuple[] >> will only allow zero-length arrayrefs to pass the constraint. If you wish C<< YourType >> and C<< YourType[] >> to mean the same thing, then do: return $Type::Tiny::parameterize_type unless @_; The constraint generator should generate and return a new constraint coderef based on the parameters. Alternatively, the constraint generator can return a fully-formed Type::Tiny object, in which case the C, C, and C attributes documented below are ignored. Optional; providing a generator makes this type into a parameterizable type constraint. If there is no generator, attempting to parameterize the type constraint will throw an exception. =item C<< name_generator >> A coderef which generates a new display_name based on parameters. Called with the same parameters and package variables as the C. Expected to return a string. Optional; the default is reasonable. =item C<< inline_generator >> A coderef which generates a new inlining coderef based on parameters. Called with the same parameters and package variables as the C. Expected to return a coderef. Optional. =item C<< coercion_generator >> A coderef which generates a new L object based on parameters. Called with the same parameters and package variables as the C. Expected to return a blessed object. Optional. =item C<< deep_explanation >> This API is not finalized. Coderef used by L to peek inside parameterized types and figure out why a value doesn't pass the constraint. =item C<< parameters >> In parameterized types, returns an arrayref of the parameters. =back =head3 Lazy generated attributes The following attributes should not be usually passed to the constructor; unless you're doing something especially unusual, you should rely on the default lazily-built return values. =over =item C<< compiled_check >> Coderef to validate a value (C<< $_[0] >>) against the type constraint. This coderef is expected to also handle all validation for the parent type constraints. =item C<< complementary_type >> A complementary type for this type. For example, the complementary type for an integer type would be all things that are not integers, including floating point numbers, but also alphabetic strings, arrayrefs, filehandles, etc. =item C<< moose_type >>, C<< mouse_type >> Objects equivalent to this type constraint, but as a L or L. It should rarely be necessary to obtain a L object from L because the L object itself should be usable pretty much anywhere a L is expected. =back =head2 Methods =head3 Predicate methods These methods return booleans indicating information about the type constraint. They are each tightly associated with a particular attribute. (See L.) =over =item C, C, C, C, C, C, C, C, C Simple Moose-style predicate methods indicating the presence or absence of an attribute. =item C Predicate method with a little extra DWIM. Returns false if the coercion is a no-op. =item C<< is_anon >> Returns true iff the type constraint does not have a C. =item C<< is_parameterized >>, C<< is_parameterizable >> Indicates whether a type has been parameterized (e.g. C<< ArrayRef[Int] >>) or could potentially be (e.g. C<< ArrayRef >>). =item C<< has_parameterized_from >> Useless alias for C. =back =head3 Validation and coercion The following methods are used for coercing and validating values against a type constraint: =over =item C<< check($value) >> Returns true iff the value passes the type constraint. =item C<< validate($value) >> Returns the error message for the value; returns an explicit undef if the value passes the type constraint. =item C<< assert_valid($value) >> Like C<< check($value) >> but dies if the value does not pass the type constraint. Yes, that's three very similar methods. Blame L whose API I'm attempting to emulate. :-) =item C<< assert_return($value) >> Like C<< assert_valid($value) >> but returns the value if it passes the type constraint. This seems a more useful behaviour than C<< assert_valid($value) >>. I would have just changed C<< assert_valid($value) >> to do this, except that there are edge cases where it could break Moose compatibility. =item C<< get_message($value) >> Returns the error message for the value; even if the value passes the type constraint. =item C<< validate_explain($value, $varname) >> Like C but instead of a string error message, returns an arrayref of strings explaining the reasoning why the value does not meet the type constraint, examining parent types, etc. The C<< $varname >> is an optional string like C<< '$foo' >> indicating the name of the variable being checked. =item C<< coerce($value) >> Attempt to coerce C<< $value >> to this type. =item C<< assert_coerce($value) >> Attempt to coerce C<< $value >> to this type. Throws an exception if this is not possible. =back =head3 Child type constraint creation and parameterization These methods generate new type constraint objects that inherit from the constraint they are called upon: =over =item C<< create_child_type(%attributes) >> Construct a new Type::Tiny object with this object as its parent. =item C<< where($coderef) >> Shortcut for creating an anonymous child type constraint. Use it like C<< HashRef->where(sub { exists($_->{name}) }) >>. That said, you can get a similar result using overloaded C<< & >>: HashRef & sub { exists($_->{name}) } Like the C<< constraint >> attribute, this will accept a string of Perl code: HashRef->where('exists($_->{name})') =item C<< child_type_class >> The class that create_child_type will construct by default. =item C<< parameterize(@parameters) >> Creates a new parameterized type; throws an exception if called on a non-parameterizable type. =item C<< of(@parameters) >> A cute alias for C. Use it like C<< ArrayRef->of(Int) >>. =item C<< plus_coercions($type1, $code1, ...) >> Shorthand for creating a new child type constraint with the same coercions as this one, but then adding some extra coercions (at a higher priority than the existing ones). =item C<< plus_fallback_coercions($type1, $code1, ...) >> Like C, but added at a lower priority. =item C<< minus_coercions($type1, ...) >> Shorthand for creating a new child type constraint with fewer type coercions. =item C<< no_coercions >> Shorthand for creating a new child type constraint with no coercions at all. =back =head3 Type relationship introspection methods These methods allow you to determine a type constraint's relationship to other type constraints in an organised hierarchy: =over =item C<< equals($other) >>, C<< is_subtype_of($other) >>, C<< is_supertype_of($other) >>, C<< is_a_type_of($other) >> Compare two types. See L for what these all mean. (OK, Moose doesn't define C, but you get the idea, right?) Note that these have a slightly DWIM side to them. If you create two L objects which test the same class, they're considered equal. And: my $subtype_of_Num = Types::Standard::Num->create_child_type; my $subtype_of_Int = Types::Standard::Int->create_child_type; $subtype_of_Int->is_subtype_of( $subtype_of_Num ); # true =item C<< strictly_equals($other) >>, C<< is_strictly_subtype_of($other) >>, C<< is_strictly_supertype_of($other) >>, C<< is_strictly_a_type_of($other) >> Stricter versions of the type comparison functions. These only care about explicit inheritance via C. my $subtype_of_Num = Types::Standard::Num->create_child_type; my $subtype_of_Int = Types::Standard::Int->create_child_type; $subtype_of_Int->is_strictly_subtype_of( $subtype_of_Num ); # false =item C<< parents >> Returns a list of all this type constraint's ancestor constraints. For example, if called on the C type constraint would return the list C<< (Value, Defined, Item, Any) >>. I<< Due to a historical misunderstanding, this differs from the Moose implementation of the C method. In Moose, C only returns the immediate parent type constraints, and because type constraints only have one immediate parent, this is effectively an alias for C. The extension module L is the only place where multiple type constraints are returned; and they are returned as an arrayref in violation of the base class' documentation. I'm keeping my behaviour as it seems more useful. >> =item C<< find_parent($coderef) >> Loops through the parent type constraints I<< including the invocant itself >> and returns the nearest ancestor type constraint where the coderef evaluates to true. Within the coderef the ancestor currently being checked is C<< $_ >>. Returns undef if there is no match. In list context also returns the number of type constraints which had been looped through before the matching constraint was found. =item C<< find_constraining_type >> Finds the nearest ancestor type constraint (including the type itself) which has a C coderef. Equivalent to: $type->find_parent(sub { not $_->_is_null_constraint }) =item C<< coercibles >> Return a type constraint which is the union of type constraints that can be coerced to this one (including this one). If this type constraint has no coercions, returns itself. =item C<< type_parameter >> In parameterized type constraints, returns the first item on the list of parameters; otherwise returns undef. For example: ( ArrayRef[Int] )->type_parameter; # returns Int ( ArrayRef[Int] )->parent; # returns ArrayRef Note that parameterizable type constraints can perfectly legitimately take multiple parameters (several of the parameterizable type constraints in L do). This method only returns the first such parameter. L documents the C attribute, which returns an arrayref of all the parameters. =item C<< parameterized_from >> Harder to spell alias for C that only works for parameterized types. =back I<< Hint for people subclassing Type::Tiny: >> Since version 1.006000, the methods for determining subtype, supertype, and type equality should I be overridden in subclasses of Type::Tiny. This is because of the problem of diamond inheritance. If X and Y are both subclasses of Type::Tiny, they I need to be consulted to figure out how type constraints are related; not just one of them should be overriding these methods. See the source code for L for an example of how subclasses can give hints about type relationships to Type::Tiny. Summary: push a coderef onto C<< @Type::Tiny::CMP >>. This coderef will be passed two type constraints. It should then return one of the constants Type::Tiny::CMP_SUBTYPE (first type is a subtype of second type), Type::Tiny::CMP_SUPERTYPE (second type is a subtype of first type), Type::Tiny::CMP_EQUAL (the two types are exactly the same), Type::Tiny::CMP_EQUIVALENT (the two types are effectively the same), or Type::Tiny::CMP_UNKNOWN (your coderef couldn't establish any relationship). =head3 Type relationship introspection function =over =item C<< Type::Tiny::cmp($type1, $type2) >> The subtype/supertype relationship between types results in a partial ordering of type constraints. This function will return one of the constants: Type::Tiny::CMP_SUBTYPE (first type is a subtype of second type), Type::Tiny::CMP_SUPERTYPE (second type is a subtype of first type), Type::Tiny::CMP_EQUAL (the two types are exactly the same), Type::Tiny::CMP_EQUIVALENT (the two types are effectively the same), or Type::Tiny::CMP_UNKNOWN (couldn't establish any relationship). In numeric contexts, these evaluate to -1, 1, 0, 0, and 0, making it potentially usable with C (though you may need to silence warnings about treating the empty string as a numeric value). =back =head3 Inlining methods =for stopwords uated The following methods are used to generate strings of Perl code which may be pasted into stringy Cuated subs to perform type checks: =over =item C<< can_be_inlined >> Returns boolean indicating if this type can be inlined. =item C<< inline_check($varname) >> Creates a type constraint check for a particular variable as a string of Perl code. For example: print( Types::Standard::Num->inline_check('$foo') ); prints the following output: (!ref($foo) && Scalar::Util::looks_like_number($foo)) For Moose-compat, there is an alias C<< _inline_check >> for this method. =item C<< inline_assert($varname) >> Much like C but outputs a statement of the form: ... or die ...; Can also be called line C<< inline_assert($varname, $typevarname, %extras) >>. In this case, it will generate a string of code that may include C<< $typevarname >> which is supposed to be the name of a variable holding the type itself. (This is kinda complicated, but it allows a useful string to still be produced if the type is not inlineable.) The C<< %extras >> are additional options to be passed to L's constructor and must be key-value pairs of strings only, no references or undefs. =back =head3 Other methods =over =item C<< qualified_name >> For non-anonymous type constraints that have a library, returns a qualified C<< "MyLib::MyType" >> sort of name. Otherwise, returns the same as C. =item C<< isa($class) >>, C<< can($method) >>, C<< AUTOLOAD(@args) >> If Moose is loaded, then the combination of these methods is used to mock a Moose::Meta::TypeConstraint. If Mouse is loaded, then C mocks Mouse::Meta::TypeConstraint. =item C<< DOES($role) >> Overridden to advertise support for various roles. See also L, etc. =item C<< TIESCALAR >>, C<< TIEARRAY >>, C<< TIEHASH >> These are provided as hooks that wrap L. (Type::Tie is distributed separately, and can be used with non-Type::Tiny type constraints too.) They allow the following to work: use Types::Standard qw(Int); tie my @list, Int; push @list, 123, 456; # ok push @list, "Hello"; # dies =back The following methods exist for Moose/Mouse compatibility, but do not do anything useful. =over =item C<< compile_type_constraint >> =item C<< hand_optimized_type_constraint >> =item C<< has_hand_optimized_type_constraint >> =item C<< inline_environment >> =item C<< meta >> =back =head2 Overloading =over =item * Stringification is overloaded to return the qualified name. =item * Boolification is overloaded to always return true. =item * Coderefification is overloaded to call C. =item * On Perl 5.10.1 and above, smart match is overloaded to call C. =item * The C<< == >> operator is overloaded to call C. =item * The C<< < >> and C<< > >> operators are overloaded to call C and C. =item * The C<< ~ >> operator is overloaded to call C. =item * The C<< | >> operator is overloaded to build a union of two type constraints. See L. =item * The C<< & >> operator is overloaded to build the intersection of two type constraints. See L. =back Previous versions of Type::Tiny would overload the C<< + >> operator to call C or C as appropriate. Support for this was dropped after 0.040. =head2 Constants =over =item C<< Type::Tiny::SUPPORT_SMARTMATCH >> Indicates whether the smart match overload is supported on your version of Perl. =back =head2 Package Variables =over =item C<< $Type::Tiny::DD >> This undef by default but may be set to a coderef that Type::Tiny and related modules will use to dump data structures in things like error messages. Otherwise Type::Tiny uses it's own routine to dump data structures. C<< $DD >> may then be set to a number to limit the lengths of the dumps. (Default limit is 72.) This is a package variable (rather than get/set class methods) to allow for easy localization. =item C<< $Type::Tiny::AvoidCallbacks >> If this variable is set to true (you should usually do it in a C scope), it acts as a hint for type constraints, when generating inlined code, to avoid making any callbacks to variables and functions defined outside the inlined code itself. This should have the effect that C<< $type->inline_check('$foo') >> will return a string of code capable of checking the type on Perl installations that don't have Type::Tiny installed. This is intended to allow Type::Tiny to be used with things like L. The variable works on the honour system. Types need to explicitly check it and decide to generate different code based on its truth value. The bundled types in L, L, and L all do. (B is sometimes unable to, and will issue a warning if it needs to rely on callbacks when asked not to.) Most normal users can ignore this. =back =head2 Environment =over =item C Currently this has more effect on L than Type::Tiny. In future it may be used to trigger or suppress the loading XS implementations of parts of Type::Tiny. =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. L, L. L, L, L, L. L, L, L, L, L, L. L, L. L. L, L, L, L, L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 THANKS Thanks to Matt S Trout for advice on L integration. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Utils.pm000644001750001750 6433313601673061 15563 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Typepackage Type::Utils; use 5.006001; use strict; use warnings; BEGIN { $Type::Utils::AUTHORITY = 'cpan:TOBYINK'; $Type::Utils::VERSION = '1.008001'; } $Type::Utils::VERSION =~ tr/_//d; sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } use Scalar::Util qw< blessed >; use Type::Library; use Type::Tiny; use Types::TypeTiny qw< TypeTiny to_TypeTiny HashLike StringLike CodeLike >; our @EXPORT = qw< declare as where message inline_as class_type role_type duck_type union intersection enum coerce from via declare_coercion to_type >; our @EXPORT_OK = ( @EXPORT, qw< extends type subtype match_on_type compile_match_on_type dwim_type english_list classifier >, ); require Exporter::Tiny; our @ISA = 'Exporter::Tiny'; sub extends { _croak "Not a type library" unless caller->isa("Type::Library"); my $caller = caller->meta; foreach my $lib (@_) { eval "use $lib; 1" or _croak "Could not load library '$lib': $@"; if ($lib->isa("Type::Library") or $lib eq 'Types::TypeTiny') { $caller->add_type( $lib->get_type($_) ) for sort $lib->meta->type_names; $caller->add_coercion( $lib->get_coercion($_) ) for sort $lib->meta->coercion_names; } elsif ($lib->isa('MooseX::Types::Base')) { require Moose::Util::TypeConstraints; my $types = $lib->type_storage; for my $name (sort keys %$types) { my $moose = Moose::Util::TypeConstraints::find_type_constraint($types->{$name}); my $tt = Types::TypeTiny::to_TypeTiny($moose); my $c = $moose->has_coercion && @{ $moose->coercion->type_coercion_map || [] }; $caller->add_type( $tt->create_child_type(library => $caller, name => $name, coercion => $c ? 1 : 0) ); } } elsif ($lib->isa('MouseX::Types::Base')) { require Mouse::Util::TypeConstraints; my $types = $lib->type_storage; for my $name (sort keys %$types) { my $mouse = Mouse::Util::TypeConstraints::find_type_constraint($types->{$name}); my $tt = Types::TypeTiny::to_TypeTiny($mouse); $caller->add_type( $tt->create_child_type(library => $caller, name => $name, coercion => $mouse->has_coercion ? 1 : 0) ); } } elsif ($lib->isa('Specio::Exporter')) { my $types = $lib->Specio::Registry::exportable_types_for_package; for my $name (sort keys %$types) { my $specio = $types->{$name}; my $tt = Types::TypeTiny::to_TypeTiny($specio); $caller->add_type( $tt->create_child_type(library => $caller, name => $name) ); } } else { _croak("'$lib' is not a type constraint library"); } } } sub declare { my %opts; if (@_ % 2 == 0) { %opts = @_; if (@_==2 and $_[0]=~ /^_*[A-Z]/ and $_[1] =~ /^[0-9]+$/) { require Carp; Carp::carp("Possible missing comma after 'declare $_[0]'"); } } else { (my($name), %opts) = @_; _croak "Cannot provide two names for type" if exists $opts{name}; $opts{name} = $name; } my $caller = caller($opts{_caller_level} || 0); $opts{library} = $caller; if (defined $opts{parent}) { $opts{parent} = to_TypeTiny($opts{parent}); unless (TypeTiny->check($opts{parent})) { $caller->isa("Type::Library") or _croak("Parent type cannot be a %s", ref($opts{parent})||'non-reference scalar'); $opts{parent} = $caller->meta->get_type($opts{parent}) or _croak("Could not find parent type"); } } my $type; if (defined $opts{parent}) { $type = delete($opts{parent})->create_child_type(%opts); } else { my $bless = delete($opts{bless}) || "Type::Tiny"; eval "require $bless"; $type = $bless->new(%opts); } if ($caller->isa("Type::Library")) { $caller->meta->add_type($type) unless $type->is_anon; } return $type; } *subtype = \&declare; *type = \&declare; sub as (@) { parent => @_; } sub where (&;@) { constraint => @_; } sub message (&;@) { message => @_; } sub inline_as (&;@) { inlined => @_; } sub class_type { my $name = ref($_[0]) ? undef : shift; my %opts = %{ shift or {} }; if (defined $name) { $opts{name} = $name unless exists $opts{name}; $opts{class} = $name unless exists $opts{class}; $opts{name} =~ s/:://g; } $opts{bless} = "Type::Tiny::Class"; { no warnings "numeric"; $opts{_caller_level}++ } declare(%opts); } sub role_type { my $name = ref($_[0]) ? undef : shift; my %opts = %{ shift or {} }; if (defined $name) { $opts{name} = $name unless exists $opts{name}; $opts{role} = $name unless exists $opts{role}; $opts{name} =~ s/:://g; } $opts{bless} = "Type::Tiny::Role"; { no warnings "numeric"; $opts{_caller_level}++ } declare(%opts); } sub duck_type { my $name = ref($_[0]) ? undef : shift; my @methods = @{ shift or [] }; my %opts; $opts{name} = $name if defined $name; $opts{methods} = \@methods; $opts{bless} = "Type::Tiny::Duck"; { no warnings "numeric"; $opts{_caller_level}++ } declare(%opts); } sub enum { my $name = ref($_[0]) ? undef : shift; my @values = @{ shift or [] }; my %opts; $opts{name} = $name if defined $name; $opts{values} = \@values; $opts{bless} = "Type::Tiny::Enum"; { no warnings "numeric"; $opts{_caller_level}++ } declare(%opts); } sub union { my $name = ref($_[0]) ? undef : shift; my @tcs = @{ shift or [] }; my %opts; $opts{name} = $name if defined $name; $opts{type_constraints} = \@tcs; $opts{bless} = "Type::Tiny::Union"; { no warnings "numeric"; $opts{_caller_level}++ } declare(%opts); } sub intersection { my $name = ref($_[0]) ? undef : shift; my @tcs = @{ shift or [] }; my %opts; $opts{name} = $name if defined $name; $opts{type_constraints} = \@tcs; $opts{bless} = "Type::Tiny::Intersection"; { no warnings "numeric"; $opts{_caller_level}++ } declare(%opts); } sub declare_coercion { my %opts; $opts{name} = shift if !ref($_[0]); while (HashLike->check($_[0]) and not TypeTiny->check($_[0])) { %opts = (%opts, %{+shift}); } my $caller = caller($opts{_caller_level} || 0); $opts{library} = $caller; my $bless = delete($opts{bless}) || "Type::Coercion"; eval "require $bless"; my $c = $bless->new(%opts); my @C; if ($caller->isa("Type::Library")) { my $meta = $caller->meta; $meta->add_coercion($c) unless $c->is_anon; while (@_) { push @C, map { ref($_) ? to_TypeTiny($_) : $meta->get_type($_)||$_ } shift; push @C, shift; } } else { @C = @_; } $c->add_type_coercions(@C); return $c->freeze; } sub coerce { if ((scalar caller)->isa("Type::Library")) { my $meta = (scalar caller)->meta; my ($type) = map { ref($_) ? to_TypeTiny($_) : $meta->get_type($_)||$_ } shift; my @opts; while (@_) { push @opts, map { ref($_) ? to_TypeTiny($_) : $meta->get_type($_)||$_ } shift; push @opts, shift; } return $type->coercion->add_type_coercions(@opts); } my ($type, @opts) = @_; $type = to_TypeTiny($type); return $type->coercion->add_type_coercions(@opts); } sub from (@) { return @_; } sub to_type (@) { my $type = shift; unless (TypeTiny->check($type)) { caller->isa("Type::Library") or _croak "Target type cannot be a string"; $type = caller->meta->get_type($type) or _croak "Could not find target type"; } return +{ type_constraint => $type }, @_; } sub via (&;@) { return @_; } sub match_on_type { my $value = shift; while (@_) { my $code; if (@_ == 1) { $code = shift; } else { (my($type), $code) = splice(@_, 0, 2); TypeTiny->($type)->check($value) or next; } if (StringLike->check($code)) { local $_ = $value; if (wantarray) { my @r = eval "$code"; die $@ if $@; return @r; } if (defined wantarray) { my $r = eval "$code"; die $@ if $@; return $r; } eval "$code"; die $@ if $@; return; } else { CodeLike->($code); local $_ = $value; return $code->($value); } } _croak("No cases matched for %s", Type::Tiny::_dd($value)); } sub compile_match_on_type { my @code = 'sub { local $_ = $_[0]; '; my @checks; my @actions; my $els = ''; while (@_) { my ($type, $code); if (@_ == 1) { require Types::Standard; ($type, $code) = (Types::Standard::Any(), shift); } else { ($type, $code) = splice(@_, 0, 2); TypeTiny->($type); } if ($type->can_be_inlined) { push @code, sprintf('%sif (%s)', $els, $type->inline_check('$_')); } else { push @checks, $type; push @code, sprintf('%sif ($checks[%d]->check($_))', $els, $#checks); } $els = 'els'; if (StringLike->check($code)) { push @code, sprintf(' { %s }', $code); } else { CodeLike->($code); push @actions, $code; push @code, sprintf(' { $actions[%d]->(@_) }', $#actions); } } push @code, 'else', ' { Type::Utils::_croak("No cases matched for %s", Type::Tiny::_dd($_[0])) }'; push @code, '}'; # /sub require Eval::TypeTiny; return Eval::TypeTiny::eval_closure( source => \@code, environment => { '@actions' => \@actions, '@checks' => \@checks, }, ); } sub classifier { my $i; compile_match_on_type( +( map { my $type = $_->[0]; $type => sub { $type }; } sort { $b->[1] <=> $a->[1] or $a->[2] <=> $b->[2] } map [$_, scalar(my @parents = $_->parents), ++$i], @_ ), q[ undef ], ); } { package #hide Type::Registry::DWIM; our @ISA = qw(Type::Registry); sub foreign_lookup { my $self = shift; my $r = $self->SUPER::foreign_lookup(@_); return $r if $r; if (my $assume = $self->{"~~assume"} and $_[0] =~ /[A-Z_a-z][0-9A-Z_a-z]*(?:::[0-9A-Z_a-z]+)*/) { my @methods = ref($assume) ? @$assume : $assume; for my $method (@methods) { $r = $self->$method(@_); return $r if $r; } } return; } sub lookup_via_moose { my $self = shift; if ($INC{'Moose.pm'}) { require Moose::Util::TypeConstraints; require Types::TypeTiny; my $r = Moose::Util::TypeConstraints::find_type_constraint($_[0]); return Types::TypeTiny::to_TypeTiny($r) if defined $r; } return; } sub lookup_via_mouse { my $self = shift; if ($INC{'Mouse.pm'}) { require Mouse::Util::TypeConstraints; require Types::TypeTiny; my $r = Mouse::Util::TypeConstraints::find_type_constraint($_[0]); return Types::TypeTiny::to_TypeTiny($r) if defined $r; } return; } sub simple_lookup { my $self = shift; my $r; # If the lookup is chained to a class, then the class' own # type registry gets first refusal. # if (defined $self->{"~~chained"}) { my $chained = "Type::Registry"->for_class($self->{"~~chained"}); $r = eval { $chained->simple_lookup(@_) } unless $self == $chained; return $r if defined $r; } # Fall back to types in Types::Standard. require Types::Standard; return 'Types::Standard'->get_type($_[0]) if 'Types::Standard'->has_type($_[0]); # Only continue any further if we've been called from Type::Parser. return unless $_[1]; my $meta; if (defined $self->{"~~chained"}) { $meta ||= Moose::Util::find_meta($self->{"~~chained"}) if $INC{'Moose.pm'}; $meta ||= Mouse::Util::find_meta($self->{"~~chained"}) if $INC{'Mouse.pm'}; } if ($meta and $meta->isa('Class::MOP::Module')) { $r = $self->lookup_via_moose(@_); return $r if $r; } elsif ($meta and $meta->isa('Mouse::Meta::Module')) { $r = $self->lookup_via_mouse(@_); return $r if $r; } return $self->foreign_lookup(@_); } } our $dwimmer; sub dwim_type { my ($string, %opts) = @_; $opts{for} = caller unless defined $opts{for}; $dwimmer ||= do { require Type::Registry; 'Type::Registry::DWIM'->new; }; local $dwimmer->{'~~chained'} = $opts{for}; local $dwimmer->{'~~assume'} = $opts{fallback} || [ qw/ lookup_via_moose lookup_via_mouse /, $opts{does} ? 'make_role_type' : 'make_class_type', ]; local $@ = undef; my $type; unless (eval { $type = $dwimmer->lookup($string); 1 }) { my $e = $@; die($e) unless $e =~ /not a known type constraint/; } $type; } sub english_list { my $conjunction = ref($_[0]) eq 'SCALAR' ? ${+shift} : 'and'; my @items = sort @_; return $items[0] if @items == 1; return "$items[0] $conjunction $items[1]" if @items == 2; my $tail = pop @items; join(', ', @items, "$conjunction $tail"); } 1; __END__ =pod =encoding utf-8 =for stopwords smush smushed =head1 NAME Type::Utils - utility functions to make defining and using type constraints a little easier =head1 SYNOPSIS package Types::Mine; use Type::Library -base; use Type::Utils -all; BEGIN { extends "Types::Standard" }; declare "AllCaps", as "Str", where { uc($_) eq $_ }, inline_as { my $varname = $_[1]; "uc($varname) eq $varname" }; coerce "AllCaps", from "Str", via { uc($_) }; =head1 STATUS This module is covered by the L. =head1 DESCRIPTION This module provides utility functions to make defining and using type constraints a little easier. =head2 Type declaration functions Many of the following are similar to the similarly named functions described in L. =over =item C<< declare $name, %options >> =item C<< declare %options >> Declare a named or anonymous type constraint. Use C and C to specify the parent type (if any) and (possibly) refine its definition. declare EvenInt, as Int, where { $_ % 2 == 0 }; my $EvenInt = declare as Int, where { $_ % 2 == 0 }; I<< NOTE: >> If the caller package inherits from L then any non-anonymous types declared in the package will be automatically installed into the library. Hidden gem: if you're inheriting from a type constraint that includes some coercions, you can include C<< coercion => 1 >> in the C<< %options >> hash to inherit the coercions. =item C<< subtype $name, %options >> =item C<< subtype %options >> Declare a named or anonymous type constraint which is descended from an existing type constraint. Use C and C to specify the parent type and refine its definition. Actually, you should use C instead; this is just an alias. This function is not exported by default. =item C<< type $name, %options >> =item C<< type %options >> Declare a named or anonymous type constraint which is not descended from an existing type constraint. Use C to provide a coderef that constrains values. Actually, you should use C instead; this is just an alias. This function is not exported by default. =item C<< as $parent >> Used with C to specify a parent type constraint: declare EvenInt, as Int, where { $_ % 2 == 0 }; =item C<< where { BLOCK } >> Used with C to provide the constraint coderef: declare EvenInt, as Int, where { $_ % 2 == 0 }; The coderef operates on C<< $_ >>, which is the value being tested. =item C<< message { BLOCK } >> Generate a custom error message when a value fails validation. declare EvenInt, as Int, where { $_ % 2 == 0 }, message { Int->validate($_) or "$_ is not divisible by two"; }; Without a custom message, the messages generated by Type::Tiny are along the lines of I<< Value "33" did not pass type constraint "EvenInt" >>, which is usually reasonable. =item C<< inline_as { BLOCK } >> Generate a string of Perl code that can be used to inline the type check into other functions. If your type check is being used within a L or L constructor or accessor methods, or used by L, this can lead to significant performance improvements. declare EvenInt, as Int, where { $_ % 2 == 0 }, inline_as { my ($constraint, $varname) = @_; my $perlcode = $constraint->parent->inline_check($varname) . "&& ($varname % 2 == 0)"; return $perlcode; }; warn EvenInt->inline_check('$xxx'); # demonstration Your C block can return a list, in which case these will be smushed together with "&&". The first item on the list may be undef, in which case the undef will be replaced by the inlined parent type constraint. (And will throw an exception if there is no parent.) declare EvenInt, as Int, where { $_ % 2 == 0 }, inline_as { return (undef, "($_ % 2 == 0)"); }; =item C<< class_type $name, { class => $package, %options } >> =item C<< class_type { class => $package, %options } >> =item C<< class_type $name >> Shortcut for declaring a L type constraint. If C<< $package >> is omitted, is assumed to be the same as C<< $name >>. If C<< $name >> contains "::" (which would be an invalid name as far as L is concerned), this will be removed. So for example, C<< class_type("Foo::Bar") >> declares a L type constraint named "FooBar" which constrains values to objects blessed into the "Foo::Bar" package. =item C<< role_type $name, { role => $package, %options } >> =item C<< role_type { role => $package, %options } >> =item C<< role_type $name >> Shortcut for declaring a L type constraint. If C<< $package >> is omitted, is assumed to be the same as C<< $name >>. If C<< $name >> contains "::" (which would be an invalid name as far as L is concerned), this will be removed. =item C<< duck_type $name, \@methods >> =item C<< duck_type \@methods >> Shortcut for declaring a L type constraint. =item C<< union $name, \@constraints >> =item C<< union \@constraints >> Shortcut for declaring a L type constraint. =item C<< enum $name, \@values >> =item C<< enum \@values >> Shortcut for declaring a L type constraint. =item C<< intersection $name, \@constraints >> =item C<< intersection \@constraints >> Shortcut for declaring a L type constraint. =back =head2 Coercion declaration functions Many of the following are similar to the similarly named functions described in L. =over =item C<< coerce $target, @coercions >> Add coercions to the target type constraint. The list of coercions is a list of type constraint, conversion code pairs. Conversion code can be either a string of Perl code or a coderef; in either case the value to be converted is C<< $_ >>. =item C<< from $source >> Sugar to specify a type constraint in a list of coercions: coerce EvenInt, from Int, via { $_ * 2 }; # As a coderef... coerce EvenInt, from Int, q { $_ * 2 }; # or as a string! =item C<< via { BLOCK } >> Sugar to specify a coderef in a list of coercions. =item C<< declare_coercion $name, \%opts, $type1, $code1, ... >> =item C<< declare_coercion \%opts, $type1, $code1, ... >> Declares a coercion that is not explicitly attached to any type in the library. For example: declare_coercion "ArrayRefFromAny", from "Any", via { [$_] }; This coercion will be exportable from the library as a L object, but the ArrayRef type exported by the library won't automatically use it. Coercions declared this way are immutable (frozen). =item C<< to_type $type >> Used with C to declare the target type constraint for a coercion, but still without explicitly attaching the coercion to the type constraint: declare_coercion "ArrayRefFromAny", to_type "ArrayRef", from "Any", via { [$_] }; You should pretty much always use this when declaring an unattached coercion because it's exceedingly useful for a type coercion to know what it will coerce to - this allows it to skip coercion when no coercion is needed (e.g. avoiding coercing C<< [] >> to C<< [ [] ] >>) and allows C to work properly. =back =head2 Type library management =over =item C<< extends @libraries >> Indicates that this type library extends other type libraries, importing their type constraints. Should usually be executed in a C<< BEGIN >> block. This is not exported by default because it's not fun to export it to Moo, Moose or Mouse classes! C<< use Type::Utils -all >> can be used to import it into your type library. =back =head2 Other =over =item C<< match_on_type $value => ($type => \&action, ..., \&default?) >> Something like a C/C or C/C construct. Dispatches along different code paths depending on the type of the incoming value. Example blatantly stolen from the Moose documentation: sub to_json { my $value = shift; return match_on_type $value => ( HashRef() => sub { my $hash = shift; '{ ' . ( join ", " => map { '"' . $_ . '" : ' . to_json( $hash->{$_} ) } sort keys %$hash ) . ' }'; }, ArrayRef() => sub { my $array = shift; '[ '.( join ", " => map { to_json($_) } @$array ).' ]'; }, Num() => q {$_}, Str() => q { '"' . $_ . '"' }, Undef() => q {'null'}, => sub { die "$_ is not acceptable json type" }, ); } Note that unlike Moose, code can be specified as a string instead of a coderef. (e.g. for C, C and C above.) For improved performance, try C. This function is not exported by default. =item C<< my $coderef = compile_match_on_type($type => \&action, ..., \&default?) >> Compile a C block into a coderef. The following JSON converter is about two orders of magnitude faster than the previous example: sub to_json; *to_json = compile_match_on_type( HashRef() => sub { my $hash = shift; '{ ' . ( join ", " => map { '"' . $_ . '" : ' . to_json( $hash->{$_} ) } sort keys %$hash ) . ' }'; }, ArrayRef() => sub { my $array = shift; '[ '.( join ", " => map { to_json($_) } @$array ).' ]'; }, Num() => q {$_}, Str() => q { '"' . $_ . '"' }, Undef() => q {'null'}, => sub { die "$_ is not acceptable json type" }, ); Remember to store the coderef somewhere fairly permanent so that you don't compile it over and over. C variables (in Perl >= 5.10) are good for this. (Same sort of idea as L.) This function is not exported by default. =item C<< my $coderef = classifier(@types) >> Returns a coderef that can be used to classify values according to their type constraint. The coderef, when passed a value, returns a type constraint which the value satisfies. use feature qw( say ); use Type::Utils qw( classifier ); use Types::Standard qw( Int Num Str Any ); my $classifier = classifier(Str, Int, Num, Any); say $classifier->( "42" )->name; # Int say $classifier->( "4.2" )->name; # Num say $classifier->( [] )->name; # Any Note that, for example, "42" satisfies Int, but it would satisfy the type constraints Num, Str, and Any as well. In this case, the classifier has picked the most specific type constraint that "42" satisfies. If no type constraint is satisfied by the value, then the classifier will return undef. =item C<< dwim_type($string, %options) >> Given a string like "ArrayRef[Int|CodeRef]", turns it into a type constraint object, hopefully doing what you mean. It uses the syntax of L. Firstly the L for the caller package is consulted; if that doesn't have a match, L is consulted for standard type constraint names. If none of the above yields a type constraint, and the caller class is a Moose-based class, then C attempts to look the type constraint up in the Moose type registry. If it's a Mouse-based class, then the Mouse type registry is used instead. If no type constraint can be found via these normal methods, several fallbacks are available: =over =item C Lookup in Moose registry even if caller is non-Moose class. =item C Lookup in Mouse registry even if caller is non-Mouse class. =item C Create a new Type::Tiny::Class constraint. =item C Create a new Type::Tiny::Role constraint. =back You can alter which should be attempted, and in which order, by passing an option to C: my $type = Type::Utils::dwim_type( "ArrayRef[Int]", fallback => [ "lookup_via_mouse" , "make_role_type" ], ); For historical reasons, by default the fallbacks attempted are: lookup_via_moose, lookup_via_mouse, make_class_type You may set C to an empty arrayref to avoid using any of these fallbacks. You can specify an alternative for the caller using the C option. my $type = dwim_type("ArrayRef", for => "Moose::Object"); While it's probably better overall to use the proper L interface for resolving type constraint strings, this function often does what you want. It should never die if it fails to find a type constraint (but may die if the type constraint string is syntactically malformed), preferring to return undef. This function is not exported by default. =item C<< english_list(\$conjunction, @items) >> Joins the items with commas, placing a conjunction before the final item. The conjunction is optional, defaulting to "and". english_list(qw/foo bar baz/); # "foo, bar, and baz" english_list(\"or", qw/quux quuux/); # "quux or quuux" This function is not exported by default. =back =head1 EXPORT By default, all of the functions documented above are exported, except C and C (prefer C instead), C, C, C/C, C, and C. This module uses L; see the documentation of that module for tips and tricks importing from Type::Utils. =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. L, L, L, L. L, L, L, L, L. L, L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Standard.pm000644001750001750 11675513601673061 16434 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Typespackage Types::Standard; use 5.006001; use strict; use warnings; BEGIN { eval { require re }; if ($] < 5.008) { require Devel::TypeTiny::Perl56Compat }; if ($] < 5.010) { require Devel::TypeTiny::Perl58Compat }; } BEGIN { $Types::Standard::AUTHORITY = 'cpan:TOBYINK'; $Types::Standard::VERSION = '1.008001'; } $Types::Standard::VERSION =~ tr/_//d; use Type::Library -base; our @EXPORT_OK = qw( slurpy ); use Scalar::Util qw( blessed looks_like_number ); use Type::Tiny (); use Types::TypeTiny (); my $is_class_loaded; BEGIN { $is_class_loaded = q{sub { return !!0 if ref $_[0]; return !!0 if not $_[0]; return !!0 if ref(do { my $tmpstr = $_[0]; \$tmpstr }) ne 'SCALAR'; my $stash = do { no strict 'refs'; \%{"$_[0]\::"} }; return !!1 if exists $stash->{'ISA'}; return !!1 if exists $stash->{'VERSION'}; foreach my $globref (values %$stash) { return !!1 if ref \$globref eq 'GLOB' ? *{$globref}{CODE} : ref $globref; # const or sub ref } return !!0; }}; *_is_class_loaded = Type::Tiny::_USE_XS ? \&Type::Tiny::XS::Util::is_class_loaded : eval $is_class_loaded; *_HAS_REFUTILXS = eval { require Ref::Util::XS; Ref::Util::XS::->VERSION(0.100); 1; } ? sub () { !!1 } : sub () { !!0 }; }; my $add_core_type = sub { my $meta = shift; my ($typedef) = @_; my $name = $typedef->{name}; my ($xsub, $xsubname); # We want Map and Tuple to be XSified, even if they're not # really core. $typedef->{_is_core} = 1 unless $name eq 'Map' || $name eq 'Tuple'; if ( Type::Tiny::_USE_XS and not ($name eq 'RegexpRef') ) { $xsub = Type::Tiny::XS::get_coderef_for($name); $xsubname = Type::Tiny::XS::get_subname_for($name); } elsif ( Type::Tiny::_USE_MOUSE and not ($name eq 'RegexpRef' or $name eq 'Int' or $name eq 'Object') ) { require Mouse::Util::TypeConstraints; $xsub = "Mouse::Util::TypeConstraints"->can($name); $xsubname = "Mouse::Util::TypeConstraints::$name" if $xsub; } if (Type::Tiny::_USE_XS and Type::Tiny::XS->VERSION < 0.014 and $name eq 'Bool') { # Broken implementation of Bool $xsub = $xsubname = undef; } if (Type::Tiny::_USE_XS and ( Type::Tiny::XS->VERSION < 0.016 or $] < 5.018 ) and $name eq 'Int') { # Broken implementation of Int $xsub = $xsubname = undef; } $typedef->{compiled_type_constraint} = $xsub if $xsub; #### TODO my $orig_inlined = $typedef->{inlined}; if (defined($xsubname) and ( # These should be faster than their normal inlined # equivalents $name eq 'Str' or $name eq 'Bool' or $name eq 'ClassName' or $name eq 'RegexpRef' or $name eq 'FileHandle' )) { $typedef->{inlined} = sub { $Type::Tiny::AvoidCallbacks ? goto($orig_inlined) : "$xsubname\($_[1])" }; } $meta->add_type($typedef); }; sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } my $meta = __PACKAGE__->meta; # Stringable and LazyLoad are optimizations that complicate # this module somewhat, but they have led to performance # improvements. If Types::Standard wasn't such a key type # library, I wouldn't use them. I strongly discourage anybody # from using them in their own code. If you're looking for # examples of how to write a type library sanely, you're # better off looking at the code for Types::Common::Numeric # and Types::Common::String. { sub Stringable (&) { bless +{ code => $_[0] }, 'Types::Standard::_Stringable'; } Types::Standard::_Stringable->Type::Tiny::_install_overloads( q[""] => sub { $_[0]{text} ||= $_[0]{code}->() } ); my $subname; sub LazyLoad ($$) { bless \@_, 'Types::Standard::LazyLoad'; } 'Types::Standard::LazyLoad'->Type::Tiny::_install_overloads( q[&{}] => sub { my ($typename, $function) = @{$_[0]}; my $type = $meta->get_type($typename); my $class = "Types::Standard::$typename"; eval "require $class; 1" or die($@); # Majorly break encapsulation for Type::Tiny :-O for my $key (keys %$type) { next unless ref($type->{$key}) eq 'Types::Standard::LazyLoad'; my $f = $type->{$key}[1]; $type->{$key} = $class->can("__$f"); } my $mm = $type->{my_methods} || {}; for my $key (keys %$mm) { $subname = eval { require Sub::Util } ? \&Sub::Util::set_subname : eval { require Sub::Name } ? \&Sub::Name::subname : 0 if not defined $subname; next unless ref($mm->{$key}) eq 'Types::Standard::LazyLoad'; my $f = $mm->{$key}[1]; $mm->{$key} = $class->can("__$f"); $subname and $subname->( sprintf("%s::my_%s", $type->qualified_name, $key), $mm->{$key}, ); } return $class->can("__$function"); }, ); } no warnings; BEGIN { *STRICTNUM = $ENV{PERL_TYPES_STANDARD_STRICTNUM} ? sub(){!!1} : sub(){!!0} }; my $_any = $meta->$add_core_type({ name => "Any", inlined => sub { "!!1" }, complement_name => 'None', }); my $_item = $meta->$add_core_type({ name => "Item", inlined => sub { "!!1" }, parent => $_any, }); my $_bool = $meta->$add_core_type({ name => "Bool", parent => $_item, constraint => sub { !ref $_ and (!defined $_ or $_ eq q() or $_ eq '0' or $_ eq '1') }, inlined => sub { "!ref $_[1] and (!defined $_[1] or $_[1] eq q() or $_[1] eq '0' or $_[1] eq '1')" }, }); $_bool->coercion->add_type_coercions($_any, q{!!$_}); my $_undef = $meta->$add_core_type({ name => "Undef", parent => $_item, constraint => sub { !defined $_ }, inlined => sub { "!defined($_[1])" }, }); my $_def = $meta->$add_core_type({ name => "Defined", parent => $_item, constraint => sub { defined $_ }, inlined => sub { "defined($_[1])" }, complementary_type => $_undef, }); # hackish, but eh Scalar::Util::weaken($_undef->{complementary_type} ||= $_def); my $_val = $meta->$add_core_type({ name => "Value", parent => $_def, constraint => sub { not ref $_ }, inlined => sub { "defined($_[1]) and not ref($_[1])" }, }); my $_str = $meta->$add_core_type({ name => "Str", parent => $_val, constraint => sub { ref(\$_) eq 'SCALAR' or ref(\(my $val = $_)) eq 'SCALAR' }, inlined => sub { "defined($_[1]) and do { ref(\\$_[1]) eq 'SCALAR' or ref(\\(my \$val = $_[1])) eq 'SCALAR' }" }, }); my $_laxnum = $meta->add_type({ name => "LaxNum", parent => $_str, constraint => sub { looks_like_number $_ }, inlined => sub { "defined($_[1]) && !ref($_[1]) && Scalar::Util::looks_like_number($_[1])" }, }); my $_strictnum = $meta->add_type({ name => "StrictNum", parent => $_str, constraint => sub { my $val = $_; ($val =~ /\A[+-]?[0-9]+\z/) || ( $val =~ /\A(?:[+-]?) #matches optional +- in the beginning (?=[0-9]|\.[0-9]) #matches previous +- only if there is something like 3 or .3 [0-9]* #matches 0-9 zero or more times (?:\.[0-9]+)? #matches optional .89 or nothing (?:[Ee](?:[+-]?[0-9]+))? #matches E1 or e1 or e-1 or e+1 etc \z/x ); }, inlined => sub { 'my $val = '.$_[1].';'. Value()->inline_check('$val') .' && ( $val =~ /\A[+-]?[0-9]+\z/ || ' . '$val =~ /\A(?:[+-]?) # matches optional +- in the beginning (?=[0-9]|\.[0-9]) # matches previous +- only if there is something like 3 or .3 [0-9]* # matches 0-9 zero or more times (?:\.[0-9]+)? # matches optional .89 or nothing (?:[Ee](?:[+-]?[0-9]+))? # matches E1 or e1 or e-1 or e+1 etc \z/x ); ' }, }); my $_num = $meta->add_type({ name => "Num", parent => (STRICTNUM ? $_strictnum : $_laxnum), }); $meta->$add_core_type({ name => "Int", parent => $_num, constraint => sub { /\A-?[0-9]+\z/ }, inlined => sub { "do { my \$tmp = $_[1]; defined(\$tmp) and !ref(\$tmp) and \$tmp =~ /\\A-?[0-9]+\\z/ }" }, }); my $_classn = $meta->add_type({ name => "ClassName", parent => $_str, constraint => \&_is_class_loaded, inlined => sub { $Type::Tiny::AvoidCallbacks ? "($is_class_loaded)->(do { my \$tmp = $_[1] })" : "Types::Standard::_is_class_loaded(do { my \$tmp = $_[1] })" }, }); $meta->add_type({ name => "RoleName", parent => $_classn, constraint => sub { not $_->can("new") }, inlined => sub { $Type::Tiny::AvoidCallbacks ? "($is_class_loaded)->(do { my \$tmp = $_[1] }) and not $_[1]\->can('new')" : "Types::Standard::_is_class_loaded(do { my \$tmp = $_[1] }) and not $_[1]\->can('new')" }, }); my $_ref = $meta->$add_core_type({ name => "Ref", parent => $_def, constraint => sub { ref $_ }, inlined => sub { "!!ref($_[1])" }, constraint_generator => sub { return $meta->get_type('Ref') unless @_; my $reftype = shift; Types::TypeTiny::StringLike->check($reftype) or _croak("Parameter to Ref[`a] expected to be string; got $reftype"); $reftype = "$reftype"; return sub { ref($_[0]) and Scalar::Util::reftype($_[0]) eq $reftype; } }, inline_generator => sub { my $reftype = shift; return sub { my $v = $_[1]; "ref($v) and Scalar::Util::reftype($v) eq q($reftype)"; }; }, deep_explanation => sub { require B; my ($type, $value, $varname) = @_; my $param = $type->parameters->[0]; return if $type->check($value); my $reftype = Scalar::Util::reftype($value); return [ sprintf('"%s" constrains reftype(%s) to be equal to %s', $type, $varname, B::perlstring($param)), sprintf('reftype(%s) is %s', $varname, defined($reftype) ? B::perlstring($reftype) : "undef"), ]; }, }); $meta->$add_core_type({ name => "CodeRef", parent => $_ref, constraint => sub { ref $_ eq "CODE" }, inlined => sub { _HAS_REFUTILXS && !$Type::Tiny::AvoidCallbacks ? "Ref::Util::XS::is_plain_coderef($_[1])" : "ref($_[1]) eq 'CODE'" }, }); my $_regexp = $meta->$add_core_type({ name => "RegexpRef", parent => $_ref, constraint => sub { ref($_) && !!re::is_regexp($_) or blessed($_) && $_->isa('Regexp') }, inlined => sub { my $v = $_[1]; "ref($v) && !!re::is_regexp($v) or Scalar::Util::blessed($v) && $v\->isa('Regexp')" }, }); $meta->$add_core_type({ name => "GlobRef", parent => $_ref, constraint => sub { ref $_ eq "GLOB" }, inlined => sub { _HAS_REFUTILXS && !$Type::Tiny::AvoidCallbacks ? "Ref::Util::XS::is_plain_globref($_[1])" : "ref($_[1]) eq 'GLOB'" }, }); $meta->$add_core_type({ name => "FileHandle", parent => $_ref, constraint => sub { (ref($_) && Scalar::Util::openhandle($_)) or (blessed($_) && $_->isa("IO::Handle")) }, inlined => sub { "(ref($_[1]) && Scalar::Util::openhandle($_[1])) ". "or (Scalar::Util::blessed($_[1]) && $_[1]\->isa(\"IO::Handle\"))" }, }); my $_arr = $meta->$add_core_type({ name => "ArrayRef", parent => $_ref, constraint => sub { ref $_ eq "ARRAY" }, inlined => sub { _HAS_REFUTILXS && !$Type::Tiny::AvoidCallbacks ? "Ref::Util::XS::is_plain_arrayref($_[1])" : "ref($_[1]) eq 'ARRAY'" }, constraint_generator => LazyLoad(ArrayRef => 'constraint_generator'), inline_generator => LazyLoad(ArrayRef => 'inline_generator'), deep_explanation => LazyLoad(ArrayRef => 'deep_explanation'), coercion_generator => LazyLoad(ArrayRef => 'coercion_generator'), }); my $_hash = $meta->$add_core_type({ name => "HashRef", parent => $_ref, constraint => sub { ref $_ eq "HASH" }, inlined => sub { _HAS_REFUTILXS && !$Type::Tiny::AvoidCallbacks ? "Ref::Util::XS::is_plain_hashref($_[1])" : "ref($_[1]) eq 'HASH'" }, constraint_generator => LazyLoad(HashRef => 'constraint_generator'), inline_generator => LazyLoad(HashRef => 'inline_generator'), deep_explanation => LazyLoad(HashRef => 'deep_explanation'), coercion_generator => LazyLoad(HashRef => 'coercion_generator'), my_methods => { hashref_allows_key => LazyLoad(HashRef => 'hashref_allows_key'), hashref_allows_value => LazyLoad(HashRef => 'hashref_allows_value'), }, }); $meta->$add_core_type({ name => "ScalarRef", parent => $_ref, constraint => sub { ref $_ eq "SCALAR" or ref $_ eq "REF" }, inlined => sub { "ref($_[1]) eq 'SCALAR' or ref($_[1]) eq 'REF'" }, constraint_generator => LazyLoad(ScalarRef => 'constraint_generator'), inline_generator => LazyLoad(ScalarRef => 'inline_generator'), deep_explanation => LazyLoad(ScalarRef => 'deep_explanation'), coercion_generator => LazyLoad(ScalarRef => 'coercion_generator'), }); my $_obj = $meta->$add_core_type({ name => "Object", parent => $_ref, constraint => sub { blessed $_ }, inlined => sub { _HAS_REFUTILXS && !$Type::Tiny::AvoidCallbacks ? "Ref::Util::XS::is_blessed_ref($_[1])" : "Scalar::Util::blessed($_[1])" }, is_object => 1, }); $meta->$add_core_type({ name => "Maybe", parent => $_item, constraint_generator => sub { return $meta->get_type('Maybe') unless @_; my $param = Types::TypeTiny::to_TypeTiny(shift); Types::TypeTiny::TypeTiny->check($param) or _croak("Parameter to Maybe[`a] expected to be a type constraint; got $param"); my $param_compiled_check = $param->compiled_check; my @xsub; if (Type::Tiny::_USE_XS) { my $paramname = Type::Tiny::XS::is_known($param_compiled_check); push @xsub, Type::Tiny::XS::get_coderef_for("Maybe[$paramname]") if $paramname; } elsif (Type::Tiny::_USE_MOUSE and $param->_has_xsub) { require Mouse::Util::TypeConstraints; my $maker = "Mouse::Util::TypeConstraints"->can("_parameterize_Maybe_for"); push @xsub, $maker->($param) if $maker; } return ( sub { my $value = shift; return !!1 unless defined $value; return $param->check($value); }, @xsub, ); }, inline_generator => sub { my $param = shift; my $param_compiled_check = $param->compiled_check; my $xsubname; if (Type::Tiny::_USE_XS) { my $paramname = Type::Tiny::XS::is_known($param_compiled_check); $xsubname = Type::Tiny::XS::get_subname_for("Maybe[$paramname]"); } return unless $param->can_be_inlined; return sub { my $v = $_[1]; return "$xsubname\($v\)" if $xsubname && !$Type::Tiny::AvoidCallbacks; my $param_check = $param->inline_check($v); "!defined($v) or $param_check"; }; }, deep_explanation => sub { my ($type, $value, $varname) = @_; my $param = $type->parameters->[0]; return [ sprintf('%s is defined', Type::Tiny::_dd($value)), sprintf('"%s" constrains the value with "%s" if it is defined', $type, $param), @{ $param->validate_explain($value, $varname) }, ]; }, coercion_generator => sub { my ($parent, $child, $param) = @_; return unless $param->has_coercion; return $param->coercion; }, }); my $_map = $meta->$add_core_type({ name => "Map", parent => $_hash, constraint_generator => LazyLoad(Map => 'constraint_generator'), inline_generator => LazyLoad(Map => 'inline_generator'), deep_explanation => LazyLoad(Map => 'deep_explanation'), coercion_generator => LazyLoad(Map => 'coercion_generator'), my_methods => { hashref_allows_key => LazyLoad(Map => 'hashref_allows_key'), hashref_allows_value => LazyLoad(Map => 'hashref_allows_value'), }, }); my $_Optional = $meta->add_type({ name => "Optional", parent => $_item, constraint_generator => sub { return $meta->get_type('Optional') unless @_; my $param = Types::TypeTiny::to_TypeTiny(shift); Types::TypeTiny::TypeTiny->check($param) or _croak("Parameter to Optional[`a] expected to be a type constraint; got $param"); sub { $param->check($_[0]) } }, inline_generator => sub { my $param = shift; return unless $param->can_be_inlined; return sub { my $v = $_[1]; $param->inline_check($v); }; }, deep_explanation => sub { my ($type, $value, $varname) = @_; my $param = $type->parameters->[0]; return [ sprintf('%s exists', $varname), sprintf('"%s" constrains %s with "%s" if it exists', $type, $varname, $param), @{ $param->validate_explain($value, $varname) }, ]; }, coercion_generator => sub { my ($parent, $child, $param) = @_; return unless $param->has_coercion; return $param->coercion; }, }); sub slurpy { my $t = shift; wantarray ? (+{ slurpy => $t }, @_) : +{ slurpy => $t }; } $meta->$add_core_type({ name => "Tuple", parent => $_arr, name_generator => sub { my ($s, @a) = @_; sprintf('%s[%s]', $s, join q[,], map { ref($_) eq "HASH" ? sprintf("slurpy %s", $_->{slurpy}) : $_ } @a); }, constraint_generator => LazyLoad(Tuple => 'constraint_generator'), inline_generator => LazyLoad(Tuple => 'inline_generator'), deep_explanation => LazyLoad(Tuple => 'deep_explanation'), coercion_generator => LazyLoad(Tuple => 'coercion_generator'), }); $meta->add_type({ name => "CycleTuple", parent => $_arr, name_generator => sub { my ($s, @a) = @_; sprintf('%s[%s]', $s, join q[,], @a); }, constraint_generator => LazyLoad(CycleTuple => 'constraint_generator'), inline_generator => LazyLoad(CycleTuple => 'inline_generator'), deep_explanation => LazyLoad(CycleTuple => 'deep_explanation'), coercion_generator => LazyLoad(CycleTuple => 'coercion_generator'), }); $meta->add_type({ name => "Dict", parent => $_hash, name_generator => sub { my ($s, @p) = @_; my $l = ref($p[-1]) eq q(HASH) ? pop(@p)->{slurpy} : undef; my %a = @p; sprintf('%s[%s%s]', $s, join(q[,], map sprintf("%s=>%s", $_, $a{$_}), sort keys %a), $l ? ",slurpy $l" : ''); }, constraint_generator => LazyLoad(Dict => 'constraint_generator'), inline_generator => LazyLoad(Dict => 'inline_generator'), deep_explanation => LazyLoad(Dict => 'deep_explanation'), coercion_generator => LazyLoad(Dict => 'coercion_generator'), my_methods => { dict_is_slurpy => LazyLoad(Dict => 'dict_is_slurpy'), hashref_allows_key => LazyLoad(Dict => 'hashref_allows_key'), hashref_allows_value => LazyLoad(Dict => 'hashref_allows_value'), }, }); $meta->add_type({ name => "Overload", parent => $_obj, constraint => sub { require overload; overload::Overloaded($_) }, inlined => sub { $INC{'overload.pm'} ? "Scalar::Util::blessed($_[1]) and overload::Overloaded($_[1])" : "Scalar::Util::blessed($_[1]) and do { use overload (); overload::Overloaded($_[1]) }" }, constraint_generator => sub { return $meta->get_type('Overload') unless @_; my @operations = map { Types::TypeTiny::StringLike->check($_) ? "$_" : _croak("Parameters to Overload[`a] expected to be a strings; got $_"); } @_; require overload; return sub { my $value = shift; for my $op (@operations) { return unless overload::Method($value, $op); } return !!1; } }, inline_generator => sub { my @operations = @_; return sub { require overload; my $v = $_[1]; join " and ", "Scalar::Util::blessed($v)", map "overload::Method($v, q[$_])", @operations; }; }, is_object => 1, }); $meta->add_type({ name => "StrMatch", parent => $_str, constraint_generator => LazyLoad(StrMatch => 'constraint_generator'), inline_generator => LazyLoad(StrMatch => 'inline_generator'), }); $meta->add_type({ name => "OptList", parent => $_arr, constraint => sub { for my $inner (@$_) { return unless ref($inner) eq q(ARRAY); return unless @$inner == 2; return unless is_Str($inner->[0]); } return !!1; }, inlined => sub { my ($self, $var) = @_; my $Str_check = Str()->inline_check('$inner->[0]'); my @code = 'do { my $ok = 1; '; push @code, sprintf('for my $inner (@{%s}) { no warnings; ', $var); push @code, sprintf('($ok=0) && last unless ref($inner) eq q(ARRAY) && @$inner == 2 && (%s); ', $Str_check); push @code, '} '; push @code, '$ok }'; return (undef, join(q( ), @code)); }, }); $meta->add_type({ name => "Tied", parent => $_ref, constraint => sub { !!tied(Scalar::Util::reftype($_) eq 'HASH' ? %{$_} : Scalar::Util::reftype($_) eq 'ARRAY' ? @{$_} : Scalar::Util::reftype($_) =~ /^(SCALAR|REF)$/ ? ${$_} : undef) }, inlined => sub { my ($self, $var) = @_; $self->parent->inline_check($var) . " and !!tied(Scalar::Util::reftype($var) eq 'HASH' ? \%{$var} : Scalar::Util::reftype($var) eq 'ARRAY' ? \@{$var} : Scalar::Util::reftype($var) =~ /^(SCALAR|REF)\$/ ? \${$var} : undef)" }, name_generator => sub { my $self = shift; my $param = Types::TypeTiny::to_TypeTiny(shift); unless (Types::TypeTiny::TypeTiny->check($param)) { Types::TypeTiny::StringLike->check($param) or _croak("Parameter to Tied[`a] expected to be a class name; got $param"); require B; return sprintf("%s[%s]", $self, B::perlstring($param)); } return sprintf("%s[%s]", $self, $param); }, constraint_generator => LazyLoad(Tied => 'constraint_generator'), inline_generator => LazyLoad(Tied => 'inline_generator'), }); $meta->add_type({ name => "InstanceOf", parent => $_obj, constraint_generator => sub { return $meta->get_type('InstanceOf') unless @_; require Type::Tiny::Class; my @classes = map { Types::TypeTiny::TypeTiny->check($_) ? $_ : "Type::Tiny::Class"->new(class => $_, display_name => sprintf('InstanceOf[%s]', B::perlstring($_))) } @_; return $classes[0] if @classes == 1; require B; require Type::Tiny::Union; return "Type::Tiny::Union"->new( type_constraints => \@classes, display_name => sprintf('InstanceOf[%s]', join q[,], map B::perlstring($_->class), @classes), ); }, }); $meta->add_type({ name => "ConsumerOf", parent => $_obj, constraint_generator => sub { return $meta->get_type('ConsumerOf') unless @_; require B; require Type::Tiny::Role; my @roles = map { Types::TypeTiny::TypeTiny->check($_) ? $_ : "Type::Tiny::Role"->new(role => $_, display_name => sprintf('ConsumerOf[%s]', B::perlstring($_))) } @_; return $roles[0] if @roles == 1; require Type::Tiny::Intersection; return "Type::Tiny::Intersection"->new( type_constraints => \@roles, display_name => sprintf('ConsumerOf[%s]', join q[,], map B::perlstring($_->role), @roles), ); }, }); $meta->add_type({ name => "HasMethods", parent => $_obj, constraint_generator => sub { return $meta->get_type('HasMethods') unless @_; require B; require Type::Tiny::Duck; return "Type::Tiny::Duck"->new( methods => \@_, display_name => sprintf('HasMethods[%s]', join q[,], map B::perlstring($_), @_), ); }, }); $meta->add_type({ name => "Enum", parent => $_str, constraint_generator => sub { return $meta->get_type('Enum') unless @_; require B; require Type::Tiny::Enum; return "Type::Tiny::Enum"->new( values => \@_, display_name => sprintf('Enum[%s]', join q[,], map B::perlstring($_), @_), ); }, }); $meta->add_coercion({ name => "MkOpt", type_constraint => $meta->get_type("OptList"), type_coercion_map => [ $_arr, q{ Exporter::Tiny::mkopt($_) }, $_hash, q{ Exporter::Tiny::mkopt($_) }, $_undef, q{ [] }, ], }); $meta->add_coercion({ name => "Join", type_constraint => $_str, coercion_generator => sub { my ($self, $target, $sep) = @_; Types::TypeTiny::StringLike->check($sep) or _croak("Parameter to Join[`a] expected to be a string; got $sep"); require B; $sep = B::perlstring($sep); return (ArrayRef(), qq{ join($sep, \@\$_) }); }, }); $meta->add_coercion({ name => "Split", type_constraint => $_arr, coercion_generator => sub { my ($self, $target, $re) = @_; ref($re) eq q(Regexp) or _croak("Parameter to Split[`a] expected to be a regular expresssion; got $re"); my $regexp_string = "$re"; $regexp_string =~ s/\\\//\\\\\//g; # toothpicks return (Str(), qq{ [split /$regexp_string/, \$_] }); }, }); __PACKAGE__->meta->make_immutable; 1; __END__ =pod =for stopwords booleans vstrings typeglobs =encoding utf-8 =for stopwords datetimes =head1 NAME Types::Standard - bundled set of built-in types for Type::Tiny =head1 SYNOPSIS use v5.12; use strict; use warnings; package Horse { use Moo; use Types::Standard qw( Str Int Enum ArrayRef Object ); use Type::Params qw( compile ); use namespace::autoclean; has name => ( is => 'ro', isa => Str, required => 1, ); has gender => ( is => 'ro', isa => Enum[qw( f m )], ); has age => ( is => 'rw', isa => Int->where( '$_ >= 0' ), ); has children => ( is => 'ro', isa => ArrayRef[Object], default => sub { return [] }, ); sub add_child { state $check = compile( Object, Object ); # method signature my ($self, $child) = $check->(@_); # unpack @_ push @{ $self->children }, $child; return $self; } } package main; my $boldruler = Horse->new( name => "Bold Ruler", gender => 'm', age => 16, ); my $secretariat = Horse->new( name => "Secretariat", gender => 'm', age => 0, ); $boldruler->add_child( $secretariat ); use Types::Standard qw( is_Object assert_Object ); # is_Object($thing) returns a boolean my $is_it_an_object = is_Object($boldruler); # assert_Object($thing) returns $thing or dies say assert_Object($boldruler)->name; # says "Bold Ruler" =head1 STATUS This module is covered by the L. =head1 DESCRIPTION This documents the details of the L type library. L is a better starting place if you're new. L bundles a few types which seem to be useful. =head2 Moose-like The following types are similar to those described in L. =over =item * B<< Any >> Absolutely any value passes this type constraint (even undef). =item * B<< Item >> Essentially the same as B. All other type constraints in this library inherit directly or indirectly from B. =item * B<< Bool >> Values that are reasonable booleans. Accepts 1, 0, the empty string and undef. =item * B<< Maybe[`a] >> Given another type constraint, also accepts undef. For example, B<< Maybe[Int] >> accepts all integers plus undef. =item * B<< Undef >> Only undef passes this type constraint. =item * B<< Defined >> Only undef fails this type constraint. =item * B<< Value >> Any defined, non-reference value. =item * B<< Str >> Any string. (The only difference between B and B is that the former accepts typeglobs and vstrings.) Other customers also bought: B<< StringLike >> from L. =item * B<< Num >> See B and B below. =item * B<< Int >> An integer; that is a string of digits 0 to 9, optionally prefixed with a hyphen-minus character. =item * B<< ClassName >> The name of a loaded package. The package must have C<< @ISA >> or C<< $VERSION >> defined, or must define at least one sub to be considered a loaded package. =item * B<< RoleName >> Like B<< ClassName >>, but the package must I define a method called C. This is subtly different from Moose's type constraint of the same name; let me know if this causes you any problems. (I can't promise I'll change anything though.) =item * B<< Ref[`a] >> Any defined reference value, including blessed objects. Unlike Moose, B is a parameterized type, allowing Scalar::Util::reftype checks, a la Ref["HASH"] # hashrefs, including blessed hashrefs =item * B<< ScalarRef[`a] >> A value where C<< ref($value) eq "SCALAR" or ref($value) eq "REF" >>. If parameterized, the referred value must pass the additional constraint. For example, B<< ScalarRef[Int] >> must be a reference to a scalar which holds an integer value. =item * B<< ArrayRef[`a] >> A value where C<< ref($value) eq "ARRAY" >>. If parameterized, the elements of the array must pass the additional constraint. For example, B<< ArrayRef[Num] >> must be a reference to an array of numbers. As an extension to Moose's B type, a minimum and maximum array length can be given: ArrayRef[CodeRef, 1] # ArrayRef of at least one CodeRef ArrayRef[FileHandle, 0, 2] # ArrayRef of up to two FileHandles ArrayRef[Any, 0, 100] # ArrayRef of up to 100 elements Other customers also bought: B<< ArrayLike >> from L. =item * B<< HashRef[`a] >> A value where C<< ref($value) eq "HASH" >>. If parameterized, the values of the hash must pass the additional constraint. For example, B<< HashRef[Num] >> must be a reference to an hash where the values are numbers. The hash keys are not constrained, but Perl limits them to strings; see B below if you need to further constrain the hash values. Other customers also bought: B<< HashLike >> from L. =item * B<< CodeRef >> A value where C<< ref($value) eq "CODE" >>. Other customers also bought: B<< CodeLike >> from L. =item * B<< RegexpRef >> A reference where C<< re::is_regexp($value) >> is true, or a blessed reference where C<< $value->isa("Regexp") >> is true. =item * B<< GlobRef >> A value where C<< ref($value) eq "GLOB" >>. =item * B<< FileHandle >> A file handle. =item * B<< Object >> A blessed object. (This also accepts regexp refs.) =back =head2 Structured OK, so I stole some ideas from L. =over =item * B<< Map[`k, `v] >> Similar to B but parameterized with type constraints for both the key and value. The constraint for keys would typically be a subtype of B. =item * B<< Tuple[...] >> Subtype of B, accepting a list of type constraints for each slot in the array. B<< Tuple[Int, HashRef] >> would match C<< [1, {}] >> but not C<< [{}, 1] >>. =item * B<< Dict[...] >> Subtype of B, accepting a list of type constraints for each slot in the hash. For example B<< Dict[name => Str, id => Int] >> allows C<< { name => "Bob", id => 42 } >>. =item * B<< Optional[`a] >> Used in conjunction with B and B to specify slots that are optional and may be omitted (but not necessarily set to an explicit undef). B<< Dict[name => Str, id => Optional[Int]] >> allows C<< { name => "Bob" } >> but not C<< { name => "Bob", id => "BOB" } >>. Note that any use of B<< Optional[`a] >> outside the context of parameterized B and B type constraints makes little sense, and its behaviour is undefined. (An exception: it is used by L for a similar purpose to how it's used in B.) =back This module also exports a C function, which can be used as follows. It can cause additional trailing values in a B to be slurped into a structure and validated. For example, slurping into an arrayfef: my $type = Tuple[Str, slurpy ArrayRef[Int]]; $type->( ["Hello"] ); # ok $type->( ["Hello", 1, 2, 3] ); # ok $type->( ["Hello", [1, 2, 3]] ); # not ok Or into a hashref: my $type2 = Tuple[Str, slurpy Map[Int, RegexpRef]]; $type2->( ["Hello"] ); # ok $type2->( ["Hello", 1, qr/one/i, 2, qr/two/] ); # ok It can cause additional values in a B to be slurped into a hashref and validated: my $type3 = Dict[ values => ArrayRef, slurpy HashRef[Str] ]; $type3->( { values => [] } ); # ok $type3->( { values => [], name => "Foo" } ); # ok $type3->( { values => [], name => [] } ); # not ok In either B or B, B<< slurpy Any >> can be used to indicate that additional values are acceptable, but should not be constrained in any way. B<< slurpy Any >> is an optimized code path. Although the following are essentially equivalent checks, the former should run a lot faster: Tuple[Int, slurpy Any] Tuple[Int, slurpy ArrayRef] =begin trustme =item slurpy =end trustme =head2 Objects OK, so I stole some ideas from L. =over =item * B<< InstanceOf[`a] >> Shortcut for a union of L constraints. B<< InstanceOf["Foo", "Bar"] >> allows objects blessed into the C or C classes, or subclasses of those. Given no parameters, just equivalent to B. =item * B<< ConsumerOf[`a] >> Shortcut for an intersection of L constraints. B<< ConsumerOf["Foo", "Bar"] >> allows objects where C<< $o->DOES("Foo") >> and C<< $o->DOES("Bar") >> both return true. Given no parameters, just equivalent to B. =item * B<< HasMethods[`a] >> Shortcut for a L constraint. B<< HasMethods["foo", "bar"] >> allows objects where C<< $o->can("foo") >> and C<< $o->can("bar") >> both return true. Given no parameters, just equivalent to B. =back =head2 More There are a few other types exported by this module: =over =item * B<< Overload[`a] >> With no parameters, checks that the value is an overloaded object. Can be given one or more string parameters, which are specific operations to check are overloaded. For example, the following checks for objects which overload addition and subtraction. Overload["+", "-"] =item * B<< Tied[`a] >> A reference to a tied scalar, array or hash. Can be parameterized with a type constraint which will be applied to the object returned by the C<< tied() >> function. As a convenience, can also be parameterized with a string, which will be inflated to a L. use Types::Standard qw(Tied); use Type::Utils qw(class_type); my $My_Package = class_type { class => "My::Package" }; tie my %h, "My::Package"; \%h ~~ Tied; # true \%h ~~ Tied[ $My_Package ]; # true \%h ~~ Tied["My::Package"]; # true tie my $s, "Other::Package"; \$s ~~ Tied; # true $s ~~ Tied; # false !! If you need to check that something is specifically a reference to a tied hash, use an intersection: use Types::Standard qw( Tied HashRef ); my $TiedHash = (Tied) & (HashRef); tie my %h, "My::Package"; tie my $s, "Other::Package"; \%h ~~ $TiedHash; # true \$s ~~ $TiedHash; # false =item * B<< StrMatch[`a] >> A string that matches a regular expression: declare "Distance", as StrMatch[ qr{^([0-9]+)\s*(mm|cm|m|km)$} ]; You can optionally provide a type constraint for the array of subexpressions: declare "Distance", as StrMatch[ qr{^([0-9]+)\s*(.+)$}, Tuple[ Int, enum(DistanceUnit => [qw/ mm cm m km /]), ], ]; Here's an example using L: package Local::Host { use Moose; use Regexp::Common; has ip_address => ( is => 'ro', required => 1. isa => StrMatch[/^$RE{net}{IPv4}$/], default => '127.0.0.1', ); } On certain versions of Perl, type constraints of the forms B<< StrMatch[qr/../ >> and B<< StrMatch[qr/\A..\z/ >> with any number of intervening dots can be optimized to simple length checks. =item * B<< Enum[`a] >> As per MooX::Types::MooseLike::Base: has size => (is => "ro", isa => Enum[qw( S M L XL XXL )]); =item * B<< OptList >> An arrayref of arrayrefs in the style of L output. =item * B<< LaxNum >>, B<< StrictNum >> In Moose 2.09, the B type constraint implementation was changed from being a wrapper around L's C function to a stricter regexp (which disallows things like "-Inf" and "Nan"). Types::Standard provides I implementations. B is measurably faster. The B type constraint is currently an alias for B unless you set the C environment variable to true before loading Types::Standard, in which case it becomes an alias for B. The constant C<< Types::Standard::STRICTNUM >> can be used to check if B is being strict. Most people should probably use B or B. Don't explicitly use B unless you specifically need an attribute which will accept things like "Inf". =item * B<< CycleTuple[`a] >> Similar to B, but cyclical. CycleTuple[Int, HashRef] will allow C<< [1,{}] >> and C<< [1,{},2,{}] >> but disallow C<< [1,{},2] >> and C<< [1,{},2,[]] >>. I think you understand B already. Currently B and C parameters are forbidden. There are fairly limited use cases for them, and it's not exactly clear what they should mean. The following is an efficient way of checking for an even-sized arrayref: CycleTuple[Any, Any] The following is an arrayref which would be suitable for coercing to a hashref: CycleTuple[Str, Any] All the examples so far have used two parameters, but the following is also a possible B: CycleTuple[Str, Int, HashRef] This will be an arrayref where the 0th, 3rd, 6th, etc values are strings, the 1st, 4th, 7th, etc values are integers, and the 2nd, 5th, 8th, etc values are hashrefs. =back =head2 Coercions Most of the types in this type library have no coercions by default. The exception is B as of Types::Standard 1.003_003, which coerces from B via C<< !!$_ >>. Some standalone coercions may be exported. These can be combined with type constraints using the C<< plus_coercions >> method. =over =item * B<< MkOpt >> A coercion from B, B or B to B. Example usage in a Moose attribute: use Types::Standard qw( OptList MkOpt ); has options => ( is => "ro", isa => OptList->plus_coercions( MkOpt ), coerce => 1, ); =item * B<< Split[`a] >> Split a string on a regexp. use Types::Standard qw( ArrayRef Str Split ); has name => ( is => "ro", isa => ArrayRef->of(Str)->plus_coercions(Split[qr/\s/]), coerce => 1, ); =item * B<< Join[`a] >> Join an array of strings with a delimiter. use Types::Standard qw( Str Join ); my $FileLines = Str->plus_coercions(Join["\n"]); has file_contents => ( is => "ro", isa => $FileLines, coerce => 1, ); =back =head2 Constants =over =item C<< Types::Standard::STRICTNUM >> Indicates whether B is an alias for B. (It is usually an alias for B.) =back =head2 Environment =over =item C Switches to more strict regexp-based number checking instead of using C. =item C If set to false, can be used to suppress the loading of XS implementions of some type constraints. =item C If C does not exist, can be set to true to suppress XS usage similarly. (Several other CPAN distributions also pay attention to this environment variable.) =back =begin private =item Stringable =item LazyLoad =end private =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. L. L, L, L, L. L, L, L. L provides some type constraints based on XML Schema's data types; this includes constraints for ISO8601-formatted datetimes, integer ranges (e.g. B<< PositiveInteger[maxInclusive=>10] >> and so on. L provides B and B type constraints that were formerly found in Types::Standard. L and L provide replacements for L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. TypeTiny.pm000644001750001750 3632313601673061 16431 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Typespackage Types::TypeTiny; use strict; use warnings; our $AUTHORITY = 'cpan:TOBYINK'; our $VERSION = '1.008001'; $VERSION =~ tr/_//d; use Scalar::Util qw< blessed refaddr weaken >; our @EXPORT_OK = ( map(@{[ $_, "is_$_", "assert_$_" ]}, __PACKAGE__->type_names), qw/to_TypeTiny/ ); our %EXPORT_TAGS = ( types => [ __PACKAGE__->type_names ], is => [ map "is_$_", __PACKAGE__->type_names ], assert => [ map "assert_$_", __PACKAGE__->type_names ], ); my %cache; # This `import` method is designed to avoid loading Exporter::Tiny. # This is so that if you stick to only using the purely OO parts of # Type::Tiny, you can skip loading the exporter. # sub import { # If this sub succeeds, it will replace itself. # uncoverable subroutine return unless @_ > 1; # uncoverable statement no warnings "redefine"; # uncoverable statement our @ISA = qw( Exporter::Tiny ); # uncoverable statement require Exporter::Tiny; # uncoverable statement my $next = \&Exporter::Tiny::import; # uncoverable statement *import = $next; # uncoverable statement my $class = shift; # uncoverable statement my $opts = { ref($_[0]) ? %{+shift} : () }; # uncoverable statement $opts->{into} ||= scalar(caller); # uncoverable statement return $class->$next($opts, @_); # uncoverable statement } for (__PACKAGE__->type_names) { eval qq{ sub is_$_ { $_()->check(shift) } sub assert_$_ { $_()->assert_return(shift) } }; } sub meta { return $_[0]; } sub type_names { qw( CodeLike StringLike TypeTiny HashLike ArrayLike _ForeignTypeConstraint ); } sub has_type { my %has = map +($_ => 1), shift->type_names; !!$has{ $_[0] }; } sub get_type { my $self = shift; return unless $self->has_type(@_); no strict qw(refs); &{$_[0]}(); } sub coercion_names { qw(); } sub has_coercion { my %has = map +($_ => 1), shift->coercion_names; !!$has{ $_[0] }; } sub get_coercion { my $self = shift; return unless $self->has_coercion(@_); no strict qw(refs); &{$_[0]}(); # uncoverable statement } my ($__get_linear_isa_dfs, $tried_mro); $__get_linear_isa_dfs = sub { if (!$tried_mro && eval { require mro }) { $__get_linear_isa_dfs = \&mro::get_linear_isa; goto $__get_linear_isa_dfs; } no strict 'refs'; my $classname = shift; my @lin = ($classname); my %stored; foreach my $parent (@{"$classname\::ISA"}) { my $plin = $__get_linear_isa_dfs->($parent); foreach (@$plin) { next if exists $stored{$_}; push(@lin, $_); $stored{$_} = 1; } } return \@lin; }; sub _check_overload { my $package = shift; if (ref $package) { $package = blessed($package); return !!0 if !defined $package; } my $op = shift; my $mro = $__get_linear_isa_dfs->($package); foreach my $p (@$mro) { my $fqmeth = $p . q{::(} . $op; return !!1 if defined &{$fqmeth}; } !!0; } sub _get_check_overload_sub { if ($Type::Tiny::AvoidCallbacks) { return '(sub { require overload; overload::Overloaded(ref $_[0] or $_[0]) and overload::Method((ref $_[0] or $_[0]), $_[1]) })->' } return 'Types::TypeTiny::_check_overload'; } sub StringLike () { require Type::Tiny; $cache{StringLike} ||= "Type::Tiny"->new( name => "StringLike", constraint => sub { defined($_ ) && !ref($_ ) or Scalar::Util::blessed($_ ) && Types::TypeTiny::_check_overload($_ , q[""]) }, inlined => sub { qq/defined($_[1]) && !ref($_[1]) or Scalar::Util::blessed($_[1]) && ${\ +_get_check_overload_sub() }($_[1], q[""])/ }, library => __PACKAGE__, ); } sub HashLike () { require Type::Tiny; $cache{HashLike} ||= "Type::Tiny"->new( name => "HashLike", constraint => sub { ref($_ ) eq q[HASH] or Scalar::Util::blessed($_ ) && Types::TypeTiny::_check_overload($_ , q[%{}]) }, inlined => sub { qq/ref($_[1]) eq q[HASH] or Scalar::Util::blessed($_[1]) && ${\ +_get_check_overload_sub() }($_[1], q[\%{}])/ }, library => __PACKAGE__, ); } sub ArrayLike () { require Type::Tiny; $cache{ArrayLike} ||= "Type::Tiny"->new( name => "ArrayLike", constraint => sub { ref($_ ) eq q[ARRAY] or Scalar::Util::blessed($_ ) && Types::TypeTiny::_check_overload($_ , q[@{}]) }, inlined => sub { qq/ref($_[1]) eq q[ARRAY] or Scalar::Util::blessed($_[1]) && ${\ +_get_check_overload_sub() }($_[1], q[\@{}])/ }, library => __PACKAGE__, ); } sub CodeLike () { require Type::Tiny; $cache{CodeLike} ||= "Type::Tiny"->new( name => "CodeLike", constraint => sub { ref($_ ) eq q[CODE] or Scalar::Util::blessed($_ ) && Types::TypeTiny::_check_overload($_ , q[&{}]) }, inlined => sub { qq/ref($_[1]) eq q[CODE] or Scalar::Util::blessed($_[1]) && ${\ +_get_check_overload_sub() }($_[1], q[\&{}])/ }, library => __PACKAGE__, ); } sub TypeTiny () { require Type::Tiny; $cache{TypeTiny} ||= "Type::Tiny"->new( name => "TypeTiny", constraint => sub { Scalar::Util::blessed($_ ) && $_ ->isa(q[Type::Tiny]) }, inlined => sub { my $var = $_[1]; "Scalar::Util::blessed($var) && $var\->isa(q[Type::Tiny])" }, library => __PACKAGE__, _build_coercion => sub { my $c = shift; $c->add_type_coercions(_ForeignTypeConstraint(), \&to_TypeTiny); $c->freeze; }, ); } sub _ForeignTypeConstraint () { require Type::Tiny; $cache{_ForeignTypeConstraint} ||= "Type::Tiny"->new( name => "_ForeignTypeConstraint", constraint => \&_is_ForeignTypeConstraint, inlined => sub { qq/ref($_[1]) && do { require Types::TypeTiny; Types::TypeTiny::_is_ForeignTypeConstraint($_[1]) }/ }, library => __PACKAGE__, ); } my %ttt_cache; sub _is_ForeignTypeConstraint { my $t = @_ ? $_[0] : $_; return !!1 if ref $t eq 'CODE'; if (my $class = blessed $t) { return !!0 if $class->isa("Type::Tiny"); return !!1 if $class->isa("Moose::Meta::TypeConstraint"); return !!1 if $class->isa("MooseX::Types::TypeDecorator"); return !!1 if $class->isa("Validation::Class::Simple"); return !!1 if $class->isa("Validation::Class"); return !!1 if $t->can("check") && $t->can("get_message"); } !!0; } sub to_TypeTiny { my $t = @_ ? $_[0] : $_; return $t unless (my $ref = ref $t); return $t if $ref =~ /^Type::Tiny\b/; return $ttt_cache{ refaddr($t) } if $ttt_cache{ refaddr($t) }; if (my $class = blessed $t) { return $t if $class->isa("Type::Tiny"); return _TypeTinyFromMoose($t) if $class eq "MooseX::Types::TypeDecorator"; # needed before MooseX::Types 0.35. return _TypeTinyFromMoose($t) if $class->isa("Moose::Meta::TypeConstraint"); return _TypeTinyFromMoose($t) if $class->isa("MooseX::Types::TypeDecorator"); return _TypeTinyFromMouse($t) if $class->isa("Mouse::Meta::TypeConstraint"); return _TypeTinyFromValidationClass($t) if $class->isa("Validation::Class::Simple"); return _TypeTinyFromValidationClass($t) if $class->isa("Validation::Class"); return _TypeTinyFromGeneric($t) if $t->can("check") && $t->can("get_message"); # i.e. Type::API::Constraint } return _TypeTinyFromCodeRef($t) if $ref eq q(CODE); $t; } sub _TypeTinyFromMoose { my $t = $_[0]; if (ref $t->{"Types::TypeTiny::to_TypeTiny"}) { return $t->{"Types::TypeTiny::to_TypeTiny"}; } if ($t->name ne '__ANON__') { require Types::Standard; my $ts = 'Types::Standard'->get_type($t->name); return $ts if $ts->{_is_core}; } my %opts; $opts{display_name} = $t->name; $opts{constraint} = $t->constraint; $opts{parent} = to_TypeTiny($t->parent) if $t->has_parent; $opts{inlined} = sub { shift; $t->_inline_check(@_) } if $t->can("can_be_inlined") && $t->can_be_inlined; $opts{message} = sub { $t->get_message($_) } if $t->has_message; $opts{moose_type} = $t; if ($t->can('parameterize')) { $opts{constraint_generator} = sub { # convert args into Moose native types; not strictly necessary my @args = map { TypeTiny->check($_) ? $_->moose_type : $_ } @_; my $paramd = $t->parameterize(@args); _TypeTinyFromMoose($paramd); }; } require Type::Tiny; my $new = 'Type::Tiny'->new(%opts); $ttt_cache{ refaddr($t) } = $new; weaken($ttt_cache{ refaddr($t) }); $new->{coercion} = do { require Type::Coercion::FromMoose; 'Type::Coercion::FromMoose'->new( type_constraint => $new, moose_coercion => $t->coercion, ); } if $t->has_coercion; return $new; } sub _TypeTinyFromValidationClass { my $t = $_[0]; require Type::Tiny; require Types::Standard; my %opts = ( parent => Types::Standard::HashRef(), _validation_class => $t, ); if ($t->VERSION >= "7.900048") { $opts{constraint} = sub { $t->params->clear; $t->params->add(%$_); my $f = $t->filtering; $t->filtering('off'); my $r = eval { $t->validate }; $t->filtering($f || 'pre'); return $r; }; $opts{message} = sub { $t->params->clear; $t->params->add(%$_); my $f = $t->filtering; $t->filtering('off'); my $r = (eval { $t->validate } ? "OK" : $t->errors_to_string); $t->filtering($f || 'pre'); return $r; }; } else # need to use hackish method { $opts{constraint} = sub { $t->params->clear; $t->params->add(%$_); no warnings "redefine"; local *Validation::Class::Directive::Filters::execute_filtering = sub { $_[0] }; eval { $t->validate }; }; $opts{message} = sub { $t->params->clear; $t->params->add(%$_); no warnings "redefine"; local *Validation::Class::Directive::Filters::execute_filtering = sub { $_[0] }; eval { $t->validate } ? "OK" : $t->errors_to_string; }; } require Type::Tiny; my $new = "Type::Tiny"->new(%opts); $new->coercion->add_type_coercions( Types::Standard::HashRef() => sub { my %params = %$_; for my $k (keys %params) { delete $params{$_} unless $t->get_fields($k) }; $t->params->clear; $t->params->add(%params); eval { $t->validate }; $t->get_hash; }, ); $ttt_cache{ refaddr($t) } = $new; weaken($ttt_cache{ refaddr($t) }); return $new; } sub _TypeTinyFromGeneric { my $t = $_[0]; my %opts = ( constraint => sub { $t->check(@_ ? @_ : $_) }, message => sub { $t->get_message(@_ ? @_ : $_) }, ); $opts{display_name} = $t->name if $t->can("name"); $opts{coercion} = sub { $t->coerce(@_ ? @_ : $_) } if $t->can("has_coercion") && $t->has_coercion && $t->can("coerce"); if ($t->can('can_be_inlined') && $t->can_be_inlined && $t->can('inline_check')) { $opts{inlined} = sub { $t->inline_check($_[1]) }; } require Type::Tiny; my $new = "Type::Tiny"->new(%opts); $ttt_cache{ refaddr($t) } = $new; weaken($ttt_cache{ refaddr($t) }); return $new; } sub _TypeTinyFromMouse { my $t = $_[0]; my %opts = ( constraint => sub { $t->check(@_ ? @_ : $_) }, message => sub { $t->get_message(@_ ? @_ : $_) }, ); $opts{display_name} = $t->name if $t->can("name"); $opts{coercion} = sub { $t->coerce(@_ ? @_ : $_) } if $t->can("has_coercion") && $t->has_coercion && $t->can("coerce"); if ($t->{'constraint_generator'}) { $opts{constraint_generator} = sub { # convert args into Moose native types; not strictly necessary my @args = map { TypeTiny->check($_) ? $_->mouse_type : $_ } @_; my $paramd = $t->parameterize(@args); _TypeTinyFromMouse($paramd); }; } require Type::Tiny; my $new = "Type::Tiny"->new(%opts); $ttt_cache{ refaddr($t) } = $new; weaken($ttt_cache{ refaddr($t) }); return $new; } my $QFS; sub _TypeTinyFromCodeRef { my $t = $_[0]; my %opts = ( constraint => sub { return !!eval { $t->($_) }; }, message => sub { local $@; eval { $t->($_); 1 } or do { chomp $@; return $@ if $@ }; return sprintf('%s did not pass type constraint', Type::Tiny::_dd($_)); }, ); if ($QFS ||= "Sub::Quote"->can("quoted_from_sub")) { my (undef, $perlstring, $captures) = @{ $QFS->($t) || [] }; if ($perlstring) { $perlstring = "!!eval{ $perlstring }"; $opts{inlined} = sub { my $var = $_[1]; Sub::Quote::inlinify( $perlstring, $var, $var eq q($_) ? '' : "local \$_ = $var;", 1, ); } if $perlstring && !$captures; } } require Type::Tiny; my $new = "Type::Tiny"->new(%opts); $ttt_cache{ refaddr($t) } = $new; weaken($ttt_cache{ refaddr($t) }); return $new; } 1; __END__ =pod =encoding utf-8 =for stopwords arrayfication hashification =head1 NAME Types::TypeTiny - type constraints used internally by Type::Tiny =head1 STATUS This module is covered by the L. =head1 DESCRIPTION Dogfooding. This isn't a real Type::Library-based type library; that would involve too much circularity. But it exports some type constraints which, while designed for use within Type::Tiny, may be more generally useful. =head2 Types =over =item C<< StringLike >> Accepts strings and objects overloading stringification. =item C<< HashLike >> Accepts hashrefs and objects overloading hashification. =item C<< ArrayLike >> Accepts arrayrefs and objects overloading arrayfication. =item C<< CodeLike >> Accepts coderefs and objects overloading codification. =item C<< TypeTiny >> Accepts blessed L objects. =item C<< _ForeignTypeConstraint >> Any reference which to_TypeTiny recognizes as something that can be coerced to a Type::Tiny object. Yeah, the underscore is included. =back =head2 Coercion Functions =over =item C<< to_TypeTiny($constraint) >> Promotes (or "demotes" if you prefer) a Moose::Meta::TypeConstraint object to a Type::Tiny object. Can also handle L objects. Type constraints built from Validation::Class objects deliberately I field filters when they do constraint checking (and go to great lengths to do so); using filters for coercion only. (The behaviour of C if we don't do that is just too weird!) Can also handle any object providing C and C methods. (This includes L objects.) If the object also provides C and C methods, these will be used too. Can also handle coderefs (but not blessed coderefs or objects overloading C<< &{} >>). Coderefs are expected to return true iff C<< $_ >> passes the constraint. If C<< $_ >> fails the type constraint, they may either return false, or die with a helpful error message. =back =head2 Methods These are implemented so that C<< Types::TypeTiny->meta->get_type($foo) >> works, for rough compatibility with a real L type library. =over =item C<< meta >> =item C<< type_names >> =item C<< get_type($name) >> =item C<< has_type($name) >> =item C<< coercion_names >> =item C<< get_coercion($name) >> =item C<< has_coercion($name) >> =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Any.t000644001750001750 1311513601673061 15171 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Any ); isa_ok(Any, 'Type::Tiny', 'Any'); is(Any->name, 'Any', 'Any has correct name'); is(Any->display_name, 'Any', 'Any has correct display_name'); is(Any->library, 'Types::Standard', 'Any knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Any'), 'Types::Standard knows it has type Any'); ok(!Any->deprecated, 'Any is not deprecated'); ok(!Any->is_anon, 'Any is not anonymous'); ok(Any->can_be_inlined, 'Any can be inlined'); is(exception { Any->inline_check(q/$xyz/) }, undef, "Inlining Any doesn't throw an exception"); ok(!Any->has_coercion, "Any doesn't have a coercion"); ok(!Any->is_parameterizable, "Any isn't parameterizable"); my @none_tests = my @tests = ( pass => 'undef' => undef, pass => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, pass => 'empty string' => '', pass => 'whitespace' => ' ', pass => 'line break' => "\n", pass => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', pass => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', pass => 'a reference to undef' => do { my $x = undef; \$x }, pass => 'a reference to false' => do { my $x = !!0; \$x }, pass => 'a reference to true' => do { my $x = !!1; \$x }, pass => 'a reference to zero' => do { my $x = 0; \$x }, pass => 'a reference to one' => do { my $x = 1; \$x }, pass => 'a reference to empty string' => do { my $x = ''; \$x }, pass => 'a reference to random string' => do { my $x = 'abc123'; \$x }, pass => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), pass => 'empty arrayref' => [], pass => 'arrayref with one zero' => [0], pass => 'arrayref of integers' => [1..10], pass => 'arrayref of numbers' => [1..10, 3.1416], pass => 'blessed arrayref' => bless([], 'SomePkg'), pass => 'empty hashref' => {}, pass => 'hashref' => { foo => 1 }, pass => 'blessed hashref' => bless({}, 'SomePkg'), pass => 'coderef' => sub { 1 }, pass => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), pass => 'glob' => do { no warnings 'once'; *SOMETHING }, pass => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, pass => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), pass => 'regexp' => qr/./, pass => 'blessed regexp' => bless(qr/./, 'SomePkg'), pass => 'filehandle' => do { open my $x, '<', $0 or die; $x }, pass => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, pass => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, pass => 'ref to arrayref' => do { my $x = []; \$x }, pass => 'ref to hashref' => do { my $x = {}; \$x }, pass => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, pass => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, pass => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, pass => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, pass => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, pass => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, pass => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, pass => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, pass => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Any, ucfirst("$label should pass Any")); } elsif ($expect eq 'fail') { should_fail($value, Any, ucfirst("$label should fail Any")); } else { fail("expected '$expect'?!"); } } # # The complement of Any is None, which rejects everything. # my $None = ~Any; is($None->name, "None", "Complement of Any is None."); ok($None->can_be_inlined, "None can be inlined."); subtest "None fails where Any passes and vice versa" => sub { while (@none_tests) { my ($expect, $label, $value) = splice(@none_tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_fail($value, $None, ucfirst("$label should fail None")); } elsif ($expect eq 'fail') { should_pass($value, $None, ucfirst("$label should pass None")); } else { fail("expected '$expect'?!"); } } }; done_testing; ArrayLike.t000644001750001750 1213713601673061 16330 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::TypeTiny qw( ArrayLike ); isa_ok(ArrayLike, 'Type::Tiny', 'ArrayLike'); is(ArrayLike->name, 'ArrayLike', 'ArrayLike has correct name'); is(ArrayLike->display_name, 'ArrayLike', 'ArrayLike has correct display_name'); is(ArrayLike->library, 'Types::TypeTiny', 'ArrayLike knows it is in the Types::TypeTiny library'); ok(Types::TypeTiny->has_type('ArrayLike'), 'Types::TypeTiny knows it has type ArrayLike'); ok(!ArrayLike->deprecated, 'ArrayLike is not deprecated'); ok(!ArrayLike->is_anon, 'ArrayLike is not anonymous'); ok(ArrayLike->can_be_inlined, 'ArrayLike can be inlined'); is(exception { ArrayLike->inline_check(q/$xyz/) }, undef, "Inlining ArrayLike doesn't throw an exception"); ok(!ArrayLike->has_coercion, "ArrayLike doesn't have a coercion"); ok(!ArrayLike->is_parameterizable, "ArrayLike isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), pass => 'empty arrayref' => [], pass => 'arrayref with one zero' => [0], pass => 'arrayref of integers' => [1..10], pass => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, pass => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, ArrayLike, ucfirst("$label should pass ArrayLike")); } elsif ($expect eq 'fail') { should_fail($value, ArrayLike, ucfirst("$label should fail ArrayLike")); } else { fail("expected '$expect'?!"); } } done_testing; ArrayRef.t000644001750001750 2242113601673061 16155 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( ArrayRef ); isa_ok(ArrayRef, 'Type::Tiny', 'ArrayRef'); is(ArrayRef->name, 'ArrayRef', 'ArrayRef has correct name'); is(ArrayRef->display_name, 'ArrayRef', 'ArrayRef has correct display_name'); is(ArrayRef->library, 'Types::Standard', 'ArrayRef knows it is in the Types::Standard library'); ok(Types::Standard->has_type('ArrayRef'), 'Types::Standard knows it has type ArrayRef'); ok(!ArrayRef->deprecated, 'ArrayRef is not deprecated'); ok(!ArrayRef->is_anon, 'ArrayRef is not anonymous'); ok(ArrayRef->can_be_inlined, 'ArrayRef can be inlined'); is(exception { ArrayRef->inline_check(q/$xyz/) }, undef, "Inlining ArrayRef doesn't throw an exception"); ok(!ArrayRef->has_coercion, "ArrayRef doesn't have a coercion"); ok(ArrayRef->is_parameterizable, "ArrayRef is parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), pass => 'empty arrayref' => [], pass => 'arrayref with one zero' => [0], pass => 'arrayref of integers' => [1..10], pass => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, ArrayRef, ucfirst("$label should pass ArrayRef")); } elsif ($expect eq 'fail') { should_fail($value, ArrayRef, ucfirst("$label should fail ArrayRef")); } else { fail("expected '$expect'?!"); } } # # ArrayRef is parameterizable # my $ArrayOfInts = ArrayRef->of( Types::Standard::Int ); isa_ok($ArrayOfInts, 'Type::Tiny', '$ArrayOfInts'); is($ArrayOfInts->display_name, 'ArrayRef[Int]', '$ArrayOfInts has correct display_name'); ok($ArrayOfInts->is_anon, '$ArrayOfInts has no name'); ok($ArrayOfInts->can_be_inlined, '$ArrayOfInts can be inlined'); is(exception { $ArrayOfInts->inline_check(q/$xyz/) }, undef, "Inlining \$ArrayOfInts doesn't throw an exception"); ok(!$ArrayOfInts->has_coercion, "\$ArrayOfInts doesn't have a coercion"); ok(!$ArrayOfInts->is_parameterizable, "\$ArrayOfInts is not parameterizable"); ok_subtype(ArrayRef, $ArrayOfInts); should_fail( 1, $ArrayOfInts ); should_fail( {}, $ArrayOfInts ); should_pass( [ ], $ArrayOfInts ); should_fail( [ [] ], $ArrayOfInts ); should_fail( [ 1.1 ], $ArrayOfInts ); should_pass( [ 1 ], $ArrayOfInts ); should_pass( [ 0 ], $ArrayOfInts ); should_pass( [ -1 ], $ArrayOfInts ); should_fail( [ \1 ], $ArrayOfInts ); should_pass( [ 1, 2 ], $ArrayOfInts ); should_fail( [ 1, [] ], $ArrayOfInts ); use Scalar::Util qw( refaddr ); my $plain = ArrayRef; my $paramd = ArrayRef[]; is( refaddr($plain), refaddr($paramd), 'parameterizing with [] has no effect' ); my $p1 = ArrayRef[Types::Standard::Int]; my $p2 = ArrayRef[Types::Standard::Int]; is(refaddr($p1), refaddr($p2), 'parameterizing is cached'); # # ArrayRef can accept a second parameter. # my $ArrayOfAtLeastTwoInts = ArrayRef->of( Types::Standard::Int, 2 ); should_fail( 1, $ArrayOfAtLeastTwoInts ); should_fail( {}, $ArrayOfAtLeastTwoInts ); should_fail( [ ], $ArrayOfAtLeastTwoInts ); should_fail( [ [] ], $ArrayOfAtLeastTwoInts ); should_fail( [ 1.1 ], $ArrayOfAtLeastTwoInts ); should_fail( [ 1 ], $ArrayOfAtLeastTwoInts ); should_fail( [ 0 ], $ArrayOfAtLeastTwoInts ); should_fail( [ -1 ], $ArrayOfAtLeastTwoInts ); should_fail( [ \1 ], $ArrayOfAtLeastTwoInts ); should_pass( [ 1, 2 ], $ArrayOfAtLeastTwoInts ); should_fail( [ 1, [] ], $ArrayOfAtLeastTwoInts ); should_pass( [ 1, -1 ], $ArrayOfAtLeastTwoInts ); should_pass( [ 1 .. 9 ], $ArrayOfAtLeastTwoInts ); # # ArrayRef has deep coercions # my $Rounded = Types::Standard::Int->plus_coercions( Types::Standard::Num, q{ int($_) } ); my $ArrayOfRounded = ArrayRef->of( $Rounded ); isa_ok($ArrayOfRounded, 'Type::Tiny', '$ArrayOfRounded'); is($ArrayOfRounded->display_name, 'ArrayRef[Int]', '$ArrayOfRounded has correct display_name'); ok($ArrayOfRounded->is_anon, '$ArrayOfRounded has no name'); ok($ArrayOfRounded->can_be_inlined, '$ArrayOfRounded can be inlined'); is(exception { $ArrayOfRounded->inline_check(q/$xyz/) }, undef, "Inlining \$ArrayOfRounded doesn't throw an exception"); ok($ArrayOfRounded->has_coercion, "\$ArrayOfRounded has a coercion"); ok($ArrayOfRounded->coercion->has_coercion_for_type(ArrayRef), '$ArrayRefOfRounded can coerce from ArrayRef'); ok($ArrayOfRounded->coercion->has_coercion_for_type(ArrayRef->of(Types::Standard::Num)), '$ArrayRefOfRounded can coerce from ArrayRef[Num]'); ok(!$ArrayOfRounded->is_parameterizable, "\$ArrayOfRounded is not parameterizable"); ok_subtype(ArrayRef, $ArrayOfRounded); should_fail( 1, $ArrayOfRounded ); should_fail( {}, $ArrayOfRounded ); should_pass( [ ], $ArrayOfRounded ); should_fail( [ [] ], $ArrayOfRounded ); should_fail( [ 1.1 ], $ArrayOfRounded ); should_pass( [ 1 ], $ArrayOfRounded ); should_pass( [ 0 ], $ArrayOfRounded ); should_pass( [ -1 ], $ArrayOfRounded ); should_fail( [ \1 ], $ArrayOfRounded ); should_pass( [ 1, 2 ], $ArrayOfRounded ); should_fail( [ 1, [] ], $ArrayOfRounded ); do { my $orig = [ 42 ]; my $coerced = $ArrayOfRounded->coerce($orig); is( refaddr($orig), refaddr($coerced), "just returned orig unchanged" ); }; do { my $orig = [ 42.1 ]; my $coerced = $ArrayOfRounded->coerce($orig); isnt( refaddr($orig), refaddr($coerced), "coercion happened" ); is($coerced->[0], 42, "... and data looks good"); should_pass($coerced, $ArrayOfRounded, "... and now passes type constraint"); }; do { my $orig = [ [] ]; my $coerced = $ArrayOfRounded->coerce($orig); is( refaddr($orig), refaddr($coerced), "coercion failed, so orig was returned" ); should_fail($coerced, $ArrayOfRounded); }; done_testing; Bool.t000644001750001750 2327713601673061 15347 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Bool ); isa_ok(Bool, 'Type::Tiny', 'Bool'); is(Bool->name, 'Bool', 'Bool has correct name'); is(Bool->display_name, 'Bool', 'Bool has correct display_name'); is(Bool->library, 'Types::Standard', 'Bool knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Bool'), 'Types::Standard knows it has type Bool'); ok(!Bool->deprecated, 'Bool is not deprecated'); ok(!Bool->is_anon, 'Bool is not anonymous'); ok(Bool->can_be_inlined, 'Bool can be inlined'); is(exception { Bool->inline_check(q/$xyz/) }, undef, "Inlining Bool doesn't throw an exception"); ok(Bool->has_coercion, "Bool has a coercion"); ok(!Bool->is_parameterizable, "Bool isn't parameterizable"); my @tests = ( pass => 'undef' => undef, pass => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, pass => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Bool, ucfirst("$label should pass Bool")); } elsif ($expect eq 'fail') { should_fail($value, Bool, ucfirst("$label should fail Bool")); } else { fail("expected '$expect'?!"); } } # # Bool has coercions from everything. # my @tests2 = ( false => 'undef' => undef, false => 'false' => !!0, true => 'true' => !!1, false => 'zero' => 0, true => 'one' => 1, true => 'negative one' => -1, true => 'non integer' => 3.1416, false => 'empty string' => '', true => 'whitespace' => ' ', true => 'line break' => "\n", true => 'random string' => 'abc123', true => 'loaded package name' => 'Type::Tiny', true => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', true => 'a reference to undef' => do { my $x = undef; \$x }, true => 'a reference to false' => do { my $x = !!0; \$x }, true => 'a reference to true' => do { my $x = !!1; \$x }, true => 'a reference to zero' => do { my $x = 0; \$x }, true => 'a reference to one' => do { my $x = 1; \$x }, true => 'a reference to empty string' => do { my $x = ''; \$x }, true => 'a reference to random string' => do { my $x = 'abc123'; \$x }, true => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), true => 'empty arrayref' => [], true => 'arrayref with one zero' => [0], true => 'arrayref of integers' => [1..10], true => 'arrayref of numbers' => [1..10, 3.1416], true => 'blessed arrayref' => bless([], 'SomePkg'), true => 'empty hashref' => {}, true => 'hashref' => { foo => 1 }, true => 'blessed hashref' => bless({}, 'SomePkg'), true => 'coderef' => sub { 1 }, true => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), true => 'glob' => do { no warnings 'once'; *SOMETHING }, true => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, true => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), true => 'regexp' => qr/./, true => 'blessed regexp' => bless(qr/./, 'SomePkg'), true => 'filehandle' => do { open my $x, '<', $0 or die; $x }, true => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, true => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, true => 'ref to arrayref' => do { my $x = []; \$x }, true => 'ref to hashref' => do { my $x = {}; \$x }, true => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, true => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, true => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[bool] => sub { !!1 }; bless [] }, true => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[bool] => sub { !!1 }; bless [] }, false => 'object boolifying to false' => do { package Local::OL::BoolFalse; use overload q[bool] => sub { !!0 }; bless [] }, true => 'object boolifying to true' => do { package Local::OL::BoolTrue; use overload q[bool] => sub { !!1 }; bless [] }, true => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[bool] => sub { !!1 }; bless [] }, true => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[bool] => sub { !!1 }; bless [] }, true => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[bool] => sub { !!1 }; bless {array=>[]} }, true => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[bool] => sub { !!1 }; bless [{}] }, true => 'object overloading coderef' => do { package Local::OL::Code; use overload q[bool] => sub { !!1 }; bless [sub { 1 }] }, ); while (@tests2) { my ($expect, $label, $value) = splice(@tests2, 0 , 3); my $coerced; my $exception = exception { $coerced = Bool->assert_coerce($value) }; is($exception, undef, "Bool coerced $label successfully"); if ($expect eq 'true') { ok($coerced, "Bool coerced $label to true"); } elsif ($expect eq 'false') { ok(!$coerced, "Bool coerced $label to false"); } else { fail("expected '$expect'?!"); } } # # Bool and JSON::PP is worth showing. # if (eval { require JSON::PP }) { my $JSON_true = JSON::PP::true(); my $JSON_false = JSON::PP::false(); my @values; my $exception = exception { @values = map Bool->assert_coerce($_), $JSON_true, $JSON_false; }; should_fail($JSON_true, Bool, "JSON::PP::true does NOT pass Bool"); should_fail($JSON_false, Bool, "JSON::PP::false does NOT pass Bool"); is($exception, undef, "Bool coerced JSON::PP::true and JSON::PP::false"); ok($values[0], "Bool coerced JSON::PP::true to true"); ok(!$values[1], "Bool coerced JSON::PP::false to false"); } done_testing; ClassName.t000644001750001750 1452013601673061 16311 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( ClassName ); isa_ok(ClassName, 'Type::Tiny', 'ClassName'); is(ClassName->name, 'ClassName', 'ClassName has correct name'); is(ClassName->display_name, 'ClassName', 'ClassName has correct display_name'); is(ClassName->library, 'Types::Standard', 'ClassName knows it is in the Types::Standard library'); ok(Types::Standard->has_type('ClassName'), 'Types::Standard knows it has type ClassName'); ok(!ClassName->deprecated, 'ClassName is not deprecated'); ok(!ClassName->is_anon, 'ClassName is not anonymous'); ok(ClassName->can_be_inlined, 'ClassName can be inlined'); is(exception { ClassName->inline_check(q/$xyz/) }, undef, "Inlining ClassName doesn't throw an exception"); ok(!ClassName->has_coercion, "ClassName doesn't have a coercion"); ok(!ClassName->is_parameterizable, "ClassName isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, ClassName, ucfirst("$label should pass ClassName")); } elsif ($expect eq 'fail') { should_fail($value, ClassName, ucfirst("$label should fail ClassName")); } else { fail("expected '$expect'?!"); } } # # ClassName accepts Class::Tiny, Moo, Moose, and Mouse classes # if (eval q{ package Local::Class::ClassTiny; use Class::Tiny; 1 }) { should_pass('Local::Class::ClassTiny', ClassName); } if (eval q{ package Local::Class::Moo; use Moo; 1 }) { should_pass('Local::Class::Moo', ClassName); } if (eval q{ package Local::Class::Moose; use Moose; 1 }) { should_pass('Local::Class::Moose', ClassName); } if (eval q{ package Local::Class::Mouse; use Mouse; 1 }) { should_pass('Local::Class::Mouse', ClassName); } # # ClassName accepts Role::Tiny, Moo::Role, Moose::Role, and Mouse::Role roles. # # This is because there's no way of knowing that these roles cannot be # used as a class. Even if there's no method called `new`, there might # be a constructor with a different name. # if (eval q{ package Local::Role::RoleTiny; use Role::Tiny; 1 }) { should_pass('Local::Role::RoleTiny', ClassName); } if (eval q{ package Local::Role::MooRole; use Moo::Role; 1 }) { should_pass('Local::Role::MooRole', ClassName); } if (eval q{ package Local::Role::MooseRole; use Moose::Role; 1 }) { should_pass('Local::Role::MooseRole', ClassName); } if (eval q{ package Local::Role::MouseRole; use Mouse::Role; 1 }) { should_pass('Local::Role::MouseRole', ClassName); } done_testing; CodeLike.t000644001750001750 1210113601673061 16113 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::TypeTiny qw( CodeLike ); isa_ok(CodeLike, 'Type::Tiny', 'CodeLike'); is(CodeLike->name, 'CodeLike', 'CodeLike has correct name'); is(CodeLike->display_name, 'CodeLike', 'CodeLike has correct display_name'); is(CodeLike->library, 'Types::TypeTiny', 'CodeLike knows it is in the Types::TypeTiny library'); ok(Types::TypeTiny->has_type('CodeLike'), 'Types::TypeTiny knows it has type CodeLike'); ok(!CodeLike->deprecated, 'CodeLike is not deprecated'); ok(!CodeLike->is_anon, 'CodeLike is not anonymous'); ok(CodeLike->can_be_inlined, 'CodeLike can be inlined'); is(exception { CodeLike->inline_check(q/$xyz/) }, undef, "Inlining CodeLike doesn't throw an exception"); ok(!CodeLike->has_coercion, "CodeLike doesn't have a coercion"); ok(!CodeLike->is_parameterizable, "CodeLike isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), pass => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, pass => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, CodeLike, ucfirst("$label should pass CodeLike")); } elsif ($expect eq 'fail') { should_fail($value, CodeLike, ucfirst("$label should fail CodeLike")); } else { fail("expected '$expect'?!"); } } done_testing; CodeRef.t000644001750001750 1204313601673061 15750 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( CodeRef ); isa_ok(CodeRef, 'Type::Tiny', 'CodeRef'); is(CodeRef->name, 'CodeRef', 'CodeRef has correct name'); is(CodeRef->display_name, 'CodeRef', 'CodeRef has correct display_name'); is(CodeRef->library, 'Types::Standard', 'CodeRef knows it is in the Types::Standard library'); ok(Types::Standard->has_type('CodeRef'), 'Types::Standard knows it has type CodeRef'); ok(!CodeRef->deprecated, 'CodeRef is not deprecated'); ok(!CodeRef->is_anon, 'CodeRef is not anonymous'); ok(CodeRef->can_be_inlined, 'CodeRef can be inlined'); is(exception { CodeRef->inline_check(q/$xyz/) }, undef, "Inlining CodeRef doesn't throw an exception"); ok(!CodeRef->has_coercion, "CodeRef doesn't have a coercion"); ok(!CodeRef->is_parameterizable, "CodeRef isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), pass => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, CodeRef, ucfirst("$label should pass CodeRef")); } elsif ($expect eq 'fail') { should_fail($value, CodeRef, ucfirst("$label should fail CodeRef")); } else { fail("expected '$expect'?!"); } } done_testing; ConsumerOf.t000644001750001750 1652613601673061 16533 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( ConsumerOf ); isa_ok(ConsumerOf, 'Type::Tiny', 'ConsumerOf'); is(ConsumerOf->name, 'ConsumerOf', 'ConsumerOf has correct name'); is(ConsumerOf->display_name, 'ConsumerOf', 'ConsumerOf has correct display_name'); is(ConsumerOf->library, 'Types::Standard', 'ConsumerOf knows it is in the Types::Standard library'); ok(Types::Standard->has_type('ConsumerOf'), 'Types::Standard knows it has type ConsumerOf'); ok(!ConsumerOf->deprecated, 'ConsumerOf is not deprecated'); ok(!ConsumerOf->is_anon, 'ConsumerOf is not anonymous'); ok(ConsumerOf->can_be_inlined, 'ConsumerOf can be inlined'); is(exception { ConsumerOf->inline_check(q/$xyz/) }, undef, "Inlining ConsumerOf doesn't throw an exception"); ok(!ConsumerOf->has_coercion, "ConsumerOf doesn't have a coercion"); ok(ConsumerOf->is_parameterizable, "ConsumerOf is parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, pass => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], pass => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, pass => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, pass => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, pass => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), xxxx => 'regexp' => qr/./, pass => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, pass => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, pass => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, pass => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, pass => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, pass => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, pass => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, pass => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, pass => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, ConsumerOf, ucfirst("$label should pass ConsumerOf")); } elsif ($expect eq 'fail') { should_fail($value, ConsumerOf, ucfirst("$label should fail ConsumerOf")); } else { fail("expected '$expect'?!"); } } # # Parameterized ConsumerOf returns a Type::Tiny::Role. # should_pass(ConsumerOf['Foo'], ConsumerOf['Type::Tiny::Role']); should_pass(ConsumerOf['Foo'], ConsumerOf['Type::Tiny']); # # If Foo::Bar is a subclass of Foo, then Foo::Bar objects # should pass ConsumerOf['Foo'] but not the other way around. # (Note: UNIVERSAL::DOES calls $object->isa.) # @Foo::Bar::ISA = qw( Foo ); should_pass( bless([], 'Foo::Bar'), ConsumerOf['Foo::Bar'] ); should_pass( bless([], 'Foo::Bar'), ConsumerOf['Foo'] ); should_fail( bless([], 'Foo'), ConsumerOf['Foo::Bar'] ); should_pass( bless([], 'Foo'), ConsumerOf['Foo'] ); # # Parameterized ConsumerOf with two parameters returns a # Type::Tiny::Intersection of two Type::Tiny::Role objects. # my $fb = ConsumerOf['Foo','Bar']; should_pass($fb, ConsumerOf['Type::Tiny::Intersection']); should_pass($fb, ConsumerOf['Type::Tiny']); is(scalar(@$fb), 2); should_pass($fb->[0], ConsumerOf['Type::Tiny::Role']); should_pass($fb->[1], ConsumerOf['Type::Tiny::Role']); { package Foo; package Bar; } @MyConsumer::ISA = qw( Foo Bar ); should_pass( bless([], 'MyConsumer'), $fb ); # # Test using Class::Tiny and Role::Tiny # if (eval q{ package My::TinyRole; use Role::Tiny; package My::TinyClass; use Class::Tiny; use Role::Tiny::With; with 'My::TinyRole'; 1 }) { should_pass(My::TinyClass->new, ConsumerOf['My::TinyRole']); should_pass(My::TinyClass->new, ConsumerOf['My::TinyClass']); } # # Test using Moo # if (eval q{ package My::MooRole; use Moo::Role; package My::MooClass; use Moo; with 'My::MooRole'; 1 }) { should_pass(My::MooClass->new, ConsumerOf['My::MooRole']); should_pass(My::MooClass->new, ConsumerOf['My::MooClass']); } # # Test using Moose # if (eval q{ package My::MooseRole; use Moose::Role; package My::MooseClass; use Moose; with 'My::MooseRole'; 1 }) { should_pass(My::MooseClass->new, ConsumerOf['My::MooseRole']); should_pass(My::MooseClass->new, ConsumerOf['My::MooseClass']); } # # Test using Mouse # if (eval q{ package My::MouseRole; use Mouse::Role; package My::MouseClass; use Mouse; with 'My::MouseRole'; 1 }) { should_pass(My::MouseClass->new, ConsumerOf['My::MouseRole']); should_pass(My::MouseClass->new, ConsumerOf['My::MouseClass']); } done_testing; CycleTuple.t000644001750001750 1502113601673061 16511 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( CycleTuple ); isa_ok(CycleTuple, 'Type::Tiny', 'CycleTuple'); is(CycleTuple->name, 'CycleTuple', 'CycleTuple has correct name'); is(CycleTuple->display_name, 'CycleTuple', 'CycleTuple has correct display_name'); is(CycleTuple->library, 'Types::Standard', 'CycleTuple knows it is in the Types::Standard library'); ok(Types::Standard->has_type('CycleTuple'), 'Types::Standard knows it has type CycleTuple'); ok(!CycleTuple->deprecated, 'CycleTuple is not deprecated'); ok(!CycleTuple->is_anon, 'CycleTuple is not anonymous'); ok(CycleTuple->can_be_inlined, 'CycleTuple can be inlined'); is(exception { CycleTuple->inline_check(q/$xyz/) }, undef, "Inlining CycleTuple doesn't throw an exception"); ok(!CycleTuple->has_coercion, "CycleTuple doesn't have a coercion"); ok(CycleTuple->is_parameterizable, "CycleTuple is parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), pass => 'empty arrayref' => [], pass => 'arrayref with one zero' => [0], pass => 'arrayref of integers' => [1..10], pass => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, CycleTuple, ucfirst("$label should pass CycleTuple")); } elsif ($expect eq 'fail') { should_fail($value, CycleTuple, ucfirst("$label should fail CycleTuple")); } else { fail("expected '$expect'?!"); } } # # Basic example. # my $type1 = CycleTuple[ Types::Standard::Int, Types::Standard::HashRef, Types::Standard::RegexpRef, ]; should_pass([ 1,{},qr// ], $type1); should_pass([ 1,{},qr// => 2,{},qr// ], $type1); should_pass([ 1,{},qr// => 2,{},qr// => 3,{},qr// ], $type1); should_pass([ 1,{},qr// => 2,{},qr// => 3,{},qr// => 4,{},qr// ], $type1); should_fail([ 1,{},qr// => 2,{},qr// => 3,{},qr// => 4,{} ], $type1); # fails because missing slot should_fail([ 1,{},qr// => 2,{},qr// => 3,{},qr// => 4,{},[] ], $type1); # fails because bad value in slot # # Empty arrayref # use Types::Standard qw( ArrayRef Any ); # An empty arrayref is okay should_pass( [], $type1 ); # Here's one way to make sure the arrayref isn't empty should_fail( [], $type1->where('@$_>0') ); # Here's another way should_fail( [], ArrayRef[Any,1] & $type1 ); # # Optional is not allowed. # my $e = exception { CycleTuple[ Types::Standard::Optional[ Types::Standard::Int, ], ] }; like($e, qr/cannot be optional/, 'correct exception'); # # Deep coercions # my $type2 = CycleTuple[ Types::Standard::Int->plus_coercions( Types::Standard::Num, q{ int($_) }, ), Types::Standard::HashRef, ]; my $coerced = $type2->coerce( [ 1.1,{} => 2.1,{} => 3.1,{} => 4.1,{} ] ); is_deeply( $coerced, [ 1,{} => 2,{} => 3,{} => 4,{} ], 'coercion worked', ); done_testing; Defined.t000644001750001750 1216013601673061 15777 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Defined ); isa_ok(Defined, 'Type::Tiny', 'Defined'); is(Defined->name, 'Defined', 'Defined has correct name'); is(Defined->display_name, 'Defined', 'Defined has correct display_name'); is(Defined->library, 'Types::Standard', 'Defined knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Defined'), 'Types::Standard knows it has type Defined'); ok(!Defined->deprecated, 'Defined is not deprecated'); ok(!Defined->is_anon, 'Defined is not anonymous'); ok(Defined->can_be_inlined, 'Defined can be inlined'); is(exception { Defined->inline_check(q/$xyz/) }, undef, "Inlining Defined doesn't throw an exception"); ok(!Defined->has_coercion, "Defined doesn't have a coercion"); ok(!Defined->is_parameterizable, "Defined isn't parameterizable"); my @tests = ( fail => 'undef' => undef, pass => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, pass => 'empty string' => '', pass => 'whitespace' => ' ', pass => 'line break' => "\n", pass => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', pass => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', pass => 'a reference to undef' => do { my $x = undef; \$x }, pass => 'a reference to false' => do { my $x = !!0; \$x }, pass => 'a reference to true' => do { my $x = !!1; \$x }, pass => 'a reference to zero' => do { my $x = 0; \$x }, pass => 'a reference to one' => do { my $x = 1; \$x }, pass => 'a reference to empty string' => do { my $x = ''; \$x }, pass => 'a reference to random string' => do { my $x = 'abc123'; \$x }, pass => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), pass => 'empty arrayref' => [], pass => 'arrayref with one zero' => [0], pass => 'arrayref of integers' => [1..10], pass => 'arrayref of numbers' => [1..10, 3.1416], pass => 'blessed arrayref' => bless([], 'SomePkg'), pass => 'empty hashref' => {}, pass => 'hashref' => { foo => 1 }, pass => 'blessed hashref' => bless({}, 'SomePkg'), pass => 'coderef' => sub { 1 }, pass => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), pass => 'glob' => do { no warnings 'once'; *SOMETHING }, pass => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, pass => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), pass => 'regexp' => qr/./, pass => 'blessed regexp' => bless(qr/./, 'SomePkg'), pass => 'filehandle' => do { open my $x, '<', $0 or die; $x }, pass => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, pass => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, pass => 'ref to arrayref' => do { my $x = []; \$x }, pass => 'ref to hashref' => do { my $x = {}; \$x }, pass => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, pass => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, pass => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, pass => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, pass => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, pass => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, pass => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, pass => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, pass => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Defined, ucfirst("$label should pass Defined")); } elsif ($expect eq 'fail') { should_fail($value, Defined, ucfirst("$label should fail Defined")); } else { fail("expected '$expect'?!"); } } is(~Defined, Types::Standard::Undef, 'The complement of Defined is Undef'); done_testing; Dict.t000644001750001750 2631413601673061 15332 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Dict ); isa_ok(Dict, 'Type::Tiny', 'Dict'); is(Dict->name, 'Dict', 'Dict has correct name'); is(Dict->display_name, 'Dict', 'Dict has correct display_name'); is(Dict->library, 'Types::Standard', 'Dict knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Dict'), 'Types::Standard knows it has type Dict'); ok(!Dict->deprecated, 'Dict is not deprecated'); ok(!Dict->is_anon, 'Dict is not anonymous'); ok(Dict->can_be_inlined, 'Dict can be inlined'); is(exception { Dict->inline_check(q/$xyz/) }, undef, "Inlining Dict doesn't throw an exception"); ok(!Dict->has_coercion, "Dict doesn't have a coercion"); ok(Dict->is_parameterizable, "Dict is parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), pass => 'empty hashref' => {}, pass => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Dict, ucfirst("$label should pass Dict")); } elsif ($expect eq 'fail') { should_fail($value, Dict, ucfirst("$label should fail Dict")); } else { fail("expected '$expect'?!"); } } # # Basic parameterized example # my $type1 = Dict[ foo => Types::Standard::Int, bar => Types::Standard::RegexpRef, ]; should_pass( { foo => 42, bar => qr// }, $type1 ); should_fail( { foo => [], bar => qr// }, $type1 ); should_fail( { foo => 42, bar => 1234 }, $type1 ); should_fail( { foo => [], bar => 1234 }, $type1 ); should_fail( { foo => 42 }, $type1 ); should_fail( { bar => qr// }, $type1 ); should_fail( [ foo => 42, bar => qr// ], $type1 ); should_fail( { foo => 42, bar => qr//, baz => undef }, $type1 ); ok( $type1->my_hashref_allows_key('bar'), 'my_hashref_allows_key("bar")' ); ok( !$type1->my_hashref_allows_key('baz'), '!my_hashref_allows_key("baz")' ); ok( $type1->my_hashref_allows_value('bar', qr//), 'my_hashref_allows_value("bar", qr//)' ); ok( !$type1->my_hashref_allows_value('bar', 1234), '!my_hashref_allows_value("bar", 1234)' ); # # Optional parameterized example # use Types::Standard qw( Optional ); # this is mostly the same as $type1... my $type2 = Dict[ foo => Types::Standard::Int, bar => Optional[ Types::Standard::RegexpRef ], ]; should_pass( { foo => 42, bar => qr// }, $type2 ); should_fail( { foo => [], bar => qr// }, $type2 ); should_fail( { foo => 42, bar => 1234 }, $type2 ); should_fail( { foo => [], bar => 1234 }, $type2 ); should_pass( { foo => 42 }, $type2 ); # this fails with $type1 should_fail( { bar => qr// }, $type2 ); should_fail( [ foo => 42, bar => qr// ], $type2 ); should_fail( { foo => 42, bar => qr//, baz => undef }, $type2 ); ok( $type2->my_hashref_allows_key('bar'), 'my_hashref_allows_key("bar")' ); ok( !$type2->my_hashref_allows_key('baz'), '!my_hashref_allows_key("baz")' ); ok( $type2->my_hashref_allows_value('bar', qr//), 'my_hashref_allows_value("bar", qr//)' ); ok( !$type2->my_hashref_allows_value('bar', 1234), '!my_hashref_allows_value("bar", 1234)' ); # # Example with slurpy # use Types::Standard qw( slurpy Map ); my $type3 = Dict[ foo => Types::Standard::Int, bar => Types::Standard::RegexpRef, slurpy Map[ Types::Standard::Int, Types::Standard::ArrayRef ], ]; should_pass( { foo => 42, bar => qr// }, $type3 ); should_fail( { foo => [], bar => qr// }, $type3 ); should_fail( { foo => 42, bar => 1234 }, $type3 ); should_fail( { foo => [], bar => 1234 }, $type3 ); should_fail( { foo => 42 }, $type3 ); should_fail( { bar => qr// }, $type3 ); should_fail( [ foo => 42, bar => qr// ], $type3 ); should_fail( { foo => 42, bar => qr//, baz => undef }, $type3 ); should_pass( { foo => 42, bar => qr//, 123 => [] }, $type3 ); should_pass( { foo => 42, bar => qr//, 123 => [], 456 => [] }, $type3 ); should_fail( { foo => 42, bar => qr//, 123 => qr// }, $type3 ); should_fail( { foo => 42, bar => qr//, 123 => qr//, 456 => [] }, $type3 ); ok( $type3->my_hashref_allows_key('bar'), 'my_hashref_allows_key("bar")' ); ok( !$type3->my_hashref_allows_key('baz'), '!my_hashref_allows_key("baz")' ); ok( $type3->my_hashref_allows_value('bar', qr//), 'my_hashref_allows_value("bar", qr//)' ); ok( !$type3->my_hashref_allows_value('bar', 1234), '!my_hashref_allows_value("bar", 1234)' ); ok( $type3->my_hashref_allows_key('123'), 'my_hashref_allows_key("123")' ); ok( $type3->my_hashref_allows_value('123', []), 'my_hashref_allows_value("123", [])' ); ok( !$type3->my_hashref_allows_value('123', qr//), '!my_hashref_allows_value("123", qr//)' ); # # Example with slurpy and Optional # my $type4 = Dict[ foo => Types::Standard::Int, bar => Optional[ Types::Standard::RegexpRef ], slurpy Map[ Types::Standard::Int, Types::Standard::ArrayRef ], ]; should_pass( { foo => 42, bar => qr// }, $type4 ); should_fail( { foo => [], bar => qr// }, $type4 ); should_fail( { foo => 42, bar => 1234 }, $type4 ); should_fail( { foo => [], bar => 1234 }, $type4 ); should_pass( { foo => 42 }, $type4 ); # this fails with $type3 should_fail( { bar => qr// }, $type4 ); should_fail( [ foo => 42, bar => qr// ], $type4 ); should_fail( { foo => 42, bar => qr//, baz => undef }, $type4 ); should_pass( { foo => 42, bar => qr//, 123 => [] }, $type4 ); should_pass( { foo => 42, bar => qr//, 123 => [], 456 => [] }, $type4 ); should_fail( { foo => 42, bar => qr//, 123 => qr// }, $type4 ); should_fail( { foo => 42, bar => qr//, 123 => qr//, 456 => [] }, $type4 ); ok( $type4->my_hashref_allows_key('bar'), 'my_hashref_allows_key("bar")' ); ok( !$type4->my_hashref_allows_key('baz'), '!my_hashref_allows_key("baz")' ); ok( $type4->my_hashref_allows_value('bar', qr//), 'my_hashref_allows_value("bar", qr//)' ); ok( !$type4->my_hashref_allows_value('bar', 1234), '!my_hashref_allows_value("bar", 1234)' ); ok( $type4->my_hashref_allows_key('123'), 'my_hashref_allows_key("123")' ); ok( $type4->my_hashref_allows_value('123', []), 'my_hashref_allows_value("123", [])' ); ok( !$type4->my_hashref_allows_value('123', qr//), '!my_hashref_allows_value("123", qr//)' ); # # Simple deep coercion # my $Rounded = Types::Standard::Int->plus_coercions( Types::Standard::Num, q{ int($_) } ); my $type5 = Dict[foo => $Rounded]; is_deeply( $type5->coerce({ foo => 4.1 }), { foo => 4 }, 'deep coercion', ); is_deeply( $type5->coerce({ foo => 4.1, bar => 'xyz' }), { foo => 4.1, bar => 'xyz' }, 'cowardly refuses to drop keys to allow coercion to work', ); # # Deep coercion with Optional # my $type6 = Dict[ foo => $Rounded, bar => Optional[$Rounded], ]; is_deeply( $type6->coerce({ foo => 4.1 }), { foo => 4 }, 'deep coercion', ); is_deeply( $type6->coerce({ foo => 4.1, bar => 5.1 }), { foo => 4, bar => 5 }, 'can coerce optional slots', ); is_deeply( $type6->coerce({ foo => 4.1, bar => 'xyz' }), { foo => 4.1, bar => 'xyz' }, 'cowardly refuses to drop keys to allow coercion to work', ); # # Deep coercion with slurpy # my $type7 = Dict[ foo => $Rounded, bar => Optional[$Rounded], slurpy Types::Standard::HashRef[$Rounded] ]; is_deeply( $type7->coerce({ foo => 4.1 }), { foo => 4 }, 'deep coercion', ); is_deeply( $type7->coerce({ foo => 4.1, bar => 5.1 }), { foo => 4, bar => 5 }, 'can coerce optional slots', ); is_deeply( $type7->coerce({ foo => 4.1, quux => 6.1 }), { foo => 4, quux => 6 }, 'can coerce slurpy', ); is_deeply( $type7->coerce({ foo => 4.1, bar => 'xyz' }), { foo => 4.1, bar => 'xyz' }, 'cowardly refuses to drop keys to allow coercion to work', ); done_testing; Enum.t000644001750001750 1364113601673061 15352 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Enum ); isa_ok(Enum, 'Type::Tiny', 'Enum'); is(Enum->name, 'Enum', 'Enum has correct name'); is(Enum->display_name, 'Enum', 'Enum has correct display_name'); is(Enum->library, 'Types::Standard', 'Enum knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Enum'), 'Types::Standard knows it has type Enum'); ok(!Enum->deprecated, 'Enum is not deprecated'); ok(!Enum->is_anon, 'Enum is not anonymous'); ok(Enum->can_be_inlined, 'Enum can be inlined'); is(exception { Enum->inline_check(q/$xyz/) }, undef, "Inlining Enum doesn't throw an exception"); ok(!Enum->has_coercion, "Enum doesn't have a coercion"); ok(Enum->is_parameterizable, "Enum is parameterizable"); my @tests = ( fail => 'undef' => undef, pass => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, pass => 'empty string' => '', pass => 'whitespace' => ' ', pass => 'line break' => "\n", pass => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', pass => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Enum, ucfirst("$label should pass Enum")); } elsif ($expect eq 'fail') { should_fail($value, Enum, ucfirst("$label should fail Enum")); } else { fail("expected '$expect'?!"); } } my $enum1 = Enum[qw/ foo bar bar baz /]; should_pass('foo', $enum1); should_pass('bar', $enum1); should_pass('baz', $enum1); should_fail('bat', $enum1); is_deeply($enum1->values, [qw/ foo bar bar baz /]); is_deeply($enum1->unique_values, [qw/ bar baz foo /]); is_deeply([@$enum1], [qw/ foo bar bar baz /]); # # Enum allows you to pass objects overloading stringification when # creating the type, but rejects blessed objects (even overloaded) # when checking values. # { package Local::Stringy; use overload q[""] => sub { ${$_[0]} }; sub new { my ($class, $str) = @_; bless \$str, $class } } my $enum2 = Enum[ map Local::Stringy->new($_), qw/ foo bar bar baz / ]; should_pass('foo', $enum2); should_pass('bar', $enum2); should_pass('baz', $enum2); should_fail('bat', $enum2); should_fail(Local::Stringy->new('foo'), $enum2); is_deeply($enum2->values, [qw/ foo bar bar baz /]); is_deeply($enum2->unique_values, [qw/ bar baz foo /]); is_deeply([@$enum2], [qw/ foo bar bar baz /]); done_testing; FileHandle.t000644001750001750 1217513601673061 16442 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( FileHandle ); isa_ok(FileHandle, 'Type::Tiny', 'FileHandle'); is(FileHandle->name, 'FileHandle', 'FileHandle has correct name'); is(FileHandle->display_name, 'FileHandle', 'FileHandle has correct display_name'); is(FileHandle->library, 'Types::Standard', 'FileHandle knows it is in the Types::Standard library'); ok(Types::Standard->has_type('FileHandle'), 'Types::Standard knows it has type FileHandle'); ok(!FileHandle->deprecated, 'FileHandle is not deprecated'); ok(!FileHandle->is_anon, 'FileHandle is not anonymous'); ok(FileHandle->can_be_inlined, 'FileHandle can be inlined'); is(exception { FileHandle->inline_check(q/$xyz/) }, undef, "Inlining FileHandle doesn't throw an exception"); ok(!FileHandle->has_coercion, "FileHandle doesn't have a coercion"); ok(!FileHandle->is_parameterizable, "FileHandle isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), pass => 'filehandle' => do { open my $x, '<', $0 or die; $x }, pass => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, FileHandle, ucfirst("$label should pass FileHandle")); } elsif ($expect eq 'fail') { should_fail($value, FileHandle, ucfirst("$label should fail FileHandle")); } else { fail("expected '$expect'?!"); } } done_testing; GlobRef.t000644001750001750 1204313601673061 15761 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( GlobRef ); isa_ok(GlobRef, 'Type::Tiny', 'GlobRef'); is(GlobRef->name, 'GlobRef', 'GlobRef has correct name'); is(GlobRef->display_name, 'GlobRef', 'GlobRef has correct display_name'); is(GlobRef->library, 'Types::Standard', 'GlobRef knows it is in the Types::Standard library'); ok(Types::Standard->has_type('GlobRef'), 'Types::Standard knows it has type GlobRef'); ok(!GlobRef->deprecated, 'GlobRef is not deprecated'); ok(!GlobRef->is_anon, 'GlobRef is not anonymous'); ok(GlobRef->can_be_inlined, 'GlobRef can be inlined'); is(exception { GlobRef->inline_check(q/$xyz/) }, undef, "Inlining GlobRef doesn't throw an exception"); ok(!GlobRef->has_coercion, "GlobRef doesn't have a coercion"); ok(!GlobRef->is_parameterizable, "GlobRef isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, pass => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), pass => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, GlobRef, ucfirst("$label should pass GlobRef")); } elsif ($expect eq 'fail') { should_fail($value, GlobRef, ucfirst("$label should fail GlobRef")); } else { fail("expected '$expect'?!"); } } done_testing; HasMethods.t000644001750001750 1516213601673061 16505 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( HasMethods ); isa_ok(HasMethods, 'Type::Tiny', 'HasMethods'); is(HasMethods->name, 'HasMethods', 'HasMethods has correct name'); is(HasMethods->display_name, 'HasMethods', 'HasMethods has correct display_name'); is(HasMethods->library, 'Types::Standard', 'HasMethods knows it is in the Types::Standard library'); ok(Types::Standard->has_type('HasMethods'), 'Types::Standard knows it has type HasMethods'); ok(!HasMethods->deprecated, 'HasMethods is not deprecated'); ok(!HasMethods->is_anon, 'HasMethods is not anonymous'); ok(HasMethods->can_be_inlined, 'HasMethods can be inlined'); is(exception { HasMethods->inline_check(q/$xyz/) }, undef, "Inlining HasMethods doesn't throw an exception"); ok(!HasMethods->has_coercion, "HasMethods doesn't have a coercion"); ok(HasMethods->is_parameterizable, "HasMethods is parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, pass => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], pass => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, pass => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, pass => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, pass => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), xxxx => 'regexp' => qr/./, pass => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, pass => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, pass => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, pass => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, pass => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, pass => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, pass => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, pass => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, pass => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, HasMethods, ucfirst("$label should pass HasMethods")); } elsif ($expect eq 'fail') { should_fail($value, HasMethods, ucfirst("$label should fail HasMethods")); } else { fail("expected '$expect'?!"); } } use Scalar::Util qw( refaddr ); my $plain = HasMethods; my $paramd = HasMethods[]; is( refaddr($plain), refaddr($paramd), 'parameterizing with [] has no effect' ); my $p1 = HasMethods['foo']; my $p2 = HasMethods['foo']; is(refaddr($p1), refaddr($p2), 'parameterizing is cached'); # # We need a real object to test HasMethods on. # Luckily HasMethods IS an object! # should_pass( HasMethods, HasMethods['constraint'], "Parameterized with one method name", ); should_pass( HasMethods, HasMethods['constraint', 'name'], "Parameterized with multiple method names", ); should_fail( HasMethods, HasMethods['constraint', 'should_not_exist'], "... acts as intersection (requires the object to support ALL the methods)" ); { # A package where $thing->foo works but # $thing->can("foo") is false. package Local::Liar1; sub foo { 1 } sub can { return if $_[1] eq 'foo'; goto \&UNIVERSAL::can; } } should_fail( bless([], 'Local::Liar1'), HasMethods['foo'], "HasMethods should believe \$object->can() if it returns false." ); { # A package where $thing->foo breaks but # $thing->can("foo") is true. package Local::Liar2; sub can { return sub { 1 } if $_[1] eq 'foo'; goto \&UNIVERSAL::can; } } should_pass( bless([], 'Local::Liar2'), HasMethods['foo'], "HasMethods should believe \$object->can() if it returns true." ); # # HasMethods is for blessed objects only. # should_fail( 'Local::Liar2', HasMethods['foo'], "HasMethods does't work on class names, even if they can do a method." ); done_testing; HashLike.t000644001750001750 1210113601673061 16124 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::TypeTiny qw( HashLike ); isa_ok(HashLike, 'Type::Tiny', 'HashLike'); is(HashLike->name, 'HashLike', 'HashLike has correct name'); is(HashLike->display_name, 'HashLike', 'HashLike has correct display_name'); is(HashLike->library, 'Types::TypeTiny', 'HashLike knows it is in the Types::TypeTiny library'); ok(Types::TypeTiny->has_type('HashLike'), 'Types::TypeTiny knows it has type HashLike'); ok(!HashLike->deprecated, 'HashLike is not deprecated'); ok(!HashLike->is_anon, 'HashLike is not anonymous'); ok(HashLike->can_be_inlined, 'HashLike can be inlined'); is(exception { HashLike->inline_check(q/$xyz/) }, undef, "Inlining HashLike doesn't throw an exception"); ok(!HashLike->has_coercion, "HashLike doesn't have a coercion"); ok(!HashLike->is_parameterizable, "HashLike isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), pass => 'empty hashref' => {}, pass => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, pass => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, HashLike, ucfirst("$label should pass HashLike")); } elsif ($expect eq 'fail') { should_fail($value, HashLike, ucfirst("$label should fail HashLike")); } else { fail("expected '$expect'?!"); } } done_testing; HashRef.t000644001750001750 2230613601673061 15764 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( HashRef ); isa_ok(HashRef, 'Type::Tiny', 'HashRef'); is(HashRef->name, 'HashRef', 'HashRef has correct name'); is(HashRef->display_name, 'HashRef', 'HashRef has correct display_name'); is(HashRef->library, 'Types::Standard', 'HashRef knows it is in the Types::Standard library'); ok(Types::Standard->has_type('HashRef'), 'Types::Standard knows it has type HashRef'); ok(!HashRef->deprecated, 'HashRef is not deprecated'); ok(!HashRef->is_anon, 'HashRef is not anonymous'); ok(HashRef->can_be_inlined, 'HashRef can be inlined'); is(exception { HashRef->inline_check(q/$xyz/) }, undef, "Inlining HashRef doesn't throw an exception"); ok(!HashRef->has_coercion, "HashRef doesn't have a coercion"); ok(HashRef->is_parameterizable, "HashRef is parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), pass => 'empty hashref' => {}, pass => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, HashRef, ucfirst("$label should pass HashRef")); } elsif ($expect eq 'fail') { should_fail($value, HashRef, ucfirst("$label should fail HashRef")); } else { fail("expected '$expect'?!"); } } # # HashRef is parameterizable # my $HashOfInts = HashRef->of( Types::Standard::Int ); isa_ok($HashOfInts, 'Type::Tiny', '$HashOfInts'); is($HashOfInts->display_name, 'HashRef[Int]', '$HashOfInts has correct display_name'); ok($HashOfInts->is_anon, '$HashOfInts has no name'); ok($HashOfInts->can_be_inlined, '$HashOfInts can be inlined'); is(exception { $HashOfInts->inline_check(q/$xyz/) }, undef, "Inlining \$HashOfInts doesn't throw an exception"); ok(!$HashOfInts->has_coercion, "\$HashOfInts doesn't have a coercion"); ok(!$HashOfInts->is_parameterizable, "\$HashOfInts is not parameterizable"); ok_subtype(HashRef, $HashOfInts); should_fail( 1, $HashOfInts ); should_fail( [], $HashOfInts ); should_pass( { }, $HashOfInts ); should_fail( { foo => [] }, $HashOfInts ); should_fail( { foo => 1.1 }, $HashOfInts ); should_pass( { foo => 1 }, $HashOfInts ); should_pass( { foo => 0 }, $HashOfInts ); should_pass( { foo => -1 }, $HashOfInts ); should_fail( { foo => \1 }, $HashOfInts ); should_fail( { 123 => \1 }, $HashOfInts ); should_pass( { 123 => 1 }, $HashOfInts ); should_pass( { foo => 1, bar => 2 }, $HashOfInts ); should_fail( { foo => 1, bar => [] }, $HashOfInts ); # # HashRef has these cool extra methods... # ok( $HashOfInts->my_hashref_allows_key('foo'), "my_hashref_allows_key('foo')", ); ok( $HashOfInts->my_hashref_allows_value('foo', 1234), "my_hashref_allows_value('foo', 1234)", ); ok( ! $HashOfInts->my_hashref_allows_value('foo', qr//), "!my_hashref_allows_value('foo', qr//)", ); # # HashRef has deep coercions # my $Rounded = Types::Standard::Int->plus_coercions( Types::Standard::Num, q{ int($_) } ); my $HashOfRounded = HashRef->of( $Rounded ); isa_ok($HashOfRounded, 'Type::Tiny', '$HashOfRounded'); is($HashOfRounded->display_name, 'HashRef[Int]', '$HashOfRounded has correct display_name'); ok($HashOfRounded->is_anon, '$HashOfRounded has no name'); ok($HashOfRounded->can_be_inlined, '$HashOfRounded can be inlined'); is(exception { $HashOfRounded->inline_check(q/$xyz/) }, undef, "Inlining \$HashOfRounded doesn't throw an exception"); ok($HashOfRounded->has_coercion, "\$HashOfRounded has a coercion"); ok($HashOfRounded->coercion->has_coercion_for_type(HashRef), '$HashRefOfRounded can coerce from HashRef'); ok($HashOfRounded->coercion->has_coercion_for_type(HashRef->of(Types::Standard::Num)), '$HashRefOfRounded can coerce from HashRef[Num]'); ok(!$HashOfRounded->is_parameterizable, "\$HashOfRounded is not parameterizable"); ok_subtype(HashRef, $HashOfRounded); should_fail( 1, $HashOfRounded ); should_fail( [], $HashOfRounded ); should_pass( { }, $HashOfRounded ); should_fail( { foo => [] }, $HashOfRounded ); should_fail( { foo => 1.1 }, $HashOfRounded ); should_pass( { foo => 1 }, $HashOfRounded ); should_pass( { foo => 0 }, $HashOfRounded ); should_pass( { foo => -1 }, $HashOfRounded ); should_fail( { foo => \1 }, $HashOfRounded ); should_fail( { 123 => \1 }, $HashOfRounded ); should_pass( { 123 => 1 }, $HashOfRounded ); should_pass( { foo => 1, bar => 2 }, $HashOfRounded ); should_fail( { foo => 1, bar => [] }, $HashOfRounded ); use Scalar::Util qw(refaddr); do { my $orig = { foo => 42 }; my $coerced = $HashOfRounded->coerce($orig); is( refaddr($orig), refaddr($coerced), "just returned orig unchanged" ); }; do { my $orig = { foo => 42.1 }; my $coerced = $HashOfRounded->coerce($orig); isnt( refaddr($orig), refaddr($coerced), "coercion happened" ); is($coerced->{foo}, 42, "... and data looks good"); should_pass($coerced, $HashOfRounded, "... and now passes type constraint"); }; do { my $orig = { foo => [] }; my $coerced = $HashOfRounded->coerce($orig); is( refaddr($orig), refaddr($coerced), "coercion failed, so orig was returned" ); should_fail($coerced, $HashOfRounded); }; # # Parameterization fails with bad parameters # do { my $e = exception { HashRef['hello world'] }; like($e, qr/expected to be a type constraint/, 'can only be parameterized with another type'); }; # this should probably issue an exception, but doesn't currently... #do { # my $e = exception { HashRef[HashRef, HashRef] }; # isnt($e, undef); #}; done_testing; InstanceOf.t000644001750001750 1422013601673061 16471 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( InstanceOf ); isa_ok(InstanceOf, 'Type::Tiny', 'InstanceOf'); is(InstanceOf->name, 'InstanceOf', 'InstanceOf has correct name'); is(InstanceOf->display_name, 'InstanceOf', 'InstanceOf has correct display_name'); is(InstanceOf->library, 'Types::Standard', 'InstanceOf knows it is in the Types::Standard library'); ok(Types::Standard->has_type('InstanceOf'), 'Types::Standard knows it has type InstanceOf'); ok(!InstanceOf->deprecated, 'InstanceOf is not deprecated'); ok(!InstanceOf->is_anon, 'InstanceOf is not anonymous'); ok(InstanceOf->can_be_inlined, 'InstanceOf can be inlined'); is(exception { InstanceOf->inline_check(q/$xyz/) }, undef, "Inlining InstanceOf doesn't throw an exception"); ok(!InstanceOf->has_coercion, "InstanceOf doesn't have a coercion"); ok(InstanceOf->is_parameterizable, "InstanceOf is parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, pass => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], pass => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, pass => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, pass => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, pass => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), xxxx => 'regexp' => qr/./, pass => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, pass => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, pass => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, pass => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, pass => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, pass => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, pass => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, pass => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, pass => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, InstanceOf, ucfirst("$label should pass InstanceOf")); } elsif ($expect eq 'fail') { should_fail($value, InstanceOf, ucfirst("$label should fail InstanceOf")); } else { fail("expected '$expect'?!"); } } # # Parameterized InstanceOf returns a Type::Tiny::Class. # should_pass(InstanceOf['Foo'], InstanceOf['Type::Tiny::Class']); should_pass(InstanceOf['Foo'], InstanceOf['Type::Tiny']); # # If Foo::Bar is a subclass of Foo, then Foo::Bar objects # should pass InstanceOf['Foo'] but not the other way around. # @Foo::Bar::ISA = qw( Foo ); should_pass( bless([], 'Foo::Bar'), InstanceOf['Foo::Bar'] ); should_pass( bless([], 'Foo::Bar'), InstanceOf['Foo'] ); should_fail( bless([], 'Foo'), InstanceOf['Foo::Bar'] ); should_pass( bless([], 'Foo'), InstanceOf['Foo'] ); # # Parameterized InstanceOf with two parameters returns # a Type::Tiny::Union of two Type::Tiny::Class objects. # my $fb = InstanceOf['Foo','Bar']; should_pass($fb, InstanceOf['Type::Tiny::Union']); should_pass($fb, InstanceOf['Type::Tiny']); is(scalar(@$fb), 2); should_pass($fb->[0], InstanceOf['Type::Tiny::Class']); should_pass($fb->[1], InstanceOf['Type::Tiny::Class']); should_pass( bless([], 'Foo'), $fb ); should_pass( bless([], 'Bar'), $fb ); done_testing; Int.t000644001750001750 1165313601673061 15201 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Int ); isa_ok(Int, 'Type::Tiny', 'Int'); is(Int->name, 'Int', 'Int has correct name'); is(Int->display_name, 'Int', 'Int has correct display_name'); is(Int->library, 'Types::Standard', 'Int knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Int'), 'Types::Standard knows it has type Int'); ok(!Int->deprecated, 'Int is not deprecated'); ok(!Int->is_anon, 'Int is not anonymous'); ok(Int->can_be_inlined, 'Int can be inlined'); is(exception { Int->inline_check(q/$xyz/) }, undef, "Inlining Int doesn't throw an exception"); ok(!Int->has_coercion, "Int doesn't have a coercion"); ok(!Int->is_parameterizable, "Int isn't parameterizable"); my @tests = ( fail => 'undef' => undef, xxxx => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Int, ucfirst("$label should pass Int")); } elsif ($expect eq 'fail') { should_fail($value, Int, ucfirst("$label should fail Int")); } else { fail("expected '$expect'?!"); } } done_testing; IntRange.t000644001750001750 1503313601673061 16152 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::Numeric qw( IntRange ); isa_ok(IntRange, 'Type::Tiny', 'IntRange'); is(IntRange->name, 'IntRange', 'IntRange has correct name'); is(IntRange->display_name, 'IntRange', 'IntRange has correct display_name'); is(IntRange->library, 'Types::Common::Numeric', 'IntRange knows it is in the Types::Common::Numeric library'); ok(Types::Common::Numeric->has_type('IntRange'), 'Types::Common::Numeric knows it has type IntRange'); ok(!IntRange->deprecated, 'IntRange is not deprecated'); ok(!IntRange->is_anon, 'IntRange is not anonymous'); ok(IntRange->can_be_inlined, 'IntRange can be inlined'); is(exception { IntRange->inline_check(q/$xyz/) }, undef, "Inlining IntRange doesn't throw an exception"); ok(!IntRange->has_coercion, "IntRange doesn't have a coercion"); ok(IntRange->is_parameterizable, "IntRange is parameterizable"); my @tests = ( fail => 'undef' => undef, xxxx => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, IntRange, ucfirst("$label should pass IntRange")); } elsif ($expect eq 'fail') { should_fail($value, IntRange, ucfirst("$label should fail IntRange")); } else { fail("expected '$expect'?!"); } } # # If there's one parameter, it is an inclusive minimum. # my $IntRange_2 = IntRange[2]; should_fail(-2, $IntRange_2); should_fail(-1, $IntRange_2); should_fail( 0, $IntRange_2); should_fail( 1, $IntRange_2); should_pass( 2, $IntRange_2); should_pass( 3, $IntRange_2); should_pass( 4, $IntRange_2); should_pass( 5, $IntRange_2); should_pass( 6, $IntRange_2); should_fail(3.1416, $IntRange_2); should_fail([], $IntRange_2); # # If there's two parameters, they are inclusive minimum and maximum. # my $IntRange_2_4 = IntRange[2, 4]; should_fail(-2, $IntRange_2_4); should_fail(-1, $IntRange_2_4); should_fail( 0, $IntRange_2_4); should_fail( 1, $IntRange_2_4); should_pass( 2, $IntRange_2_4); should_pass( 3, $IntRange_2_4); should_pass( 4, $IntRange_2_4); should_fail( 5, $IntRange_2_4); should_fail( 6, $IntRange_2_4); should_fail(3.1416, $IntRange_2_4); should_fail([], $IntRange_2_4); # # Can set an exclusive minimum and maximum. # my $IntRange_2_4_ex = IntRange[2, 4, 1, 1]; should_fail(-2, $IntRange_2_4_ex); should_fail(-1, $IntRange_2_4_ex); should_fail( 0, $IntRange_2_4_ex); should_fail( 1, $IntRange_2_4_ex); should_fail( 2, $IntRange_2_4_ex); should_pass( 3, $IntRange_2_4_ex); should_fail( 4, $IntRange_2_4_ex); should_fail( 5, $IntRange_2_4_ex); should_fail( 6, $IntRange_2_4_ex); should_fail(3.1416, $IntRange_2_4_ex); should_fail([], $IntRange_2_4_ex); my $e = exception { IntRange[1.1] }; like($e, qr/min must be/, 'bad parameter'); done_testing; Item.t000644001750001750 1171113601673061 15340 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Item ); isa_ok(Item, 'Type::Tiny', 'Item'); is(Item->name, 'Item', 'Item has correct name'); is(Item->display_name, 'Item', 'Item has correct display_name'); is(Item->library, 'Types::Standard', 'Item knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Item'), 'Types::Standard knows it has type Item'); ok(!Item->deprecated, 'Item is not deprecated'); ok(!Item->is_anon, 'Item is not anonymous'); ok(Item->can_be_inlined, 'Item can be inlined'); is(exception { Item->inline_check(q/$xyz/) }, undef, "Inlining Item doesn't throw an exception"); ok(!Item->has_coercion, "Item doesn't have a coercion"); ok(!Item->is_parameterizable, "Item isn't parameterizable"); my @tests = ( pass => 'undef' => undef, pass => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, pass => 'empty string' => '', pass => 'whitespace' => ' ', pass => 'line break' => "\n", pass => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', pass => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', pass => 'a reference to undef' => do { my $x = undef; \$x }, pass => 'a reference to false' => do { my $x = !!0; \$x }, pass => 'a reference to true' => do { my $x = !!1; \$x }, pass => 'a reference to zero' => do { my $x = 0; \$x }, pass => 'a reference to one' => do { my $x = 1; \$x }, pass => 'a reference to empty string' => do { my $x = ''; \$x }, pass => 'a reference to random string' => do { my $x = 'abc123'; \$x }, pass => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), pass => 'empty arrayref' => [], pass => 'arrayref with one zero' => [0], pass => 'arrayref of integers' => [1..10], pass => 'arrayref of numbers' => [1..10, 3.1416], pass => 'blessed arrayref' => bless([], 'SomePkg'), pass => 'empty hashref' => {}, pass => 'hashref' => { foo => 1 }, pass => 'blessed hashref' => bless({}, 'SomePkg'), pass => 'coderef' => sub { 1 }, pass => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), pass => 'glob' => do { no warnings 'once'; *SOMETHING }, pass => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, pass => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), pass => 'regexp' => qr/./, pass => 'blessed regexp' => bless(qr/./, 'SomePkg'), pass => 'filehandle' => do { open my $x, '<', $0 or die; $x }, pass => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, pass => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, pass => 'ref to arrayref' => do { my $x = []; \$x }, pass => 'ref to hashref' => do { my $x = {}; \$x }, pass => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, pass => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, pass => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, pass => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, pass => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, pass => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, pass => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, pass => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, pass => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Item, ucfirst("$label should pass Item")); } elsif ($expect eq 'fail') { should_fail($value, Item, ucfirst("$label should fail Item")); } else { fail("expected '$expect'?!"); } } done_testing; LaxNum.t000644001750001750 1200513601673061 15643 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( LaxNum ); isa_ok(LaxNum, 'Type::Tiny', 'LaxNum'); is(LaxNum->name, 'LaxNum', 'LaxNum has correct name'); is(LaxNum->display_name, 'LaxNum', 'LaxNum has correct display_name'); is(LaxNum->library, 'Types::Standard', 'LaxNum knows it is in the Types::Standard library'); ok(Types::Standard->has_type('LaxNum'), 'Types::Standard knows it has type LaxNum'); ok(!LaxNum->deprecated, 'LaxNum is not deprecated'); ok(!LaxNum->is_anon, 'LaxNum is not anonymous'); ok(LaxNum->can_be_inlined, 'LaxNum can be inlined'); is(exception { LaxNum->inline_check(q/$xyz/) }, undef, "Inlining LaxNum doesn't throw an exception"); ok(!LaxNum->has_coercion, "LaxNum doesn't have a coercion"); ok(!LaxNum->is_parameterizable, "LaxNum isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, LaxNum, ucfirst("$label should pass LaxNum")); } elsif ($expect eq 'fail') { should_fail($value, LaxNum, ucfirst("$label should fail LaxNum")); } else { fail("expected '$expect'?!"); } } done_testing; LowerCaseSimpleStr.t000644001750001750 1524213601673061 20174 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::String qw( LowerCaseSimpleStr ); isa_ok(LowerCaseSimpleStr, 'Type::Tiny', 'LowerCaseSimpleStr'); is(LowerCaseSimpleStr->name, 'LowerCaseSimpleStr', 'LowerCaseSimpleStr has correct name'); is(LowerCaseSimpleStr->display_name, 'LowerCaseSimpleStr', 'LowerCaseSimpleStr has correct display_name'); is(LowerCaseSimpleStr->library, 'Types::Common::String', 'LowerCaseSimpleStr knows it is in the Types::Common::String library'); ok(Types::Common::String->has_type('LowerCaseSimpleStr'), 'Types::Common::String knows it has type LowerCaseSimpleStr'); ok(!LowerCaseSimpleStr->deprecated, 'LowerCaseSimpleStr is not deprecated'); ok(!LowerCaseSimpleStr->is_anon, 'LowerCaseSimpleStr is not anonymous'); ok(LowerCaseSimpleStr->can_be_inlined, 'LowerCaseSimpleStr can be inlined'); is(exception { LowerCaseSimpleStr->inline_check(q/$xyz/) }, undef, "Inlining LowerCaseSimpleStr doesn't throw an exception"); ok(LowerCaseSimpleStr->has_coercion, "LowerCaseSimpleStr has a coercion"); ok(!LowerCaseSimpleStr->is_parameterizable, "LowerCaseSimpleStr isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, fail => 'empty string' => '', pass => 'whitespace' => ' ', fail => 'line break' => "\n", pass => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, LowerCaseSimpleStr, ucfirst("$label should pass LowerCaseSimpleStr")); } elsif ($expect eq 'fail') { should_fail($value, LowerCaseSimpleStr, ucfirst("$label should fail LowerCaseSimpleStr")); } else { fail("expected '$expect'?!"); } } # Cyrillic Small Letter Zhe should_pass("\x{0436}", LowerCaseSimpleStr); # Cyrillic Capital Letter Zhe should_fail("\x{0416}", LowerCaseSimpleStr); # # SimpleStr is limited to 255 characters # should_pass("a" x 255, LowerCaseSimpleStr); should_fail("a" x 256, LowerCaseSimpleStr); # # Length counts are characters, not bytes, # so test with a multibyte character. # should_pass("\x{0436}" x 255, LowerCaseSimpleStr); should_fail("\x{0436}" x 256, LowerCaseSimpleStr); # # These examples are probably obvious. # should_fail('ABCDEF', LowerCaseSimpleStr); should_fail('ABC123', LowerCaseSimpleStr); should_pass('abc123', LowerCaseSimpleStr); should_pass('abcdef', LowerCaseSimpleStr); # # A string with only non-letter characters passes. # should_pass('123456', LowerCaseSimpleStr); should_pass(' ', LowerCaseSimpleStr); # # But the empty string fails. # (Which is weird, but consistent with MooseX::Types::Common::String.) # should_fail('', LowerCaseSimpleStr); # # Can coerce from uppercase strings. # is(LowerCaseSimpleStr->coerce('ABC123'), 'abc123', 'coercion success'); # # Won't even attempt to coerce non-strings. # use Scalar::Util qw( refaddr ); my $arr = []; my $coerced = LowerCaseSimpleStr->coerce($arr); is(refaddr($coerced), refaddr($arr), 'does not coerce non-strings'); done_testing; LowerCaseStr.t000644001750001750 1415013601673061 17017 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::String qw( LowerCaseStr ); isa_ok(LowerCaseStr, 'Type::Tiny', 'LowerCaseStr'); is(LowerCaseStr->name, 'LowerCaseStr', 'LowerCaseStr has correct name'); is(LowerCaseStr->display_name, 'LowerCaseStr', 'LowerCaseStr has correct display_name'); is(LowerCaseStr->library, 'Types::Common::String', 'LowerCaseStr knows it is in the Types::Common::String library'); ok(Types::Common::String->has_type('LowerCaseStr'), 'Types::Common::String knows it has type LowerCaseStr'); ok(!LowerCaseStr->deprecated, 'LowerCaseStr is not deprecated'); ok(!LowerCaseStr->is_anon, 'LowerCaseStr is not anonymous'); ok(LowerCaseStr->can_be_inlined, 'LowerCaseStr can be inlined'); is(exception { LowerCaseStr->inline_check(q/$xyz/) }, undef, "Inlining LowerCaseStr doesn't throw an exception"); ok(LowerCaseStr->has_coercion, "LowerCaseStr has a coercion"); ok(!LowerCaseStr->is_parameterizable, "LowerCaseStr isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, fail => 'empty string' => '', pass => 'whitespace' => ' ', pass => 'line break' => "\n", pass => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, LowerCaseStr, ucfirst("$label should pass LowerCaseStr")); } elsif ($expect eq 'fail') { should_fail($value, LowerCaseStr, ucfirst("$label should fail LowerCaseStr")); } else { fail("expected '$expect'?!"); } } # Cyrillic Small Letter Zhe should_pass("\x{0436}", LowerCaseStr); # Cyrillic Capital Letter Zhe should_fail("\x{0416}", LowerCaseStr); # # These examples are probably obvious. # should_fail('ABCDEF', LowerCaseStr); should_fail('ABC123', LowerCaseStr); should_pass('abc123', LowerCaseStr); should_pass('abcdef', LowerCaseStr); # # A string with only non-letter characters passes. # should_pass('123456', LowerCaseStr); should_pass(' ', LowerCaseStr); # # But the empty string fails. # (Which is weird, but consistent with MooseX::Types::Common::String.) # should_fail('', LowerCaseStr); # # Can coerce from uppercase strings. # is(LowerCaseStr->coerce('ABC123'), 'abc123', 'coercion success'); # # Won't even attempt to coerce non-strings. # use Scalar::Util qw( refaddr ); my $arr = []; my $coerced = LowerCaseStr->coerce($arr); is(refaddr($coerced), refaddr($arr), 'does not coerce non-strings'); done_testing; Map.t000644001750001750 2171413601673061 15163 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Map ); isa_ok(Map, 'Type::Tiny', 'Map'); is(Map->name, 'Map', 'Map has correct name'); is(Map->display_name, 'Map', 'Map has correct display_name'); is(Map->library, 'Types::Standard', 'Map knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Map'), 'Types::Standard knows it has type Map'); ok(!Map->deprecated, 'Map is not deprecated'); ok(!Map->is_anon, 'Map is not anonymous'); ok(Map->can_be_inlined, 'Map can be inlined'); is(exception { Map->inline_check(q/$xyz/) }, undef, "Inlining Map doesn't throw an exception"); ok(!Map->has_coercion, "Map doesn't have a coercion"); ok(Map->is_parameterizable, "Map is parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), pass => 'empty hashref' => {}, pass => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Map, ucfirst("$label should pass Map")); } elsif ($expect eq 'fail') { should_fail($value, Map, ucfirst("$label should fail Map")); } else { fail("expected '$expect'?!"); } } # # Map to constrain keys of hash # my $MapWithIntKeys = Map->of( Types::Standard::Int, Types::Standard::Any ); isa_ok($MapWithIntKeys, 'Type::Tiny', '$MapWithIntKeys'); is($MapWithIntKeys->display_name, 'Map[Int,Any]', '$MapWithIntKeys has correct display_name'); ok($MapWithIntKeys->is_anon, '$MapWithIntKeys has no name'); ok($MapWithIntKeys->can_be_inlined, '$MapWithIntKeys can be inlined'); is(exception { $MapWithIntKeys->inline_check(q/$xyz/) }, undef, "Inlining \$MapWithIntKeys doesn't throw an exception"); ok(!$MapWithIntKeys->has_coercion, "\$MapWithIntKeys doesn't have a coercion"); ok(!$MapWithIntKeys->is_parameterizable, "\$MapWithIntKeys is not parameterizable"); ok_subtype(Types::Standard::HashRef, $MapWithIntKeys); should_fail( 1, $MapWithIntKeys ); should_fail( [], $MapWithIntKeys ); should_pass( { }, $MapWithIntKeys ); should_fail( { 1.1 => [] }, $MapWithIntKeys ); should_pass( { 1 => 1 }, $MapWithIntKeys ); should_pass( { 1 => 0 }, $MapWithIntKeys ); should_pass( { 1 => -1 }, $MapWithIntKeys ); should_pass( { 1 => \1 }, $MapWithIntKeys ); should_pass( { -1 => -1 }, $MapWithIntKeys ); should_fail( { foo => 1 }, $MapWithIntKeys ); # # Map has these cool extra methods... # ok( $MapWithIntKeys->my_hashref_allows_key('1234'), "my_hashref_allows_key('1234')", ); ok( !$MapWithIntKeys->my_hashref_allows_key('abc'), "!my_hashref_allows_key('abc')", ); # # Map to constrain values of hash. # Basically like HashRef[Int] # my $HashOfInts = Map->of( Types::Standard::Any, Types::Standard::Int ); isa_ok($HashOfInts, 'Type::Tiny', '$HashOfInts'); is($HashOfInts->display_name, 'Map[Any,Int]', '$HashOfInts has correct display_name'); ok($HashOfInts->is_anon, '$HashOfInts has no name'); ok($HashOfInts->can_be_inlined, '$HashOfInts can be inlined'); is(exception { $HashOfInts->inline_check(q/$xyz/) }, undef, "Inlining \$HashOfInts doesn't throw an exception"); ok(!$HashOfInts->has_coercion, "\$HashOfInts doesn't have a coercion"); ok(!$HashOfInts->is_parameterizable, "\$HashOfInts is not parameterizable"); ok_subtype(Types::Standard::HashRef, $HashOfInts); should_fail( 1, $HashOfInts ); should_fail( [], $HashOfInts ); should_pass( { }, $HashOfInts ); should_fail( { foo => [] }, $HashOfInts ); should_fail( { foo => 1.1 }, $HashOfInts ); should_pass( { foo => 1 }, $HashOfInts ); should_pass( { foo => 0 }, $HashOfInts ); should_pass( { foo => -1 }, $HashOfInts ); should_fail( { foo => \1 }, $HashOfInts ); should_fail( { 123 => \1 }, $HashOfInts ); should_pass( { 123 => 1 }, $HashOfInts ); should_pass( { foo => 1, bar => 2 }, $HashOfInts ); should_fail( { foo => 1, bar => [] }, $HashOfInts ); # # More Map extra methods... # ok( $HashOfInts->my_hashref_allows_key('foo'), "my_hashref_allows_key('foo')", ); ok( $HashOfInts->my_hashref_allows_value('foo', 1234), "my_hashref_allows_value('foo', 1234)", ); ok( ! $HashOfInts->my_hashref_allows_value('foo', qr//), "!my_hashref_allows_value('foo', qr//)", ); # # Map has deep coercions # my $Rounded = Types::Standard::Int->plus_coercions( Types::Standard::Num, q{ int($_) } ); my $HashOfRounded = Map->of( $Rounded, $Rounded ); use Scalar::Util qw(refaddr); do { my $orig = { 3 => 4 }; my $coerced = $HashOfRounded->coerce($orig); is( refaddr($orig), refaddr($coerced), "just returned orig unchanged" ); }; do { my $orig = { 3.1 => 4.2 }; my $coerced = $HashOfRounded->coerce($orig); # {3=>4} isnt( refaddr($orig), refaddr($coerced), "coercion happened" ); is($coerced->{3}, 4, "... and data looks good"); should_pass($coerced, $HashOfRounded, "... and now passes type constraint"); }; do { my $orig = { foo => [] }; my $coerced = $HashOfRounded->coerce($orig); is( refaddr($orig), refaddr($coerced), "coercion failed, so orig was returned" ); should_fail($coerced, $HashOfRounded); }; # # Parameterization fails with bad parameters # do { my $e = exception { Map[qw(hello world)] }; like($e, qr/expected to be a type constraint/, 'bad parameters'); }; done_testing; Maybe.t000644001750001750 1224313601673061 15500 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Maybe ); isa_ok(Maybe, 'Type::Tiny', 'Maybe'); is(Maybe->name, 'Maybe', 'Maybe has correct name'); is(Maybe->display_name, 'Maybe', 'Maybe has correct display_name'); is(Maybe->library, 'Types::Standard', 'Maybe knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Maybe'), 'Types::Standard knows it has type Maybe'); ok(!Maybe->deprecated, 'Maybe is not deprecated'); ok(!Maybe->is_anon, 'Maybe is not anonymous'); ok(Maybe->can_be_inlined, 'Maybe can be inlined'); is(exception { Maybe->inline_check(q/$xyz/) }, undef, "Inlining Maybe doesn't throw an exception"); ok(!Maybe->has_coercion, "Maybe doesn't have a coercion"); ok(Maybe->is_parameterizable, "Maybe is parameterizable"); my @tests = ( pass => 'undef' => undef, pass => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, pass => 'empty string' => '', pass => 'whitespace' => ' ', pass => 'line break' => "\n", pass => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', pass => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', pass => 'a reference to undef' => do { my $x = undef; \$x }, pass => 'a reference to false' => do { my $x = !!0; \$x }, pass => 'a reference to true' => do { my $x = !!1; \$x }, pass => 'a reference to zero' => do { my $x = 0; \$x }, pass => 'a reference to one' => do { my $x = 1; \$x }, pass => 'a reference to empty string' => do { my $x = ''; \$x }, pass => 'a reference to random string' => do { my $x = 'abc123'; \$x }, pass => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), pass => 'empty arrayref' => [], pass => 'arrayref with one zero' => [0], pass => 'arrayref of integers' => [1..10], pass => 'arrayref of numbers' => [1..10, 3.1416], pass => 'blessed arrayref' => bless([], 'SomePkg'), pass => 'empty hashref' => {}, pass => 'hashref' => { foo => 1 }, pass => 'blessed hashref' => bless({}, 'SomePkg'), pass => 'coderef' => sub { 1 }, pass => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), pass => 'glob' => do { no warnings 'once'; *SOMETHING }, pass => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, pass => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), pass => 'regexp' => qr/./, pass => 'blessed regexp' => bless(qr/./, 'SomePkg'), pass => 'filehandle' => do { open my $x, '<', $0 or die; $x }, pass => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, pass => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, pass => 'ref to arrayref' => do { my $x = []; \$x }, pass => 'ref to hashref' => do { my $x = {}; \$x }, pass => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, pass => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, pass => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, pass => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, pass => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, pass => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, pass => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, pass => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, pass => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Maybe, ucfirst("$label should pass Maybe")); } elsif ($expect eq 'fail') { should_fail($value, Maybe, ucfirst("$label should fail Maybe")); } else { fail("expected '$expect'?!"); } } # # Maybe[X] is an undef-tolerant version of X. # my $type = Maybe[ Types::Standard::Int ]; should_pass(0, $type); should_pass(1, $type); should_fail(1.1, $type); should_pass(undef, $type); done_testing; NegativeInt.t000644001750001750 1230513601673061 16657 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::Numeric qw( NegativeInt ); isa_ok(NegativeInt, 'Type::Tiny', 'NegativeInt'); is(NegativeInt->name, 'NegativeInt', 'NegativeInt has correct name'); is(NegativeInt->display_name, 'NegativeInt', 'NegativeInt has correct display_name'); is(NegativeInt->library, 'Types::Common::Numeric', 'NegativeInt knows it is in the Types::Common::Numeric library'); ok(Types::Common::Numeric->has_type('NegativeInt'), 'Types::Common::Numeric knows it has type NegativeInt'); ok(!NegativeInt->deprecated, 'NegativeInt is not deprecated'); ok(!NegativeInt->is_anon, 'NegativeInt is not anonymous'); ok(NegativeInt->can_be_inlined, 'NegativeInt can be inlined'); is(exception { NegativeInt->inline_check(q/$xyz/) }, undef, "Inlining NegativeInt doesn't throw an exception"); ok(!NegativeInt->has_coercion, "NegativeInt doesn't have a coercion"); ok(!NegativeInt->is_parameterizable, "NegativeInt isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, pass => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, NegativeInt, ucfirst("$label should pass NegativeInt")); } elsif ($expect eq 'fail') { should_fail($value, NegativeInt, ucfirst("$label should fail NegativeInt")); } else { fail("expected '$expect'?!"); } } done_testing; NegativeNum.t000644001750001750 1230513601673061 16664 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::Numeric qw( NegativeNum ); isa_ok(NegativeNum, 'Type::Tiny', 'NegativeNum'); is(NegativeNum->name, 'NegativeNum', 'NegativeNum has correct name'); is(NegativeNum->display_name, 'NegativeNum', 'NegativeNum has correct display_name'); is(NegativeNum->library, 'Types::Common::Numeric', 'NegativeNum knows it is in the Types::Common::Numeric library'); ok(Types::Common::Numeric->has_type('NegativeNum'), 'Types::Common::Numeric knows it has type NegativeNum'); ok(!NegativeNum->deprecated, 'NegativeNum is not deprecated'); ok(!NegativeNum->is_anon, 'NegativeNum is not anonymous'); ok(NegativeNum->can_be_inlined, 'NegativeNum can be inlined'); is(exception { NegativeNum->inline_check(q/$xyz/) }, undef, "Inlining NegativeNum doesn't throw an exception"); ok(!NegativeNum->has_coercion, "NegativeNum doesn't have a coercion"); ok(!NegativeNum->is_parameterizable, "NegativeNum isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, pass => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, NegativeNum, ucfirst("$label should pass NegativeNum")); } elsif ($expect eq 'fail') { should_fail($value, NegativeNum, ucfirst("$label should fail NegativeNum")); } else { fail("expected '$expect'?!"); } } done_testing; NegativeOrZeroInt.t000644001750001750 1257113601673061 20025 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::Numeric qw( NegativeOrZeroInt ); isa_ok(NegativeOrZeroInt, 'Type::Tiny', 'NegativeOrZeroInt'); is(NegativeOrZeroInt->name, 'NegativeOrZeroInt', 'NegativeOrZeroInt has correct name'); is(NegativeOrZeroInt->display_name, 'NegativeOrZeroInt', 'NegativeOrZeroInt has correct display_name'); is(NegativeOrZeroInt->library, 'Types::Common::Numeric', 'NegativeOrZeroInt knows it is in the Types::Common::Numeric library'); ok(Types::Common::Numeric->has_type('NegativeOrZeroInt'), 'Types::Common::Numeric knows it has type NegativeOrZeroInt'); ok(!NegativeOrZeroInt->deprecated, 'NegativeOrZeroInt is not deprecated'); ok(!NegativeOrZeroInt->is_anon, 'NegativeOrZeroInt is not anonymous'); ok(NegativeOrZeroInt->can_be_inlined, 'NegativeOrZeroInt can be inlined'); is(exception { NegativeOrZeroInt->inline_check(q/$xyz/) }, undef, "Inlining NegativeOrZeroInt doesn't throw an exception"); ok(!NegativeOrZeroInt->has_coercion, "NegativeOrZeroInt doesn't have a coercion"); ok(!NegativeOrZeroInt->is_parameterizable, "NegativeOrZeroInt isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, pass => 'zero' => 0, fail => 'one' => 1, pass => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, NegativeOrZeroInt, ucfirst("$label should pass NegativeOrZeroInt")); } elsif ($expect eq 'fail') { should_fail($value, NegativeOrZeroInt, ucfirst("$label should fail NegativeOrZeroInt")); } else { fail("expected '$expect'?!"); } } done_testing; NegativeOrZeroNum.t000644001750001750 1257113601673061 20032 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::Numeric qw( NegativeOrZeroNum ); isa_ok(NegativeOrZeroNum, 'Type::Tiny', 'NegativeOrZeroNum'); is(NegativeOrZeroNum->name, 'NegativeOrZeroNum', 'NegativeOrZeroNum has correct name'); is(NegativeOrZeroNum->display_name, 'NegativeOrZeroNum', 'NegativeOrZeroNum has correct display_name'); is(NegativeOrZeroNum->library, 'Types::Common::Numeric', 'NegativeOrZeroNum knows it is in the Types::Common::Numeric library'); ok(Types::Common::Numeric->has_type('NegativeOrZeroNum'), 'Types::Common::Numeric knows it has type NegativeOrZeroNum'); ok(!NegativeOrZeroNum->deprecated, 'NegativeOrZeroNum is not deprecated'); ok(!NegativeOrZeroNum->is_anon, 'NegativeOrZeroNum is not anonymous'); ok(NegativeOrZeroNum->can_be_inlined, 'NegativeOrZeroNum can be inlined'); is(exception { NegativeOrZeroNum->inline_check(q/$xyz/) }, undef, "Inlining NegativeOrZeroNum doesn't throw an exception"); ok(!NegativeOrZeroNum->has_coercion, "NegativeOrZeroNum doesn't have a coercion"); ok(!NegativeOrZeroNum->is_parameterizable, "NegativeOrZeroNum isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, pass => 'zero' => 0, fail => 'one' => 1, pass => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, NegativeOrZeroNum, ucfirst("$label should pass NegativeOrZeroNum")); } elsif ($expect eq 'fail') { should_fail($value, NegativeOrZeroNum, ucfirst("$label should fail NegativeOrZeroNum")); } else { fail("expected '$expect'?!"); } } done_testing; NonEmptySimpleStr.t000644001750001750 1256313601673061 20064 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::String qw( NonEmptySimpleStr ); isa_ok(NonEmptySimpleStr, 'Type::Tiny', 'NonEmptySimpleStr'); is(NonEmptySimpleStr->name, 'NonEmptySimpleStr', 'NonEmptySimpleStr has correct name'); is(NonEmptySimpleStr->display_name, 'NonEmptySimpleStr', 'NonEmptySimpleStr has correct display_name'); is(NonEmptySimpleStr->library, 'Types::Common::String', 'NonEmptySimpleStr knows it is in the Types::Common::String library'); ok(Types::Common::String->has_type('NonEmptySimpleStr'), 'Types::Common::String knows it has type NonEmptySimpleStr'); ok(!NonEmptySimpleStr->deprecated, 'NonEmptySimpleStr is not deprecated'); ok(!NonEmptySimpleStr->is_anon, 'NonEmptySimpleStr is not anonymous'); ok(NonEmptySimpleStr->can_be_inlined, 'NonEmptySimpleStr can be inlined'); is(exception { NonEmptySimpleStr->inline_check(q/$xyz/) }, undef, "Inlining NonEmptySimpleStr doesn't throw an exception"); ok(!NonEmptySimpleStr->has_coercion, "NonEmptySimpleStr doesn't have a coercion"); ok(!NonEmptySimpleStr->is_parameterizable, "NonEmptySimpleStr isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, fail => 'empty string' => '', pass => 'whitespace' => ' ', fail => 'line break' => "\n", pass => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', pass => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, NonEmptySimpleStr, ucfirst("$label should pass NonEmptySimpleStr")); } elsif ($expect eq 'fail') { should_fail($value, NonEmptySimpleStr, ucfirst("$label should fail NonEmptySimpleStr")); } else { fail("expected '$expect'?!"); } } done_testing; NonEmptyStr.t000644001750001750 1227713601673061 16714 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::String qw( NonEmptyStr ); isa_ok(NonEmptyStr, 'Type::Tiny', 'NonEmptyStr'); is(NonEmptyStr->name, 'NonEmptyStr', 'NonEmptyStr has correct name'); is(NonEmptyStr->display_name, 'NonEmptyStr', 'NonEmptyStr has correct display_name'); is(NonEmptyStr->library, 'Types::Common::String', 'NonEmptyStr knows it is in the Types::Common::String library'); ok(Types::Common::String->has_type('NonEmptyStr'), 'Types::Common::String knows it has type NonEmptyStr'); ok(!NonEmptyStr->deprecated, 'NonEmptyStr is not deprecated'); ok(!NonEmptyStr->is_anon, 'NonEmptyStr is not anonymous'); ok(NonEmptyStr->can_be_inlined, 'NonEmptyStr can be inlined'); is(exception { NonEmptyStr->inline_check(q/$xyz/) }, undef, "Inlining NonEmptyStr doesn't throw an exception"); ok(!NonEmptyStr->has_coercion, "NonEmptyStr doesn't have a coercion"); ok(!NonEmptyStr->is_parameterizable, "NonEmptyStr isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, fail => 'empty string' => '', pass => 'whitespace' => ' ', pass => 'line break' => "\n", pass => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', pass => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, NonEmptyStr, ucfirst("$label should pass NonEmptyStr")); } elsif ($expect eq 'fail') { should_fail($value, NonEmptyStr, ucfirst("$label should fail NonEmptyStr")); } else { fail("expected '$expect'?!"); } } done_testing; Num.t000644001750001750 1165313601673061 15206 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Num ); isa_ok(Num, 'Type::Tiny', 'Num'); is(Num->name, 'Num', 'Num has correct name'); is(Num->display_name, 'Num', 'Num has correct display_name'); is(Num->library, 'Types::Standard', 'Num knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Num'), 'Types::Standard knows it has type Num'); ok(!Num->deprecated, 'Num is not deprecated'); ok(!Num->is_anon, 'Num is not anonymous'); ok(Num->can_be_inlined, 'Num can be inlined'); is(exception { Num->inline_check(q/$xyz/) }, undef, "Inlining Num doesn't throw an exception"); ok(!Num->has_coercion, "Num doesn't have a coercion"); ok(!Num->is_parameterizable, "Num isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Num, ucfirst("$label should pass Num")); } elsif ($expect eq 'fail') { should_fail($value, Num, ucfirst("$label should fail Num")); } else { fail("expected '$expect'?!"); } } done_testing; NumRange.t000644001750001750 1601113601673061 16154 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::Numeric qw( NumRange ); isa_ok(NumRange, 'Type::Tiny', 'NumRange'); is(NumRange->name, 'NumRange', 'NumRange has correct name'); is(NumRange->display_name, 'NumRange', 'NumRange has correct display_name'); is(NumRange->library, 'Types::Common::Numeric', 'NumRange knows it is in the Types::Common::Numeric library'); ok(Types::Common::Numeric->has_type('NumRange'), 'Types::Common::Numeric knows it has type NumRange'); ok(!NumRange->deprecated, 'NumRange is not deprecated'); ok(!NumRange->is_anon, 'NumRange is not anonymous'); ok(NumRange->can_be_inlined, 'NumRange can be inlined'); is(exception { NumRange->inline_check(q/$xyz/) }, undef, "Inlining NumRange doesn't throw an exception"); ok(!NumRange->has_coercion, "NumRange doesn't have a coercion"); ok(NumRange->is_parameterizable, "NumRange is parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, NumRange, ucfirst("$label should pass NumRange")); } elsif ($expect eq 'fail') { should_fail($value, NumRange, ucfirst("$label should fail NumRange")); } else { fail("expected '$expect'?!"); } } # # If there's one parameter, it is an inclusive minimum. # my $NumRange_2 = NumRange[2]; should_fail(-2, $NumRange_2); should_fail(-1, $NumRange_2); should_fail( 0, $NumRange_2); should_fail( 1, $NumRange_2); should_pass( 2, $NumRange_2); should_pass( 3, $NumRange_2); should_pass( 4, $NumRange_2); should_pass( 5, $NumRange_2); should_pass( 6, $NumRange_2); should_pass(3.1416, $NumRange_2); should_fail([], $NumRange_2); # # If there's two parameters, they are inclusive minimum and maximum. # my $NumRange_2_4 = NumRange[2, 4]; should_fail(-2, $NumRange_2_4); should_fail(-1, $NumRange_2_4); should_fail( 0, $NumRange_2_4); should_fail( 1, $NumRange_2_4); should_pass( 2, $NumRange_2_4); should_pass( 3, $NumRange_2_4); should_pass( 4, $NumRange_2_4); should_fail( 5, $NumRange_2_4); should_fail( 6, $NumRange_2_4); should_pass(3.1416, $NumRange_2_4); should_fail([], $NumRange_2_4); # # Can set an exclusive minimum and maximum. # my $NumRange_2_4_ex = NumRange[2, 4, 1, 1]; should_fail(-2, $NumRange_2_4_ex); should_fail(-1, $NumRange_2_4_ex); should_fail( 0, $NumRange_2_4_ex); should_fail( 1, $NumRange_2_4_ex); should_fail( 2, $NumRange_2_4_ex); should_pass( 3, $NumRange_2_4_ex); should_fail( 4, $NumRange_2_4_ex); should_fail( 5, $NumRange_2_4_ex); should_fail( 6, $NumRange_2_4_ex); should_pass(3.1416, $NumRange_2_4_ex); should_fail([], $NumRange_2_4_ex); # # NumRange allows minimum and maximum to be non-integers # my $NumRange_nonint = NumRange[1.5, 3.5]; should_fail(-2, $NumRange_nonint); should_fail(-1, $NumRange_nonint); should_fail( 0, $NumRange_nonint); should_fail( 1, $NumRange_nonint); should_pass( 2, $NumRange_nonint); should_pass( 3, $NumRange_nonint); should_fail( 4, $NumRange_nonint); should_fail( 5, $NumRange_nonint); should_fail( 6, $NumRange_nonint); should_pass(3.1416, $NumRange_nonint); should_fail([], $NumRange_nonint); my $e = exception { NumRange[{}] }; like($e, qr/min must be/, 'bad parameter'); done_testing; NumericCode.t000644001750001750 1240613601673061 16641 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::String qw( NumericCode ); isa_ok(NumericCode, 'Type::Tiny', 'NumericCode'); is(NumericCode->name, 'NumericCode', 'NumericCode has correct name'); is(NumericCode->display_name, 'NumericCode', 'NumericCode has correct display_name'); is(NumericCode->library, 'Types::Common::String', 'NumericCode knows it is in the Types::Common::String library'); ok(Types::Common::String->has_type('NumericCode'), 'Types::Common::String knows it has type NumericCode'); ok(!NumericCode->deprecated, 'NumericCode is not deprecated'); ok(!NumericCode->is_anon, 'NumericCode is not anonymous'); ok(NumericCode->can_be_inlined, 'NumericCode can be inlined'); is(exception { NumericCode->inline_check(q/$xyz/) }, undef, "Inlining NumericCode doesn't throw an exception"); ok(NumericCode->has_coercion, "NumericCode has a coercion"); ok(!NumericCode->is_parameterizable, "NumericCode isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, NumericCode, ucfirst("$label should pass NumericCode")); } elsif ($expect eq 'fail') { should_fail($value, NumericCode, ucfirst("$label should fail NumericCode")); } else { fail("expected '$expect'?!"); } } is(NumericCode->coerce('123-456 789-0'), '1234567890', 'coercion from string'); done_testing; Object.t000644001750001750 1200513601673061 15645 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Object ); isa_ok(Object, 'Type::Tiny', 'Object'); is(Object->name, 'Object', 'Object has correct name'); is(Object->display_name, 'Object', 'Object has correct display_name'); is(Object->library, 'Types::Standard', 'Object knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Object'), 'Types::Standard knows it has type Object'); ok(!Object->deprecated, 'Object is not deprecated'); ok(!Object->is_anon, 'Object is not anonymous'); ok(Object->can_be_inlined, 'Object can be inlined'); is(exception { Object->inline_check(q/$xyz/) }, undef, "Inlining Object doesn't throw an exception"); ok(!Object->has_coercion, "Object doesn't have a coercion"); ok(!Object->is_parameterizable, "Object isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, pass => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], pass => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, pass => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, pass => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, pass => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), xxxx => 'regexp' => qr/./, pass => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, pass => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, pass => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, pass => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, pass => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, pass => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, pass => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, pass => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, pass => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Object, ucfirst("$label should pass Object")); } elsif ($expect eq 'fail') { should_fail($value, Object, ucfirst("$label should fail Object")); } else { fail("expected '$expect'?!"); } } done_testing; OptList.t000644001750001750 1204313601673061 16037 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( OptList ); isa_ok(OptList, 'Type::Tiny', 'OptList'); is(OptList->name, 'OptList', 'OptList has correct name'); is(OptList->display_name, 'OptList', 'OptList has correct display_name'); is(OptList->library, 'Types::Standard', 'OptList knows it is in the Types::Standard library'); ok(Types::Standard->has_type('OptList'), 'Types::Standard knows it has type OptList'); ok(!OptList->deprecated, 'OptList is not deprecated'); ok(!OptList->is_anon, 'OptList is not anonymous'); ok(OptList->can_be_inlined, 'OptList can be inlined'); is(exception { OptList->inline_check(q/$xyz/) }, undef, "Inlining OptList doesn't throw an exception"); ok(!OptList->has_coercion, "OptList doesn't have a coercion"); ok(!OptList->is_parameterizable, "OptList isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), pass => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, OptList, ucfirst("$label should pass OptList")); } elsif ($expect eq 'fail') { should_fail($value, OptList, ucfirst("$label should fail OptList")); } else { fail("expected '$expect'?!"); } } done_testing; Optional.t000644001750001750 1570513601673061 16236 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Optional ); isa_ok(Optional, 'Type::Tiny', 'Optional'); is(Optional->name, 'Optional', 'Optional has correct name'); is(Optional->display_name, 'Optional', 'Optional has correct display_name'); is(Optional->library, 'Types::Standard', 'Optional knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Optional'), 'Types::Standard knows it has type Optional'); ok(!Optional->deprecated, 'Optional is not deprecated'); ok(!Optional->is_anon, 'Optional is not anonymous'); ok(Optional->can_be_inlined, 'Optional can be inlined'); is(exception { Optional->inline_check(q/$xyz/) }, undef, "Inlining Optional doesn't throw an exception"); ok(!Optional->has_coercion, "Optional doesn't have a coercion"); ok(Optional->is_parameterizable, "Optional is parameterizable"); my @tests = ( pass => 'undef' => undef, pass => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, pass => 'empty string' => '', pass => 'whitespace' => ' ', pass => 'line break' => "\n", pass => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', pass => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', pass => 'a reference to undef' => do { my $x = undef; \$x }, pass => 'a reference to false' => do { my $x = !!0; \$x }, pass => 'a reference to true' => do { my $x = !!1; \$x }, pass => 'a reference to zero' => do { my $x = 0; \$x }, pass => 'a reference to one' => do { my $x = 1; \$x }, pass => 'a reference to empty string' => do { my $x = ''; \$x }, pass => 'a reference to random string' => do { my $x = 'abc123'; \$x }, pass => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), pass => 'empty arrayref' => [], pass => 'arrayref with one zero' => [0], pass => 'arrayref of integers' => [1..10], pass => 'arrayref of numbers' => [1..10, 3.1416], pass => 'blessed arrayref' => bless([], 'SomePkg'), pass => 'empty hashref' => {}, pass => 'hashref' => { foo => 1 }, pass => 'blessed hashref' => bless({}, 'SomePkg'), pass => 'coderef' => sub { 1 }, pass => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), pass => 'glob' => do { no warnings 'once'; *SOMETHING }, pass => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, pass => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), pass => 'regexp' => qr/./, pass => 'blessed regexp' => bless(qr/./, 'SomePkg'), pass => 'filehandle' => do { open my $x, '<', $0 or die; $x }, pass => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, pass => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, pass => 'ref to arrayref' => do { my $x = []; \$x }, pass => 'ref to hashref' => do { my $x = {}; \$x }, pass => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, pass => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, pass => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, pass => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, pass => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, pass => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, pass => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, pass => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, pass => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Optional, ucfirst("$label should pass Optional")); } elsif ($expect eq 'fail') { should_fail($value, Optional, ucfirst("$label should fail Optional")); } else { fail("expected '$expect'?!"); } } # # Optional[X] is basically just the same as X. Optional acts like a no-op. # Optional is just a hint to Dict/Tuple/CycleTuple and Type::Params. # my $type = Optional[ Types::Standard::Int ]; should_pass(0, $type); should_pass(1, $type); should_fail(1.1, $type); should_fail(undef, $type); if (eval q{ package Local::MyClass::Moo; use Moo; use Types::Standard qw( Int Optional ); has xyz => ( is => 'ro', isa => Optional[Int] ); 1; }) { my $e; $e = exception { Local::MyClass::Moo->new( xyz => 0 ); }; is($e, undef); $e = exception { Local::MyClass::Moo->new( xyz => 1 ); }; is($e, undef); $e = exception { Local::MyClass::Moo->new( xyz => 1.1 ); }; like($e, qr/type constraint/); $e = exception { Local::MyClass::Moo->new( xyz => undef ); }; like($e, qr/type constraint/); } if (eval q{ package Local::MyClass::Moose; use Moose; use Types::Standard qw( Int Optional ); has xyz => ( is => 'ro', isa => Optional[Int] ); 1; }) { my $e; $e = exception { Local::MyClass::Moose->new( xyz => 0 ); }; is($e, undef); $e = exception { Local::MyClass::Moose->new( xyz => 1 ); }; is($e, undef); $e = exception { Local::MyClass::Moose->new( xyz => 1.1 ); }; like($e, qr/type constraint/); $e = exception { Local::MyClass::Moose->new( xyz => undef ); }; like($e, qr/type constraint/); } if (eval q{ package Local::MyClass::Mouse; use Mouse; use Types::Standard qw( Int Optional ); has xyz => ( is => 'ro', isa => Optional[Int] ); 1; }) { my $e; $e = exception { Local::MyClass::Mouse->new( xyz => 0 ); }; is($e, undef); $e = exception { Local::MyClass::Mouse->new( xyz => 1 ); }; is($e, undef); $e = exception { Local::MyClass::Mouse->new( xyz => 1.1 ); }; like($e, qr/type constraint/); $e = exception { Local::MyClass::Mouse->new( xyz => undef ); }; like($e, qr/type constraint/); } # # See also: Dict.t, Tuple.t, CycleTuple.t. # done_testing; Overload.t000644001750001750 1416613601673061 16224 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Overload ); isa_ok(Overload, 'Type::Tiny', 'Overload'); is(Overload->name, 'Overload', 'Overload has correct name'); is(Overload->display_name, 'Overload', 'Overload has correct display_name'); is(Overload->library, 'Types::Standard', 'Overload knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Overload'), 'Types::Standard knows it has type Overload'); ok(!Overload->deprecated, 'Overload is not deprecated'); ok(!Overload->is_anon, 'Overload is not anonymous'); ok(Overload->can_be_inlined, 'Overload can be inlined'); is(exception { Overload->inline_check(q/$xyz/) }, undef, "Inlining Overload doesn't throw an exception"); ok(!Overload->has_coercion, "Overload doesn't have a coercion"); ok(Overload->is_parameterizable, "Overload is parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, pass => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, pass => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, pass => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, pass => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, pass => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, pass => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, pass => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Overload, ucfirst("$label should pass Overload")); } elsif ($expect eq 'fail') { should_fail($value, Overload, ucfirst("$label should fail Overload")); } else { fail("expected '$expect'?!"); } } # # Type::Tiny itself overloads q[&{}] and q[""] but not q[${}]. # should_pass(Overload, Overload[ q[&{}] ]); should_pass(Overload, Overload[ q[""] ]); should_fail(Overload, Overload[ q[${}] ]); # # It's possible to check multiple overloaded operations. # should_pass(Overload, Overload[ q[&{}], q[""] ]); should_fail(Overload, Overload[ q[""], q[${}] ]); should_fail(Overload, Overload[ q[&{}], q[${}] ]); # # In the following example, $fortytwo_withfallback doesn't overload # '+' but still passes Overload['+'] because it provides a numification # overload and allows fallbacks. # my $fortytwo_nofallback = do { package Local::OL::NoFallback; use overload q[0+] => sub { ${$_[0]} }; my $x = 42; bless \$x; }; my $fortytwo_withfallback = do { package Local::OL::WithFallback; use overload q[0+] => sub { ${$_[0]} }, fallback => 1; my $x = 42; bless \$x; }; should_pass($fortytwo_nofallback, Overload['0+']); should_pass($fortytwo_withfallback, Overload['0+']); should_fail($fortytwo_nofallback, Overload['+']); should_fail($fortytwo_withfallback, Overload['+']); done_testing; Password.t000644001750001750 1214513601673061 16246 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::String qw( Password ); isa_ok(Password, 'Type::Tiny', 'Password'); is(Password->name, 'Password', 'Password has correct name'); is(Password->display_name, 'Password', 'Password has correct display_name'); is(Password->library, 'Types::Common::String', 'Password knows it is in the Types::Common::String library'); ok(Types::Common::String->has_type('Password'), 'Types::Common::String knows it has type Password'); ok(!Password->deprecated, 'Password is not deprecated'); ok(!Password->is_anon, 'Password is not anonymous'); ok(Password->can_be_inlined, 'Password can be inlined'); is(exception { Password->inline_check(q/$xyz/) }, undef, "Inlining Password doesn't throw an exception"); ok(!Password->has_coercion, "Password doesn't have a coercion"); ok(!Password->is_parameterizable, "Password isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, pass => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", pass => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', pass => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Password, ucfirst("$label should pass Password")); } elsif ($expect eq 'fail') { should_fail($value, Password, ucfirst("$label should fail Password")); } else { fail("expected '$expect'?!"); } } done_testing; PositiveInt.t000644001750001750 1230513601673061 16717 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::Numeric qw( PositiveInt ); isa_ok(PositiveInt, 'Type::Tiny', 'PositiveInt'); is(PositiveInt->name, 'PositiveInt', 'PositiveInt has correct name'); is(PositiveInt->display_name, 'PositiveInt', 'PositiveInt has correct display_name'); is(PositiveInt->library, 'Types::Common::Numeric', 'PositiveInt knows it is in the Types::Common::Numeric library'); ok(Types::Common::Numeric->has_type('PositiveInt'), 'Types::Common::Numeric knows it has type PositiveInt'); ok(!PositiveInt->deprecated, 'PositiveInt is not deprecated'); ok(!PositiveInt->is_anon, 'PositiveInt is not anonymous'); ok(PositiveInt->can_be_inlined, 'PositiveInt can be inlined'); is(exception { PositiveInt->inline_check(q/$xyz/) }, undef, "Inlining PositiveInt doesn't throw an exception"); ok(!PositiveInt->has_coercion, "PositiveInt doesn't have a coercion"); ok(!PositiveInt->is_parameterizable, "PositiveInt isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, pass => 'true' => !!1, fail => 'zero' => 0, pass => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, PositiveInt, ucfirst("$label should pass PositiveInt")); } elsif ($expect eq 'fail') { should_fail($value, PositiveInt, ucfirst("$label should fail PositiveInt")); } else { fail("expected '$expect'?!"); } } done_testing; PositiveNum.t000644001750001750 1230513601673061 16724 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::Numeric qw( PositiveNum ); isa_ok(PositiveNum, 'Type::Tiny', 'PositiveNum'); is(PositiveNum->name, 'PositiveNum', 'PositiveNum has correct name'); is(PositiveNum->display_name, 'PositiveNum', 'PositiveNum has correct display_name'); is(PositiveNum->library, 'Types::Common::Numeric', 'PositiveNum knows it is in the Types::Common::Numeric library'); ok(Types::Common::Numeric->has_type('PositiveNum'), 'Types::Common::Numeric knows it has type PositiveNum'); ok(!PositiveNum->deprecated, 'PositiveNum is not deprecated'); ok(!PositiveNum->is_anon, 'PositiveNum is not anonymous'); ok(PositiveNum->can_be_inlined, 'PositiveNum can be inlined'); is(exception { PositiveNum->inline_check(q/$xyz/) }, undef, "Inlining PositiveNum doesn't throw an exception"); ok(!PositiveNum->has_coercion, "PositiveNum doesn't have a coercion"); ok(!PositiveNum->is_parameterizable, "PositiveNum isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, pass => 'true' => !!1, fail => 'zero' => 0, pass => 'one' => 1, fail => 'negative one' => -1, pass => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, PositiveNum, ucfirst("$label should pass PositiveNum")); } elsif ($expect eq 'fail') { should_fail($value, PositiveNum, ucfirst("$label should fail PositiveNum")); } else { fail("expected '$expect'?!"); } } done_testing; PositiveOrZeroInt.t000644001750001750 1257113601673061 20065 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::Numeric qw( PositiveOrZeroInt ); isa_ok(PositiveOrZeroInt, 'Type::Tiny', 'PositiveOrZeroInt'); is(PositiveOrZeroInt->name, 'PositiveOrZeroInt', 'PositiveOrZeroInt has correct name'); is(PositiveOrZeroInt->display_name, 'PositiveOrZeroInt', 'PositiveOrZeroInt has correct display_name'); is(PositiveOrZeroInt->library, 'Types::Common::Numeric', 'PositiveOrZeroInt knows it is in the Types::Common::Numeric library'); ok(Types::Common::Numeric->has_type('PositiveOrZeroInt'), 'Types::Common::Numeric knows it has type PositiveOrZeroInt'); ok(!PositiveOrZeroInt->deprecated, 'PositiveOrZeroInt is not deprecated'); ok(!PositiveOrZeroInt->is_anon, 'PositiveOrZeroInt is not anonymous'); ok(PositiveOrZeroInt->can_be_inlined, 'PositiveOrZeroInt can be inlined'); is(exception { PositiveOrZeroInt->inline_check(q/$xyz/) }, undef, "Inlining PositiveOrZeroInt doesn't throw an exception"); ok(!PositiveOrZeroInt->has_coercion, "PositiveOrZeroInt doesn't have a coercion"); ok(!PositiveOrZeroInt->is_parameterizable, "PositiveOrZeroInt isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, PositiveOrZeroInt, ucfirst("$label should pass PositiveOrZeroInt")); } elsif ($expect eq 'fail') { should_fail($value, PositiveOrZeroInt, ucfirst("$label should fail PositiveOrZeroInt")); } else { fail("expected '$expect'?!"); } } done_testing; PositiveOrZeroNum.t000644001750001750 1257113601673061 20072 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::Numeric qw( PositiveOrZeroNum ); isa_ok(PositiveOrZeroNum, 'Type::Tiny', 'PositiveOrZeroNum'); is(PositiveOrZeroNum->name, 'PositiveOrZeroNum', 'PositiveOrZeroNum has correct name'); is(PositiveOrZeroNum->display_name, 'PositiveOrZeroNum', 'PositiveOrZeroNum has correct display_name'); is(PositiveOrZeroNum->library, 'Types::Common::Numeric', 'PositiveOrZeroNum knows it is in the Types::Common::Numeric library'); ok(Types::Common::Numeric->has_type('PositiveOrZeroNum'), 'Types::Common::Numeric knows it has type PositiveOrZeroNum'); ok(!PositiveOrZeroNum->deprecated, 'PositiveOrZeroNum is not deprecated'); ok(!PositiveOrZeroNum->is_anon, 'PositiveOrZeroNum is not anonymous'); ok(PositiveOrZeroNum->can_be_inlined, 'PositiveOrZeroNum can be inlined'); is(exception { PositiveOrZeroNum->inline_check(q/$xyz/) }, undef, "Inlining PositiveOrZeroNum doesn't throw an exception"); ok(!PositiveOrZeroNum->has_coercion, "PositiveOrZeroNum doesn't have a coercion"); ok(!PositiveOrZeroNum->is_parameterizable, "PositiveOrZeroNum isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, fail => 'negative one' => -1, pass => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, PositiveOrZeroNum, ucfirst("$label should pass PositiveOrZeroNum")); } elsif ($expect eq 'fail') { should_fail($value, PositiveOrZeroNum, ucfirst("$label should fail PositiveOrZeroNum")); } else { fail("expected '$expect'?!"); } } done_testing; Ref.t000644001750001750 1462213601673061 15162 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Ref ); isa_ok(Ref, 'Type::Tiny', 'Ref'); is(Ref->name, 'Ref', 'Ref has correct name'); is(Ref->display_name, 'Ref', 'Ref has correct display_name'); is(Ref->library, 'Types::Standard', 'Ref knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Ref'), 'Types::Standard knows it has type Ref'); ok(!Ref->deprecated, 'Ref is not deprecated'); ok(!Ref->is_anon, 'Ref is not anonymous'); ok(Ref->can_be_inlined, 'Ref can be inlined'); is(exception { Ref->inline_check(q/$xyz/) }, undef, "Inlining Ref doesn't throw an exception"); ok(!Ref->has_coercion, "Ref doesn't have a coercion"); ok(Ref->is_parameterizable, "Ref is parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', pass => 'a reference to undef' => do { my $x = undef; \$x }, pass => 'a reference to false' => do { my $x = !!0; \$x }, pass => 'a reference to true' => do { my $x = !!1; \$x }, pass => 'a reference to zero' => do { my $x = 0; \$x }, pass => 'a reference to one' => do { my $x = 1; \$x }, pass => 'a reference to empty string' => do { my $x = ''; \$x }, pass => 'a reference to random string' => do { my $x = 'abc123'; \$x }, pass => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), pass => 'empty arrayref' => [], pass => 'arrayref with one zero' => [0], pass => 'arrayref of integers' => [1..10], pass => 'arrayref of numbers' => [1..10, 3.1416], pass => 'blessed arrayref' => bless([], 'SomePkg'), pass => 'empty hashref' => {}, pass => 'hashref' => { foo => 1 }, pass => 'blessed hashref' => bless({}, 'SomePkg'), pass => 'coderef' => sub { 1 }, pass => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, pass => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, pass => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), pass => 'regexp' => qr/./, pass => 'blessed regexp' => bless(qr/./, 'SomePkg'), pass => 'filehandle' => do { open my $x, '<', $0 or die; $x }, pass => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, pass => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, pass => 'ref to arrayref' => do { my $x = []; \$x }, pass => 'ref to hashref' => do { my $x = {}; \$x }, pass => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, pass => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, pass => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, pass => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, pass => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, pass => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, pass => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, pass => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, pass => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Ref, ucfirst("$label should pass Ref")); } elsif ($expect eq 'fail') { should_fail($value, Ref, ucfirst("$label should fail Ref")); } else { fail("expected '$expect'?!"); } } # # Tests for parameterized Ref # Ref['HASH'] # Ref['ARRAY'] # Ref['SCALAR'] # Ref['CODE'] # Ref['GLOB'] # Ref['LVALUE'] # my $x = 1; my %more_tests = ( HASH => [ {}, bless({}, 'Foo') ], ARRAY => [ [], bless([], 'Foo') ], SCALAR => [ do { my $x; \$x }, bless(do { my $x; \$x }, 'Foo') ], CODE => [ sub { 1 }, bless(sub { 1 }, 'Foo') ], GLOB => do { no warnings;[ \*BLEH, bless(\*BLEH2, 'Foo') ] }, # LVALUE => [ \substr($x, 0, 1), bless(\substr($x, 0, 1), 'Foo') ], ); my @reftypes = sort keys %more_tests; # The LVALUE examples *do* work, but generating output for the test # via Data::Dumper results in annoying warning messages, so the tests # are disabled. # Regexp, IO, FORMAT, VSTRING are all "todo". for my $reftype (@reftypes) { my $type = Ref[$reftype]; note("== $type =="); isa_ok($type, 'Type::Tiny', '$type'); ok($type->is_anon, '$type is not anonymous'); ok($type->can_be_inlined, '$type can be inlined'); is(exception { $type->inline_check(q/$xyz/) }, undef, "Inlining \$type doesn't throw an exception"); ok(!$type->has_coercion, "\$type doesn't have a coercion"); ok(!$type->is_parameterizable, "\$type isn't parameterizable"); ok($type->is_parameterized, "\$type is parameterized"); is($type->parameterized_from, Ref, "\$type's parent is Ref"); foreach my $other (@reftypes) { my @values = @{ $more_tests{$other} }; if ($reftype eq $other) { should_pass($_, $type) for @values; } else { should_fail($_, $type) for @values; } } } done_testing; RegexpRef.t000644001750001750 1213713601673061 16334 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( RegexpRef ); isa_ok(RegexpRef, 'Type::Tiny', 'RegexpRef'); is(RegexpRef->name, 'RegexpRef', 'RegexpRef has correct name'); is(RegexpRef->display_name, 'RegexpRef', 'RegexpRef has correct display_name'); is(RegexpRef->library, 'Types::Standard', 'RegexpRef knows it is in the Types::Standard library'); ok(Types::Standard->has_type('RegexpRef'), 'Types::Standard knows it has type RegexpRef'); ok(!RegexpRef->deprecated, 'RegexpRef is not deprecated'); ok(!RegexpRef->is_anon, 'RegexpRef is not anonymous'); ok(RegexpRef->can_be_inlined, 'RegexpRef can be inlined'); is(exception { RegexpRef->inline_check(q/$xyz/) }, undef, "Inlining RegexpRef doesn't throw an exception"); ok(!RegexpRef->has_coercion, "RegexpRef doesn't have a coercion"); ok(!RegexpRef->is_parameterizable, "RegexpRef isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), pass => 'regexp' => qr/./, pass => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, RegexpRef, ucfirst("$label should pass RegexpRef")); } elsif ($expect eq 'fail') { should_fail($value, RegexpRef, ucfirst("$label should fail RegexpRef")); } else { fail("expected '$expect'?!"); } } done_testing; RoleName.t000644001750001750 1415513601673061 16151 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( RoleName ); isa_ok(RoleName, 'Type::Tiny', 'RoleName'); is(RoleName->name, 'RoleName', 'RoleName has correct name'); is(RoleName->display_name, 'RoleName', 'RoleName has correct display_name'); is(RoleName->library, 'Types::Standard', 'RoleName knows it is in the Types::Standard library'); ok(Types::Standard->has_type('RoleName'), 'Types::Standard knows it has type RoleName'); ok(!RoleName->deprecated, 'RoleName is not deprecated'); ok(!RoleName->is_anon, 'RoleName is not anonymous'); ok(RoleName->can_be_inlined, 'RoleName can be inlined'); is(exception { RoleName->inline_check(q/$xyz/) }, undef, "Inlining RoleName doesn't throw an exception"); ok(!RoleName->has_coercion, "RoleName doesn't have a coercion"); ok(!RoleName->is_parameterizable, "RoleName isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, RoleName, ucfirst("$label should pass RoleName")); } elsif ($expect eq 'fail') { should_fail($value, RoleName, ucfirst("$label should fail RoleName")); } else { fail("expected '$expect'?!"); } } # # RoleName accepts Role::Tiny, Moo::Role, Moose::Role, and Mouse::Role roles # if (eval q{ package Local::Role::RoleTiny; use Role::Tiny; 1 }) { should_pass('Local::Role::RoleTiny', RoleName); } if (eval q{ package Local::Role::MooRole; use Moo::Role; 1 }) { should_pass('Local::Role::MooRole', RoleName); } if (eval q{ package Local::Role::MooseRole; use Moose::Role; 1 }) { should_pass('Local::Role::MooseRole', RoleName); } if (eval q{ package Local::Role::MouseRole; use Mouse::Role; 1 }) { should_pass('Local::Role::MouseRole', RoleName); } # # RoleName rejects Class::Tiny, Moo, Moose, and Mouse classes # if (eval q{ package Local::Class::ClassTiny; use Class::Tiny; 1 }) { should_fail('Local::Class::ClassTiny', RoleName); } if (eval q{ package Local::Class::Moo; use Moo; 1 }) { should_fail('Local::Class::Moo', RoleName); } if (eval q{ package Local::Class::Moose; use Moose; 1 }) { should_fail('Local::Class::Moose', RoleName); } if (eval q{ package Local::Class::Mouse; use Mouse; 1 }) { should_fail('Local::Class::Mouse', RoleName); } done_testing; ScalarRef.t000644001750001750 1446213601673061 16312 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( ScalarRef ); isa_ok(ScalarRef, 'Type::Tiny', 'ScalarRef'); is(ScalarRef->name, 'ScalarRef', 'ScalarRef has correct name'); is(ScalarRef->display_name, 'ScalarRef', 'ScalarRef has correct display_name'); is(ScalarRef->library, 'Types::Standard', 'ScalarRef knows it is in the Types::Standard library'); ok(Types::Standard->has_type('ScalarRef'), 'Types::Standard knows it has type ScalarRef'); ok(!ScalarRef->deprecated, 'ScalarRef is not deprecated'); ok(!ScalarRef->is_anon, 'ScalarRef is not anonymous'); ok(ScalarRef->can_be_inlined, 'ScalarRef can be inlined'); is(exception { ScalarRef->inline_check(q/$xyz/) }, undef, "Inlining ScalarRef doesn't throw an exception"); ok(!ScalarRef->has_coercion, "ScalarRef doesn't have a coercion"); ok(ScalarRef->is_parameterizable, "ScalarRef is parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', pass => 'a reference to undef' => do { my $x = undef; \$x }, pass => 'a reference to false' => do { my $x = !!0; \$x }, pass => 'a reference to true' => do { my $x = !!1; \$x }, pass => 'a reference to zero' => do { my $x = 0; \$x }, pass => 'a reference to one' => do { my $x = 1; \$x }, pass => 'a reference to empty string' => do { my $x = ''; \$x }, pass => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, pass => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, pass => 'ref to arrayref' => do { my $x = []; \$x }, pass => 'ref to hashref' => do { my $x = {}; \$x }, pass => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, pass => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, ScalarRef, ucfirst("$label should pass ScalarRef")); } elsif ($expect eq 'fail') { should_fail($value, ScalarRef, ucfirst("$label should fail ScalarRef")); } else { fail("expected '$expect'?!"); } } use Scalar::Util qw( refaddr ); my $plain = ScalarRef; my $paramd = ScalarRef[]; is( refaddr($plain), refaddr($paramd), 'parameterizing with [] has no effect' ); # # Parameterization with a type constraint # my $IntRef = ScalarRef[ Types::Standard::Int ]; should_pass(\"1", $IntRef); should_fail(\"1.2", $IntRef); should_fail(\"abc", $IntRef); # # Deep coercion # my $Rounded = Types::Standard::Int->plus_coercions( Types::Standard::Num, 'int($_)' ); my $RoundedRef = ScalarRef[ $Rounded ]; should_pass(\"1", $RoundedRef); should_fail(\"1.2", $RoundedRef); should_fail(\"abc", $RoundedRef); ok($RoundedRef->has_coercion); is_deeply($RoundedRef->coerce(\"3.1"), \"3"); # # Let's do it with a reference to a reference. # my $RoundedArrayRefRef = ScalarRef[ Types::Standard::ArrayRef[$Rounded] ]; should_pass(\[], $RoundedArrayRefRef); should_pass(\["1"], $RoundedArrayRefRef); should_fail(\["1.2"], $RoundedArrayRefRef); should_fail(\["abc"], $RoundedArrayRefRef); should_fail([], $RoundedArrayRefRef); should_fail(["1"], $RoundedArrayRefRef); should_fail(["1.2"], $RoundedArrayRefRef); should_fail(["abc"], $RoundedArrayRefRef); ok($RoundedArrayRefRef->has_coercion); is_deeply($RoundedArrayRefRef->coerce(\["3.1"]), \["3"]); done_testing; SimpleStr.t000644001750001750 1220313601673061 16361 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::String qw( SimpleStr ); isa_ok(SimpleStr, 'Type::Tiny', 'SimpleStr'); is(SimpleStr->name, 'SimpleStr', 'SimpleStr has correct name'); is(SimpleStr->display_name, 'SimpleStr', 'SimpleStr has correct display_name'); is(SimpleStr->library, 'Types::Common::String', 'SimpleStr knows it is in the Types::Common::String library'); ok(Types::Common::String->has_type('SimpleStr'), 'Types::Common::String knows it has type SimpleStr'); ok(!SimpleStr->deprecated, 'SimpleStr is not deprecated'); ok(!SimpleStr->is_anon, 'SimpleStr is not anonymous'); ok(SimpleStr->can_be_inlined, 'SimpleStr can be inlined'); is(exception { SimpleStr->inline_check(q/$xyz/) }, undef, "Inlining SimpleStr doesn't throw an exception"); ok(!SimpleStr->has_coercion, "SimpleStr doesn't have a coercion"); ok(!SimpleStr->is_parameterizable, "SimpleStr isn't parameterizable"); my @tests = ( fail => 'undef' => undef, pass => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, pass => 'empty string' => '', pass => 'whitespace' => ' ', fail => 'line break' => "\n", pass => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', pass => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, SimpleStr, ucfirst("$label should pass SimpleStr")); } elsif ($expect eq 'fail') { should_fail($value, SimpleStr, ucfirst("$label should fail SimpleStr")); } else { fail("expected '$expect'?!"); } } done_testing; SingleDigit.t000644001750001750 1230513601673061 16644 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::Numeric qw( SingleDigit ); isa_ok(SingleDigit, 'Type::Tiny', 'SingleDigit'); is(SingleDigit->name, 'SingleDigit', 'SingleDigit has correct name'); is(SingleDigit->display_name, 'SingleDigit', 'SingleDigit has correct display_name'); is(SingleDigit->library, 'Types::Common::Numeric', 'SingleDigit knows it is in the Types::Common::Numeric library'); ok(Types::Common::Numeric->has_type('SingleDigit'), 'Types::Common::Numeric knows it has type SingleDigit'); ok(!SingleDigit->deprecated, 'SingleDigit is not deprecated'); ok(!SingleDigit->is_anon, 'SingleDigit is not anonymous'); ok(SingleDigit->can_be_inlined, 'SingleDigit can be inlined'); is(exception { SingleDigit->inline_check(q/$xyz/) }, undef, "Inlining SingleDigit doesn't throw an exception"); ok(!SingleDigit->has_coercion, "SingleDigit doesn't have a coercion"); ok(!SingleDigit->is_parameterizable, "SingleDigit isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, SingleDigit, ucfirst("$label should pass SingleDigit")); } elsif ($expect eq 'fail') { should_fail($value, SingleDigit, ucfirst("$label should fail SingleDigit")); } else { fail("expected '$expect'?!"); } } done_testing; Str.t000644001750001750 1165313601673061 15217 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Str ); isa_ok(Str, 'Type::Tiny', 'Str'); is(Str->name, 'Str', 'Str has correct name'); is(Str->display_name, 'Str', 'Str has correct display_name'); is(Str->library, 'Types::Standard', 'Str knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Str'), 'Types::Standard knows it has type Str'); ok(!Str->deprecated, 'Str is not deprecated'); ok(!Str->is_anon, 'Str is not anonymous'); ok(Str->can_be_inlined, 'Str can be inlined'); is(exception { Str->inline_check(q/$xyz/) }, undef, "Inlining Str doesn't throw an exception"); ok(!Str->has_coercion, "Str doesn't have a coercion"); ok(!Str->is_parameterizable, "Str isn't parameterizable"); my @tests = ( fail => 'undef' => undef, pass => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, pass => 'empty string' => '', pass => 'whitespace' => ' ', pass => 'line break' => "\n", pass => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', pass => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Str, ucfirst("$label should pass Str")); } elsif ($expect eq 'fail') { should_fail($value, Str, ucfirst("$label should fail Str")); } else { fail("expected '$expect'?!"); } } done_testing; StrLength.t000644001750001750 1636213601673061 16363 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::String qw( StrLength ); isa_ok(StrLength, 'Type::Tiny', 'StrLength'); is(StrLength->name, 'StrLength', 'StrLength has correct name'); is(StrLength->display_name, 'StrLength', 'StrLength has correct display_name'); is(StrLength->library, 'Types::Common::String', 'StrLength knows it is in the Types::Common::String library'); ok(Types::Common::String->has_type('StrLength'), 'Types::Common::String knows it has type StrLength'); ok(!StrLength->deprecated, 'StrLength is not deprecated'); ok(!StrLength->is_anon, 'StrLength is not anonymous'); ok(StrLength->can_be_inlined, 'StrLength can be inlined'); is(exception { StrLength->inline_check(q/$xyz/) }, undef, "Inlining StrLength doesn't throw an exception"); ok(!StrLength->has_coercion, "StrLength doesn't have a coercion"); ok(StrLength->is_parameterizable, "StrLength is parameterizable"); my @tests = ( fail => 'undef' => undef, pass => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, pass => 'empty string' => '', pass => 'whitespace' => ' ', pass => 'line break' => "\n", pass => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', pass => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, StrLength, ucfirst("$label should pass StrLength")); } elsif ($expect eq 'fail') { should_fail($value, StrLength, ucfirst("$label should fail StrLength")); } else { fail("expected '$expect'?!"); } } # # String with a minimum length # my $StrLength_2 = StrLength[2]; should_fail('', $StrLength_2); should_fail('1', $StrLength_2); should_pass('12', $StrLength_2); should_pass('123', $StrLength_2); should_pass('1234', $StrLength_2); should_pass('12345', $StrLength_2); should_pass('123456', $StrLength_2); should_pass('1234567', $StrLength_2); should_pass('12345678', $StrLength_2); should_pass('123456789', $StrLength_2); # Cyrillic Small Letter Zhe - two bytes as UTF-8 but only one character should_fail("\x{0436}" x 1, $StrLength_2); should_pass("\x{0436}" x 2, $StrLength_2); should_pass("\x{0436}" x 6, $StrLength_2); # # String with a minimum and maximum length # my $StrLength_2_5 = StrLength[2, 5]; should_fail('', $StrLength_2_5); should_fail('1', $StrLength_2_5); should_pass('12', $StrLength_2_5); should_pass('123', $StrLength_2_5); should_pass('1234', $StrLength_2_5); should_pass('12345', $StrLength_2_5); should_fail('123456', $StrLength_2_5); should_fail('1234567', $StrLength_2_5); should_fail('12345678', $StrLength_2_5); should_fail('123456789', $StrLength_2_5); should_fail("\x{0436}" x 1, $StrLength_2_5); should_pass("\x{0436}" x 2, $StrLength_2_5); should_fail("\x{0436}" x 6, $StrLength_2_5); # # Overloaded objects are not allowed # { package Local::OL::Stringy; use overload q[""] => sub { ${$_[0]} }; sub new { my ($class, $str) = @_; bless(\$str, $class) } } my $abc_obj = Local::OL::Stringy->new('abc'); is("$abc_obj", "abc"); should_fail($abc_obj, $StrLength_2_5); # # But you can do this to create a type accepting a overloaded objects # that stringify to a string matching $StrLength_2_5. # use Types::Standard qw(Overload); my $Overloaded_StrLength_2_5 = Overload->of(q[""])->stringifies_to($StrLength_2_5); should_pass($abc_obj, $Overloaded_StrLength_2_5); # ... though that doesn't accept real strings. should_fail('abc', $Overloaded_StrLength_2_5); # # Union type constraint to the rescue! # my $Union_2_5 = $StrLength_2_5 | $Overloaded_StrLength_2_5; should_pass($abc_obj, $Union_2_5); should_pass('abc', $Union_2_5); done_testing; StrMatch.t000644001750001750 1625013601673061 16172 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( StrMatch ); isa_ok(StrMatch, 'Type::Tiny', 'StrMatch'); is(StrMatch->name, 'StrMatch', 'StrMatch has correct name'); is(StrMatch->display_name, 'StrMatch', 'StrMatch has correct display_name'); is(StrMatch->library, 'Types::Standard', 'StrMatch knows it is in the Types::Standard library'); ok(Types::Standard->has_type('StrMatch'), 'Types::Standard knows it has type StrMatch'); ok(!StrMatch->deprecated, 'StrMatch is not deprecated'); ok(!StrMatch->is_anon, 'StrMatch is not anonymous'); ok(StrMatch->can_be_inlined, 'StrMatch can be inlined'); is(exception { StrMatch->inline_check(q/$xyz/) }, undef, "Inlining StrMatch doesn't throw an exception"); ok(!StrMatch->has_coercion, "StrMatch doesn't have a coercion"); ok(StrMatch->is_parameterizable, "StrMatch is parameterizable"); my @tests = ( fail => 'undef' => undef, pass => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, pass => 'empty string' => '', pass => 'whitespace' => ' ', pass => 'line break' => "\n", pass => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', pass => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, StrMatch, ucfirst("$label should pass StrMatch")); } elsif ($expect eq 'fail') { should_fail($value, StrMatch, ucfirst("$label should fail StrMatch")); } else { fail("expected '$expect'?!"); } } # # This should be pretty obvious. # my $type1 = StrMatch[ qr/a[b]c/i ]; should_pass('abc', $type1); should_pass('ABC', $type1); should_pass('fooabcbar', $type1); should_pass('fooABCbar', $type1); should_fail('a[b]c', $type1); # # StrMatch only accepts true strings. # { package Local::OL::Stringy; use overload q[""] => sub { ${$_[0]} }; sub new { my ($class, $str) = @_; bless(\$str, $class) } } my $abc_obj = Local::OL::Stringy->new('abc'); is("$abc_obj", "abc"); should_fail($abc_obj, $type1); # # But you can do this to create a type accepting a overloaded objects # that stringify to a string matching $type1. # use Types::Standard qw(Overload); my $type2 = Overload->of(q[""])->stringifies_to($type1); should_pass($abc_obj, $type2); should_fail('abc', $type2); # ... though that doesn't accept real strings. # # Union type constraint to the rescue! # my $type3 = $type1 | $type2; should_pass($abc_obj, $type3); should_pass('abc', $type3); # # Okay, it was fun looking at overloaded objects, but let's look at # something else... # use Types::Standard qw( +Num Enum Tuple ); my $metric_distance = StrMatch[ # Strings must match this regexp qr/^(\S+) (\S+)$/, # Captures get checked against this constraint Tuple[ Num, Enum[qw/ mm cm m km /], ], ]; should_pass('1 km', $metric_distance); should_pass('-1.6 cm', $metric_distance); should_fail('xyz km', $metric_distance); should_fail('7 miles', $metric_distance); should_fail('7 km ', $metric_distance); # # You could implement it like this instead because a coderef # returning a boolean can be used like a type constraint. # $metric_distance = StrMatch[ # Strings must match this regexp qr/^(\S+) (\S+)$/, sub { my $captures = shift; return !!0 unless is_Num $captures->[0]; return !!1 if $captures->[1] eq 'mm'; return !!1 if $captures->[1] eq 'cm'; return !!1 if $captures->[1] eq 'm'; return !!1 if $captures->[1] eq 'km'; return !!0; } ]; should_pass('1 km', $metric_distance); should_pass('-1.6 cm', $metric_distance); should_fail('xyz km', $metric_distance); should_fail('7 miles', $metric_distance); should_fail('7 km ', $metric_distance); done_testing; StrictNum.t000644001750001750 1213713601673061 16375 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( StrictNum ); isa_ok(StrictNum, 'Type::Tiny', 'StrictNum'); is(StrictNum->name, 'StrictNum', 'StrictNum has correct name'); is(StrictNum->display_name, 'StrictNum', 'StrictNum has correct display_name'); is(StrictNum->library, 'Types::Standard', 'StrictNum knows it is in the Types::Standard library'); ok(Types::Standard->has_type('StrictNum'), 'Types::Standard knows it has type StrictNum'); ok(!StrictNum->deprecated, 'StrictNum is not deprecated'); ok(!StrictNum->is_anon, 'StrictNum is not anonymous'); ok(StrictNum->can_be_inlined, 'StrictNum can be inlined'); is(exception { StrictNum->inline_check(q/$xyz/) }, undef, "Inlining StrictNum doesn't throw an exception"); ok(!StrictNum->has_coercion, "StrictNum doesn't have a coercion"); ok(!StrictNum->is_parameterizable, "StrictNum isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, StrictNum, ucfirst("$label should pass StrictNum")); } elsif ($expect eq 'fail') { should_fail($value, StrictNum, ucfirst("$label should fail StrictNum")); } else { fail("expected '$expect'?!"); } } done_testing; StringLike.t000644001750001750 1217513601673061 16522 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::TypeTiny qw( StringLike ); isa_ok(StringLike, 'Type::Tiny', 'StringLike'); is(StringLike->name, 'StringLike', 'StringLike has correct name'); is(StringLike->display_name, 'StringLike', 'StringLike has correct display_name'); is(StringLike->library, 'Types::TypeTiny', 'StringLike knows it is in the Types::TypeTiny library'); ok(Types::TypeTiny->has_type('StringLike'), 'Types::TypeTiny knows it has type StringLike'); ok(!StringLike->deprecated, 'StringLike is not deprecated'); ok(!StringLike->is_anon, 'StringLike is not anonymous'); ok(StringLike->can_be_inlined, 'StringLike can be inlined'); is(exception { StringLike->inline_check(q/$xyz/) }, undef, "Inlining StringLike doesn't throw an exception"); ok(!StringLike->has_coercion, "StringLike doesn't have a coercion"); ok(!StringLike->is_parameterizable, "StringLike isn't parameterizable"); my @tests = ( fail => 'undef' => undef, pass => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, pass => 'empty string' => '', pass => 'whitespace' => ' ', pass => 'line break' => "\n", pass => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', pass => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), xxxx => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, pass => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, pass => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, StringLike, ucfirst("$label should pass StringLike")); } elsif ($expect eq 'fail') { should_fail($value, StringLike, ucfirst("$label should fail StringLike")); } else { fail("expected '$expect'?!"); } } done_testing; StrongPassword.t000644001750001750 1243113601673061 17441 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::String qw( StrongPassword ); isa_ok(StrongPassword, 'Type::Tiny', 'StrongPassword'); is(StrongPassword->name, 'StrongPassword', 'StrongPassword has correct name'); is(StrongPassword->display_name, 'StrongPassword', 'StrongPassword has correct display_name'); is(StrongPassword->library, 'Types::Common::String', 'StrongPassword knows it is in the Types::Common::String library'); ok(Types::Common::String->has_type('StrongPassword'), 'Types::Common::String knows it has type StrongPassword'); ok(!StrongPassword->deprecated, 'StrongPassword is not deprecated'); ok(!StrongPassword->is_anon, 'StrongPassword is not anonymous'); ok(StrongPassword->can_be_inlined, 'StrongPassword can be inlined'); is(exception { StrongPassword->inline_check(q/$xyz/) }, undef, "Inlining StrongPassword doesn't throw an exception"); ok(!StrongPassword->has_coercion, "StrongPassword doesn't have a coercion"); ok(!StrongPassword->is_parameterizable, "StrongPassword isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', pass => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, StrongPassword, ucfirst("$label should pass StrongPassword")); } elsif ($expect eq 'fail') { should_fail($value, StrongPassword, ucfirst("$label should fail StrongPassword")); } else { fail("expected '$expect'?!"); } } done_testing; Tied.t000644001750001750 1450113601673061 15327 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Tied ); isa_ok(Tied, 'Type::Tiny', 'Tied'); is(Tied->name, 'Tied', 'Tied has correct name'); is(Tied->display_name, 'Tied', 'Tied has correct display_name'); is(Tied->library, 'Types::Standard', 'Tied knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Tied'), 'Types::Standard knows it has type Tied'); ok(!Tied->deprecated, 'Tied is not deprecated'); ok(!Tied->is_anon, 'Tied is not anonymous'); ok(Tied->can_be_inlined, 'Tied can be inlined'); is(exception { Tied->inline_check(q/$xyz/) }, undef, "Inlining Tied doesn't throw an exception"); ok(!Tied->has_coercion, "Tied doesn't have a coercion"); ok(Tied->is_parameterizable, "Tied is parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Tied, ucfirst("$label should pass Tied")); } elsif ($expect eq 'fail') { should_fail($value, Tied, ucfirst("$label should fail Tied")); } else { fail("expected '$expect'?!"); } } # # Test with tied scalar # require Tie::Scalar; tie my $var, 'Tie::StdScalar'; should_pass( \$var, Tied ); should_pass( \$var, Tied['Tie::StdScalar'] ); should_pass( \$var, Tied['Tie::Scalar'] ); should_fail( \$var, Tied['IO::File'] ); # Tie::StdScalar inherits # # Blessed scalarrefs can still be tied # bless(\$var, 'Bleh'); should_pass( \$var, Tied['Tie::Scalar'] ); should_fail( \$var, Tied['Bleh'] ); # # Tied is for blessed references only! # Couldn't reliably test non-reference even if we wanted to. # ok(tied($var), '$var is tied'); should_fail( $var, Tied ); # # Test with tied array # require Tie::Array; tie my @arr, 'Tie::StdArray'; should_pass( \@arr, Tied ); should_pass( \@arr, Tied['Tie::StdArray'] ); should_pass( \@arr, Tied['Tie::Array'] ); should_fail( \@arr, Tied['IO::File'] ); # Tie::StdArray inherits # # Blessed arrayrefs can still be tied # bless(\@arr, 'Bleh'); should_pass( \@arr, Tied['Tie::Array'] ); should_fail( \@arr, Tied['Bleh'] ); # # Test with tied hash # require Tie::Hash; @Tie::StdHash::ISA = qw(Tie::Hash); tie my %h, 'Tie::StdHash'; should_pass( \%h, Tied ); should_pass( \%h, Tied['Tie::StdHash'] ); should_pass( \%h, Tied['Tie::Hash'] ); should_fail( \%h, Tied['IO::File'] ); # Tie::StdHash inherits # # Blessed hashrefs can still be tied # bless(\%h, 'Bleh'); should_pass( \%h, Tied['Tie::Hash'] ); should_fail( \%h, Tied['Bleh'] ); done_testing; Tuple.t000644001750001750 2430413601673061 15535 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Tuple ); isa_ok(Tuple, 'Type::Tiny', 'Tuple'); is(Tuple->name, 'Tuple', 'Tuple has correct name'); is(Tuple->display_name, 'Tuple', 'Tuple has correct display_name'); is(Tuple->library, 'Types::Standard', 'Tuple knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Tuple'), 'Types::Standard knows it has type Tuple'); ok(!Tuple->deprecated, 'Tuple is not deprecated'); ok(!Tuple->is_anon, 'Tuple is not anonymous'); ok(Tuple->can_be_inlined, 'Tuple can be inlined'); is(exception { Tuple->inline_check(q/$xyz/) }, undef, "Inlining Tuple doesn't throw an exception"); ok(!Tuple->has_coercion, "Tuple doesn't have a coercion"); ok(Tuple->is_parameterizable, "Tuple is parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), pass => 'empty arrayref' => [], pass => 'arrayref with one zero' => [0], pass => 'arrayref of integers' => [1..10], pass => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Tuple, ucfirst("$label should pass Tuple")); } elsif ($expect eq 'fail') { should_fail($value, Tuple, ucfirst("$label should fail Tuple")); } else { fail("expected '$expect'?!"); } } # # A basic tuple. # my $type1 = Tuple[ Types::Standard::Int, Types::Standard::ArrayRef, Types::Standard::Undef, ]; should_pass( [42,[1..4],undef], $type1 ); should_fail( [{},[1..4],undef], $type1 ); # first slot fails should_fail( [42,{ },undef], $type1 ); # second slot fails should_fail( [42,[1..4],{ } ], $type1 ); # third slot fails should_fail( [42,[1..4],undef,1], $type1 ); # too many slots should_fail( [42,[1..4]], $type1 ); # not enough slots should_fail( [], $type1 ); # not enough slots (empty arrayref) should_fail( 42, $type1 ); # not even an arrayref should_fail( bless([42,[1..10],undef], 'Foo'), $type1 ); # blessed # # Some Optional slots. # use Types::Standard qw( Optional ); my $type2 = Tuple[ Types::Standard::Int, Types::Standard::ArrayRef, Optional[ Types::Standard::HashRef ], Optional[ Types::Standard::ScalarRef ], ]; should_pass([42,[],{},\0], $type2); should_pass([42,[],{}], $type2); # missing optional fourth slot should_pass([42,[]], $type2); # missing optional third slot should_fail([42], $type2); # missing required second slot should_fail([], $type2); # missing required first slot # can't put undef in slot 3 as a way to supply a value for slot 4 should_fail([42,[],undef,\0], $type2); # # The difference between Optional and Maybe # use Types::Standard qw( Maybe ); my $type3 = Tuple[ Types::Standard::Int, Types::Standard::ArrayRef, Maybe[ Types::Standard::HashRef ], Maybe[ Types::Standard::ScalarRef ], ]; should_fail([42,[],{}], $type3); # missing fourth slot fails! should_pass([42,[],{},undef], $type3); # ... but undef is okay # # Simple slurpy example # use Types::Standard qw(slurpy); my $type4 = Tuple[ Types::Standard::RegexpRef, slurpy Types::Standard::ArrayRef[ Types::Standard::Int, ], ]; should_pass([qr//], $type4); should_pass([qr//,1..4], $type4); should_fail([qr//,1..4,qr//], $type4); # note that the slurpy slurps stuff into an arrayref to check # so it will fail when there's an actual arrayref there. should_fail([qr//,[1..4]], $type4); # # Optional + slurpy example # my $type5 = Tuple[ Types::Standard::RegexpRef, Optional[ Types::Standard::HashRef ], slurpy Types::Standard::ArrayRef[ Types::Standard::Int, ], ]; should_pass([qr//], $type5); should_pass([qr//,{}], $type5); should_pass([qr//,{},1..4], $type5); # can't omit Optional element but still provide slurpy should_fail([qr//,1..4], $type5); # # Slurpy Tuple inside a Tuple # my $type6 = Tuple[ Types::Standard::RegexpRef, slurpy Types::Standard::Tuple[ Types::Standard::Int, Types::Standard::Int, ], ]; should_pass([qr//], $type6); should_fail([qr//,1], $type6); should_pass([qr//,1,2], $type6); # pass because two ints should_fail([qr//,1,2,3], $type6); should_fail([qr//,1,2,3,4], $type6); should_fail([qr//,1,2,3,4,5], $type6); # # Optional + slurpy Tuple inside a Tuple # my $type7 = Tuple[ Types::Standard::RegexpRef, Optional[ Types::Standard::RegexpRef ], slurpy Types::Standard::Tuple[ Types::Standard::Int, Types::Standard::Int, ], ]; should_pass([qr//], $type7); should_pass([qr//,qr//], $type7); should_fail([qr//,qr//,1], $type7); should_pass([qr//,qr//,1,2], $type7); # pass because two ints after optional should_fail([qr//,1,2], $type7); # fail because two ints with no optional should_fail([qr//,qr//,1,2,3], $type7); should_fail([qr//,qr//,1,2,3,4], $type7); should_fail([qr//,qr//,1,2,3,4,5], $type7); # # Simple slurpy hashref example # my $type8 = Tuple[ Types::Standard::RegexpRef, slurpy Types::Standard::HashRef[ Types::Standard::Int, ], ]; should_pass([qr//], $type8); should_pass([qr//,foo=>1,bar=>2], $type8); should_fail([qr//,foo=>1,bar=>2,qr//], $type8); # note that the slurpy slurps stuff into an hashref to check # so it will fail when there's an actual hashref there. should_fail([qr//,[foo=>1,bar=>2]], $type8); # # Optional + slurpy hashref example # my $type9 = Tuple[ Types::Standard::RegexpRef, Optional[ Types::Standard::ScalarRef ], slurpy Types::Standard::HashRef[ Types::Standard::Int, ], ]; should_pass([qr//], $type9); should_pass([qr//,\1], $type9); should_pass([qr//,\1,foo=>1,bar=>2], $type9); # can't omit Optional element but still provide slurpy should_fail([qr//,foo=>1,bar=>2], $type9); # # Deep coercions # my $Rounded = Types::Standard::Int->plus_coercions( Types::Standard::Num, sub{ int($_) }, ); my $type10 = Tuple[ $Rounded, Types::Standard::ArrayRef[$Rounded], Optional[$Rounded], slurpy Types::Standard::HashRef[$Rounded], ]; my $coerced = $type10->coerce([ 3.1, [ 1.1, 1.2, 1.3 ], 4.2, foo => 5.1, bar => 6.1, ]); subtest 'coercion happened as expected' => sub { is($coerced->[0], 3); is_deeply($coerced->[1], [1,1,1]); is($coerced->[2], 4); is_deeply({@$coerced[3..6]}, {foo=>5,bar=>6}); }; # One thing to note is that coercions succeed as a whole or fail as a whole. # The tuple had to coerce the first element to an integer, the second to an # arrayref of integers, the third (if it existed) to an integer, and whatever # was left, it slurped into a temp hashef, coerced that to a hashref of # integers, and then flattened that back into the tuple it was returning. # If any single part of it had ended up not conforming to the target type, # then the original tuple would have been returned with no coercions done # at all! done_testing; TypeTiny.t000644001750001750 1520313601673061 16227 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::TypeTiny qw( TypeTiny ); isa_ok(TypeTiny, 'Type::Tiny', 'TypeTiny'); is(TypeTiny->name, 'TypeTiny', 'TypeTiny has correct name'); is(TypeTiny->display_name, 'TypeTiny', 'TypeTiny has correct display_name'); is(TypeTiny->library, 'Types::TypeTiny', 'TypeTiny knows it is in the Types::TypeTiny library'); ok(Types::TypeTiny->has_type('TypeTiny'), 'Types::TypeTiny knows it has type TypeTiny'); ok(!TypeTiny->deprecated, 'TypeTiny is not deprecated'); ok(!TypeTiny->is_anon, 'TypeTiny is not anonymous'); ok(TypeTiny->can_be_inlined, 'TypeTiny can be inlined'); is(exception { TypeTiny->inline_check(q/$xyz/) }, undef, "Inlining TypeTiny doesn't throw an exception"); ok(TypeTiny->has_coercion, "TypeTiny has a coercion"); ok(!TypeTiny->is_parameterizable, "TypeTiny isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, TypeTiny, ucfirst("$label should pass TypeTiny")); } elsif ($expect eq 'fail') { should_fail($value, TypeTiny, ucfirst("$label should fail TypeTiny")); } else { fail("expected '$expect'?!"); } } should_pass(TypeTiny, TypeTiny); # dogfooding subtest "Can coerce from coderef to TypeTiny" => sub { my $Arrayref = TypeTiny->coerce( sub { ref($_) eq 'ARRAY' } ); should_pass( $Arrayref, TypeTiny ); should_pass( [], $Arrayref ); should_fail( {}, $Arrayref ); }; subtest "Can coerce from Type::Nano to TypeTiny" => sub { my $Arrayref = TypeTiny->coerce( Local::Dummy1::ArrayRef() ); should_pass( $Arrayref, TypeTiny ); should_pass( [], $Arrayref ); should_fail( {}, $Arrayref ); } if eval q{ package Local::Dummy1; use Type::Nano qw(ArrayRef); 1 }; subtest "Can coerce from MooseX::Types to TypeTiny" => sub { my $Arrayref = TypeTiny->coerce( Local::Dummy2::ArrayRef() ); should_pass( $Arrayref, TypeTiny ); should_pass( [], $Arrayref ); should_fail( {}, $Arrayref ); ok($Arrayref->is_parameterizable); ok($Arrayref->can_be_inlined); } if eval q{ package Local::Dummy2; use MooseX::Types::Moose qw(ArrayRef); 1 }; subtest "Can coerce from MouseX::Types to TypeTiny" => sub { my $Arrayref = TypeTiny->coerce( Local::Dummy3::ArrayRef() ); should_pass( $Arrayref, TypeTiny ); should_pass( [], $Arrayref ); should_fail( {}, $Arrayref ); ok($Arrayref->is_parameterizable); } if eval q{ package Local::Dummy3; use MouseX::Types::Mouse qw(ArrayRef); 1 }; subtest "Can coerce from Specio to TypeTiny" => sub { my $Arrayref = TypeTiny->coerce( Local::Dummy4::t('ArrayRef') ); should_pass( $Arrayref, TypeTiny ); should_pass( [], $Arrayref ); should_fail( {}, $Arrayref ); ok($Arrayref->can_be_inlined); } if eval q{ package Local::Dummy4; use Specio::Library::Builtins; 1 }; done_testing; Undef.t000644001750001750 1206413601673061 15505 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Undef ); isa_ok(Undef, 'Type::Tiny', 'Undef'); is(Undef->name, 'Undef', 'Undef has correct name'); is(Undef->display_name, 'Undef', 'Undef has correct display_name'); is(Undef->library, 'Types::Standard', 'Undef knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Undef'), 'Types::Standard knows it has type Undef'); ok(!Undef->deprecated, 'Undef is not deprecated'); ok(!Undef->is_anon, 'Undef is not anonymous'); ok(Undef->can_be_inlined, 'Undef can be inlined'); is(exception { Undef->inline_check(q/$xyz/) }, undef, "Inlining Undef doesn't throw an exception"); ok(!Undef->has_coercion, "Undef doesn't have a coercion"); ok(!Undef->is_parameterizable, "Undef isn't parameterizable"); my @tests = ( pass => 'undef' => undef, fail => 'false' => !!0, fail => 'true' => !!1, fail => 'zero' => 0, fail => 'one' => 1, fail => 'negative one' => -1, fail => 'non integer' => 3.1416, fail => 'empty string' => '', fail => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Undef, ucfirst("$label should pass Undef")); } elsif ($expect eq 'fail') { should_fail($value, Undef, ucfirst("$label should fail Undef")); } else { fail("expected '$expect'?!"); } } is(~Undef, Types::Standard::Defined, 'The complement of Undef is Defined'); done_testing; UpperCaseSimpleStr.t000644001750001750 1524113601673061 20176 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::String qw( UpperCaseSimpleStr ); isa_ok(UpperCaseSimpleStr, 'Type::Tiny', 'UpperCaseSimpleStr'); is(UpperCaseSimpleStr->name, 'UpperCaseSimpleStr', 'UpperCaseSimpleStr has correct name'); is(UpperCaseSimpleStr->display_name, 'UpperCaseSimpleStr', 'UpperCaseSimpleStr has correct display_name'); is(UpperCaseSimpleStr->library, 'Types::Common::String', 'UpperCaseSimpleStr knows it is in the Types::Common::String library'); ok(Types::Common::String->has_type('UpperCaseSimpleStr'), 'Types::Common::String knows it has type UpperCaseSimpleStr'); ok(!UpperCaseSimpleStr->deprecated, 'UpperCaseSimpleStr is not deprecated'); ok(!UpperCaseSimpleStr->is_anon, 'UpperCaseSimpleStr is not anonymous'); ok(UpperCaseSimpleStr->can_be_inlined, 'UpperCaseSimpleStr can be inlined'); is(exception { UpperCaseSimpleStr->inline_check(q/$xyz/) }, undef, "Inlining UpperCaseSimpleStr doesn't throw an exception"); ok(UpperCaseSimpleStr->has_coercion, "UpperCaseSimpleStr has a coercion"); ok(!UpperCaseSimpleStr->is_parameterizable, "UpperCaseSimpleStr isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, fail => 'empty string' => '', pass => 'whitespace' => ' ', fail => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, UpperCaseSimpleStr, ucfirst("$label should pass UpperCaseSimpleStr")); } elsif ($expect eq 'fail') { should_fail($value, UpperCaseSimpleStr, ucfirst("$label should fail UpperCaseSimpleStr")); } else { fail("expected '$expect'?!"); } } # Cyrillic Small Letter Zhe should_fail("\x{0436}", UpperCaseSimpleStr); # Cyrillic Capital Letter Zhe should_pass("\x{0416}", UpperCaseSimpleStr); # # SimpleStr is limited to 255 characters # should_pass("A" x 255, UpperCaseSimpleStr); should_fail("A" x 256, UpperCaseSimpleStr); # # Length counts are characters, not bytes, # so test with a multibyte character. # should_pass("\x{0416}" x 255, UpperCaseSimpleStr); should_fail("\x{0416}" x 256, UpperCaseSimpleStr); # # These examples are probably obvious. # should_pass('ABCDEF', UpperCaseSimpleStr); should_pass('ABC123', UpperCaseSimpleStr); should_fail('abc123', UpperCaseSimpleStr); should_fail('abcdef', UpperCaseSimpleStr); # # A string with only non-letter characters passes. # should_pass('123456', UpperCaseSimpleStr); should_pass(' ', UpperCaseSimpleStr); # # But the empty string fails. # (Which is weird, but consistent with MooseX::Types::Common::String.) # should_fail('', UpperCaseSimpleStr); # # Can coerce from lowercase strings. # is(UpperCaseSimpleStr->coerce('abc123'), 'ABC123', 'coercion success'); # # Won't even attempt to coerce non-strings. # use Scalar::Util qw( refaddr ); my $arr = []; my $coerced = UpperCaseSimpleStr->coerce($arr); is(refaddr($coerced), refaddr($arr), 'does not coerce non-strings'); done_testing; UpperCaseStr.t000644001750001750 1415013601673061 17022 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Common::String qw( UpperCaseStr ); isa_ok(UpperCaseStr, 'Type::Tiny', 'UpperCaseStr'); is(UpperCaseStr->name, 'UpperCaseStr', 'UpperCaseStr has correct name'); is(UpperCaseStr->display_name, 'UpperCaseStr', 'UpperCaseStr has correct display_name'); is(UpperCaseStr->library, 'Types::Common::String', 'UpperCaseStr knows it is in the Types::Common::String library'); ok(Types::Common::String->has_type('UpperCaseStr'), 'Types::Common::String knows it has type UpperCaseStr'); ok(!UpperCaseStr->deprecated, 'UpperCaseStr is not deprecated'); ok(!UpperCaseStr->is_anon, 'UpperCaseStr is not anonymous'); ok(UpperCaseStr->can_be_inlined, 'UpperCaseStr can be inlined'); is(exception { UpperCaseStr->inline_check(q/$xyz/) }, undef, "Inlining UpperCaseStr doesn't throw an exception"); ok(UpperCaseStr->has_coercion, "UpperCaseStr has a coercion"); ok(!UpperCaseStr->is_parameterizable, "UpperCaseStr isn't parameterizable"); my @tests = ( fail => 'undef' => undef, fail => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, fail => 'empty string' => '', pass => 'whitespace' => ' ', pass => 'line break' => "\n", fail => 'random string' => 'abc123', fail => 'loaded package name' => 'Type::Tiny', fail => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), fail => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, UpperCaseStr, ucfirst("$label should pass UpperCaseStr")); } elsif ($expect eq 'fail') { should_fail($value, UpperCaseStr, ucfirst("$label should fail UpperCaseStr")); } else { fail("expected '$expect'?!"); } } # Cyrillic Small Letter Zhe should_fail("\x{0436}", UpperCaseStr); # Cyrillic Capital Letter Zhe should_pass("\x{0416}", UpperCaseStr); # # These examples are probably obvious. # should_pass('ABCDEF', UpperCaseStr); should_pass('ABC123', UpperCaseStr); should_fail('abc123', UpperCaseStr); should_fail('abcdef', UpperCaseStr); # # A string with only non-letter characters passes. # should_pass('123456', UpperCaseStr); should_pass(' ', UpperCaseStr); # # But the empty string fails. # (Which is weird, but consistent with MooseX::Types::Common::String.) # should_fail('', UpperCaseStr); # # Can coerce from lowercase strings. # is(UpperCaseStr->coerce('abc123'), 'ABC123', 'coercion success'); # # Won't even attempt to coerce non-strings. # use Scalar::Util qw( refaddr ); my $arr = []; my $coerced = UpperCaseStr->coerce($arr); is(refaddr($coerced), refaddr($arr), 'does not coerce non-strings'); done_testing; Value.t000644001750001750 1174713601673061 15527 0ustar00taitai000000000000Type-Tiny-1.008001/t/21-types=pod =encoding utf-8 =head1 PURPOSE Basic tests for B from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Value ); isa_ok(Value, 'Type::Tiny', 'Value'); is(Value->name, 'Value', 'Value has correct name'); is(Value->display_name, 'Value', 'Value has correct display_name'); is(Value->library, 'Types::Standard', 'Value knows it is in the Types::Standard library'); ok(Types::Standard->has_type('Value'), 'Types::Standard knows it has type Value'); ok(!Value->deprecated, 'Value is not deprecated'); ok(!Value->is_anon, 'Value is not anonymous'); ok(Value->can_be_inlined, 'Value can be inlined'); is(exception { Value->inline_check(q/$xyz/) }, undef, "Inlining Value doesn't throw an exception"); ok(!Value->has_coercion, "Value doesn't have a coercion"); ok(!Value->is_parameterizable, "Value isn't parameterizable"); my @tests = ( fail => 'undef' => undef, pass => 'false' => !!0, pass => 'true' => !!1, pass => 'zero' => 0, pass => 'one' => 1, pass => 'negative one' => -1, pass => 'non integer' => 3.1416, pass => 'empty string' => '', pass => 'whitespace' => ' ', pass => 'line break' => "\n", pass => 'random string' => 'abc123', pass => 'loaded package name' => 'Type::Tiny', pass => 'unloaded package name' => 'This::Has::Probably::Not::Been::Loaded', fail => 'a reference to undef' => do { my $x = undef; \$x }, fail => 'a reference to false' => do { my $x = !!0; \$x }, fail => 'a reference to true' => do { my $x = !!1; \$x }, fail => 'a reference to zero' => do { my $x = 0; \$x }, fail => 'a reference to one' => do { my $x = 1; \$x }, fail => 'a reference to empty string' => do { my $x = ''; \$x }, fail => 'a reference to random string' => do { my $x = 'abc123'; \$x }, fail => 'blessed scalarref' => bless(do { my $x = undef; \$x }, 'SomePkg'), fail => 'empty arrayref' => [], fail => 'arrayref with one zero' => [0], fail => 'arrayref of integers' => [1..10], fail => 'arrayref of numbers' => [1..10, 3.1416], fail => 'blessed arrayref' => bless([], 'SomePkg'), fail => 'empty hashref' => {}, fail => 'hashref' => { foo => 1 }, fail => 'blessed hashref' => bless({}, 'SomePkg'), fail => 'coderef' => sub { 1 }, fail => 'blessed coderef' => bless(sub { 1 }, 'SomePkg'), pass => 'glob' => do { no warnings 'once'; *SOMETHING }, fail => 'globref' => do { no warnings 'once'; my $x = *SOMETHING; \$x }, fail => 'blessed globref' => bless(do { no warnings 'once'; my $x = *SOMETHING; \$x }, 'SomePkg'), fail => 'regexp' => qr/./, fail => 'blessed regexp' => bless(qr/./, 'SomePkg'), fail => 'filehandle' => do { open my $x, '<', $0 or die; $x }, fail => 'filehandle object' => do { require IO::File; 'IO::File'->new($0, 'r') }, fail => 'ref to scalarref' => do { my $x = undef; my $y = \$x; \$y }, fail => 'ref to arrayref' => do { my $x = []; \$x }, fail => 'ref to hashref' => do { my $x = {}; \$x }, fail => 'ref to coderef' => do { my $x = sub { 1 }; \$x }, fail => 'ref to blessed hashref' => do { my $x = bless({}, 'SomePkg'); \$x }, fail => 'object stringifying to ""' => do { package Local::OL::StringEmpty; use overload q[""] => sub { "" }; bless [] }, fail => 'object stringifying to "1"' => do { package Local::OL::StringOne; use overload q[""] => sub { "1" }; bless [] }, fail => 'object numifying to 0' => do { package Local::OL::NumZero; use overload q[0+] => sub { 0 }; bless [] }, fail => 'object numifying to 1' => do { package Local::OL::NumOne; use overload q[0+] => sub { 1 }; bless [] }, fail => 'object overloading arrayref' => do { package Local::OL::Array; use overload q[@{}] => sub { $_[0]{array} }; bless {array=>[]} }, fail => 'object overloading hashref' => do { package Local::OL::Hash; use overload q[%{}] => sub { $_[0][0] }; bless [{}] }, fail => 'object overloading coderef' => do { package Local::OL::Code; use overload q[&{}] => sub { $_[0][0] }; bless [sub { 1 }] }, #TESTS ); while (@tests) { my ($expect, $label, $value) = splice(@tests, 0 , 3); if ($expect eq 'xxxx') { note("UNDEFINED OUTCOME: $label"); } elsif ($expect eq 'pass') { should_pass($value, Value, ucfirst("$label should pass Value")); } elsif ($expect eq 'fail') { should_fail($value, Value, ucfirst("$label should fail Value")); } else { fail("expected '$expect'?!"); } } done_testing; 73f51e2d.pl000644001750001750 116313601673061 16747 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Helper file for C<< 73f51e2d.t >>. =head1 AUTHOR Graham Knop Ehaarg@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Graham Knop. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use threads; use strict; use warnings; use Type::Tiny; my $int = Type::Tiny->new( name => "Integer", constraint => sub { /^(?:-?[1-9][0-9]*|0)$|/ }, message => sub { "$_ isn't an integer" }, ); threads->create(sub { my $type = $int; 1; })->join; 73f51e2d.t000644001750001750 122213601673061 16573 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Possible issue causing segfaults on threaded Perl 5.18.x. =head1 AUTHOR Graham Knop Ehaarg@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Graham Knop. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Config; BEGIN { plan skip_all => "ithreads" unless $Config{useithreads}; }; (my $script = __FILE__) =~ s/t\z/pl/; for (1..100) { my $out = system $^X, (map {; '-I', $_ } @INC), $script; is($out, 0); } done_testing; gh1.t000644001750001750 154713601673061 16124 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Test that subtypes of Type::Tiny::Class work. =head1 SEE ALSO L, L. =head1 AUTHOR Richard Simões Ersimoes@cpan.orgE. (Minor changes by Toby Inkster Etobyink@cpan.orgE.) =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Richard Simões. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::TypeTiny; use Type::Utils; use Math::BigFloat; my $pc = declare as class_type({ class => 'Math::BigFloat' }), where { 1 }; my $value = Math::BigFloat->new(0.5); ok $pc->($value); should_pass($value, $pc); should_fail(0.5, $pc); done_testing; gh14.t000644001750001750 266613601673061 16213 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Test for non-inlined coercions in Moo. The issue that prompted this test was actually invalid, caused by a typo in the bug reporter's code. But I wrote the test case, so I might as well include it. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::Requires { Moo => '1.006' }; { package FinancialTypes; use Type::Library -base; use Type::Utils -all; BEGIN { extends "Types::Standard" }; declare 'BankAccountNo', as Str, where { /^\d{26}$/ or /^[A-Z]{2}\d{18,26}$/ or /^\d{8}-\d+(-\d+)+$/ }, message { "Bad account: $_"}; coerce 'BankAccountNo', from Str, via { $_ =~ s{\s+}{}g; $_; }; } { package BankAccount; use Moo; has account_number => ( is => 'ro', required => !!1, isa => FinancialTypes::BankAccountNo(), coerce => FinancialTypes::BankAccountNo()->coercion, ); } my $x; my $e = exception { $x = BankAccount::->new( account_number => "10 2030 4050 1111 2222 3333 4444" ); }; is($e, undef); is($x->account_number, "10203040501111222233334444"); done_testing(); rt102748.t000644001750001750 164013601673061 16552 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Tests inheriting from a MooseX::Types library that uses L and L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; { package Local::XYZ1; use Test::Requires 'MooseX::Types'; } { package Local::XYZ2; use Test::Requires 'MooseX::Types::DBIx::Class'; } my $e = exception { package MyApp::Types; use namespace::autoclean; use Type::Library -base; use Type::Utils 'extends'; extends 'MooseX::Types::DBIx::Class'; }; is($e, undef); done_testing; rt104154.t000644001750001750 412113601673061 16540 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Tests for deep coercion. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Type::Tiny; use Test::More; my $type_without = "Type::Tiny"->new( name => "HasParam_without", message => sub { "$_ ain't got a number" }, constraint_generator => sub { sub { 0 } }, # Reject everything deep_explanation => sub { ["love to contradict"] }, ); my $type_with = "Type::Tiny"->new( constraint => sub { 1 }, # Un-parameterized accepts al name => "HasParam_with", message => sub { "$_ ain't got a number" }, constraint_generator => sub { sub { 0 } }, # Reject everything deep_explanation => sub { ["love to contradict"] }, ); my $type_parent = "Type::Tiny"->new( parent => $type_without, name => "HasParam_parent", message => sub { "$_ ain't got a number" }, constraint_generator => sub { sub { 0 } }, # Reject everything deep_explanation => sub { ["love to contradict"] }, ); my $s = 'a string'; my $param_with = $type_with->parameterize('an ignored parameter'); my $param_parent = $type_parent->parameterize('an ignored parameter'); my $param_without = $type_without->parameterize('an ignored parameter'); my $explain_with=join("\n ",@{$param_with->validate_explain($s,'$s')}); my $explain_parent=join("\n ",@{$param_parent->validate_explain($s,'$s')}); my $explain_without=join("\n ",@{$param_without->validate_explain($s,'$s')}); #diag "With a plain constraint:\n $explain_with\n"; #diag "With a parent constraint:\n $explain_parent\n"; #diag "Without a plain constraint:\n $explain_without\n"; $explain_with =~ s/(HasParam)_\w+/$1/g; $explain_parent =~ s/(HasParam)_\w+/$1/g; $explain_without =~ s/(HasParam)_\w+/$1/g; ok $explain_with eq $explain_without; ok $explain_parent eq $explain_without; done_testing; rt121763.t000644001750001750 155213601673061 16552 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Test to make sure C keeps a reference to all the types that get compiled, to avoid them going away before exceptions can be thrown for them. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Types::Standard -types; use Type::Params qw(compile); my $x; my $sub; my $check; my $e = exception { $sub = sub { $check = compile(Dict[key => Int]); $check->(@_); }; $sub->({key => 'yeah'}); }; is($e->type->display_name, 'Dict[key=>Int]'); done_testing; rt125132.t000644001750001750 304613601673061 16544 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Test inlined Int type check clobbering C<< $1 >>. =head1 SEE ALSO L. =head1 AUTHOR Marc Ballarin . Some modifications by Toby Inkster . =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2018-2019 by Marc Ballarin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Type::Params qw(compile); use Types::Standard qw(Str Int); { my $check; sub check_int_tt_compile { $check ||= compile(Int); my ($int) = $check->(@_); is($int, 123, 'check_int_tt_compile'); } } { my $check; sub check_str_tt { $check ||= compile(Str); my ($int) = $check->(@_); is($int, 123, 'check_str_tt'); } } { sub check_int_manual { my ($int) = @_; die "no Int!" unless $int =~ /^\d+$/; is($int, 123, 'check_int_manual'); } } { sub check_int_tt_no_compile { my ($int) = @_; Int->assert_valid($int); is($int, 123, 'check_int_tt_no_compile'); } } my $string = 'a123'; subtest 'using temporary variable' => sub { if ($string =~ /a(\d+)/) { my $matched = $1; check_int_tt_compile($matched); check_int_manual($matched); check_str_tt($matched); check_int_tt_no_compile($matched); } }; subtest 'using direct $1' => sub { if ($string =~ /a(\d+)/) { check_int_tt_compile($1); check_int_manual($1); check_str_tt($1); check_int_tt_no_compile($1); } }; done_testing; rt125765.t000644001750001750 225113601673061 16555 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Check weird error doesn't happen with deep explain. =head1 SEE ALSO L. =head1 AUTHOR KB Jørgensen . Some modifications by Toby Inkster . =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2018-2019 by KB Jørgensen. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Types::Standard qw(Dict Tuple Any); my @warnings; $SIG{__WARN__} = sub { push @warnings, $_[0]; }; my $type = Dict->of(foo => Any); my $e = exception { $type->assert_valid({ foo => 1, asd => 1 }); }; like($e, qr/Reference .+ did not pass type constraint/, "got correct error for Dict"); is_deeply(\@warnings, [], 'no warnings') or diag explain \@warnings; @warnings = (); $type = Tuple->of(Any); $e = exception { $type->assert_valid([1, 2]); }; like($e, qr/Reference .+ did not pass type constraint/, "got correct error for Tuple"); is_deeply(\@warnings, [], 'no warnings') or diag explain \@warnings; done_testing; rt129729.t000644001750001750 145213601673061 16563 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Test that Enum types containing hyphens work. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::TypeTiny; use Types::Standard qw[ Bool Enum ]; my $x = Bool | Enum [ 'start-end', 'end' ]; should_pass 1, $x; should_pass 0, $x; should_fail 2, $x; should_pass 'end', $x; should_fail 'bend', $x; should_fail 'start', $x; should_fail 'start-', $x; should_fail '-end', $x; should_pass 'start-end', $x; done_testing; rt130823.t000644001750001750 114513601673061 16545 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Check for memory cycles. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster . =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Requires 'Test::Memory::Cycle'; use Test::Memory::Cycle; use Types::Standard qw(Bool); memory_cycle_ok(Bool, 'Bool has no cycles'); done_testing; rt85911.t000644001750001750 221413601673061 16472 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Test L with deep Dict coercion. =head1 SEE ALSO L. =head1 AUTHOR Diab Jerius Edjerius@cpan.orgE. (Minor changes by Toby Inkster Etobyink@cpan.orgE.) =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Diab Jerius. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; BEGIN { package MyTypes; use Type::Library -base, -declare => qw[ StrList ]; use Type::Utils; use Types::Standard qw[ ArrayRef Str ]; declare StrList, as ArrayRef[Str]; coerce StrList, from Str, via { [$_] }; } use Type::Params qw[ compile ]; use Types::Standard qw[ Dict slurpy Optional ]; sub foo { my $check = compile( slurpy Dict [ foo => MyTypes::StrList ] ); return [ $check->( @_ ) ]; } sub bar { my $check = compile( MyTypes::StrList ); return [ $check->( @_ ) ]; } is_deeply( bar( 'b' ), [ ["b"] ], ); is_deeply( foo( foo => 'a' ), [ { foo=>["a"] } ], ); done_testing; rt86004.t000644001750001750 512713601673061 16472 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Test L with more complex Dict coercion. =head1 SEE ALSO L. =head1 AUTHOR Diab Jerius Edjerius@cpan.orgE. (Minor changes by Toby Inkster Etobyink@cpan.orgE.) =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Diab Jerius. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; BEGIN { package Types; use Type::Library -base, -declare => qw[ StrList ]; use Type::Utils; use Types::Standard qw[ ArrayRef Str ]; declare StrList, as ArrayRef [Str]; coerce StrList, from Str, q { [$_] }; }; use Test::More; use Test::Fatal; use Type::Params qw[ validate compile ]; use Types::Standard -all; sub a { validate( \@_, slurpy Dict [ connect => Optional [Bool], encoding => Optional [Str], hg => Optional [Types::StrList], ] ); } sub b { validate( \@_, slurpy Dict [ connect => Optional [Bool], hg => Optional [Types::StrList], ] ); } sub c { validate( \@_, slurpy Dict [ connect => Optional [Bool], encoding => Optional [Str], hg2 => Optional [Types::StrList->no_coercions->plus_coercions(Types::Standard::Str, sub {[$_]})], ] ); } my $expect = { connect => 1, hg => ['a'], }; my $expect2 = { connect => 1, hg2 => ['a'], }; # 1 { my ( $opts, $e ); $e = exception { ( $opts ) = a( connect => 1, hg => ['a'] ) } and diag $e; is_deeply( $opts, $expect, "StrList ArrayRef" ); } # 2 { my ( $opts, $e ); $e = exception { ( $opts ) = a( connect => 1, hg => 'a' ) } and diag $e; is_deeply( $opts, $expect, "StrList scalar" ); } # 3 { my ( $opts, $e ); $e = exception { ( $opts ) = b( connect => 1, hg => ['a'] ) } and diag $e; is_deeply( $opts, $expect, "StrList ArrayRef" ); } # 4 { my ( $opts, $e ); $e = exception { ( $opts ) = b( connect => 1, hg => 'a' ) } and diag $e; is_deeply( $opts, $expect, "StrList scalar" ); } # 5 { my ( $opts, $e ); $e = exception { ( $opts ) = c( connect => 1, hg2 => ['a'] ) } and diag $e; is_deeply( $opts, $expect2, "StrList ArrayRef - noninline" ); } # 6 { my ( $opts, $e ); $e = exception { ( $opts ) = c( connect => 1, hg2 => 'a' ) } and diag $e; is_deeply( $opts, $expect2, "StrList scalar - noninline" ); } #note compile( # { want_source => 1 }, # slurpy Dict [ # connect => Optional[Bool], # encoding => Optional[Str], # hg => Optional[Types::StrList], # ], #); done_testing; rt86233.t000644001750001750 202513601673061 16470 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Fix: "Cannot inline type constraint check" error with compile and Dict. =head1 SEE ALSO L. =head1 AUTHOR Vyacheslav Matyukhin Emmcleric@cpan.orgE. (Minor changes by Toby Inkster Etobyink@cpan.orgE.) =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Vyacheslav Matyukhin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; BEGIN { package Types; use Type::Library -base, -declare => qw[ Login ]; use Type::Utils; use Types::Standard qw[ Str ]; declare Login, as Str, where { /^\w+$/ }; }; use Type::Params qw[ compile ]; use Types::Standard qw[ Dict ]; my $type = Dict[login => Types::Login]; ok not( $type->can_be_inlined ); ok not( $type->coercion->can_be_inlined ); is(exception { compile($type) }, undef); done_testing; rt86239.t000644001750001750 232213601673061 16476 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Fix: Optional constraints ignored if wrapped in Dict. =head1 SEE ALSO L. =head1 AUTHOR Vyacheslav Matyukhin Emmcleric@cpan.orgE. (Minor changes by Toby Inkster Etobyink@cpan.orgE.) =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Vyacheslav Matyukhin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params qw(validate compile); use Types::Standard qw(ArrayRef Dict Optional Str); my $i = 0; sub announce { note sprintf("Test %d ########", ++$i) } sub got { note "got: " . join ", ", explain(@_) } sub f { announce(); got validate( \@_, Optional[Str], ); } is exception { f("foo") }, undef; is exception { f() }, undef; like exception { f(["abc"]) }, qr/type constraint/; sub g { announce(); got validate( \@_, Dict[foo => Optional[Str]], ); } is exception { g({ foo => "foo" }) }, undef; is exception { g({}) }, undef; like exception { g({ foo => ["abc"] }) }, qr/type constraint/; done_testing; rt90096-2.t000644001750001750 157713601673061 16644 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Additional tests related to RT#90096. Make sure that L localizes C<< $_ >>. =head1 SEE ALSO L. =head1 AUTHOR Diab Jerius Edjerius@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Diab Jerius. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Type::Params qw[ compile ]; use Types::Standard -all; { my $check = compile( Dict [ a => Num ] ); grep { $_->( { a => 3 } ) } $check; is( ref $check, 'CODE', "check is still code" ); } { my $check = compile( slurpy Dict [ a => Num ] ); grep { $_->( a => 3 ) } $check; is( ref $check, 'CODE', "slurpy check is still code" ); } done_testing; rt90096.t000644001750001750 137113601673061 16475 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Make sure that L localizes C<< $_ >>. =head1 SEE ALSO L. =head1 AUTHOR Samuel Kaufman Eskaufman@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Samuel Kaufman. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings FATAL=> 'all'; use Test::More tests => 3; use Type::Params qw[ compile ]; use Types::Standard qw[ slurpy Dict Bool ]; my $check = compile slurpy Dict [ with_connection => Bool ]; for (qw[ 1 2 3 ]) { # $_ is read-only in here ok $check->( with_connection => 1 ); } rt92571-2.t000644001750001750 130713601673061 16633 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Make sure that the weakening of the reference from a Type::Coercion::Union object back to its "owner" type constraint does not break functionality. =head1 SEE ALSO L. =head1 AUTHOR Diab Jerius Edjerius@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Diab Jerius. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings FATAL=> 'all'; use Test::More; use Types::Standard -all; my $sub = (Str | Str)->coercion; is( $sub->('x'), 'x', ); done_testing; rt92571.t000644001750001750 234113601673061 16473 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Make sure that the weakening of the reference from a Type::Coercion object back to its "owner" type constraint does not break functionality. =head1 SEE ALSO L. =head1 AUTHOR Diab Jerius Edjerius@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Diab Jerius. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings FATAL=> 'all'; use Test::More; use Type::Library -base, -declare => qw[ ArrayRefFromAny ]; use Types::Standard -all; use Type::Utils -all; declare_coercion ArrayRefFromAny, to_type ArrayRef, from Any, via { [$_] } ; my $x = ArrayRef->plus_coercions(ArrayRefFromAny); is_deeply( $x->coerce( ['a'] ), ['a'], ); # types hang around until after the coerce method is run is_deeply( ArrayRef->plus_coercions(ArrayRefFromAny)->coerce( ['a'] ), ['a'], ); # types go away after generation of coercion sub, breaking it my $coerce = ArrayRef->plus_coercions(ArrayRefFromAny)->coercion; is_deeply( $coerce->( ['a'] ), ['a'], ) or diag explain($coerce->( ['a'] )); done_testing; rt92591.t000644001750001750 242413601673061 16477 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Make sure that C works outside type libraries. =head1 SEE ALSO L. =head1 AUTHOR Diab Jerius Edjerius@cpan.orgE. Some additions by Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Diab Jerius. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings FATAL=> 'all'; use Test::More; { package Local::TypeLib; use Type::Library -base; use Types::Standard -all; use Type::Utils -all; my $foo = declare_coercion to_type ArrayRef, from Any, via { [$_] }; ::is( $foo->type_constraint, 'ArrayRef', "Type library, coercion target", ); ::is( $foo->type_coercion_map->[0], 'Any', "Type library, coercion type map", ); } { package Local::NotTypeLib; use Types::Standard -all; use Type::Utils -all; my $foo = declare_coercion to_type ArrayRef, from Any, via { [$_] }; ::is( $foo->type_constraint, 'ArrayRef', "Not type library, coercion target", ); ::is( $foo->type_coercion_map->[0], 'Any', "Not type library, coercion type map", ); } done_testing; rt94196.t000644001750001750 160013601673061 16475 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Problematic inlining using C<< $_ >>. =head1 SEE ALSO L. =head1 AUTHOR Diab Jerius Edjerius@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Diab Jerius. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings FATAL=> 'all'; use Test::More; use Test::Fatal; use Type::Params qw( validate ); use Types::Standard qw( -types slurpy ); { package Foo; sub new { bless {}, shift } sub send { } }; my $type = Dict[ encoder => HasMethods ['send'] ]; is( exception { my @params = ( encoder => Foo->new ); validate(\@params, slurpy($type)); }, undef, "slurpy Dict w/ HasMethods", ) or note( $type->inline_check('$_') ); done_testing; rt97684.t000644001750001750 207713601673061 16513 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE The "too few arguments for type constraint check functions" error. =head1 SEE ALSO L. =head1 AUTHOR Diab Jerius Edjerius@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Diab Jerius. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut BEGIN { $ENV{'DEVEL_HIDE_VERBOSE'} = 0 }; use strict; use warnings; use Test::More; use Test::Requires 'Devel::Hide'; use Test::Requires { Mouse => '1.0000' }; use Devel::Hide qw(Type::Tiny::XS); { package Local::Class; use Mouse; } { package Local::Types; use Type::Library -base, -declare => qw( Coord ExistingCoord ); use Type::Utils -all; use Types::Standard -all; declare ExistingCoord, as Str, where { 0 }; declare Coord, as Str; } use Types::Standard -all; use Type::Params qw( validate ); validate( [], slurpy Dict[ with => Optional[Local::Types::ExistingCoord] ], ); ok 1; done_testing; rt98113.t000644001750001750 156613601673061 16501 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Test overload fallback =head1 SEE ALSO L. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. =head1 AUTHOR Dagfinn Ilmari Mannsåker Eilmari@ilmari.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Dagfinn Ilmari Mannsåker This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use BiggerLib -types, -coercions; is( exception { no warnings 'numeric'; BigInteger + 42 }, undef, 'Type::Tiny overload fallback works', ); is( exception { BigInteger->coercion eq '1' }, undef, 'Type::Coercion overload fallback works', ); done_testing; ttxs-gh1.t000644001750001750 225713601673061 17123 0ustar00taitai000000000000Type-Tiny-1.008001/t/40-regression=pod =encoding utf-8 =head1 PURPOSE Test that was failing with Type::Tiny::XS prior to 0.009. =head1 AUTHOR Jed Lund Ejandrew@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Jed Lund. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; { package MyTest; use Type::Utils 0.046 -all; use Type::Library 0.046 -base, -declare => qw(TestDictionary SuperClassesList NameSpace); use Types::Standard 0.046 -types; declare NameSpace, as Str, where { $_ =~ /^[A-Za-z:]+$/ }, # inline_as { undef, "$_ =~ /^[A-Za-z:]+\$/" }, message { "-$_- does not match: " . qr/^[A-Za-z:]+$/ }; declare SuperClassesList, as ArrayRef[ ClassName ], # inline_as { undef, "\@{$_} > 0" }, where { scalar( @$_ ) > 0 }; declare TestDictionary, as Dict[ package => Optional[ NameSpace ], superclasses => Optional[ SuperClassesList ], ]; } ok( MyTest::TestDictionary->check( { package => 'My::Package' } ), "Test TestDictionary" ); #diag MyTest::TestDictionary->inline_check('$dict'); done_testing; BiggerLib.pm000644001750001750 345613601673061 15612 0ustar00taitai000000000000Type-Tiny-1.008001/t/lib=pod =encoding utf-8 =head1 PURPOSE Type library used in several test cases. Defines types C, C and C. Defines classes C and C along with correponding C and C class type constraints; defines role C and the C role type constraint. Library extends DemoLib.pm. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut package BiggerLib; use strict; use warnings; use Type::Utils qw(:all); use Type::Library -base; extends "DemoLib"; extends "Types::Standard"; declare "SmallInteger", as "Integer", where { no warnings; $_ < 10 } message { no warnings; "$_ is too big" }; declare "BigInteger", as "Integer", where { no warnings; $_ >= 10 }; { package Quux; our $VERSION = 1; } role_type "DoesQuux", { role => "Quux" }; { package Foo::Bar; sub new { my $c = shift; bless {@_}, $c } sub foo { 1 } sub bar { 2 } } class_type "FooBar", { class => "Foo::Bar" }; { package Foo::Baz; our @ISA = "Foo::Bar"; sub DOES { return 1 if $_[1] eq 'Quux'; $_[0]->isa($_[0]); } sub foo { 3 } sub baz { 4 } } class_type "Foo::Baz"; duck_type "CanFooBar", [qw/ foo bar /]; duck_type "CanFooBaz", [qw/ foo baz /]; coerce "SmallInteger", from BigInteger => via { abs($_) % 10 }, from ArrayRef => via { 1 }; coerce "BigInteger", from SmallInteger => via { abs($_) + 10 }, from ArrayRef => via { 100 }; declare_coercion "ArrayRefFromAny", to_type "ArrayRef", from "Any", q { [$_] }; declare_coercion "ArrayRefFromPiped", to_type "ArrayRef", from "Str", q { [split /\\|/] }; 1; DemoLib.pm000644001750001750 145113601673061 15270 0ustar00taitai000000000000Type-Tiny-1.008001/t/lib=pod =encoding utf-8 =head1 PURPOSE Type library used in several test cases. Defines types C, C and C. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut package DemoLib; use strict; use warnings; use Scalar::Util "looks_like_number"; use Type::Utils; use Type::Library -base; declare "String", where { not ref $_ } message { "is not a string" }; declare "Number", as "String", where { looks_like_number $_ }, message { "'$_' doesn't look like a number" }; declare "Integer", as "Number", where { $_ eq int($_) }; 1; Builder.pm000644001750001750 16545113601673061 17467 0ustar00taitai000000000000Type-Tiny-1.008001/inc/archaic/Testpackage Test::Builder; use 5.006; use strict; use warnings; our $VERSION = '0.98'; $VERSION = eval $VERSION; ## no critic (BuiltinFunctions::ProhibitStringyEval) BEGIN { if( $] < 5.008 ) { require Test::Builder::IO::Scalar; } } # Make Test::Builder thread-safe for ithreads. BEGIN { use Config; # Load threads::shared when threads are turned on. # 5.8.0's threads are so busted we no longer support them. if( $] >= 5.008001 && $Config{useithreads} && $INC{'threads.pm'} ) { require threads::shared; # Hack around YET ANOTHER threads::shared bug. It would # occasionally forget the contents of the variable when sharing it. # So we first copy the data, then share, then put our copy back. *share = sub (\[$@%]) { my $type = ref $_[0]; my $data; if( $type eq 'HASH' ) { %$data = %{ $_[0] }; } elsif( $type eq 'ARRAY' ) { @$data = @{ $_[0] }; } elsif( $type eq 'SCALAR' ) { $$data = ${ $_[0] }; } else { die( "Unknown type: " . $type ); } $_[0] = &threads::shared::share( $_[0] ); if( $type eq 'HASH' ) { %{ $_[0] } = %$data; } elsif( $type eq 'ARRAY' ) { @{ $_[0] } = @$data; } elsif( $type eq 'SCALAR' ) { ${ $_[0] } = $$data; } else { die( "Unknown type: " . $type ); } return $_[0]; }; } # 5.8.0's threads::shared is busted when threads are off # and earlier Perls just don't have that module at all. else { *share = sub { return $_[0] }; *lock = sub { 0 }; } } =head1 NAME Test::Builder - Backend for building test libraries =head1 SYNOPSIS package My::Test::Module; use base 'Test::Builder::Module'; my $CLASS = __PACKAGE__; sub ok { my($test, $name) = @_; my $tb = $CLASS->builder; $tb->ok($test, $name); } =head1 DESCRIPTION Test::Simple and Test::More have proven to be popular testing modules, but they're not always flexible enough. Test::Builder provides a building block upon which to write your own test libraries I. =head2 Construction =over 4 =item B my $Test = Test::Builder->new; Returns a Test::Builder object representing the current state of the test. Since you only run one test per program C always returns the same Test::Builder object. No matter how many times you call C, you're getting the same object. This is called a singleton. This is done so that multiple modules share such global information as the test counter and where test output is going. If you want a completely new Test::Builder object different from the singleton, use C. =cut our $Test = Test::Builder->new; sub new { my($class) = shift; $Test ||= $class->create; return $Test; } =item B my $Test = Test::Builder->create; Ok, so there can be more than one Test::Builder object and this is how you get it. You might use this instead of C if you're testing a Test::Builder based module, but otherwise you probably want C. B: the implementation is not complete. C, for example, is still shared amongst B Test::Builder objects, even ones created using this method. Also, the method name may change in the future. =cut sub create { my $class = shift; my $self = bless {}, $class; $self->reset; return $self; } =item B my $child = $builder->child($name_of_child); $child->plan( tests => 4 ); $child->ok(some_code()); ... $child->finalize; Returns a new instance of C. Any output from this child will be indented four spaces more than the parent's indentation. When done, the C method I be called explicitly. Trying to create a new child with a previous child still active (i.e., C not called) will C. Trying to run a test when you have an open child will also C and cause the test suite to fail. =cut sub child { my( $self, $name ) = @_; if( $self->{Child_Name} ) { $self->croak("You already have a child named ($self->{Child_Name}) running"); } my $parent_in_todo = $self->in_todo; # Clear $TODO for the child. my $orig_TODO = $self->find_TODO(undef, 1, undef); my $child = bless {}, ref $self; $child->reset; # Add to our indentation $child->_indent( $self->_indent . ' ' ); $child->{$_} = $self->{$_} foreach qw{Out_FH Todo_FH Fail_FH}; if ($parent_in_todo) { $child->{Fail_FH} = $self->{Todo_FH}; } # This will be reset in finalize. We do this here lest one child failure # cause all children to fail. $child->{Child_Error} = $?; $? = 0; $child->{Parent} = $self; $child->{Parent_TODO} = $orig_TODO; $child->{Name} = $name || "Child of " . $self->name; $self->{Child_Name} = $child->name; return $child; } =item B $builder->subtest($name, \&subtests); See documentation of C in Test::More. =cut sub subtest { my $self = shift; my($name, $subtests) = @_; if ('CODE' ne ref $subtests) { $self->croak("subtest()'s second argument must be a code ref"); } # Turn the child into the parent so anyone who has stored a copy of # the Test::Builder singleton will get the child. my($error, $child, %parent); { # child() calls reset() which sets $Level to 1, so we localize # $Level first to limit the scope of the reset to the subtest. local $Test::Builder::Level = $Test::Builder::Level + 1; $child = $self->child($name); %parent = %$self; %$self = %$child; my $run_the_subtests = sub { $subtests->(); $self->done_testing unless $self->_plan_handled; 1; }; if( !eval { $run_the_subtests->() } ) { $error = $@; } } # Restore the parent and the copied child. %$child = %$self; %$self = %parent; # Restore the parent's $TODO $self->find_TODO(undef, 1, $child->{Parent_TODO}); # Die *after* we restore the parent. die $error if $error and !eval { $error->isa('Test::Builder::Exception') }; local $Test::Builder::Level = $Test::Builder::Level + 1; return $child->finalize; } =begin _private =item B<_plan_handled> if ( $Test->_plan_handled ) { ... } Returns true if the developer has explicitly handled the plan via: =over 4 =item * Explicitly setting the number of tests =item * Setting 'no_plan' =item * Set 'skip_all'. =back This is currently used in subtests when we implicitly call C<< $Test->done_testing >> if the developer has not set a plan. =end _private =cut sub _plan_handled { my $self = shift; return $self->{Have_Plan} || $self->{No_Plan} || $self->{Skip_All}; } =item B my $ok = $child->finalize; When your child is done running tests, you must call C to clean up and tell the parent your pass/fail status. Calling finalize on a child with open children will C. If the child falls out of scope before C is called, a failure diagnostic will be issued and the child is considered to have failed. No attempt to call methods on a child after C is called is guaranteed to succeed. Calling this on the root builder is a no-op. =cut sub finalize { my $self = shift; return unless $self->parent; if( $self->{Child_Name} ) { $self->croak("Can't call finalize() with child ($self->{Child_Name}) active"); } local $? = 0; # don't fail if $subtests happened to set $? nonzero $self->_ending; # XXX This will only be necessary for TAP envelopes (we think) #$self->_print( $self->is_passing ? "PASS\n" : "FAIL\n" ); local $Test::Builder::Level = $Test::Builder::Level + 1; my $ok = 1; $self->parent->{Child_Name} = undef; if ( $self->{Skip_All} ) { $self->parent->skip($self->{Skip_All}); } elsif ( not @{ $self->{Test_Results} } ) { $self->parent->ok( 0, sprintf q[No tests run for subtest "%s"], $self->name ); } else { $self->parent->ok( $self->is_passing, $self->name ); } $? = $self->{Child_Error}; delete $self->{Parent}; return $self->is_passing; } sub _indent { my $self = shift; if( @_ ) { $self->{Indent} = shift; } return $self->{Indent}; } =item B if ( my $parent = $builder->parent ) { ... } Returns the parent C instance, if any. Only used with child builders for nested TAP. =cut sub parent { shift->{Parent} } =item B diag $builder->name; Returns the name of the current builder. Top level builders default to C<$0> (the name of the executable). Child builders are named via the C method. If no name is supplied, will be named "Child of $parent->name". =cut sub name { shift->{Name} } sub DESTROY { my $self = shift; if ( $self->parent and $$ == $self->{Original_Pid} ) { my $name = $self->name; $self->diag(<<"FAIL"); Child ($name) exited without calling finalize() FAIL $self->parent->{In_Destroy} = 1; $self->parent->ok(0, $name); } } =item B $Test->reset; Reinitializes the Test::Builder singleton to its original state. Mostly useful for tests run in persistent environments where the same test might be run multiple times in the same process. =cut our $Level; sub reset { ## no critic (Subroutines::ProhibitBuiltinHomonyms) my($self) = @_; # We leave this a global because it has to be localized and localizing # hash keys is just asking for pain. Also, it was documented. $Level = 1; $self->{Name} = $0; $self->is_passing(1); $self->{Ending} = 0; $self->{Have_Plan} = 0; $self->{No_Plan} = 0; $self->{Have_Output_Plan} = 0; $self->{Done_Testing} = 0; $self->{Original_Pid} = $$; $self->{Child_Name} = undef; $self->{Indent} ||= ''; share( $self->{Curr_Test} ); $self->{Curr_Test} = 0; $self->{Test_Results} = &share( [] ); $self->{Exported_To} = undef; $self->{Expected_Tests} = 0; $self->{Skip_All} = 0; $self->{Use_Nums} = 1; $self->{No_Header} = 0; $self->{No_Ending} = 0; $self->{Todo} = undef; $self->{Todo_Stack} = []; $self->{Start_Todo} = 0; $self->{Opened_Testhandles} = 0; $self->_dup_stdhandles; return; } =back =head2 Setting up tests These methods are for setting up tests and declaring how many there are. You usually only want to call one of these methods. =over 4 =item B $Test->plan('no_plan'); $Test->plan( skip_all => $reason ); $Test->plan( tests => $num_tests ); A convenient way to set up your tests. Call this and Test::Builder will print the appropriate headers and take the appropriate actions. If you call C, don't call any of the other methods below. If a child calls "skip_all" in the plan, a C is thrown. Trap this error, call C and don't run any more tests on the child. my $child = $Test->child('some child'); eval { $child->plan( $condition ? ( skip_all => $reason ) : ( tests => 3 ) ) }; if ( eval { $@->isa('Test::Builder::Exception') } ) { $child->finalize; return; } # run your tests =cut my %plan_cmds = ( no_plan => \&no_plan, skip_all => \&skip_all, tests => \&_plan_tests, ); sub plan { my( $self, $cmd, $arg ) = @_; return unless $cmd; local $Level = $Level + 1; $self->croak("You tried to plan twice") if $self->{Have_Plan}; if( my $method = $plan_cmds{$cmd} ) { local $Level = $Level + 1; $self->$method($arg); } else { my @args = grep { defined } ( $cmd, $arg ); $self->croak("plan() doesn't understand @args"); } return 1; } sub _plan_tests { my($self, $arg) = @_; if($arg) { local $Level = $Level + 1; return $self->expected_tests($arg); } elsif( !defined $arg ) { $self->croak("Got an undefined number of tests"); } else { $self->croak("You said to run 0 tests"); } return; } =item B my $max = $Test->expected_tests; $Test->expected_tests($max); Gets/sets the number of tests we expect this test to run and prints out the appropriate headers. =cut sub expected_tests { my $self = shift; my($max) = @_; if(@_) { $self->croak("Number of tests must be a positive integer. You gave it '$max'") unless $max =~ /^\+?\d+$/; $self->{Expected_Tests} = $max; $self->{Have_Plan} = 1; $self->_output_plan($max) unless $self->no_header; } return $self->{Expected_Tests}; } =item B $Test->no_plan; Declares that this test will run an indeterminate number of tests. =cut sub no_plan { my($self, $arg) = @_; $self->carp("no_plan takes no arguments") if $arg; $self->{No_Plan} = 1; $self->{Have_Plan} = 1; return 1; } =begin private =item B<_output_plan> $tb->_output_plan($max); $tb->_output_plan($max, $directive); $tb->_output_plan($max, $directive => $reason); Handles displaying the test plan. If a C<$directive> and/or C<$reason> are given they will be output with the plan. So here's what skipping all tests looks like: $tb->_output_plan(0, "SKIP", "Because I said so"); It sets C<< $tb->{Have_Output_Plan} >> and will croak if the plan was already output. =end private =cut sub _output_plan { my($self, $max, $directive, $reason) = @_; $self->carp("The plan was already output") if $self->{Have_Output_Plan}; my $plan = "1..$max"; $plan .= " # $directive" if defined $directive; $plan .= " $reason" if defined $reason; $self->_print("$plan\n"); $self->{Have_Output_Plan} = 1; return; } =item B $Test->done_testing(); $Test->done_testing($num_tests); Declares that you are done testing, no more tests will be run after this point. If a plan has not yet been output, it will do so. $num_tests is the number of tests you planned to run. If a numbered plan was already declared, and if this contradicts, a failing test will be run to reflect the planning mistake. If C was declared, this will override. If C is called twice, the second call will issue a failing test. If C<$num_tests> is omitted, the number of tests run will be used, like no_plan. C is, in effect, used when you'd want to use C, but safer. You'd use it like so: $Test->ok($a == $b); $Test->done_testing(); Or to plan a variable number of tests: for my $test (@tests) { $Test->ok($test); } $Test->done_testing(@tests); =cut sub done_testing { my($self, $num_tests) = @_; # If done_testing() specified the number of tests, shut off no_plan. if( defined $num_tests ) { $self->{No_Plan} = 0; } else { $num_tests = $self->current_test; } if( $self->{Done_Testing} ) { my($file, $line) = @{$self->{Done_Testing}}[1,2]; $self->ok(0, "done_testing() was already called at $file line $line"); return; } $self->{Done_Testing} = [caller]; if( $self->expected_tests && $num_tests != $self->expected_tests ) { $self->ok(0, "planned to run @{[ $self->expected_tests ]} ". "but done_testing() expects $num_tests"); } else { $self->{Expected_Tests} = $num_tests; } $self->_output_plan($num_tests) unless $self->{Have_Output_Plan}; $self->{Have_Plan} = 1; # The wrong number of tests were run $self->is_passing(0) if $self->{Expected_Tests} != $self->{Curr_Test}; # No tests were run $self->is_passing(0) if $self->{Curr_Test} == 0; return 1; } =item B $plan = $Test->has_plan Find out whether a plan has been defined. C<$plan> is either C (no plan has been set), C (indeterminate # of tests) or an integer (the number of expected tests). =cut sub has_plan { my $self = shift; return( $self->{Expected_Tests} ) if $self->{Expected_Tests}; return('no_plan') if $self->{No_Plan}; return(undef); } =item B $Test->skip_all; $Test->skip_all($reason); Skips all the tests, using the given C<$reason>. Exits immediately with 0. =cut sub skip_all { my( $self, $reason ) = @_; $self->{Skip_All} = $self->parent ? $reason : 1; $self->_output_plan(0, "SKIP", $reason) unless $self->no_header; if ( $self->parent ) { die bless {} => 'Test::Builder::Exception'; } exit(0); } =item B my $pack = $Test->exported_to; $Test->exported_to($pack); Tells Test::Builder what package you exported your functions to. This method isn't terribly useful since modules which share the same Test::Builder object might get exported to different packages and only the last one will be honored. =cut sub exported_to { my( $self, $pack ) = @_; if( defined $pack ) { $self->{Exported_To} = $pack; } return $self->{Exported_To}; } =back =head2 Running tests These actually run the tests, analogous to the functions in Test::More. They all return true if the test passed, false if the test failed. C<$name> is always optional. =over 4 =item B $Test->ok($test, $name); Your basic test. Pass if C<$test> is true, fail if $test is false. Just like Test::Simple's C. =cut sub ok { my( $self, $test, $name ) = @_; if ( $self->{Child_Name} and not $self->{In_Destroy} ) { $name = 'unnamed test' unless defined $name; $self->is_passing(0); $self->croak("Cannot run test ($name) with active children"); } # $test might contain an object which we don't want to accidentally # store, so we turn it into a boolean. $test = $test ? 1 : 0; lock $self->{Curr_Test}; $self->{Curr_Test}++; # In case $name is a string overloaded object, force it to stringify. $self->_unoverload_str( \$name ); $self->diag(<<"ERR") if defined $name and $name =~ /^[\d\s]+$/; You named your test '$name'. You shouldn't use numbers for your test names. Very confusing. ERR # Capture the value of $TODO for the rest of this ok() call # so it can more easily be found by other routines. my $todo = $self->todo(); my $in_todo = $self->in_todo; local $self->{Todo} = $todo if $in_todo; $self->_unoverload_str( \$todo ); my $out; my $result = &share( {} ); unless($test) { $out .= "not "; @$result{ 'ok', 'actual_ok' } = ( ( $self->in_todo ? 1 : 0 ), 0 ); } else { @$result{ 'ok', 'actual_ok' } = ( 1, $test ); } $out .= "ok"; $out .= " $self->{Curr_Test}" if $self->use_numbers; if( defined $name ) { $name =~ s|#|\\#|g; # # in a name can confuse Test::Harness. $out .= " - $name"; $result->{name} = $name; } else { $result->{name} = ''; } if( $self->in_todo ) { $out .= " # TODO $todo"; $result->{reason} = $todo; $result->{type} = 'todo'; } else { $result->{reason} = ''; $result->{type} = ''; } $self->{Test_Results}[ $self->{Curr_Test} - 1 ] = $result; $out .= "\n"; $self->_print($out); unless($test) { my $msg = $self->in_todo ? "Failed (TODO)" : "Failed"; $self->_print_to_fh( $self->_diag_fh, "\n" ) if $ENV{HARNESS_ACTIVE}; my( undef, $file, $line ) = $self->caller; if( defined $name ) { $self->diag(qq[ $msg test '$name'\n]); $self->diag(qq[ at $file line $line.\n]); } else { $self->diag(qq[ $msg test at $file line $line.\n]); } } $self->is_passing(0) unless $test || $self->in_todo; # Check that we haven't violated the plan $self->_check_is_passing_plan(); return $test ? 1 : 0; } # Check that we haven't yet violated the plan and set # is_passing() accordingly sub _check_is_passing_plan { my $self = shift; my $plan = $self->has_plan; return unless defined $plan; # no plan yet defined return unless $plan !~ /\D/; # no numeric plan $self->is_passing(0) if $plan < $self->{Curr_Test}; } sub _unoverload { my $self = shift; my $type = shift; $self->_try(sub { require overload; }, die_on_fail => 1); foreach my $thing (@_) { if( $self->_is_object($$thing) ) { if( my $string_meth = overload::Method( $$thing, $type ) ) { $$thing = $$thing->$string_meth(); } } } return; } sub _is_object { my( $self, $thing ) = @_; return $self->_try( sub { ref $thing && $thing->isa('UNIVERSAL') } ) ? 1 : 0; } sub _unoverload_str { my $self = shift; return $self->_unoverload( q[""], @_ ); } sub _unoverload_num { my $self = shift; $self->_unoverload( '0+', @_ ); for my $val (@_) { next unless $self->_is_dualvar($$val); $$val = $$val + 0; } return; } # This is a hack to detect a dualvar such as $! sub _is_dualvar { my( $self, $val ) = @_; # Objects are not dualvars. return 0 if ref $val; no warnings 'numeric'; my $numval = $val + 0; return $numval != 0 and $numval ne $val ? 1 : 0; } =item B $Test->is_eq($got, $expected, $name); Like Test::More's C. Checks if C<$got eq $expected>. This is the string version. C only ever matches another C. =item B $Test->is_num($got, $expected, $name); Like Test::More's C. Checks if C<$got == $expected>. This is the numeric version. C only ever matches another C. =cut sub is_eq { my( $self, $got, $expect, $name ) = @_; local $Level = $Level + 1; if( !defined $got || !defined $expect ) { # undef only matches undef and nothing else my $test = !defined $got && !defined $expect; $self->ok( $test, $name ); $self->_is_diag( $got, 'eq', $expect ) unless $test; return $test; } return $self->cmp_ok( $got, 'eq', $expect, $name ); } sub is_num { my( $self, $got, $expect, $name ) = @_; local $Level = $Level + 1; if( !defined $got || !defined $expect ) { # undef only matches undef and nothing else my $test = !defined $got && !defined $expect; $self->ok( $test, $name ); $self->_is_diag( $got, '==', $expect ) unless $test; return $test; } return $self->cmp_ok( $got, '==', $expect, $name ); } sub _diag_fmt { my( $self, $type, $val ) = @_; if( defined $$val ) { if( $type eq 'eq' or $type eq 'ne' ) { # quote and force string context $$val = "'$$val'"; } else { # force numeric context $self->_unoverload_num($val); } } else { $$val = 'undef'; } return; } sub _is_diag { my( $self, $got, $type, $expect ) = @_; $self->_diag_fmt( $type, $_ ) for \$got, \$expect; local $Level = $Level + 1; return $self->diag(<<"DIAGNOSTIC"); got: $got expected: $expect DIAGNOSTIC } sub _isnt_diag { my( $self, $got, $type ) = @_; $self->_diag_fmt( $type, \$got ); local $Level = $Level + 1; return $self->diag(<<"DIAGNOSTIC"); got: $got expected: anything else DIAGNOSTIC } =item B $Test->isnt_eq($got, $dont_expect, $name); Like Test::More's C. Checks if C<$got ne $dont_expect>. This is the string version. =item B $Test->isnt_num($got, $dont_expect, $name); Like Test::More's C. Checks if C<$got ne $dont_expect>. This is the numeric version. =cut sub isnt_eq { my( $self, $got, $dont_expect, $name ) = @_; local $Level = $Level + 1; if( !defined $got || !defined $dont_expect ) { # undef only matches undef and nothing else my $test = defined $got || defined $dont_expect; $self->ok( $test, $name ); $self->_isnt_diag( $got, 'ne' ) unless $test; return $test; } return $self->cmp_ok( $got, 'ne', $dont_expect, $name ); } sub isnt_num { my( $self, $got, $dont_expect, $name ) = @_; local $Level = $Level + 1; if( !defined $got || !defined $dont_expect ) { # undef only matches undef and nothing else my $test = defined $got || defined $dont_expect; $self->ok( $test, $name ); $self->_isnt_diag( $got, '!=' ) unless $test; return $test; } return $self->cmp_ok( $got, '!=', $dont_expect, $name ); } =item B $Test->like($this, qr/$regex/, $name); $Test->like($this, '/$regex/', $name); Like Test::More's C. Checks if $this matches the given C<$regex>. =item B $Test->unlike($this, qr/$regex/, $name); $Test->unlike($this, '/$regex/', $name); Like Test::More's C. Checks if $this B the given C<$regex>. =cut sub like { my( $self, $this, $regex, $name ) = @_; local $Level = $Level + 1; return $self->_regex_ok( $this, $regex, '=~', $name ); } sub unlike { my( $self, $this, $regex, $name ) = @_; local $Level = $Level + 1; return $self->_regex_ok( $this, $regex, '!~', $name ); } =item B $Test->cmp_ok($this, $type, $that, $name); Works just like Test::More's C. $Test->cmp_ok($big_num, '!=', $other_big_num); =cut my %numeric_cmps = map { ( $_, 1 ) } ( "<", "<=", ">", ">=", "==", "!=", "<=>" ); sub cmp_ok { my( $self, $got, $type, $expect, $name ) = @_; my $test; my $error; { ## no critic (BuiltinFunctions::ProhibitStringyEval) local( $@, $!, $SIG{__DIE__} ); # isolate eval my($pack, $file, $line) = $self->caller(); # This is so that warnings come out at the caller's level $test = eval qq[ #line $line "(eval in cmp_ok) $file" \$got $type \$expect; ]; $error = $@; } local $Level = $Level + 1; my $ok = $self->ok( $test, $name ); # Treat overloaded objects as numbers if we're asked to do a # numeric comparison. my $unoverload = $numeric_cmps{$type} ? '_unoverload_num' : '_unoverload_str'; $self->diag(<<"END") if $error; An error occurred while using $type: ------------------------------------ $error ------------------------------------ END unless($ok) { $self->$unoverload( \$got, \$expect ); if( $type =~ /^(eq|==)$/ ) { $self->_is_diag( $got, $type, $expect ); } elsif( $type =~ /^(ne|!=)$/ ) { $self->_isnt_diag( $got, $type ); } else { $self->_cmp_diag( $got, $type, $expect ); } } return $ok; } sub _cmp_diag { my( $self, $got, $type, $expect ) = @_; $got = defined $got ? "'$got'" : 'undef'; $expect = defined $expect ? "'$expect'" : 'undef'; local $Level = $Level + 1; return $self->diag(<<"DIAGNOSTIC"); $got $type $expect DIAGNOSTIC } sub _caller_context { my $self = shift; my( $pack, $file, $line ) = $self->caller(1); my $code = ''; $code .= "#line $line $file\n" if defined $file and defined $line; return $code; } =back =head2 Other Testing Methods These are methods which are used in the course of writing a test but are not themselves tests. =over 4 =item B $Test->BAIL_OUT($reason); Indicates to the Test::Harness that things are going so badly all testing should terminate. This includes running any additional test scripts. It will exit with 255. =cut sub BAIL_OUT { my( $self, $reason ) = @_; $self->{Bailed_Out} = 1; $self->_print("Bail out! $reason"); exit 255; } =for deprecated BAIL_OUT() used to be BAILOUT() =cut { no warnings 'once'; *BAILOUT = \&BAIL_OUT; } =item B $Test->skip; $Test->skip($why); Skips the current test, reporting C<$why>. =cut sub skip { my( $self, $why ) = @_; $why ||= ''; $self->_unoverload_str( \$why ); lock( $self->{Curr_Test} ); $self->{Curr_Test}++; $self->{Test_Results}[ $self->{Curr_Test} - 1 ] = &share( { 'ok' => 1, actual_ok => 1, name => '', type => 'skip', reason => $why, } ); my $out = "ok"; $out .= " $self->{Curr_Test}" if $self->use_numbers; $out .= " # skip"; $out .= " $why" if length $why; $out .= "\n"; $self->_print($out); return 1; } =item B $Test->todo_skip; $Test->todo_skip($why); Like C, only it will declare the test as failing and TODO. Similar to print "not ok $tnum # TODO $why\n"; =cut sub todo_skip { my( $self, $why ) = @_; $why ||= ''; lock( $self->{Curr_Test} ); $self->{Curr_Test}++; $self->{Test_Results}[ $self->{Curr_Test} - 1 ] = &share( { 'ok' => 1, actual_ok => 0, name => '', type => 'todo_skip', reason => $why, } ); my $out = "not ok"; $out .= " $self->{Curr_Test}" if $self->use_numbers; $out .= " # TODO & SKIP $why\n"; $self->_print($out); return 1; } =begin _unimplemented =item B $Test->skip_rest; $Test->skip_rest($reason); Like C, only it skips all the rest of the tests you plan to run and terminates the test. If you're running under C, it skips once and terminates the test. =end _unimplemented =back =head2 Test building utility methods These methods are useful when writing your own test methods. =over 4 =item B $Test->maybe_regex(qr/$regex/); $Test->maybe_regex('/$regex/'); This method used to be useful back when Test::Builder worked on Perls before 5.6 which didn't have qr//. Now its pretty useless. Convenience method for building testing functions that take regular expressions as arguments. Takes a quoted regular expression produced by C, or a string representing a regular expression. Returns a Perl value which may be used instead of the corresponding regular expression, or C if its argument is not recognised. For example, a version of C, sans the useful diagnostic messages, could be written as: sub laconic_like { my ($self, $this, $regex, $name) = @_; my $usable_regex = $self->maybe_regex($regex); die "expecting regex, found '$regex'\n" unless $usable_regex; $self->ok($this =~ m/$usable_regex/, $name); } =cut sub maybe_regex { my( $self, $regex ) = @_; my $usable_regex = undef; return $usable_regex unless defined $regex; my( $re, $opts ); # Check for qr/foo/ if( _is_qr($regex) ) { $usable_regex = $regex; } # Check for '/foo/' or 'm,foo,' elsif(( $re, $opts ) = $regex =~ m{^ /(.*)/ (\w*) $ }sx or ( undef, $re, $opts ) = $regex =~ m,^ m([^\w\s]) (.+) \1 (\w*) $,sx ) { $usable_regex = length $opts ? "(?$opts)$re" : $re; } return $usable_regex; } sub _is_qr { my $regex = shift; # is_regexp() checks for regexes in a robust manner, say if they're # blessed. return re::is_regexp($regex) if defined &re::is_regexp; return ref $regex eq 'Regexp'; } sub _regex_ok { my( $self, $this, $regex, $cmp, $name ) = @_; my $ok = 0; my $usable_regex = $self->maybe_regex($regex); unless( defined $usable_regex ) { local $Level = $Level + 1; $ok = $self->ok( 0, $name ); $self->diag(" '$regex' doesn't look much like a regex to me."); return $ok; } { ## no critic (BuiltinFunctions::ProhibitStringyEval) my $test; my $context = $self->_caller_context; local( $@, $!, $SIG{__DIE__} ); # isolate eval $test = eval $context . q{$test = $this =~ /$usable_regex/ ? 1 : 0}; $test = !$test if $cmp eq '!~'; local $Level = $Level + 1; $ok = $self->ok( $test, $name ); } unless($ok) { $this = defined $this ? "'$this'" : 'undef'; my $match = $cmp eq '=~' ? "doesn't match" : "matches"; local $Level = $Level + 1; $self->diag( sprintf <<'DIAGNOSTIC', $this, $match, $regex ); %s %13s '%s' DIAGNOSTIC } return $ok; } # I'm not ready to publish this. It doesn't deal with array return # values from the code or context. =begin private =item B<_try> my $return_from_code = $Test->try(sub { code }); my($return_from_code, $error) = $Test->try(sub { code }); Works like eval BLOCK except it ensures it has no effect on the rest of the test (ie. C<$@> is not set) nor is effected by outside interference (ie. C<$SIG{__DIE__}>) and works around some quirks in older Perls. C<$error> is what would normally be in C<$@>. It is suggested you use this in place of eval BLOCK. =cut sub _try { my( $self, $code, %opts ) = @_; my $error; my $return; { local $!; # eval can mess up $! local $@; # don't set $@ in the test local $SIG{__DIE__}; # don't trip an outside DIE handler. $return = eval { $code->() }; $error = $@; } die $error if $error and $opts{die_on_fail}; return wantarray ? ( $return, $error ) : $return; } =end private =item B my $is_fh = $Test->is_fh($thing); Determines if the given C<$thing> can be used as a filehandle. =cut sub is_fh { my $self = shift; my $maybe_fh = shift; return 0 unless defined $maybe_fh; return 1 if ref $maybe_fh eq 'GLOB'; # its a glob ref return 1 if ref \$maybe_fh eq 'GLOB'; # its a glob return eval { $maybe_fh->isa("IO::Handle") } || eval { tied($maybe_fh)->can('TIEHANDLE') }; } =back =head2 Test style =over 4 =item B $Test->level($how_high); How far up the call stack should C<$Test> look when reporting where the test failed. Defaults to 1. Setting L<$Test::Builder::Level> overrides. This is typically useful localized: sub my_ok { my $test = shift; local $Test::Builder::Level = $Test::Builder::Level + 1; $TB->ok($test); } To be polite to other functions wrapping your own you usually want to increment C<$Level> rather than set it to a constant. =cut sub level { my( $self, $level ) = @_; if( defined $level ) { $Level = $level; } return $Level; } =item B $Test->use_numbers($on_or_off); Whether or not the test should output numbers. That is, this if true: ok 1 ok 2 ok 3 or this if false ok ok ok Most useful when you can't depend on the test output order, such as when threads or forking is involved. Defaults to on. =cut sub use_numbers { my( $self, $use_nums ) = @_; if( defined $use_nums ) { $self->{Use_Nums} = $use_nums; } return $self->{Use_Nums}; } =item B $Test->no_diag($no_diag); If set true no diagnostics will be printed. This includes calls to C. =item B $Test->no_ending($no_ending); Normally, Test::Builder does some extra diagnostics when the test ends. It also changes the exit code as described below. If this is true, none of that will be done. =item B $Test->no_header($no_header); If set to true, no "1..N" header will be printed. =cut foreach my $attribute (qw(No_Header No_Ending No_Diag)) { my $method = lc $attribute; my $code = sub { my( $self, $no ) = @_; if( defined $no ) { $self->{$attribute} = $no; } return $self->{$attribute}; }; no strict 'refs'; ## no critic *{ __PACKAGE__ . '::' . $method } = $code; } =back =head2 Output Controlling where the test output goes. It's ok for your test to change where STDOUT and STDERR point to, Test::Builder's default output settings will not be affected. =over 4 =item B $Test->diag(@msgs); Prints out the given C<@msgs>. Like C, arguments are simply appended together. Normally, it uses the C handle, but if this is for a TODO test, the C handle is used. Output will be indented and marked with a # so as not to interfere with test output. A newline will be put on the end if there isn't one already. We encourage using this rather than calling print directly. Returns false. Why? Because C is often used in conjunction with a failing test (C) it "passes through" the failure. return ok(...) || diag(...); =for blame transfer Mark Fowler =cut sub diag { my $self = shift; $self->_print_comment( $self->_diag_fh, @_ ); } =item B $Test->note(@msgs); Like C, but it prints to the C handle so it will not normally be seen by the user except in verbose mode. =cut sub note { my $self = shift; $self->_print_comment( $self->output, @_ ); } sub _diag_fh { my $self = shift; local $Level = $Level + 1; return $self->in_todo ? $self->todo_output : $self->failure_output; } sub _print_comment { my( $self, $fh, @msgs ) = @_; return if $self->no_diag; return unless @msgs; # Prevent printing headers when compiling (i.e. -c) return if $^C; # Smash args together like print does. # Convert undef to 'undef' so its readable. my $msg = join '', map { defined($_) ? $_ : 'undef' } @msgs; # Escape the beginning, _print will take care of the rest. $msg =~ s/^/# /; local $Level = $Level + 1; $self->_print_to_fh( $fh, $msg ); return 0; } =item B my @dump = $Test->explain(@msgs); Will dump the contents of any references in a human readable format. Handy for things like... is_deeply($have, $want) || diag explain $have; or is_deeply($have, $want) || note explain $have; =cut sub explain { my $self = shift; return map { ref $_ ? do { $self->_try(sub { require Data::Dumper }, die_on_fail => 1); my $dumper = Data::Dumper->new( [$_] ); $dumper->Indent(1)->Terse(1); $dumper->Sortkeys(1) if $dumper->can("Sortkeys"); $dumper->Dump; } : $_ } @_; } =begin _private =item B<_print> $Test->_print(@msgs); Prints to the C filehandle. =end _private =cut sub _print { my $self = shift; return $self->_print_to_fh( $self->output, @_ ); } sub _print_to_fh { my( $self, $fh, @msgs ) = @_; # Prevent printing headers when only compiling. Mostly for when # tests are deparsed with B::Deparse return if $^C; my $msg = join '', @msgs; my $indent = $self->_indent; local( $\, $", $, ) = ( undef, ' ', '' ); # Escape each line after the first with a # so we don't # confuse Test::Harness. $msg =~ s{\n(?!\z)}{\n$indent# }sg; # Stick a newline on the end if it needs it. $msg .= "\n" unless $msg =~ /\n\z/; return print $fh $indent, $msg; } =item B =item B =item B my $filehandle = $Test->output; $Test->output($filehandle); $Test->output($filename); $Test->output(\$scalar); These methods control where Test::Builder will print its output. They take either an open C<$filehandle>, a C<$filename> to open and write to or a C<$scalar> reference to append to. It will always return a C<$filehandle>. B is where normal "ok/not ok" test output goes. Defaults to STDOUT. B is where diagnostic output on test failures and C goes. It is normally not read by Test::Harness and instead is displayed to the user. Defaults to STDERR. C is used instead of C for the diagnostics of a failing TODO test. These will not be seen by the user. Defaults to STDOUT. =cut sub output { my( $self, $fh ) = @_; if( defined $fh ) { $self->{Out_FH} = $self->_new_fh($fh); } return $self->{Out_FH}; } sub failure_output { my( $self, $fh ) = @_; if( defined $fh ) { $self->{Fail_FH} = $self->_new_fh($fh); } return $self->{Fail_FH}; } sub todo_output { my( $self, $fh ) = @_; if( defined $fh ) { $self->{Todo_FH} = $self->_new_fh($fh); } return $self->{Todo_FH}; } sub _new_fh { my $self = shift; my($file_or_fh) = shift; my $fh; if( $self->is_fh($file_or_fh) ) { $fh = $file_or_fh; } elsif( ref $file_or_fh eq 'SCALAR' ) { # Scalar refs as filehandles was added in 5.8. if( $] >= 5.008 ) { open $fh, ">>", $file_or_fh or $self->croak("Can't open scalar ref $file_or_fh: $!"); } # Emulate scalar ref filehandles with a tie. else { $fh = Test::Builder::IO::Scalar->new($file_or_fh) or $self->croak("Can't tie scalar ref $file_or_fh"); } } else { open $fh, ">", $file_or_fh or $self->croak("Can't open test output log $file_or_fh: $!"); _autoflush($fh); } return $fh; } sub _autoflush { my($fh) = shift; my $old_fh = select $fh; $| = 1; select $old_fh; return; } my( $Testout, $Testerr ); sub _dup_stdhandles { my $self = shift; $self->_open_testhandles; # Set everything to unbuffered else plain prints to STDOUT will # come out in the wrong order from our own prints. _autoflush($Testout); _autoflush( \*STDOUT ); _autoflush($Testerr); _autoflush( \*STDERR ); $self->reset_outputs; return; } sub _open_testhandles { my $self = shift; return if $self->{Opened_Testhandles}; # We dup STDOUT and STDERR so people can change them in their # test suites while still getting normal test output. open( $Testout, ">&STDOUT" ) or die "Can't dup STDOUT: $!"; open( $Testerr, ">&STDERR" ) or die "Can't dup STDERR: $!"; $self->_copy_io_layers( \*STDOUT, $Testout ); $self->_copy_io_layers( \*STDERR, $Testerr ); $self->{Opened_Testhandles} = 1; return; } sub _copy_io_layers { my( $self, $src, $dst ) = @_; $self->_try( sub { require PerlIO; my @src_layers = PerlIO::get_layers($src); _apply_layers($dst, @src_layers) if @src_layers; } ); return; } sub _apply_layers { my ($fh, @layers) = @_; my %seen; my @unique = grep { $_ ne 'unix' and !$seen{$_}++ } @layers; binmode($fh, join(":", "", "raw", @unique)); } =item reset_outputs $tb->reset_outputs; Resets all the output filehandles back to their defaults. =cut sub reset_outputs { my $self = shift; $self->output ($Testout); $self->failure_output($Testerr); $self->todo_output ($Testout); return; } =item carp $tb->carp(@message); Warns with C<@message> but the message will appear to come from the point where the original test function was called (C<< $tb->caller >>). =item croak $tb->croak(@message); Dies with C<@message> but the message will appear to come from the point where the original test function was called (C<< $tb->caller >>). =cut sub _message_at_caller { my $self = shift; local $Level = $Level + 1; my( $pack, $file, $line ) = $self->caller; return join( "", @_ ) . " at $file line $line.\n"; } sub carp { my $self = shift; return warn $self->_message_at_caller(@_); } sub croak { my $self = shift; return die $self->_message_at_caller(@_); } =back =head2 Test Status and Info =over 4 =item B my $curr_test = $Test->current_test; $Test->current_test($num); Gets/sets the current test number we're on. You usually shouldn't have to set this. If set forward, the details of the missing tests are filled in as 'unknown'. if set backward, the details of the intervening tests are deleted. You can erase history if you really want to. =cut sub current_test { my( $self, $num ) = @_; lock( $self->{Curr_Test} ); if( defined $num ) { $self->{Curr_Test} = $num; # If the test counter is being pushed forward fill in the details. my $test_results = $self->{Test_Results}; if( $num > @$test_results ) { my $start = @$test_results ? @$test_results : 0; for( $start .. $num - 1 ) { $test_results->[$_] = &share( { 'ok' => 1, actual_ok => undef, reason => 'incrementing test number', type => 'unknown', name => undef } ); } } # If backward, wipe history. Its their funeral. elsif( $num < @$test_results ) { $#{$test_results} = $num - 1; } } return $self->{Curr_Test}; } =item B my $ok = $builder->is_passing; Indicates if the test suite is currently passing. More formally, it will be false if anything has happened which makes it impossible for the test suite to pass. True otherwise. For example, if no tests have run C will be true because even though a suite with no tests is a failure you can add a passing test to it and start passing. Don't think about it too much. =cut sub is_passing { my $self = shift; if( @_ ) { $self->{Is_Passing} = shift; } return $self->{Is_Passing}; } =item B my @tests = $Test->summary; A simple summary of the tests so far. True for pass, false for fail. This is a logical pass/fail, so todos are passes. Of course, test #1 is $tests[0], etc... =cut sub summary { my($self) = shift; return map { $_->{'ok'} } @{ $self->{Test_Results} }; } =item B
my @tests = $Test->details; Like C, but with a lot more detail. $tests[$test_num - 1] = { 'ok' => is the test considered a pass? actual_ok => did it literally say 'ok'? name => name of the test (if any) type => type of test (if any, see below). reason => reason for the above (if any) }; 'ok' is true if Test::Harness will consider the test to be a pass. 'actual_ok' is a reflection of whether or not the test literally printed 'ok' or 'not ok'. This is for examining the result of 'todo' tests. 'name' is the name of the test. 'type' indicates if it was a special test. Normal tests have a type of ''. Type can be one of the following: skip see skip() todo see todo() todo_skip see todo_skip() unknown see below Sometimes the Test::Builder test counter is incremented without it printing any test output, for example, when C is changed. In these cases, Test::Builder doesn't know the result of the test, so its type is 'unknown'. These details for these tests are filled in. They are considered ok, but the name and actual_ok is left C. For example "not ok 23 - hole count # TODO insufficient donuts" would result in this structure: $tests[22] = # 23 - 1, since arrays start from 0. { ok => 1, # logically, the test passed since its todo actual_ok => 0, # in absolute terms, it failed name => 'hole count', type => 'todo', reason => 'insufficient donuts' }; =cut sub details { my $self = shift; return @{ $self->{Test_Results} }; } =item B my $todo_reason = $Test->todo; my $todo_reason = $Test->todo($pack); If the current tests are considered "TODO" it will return the reason, if any. This reason can come from a C<$TODO> variable or the last call to C. Since a TODO test does not need a reason, this function can return an empty string even when inside a TODO block. Use C<< $Test->in_todo >> to determine if you are currently inside a TODO block. C is about finding the right package to look for C<$TODO> in. It's pretty good at guessing the right package to look at. It first looks for the caller based on C<$Level + 1>, since C is usually called inside a test function. As a last resort it will use C. Sometimes there is some confusion about where todo() should be looking for the C<$TODO> variable. If you want to be sure, tell it explicitly what $pack to use. =cut sub todo { my( $self, $pack ) = @_; return $self->{Todo} if defined $self->{Todo}; local $Level = $Level + 1; my $todo = $self->find_TODO($pack); return $todo if defined $todo; return ''; } =item B my $todo_reason = $Test->find_TODO(); my $todo_reason = $Test->find_TODO($pack); Like C but only returns the value of C<$TODO> ignoring C. Can also be used to set C<$TODO> to a new value while returning the old value: my $old_reason = $Test->find_TODO($pack, 1, $new_reason); =cut sub find_TODO { my( $self, $pack, $set, $new_value ) = @_; $pack = $pack || $self->caller(1) || $self->exported_to; return unless $pack; no strict 'refs'; ## no critic my $old_value = ${ $pack . '::TODO' }; $set and ${ $pack . '::TODO' } = $new_value; return $old_value; } =item B my $in_todo = $Test->in_todo; Returns true if the test is currently inside a TODO block. =cut sub in_todo { my $self = shift; local $Level = $Level + 1; return( defined $self->{Todo} || $self->find_TODO ) ? 1 : 0; } =item B $Test->todo_start(); $Test->todo_start($message); This method allows you declare all subsequent tests as TODO tests, up until the C method has been called. The C and C<$TODO> syntax is generally pretty good about figuring out whether or not we're in a TODO test. However, often we find that this is not possible to determine (such as when we want to use C<$TODO> but the tests are being executed in other packages which can't be inferred beforehand). Note that you can use this to nest "todo" tests $Test->todo_start('working on this'); # lots of code $Test->todo_start('working on that'); # more code $Test->todo_end; $Test->todo_end; This is generally not recommended, but large testing systems often have weird internal needs. We've tried to make this also work with the TODO: syntax, but it's not guaranteed and its use is also discouraged: TODO: { local $TODO = 'We have work to do!'; $Test->todo_start('working on this'); # lots of code $Test->todo_start('working on that'); # more code $Test->todo_end; $Test->todo_end; } Pick one style or another of "TODO" to be on the safe side. =cut sub todo_start { my $self = shift; my $message = @_ ? shift : ''; $self->{Start_Todo}++; if( $self->in_todo ) { push @{ $self->{Todo_Stack} } => $self->todo; } $self->{Todo} = $message; return; } =item C $Test->todo_end; Stops running tests as "TODO" tests. This method is fatal if called without a preceding C method call. =cut sub todo_end { my $self = shift; if( !$self->{Start_Todo} ) { $self->croak('todo_end() called without todo_start()'); } $self->{Start_Todo}--; if( $self->{Start_Todo} && @{ $self->{Todo_Stack} } ) { $self->{Todo} = pop @{ $self->{Todo_Stack} }; } else { delete $self->{Todo}; } return; } =item B my $package = $Test->caller; my($pack, $file, $line) = $Test->caller; my($pack, $file, $line) = $Test->caller($height); Like the normal C, except it reports according to your C. C<$height> will be added to the C. If C winds up off the top of the stack it report the highest context. =cut sub caller { ## no critic (Subroutines::ProhibitBuiltinHomonyms) my( $self, $height ) = @_; $height ||= 0; my $level = $self->level + $height + 1; my @caller; do { @caller = CORE::caller( $level ); $level--; } until @caller; return wantarray ? @caller : $caller[0]; } =back =cut =begin _private =over 4 =item B<_sanity_check> $self->_sanity_check(); Runs a bunch of end of test sanity checks to make sure reality came through ok. If anything is wrong it will die with a fairly friendly error message. =cut #'# sub _sanity_check { my $self = shift; $self->_whoa( $self->{Curr_Test} < 0, 'Says here you ran a negative number of tests!' ); $self->_whoa( $self->{Curr_Test} != @{ $self->{Test_Results} }, 'Somehow you got a different number of results than tests ran!' ); return; } =item B<_whoa> $self->_whoa($check, $description); A sanity check, similar to C. If the C<$check> is true, something has gone horribly wrong. It will die with the given C<$description> and a note to contact the author. =cut sub _whoa { my( $self, $check, $desc ) = @_; if($check) { local $Level = $Level + 1; $self->croak(<<"WHOA"); WHOA! $desc This should never happen! Please contact the author immediately! WHOA } return; } =item B<_my_exit> _my_exit($exit_num); Perl seems to have some trouble with exiting inside an C block. 5.6.1 does some odd things. Instead, this function edits C<$?> directly. It should B be called from inside an C block. It doesn't actually exit, that's your job. =cut sub _my_exit { $? = $_[0]; ## no critic (Variables::RequireLocalizedPunctuationVars) return 1; } =back =end _private =cut sub _ending { my $self = shift; return if $self->no_ending; return if $self->{Ending}++; my $real_exit_code = $?; # Don't bother with an ending if this is a forked copy. Only the parent # should do the ending. if( $self->{Original_Pid} != $$ ) { return; } # Ran tests but never declared a plan or hit done_testing if( !$self->{Have_Plan} and $self->{Curr_Test} ) { $self->is_passing(0); $self->diag("Tests were run but no plan was declared and done_testing() was not seen."); } # Exit if plan() was never called. This is so "require Test::Simple" # doesn't puke. if( !$self->{Have_Plan} ) { return; } # Don't do an ending if we bailed out. if( $self->{Bailed_Out} ) { $self->is_passing(0); return; } # Figure out if we passed or failed and print helpful messages. my $test_results = $self->{Test_Results}; if(@$test_results) { # The plan? We have no plan. if( $self->{No_Plan} ) { $self->_output_plan($self->{Curr_Test}) unless $self->no_header; $self->{Expected_Tests} = $self->{Curr_Test}; } # Auto-extended arrays and elements which aren't explicitly # filled in with a shared reference will puke under 5.8.0 # ithreads. So we have to fill them in by hand. :( my $empty_result = &share( {} ); for my $idx ( 0 .. $self->{Expected_Tests} - 1 ) { $test_results->[$idx] = $empty_result unless defined $test_results->[$idx]; } my $num_failed = grep !$_->{'ok'}, @{$test_results}[ 0 .. $self->{Curr_Test} - 1 ]; my $num_extra = $self->{Curr_Test} - $self->{Expected_Tests}; if( $num_extra != 0 ) { my $s = $self->{Expected_Tests} == 1 ? '' : 's'; $self->diag(<<"FAIL"); Looks like you planned $self->{Expected_Tests} test$s but ran $self->{Curr_Test}. FAIL $self->is_passing(0); } if($num_failed) { my $num_tests = $self->{Curr_Test}; my $s = $num_failed == 1 ? '' : 's'; my $qualifier = $num_extra == 0 ? '' : ' run'; $self->diag(<<"FAIL"); Looks like you failed $num_failed test$s of $num_tests$qualifier. FAIL $self->is_passing(0); } if($real_exit_code) { $self->diag(<<"FAIL"); Looks like your test exited with $real_exit_code just after $self->{Curr_Test}. FAIL $self->is_passing(0); _my_exit($real_exit_code) && return; } my $exit_code; if($num_failed) { $exit_code = $num_failed <= 254 ? $num_failed : 254; } elsif( $num_extra != 0 ) { $exit_code = 255; } else { $exit_code = 0; } _my_exit($exit_code) && return; } elsif( $self->{Skip_All} ) { _my_exit(0) && return; } elsif($real_exit_code) { $self->diag(<<"FAIL"); Looks like your test exited with $real_exit_code before it could output anything. FAIL $self->is_passing(0); _my_exit($real_exit_code) && return; } else { $self->diag("No tests run!\n"); $self->is_passing(0); _my_exit(255) && return; } $self->is_passing(0); $self->_whoa( 1, "We fell off the end of _ending()" ); } END { $Test->_ending if defined $Test; } =head1 EXIT CODES If all your tests passed, Test::Builder will exit with zero (which is normal). If anything failed it will exit with how many failed. If you run less (or more) tests than you planned, the missing (or extras) will be considered failures. If no tests were ever run Test::Builder will throw a warning and exit with 255. If the test died, even after having successfully completed all its tests, it will still be considered a failure and will exit with 255. So the exit codes are... 0 all tests successful 255 test died or all passed but wrong # of tests run any other number how many failed (including missing or extras) If you fail more than 254 tests, it will be reported as 254. =head1 THREADS In perl 5.8.1 and later, Test::Builder is thread-safe. The test number is shared amongst all threads. This means if one thread sets the test number using C they will all be effected. While versions earlier than 5.8.1 had threads they contain too many bugs to support. Test::Builder is only thread-aware if threads.pm is loaded I Test::Builder. =head1 MEMORY An informative hash, accessible via C<>, is stored for each test you perform. So memory usage will scale linearly with each test run. Although this is not a problem for most test suites, it can become an issue if you do large (hundred thousands to million) combinatorics tests in the same run. In such cases, you are advised to either split the test file into smaller ones, or use a reverse approach, doing "normal" (code) compares and triggering fail() should anything go unexpected. Future versions of Test::Builder will have a way to turn history off. =head1 EXAMPLES CPAN can provide the best examples. Test::Simple, Test::More, Test::Exception and Test::Differences all use Test::Builder. =head1 SEE ALSO Test::Simple, Test::More, Test::Harness =head1 AUTHORS Original code by chromatic, maintained by Michael G Schwern Eschwern@pobox.comE =head1 COPYRIGHT Copyright 2002-2008 by chromatic Echromatic@wgz.orgE and Michael G Schwern Eschwern@pobox.comE. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See F =cut 1; More.pm000644001750001750 13313613601673061 16776 0ustar00taitai000000000000Type-Tiny-1.008001/inc/archaic/Testpackage Test::More; use 5.006; use strict; use warnings; #---- perlcritic exemptions. ----# # We use a lot of subroutine prototypes ## no critic (Subroutines::ProhibitSubroutinePrototypes) # Can't use Carp because it might cause use_ok() to accidentally succeed # even though the module being used forgot to use Carp. Yes, this # actually happened. sub _carp { my( $file, $line ) = ( caller(1) )[ 1, 2 ]; return warn @_, " at $file line $line\n"; } our $VERSION = '0.98'; $VERSION = eval $VERSION; ## no critic (BuiltinFunctions::ProhibitStringyEval) use Test::Builder::Module; our @ISA = qw(Test::Builder::Module); our @EXPORT = qw(ok use_ok require_ok is isnt like unlike is_deeply cmp_ok skip todo todo_skip pass fail eq_array eq_hash eq_set $TODO plan done_testing can_ok isa_ok new_ok diag note explain subtest BAIL_OUT ); =head1 NAME Test::More - yet another framework for writing test scripts =head1 SYNOPSIS use Test::More tests => 23; # or use Test::More skip_all => $reason; # or use Test::More; # see done_testing() BEGIN { use_ok( 'Some::Module' ); } require_ok( 'Some::Module' ); # Various ways to say "ok" ok($got eq $expected, $test_name); is ($got, $expected, $test_name); isnt($got, $expected, $test_name); # Rather than print STDERR "# here's what went wrong\n" diag("here's what went wrong"); like ($got, qr/expected/, $test_name); unlike($got, qr/expected/, $test_name); cmp_ok($got, '==', $expected, $test_name); is_deeply($got_complex_structure, $expected_complex_structure, $test_name); SKIP: { skip $why, $how_many unless $have_some_feature; ok( foo(), $test_name ); is( foo(42), 23, $test_name ); }; TODO: { local $TODO = $why; ok( foo(), $test_name ); is( foo(42), 23, $test_name ); }; can_ok($module, @methods); isa_ok($object, $class); pass($test_name); fail($test_name); BAIL_OUT($why); # UNIMPLEMENTED!!! my @status = Test::More::status; =head1 DESCRIPTION B If you're just getting started writing tests, have a look at L first. This is a drop in replacement for Test::Simple which you can switch to once you get the hang of basic testing. The purpose of this module is to provide a wide range of testing utilities. Various ways to say "ok" with better diagnostics, facilities to skip tests, test future features and compare complicated data structures. While you can do almost anything with a simple C function, it doesn't provide good diagnostic output. =head2 I love it when a plan comes together Before anything else, you need a testing plan. This basically declares how many tests your script is going to run to protect against premature failure. The preferred way to do this is to declare a plan when you C. use Test::More tests => 23; There are cases when you will not know beforehand how many tests your script is going to run. In this case, you can declare your tests at the end. use Test::More; ... run your tests ... done_testing( $number_of_tests_run ); Sometimes you really don't know how many tests were run, or it's too difficult to calculate. In which case you can leave off $number_of_tests_run. In some cases, you'll want to completely skip an entire testing script. use Test::More skip_all => $skip_reason; Your script will declare a skip with the reason why you skipped and exit immediately with a zero (success). See L for details. If you want to control what functions Test::More will export, you have to use the 'import' option. For example, to import everything but 'fail', you'd do: use Test::More tests => 23, import => ['!fail']; Alternatively, you can use the plan() function. Useful for when you have to calculate the number of tests. use Test::More; plan tests => keys %Stuff * 3; or for deciding between running the tests at all: use Test::More; if( $^O eq 'MacOS' ) { plan skip_all => 'Test irrelevant on MacOS'; } else { plan tests => 42; } =cut sub plan { my $tb = Test::More->builder; return $tb->plan(@_); } # This implements "use Test::More 'no_diag'" but the behavior is # deprecated. sub import_extra { my $class = shift; my $list = shift; my @other = (); my $idx = 0; while( $idx <= $#{$list} ) { my $item = $list->[$idx]; if( defined $item and $item eq 'no_diag' ) { $class->builder->no_diag(1); } else { push @other, $item; } $idx++; } @$list = @other; return; } =over 4 =item B done_testing(); done_testing($number_of_tests); If you don't know how many tests you're going to run, you can issue the plan when you're done running tests. $number_of_tests is the same as plan(), it's the number of tests you expected to run. You can omit this, in which case the number of tests you ran doesn't matter, just the fact that your tests ran to conclusion. This is safer than and replaces the "no_plan" plan. =back =cut sub done_testing { my $tb = Test::More->builder; $tb->done_testing(@_); } =head2 Test names By convention, each test is assigned a number in order. This is largely done automatically for you. However, it's often very useful to assign a name to each test. Which would you rather see: ok 4 not ok 5 ok 6 or ok 4 - basic multi-variable not ok 5 - simple exponential ok 6 - force == mass * acceleration The later gives you some idea of what failed. It also makes it easier to find the test in your script, simply search for "simple exponential". All test functions take a name argument. It's optional, but highly suggested that you use it. =head2 I'm ok, you're not ok. The basic purpose of this module is to print out either "ok #" or "not ok #" depending on if a given test succeeded or failed. Everything else is just gravy. All of the following print "ok" or "not ok" depending on if the test succeeded or failed. They all also return true or false, respectively. =over 4 =item B ok($got eq $expected, $test_name); This simply evaluates any expression (C<$got eq $expected> is just a simple example) and uses that to determine if the test succeeded or failed. A true expression passes, a false one fails. Very simple. For example: ok( $exp{9} == 81, 'simple exponential' ); ok( Film->can('db_Main'), 'set_db()' ); ok( $p->tests == 4, 'saw tests' ); ok( !grep !defined $_, @items, 'items populated' ); (Mnemonic: "This is ok.") $test_name is a very short description of the test that will be printed out. It makes it very easy to find a test in your script when it fails and gives others an idea of your intentions. $test_name is optional, but we B strongly encourage its use. Should an ok() fail, it will produce some diagnostics: not ok 18 - sufficient mucus # Failed test 'sufficient mucus' # in foo.t at line 42. This is the same as Test::Simple's ok() routine. =cut sub ok ($;$) { my( $test, $name ) = @_; my $tb = Test::More->builder; return $tb->ok( $test, $name ); } =item B =item B is ( $got, $expected, $test_name ); isnt( $got, $expected, $test_name ); Similar to ok(), is() and isnt() compare their two arguments with C and C respectively and use the result of that to determine if the test succeeded or failed. So these: # Is the ultimate answer 42? is( ultimate_answer(), 42, "Meaning of Life" ); # $foo isn't empty isnt( $foo, '', "Got some foo" ); are similar to these: ok( ultimate_answer() eq 42, "Meaning of Life" ); ok( $foo ne '', "Got some foo" ); C will only ever match C. So you can test a value agains C like this: is($not_defined, undef, "undefined as expected"); (Mnemonic: "This is that." "This isn't that.") So why use these? They produce better diagnostics on failure. ok() cannot know what you are testing for (beyond the name), but is() and isnt() know what the test was and why it failed. For example this test: my $foo = 'waffle'; my $bar = 'yarblokos'; is( $foo, $bar, 'Is foo the same as bar?' ); Will produce something like this: not ok 17 - Is foo the same as bar? # Failed test 'Is foo the same as bar?' # in foo.t at line 139. # got: 'waffle' # expected: 'yarblokos' So you can figure out what went wrong without rerunning the test. You are encouraged to use is() and isnt() over ok() where possible, however do not be tempted to use them to find out if something is true or false! # XXX BAD! is( exists $brooklyn{tree}, 1, 'A tree grows in Brooklyn' ); This does not check if C is true, it checks if it returns 1. Very different. Similar caveats exist for false and 0. In these cases, use ok(). ok( exists $brooklyn{tree}, 'A tree grows in Brooklyn' ); A simple call to isnt() usually does not provide a strong test but there are cases when you cannot say much more about a value than that it is different from some other value: new_ok $obj, "Foo"; my $clone = $obj->clone; isa_ok $obj, "Foo", "Foo->clone"; isnt $obj, $clone, "clone() produces a different object"; For those grammatical pedants out there, there's an C function which is an alias of isnt(). =cut sub is ($$;$) { my $tb = Test::More->builder; return $tb->is_eq(@_); } sub isnt ($$;$) { my $tb = Test::More->builder; return $tb->isnt_eq(@_); } *isn't = \&isnt; =item B like( $got, qr/expected/, $test_name ); Similar to ok(), like() matches $got against the regex C. So this: like($got, qr/expected/, 'this is like that'); is similar to: ok( $got =~ /expected/, 'this is like that'); (Mnemonic "This is like that".) The second argument is a regular expression. It may be given as a regex reference (i.e. C) or (for better compatibility with older perls) as a string that looks like a regex (alternative delimiters are currently not supported): like( $got, '/expected/', 'this is like that' ); Regex options may be placed on the end (C<'/expected/i'>). Its advantages over ok() are similar to that of is() and isnt(). Better diagnostics on failure. =cut sub like ($$;$) { my $tb = Test::More->builder; return $tb->like(@_); } =item B unlike( $got, qr/expected/, $test_name ); Works exactly as like(), only it checks if $got B match the given pattern. =cut sub unlike ($$;$) { my $tb = Test::More->builder; return $tb->unlike(@_); } =item B cmp_ok( $got, $op, $expected, $test_name ); Halfway between ok() and is() lies cmp_ok(). This allows you to compare two arguments using any binary perl operator. # ok( $got eq $expected ); cmp_ok( $got, 'eq', $expected, 'this eq that' ); # ok( $got == $expected ); cmp_ok( $got, '==', $expected, 'this == that' ); # ok( $got && $expected ); cmp_ok( $got, '&&', $expected, 'this && that' ); ...etc... Its advantage over ok() is when the test fails you'll know what $got and $expected were: not ok 1 # Failed test in foo.t at line 12. # '23' # && # undef It's also useful in those cases where you are comparing numbers and is()'s use of C will interfere: cmp_ok( $big_hairy_number, '==', $another_big_hairy_number ); It's especially useful when comparing greater-than or smaller-than relation between values: cmp_ok( $some_value, '<=', $upper_limit ); =cut sub cmp_ok($$$;$) { my $tb = Test::More->builder; return $tb->cmp_ok(@_); } =item B can_ok($module, @methods); can_ok($object, @methods); Checks to make sure the $module or $object can do these @methods (works with functions, too). can_ok('Foo', qw(this that whatever)); is almost exactly like saying: ok( Foo->can('this') && Foo->can('that') && Foo->can('whatever') ); only without all the typing and with a better interface. Handy for quickly testing an interface. No matter how many @methods you check, a single can_ok() call counts as one test. If you desire otherwise, use: foreach my $meth (@methods) { can_ok('Foo', $meth); } =cut sub can_ok ($@) { my( $proto, @methods ) = @_; my $class = ref $proto || $proto; my $tb = Test::More->builder; unless($class) { my $ok = $tb->ok( 0, "->can(...)" ); $tb->diag(' can_ok() called with empty class or reference'); return $ok; } unless(@methods) { my $ok = $tb->ok( 0, "$class->can(...)" ); $tb->diag(' can_ok() called with no methods'); return $ok; } my @nok = (); foreach my $method (@methods) { $tb->_try( sub { $proto->can($method) } ) or push @nok, $method; } my $name = (@methods == 1) ? "$class->can('$methods[0]')" : "$class->can(...)" ; my $ok = $tb->ok( !@nok, $name ); $tb->diag( map " $class->can('$_') failed\n", @nok ); return $ok; } =item B isa_ok($object, $class, $object_name); isa_ok($subclass, $class, $object_name); isa_ok($ref, $type, $ref_name); Checks to see if the given C<< $object->isa($class) >>. Also checks to make sure the object was defined in the first place. Handy for this sort of thing: my $obj = Some::Module->new; isa_ok( $obj, 'Some::Module' ); where you'd otherwise have to write my $obj = Some::Module->new; ok( defined $obj && $obj->isa('Some::Module') ); to safeguard against your test script blowing up. You can also test a class, to make sure that it has the right ancestor: isa_ok( 'Vole', 'Rodent' ); It works on references, too: isa_ok( $array_ref, 'ARRAY' ); The diagnostics of this test normally just refer to 'the object'. If you'd like them to be more specific, you can supply an $object_name (for example 'Test customer'). =cut sub isa_ok ($$;$) { my( $object, $class, $obj_name ) = @_; my $tb = Test::More->builder; my $diag; if( !defined $object ) { $obj_name = 'The thing' unless defined $obj_name; $diag = "$obj_name isn't defined"; } else { my $whatami = ref $object ? 'object' : 'class'; # We can't use UNIVERSAL::isa because we want to honor isa() overrides my( $rslt, $error ) = $tb->_try( sub { $object->isa($class) } ); if($error) { if( $error =~ /^Can't call method "isa" on unblessed reference/ ) { # Its an unblessed reference $obj_name = 'The reference' unless defined $obj_name; if( !UNIVERSAL::isa( $object, $class ) ) { my $ref = ref $object; $diag = "$obj_name isn't a '$class' it's a '$ref'"; } } elsif( $error =~ /Can't call method "isa" without a package/ ) { # It's something that can't even be a class $obj_name = 'The thing' unless defined $obj_name; $diag = "$obj_name isn't a class or reference"; } else { die <isa on your $whatami and got some weird error. Here's the error. $error WHOA } } else { $obj_name = "The $whatami" unless defined $obj_name; if( !$rslt ) { my $ref = ref $object; $diag = "$obj_name isn't a '$class' it's a '$ref'"; } } } my $name = "$obj_name isa $class"; my $ok; if($diag) { $ok = $tb->ok( 0, $name ); $tb->diag(" $diag\n"); } else { $ok = $tb->ok( 1, $name ); } return $ok; } =item B my $obj = new_ok( $class ); my $obj = new_ok( $class => \@args ); my $obj = new_ok( $class => \@args, $object_name ); A convenience function which combines creating an object and calling isa_ok() on that object. It is basically equivalent to: my $obj = $class->new(@args); isa_ok $obj, $class, $object_name; If @args is not given, an empty list will be used. This function only works on new() and it assumes new() will return just a single object which isa C<$class>. =cut sub new_ok { my $tb = Test::More->builder; $tb->croak("new_ok() must be given at least a class") unless @_; my( $class, $args, $object_name ) = @_; $args ||= []; $object_name = "The object" unless defined $object_name; my $obj; my( $success, $error ) = $tb->_try( sub { $obj = $class->new(@$args); 1 } ); if($success) { local $Test::Builder::Level = $Test::Builder::Level + 1; isa_ok $obj, $class, $object_name; } else { $tb->ok( 0, "new() died" ); $tb->diag(" Error was: $error"); } return $obj; } =item B subtest $name => \&code; subtest() runs the &code as its own little test with its own plan and its own result. The main test counts this as a single test using the result of the whole subtest to determine if its ok or not ok. For example... use Test::More tests => 3; pass("First test"); subtest 'An example subtest' => sub { plan tests => 2; pass("This is a subtest"); pass("So is this"); }; pass("Third test"); This would produce. 1..3 ok 1 - First test 1..2 ok 1 - This is a subtest ok 2 - So is this ok 2 - An example subtest ok 3 - Third test A subtest may call "skip_all". No tests will be run, but the subtest is considered a skip. subtest 'skippy' => sub { plan skip_all => 'cuz I said so'; pass('this test will never be run'); }; Returns true if the subtest passed, false otherwise. Due to how subtests work, you may omit a plan if you desire. This adds an implicit C to the end of your subtest. The following two subtests are equivalent: subtest 'subtest with implicit done_testing()', sub { ok 1, 'subtests with an implicit done testing should work'; ok 1, '... and support more than one test'; ok 1, '... no matter how many tests are run'; }; subtest 'subtest with explicit done_testing()', sub { ok 1, 'subtests with an explicit done testing should work'; ok 1, '... and support more than one test'; ok 1, '... no matter how many tests are run'; done_testing(); }; =cut sub subtest { my ($name, $subtests) = @_; my $tb = Test::More->builder; return $tb->subtest(@_); } =item B =item B pass($test_name); fail($test_name); Sometimes you just want to say that the tests have passed. Usually the case is you've got some complicated condition that is difficult to wedge into an ok(). In this case, you can simply use pass() (to declare the test ok) or fail (for not ok). They are synonyms for ok(1) and ok(0). Use these very, very, very sparingly. =cut sub pass (;$) { my $tb = Test::More->builder; return $tb->ok( 1, @_ ); } sub fail (;$) { my $tb = Test::More->builder; return $tb->ok( 0, @_ ); } =back =head2 Module tests You usually want to test if the module you're testing loads ok, rather than just vomiting if its load fails. For such purposes we have C and C. =over 4 =item B BEGIN { use_ok($module); } BEGIN { use_ok($module, @imports); } These simply use the given $module and test to make sure the load happened ok. It's recommended that you run use_ok() inside a BEGIN block so its functions are exported at compile-time and prototypes are properly honored. If @imports are given, they are passed through to the use. So this: BEGIN { use_ok('Some::Module', qw(foo bar)) } is like doing this: use Some::Module qw(foo bar); Version numbers can be checked like so: # Just like "use Some::Module 1.02" BEGIN { use_ok('Some::Module', 1.02) } Don't try to do this: BEGIN { use_ok('Some::Module'); ...some code that depends on the use... ...happening at compile time... } because the notion of "compile-time" is relative. Instead, you want: BEGIN { use_ok('Some::Module') } BEGIN { ...some code that depends on the use... } If you want the equivalent of C, use a module but not import anything, use C. BEGIN { require_ok "Foo" } =cut sub use_ok ($;@) { my( $module, @imports ) = @_; @imports = () unless @imports; my $tb = Test::More->builder; my( $pack, $filename, $line ) = caller; my $code; if( @imports == 1 and $imports[0] =~ /^\d+(?:\.\d+)?$/ ) { # probably a version check. Perl needs to see the bare number # for it to work with non-Exporter based modules. $code = <ok( $eval_result, "use $module;" ); unless($ok) { chomp $eval_error; $@ =~ s{^BEGIN failed--compilation aborted at .*$} {BEGIN failed--compilation aborted at $filename line $line.}m; $tb->diag(< require_ok($module); require_ok($file); Like use_ok(), except it requires the $module or $file. =cut sub require_ok ($) { my($module) = shift; my $tb = Test::More->builder; my $pack = caller; # Try to determine if we've been given a module name or file. # Module names must be barewords, files not. $module = qq['$module'] unless _is_module_name($module); my $code = <ok( $eval_result, "require $module;" ); unless($ok) { chomp $eval_error; $tb->diag(< I'm not quite sure what will happen with filehandles. =over 4 =item B is_deeply( $got, $expected, $test_name ); Similar to is(), except that if $got and $expected are references, it does a deep comparison walking each data structure to see if they are equivalent. If the two structures are different, it will display the place where they start differing. is_deeply() compares the dereferenced values of references, the references themselves (except for their type) are ignored. This means aspects such as blessing and ties are not considered "different". is_deeply() currently has very limited handling of function reference and globs. It merely checks if they have the same referent. This may improve in the future. L and L provide more in-depth functionality along these lines. =cut our( @Data_Stack, %Refs_Seen ); my $DNE = bless [], 'Does::Not::Exist'; sub _dne { return ref $_[0] eq ref $DNE; } ## no critic (Subroutines::RequireArgUnpacking) sub is_deeply { my $tb = Test::More->builder; unless( @_ == 2 or @_ == 3 ) { my $msg = <<'WARNING'; is_deeply() takes two or three args, you gave %d. This usually means you passed an array or hash instead of a reference to it WARNING chop $msg; # clip off newline so carp() will put in line/file _carp sprintf $msg, scalar @_; return $tb->ok(0); } my( $got, $expected, $name ) = @_; $tb->_unoverload_str( \$expected, \$got ); my $ok; if( !ref $got and !ref $expected ) { # neither is a reference $ok = $tb->is_eq( $got, $expected, $name ); } elsif( !ref $got xor !ref $expected ) { # one's a reference, one isn't $ok = $tb->ok( 0, $name ); $tb->diag( _format_stack({ vals => [ $got, $expected ] }) ); } else { # both references local @Data_Stack = (); if( _deep_check( $got, $expected ) ) { $ok = $tb->ok( 1, $name ); } else { $ok = $tb->ok( 0, $name ); $tb->diag( _format_stack(@Data_Stack) ); } } return $ok; } sub _format_stack { my(@Stack) = @_; my $var = '$FOO'; my $did_arrow = 0; foreach my $entry (@Stack) { my $type = $entry->{type} || ''; my $idx = $entry->{'idx'}; if( $type eq 'HASH' ) { $var .= "->" unless $did_arrow++; $var .= "{$idx}"; } elsif( $type eq 'ARRAY' ) { $var .= "->" unless $did_arrow++; $var .= "[$idx]"; } elsif( $type eq 'REF' ) { $var = "\${$var}"; } } my @vals = @{ $Stack[-1]{vals} }[ 0, 1 ]; my @vars = (); ( $vars[0] = $var ) =~ s/\$FOO/ \$got/; ( $vars[1] = $var ) =~ s/\$FOO/\$expected/; my $out = "Structures begin differing at:\n"; foreach my $idx ( 0 .. $#vals ) { my $val = $vals[$idx]; $vals[$idx] = !defined $val ? 'undef' : _dne($val) ? "Does not exist" : ref $val ? "$val" : "'$val'"; } $out .= "$vars[0] = $vals[0]\n"; $out .= "$vars[1] = $vals[1]\n"; $out =~ s/^/ /msg; return $out; } sub _type { my $thing = shift; return '' if !ref $thing; for my $type (qw(Regexp ARRAY HASH REF SCALAR GLOB CODE)) { return $type if UNIVERSAL::isa( $thing, $type ); } return ''; } =back =head2 Diagnostics If you pick the right test function, you'll usually get a good idea of what went wrong when it failed. But sometimes it doesn't work out that way. So here we have ways for you to write your own diagnostic messages which are safer than just C. =over 4 =item B diag(@diagnostic_message); Prints a diagnostic message which is guaranteed not to interfere with test output. Like C @diagnostic_message is simply concatenated together. Returns false, so as to preserve failure. Handy for this sort of thing: ok( grep(/foo/, @users), "There's a foo user" ) or diag("Since there's no foo, check that /etc/bar is set up right"); which would produce: not ok 42 - There's a foo user # Failed test 'There's a foo user' # in foo.t at line 52. # Since there's no foo, check that /etc/bar is set up right. You might remember C with the mnemonic C. B The exact formatting of the diagnostic output is still changing, but it is guaranteed that whatever you throw at it it won't interfere with the test. =item B note(@diagnostic_message); Like diag(), except the message will not be seen when the test is run in a harness. It will only be visible in the verbose TAP stream. Handy for putting in notes which might be useful for debugging, but don't indicate a problem. note("Tempfile is $tempfile"); =cut sub diag { return Test::More->builder->diag(@_); } sub note { return Test::More->builder->note(@_); } =item B my @dump = explain @diagnostic_message; Will dump the contents of any references in a human readable format. Usually you want to pass this into C or C. Handy for things like... is_deeply($have, $want) || diag explain $have; or note explain \%args; Some::Class->method(%args); =cut sub explain { return Test::More->builder->explain(@_); } =back =head2 Conditional tests Sometimes running a test under certain conditions will cause the test script to die. A certain function or method isn't implemented (such as fork() on MacOS), some resource isn't available (like a net connection) or a module isn't available. In these cases it's necessary to skip tests, or declare that they are supposed to fail but will work in the future (a todo test). For more details on the mechanics of skip and todo tests see L. The way Test::More handles this is with a named block. Basically, a block of tests which can be skipped over or made todo. It's best if I just show you... =over 4 =item B SKIP: { skip $why, $how_many if $condition; ...normal testing code goes here... } This declares a block of tests that might be skipped, $how_many tests there are, $why and under what $condition to skip them. An example is the easiest way to illustrate: SKIP: { eval { require HTML::Lint }; skip "HTML::Lint not installed", 2 if $@; my $lint = new HTML::Lint; isa_ok( $lint, "HTML::Lint" ); $lint->parse( $html ); is( $lint->errors, 0, "No errors found in HTML" ); } If the user does not have HTML::Lint installed, the whole block of code I. Test::More will output special ok's which Test::Harness interprets as skipped, but passing, tests. It's important that $how_many accurately reflects the number of tests in the SKIP block so the # of tests run will match up with your plan. If your plan is C $how_many is optional and will default to 1. It's perfectly safe to nest SKIP blocks. Each SKIP block must have the label C, or Test::More can't work its magic. You don't skip tests which are failing because there's a bug in your program, or for which you don't yet have code written. For that you use TODO. Read on. =cut ## no critic (Subroutines::RequireFinalReturn) sub skip { my( $why, $how_many ) = @_; my $tb = Test::More->builder; unless( defined $how_many ) { # $how_many can only be avoided when no_plan is in use. _carp "skip() needs to know \$how_many tests are in the block" unless $tb->has_plan eq 'no_plan'; $how_many = 1; } if( defined $how_many and $how_many =~ /\D/ ) { _carp "skip() was passed a non-numeric number of tests. Did you get the arguments backwards?"; $how_many = 1; } for( 1 .. $how_many ) { $tb->skip($why); } no warnings 'exiting'; last SKIP; } =item B TODO: { local $TODO = $why if $condition; ...normal testing code goes here... } Declares a block of tests you expect to fail and $why. Perhaps it's because you haven't fixed a bug or haven't finished a new feature: TODO: { local $TODO = "URI::Geller not finished"; my $card = "Eight of clubs"; is( URI::Geller->your_card, $card, 'Is THIS your card?' ); my $spoon; URI::Geller->bend_spoon; is( $spoon, 'bent', "Spoon bending, that's original" ); } With a todo block, the tests inside are expected to fail. Test::More will run the tests normally, but print out special flags indicating they are "todo". Test::Harness will interpret failures as being ok. Should anything succeed, it will report it as an unexpected success. You then know the thing you had todo is done and can remove the TODO flag. The nice part about todo tests, as opposed to simply commenting out a block of tests, is it's like having a programmatic todo list. You know how much work is left to be done, you're aware of what bugs there are, and you'll know immediately when they're fixed. Once a todo test starts succeeding, simply move it outside the block. When the block is empty, delete it. =item B TODO: { todo_skip $why, $how_many if $condition; ...normal testing code... } With todo tests, it's best to have the tests actually run. That way you'll know when they start passing. Sometimes this isn't possible. Often a failing test will cause the whole program to die or hang, even inside an C with and using C. In these extreme cases you have no choice but to skip over the broken tests entirely. The syntax and behavior is similar to a C except the tests will be marked as failing but todo. Test::Harness will interpret them as passing. =cut sub todo_skip { my( $why, $how_many ) = @_; my $tb = Test::More->builder; unless( defined $how_many ) { # $how_many can only be avoided when no_plan is in use. _carp "todo_skip() needs to know \$how_many tests are in the block" unless $tb->has_plan eq 'no_plan'; $how_many = 1; } for( 1 .. $how_many ) { $tb->todo_skip($why); } no warnings 'exiting'; last TODO; } =item When do I use SKIP vs. TODO? B, use SKIP. This includes optional modules that aren't installed, running under an OS that doesn't have some feature (like fork() or symlinks), or maybe you need an Internet connection and one isn't available. B, use TODO. This is for any code you haven't written yet, or bugs you have yet to fix, but want to put tests in your testing script (always a good idea). =back =head2 Test control =over 4 =item B BAIL_OUT($reason); Indicates to the harness that things are going so badly all testing should terminate. This includes the running of any additional test scripts. This is typically used when testing cannot continue such as a critical module failing to compile or a necessary external utility not being available such as a database connection failing. The test will exit with 255. For even better control look at L. =cut sub BAIL_OUT { my $reason = shift; my $tb = Test::More->builder; $tb->BAIL_OUT($reason); } =back =head2 Discouraged comparison functions The use of the following functions is discouraged as they are not actually testing functions and produce no diagnostics to help figure out what went wrong. They were written before is_deeply() existed because I couldn't figure out how to display a useful diff of two arbitrary data structures. These functions are usually used inside an ok(). ok( eq_array(\@got, \@expected) ); C can do that better and with diagnostics. is_deeply( \@got, \@expected ); They may be deprecated in future versions. =over 4 =item B my $is_eq = eq_array(\@got, \@expected); Checks if two arrays are equivalent. This is a deep check, so multi-level structures are handled correctly. =cut #'# sub eq_array { local @Data_Stack = (); _deep_check(@_); } sub _eq_array { my( $a1, $a2 ) = @_; if( grep _type($_) ne 'ARRAY', $a1, $a2 ) { warn "eq_array passed a non-array ref"; return 0; } return 1 if $a1 eq $a2; my $ok = 1; my $max = $#$a1 > $#$a2 ? $#$a1 : $#$a2; for( 0 .. $max ) { my $e1 = $_ > $#$a1 ? $DNE : $a1->[$_]; my $e2 = $_ > $#$a2 ? $DNE : $a2->[$_]; next if _equal_nonrefs($e1, $e2); push @Data_Stack, { type => 'ARRAY', idx => $_, vals => [ $e1, $e2 ] }; $ok = _deep_check( $e1, $e2 ); pop @Data_Stack if $ok; last unless $ok; } return $ok; } sub _equal_nonrefs { my( $e1, $e2 ) = @_; return if ref $e1 or ref $e2; if ( defined $e1 ) { return 1 if defined $e2 and $e1 eq $e2; } else { return 1 if !defined $e2; } return; } sub _deep_check { my( $e1, $e2 ) = @_; my $tb = Test::More->builder; my $ok = 0; # Effectively turn %Refs_Seen into a stack. This avoids picking up # the same referenced used twice (such as [\$a, \$a]) to be considered # circular. local %Refs_Seen = %Refs_Seen; { $tb->_unoverload_str( \$e1, \$e2 ); # Either they're both references or both not. my $same_ref = !( !ref $e1 xor !ref $e2 ); my $not_ref = ( !ref $e1 and !ref $e2 ); if( defined $e1 xor defined $e2 ) { $ok = 0; } elsif( !defined $e1 and !defined $e2 ) { # Shortcut if they're both undefined. $ok = 1; } elsif( _dne($e1) xor _dne($e2) ) { $ok = 0; } elsif( $same_ref and( $e1 eq $e2 ) ) { $ok = 1; } elsif($not_ref) { push @Data_Stack, { type => '', vals => [ $e1, $e2 ] }; $ok = 0; } else { if( $Refs_Seen{$e1} ) { return $Refs_Seen{$e1} eq $e2; } else { $Refs_Seen{$e1} = "$e2"; } my $type = _type($e1); $type = 'DIFFERENT' unless _type($e2) eq $type; if( $type eq 'DIFFERENT' ) { push @Data_Stack, { type => $type, vals => [ $e1, $e2 ] }; $ok = 0; } elsif( $type eq 'ARRAY' ) { $ok = _eq_array( $e1, $e2 ); } elsif( $type eq 'HASH' ) { $ok = _eq_hash( $e1, $e2 ); } elsif( $type eq 'REF' ) { push @Data_Stack, { type => $type, vals => [ $e1, $e2 ] }; $ok = _deep_check( $$e1, $$e2 ); pop @Data_Stack if $ok; } elsif( $type eq 'SCALAR' ) { push @Data_Stack, { type => 'REF', vals => [ $e1, $e2 ] }; $ok = _deep_check( $$e1, $$e2 ); pop @Data_Stack if $ok; } elsif($type) { push @Data_Stack, { type => $type, vals => [ $e1, $e2 ] }; $ok = 0; } else { _whoa( 1, "No type in _deep_check" ); } } } return $ok; } sub _whoa { my( $check, $desc ) = @_; if($check) { die <<"WHOA"; WHOA! $desc This should never happen! Please contact the author immediately! WHOA } } =item B my $is_eq = eq_hash(\%got, \%expected); Determines if the two hashes contain the same keys and values. This is a deep check. =cut sub eq_hash { local @Data_Stack = (); return _deep_check(@_); } sub _eq_hash { my( $a1, $a2 ) = @_; if( grep _type($_) ne 'HASH', $a1, $a2 ) { warn "eq_hash passed a non-hash ref"; return 0; } return 1 if $a1 eq $a2; my $ok = 1; my $bigger = keys %$a1 > keys %$a2 ? $a1 : $a2; foreach my $k ( keys %$bigger ) { my $e1 = exists $a1->{$k} ? $a1->{$k} : $DNE; my $e2 = exists $a2->{$k} ? $a2->{$k} : $DNE; next if _equal_nonrefs($e1, $e2); push @Data_Stack, { type => 'HASH', idx => $k, vals => [ $e1, $e2 ] }; $ok = _deep_check( $e1, $e2 ); pop @Data_Stack if $ok; last unless $ok; } return $ok; } =item B my $is_eq = eq_set(\@got, \@expected); Similar to eq_array(), except the order of the elements is B important. This is a deep check, but the irrelevancy of order only applies to the top level. ok( eq_set(\@got, \@expected) ); Is better written: is_deeply( [sort @got], [sort @expected] ); B By historical accident, this is not a true set comparison. While the order of elements does not matter, duplicate elements do. B eq_set() does not know how to deal with references at the top level. The following is an example of a comparison which might not work: eq_set([\1, \2], [\2, \1]); L contains much better set comparison functions. =cut sub eq_set { my( $a1, $a2 ) = @_; return 0 unless @$a1 == @$a2; no warnings 'uninitialized'; # It really doesn't matter how we sort them, as long as both arrays are # sorted with the same algorithm. # # Ensure that references are not accidentally treated the same as a # string containing the reference. # # Have to inline the sort routine due to a threading/sort bug. # See [rt.cpan.org 6782] # # I don't know how references would be sorted so we just don't sort # them. This means eq_set doesn't really work with refs. return eq_array( [ grep( ref, @$a1 ), sort( grep( !ref, @$a1 ) ) ], [ grep( ref, @$a2 ), sort( grep( !ref, @$a2 ) ) ], ); } =back =head2 Extending and Embedding Test::More Sometimes the Test::More interface isn't quite enough. Fortunately, Test::More is built on top of Test::Builder which provides a single, unified backend for any test library to use. This means two test libraries which both use Test::Builder B. If you simply want to do a little tweaking of how the tests behave, you can access the underlying Test::Builder object like so: =over 4 =item B my $test_builder = Test::More->builder; Returns the Test::Builder object underlying Test::More for you to play with. =back =head1 EXIT CODES If all your tests passed, Test::Builder will exit with zero (which is normal). If anything failed it will exit with how many failed. If you run less (or more) tests than you planned, the missing (or extras) will be considered failures. If no tests were ever run Test::Builder will throw a warning and exit with 255. If the test died, even after having successfully completed all its tests, it will still be considered a failure and will exit with 255. So the exit codes are... 0 all tests successful 255 test died or all passed but wrong # of tests run any other number how many failed (including missing or extras) If you fail more than 254 tests, it will be reported as 254. B This behavior may go away in future versions. =head1 CAVEATS and NOTES =over 4 =item Backwards compatibility Test::More works with Perls as old as 5.6.0. =item utf8 / "Wide character in print" If you use utf8 or other non-ASCII characters with Test::More you might get a "Wide character in print" warning. Using C will not fix it. Test::Builder (which powers Test::More) duplicates STDOUT and STDERR. So any changes to them, including changing their output disciplines, will not be seem by Test::More. The work around is to change the filehandles used by Test::Builder directly. my $builder = Test::More->builder; binmode $builder->output, ":utf8"; binmode $builder->failure_output, ":utf8"; binmode $builder->todo_output, ":utf8"; =item Overloaded objects String overloaded objects are compared B (or in cmp_ok()'s case, strings or numbers as appropriate to the comparison op). This prevents Test::More from piercing an object's interface allowing better blackbox testing. So if a function starts returning overloaded objects instead of bare strings your tests won't notice the difference. This is good. However, it does mean that functions like is_deeply() cannot be used to test the internals of string overloaded objects. In this case I would suggest L which contains more flexible testing functions for complex data structures. =item Threads Test::More will only be aware of threads if "use threads" has been done I Test::More is loaded. This is ok: use threads; use Test::More; This may cause problems: use Test::More use threads; 5.8.1 and above are supported. Anything below that has too many bugs. =back =head1 HISTORY This is a case of convergent evolution with Joshua Pritikin's Test module. I was largely unaware of its existence when I'd first written my own ok() routines. This module exists because I can't figure out how to easily wedge test names into Test's interface (along with a few other problems). The goal here is to have a testing utility that's simple to learn, quick to use and difficult to trip yourself up with while still providing more flexibility than the existing Test.pm. As such, the names of the most common routines are kept tiny, special cases and magic side-effects are kept to a minimum. WYSIWYG. =head1 SEE ALSO L if all this confuses you and you just want to write some tests. You can upgrade to Test::More later (it's forward compatible). L is the test runner and output interpreter for Perl. It's the thing that powers C and where the C utility comes from. L tests written with Test.pm, the original testing module, do not play well with other testing libraries. Test::Legacy emulates the Test.pm interface and does play well with others. L for more ways to test complex data structures. And it plays well with Test::More. L is like xUnit but more perlish. L gives you more powerful complex data structure testing. L shows the idea of embedded testing. L installs a whole bunch of useful test modules. =head1 AUTHORS Michael G Schwern Eschwern@pobox.comE with much inspiration from Joshua Pritikin's Test module and lots of help from Barrie Slaymaker, Tony Bowden, blackstar.co.uk, chromatic, Fergal Daly and the perl-qa gang. =head1 BUGS See F to report and view bugs. =head1 SOURCE The source code repository for Test::More can be found at F. =head1 COPYRIGHT Copyright 2001-2008 by Michael G Schwern Eschwern@pobox.comE. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See F =cut 1; Simple.pm000644001750001750 1447613601673061 17312 0ustar00taitai000000000000Type-Tiny-1.008001/inc/archaic/Testpackage Test::Simple; use 5.006; use strict; our $VERSION = '0.98'; $VERSION = eval $VERSION; ## no critic (BuiltinFunctions::ProhibitStringyEval) use Test::Builder::Module; our @ISA = qw(Test::Builder::Module); our @EXPORT = qw(ok); my $CLASS = __PACKAGE__; =head1 NAME Test::Simple - Basic utilities for writing tests. =head1 SYNOPSIS use Test::Simple tests => 1; ok( $foo eq $bar, 'foo is bar' ); =head1 DESCRIPTION ** If you are unfamiliar with testing B first! ** This is an extremely simple, extremely basic module for writing tests suitable for CPAN modules and other pursuits. If you wish to do more complicated testing, use the Test::More module (a drop-in replacement for this one). The basic unit of Perl testing is the ok. For each thing you want to test your program will print out an "ok" or "not ok" to indicate pass or fail. You do this with the ok() function (see below). The only other constraint is you must pre-declare how many tests you plan to run. This is in case something goes horribly wrong during the test and your test program aborts, or skips a test or whatever. You do this like so: use Test::Simple tests => 23; You must have a plan. =over 4 =item B ok( $foo eq $bar, $name ); ok( $foo eq $bar ); ok() is given an expression (in this case C<$foo eq $bar>). If it's true, the test passed. If it's false, it didn't. That's about it. ok() prints out either "ok" or "not ok" along with a test number (it keeps track of that for you). # This produces "ok 1 - Hell not yet frozen over" (or not ok) ok( get_temperature($hell) > 0, 'Hell not yet frozen over' ); If you provide a $name, that will be printed along with the "ok/not ok" to make it easier to find your test when if fails (just search for the name). It also makes it easier for the next guy to understand what your test is for. It's highly recommended you use test names. All tests are run in scalar context. So this: ok( @stuff, 'I have some stuff' ); will do what you mean (fail if stuff is empty) =cut sub ok ($;$) { ## no critic (Subroutines::ProhibitSubroutinePrototypes) return $CLASS->builder->ok(@_); } =back Test::Simple will start by printing number of tests run in the form "1..M" (so "1..5" means you're going to run 5 tests). This strange format lets Test::Harness know how many tests you plan on running in case something goes horribly wrong. If all your tests passed, Test::Simple will exit with zero (which is normal). If anything failed it will exit with how many failed. If you run less (or more) tests than you planned, the missing (or extras) will be considered failures. If no tests were ever run Test::Simple will throw a warning and exit with 255. If the test died, even after having successfully completed all its tests, it will still be considered a failure and will exit with 255. So the exit codes are... 0 all tests successful 255 test died or all passed but wrong # of tests run any other number how many failed (including missing or extras) If you fail more than 254 tests, it will be reported as 254. This module is by no means trying to be a complete testing system. It's just to get you started. Once you're off the ground its recommended you look at L. =head1 EXAMPLE Here's an example of a simple .t file for the fictional Film module. use Test::Simple tests => 5; use Film; # What you're testing. my $btaste = Film->new({ Title => 'Bad Taste', Director => 'Peter Jackson', Rating => 'R', NumExplodingSheep => 1 }); ok( defined($btaste) && ref $btaste eq 'Film', 'new() works' ); ok( $btaste->Title eq 'Bad Taste', 'Title() get' ); ok( $btaste->Director eq 'Peter Jackson', 'Director() get' ); ok( $btaste->Rating eq 'R', 'Rating() get' ); ok( $btaste->NumExplodingSheep == 1, 'NumExplodingSheep() get' ); It will produce output like this: 1..5 ok 1 - new() works ok 2 - Title() get ok 3 - Director() get not ok 4 - Rating() get # Failed test 'Rating() get' # in t/film.t at line 14. ok 5 - NumExplodingSheep() get # Looks like you failed 1 tests of 5 Indicating the Film::Rating() method is broken. =head1 CAVEATS Test::Simple will only report a maximum of 254 failures in its exit code. If this is a problem, you probably have a huge test script. Split it into multiple files. (Otherwise blame the Unix folks for using an unsigned short integer as the exit status). Because VMS's exit codes are much, much different than the rest of the universe, and perl does horrible mangling to them that gets in my way, it works like this on VMS. 0 SS$_NORMAL all tests successful 4 SS$_ABORT something went wrong Unfortunately, I can't differentiate any further. =head1 NOTES Test::Simple is B tested all the way back to perl 5.6.0. Test::Simple is thread-safe in perl 5.8.1 and up. =head1 HISTORY This module was conceived while talking with Tony Bowden in his kitchen one night about the problems I was having writing some really complicated feature into the new Testing module. He observed that the main problem is not dealing with these edge cases but that people hate to write tests B. What was needed was a dead simple module that took all the hard work out of testing and was really, really easy to learn. Paul Johnson simultaneously had this idea (unfortunately, he wasn't in Tony's kitchen). This is it. =head1 SEE ALSO =over 4 =item L More testing functions! Once you outgrow Test::Simple, look at Test::More. Test::Simple is 100% forward compatible with Test::More (i.e. you can just use Test::More instead of Test::Simple in your programs and things will still work). =back Look in Test::More's SEE ALSO for more testing modules. =head1 AUTHORS Idea by Tony Bowden and Paul Johnson, code by Michael G Schwern Eschwern@pobox.comE, wardrobe by Calvin Klein. =head1 COPYRIGHT Copyright 2001-2008 by Michael G Schwern Eschwern@pobox.comE. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See F =cut 1; Perl56Compat.pm000644001750001750 347613601673061 20570 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Devel/TypeTinypackage Devel::TypeTiny::Perl56Compat; use 5.006; use strict; use warnings; our $AUTHORITY = 'cpan:TOBYINK'; our $VERSION = '1.008001'; $VERSION =~ tr/_//d; #### B doesn't provide perlstring() in 5.6. Monkey patch it. use B (); unless (exists &B::perlstring) { my $d; *B::perlstring = sub { no warnings 'uninitialized'; require Data::Dumper; $d ||= 'Data::Dumper'->new([])->Indent(0)->Purity(0)->Pad('')->Useqq(1)->Terse(1)->Freezer('')->Toaster(''); my $perlstring = $d->Values([''.shift])->Dump; ($perlstring =~ /^"/) ? $perlstring : qq["$perlstring"]; }; } unless (exists &B::cstring) { *B::cstring = \&B::perlstring; } push @B::EXPORT_OK, qw( perlstring cstring ); #### Done! 5.6; __END__ =pod =encoding utf-8 =for stopwords pragmas =head1 NAME Devel::TypeTiny::Perl56Compat - shims to allow Type::Tiny to run on Perl 5.6.x =head1 STATUS This module is considered part of Type-Tiny's internals. It is not covered by the L. =head1 DESCRIPTION This is not considered part of Type::Tiny's public API. Currently this module just has one job: it patches L to export a C function, as this was only added in Perl 5.8.0. =head1 BUGS Please report any bugs to L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Perl58Compat.pm000644001750001750 276613601673061 20573 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Devel/TypeTinypackage Devel::TypeTiny::Perl58Compat; use 5.006; use strict; use warnings; our $AUTHORITY = 'cpan:TOBYINK'; our $VERSION = '1.008001'; $VERSION =~ tr/_//d; #### re doesn't provide is_regexp in Perl < 5.10 eval 'require re'; unless (exists &re::is_regexp) { require B; *re::is_regexp = sub { eval { B::svref_2object($_[0])->MAGIC->TYPE eq 'r' }; }; } #### Done! 5.8; __END__ =pod =encoding utf-8 =for stopwords pragmas =head1 NAME Devel::TypeTiny::Perl58Compat - shims to allow Type::Tiny to run on Perl 5.8.x =head1 STATUS This module is considered part of Type-Tiny's internals. It is not covered by the L. =head1 DESCRIPTION This is not considered part of Type::Tiny's public API. Currently this module just has one job: it patches L to provide a C function, as this was only added in Perl 5.9.5. =head1 BUGS Please report any bugs to L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Assertion.pm000644001750001750 1162613601673061 20364 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Error/TypeTinypackage Error::TypeTiny::Assertion; use 5.006001; use strict; use warnings; BEGIN { if ($] < 5.008) { require Devel::TypeTiny::Perl56Compat }; } BEGIN { $Error::TypeTiny::Assertion::AUTHORITY = 'cpan:TOBYINK'; $Error::TypeTiny::Assertion::VERSION = '1.008001'; } $Error::TypeTiny::Assertion::VERSION =~ tr/_//d; require Error::TypeTiny; our @ISA = 'Error::TypeTiny'; sub type { $_[0]{type} }; sub value { $_[0]{value} }; sub varname { $_[0]{varname} ||= '$_' }; sub attribute_step { $_[0]{attribute_step} }; sub attribute_name { $_[0]{attribute_name} }; sub has_type { defined $_[0]{type} }; # sic sub has_attribute_step { exists $_[0]{attribute_step} }; sub has_attribute_name { exists $_[0]{attribute_name} }; sub new { my $class = shift; my $self = $class->SUPER::new(@_); # Supported but undocumented parameter is `mgaca`. # This indicates whether Error::TypeTiny::Assertion # should attempt to figure out which attribute caused # the error from Method::Generate::Accessor's info. # Can be set to true/false or not set. If not set, # the current behaviour is true, but this may change # in the future. If set to false, will ignore the # $Method::Generate::Accessor::CurrentAttribute hashref. # if (ref $Method::Generate::Accessor::CurrentAttribute and $self->{mgaca} || !exists $self->{mgaca}) { require B; my %d = %{$Method::Generate::Accessor::CurrentAttribute}; $self->{attribute_name} = $d{name} if defined $d{name}; $self->{attribute_step} = $d{step} if defined $d{step}; if (defined $d{init_arg}) { $self->{varname} = sprintf('$args->{%s}', B::perlstring($d{init_arg})); } elsif (defined $d{name}) { $self->{varname} = sprintf('$self->{%s}', B::perlstring($d{name})); } } return $self; } sub message { my $e = shift; $e->varname eq '$_' ? $e->SUPER::message : sprintf('%s (in %s)', $e->SUPER::message, $e->varname); } sub _build_message { my $e = shift; $e->has_type ? sprintf('%s did not pass type constraint "%s"', Type::Tiny::_dd($e->value), $e->type) : sprintf('%s did not pass type constraint', Type::Tiny::_dd($e->value)) } *to_string = sub { my $e = shift; my $msg = $e->message; my $c = $e->context; $msg .= sprintf(" at %s line %s", $c->{file}||'file?', $c->{line}||'NaN') if $c; my $explain = $e->explain; return "$msg\n" unless @{ $explain || [] }; $msg .= "\n"; for my $line (@$explain) { $msg .= " $line\n"; } return $msg; } if $] >= 5.008; sub explain { my $e = shift; return undef unless $e->has_type; $e->type->validate_explain($e->value, $e->varname); } 1; __END__ =pod =encoding utf-8 =head1 NAME Error::TypeTiny::Assertion - exception when a value fails a type constraint =head1 STATUS This module is covered by the L. =head1 DESCRIPTION This exception is thrown when a value fails a type constraint assertion. This package inherits from L; see that for most documentation. Major differences are listed below: =head2 Attributes =over =item C The type constraint that was checked against. Weakened links are involved, so this may end up being C. =item C The value that was tested. =item C The name of the variable that was checked, if known. Defaults to C<< '$_' >>. =item C If this exception was thrown as the result of an isa check or a failed coercion for a Moo attribute, then this will tell you which attribute (if your Moo is new enough). (Hopefully one day this will support other OO frameworks.) =item C If this exception was thrown as the result of an isa check or a failed coercion for a Moo attribute, then this will contain either C<< "isa check" >> or C<< "coercion" >> to indicate which went wrong (if your Moo is new enough). (Hopefully one day this will support other OO frameworks.) =back =head2 Methods =over =item C, C, C Predicate methods. =item C Overridden to add C to the message if defined. =item C Attempts to explain why the value did not pass the type constraint. Returns an arrayref of strings providing step-by-step reasoning; or returns undef if no explanation is possible. =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Compilation.pm000644001750001750 360413601673061 20650 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Error/TypeTinypackage Error::TypeTiny::Compilation; use 5.006001; use strict; use warnings; BEGIN { $Error::TypeTiny::Compilation::AUTHORITY = 'cpan:TOBYINK'; $Error::TypeTiny::Compilation::VERSION = '1.008001'; } $Error::TypeTiny::Compilation::VERSION =~ tr/_//d; require Error::TypeTiny; our @ISA = 'Error::TypeTiny'; sub code { $_[0]{code} }; sub environment { $_[0]{environment} ||= {} }; sub errstr { $_[0]{errstr} }; sub _build_message { my $self = shift; sprintf("Failed to compile source because: %s", $self->errstr); } 1; __END__ =pod =encoding utf-8 =head1 NAME Error::TypeTiny::Compilation - exception for Eval::TypeTiny =head1 STATUS This module is covered by the L. =head1 DESCRIPTION Thrown when compiling a closure fails. Common causes are problems with inlined type constraints, and syntax errors when coercions are given as strings of Perl code. This package inherits from L; see that for most documentation. Major differences are listed below: =head2 Attributes =over =item C The Perl source code being compiled. =item C Hashref of variables being closed over. =item C Error message from Perl compiler. =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. WrongNumberOfParameters.pm000644001750001750 514313601673061 23150 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Error/TypeTinypackage Error::TypeTiny::WrongNumberOfParameters; use 5.006001; use strict; use warnings; BEGIN { $Error::TypeTiny::WrongNumberOfParameters::AUTHORITY = 'cpan:TOBYINK'; $Error::TypeTiny::WrongNumberOfParameters::VERSION = '1.008001'; } $Error::TypeTiny::WrongNumberOfParameters::VERSION =~ tr/_//d; require Error::TypeTiny; our @ISA = 'Error::TypeTiny'; sub minimum { $_[0]{minimum} }; sub maximum { $_[0]{maximum} }; sub got { $_[0]{got} }; sub has_minimum { exists $_[0]{minimum} }; sub has_maximum { exists $_[0]{maximum} }; sub _build_message { my $e = shift; if ($e->has_minimum and $e->has_maximum and $e->minimum == $e->maximum) { return sprintf( "Wrong number of parameters; got %d; expected %d", $e->got, $e->minimum, ); } elsif ($e->has_minimum and $e->has_maximum and $e->minimum < $e->maximum) { return sprintf( "Wrong number of parameters; got %d; expected %d to %d", $e->got, $e->minimum, $e->maximum, ); } elsif ($e->has_minimum) { return sprintf( "Wrong number of parameters; got %d; expected at least %d", $e->got, $e->minimum, ); } else { return sprintf( "Wrong number of parameters; got %d", $e->got, ); } } 1; __END__ =pod =encoding utf-8 =head1 NAME Error::TypeTiny::WrongNumberOfParameters - exception for Type::Params =head1 STATUS This module is covered by the L. =head1 DESCRIPTION Thrown when a Type::Params compiled check is called with the wrong number of parameters. This package inherits from L; see that for most documentation. Major differences are listed below: =head2 Attributes =over =item C The minimum expected number of parameters. =item C The maximum expected number of parameters. =item C The number of parameters actually passed to the compiled check. =back =head2 Methods =over =item C, C Predicate methods. =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. TypeTiny.pm000644001750001750 375313601673061 17637 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Reply/Pluginpackage Reply::Plugin::TypeTiny; use strict; use warnings; BEGIN { $Reply::Plugin::TypeTiny::AUTHORITY = 'cpan:TOBYINK'; $Reply::Plugin::TypeTiny::VERSION = '1.008001'; }; $Reply::Plugin::TypeTiny::VERSION =~ tr/_//d; require Reply::Plugin; our @ISA = 'Reply::Plugin'; use Scalar::Util qw(blessed); use Term::ANSIColor; sub mangle_error { my $self = shift; my ($err) = @_; if (blessed $err and $err->isa("Error::TypeTiny::Assertion")) { my $explain = $err->explain; if ($explain) { print color("cyan"); print "Error::TypeTiny::Assertion explain:\n"; $self->_explanation($explain, ""); local $| = 1; print "\n"; print color("reset"); } } return @_; } sub _explanation { my $self = shift; my ($ex, $indent) = @_; for my $line (@$ex) { if (ref($line) eq q(ARRAY)) { print "$indent * Explain:\n"; $self->_explanation($line, "$indent "); } else { print "$indent * $line\n"; } } } 1; __END__ =pod =encoding utf-8 =head1 NAME Reply::Plugin::TypeTiny - improved type constraint exceptions in Reply =head1 STATUS This module is not covered by the L. =head1 DESCRIPTION This is a small plugin to improve error messages in L. Not massively tested. =begin trustme =item mangle_error =end trustme =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L, L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. FromMoose.pm000644001750001750 517513601673061 20111 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Coercionpackage Type::Coercion::FromMoose; use 5.006001; use strict; use warnings; BEGIN { $Type::Coercion::FromMoose::AUTHORITY = 'cpan:TOBYINK'; $Type::Coercion::FromMoose::VERSION = '1.008001'; } $Type::Coercion::FromMoose::VERSION =~ tr/_//d; use Scalar::Util qw< blessed >; use Types::TypeTiny (); sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } require Type::Coercion; our @ISA = 'Type::Coercion'; sub type_coercion_map { my $self = shift; my @from; if ($self->type_constraint) { my $moose = $self->type_constraint->{moose_type}; @from = @{ $moose->coercion->type_coercion_map } if $moose && $moose->has_coercion; } else { _croak "The type constraint attached to this coercion has been garbage collected... PANIC"; } my @return; while (@from) { my ($type, $code) = splice(@from, 0, 2); $type = Moose::Util::TypeConstraints::find_type_constraint($type) unless ref $type; push @return, Types::TypeTiny::to_TypeTiny($type), $code; } return \@return; } sub add_type_coercions { my $self = shift; _croak "Adding coercions to Type::Coercion::FromMoose not currently supported" if @_; } sub _build_moose_coercion { my $self = shift; if ($self->type_constraint) { my $moose = $self->type_constraint->{moose_type}; return $moose->coercion if $moose && $moose->has_coercion; } $self->SUPER::_build_moose_coercion(@_); } sub can_be_inlined { 0; } 1; __END__ =pod =encoding utf-8 =head1 NAME Type::Coercion::FromMoose - a set of coercions borrowed from Moose =head1 STATUS This module is considered part of Type-Tiny's internals. It is not covered by the L. =head1 DESCRIPTION This package inherits from L; see that for most documentation. The major differences are that C always throws an exception, and the C is automatically populated from Moose. This is mostly for internal purposes. =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Union.pm000644001750001750 570413601673061 17271 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Coercionpackage Type::Coercion::Union; use 5.006001; use strict; use warnings; BEGIN { $Type::Coercion::Union::AUTHORITY = 'cpan:TOBYINK'; $Type::Coercion::Union::VERSION = '1.008001'; } $Type::Coercion::Union::VERSION =~ tr/_//d; use Scalar::Util qw< blessed >; use Types::TypeTiny (); sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } require Type::Coercion; our @ISA = 'Type::Coercion'; sub _preserve_type_constraint { my $self = shift; $self->{_union_of} = $self->{type_constraint}->type_constraints if $self->{type_constraint}; } sub _maybe_restore_type_constraint { my $self = shift; if ( my $union = $self->{_union_of} ) { return Type::Tiny::Union->new(type_constraints => $union); } return; # uncoverable statement } sub type_coercion_map { my $self = shift; Types::TypeTiny::TypeTiny->assert_valid(my $type = $self->type_constraint); $type->isa('Type::Tiny::Union') or _croak "Type::Coercion::Union must be used in conjunction with Type::Tiny::Union"; my @c; for my $tc (@$type) { next unless $tc->has_coercion; push @c, @{$tc->coercion->type_coercion_map}; } return \@c; } sub add_type_coercions { my $self = shift; _croak "Adding coercions to Type::Coercion::Union not currently supported" if @_; } sub _build_moose_coercion { my $self = shift; my %options = (); $options{type_constraint} = $self->type_constraint if $self->has_type_constraint; require Moose::Meta::TypeCoercion::Union; my $r = "Moose::Meta::TypeCoercion::Union"->new(%options); return $r; } sub can_be_inlined { my $self = shift; Types::TypeTiny::TypeTiny->assert_valid(my $type = $self->type_constraint); for my $tc (@$type) { next unless $tc->has_coercion; return !!0 unless $tc->coercion->can_be_inlined; } !!1; } 1; __END__ =pod =encoding utf-8 =head1 NAME Type::Coercion::Union - a set of coercions to a union type constraint =head1 STATUS This module is covered by the L. =head1 DESCRIPTION This package inherits from L; see that for most documentation. The major differences are that C always throws an exception, and the C is automatically populated from the child constraints of the union type constraint. =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Class.pm000644001750001750 2001213601673061 16435 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tinypackage Type::Tiny::Class; use 5.006001; use strict; use warnings; BEGIN { if ($] < 5.008) { require Devel::TypeTiny::Perl56Compat }; } BEGIN { $Type::Tiny::Class::AUTHORITY = 'cpan:TOBYINK'; $Type::Tiny::Class::VERSION = '1.008001'; } $Type::Tiny::Class::VERSION =~ tr/_//d; use Scalar::Util qw< blessed >; sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } require Type::Tiny::ConstrainedObject; our @ISA = 'Type::Tiny::ConstrainedObject'; sub _short_name { 'Class' } sub new { my $proto = shift; return $proto->class->new(@_) if blessed $proto; # DWIM my %opts = (@_==1) ? %{$_[0]} : @_; _croak "Need to supply class name" unless exists $opts{class}; if (Type::Tiny::_USE_XS) { my $xsub = Type::Tiny::XS::get_coderef_for("InstanceOf[".$opts{class}."]"); $opts{compiled_type_constraint} = $xsub if $xsub; } elsif (Type::Tiny::_USE_MOUSE) { require Mouse::Util::TypeConstraints; my $maker = "Mouse::Util::TypeConstraints"->can("generate_isa_predicate_for"); $opts{compiled_type_constraint} = $maker->($opts{class}) if $maker; } return $proto->SUPER::new(%opts); } sub class { $_[0]{class} } sub inlined { $_[0]{inlined} ||= $_[0]->_build_inlined } sub has_inlined { !!1 } sub _is_null_constraint { 0 } sub _build_constraint { my $self = shift; my $class = $self->class; return sub { blessed($_) and $_->isa($class) }; } sub _build_inlined { my $self = shift; my $class = $self->class; if (Type::Tiny::_USE_XS) { my $xsub = Type::Tiny::XS::get_subname_for("InstanceOf[$class]"); return sub { my $var = $_[1]; "$xsub\($var\)" } if $xsub; } sub { my $var = $_[1]; qq{Scalar::Util::blessed($var) and $var->isa(q[$class])}; }; } sub _build_default_message { no warnings 'uninitialized'; my $self = shift; my $c = $self->class; return sub { sprintf '%s did not pass type constraint (not isa %s)', Type::Tiny::_dd($_[0]), $c } if $self->is_anon; my $name = "$self"; return sub { sprintf '%s did not pass type constraint "%s" (not isa %s)', Type::Tiny::_dd($_[0]), $name, $c }; } sub _instantiate_moose_type { my $self = shift; my %opts = @_; delete $opts{parent}; delete $opts{constraint}; delete $opts{inlined}; require Moose::Meta::TypeConstraint::Class; return "Moose::Meta::TypeConstraint::Class"->new(%opts, class => $self->class); } sub plus_constructors { my $self = shift; unless (@_) { require Types::Standard; push @_, Types::Standard::HashRef(), "new"; } require B; require Types::TypeTiny; my $class = B::perlstring($self->class); my @r; while (@_) { my $source = shift; Types::TypeTiny::TypeTiny->check($source) or _croak "Expected type constraint; got $source"; my $constructor = shift; Types::TypeTiny::StringLike->check($constructor) or _croak "Expected string; got $constructor"; push @r, $source, sprintf('%s->%s($_)', $class, $constructor); } return $self->plus_coercions(\@r); } sub parent { $_[0]{parent} ||= $_[0]->_build_parent; } sub _build_parent { my $self = shift; my $class = $self->class; # Some classes (I'm looking at you, Math::BigFloat) include a class in # their @ISA to inherit methods, but then override isa() to return false, # so that they don't appear to be a subclass. # # In these cases, we don't want to list the parent class as a parent # type constraint. # my @isa = grep $class->isa($_), do { no strict "refs"; no warnings; @{"$class\::ISA"} }; if (@isa == 0) { require Types::Standard; return Types::Standard::Object(); } if (@isa == 1) { return ref($self)->new(class => $isa[0]) } require Type::Tiny::Intersection; "Type::Tiny::Intersection"->new( type_constraints => [ map ref($self)->new(class => $_), @isa ], ); } *__get_linear_isa_dfs = eval { require mro } ? \&mro::get_linear_isa : sub { no strict 'refs'; my $classname = shift; my @lin = ($classname); my %stored; foreach my $parent (@{"$classname\::ISA"}) { my $plin = __get_linear_isa_dfs($parent); foreach (@$plin) { next if exists $stored{$_}; push(@lin, $_); $stored{$_} = 1; } } return \@lin; }; sub validate_explain { my $self = shift; my ($value, $varname) = @_; $varname = '$_' unless defined $varname; return undef if $self->check($value); return ["Not a blessed reference"] unless blessed($value); my @isa = @{ __get_linear_isa_dfs(ref $value) }; my $display_var = $varname eq q{$_} ? '' : sprintf(' (in %s)', $varname); require Type::Utils; return [ sprintf('"%s" requires that the reference isa %s', $self, $self->class), sprintf('The reference%s isa %s', $display_var, Type::Utils::english_list(@isa)), ]; } 1; __END__ =pod =encoding utf-8 =head1 NAME Type::Tiny::Class - type constraints based on the "isa" method =head1 STATUS This module is covered by the L. =head1 DESCRIPTION Type constraints of the general form C<< { $_->isa("Some::Class") } >>. This package inherits from L; see that for most documentation. Major differences are listed below: =head2 Constructor =over =item C When the constructor is called on an I of Type::Tiny::Class, it passes the call through to the constructor of the class for the constraint. So for example: my $type = Type::Tiny::Class->new(class => "Foo::Bar"); my $obj = $type->new(hello => "World"); say ref($obj); # prints "Foo::Bar" This little bit of DWIM was borrowed from L, but Type::Tiny doesn't take the idea quite as far. =back =head2 Attributes =over =item C The class for the constraint. =item C Unlike Type::Tiny, you I pass a constraint coderef to the constructor. Instead rely on the default. =item C Unlike Type::Tiny, you I pass an inlining coderef to the constructor. Instead rely on the default. =item C Parent is automatically calculated, and cannot be passed to the constructor. =back =head2 Methods =over =item C<< plus_constructors($source, $method_name) >> Much like C but adds coercions that go via a constructor. (In fact, this is implemented as a wrapper for C.) Example: package MyApp::Minion; use Moose; extends "MyApp::Person"; use Types::Standard qw( HashRef Str ); use Type::Utils qw( class_type ); my $Person = class_type({ class => "MyApp::Person" }); has boss => ( is => "ro", isa => $Person->plus_constructors( HashRef, "new", Str, "_new_from_name", ), coerce => 1, ); package main; MyApp::Minion->new( ..., boss => "Bob", ## via MyApp::Person->_new_from_name ); MyApp::Minion->new( ..., boss => { name => "Bob" }, ## via MyApp::Person->new ); Because coercing C via constructor is a common desire, if you call C with no arguments at all, this is the default. $classtype->plus_constructors(HashRef, "new") $classtype->plus_constructors() ## identical to above This is handy for Moose/Mouse/Moo-based classes. =item C<< stringifies_to($constraint) >> See L. =item C<< numifies_to($constraint) >> See L. =item C<< with_attribute_values($attr1 => $constraint1, ...) >> See L. =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. L. L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ConstrainedObject.pm000644001750001750 1370313601673061 21001 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tinypackage Type::Tiny::ConstrainedObject; use 5.006001; use strict; use warnings; BEGIN { $Type::Tiny::ConstrainedObject::AUTHORITY = 'cpan:TOBYINK'; $Type::Tiny::ConstrainedObject::VERSION = '1.008001'; } $Type::Tiny::ConstrainedObject::VERSION =~ tr/_//d; sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } require Type::Tiny; our @ISA = 'Type::Tiny'; my %errlabel = ( parent => 'a parent', constraint => 'a constraint coderef', inlined => 'an inlining coderef', ); sub new { my $proto = shift; my %opts = (@_==1) ? %{$_[0]} : @_; for my $key (qw/ parent constraint inlined /) { next unless exists $opts{$key}; _croak( '%s type constraints cannot have %s passed to the constructor', $proto->_short_name, $errlabel{$key}, ); } $proto->SUPER::new(%opts); } sub has_parent { !!1; } sub parent { require Types::Standard; Types::Standard::Object(); } sub _short_name { die "implement this"; } my $i = 0; my $_where_expressions = sub { my $self = shift; my $name = shift; $name ||= "where expression check"; my (%env, @codes); while (@_) { my $expr = shift; my $constraint = shift; if (!ref $constraint) { push @codes, sprintf('do { local $_ = %s; %s }', $expr, $constraint); } else { require Types::Standard; my $type = Types::Standard::is_RegexpRef($constraint) ? Types::Standard::StrMatch()->of($constraint) : Types::TypeTiny::to_TypeTiny($constraint); if ($type->can_be_inlined) { push @codes, sprintf('do { my $tmp = %s; %s }', $expr, $type->inline_check('$tmp')); } else { ++$i; $env{'$chk'.$i} = do { my $chk = $type->compiled_check; \$chk }; push @codes, sprintf('$chk%d->(%s)', $i, $expr); } } } if (keys %env) { # cannot inline my $sub = Eval::TypeTiny::eval_closure( source => sprintf('sub ($) { local $_ = shift; %s }', join(q( and ), @codes)), description => sprintf('%s for %s', $name, $self->name), environment => \%env, ); return $self->where($sub); } else { return $self->where(join(q( and ), @codes)); } }; sub stringifies_to { my $self = shift; my ($constraint) = @_; $self->$_where_expressions("stringification check", q{"$_"}, $constraint); } sub numifies_to { my $self = shift; my ($constraint) = @_; $self->$_where_expressions("numification check", q{0+$_}, $constraint); } sub with_attribute_values { my $self = shift; my %constraint = @_; $self->$_where_expressions( "attributes check", map { my $attr = $_; qq{\$_->$attr} => $constraint{$attr} } sort keys %constraint, ); } 1; __END__ =pod =encoding utf-8 =head1 NAME Type::Tiny::ConstrainedObject - shared behavour for Type::Tiny::Class, etc =head1 STATUS This module is considered experiemental. =head1 DESCRIPTION =head2 Methods The following methods exist for L, L, L, and any type constraints that inherit from C or C in L. These methods will also work for L if at least one of the types in the intersection provides these methods. These methods will also work for L if all of the types in the union provide these methods. =over =item C<< stringifies_to($constraint) >> Generates a new child type constraint which checks the object's stringification against a constraint. For example: my $type = Type::Tiny::Class->new(class => 'URI'); my $child = $type->stringifies_to( StrMatch[qr/^http:/] ); $child->assert_valid( URI->new("http://example.com/") ); In the above example, C<< $child >> is a type constraint that checks objects are blessed into (or inherit from) the URI class, and when stringified (e.g. though overloading) the result matches the regular expression C<< qr/^http:/ >>. C<< $constraint >> may be a type constraint, something that can be coerced to a type constraint (such as a coderef returning a boolean), a string of Perl code operating on C<< $_ >>, or a reference to a regular expression. So the following would work: my $child = $type->stringifies_to( sub { qr/^http:/ } ); my $child = $type->stringifies_to( qr/^http:/ ); my $child = $type->stringifies_to( 'm/^http:/' ); my $child = $type->where('"$_" =~ /^http:/'); =item C<< numifies_to($constraint) >> The same as C but checks numification. The following might be useful: use Types::Standard qw(Int Overload); my $IntLike = Int | Overload->numifies_to(Int) =item C<< with_attribute_values($attr1 => $constraint1, ...) >> This is best explained with an example: use Types::Standard qw(InstanceOf StrMatch); use Types::Common::Numeric qw(IntRange); my $person = InstanceOf['Local::Human']; my $woman = $person->with_attribute_values( gender => StrMatch[ qr/^F/i ], age => IntRange[ 18 => () ], ); $woman->assert_valid($alice); This assertion will firstly check that C<< $alice >> is a Local::Human, then check that C<< $alice->gender >> starts with an "F", and lastly check that C<< $alice->age >> is an integer at least 18. Again, constraints can be type constraints, coderefs, strings of Perl code, or regular expressions. Technically the "attributes" don't need to be Moo/Moose/Mouse attributes, but any methods which can be called with no parameters and return a scalar. =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Duck.pm000644001750001750 1242113601673061 16263 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tinypackage Type::Tiny::Duck; use 5.006001; use strict; use warnings; BEGIN { $Type::Tiny::Duck::AUTHORITY = 'cpan:TOBYINK'; $Type::Tiny::Duck::VERSION = '1.008001'; } $Type::Tiny::Duck::VERSION =~ tr/_//d; use Scalar::Util qw< blessed >; sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } require Type::Tiny::ConstrainedObject; our @ISA = 'Type::Tiny::ConstrainedObject'; sub _short_name { 'Duck' } sub new { my $proto = shift; my %opts = (@_==1) ? %{$_[0]} : @_; _croak "Need to supply list of methods" unless exists $opts{methods}; $opts{methods} = [$opts{methods}] unless ref $opts{methods}; if (Type::Tiny::_USE_XS) { my $methods = join ",", sort(@{$opts{methods}}); my $xsub = Type::Tiny::XS::get_coderef_for("HasMethods[$methods]"); $opts{compiled_type_constraint} = $xsub if $xsub; } elsif (Type::Tiny::_USE_MOUSE) { require Mouse::Util::TypeConstraints; my $maker = "Mouse::Util::TypeConstraints"->can("generate_can_predicate_for"); $opts{compiled_type_constraint} = $maker->($opts{methods}) if $maker; } return $proto->SUPER::new(%opts); } sub methods { $_[0]{methods} } sub inlined { $_[0]{inlined} ||= $_[0]->_build_inlined } sub has_inlined { !!1 } sub _is_null_constraint { 0 } sub _build_constraint { my $self = shift; my @methods = @{$self->methods}; return sub { blessed($_[0]) and not grep(!$_[0]->can($_), @methods) }; } sub _build_inlined { my $self = shift; my @methods = @{$self->methods}; if (Type::Tiny::_USE_XS) { my $methods = join ",", sort(@{$self->methods}); my $xsub = Type::Tiny::XS::get_subname_for("HasMethods[$methods]"); return sub { my $var = $_[1]; "$xsub\($var\)" } if $xsub; } sub { my $var = $_[1]; local $" = q{ }; # If $var is $_ or $_->{foo} or $foo{$_} or somesuch, then we # can't use it within the grep expression, so we need to save # it into a temporary variable ($tmp). ($var =~ /\$_/) ? qq{ Scalar::Util::blessed($var) and not do { my \$tmp = $var; grep(!\$tmp->can(\$_), qw/@methods/) } } : qq{ Scalar::Util::blessed($var) and not grep(!$var->can(\$_), qw/@methods/) }; }; } sub _instantiate_moose_type { my $self = shift; my %opts = @_; delete $opts{parent}; delete $opts{constraint}; delete $opts{inlined}; require Moose::Meta::TypeConstraint::DuckType; return "Moose::Meta::TypeConstraint::DuckType"->new(%opts, methods => $self->methods); } sub validate_explain { my $self = shift; my ($value, $varname) = @_; $varname = '$_' unless defined $varname; return undef if $self->check($value); return ["Not a blessed reference"] unless blessed($value); require Type::Utils; return [ sprintf( '"%s" requires that the reference can %s', $self, Type::Utils::english_list(map qq["$_"], @{$self->methods}), ), map sprintf('The reference cannot "%s"', $_), grep !$value->can($_), @{$self->methods} ]; } push @Type::Tiny::CMP, sub { my $A = shift->find_constraining_type; my $B = shift->find_constraining_type; return Type::Tiny::CMP_UNKNOWN unless $A->isa(__PACKAGE__) && $B->isa(__PACKAGE__); my %seen; for my $word (@{$A->methods}) { $seen{$word} += 1; } for my $word (@{$B->methods}) { $seen{$word} += 2; } my $values = join('', CORE::values %seen); if ($values =~ /^3*$/) { return Type::Tiny::CMP_EQUIVALENT; } elsif ($values !~ /2/) { return Type::Tiny::CMP_SUBTYPE; } elsif ($values !~ /1/) { return Type::Tiny::CMP_SUPERTYPE; } return Type::Tiny::CMP_UNKNOWN; }; 1; __END__ =pod =encoding utf-8 =head1 NAME Type::Tiny::Duck - type constraints based on the "can" method =head1 STATUS This module is covered by the L. =head1 DESCRIPTION Type constraints of the general form C<< { $_->can("method") } >>. This package inherits from L; see that for most documentation. Major differences are listed below: =head2 Attributes =over =item C An arrayref of method names. =item C Unlike Type::Tiny, you I pass a constraint coderef to the constructor. Instead rely on the default. =item C Unlike Type::Tiny, you I pass an inlining coderef to the constructor. Instead rely on the default. =item C Parent is always B, and cannot be passed to the constructor. =back =head2 Methods =over =item C<< stringifies_to($constraint) >> See L. =item C<< numifies_to($constraint) >> See L. =item C<< with_attribute_values($attr1 => $constraint1, ...) >> See L. =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. L. L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Enum.pm000644001750001750 1404313601673061 16303 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tinypackage Type::Tiny::Enum; use 5.006001; use strict; use warnings; BEGIN { $Type::Tiny::Enum::AUTHORITY = 'cpan:TOBYINK'; $Type::Tiny::Enum::VERSION = '1.008001'; } $Type::Tiny::Enum::VERSION =~ tr/_//d; sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } use Type::Tiny (); our @ISA = 'Type::Tiny'; __PACKAGE__->_install_overloads( q[@{}] => sub { shift->values }, ); sub new { my $proto = shift; my %opts = (@_==1) ? %{$_[0]} : @_; _croak "Enum type constraints cannot have a parent constraint passed to the constructor" if exists $opts{parent}; _croak "Enum type constraints cannot have a constraint coderef passed to the constructor" if exists $opts{constraint}; _croak "Enum type constraints cannot have a inlining coderef passed to the constructor" if exists $opts{inlined}; _croak "Need to supply list of values" unless exists $opts{values}; no warnings 'uninitialized'; $opts{values} = [ map "$_", @{ ref $opts{values} eq 'ARRAY' ? $opts{values} : [$opts{values}] } ]; my %tmp; undef $tmp{$_} for @{$opts{values}}; $opts{unique_values} = [sort keys %tmp]; if (Type::Tiny::_USE_XS and not grep /-/, @{$opts{unique_values}}) { my $enum = join ",", @{$opts{unique_values}}; my $xsub = Type::Tiny::XS::get_coderef_for("Enum[$enum]"); $opts{compiled_type_constraint} = $xsub if $xsub; } return $proto->SUPER::new(%opts); } sub values { $_[0]{values} } sub unique_values { $_[0]{unique_values} } sub constraint { $_[0]{constraint} ||= $_[0]->_build_constraint } sub _is_null_constraint { 0 } sub _build_display_name { my $self = shift; sprintf("Enum[%s]", join q[,], @{$self->unique_values}); } { my %cached; sub _build_constraint { my $self = shift; my $regexp = join "|", map quotemeta, @{$self->unique_values}; return $cached{$regexp} if $cached{$regexp}; my $coderef = ($cached{$regexp} = sub { defined and m{\A(?:$regexp)\z} }); Scalar::Util::weaken($cached{$regexp}); return $coderef; } } { my %cached; sub _build_compiled_check { my $self = shift; my $regexp = join "|", map quotemeta, @{$self->unique_values}; return $cached{$regexp} if $cached{$regexp}; my $coderef = ($cached{$regexp} = $self->SUPER::_build_compiled_check(@_)); Scalar::Util::weaken($cached{$regexp}); return $coderef; } } sub can_be_inlined { !!1; } sub inline_check { my $self = shift; if (Type::Tiny::_USE_XS and not grep /-/, @{$self->unique_values}) { my $enum = join ",", @{$self->unique_values}; my $xsub = Type::Tiny::XS::get_subname_for("Enum[$enum]"); return "$xsub\($_[0]\)" if $xsub; } my $regexp = join "|", map quotemeta, @{$self->unique_values}; $_[0] eq '$_' ? "(defined and !ref and m{\\A(?:$regexp)\\z})" : "(defined($_[0]) and !ref($_[0]) and $_[0] =~ m{\\A(?:$regexp)\\z})"; } sub _instantiate_moose_type { my $self = shift; my %opts = @_; delete $opts{parent}; delete $opts{constraint}; delete $opts{inlined}; require Moose::Meta::TypeConstraint::Enum; return "Moose::Meta::TypeConstraint::Enum"->new(%opts, values => $self->values); } sub has_parent { !!1; } sub parent { require Types::Standard; Types::Standard::Str(); } sub validate_explain { my $self = shift; my ($value, $varname) = @_; $varname = '$_' unless defined $varname; return undef if $self->check($value); require Type::Utils; !defined($value) ? [ sprintf( '"%s" requires that the value is defined', $self, ), ] : @$self < 13 ? [ sprintf( '"%s" requires that the value is equal to %s', $self, Type::Utils::english_list(\"or", map B::perlstring($_), @$self), ), ] : [ sprintf( '"%s" requires that the value is one of an enumerated list of strings', $self, ), ]; } push @Type::Tiny::CMP, sub { my $A = shift->find_constraining_type; my $B = shift->find_constraining_type; return Type::Tiny::CMP_UNKNOWN unless $A->isa(__PACKAGE__) && $B->isa(__PACKAGE__); my %seen; for my $word (@{$A->unique_values}) { $seen{$word} += 1; } for my $word (@{$B->unique_values}) { $seen{$word} += 2; } my $values = join('', CORE::values %seen); if ($values =~ /^3*$/) { return Type::Tiny::CMP_EQUIVALENT; } elsif ($values !~ /2/) { return Type::Tiny::CMP_SUPERTYPE; } elsif ($values !~ /1/) { return Type::Tiny::CMP_SUBTYPE; } return Type::Tiny::CMP_UNKNOWN; }; 1; __END__ =pod =encoding utf-8 =head1 NAME Type::Tiny::Enum - string enum type constraints =head1 STATUS This module is covered by the L. =head1 DESCRIPTION Enum type constraints. This package inherits from L; see that for most documentation. Major differences are listed below: =head2 Attributes =over =item C Arrayref of allowable value strings. Non-string values (e.g. objects with overloading) will be stringified in the constructor. =item C Unlike Type::Tiny, you I pass a constraint coderef to the constructor. Instead rely on the default. =item C Unlike Type::Tiny, you I pass an inlining coderef to the constructor. Instead rely on the default. =item C Parent is always B, and cannot be passed to the constructor. =item C The list of C but sorted and with duplicates removed. This cannot be passed to the constructor. =back =head2 Overloading =over =item * Arrayrefification calls C. =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. L. L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intersection.pm000644001750001750 1562613601673061 20055 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tinypackage Type::Tiny::Intersection; use 5.006001; use strict; use warnings; BEGIN { $Type::Tiny::Intersection::AUTHORITY = 'cpan:TOBYINK'; $Type::Tiny::Intersection::VERSION = '1.008001'; } $Type::Tiny::Intersection::VERSION =~ tr/_//d; use Scalar::Util qw< blessed >; use Types::TypeTiny (); sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } use Type::Tiny (); our @ISA = 'Type::Tiny'; __PACKAGE__->_install_overloads( q[@{}] => sub { $_[0]{type_constraints} ||= [] }, ); sub new { my $proto = shift; my %opts = (@_==1) ? %{$_[0]} : @_; _croak "Intersection type constraints cannot have a parent constraint" if exists $opts{parent}; _croak "Intersection type constraints cannot have a constraint coderef passed to the constructor" if exists $opts{constraint}; _croak "Intersection type constraints cannot have a inlining coderef passed to the constructor" if exists $opts{inlined}; _croak "Need to supply list of type constraints" unless exists $opts{type_constraints}; $opts{type_constraints} = [ map { $_->isa(__PACKAGE__) ? @$_ : $_ } map Types::TypeTiny::to_TypeTiny($_), @{ ref $opts{type_constraints} eq "ARRAY" ? $opts{type_constraints} : [$opts{type_constraints}] } ]; if (Type::Tiny::_USE_XS) { my @constraints = @{$opts{type_constraints}}; my @known = map { my $known = Type::Tiny::XS::is_known($_->compiled_check); defined($known) ? $known : (); } @constraints; if (@known == @constraints) { my $xsub = Type::Tiny::XS::get_coderef_for( sprintf "AllOf[%s]", join(',', @known) ); $opts{compiled_type_constraint} = $xsub if $xsub; } } return $proto->SUPER::new(%opts); } sub type_constraints { $_[0]{type_constraints} } sub constraint { $_[0]{constraint} ||= $_[0]->_build_constraint } sub _is_null_constraint { 0 } sub _build_display_name { my $self = shift; join q[&], @$self; } sub _build_constraint { my @checks = map $_->compiled_check, @{+shift}; return sub { my $val = $_; $_->($val) || return for @checks; return !!1; } } sub can_be_inlined { my $self = shift; not grep !$_->can_be_inlined, @$self; } sub inline_check { my $self = shift; if (Type::Tiny::_USE_XS and !exists $self->{xs_sub}) { $self->{xs_sub} = undef; my @constraints = @{$self->type_constraints}; my @known = map { my $known = Type::Tiny::XS::is_known($_->compiled_check); defined($known) ? $known : (); } @constraints; if (@known == @constraints) { $self->{xs_sub} = Type::Tiny::XS::get_subname_for( sprintf "AllOf[%s]", join(',', @known) ); } } if (Type::Tiny::_USE_XS and $self->{xs_sub}) { return "$self->{xs_sub}\($_[0]\)"; } sprintf '(%s)', join " and ", map $_->inline_check($_[0]), @$self; } sub has_parent { !!@{ $_[0]{type_constraints} }; } sub parent { $_[0]{type_constraints}[0]; } sub validate_explain { my $self = shift; my ($value, $varname) = @_; $varname = '$_' unless defined $varname; return undef if $self->check($value); require Type::Utils; for my $type (@$self) { my $deep = $type->validate_explain($value, $varname); return [ sprintf( '"%s" requires that the value pass %s', $self, Type::Utils::english_list(map qq["$_"], @$self), ), @$deep, ] if $deep; } # This should never happen... return; # uncoverable statement } my $_delegate = sub { my ($self, $method) = (shift, shift); my @types = @{ $self->type_constraints }; my $found = 0; for my $i (0 .. $#types) { my $type = $types[$i]; if ($type->can($method)) { $types[$i] = $type->$method(@_); ++$found; last; } } _croak('Could not apply method %s to any type within the intersection', $method) unless $found; ref($self)->new(type_constraints => \@types); }; sub stringifies_to { my $self = shift; $self->$_delegate(stringifies_to => @_); } sub numifies_to { my $self = shift; $self->$_delegate(numifies_to => @_); } sub with_attribute_values { my $self = shift; $self->$_delegate(with_attribute_values => @_); } my $comparator; $comparator = sub { my $A = shift->find_constraining_type; my $B = shift->find_constraining_type; if ($A->isa(__PACKAGE__)) { my @A_constraints = map $_->find_constraining_type, @{ $A->type_constraints }; my @A_equal_to_B = grep $_->equals($B), @A_constraints; if (@A_equal_to_B == @A_constraints) { return Type::Tiny::CMP_EQUIVALENT(); } my @A_subs_of_B = grep $_->is_a_type_of($B), @A_constraints; if (@A_subs_of_B) { return Type::Tiny::CMP_SUBTYPE(); } } elsif ($B->isa(__PACKAGE__)) { my $r = $comparator->($B, $A); return $r if $r eq Type::Tiny::CMP_EQUIVALENT(); return -$r if $r eq Type::Tiny::CMP_SUBTYPE(); } return Type::Tiny::CMP_UNKNOWN(); }; push @Type::Tiny::CMP, $comparator; 1; __END__ =pod =encoding utf-8 =head1 NAME Type::Tiny::Intersection - intersection type constraints =head1 STATUS This module is covered by the L. =head1 DESCRIPTION Intersection type constraints. This package inherits from L; see that for most documentation. Major differences are listed below: =head2 Attributes =over =item C Arrayref of type constraints. When passed to the constructor, if any of the type constraints in the intersection is itself an intersection type constraint, this is "exploded" into the new intersection. =item C Unlike Type::Tiny, you I pass a constraint coderef to the constructor. Instead rely on the default. =item C Unlike Type::Tiny, you I pass an inlining coderef to the constructor. Instead rely on the default. =item C Unlike Type::Tiny, you I pass an inlining coderef to the constructor. A parent will instead be automatically calculated. (Technically any of the types in the intersection could be treated as a parent type; we choose the first arbitrarily.) =back =head2 Methods =over =item C<< stringifies_to($constraint) >> See L. =item C<< numifies_to($constraint) >> See L. =item C<< with_attribute_values($attr1 => $constraint1, ...) >> See L. =back =head2 Overloading =over =item * Arrayrefification calls C. =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. L. L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Manual.pod000644001750001750 1444513601673061 16770 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual - an overview of Type::Tiny =head1 SYNOPSIS L is a small L class for writing type constraints, inspired by L's type constraint API and L. It has only one non-core dependency (and even that is simply a module that was previously distributed as part of Type::Tiny but has since been spun off), and can be used with L, L, or L (or none of the above). Type::Tiny is used by over 800 Perl distributions on the CPAN (Comprehensive Perl Archive Network) and can be considered a stable and mature framework for efficiently and reliably enforcing data types. Type::Tiny is bundled with L a framework for organizing type constraints into collections. Also bundled is L, a Moose-inspired library of useful type constraints. L is also provided, to allow very fast checking and coercion of function and method parameters. The following example gives you an idea of some of the features of these modules. If you don't understand it all, that's fine; that's what the rest of the manual is for. Although the example uses Moo, the C could be changed to C or C and it would still work. use v5.12; use strict; use warnings; package Horse { use Moo; use Types::Standard qw( Str Int Enum ArrayRef InstanceOf ); use Type::Params qw( compile ); use namespace::autoclean; has name => ( is => 'ro', isa => Str, required => 1, ); has gender => ( is => 'ro', isa => Enum[qw( f m )], ); has age => ( is => 'rw', isa => Int->where( '$_ >= 0' ), ); has children => ( is => 'ro', isa => ArrayRef[ InstanceOf['Horse'] ], default => sub { return [] }, ); sub add_child { # method signature state $check = compile( InstanceOf['Horse'], InstanceOf['Horse'] ); my ($self, $child) = $check->(@_); # unpack @_ push @{ $self->children }, $child; return $self; } } package main; my $boldruler = Horse->new( name => "Bold Ruler", gender => 'm', age => 16, ); my $secretariat = Horse->new( name => "Secretariat", gender => 'm', age => 0, ); $boldruler->add_child( $secretariat ); use Types::Standard qw( is_Object assert_Object ); # is_Object will return a boolean # if ( is_Object($boldruler) ) { say $boldruler->name; } # assert_Object will return $secretariat or die # say assert_Object($secretariat)->name; =head1 MANUAL Even if you are using Type::Tiny with other object-oriented programming toolkits (such as Moose or Mouse), you should start with the Moo sections of the manual. Most of the information is directly transferrable and the Moose and Mouse sections of the manual list the minor differences between using Type::Tiny with Moo and with them. In general, this manual assumes you use Perl 5.12 or above and may use examples that do not work on older versions of Perl. Type::Tiny does work on earlier versions of Perl, but not all the examples and features in the manual will run without adjustment. (For instance, you may need to replace C variables with lexical variables, avoid the C<< package NAME { BLOCK } >> syntax, etc.) =over =item * L How to install Type::Tiny. If Type::Tiny is already installed, you can skip this. =item * L Basic use of Type::Tiny with Moo, including attribute type constraints, parameterized type constraints, coercions, and method parameter checking. =item * L Advanced use of Type::Tiny with Moo, including unions and intersections, C, C, C, and C. =item * L There's more than one way to do it! Alternative ways of using Type::Tiny, including type registries, exported functions, and C. =item * L Defining your own type libraries, including extending existing libraries, defining new types, adding coercions, defining parameterizable types, and the declarative style. =item * L How to use Type::Tiny with Moose, including the advantages of Type::Tiny over built-in type constraints, and Moose-specific features. =item * L How to use Type::Tiny with Mouse, including the advantages of Type::Tiny over built-in type constraints, and Mouse-specific features. =item * L Including how to Type::Tiny in your object's C method, and third-party shims between Type::Tiny and Class::Tiny. =item * L Using Type::Tiny with Class::InsideOut, Params::Check, and Object::Accessor. =item * L Type::Tiny for test suites. =item * L Advanced information on Type::Params, and using Type::Tiny with other signature modules like Function::Parameters and Kavorka. =item * L Type::Tiny in non-object-oriented code. =item * L Squeeze the most out of your CPU. =item * L Advanced information on coercions. =item * L An alphabetical list of all type constraints bundled with Type::Tiny. =item * L Policies related to Type::Tiny development. =item * L Contributing to Type::Tiny development. =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut Role.pm000644001750001750 1003013601673061 16270 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tinypackage Type::Tiny::Role; use 5.006001; use strict; use warnings; BEGIN { $Type::Tiny::Role::AUTHORITY = 'cpan:TOBYINK'; $Type::Tiny::Role::VERSION = '1.008001'; } $Type::Tiny::Role::VERSION =~ tr/_//d; use Scalar::Util qw< blessed weaken >; sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } require Type::Tiny::ConstrainedObject; our @ISA = 'Type::Tiny::ConstrainedObject'; sub _short_name { 'Role' } my %cache; sub new { my $proto = shift; my %opts = (@_==1) ? %{$_[0]} : @_; _croak "Need to supply role name" unless exists $opts{role}; return $proto->SUPER::new(%opts); } sub role { $_[0]{role} } sub inlined { $_[0]{inlined} ||= $_[0]->_build_inlined } sub has_inlined { !!1 } sub _is_null_constraint { 0 } sub _build_constraint { my $self = shift; my $role = $self->role; return sub { blessed($_) and do { my $method = $_->can('DOES')||$_->can('isa'); $_->$method($role) } }; } sub _build_inlined { my $self = shift; my $role = $self->role; sub { my $var = $_[1]; qq{Scalar::Util::blessed($var) and do { my \$method = $var->can('DOES')||$var->can('isa'); $var->\$method(q[$role]) }}; }; } sub _build_default_message { my $self = shift; my $c = $self->role; return sub { sprintf '%s did not pass type constraint (not DOES %s)', Type::Tiny::_dd($_[0]), $c } if $self->is_anon; my $name = "$self"; return sub { sprintf '%s did not pass type constraint "%s" (not DOES %s)', Type::Tiny::_dd($_[0]), $name, $c }; } sub validate_explain { my $self = shift; my ($value, $varname) = @_; $varname = '$_' unless defined $varname; return undef if $self->check($value); return ["Not a blessed reference"] unless blessed($value); return ["Reference provides no DOES method to check roles"] unless $value->can('DOES'); my $display_var = $varname eq q{$_} ? '' : sprintf(' (in %s)', $varname); return [ sprintf('"%s" requires that the reference does %s', $self, $self->role), sprintf("The reference%s doesn't %s", $display_var, $self->role), ]; } 1; __END__ =pod =encoding utf-8 =head1 NAME Type::Tiny::Role - type constraints based on the "DOES" method =head1 STATUS This module is covered by the L. =head1 DESCRIPTION Type constraints of the general form C<< { $_->DOES("Some::Role") } >>. This package inherits from L; see that for most documentation. Major differences are listed below: =head2 Attributes =over =item C The role for the constraint. Note that this package doesn't subscribe to any particular flavour of roles (L, L, L, L, etc). It simply trusts the object's C method (see L). =item C Unlike Type::Tiny, you I pass a constraint coderef to the constructor. Instead rely on the default. =item C Unlike Type::Tiny, you I pass an inlining coderef to the constructor. Instead rely on the default. =item C Parent is always B, and cannot be passed to the constructor. =back =head2 Methods =over =item C<< stringifies_to($constraint) >> See L. =item C<< numifies_to($constraint) >> See L. =item C<< with_attribute_values($attr1 => $constraint1, ...) >> See L. =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. L. L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Union.pm000644001750001750 2431113601673061 16466 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tinypackage Type::Tiny::Union; use 5.006001; use strict; use warnings; BEGIN { $Type::Tiny::Union::AUTHORITY = 'cpan:TOBYINK'; $Type::Tiny::Union::VERSION = '1.008001'; } $Type::Tiny::Union::VERSION =~ tr/_//d; use Scalar::Util qw< blessed >; use Types::TypeTiny (); sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } use Type::Tiny (); our @ISA = 'Type::Tiny'; __PACKAGE__->_install_overloads( q[@{}] => sub { $_[0]{type_constraints} ||= [] } ); sub new { my $proto = shift; my %opts = (@_==1) ? %{$_[0]} : @_; _croak "Union type constraints cannot have a parent constraint passed to the constructor" if exists $opts{parent}; _croak "Union type constraints cannot have a constraint coderef passed to the constructor" if exists $opts{constraint}; _croak "Union type constraints cannot have a inlining coderef passed to the constructor" if exists $opts{inlined}; _croak "Need to supply list of type constraints" unless exists $opts{type_constraints}; $opts{type_constraints} = [ map { $_->isa(__PACKAGE__) ? @$_ : $_ } map Types::TypeTiny::to_TypeTiny($_), @{ ref $opts{type_constraints} eq "ARRAY" ? $opts{type_constraints} : [$opts{type_constraints}] } ]; if (Type::Tiny::_USE_XS) { my @constraints = @{$opts{type_constraints}}; my @known = map { my $known = Type::Tiny::XS::is_known($_->compiled_check); defined($known) ? $known : (); } @constraints; if (@known == @constraints) { my $xsub = Type::Tiny::XS::get_coderef_for( sprintf "AnyOf[%s]", join(',', @known) ); $opts{compiled_type_constraint} = $xsub if $xsub; } } my $self = $proto->SUPER::new(%opts); $self->coercion if grep $_->has_coercion, @$self; return $self; } sub type_constraints { $_[0]{type_constraints} } sub constraint { $_[0]{constraint} ||= $_[0]->_build_constraint } sub _is_null_constraint { 0 } sub _build_display_name { my $self = shift; join q[|], @$self; } sub _build_coercion { require Type::Coercion::Union; my $self = shift; return "Type::Coercion::Union"->new(type_constraint => $self); } sub _build_constraint { my @checks = map $_->compiled_check, @{+shift}; return sub { my $val = $_; $_->($val) && return !!1 for @checks; return; } } sub can_be_inlined { my $self = shift; not grep !$_->can_be_inlined, @$self; } sub inline_check { my $self = shift; if (Type::Tiny::_USE_XS and !exists $self->{xs_sub}) { $self->{xs_sub} = undef; my @constraints = @{$self->type_constraints}; my @known = map { my $known = Type::Tiny::XS::is_known($_->compiled_check); defined($known) ? $known : (); } @constraints; if (@known == @constraints) { $self->{xs_sub} = Type::Tiny::XS::get_subname_for( sprintf "AnyOf[%s]", join(',', @known) ); } } if (Type::Tiny::_USE_XS and $self->{xs_sub}) { return "$self->{xs_sub}\($_[0]\)"; } sprintf '(%s)', join " or ", map $_->inline_check($_[0]), @$self; } sub _instantiate_moose_type { my $self = shift; my %opts = @_; delete $opts{parent}; delete $opts{constraint}; delete $opts{inlined}; my @tc = map $_->moose_type, @{$self->type_constraints}; require Moose::Meta::TypeConstraint::Union; return "Moose::Meta::TypeConstraint::Union"->new(%opts, type_constraints => \@tc); } sub has_parent { defined(shift->parent); } sub parent { $_[0]{parent} ||= $_[0]->_build_parent; } sub _build_parent { my $self = shift; my ($first, @rest) = @$self; for my $parent ($first, $first->parents) { return $parent unless grep !$_->is_a_type_of($parent), @rest; } return; } sub find_type_for { my @types = @{+shift}; for my $type (@types) { return $type if $type->check(@_); } return; } sub validate_explain { my $self = shift; my ($value, $varname) = @_; $varname = '$_' unless defined $varname; return undef if $self->check($value); require Type::Utils; return [ sprintf( '"%s" requires that the value pass %s', $self, Type::Utils::english_list(\"or", map qq["$_"], @$self), ), map { $_->get_message($value), map(" $_", @{ $_->validate_explain($value) || []}), } @$self ]; } my $_delegate = sub { my ($self, $method) = (shift, shift); my @types = @{ $self->type_constraints }; my @unsupported = grep !$_->can($method), @types; _croak('Could not apply method %s to all types within the union', $method) if @unsupported; ref($self)->new(type_constraints => [ map $_->$method(@_), @types ]); }; sub stringifies_to { my $self = shift; $self->$_delegate(stringifies_to => @_); } sub numifies_to { my $self = shift; $self->$_delegate(numifies_to => @_); } sub with_attribute_values { my $self = shift; $self->$_delegate(with_attribute_values => @_); } push @Type::Tiny::CMP, sub { my $A = shift->find_constraining_type; my $B = shift->find_constraining_type; if ($A->isa(__PACKAGE__) and $B->isa(__PACKAGE__)) { my @A_constraints = @{ $A->type_constraints }; my @B_constraints = @{ $B->type_constraints }; # If everything in @A_constraints is equal to something in @B_constraints and vice versa, then $A equiv to $B EQUALITY: { my $everything_in_a_is_equal = 1; OUTER: for my $A_child (@A_constraints) { INNER: for my $B_child (@B_constraints) { if ($A_child->equals($B_child)) { next OUTER; } } $everything_in_a_is_equal = 0; last OUTER; } my $everything_in_b_is_equal = 1; OUTER: for my $B_child (@B_constraints) { INNER: for my $A_child (@A_constraints) { if ($B_child->equals($A_child)) { next OUTER; } } $everything_in_b_is_equal = 0; last OUTER; } return Type::Tiny::CMP_EQUIVALENT if $everything_in_a_is_equal && $everything_in_b_is_equal; } # If everything in @A_constraints is a subtype of something in @B_constraints, then $A is subtype of $B SUBTYPE: { OUTER: for my $A_child (@A_constraints) { my $a_child_is_subtype_of_something = 0; INNER: for my $B_child (@B_constraints) { if ($A_child->is_a_type_of($B_child)) { ++$a_child_is_subtype_of_something; last INNER; } } if (not $a_child_is_subtype_of_something) { last SUBTYPE; } } return Type::Tiny::CMP_SUBTYPE; } # If everything in @B_constraints is a subtype of something in @A_constraints, then $A is supertype of $B SUPERTYPE: { OUTER: for my $B_child (@B_constraints) { my $b_child_is_subtype_of_something = 0; INNER: for my $A_child (@A_constraints) { if ($B_child->is_a_type_of($A_child)) { ++$b_child_is_subtype_of_something; last INNER; } } if (not $b_child_is_subtype_of_something) { last SUPERTYPE; } } return Type::Tiny::CMP_SUPERTYPE; } } # I think it might be possible to merge this into the first bit by treating $B as union[$B]. # Test cases first though. if ($A->isa(__PACKAGE__)) { my @A_constraints = @{ $A->type_constraints }; if (@A_constraints == 1) { my $result = Type::Tiny::cmp($A_constraints[0], $B); return $result unless $result eq Type::Tiny::CMP_UNKNOWN; } my $subtype = 1; for my $child (@A_constraints) { if ($B->is_a_type_of($child)) { return Type::Tiny::CMP_SUPERTYPE; } if ($subtype and not $B->is_supertype_of($child)) { $subtype = 0; } } if ($subtype) { return Type::Tiny::CMP_SUBTYPE; } } # I think it might be possible to merge this into the first bit by treating $A as union[$A]. # Test cases first though. if ($B->isa(__PACKAGE__)) { my @B_constraints = @{ $B->type_constraints }; if (@B_constraints == 1) { my $result = Type::Tiny::cmp($A, $B_constraints[0]); return $result unless $result eq Type::Tiny::CMP_UNKNOWN; } my $supertype = 1; for my $child (@B_constraints) { if ($A->is_a_type_of($child)) { return Type::Tiny::CMP_SUBTYPE; } if ($supertype and not $A->is_supertype_of($child)) { $supertype = 0; } } if ($supertype) { return Type::Tiny::CMP_SUPERTYPE; } } return Type::Tiny::CMP_UNKNOWN; }; 1; __END__ =pod =encoding utf-8 =head1 NAME Type::Tiny::Union - union type constraints =head1 STATUS This module is covered by the L. =head1 DESCRIPTION Union type constraints. This package inherits from L; see that for most documentation. Major differences are listed below: =head2 Attributes =over =item C Arrayref of type constraints. When passed to the constructor, if any of the type constraints in the union is itself a union type constraint, this is "exploded" into the new union. =item C Unlike Type::Tiny, you I pass a constraint coderef to the constructor. Instead rely on the default. =item C Unlike Type::Tiny, you I pass an inlining coderef to the constructor. Instead rely on the default. =item C Unlike Type::Tiny, you I pass an inlining coderef to the constructor. A parent will instead be automatically calculated. =item C You probably do not pass this to the constructor. (It's not currently disallowed, as there may be a use for it that I haven't thought of.) The auto-generated default will be a L object. =back =head2 Methods =over =item C<< find_type_for($value) >> Returns the first individual type constraint in the union which C<< $value >> passes. =item C<< stringifies_to($constraint) >> See L. =item C<< numifies_to($constraint) >> See L. =item C<< with_attribute_values($attr1 => $constraint1, ...) >> See L. =back =head2 Overloading =over =item * Arrayrefification calls C. =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. _HalfOp.pm000644001750001750 334413601673061 16671 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tinypackage Type::Tiny::_HalfOp; use 5.006001; use strict; use warnings; BEGIN { $Type::Tiny::_HalfOp::AUTHORITY = 'cpan:TOBYINK'; $Type::Tiny::_HalfOp::VERSION = '1.008001'; } $Type::Tiny::_HalfOp::VERSION =~ tr/_//d; sub new { my ($class, $op, $param, $type) = @_; bless { op => $op, param => $param, type => $type, }, $class; } sub complete { require overload; my ($self, $type) = @_; my $complete_type = $type->parameterize(@{$self->{param}}); my $method = overload::Method($complete_type, $self->{op}); $complete_type->$method($self->{type}); } 1; __END__ =pod =encoding utf-8 =for stopwords pragmas =head1 NAME Type::Tiny::_HalfOp - half-completed overloaded operation =head1 STATUS This module is considered part of Type-Tiny's internals. It is not covered by the L. =head1 DESCRIPTION This is not considered part of Type::Tiny's public API. It is a class representing a half-completed overloaded operation. =head2 Constructor =over =item C<< new($operation, $param, $type) >> =back =head2 Method =over =item C<< complete($type) >> =back =head1 BUGS Please report any bugs to L. =head1 AUTHOR Graham Knop Ehaarg@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Graham Knop. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Numeric.pm000644001750001750 1741613601673061 17500 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Types/Commonpackage Types::Common::Numeric; use 5.006001; use strict; use warnings; BEGIN { if ($] < 5.008) { require Devel::TypeTiny::Perl56Compat }; } BEGIN { $Types::Common::Numeric::AUTHORITY = 'cpan:TOBYINK'; $Types::Common::Numeric::VERSION = '1.008001'; } $Types::Common::Numeric::VERSION =~ tr/_//d; use Type::Library -base, -declare => qw( PositiveNum PositiveOrZeroNum PositiveInt PositiveOrZeroInt NegativeNum NegativeOrZeroNum NegativeInt NegativeOrZeroInt SingleDigit NumRange IntRange ); use Type::Tiny (); use Types::Standard qw( Num Int Bool ); sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } my $meta = __PACKAGE__->meta; $meta->add_type( name => 'PositiveNum', parent => Num, constraint => sub { $_ > 0 }, inlined => sub { undef, qq($_ > 0) }, message => sub { "Must be a positive number" }, ); $meta->add_type( name => 'PositiveOrZeroNum', parent => Num, constraint => sub { $_ >= 0 }, inlined => sub { undef, qq($_ >= 0) }, message => sub { "Must be a number greater than or equal to zero" }, ); my ($pos_int, $posz_int); if (Type::Tiny::_USE_XS) { $pos_int = Type::Tiny::XS::get_coderef_for('PositiveInt') if Type::Tiny::XS->VERSION >= 0.013; # fixed bug with "00" $posz_int = Type::Tiny::XS::get_coderef_for('PositiveOrZeroInt'); } $meta->add_type( name => 'PositiveInt', parent => Int, constraint => sub { $_ > 0 }, inlined => sub { if ($pos_int) { my $xsub = Type::Tiny::XS::get_subname_for($_[0]->name); return "$xsub($_[1])" if $xsub && !$Type::Tiny::AvoidCallbacks; } undef, qq($_ > 0); }, message => sub { "Must be a positive integer" }, $pos_int ? ( compiled_type_constraint => $pos_int ) : (), ); $meta->add_type( name => 'PositiveOrZeroInt', parent => Int, constraint => sub { $_ >= 0 }, inlined => sub { if ($posz_int) { my $xsub = Type::Tiny::XS::get_subname_for($_[0]->name); return "$xsub($_[1])" if $xsub && !$Type::Tiny::AvoidCallbacks; } undef, qq($_ >= 0); }, message => sub { "Must be an integer greater than or equal to zero" }, $posz_int ? ( compiled_type_constraint => $posz_int ) : (), ); $meta->add_type( name => 'NegativeNum', parent => Num, constraint => sub { $_ < 0 }, inlined => sub { undef, qq($_ < 0) }, message => sub { "Must be a negative number" }, ); $meta->add_type( name => 'NegativeOrZeroNum', parent => Num, constraint => sub { $_ <= 0 }, inlined => sub { undef, qq($_ <= 0) }, message => sub { "Must be a number less than or equal to zero" }, ); $meta->add_type( name => 'NegativeInt', parent => Int, constraint => sub { $_ < 0 }, inlined => sub { undef, qq($_ < 0) }, message => sub { "Must be a negative integer" }, ); $meta->add_type( name => 'NegativeOrZeroInt', parent => Int, constraint => sub { $_ <= 0 }, inlined => sub { undef, qq($_ <= 0) }, message => sub { "Must be an integer less than or equal to zero" }, ); $meta->add_type( name => 'SingleDigit', parent => Int, constraint => sub { $_ >= -9 and $_ <= 9 }, inlined => sub { undef, qq($_ >= -9), qq($_ <= 9) }, message => sub { "Must be a single digit" }, ); for my $base (qw/Num Int/) { $meta->add_type( name => "${base}Range", parent => Types::Standard->get_type($base), constraint_generator => sub { return $meta->get_type("${base}Range") unless @_; my $base_obj = Types::Standard->get_type($base); my ($min, $max, $min_excl, $max_excl) = @_; !defined($min) or $base_obj->check($min) or _croak("${base}Range min must be a %s; got %s", lc($base), $min); !defined($max) or $base_obj->check($max) or _croak("${base}Range max must be a %s; got %s", lc($base), $max); !defined($min_excl) or Bool->check($min_excl) or _croak("${base}Range minexcl must be a boolean; got $min_excl"); !defined($max_excl) or Bool->check($max_excl) or _croak("${base}Range maxexcl must be a boolean; got $max_excl"); # this is complicated so defer to the inline generator eval sprintf( 'sub { %s }', join ' and ', grep defined, $meta->get_type("${base}Range")->inline_generator->(@_)->(undef, '$_[0]'), ); }, inline_generator => sub { my ($min, $max, $min_excl, $max_excl) = @_; my $gt = $min_excl ? '>' : '>='; my $lt = $max_excl ? '<' : '<='; return sub { my $v = $_[1]; my @code = (undef); # parent constraint push @code, "$v $gt $min"; push @code, "$v $lt $max" if defined $max; return @code; }; }, deep_explanation => sub { my ($type, $value, $varname) = @_; my ($min, $max, $min_excl, $max_excl) = @{ $type->parameters || [] }; my @whines; if (defined $max) { push @whines, sprintf( '"%s" expects %s to be %s %d and %s %d', $type, $varname, $min_excl ? 'greater than' : 'at least', $min, $max_excl ? 'less than' : 'at most', $max, ); } else { push @whines, sprintf( '"%s" expects %s to be %s %d', $type, $varname, $min_excl ? 'greater than' : 'at least', $min, ); } push @whines, sprintf( "length(%s) is %d", $varname, length($value), ); return \@whines; }, ); } __PACKAGE__->meta->make_immutable; 1; __END__ =pod =encoding utf-8 =head1 NAME Types::Common::Numeric - drop-in replacement for MooseX::Types::Common::Numeric =head1 STATUS This module is covered by the L. =head1 DESCRIPTION A drop-in replacement for L. =head2 Types The following types are similar to those described in L. =over =item * B =item * B =item * B =item * B =item * B =item * B =item * B =item * B =item * B C interestingly accepts the numbers -9 to -1; not just 0 to 9. =back This module also defines an extra pair of type constraints not found in L. =over =item * B<< IntRange[`min, `max] >> Type constraint for an integer between min and max. For example: IntRange[1, 10] The maximum can be omitted. IntRange[10] # at least 10 The minimum and maximum are inclusive. =item * B<< NumRange[`min, `max] >> Type constraint for a number between min and max. For example: NumRange[0.1, 10.0] As with IntRange, the maximum can be omitted, and the minimum and maximum are inclusive. Exclusive ranges can be useful for non-integer values, so additional parameters can be given to make the minimum and maximum exclusive. NumRange[0.1, 10.0, 0, 0] # both inclusive NumRange[0.1, 10.0, 0, 1] # exclusive maximum, so 10.0 is invalid NumRange[0.1, 10.0, 1, 0] # exclusive minimum, so 0.1 is invalid NumRange[0.1, 10.0, 1, 1] # both exclusive Making one of the limits exclusive means that a C<< < >> or C<< > >> operator will be used instead of the usual C<< <= >> or C<< >= >> operators. =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L, L. L, L, L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. String.pm000644001750001750 1603213601673061 17335 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Types/Commonpackage Types::Common::String; use 5.006001; use strict; use warnings; use utf8; BEGIN { if ($] < 5.008) { require Devel::TypeTiny::Perl56Compat }; } BEGIN { $Types::Common::String::AUTHORITY = 'cpan:TOBYINK'; $Types::Common::String::VERSION = '1.008001'; } $Types::Common::String::VERSION =~ tr/_//d; use Type::Library -base, -declare => qw( SimpleStr NonEmptySimpleStr NumericCode LowerCaseSimpleStr UpperCaseSimpleStr Password StrongPassword NonEmptyStr LowerCaseStr UpperCaseStr StrLength ); use Type::Tiny (); use Types::Standard qw( Str ); my $meta = __PACKAGE__->meta; $meta->add_type( name => SimpleStr, parent => Str, constraint => sub { length($_) <= 255 and not /\n/ }, inlined => sub { undef, qq(length($_) <= 255), qq($_ !~ /\\n/) }, message => sub { "Must be a single line of no more than 255 chars" }, ); $meta->add_type( name => NonEmptySimpleStr, parent => SimpleStr, constraint => sub { length($_) > 0 }, inlined => sub { undef, qq(length($_) > 0) }, message => sub { "Must be a non-empty single line of no more than 255 chars" }, ); $meta->add_type( name => NumericCode, parent => NonEmptySimpleStr, constraint => sub { /^[0-9]+$/ }, inlined => sub { SimpleStr->inline_check($_), qq($_ =~ m/^[0-9]+\$/) }, message => sub { 'Must be a non-empty single line of no more than 255 chars that consists ' . 'of numeric characters only' }, ); NumericCode->coercion->add_type_coercions( NonEmptySimpleStr, q[ do { (my $code = $_) =~ s/[[:punct:][:space:]]//g; $code } ], ); $meta->add_type( name => Password, parent => NonEmptySimpleStr, constraint => sub { length($_) > 3 }, inlined => sub { SimpleStr->inline_check($_), qq(length($_) > 3) }, message => sub { "Must be between 4 and 255 chars" }, ); $meta->add_type( name => StrongPassword, parent => Password, constraint => sub { length($_) > 7 and /[^a-zA-Z]/ }, inlined => sub { SimpleStr()->inline_check($_), qq(length($_) > 7), qq($_ =~ /[^a-zA-Z]/) }, message => sub { "Must be between 8 and 255 chars, and contain a non-alpha char" }, ); my ($nestr); if (Type::Tiny::_USE_XS) { $nestr = Type::Tiny::XS::get_coderef_for('NonEmptyStr'); } $meta->add_type( name => NonEmptyStr, parent => Str, constraint => sub { length($_) > 0 }, inlined => sub { if ($nestr) { my $xsub = Type::Tiny::XS::get_subname_for($_[0]->name); return "$xsub($_[1])" if $xsub && !$Type::Tiny::AvoidCallbacks; } undef, qq(length($_) > 0); }, message => sub { "Must not be empty" }, $nestr ? ( compiled_type_constraint => $nestr ) : (), ); $meta->add_type( name => LowerCaseStr, parent => NonEmptyStr, constraint => sub { !/\p{Upper}/ms }, inlined => sub { undef, qq($_ !~ /\\p{Upper}/ms) }, message => sub { "Must not contain upper case letters" }, ); LowerCaseStr->coercion->add_type_coercions( NonEmptyStr, q[ lc($_) ], ); $meta->add_type( name => UpperCaseStr, parent => NonEmptyStr, constraint => sub { !/\p{Lower}/ms }, inlined => sub { undef, qq($_ !~ /\\p{Lower}/ms) }, message => sub { "Must not contain lower case letters" }, ); UpperCaseStr->coercion->add_type_coercions( NonEmptyStr, q[ uc($_) ], ); $meta->add_type( name => LowerCaseSimpleStr, parent => NonEmptySimpleStr, constraint => sub { !/\p{Upper}/ms }, inlined => sub { undef, qq($_ !~ /\\p{Upper}/ms) }, message => sub { "Must not contain upper case letters" }, ); LowerCaseSimpleStr->coercion->add_type_coercions( NonEmptySimpleStr, q[ lc($_) ], ); $meta->add_type( name => UpperCaseSimpleStr, parent => NonEmptySimpleStr, constraint => sub { !/\p{Lower}/ms }, inlined => sub { undef, qq($_ !~ /\\p{Lower}/ms) }, message => sub { "Must not contain lower case letters" }, ); UpperCaseSimpleStr->coercion->add_type_coercions( NonEmptySimpleStr, q[ uc($_) ], ); $meta->add_type( name => StrLength, parent => Str, constraint_generator => sub { return $meta->get_type('StrLength') unless @_; my ($min, $max) = @_; Types::Standard::Int->check($_) || Types::Standard::_croak("Parameters for StrLength[`min, `max] expected to be integers; got $_") for @_; if (defined $max) { return sub { length($_[0]) >= $min and length($_[0]) <= $max }; } else { return sub { length($_[0]) >= $min }; } }, inline_generator => sub { my ($min, $max) = @_; return sub { my $v = $_[1]; my @code = (undef); # parent constraint push @code, "length($v) >= $min"; push @code, "length($v) <= $max" if defined $max; return @code; }; }, deep_explanation => sub { my ($type, $value, $varname) = @_; my ($min, $max) = @{ $type->parameters || [] }; my @whines; if (defined $max) { push @whines, sprintf( '"%s" expects length(%s) to be between %d and %d', $type, $varname, $min, $max, ); } else { push @whines, sprintf( '"%s" expects length(%s) to be at least %d', $type, $varname, $min, ); } push @whines, sprintf( "length(%s) is %d", $varname, length($value), ); return \@whines; }, ); __PACKAGE__->meta->make_immutable; 1; __END__ =pod =encoding utf-8 =head1 NAME Types::Common::String - drop-in replacement for MooseX::Types::Common::String =head1 STATUS This module is covered by the L. =head1 DESCRIPTION A drop-in replacement for L. =head2 Types The following types are similar to those described in L. =over =item * B =item * B =item * B =item * B =item * B =item * B =item * B =item * B =item * B =item * B =back This module also defines an extra type constraint not found in L. =over =item * B<< StrLength[`min, `max] >> Type constraint for a string between min and max characters long. For example: StrLength[4, 20] It is sometimes useful to combine this with another type constraint in an intersection. (LowerCaseStr) & (StrLength[4, 20]) The max length can be omitted. StrLength[10] # at least 10 characters Lengths are inclusive. =back =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L, L. L, L, L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ArrayRef.pm000644001750001750 1357113601673061 20117 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Types/Standardpackage Types::Standard::ArrayRef; use 5.006001; use strict; use warnings; BEGIN { $Types::Standard::ArrayRef::AUTHORITY = 'cpan:TOBYINK'; $Types::Standard::ArrayRef::VERSION = '1.008001'; } $Types::Standard::ArrayRef::VERSION =~ tr/_//d; use Type::Tiny (); use Types::Standard (); use Types::TypeTiny (); sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } no warnings; sub __constraint_generator { return Types::Standard::ArrayRef unless @_; my $param = shift; Types::TypeTiny::TypeTiny->check($param) or _croak("Parameter to ArrayRef[`a] expected to be a type constraint; got $param"); my ($min, $max) = (0, -1); $min = Types::Standard::Int->assert_return(shift) if @_; $max = Types::Standard::Int->assert_return(shift) if @_; my $param_compiled_check = $param->compiled_check; my $xsub; if (Type::Tiny::_USE_XS and $min==0 and $max==-1) { my $paramname = Type::Tiny::XS::is_known($param_compiled_check); $xsub = Type::Tiny::XS::get_coderef_for("ArrayRef[$paramname]") if $paramname; } elsif (Type::Tiny::_USE_MOUSE and $param->_has_xsub and $min==0 and $max==-1) { require Mouse::Util::TypeConstraints; my $maker = "Mouse::Util::TypeConstraints"->can("_parameterize_ArrayRef_for"); $xsub = $maker->($param) if $maker; } return ( sub { my $array = shift; $param->check($_) || return for @$array; return !!1; }, $xsub, ) if $min==0 and $max==-1; return sub { my $array = shift; return if @$array < $min; $param->check($_) || return for @$array; return !!1; } if $max==-1; return sub { my $array = shift; return if @$array > $max; $param->check($_) || return for @$array; return !!1; } if $min==0; return sub { my $array = shift; return if @$array < $min; return if @$array > $max; $param->check($_) || return for @$array; return !!1; }; } sub __inline_generator { my $param = shift; my ($min, $max) = (0, -1); $min = shift if @_; $max = shift if @_; my $param_compiled_check = $param->compiled_check; my $xsubname; if (Type::Tiny::_USE_XS and $min==0 and $max==-1) { my $paramname = Type::Tiny::XS::is_known($param_compiled_check); $xsubname = Type::Tiny::XS::get_subname_for("ArrayRef[$paramname]"); } return unless $param->can_be_inlined; return sub { my $v = $_[1]; return "$xsubname\($v\)" if $xsubname && !$Type::Tiny::AvoidCallbacks; my $p = Types::Standard::ArrayRef->inline_check($v); if ($min != 0) { $p .= sprintf(' and @{%s} >= %d', $v, $min); } if ($max > 0) { $p .= sprintf(' and @{%s} <= %d', $v, $max); } my $param_check = $param->inline_check('$i'); return $p if $param->{uniq} eq Types::Standard::Any->{uniq}; "$p and do { " . "my \$ok = 1; " . "for my \$i (\@{$v}) { " . "(\$ok = 0, last) unless $param_check " . "}; " . "\$ok " ."}" }; } sub __deep_explanation { my ($type, $value, $varname) = @_; my $param = $type->parameters->[0]; my ($min, $max) = (0, -1); $min = $type->parameters->[1] if @{$type->parameters} > 1; # TODO $max = $type->parameters->[2] if @{$type->parameters} > 2; # TODO if ($min != 0 and @$value < $min) { return [ sprintf('"%s" constrains array length at least %s', $type, $min), sprintf('@{%s} is %d', $varname, scalar @$value), ]; } if ($max > 0 and @$value > $max) { return [ sprintf('"%s" constrains array length at most %d', $type, $max), sprintf('@{%s} is %d', $varname, scalar @$value), ]; } for my $i (0 .. $#$value) { my $item = $value->[$i]; next if $param->check($item); return [ sprintf('"%s" constrains each value in the array with "%s"', $type, $param), @{ $param->validate_explain($item, sprintf('%s->[%d]', $varname, $i)) }, ]; } # This should never happen... return; # uncoverable statement } # TODO: min and max??? sub __coercion_generator { my ($parent, $child, $param) = @_; return unless $param->has_coercion; my $coercable_item = $param->coercion->_source_type_union; my $C = "Type::Coercion"->new(type_constraint => $child); if ($param->coercion->can_be_inlined and $coercable_item->can_be_inlined) { $C->add_type_coercions($parent => Types::Standard::Stringable { my @code; push @code, 'do { my ($orig, $return_orig, @new) = ($_, 0);'; push @code, 'for (@$orig) {'; push @code, sprintf('++$return_orig && last unless (%s);', $coercable_item->inline_check('$_')); push @code, sprintf('push @new, (%s);', $param->coercion->inline_coercion('$_')); push @code, '}'; push @code, '$return_orig ? $orig : \\@new'; push @code, '}'; "@code"; }); } else { $C->add_type_coercions( $parent => sub { my $value = @_ ? $_[0] : $_; my @new; for my $item (@$value) { return $value unless $coercable_item->check($item); push @new, $param->coerce($item); } return \@new; }, ); } return $C; } 1; __END__ =pod =encoding utf-8 =head1 NAME Types::Standard::ArrayRef - internals for the Types::Standard ArrayRef type constraint =head1 STATUS This module is considered part of Type-Tiny's internals. It is not covered by the L. =head1 DESCRIPTION This file contains some of the guts for L. It will be loaded on demand. You may ignore its presence. =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. CycleTuple.pm000644001750001750 1422113601673061 20446 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Types/Standardpackage Types::Standard::CycleTuple; use 5.006001; use strict; use warnings; BEGIN { $Types::Standard::CycleTuple::AUTHORITY = 'cpan:TOBYINK'; $Types::Standard::CycleTuple::VERSION = '1.008001'; } $Types::Standard::CycleTuple::VERSION =~ tr/_//d; use Type::Tiny (); use Types::Standard (); use Types::TypeTiny (); sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } my $_Optional = Types::Standard::Optional; my $_arr = Types::Standard::ArrayRef; no warnings; my $cycleuniq = 0; sub __constraint_generator { my @params = map { ref($_) eq 'HASH' and exists($_->{slurpy}) and _croak("Parameters to CycleTuple[...] cannot be slurpy"); my $param = $_; Types::TypeTiny::TypeTiny->check($param) or _croak("Parameters to CycleTuple[...] expected to be type constraints; got $param"); $param; } @_; my $count = @params; my $tuple = Types::Standard::Tuple()->of(@params); _croak("Parameters to CycleTuple[...] cannot be optional") if grep !!$_->is_strictly_a_type_of($_Optional), @params; sub { my $value = shift; return unless $_arr->check($value); return if @$value % $count; my $i = 0; while ($i < $#$value) { my $tmp = [@$value[ $i .. $i+$count-1 ]]; return unless $tuple->check($tmp); $i += $count; } !!1; } } sub __inline_generator { my @params = map { my $param = $_; Types::TypeTiny::TypeTiny->check($param) or _croak("Parameter to CycleTuple[`a] expected to be a type constraint; got $param"); $param; } @_; my $count = @params; my $tuple = Types::Standard::Tuple()->of(@params); return unless $tuple->can_be_inlined; sub { $cycleuniq++; my $v = $_[1]; my @checks = $_arr->inline_check($v); push @checks, sprintf( 'not(@%s %% %d)', ($v=~/\A\$[a-z0-9_]+\z/i ? $v : "{$v}"), $count, ); push @checks, sprintf( 'do { my $cyclecount%d = 0; my $cycleok%d = 1; while ($cyclecount%d < $#{%s}) { my $cycletmp%d = [@{%s}[$cyclecount%d .. $cyclecount%d+%d]]; unless (%s) { $cycleok%d = 0; last; }; $cyclecount%d += %d; }; $cycleok%d; }', $cycleuniq, $cycleuniq, $cycleuniq, $v, $cycleuniq, $v, $cycleuniq, $cycleuniq, $count - 1, $tuple->inline_check("\$cycletmp$cycleuniq"), $cycleuniq, $cycleuniq, $count, $cycleuniq, ) if grep { $_->inline_check('$xyz') ne '(!!1)' } @params; join(' && ', @checks); } } sub __deep_explanation { my ($type, $value, $varname) = @_; my @constraints = map Types::TypeTiny::to_TypeTiny($_), @{ $type->parameters }; if (@$value % @constraints) { return [ sprintf('"%s" expects a multiple of %d values in the array', $type, scalar(@constraints)), sprintf('%d values found', scalar(@$value)), ]; } for my $i (0 .. $#$value) { my $constraint = $constraints[$i % @constraints]; next if $constraint->check($value->[$i]); return [ sprintf('"%s" constrains value at index %d of array with "%s"', $type, $i, $constraint), @{ $constraint->validate_explain($value->[$i], sprintf('%s->[%s]', $varname, $i)) }, ]; } # This should never happen... return; # uncoverable statement } my $label_counter = 0; sub __coercion_generator { my ($parent, $child, @tuple) = @_; my $child_coercions_exist = 0; my $all_inlinable = 1; for my $tc (@tuple) { $all_inlinable = 0 if !$tc->can_be_inlined; $all_inlinable = 0 if $tc->has_coercion && !$tc->coercion->can_be_inlined; $child_coercions_exist++ if $tc->has_coercion; } return unless $child_coercions_exist; my $C = "Type::Coercion"->new(type_constraint => $child); if ($all_inlinable) { $C->add_type_coercions($parent => Types::Standard::Stringable { my $label = sprintf("CTUPLELABEL%d", ++$label_counter); my $label2 = sprintf("CTUPLEINNER%d", $label_counter); my @code; push @code, 'do { my ($orig, $return_orig, $tmp, @new) = ($_, 0);'; push @code, "$label: {"; push @code, sprintf('(($return_orig = 1), last %s) if scalar(@$orig) %% %d != 0;', $label, scalar @tuple); push @code, sprintf('my $%s = 0; while ($%s < @$orig) {', $label2, $label2); for my $i (0 .. $#tuple) { my $ct = $tuple[$i]; my $ct_coerce = $ct->has_coercion; push @code, sprintf( 'do { $tmp = %s; (%s) ? ($new[$%s + %d]=$tmp) : (($return_orig=1), last %s) };', $ct_coerce ? $ct->coercion->inline_coercion("\$orig->[\$$label2 + $i]") : "\$orig->[\$$label2 + $i]", $ct->inline_check('$tmp'), $label2, $i, $label, ); } push @code, sprintf('$%s += %d;', $label2, scalar(@tuple)); push @code, '}'; push @code, '}'; push @code, '$return_orig ? $orig : \\@new'; push @code, '}'; "@code"; }); } else { $C->add_type_coercions( $parent => sub { my $value = @_ ? $_[0] : $_; if (scalar(@$value) % scalar(@tuple) != 0) { return $value; } my @new; for my $i (0 .. $#$value) { my $ct = $tuple[$i % @tuple]; my $x = $ct->has_coercion ? $ct->coerce($value->[$i]) : $value->[$i]; return $value unless $ct->check($x); $new[$i] = $x; } return \@new; }, ); }; return $C; } 1; __END__ =pod =encoding utf-8 =head1 NAME Types::Standard::CycleTuple - internals for the Types::Standard CycleTuple type constraint =head1 STATUS This module is considered part of Type-Tiny's internals. It is not covered by the L. =head1 DESCRIPTION This file contains some of the guts for L. It will be loaded on demand. You may ignore its presence. =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Dict.pm000644001750001750 2754513601673061 17275 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Types/Standardpackage Types::Standard::Dict; use 5.006001; use strict; use warnings; BEGIN { $Types::Standard::Dict::AUTHORITY = 'cpan:TOBYINK'; $Types::Standard::Dict::VERSION = '1.008001'; } $Types::Standard::Dict::VERSION =~ tr/_//d; use Types::Standard (); use Types::TypeTiny (); sub _croak ($;@) { require Carp; goto \&Carp::confess; require Error::TypeTiny; goto \&Error::TypeTiny::croak } my $_optional = Types::Standard::Optional; my $_hash = Types::Standard::HashRef; my $_map = Types::Standard::Map; my $_any = Types::Standard::Any; no warnings; sub pair_iterator { _croak("Expected even-sized list") if @_ % 2; my @array = @_; sub { return unless @array; splice(@array, 0, 2); }; } sub __constraint_generator { my $shash; my $slurpy = ref($_[-1]) eq q(HASH) ? do { $shash = pop @_; Types::TypeTiny::to_TypeTiny($shash->{slurpy}) } : undef; my $iterator = pair_iterator @_; my %constraints; my %is_optional; my @keys; if ($slurpy) { Types::TypeTiny::TypeTiny->check($slurpy) or _croak("Slurpy parameter to Dict[...] expected to be a type constraint; got $slurpy"); $shash->{slurpy} = $slurpy; # store canonicalized slurpy } while (my ($k, $v) = $iterator->()) { $constraints{$k} = $v; Types::TypeTiny::TypeTiny->check($v) or _croak("Parameter for Dict[...] with key '$k' expected to be a type constraint; got $v"); Types::TypeTiny::StringLike->check($k) or _croak("Key for Dict[...] expected to be string; got $k"); push @keys, $k; $is_optional{$k} = !!$constraints{$k}->is_strictly_a_type_of($_optional); } return sub { my $value = $_[0]; if ($slurpy) { my %tmp = map { exists($constraints{$_}) ? () : ($_ => $value->{$_}) } keys %$value; return unless $slurpy->check(\%tmp); } else { exists($constraints{$_}) || return for sort keys %$value; } for my $k (@keys) { exists($value->{$k}) or ($is_optional{$k} ? next : return); $constraints{$k}->check($value->{$k}) or return; } return !!1; }; } sub __inline_generator { # We can only inline a parameterized Dict if all the # constraints inside can be inlined. my $slurpy = ref($_[-1]) eq q(HASH) ? pop(@_)->{slurpy} : undef; return if $slurpy && !$slurpy->can_be_inlined; # Is slurpy a very loose type constraint? # i.e. Any, Item, Defined, Ref, or HashRef my $slurpy_is_any = $slurpy && $_hash->is_a_type_of( $slurpy ); # Is slurpy a parameterized Map, or expressable as a parameterized Map? my $slurpy_is_map = $slurpy && $slurpy->is_parameterized && (( $slurpy->parent->strictly_equals($_map) && $slurpy->parameters )||( $slurpy->parent->strictly_equals($_hash) && [ $_any, $slurpy->parameters->[0] ] )); my $iterator = pair_iterator @_; my %constraints; my @keys; while (my ($k, $c) = $iterator->()) { return unless $c->can_be_inlined; $constraints{$k} = $c; push @keys, $k; } my $regexp = join "|", map quotemeta, @keys; return sub { require B; my $h = $_[1]; join " and ", Types::Standard::HashRef->inline_check($h), ( $slurpy_is_any ? () : $slurpy_is_map ? do { '(not grep {' ."my \$v = ($h)->{\$_};" .sprintf( 'not((/\\A(?:%s)\\z/) or ((%s) and (%s)))', $regexp, $slurpy_is_map->[0]->inline_check('$_'), $slurpy_is_map->[1]->inline_check('$v'), ) ."} keys \%{$h})" } : $slurpy ? do { 'do {' . "my \$slurpy_tmp = +{ map /\\A(?:$regexp)\\z/ ? () : (\$_ => ($h)->{\$_}), keys \%{$h} };" . $slurpy->inline_check('$slurpy_tmp') . '}' } : "not(grep !/\\A(?:$regexp)\\z/, keys \%{$h})" ), ( map { my $k = B::perlstring($_); $constraints{$_}->is_strictly_a_type_of( $_optional ) ? sprintf('(!exists %s->{%s} or %s)', $h, $k, $constraints{$_}->inline_check("$h\->{$k}")) : ( "exists($h\->{$k})", $constraints{$_}->inline_check("$h\->{$k}") ) } @keys ), } } sub __deep_explanation { require B; my ($type, $value, $varname) = @_; my @params = @{ $type->parameters }; my $slurpy = ref($params[-1]) eq q(HASH) ? pop(@params)->{slurpy} : undef; my $iterator = pair_iterator @params; my %constraints; my @keys; while (my ($k, $c) = $iterator->()) { push @keys, $k; $constraints{$k} = $c; } for my $k (@keys) { next if $constraints{$k}->has_parent && ($constraints{$k}->parent == Types::Standard::Optional) && (!exists $value->{$k}); next if $constraints{$k}->check($value->{$k}); return [ sprintf('"%s" requires key %s to appear in hash', $type, B::perlstring($k)) ] unless exists $value->{$k}; return [ sprintf('"%s" constrains value at key %s of hash with "%s"', $type, B::perlstring($k), $constraints{$k}), @{ $constraints{$k}->validate_explain($value->{$k}, sprintf('%s->{%s}', $varname, B::perlstring($k))) }, ]; } if ($slurpy) { my %tmp = map { exists($constraints{$_}) ? () : ($_ => $value->{$_}) } keys %$value; my $explain = $slurpy->validate_explain(\%tmp, '$slurpy'); return [ sprintf('"%s" requires the hashref of additional key/value pairs to conform to "%s"', $type, $slurpy), @$explain, ] if $explain; } else { for my $k (sort keys %$value) { return [ sprintf('"%s" does not allow key %s to appear in hash', $type, B::perlstring($k)) ] unless exists $constraints{$k}; } } # This should never happen... return; # uncoverable statement } my $label_counter = 0; our ($keycheck_counter, @KEYCHECK) = -1; sub __coercion_generator { my $slurpy = ref($_[-1]) eq q(HASH) ? pop(@_)->{slurpy} : undef; my ($parent, $child, %dict) = @_; my $C = "Type::Coercion"->new(type_constraint => $child); my $all_inlinable = 1; my $child_coercions_exist = 0; for my $tc (values %dict) { $all_inlinable = 0 if !$tc->can_be_inlined; $all_inlinable = 0 if $tc->has_coercion && !$tc->coercion->can_be_inlined; $child_coercions_exist++ if $tc->has_coercion; } $all_inlinable = 0 if $slurpy && !$slurpy->can_be_inlined; $all_inlinable = 0 if $slurpy && $slurpy->has_coercion && !$slurpy->coercion->can_be_inlined; $child_coercions_exist++ if $slurpy && $slurpy->has_coercion; return unless $child_coercions_exist; if ($all_inlinable) { $C->add_type_coercions($parent => Types::Standard::Stringable { require B; my $keycheck = join "|", map quotemeta, sort { length($b) <=> length($a) or $a cmp $b } keys %dict; $keycheck = $KEYCHECK[++$keycheck_counter] = qr{^($keycheck)$}ms; # regexp for legal keys my $label = sprintf("DICTLABEL%d", ++$label_counter); my @code; push @code, 'do { my ($orig, $return_orig, $tmp, %new) = ($_, 0);'; push @code, "$label: {"; if ($slurpy) { push @code, sprintf('my $slurped = +{ map +($_=~$%s::KEYCHECK[%d])?():($_=>$orig->{$_}), keys %%$orig };', __PACKAGE__, $keycheck_counter); if ($slurpy->has_coercion) { push @code, sprintf('my $coerced = %s;', $slurpy->coercion->inline_coercion('$slurped')); push @code, sprintf('((%s)&&(%s))?(%%new=%%$coerced):(($return_orig = 1), last %s);', $_hash->inline_check('$coerced'), $slurpy->inline_check('$coerced'), $label); } else { push @code, sprintf('(%s)?(%%new=%%$slurped):(($return_orig = 1), last %s);', $slurpy->inline_check('$slurped'), $label); } } else { push @code, sprintf('($_ =~ $%s::KEYCHECK[%d])||(($return_orig = 1), last %s) for sort keys %%$orig;', __PACKAGE__, $keycheck_counter, $label); } for my $k (keys %dict) { my $ct = $dict{$k}; my $ct_coerce = $ct->has_coercion; my $ct_optional = $ct->is_a_type_of($_optional); my $K = B::perlstring($k); push @code, sprintf( 'if (exists $orig->{%s}) { $tmp = %s; (%s) ? ($new{%s}=$tmp) : (($return_orig=1), last %s) }', $K, $ct_coerce ? $ct->coercion->inline_coercion("\$orig->{$K}") : "\$orig->{$K}", $ct->inline_check('$tmp'), $K, $label, ); } push @code, '}'; push @code, '$return_orig ? $orig : \\%new'; push @code, '}'; #warn "CODE:: @code"; "@code"; }); } else { my %is_optional = map { ; $_ => !!$dict{$_}->is_strictly_a_type_of($_optional) } sort keys %dict; $C->add_type_coercions( $parent => sub { my $value = @_ ? $_[0] : $_; my %new; if ($slurpy) { my %slurped = map exists($dict{$_}) ? () : ($_ => $value->{$_}), keys %$value; if ($slurpy->check(\%slurped)) { %new = %slurped; } elsif ($slurpy->has_coercion) { my $coerced = $slurpy->coerce(\%slurped); $slurpy->check($coerced) ? (%new = %$coerced) : (return $value); } else { return $value; } } else { for my $k (keys %$value) { return $value unless exists $dict{$k}; } } for my $k (keys %dict) { next if $is_optional{$k} and not exists $value->{$k}; my $ct = $dict{$k}; my $x = $ct->has_coercion ? $ct->coerce($value->{$k}) : $value->{$k}; return $value unless $ct->check($x); $new{$k} = $x; } return \%new; }, ); } return $C; } sub __dict_is_slurpy { my $self = shift; return !!0 if $self==Types::Standard::Dict(); my $dict = $self->find_parent(sub { $_->has_parent && $_->parent==Types::Standard::Dict() }); ref($dict->parameters->[-1]) eq q(HASH) ? $dict->parameters->[-1]{slurpy} : !!0 } sub __hashref_allows_key { my $self = shift; my ($key) = @_; return Types::Standard::Str()->check($key) if $self==Types::Standard::Dict(); my $dict = $self->find_parent(sub { $_->has_parent && $_->parent==Types::Standard::Dict() }); my %params; my $slurpy = $dict->my_dict_is_slurpy; if ($slurpy) { my @args = @{$dict->parameters}; pop @args; %params = @args; } else { %params = @{ $dict->parameters } } return !!1 if exists($params{$key}); return !!0 if !$slurpy; return Types::Standard::Str()->check($key) if $slurpy==Types::Standard::Any() || $slurpy==Types::Standard::Item() || $slurpy==Types::Standard::Defined() || $slurpy==Types::Standard::Ref(); return $slurpy->my_hashref_allows_key($key) if $slurpy->is_a_type_of(Types::Standard::HashRef()); return !!0; } sub __hashref_allows_value { my $self = shift; my ($key, $value) = @_; return !!0 unless $self->my_hashref_allows_key($key); return !!1 if $self==Types::Standard::Dict(); my $dict = $self->find_parent(sub { $_->has_parent && $_->parent==Types::Standard::Dict() }); my %params; my $slurpy = $dict->my_dict_is_slurpy; if ($slurpy) { my @args = @{$dict->parameters}; pop @args; %params = @args; } else { %params = @{ $dict->parameters } } return !!1 if exists($params{$key}) && $params{$key}->check($value); return !!0 if !$slurpy; return !!1 if $slurpy==Types::Standard::Any() || $slurpy==Types::Standard::Item() || $slurpy==Types::Standard::Defined() || $slurpy==Types::Standard::Ref(); return $slurpy->my_hashref_allows_value($key, $value) if $slurpy->is_a_type_of(Types::Standard::HashRef()); return !!0; } 1; __END__ =pod =encoding utf-8 =head1 NAME Types::Standard::Dict - internals for the Types::Standard Dict type constraint =head1 STATUS This module is considered part of Type-Tiny's internals. It is not covered by the L. =head1 DESCRIPTION This file contains some of the guts for L. It will be loaded on demand. You may ignore its presence. =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. HashRef.pm000644001750001750 1171113601673061 17716 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Types/Standardpackage Types::Standard::HashRef; use 5.006001; use strict; use warnings; BEGIN { $Types::Standard::HashRef::AUTHORITY = 'cpan:TOBYINK'; $Types::Standard::HashRef::VERSION = '1.008001'; } $Types::Standard::HashRef::VERSION =~ tr/_//d; use Type::Tiny (); use Types::Standard (); use Types::TypeTiny (); sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } no warnings; sub __constraint_generator { return Types::Standard::HashRef unless @_; my $param = shift; Types::TypeTiny::TypeTiny->check($param) or _croak("Parameter to HashRef[`a] expected to be a type constraint; got $param"); my $param_compiled_check = $param->compiled_check; my $xsub; if (Type::Tiny::_USE_XS) { my $paramname = Type::Tiny::XS::is_known($param_compiled_check); $xsub = Type::Tiny::XS::get_coderef_for("HashRef[$paramname]") if $paramname; } elsif (Type::Tiny::_USE_MOUSE and $param->_has_xsub) { require Mouse::Util::TypeConstraints; my $maker = "Mouse::Util::TypeConstraints"->can("_parameterize_HashRef_for"); $xsub = $maker->($param) if $maker; } return ( sub { my $hash = shift; $param->check($_) || return for values %$hash; return !!1; }, $xsub, ); } sub __inline_generator { my $param = shift; my $compiled = $param->compiled_check; my $xsubname; if (Type::Tiny::_USE_XS and not $Type::Tiny::AvoidCallbacks) { my $paramname = Type::Tiny::XS::is_known($compiled); $xsubname = Type::Tiny::XS::get_subname_for("HashRef[$paramname]"); } return unless $param->can_be_inlined; return sub { my $v = $_[1]; return "$xsubname\($v\)" if $xsubname && !$Type::Tiny::AvoidCallbacks; my $p = Types::Standard::HashRef->inline_check($v); my $param_check = $param->inline_check('$i'); "$p and do { " . "my \$ok = 1; " . "for my \$i (values \%{$v}) { " . "(\$ok = 0, last) unless $param_check " . "}; " . "\$ok " ."}" }; } sub __deep_explanation { require B; my ($type, $value, $varname) = @_; my $param = $type->parameters->[0]; for my $k (sort keys %$value) { my $item = $value->{$k}; next if $param->check($item); return [ sprintf('"%s" constrains each value in the hash with "%s"', $type, $param), @{ $param->validate_explain($item, sprintf('%s->{%s}', $varname, B::perlstring($k))) }, ]; } # This should never happen... return; # uncoverable statement } sub __coercion_generator { my ($parent, $child, $param) = @_; return unless $param->has_coercion; my $coercable_item = $param->coercion->_source_type_union; my $C = "Type::Coercion"->new(type_constraint => $child); if ($param->coercion->can_be_inlined and $coercable_item->can_be_inlined) { $C->add_type_coercions($parent => Types::Standard::Stringable { my @code; push @code, 'do { my ($orig, $return_orig, %new) = ($_, 0);'; push @code, 'for (keys %$orig) {'; push @code, sprintf('$return_orig++ && last unless (%s);', $coercable_item->inline_check('$orig->{$_}')); push @code, sprintf('$new{$_} = (%s);', $param->coercion->inline_coercion('$orig->{$_}')); push @code, '}'; push @code, '$return_orig ? $orig : \\%new'; push @code, '}'; "@code"; }); } else { $C->add_type_coercions( $parent => sub { my $value = @_ ? $_[0] : $_; my %new; for my $k (keys %$value) { return $value unless $coercable_item->check($value->{$k}); $new{$k} = $param->coerce($value->{$k}); } return \%new; }, ); } return $C; } sub __hashref_allows_key { my $self = shift; Types::Standard::Str()->check($_[0]); } sub __hashref_allows_value { my $self = shift; my ($key, $value) = @_; return !!0 unless $self->my_hashref_allows_key($key); return !!1 if $self==Types::Standard::HashRef(); my $href = $self->find_parent(sub { $_->has_parent && $_->parent==Types::Standard::HashRef() }); my $param = $href->type_parameter; Types::Standard::Str()->check($key) and $param->check($value); } 1; __END__ =pod =encoding utf-8 =head1 NAME Types::Standard::HashRef - internals for the Types::Standard HashRef type constraint =head1 STATUS This module is considered part of Type-Tiny's internals. It is not covered by the L. =head1 DESCRIPTION This file contains some of the guts for L. It will be loaded on demand. You may ignore its presence. =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Map.pm000644001750001750 1453313601673061 17120 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Types/Standardpackage Types::Standard::Map; use 5.006001; use strict; use warnings; BEGIN { $Types::Standard::Map::AUTHORITY = 'cpan:TOBYINK'; $Types::Standard::Map::VERSION = '1.008001'; } $Types::Standard::Map::VERSION =~ tr/_//d; use Type::Tiny (); use Types::Standard (); use Types::TypeTiny (); sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } my $meta = Types::Standard->meta; no warnings; sub __constraint_generator { return $meta->get_type('Map') unless @_; my ($keys, $values) = @_; Types::TypeTiny::TypeTiny->check($keys) or _croak("First parameter to Map[`k,`v] expected to be a type constraint; got $keys"); Types::TypeTiny::TypeTiny->check($values) or _croak("Second parameter to Map[`k,`v] expected to be a type constraint; got $values"); my @xsub; if (Type::Tiny::_USE_XS) { my @known = map { my $known = Type::Tiny::XS::is_known($_->compiled_check); defined($known) ? $known : (); } ($keys, $values); if (@known == 2) { my $xsub = Type::Tiny::XS::get_coderef_for( sprintf "Map[%s,%s]", @known ); push @xsub, $xsub if $xsub; } } sub { my $hash = shift; $keys->check($_) || return for keys %$hash; $values->check($_) || return for values %$hash; return !!1; }, @xsub; } sub __inline_generator { my ($k, $v) = @_; return unless $k->can_be_inlined && $v->can_be_inlined; my $xsubname; if (Type::Tiny::_USE_XS) { my @known = map { my $known = Type::Tiny::XS::is_known($_->compiled_check); defined($known) ? $known : (); } ($k, $v); if (@known == 2) { $xsubname = Type::Tiny::XS::get_subname_for( sprintf "Map[%s,%s]", @known ); } } return sub { my $h = $_[1]; return "$xsubname\($h\)" if $xsubname && !$Type::Tiny::AvoidCallbacks; my $p = Types::Standard::HashRef->inline_check($h); my $k_check = $k->inline_check('$k'); my $v_check = $v->inline_check('$v'); "$p and do { " . "my \$ok = 1; " . "for my \$v (values \%{$h}) { " . "(\$ok = 0, last) unless $v_check " . "}; " . "for my \$k (keys \%{$h}) { " . "(\$ok = 0, last) unless $k_check " . "}; " . "\$ok " ."}" }; } sub __deep_explanation { require B; my ($type, $value, $varname) = @_; my ($kparam, $vparam) = @{ $type->parameters }; for my $k (sort keys %$value) { unless ($kparam->check($k)) { return [ sprintf('"%s" constrains each key in the hash with "%s"', $type, $kparam), @{ $kparam->validate_explain($k, sprintf('key %s->{%s}', $varname, B::perlstring($k))) }, ]; } unless ($vparam->check($value->{$k})) { return [ sprintf('"%s" constrains each value in the hash with "%s"', $type, $vparam), @{ $vparam->validate_explain($value->{$k}, sprintf('%s->{%s}', $varname, B::perlstring($k))) }, ]; } } # This should never happen... return; # uncoverable statement } sub __coercion_generator { my ($parent, $child, $kparam, $vparam) = @_; return unless $kparam->has_coercion || $vparam->has_coercion; my $kcoercable_item = $kparam->has_coercion ? $kparam->coercion->_source_type_union : $kparam; my $vcoercable_item = $vparam->has_coercion ? $vparam->coercion->_source_type_union : $vparam; my $C = "Type::Coercion"->new(type_constraint => $child); if ((!$kparam->has_coercion or $kparam->coercion->can_be_inlined) and (!$vparam->has_coercion or $vparam->coercion->can_be_inlined) and $kcoercable_item->can_be_inlined and $vcoercable_item->can_be_inlined) { $C->add_type_coercions($parent => Types::Standard::Stringable { my @code; push @code, 'do { my ($orig, $return_orig, %new) = ($_, 0);'; push @code, 'for (keys %$orig) {'; push @code, sprintf('++$return_orig && last unless (%s);', $kcoercable_item->inline_check('$_')); push @code, sprintf('++$return_orig && last unless (%s);', $vcoercable_item->inline_check('$orig->{$_}')); push @code, sprintf('$new{(%s)} = (%s);', $kparam->has_coercion ? $kparam->coercion->inline_coercion('$_') : '$_', $vparam->has_coercion ? $vparam->coercion->inline_coercion('$orig->{$_}') : '$orig->{$_}', ); push @code, '}'; push @code, '$return_orig ? $orig : \\%new'; push @code, '}'; "@code"; }); } else { $C->add_type_coercions( $parent => sub { my $value = @_ ? $_[0] : $_; my %new; for my $k (keys %$value) { return $value unless $kcoercable_item->check($k) && $vcoercable_item->check($value->{$k}); $new{$kparam->has_coercion ? $kparam->coerce($k) : $k} = $vparam->has_coercion ? $vparam->coerce($value->{$k}) : $value->{$k}; } return \%new; }, ); } return $C; } sub __hashref_allows_key { my $self = shift; my ($key) = @_; return Types::Standard::Str()->check($key) if $self==Types::Standard::Map(); my $map = $self->find_parent(sub { $_->has_parent && $_->parent==Types::Standard::Map() }); my ($kcheck, $vcheck) = @{ $map->parameters }; ($kcheck or Types::Standard::Any())->check($key); } sub __hashref_allows_value { my $self = shift; my ($key, $value) = @_; return !!0 unless $self->my_hashref_allows_key($key); return !!1 if $self==Types::Standard::Map(); my $map = $self->find_parent(sub { $_->has_parent && $_->parent==Types::Standard::Map() }); my ($kcheck, $vcheck) = @{ $map->parameters }; ($kcheck or Types::Standard::Any())->check($key) and ($vcheck or Types::Standard::Any())->check($value); } 1; __END__ =pod =encoding utf-8 =head1 NAME Types::Standard::Map - internals for the Types::Standard Map type constraint =head1 STATUS This module is considered part of Type-Tiny's internals. It is not covered by the L. =head1 DESCRIPTION This file contains some of the guts for L. It will be loaded on demand. You may ignore its presence. =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ScalarRef.pm000644001750001750 666313601673061 20232 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Types/Standardpackage Types::Standard::ScalarRef; use 5.006001; use strict; use warnings; BEGIN { $Types::Standard::ScalarRef::AUTHORITY = 'cpan:TOBYINK'; $Types::Standard::ScalarRef::VERSION = '1.008001'; } $Types::Standard::ScalarRef::VERSION =~ tr/_//d; use Types::Standard (); use Types::TypeTiny (); sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } no warnings; sub __constraint_generator { return Types::Standard::ScalarRef unless @_; my $param = shift; Types::TypeTiny::TypeTiny->check($param) or _croak("Parameter to ScalarRef[`a] expected to be a type constraint; got $param"); return sub { my $ref = shift; $param->check($$ref) || return; return !!1; }; } sub __inline_generator { my $param = shift; return unless $param->can_be_inlined; return sub { my $v = $_[1]; my $param_check = $param->inline_check("\${$v}"); "(ref($v) eq 'SCALAR' or ref($v) eq 'REF') and $param_check"; }; } sub __deep_explanation { my ($type, $value, $varname) = @_; my $param = $type->parameters->[0]; for my $item ($$value) { next if $param->check($item); return [ sprintf('"%s" constrains the referenced scalar value with "%s"', $type, $param), @{ $param->validate_explain($item, sprintf('${%s}', $varname)) }, ]; } # This should never happen... return; # uncoverable statement } sub __coercion_generator { my ($parent, $child, $param) = @_; return unless $param->has_coercion; my $coercable_item = $param->coercion->_source_type_union; my $C = "Type::Coercion"->new(type_constraint => $child); if ($param->coercion->can_be_inlined and $coercable_item->can_be_inlined) { $C->add_type_coercions($parent => Types::Standard::Stringable { my @code; push @code, 'do { my ($orig, $return_orig, $new) = ($_, 0);'; push @code, 'for ($$orig) {'; push @code, sprintf('++$return_orig && last unless (%s);', $coercable_item->inline_check('$_')); push @code, sprintf('$new = (%s);', $param->coercion->inline_coercion('$_')); push @code, '}'; push @code, '$return_orig ? $orig : \\$new'; push @code, '}'; "@code"; }); } else { $C->add_type_coercions( $parent => sub { my $value = @_ ? $_[0] : $_; my $new; for my $item ($$value) { return $value unless $coercable_item->check($item); $new = $param->coerce($item); } return \$new; }, ); } return $C; } 1; __END__ =pod =encoding utf-8 =head1 NAME Types::Standard::ScalarRef - internals for the Types::Standard ScalarRef type constraint =head1 STATUS This module is considered part of Type-Tiny's internals. It is not covered by the L. =head1 DESCRIPTION This file contains some of the guts for L. It will be loaded on demand. You may ignore its presence. =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. StrMatch.pm000644001750001750 754213601673061 20112 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Types/Standardpackage Types::Standard::StrMatch; use 5.006001; use strict; use warnings; BEGIN { $Types::Standard::StrMatch::AUTHORITY = 'cpan:TOBYINK'; $Types::Standard::StrMatch::VERSION = '1.008001'; } $Types::Standard::StrMatch::VERSION =~ tr/_//d; use Type::Tiny (); use Types::Standard (); use Types::TypeTiny (); sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } no warnings; our %expressions; my $has_regexp_util; my $serialize_regexp = sub { $has_regexp_util = eval { require Regexp::Util; Regexp::Util->VERSION('0.003'); 1; } || 0 unless defined $has_regexp_util; my $re = shift; my $serialized; if ($has_regexp_util) { $serialized = eval { Regexp::Util::serialize_regexp($re) }; } unless (defined $serialized) { my $key = sprintf('%s|%s', ref($re), $re); $expressions{$key} = $re; $serialized = sprintf('$Types::Standard::StrMatch::expressions{%s}', B::perlstring($key)); } return $serialized; }; sub __constraint_generator { return Types::Standard->meta->get_type('StrMatch') unless @_; my ($regexp, $checker) = @_; Types::Standard::RegexpRef->check($regexp) or _croak("First parameter to StrMatch[`a] expected to be a Regexp; got $regexp"); if (@_ > 1) { $checker = Types::TypeTiny::to_TypeTiny($checker); Types::TypeTiny::TypeTiny->check($checker) or _croak("Second parameter to StrMatch[`a] expected to be a type constraint; got $checker") } $checker ? sub { my $value = shift; return if ref($value); my @m = ($value =~ $regexp); $checker->check(\@m); } : sub { my $value = shift; !ref($value) and $value =~ $regexp; } ; } sub __inline_generator { require B; my ($regexp, $checker) = @_; my $serialized_re = $regexp->$serialize_regexp or return; if ($checker) { return unless $checker->can_be_inlined; return sub { my $v = $_[1]; if ($Type::Tiny::AvoidCallbacks and $serialized_re =~ /Types::Standard::StrMatch::expressions/) { require Carp; Carp::carp("Cannot serialize regexp without callbacks; serializing using callbacks"); } sprintf "!ref($v) and do { my \$m = [$v =~ %s]; %s }", $serialized_re, $checker->inline_check('$m'), ; }; } else { my $regexp_string = "$regexp"; if ($regexp_string =~ /\A\(\?\^u?:\\A(\.+)\)\z/) { my $length = length $1; return sub { "!ref($_) and length($_)>=$length" }; } if ($regexp_string =~ /\A\(\?\^u?:\\A(\.+)\\z\)\z/) { my $length = length $1; return sub { "!ref($_) and length($_)==$length" }; } return sub { my $v = $_[1]; if ($Type::Tiny::AvoidCallbacks and $serialized_re =~ /Types::Standard::StrMatch::expressions/) { require Carp; Carp::carp("Cannot serialize regexp without callbacks; serializing using callbacks"); } "!ref($v) and $v =~ $serialized_re"; }; } } 1; __END__ =pod =encoding utf-8 =head1 NAME Types::Standard::StrMatch - internals for the Types::Standard StrMatch type constraint =head1 STATUS This module is considered part of Type-Tiny's internals. It is not covered by the L. =head1 DESCRIPTION This file contains some of the guts for L. It will be loaded on demand. You may ignore its presence. =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Tied.pm000644001750001750 544613601673061 17253 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Types/Standardpackage Types::Standard::Tied; use 5.006001; use strict; use warnings; BEGIN { $Types::Standard::Tied::AUTHORITY = 'cpan:TOBYINK'; $Types::Standard::Tied::VERSION = '1.008001'; } $Types::Standard::Tied::VERSION =~ tr/_//d; use Type::Tiny (); use Types::Standard (); use Types::TypeTiny (); sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } no warnings; sub __constraint_generator { return Types::Standard->meta->get_type('Tied') unless @_; my $param = Types::TypeTiny::to_TypeTiny(shift); unless (Types::TypeTiny::TypeTiny->check($param)) { Types::TypeTiny::StringLike->check($param) or _croak("Parameter to Tied[`a] expected to be a class name; got $param"); require Type::Tiny::Class; $param = "Type::Tiny::Class"->new(class => "$param"); } my $check = $param->compiled_check; sub { $check->(tied(Scalar::Util::reftype($_) eq 'HASH' ? %{$_} : Scalar::Util::reftype($_) eq 'ARRAY' ? @{$_} : Scalar::Util::reftype($_) =~ /^(SCALAR|REF)$/ ? ${$_} : undef)); }; } sub __inline_generator { my $param = Types::TypeTiny::to_TypeTiny(shift); unless (Types::TypeTiny::TypeTiny->check($param)) { Types::TypeTiny::StringLike->check($param) or _croak("Parameter to Tied[`a] expected to be a class name; got $param"); require Type::Tiny::Class; $param = "Type::Tiny::Class"->new(class => "$param"); } return unless $param->can_be_inlined; sub { require B; my $var = $_[1]; sprintf( "%s and do { my \$TIED = tied(Scalar::Util::reftype($var) eq 'HASH' ? \%{$var} : Scalar::Util::reftype($var) eq 'ARRAY' ? \@{$var} : Scalar::Util::reftype($var) =~ /^(SCALAR|REF)\$/ ? \${$var} : undef); %s }", Types::Standard::Ref()->inline_check($var), $param->inline_check('$TIED') ); } } 1; __END__ =pod =encoding utf-8 =head1 NAME Types::Standard::Tied - internals for the Types::Standard Tied type constraint =head1 STATUS This module is considered part of Type-Tiny's internals. It is not covered by the L. =head1 DESCRIPTION This file contains some of the guts for L. It will be loaded on demand. You may ignore its presence. =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. Tuple.pm000644001750001750 2412013601673061 17465 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Types/Standardpackage Types::Standard::Tuple; use 5.006001; use strict; use warnings; BEGIN { $Types::Standard::Tuple::AUTHORITY = 'cpan:TOBYINK'; $Types::Standard::Tuple::VERSION = '1.008001'; } $Types::Standard::Tuple::VERSION =~ tr/_//d; use Type::Tiny (); use Types::Standard (); use Types::TypeTiny (); sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak } my $_Optional = Types::Standard::Optional; no warnings; sub __constraint_generator { my @constraints = @_; my $slurpy; if (exists $constraints[-1] and ref $constraints[-1] eq "HASH") { $slurpy = Types::TypeTiny::to_TypeTiny($constraints[-1]{slurpy}); Types::TypeTiny::TypeTiny->check($slurpy) or _croak("Slurpy parameter to Tuple[...] expected to be a type constraint; got $slurpy"); pop(@constraints)->{slurpy} = $slurpy; # keep canonicalized version around } for (@constraints) { Types::TypeTiny::TypeTiny->check($_) or _croak("Parameters to Tuple[...] expected to be type constraints; got $_"); } # By god, the Type::Tiny::XS API is currently horrible my @xsub; if (Type::Tiny::_USE_XS and !$slurpy) { my @known = map { my $known; $known = Type::Tiny::XS::is_known($_->compiled_check) unless $_->is_strictly_a_type_of($_Optional); defined($known) ? $known : (); } @constraints; if (@known == @constraints) { my $xsub = Type::Tiny::XS::get_coderef_for( sprintf "Tuple[%s]", join(',', @known) ); push @xsub, $xsub if $xsub; } } my @is_optional = map !!$_->is_strictly_a_type_of($_Optional), @constraints; my $slurp_hash = $slurpy && $slurpy->is_a_type_of(Types::Standard::HashRef); my $slurp_any = $slurpy && $slurpy->equals(Types::Standard::Any); my @sorted_is_optional = sort @is_optional; join("|", @sorted_is_optional) eq join("|", @is_optional) or _croak("Optional parameters to Tuple[...] cannot precede required parameters"); sub { my $value = $_[0]; if ($#constraints < $#$value) { return !!0 unless $slurpy; my $tmp; if ($slurp_hash) { ($#$value - $#constraints+1) % 2 or return; $tmp = +{@$value[$#constraints+1 .. $#$value]}; $slurpy->check($tmp) or return; } elsif (not $slurp_any) { $tmp = +[@$value[$#constraints+1 .. $#$value]]; $slurpy->check($tmp) or return; } } for my $i (0 .. $#constraints) { ($i > $#$value) and return !!$is_optional[$i]; $constraints[$i]->check($value->[$i]) or return !!0; } return !!1; }, @xsub; } sub __inline_generator { my @constraints = @_; my $slurpy; if (exists $constraints[-1] and ref $constraints[-1] eq "HASH") { $slurpy = pop(@constraints)->{slurpy}; } return if grep { not $_->can_be_inlined } @constraints; return if defined $slurpy && !$slurpy->can_be_inlined; my $xsubname; if (Type::Tiny::_USE_XS and !$slurpy) { my @known = map { my $known; $known = Type::Tiny::XS::is_known($_->compiled_check) unless $_->is_strictly_a_type_of($_Optional); defined($known) ? $known : (); } @constraints; if (@known == @constraints) { $xsubname = Type::Tiny::XS::get_subname_for( sprintf "Tuple[%s]", join(',', @known) ); } } my $tmpl = "do { my \$tmp = +[\@{%s}[%d..\$#{%s}]]; %s }"; my $slurpy_any; if (defined $slurpy) { $tmpl = 'do { my ($orig, $from, $to) = (%s, %d, $#{%s});' . '($to-$from %% 2) and do { my $tmp = +{@{$orig}[$from..$to]}; %s }' . '}' if $slurpy->is_a_type_of(Types::Standard::HashRef); $slurpy_any = 1 if $slurpy->equals(Types::Standard::Any); } my @is_optional = map !!$_->is_strictly_a_type_of($_Optional), @constraints; my $min = 0 + grep !$_, @is_optional; return sub { my $v = $_[1]; return "$xsubname\($v\)" if $xsubname && !$Type::Tiny::AvoidCallbacks; join " and ", Types::Standard::ArrayRef->inline_check($v), ( (scalar @constraints == $min and not $slurpy) ? "\@{$v} == $min" : sprintf( "(\@{$v} == $min or (\@{$v} > $min and \@{$v} <= ${\(1+$#constraints)}) or (\@{$v} > ${\(1+$#constraints)} and %s))", ( $slurpy_any ? '!!1' : ( $slurpy ? sprintf($tmpl, $v, $#constraints+1, $v, $slurpy->inline_check('$tmp')) : sprintf("\@{$v} <= %d", scalar @constraints) ) ), ) ), map { my $inline = $constraints[$_]->inline_check("$v\->[$_]"); $inline eq '(!!1)' ? () : ( $is_optional[$_] ? sprintf('(@{%s} <= %d or %s)', $v, $_, $inline) : $inline ); } 0 .. $#constraints; }; } sub __deep_explanation { my ($type, $value, $varname) = @_; my @constraints = @{ $type->parameters }; my $slurpy; if (exists $constraints[-1] and ref $constraints[-1] eq "HASH") { $slurpy = Types::TypeTiny::to_TypeTiny(pop(@constraints)->{slurpy}); } @constraints = map Types::TypeTiny::to_TypeTiny($_), @constraints; if (@constraints < @$value and not $slurpy) { return [ sprintf('"%s" expects at most %d values in the array', $type, scalar(@constraints)), sprintf('%d values found; too many', scalar(@$value)), ]; } for my $i (0 .. $#constraints) { next if $constraints[$i]->is_strictly_a_type_of( Types::Standard::Optional ) && $i > $#$value; next if $constraints[$i]->check($value->[$i]); return [ sprintf('"%s" constrains value at index %d of array with "%s"', $type, $i, $constraints[$i]), @{ $constraints[$i]->validate_explain($value->[$i], sprintf('%s->[%s]', $varname, $i)) }, ]; } if (defined($slurpy)) { my $tmp = $slurpy->is_a_type_of(Types::Standard::HashRef) ? +{@$value[$#constraints+1 .. $#$value]} : +[@$value[$#constraints+1 .. $#$value]]; $slurpy->check($tmp) or return [ sprintf( 'Array elements from index %d are slurped into a %s which is constrained with "%s"', $#constraints+1, $slurpy->is_a_type_of(Types::Standard::HashRef) ? 'hashref' : 'arrayref', $slurpy, ), @{ $slurpy->validate_explain($tmp, '$SLURPY') }, ]; } # This should never happen... return; # uncoverable statement } my $label_counter = 0; sub __coercion_generator { my ($parent, $child, @tuple) = @_; my $slurpy; if (exists $tuple[-1] and ref $tuple[-1] eq "HASH") { $slurpy = pop(@tuple)->{slurpy}; } my $child_coercions_exist = 0; my $all_inlinable = 1; for my $tc (@tuple, ($slurpy ? $slurpy : ())) { $all_inlinable = 0 if !$tc->can_be_inlined; $all_inlinable = 0 if $tc->has_coercion && !$tc->coercion->can_be_inlined; $child_coercions_exist++ if $tc->has_coercion; } return unless $child_coercions_exist; my $C = "Type::Coercion"->new(type_constraint => $child); my $slurpy_is_hashref = $slurpy && $slurpy->is_a_type_of(Types::Standard::HashRef); if ($all_inlinable) { $C->add_type_coercions($parent => Types::Standard::Stringable { my $label = sprintf("TUPLELABEL%d", ++$label_counter); my @code; push @code, 'do { my ($orig, $return_orig, $tmp, @new) = ($_, 0);'; push @code, "$label: {"; push @code, sprintf('(($return_orig = 1), last %s) if @$orig > %d;', $label, scalar @tuple) unless $slurpy; for my $i (0 .. $#tuple) { my $ct = $tuple[$i]; my $ct_coerce = $ct->has_coercion; my $ct_optional = $ct->is_a_type_of(Types::Standard::Optional); push @code, sprintf( 'if (@$orig > %d) { $tmp = %s; (%s) ? ($new[%d]=$tmp) : (($return_orig=1), last %s) }', $i, $ct_coerce ? $ct->coercion->inline_coercion("\$orig->[$i]") : "\$orig->[$i]", $ct->inline_check('$tmp'), $i, $label, ); } if ($slurpy) { my $size = @tuple; push @code, sprintf('if (@$orig > %d) {', $size); push @code, sprintf( ($slurpy_is_hashref ? 'my $tail = do { no warnings; +{ @{$orig}[%d .. $#$orig]} };' : 'my $tail = [ @{$orig}[%d .. $#$orig] ];'), $size, ); push @code, $slurpy->has_coercion ? sprintf('$tail = %s;', $slurpy->coercion->inline_coercion('$tail')) : q(); push @code, sprintf( '(%s) ? push(@new, %s$tail) : ($return_orig++);', $slurpy->inline_check('$tail'), ($slurpy_is_hashref ? '%' : '@'), ); push @code, '}'; } push @code, '}'; push @code, '$return_orig ? $orig : \\@new'; push @code, '}'; "@code"; }); } else { my @is_optional = map !!$_->is_strictly_a_type_of($_Optional), @tuple; $C->add_type_coercions( $parent => sub { my $value = @_ ? $_[0] : $_; if (!$slurpy and @$value > @tuple) { return $value; } my @new; for my $i (0 .. $#tuple) { return \@new if $i > $#$value and $is_optional[$i]; my $ct = $tuple[$i]; my $x = $ct->has_coercion ? $ct->coerce($value->[$i]) : $value->[$i]; return $value unless $ct->check($x); $new[$i] = $x; } if ($slurpy and @$value > @tuple) { no warnings; my $tmp = $slurpy_is_hashref ? { @{$value}[@tuple .. $#$value] } : [ @{$value}[@tuple .. $#$value] ]; $tmp = $slurpy->coerce($tmp) if $slurpy->has_coercion; $slurpy->check($tmp) ? push(@new, $slurpy_is_hashref ? %$tmp : @$tmp) : return($value); } return \@new; }, ); }; return $C; } 1; __END__ =pod =encoding utf-8 =head1 NAME Types::Standard::Tuple - internals for the Types::Standard Tuple type constraint =head1 STATUS This module is considered part of Type-Tiny's internals. It is not covered by the L. =head1 DESCRIPTION This file contains some of the guts for L. It will be loaded on demand. You may ignore its presence. =head1 BUGS Please report any bugs to L. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. basic.t000644001750001750 116413601673061 22357 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Devel-TypeTiny-Perl56Compat=pod =encoding utf-8 =head1 PURPOSE Checks C<< B::perlstring() >> works. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use B; use Test::More; use Types::Standard; is( +eval(sprintf "use strict; %s", B::perlstring("foo")), "foo", 'eval(sprintf "use strict; %s", B::perlstring("foo"))', ); done_testing; basic.t000644001750001750 120013601673061 22350 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Devel-TypeTiny-Perl58Compat=pod =encoding utf-8 =head1 PURPOSE Checks C<< re::is_regexp() >> works. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Types::Standard; ok( +re::is_regexp(qr{foo}), 're::is_regexp(qr{foo})', ); ok( +re::is_regexp(bless qr{foo}, "Foo"), 're::is_regexp(bless qr{foo}, "Foo")', ); done_testing; basic.t000644001750001750 210713601673061 20170 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Error-TypeTiny=pod =encoding utf-8 =head1 PURPOSE Tests for basic L functionality. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Error::TypeTiny; #line 31 "basic.t" my $e1 = exception { 'Error::TypeTiny'->throw() }; is($e1->message, 'An exception has occurred', '$e1->message (default)'); is($e1->context->{package}, 'main', '$e1->context->{main}'); is($e1->context->{line}, '31', '$e1->contex1t->{line}'); is($e1->context->{file}, 'basic.t', '$e1->context->{file}'); my $e2 = exception { 'Error::TypeTiny'->throw(message => 'oh dear') }; is($e2->message, 'oh dear', '$e2->message'); my $e3 = exception { Error::TypeTiny::croak('oh %s', 'drat') }; is($e3->message, 'oh drat', '$e3->message (set by croak)'); done_testing; stacktrace.t000644001750001750 156413601673061 21241 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Error-TypeTiny=pod =encoding utf-8 =head1 PURPOSE Tests that L is capable of providing stack traces. =head1 DEPENDENCIES Requires L; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); local $Error::TypeTiny::StackTrace; use Test::More; use Test::Fatal; use Test::Requires { "Devel::StackTrace" => 0 }; use Types::Standard slurpy => -types; sub foo { local $Error::TypeTiny::StackTrace = 1; Int->(@_); } my $e = exception { foo(undef) }; is( $e->stack_trace->frame(1)->subroutine, "main::foo", ); done_testing; basic.t000644001750001750 2644513601673061 22170 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Error-TypeTiny-Assertion=pod =encoding utf-8 =head1 PURPOSE Tests L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); local $Error::TypeTiny::LastError; use Test::More; use Test::Fatal; use Scalar::Util qw(refaddr); use Types::Standard slurpy => -types; require Error::TypeTiny::Assertion; my $tmp = Error::TypeTiny::Assertion->new(value => 1.1, type => Int, varname => '$bob'); is($tmp->message, "Value \"1.1\" did not pass type constraint \"Int\" (in \$bob)", "autogeneration of \$e->message"); my $supernum = Types::Standard::STRICTNUM ? "StrictNum" : "LaxNum"; my $v = []; my $e = exception { Int->create_child_type->assert_valid($v) }; isa_ok($e, "Error::TypeTiny", '$e'); is(refaddr($e), refaddr($Error::TypeTiny::LastError), '$Error::TypeTiny::LastError'); is( $e->message, q{Reference [] did not pass type constraint}, '$e->message is as expected', ); isa_ok($e, "Error::TypeTiny::Assertion", '$e'); cmp_ok( $e->type, '==', Int, '$e->type is as expected', ); is( $e->value, $v, '$e->value is as expected', ); is_deeply( $e->explain, [ '"__ANON__" is a subtype of "Int"', '"Int" is a subtype of "Num"', '"Num" is a subtype of "'.$supernum.'"', '"'.$supernum.'" is a subtype of "Str"', '"Str" is a subtype of "Value"', 'Reference [] did not pass type constraint "Value"', '"Value" is defined as: (defined($_) and not ref($_))', ], '$e->explain is as expected', ); is_deeply( (exception { (ArrayRef[Int])->([1, 2, [3]]) })->explain, [ 'Reference [1,2,[3]] did not pass type constraint "ArrayRef[Int]"', '"ArrayRef[Int]" constrains each value in the array with "Int"', '"Int" is a subtype of "Num"', '"Num" is a subtype of "'.$supernum.'"', '"'.$supernum.'" is a subtype of "Str"', '"Str" is a subtype of "Value"', 'Reference [3] did not pass type constraint "Value" (in $_->[2])', '"Value" is defined as: (defined($_) and not ref($_))', ], 'ArrayRef[Int] deep explanation, given [1, 2, [3]]', ); is_deeply( [ @{ (exception { (ArrayRef[Int])->({}) })->explain }[0..1] ], [ '"ArrayRef[Int]" is a subtype of "ArrayRef"', 'Reference {} did not pass type constraint "ArrayRef"', # '"ArrayRef" is defined as: (ref($_) eq \'ARRAY\')', ], 'ArrayRef[Int] deep explanation, given {}', ); is_deeply( (exception { (Ref["ARRAY"])->({}) })->explain, [ 'Reference {} did not pass type constraint "Ref[ARRAY]"', '"Ref[ARRAY]" constrains reftype($_) to be equal to "ARRAY"', 'reftype($_) is "HASH"', ], 'Ref["ARRAY"] deep explanation, given {}', ); is_deeply( (exception { (HashRef[Maybe[Int]])->({a => undef, b => 42, c => []}) })->explain, [ 'Reference {"a" => undef,"b" => 42,"c" => []} did not pass type constraint "HashRef[Maybe[Int]]"', '"HashRef[Maybe[Int]]" constrains each value in the hash with "Maybe[Int]"', 'Reference [] did not pass type constraint "Maybe[Int]" (in $_->{"c"})', 'Reference [] is defined', '"Maybe[Int]" constrains the value with "Int" if it is defined', '"Int" is a subtype of "Num"', '"Num" is a subtype of "'.$supernum.'"', '"'.$supernum.'" is a subtype of "Str"', '"Str" is a subtype of "Value"', 'Reference [] did not pass type constraint "Value" (in $_->{"c"})', '"Value" is defined as: (defined($_) and not ref($_))', ], 'HashRef[Maybe[Int]] deep explanation, given {a => undef, b => 42, c => []}', ); my $dict = Dict[a => Int, b => Optional[ArrayRef[Str]]]; is_deeply( (exception { $dict->({a => 1, c => 1}) })->explain, [ 'Reference {"a" => 1,"c" => 1} did not pass type constraint "Dict[a=>Int,b=>Optional[ArrayRef[Str]]]"', '"Dict[a=>Int,b=>Optional[ArrayRef[Str]]]" does not allow key "c" to appear in hash', ], '$dict deep explanation, given {a => 1, c => 1}', ); is_deeply( (exception { $dict->({b => 1}) })->explain, [ 'Reference {"b" => 1} did not pass type constraint "Dict[a=>Int,b=>Optional[ArrayRef[Str]]]"', '"Dict[a=>Int,b=>Optional[ArrayRef[Str]]]" requires key "a" to appear in hash', ], '$dict deep explanation, given {b => 1}', ); is_deeply( (exception { $dict->({a => 1, b => 2}) })->explain, [ 'Reference {"a" => 1,"b" => 2} did not pass type constraint "Dict[a=>Int,b=>Optional[ArrayRef[Str]]]"', '"Dict[a=>Int,b=>Optional[ArrayRef[Str]]]" constrains value at key "b" of hash with "Optional[ArrayRef[Str]]"', 'Value "2" did not pass type constraint "Optional[ArrayRef[Str]]" (in $_->{"b"})', '$_->{"b"} exists', '"Optional[ArrayRef[Str]]" constrains $_->{"b"} with "ArrayRef[Str]" if it exists', '"ArrayRef[Str]" is a subtype of "ArrayRef"', '"ArrayRef" is a subtype of "Ref"', 'Value "2" did not pass type constraint "Ref" (in $_->{"b"})', '"Ref" is defined as: (!!ref($_))', ], '$dict deep explanation, given {a => 1, b => 2}', ); TODO: { no warnings 'numeric'; require Data::Dumper; local $TODO = (Data::Dumper->VERSION > 2.145) ? "Data::Dumper output changed after 2.145" : (Data::Dumper->VERSION < 2.121) ? "Data::Dumper too old" : undef; is_deeply( (exception { (Map[Int,Num])->({1=>1.1,2.2=>2.3,3.3=>3.4}) })->explain, [ 'Reference {1 => "1.1","2.2" => "2.3","3.3" => "3.4"} did not pass type constraint "Map[Int,Num]"', '"Map[Int,Num]" constrains each key in the hash with "Int"', 'Value "2.2" did not pass type constraint "Int" (in key $_->{"2.2"})', '"Int" is defined as: (do { my $tmp = $_; defined($tmp) and !ref($tmp) and $tmp =~ /\A-?[0-9]+\z/ })', ], 'Map[Int,Num] deep explanation, given {1=>1.1,2.2=>2.3,3.3=>3.4}', ); } TODO: { no warnings 'numeric'; require Data::Dumper; local $TODO = (Data::Dumper->VERSION < 2.121) ? "Data::Dumper too old" : undef; my $Ext = (StrMatch[qr/^x_/])->create_child_type(name => 'Ext'); my $dict2 = Dict[foo => ArrayRef, slurpy Map[$Ext, Int]]; ok( $dict2->({ foo => [], x_bar => 1, x_baz => 2 }), "$dict2 works ok it seems", ); my $e = exception { $dict2->({foo => [], x_bar => 1, x_baz => []}) }; is_deeply( $e->explain, [ 'Reference {"foo" => [],"x_bar" => 1,"x_baz" => []} did not pass type constraint "Dict[foo=>ArrayRef,slurpy Map[Ext,Int]]"', '"Dict[foo=>ArrayRef,slurpy Map[Ext,Int]]" requires the hashref of additional key/value pairs to conform to "Map[Ext,Int]"', 'Reference {"x_bar" => 1,"x_baz" => []} did not pass type constraint "Map[Ext,Int]" (in $slurpy)', '"Map[Ext,Int]" constrains each value in the hash with "Int"', '"Int" is a subtype of "Num"', '"Num" is a subtype of "'.$supernum.'"', '"'.$supernum.'" is a subtype of "Str"', '"Str" is a subtype of "Value"', 'Reference [] did not pass type constraint "Value" (in $slurpy->{"x_baz"})', '"Value" is defined as: (defined($_) and not ref($_))' ], "$dict2 explanation, given {foo => [], x_bar => 1, x_baz => []}", ) or diag explain($e->explain); } my $AlwaysFail = Any->create_child_type(constraint => sub { 0 }); is_deeply( (exception { $AlwaysFail->(1) })->explain, [ 'Value "1" did not pass type constraint', '"__ANON__" is defined as: sub { 0; }', ], '$AlwaysFail explanation, given 1', ); my $TupleOf1 = Tuple[ Int ]; is_deeply( (exception { $TupleOf1->([1,2]) })->explain, [ 'Reference [1,2] did not pass type constraint "Tuple[Int]"', '"Tuple[Int]" expects at most 1 values in the array', '2 values found; too many', ], '$TupleOf1 explanation, given [1,2]', ); my $CTuple = CycleTuple[ Int, ArrayRef ]; is_deeply( (exception { $CTuple->([1,"Foo"]) })->explain, [ 'Reference [1,"Foo"] did not pass type constraint "CycleTuple[Int,ArrayRef]"', '"CycleTuple[Int,ArrayRef]" constrains value at index 1 of array with "ArrayRef"', '"ArrayRef" is a subtype of "Ref"', 'Value "Foo" did not pass type constraint "Ref" (in $_->[1])', '"Ref" is defined as: (!!ref($_))', ], '$CTuple explanation, given [1,"Foo"]', ); TODO: { no warnings 'numeric'; require Data::Dumper; local $TODO = (Data::Dumper->VERSION < 2.121) ? "Data::Dumper too old" : undef; my $SlurpyThing = Tuple[ Num, slurpy Map[Str, ArrayRef] ]; is_deeply( (exception { $SlurpyThing->(1) })->explain, [ '"Tuple[Num,slurpy Map[Str,ArrayRef]]" is a subtype of "Tuple"', '"Tuple" is a subtype of "ArrayRef"', '"ArrayRef" is a subtype of "Ref"', 'Value "1" did not pass type constraint "Ref"', '"Ref" is defined as: (!!ref($_))', ], '$SlurpyThing explanation, given 1', ); is_deeply( (exception { $SlurpyThing->([[]]) })->explain, [ 'Reference [[]] did not pass type constraint "Tuple[Num,slurpy Map[Str,ArrayRef]]"', '"Tuple[Num,slurpy Map[Str,ArrayRef]]" constrains value at index 0 of array with "Num"', '"Num" is a subtype of "'.$supernum.'"', '"'.$supernum.'" is a subtype of "Str"', '"Str" is a subtype of "Value"', 'Reference [] did not pass type constraint "Value" (in $_->[0])', '"Value" is defined as: (defined($_) and not ref($_))', ], '$SlurpyThing explanation, given [[]]', ); is_deeply( (exception { $SlurpyThing->([1.1, yeah => "Hello"]) })->explain, [ 'Reference ["1.1","yeah","Hello"] did not pass type constraint "Tuple[Num,slurpy Map[Str,ArrayRef]]"', 'Array elements from index 1 are slurped into a hashref which is constrained with "Map[Str,ArrayRef]"', 'Reference {"yeah" => "Hello"} did not pass type constraint "Map[Str,ArrayRef]" (in $SLURPY)', '"Map[Str,ArrayRef]" constrains each value in the hash with "ArrayRef"', '"ArrayRef" is a subtype of "Ref"', 'Value "Hello" did not pass type constraint "Ref" (in $SLURPY->{"yeah"})', '"Ref" is defined as: (!!ref($_))', ], '$SlurpyThing explanation, given [1.1, yeah => "Hello"]', ); } my $UndefRef = ScalarRef[Undef]; is_deeply( (exception { $UndefRef->(do { my $x = "bar"; \$x }) })->explain, [ 'Reference \\"bar" did not pass type constraint "ScalarRef[Undef]"', '"ScalarRef[Undef]" constrains the referenced scalar value with "Undef"', 'Value "bar" did not pass type constraint "Undef" (in ${$_})', '"Undef" is defined as: (!defined($_))', ], '$UndefRef explanantion, given \"bar"', ); is_deeply( (exception { $UndefRef->([]) })->explain, [ '"ScalarRef[Undef]" is a subtype of "ScalarRef"', 'Reference [] did not pass type constraint "ScalarRef"', '"ScalarRef" is defined as: (ref($_) eq \'SCALAR\' or ref($_) eq \'REF\')', ], '$UndefRef explanantion, given []', ); my $e_where = exception { #line 1 "thisfile.plx" package Monkey::Nuts; "Error::TypeTiny"->throw(message => "Test"); }; #line 230 "exceptions.t" is_deeply( $e_where->context, { package => "Monkey::Nuts", file => "thisfile.plx", line => 2, }, '$e_where->context', ); is( "$e_where", "Test at thisfile.plx line 2.\n", '"$e_where"', ); BEGIN { package MyTypes; use Type::Library -base, -declare => qw(HttpMethod); use Type::Utils -all; use Types::Standard qw(Enum); declare HttpMethod, as Enum[qw/ HEAD GET POST PUT DELETE OPTIONS PATCH /], message { "$_ is not a HttpMethod" }; }; like( exception { MyTypes::HttpMethod->("FOOL") }, qr{^FOOL is not a HttpMethod}, "correct exception from type with null constraint", ); { local $Type::Tiny::DD = sub { substr("$_[0]", 0, 5) }; like( exception { Types::Standard::Str->([]) }, qr{^ARRAY did not pass type constraint}, "local \$Type::Tiny::DD", ); } done_testing; basic.t000644001750001750 304213601673061 22443 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Error-TypeTiny-Compilation=pod =encoding utf-8 =head1 PURPOSE Tests for L, mostly by triggering compilation errors using L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Eval::TypeTiny; my $e = exception { no warnings qw(void); 0; 1; 2; #line 38 "basic.t" eval_closure( source => 'sub { 1 ]', environment => { '$x' => do { my $x = 42; \$x } }, ); 3; 4; 5; 6; }; isa_ok( $e, 'Error::TypeTiny::Compilation', '$e', ); like( $e, qr{^Failed to compile source because: syntax error}, 'throw exception when code does not compile', ); like( $e->message, qr{^Failed to compile source because: syntax error}, '$e->message', ); subtest '$e->context' => sub { my $ctx = $e->context; is($ctx->{package}, 'main', '$ctx->{package}'); is($ctx->{file}, 'basic.t', '$ctx->{file}'); ok($ctx->{line} >= 37, '$ctx->{line} >= 37') or diag('line is '.$ctx->{line}); ok($ctx->{line} <= 42, '$ctx->{line} <= 42') or diag('line is '.$ctx->{line}); }; like( $e->errstr, qr{^syntax error}, '$e->errstr', ); like( $e->code, qr{sub \{ 1 \]}, '$e->code', ); is_deeply( $e->environment, { '$x' => do { my $x = 42; \$x } }, '$e->environment', ); done_testing; basic.t000644001750001750 467113601673061 24754 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Error-TypeTiny-WrongNumberOfParameters=pod =encoding utf-8 =head1 PURPOSE Test L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params qw(compile); use Types::Standard qw(Num Optional slurpy ArrayRef); my $check1; sub nth_root { $check1 ||= compile( Num, Num ); [ $check1->(@_) ]; } subtest "nth_root()" => sub { my $e = exception { nth_root() }; ok($e->has_minimum); is($e->minimum, 2); ok($e->has_maximum); is($e->maximum, 2); is($e->got, 0); like($e, qr{^Wrong number of parameters; got 0; expected 2}); }; subtest "nth_root(1)" => sub { my $e = exception { nth_root(1) }; ok($e->has_minimum); is($e->minimum, 2); ok($e->has_maximum); is($e->maximum, 2); is($e->got, 1); like($e, qr{^Wrong number of parameters; got 1; expected 2}); }; subtest "nth_root(1, 2, 3)" => sub { my $e = exception { nth_root(1, 2, 3) }; ok($e->has_minimum); is($e->minimum, 2); ok($e->has_maximum); is($e->maximum, 2); is($e->got, 3); like($e, qr{^Wrong number of parameters; got 3; expected 2}); }; my $check2; sub nth_root_opt { $check2 ||= compile( Num, Optional[Num] ); [ $check2->(@_) ]; } subtest "nth_root_opt()" => sub { my $e = exception { nth_root_opt() }; ok($e->has_minimum); is($e->minimum, 1); ok($e->has_maximum); is($e->maximum, 2); is($e->got, 0); like($e, qr{^Wrong number of parameters; got 0; expected 1 to 2}); }; my $check3; sub nth_root_slurp { $check3 ||= compile( Num, slurpy ArrayRef[Num] ); [ $check3->(@_) ]; } subtest "nth_root_slurp()" => sub { my $e = exception { nth_root_slurp() }; ok($e->has_minimum); is($e->minimum, 1); ok(!$e->has_maximum); is($e->maximum, undef); is($e->got, 0); like($e, qr{^Wrong number of parameters; got 0; expected at least 1}); }; my $silly = exception { Error::TypeTiny::WrongNumberOfParameters->throw( minimum => 3, maximum => 2, got => 0, ); }; like($silly, qr{^Wrong number of parameters; got 0}, 'silly exception which should never happen anyway'); my $unspecific = exception { Error::TypeTiny::WrongNumberOfParameters->throw(got => 0); }; like($unspecific, qr{^Wrong number of parameters; got 0}, 'unspecific exception'); done_testing; aliases-devel-lexalias.t000644001750001750 1036713601673061 23252 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Eval-TypeTiny=pod =encoding utf-8 =head1 PURPOSE Tests L supports alias=>1 using L implementation. =head1 DEPENDENCIES Requires Devel::LexAlias. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires 'Devel::LexAlias'; use Eval::TypeTiny; Eval::TypeTiny::_force_implementation( Eval::TypeTiny::IMPLEMENTATION_DEVEL_LEXALIAS ); my %env = ( '$foo' => do { my $x = "foo"; \$x }, '@bar' => [ "bar" ], '%baz' => { "baz" => "1" }, ); my $source = <<'SRC'; sub { if (!@_) { return defined tied($foo); } return $foo if $_[0] eq '$foo'; return @bar if $_[0] eq '@bar'; return %baz if $_[0] eq '%baz'; return; } SRC my $closure = eval_closure(source => $source, environment => \%env, alias => 1); ok( ! $closure->(), 'tied implementation was not used', ); is_deeply( [ $closure->('$foo') ], [ 'foo' ], 'closure over scalar', ); is_deeply( [ $closure->('@bar') ], [ 'bar' ], 'closure over array', ); is_deeply( [ $closure->('%baz') ], [ 'baz' => 1 ], 'closure over hash', ); ${ $env{'$foo'} } = 'FOO'; @{ $env{'@bar'} } = ('BAR'); %{ $env{'%baz'} } = ('BAZ' => 99); is_deeply( [ $closure->('$foo') ], [ 'FOO' ], 'closure over scalar - worked', ); is_deeply( [ $closure->('@bar') ], [ 'BAR' ], 'closure over array - worked', ); is_deeply( [ $closure->('%baz') ], [ 'BAZ' => 99 ], 'closure over hash - worked', ); my $external = 40; my $closure2 = eval_closure( source => 'sub { $xxx += 2 }', environment => { '$xxx' => \$external }, alias => 1, ); $closure2->(); is($external, 42, 'closing over variables really really really works!'); { my $destroyed = 0; { package MyIndicator; sub DESTROY { $destroyed++ } } { my $number = bless \(my $foo), "MyIndicator"; $$number = 40; my $closure = eval_closure( source => 'sub { $$xxx += 2 }', environment => { '$xxx' => \$number }, alias => 1, ); $closure->(); is($$number, 42); is($destroyed, 0); } is($destroyed, 1, 'closed over variables disappear on cue'); } if (0) { # BROKEN my @store; { package MyTie; use Tie::Scalar (); our @ISA = 'Tie::StdScalar'; sub STORE { my $self = shift; push @store, $_[0]; $self->SUPER::STORE(@_); } sub method_of_mine { 42 } } tie(my($var), 'MyTie'); $var = 1; my $closure = eval_closure( source => 'sub { $xxx = $_[0]; tied($xxx)->method_of_mine }', environment => { '$xxx' => \$var }, alias => 1, ); is($closure->(2), 42, 'can close over tied variables ... AUTOLOAD stuff'); $closure->(3); my $nother_closure = eval_closure( source => 'sub { tied($xxx)->can(@_) }', environment => { '$xxx' => \$var }, alias => 1, ); ok( $nother_closure->('method_of_mine'), '... can'); ok(!$nother_closure->('your_method'), '... !can'); is_deeply( \@store, [ 1 .. 3], '... tie still works', ); { package OtherTie; our @ISA = 'MyTie'; sub method_of_mine { 666 } } tie($var, 'OtherTie'); is($closure->(4), 666, '... can be retied'); untie($var); my $e = exception { $closure->(5) }; like($e, qr{^Can't call method "method_of_mine" on an undefined value}, '... can be untied'); } if (0) { # ALSO BROKEN my $e = exception { eval_closure(source => 'sub { 1 ]') }; isa_ok( $e, 'Error::TypeTiny::Compilation', '$e', ); like( $e, qr{^Failed to compile source because: syntax error}, 'throw exception when code does not compile', ); like( $e->errstr, qr{^syntax error}, '$e->errstr', ); like( $e->code, qr{sub \{ 1 \]}, '$e->code', ); my $c1 = eval_closure(source => 'sub { die("BANG") }', description => 'test1'); my $e1 = exception { $c1->() }; like( $e1, qr{^BANG at test1 line 1}, '"description" option works', ); my $c2 = eval_closure(source => 'sub { die("BANG") }', description => 'test2', line => 222); my $e2 = exception { $c2->() }; like( $e2, qr{^BANG at test2 line 222}, '"line" option works', ); } done_testing; aliases-native.t000644001750001750 1031613601673061 21633 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Eval-TypeTiny=pod =encoding utf-8 =head1 PURPOSE Tests L supports alias=>1 using Perl refaliasing. =head1 DEPENDENCIES Requires Perl 5.22. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires 'v5.22'; use Eval::TypeTiny; Eval::TypeTiny::_force_implementation( Eval::TypeTiny::IMPLEMENTATION_NATIVE ); my %env = ( '$foo' => do { my $x = "foo"; \$x }, '@bar' => [ "bar" ], '%baz' => { "baz" => "1" }, ); my $source = <<'SRC'; sub { if (!@_) { return defined tied($foo); } return $foo if $_[0] eq '$foo'; return @bar if $_[0] eq '@bar'; return %baz if $_[0] eq '%baz'; return; } SRC my $closure = eval_closure(source => $source, environment => \%env, alias => 1); ok( ! $closure->(), 'tied implementation was not used', ); is_deeply( [ $closure->('$foo') ], [ 'foo' ], 'closure over scalar', ); is_deeply( [ $closure->('@bar') ], [ 'bar' ], 'closure over array', ); is_deeply( [ $closure->('%baz') ], [ 'baz' => 1 ], 'closure over hash', ); ${ $env{'$foo'} } = 'FOO'; @{ $env{'@bar'} } = ('BAR'); %{ $env{'%baz'} } = ('BAZ' => 99); is_deeply( [ $closure->('$foo') ], [ 'FOO' ], 'closure over scalar - worked', ); is_deeply( [ $closure->('@bar') ], [ 'BAR' ], 'closure over array - worked', ); is_deeply( [ $closure->('%baz') ], [ 'BAZ' => 99 ], 'closure over hash - worked', ); my $external = 40; my $closure2 = eval_closure( source => 'sub { $xxx += 2 }', environment => { '$xxx' => \$external }, alias => 1, ); $closure2->(); is($external, 42, 'closing over variables really really really works!'); { my $destroyed = 0; { package MyIndicator; sub DESTROY { $destroyed++ } } { my $number = bless \(my $foo), "MyIndicator"; $$number = 40; my $closure = eval_closure( source => 'sub { $$xxx += 2 }', environment => { '$xxx' => \$number }, alias => 1, ); $closure->(); is($$number, 42); is($destroyed, 0); } is($destroyed, 1, 'closed over variables disappear on cue'); } if (0) { # BROKEN my @store; { package MyTie; use Tie::Scalar (); our @ISA = 'Tie::StdScalar'; sub STORE { my $self = shift; push @store, $_[0]; $self->SUPER::STORE(@_); } sub method_of_mine { 42 } } tie(my($var), 'MyTie'); $var = 1; my $closure = eval_closure( source => 'sub { $xxx = $_[0]; tied($xxx)->method_of_mine }', environment => { '$xxx' => \$var }, alias => 1, ); is($closure->(2), 42, 'can close over tied variables ... AUTOLOAD stuff'); $closure->(3); my $nother_closure = eval_closure( source => 'sub { tied($xxx)->can(@_) }', environment => { '$xxx' => \$var }, alias => 1, ); ok( $nother_closure->('method_of_mine'), '... can'); ok(!$nother_closure->('your_method'), '... !can'); is_deeply( \@store, [ 1 .. 3], '... tie still works', ); { package OtherTie; our @ISA = 'MyTie'; sub method_of_mine { 666 } } tie($var, 'OtherTie'); is($closure->(4), 666, '... can be retied'); untie($var); my $e = exception { $closure->(5) }; like($e, qr{^Can't call method "method_of_mine" on an undefined value}, '... can be untied'); } if (0) { # ALSO BROKEN my $e = exception { eval_closure(source => 'sub { 1 ]') }; isa_ok( $e, 'Error::TypeTiny::Compilation', '$e', ); like( $e, qr{^Failed to compile source because: syntax error}, 'throw exception when code does not compile', ); like( $e->errstr, qr{^syntax error}, '$e->errstr', ); like( $e->code, qr{sub \{ 1 \]}, '$e->code', ); my $c1 = eval_closure(source => 'sub { die("BANG") }', description => 'test1'); my $e1 = exception { $c1->() }; like( $e1, qr{^BANG at test1 line 1}, '"description" option works', ); my $c2 = eval_closure(source => 'sub { die("BANG") }', description => 'test2', line => 222); my $e2 = exception { $c2->() }; like( $e2, qr{^BANG at test2 line 222}, '"line" option works', ); } done_testing; aliases-padwalker.t000644001750001750 1034013601673061 22314 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Eval-TypeTiny=pod =encoding utf-8 =head1 PURPOSE Tests L supports alias=>1 using L implementation. =head1 DEPENDENCIES Requires PadWalker. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires 'PadWalker'; use Eval::TypeTiny; Eval::TypeTiny::_force_implementation( Eval::TypeTiny::IMPLEMENTATION_PADWALKER ); my %env = ( '$foo' => do { my $x = "foo"; \$x }, '@bar' => [ "bar" ], '%baz' => { "baz" => "1" }, ); my $source = <<'SRC'; sub { if (!@_) { return defined tied($foo); } return $foo if $_[0] eq '$foo'; return @bar if $_[0] eq '@bar'; return %baz if $_[0] eq '%baz'; return; } SRC my $closure = eval_closure(source => $source, environment => \%env, alias => 1); ok( ! $closure->(), 'tied implementation was not used', ); is_deeply( [ $closure->('$foo') ], [ 'foo' ], 'closure over scalar', ); is_deeply( [ $closure->('@bar') ], [ 'bar' ], 'closure over array', ); is_deeply( [ $closure->('%baz') ], [ 'baz' => 1 ], 'closure over hash', ); ${ $env{'$foo'} } = 'FOO'; @{ $env{'@bar'} } = ('BAR'); %{ $env{'%baz'} } = ('BAZ' => 99); is_deeply( [ $closure->('$foo') ], [ 'FOO' ], 'closure over scalar - worked', ); is_deeply( [ $closure->('@bar') ], [ 'BAR' ], 'closure over array - worked', ); is_deeply( [ $closure->('%baz') ], [ 'BAZ' => 99 ], 'closure over hash - worked', ); my $external = 40; my $closure2 = eval_closure( source => 'sub { $xxx += 2 }', environment => { '$xxx' => \$external }, alias => 1, ); $closure2->(); is($external, 42, 'closing over variables really really really works!'); { my $destroyed = 0; { package MyIndicator; sub DESTROY { $destroyed++ } } { my $number = bless \(my $foo), "MyIndicator"; $$number = 40; my $closure = eval_closure( source => 'sub { $$xxx += 2 }', environment => { '$xxx' => \$number }, alias => 1, ); $closure->(); is($$number, 42); is($destroyed, 0); } is($destroyed, 1, 'closed over variables disappear on cue'); } if (0) { # BROKEN my @store; { package MyTie; use Tie::Scalar (); our @ISA = 'Tie::StdScalar'; sub STORE { my $self = shift; push @store, $_[0]; $self->SUPER::STORE(@_); } sub method_of_mine { 42 } } tie(my($var), 'MyTie'); $var = 1; my $closure = eval_closure( source => 'sub { $xxx = $_[0]; tied($xxx)->method_of_mine }', environment => { '$xxx' => \$var }, alias => 1, ); is($closure->(2), 42, 'can close over tied variables ... AUTOLOAD stuff'); $closure->(3); my $nother_closure = eval_closure( source => 'sub { tied($xxx)->can(@_) }', environment => { '$xxx' => \$var }, alias => 1, ); ok( $nother_closure->('method_of_mine'), '... can'); ok(!$nother_closure->('your_method'), '... !can'); is_deeply( \@store, [ 1 .. 3], '... tie still works', ); { package OtherTie; our @ISA = 'MyTie'; sub method_of_mine { 666 } } tie($var, 'OtherTie'); is($closure->(4), 666, '... can be retied'); untie($var); my $e = exception { $closure->(5) }; like($e, qr{^Can't call method "method_of_mine" on an undefined value}, '... can be untied'); } if (0) { # ALSO BROKEN my $e = exception { eval_closure(source => 'sub { 1 ]') }; isa_ok( $e, 'Error::TypeTiny::Compilation', '$e', ); like( $e, qr{^Failed to compile source because: syntax error}, 'throw exception when code does not compile', ); like( $e->errstr, qr{^syntax error}, '$e->errstr', ); like( $e->code, qr{sub \{ 1 \]}, '$e->code', ); my $c1 = eval_closure(source => 'sub { die("BANG") }', description => 'test1'); my $e1 = exception { $c1->() }; like( $e1, qr{^BANG at test1 line 1}, '"description" option works', ); my $c2 = eval_closure(source => 'sub { die("BANG") }', description => 'test2', line => 222); my $e2 = exception { $c2->() }; like( $e2, qr{^BANG at test2 line 222}, '"line" option works', ); } done_testing; aliases-tie.t000644001750001750 1021013601673061 21117 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Eval-TypeTiny=pod =encoding utf-8 =head1 PURPOSE Tests L supports alias=>1 using C implementation. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Eval::TypeTiny; Eval::TypeTiny::_force_implementation( Eval::TypeTiny::IMPLEMENTATION_TIE ); my %env = ( '$foo' => do { my $x = "foo"; \$x }, '@bar' => [ "bar" ], '%baz' => { "baz" => "1" }, ); my $source = <<'SRC'; sub { if (!@_) { return defined tied($foo); } return $foo if $_[0] eq '$foo'; return @bar if $_[0] eq '@bar'; return %baz if $_[0] eq '%baz'; return; } SRC my $closure = eval_closure(source => $source, environment => \%env, alias => 1); ok( $closure->(), 'tied implementation was loaded', ); is_deeply( [ $closure->('$foo') ], [ 'foo' ], 'closure over scalar', ); is_deeply( [ $closure->('@bar') ], [ 'bar' ], 'closure over array', ); is_deeply( [ $closure->('%baz') ], [ 'baz' => 1 ], 'closure over hash', ); ${ $env{'$foo'} } = 'FOO'; @{ $env{'@bar'} } = ('BAR'); %{ $env{'%baz'} } = ('BAZ' => 99); is_deeply( [ $closure->('$foo') ], [ 'FOO' ], 'closure over scalar - worked', ); is_deeply( [ $closure->('@bar') ], [ 'BAR' ], 'closure over array - worked', ); is_deeply( [ $closure->('%baz') ], [ 'BAZ' => 99 ], 'closure over hash - worked', ); my $external = 40; my $closure2 = eval_closure( source => 'sub { $xxx += 2 }', environment => { '$xxx' => \$external }, alias => 1, ); $closure2->(); is($external, 42, 'closing over variables really really really works!'); { my $destroyed = 0; { package MyIndicator; sub DESTROY { $destroyed++ } } { my $number = bless \(my $foo), "MyIndicator"; $$number = 40; my $closure = eval_closure( source => 'sub { $$xxx += 2 }', environment => { '$xxx' => \$number }, alias => 1, ); $closure->(); is($$number, 42); is($destroyed, 0); } is($destroyed, 1, 'closed over variables disappear on cue'); } if (0) { # BROKEN my @store; { package MyTie; use Tie::Scalar (); our @ISA = 'Tie::StdScalar'; sub STORE { my $self = shift; push @store, $_[0]; $self->SUPER::STORE(@_); } sub method_of_mine { 42 } } tie(my($var), 'MyTie'); $var = 1; my $closure = eval_closure( source => 'sub { $xxx = $_[0]; tied($xxx)->method_of_mine }', environment => { '$xxx' => \$var }, alias => 1, ); is($closure->(2), 42, 'can close over tied variables ... AUTOLOAD stuff'); $closure->(3); my $nother_closure = eval_closure( source => 'sub { tied($xxx)->can(@_) }', environment => { '$xxx' => \$var }, alias => 1, ); ok( $nother_closure->('method_of_mine'), '... can'); ok(!$nother_closure->('your_method'), '... !can'); is_deeply( \@store, [ 1 .. 3], '... tie still works', ); { package OtherTie; our @ISA = 'MyTie'; sub method_of_mine { 666 } } tie($var, 'OtherTie'); is($closure->(4), 666, '... can be retied'); untie($var); my $e = exception { $closure->(5) }; like($e, qr{^Can't call method "method_of_mine" on an undefined value}, '... can be untied'); } if (0) { # ALSO BROKEN my $e = exception { eval_closure(source => 'sub { 1 ]') }; isa_ok( $e, 'Error::TypeTiny::Compilation', '$e', ); like( $e, qr{^Failed to compile source because: syntax error}, 'throw exception when code does not compile', ); like( $e->errstr, qr{^syntax error}, '$e->errstr', ); like( $e->code, qr{sub \{ 1 \]}, '$e->code', ); my $c1 = eval_closure(source => 'sub { die("BANG") }', description => 'test1'); my $e1 = exception { $c1->() }; like( $e1, qr{^BANG at test1 line 1}, '"description" option works', ); my $c2 = eval_closure(source => 'sub { die("BANG") }', description => 'test2', line => 222); my $e2 = exception { $c2->() }; like( $e2, qr{^BANG at test2 line 222}, '"line" option works', ); } done_testing; basic.t000644001750001750 1251613601673061 20013 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Eval-TypeTiny=pod =encoding utf-8 =head1 PURPOSE Tests L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Eval::TypeTiny; subtest "constants exist" => sub { my @constants = qw( HAS_LEXICAL_VARS HAS_LEXICAL_SUBS ALIAS_IMPLEMENTATION IMPLEMENTATION_DEVEL_LEXALIAS IMPLEMENTATION_PADWALKER IMPLEMENTATION_NATIVE IMPLEMENTATION_TIE ); for my $c (@constants) { subtest "constant $c" => sub { my $can = Eval::TypeTiny->can($c); ok $can, "constant $c exists"; is exception { $can->() }, undef, "... and doesn't throw an error"; is $can->(undef), $can->(999), "... and seems to be constant"; }; } }; my $s = <<'SRC'; sub { return $foo if $_[0] eq '$foo'; return @bar if $_[0] eq '@bar'; return %baz if $_[0] eq '%baz'; return; } SRC my %sources = (string => $s, arrayref => [split /\n/, $s]); foreach my $key (reverse sort keys %sources) { subtest "compiling $key source" => sub { my %env = ( '$foo' => do { my $x = "foo"; \$x }, '@bar' => [ "bar" ], '%baz' => { "baz" => "1" }, ); my $source = $sources{$key}; my $closure = eval_closure(source => $source, environment => \%env); is_deeply( [ $closure->('$foo') ], [ 'foo' ], 'closure over scalar', ); is_deeply( [ $closure->('@bar') ], [ 'bar' ], 'closure over array', ); is_deeply( [ $closure->('%baz') ], [ 'baz' => 1 ], 'closure over hash', ); }; } my $external = 40; my $closure2 = eval_closure( source => 'sub { $xxx += 2 }', environment => { '$xxx' => \$external }, alias => 1, ); $closure2->(); is($external, 42, 'closing over variables really really really works!'); { my $destroyed = 0; { package MyIndicator; sub DESTROY { $destroyed++ } } subtest 'closed over variables disappear on cue' => sub { { my $number = bless \(my $foo), "MyIndicator"; $$number = 40; my $closure = eval_closure( source => 'sub { $$xxx += 2 }', environment => { '$xxx' => \$number }, alias => 1, ); $closure->(); is($$number, 42, 'closure works'); is($destroyed, 0, 'closed over variable still exists'); } is($destroyed, 1, 'closed over variable destroyed once closure has been destroyed'); }; } { my @store; Eval::TypeTiny::_force_implementation( Eval::TypeTiny::IMPLEMENTATION_TIE ); { package MyTie; use Tie::Scalar (); our @ISA = 'Tie::StdScalar'; sub STORE { my $self = shift; push @store, $_[0]; $self->SUPER::STORE(@_); } sub method_of_mine { 42 } } { package OtherTie; our @ISA = 'MyTie'; sub method_of_mine { 666 } } tie(my($var), 'MyTie'); $var = 1; subtest "tied variables can be closed over (even with tied alias implementation)" => sub { my $closure = eval_closure( source => 'sub { $xxx = $_[0]; tied($xxx)->method_of_mine }', environment => { '$xxx' => \$var }, alias => 1, ); is($closure->(2), 42, 'can close over tied variables ... AUTOLOAD stuff'); $closure->(3); my $nother_closure = eval_closure( source => 'sub { tied($xxx)->can(@_) }', environment => { '$xxx' => \$var }, alias => 1, ); ok( $nother_closure->('method_of_mine'), '... can'); ok(!$nother_closure->('your_method'), '... !can'); is_deeply( \@store, [ 1 .. 3], '... tie still works', ); tie($var, 'OtherTie'); is($closure->(4), 666, '... can be retied'); untie($var); my $e = exception { $closure->(5) }; like($e, qr{^Can't call method "method_of_mine" on an undefined value}, '... can be untied'); }; } my $c1 = eval_closure(source => 'sub { die("BANG") }', description => 'test1'); my $e1 = exception { $c1->() }; like( $e1, qr{^BANG at test1 line 1}, '"description" option works', ); my $c2 = eval_closure(source => 'sub { die("BANG") }', description => 'test2', line => 222); my $e2 = exception { $c2->() }; like( $e2, qr{^BANG at test2 line 222}, '"line" option works', ); subtest "exception for syntax error" => sub { my $e3 = exception { eval_closure source => 'sub {' }; ok( $e3->isa('Error::TypeTiny::Compilation'), 'proper exceptions thrown for compilation errors' ); is( $e3->code, 'sub {', '$exception->code' ); like( $e3->errstr, qr/Missing right curly/, '$exception->errstr' ); is( ref $e3->context, 'HASH', '$exception->context' ); }; subtest "exception for syntax error (given arrayref)" => sub { my $e3 = exception { eval_closure source => ['sub {', ''] }; ok( $e3->isa('Error::TypeTiny::Compilation'), 'proper exceptions thrown for compilation errors' ); is( $e3->code, "sub {\n", '$exception->code' ); like( $e3->errstr, qr/Missing right curly/, '$exception->errstr' ); is( ref $e3->context, 'HASH', '$exception->context' ); }; subtest "exception for wrong reference type" => sub { my $e3 = exception { eval_closure source => 'sub {', environment => { '%foo' => [] } }; ok($e3->isa('Error::TypeTiny'), 'exception was thrown'); if (Eval::TypeTiny::_EXTENDED_TESTING) { like($e3->message, qr/^Expected a variable name and ref/, 'correct exception message'); } }; done_testing; lexical-subs.t000644001750001750 437613601673061 21312 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Eval-TypeTiny=pod =encoding utf-8 =head1 PURPOSE Tests L with experimental lexical subs. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires 'v5.18'; use Test::Fatal; use Eval::TypeTiny; my $variable; my %env = ( '$foo' => do { my $x = "foo"; \$x }, '@bar' => [ "bar" ], '%baz' => { "baz" => "1" }, '&quux' => sub { $variable }, '&quuux' => sub { $variable + 40 }, ); my $source = <<'SRC'; sub { package Kill::La::NonLexikill; return $foo if $_[0] eq '$foo'; return @bar if $_[0] eq '@bar'; return %baz if $_[0] eq '%baz'; return quux() if $_[0] eq '&quux'; return quuux if $_[0] eq '&quuux'; return; } SRC my $closure = eval_closure(source => $source, environment => \%env); is_deeply( [ $closure->('$foo') ], [ 'foo' ], 'closure over scalar', ); is_deeply( [ $closure->('@bar') ], [ 'bar' ], 'closure over array', ); is_deeply( [ $closure->('%baz') ], [ 'baz' => 1 ], 'closure over hash', ); is_deeply( [ $closure->('&quux') ], [ undef ], 'closure over lexical sub - undef', ); $variable = 2; is_deeply( [ $closure->('&quux') ], [ 2 ], 'closure over lexical sub - 2', ); is_deeply( [ $closure->('&quuux') ], [ 42 ], 'closure over lexical sub - 42', ); my $e = exception { eval_closure(source => 'sub { 1 ]') }; isa_ok( $e, 'Error::TypeTiny::Compilation', '$e', ); like( $e, qr{^Failed to compile source because: syntax error}, 'throw exception when code does not compile', ); like( $e->errstr, qr{^syntax error}, '$e->errstr', ); like( $e->code, qr{sub \{ 1 \]}, '$e->code', ); my $c1 = eval_closure(source => 'sub { die("BANG") }', description => 'test1'); my $e1 = exception { $c1->() }; like( $e1, qr{^BANG at test1 line 1}, '"description" option works', ); my $c2 = eval_closure(source => 'sub { die("BANG") }', description => 'test2', line => 222); my $e2 = exception { $c2->() }; like( $e2, qr{^BANG at test2 line 222}, '"line" option works', ); done_testing; basic.t000644001750001750 370513601673061 20023 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Test-TypeTiny=pod =encoding utf-8 =head1 PURPOSE Tests L (which is somewhat important because Test::TypeTiny is itself used for the majority of the type constraint tests). In particular, this tests that everything works when the C<< $EXTENDED_TESTING >> environment variable is false. =head1 DEPENDENCIES Requires L 0.109. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; BEGIN { $ENV{EXTENDED_TESTING} = 0; if (eval { require Test::Tester }) { Test::Tester->import(tests => 48); } else { require Test::More; Test::More->import(skip_all => 'requires Test::Tester'); } } use Test::TypeTiny; use Types::Standard qw( Int Num ); check_test( sub { should_pass(1, Int) }, { ok => 1, name => 'Value "1" passes type constraint Int', diag => '', type => '', }, 'successful should_pass', ); check_test( sub { should_pass([], Int) }, { ok => 0, name => 'Reference [] passes type constraint Int', diag => '', type => '', }, 'unsuccessful should_pass', ); check_test( sub { should_fail([], Int) }, { ok => 1, name => 'Reference [] fails type constraint Int', diag => '', type => '', }, 'successful (i.e. failing) should_fail', ); check_test( sub { should_fail(1, Int) }, { ok => 0, name => 'Value "1" fails type constraint Int', diag => '', type => '', }, 'unsuccessful (i.e. passing) should_fail', ); check_test( sub { ok_subtype(Num, Int) }, { ok => 1, name => 'Num subtype: Int', diag => '', type => '', }, 'successful ok_subtype', ); check_test( sub { ok_subtype(Int, Num) }, { ok => 0, name => 'Int subtype: Num', diag => '', type => '', }, 'unsuccessful ok_subtype', ); extended.t000644001750001750 230213601673061 20532 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Test-TypeTiny=pod =encoding utf-8 =head1 PURPOSE Tests L works when the C<< $EXTENDED_TESTING >> environment variable is true. Note that L appears to have issues with subtests, so currently C and C are not tested. =head1 DEPENDENCIES Requires L 0.109. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; BEGIN { $ENV{EXTENDED_TESTING} = 1; if (eval { require Test::Tester }) { Test::Tester->import(tests => 16); } else { require Test::More; Test::More->import(skip_all => 'requires Test::Tester'); } } use Test::TypeTiny; use Types::Standard qw( Int Num ); check_test( sub { ok_subtype(Num, Int) }, { ok => 1, name => 'Num subtype: Int', diag => '', type => '', }, 'successful ok_subtype', ); check_test( sub { ok_subtype(Int, Num) }, { ok => 0, name => 'Int subtype: Num', diag => '', type => '', }, 'unsuccessful ok_subtype', ); matchfor.t000644001750001750 502313601673061 20540 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Test-TypeTiny=pod =encoding utf-8 =head1 PURPOSE Tests L (which is somewhat important because Test::TypeTiny is itself used for the majority of the type constraint tests). In particular, this tests that everything works when the C<< $EXTENDED_TESTING >> environment variable is false. =head1 DEPENDENCIES Requires L 0.109. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; BEGIN { $ENV{EXTENDED_TESTING} = 0; if (eval { require Test::Tester }) { require Test::More; Test::Tester->import(tests => 6); } else { require Test::More; Test::More->import(skip_all => 'requires Test::Tester'); } } use Test::TypeTiny qw(matchfor); my $mf = matchfor("foo", "bar"); Test::More::is("$mf", "foo", "stringification"); Test::More::subtest "successful matchfor(qr//)" => sub { check_test( sub { Test::More::is( "Hello world", matchfor(qr/hello/i, qr/hiya/i, "Greeting::Global"), 'ONE', ); }, { ok => 1, name => 'ONE', diag => '', type => '', }, 'successful matchfor(qr//)', ); }; Test::More::subtest "successful matchfor(qr//) 2" => sub { check_test( sub { Test::More::is( "Hiya world", matchfor(qr/hello/i, qr/hiya/i, "Greeting::Global"), 'TWO', ); }, { ok => 1, name => 'TWO', diag => '', type => '', }, 'successful matchfor(qr//)', ); }; Test::More::subtest 'unsuccessful matchfor(qr//)' => sub { check_test( sub { Test::More::is( "Booooooooooooooo", matchfor(qr/hello/i, qr/hiya/i, "Greeting::Global"), 'THREE', ); }, { ok => 0, name => 'THREE', }, 'unsuccessful matchfor(qr//)', ); }; Test::More::subtest 'successful matchfor(CLASS)' => sub { check_test( sub { Test::More::is( bless({}, "Greeting::Global"), matchfor(qr/hello/i, qr/hiya/i, "Greeting::Global"), 'FOUR', ); }, { ok => 1, name => 'FOUR', diag => '', type => '', }, 'successful matchfor(CLASS)', ); }; Test::More::subtest 'unsuccessful successful matchfor(CLASS)' => sub { check_test( sub { Test::More::is( bless({}, "Greeting::Local"), matchfor(qr/hello/i, qr/hiya/i, "Greeting::Global"), 'FIVE', ); }, { ok => 0, name => 'FIVE', }, 'unsuccessful successful matchfor(CLASS)', ); }; basic.t000644001750001750 1077213601673061 20023 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Coercion=pod =encoding utf-8 =head1 PURPOSE Checks Type::Coercion works. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use BiggerLib -types, -coercions; is( BigInteger->coercion->coerce(2), 12, 'coercion works', ); is( BigInteger->coercion->(2), 12, 'coercion overloads &{}', ); ok( BigInteger->coercion->has_coercion_for_type(ArrayRef), 'BigInteger has_coercion_for_type ArrayRef', ); ok( BigInteger->coercion->has_coercion_for_type(SmallInteger), 'BigInteger has_coercion_for_type SmallInteger', ); ok( !BigInteger->coercion->has_coercion_for_type(HashRef), 'not BigInteger has_coercion_for_type SmallInteger', ); cmp_ok( BigInteger->coercion->has_coercion_for_type(BigInteger), eq => '0 but true', 'BigInteger has_coercion_for_type BigInteger eq "0 but true"' ); my $BiggerInteger = BigInteger->create_child_type( constraint => sub { $_ > 1_000_000 }, ); cmp_ok( BigInteger->coercion->has_coercion_for_type($BiggerInteger), eq => '0 but true', 'BigInteger has_coercion_for_type $BiggerInteger eq "0 but true"' ); ok( BigInteger->coercion->has_coercion_for_value([]), 'BigInteger has_coercion_for_value []', ); ok( BigInteger->coercion->has_coercion_for_value(2), 'BigInteger has_coercion_for_value 2', ); ok( !BigInteger->coercion->has_coercion_for_value({}), 'not BigInteger has_coercion_for_value {}', ); cmp_ok( BigInteger->coercion->has_coercion_for_value(200), eq => '0 but true', 'BigInteger has_coercion_for_value 200 eq "0 but true"' ); is( exception { BigInteger->coerce([]) }, undef, "coerce doesn't throw an exception if it can coerce", ); is( exception { BigInteger->coerce({}) }, undef, "coerce doesn't throw an exception if it can't coerce", ); is( exception { BigInteger->assert_coerce([]) }, undef, "assert_coerce doesn't throw an exception if it can coerce", ); like( exception { BigInteger->assert_coerce({}) }, qr{^Reference \{\} did not pass type constraint "BigInteger"}, "assert_coerce DOES throw an exception if it can't coerce", ); isa_ok( ArrayRefFromAny, 'Type::Coercion', 'ArrayRefFromAny', ); is_deeply( ArrayRefFromAny->coerce(1), [1], 'ArrayRefFromAny coercion works', ); my $sum1 = 'Type::Coercion'->add(ArrayRefFromAny, ArrayRefFromPiped); is_deeply( $sum1->coerce("foo|bar"), ["foo|bar"], "Coercion $sum1 prioritizes ArrayRefFromAny", ); my $sum2 = 'Type::Coercion'->add(ArrayRefFromPiped, ArrayRefFromAny); is_deeply( $sum2->coerce("foo|bar"), ["foo","bar"], "Coercion $sum2 prioritizes ArrayRefFromPiped", ); my $arr = ArrayRef->plus_fallback_coercions(ArrayRefFromAny); is_deeply( $arr->coerce("foo|bar"), ["foo|bar"], "Type \$arr coercion works", ); my $sum3 = $arr->plus_fallback_coercions(ArrayRefFromPiped); is_deeply( $sum3->coerce("foo|bar"), ["foo|bar"], "Type \$sum3 coercion works", ); my $sum4 = $arr->plus_coercions(ArrayRefFromPiped); is_deeply( $sum4->coerce("foo|bar"), ["foo","bar"], "Type \$sum4 coercion works", ); use Test::TypeTiny; my $arrayref_from_piped = ArrayRef->plus_coercions(ArrayRefFromPiped); my $coercibles = $arrayref_from_piped->coercibles; should_pass([], $coercibles); should_pass('1|2|3', $coercibles); should_fail({}, $coercibles); should_pass([], ArrayRef->coercibles); should_fail('1|2|3', ArrayRef->coercibles); should_fail({}, ArrayRef->coercibles); is($arrayref_from_piped->coercibles, $arrayref_from_piped->coercibles, '$arrayref_from_piped->coercibles == $arrayref_from_piped->coercibles'); # ensure that add_type_coercion can handle Type::Coercions subtest 'add a Type::Coercion to a Type::Coercion' => sub { my $coercion = Type::Coercion->new; ok( !$coercion->has_coercion_for_type( Str ), "empty coercion can't coerce a Str" ); is( exception { $coercion->add_type_coercions( ArrayRefFromPiped ) }, undef, "add a coercion from Str" ); ok( $coercion->has_coercion_for_type( Str ), "check that coercion was added" ); # now see if coercion actually works my $arrayref_from_piped = ArrayRef->plus_coercions($coercion); my $coercibles = $arrayref_from_piped->coercibles; should_pass('1|2|3', $coercibles, "can coerce from a Str"); }; done_testing; esoteric.t000644001750001750 250213601673061 20527 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Coercion=pod =encoding utf-8 =head1 PURPOSE Checks various undocumented Type::Coercion methods. The fact that these are tested here should not be construed to mean tht they are any any way a stable, supported part of the Type::Coercion API. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Test::TypeTiny; use Type::Coercion; use Types::Standard -types; my $type = Int->create_child_type; $type->coercion->add_type_coercions( Num, q[int($_)] ); like( exception { $type->coercion->meta }, qr/^Not really a Moose::Meta::TypeCoercion/, '$type->coercion->meta', ); $type->coercion->_compiled_type_coercion( Type::Coercion->new( type_coercion_map => [ ArrayRef, q[666] ], ), ); $type->coercion->_compiled_type_coercion( sub { 999 }, ); is($type->coerce(3.1), 3, '$type->coercion->add_type_coercions(TYPE, STR)'); is($type->coerce([]), 666, '$type->coercion->_compiled_type_coercion(OBJECT)'); is($type->coerce(undef), 999, '$type->coercion->_compiled_type_coercion(CODE)'); done_testing; frozen.t000644001750001750 326213601673061 20221 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Coercion=pod =encoding utf-8 =head1 PURPOSE Type::Coercion objects are mutable, unlike Type::Tiny objects. However, they can be frozen, making them immutable. (And Type::Tiny will freeze them occasionally, if it feels it has to.) =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. Requires Moose 2.0000 =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::Requires { Moose => 2.0000 }; use Test::More; use Test::Fatal; use BiggerLib -types; ok(!BigInteger->coercion->frozen, 'coercions are not initially frozen'); BigInteger->coercion->add_type_coercions(Undef, sub { 777 }); ok(!BigInteger->coercion->frozen, 'coercions do not freeze because of adding code'); is(BigInteger->coerce(undef), 777, '... and they work'); BigInteger->coercion->moose_coercion; ok(BigInteger->coercion->frozen, 'coercions do freeze when forced inflation to Moose'); my $e = exception { BigInteger->coercion->add_type_coercions(Item, sub { 999 }) }; like($e, qr{Attempt to add coercion code to a Type::Coercion which has been frozen}, 'cannot add code to a frozen coercion'); BigInteger->coercion->i_really_want_to_unfreeze; ok(!BigInteger->coercion->frozen, 'i_really_want_to_unfreeze'); $e = exception { BigInteger->coercion->add_type_coercions(Item, sub { 888 }) }; is($e, undef, '... can now add coercions'); is(BigInteger->coerce(\$e), 888, '... ... which work'); done_testing; inlining.t000644001750001750 256713601673061 20534 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Coercion=pod =encoding utf-8 =head1 PURPOSE Checks Type::Coercion can be inlined. =head1 DEPENDENCIES Requires JSON::PP 2.27105. Test is skipped if this module is not present. Note that this is bundled with Perl v5.13.11 and above. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::Requires { "JSON::PP" => "2.27105" }; use Test::More; use Test::Fatal; { package T; require JSON::PP; use Type::Library -base, -declare => qw/ JsonHash JsonArray /; use Type::Utils; use Types::Standard -types; declare JsonHash, as HashRef; declare JsonArray, as ArrayRef; coerce JsonHash, from Str, 'JSON::PP::decode_json($_)'; coerce JsonArray, from Str, 'JSON::PP::decode_json($_)'; __PACKAGE__->meta->make_immutable; } my $code = T::JsonArray->coercion->inline_coercion('$::foo'); our $foo = "[3,2,1]"; is_deeply( eval $code, [3,2,1], 'inlined coercion works', ); $foo = [5,4,3]; is_deeply( eval $code, [5,4,3], 'no coercion necessary', ); $foo = {foo => "bar"}; is_deeply( eval $code, {foo => "bar"}, 'no coercion possible', ); done_testing; parameterized.t000644001750001750 1112713601673061 21571 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Coercion=pod =encoding utf-8 =head1 PURPOSE Checks the C and C parameterized coercions from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( . ./t ../inc ./inc ); use utf8; use Test::More; use Test::Requires { "Encode" => 0 }; use Test::TypeTiny; use Encode; use Types::Standard qw( Str ArrayRef HashRef Join Split ); use Type::Utils; my $chars = "Café Paris|Garçon"; my $bytes_utf8 = Encode::encode("utf-8", $chars); my $bytes_western = Encode::encode("iso-8859-1", $chars); is(length($chars), 17, 'length $chars == 17'); is(length($bytes_utf8), 19, 'length $bytes_utf8 == 19'); is(length($bytes_western), 17, 'length $bytes_western == 17'); my $SplitSpace = (ArrayRef[Str])->plus_coercions(Split[qr/\s/]); my $SplitPipe = (ArrayRef[Str])->plus_coercions(Split[qr/\|/]); ok($SplitSpace->can_be_inlined, '$SplitSpace can be inlined'); ok($SplitPipe->can_be_inlined, '$SplitPipe can be inlined'); is_deeply( $SplitSpace->coerce($chars), [ "Café", "Paris|Garçon" ], '$SplitSpace->coerce($chars)', ); is_deeply( $SplitSpace->coerce($bytes_utf8), [ map Encode::encode("utf-8", $_), "Café", "Paris|Garçon" ], '$SplitSpace->coerce($bytes_utf8)', ); is_deeply( $SplitSpace->coerce($bytes_western), [ map Encode::encode("iso-8859-1", $_), "Café", "Paris|Garçon" ], '$SplitSpace->coerce($bytes_western)', ); should_pass($SplitSpace->coerce($chars), ArrayRef[Str]); should_pass($SplitSpace->coerce($bytes_utf8), ArrayRef[Str]); should_pass($SplitSpace->coerce($bytes_western), ArrayRef[Str]); is_deeply( my $arr_chars = $SplitPipe->coerce($chars), [ "Café Paris", "Garçon" ], '$SplitPipe->coerce($chars)', ); is_deeply( my $arr_bytes_utf8 = $SplitPipe->coerce($bytes_utf8), [ map Encode::encode("utf-8", $_), "Café Paris", "Garçon" ], '$SplitPipe->coerce($bytes_utf8)', ); is_deeply( my $arr_bytes_western = $SplitPipe->coerce($bytes_western), [ map Encode::encode("iso-8859-1", $_), "Café Paris", "Garçon" ], '$SplitPipe->coerce($bytes_western)', ); my $JoinPipe = Str->plus_coercions(Join["|"]); is( $_ = $JoinPipe->coerce($arr_chars), $chars, '$JoinPipe->coerce($arr_chars)', ); should_pass($_, Str); is( $_ = $JoinPipe->coerce($arr_bytes_utf8), $bytes_utf8, '$JoinPipe->coerce($arr_bytes_utf8)', ); should_pass($_, Str); is( $_ = $JoinPipe->coerce($arr_bytes_western), $bytes_western, '$JoinPipe->coerce($arr_bytes_western)', ); should_pass($_, Str); # Re-parameterization stuff: { # A type constraint with a useless parameter... # my $Stringy = Str->create_child_type( name => 'Stringy', parent => Str, constraint_generator => sub { sub {} }, ); ok($Stringy->is_parameterizable, '$Stringy->is_parameterizable'); # A parameterizable coercion... my $Joiny = 'Type::Coercion'->new( name => 'Joiny', type_constraint => $Stringy, type_coercion_map => [ HashRef, sub { 'hello' } ], coercion_generator => sub { my ($self, $type, $from, $to) = @_; my $joinchar = ':'; if ($type->is_a_type_of($Stringy) and $type->is_parameterized) { $joinchar = $type->type_parameter; } return ( @{ $self->type_coercion_map }, ArrayRef, sub { my @arr = @$_; join($joinchar, @arr[$from..$to]) }, ); }, ); isa_ok( $Joiny, 'Type::Coercion', 'parameterizable coercion', ); is( $Joiny->coerce({}), 'hello', '... coercion included in base definition works' ); is_deeply( $Joiny->coerce(['a'..'z']), ['a'..'z'], '... coercion generated by parameterization does not exist yet' ); my $Joiny23 = $Joiny->parameterize(2, 3); isa_ok( $Joiny23, 'Type::Coercion', 'parameterized coercion which has not yet been combined with type constraint', ); is( $Joiny23->coerce({}), 'hello', '... coercion included in base definition works' ); is( $Joiny23->coerce(['a'..'z']), 'c:d', '... coercion generated by parameterization works' ); my $StringyPipe = $Stringy->parameterize('|')->plus_coercions($Joiny23); isa_ok( $StringyPipe, 'Type::Tiny', 'type constraint consuming parameterized coercion', ); is( $StringyPipe->coerce({}), 'hello', '... coercion included in base definition works' ); is( $StringyPipe->coerce(['a'..'z']), 'c|d', '... coercion generated by parameterization works; must have been regenerated' ); } done_testing; smartmatch.t000644001750001750 144013601673061 21055 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Coercion=pod =encoding utf-8 =head1 PURPOSE Checks Type::Coercion overload of C<< ~~ >>. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Type::Tiny (); BEGIN { Type::Tiny::SUPPORT_SMARTMATCH or plan skip_all => 'smartmatch support not available for this version or Perl'; } use Types::Standard qw( Num Int ); my $type = Int->plus_coercions( Num, sub{+int} ); no warnings; #!! ok ( 3.1 ~~ $type->coercion ); ok not ( [ ] ~~ $type->coercion ); done_testing; typetiny-constructor.t000644001750001750 213313601673061 23162 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Coercion=pod =encoding utf-8 =head1 PURPOSE Checks proper Type::Coercion objects are automatically created by the Type::Tiny constructor. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Type::Tiny; use Types::Standard qw( Int Num Any ); subtest "coercion => ARRAY" => sub { my $type = Type::Tiny->new( name => 'Test', parent => Int, coercion => [ Num, sub { int($_) } ], ); ok $type->has_coercion; is $type->coercion->type_coercion_map->[0], Num; is $type->coerce(3.2), 3; }; subtest "coercion => CODE" => sub { my $type = Type::Tiny->new( name => 'Test', parent => Int, coercion => sub { int($_) }, ); ok $type->has_coercion; is $type->coercion->type_coercion_map->[0], Any; is $type->coerce(3.2), 3; }; done_testing; basic.t000644001750001750 335513601673061 21706 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Coercion-FromMoose=pod =encoding utf-8 =head1 PURPOSE Checks the types adopted from Moose still have a coercion which works. =head1 DEPENDENCIES Moose 2.0000; otherwise skipped. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { Moose => '2.0000' }; use Test::TypeTiny; use Moose::Util::TypeConstraints; my $Rounded = do { subtype 'RoundedInt', as 'Int'; coerce 'RoundedInt', from 'Num', via { int($_) }; find_type_constraint 'RoundedInt'; }; my $Array_of_Rounded = do { use Types::Standard -types; ArrayRef[$Rounded]; }; isa_ok( $Array_of_Rounded->type_parameter, 'Type::Tiny', '$Array_of_Rounded->type_parameter', ); isa_ok( $Array_of_Rounded->type_parameter->coercion, 'Type::Coercion', '$Array_of_Rounded->type_parameter->coercion', ); isa_ok( $Array_of_Rounded->type_parameter->coercion, 'Type::Coercion::FromMoose', '$Array_of_Rounded->type_parameter->coercion', ); is_deeply( $Array_of_Rounded->coerce([ 9.1, 1.1, 2.2, 3.3 ]), [ 9, 1..3 ], 'coercion works', ); # Making this work might prevent coercions from being inlined # unless the coercion has been frozen. # # See https://rt.cpan.org/Ticket/Display.html?id=93345#txn-1395097 # TODO: { local $TODO = "\$Array_of_Rounded's coercion has already been compiled"; coerce 'RoundedInt', from 'Undef', via { 0 }; is_deeply( $Array_of_Rounded->coerce([ 9.1, 1.1, undef, 3.3 ]), [ 9, 1, 0, 3 ], 'coercion can be altered later', ); }; done_testing; errors.t000644001750001750 317713601673061 22143 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Coercion-FromMoose=pod =encoding utf-8 =head1 PURPOSE Checks crazy Type::Coercion::FromMoose errors. =head1 DEPENDENCIES Moose 2.0000; otherwise skipped. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { Moose => '2.0000' }; use Test::Fatal; use Types::Standard -types; use Types::TypeTiny qw( to_TypeTiny ); use Scalar::Util qw(refaddr); my $orig = do { use Moose::Util::TypeConstraints; subtype 'RoundedInt', as 'Int'; coerce 'RoundedInt', from 'Num', via { int($_) }; find_type_constraint 'RoundedInt'; }; my $type = to_TypeTiny($orig); is( refaddr($type->coercion->moose_coercion), refaddr($orig->coercion), ); is( refaddr($type->moose_type->coercion), refaddr($orig->coercion), ); TODO: { local $TODO = "Adding coercions to Type::Coercion::FromMoose not currently supported"; is( exception { $type->coercion->add_type_coercions(Any, sub {666}) }, undef, 'no exception adding coercions to a Moose-imported type constraint', ); is( $type->coerce([]), 666, '... and the coercion works' ); }; # Fake a T:C:FromMoose where the Type::Tiny object has been reaped... require Type::Coercion::FromMoose; my $dummy = Type::Coercion::FromMoose->new; like ( exception { $dummy->moose_coercion }, qr/^The type constraint attached to this coercion has been garbage collected... PANIC/, ); done_testing; basic.t000644001750001750 504113601673061 21062 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Coercion-Union=pod =encoding utf-8 =head1 PURPOSE Checks Type::Coercion::Union works. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard -types; use Type::Utils; my $RoundedInteger = declare RoundedInteger => as Int; $RoundedInteger->coercion->add_type_coercions(Num, 'int($_)')->freeze; should_pass("4", $RoundedInteger); should_fail("1.1", $RoundedInteger); should_fail("xyz", $RoundedInteger); my $String3 = declare String3 => as StrMatch[qr/^.{3}$/]; $String3->coercion->add_type_coercions(Str, 'substr("$_ ", 0, 3)')->freeze; should_pass("xyz", $String3); should_fail("x", $String3); should_fail("wxyz", $String3); my $Union1 = union Union1 => [$RoundedInteger, $String3]; should_pass("3.4", $Union1); should_pass("30", $Union1); should_fail("3.12", $Union1); should_fail("wxyz", $Union1); is( $RoundedInteger->coerce("3.4"), "3", "RoundedInteger coerces from Num", ); is( $RoundedInteger->coerce("xyz"), "xyz", "RoundedInteger does not coerce from Str", ); is( $String3->coerce("30"), "30 ", "String3 coerces from Str", ); my $arr = []; is( $String3->coerce($arr), $arr, "String3 does not coerce from ArrayRef", ); ok( $Union1->has_coercion, "unions automatically have a coercion if their child constraints do", ); note $Union1->coercion->inline_coercion('$X'); ok( union([Str, ArrayRef]), "unions do not automatically have a coercion if their child constraints do not", ); is( $Union1->coerce("4"), "4", "Union1 does not need to coerce an Int", ); is( $Union1->coerce("xyz"), "xyz", "Union1 does not need to coerce a String3", ); is( $Union1->coerce("3.1"), "3.1", "Union1 does not need to coerce a String3, even if it looks like a Num", ); is( $Union1->coerce("abcde"), "abc", "Union1 coerces Str -> String3", ); is( $Union1->coerce("3.123"), "3", "given the choice of two valid coercions, Union1 prefers RoundedInteger because it occurs sooner", ); is( $Union1->coerce($arr), $arr, "Union1 cannot coerce an arrayref", ); like( exception { $Union1->coercion->add_type_coercions(ArrayRef, q[ scalar(@$_) ]) }, qr/^Adding coercions to Type::Coercion::Union not currently supported/, "Cannot add to Type::Tiny::Union's coercion", ); done_testing; assert.t000644001750001750 236713601673061 20067 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Library=pod =encoding utf-8 =head1 PURPOSE Checks that the assertion functions exported by a type library work as expected. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use BiggerLib qw( :assert ); ok assert_String("rats"), "assert_String works (value that should pass)"; like( exception { assert_String([]) }, qr{^is not a string}, "assert_String works (value that should fail)" ); ok BiggerLib::assert_String("rats"), "BiggerLib::assert_String works (value that should pass)"; like( exception { BiggerLib::assert_String([]) }, qr{^is not a string}, "BiggerLib::assert_String works (value that should fail)" ); ok assert_SmallInteger(5), "assert_SmallInteger works (value that should pass)"; like( exception { assert_SmallInteger([]) }, qr{^ARRAY\(\w+\) is too big}, "assert_SmallInteger works (value that should fail)" ); done_testing; deprecation.t000644001750001750 321513601673061 21054 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Library=pod =encoding utf-8 =head1 PURPOSE Checks Type::Library warns about deprecated types. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2018-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Test::TypeTiny; use Type::Tiny; BEGIN { package Local::Library; use Type::Library -base; my $t1 = Type::Tiny->new(name => "Base"); my $t2 = Type::Tiny->new(name => "Derived_1", parent => $t1); my $t3 = Type::Tiny->new(name => "Derived_2", parent => $t1, deprecated => 1); my $t4 = Type::Tiny->new(name => "Double_Derived_1", parent => $t3); my $t5 = Type::Tiny->new(name => "Double_Derived_2", parent => $t3, deprecated => 0); __PACKAGE__->meta->add_type($_) for $t1, $t2, $t3, $t4, $t5; $INC{'Local/Library.pm'} = __FILE__; }; { my @WARNINGS; sub get_warnings { [@WARNINGS] } sub reset_warnings { @WARNINGS = () } $SIG{__WARN__} = sub { push @WARNINGS, $_[0] }; }; reset_warnings(); eval q{ package Local::Example1; use Local::Library qw(Derived_1); 1; } or die($@); is_deeply(get_warnings(), []); reset_warnings(); eval q{ package Local::Example2; use Local::Library qw(Derived_2); 1; } or die($@); like(get_warnings()->[0], qr/^Exporting deprecated type Derived_2 to package Local::Example2/); reset_warnings(); eval q{ package Local::Example3; use Local::Library -allow_deprecated, qw(Derived_2); 1; } or die($@); is_deeply(get_warnings(), []); done_testing; errors.t000644001750001750 223613601673061 20075 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Library=pod =encoding utf-8 =head1 PURPOSE Tests errors thrown by L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Type::Library -base; use Type::Tiny; my $e1 = exception { my $m = __PACKAGE__->meta; $m->add_type(name => 'Foo'); $m->add_type(name => 'Foo'); }; like( $e1, qr/^Type Foo already exists in this library/, 'cannot add same type constraint twice', ); my $e2 = exception { my $m = __PACKAGE__->meta; $m->add_type(constraint => sub { 0 }); }; like( $e2, qr/^Cannot add anonymous type to a library/, 'cannot add an anonymous type constraint to a library', ); my $e3 = exception { my $m = __PACKAGE__->meta; $m->add_coercion(name => 'Foo'); }; like( $e3, qr/^Coercion Foo conflicts with type of same name/, 'cannot add a coercion with same name as a constraint', ); done_testing; import-params.t000644001750001750 326013601673061 21352 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Library=pod =encoding utf-8 =head1 PURPOSE Checks C<< of >> and C<< where >> import options works. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Test::TypeTiny; BEGIN { package MyTypes; use Type::Library -base; $INC{'MyTypes.pm'} = __FILE__; __PACKAGE__->add_type( name => 'Ref', constraint => sub { ref $_[0] }, constraint_generator => sub { my $x = shift; sub { ref $_[0] eq $x }; }, ); }; use MyTypes 'Ref'; should_pass([], Ref); should_pass({}, Ref); should_pass(sub {}, Ref); should_fail(1, Ref); should_pass([], Ref['ARRAY']); should_fail({}, Ref['ARRAY']); should_fail(sub {}, Ref['ARRAY']); should_fail(1, Ref['ARRAY']); should_pass({}, Ref['HASH']); should_fail([], Ref['HASH']); should_fail(sub {}, Ref['HASH']); should_fail(1, Ref['HASH']); use MyTypes Ref => { of => 'HASH', -as => 'HashRef' }; should_pass({}, HashRef); should_fail([], HashRef); should_fail(sub {}, HashRef); should_fail(1, HashRef); use MyTypes Ref => { where => sub { ref $_[0] eq 'ARRAY' or ref $_[0] eq 'HASH' }, -as => 'ContainerRef', }; should_pass({}, ContainerRef); should_pass([], ContainerRef); should_fail(sub {}, ContainerRef); should_fail(1, ContainerRef); use MyTypes is_Ref => { of => 'HASH', -as => 'is_HashRef' }; ok is_HashRef({}); ok !is_HashRef([]); ok !is_HashRef(sub {}); ok !is_HashRef(1); done_testing; inheritance.t000644001750001750 546613601673061 21062 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Library=pod =encoding utf-8 =head1 PURPOSE Checks that it's possible to extend existing type libraries. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( . ./t ../inc ./inc ); use utf8; use Test::More; use Test::Requires { Encode => 0 }; use Test::TypeTiny; BEGIN { package Local::Types; use Type::Library -base; use Type::Utils -all; extends 'Types::Standard'; declare "Foo", as "Str"; $INC{'Local/Types.pm'} = __FILE__; }; use Local::Types -all; use Type::Utils; my $chars = "Café Paris|Garçon"; my $bytes_utf8 = Encode::encode("utf-8", $chars); my $bytes_western = Encode::encode("iso-8859-1", $chars); is(length($chars), 17, 'length $chars == 17'); is(length($bytes_utf8), 19, 'length $bytes_utf8 == 19'); is(length($bytes_western), 17, 'length $bytes_western == 17'); my $SplitSpace = (ArrayRef[Str])->plus_coercions(Split[qr/\s/]); my $SplitPipe = (ArrayRef[Foo])->plus_coercions(Split[qr/\|/]); ok($SplitSpace->can_be_inlined, '$SplitSpace can be inlined'); ok($SplitPipe->can_be_inlined, '$SplitPipe can be inlined'); is_deeply( $SplitSpace->coerce($chars), [ "Café", "Paris|Garçon" ], '$SplitSpace->coerce($chars)', ); is_deeply( $SplitSpace->coerce($bytes_utf8), [ map Encode::encode("utf-8", $_), "Café", "Paris|Garçon" ], '$SplitSpace->coerce($bytes_utf8)', ); is_deeply( $SplitSpace->coerce($bytes_western), [ map Encode::encode("iso-8859-1", $_), "Café", "Paris|Garçon" ], '$SplitSpace->coerce($bytes_western)', ); should_pass($SplitSpace->coerce($chars), ArrayRef[Str]); should_pass($SplitSpace->coerce($bytes_utf8), ArrayRef[Str]); should_pass($SplitSpace->coerce($bytes_western), ArrayRef[Str]); is_deeply( my $arr_chars = $SplitPipe->coerce($chars), [ "Café Paris", "Garçon" ], '$SplitPipe->coerce($chars)', ); is_deeply( my $arr_bytes_utf8 = $SplitPipe->coerce($bytes_utf8), [ map Encode::encode("utf-8", $_), "Café Paris", "Garçon" ], '$SplitPipe->coerce($bytes_utf8)', ); is_deeply( my $arr_bytes_western = $SplitPipe->coerce($bytes_western), [ map Encode::encode("iso-8859-1", $_), "Café Paris", "Garçon" ], '$SplitPipe->coerce($bytes_western)', ); my $JoinPipe = Foo->plus_coercions(Join["|"]); is( $_ = $JoinPipe->coerce($arr_chars), $chars, '$JoinPipe->coerce($arr_chars)', ); should_pass($_, Str); is( $_ = $JoinPipe->coerce($arr_bytes_utf8), $bytes_utf8, '$JoinPipe->coerce($arr_bytes_utf8)', ); should_pass($_, Str); is( $_ = $JoinPipe->coerce($arr_bytes_western), $bytes_western, '$JoinPipe->coerce($arr_bytes_western)', ); should_pass($_, Str); done_testing; is.t000644001750001750 222713601673061 17174 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Library=pod =encoding utf-8 =head1 PURPOSE Checks that the check functions exported by a type library work as expected. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use BiggerLib qw( :is ); ok is_String("rats"), "is_String works (value that should pass)"; ok !is_String([]), "is_String works (value that should fail)"; ok is_Number(5.5), "is_Number works (value that should pass)"; ok !is_Number("rats"), "is_Number works (value that should fail)"; ok is_Integer(5), "is_Integer works (value that should pass)"; ok !is_Integer(5.5), "is_Integer works (value that should fail)"; ok is_SmallInteger(5), "is_SmallInteger works (value that should pass)"; ok !is_SmallInteger(12), "is_SmallInteger works (value that should fail)"; done_testing; to.t000644001750001750 166213601673061 17205 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Library=pod =encoding utf-8 =head1 PURPOSE Checks that the coercion functions exported by a type library work as expected. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal qw(dies_ok); use BiggerLib qw(:to); is( to_BigInteger(8), 18, 'to_BigInteger converts a small integer OK' ); is( to_BigInteger(17), 17, 'to_BigInteger leaves an existing BigInteger OK' ); is( to_BigInteger(3.14), 3.14, 'to_BigInteger ignores something it cannot coerce' ); dies_ok { to_Str [] } "no coercion for Str - should die"; done_testing; types.t000644001750001750 454313601673061 17730 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Library=pod =encoding utf-8 =head1 PURPOSE Checks that the type functions exported by a type library work as expected. =head1 DEPENDENCIES Uses the bundled DemoLib.pm type library. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use DemoLib -types; isa_ok String, "Type::Tiny", "String"; isa_ok Number, "Type::Tiny", "Number"; isa_ok Integer, "Type::Tiny", "Integer"; isa_ok DemoLib::String, "Type::Tiny", "DemoLib::String"; isa_ok DemoLib::Number, "Type::Tiny", "DemoLib::Number"; isa_ok DemoLib::Integer, "Type::Tiny", "DemoLib::Integer"; is(String."", "String", "String has correct stringification"); is(Number."", "Number", "Number has correct stringification"); is(Integer."", "Integer", "Integer has correct stringification"); is(DemoLib::String."", "String", "DemoLib::String has correct stringification"); is(DemoLib::Number."", "Number", "DemoLib::Number has correct stringification"); is(DemoLib::Integer."", "Integer", "DemoLib::Integer has correct stringification"); is( exception { Integer->(5) }, undef, "coderef overload (with value that should pass type constraint) does not die", ); is( Integer->(5), 5, "coderef overload returns correct value", ); like( exception { Integer->(5.5) }, qr{^Value "5\.5" did not pass type constraint "Integer"}, "coderef overload (value that should fail type constraint) dies", ); use DemoLib String => { -prefix => "foo", -as => "bar", -suffix => "baz", }; is(foobarbaz->qualified_name, "DemoLib::String", "Sub::Exporter-style export renaming"); ok( Integer eq Integer, 'eq works', ); use Types::Standard qw(ArrayRef Int); my $int = Int; my $arrayref = ArrayRef; my $arrayref_int = ArrayRef[Int]; is_deeply( [ 1, 2, Int, 3, 4 ], [ 1, 2, $int, 3, 4 ], 'type constant in list context', ); is_deeply( [ 1, 2, ArrayRef, 3, 4 ], [ 1, 2, $arrayref, 3, 4 ], 'parameterizable type constant in list context', ); is_deeply( [ 1, 2, ArrayRef[Int], 3, 4 ], [ 1, 2, $arrayref_int, 3, 4 ], 'parameterized type constant in list context', ); done_testing; badsigs.t000644001750001750 205013601673061 20006 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Check that people doing silly things with Test::Params get =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params qw( compile ); use Types::Standard qw( Optional Int ArrayRef slurpy ); like( exception { compile(Optional[Int], Int) }, qr{^Non-Optional parameter following Optional parameter}, "Cannot follow an optional parameter with a required parameter", ); like( exception { compile(slurpy ArrayRef[Int], Optional[Int]) }, qr{^Parameter following slurpy parameter}, "Cannot follow a slurpy parameter with anything", ); like( exception { compile(slurpy Int) }, qr{^Slurpy parameter not of type HashRef or ArrayRef}, "Slurpy parameters must be hashrefs or arrayrefs", ); done_testing; carping.t000644001750001750 165013601673061 20022 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test L' interaction with L: use Type::Params compile => { confess => 1 }; =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params compile => { confess => 1 }; use Types::Standard qw(Int); my $check; #line 1 "testsub1.chunk" sub testsub1 { $check ||= compile(Int); [ $check->(@_) ]; } #line 1 "testsub2.chunk" sub testsub2 { testsub1(@_); } #line 52 "params-carping.t" my $e = exception { testsub2(1.1); }; isa_ok($e, 'Error::TypeTiny'); like( $e, qr{^Value "1\.1" did not pass type constraint "Int" \(in \$_\[0\]\)}, ); done_testing; coerce.t000644001750001750 303713601673061 17640 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test L usage of types with coercions. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params qw(compile); use Types::Standard -types, "slurpy"; use Type::Utils; use Scalar::Util qw(refaddr); my $RoundedInt = declare as Int; coerce $RoundedInt, from Num, q{ int($_) }; my $chk = compile(Int, $RoundedInt, Num); is_deeply( [ $chk->(1, 2, 3.3) ], [ 1, 2, 3.3 ] ); is_deeply( [ $chk->(1, 2.2, 3.3) ], [ 1, 2, 3.3 ] ); like( exception { $chk->(1.1, 2.2, 3.3) }, qr{^Value "1\.1" did not pass type constraint "Int" \(in \$_\[0\]\)}, ); my $chk2 = compile(ArrayRef[$RoundedInt]); is_deeply( [ $chk2->([1, 2, 3]) ], [ [1, 2, 3] ] ); is_deeply( [ $chk2->([1.1, 2.2, 3.3]) ], [ [1, 2, 3] ] ); is_deeply( [ $chk2->([1.1, 2, 3.3]) ], [ [1, 2, 3] ] ); my $arr = [ 1 ]; my $arr2 = [ 1.1 ]; is( refaddr( [$chk2->($arr)]->[0] ), refaddr($arr), 'if value passes type constraint; no need to clone arrayref' ); isnt( refaddr( [$chk2->($arr2)]->[0] ), refaddr($arr2), 'if value fails type constraint; need to clone arrayref' ); my $chk3 = compile($RoundedInt->no_coercions); like( exception { $chk3->(1.1) }, qr{^Value "1\.1" did not pass type constraint}, ); done_testing; compile-named-bless.t000644001750001750 2477113601673061 22250 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test L' brand spanking new C function. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params qw(compile_named validate_named); use Types::Standard -types, "slurpy"; use Type::Utils; use Scalar::Util qw(refaddr); { package # hide Type::Tiny::_Test::Blessed; sub new { bless $_[1], 'Type::Tiny::_Test::Constructed' } sub new2 { bless $_[1], 'Type::Tiny::_Test::Constructed2' } } sub simple_test { my ($name, @spec) = @_; unshift @spec, my $opts = {}; my $expected_class = undef; local $Test::Builder::Level = $Test::Builder::Level + 1; subtest $name => sub { subtest "bless => CLASS" => sub { %$opts = (bless => 'Type::Tiny::_Test::Blessed'); $expected_class = 'Type::Tiny::_Test::Blessed'; _simple_test( validate_named => $expected_class, sub { validate_named(\@_, $opts, @spec) } ); _simple_test( compile_named => $expected_class, compile_named($opts, @spec) ); }; subtest "class => CLASS" => sub { %$opts = (class => 'Type::Tiny::_Test::Blessed'); $expected_class = 'Type::Tiny::_Test::Constructed'; _simple_test( validate_named => $expected_class, sub { validate_named(\@_, $opts, @spec) } ); _simple_test( compile_named => $expected_class, compile_named($opts, @spec) ); }; subtest "class => [CLASS, METHOD]" => sub { %$opts = (class => ['Type::Tiny::_Test::Blessed', 'new2']); $expected_class = 'Type::Tiny::_Test::Constructed2'; _simple_test( validate_named => $expected_class, sub { validate_named(\@_, $opts, @spec) } ); _simple_test( compile_named => $expected_class, compile_named($opts, @spec) ); }; subtest "class => CLASS, constructor METHOD" => sub { %$opts = (class => 'Type::Tiny::_Test::Blessed', constructor => 'new2'); $expected_class = 'Type::Tiny::_Test::Constructed2'; _simple_test( validate_named => $expected_class, sub { validate_named(\@_, $opts, @spec) } ); _simple_test( compile_named => $expected_class, compile_named($opts, @spec) ); }; }; } sub slurpy_test { my ($name, @spec) = @_; unshift @spec, my $opts = {}; my $expected_class = undef; local $Test::Builder::Level = $Test::Builder::Level + 1; subtest $name => sub { subtest "bless => CLASS" => sub { %$opts = (bless => 'Type::Tiny::_Test::Blessed'); $expected_class = 'Type::Tiny::_Test::Blessed'; _slurpy_test( validate_named => $expected_class, sub { validate_named(\@_, $opts, @spec) } ); _slurpy_test( compile_named => $expected_class, compile_named($opts, @spec) ); }; subtest "class => CLASS" => sub { %$opts = (class => 'Type::Tiny::_Test::Blessed'); $expected_class = 'Type::Tiny::_Test::Constructed'; _slurpy_test( validate_named => $expected_class, sub { validate_named(\@_, $opts, @spec) } ); _slurpy_test( compile_named => $expected_class, compile_named($opts, @spec) ); }; subtest "class => [CLASS, METHOD]" => sub { %$opts = (class => ['Type::Tiny::_Test::Blessed', 'new2']); $expected_class = 'Type::Tiny::_Test::Constructed2'; _slurpy_test( validate_named => $expected_class, sub { validate_named(\@_, $opts, @spec) } ); _slurpy_test( compile_named => $expected_class, compile_named($opts, @spec) ); }; subtest "class => CLASS, constructor METHOD" => sub { %$opts = (class => 'Type::Tiny::_Test::Blessed', constructor => 'new2'); $expected_class = 'Type::Tiny::_Test::Constructed2'; _slurpy_test( validate_named => $expected_class, sub { validate_named(\@_, $opts, @spec) } ); _slurpy_test( compile_named => $expected_class, compile_named($opts, @spec) ); }; }; } sub _simple_test { my ($name, $expected_class, $check) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; subtest $name, sub { is_deeply( $check->( foo => 3, bar => 42 ), bless({ foo => 3, bar => 42 }, $expected_class), 'accept a hash', ); is_deeply( $check->( foo => 3, bar => 42, baz => [1..3] ), bless({ foo => 3, bar => 42, baz => [1..3] }, $expected_class), 'accept a hash, with optional parameter', ); is_deeply( $check->( foo => 3.1, bar => 42 ), bless({ foo => 3, bar => 42 }, $expected_class), 'accept a hash, and coerce', ); is_deeply( $check->( foo => 3.1, bar => 42, baz => [1..3, 4.2] ), bless({ foo => 3, bar => 42, baz => [1..4] }, $expected_class), 'accept a hash, with optional parameter, and coerce', ); is_deeply( $check->({ foo => 3, bar => 42 }), bless({ foo => 3, bar => 42 }, $expected_class), 'accept a hashref', ); is_deeply( $check->({ foo => 3, bar => 42, baz => [1..3] }), bless({ foo => 3, bar => 42, baz => [1..3] }, $expected_class), 'accept a hashref, with optional parameter', ); is_deeply( $check->({ foo => 3.1, bar => 42 }), bless({ foo => 3, bar => 42 }, $expected_class), 'accept a hashref, and coerce', ); is_deeply( $check->({ foo => 3.1, bar => 42, baz => [1..3, 4.2] }), bless({ foo => 3, bar => 42, baz => [1..4] }, $expected_class), 'accept a hashref, with optional parameter, and coerce', ); like( exception { $check->({ foo => [], bar => 42 }) }, qr/^Reference \[\] did not pass type constraint/, 'bad "foo" parameter', ); like( exception { $check->({ foo => 3, bar => [] }) }, qr/^Reference \[\] did not pass type constraint/, 'bad "bar" parameter', ); like( exception { $check->({ foo => {}, bar => [] }) }, qr/^Reference \{\} did not pass type constraint/, 'two bad parameters; "foo" throws before "bar" gets a chance', ); like( exception { $check->({ foo => 3, bar => 42, baz => {} }) }, qr/^Reference \{\} did not pass type constraint/, 'bad optional "baz" parameter', ); like( exception { $check->({ foo => 3, bar => 42, xxx => 1 }) }, qr/^Unrecognized parameter: xxx/, 'additional parameter', ); like( exception { $check->({ foo => 3, bar => 42, xxx => 1, yyy => 2, zzz => 3 }) }, qr/^Unrecognized parameters: xxx, yyy, and zzz/, 'additional parameters', ); like( exception { $check->({ }) }, qr/^Missing required parameter: foo/, 'missing parameter', ); }; } sub _slurpy_test { my ($name, $expected_class, $check) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; subtest $name, sub { is_deeply( $check->( foo => 3, bar => 42 ), bless({ XXX => {}, foo => 3, bar => 42 }, $expected_class), 'accept a hash', ); is_deeply( $check->( foo => 3, bar => 42, baz => [1..3] ), bless({ XXX => {}, foo => 3, bar => 42, baz => [1..3] }, $expected_class), 'accept a hash, with optional parameter', ); is_deeply( $check->( foo => 3.1, bar => 42 ), bless({ XXX => {}, foo => 3, bar => 42 }, $expected_class), 'accept a hash, and coerce', ); is_deeply( $check->( foo => 3.1, bar => 42, baz => [1..3, 4.2] ), bless({ XXX => {}, foo => 3, bar => 42, baz => [1..4] }, $expected_class), 'accept a hash, with optional parameter, and coerce', ); is_deeply( $check->({ foo => 3, bar => 42 }), bless({ XXX => {}, foo => 3, bar => 42 }, $expected_class), 'accept a hashref', ); is_deeply( $check->({ foo => 3, bar => 42, baz => [1..3] }), bless({ XXX => {}, foo => 3, bar => 42, baz => [1..3] }, $expected_class), 'accept a hashref, with optional parameter', ); is_deeply( $check->({ foo => 3.1, bar => 42 }), bless({ XXX => {}, foo => 3, bar => 42 }, $expected_class), 'accept a hashref, and coerce', ); is_deeply( $check->({ foo => 3.1, bar => 42, baz => [1..3, 4.2] }), bless({ XXX => {}, foo => 3, bar => 42, baz => [1..4] }, $expected_class), 'accept a hashref, with optional parameter, and coerce', ); like( exception { $check->({ foo => [], bar => 42 }) }, qr/^Reference \[\] did not pass type constraint/, 'bad "foo" parameter', ); like( exception { $check->({ foo => 3, bar => [] }) }, qr/^Reference \[\] did not pass type constraint/, 'bad "bar" parameter', ); like( exception { $check->({ foo => {}, bar => [] }) }, qr/^Reference \{\} did not pass type constraint/, 'two bad parameters; "foo" throws before "bar" gets a chance', ); like( exception { $check->({ foo => 3, bar => 42, baz => {} }) }, qr/^Reference \{\} did not pass type constraint/, 'bad optional "baz" parameter', ); is_deeply( $check->({ foo => 3, bar => 42, xxx => 1 }), { XXX => { xxx => 1 }, foo => 3, bar => 42 }, 'additional parameter', ); is_deeply( $check->({ foo => 3, bar => 42, xxx => 1, yyy => 2, zzz => 3 }), { XXX => { xxx => 1, yyy => 2, zzz => 3 }, foo => 3, bar => 42 }, 'additional parameters', ); is_deeply( $check->({ foo => 3, bar => 42, xxx => 1.1, yyy => 2.2, zzz => 3 }), { XXX => { xxx => 1, yyy => 2, zzz => 3 }, foo => 3, bar => 42 }, 'coercion of additional parameters', ); like( exception { $check->({ }) }, qr/^Missing required parameter: foo/, 'missing parameter', ); }; } my $Rounded; $Rounded = Int->plus_coercions(Num, q{ int($_) }); simple_test( "simple test with everything inlineable", foo => $Rounded, bar => Int, baz => Optional[ArrayRef->of($Rounded)], ); $Rounded = Int->plus_coercions(Num, sub { int($_) }); simple_test( "simple test with inlineable types, but non-inlineable coercion", foo => $Rounded, bar => Int, baz => Optional[ArrayRef->of($Rounded)], ); $Rounded = Int->where(sub { !!1 })->plus_coercions(Num, sub { int($_) }); simple_test( "simple test with everything non-inlineable", foo => $Rounded, bar => Int->where(sub { !!1 }), baz => Optional[ArrayRef->of($Rounded)], ); $Rounded = Int->plus_coercions(Num, q{ int($_) }); slurpy_test( "slurpy test with everything inlineable", foo => $Rounded, bar => Int, baz => Optional[ArrayRef->of($Rounded)], XXX => slurpy HashRef[$Rounded], ); $Rounded = Int->plus_coercions(Num, sub { int($_) }); slurpy_test( "slurpy test with inlineable types, but non-inlineable coercion", foo => $Rounded, bar => Int, baz => Optional[ArrayRef->of($Rounded)], XXX => slurpy HashRef[$Rounded], ) if 0; $Rounded = Int->where(sub { !!1 })->plus_coercions(Num, sub { int($_) }); slurpy_test( "slurpy test with everything non-inlineable", foo => $Rounded, bar => Int->where(sub { !!1 }), baz => Optional[ArrayRef->of($Rounded)], XXX => slurpy HashRef[$Rounded], ) if 0; done_testing; compile-named-oo.t000644001750001750 514213601673061 21524 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test L C function. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2018-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params qw( compile_named_oo ); use Types::Standard qw( -types ); my $coderef = compile_named_oo( foo => Int, bar => Optional[Int], baz => Optional[HashRef], { getter => 'bazz', predicate => 'haz' }, ); ok(CodeRef->check($coderef), 'compile_named_oo returns a coderef'); my @object; $object[0] = $coderef->( foo => 42, bar => 69, baz => { quux => 666 } ); $object[1] = $coderef->({ foo => 42, bar => 69, baz => { quux => 666 } }); $object[2] = $coderef->( foo => 42 ); $object[3] = $coderef->({ foo => 42 }); for my $i (0 .. 1) { ok(Object->check($object[$i]), "\$object[$i] is an object"); can_ok($object[$i], qw( foo bar has_bar bazz haz )); is($object[$i]->foo, 42, "\$object[$i]->foo == 42"); is($object[$i]->bar, 69, "\$object[$i]->bar == 69"); is($object[$i]->bazz->{quux}, 666, "\$object[$i]->bazz->{quux} == 666"); ok($object[$i]->has_bar, "\$object[$i]->has_bar"); ok($object[$i]->haz, "\$object[$i]->haz"); ok(! $object[$i]->can("has_foo"), 'no has_foo method'); ok(! $object[$i]->can("has_baz"), 'no has_baz method'); } for my $i (2 .. 3) { ok(Object->check($object[$i]), "\$object[$i] is an object"); can_ok($object[$i], qw( foo bar has_bar bazz haz )); is($object[$i]->foo, 42, "\$object[$i]->foo == 42"); is($object[$i]->bar, undef, "not defined \$object[$i]->bar"); is($object[$i]->bazz, undef, "not defined \$object[$i]->bazz"); ok(! $object[$i]->has_bar, "!\$object[$i]->has_bar"); ok(! $object[$i]->haz, "!\$object[$i]->haz"); ok(! $object[$i]->can("has_foo"), 'no has_foo method'); ok(! $object[$i]->can("has_baz"), 'no has_baz method'); } my $e = exception { compile_named_oo( 999 => Int ); }; ok(Object->check($e), 'exception thrown for bad accessor name'); like($e->message, qr/bad accessor name/i, 'correct message'); my $coderef2 = compile_named_oo( bar => Optional[ArrayRef], baz => Optional[CodeRef], { getter => 'bazz', predicate => 'haz' }, foo => Num, ); my $coderef2obj = $coderef2->(foo => 1.1, bar => []); is(ref($object[0]), ref($coderef2obj), 'packages reused when possible'); my $details = compile_named_oo( { want_details => 1 }, fooble => Int ); like($details->{source}, qr/fooble/, 'want_details'); done_testing; compile-named.t000644001750001750 1753413601673061 21141 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test L' brand spanking new C function. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params qw(compile_named validate_named); use Types::Standard -types, "slurpy"; use Type::Utils; use Scalar::Util qw(refaddr); { package Type::Tiny::_Test::X; sub new { bless $_[1], $_[0] } } sub simple_test { my ($name, @spec) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; subtest $name => sub { _simple_test( validate_named => sub { validate_named(\@_, @spec) } ); _simple_test( compile_named => compile_named(@spec) ); }; } sub slurpy_test { my ($name, @spec) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; subtest $name => sub { _slurpy_test( validate_named => sub { validate_named(\@_, @spec) } ); _slurpy_test( compile_named => compile_named(@spec) ); }; } sub _simple_test { my ($name, $check) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; subtest $name, sub { is_deeply( $check->( foo => 3, bar => 42 ), { foo => 3, bar => 42 }, 'accept a hash', ); is_deeply( $check->( foo => 3, bar => 42, baz => [1..3] ), { foo => 3, bar => 42, baz => [1..3] }, 'accept a hash, with optional parameter', ); is_deeply( $check->( foo => 3.1, bar => 42 ), { foo => 3, bar => 42 }, 'accept a hash, and coerce', ); is_deeply( $check->( foo => 3.1, bar => 42, baz => [1..3, 4.2] ), { foo => 3, bar => 42, baz => [1..4] }, 'accept a hash, with optional parameter, and coerce', ); is_deeply( $check->({ foo => 3, bar => 42 }), { foo => 3, bar => 42 }, 'accept a hashref', ); is_deeply( $check->({ foo => 3, bar => 42, baz => [1..3] }), { foo => 3, bar => 42, baz => [1..3] }, 'accept a hashref, with optional parameter', ); is_deeply( $check->({ foo => 3.1, bar => 42 }), { foo => 3, bar => 42 }, 'accept a hashref, and coerce', ); is_deeply( $check->({ foo => 3.1, bar => 42, baz => [1..3, 4.2] }), { foo => 3, bar => 42, baz => [1..4] }, 'accept a hashref, with optional parameter, and coerce', ); like( exception { $check->({ foo => [], bar => 42 }) }, qr/^Reference \[\] did not pass type constraint/, 'bad "foo" parameter', ); like( exception { $check->({ foo => 3, bar => [] }) }, qr/^Reference \[\] did not pass type constraint/, 'bad "bar" parameter', ); like( exception { $check->({ foo => {}, bar => [] }) }, qr/^Reference \{\} did not pass type constraint/, 'two bad parameters; "foo" throws before "bar" gets a chance', ); like( exception { $check->({ foo => 3, bar => 42, baz => {} }) }, qr/^Reference \{\} did not pass type constraint/, 'bad optional "baz" parameter', ); like( exception { $check->({ foo => 3, bar => 42, xxx => 1 }) }, qr/^Unrecognized parameter: xxx/, 'additional parameter', ); like( exception { $check->({ foo => 3, bar => 42, xxx => 1, yyy => 2, zzz => 3 }) }, qr/^Unrecognized parameters: xxx, yyy, and zzz/, 'additional parameters', ); like( exception { $check->({ }) }, qr/^Missing required parameter: foo/, 'missing parameter', ); }; } sub _slurpy_test { my ($name, $check) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; subtest $name, sub { is_deeply( $check->( foo => 3, bar => 42 ), { XXX => {}, foo => 3, bar => 42 }, 'accept a hash', ); is_deeply( $check->( foo => 3, bar => 42, baz => [1..3] ), { XXX => {}, foo => 3, bar => 42, baz => [1..3] }, 'accept a hash, with optional parameter', ); is_deeply( $check->( foo => 3.1, bar => 42 ), { XXX => {}, foo => 3, bar => 42 }, 'accept a hash, and coerce', ); is_deeply( $check->( foo => 3.1, bar => 42, baz => [1..3, 4.2] ), { XXX => {}, foo => 3, bar => 42, baz => [1..4] }, 'accept a hash, with optional parameter, and coerce', ); is_deeply( $check->({ foo => 3, bar => 42 }), { XXX => {}, foo => 3, bar => 42 }, 'accept a hashref', ); is_deeply( $check->({ foo => 3, bar => 42, baz => [1..3] }), { XXX => {}, foo => 3, bar => 42, baz => [1..3] }, 'accept a hashref, with optional parameter', ); is_deeply( $check->({ foo => 3.1, bar => 42 }), { XXX => {}, foo => 3, bar => 42 }, 'accept a hashref, and coerce', ); is_deeply( $check->({ foo => 3.1, bar => 42, baz => [1..3, 4.2] }), { XXX => {}, foo => 3, bar => 42, baz => [1..4] }, 'accept a hashref, with optional parameter, and coerce', ); like( exception { $check->({ foo => [], bar => 42 }) }, qr/^Reference \[\] did not pass type constraint/, 'bad "foo" parameter', ); like( exception { $check->({ foo => 3, bar => [] }) }, qr/^Reference \[\] did not pass type constraint/, 'bad "bar" parameter', ); like( exception { $check->({ foo => {}, bar => [] }) }, qr/^Reference \{\} did not pass type constraint/, 'two bad parameters; "foo" throws before "bar" gets a chance', ); like( exception { $check->({ foo => 3, bar => 42, baz => {} }) }, qr/^Reference \{\} did not pass type constraint/, 'bad optional "baz" parameter', ); is_deeply( $check->({ foo => 3, bar => 42, xxx => 1 }), { XXX => { xxx => 1 }, foo => 3, bar => 42 }, 'additional parameter', ); is_deeply( $check->({ foo => 3, bar => 42, xxx => 1, yyy => 2, zzz => 3 }), { XXX => { xxx => 1, yyy => 2, zzz => 3 }, foo => 3, bar => 42 }, 'additional parameters', ); is_deeply( $check->({ foo => 3, bar => 42, xxx => 1.1, yyy => 2.2, zzz => 3 }), { XXX => { xxx => 1, yyy => 2, zzz => 3 }, foo => 3, bar => 42 }, 'coercion of additional parameters', ); like( exception { $check->({ }) }, qr/^Missing required parameter: foo/, 'missing parameter', ); }; } my $Rounded; $Rounded = Int->plus_coercions(Num, q{ int($_) }); simple_test( "simple test with everything inlineable", foo => $Rounded, bar => Int, baz => Optional[ArrayRef->of($Rounded)], ); $Rounded = Int->plus_coercions(Num, sub { int($_) }); simple_test( "simple test with inlineable types, but non-inlineable coercion", foo => $Rounded, bar => Int, baz => Optional[ArrayRef->of($Rounded)], ); $Rounded = Int->where(sub { !!1 })->plus_coercions(Num, sub { int($_) }); simple_test( "simple test with everything non-inlineable", foo => $Rounded, bar => Int->where(sub { !!1 }), baz => Optional[ArrayRef->of($Rounded)], ); $Rounded = Int->plus_coercions(Num, q{ int($_) }); slurpy_test( "slurpy test with everything inlineable", foo => $Rounded, bar => Int, baz => Optional[ArrayRef->of($Rounded)], XXX => slurpy HashRef[$Rounded], ); $Rounded = Int->plus_coercions(Num, sub { int($_) }); slurpy_test( "slurpy test with inlineable types, but non-inlineable coercion", foo => $Rounded, bar => Int, baz => Optional[ArrayRef->of($Rounded)], XXX => slurpy HashRef[$Rounded], ); $Rounded = Int->where(sub { !!1 })->plus_coercions(Num, sub { int($_) }); slurpy_test( "slurpy test with everything non-inlineable", foo => $Rounded, bar => Int->where(sub { !!1 }), baz => Optional[ArrayRef->of($Rounded)], XXX => slurpy HashRef[$Rounded], ); subtest "Shortcuts for Any and Optional[Any]" => sub { my $chk = compile_named(foo => 1, bar => 0); is( exception { $chk->(foo => "xyz") }, undef, ); is( exception { $chk->(foo => "xyz", bar => "abc") }, undef, ); like( exception { $chk->(foo => "xyz", bar => "abc", baz => "def") }, qr/Unrecognized parameter/, ); like( exception { $chk->(bar => "abc") }, qr/^Missing required parameter/, ); }; done_testing; defaults.t000644001750001750 624013601673061 20206 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test C and C support defaults for parameters. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2018-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use Test::More; use Test::Fatal; use Types::Standard -types; use Type::Params qw( compile compile_named ); my @rv; is( exception { @rv = compile(Int, { default => 42 } )->() }, undef, 'compile: no exception thrown because of defaulted argument' ); is_deeply( \@rv, [42], 'compile: default applied correctly' ); @rv = (); is( exception { @rv = compile(Int, { default => sub { 42 } } )->() }, undef, 'compile: no exception thrown because of defaulted argument via coderef' ); is_deeply( \@rv, [42], 'compile: default applied correctly via coderef' ); @rv = (); is( exception { @rv = compile(ArrayRef, { default => [] } )->() }, undef, 'compile: no exception thrown because of defaulted argument via arrayref' ); is_deeply( \@rv, [[]], 'compile: default applied correctly via arrayref' ); @rv = (); is( exception { @rv = compile(HashRef, { default => {} } )->() }, undef, 'compile: no exception thrown because of defaulted argument via hashref' ); is_deeply( \@rv, [{}], 'compile: default applied correctly via hashref' ); @rv = (); is( exception { @rv = compile(Any, { default => undef } )->() }, undef, 'compile: no exception thrown because of defaulted argument via undef' ); is_deeply( \@rv, [undef], 'compile: default applied correctly via undef' ); @rv = (); is( exception { @rv = compile_named(thing => Int, { default => 42 } )->() }, undef, 'compile_named: no exception thrown because of defaulted argument' ); is_deeply( \@rv, [{ thing => 42 }], 'compile_named: default applied correctly' ); @rv = (); is( exception { @rv = compile_named(thing => Int, { default => sub { 42 } } )->() }, undef, 'compile_named: no exception thrown because of defaulted argument via coderef' ); is_deeply( \@rv, [{ thing => 42 }], 'compile_named: default applied correctly via coderef' ); @rv = (); is( exception { @rv = compile_named(thing => ArrayRef, { default => [] } )->() }, undef, 'compile_named: no exception thrown because of defaulted argument via arrayref' ); is_deeply( \@rv, [{ thing => [] }], 'compile_named: default applied correctly via arrayref' ); @rv = (); is( exception { @rv = compile_named(thing => HashRef, { default => {} } )->() }, undef, 'compile_named: no exception thrown because of defaulted argument via hashref' ); is_deeply( \@rv, [{ thing => {} }], 'compile_named: default applied correctly via hashref' ); @rv = (); is( exception { @rv = compile_named(thing => Any, { default => undef } )->() }, undef, 'compile_named: no exception thrown because of defaulted argument via undef' ); is_deeply( \@rv, [{ thing => undef }], 'compile_named: default applied correctly via undef' ); like( exception { compile(HashRef, { default => \*STDOUT } ) }, qr/Default expected to be/, 'compile: exception because bad default' ); done_testing; hashorder.t000644001750001750 320413601673061 20353 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test L' brand spanking new C function. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params qw(compile_named); use Types::Standard qw(Int); subtest "predictable error message when problems with two parameters" => sub { for my $i (1..20) { my $check1 = compile_named( a => Int, b => Int ); my $check2 = compile_named( b => Int, a => Int ); like( exception { $check1->() }, qr/Missing required parameter: a/, "Iteration $i, check 1, missing parameters", ); like( exception { $check1->(a => [], b => {}) }, qr/Reference \[\] did not pass type constraint "Int"/, "Iteration $i, check 1, invalid values", ); like( exception { $check1->(a => 1, b => 2, c => '3PO', r2d => 2) }, qr/Unrecognized parameters: c and r2d/, "Iteration $i, check 1, extra values", ); like( exception { $check2->() }, qr/Missing required parameter: b/, "Iteration $i, check 2, missing parameters", ); like( exception { $check2->(a => [], b => {}) }, qr/Reference \{\} did not pass type constraint "Int"/, "Iteration $i, check 2, invalid values", ); like( exception { $check2->(a => 1, b => 2, c => '3PO', r2d => 2) }, qr/Unrecognized parameters: c and r2d/, "Iteration $i, check 2, extra values", ); } }; done_testing; methods.t000644001750001750 334113601673061 20041 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test L usage for method calls. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; { package Silly::String; use Type::Params qw(Invocant compile); use Types::Standard qw(ClassName Object Str Int); my %chk; sub new { $chk{new} ||= compile(ClassName, Str); my ($class, $str) = $chk{new}->(@_); bless \$str, $class; } sub repeat { $chk{repeat} ||= compile(Object, Int); my ($self, $n) = $chk{repeat}->(@_); $self->get x $n; } sub get { $chk{get} ||= compile(Object); my ($self) = $chk{get}->(@_); $$self; } sub set { $chk{set} ||= compile(Invocant, Str); my ($proto, $str) = $chk{set}->(@_); Object->check($proto) ? ($$proto = $str) : $proto->new($str); } } is( exception { my $o = Silly::String->new("X"); is($o->get, "X"); is($o->repeat(4), "XXXX"); $o->set("Y"); is($o->repeat(4), "YYYY"); my $p = Silly::String->set("Z"); is($p->repeat(4), "ZZZZ"); }, undef, 'clean operation', ); like( exception { Silly::String::new() }, qr{^Wrong number of parameters; got 0; expected 2}, 'exception calling new() with no args', ); like( exception { Silly::String->new() }, qr{^Wrong number of parameters; got 1; expected 2}, 'exception calling ->new() with no args', ); like( exception { Silly::String::set() }, qr{^Wrong number of parameters; got 0; expected 2}, 'exception calling set() with no args', ); done_testing; mixednamed.t000644001750001750 201513601673061 20506 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test L usage with mix of positional and named parameters. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params qw(compile); use Types::Standard -types, "slurpy"; my $chk = compile(ClassName, slurpy Dict[ foo => Int, bar => Str, baz => ArrayRef, ]); is_deeply( [ $chk->("Type::Tiny", foo => 1, bar => "Hello", baz => []) ], [ "Type::Tiny", { foo => 1, bar => "Hello", baz => [] } ] ); is_deeply( [ $chk->("Type::Tiny", bar => "Hello", baz => [], foo => 1) ], [ "Type::Tiny", { foo => 1, bar => "Hello", baz => [] } ] ); like( exception { $chk->("Type::Tiny", foo => 1, bar => "Hello") }, qr{did not pass type constraint "Dict}, ); done_testing; multisig-custom-message.t000644001750001750 453713601673061 23175 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Make sure that custom C messages work. =head1 AUTHOR Benct Philip Jonsson Ebpjonsson@gmail.comE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2018-2019 by Benct Philip Jonsson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params qw( multisig ); use Types::Standard qw( Optional Str Int Bool Dict slurpy ); sub _maybe_slurpy { my @sig = @_; $sig[-1] = slurpy $sig[-1]; return ( [@_], \@sig ); } my $foo_args; sub foo { $foo_args ||= multisig( { description => "parameter validation for foo()", message => 'USAGE: foo($string [, \%options|%options])', }, _maybe_slurpy( Str, Dict[ bool => Optional[Bool], num => Optional[Int] ] ), ); return $foo_args->(@_); } my $bar_args; sub bar { $bar_args ||= multisig( { description => "parameter validation for bar()", message => 'USAGE: bar()', }, [], ); return $bar_args->(@_); } my @tests = ( [ 'bar(1)' => sub { bar( 1 ) }, 'USAGE: bar()', undef ], [ 'bar()' => sub { bar() }, "", 0 ], [ 'foo($string, num => "x")' => sub { foo( "baz", num => "x" ) }, 'USAGE: foo($string [, \\%options|%options])', 0, ], [ 'foo([], num => 42)' => sub { foo( [], num => 42 ) }, 'USAGE: foo($string [, \\%options|%options])', 0, ], [ 'foo($string, quux => 0)' => sub { foo( "baz", quux => 0 ) }, 'USAGE: foo($string [, \\%options|%options])', 0, ], [ 'foo($string, [])' => sub { foo( "baz", [] ) }, 'USAGE: foo($string [, \\%options|%options])', 0, ], [ 'foo($string, bool => 1)', sub { is_deeply [ foo( "baz", bool => 1 ) ], [ "baz", { bool => 1 } ], 'slurpy options'; }, "", 1, ], [ 'foo($string, { bool => 1 })', sub { is_deeply [ foo( "baz", { bool => 1 } ) ], [ "baz", { bool => 1 } ], 'hashref options'; }, "", 0 ], [ 'foo($string)', sub { is_deeply [ foo( "baz" ) ], [ "baz", {} ], 'no options'; }, "", 1 ], ); for my $test ( @tests ) { no warnings 'uninitialized'; my($name, $code, $expected, $sig) = @$test; like( exception { $code->() }, qr/\A\Q$expected/, $name); is ${^TYPE_PARAMS_MULTISIG}, $sig, "$name \${^TYPE_PARAMS_MULTISIG}"; } done_testing; multisig.t000644001750001750 510513601673061 20233 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test L C function. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. Portions by Diab Jerius Edjerius@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params qw( multisig compile validate ); use Types::Standard qw( -types slurpy ); my $Rounded = Int->plus_coercions(Num, 'int($_)'); my $sig = multisig( [ Int, ArrayRef[$Rounded] ], [ ArrayRef[$Rounded], Int ], [ HashRef[Num] ], ); is_deeply( [ $sig->( 1, [2,3,4] ) ], [ 1, [2,3,4] ], 'first choice in multi, no coercion, should pass', ); is( ${^TYPE_PARAMS_MULTISIG}, 0, '...${^TYPE_PARAMS_MULTISIG}', ); is_deeply( [ $sig->( 1, [2.2,3.3,4.4] ) ], [ 1, [2,3,4] ], 'first choice in multi, coercion, should pass', ); is( ${^TYPE_PARAMS_MULTISIG}, 0, '...${^TYPE_PARAMS_MULTISIG}', ); like( exception { $sig->( 1.1, [2.2,3.3,4.4] ) }, qr{^Parameter validation failed}, 'first choice in multi, should fail', ); is_deeply( [ $sig->( [2,3,4], 1 ) ], [ [2,3,4], 1 ], 'second choice in multi, no coercion, should pass', ); is( ${^TYPE_PARAMS_MULTISIG}, 1, '...${^TYPE_PARAMS_MULTISIG}', ); is_deeply( [ $sig->( [2.2,3.3,4.4], 1 ) ], [ [2,3,4], 1 ], 'second choice in multi, coercion, should pass', ); is( ${^TYPE_PARAMS_MULTISIG}, 1, '...${^TYPE_PARAMS_MULTISIG}', ); like( exception { $sig->( [2.2,3.3,4.4], 1.1 ) }, qr{^Parameter validation failed}, 'second choice in multi, should fail', ); is_deeply( [ $sig->( { a => 1.1, b => 7 } ) ], [ { a => 1.1, b => 7 } ], 'third choice in multi, no coercion, should pass', ); is( ${^TYPE_PARAMS_MULTISIG}, 2, '...${^TYPE_PARAMS_MULTISIG}', ); like( exception { $sig->( { a => 1.1, b => 7, c => "Hello" } ) }, qr{^Parameter validation failed}, 'third choice in multi, should fail', ); my $a = Dict [ a => Num ]; my $b = Dict [ b => Num ]; is exception { validate( [ { a => 3 } ], $a ); validate( [ a => 3 ], slurpy $a ); }, undef; is exception { my $check = multisig( [ $a ], [ $b ] ); $check->( { a => 3 } ); $check->( { b => 3 } ); }, undef; is exception { my $check = multisig( [ slurpy $a ], [ slurpy $b ] ); $check->( a => 3 ); $check->( b => 3 ); }, undef; is exception { my $check = multisig( compile(slurpy $a), compile(slurpy $b) ); $check->( a => 3 ); $check->( b => 3 ); }, undef; done_testing; named-to-list.t000644001750001750 347013601673061 21056 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test L usage with named parameters and C. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Types::Standard qw(Int); use Type::Params qw(compile_named); my $check1 = compile_named( { named_to_list => 1 }, foo => Int, bar => Int, ); is_deeply( [$check1->(foo => 1, bar => 2)], [1, 2], ); is_deeply( [$check1->(bar => 2, foo => 1)], [1, 2], ); is_deeply( [$check1->(bar => 2, foo => 99)], [99, 2], ); my $check2 = compile_named( { named_to_list => 1 }, foo => Int, bar => Int, baz => Int, { optional => 1 }, ); is_deeply( [$check2->(foo => 1, bar => 2)], [1, 2, undef], ); is_deeply( [$check2->(bar => 2, foo => 1)], [1, 2, undef], ); is_deeply( [$check2->(bar => 2, foo => 99)], [99, 2, undef], ); is_deeply( [$check2->(baz => 666, foo => 1, bar => 2)], [1, 2, 666], ); is_deeply( [$check2->(bar => 2, baz => 666, foo => 1)], [1, 2, 666], ); is_deeply( [$check2->(bar => 2, foo => 99, baz => 666)], [99, 2, 666], ); my $check3 = compile_named( { named_to_list => [qw(baz bar)] }, foo => Int, bar => Int, baz => Int, { optional => 1 }, ); is_deeply( [$check3->(foo => 1, bar => 2)], [undef, 2], ); is_deeply( [$check3->(bar => 2, foo => 1)], [undef, 2], ); is_deeply( [$check3->(bar => 2, foo => 99)], [undef, 2], ); is_deeply( [$check3->(baz => 666, foo => 1, bar => 2)], [666, 2], ); is_deeply( [$check3->(bar => 2, baz => 666, foo => 1)], [666, 2], ); is_deeply( [$check3->(bar => 2, foo => 99, baz => 666)], [666, 2], ); done_testing; named.t000644001750001750 231113601673061 17456 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test L usage with named parameters. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params qw(compile); use Types::Standard -types, "slurpy"; my $chk = compile slurpy Dict[ foo => Int, bar => Str, baz => ArrayRef, ]; is_deeply( [ $chk->(foo => 1, bar => "Hello", baz => []) ], [ { foo => 1, bar => "Hello", baz => [] } ] ); is_deeply( [ $chk->(bar => "Hello", baz => [], foo => 1) ], [ { foo => 1, bar => "Hello", baz => [] } ] ); like( exception { $chk->(foo => 1, bar => "Hello") }, qr{did not pass type constraint "Dict}, ); my $chk2 = compile slurpy Dict[ foo => Int, bar => Str, baz => Optional[ArrayRef], ]; is_deeply( [ $chk2->(foo => 1, bar => "Hello") ], [ { foo => 1, bar => "Hello" } ] ); like( exception { $chk2->(foo => 1, bar => "Hello", zab => []) }, qr{did not pass type constraint "Dict}, ); done_testing; noninline.t000644001750001750 344113601673061 20370 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test L with type constraints that cannot be inlined. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params qw(compile); use Types::Standard qw(Num ArrayRef); use Type::Utils; my $NumX = declare NumX => as Num, where { $_ != 42 }; my $check; sub nth_root { $check ||= compile( $NumX, $NumX ); [ $check->(@_) ]; } is_deeply( nth_root(1, 2), [ 1, 2 ], '(1, 2)', ); is_deeply( nth_root("1.1", 2), [ "1.1", 2 ], '(1.1, 2)', ); { my $e = exception { nth_root() }; like($e, qr{^Wrong number of parameters; got 0; expected 2}, '()'); } { my $e = exception { nth_root(1) }; like($e, qr{^Wrong number of parameters; got 1; expected 2}, '(1)'); } { my $e = exception { nth_root(undef, 1) }; like($e, qr{^Undef did not pass type constraint "NumX" \(in \$_\[0\]\)}, '(undef, 1)'); } { my $e = exception { nth_root(41, 42) }; like($e, qr{^Value "42" did not pass type constraint "NumX" \(in \$_\[1\]\)}, '(42)'); } my $check2; sub nth_root_coerce { $check2 ||= compile( $NumX->plus_coercions( Num, sub { 21 }, # non-inline ArrayRef, q { scalar(@$_) }, # inline ), $NumX, ); [ $check2->(@_) ]; } is_deeply( nth_root_coerce(42, 11), [21, 11], '(42, 11)' ); is_deeply( nth_root_coerce([1..3], 11), [3, 11], '([1..3], 11)' ); { my $e = exception { nth_root_coerce([1..41], 42) }; like($e, qr{^Value "42" did not pass type constraint "NumX" \(in \$_\[1\]\)}, '([1..41], 42)'); } done_testing; optional.t000644001750001750 344413601673061 20227 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test L usage with optional parameters. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params qw(compile); use Types::Standard -types; my $chk1 = compile(Num, Optional[Int], Optional[ArrayRef], Optional[HashRef]); my $chk2 = compile(Num, Int, {optional=>1}, ArrayRef, {optional=>1}, HashRef, {optional=>1}); my $chk3 = compile(Num, Int, {optional=>1}, Optional[ArrayRef], HashRef, {optional=>1}); my $chk4 = compile(Num, Int, {optional=>1}, Optional[ArrayRef], {optional=>1}, HashRef, {optional=>1}); my $chk5 = compile(Num, {optional=>0}, Optional[Int], Optional[ArrayRef], Optional[HashRef]); for my $chk ($chk1, $chk2, $chk3, $chk4, $chk5) { is_deeply( [ $chk->(1.1, 2, [], {}) ], [ 1.1, 2, [], {} ] ); is_deeply( [ $chk->(1.1, 2, []) ], [ 1.1, 2, [] ] ); is_deeply( [ $chk->(1.1, 2) ], [ 1.1, 2 ] ); is_deeply( [ $chk->(1.1) ], [ 1.1 ] ); like( exception { $chk->(1.1, 2, {}) }, qr{^Reference \{\} did not pass type constraint "(Optional\[)?ArrayRef\]?" \(in \$_\[2\]\)}, ); like( exception { $chk->() }, qr{^Wrong number of parameters; got 0; expected 1 to 4}, ); like( exception { $chk->(1 .. 5) }, qr{^Wrong number of parameters; got 5; expected 1 to 4}, ); like( exception { $chk->(1, 2, undef) }, qr{^Undef did not pass type constraint}, ); } my $chk99 = compile(1, 0, 0); like( exception { $chk99->() }, qr{^Wrong number of parameters; got 0; expected 1 to 3}, ); done_testing; positional.t000644001750001750 253313601673061 20561 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test L positional parameters, a la the example in the documentation: sub nth_root { state $check = compile( Num, Num ); my ($x, $n) = $check->(@_); return $x ** (1 / $n); } =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params qw(compile); use Types::Standard qw(Num); my $check; sub nth_root { $check ||= compile( Num, Num ); [ $check->(@_) ]; } is_deeply( nth_root(1, 2), [ 1, 2 ], '(1, 2)', ); is_deeply( nth_root("1.1", 2), [ "1.1", 2 ], '(1.1, 2)', ); { my $e = exception { nth_root() }; like($e, qr{^Wrong number of parameters; got 0; expected 2}, '(1)'); } { my $e = exception { nth_root(1) }; like($e, qr{^Wrong number of parameters; got 1; expected 2}, '(1)'); } { my $e = exception { nth_root(undef, 1) }; like($e, qr{^Undef did not pass type constraint "Num" \(in \$_\[0\]\)}, '(undef, 1)'); } { my $e = exception { nth_root(1, 2, 3) }; like($e, qr{^Wrong number of parameters; got 3; expected 2}, '(1)'); } done_testing; slurpy.t000644001750001750 276113601673061 17741 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test L usage with slurpy parameters. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Params qw(compile); use Types::Standard -types, "slurpy"; my $chk = compile(Str, slurpy HashRef[Int]); is_deeply( [ $chk->("Hello", foo => 1, bar => 2) ], [ "Hello", { foo => 1, bar => 2 } ] ); is_deeply( [ $chk->("Hello", { foo => 1, bar => 2 }) ], [ "Hello", { foo => 1, bar => 2 } ] ); like( exception { $chk->("Hello", foo => 1, bar => 2.1) }, qr{did not pass type constraint "HashRef\[Int\]" \(in \$SLURPY\)}, ); my $chk2 = compile(Str, slurpy HashRef); is_deeply( [ $chk2->("Hello", foo => 1, bar => 2) ], [ "Hello", { foo => 1, bar => 2 } ] ); is_deeply( [ $chk2->("Hello", { foo => 1, bar => 2 }) ], [ "Hello", { foo => 1, bar => 2 } ] ); like( exception { $chk2->("Hello", foo => 1, "bar") }, qr{^Odd number of elements in HashRef}, ); my $chk3 = compile(Str, slurpy Map); like( exception { $chk3->("Hello", foo => 1, "bar") }, qr{^Odd number of elements in Map}, ); my $chk4 = compile(Str, slurpy Tuple[Str, Int, Str]); is_deeply( [ $chk4->("Hello", foo => 1, "bar") ], [ Hello => [qw/ foo 1 bar /] ], ); done_testing; wrap.t000644001750001750 726213601673061 17355 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Params=pod =encoding utf-8 =head1 PURPOSE Test C and C from L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; { package Local::Test1; use Types::Standard qw( Str Int Num ArrayRef ); use Type::Params qw( wrap_subs wrap_methods compile_named ); sub abc { return @_; } sub xyz { return @_; } wrap_subs( abc => [Int, Int, Int], uvw => [Str], # wraps sub {} xyz => compile_named({ subname => 'xyz' }, x => Int, y => Int, z => Int), ); } subtest "simple use of wrap_subs" => sub { is_deeply( [ Local::Test1::abc(1, 2, 3) ], [ 1, 2, 3 ], ); is_deeply( [Local::Test1::uvw('hello world')], [], ); is_deeply( [ Local::Test1::xyz(x => 1, y => 2, z => 3) ], [{ x => 1, y => 2, z => 3 }], ); my $e = exception { Local::Test1::abc(1, 2), }; like($e, qr/Wrong number of parameters/); $e = exception { Local::Test1::uvw({}), }; like($e, qr/Reference \{\} did not pass type constraint "Str" \(in \$_\[0]\)/); $e = exception { Local::Test1::xyz(x => 1, y => 2, z => []), }; like($e, qr/Reference \[\] did not pass type constraint "Int" \(in \$_\{"z"\}\)/); }; { package Local::Test2; use Types::Standard qw( Str Int Num ArrayRef ); use Type::Params qw( wrap_subs wrap_methods compile_named ); sub abc { return @_; } sub def { return @_; } sub xyz { return @_; } wrap_methods( abc => [Int, Int, Int], uvw => [Str], # wraps sub {} xyz => compile_named({ subname => 'xyz' }, x => Int, y => Int, z => Int), ); } subtest "simple use of wrap_methods" => sub { is_deeply( [ Local::Test2->abc(1, 2, 3) ], [ 'Local::Test2', 1, 2, 3 ], ); is_deeply( [ Local::Test2->uvw('hello world') ], [], ); is_deeply( [ Local::Test2->xyz(x => 1, y => 2, z => 3) ], [ 'Local::Test2', { x => 1, y => 2, z => 3 }], ); my $e = exception { Local::Test2->abc(1, 2), }; like($e, qr/Wrong number of parameters/); $e = exception { Local::Test2->uvw({}), }; like($e, qr/Reference \{\} did not pass type constraint "Str" \(in \$_\[0]\)/); $e = exception { Local::Test2->xyz(x => 1, y => 2, z => []), }; like($e, qr/Reference \[\] did not pass type constraint "Int" \(in \$_\{"z"\}\)/); }; { package Local::Test3; our @ISA = 'Local::Test2'; use Types::Standard qw( Str Int Num ArrayRef ); use Type::Params qw( wrap_subs wrap_methods compile_named ); my $Even = Int->where(q{ $_ % 2 == 0 }); wrap_methods( abc => [$Even, $Even, $Even], def => [Num], # inherited ); } subtest "wrap_methods with inheritance" => sub { is_deeply( [ Local::Test3->abc(2, 4, 6) ], [ 'Local::Test3', 2, 4, 6 ], ); is_deeply( [ Local::Test3->def(3.1) ], [ 'Local::Test3', 3.1 ], ); is_deeply( [ Local::Test3->uvw('hello world') ], [], ); is_deeply( [ Local::Test3->xyz(x => 1, y => 2, z => 3) ], [ 'Local::Test3', { x => 1, y => 2, z => 3 }], ); my $e = exception { Local::Test3->abc(1, 2, 2), }; like($e, qr/Value "1" did not pass type constraint \(in \$_\[0\]\)/); $e = exception { Local::Test3->def({}), }; like($e, qr/Reference \{\} did not pass type constraint "Num" \(in \$_\[0]\)/); $e = exception { Local::Test3->uvw({}), }; like($e, qr/Reference \{\} did not pass type constraint "Str" \(in \$_\[0]\)/); $e = exception { Local::Test3->xyz(x => 1, y => 2, z => []), }; like($e, qr/Reference \[\] did not pass type constraint "Int" \(in \$_\{"z"\}\)/); }; done_testing; basic.t000644001750001750 1621613601673061 17515 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Parser=pod =encoding utf-8 =head1 PURPOSE Checks Type::Parser works. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use Test::Fatal; use Type::Parser qw( _std_eval parse extract_type ); use Types::Standard qw( -types slurpy ); use Type::Utils; sub types_equal { my ($a, $b) = map { ref($_) ? $_ : _std_eval($_) } @_[0, 1]; my ($A, $B) = map { $_->inline_check('$X') } ($a, $b); my $msg = "$_[0] eq $_[1]"; $msg = "$msg - $_[2]" if $_[2]; @_ = ($A, $B, $msg); goto \&Test::More::is; } note "Basics"; types_equal("Int", Int); types_equal("(Int)", Int, "redundant parentheses"); types_equal("((((Int))))", Int, "many redundant parentheses"); note "Class types"; types_equal("DateTime::", InstanceOf["DateTime"]); types_equal("InstanceOf['DateTime']", InstanceOf["DateTime"]); types_equal("Tied[Foo::]", Tied["Foo"]); types_equal("Tied['Foo']", Tied["Foo"]); note "Parameterization"; types_equal("Int[]", Int, "empty parameterization against non-parameterizable type"); types_equal("Tuple[]", Tuple[], "empty parameterization against parameterizble type"); types_equal("ArrayRef[]", ArrayRef, "empty parameterization against parameterizable type"); types_equal("ArrayRef[Int]", ArrayRef[Int], "parameterized type"); types_equal("Ref['HASH']", Ref['HASH'], "string parameter (singles)"); types_equal("Ref[\"HASH\"]", Ref['HASH'], "string parameter (doubles)"); types_equal("Ref[q(HASH)]", Ref['HASH'], "string parameter (q)"); types_equal("Ref[qq(HASH)]", Ref['HASH'], "string parameter (qq)"); types_equal("StrMatch[qr{foo}]", StrMatch[qr{foo}], "regexp parameter"); note "Unions"; types_equal("Int|HashRef", Int|HashRef); types_equal("Int|HashRef|ArrayRef", Int|HashRef|ArrayRef); types_equal("ArrayRef[Int|HashRef]", ArrayRef[Int|HashRef], "union as a parameter"); types_equal("ArrayRef[Int|HashRef[Int]]", ArrayRef[Int|HashRef[Int]]); types_equal("ArrayRef[HashRef[Int]|Int]", ArrayRef[HashRef([Int]) | Int]); note "Intersections"; types_equal("Int&Num", Int & Num); types_equal("Int&Num&Defined", Int & Num & Defined); types_equal("ArrayRef[Int]&Defined", (ArrayRef[Int]) & Defined); note "Union + Intersection"; types_equal("Int&Num|ArrayRef", (Int & Num) | ArrayRef); types_equal("(Int&Num)|ArrayRef", (Int & Num) | ArrayRef); types_equal("Int&(Num|ArrayRef)", Int & (Num | ArrayRef)); types_equal("Int&Num|ArrayRef&Ref", intersection([Int, Num]) | intersection([ArrayRef, Ref])); note "Complementary types"; types_equal("~Int", ~Int); types_equal("~ArrayRef[Int]", ArrayRef([Int])->complementary_type); types_equal("~Int|CodeRef", (~Int)|CodeRef); types_equal("~(Int|CodeRef)", ~(Int|CodeRef), 'precedence of "~" versus "|"'); note "Comma"; types_equal("Map[Num,Int]", Map[Num,Int]); types_equal("Map[Int,Num]", Map[Int,Num]); types_equal("Map[Int,Int|ArrayRef[Int]]", Map[Int,Int|ArrayRef[Int]]); types_equal("Map[Int,ArrayRef[Int]|Int]", Map[Int,ArrayRef([Int])|Int]); types_equal("Dict[foo=>Int,bar=>Num]", Dict[foo=>Int,bar=>Num]); types_equal("Dict['foo'=>Int,'bar'=>Num]", Dict[foo=>Int,bar=>Num]); types_equal("Dict['foo',Int,'bar',Num]", Dict[foo=>Int,bar=>Num]); note "Slurpy"; types_equal("Dict[slurpy=>Int,bar=>Num]", Dict[slurpy=>Int,bar=>Num]); types_equal("Tuple[Str, Int, slurpy ArrayRef[Int]]", Tuple[Str, Int, slurpy ArrayRef[Int]]); types_equal("Tuple[Str, Int, slurpy(ArrayRef[Int])]", Tuple[Str, Int, slurpy ArrayRef[Int]]); note "Complexity"; types_equal( "ArrayRef[DateTime::]|HashRef[Int|DateTime::]|CodeRef", ArrayRef([InstanceOf["DateTime"]]) | HashRef([Int|InstanceOf["DateTime"]]) | CodeRef ); types_equal( "ArrayRef [DateTime::] |HashRef[ Int|\tDateTime::]|CodeRef ", ArrayRef([InstanceOf["DateTime"]]) | HashRef([Int|InstanceOf["DateTime"]]) | CodeRef, "gratuitous whitespace", ); note "Bad expressions"; like( exception { _std_eval('%hello') }, qr{^Unexpected token in primary type expression; got '%hello'}, 'weird token' ); like( exception { _std_eval('Str Int') }, qr{^Unexpected tail on type expression: Int}, 'weird stuff 1' ); like( exception { _std_eval('ArrayRef(Int)') }, qr{^Unexpected tail on type expression: .Int.}, 'weird stuff 2' ); note "Tail retention"; my ($ast, $remaining) = parse("ArrayRef [DateTime::] |HashRef[ Int|\tDateTime::]|CodeRef monkey nuts "); is($remaining, " monkey nuts ", "remainder is ok"); ($ast, $remaining) = parse("Int, Str"); is($remaining, ", Str", "comma can indicate beginning of remainder"); require Type::Registry; my $type; my $reg = Type::Registry->new; $reg->add_types( -Standard ); ($type, $remaining) = extract_type('ArrayRef [ Int ] yah', $reg); types_equal($type, ArrayRef[Int], 'extract_type works'); like($remaining, qr/\A\s?yah\z/, '... and provides proper remainder too'); note "Parsing edge cases"; is_deeply( scalar parse('Xyzzy[Foo]'), { 'type' => 'parameterized', 'base' => { 'type' => 'primary', 'token' => bless( [ 'TYPE', 'Xyzzy' ], 'Type::Parser::Token' ), }, 'params' => { 'type' => 'list', 'list' => [ { 'type' => 'primary', 'token' => bless( [ 'TYPE', 'Foo' ], 'Type::Parser::Token' ), } ], }, }, 'Xyzzy[Foo] - parameter is treated as a type constraint' ); is_deeply( scalar parse('Xyzzy["Foo"]'), { 'type' => 'parameterized', 'base' => { 'type' => 'primary', 'token' => bless( [ 'TYPE', 'Xyzzy' ], 'Type::Parser::Token' ), }, 'params' => { 'type' => 'list', 'list' => [ { 'type' => 'primary', 'token' => bless( [ 'QUOTELIKE', '"Foo"' ], 'Type::Parser::Token' ), } ], }, }, 'Xyzzy["Foo"] - parameter is treated as a string' ); is_deeply( scalar parse('Xyzzy[-100]'), { 'type' => 'parameterized', 'base' => { 'type' => 'primary', 'token' => bless( [ 'TYPE', 'Xyzzy' ], 'Type::Parser::Token' ), }, 'params' => { 'type' => 'list', 'list' => [ { 'type' => 'primary', 'token' => bless( [ 'STRING', '-100' ], 'Type::Parser::Token' ), } ], }, }, 'Xyzzy[-100] - parameter is treated as a string' ); is_deeply( scalar parse('Xyzzy[200]'), { 'type' => 'parameterized', 'base' => { 'type' => 'primary', 'token' => bless( [ 'TYPE', 'Xyzzy' ], 'Type::Parser::Token' ), }, 'params' => { 'type' => 'list', 'list' => [ { 'type' => 'primary', 'token' => bless( [ 'STRING', '200' ], 'Type::Parser::Token' ), } ], }, }, 'Xyzzy[200] - parameter is treated as a string' ); is_deeply( scalar parse('Xyzzy[+20.0]'), { 'type' => 'parameterized', 'base' => { 'type' => 'primary', 'token' => bless( [ 'TYPE', 'Xyzzy' ], 'Type::Parser::Token' ), }, 'params' => { 'type' => 'list', 'list' => [ { 'type' => 'primary', 'token' => bless( [ 'STRING', '+20.0' ], 'Type::Parser::Token' ), } ], }, }, 'Xyzzy[+20.0] - parameter is treated as a string' ); done_testing; moosextypes.t000644001750001750 176213601673061 21013 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Parser=pod =encoding utf-8 =head1 PURPOSE Checks Type::Parser can pick up MooseX::Types type constraints. =head1 DEPENDENCIES Requires L 2.0201 and L 0.001004; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { 'Moose' => '2.0201' }; use Test::Requires { 'MooseX::Types::Common' => '0.001004' }; use Test::TypeTiny; use Test::Fatal; use Type::Parser qw(_std_eval parse); use Types::Standard qw(-types slurpy); use Type::Utils; my $type = _std_eval("ArrayRef[MooseX::Types::Common::Numeric::PositiveInt]"); should_pass([1,2,3], $type); should_pass([], $type); should_fail([1,-2,3], $type); done_testing; automagic.t000644001750001750 145413601673061 20737 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Registry=pod =encoding utf-8 =head1 PURPOSE Checks Type::Registry->for_class is automagically populated. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Types::Common::Numeric PositiveOrZeroInt => { -as => 'NonNegativeInt' }; ok( !$INC{'Type/Registry.pm'}, 'Type::Registry is not automatically loaded', ); require Type::Registry; my $reg = Type::Registry->for_me; ok( $reg->lookup('NonNegativeInt') == NonNegativeInt, 'Type::Registry was auto-populated', ); done_testing; basic.t000644001750001750 610713601673061 20047 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Registry=pod =encoding utf-8 =head1 PURPOSE Checks Type::Registry works. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use Test::Fatal; { package Local::Pkg1; use Type::Registry "t"; ::is(t(), Type::Registry->for_me, 'Type::Registry->for_me works'); ::is(t(), Type::Registry->for_class(__PACKAGE__), 'Type::Registry->for_class works'); t->add_types(-Standard); ::like( ::exception { t->add_types(-MonkeyNutsAndChimpanzeeRaisins) }, qr{^Types::MonkeyNutsAndChimpanzeeRaisins is not a type library}, 'cannot add non-existant type library to registry', ); t->alias_type(Int => "Integer"); ::like( ::exception { t->alias_type(ChimpanzeeRaisins => "ChimpSultanas") }, qr{^Expected existing type constraint name}, 'cannot alias non-existant type in registry', ); ::ok(t->Integer == Types::Standard::Int(), 'alias works'); ::ok(t("Integer") == Types::Standard::Int(), 'alias works via simple_lookup'); ::ok(t("Integer[]") == Types::Standard::Int(), 'alias works via lookup'); } { package Local::Pkg2; use Type::Registry "t"; t->add_types(-Standard => [ -types => { -prefix => 'XYZ_' } ]); ::ok(t->XYZ_Int == Types::Standard::Int(), 'prefix works'); } ok( exception { Local::Pkg2::t->lookup("Integer") }, 'type registries are separate', ); my $no_e = exception { do { my $obj = Type::Registry->new; }; # DESTROY called }; is($no_e, undef, 'DESTROY does not cause problems'); my $r = Type::Registry->for_class("Local::Pkg1"); should_pass([1, 2, 3], $r->lookup("ArrayRef[Integer]")); should_fail([1, 2, 3.14159], $r->lookup("ArrayRef[Integer]")); like( exception { $r->lookup('%foo') }, qr{^Unexpected token in primary type expression; got '\%foo'}, 'type constraint invalid syntax', ); like( exception { $r->lookup('MonkeyNuts') }, qr{^MonkeyNuts is not a known type constraint }, 'type constraint unknown type', ); like( exception { $r->MonkeyNuts }, qr{^Can't locate object method "MonkeyNuts" via package}, 'type constraint unknown type (as method call)', ); is( $r->lookup('MonkeyNuts::')->class, 'MonkeyNuts', 'class type', ); require Type::Tiny::Enum; $r->add_type('Type::Tiny::Enum'->new(values => [qw/Monkey Nuts/]), 'MonkeyNuts'); my $mn = $r->lookup('MonkeyNuts'); should_pass('Monkey', $mn); should_pass('Nuts', $mn); should_fail('Cashews', $mn); use Type::Utils qw(dwim_type role_type class_type); is( dwim_type('MonkeyNuts')->class, 'MonkeyNuts', 'DWIM - class type', ); is( dwim_type('MonkeyNuts', does => 1)->role, 'MonkeyNuts', 'DWIM - role type', ); is( dwim_type('ArrayRef[MonkeyNuts | Foo::]', does => 1)->inline_check('$X'), Types::Standard::ArrayRef()->parameterize(role_type({role=>"MonkeyNuts"}) | class_type({class=>"Foo"}))->inline_check('$X'), 'DWIM - complex type', ); done_testing; methods.t000644001750001750 356013601673061 20431 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Registry=pod =encoding utf-8 =head1 PURPOSE Checks various newish Type::Registry method calls. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use Test::Fatal; use Type::Registry qw( t ); use Types::Standard -types; sub types_equal { my ($a, $b) = map { ref($_) ? $_ : do { require Type::Parser; Type::Parser::_std_eval($_) } } @_[0, 1]; my ($A, $B) = map { $_->inline_check('$X') } ($a, $b); my $msg = "$_[0] eq $_[1]"; $msg = "$msg - $_[2]" if $_[2]; @_ = ($A, $B, $msg); goto \&Test::More::is; } t->add_types( -Standard ); types_equal( t->make_class_type("Foo"), InstanceOf["Foo"], 't->make_class_type', ); types_equal( t->make_role_type("Foo"), ConsumerOf["Foo"], 't->make_role_type', ); types_equal( t->make_union(t->ArrayRef, t->Int), ArrayRef|Int, 't->make_union', ); types_equal( t->make_intersection(t->ArrayRef, t->Int), ArrayRef() &+ Int(), 't->make_intersection', ); my $type = t->foreign_lookup('Types::Common::Numeric::PositiveInt'); should_pass(420, $type); should_fail(-42, $type); t->add_type($type); should_pass(420, t->PositiveInt); should_fail(-42, t->PositiveInt); t->add_type($type, 'PossyWossy1'); should_pass(420, t->PossyWossy1); should_fail(-42, t->PossyWossy1); t->add_type($type->create_child_type, 'PossyWossy2'); should_pass(420, t->PossyWossy2); should_fail(-42, t->PossyWossy2); like( exception { t->add_type($type->create_child_type) }, qr/^Expected named type constraint; got anonymous type constraint/, 'cannot add an anonymous type without giving it an alias', ); done_testing; moosextypes.t000644001750001750 217613601673061 21367 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Registry=pod =encoding utf-8 =head1 PURPOSE Checks Type::Registry works with MooseX::Types. =head1 DEPENDENCIES Requires L 2.0201 and L 0.001004; kipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { 'Moose' => '2.0201' }; use Test::Requires { 'MooseX::Types::Common' => '0.001004' }; use Test::TypeTiny; use Test::Fatal; use Type::Registry 't'; t->add_types(-Standard); my $ucstrs = t->lookup('ArrayRef[MooseX::Types::Common::String::UpperCaseStr]'); should_pass([], $ucstrs); should_pass(['FOO', 'BAR'], $ucstrs); should_fail(['FOO', 'Bar'], $ucstrs); t->add_types('MooseX::Types::Common::Numeric'); should_pass(8, t->SingleDigit); should_pass(9, t->SingleDigit); should_fail(10, t->SingleDigit); should_pass(10, t->PositiveInt); done_testing; mousextypes.t000644001750001750 206613601673061 21373 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Registry=pod =encoding utf-8 =head1 PURPOSE Checks Type::Registry works with MouseX::Types. =head1 DEPENDENCIES Requires L 0.001000; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { 'MouseX::Types::Common' => '0.001000' }; use Test::TypeTiny; use Test::Fatal; use Type::Registry 't'; t->add_types(-Standard); my $nestr = t->lookup('ArrayRef[MouseX::Types::Common::String::NonEmptyStr]'); should_pass([], $nestr); should_pass(['FOO', 'BAR'], $nestr); should_fail(['FOO', ''], $nestr); t->add_types('MouseX::Types::Common::Numeric'); should_pass(8, t->SingleDigit); should_pass(9, t->SingleDigit); should_fail(10, t->SingleDigit); should_pass(10, t->PositiveInt); done_testing; arithmetic.t000644001750001750 1136013601673061 20247 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny=pod =encoding utf-8 =head1 PURPOSE Tests overloading of bitwise operators and numeric comparison operators for L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use Types::Standard -all; my $var = 123; should_fail(\$var, ~ScalarRef); should_fail([], ~ArrayRef); should_fail(+{}, ~HashRef); should_fail(sub {0}, ~CodeRef); should_fail(\*STDOUT, ~GlobRef); should_fail(\(\"Hello"), ~Ref); should_fail(\*STDOUT, ~FileHandle); should_fail(qr{x}, ~RegexpRef); should_fail(1, ~Str); should_fail(1, ~Num); should_fail(1, ~Int); should_fail(1, ~Defined); should_fail(1, ~Value); should_fail(undef, ~Undef); should_fail(undef, ~Item); should_fail(undef, ~Any); should_fail('Type::Tiny', ~ClassName); should_fail('Type::Library', ~RoleName); should_fail(undef, ~Bool); should_fail('', ~Bool); should_fail(0, ~Bool); should_fail(1, ~Bool); should_pass(7, ~Bool); should_fail(\(\"Hello"), ~ScalarRef); should_pass('Type::Tiny', ~RoleName); should_pass([], ~Str); should_pass([], ~Num); should_pass([], ~Int); should_fail("4x4", ~Str); should_pass("4x4", ~Num); should_pass("4.2", ~Int); should_pass(undef, ~Str); should_pass(undef, ~Num); should_pass(undef, ~Int); should_pass(undef, ~Defined); should_pass(undef, ~Value); { package Local::Class1; use strict; } { no warnings 'once'; $Local::Class2::VERSION = 0.001; @Local::Class3::ISA = qw(UNIVERSAL); @Local::Dummy1::FOO = qw(UNIVERSAL); } { package Local::Class4; sub XYZ () { 1 } package Local::Class5; use constant XZY => 2 } should_pass(undef, ~ClassName); should_pass([], ~ClassName); should_fail("Local::Class$_", ~ClassName) for 2..5; should_pass("Local::Dummy1", ~ClassName); should_fail([], ~(ArrayRef[Int])); should_fail([1,2,3], ~(ArrayRef[Int])); should_pass([1.1,2,3], ~(ArrayRef[Int])); should_pass([1,2,3.1], ~(ArrayRef[Int])); should_pass([[]], ~(ArrayRef[Int])); should_fail([[3]], ~(ArrayRef[ArrayRef[Int]])); should_pass([["A"]], ~(ArrayRef[ArrayRef[Int]])); should_fail(undef, ~(Maybe[Int])); should_fail(123, ~(Maybe[Int])); should_pass(1.3, ~(Maybe[Int])); my $even = "Type::Tiny"->new( name => "Even", parent => Int, constraint => sub { !(abs($_) % 2) }, ); my $odd = "Type::Tiny"->new( name => "Even", parent => Int, constraint => sub { !!(abs($_) % 2) }, ); my $positive = "Type::Tiny"->new( name => "Positive", parent => Int, constraint => sub { $_ > 0 }, ); my $negative = "Type::Tiny"->new( name => "Negative", parent => Int, constraint => sub { $_ < 0 }, ); should_pass(-2, $even & $negative); should_pass(-1, $odd & $negative); should_pass(0, $even & ~$negative & ~$positive); should_pass(1, $odd & $positive); should_pass(2, $even & $positive); should_pass(3, $even | $odd); should_pass(4, $even | $odd); should_pass(5, $negative | $positive); should_pass(-6, $negative | $positive); should_fail(-3, $even & $negative); should_fail(1, $odd & $negative); should_fail(1, $even & ~$negative & ~$positive); should_fail(2, $odd & $positive); should_fail(1, $even & $positive); should_fail("Str", $even | $odd); should_fail(1.1, $even | $odd); should_fail(0, $negative | $positive); should_fail("Str", $negative | $positive); is( ($even & ~$negative & ~$positive)->display_name, "Even&~Negative&~Positive", "coolio stringification", ); ok(Item > Value, "Item > Value"); ok(Value > Str, "Value > Str"); ok(Str > Num, "Str > Num"); ok(Num > Int, "Num > Int"); ok(Int > $odd, "Int > \$odd"); ok(Item >= Value, "Item >= Value"); ok(Value >= Str, "Value >= Str"); ok(Str >= Num, "Str >= Num"); ok(Num >= Int, "Num >= Int"); ok(Int >= $odd, "Int >= \$odd"); ok(Value() < Item, "Value < Item"); ok(Str() < Value, "Str < Value"); ok(Num() < Str, "Num < Str"); ok(Int() < Num, "Int < Num"); ok($even < Int, "\$even < Int"); ok(Value() <= Item, "Value <= Item"); ok(Str() <= Value, "Str <= Value"); ok(Num() <= Str, "Num <= Str"); ok(Int() <= Num, "Int <= Num"); ok($even <= Int, "\$even < Int"); ok(not(Int > Int), "not(Int > Int)"); ok(not(Int() < Int), "not(Int < Int)"); ok(Int() <= Int, "Int <= Int"); ok(Int >= Int, "Int >= Int"); ok(not((ArrayRef[Int]) > (ArrayRef[Num])), 'not(ArrayRef[Int] > ArrayRef[Num])'); ok(not((ArrayRef[Int]) == (ArrayRef[Num])), 'not(ArrayRef[Int] == ArrayRef[Num])'); ok((ArrayRef[Int]) == (ArrayRef[Int]), 'ArrayRef[Int] == ArrayRef[Int]'); ok(not(ArrayRef == ArrayRef[Int]), 'not(ArrayRef == ArrayRef[Int])'); ok(ArrayRef > ArrayRef[Int], 'ArrayRef > ArrayRef[Int]'); done_testing; basic.t000644001750001750 1172313601673061 17202 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny=pod =encoding utf-8 =head1 PURPOSE Checks Type::Tiny works. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Test::TypeTiny; use Type::Tiny; my $Any = "Type::Tiny"->new(name => "Any"); ok(!$Any->is_anon, "Any is not anon"); is($Any->name, "Any", "Any is called Any"); ok($Any->can_be_inlined, 'Any can be inlined'); should_pass($_, $Any) for 1, 1.2, "Hello World", [], {}, undef, \*STDOUT; like( exception { $Any->create_child_type(name => "1") }, qr{^"1" is not a valid type name}, "bad type constraint name", ); my $Int = $Any->create_child_type( constraint => sub { defined($_) and !ref($_) and $_ =~ /^[+-]?[0-9]+$/sm }, ); ok($Int->is_anon, "\$Int is anon"); is($Int->name, "__ANON__", "\$Int is called __ANON__"); ok(!$Int->can_be_inlined, '$Int cannot be inlined'); should_pass($_, $Int) for 1, -1, 0, 100, 10000, 987654; should_fail($_, $Int) for 1.2, "Hello World", [], {}, undef, \*STDOUT; ok_subtype($Any, $Int); ok($Any->is_supertype_of($Int), 'Any is_supertype_of $Int'); ok($Int->is_a_type_of($Any), '$Int is_a_type_of Any'); ok($Int->is_a_type_of($Int), '$Int is_a_type_of $Int'); ok(!$Int->is_subtype_of($Int), 'not $Int is_subtype_of $Int'); my $Below = $Int->create_child_type( name => "Below", constraint_generator => sub { my $param = shift; return sub { $_ < $param }; }, ); ok($Below->is_parameterizable, 'Below is_parameterizable'); ok(!$Below->is_parameterized, 'not Below is_parameterized'); should_pass($_, $Below) for 1, -1, 0, 100, 10000, 987654; should_fail($_, $Below) for 1.2, "Hello World", [], {}, undef, \*STDOUT; my $Below5 = $Below->parameterize(5); ok($Below5->is_anon, '$Below5 is anon'); is($Below5->display_name, 'Below[5]', '... but still has a nice display name'); should_pass($_, $Below5) for 1, -1, 0; should_fail($_, $Below5) for 1.2, "Hello World", [], {}, undef, \*STDOUT, 100, 10000, 987654; ok_subtype($_, $Below5) for $Any, $Int, $Below; ok($Below5->is_parameterized, 'Below[5] is_parameterized'); ok(!$Below->has_parameters, 'has_parameters method works - negative'); ok($Below5->has_parameters, 'has_parameters method works - positive'); is_deeply($Below5->parameters, [5], 'parameters method works'); my $Ref = "Type::Tiny"->new( name => "Ref", constraint => sub { ref($_) }, inlined => sub { "ref($_)" }, ); my $ArrayRef = "Type::Tiny"->new( name => "ArrayRef", parent => $Ref, constraint => sub { ref($_) eq 'ARRAY' }, inlined => sub { undef, "ref($_) eq 'ARRAY'" }, ); is( $ArrayRef->inline_check('$xxx'), q[(((ref($xxx))) && (ref($xxx) eq 'ARRAY'))], 'inlining stuff can return a list', ); use Types::Standard (); { my $subtype_of_Num = Types::Standard::Num->create_child_type; my $subtype_of_Int = Types::Standard::Int->create_child_type; ok( $subtype_of_Int->is_subtype_of( $subtype_of_Num ), 'loose subtype comparison 1', ); ok( ! $subtype_of_Int->is_strictly_subtype_of( $subtype_of_Num ), 'strict subtype comparison 1', ); ok( $subtype_of_Num->is_supertype_of( $subtype_of_Int ), 'loose supertype comparison 1', ); ok( ! $subtype_of_Num->is_strictly_supertype_of( $subtype_of_Int ), 'strict supertype comparison 1', ); ok( Types::Standard::Int->is_subtype_of( Types::Standard::Num ), 'loose subtype comparison 2', ); ok( Types::Standard::Int->is_strictly_subtype_of( Types::Standard::Num ), 'strict subtype comparison 2', ); ok( Types::Standard::Num->is_supertype_of( Types::Standard::Int ), 'loose supertype comparison 2', ); ok( Types::Standard::Num->is_strictly_supertype_of( Types::Standard::Int ), 'strict supertype comparison 2', ); } my $t1 = Types::Standard::Int; my $t2 = $t1->create_child_type(name => 'T2'); my $t3 = $t2->create_child_type(name => 'T3'); my $t4 = $t3->create_child_type(name => 'T4'); my $t5 = $t4->create_child_type(name => 'T5'); my $t6 = $t5->create_child_type(name => 'T6'); my $found = $t6->find_parent(sub { $_->has_parent and $_->parent->name eq 'Int' }); is($found->name, 'T2', 'find_parent (scalar context)'); my ($found2, $n2) = $t6->find_parent(sub { $_->has_parent and $_->parent->name eq 'Int' }); is($found2->name, 'T2', 'find_parent (list context)'); is($n2, 4, '... includes a count'); my ($found3, $n3) = $t6->find_parent(sub { $_->name eq 'Kristoff' }); is($found3, undef, 'find_parent (null result)'); is($3, undef, '... includes an undef count'); { my $Any = "Type::Tiny"->new(name => "Any"); my $Blah = $Any->create_child_type->create_child_type(constraint => sub { "yes" }); my $Bleh = $Blah->create_child_type(name => "Bleh")->create_child_type; is($Bleh->find_constraining_type->{uniq}, $Blah->{uniq}, 'find_constraining_type'); } done_testing; cmp.t000644001750001750 664113601673061 16663 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny=pod =encoding utf-8 =head1 PURPOSE Test new type comparison stuff with Type::Tiny objects. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2018-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Type::Tiny; use Test::More; use Test::TypeTiny; my $string = Type::Tiny->new( constraint => sub { defined($_) && !ref($_) }, ); my $integer = $string->where(sub { /^-?[0-9]+$/ and not $_ eq '-0' }); my $natural = $integer->where(sub { $_ >= 0 }); my $digit = $natural->where(sub { $_ < 10 }); my $undef = Type::Tiny->new(constraint => sub { !defined }); my ($stringX, $integerX, $naturalX, $digitX) = map { $_->plus_coercions($undef, sub { 0 }); } ($string, $integer, $natural, $digit); ok_subtype($string => $integer, $natural, $digit, $stringX, $integerX, $naturalX, $digitX); ok_subtype($stringX => $string, $integer, $natural, $digit, $integerX, $naturalX, $digitX); ok_subtype($integer => $natural, $digit, $integerX, $naturalX, $digitX); ok_subtype($integerX => $integer, $natural, $digit, $naturalX, $digitX); ok_subtype($natural => $digit, $naturalX, $digitX); ok_subtype($naturalX => $natural, $digit, $digitX); ok_subtype($digit => $digitX); ok_subtype($digitX => $digit); ok !$string->is_a_type_of($undef); ok !$undef->is_a_type_of($string); ok !$digit->is_a_type_of($undef); ok !$undef->is_a_type_of($digit); ok !$stringX->is_a_type_of($undef); ok !$undef->is_a_type_of($stringX); ok !$digitX->is_a_type_of($undef); ok !$undef->is_a_type_of($digitX); is(Type::Tiny::cmp($string, $digit), Type::Tiny::CMP_SUPERTYPE); is(Type::Tiny::cmp($stringX, $digit), Type::Tiny::CMP_SUPERTYPE); is(Type::Tiny::cmp($string, $digitX), Type::Tiny::CMP_SUPERTYPE); is(Type::Tiny::cmp($stringX, $digitX), Type::Tiny::CMP_SUPERTYPE); is(Type::Tiny::cmp($digit, $string), Type::Tiny::CMP_SUBTYPE); is(Type::Tiny::cmp($digit, $stringX), Type::Tiny::CMP_SUBTYPE); is(Type::Tiny::cmp($digitX, $string), Type::Tiny::CMP_SUBTYPE); is(Type::Tiny::cmp($digitX, $stringX), Type::Tiny::CMP_SUBTYPE); is(Type::Tiny::cmp($string, $stringX), Type::Tiny::CMP_EQUAL); is(Type::Tiny::cmp($stringX, $string), Type::Tiny::CMP_EQUAL); is(Type::Tiny::cmp($digit, $digitX), Type::Tiny::CMP_EQUAL); is(Type::Tiny::cmp($digitX, $digit), Type::Tiny::CMP_EQUAL); is(Type::Tiny::cmp($string, $undef), Type::Tiny::CMP_UNKNOWN); is(Type::Tiny::cmp($stringX, $undef), Type::Tiny::CMP_UNKNOWN); is(Type::Tiny::cmp($undef, $string), Type::Tiny::CMP_UNKNOWN); is(Type::Tiny::cmp($undef, $stringX), Type::Tiny::CMP_UNKNOWN); my $type1 = Type::Tiny->new(constraint => '$_ eq "FLIBBLE"'); my $type2 = Type::Tiny->new(constraint => '$_ eq "FLIBBLE"'); my $type3 = Type::Tiny->new(constraint => '$_ eq "FLOBBLE"'); is(Type::Tiny::cmp($type1, $type2), Type::Tiny::CMP_EQUAL); is(Type::Tiny::cmp($type1, $type3), Type::Tiny::CMP_UNKNOWN); is(Type::Tiny::cmp($type2, $type1), Type::Tiny::CMP_EQUAL); is(Type::Tiny::cmp($type2, $type3), Type::Tiny::CMP_UNKNOWN); is(Type::Tiny::cmp($type3, $type1), Type::Tiny::CMP_UNKNOWN); is(Type::Tiny::cmp($type3, $type2), Type::Tiny::CMP_UNKNOWN); is(Type::Tiny::cmp($type1, $type2->create_child_type), Type::Tiny::CMP_EQUAL); is(Type::Tiny::cmp($type1, $type2->where(sub { 0 })), Type::Tiny::CMP_SUPERTYPE); done_testing; coercion-modifiers.t000644001750001750 376413601673061 21667 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny=pod =encoding utf-8 =head1 PURPOSE Checks C, C and C methods work. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal qw(dies_ok); use BiggerLib -types; my $new_type = BigInteger->plus_coercions( HashRef, "999", Undef, sub { 666 }, ); my $arr = []; my $hash = {}; ok( $new_type->coercion->has_coercion_for_type(HashRef), 'has_coercian_for_type - obvious', ); ok( $new_type->coercion->has_coercion_for_type(HashRef[Num]), 'has_coercian_for_type - subtle', ); ok( not($new_type->coercion->has_coercion_for_type(Ref["CODE"])), 'has_coercian_for_type - negative', ); is($new_type->coerce($hash), 999, 'plus_coercions - added coercion'); is($new_type->coerce(undef), 666, 'plus_coercions - added coercion'); is($new_type->coerce(-1), 11, 'plus_coercions - retained coercion'); is($new_type->coerce($arr), 100, 'plus_coercions - retained coercion'); my $newer_type = $new_type->minus_coercions(ArrayRef, Undef); is($newer_type->coerce($hash), 999, 'minus_coercions - retained coercion'); is($newer_type->coerce(undef), undef, 'minus_coercions - removed coercion'); is($newer_type->coerce(-1), 11, 'minus_coercions - retained coercion'); is($newer_type->coerce($arr), $arr, 'minus_coercions - removed coercion'); my $no_coerce = $new_type->no_coercions; dies_ok { $no_coerce->coerce($hash) } 'no_coercions - removed coercion'; dies_ok { $no_coerce->coerce(undef) } 'no_coercions - removed coercion'; dies_ok { $no_coerce->coerce(-1) } 'no_coercions - removed coercion'; dies_ok { $no_coerce->coerce($arr) } 'no_coercions - removed coercion'; done_testing; constraint-strings.t000644001750001750 227413601673061 21755 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny=pod =encoding utf-8 =head1 PURPOSE Checks Type::Tiny works accepts strings of Perl code as constraints. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Types::Standard -types; my $Str = Str->where( 'length($_) > 0' ); my $Arr = ArrayRef->where( '@$_ > 0' ); my $Hash = HashRef->where( 'keys(%$_) > 0' ); use Test::More; use Test::Fatal; is( exception { $Str->assert_valid( 'u' ) }, undef, 'non-empty string, okay', ); isa_ok( exception { $Str->assert_valid( '' ) }, 'Error::TypeTiny', 'result of empty string', ); is( exception { $Arr->assert_valid( [undef] ) }, undef, 'non-empty arrayref, okay', ); isa_ok( exception { $Arr->assert_valid( [] ) }, 'Error::TypeTiny', 'result of empty arrayref', ); is( exception { $Hash->assert_valid( { '' => undef } ) }, undef, 'non-empty hashref, okay', ); isa_ok( exception { $Hash->assert_valid( +{} ) }, 'Error::TypeTiny', 'result of empty hashref', ); done_testing; deprecation.t000644001750001750 174113601673061 20375 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny=pod =encoding utf-8 =head1 PURPOSE Checks Type::Tiny's C attribute works. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2018-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Test::TypeTiny; use Type::Tiny; my $t1 = Type::Tiny->new(name => "Base"); my $t2 = Type::Tiny->new(name => "Derived_1", parent => $t1); my $t3 = Type::Tiny->new(name => "Derived_2", parent => $t1, deprecated => 1); my $t4 = Type::Tiny->new(name => "Double_Derived_1", parent => $t3); my $t5 = Type::Tiny->new(name => "Double_Derived_2", parent => $t3, deprecated => 0); ok not $t1->deprecated; ok not $t2->deprecated; ok $t3->deprecated; ok $t4->deprecated; ok not $t5->deprecated; done_testing; esoteric.t000644001750001750 421613601673061 17715 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny=pod =encoding utf-8 =head1 PURPOSE Checks various undocumented Type::Tiny methods. The fact that these are tested here should not be construed to mean tht they are any any way a stable, supported part of the Type::Tiny API. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Test::TypeTiny; use Type::Tiny; use Types::Standard -types; is_deeply( Int->inline_environment, {}, '$type->inline_environment', ); my $check = Int->_inline_check('$foo'); ok( eval("my \$foo = 42; $check") && !eval("my \$foo = 4.2; $check"), '$type->_inline_check', ); ok( Int->_compiled_type_constraint->("42") && !Int->_compiled_type_constraint->("4.2"), '$type->_compiled_type_constraint', ); like( exception { Any->meta }, qr/^Not really a Moose::Meta::TypeConstraint/, '$type->meta', ); ok( Int->compile_type_constraint->("42") && !Int->compile_type_constraint->("4.2"), '$type->compile_type_constraint', ); ok( Int->_actually_compile_type_constraint->("42") && !Int->_actually_compile_type_constraint->("4.2"), '$type->_actually_compile_type_constraint', ); is( Int->hand_optimized_type_constraint, undef, '$type->hand_optimized_type_constraint', ); ok( !Int->has_hand_optimized_type_constraint, '$type->has_hand_optimized_type_constraint', ); ok( (ArrayRef[Int])->__is_parameterized && !Int->__is_parameterized, '$type->__is_parameterized', ); my $Int = Int->create_child_type; $Int->_add_type_coercions(Num, q[int($_)]); is( $Int->coerce(42.1), 42, '$type->_add_type_coercions', ); is( Int->_as_string, 'Types::Standard::Int', '$type->_as_string', ); is( $Int->_compiled_type_coercion->(6.2), 6, '$type->_compiled_type_coercion', ); ok( Int->_identity != $Int->_identity, '$type->_identity', ); my $union = Int->_unite(ArrayRef); ok( $union->equals( Int | ArrayRef ), '$type->_unite', ); done_testing; inline-assert.t000644001750001750 544213601673061 20657 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny=pod =encoding utf-8 =head1 PURPOSE Tests for Type::Tiny's C method. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Types::Standard qw( Int ); # Exceptions do seem to work on older Perls, but checking them with like() # seems to break stuff, so just skip. use constant SANE_PERL => ($] ge '5.008001'); my ($inline_assert, @VALUE, $r); local $@; note("INLINE ASSERTION, INLINABLE TYPE, NO TYPEVAR"); note($inline_assert = Int->inline_assert('$VALUE[0]')); @VALUE = (12); $@ = undef; $r = eval "$inline_assert; 1234"; is($r, 1234, 'successful check'); @VALUE = (1.2); $@ = undef; $r = eval "$inline_assert; 1234"; is($r, undef, 'successful throw'); like($@, qr/Value "1.2" did not pass type constraint "Int"/, '... with correct exception') if SANE_PERL; note("INLINE ASSERTION, INLINABLE TYPE, WITH TYPEVAR"); my $type = Int; note($inline_assert = $type->inline_assert('$VALUE[0]', '$type')); @VALUE = (12); $@ = undef; $r = eval "$inline_assert; 1234"; is($r, 1234, 'successful check'); @VALUE = (1.2); $@ = undef; $r = eval "$inline_assert; 1234"; is($r, undef, 'successful throw'); like($@, qr/Value "1.2" did not pass type constraint "Int"/, '... with correct exception') if SANE_PERL; undef $type; @VALUE = (1.2); $@ = undef; $r = eval "$inline_assert; 1234"; is($r, undef, 'successful throw even when $type is undef'); like($@, qr/Value "1.2" did not pass type constraint "Int"/, '... with correct exception') if SANE_PERL; is($@->type, undef, '... but the exception does not know which type it was thrown by') if SANE_PERL; note("INLINE ASSERTION, NON-INLINABLE TYPE, NO TYPEVAR"); $type = Int->where(sub {1}); # cannot be inlined undef $inline_assert; my $e = exception { $inline_assert = $type->inline_assert('$VALUE[0]'); }; isnt($e, undef, 'cannot be done!'); note("INLINE ASSERTION, NON-INLINABLE TYPE, WITH TYPEVAR"); note($inline_assert = $type->inline_assert('$VALUE[0]', '$type')); @VALUE = (12); $@ = undef; $r = eval "$inline_assert; 1234"; is($r, 1234, 'successful check'); @VALUE = (1.2); $@ = undef; $r = eval "$inline_assert; 1234"; is($r, undef, 'successful throw'); like($@, qr/Value "1.2" did not pass type constraint "Int"/, '... with correct exception') if SANE_PERL; note("INLINE ASSERTION, NON-INLINABLE TYPE, WITH TYPEVAR AND EXTRAS"); note($inline_assert = $type->inline_assert('$VALUE[0]', '$type', foo => "bar")); @VALUE = (1.2); $@ = undef; $r = eval "$inline_assert; 1234"; is($@->{foo}, 'bar', 'extras work') if SANE_PERL; done_testing; my-methods.t000644001750001750 156013601673061 20165 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny=pod =encoding utf-8 =head1 PURPOSE Checks Type::Tiny's C attribute. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Types::Standard qw(Num); my $type = Num->create_child_type( name => 'Number', my_methods => { round_off => sub { int($_[1]) } } ); my $type2 = $type->create_child_type(name => 'Number2'); can_ok($_, 'my_round_off') for $type, $type2; is($_->my_round_off(42.3), 42, "$_ my_round_off works") for $type, $type2; ok(!$_->can('my_smirnoff'), "$_ cannot my_smirnoff") for $type, $type2; done_testing; parameterization.t000644001750001750 416613601673061 21462 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny=pod =encoding utf-8 =head1 PURPOSE There are loads of tests for parameterization in C, C, C, C, C, C, etc. This file includes a handful of other parameterization-related tests that didn't fit anywhere else. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny -all; use Test::Fatal; use Types::Standard qw/ -types slurpy /; my $p1 = ArrayRef[Int]; my $p2 = ArrayRef[Int]; my $p3 = ArrayRef[Int->create_child_type()]; is($p1->{uniq}, $p2->{uniq}, "Avoid duplicating parameterized types"); isnt($p1->{uniq}, $p3->{uniq}, "... except when necessary!"); my $p4 = ArrayRef[sub { $_ eq "Bob" }]; my $p5 = ArrayRef[sub { $_ eq "Bob" or die "not Bob" }]; my $p6 = ArrayRef[Str & +sub { $_ eq "Bob" or die "not Bob" }]; should_pass(["Bob"], $p4); should_pass(["Bob", "Bob"], $p4); should_fail(["Bob", "Bob", "Suzie"], $p4); should_pass(["Bob"], $p5); should_pass(["Bob", "Bob"], $p5); should_fail(["Bob", "Bob", "Suzie"], $p5); should_pass(["Bob"], $p6); should_pass(["Bob", "Bob"], $p6); should_fail(["Bob", "Bob", "Suzie"], $p6); is( $p4->parameters->[0]->validate("Suzie"), 'Value "Suzie" did not pass type constraint', 'error message when a coderef returns false', ); like( $p5->parameters->[0]->validate("Suzie"), qr{^not Bob}, 'error message when a coderef dies', ); my $p7 = ArrayRef[Dict[foo =>Int, slurpy Any]]; my $p8 = ArrayRef[Dict[foo =>Int, slurpy Any]]; is($p7->inline_check(q/$X/), $p8->inline_check(q/$X/), '$p7 and $p8 stringify the same'); is($p7->{uniq}, $p8->{uniq}, '$p7 and $p8 are the same'); #like( # exception { ArrayRef[Int, Int] }, # qr/^\QOnly one parameter to ArrayRef[`a] expected; got 2/, # 'error message when ArrayRef[`a] passed multiple parameters' #); done_testing; shortcuts.t000644001750001750 146013601673061 20134 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny=pod =encoding utf-8 =head1 PURPOSE Test the C<< ->of >> and C<< ->where >> shortcut methods. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny -all; use Types::Standard -types; my $p1 = ArrayRef->parameterize( Int ); my $p2 = ArrayRef->of( Int ); is($p1->{uniq}, $p2->{uniq}, "->of method works same as ->parameterize"); my $p3 = ArrayRef->where(sub { $_->[0] eq 'Bob' }); should_pass ['Bob', 'Alice'], $p3; should_fail ['Alice', 'Bob'], $p3; done_testing; smartmatch.t000644001750001750 224013601673061 20236 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny=pod =encoding utf-8 =head1 PURPOSE Checks Type::Tiny works with the smartmatch operator. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Type::Tiny (); BEGIN { Type::Tiny::SUPPORT_SMARTMATCH or plan skip_all => 'smartmatch support not available for this version or Perl'; } use Types::Standard -all; no warnings; # !! ok( 42 ~~ Int ); ok( 42 ~~ Num ); ok not( 42 ~~ ArrayRef ); ok( 42 ~~ \&is_Int ); ok not( 42 ~~ \&is_ArrayRef ); TODO: { use feature qw(switch); given (4) { when ( \&is_RegexpRef ) { fail('regexpref') } when ( \&is_Int ) { pass('int') } default { fail('default') } } local $TODO = 'this would be nice, but probably requires changes to perl'; given (4) { when ( RegexpRef ) { fail('regexpref') } when ( Int ) { pass('int') } default { fail('default') } } }; done_testing; syntax.t000644001750001750 342213601673061 17424 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny=pod =encoding utf-8 =head1 PURPOSE Checks that all this Type[Param] syntactic sugar works. In particular, the following three type constraints are expected to be equivalent to each other: use Types::Standard qw( ArrayRef Int Num Str ); use Type::Utils qw( union intersection ); my $type1 = ArrayRef[Int] | ArrayRef[Num & ~Int] | ArrayRef[Str & ~Num]; my $type2 = union [ ArrayRef[Int], ArrayRef[Num & ~Int], ArrayRef[Str & ~Num], ]; my $type3 = union([ ArrayRef->parameterize(Int), ArrayRef->parameterize( intersection([ Num, Int->complementary_type, ]), ), ArrayRef->parameterize( intersection([ Str, Num->complementary_type, ]), ), ]); =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( . ./t ../inc ./inc ); use Test::More; use Types::Standard qw( ArrayRef Int Num Str ); use Type::Utils qw( union intersection ); my $type1 = ArrayRef[Int] | ArrayRef[Num & ~Int] | ArrayRef[Str & ~Num]; my $type2 = union [ ArrayRef[Int], ArrayRef[Num & ~Int], ArrayRef[Str & ~Num], ]; my $type3 = union([ ArrayRef->parameterize(Int), ArrayRef->parameterize( intersection([ Num, Int->complementary_type, ]), ), ArrayRef->parameterize( intersection([ Str, Num->complementary_type, ]), ), ]); ok($type1==$type2, '$type1==$type2'); ok($type1==$type3, '$type1==$type3'); ok($type2==$type3, '$type2==$type3'); done_testing; to-moose.t000644001750001750 223713601673061 17643 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny=pod =encoding utf-8 =head1 PURPOSE Checks Type::Tiny objects can be converted to Moose type constraint objects. =head1 DEPENDENCIES Requires Moose 2.0000; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { 'Moose' => '2.0000' }; use Test::TypeTiny; use Type::Tiny; my $Any = "Type::Tiny"->new(name => "Anything"); my $Int = $Any->create_child_type( name => "Integer", constraint => sub { defined($_) and !ref($_) and $_ =~ /^[+-]?[0-9]+$/sm }, ); my $mAny = $Any->moose_type; my $mInt = $Int->moose_type; isa_ok($mAny, 'Moose::Meta::TypeConstraint', '$mAny'); isa_ok($mInt, 'Moose::Meta::TypeConstraint', '$mInt'); is($mInt->parent, $mAny, 'type constraint inheritance seems right'); should_pass(42, $mAny); should_pass([], $mAny); should_pass(42, $mInt); should_fail([], $mInt); done_testing; to-mouse.t000644001750001750 213513601673061 17646 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny=pod =encoding utf-8 =head1 PURPOSE Checks Type::Tiny objects can be converted to Mouse type constraint objects. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { 'Mouse' => '1.00' }; use Test::TypeTiny; use Type::Tiny; my $Any = "Type::Tiny"->new(name => "Anything"); my $Int = $Any->create_child_type( name => "Integer", constraint => sub { defined($_) and !ref($_) and $_ =~ /^[+-]?[0-9]+$/sm }, ); my $mAny = $Any->mouse_type; my $mInt = $Int->mouse_type; isa_ok($mAny, 'Mouse::Meta::TypeConstraint', '$mAny'); isa_ok($mInt, 'Mouse::Meta::TypeConstraint', '$mInt'); is($mInt->parent, $mAny, 'type constraint inheritance seems right'); should_pass(42, $mAny); should_pass([], $mAny); should_pass(42, $mInt); should_fail([], $mInt); done_testing; basic.t000644001750001750 335513601673061 20227 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Class=pod =encoding utf-8 =head1 PURPOSE Checks class type constraints work. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use BiggerLib qw( :types ); isa_ok(FooBar, "Type::Tiny", "FooBar"); isa_ok(FooBar, "Type::Tiny::Class", "FooBar"); isa_ok(FooBaz, "Type::Tiny", "FooBaz"); isa_ok(FooBaz, "Type::Tiny::Class", "FooBaz"); isa_ok(FooBar->new, "Foo::Bar", "FooBar->new"); isa_ok(FooBaz->new, "Foo::Baz", "FooBaz->new"); isa_ok(FooBar->class->new, "Foo::Bar", "FooBar->class->new"); isa_ok(FooBaz->class->new, "Foo::Baz", "FooBaz->class->new"); should_pass("Foo::Bar"->new, FooBar); should_pass("Foo::Baz"->new, FooBar); should_fail("Foo::Bar"->new, FooBaz); should_pass("Foo::Baz"->new, FooBaz); should_fail(undef, FooBar); should_fail(undef, FooBaz); should_fail({}, FooBar); should_fail({}, FooBaz); should_fail(FooBar, FooBar); should_fail(FooBar, FooBaz); should_fail(FooBaz, FooBar); should_fail(FooBaz, FooBaz); should_fail("Foo::Bar", FooBar); should_fail("Foo::Bar", FooBaz); should_fail("Foo::Baz", FooBar); should_fail("Foo::Baz", FooBaz); is( ref(FooBar->new), ref(FooBar->class->new), 'DWIM Type::Tiny::Class::new', ); is( 'Type::Tiny::Class'->new( class => 'Xyzzy' )->inline_check('$x'), 'Type::Tiny::Class'->new({ class => 'Xyzzy' })->inline_check('$x'), 'constructor can be passed a hash or hashref', ); done_testing; errors.t000644001750001750 276213601673061 20463 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Class=pod =encoding utf-8 =head1 PURPOSE Checks class type constraints throw sane error messages. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Types::Standard qw(Int); use Type::Tiny::Class; like( exception { Type::Tiny::Class->new(parent => Int, class => 'Foo') }, qr/^Class type constraints cannot have a parent/, ); like( exception { Type::Tiny::Class->new(constraint => sub { 1 }, class => 'Foo') }, qr/^Class type constraints cannot have a constraint coderef/, ); like( exception { Type::Tiny::Class->new(inlined => sub { 1 }, class => 'Foo') }, qr/^Class type constraints cannot have an inlining coderef/, ); like( exception { Type::Tiny::Class->new() }, qr/^Need to supply class name/, ); { package Quux; our @ISA = qw(); sub new { bless [], shift } } { package Quuux; our @ISA = qw(); } { package Baz; our @ISA = qw(Quuux); } { package Bar; our @ISA = qw(Baz Quux); } my $e = exception { Type::Tiny::Class ->new(name => "Elsa", class => "Foo") ->assert_valid( Bar->new ); }; is_deeply( $e->explain, [ '"Elsa" requires that the reference isa Foo', 'The reference isa Bar, Baz, Quuux, and Quux', ], ); done_testing; plus-constructors.t000644001750001750 477313601673061 22704 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Class=pod =encoding utf-8 =head1 PURPOSE Checks the C's C method. =head1 DEPENDENCIES Requires Moose 2.00; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( . ./t ../inc ./inc ); use utf8; use Test::More; use Test::Requires { Moose => 2.00 }; use Test::TypeTiny; my ($Address, $Person); BEGIN { package Address; use Moose; use Types::Standard qw( Str ); use Type::Utils; has [qw/ line1 line2 town county postcode country /] => ( is => "ro", isa => Str, ); sub _new_from_array { my $class = shift; my @addr = ref($_[0]) ? @{$_[0]} : @_; $class->new( line1 => $addr[0], line2 => $addr[1], town => $addr[2], county => $addr[3], postcode => $addr[4], country => $addr[5], ); } $Address = class_type { class => __PACKAGE__ }; }; BEGIN { package Person; use Moose; use Types::Standard qw( Str Join Tuple HashRef ); use Type::Utils; has name => ( required => 1, coerce => 1, is => "ro", isa => Str->plus_coercions(Join[" "]), ); has addr => ( coerce => 1, is => "ro", isa => $Address->plus_constructors( (Tuple[(Str) x 6]) => "_new_from_array", (HashRef) => "new", ), ); sub _new_from_name { my $class = shift; my ($name) = @_; $class->new(name => $name); } $Person = class_type { class => __PACKAGE__ }; }; ok( "Person"->meta->get_attribute("addr")->type_constraint->is_a_type_of($Address), q["Person"->meta->get_attribute("addr")->type_constraint->is_a_type_of($Address)], ); my $me = Person->new( name => ["Toby", "Inkster"], addr => ["Flat 2, 39 Hartington Road", "West Ealing", "LONDON", "", "W13 8QL", "United Kingdom"], ); my $me2 = Person->new( name => "Toby Inkster", addr => Address->new( line1 => "Flat 2, 39 Hartington Road", line2 => "West Ealing", town => "LONDON", county => "", postcode => "W13 8QL", country => "United Kingdom", ), ); is_deeply($me, $me2, 'coercion worked'); my $you = $Person->plus_constructors->coerce({ name => "Livvy" }); my $you2 = Person->new(name => "Livvy"); is_deeply($you, $you2, 'coercion worked (plus_constructors with no parameters)'); done_testing; basic.t000644001750001750 627713601673061 22570 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-ConstrainedObject=pod =encoding utf-8 =head1 PURPOSE Check C, C, and C work for L, L, and L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::TypeTiny; BEGIN { package Local::Class; use overload ( q[""] => sub { shift->as_string }, q[0+] => sub { shift->as_number }, fallback => 1, ); sub new { my $class = shift; my %args = ref $_[0] ? %{$_[0]} : @_; bless \%args => $class; } sub AUTOLOAD { my $self = shift; our $AUTOLOAD; (my $method = $AUTOLOAD) =~ s/^.*:://; $self->{$method}; } sub DOES { my $self = shift; my ($role) = @_; return 1 if $role eq 'Local::Role'; $self->SUPER::DOES(@_); } sub can { my $self = shift; my ($method) = @_; my $r = $self->SUPER::can(@_); return $r if $r; if ($method !~ /^__/) { return sub { shift->{$method} }; } $r; } sub DESTROY { } }; use Type::Tiny::Class; use Type::Tiny::Duck; use Type::Tiny::Role; use Types::Standard -types; my $class_type = Type::Tiny::Class->new(class => 'Local::Class'); my $role_type = Type::Tiny::Role->new(role => 'Local::Role'); my $duck_type = Type::Tiny::Duck->new(methods => [qw/foo bar baz quux/]); my @test_types = ( [ $class_type, 'Class types...' ], [ $role_type, 'Role types...' ], [ $duck_type, 'Duck types...' ], ); for my $tt (@test_types) { my ($base_type, $label) = @$tt; should_pass( Local::Class->new, $base_type, $label, ); should_pass( Local::Class->new( as_string => '3', as_number => '3.1' ), $base_type->stringifies_to( Int ), '... stringifies_to (should pass)', ); should_fail( Local::Class->new( as_string => '3.1', as_number => '3.1' ), $base_type->stringifies_to( Int ), '... stringifies_to (should fail)', ); should_pass( Local::Class->new( as_string => '3.1', as_number => '3' ), $base_type->numifies_to( Int ), '... numifies_to (should pass)', ); should_fail( Local::Class->new( as_string => '3.1', as_number => '3.1' ), $base_type->numifies_to( Int ), '... numifies_to (should fail)', ); should_pass( Local::Class->new( foo => 1, bar => 'ABARA', baz => 3 ), $base_type->with_attribute_values( foo => Int, bar => qr/BAR/, baz => '$_%2' ), '... with_attribute_values (should pass)', ); should_fail( Local::Class->new( foo => 'xyz', bar => 'ABARA', baz => 3 ), $base_type->with_attribute_values( foo => Int, bar => qr/BAR/, baz => '$_%2' ), '... with_attribute_values (should fail because of foo)', ); should_fail( Local::Class->new( foo => 1, bar => 'XXX', baz => 3 ), $base_type->with_attribute_values( foo => Int, bar => qr/BAR/, baz => '$_%2' ), '... with_attribute_values (should fail because of bar)', ); should_fail( Local::Class->new( foo => 1, bar => 'ABARA', baz => 2 ), $base_type->with_attribute_values( foo => Int, bar => qr/BAR/, baz => '$_%2' ), '... with_attribute_values (should fail because of baz)', ); } done_testing(); basic.t000644001750001750 203013601673061 20035 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Duck=pod =encoding utf-8 =head1 PURPOSE Checks duck type constraints work. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use BiggerLib qw( :types ); isa_ok(CanFooBar, "Type::Tiny", "CanFooBar"); isa_ok(CanFooBaz, "Type::Tiny::Duck", "CanFooBar"); should_pass("Foo::Bar"->new, CanFooBar); should_fail("Foo::Bar"->new, CanFooBaz); should_pass("Foo::Baz"->new, CanFooBar); should_pass("Foo::Baz"->new, CanFooBaz); should_fail(undef, CanFooBar); should_fail({}, CanFooBar); should_fail(FooBar, CanFooBar); should_fail(FooBaz, CanFooBar); should_fail(CanFooBar, CanFooBar); should_fail("Foo::Bar", CanFooBar); done_testing; cmp.t000644001750001750 243113601673061 17540 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Duck=pod =encoding utf-8 =head1 PURPOSE Test new type comparison stuff with Type::Tiny::Duck objects. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2018-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use Type::Utils qw(duck_type); my $type1 = duck_type Type1 => [qw( foo bar )]; my $type2 = duck_type Type2 => [qw( bar foo )]; my $type3 = duck_type Type3 => [qw( foo bar baz )]; ok_subtype($type1 => $type2, $type3); ok_subtype($type2 => $type1, $type3); ok($type1->equals($type2)); ok($type2->equals($type1)); ok($type3->is_subtype_of($type2)); ok($type2->is_supertype_of($type3)); ok($type1->equals($type2->create_child_type)); ok($type2->equals($type1->create_child_type)); ok($type3->is_subtype_of($type2->create_child_type)); ok($type2->is_supertype_of($type3->create_child_type)); ok($type1->create_child_type->equals($type2)); ok($type2->create_child_type->equals($type1)); ok($type3->create_child_type->is_subtype_of($type2)); ok($type2->create_child_type->is_supertype_of($type3)); done_testing; errors.t000644001750001750 267013601673061 20302 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Duck=pod =encoding utf-8 =head1 PURPOSE Checks duck type constraints throw sane error messages. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Types::Standard qw(Int); use Type::Tiny::Duck; like( exception { Type::Tiny::Duck->new(parent => Int, methods => []) }, qr/^Duck type constraints cannot have a parent/, ); like( exception { Type::Tiny::Duck->new(constraint => sub { 1 }, methods => []) }, qr/^Duck type constraints cannot have a constraint coderef/, ); like( exception { Type::Tiny::Duck->new(inlined => sub { 1 }, methods => []) }, qr/^Duck type constraints cannot have an inlining coderef/, ); like( exception { Type::Tiny::Duck->new() }, qr/^Need to supply list of methods/, ); { package Bar; sub new { bless [], shift }; sub shake { fail("aquiver") }; } my $e = exception { Type::Tiny::Duck ->new(name => "Elsa", methods => [qw/ shake rattle roll /]) ->assert_valid( Bar->new ); }; is_deeply( $e->explain, [ '"Elsa" requires that the reference can "rattle", "roll", and "shake"', 'The reference cannot "rattle"', 'The reference cannot "roll"', ], ); done_testing; basic.t000644001750001750 250213601673061 20057 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Enum=pod =encoding utf-8 =head1 PURPOSE Checks enum type constraints work. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use Type::Utils qw< enum >; use constant FBB => enum(FBB => [qw/foo bar baz/]); isa_ok(FBB, "Type::Tiny", "FBB"); isa_ok(FBB, "Type::Tiny::Enum", "FBB"); should_pass("foo", FBB); should_pass("bar", FBB); should_pass("baz", FBB); should_fail("quux", FBB); should_fail(" foo", FBB); should_fail("foo\n", FBB); should_fail("\nfoo", FBB); should_fail("\nfoo\n", FBB); should_fail("foo|", FBB); should_fail("|foo", FBB); should_fail(undef, FBB); should_fail({}, FBB); should_fail(\$_, FBB) for "foo", "bar", "baz"; is_deeply( [sort @{FBB->values}], [sort qw/foo bar baz/], 'FBB->values works', ); is_deeply( FBB->values, [qw/foo bar baz/], 'FBB->values retains order', ); use Scalar::Util qw(refaddr); is( refaddr(FBB->compiled_check), refaddr(enum(FBB2 => [qw/foo foo foo bar baz/])->compiled_check), "don't create duplicate coderefs", ); done_testing; cmp.t000644001750001750 422113601673061 17555 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Enum=pod =encoding utf-8 =head1 PURPOSE Test new type comparison stuff with Type::Tiny::Enum. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2018-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Type::Tiny; use Type::Utils qw(enum); use Test::More; use Test::TypeTiny; my $animals = enum Animals => [qw( cat dog mouse rabbit cow horse sheep goat pig zebra lion )]; my $farmAnimals = enum FarmAnimals => [qw( cow horse sheep goat pig )]; my $petAnimals = enum PetAnimals => [qw( cat dog mouse rabbit )]; my $wildAnimals = enum WildAnimals => [qw( zebra lion )]; my $catAnimals = enum CatAnimals => [qw( cat lion )]; my $catAnimals2 = enum FelineAnimals => [qw( lion cat )]; my @combos = ( [ $animals, $animals, Type::Tiny::CMP_EQUAL ], [ $animals, $farmAnimals, Type::Tiny::CMP_SUPERTYPE ], [ $animals, $petAnimals, Type::Tiny::CMP_SUPERTYPE ], [ $animals, $wildAnimals, Type::Tiny::CMP_SUPERTYPE ], [ $farmAnimals, $animals, Type::Tiny::CMP_SUBTYPE ], [ $farmAnimals, $farmAnimals, Type::Tiny::CMP_EQUAL ], [ $farmAnimals, $petAnimals, Type::Tiny::CMP_UNKNOWN ], [ $farmAnimals, $wildAnimals, Type::Tiny::CMP_UNKNOWN ], [ $petAnimals, $animals, Type::Tiny::CMP_SUBTYPE ], [ $petAnimals, $farmAnimals, Type::Tiny::CMP_UNKNOWN ], [ $petAnimals, $petAnimals, Type::Tiny::CMP_EQUAL ], [ $petAnimals, $wildAnimals, Type::Tiny::CMP_UNKNOWN ], [ $wildAnimals, $animals, Type::Tiny::CMP_SUBTYPE ], [ $wildAnimals, $farmAnimals, Type::Tiny::CMP_UNKNOWN ], [ $wildAnimals, $petAnimals, Type::Tiny::CMP_UNKNOWN ], [ $wildAnimals, $wildAnimals, Type::Tiny::CMP_EQUAL ], [ $petAnimals, $catAnimals, Type::Tiny::CMP_UNKNOWN ], [ $catAnimals, $petAnimals, Type::Tiny::CMP_UNKNOWN ], [ $catAnimals, $catAnimals2, Type::Tiny::CMP_EQUAL ], [ $catAnimals2, $catAnimals, Type::Tiny::CMP_EQUAL ], ); for (@combos) { my ($t1, $t2, $r) = @$_; is(Type::Tiny::cmp($t1, $t2), $r, "Relationship between $t1 and $t2"); } done_testing; errors.t000644001750001750 212213601673061 20310 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Enum=pod =encoding utf-8 =head1 PURPOSE Checks enum type constraints throw sane error messages. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Types::Standard qw(Int); use Type::Tiny::Enum; like( exception { Type::Tiny::Enum->new(parent => Int) }, qr/^Enum type constraints cannot have a parent constraint/, ); like( exception { Type::Tiny::Enum->new(constraint => sub { 1 }) }, qr/^Enum type constraints cannot have a constraint coderef/, ); like( exception { Type::Tiny::Enum->new(inlined => sub { 1 }) }, qr/^Enum type constraints cannot have a inlining coderef/, ); like( exception { Type::Tiny::Enum->new() }, qr/^Need to supply list of values/, ); ok( !exception { Type::Tiny::Enum->new(values => [qw/foo bar/]) }, ); done_testing; basic.t000644001750001750 436113601673061 21626 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Intersection=pod =encoding utf-8 =head1 PURPOSE Checks intersection type constraints work. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use BiggerLib qw( :types ); use Type::Utils qw( intersection ); { my $x; sub FooBarAndDoesQuux () { $x ||= intersection(FooBarAndDoesQuux => [FooBar, DoesQuux]) } } isa_ok( FooBarAndDoesQuux, 'Type::Tiny::Intersection', 'FooBarAndDoesQuux', ); isa_ok( FooBarAndDoesQuux->[0], 'Type::Tiny::Class', 'FooBarAndDoesQuux->[0]', ); isa_ok( FooBarAndDoesQuux->[1], 'Type::Tiny::Role', 'FooBarAndDoesQuux->[1]', ); is( FooBarAndDoesQuux."", 'FooBar&DoesQuux', 'stringification good', ); my $something = bless [] => do { package Something; sub DOES { return 1 if $_[1] eq 'Quux'; $_[0]->isa($_[0]); } __PACKAGE__; }; should_fail("Foo::Bar"->new, FooBarAndDoesQuux); should_pass("Foo::Baz"->new, FooBarAndDoesQuux); should_fail($something, FooBarAndDoesQuux); my $something_else = bless [] => do { package Something::Else; sub DOES { return 1 if $_[1] eq 'Else'; $_[0]->isa($_[0]); } __PACKAGE__; }; should_fail($something_else, FooBarAndDoesQuux); should_fail("Foo::Bar", FooBarAndDoesQuux); should_fail("Foo::Baz", FooBarAndDoesQuux); require Types::Standard; my $reftype_array = Types::Standard::Ref["ARRAY"]; { my $x; sub NotherSect () { $x ||= intersection(NotherUnion => [FooBarAndDoesQuux, $reftype_array]) } } is( scalar @{+NotherSect}, 3, "intersections don't get unnecessarily deep", ); note NotherSect->inline_check('$X'); should_pass(bless([], "Foo::Baz"), NotherSect); should_fail(bless({}, "Foo::Baz"), NotherSect); my $SmallEven = SmallInteger & sub { $_ % 2 == 0 }; isa_ok($SmallEven, "Type::Tiny::Intersection"); ok(!$SmallEven->can_be_inlined, "not ($SmallEven)->can_be_inlined"); should_pass(2, $SmallEven); should_fail(20, $SmallEven); should_fail(3, $SmallEven); done_testing; cmp.t000644001750001750 304113601673061 21316 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Intersection=pod =encoding utf-8 =head1 PURPOSE Check cmp for Type::Tiny::Intersection. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::TypeTiny; use Types::Common::Numeric qw(PositiveInt); use Types::Standard qw(Int Num); my $Even = Int->create_child_type(name => 'Even', constraint => sub { not $_ % 2 }); my $PositiveEven = $Even & +PositiveInt; should_pass(2, $PositiveEven); should_fail(-2, $PositiveEven); should_fail(1, $PositiveEven); ok_subtype( Num ,=> Int, PositiveInt, $Even, $PositiveEven ); ok_subtype( Int ,=> PositiveInt, $Even, $PositiveEven ); ok_subtype( PositiveInt ,=> $PositiveEven ); ok_subtype( $Even ,=> $PositiveEven ); ok_subtype(Num->create_child_type, Int, PositiveInt, $Even, $PositiveEven->create_child_type); ok_subtype(Int->create_child_type, PositiveInt, $Even, $PositiveEven->create_child_type); ok_subtype(PositiveInt->create_child_type, $PositiveEven->create_child_type); ok_subtype($Even->create_child_type, $PositiveEven->create_child_type); ok_subtype($PositiveEven, $PositiveEven->create_child_type); ok($Even > $PositiveEven, 'Even >'); ok($PositiveEven < $Even, '< Even'); ok(Int > $PositiveEven, 'Int >'); ok($PositiveEven < Int, '< Int'); ok($PositiveEven == $PositiveEven->create_child_type, '=='); done_testing; constrainedobject.t000644001750001750 417613601673061 24251 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Intersection=pod =encoding utf-8 =head1 PURPOSE Check C, C, and C work for L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::TypeTiny; BEGIN { package Local::Class; use overload ( q[""] => sub { shift->as_string }, q[0+] => sub { shift->as_number }, fallback => 1, ); sub new { my $class = shift; my %args = ref $_[0] ? %{$_[0]} : @_; bless \%args => $class; } sub AUTOLOAD { my $self = shift; our $AUTOLOAD; (my $method = $AUTOLOAD) =~ s/^.*:://; $self->{$method}; } sub DOES { my $self = shift; my ($role) = @_; return 1 if $role eq 'Local::Role'; $self->SUPER::DOES(@_); } sub can { my $self = shift; my ($method) = @_; my $r = $self->SUPER::can(@_); return $r if $r; if ($method !~ /^__/) { return sub { shift->{$method} }; } $r; } sub DESTROY { } }; use Type::Tiny::Class; use Type::Tiny::Duck; use Type::Tiny::Role; use Types::Standard -types; my $class_type = Type::Tiny::Class->new(class => 'Local::Class'); my $role_type = Type::Tiny::Role->new(role => 'Local::Role'); my $duck_type = Type::Tiny::Duck->new(methods => [qw/foo bar baz quux/]); my $intersect = $class_type & $role_type & $duck_type; my $new = $intersect->with_attribute_values(foo => '%_<5'); my @new = @{ $new->type_constraints }; ok($new->[0] == $class_type->with_attribute_values(foo => '%_<5')); ok($new->[1] == $role_type); ok($new->[2] == $duck_type); # nothing can pass this constraint but that doesn't matter my $new2 = ((Int) & $class_type & (ArrayRef) & $role_type & $duck_type) ->with_attribute_values(foo => '%_<5'); my @new2 = @{ $new2->type_constraints }; ok($new2->[0] == Int); ok($new2->[1] == $class_type->with_attribute_values(foo => '%_<5')); ok($new2->[2] == ArrayRef); ok($new2->[3] == $role_type); ok($new2->[4] == $duck_type); done_testing(); errors.t000644001750001750 301513601673061 22054 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Intersection=pod =encoding utf-8 =head1 PURPOSE Checks intersection type constraints throw sane error messages. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Types::Standard qw(Int ArrayRef); use Type::Tiny::Intersection; like( exception { Type::Tiny::Intersection->new(parent => Int) }, qr/^Intersection type constraints cannot have a parent constraint/, ); like( exception { Type::Tiny::Intersection->new(constraint => sub { 1 }) }, qr/^Intersection type constraints cannot have a constraint coderef/, ); like( exception { Type::Tiny::Intersection->new(inlined => sub { 1 }) }, qr/^Intersection type constraints cannot have a inlining coderef/, ); like( exception { Type::Tiny::Intersection->new() }, qr/^Need to supply list of type constraints/, ); my $e = exception { Type::Tiny::Intersection ->new(name => "Elsa", type_constraints => [Int, Int]) ->assert_valid( 3.14159 ); }; is_deeply( $e->explain, [ '"Int&Int" requires that the value pass "Int" and "Int"', 'Value "3.14159" did not pass type constraint "Int"', '"Int" is defined as: (do { my $tmp = $_; defined($tmp) and !ref($tmp) and $tmp =~ /\\A-?[0-9]+\\z/ })', ], ) or diag explain($e->explain); done_testing; basic.t000644001750001750 216313601673061 20057 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Role=pod =encoding utf-8 =head1 PURPOSE Checks role type constraints work. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use BiggerLib qw( :types ); isa_ok(DoesQuux, "Type::Tiny", "DoesQuux"); isa_ok(DoesQuux, "Type::Tiny::Role", "DoesQuux"); should_fail("Foo::Bar"->new, DoesQuux); should_pass("Foo::Baz"->new, DoesQuux); should_fail(undef, DoesQuux); should_fail({}, DoesQuux); should_fail(FooBar, DoesQuux); should_fail(FooBaz, DoesQuux); should_fail(DoesQuux, DoesQuux); should_fail("Quux", DoesQuux); is( 'Type::Tiny::Role'->new( role => 'Xyzzy' )->inline_check('$x'), 'Type::Tiny::Role'->new({ role => 'Xyzzy' })->inline_check('$x'), 'constructor can be passed a hash or hashref', ); done_testing; errors.t000644001750001750 252113601673061 20310 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Role=pod =encoding utf-8 =head1 PURPOSE Checks role type constraints throw sane error messages. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Types::Standard qw(Int); use Type::Tiny::Role; like( exception { Type::Tiny::Role->new(parent => Int, role => 'Foo') }, qr/^Role type constraints cannot have a parent/, ); like( exception { Type::Tiny::Role->new(constraint => sub { 1 }, role => 'Foo') }, qr/^Role type constraints cannot have a constraint coderef/, ); like( exception { Type::Tiny::Role->new(inlined => sub { 1 }, role => 'Foo') }, qr/^Role type constraints cannot have an inlining coderef/, ); like( exception { Type::Tiny::Role->new() }, qr/^Need to supply role name/, ); { package Bar; sub new { bless [], shift } sub DOES { 0 } } my $e = exception { Type::Tiny::Role ->new(name => "Elsa", role => "Foo") ->assert_valid( Bar->new ); }; is_deeply( $e->explain, [ '"Elsa" requires that the reference does Foo', "The reference doesn't Foo", ], ); done_testing; basic.t000644001750001750 610613601673061 20247 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Union=pod =encoding utf-8 =head1 PURPOSE Checks union type constraints work. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use BiggerLib qw( :types ); use Type::Utils qw( union class_type ); { my $x; sub FooBarOrDoesQuux () { $x ||= union(FooBarOrDoesQuux => [FooBar, DoesQuux]) } } isa_ok( FooBarOrDoesQuux, 'Type::Tiny::Union', 'FooBarOrDoesQuux', ); isa_ok( FooBarOrDoesQuux->[0], 'Type::Tiny::Class', 'FooBarOrDoesQuux->[0]', ); isa_ok( FooBarOrDoesQuux->[1], 'Type::Tiny::Role', 'FooBarOrDoesQuux->[1]', ); is( FooBarOrDoesQuux."", 'FooBar|DoesQuux', 'stringification good', ); my $something = bless [] => do { package Something; sub DOES { return 1 if $_[1] eq 'Quux'; $_[0]->isa($_[0]); } __PACKAGE__; }; should_pass("Foo::Bar"->new, FooBarOrDoesQuux); should_pass("Foo::Baz"->new, FooBarOrDoesQuux); should_pass($something, FooBarOrDoesQuux); my $something_else = bless [] => do { package Something::Else; sub DOES { return 1 if $_[1] eq 'Else'; $_[0]->isa($_[0]); } __PACKAGE__; }; should_fail($something_else, FooBarOrDoesQuux); should_fail("Foo::Bar", FooBarOrDoesQuux); should_fail("Foo::Baz", FooBarOrDoesQuux); { my $x; sub NotherUnion () { $x ||= union(NotherUnion => [BigInteger, FooBarOrDoesQuux, SmallInteger]) } } is( scalar @{+NotherUnion}, 4, "unions don't get unnecessarily deep", ); { package Local::A } { package Local::B } { package Local::C } { package Local::A::A; our @ISA = qw(Local::A) } { package Local::A::B; our @ISA = qw(Local::A) } { package Local::A::AB; our @ISA = qw(Local::A::A Local::A::B) } { package Local::A::X; our @ISA = qw(Local::A) } my $c1 = union [ class_type({ class => "Local::A::AB" }), class_type({ class => "Local::A::X" }), ]; ok( $c1->parent == class_type({ class => "Local::A" }), "can climb up parents of union type constraints to find best common ancestor", ); my $c2 = union [ class_type({ class => "Local::A" }), class_type({ class => "Local::B" }), class_type({ class => "Local::C" }), ]; ok( $c2->parent == Types::Standard::Object(), "can climb up parents of union type constraints to find best common ancestor (again)", ); is( $c2->find_type_for( bless({}, 'Local::B') )->class, 'Local::B', 'Union find_type_for', ); is( $c2->find_type_for( bless({}, 'Local::A::A') )->class, 'Local::A', 'Union find_type_for (less obvious)', ); is( $c2->find_type_for( bless({}, 'Local::A::AB') )->class, 'Local::A', 'Union find_type_for (ambiguous)', ); is( $c2->find_type_for( bless({}, 'Local::D') ), undef, 'Union find_type_for (none)', ); ok( (FooBar|DoesQuux)==(DoesQuux|FooBar), 'Union equals', ); ok( (FooBar|DoesQuux)!=(DoesQuux|SmallInteger), 'Union not equals', ); done_testing; constrainedobject.t000644001750001750 347013601673061 22667 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Union=pod =encoding utf-8 =head1 PURPOSE Check C, C, and C work for L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::TypeTiny; BEGIN { package Local::Class; use overload ( q[""] => sub { shift->as_string }, q[0+] => sub { shift->as_number }, fallback => 1, ); sub new { my $class = shift; my %args = ref $_[0] ? %{$_[0]} : @_; bless \%args => $class; } sub AUTOLOAD { my $self = shift; our $AUTOLOAD; (my $method = $AUTOLOAD) =~ s/^.*:://; $self->{$method}; } sub DOES { my $self = shift; my ($role) = @_; return 1 if $role eq 'Local::Role'; $self->SUPER::DOES(@_); } sub can { my $self = shift; my ($method) = @_; my $r = $self->SUPER::can(@_); return $r if $r; if ($method !~ /^__/) { return sub { shift->{$method} }; } $r; } sub DESTROY { } }; use Type::Tiny::Class; use Type::Tiny::Duck; use Type::Tiny::Role; use Types::Standard -types; my $class_type = Type::Tiny::Class->new(class => 'Local::Class'); my $role_type = Type::Tiny::Role->new(role => 'Local::Role'); my $duck_type = Type::Tiny::Duck->new(methods => [qw/foo bar baz quux/]); my $intersect = $class_type | $role_type | $duck_type; my $new = $intersect->with_attribute_values(foo => '%_<5'); my @new = @{ $new->type_constraints }; ok($new->[0] == $class_type->with_attribute_values(foo => '%_<5')); ok($new->[1] == $role_type->with_attribute_values(foo => '%_<5')); ok($new->[2] == $duck_type->with_attribute_values(foo => '%_<5')); done_testing(); errors.t000644001750001750 345213601673061 20503 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Union=pod =encoding utf-8 =head1 PURPOSE Checks union type constraints throw sane error messages. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Types::Standard qw(Int ArrayRef); use Type::Tiny::Union; like( exception { Type::Tiny::Union->new(parent => Int) }, qr/^Union type constraints cannot have a parent constraint/, ); like( exception { Type::Tiny::Union->new(constraint => sub { 1 }) }, qr/^Union type constraints cannot have a constraint coderef/, ); like( exception { Type::Tiny::Union->new(inlined => sub { 1 }) }, qr/^Union type constraints cannot have a inlining coderef/, ); like( exception { Type::Tiny::Union->new() }, qr/^Need to supply list of type constraints/, ); my $e = exception { Type::Tiny::Union ->new(name => "Elsa", type_constraints => [Int, ArrayRef[Int]]) ->assert_valid( 3.14159 ); }; is_deeply( $e->explain, [ '"Int|ArrayRef[Int]" requires that the value pass "ArrayRef[Int]" or "Int"', 'Value "3.14159" did not pass type constraint "Int"', ' Value "3.14159" did not pass type constraint "Int"', ' "Int" is defined as: (do { my $tmp = $_; defined($tmp) and !ref($tmp) and $tmp =~ /\\A-?[0-9]+\\z/ })', 'Value "3.14159" did not pass type constraint "ArrayRef[Int]"', ' "ArrayRef[Int]" is a subtype of "ArrayRef"', ' "ArrayRef" is a subtype of "Ref"', ' Value "3.14159" did not pass type constraint "Ref"', ' "Ref" is defined as: (!!ref($_))', ], ) or diag explain($e->explain); done_testing; relationships.t000644001750001750 224013601673061 22045 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-Union=pod =encoding utf-8 =head1 PURPOSE Checks union type constraint subtype/supertype relationships. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use BiggerLib qw( :types ); use Type::Utils qw( union class_type ); use Types::Standard Object => { -as => "Blessed" }; { my $x; sub FooBarOrDoesQuux () { $x ||= union(FooBarOrDoesQuux => [FooBar, DoesQuux]) } } ok( FooBarOrDoesQuux->is_a_type_of(FooBarOrDoesQuux), ); ok( FooBarOrDoesQuux->is_supertype_of(FooBar), ); ok( FooBarOrDoesQuux->is_supertype_of(DoesQuux), ); ok( FooBarOrDoesQuux->is_a_type_of(Blessed), ); ok( ! FooBarOrDoesQuux->is_supertype_of(Blessed), ); ok( ! FooBarOrDoesQuux->is_subtype_of(FooBarOrDoesQuux), ); ok( FooBarOrDoesQuux->is_subtype_of(Blessed), ); done_testing; double-union.t000644001750001750 136013601673061 22003 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-_HalfOp=pod =encoding utf-8 =head1 PURPOSE Ensure that the following works: ArrayRef[Str] | Undef | Str =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings FATAL => 'all'; use Test::More; use Types::Standard -all; my $union = eval { ArrayRef[Str] | Undef | Str }; SKIP: { ok $union or skip 'broken type', 6; ok $union->check([qw/ a b /]); ok !$union->check([[]]); ok $union->check(undef); ok $union->check("a"); ok !$union->check([undef]); ok !$union->check({}); } done_testing; overload-precedence.t000644001750001750 146113601673061 23313 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Tiny-_HalfOp=pod =encoding utf-8 =head1 PURPOSE Ensure that the following works consistently on all supported Perls: ArrayRef[Int] | HashRef[Int] =head1 AUTHOR Graham Knop Ehaarg@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Graham Knop. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings FATAL => 'all'; use Test::More; use Types::Standard -all; my $union = eval { ArrayRef[Int] | HashRef[Int] }; SKIP: { ok $union or skip 'broken type', 6; ok $union->check({welp => 1}); ok !$union->check({welp => 1.4}); ok !$union->check({welp => "guff"}); ok $union->check([1]); ok !$union->check([1.4]); ok !$union->check(["guff"]); } done_testing; classifier.t000644001750001750 214313601673061 20376 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Utils=pod =encoding utf-8 =head1 PURPOSE Test L C function. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Type::Utils qw( classifier ); use Types::Standard -types; my $classify = classifier(Num, Str, Int, Ref, ArrayRef, HashRef, Any, InstanceOf['Type::Tiny']); sub classified ($$) { my $got = $classify->($_[0]); my $expected = $_[1]; local $Test::Builder::Level = $Test::Builder::Level + 1; is( $got->name, $expected->name, sprintf("%s classified as %s", Type::Tiny::_dd($_[0]), $expected), ); } classified(42, Int); classified(1.1, Num); classified("Hello world", Str); classified("42", Int); classified("1.1", Num); classified((\(my $x)), Ref); classified([], ArrayRef); classified({}, HashRef); classified(undef, Any); classified(Num, InstanceOf['Type::Tiny']); done_testing; dwim-both.t000644001750001750 251713601673061 20151 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Utils=pod =encoding utf-8 =head1 PURPOSE Checks sane behaviour of C from L when both Moose and Mouse are loaded. =head1 DEPENDENCIES Mouse 1.00 and Moose 2.0000; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; { package AAA; use Test::Requires { "Mouse" => "1.00" } }; { package BBB; use Test::Requires { "Moose" => "2.0000" } }; { package Minnie; use Mouse; use Mouse::Util::TypeConstraints qw(:all); subtype "FortyFive", as "Int", where { $_ == 40 or $_ == 5 }; } { package Bulwinkle; use Moose; use Moose::Util::TypeConstraints qw(:all); subtype "FortyFive", as "Int", where { $_ == 45 }; } use Test::TypeTiny; use Type::Utils 0.015 qw(dwim_type); my $mouse = dwim_type "FortyFive", for => "Minnie"; should_fail 2, $mouse; should_pass 5, $mouse; should_pass 40, $mouse; should_fail 45, $mouse; should_fail 99, $mouse; my $moose = dwim_type "FortyFive", for => "Bulwinkle"; should_fail 2, $moose; should_fail 5, $moose; should_fail 40, $moose; should_pass 45, $moose; should_fail 99, $moose; done_testing; dwim-moose.t000644001750001750 473213601673061 20340 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Utils=pod =encoding utf-8 =head1 PURPOSE Checks Moose type constraints, and L type constraints are picked up by C from L. =head1 DEPENDENCIES Moose 2.0201 and MooseX::Types 0.31; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Requires { "Moose" => "2.0201" }; use Test::Requires { "MooseX::Types" => "0.31" }; use Test::TypeTiny; use Moose; use Moose::Util::TypeConstraints qw(:all); use Type::Utils qw(dwim_type); # Creating a type constraint with Moose subtype "Two", as "Int", where { $_ eq 2 }; my $two = dwim_type("Two"); my $twos = dwim_type("ArrayRef[Two]"); isa_ok($two, 'Type::Tiny', '$two'); isa_ok($twos, 'Type::Tiny', '$twos'); should_pass(2, $two); should_fail(3, $two); should_pass([2, 2, 2], $twos); should_fail([2, 3, 2], $twos); # Creating a type constraint with MooseX::Types { package MyTypes; use MooseX::Types -declare => ["Three"]; use MooseX::Types::Moose "Int"; subtype Three, as Int, where { $_ eq 3 }; $INC{'MyTypes.pm'} = __FILE__; } # Note that MooseX::Types namespace-prefixes its types. my $three = dwim_type("MyTypes::Three"); my $threes = dwim_type("ArrayRef[MyTypes::Three]"); isa_ok($three, 'Type::Tiny', '$three'); isa_ok($threes, 'Type::Tiny', '$threes'); should_pass(3, $three); should_fail(4, $three); should_pass([3, 3, 3], $threes); should_fail([3, 4, 3], $threes); { my $testclass = 'Local::Some::Class'; my $fallback = dwim_type($testclass); should_pass(bless({}, $testclass), $fallback); should_fail(bless({}, 'main'), $fallback); my $fallbackp = dwim_type("ArrayRef[$testclass]"); should_pass([bless({}, $testclass)], $fallbackp); should_pass([], $fallbackp); should_fail([bless({}, 'main')], $fallbackp); my $fallbacku = dwim_type("ArrayRef[$testclass]", fallback => []); is($fallbacku, undef); } { my $testclass = 'Local::Some::Class'; my $fallback = dwim_type("$testclass\::"); should_pass(bless({}, $testclass), $fallback); should_fail(bless({}, 'main'), $fallback); my $fallbackp = dwim_type("ArrayRef[$testclass\::]"); should_pass([bless({}, $testclass)], $fallbackp); should_pass([], $fallbackp); should_fail([bless({}, 'main')], $fallbackp); } done_testing; dwim-mouse.t000644001750001750 473613601673061 20352 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Utils=pod =encoding utf-8 =head1 PURPOSE Checks Mouse type constraints, and L type constraints are picked up by C from L. =head1 DEPENDENCIES Mouse 1.00 and MouseX::Types 0.06; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Requires { "Mouse" => "1.00" }; use Test::Requires { "MouseX::Types" => "0.06" }; use Test::TypeTiny; use Mouse; use Mouse::Util::TypeConstraints qw(:all); use Type::Utils 0.015 qw(dwim_type); # Creating a type constraint with Mouse subtype "Two", as "Int", where { $_ eq 2 }; my $two = dwim_type("Two"); my $twos = dwim_type("ArrayRef[Two]"); isa_ok($two, 'Type::Tiny', '$two'); isa_ok($twos, 'Type::Tiny', '$twos'); should_pass(2, $two); should_fail(3, $two); should_pass([2, 2, 2], $twos); should_fail([2, 3, 2], $twos); # Creating a type constraint with MouseX::Types { package MyTypes; use MouseX::Types -declare => ["Three"]; use MouseX::Types::Moose "Int"; subtype Three, as Int, where { $_ eq 3 }; $INC{'MyTypes.pm'} = __FILE__; } # Note that MouseX::Types namespace-prefixes its types. my $three = dwim_type("MyTypes::Three"); my $threes = dwim_type("ArrayRef[MyTypes::Three]"); isa_ok($three, 'Type::Tiny', '$three'); isa_ok($threes, 'Type::Tiny', '$threes'); should_pass(3, $three); should_fail(4, $three); should_pass([3, 3, 3], $threes); should_fail([3, 4, 3], $threes); { my $testclass = 'Local::Some::Class'; my $fallback = dwim_type($testclass); should_pass(bless({}, $testclass), $fallback); should_fail(bless({}, 'main'), $fallback); my $fallbackp = dwim_type("ArrayRef[$testclass]"); should_pass([bless({}, $testclass)], $fallbackp); should_pass([], $fallbackp); should_fail([bless({}, 'main')], $fallbackp); my $fallbacku = dwim_type("ArrayRef[$testclass]", fallback => []); is($fallbacku, undef); } { my $testclass = 'Local::Some::Class'; my $fallback = dwim_type("$testclass\::"); should_pass(bless({}, $testclass), $fallback); should_fail(bless({}, 'main'), $fallback); my $fallbackp = dwim_type("ArrayRef[$testclass\::]"); should_pass([bless({}, $testclass)], $fallbackp); should_pass([], $fallbackp); should_fail([bless({}, 'main')], $fallbackp); } done_testing; match-on-type.t000644001750001750 1152713601673061 20765 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Utils=pod =encoding utf-8 =head1 PURPOSE Test L C and C functions. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Type::Utils qw( match_on_type compile_match_on_type ); use Types::Standard -types; sub to_json; *to_json = compile_match_on_type( HashRef() => sub { my $hash = shift; '{ ' . ( join ", " => map { '"' . $_ . '" : ' . to_json( $hash->{$_} ) } sort keys %$hash ) . ' }'; }, ArrayRef() => sub { my $array = shift; '[ ' . ( join ", " => map { to_json($_) } @$array ) . ' ]'; }, Num() => q {$_}, Str() => q { '"' . $_ . '"' }, Undef() => q {'null'}, ScalarRef() &+ sub { Bool->check($$_) } => q { $$_ ? 'true' : 'false' }, => sub { die "$_ is not acceptable json type" }, ); is( to_json({foo => 1, bar => 2, baz => [3 .. 5], quux => undef, xyzzy => \1 }), '{ "bar" : 2, "baz" : [ 3, 4, 5 ], "foo" : 1, "quux" : null, "xyzzy" : true }', 'to_json using compile_match_on_type works', ); sub to_json_2 { return match_on_type $_[0] => ( HashRef() => sub { my $hash = shift; '{ ' . ( join ", " => map { '"' . $_ . '" : ' . to_json_2( $hash->{$_} ) } sort keys %$hash ) . ' }'; }, ArrayRef() => sub { my $array = shift; '[ ' . ( join ", " => map { to_json_2($_) } @$array ) . ' ]'; }, Num() => q {$_}, Str() => q { '"' . $_ . '"' }, Undef() => q {'null'}, ScalarRef() &+ sub { Bool->check($$_) } => q { $$_ ? 'true' : 'false' }, => sub { die "$_ is not acceptable json type" }, ); } is( to_json_2({foo => 1, bar => 2, baz => [3 .. 5], quux => undef, xyzzy => \1 }), '{ "bar" : 2, "baz" : [ 3, 4, 5 ], "foo" : 1, "quux" : null, "xyzzy" : true }', 'to_json_2 using match_on_type works', ); like( exception { to_json(do { my $x = "hello"; \$x }) }, qr{\ASCALAR\(\w+\) is not acceptable json type}, "fallthrough works for compile_match_on_type", ); like( exception { to_json_2(do { my $x = "hello"; \$x }) }, qr{\ASCALAR\(\w+\) is not acceptable json type}, "fallthrough works for match_on_type", ); my $compiled1 = compile_match_on_type( HashRef() => sub { 'HASH' }, ArrayRef() => sub { 'ARRAY' }, ); is(ref($compiled1), 'CODE', 'compile_match_on_type returns a coderef'); is($compiled1->({}), 'HASH', '... correct result'); is($compiled1->([]), 'ARRAY', '... correct result'); like( exception { $compiled1->(42) }, qr/^No cases matched for Value "?42"?/, '... correct exception', ); if ($ENV{EXTENDED_TESTING}) { require Benchmark; my $iters = 5_000; my $standard = Benchmark::timethis( $iters, '::to_json_2({foo => 1, bar => 2, baz => [3 .. 5], quux => undef})', 'standard', 'none', ); diag "match_on_type: " . Benchmark::timestr($standard); my $compiled = Benchmark::timethis( $iters, '::to_json({foo => 1, bar => 2, baz => [3 .. 5], quux => undef})', 'compiled', 'none', ); diag "compile_match_on_type: " . Benchmark::timestr($compiled); } like( exception { match_on_type([], Int, sub { 44 }); }, qr/^No cases matched/, 'match_on_type with no match', ); like( exception { compile_match_on_type(Int, sub { 44 })->([]); }, qr/^No cases matched/, 'coderef compiled by compile_match_on_type with no match', ); our $context; MATCH_VOID: { match_on_type([], ArrayRef, sub { $context = wantarray }); ok(!defined($context), 'match_on_type void context'); }; MATCH_SCALAR: { my $x = match_on_type([], ArrayRef, sub { $context = wantarray }); ok(defined($context) && !$context, 'match_on_type scalar context'); }; MATCH_LIST: { my @x = match_on_type([], ArrayRef, sub { $context = wantarray }); ok(defined($context) && $context, 'match_on_type list context'); }; MATCH_VOID_STRINGOFCODE: { match_on_type([], ArrayRef, q{ $::context = wantarray }); ok(!defined($context), 'match_on_type void context (string of code)'); }; MATCH_SCALAR_STRINGOFCODE: { my $x = match_on_type([], ArrayRef, q{ $::context = wantarray }); ok(defined($context) && !$context, 'match_on_type scalar context (string of code)'); }; MATCH_LIST_STRINGOFCODE: { my @x = match_on_type([], ArrayRef, q{ $::context = wantarray }); ok(defined($context) && $context, 'match_on_type list context (string of code)'); }; my $compiled = compile_match_on_type(ArrayRef, sub { $context = wantarray }); COMPILE_VOID: { $compiled->([]); ok(!defined($context), 'compile_match_on_type void context'); }; COMPILE_SCALAR: { my $x = $compiled->([]); ok(defined($context) && !$context, 'compile_match_on_type scalar context'); }; COMPILE_LIST: { my @x = $compiled->([]); ok(defined($context) && $context, 'compile_match_on_type list context'); }; done_testing; warnings.t000644001750001750 174213601673061 20106 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Type-Utils=pod =encoding utf-8 =head1 PURPOSE Tests warnings raised by L. =head1 DEPENDENCIES Requires Perl 5.14 and L; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires '5.014'; use Test::Requires { 'Test::Warnings' => 0.005 }; #warnings added in this version use Test::Warnings qw( :no_end_test warnings ); use Type::Library -base, -declare => qw/WholeNumber/; use Type::Utils -all; use Types::Standard qw/Int/; my @warnings = warnings { declare WholeNumber as Int; }; like( $warnings[0], qr/^Possible missing comma after 'declare WholeNumber'/, 'warning for missing comma', ); done_testing; basic.t000644001750001750 634213601673061 21253 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Common-Numeric=pod =encoding utf-8 =head1 PURPOSE Tests constraints for L. These tests are based on tests from L. =head1 AUTHORS =over 4 =item * Matt S Trout - mst (at) shadowcatsystems.co.uk (L) =item * K. James Cheetham =item * Guillermo Roditi =back Test cases ported to L by Toby Inkster. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Matt S Trout - mst (at) shadowcatsystems.co.uk (L). This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings FATAL => 'all'; use Test::More; use Test::TypeTiny; use Types::Common::Numeric -all; should_fail(100, SingleDigit, "SingleDigit 100"); should_fail(10, SingleDigit, "SingleDigit 10"); should_pass(9, SingleDigit, "SingleDigit 9"); should_pass(1, SingleDigit, "SingleDigit 1"); should_pass(0, SingleDigit, "SingleDigit 0"); should_pass(-1, SingleDigit, "SingleDigit -1"); should_pass(-9, SingleDigit, "SingleDigit -9"); should_fail(-10, SingleDigit, "SingleDigit -10"); should_fail(-100, PositiveInt, "PositiveInt (-100)"); should_fail(0, PositiveInt, "PositiveInt (0)"); should_fail(100.885, PositiveInt, "PositiveInt (100.885)"); should_pass(100, PositiveInt, "PositiveInt (100)"); should_fail(0, PositiveNum, "PositiveNum (0)"); should_pass(100.885, PositiveNum, "PositiveNum (100.885)"); should_fail(-100.885, PositiveNum, "PositiveNum (-100.885)"); should_pass(0.0000000001, PositiveNum, "PositiveNum (0.0000000001)"); should_fail(-100, PositiveOrZeroInt, "PositiveOrZeroInt (-100)"); should_pass(0, PositiveOrZeroInt, "PositiveOrZeroInt (0)"); should_fail(100.885, PositiveOrZeroInt, "PositiveOrZeroInt (100.885)"); should_pass(100, PositiveOrZeroInt, "PositiveOrZeroInt (100)"); should_pass(0, PositiveOrZeroNum, "PositiveOrZeroNum (0)"); should_pass(100.885, PositiveOrZeroNum, "PositiveOrZeroNum (100.885)"); should_fail(-100.885, PositiveOrZeroNum, "PositiveOrZeroNum (-100.885)"); should_pass(0.0000000001, PositiveOrZeroNum, "PositiveOrZeroNum (0.0000000001)"); should_fail(100, NegativeInt, "NegativeInt (100)"); should_fail(-100.885, NegativeInt, "NegativeInt (-100.885)"); should_pass(-100, NegativeInt, "NegativeInt (-100)"); should_fail(0, NegativeInt, "NegativeInt (0)"); should_pass(-100.885, NegativeNum, "NegativeNum (-100.885)"); should_fail(100.885, NegativeNum, "NegativeNum (100.885)"); should_fail(0, NegativeNum, "NegativeNum (0)"); should_pass(-0.0000000001, NegativeNum, "NegativeNum (-0.0000000001)"); should_fail(100, NegativeOrZeroInt, "NegativeOrZeroInt (100)"); should_fail(-100.885, NegativeOrZeroInt, "NegativeOrZeroInt (-100.885)"); should_pass(-100, NegativeOrZeroInt, "NegativeOrZeroInt (-100)"); should_pass(0, NegativeOrZeroInt, "NegativeOrZeroInt (0)"); should_pass(-100.885, NegativeOrZeroNum, "NegativeOrZeroNum (-100.885)"); should_fail(100.885, NegativeOrZeroNum, "NegativeOrZeroNum (100.885)"); should_pass(0, NegativeOrZeroNum, "NegativeOrZeroNum (0)"); should_pass(-0.0000000001, NegativeOrZeroNum, "NegativeOrZeroNum (-0.0000000001)"); done_testing; ranges.t000644001750001750 1012413601673061 21462 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Common-Numeric=pod =encoding utf-8 =head1 PURPOSE Tests constraints for L's C and C. =head1 AUTHOR Toby Inkster. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2018-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings FATAL => 'all'; use Test::More; use Test::TypeTiny qw( -all ); use Test::Fatal; use Types::Common::Numeric -all; should_fail($_, IntRange[10,15]) for -19 .. +9; should_pass($_, IntRange[10,15]) for 10 .. 15; should_fail($_, IntRange[10,15]) for 16 .. 20; should_fail($_ + 0.5, IntRange[10,15]) for -9 .. 20; should_fail($_, IntRange[10,15]) for ([], {}, sub { 3 }, "hello world"); should_fail($_, IntRange[10]) for -19 .. 9; should_pass($_, IntRange[10]) for 10 .. 24, 1000, 1_000_000; ########### should_fail($_, NumRange[10,15]) for -19 .. +9; should_pass($_, NumRange[10,15]) for 10 .. 15; should_fail($_, NumRange[10,15]) for 16 .. 20; should_fail($_ + 0.5, NumRange[10,15]) for -9 .. 9; should_pass($_ + 0.5, NumRange[10,15]) for 10 .. 14; should_fail($_ + 0.5, NumRange[10,15]) for 15 .. 20; should_fail($_, NumRange[10,15]) for ([], {}, sub { 3 }, "hello world"); should_fail($_, NumRange[10]) for -19 .. 9; should_pass($_, NumRange[10]) for 10 .. 24, 1000, 1_000_000; ########### should_fail( '9.99', NumRange[10,15,0,0] ); should_pass( '10.00', NumRange[10,15,0,0] ); should_pass( '10.01', NumRange[10,15,0,0] ); should_pass( '12.50', NumRange[10,15,0,0] ); should_pass( '14.99', NumRange[10,15,0,0] ); should_pass( '15.00', NumRange[10,15,0,0] ); should_fail( '15.01', NumRange[10,15,0,0] ); should_fail( '9.99', NumRange[10,15,1,0] ); should_fail( '10.00', NumRange[10,15,1,0] ); should_pass( '10.01', NumRange[10,15,1,0] ); should_pass( '12.50', NumRange[10,15,1,0] ); should_pass( '14.99', NumRange[10,15,1,0] ); should_pass( '15.00', NumRange[10,15,1,0] ); should_fail( '15.01', NumRange[10,15,1,0] ); should_fail( '9.99', NumRange[10,15,0,1] ); should_pass( '10.00', NumRange[10,15,0,1] ); should_pass( '10.01', NumRange[10,15,0,1] ); should_pass( '12.50', NumRange[10,15,0,1] ); should_pass( '14.99', NumRange[10,15,0,1] ); should_fail( '15.00', NumRange[10,15,0,1] ); should_fail( '15.01', NumRange[10,15,0,1] ); should_fail( '9.99', NumRange[10,15,1,1] ); should_fail( '10.00', NumRange[10,15,1,1] ); should_pass( '10.01', NumRange[10,15,1,1] ); should_pass( '12.50', NumRange[10,15,1,1] ); should_pass( '14.99', NumRange[10,15,1,1] ); should_fail( '15.00', NumRange[10,15,1,1] ); should_fail( '15.01', NumRange[10,15,1,1] ); ########### should_pass(1, IntRange); should_fail($_, IntRange) for ([], {}, sub { 3 }, "hello world", '1.2345'); should_pass(1, NumRange); should_fail($_, NumRange) for ([], {}, sub { 3 }, "hello world"); should_pass('1.2345', NumRange); ########### foreach my $test ( [NumRange, [{}, 5], qr/NumRange min must be a num/, "NumRange non-numeric min"], [NumRange, [5, {}], qr/NumRange max must be a num/, "NumRange non-numeric max"], [NumRange, [5, 10, {}], qr/NumRange minexcl must be a boolean/, "NumRange non-boolean minexcl"], [NumRange, [5, 10, 0, {}], qr/NumRange maxexcl must be a boolean/, "NumRange non-boolean maxexcl"], [NumRange, [{}, {}], qr/NumRange min must be a num/, "NumRange non-numeric min and max"], [IntRange, [{}, 5], qr/IntRange min must be a int/, "IntRange non-numeric min"], [IntRange, [5, {}], qr/IntRange max must be a int/, "IntRange non-numeric max"], [IntRange, [5, 10, {}], qr/IntRange minexcl must be a boolean/, "IntRange non-boolean minexcl"], [IntRange, [5, 10, 0, {}], qr/IntRange maxexcl must be a boolean/, "IntRange non-boolean maxexcl"], [IntRange, [{}, {}], qr/IntRange min must be a int/, "IntRange non-numeric min and max"], [IntRange, [1.1, 5], qr/IntRange min must be a int/, "IntRange non-integer min"], [IntRange, [5, 9.9], qr/IntRange max must be a int/, "IntRange non-integer max"], ) { my ($base, $params, $qr, $desc) = @$test; my $e = exception { $base->of(@$params) }; like($e, $qr, "Exception thrown for $desc"); } done_testing; basic.t000644001750001750 543113601673061 21115 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Common-String=pod =encoding utf-8 =head1 PURPOSE Tests constraints for L. These tests are based on tests from L. =head1 AUTHORS =over 4 =item * Matt S Trout - mst (at) shadowcatsystems.co.uk (L) =item * K. James Cheetham =item * Guillermo Roditi =back Test cases ported to L by Toby Inkster. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Matt S Trout - mst (at) shadowcatsystems.co.uk (L). This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings FATAL => 'all'; use Test::More; use Test::TypeTiny; use Types::Common::String -all; should_pass('', SimpleStr, "SimpleStr"); should_pass('a string', SimpleStr, "SimpleStr 2"); should_fail("another\nstring", SimpleStr, "SimpleStr 3"); should_fail(join('', ("long string" x 25)), SimpleStr, "SimpleStr 4"); should_fail('', NonEmptyStr, "NonEmptyStr"); should_pass('a string', NonEmptyStr, "NonEmptyStr 2"); should_pass("another string", NonEmptyStr, "NonEmptyStr 3"); should_pass(join('', ("long string" x 25)), NonEmptyStr, "NonEmptyStr 4"); should_pass('good str', NonEmptySimpleStr, "NonEmptySimplrStr"); should_fail('', NonEmptySimpleStr, "NonEmptyStr 2"); should_fail('no', Password, "Password"); should_pass('okay', Password, "Password 2"); should_fail('notokay', StrongPassword, "StrongPassword"); should_pass('83773r_ch01c3', StrongPassword, "StrongPassword 2"); should_fail('NOTOK', LowerCaseSimpleStr, "LowerCaseSimpleStr"); should_pass('ok', LowerCaseSimpleStr, "LowerCaseSimpleStr 2"); should_fail('NOTOK_123`"', LowerCaseSimpleStr, "LowerCaseSimpleStr 3"); should_pass('ok_123`"', LowerCaseSimpleStr, "LowerCaseSimpleStr 4"); should_fail('notok', UpperCaseSimpleStr, "UpperCaseSimpleStr"); should_pass('OK', UpperCaseSimpleStr, "UpperCaseSimpleStr 2"); should_fail('notok_123`"', UpperCaseSimpleStr, "UpperCaseSimpleStr 3"); should_pass('OK_123`"', UpperCaseSimpleStr, "UpperCaseSimpleStr 4"); should_fail('NOTOK', LowerCaseStr, "LowerCaseStr"); should_pass("ok\nok", LowerCaseStr, "LowerCaseStr 2"); should_fail('NOTOK_123`"', LowerCaseStr, "LowerCaseStr 3"); should_pass("ok\n_123`'", LowerCaseStr, "LowerCaseStr 4"); should_fail('notok', UpperCaseStr, "UpperCaseStr"); should_pass("OK\nOK", UpperCaseStr, "UpperCaseStr 2"); should_fail('notok_123`"', UpperCaseStr, "UpperCaseStr 3"); should_pass("OK\n_123`'", UpperCaseStr, "UpperCaseStr 4"); should_pass('032', NumericCode, "NumericCode lives"); should_fail('abc', NumericCode, "NumericCode dies"); should_fail('x18', NumericCode, "mixed NumericCode dies"); done_testing; coerce.t000644001750001750 240113601673061 21266 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Common-String=pod =encoding utf-8 =head1 PURPOSE Tests coercions for L. These tests are based on tests from L. =head1 AUTHORS =over 4 =item * Matt S Trout - mst (at) shadowcatsystems.co.uk (L) =item * K. James Cheetham =item * Guillermo Roditi =back =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Matt S Trout - mst (at) shadowcatsystems.co.uk (L). This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings FATAL => 'all'; use Test::More; use Types::Common::String qw( +LowerCaseSimpleStr +UpperCaseSimpleStr +LowerCaseStr +UpperCaseStr +NumericCode ); is(to_UpperCaseSimpleStr('foo'), 'FOO', 'uppercase str' ); is(to_LowerCaseSimpleStr('BAR'), 'bar', 'lowercase str' ); is(to_UpperCaseStr('foo'), 'FOO', 'uppercase str' ); is(to_LowerCaseStr('BAR'), 'bar', 'lowercase str' ); is(to_NumericCode('4111-1111-1111-1111'), '4111111111111111', 'numeric code' ); is(to_NumericCode('+1 (800) 555-01-23'), '18005550123', 'numeric code' ); done_testing; strlength.t000644001750001750 171713601673061 22051 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Common-String=pod =encoding utf-8 =head1 PURPOSE Tests constraints for L's Ctring =head1 AUTHOR Toby Inkster. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2018-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use utf8; use strict; use warnings FATAL => 'all'; use Test::More; use Test::TypeTiny; use Types::Common::String -all; my $type = StrLength[5,10]; should_fail($_, $type) for ([], {}, sub { 3 }, undef, "", 123, "Hiya", "Hello World"); should_pass($_, $type) for ("Hello", "Hello!", " " x 8, "HelloWorld"); my $type2 = StrLength[4,4]; should_pass("café", $type2); should_pass("™ķ⁹—", $type2); my $type3 = StrLength[4]; should_fail($_, $type3) for ([], {}, sub { 3 }, undef, "", 123); should_pass($_, $type3) for ("Hello", "Hello!", " " x 8, "HelloWorld", "Hiya", "Hello World"); done_testing; unicode.t000644001750001750 310513601673061 21456 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Common-String=pod =encoding utf-8 =head1 PURPOSE Tests Unicode support for L. These tests are based on tests from L. =head1 AUTHORS =over 4 =item * Matt S Trout - mst (at) shadowcatsystems.co.uk (L) =item * K. James Cheetham =item * Guillermo Roditi =back Test cases ported to L by Toby Inkster. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Matt S Trout - mst (at) shadowcatsystems.co.uk (L). This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings FATAL => 'all'; use utf8; use Test::More; use Test::TypeTiny; use Types::Common::String -all; should_pass('CAFÉ', UpperCaseStr, "CAFÉ is uppercase"); should_fail('CAFé', UpperCaseStr, "CAFé is not (entirely) uppercase"); should_fail('ŐħĤăĩ', UpperCaseStr, "----- not entirely uppercase"); should_fail('ŐħĤăĩ', LowerCaseStr, "----- not entirely lowercase"); should_pass('café', LowerCaseStr, "café is lowercase"); should_fail('cafÉ', LowerCaseStr, "cafÉ is not (entirely) lowercase"); should_pass('CAFÉ', UpperCaseSimpleStr, "CAFÉ is uppercase"); should_fail('CAFé', UpperCaseSimpleStr, "CAFé is not (entirely) uppercase"); should_pass('café', LowerCaseSimpleStr, "café is lowercase"); should_fail('cafÉ', LowerCaseSimpleStr, "cafÉ is not (entirely) lowercase"); done_testing; arrayreflength.t000644001750001750 270013601673061 22111 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Standard=pod =encoding utf-8 =head1 PURPOSE Checks the new ArrayRef[$type, $min, $max] from Types::Standard. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2018-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( . ./t ../inc ./inc ); use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw(ArrayRef Int Any); my $type = ArrayRef[Int, 2]; should_fail([], $type); should_fail([0], $type); should_pass([0..1], $type); should_pass([0..2], $type); should_pass([0..3], $type); should_pass([0..4], $type); should_pass([0..5], $type); should_pass([0..6], $type); should_fail([0..1, "nope"], $type); should_fail(["nope", 0..1], $type); $type = ArrayRef[Int, 2, 4]; should_fail([], $type); should_fail([0], $type); should_pass([0..1], $type); should_pass([0..2], $type); should_pass([0..3], $type); should_fail([0..4], $type); should_fail([0..5], $type); should_fail([0..6], $type); should_fail([0..1, "nope"], $type); should_fail(["nope", 0..1], $type); unlike(ArrayRef->of(Any), qr/for/, 'ArrayRef[Any] optimization'); unlike(ArrayRef->of(Any, 2), qr/for/, 'ArrayRef[Any,2] optimization'); unlike(ArrayRef->of(Any, 2, 4), qr/for/, 'ArrayRef[Any,2,4] optimization'); # diag ArrayRef->of(Any, 2, 4)->inline_check('$XXX'); done_testing; basic.t000644001750001750 1067713601673061 20211 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Standard=pod =encoding utf-8 =head1 PURPOSE Checks various values against the type constraints from Types::Standard. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( . ./t ../inc ./inc ); use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard -all; is(Num->library, "Types::Standard", "->library method"); my $var = 123; should_pass(\$var, ScalarRef); should_pass([], ArrayRef); should_pass(+{}, HashRef); should_pass(sub {0}, CodeRef); should_pass(\*STDOUT, GlobRef); should_pass(\(\"Hello"), Ref); should_pass(\*STDOUT, FileHandle); should_pass(qr{x}, RegexpRef); should_pass(1, Str); should_pass(1, Num); should_pass(1, Int); should_pass(1, Defined); should_pass(1, Value); should_pass(undef, Undef); should_pass(undef, Item); should_pass(undef, Any); should_pass('Type::Tiny', ClassName); should_pass('Type::Library', RoleName); should_pass(undef, Bool); should_pass('', Bool); should_pass(0, Bool); should_pass(1, Bool); should_fail(7, Bool); should_pass(\(\"Hello"), ScalarRef); should_fail('Type::Tiny', RoleName); should_fail([], Str); should_fail([], Num); should_fail([], Int); should_pass("4x4", Str); should_fail("4x4", Num); should_fail("4.2", Int); should_fail(undef, Str); should_fail(undef, Num); should_fail(undef, Int); should_fail(undef, Defined); should_fail(undef, Value); { package Local::Class1; use strict; } { no warnings 'once'; $Local::Class2::VERSION = 0.001; @Local::Class3::ISA = qw(UNIVERSAL); @Local::Dummy1::FOO = qw(UNIVERSAL); } { package Local::Class4; sub XYZ () { 1 } } should_fail(undef, ClassName); should_fail([], ClassName); should_pass("Local::Class$_", ClassName) for 2..4; should_fail("Local::Dummy1", ClassName); should_pass([], ArrayRef[Int]); should_pass([1,2,3], ArrayRef[Int]); should_fail([1.1,2,3], ArrayRef[Int]); should_fail([1,2,3.1], ArrayRef[Int]); should_fail([[]], ArrayRef[Int]); should_pass([[3]], ArrayRef[ArrayRef[Int]]); should_fail([["A"]], ArrayRef[ArrayRef[Int]]); my $deep = ArrayRef[HashRef[ArrayRef[HashRef[Int]]]]; ok($deep->can_be_inlined, "$deep can be inlined"); should_pass([{foo1=>[{bar=>1}]},{foo2=>[{baz=>2}]}], $deep); should_pass([{foo1=>[{bar=>1}]},{foo2=>[]}], $deep); should_fail([{foo1=>[{bar=>1}]},{foo2=>[2]}], $deep); should_pass(undef, Maybe[Int]); should_pass(123, Maybe[Int]); should_fail(1.3, Maybe[Int]); my $i = 1; my $f = 1.1; my $s = "Hello"; should_pass(\$s, ScalarRef[Str]); should_pass(\$f, ScalarRef[Str]); should_pass(\$i, ScalarRef[Str]); should_fail(\$s, ScalarRef[Num]); should_pass(\$f, ScalarRef[Num]); should_pass(\$i, ScalarRef[Num]); should_fail(\$s, ScalarRef[Int]); should_fail(\$f, ScalarRef[Int]); should_pass(\$i, ScalarRef[Int]); should_pass(bless([], "Local::Class4"), Ref["ARRAY"]); should_pass(bless({}, "Local::Class4"), Ref["HASH"]); should_pass([], Ref["ARRAY"]); should_pass({}, Ref["HASH"]); should_fail(bless([], "Local::Class4"), Ref["HASH"]); should_fail(bless({}, "Local::Class4"), Ref["ARRAY"]); should_fail([], Ref["HASH"]); should_fail({}, Ref["ARRAY"]); like( exception { ArrayRef["Int"] }, qr{^Parameter to ArrayRef\[\`a\] expected to be a type constraint; got Int}, qq{ArrayRef["Int"] is not a valid type constraint}, ); like( exception { HashRef[[]] }, qr{^Parameter to HashRef\[\`a\] expected to be a type constraint; got ARRAY}, qq{HashRef[[]] is not a valid type constraint}, ); like( exception { ScalarRef[undef] }, qr{^Parameter to ScalarRef\[\`a\] expected to be a type constraint; got}, qq{ScalarRef[undef] is not a valid type constraint}, ); like( exception { Ref[{}] }, qr{^Parameter to Ref\[\`a\] expected to be string; got HASH}, qq{Ref[{}] is not a valid type constraint}, ); SKIP: { skip "requires Perl 5.8", 3 if $] < 5.008; ok( !!Num->check("Inf") == !Types::Standard::STRICTNUM, "'Inf' passes Num unless Types::Standard::STRICTNUM", ); ok( !!Num->check("-Inf") == !Types::Standard::STRICTNUM, "'-Inf' passes Num unless Types::Standard::STRICTNUM", ); ok( !!Num->check("Nan") == !Types::Standard::STRICTNUM, "'Nan' passes Num unless Types::Standard::STRICTNUM", ); } ok( !!Num->check("0.") == !Types::Standard::STRICTNUM, "'0.' passes Num unless Types::Standard::STRICTNUM", ); ok_subtype(Any, Item); done_testing; cycletuple.t000644001750001750 370113601673061 21247 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Standard=pod =encoding utf-8 =head1 PURPOSE Checks various values against C from Types::Standard. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use Test::Fatal qw(exception); use Types::Standard qw( CycleTuple Num Int HashRef ArrayRef Any Optional slurpy ); use Type::Utils qw( class_type ); my $type1 = CycleTuple[ Int->plus_coercions(Num, 'int($_)'), HashRef, ArrayRef, ]; my $type2 = CycleTuple[ Int->where(sub{2})->plus_coercions(Num, 'int($_)'), HashRef, ArrayRef, ]; my $type3 = CycleTuple[ Int->plus_coercions(Num->where(sub{2}), 'int($_)'), HashRef, ArrayRef, ]; my $type4 = CycleTuple[ Int->where(sub{2})->plus_coercions(Num->where(sub{2}), 'int($_)'), HashRef, ArrayRef, ]; my $i; for my $type ($type1, $type2, $type3, $type4) { ++$i; subtest "\$type$i" => sub { should_fail(undef, $type); should_fail({}, $type); should_pass([], $type); should_fail([{}], $type); should_fail([1], $type); should_fail([1,{}], $type); should_pass([1,{}, []], $type); should_fail([1,{}, [], undef], $type); should_fail([1,{}, [], 2], $type); should_pass([1,{}, [], 2, {}, [1]], $type); is_deeply( $type->coerce([1.1, {}, [], 2.2, {}, [3.3]]), [1, {}, [], 2, {}, [3.3]], 'automagic coercion', ); }; } like( exception { CycleTuple[Any, Optional[Any]] }, qr/cannot be optional/i, 'cannot make CycleTuples with optional slots', ); like( exception { CycleTuple[Any, slurpy ArrayRef] }, qr/cannot be slurpy/i, 'cannot make CycleTuples with slurpy slots', ); # should probably write a test case for this. #diag exception { $type->assert_return([1,{},[],[],[],[]]) }; done_testing; deep-coercions.t000644001750001750 3052013601673061 22014 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Standard=pod =encoding utf-8 =head1 PURPOSE If a coercion exists for type C, then Type::Tiny should be able to auto-generate a coercion for type C<< ArrayRef[Foo] >>, etc. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Types::Standard qw( -types slurpy ); use Type::Utils; ok( ! Dict->of(x => Int)->has_coercion, "Dict of type without coercion shouldn't have coercion", ); ok( Dict->of(x => Int->plus_coercions(Any, 1))->has_coercion, "Dict of type with coercion should have coercion", ); ok( ! Tuple->of(Int)->has_coercion, "Tuple of type without coercion shouldn't have coercion", ); ok( Tuple->of(Int->plus_coercions(Any, 1))->has_coercion, "Tuple of type with coercion should have coercion", ); ok( ! Map->of(Str, Int)->has_coercion, "Map of type without coercion shouldn't have coercion", ); ok( Map->of(Str, Int->plus_coercions(Any, 1))->has_coercion, "Map of type with coercion should have coercion", ); NONINLINED: { my $Foo = declare Foo => as Int; coerce $Foo, from Num, via { int($_) }; my $ArrayOfFoo = declare ArrayOfFoo => as ArrayRef[$Foo], coercion => 1; ok($ArrayOfFoo->has_coercion, '$ArrayOfFoo has coercion'); my $arr1 = [1..3]; my $arr2 = [1..3, "Hello"]; is( $ArrayOfFoo->coerce($arr1), $arr1, '$ArrayOfFoo does not coerce value that needs no coercion', ); is_deeply( $ArrayOfFoo->coerce([1.1, 2.1, 3.1]), [1, 2, 3], '$ArrayOfFoo does coerce value that can be coerced', ); is( $ArrayOfFoo->coerce($arr2), $arr2, '$ArrayOfFoo does not coerce value that cannot be coerced', ); my $HashOfFoo = HashRef[$Foo]; ok($HashOfFoo->has_coercion, '$HashOfFoo has coercion'); my $hsh1 = {one => 1, two => 2, three => 3}; my $hsh2 = {one => 1, two => 2, three => 3, greeting => "Hello"}; is( $HashOfFoo->coerce($hsh1), $hsh1, '$HashOfFoo does not coerce value that needs no coercion', ); is_deeply( $HashOfFoo->coerce({one => 1.1, two => 2.2, three => 3.3}), {one => 1, two => 2, three => 3}, '$HashOfFoo does coerce value that can be coerced', ); is( $HashOfFoo->coerce($hsh2), $hsh2, '$HashOfFoo does not coerce value that cannot be coerced', ); my $RefOfFoo = ScalarRef[$Foo]; ok($RefOfFoo->has_coercion, '$RefOfFoo has coercion'); my $ref1 = do { my $x = 1; \$x }; my $ref2 = do { my $x = "xxx"; \$x }; is( $RefOfFoo->coerce($ref1), $ref1, '$RefOfFoo does not coerce value that needs no coercion', ); is_deeply( ${ $RefOfFoo->coerce(do { my $x = 1.1; \$x }) }, 1, '$RefOfFoo does coerce value that can be coerced', ); is( $RefOfFoo->coerce($ref2), $ref2, '$RefOfFoo does not coerce value that cannot be coerced', ); # This added coercion should be ignored, because undef shouldn't # need coercion! my $MaybeFoo = Maybe[$Foo->plus_coercions(Undef, 999)]; is( $MaybeFoo->coerce(undef), undef, '$MaybeFoo does not coerce undef', ); is( $MaybeFoo->coerce(42), 42, '$MaybeFoo does not coerce integer', ); is( $MaybeFoo->coerce(4.2), 4, '$MaybeFoo does coerce non-integer number', ); is( $MaybeFoo->coerce("xyz"), "xyz", '$MaybeFoo cannot coerce non-number', ); }; INLINED: { my $Bar = declare Bar => as Int; coerce $Bar, from Num, q { int($_) }; $Bar->coercion->freeze; my $ArrayOfBar = ArrayRef[$Bar]; $ArrayOfBar->coercion->freeze; ok($ArrayOfBar->has_coercion, '$ArrayOfBar has coercion'); ok($ArrayOfBar->coercion->can_be_inlined, '$ArrayOfBar coercion can be inlined'); my $arr1 = [1..3]; my $arr2 = [1..3, "Hello"]; is( $ArrayOfBar->coerce($arr1), $arr1, '$ArrayOfBar does not coerce value that needs no coercion', ); is_deeply( $ArrayOfBar->coerce([1.1, 2.1, 3.1]), [1, 2, 3], '$ArrayOfBar does coerce value that can be coerced', ); is( $ArrayOfBar->coerce($arr2), $arr2, '$ArrayOfBar does not coerce value that cannot be coerced', ); my $HashOfBar = HashRef[$Bar]; $HashOfBar->coercion->freeze; ok($HashOfBar->has_coercion, '$HashOfBar has coercion'); ok($HashOfBar->coercion->can_be_inlined, '$HashOfBar coercion can be inlined'); my $hsh1 = {one => 1, two => 2, three => 3}; my $hsh2 = {one => 1, two => 2, three => 3, greeting => "Hello"}; is( $HashOfBar->coerce($hsh1), $hsh1, '$HashOfBar does not coerce value that needs no coercion', ); is_deeply( $HashOfBar->coerce({one => 1.1, two => 2.2, three => 3.3}), {one => 1, two => 2, three => 3}, '$HashOfBar does coerce value that can be coerced', ); is( $HashOfBar->coerce($hsh2), $hsh2, '$HashOfBar does not coerce value that cannot be coerced', ); my $RefOfBar = ScalarRef[$Bar]; $RefOfBar->coercion->freeze; ok($RefOfBar->has_coercion, '$RefOfBar has coercion'); ok($RefOfBar->coercion->can_be_inlined, '$RefOfBar coercion can be inlined'); my $ref1 = do { my $x = 1; \$x }; my $ref2 = do { my $x = "xxx"; \$x }; is( $RefOfBar->coerce($ref1), $ref1, '$RefOfBar does not coerce value that needs no coercion', ); is_deeply( ${ $RefOfBar->coerce(do { my $x = 1.1; \$x }) }, 1, '$RefOfBar does coerce value that can be coerced', ); is( $RefOfBar->coerce($ref2), $ref2, '$RefOfBar does not coerce value that cannot be coerced', ); # This added coercion should be ignored, because undef shouldn't # need coercion! my $MaybeBar = Maybe[$Bar->plus_coercions(Undef, 999)]; $MaybeBar->coercion->freeze; is( $MaybeBar->coerce(undef), undef, '$MaybeBar does not coerce undef', ); is( $MaybeBar->coerce(42), 42, '$MaybeBar does not coerce integer', ); is( $MaybeBar->coerce(4.2), 4, '$MaybeBar does coerce non-integer number', ); is( $MaybeBar->coerce("xyz"), "xyz", '$MaybeBar cannot coerce non-number', ); }; MAP: { my $IntFromStr = declare IntFromStr => as Int; coerce $IntFromStr, from Str, q{ length($_) }; my $IntFromNum = declare IntFromNum => as Int; coerce $IntFromNum, from Num, q{ int($_) }; my $IntFromArray = declare IntFromArray => as Int; coerce $IntFromArray, from ArrayRef, via { scalar(@$_) }; $_->coercion->freeze for $IntFromStr, $IntFromNum, $IntFromArray; my $Map1 = Map[$IntFromNum, $IntFromStr]; ok( $Map1->has_coercion && $Map1->coercion->can_be_inlined, "$Map1 has an inlinable coercion", ); is_deeply( $Map1->coerce({ 1.1 => "Hello", 2.1 => "World", 3.1 => "Hiya" }), { 1 => 5, 2 => 5, 3 => 4 }, "Coercions to $Map1", ); is_deeply( $Map1->coerce({ 1.1 => "Hello", 2.1 => "World", 3.1 => [] }), { 1.1 => "Hello", 2.1 => "World", 3.1 => [] }, "Impossible coercion to $Map1", ); my $m = { 1 => 2 }; is( $Map1->coerce($m), $m, "Unneeded coercion to $Map1", ); my $Map2 = Map[$IntFromNum, $IntFromArray]; ok( $Map2->has_coercion && !$Map2->coercion->can_be_inlined, "$Map2 has a coercion, but it cannot be inlined", ); is_deeply( $Map2->coerce({ 1.1 => [1], 2.1 => [1,2], 3.1 => [] }), { 1 => 1, 2 => 2, 3 => 0 }, "Coercions to $Map2", ); is_deeply( $Map2->coerce({ 1.1 => [1], 2.1 => [1,2], 3.1 => {} }), { 1.1 => [1], 2.1 => [1,2], 3.1 => {} }, "Impossible coercion to $Map2", ); $m = { 1 => 2 }; is( $Map2->coerce($m), $m, "Unneeded coercion to $Map2", ); }; DICT: { my $IntFromStr = declare IntFromStr => as Int; coerce $IntFromStr, from Str, q{ length($_) }; my $IntFromNum = declare IntFromNum => as Int; coerce $IntFromNum, from Num, q{ int($_) }; my $IntFromArray = declare IntFromArray => as Int; coerce $IntFromArray, from ArrayRef, via { scalar(@$_) }; $_->coercion->freeze for $IntFromStr, $IntFromNum, $IntFromArray; my @a = (a => $IntFromStr, b => $IntFromNum, c => Optional[$IntFromNum]); my $Dict1 = Dict[ a => $IntFromStr, b => $IntFromNum, c => Optional[$IntFromNum] ]; ok( $Dict1->has_coercion && $Dict1->coercion->can_be_inlined, "$Dict1 has an inlinable coercion", ); is_deeply( $Dict1->coerce({ a => "Hello", b => 1.1, c => 2.2 }), { a => 5, b => 1, c => 2 }, "Coercion (A) to $Dict1", ); is_deeply( $Dict1->coerce({ a => "Hello", b => 1 }), { a => 5, b => 1 }, "Coercion (B) to $Dict1", ); is_deeply( $Dict1->coerce({ a => "Hello", b => 1, c => [], d => 1 }), { a => "Hello", b => 1, c => [], d => 1 }, "Coercion (C) to $Dict1 - changed in 0.003_11; the presence of an additional value cancels coercion", ); }; DICT_PLUS_SLURPY: { my $Rounded1 = Int->plus_coercions(Num, q[int($_)]); my $Dict1 = Dict[ a => $Rounded1, slurpy Map[$Rounded1, $Rounded1] ]; is_deeply( $Dict1->coerce({ a => 1.1, 2.2 => 3.3, 4.4 => 5 }), { a => 1, 2 => 3, 4 => 5 }, "Coercion to $Dict1 (inlined)", ); my $Rounded2 = Int->plus_coercions(Num, sub { int($_) }); my $Dict2 = Dict[ a => $Rounded2, slurpy Map[$Rounded2, $Rounded2] ]; is_deeply( $Dict2->coerce({ a => 1.1, 2.2 => 3.3, 4.4 => 5 }), { a => 1, 2 => 3, 4 => 5 }, "Coercion to $Dict2 (non-inlined)", ); }; DICT_PLUS_OPTIONAL: { my $IntFromStr = declare IntFromStr => as Int; coerce $IntFromStr, from Str, sub { length($_) }; $IntFromStr->coercion->freeze; my $Dict1 = Dict[ a => $IntFromStr, b => Optional[Int], c => Optional[Int] ]; ok( $Dict1->has_coercion && !$Dict1->coercion->can_be_inlined, "$Dict1 has a non-inlinable coercion", ); is_deeply( $Dict1->coerce({ a => "Hello", b => 1, c => 2 }), { a => 5, b => 1, c => 2 }, "Coercion (A) to $Dict1", ); is_deeply( $Dict1->coerce({ a => "Hello", b => 1 }), { a => 5, b => 1 }, "Coercion (B) to $Dict1", ); }; TUPLE: { my $IntFromStr = declare IntFromStr => as Int; coerce $IntFromStr, from Str, q{ length($_) }; my $IntFromNum = declare IntFromNum => as Int; coerce $IntFromNum, from Num, q{ int($_) }; my $IntFromArray = declare IntFromArray => as Int; coerce $IntFromArray, from ArrayRef, via { scalar(@$_) }; $_->coercion->freeze for $IntFromStr, $IntFromNum, $IntFromArray; my $Tuple1 = Tuple[ $IntFromNum, Optional[$IntFromStr], slurpy ArrayRef[$IntFromNum]]; ok( $Tuple1->has_coercion && $Tuple1->coercion->can_be_inlined, "$Tuple1 has an inlinable coercion", ); is_deeply( $Tuple1->coerce([qw( 1.1 1.1 )]), [1, 3], "Coercion (A) to $Tuple1", ); is_deeply( $Tuple1->coerce([qw( 1.1 1.1 2.2 2.2 33 3.3 )]), [1, 3, 2, 2, 33, 3], "Coercion (B) to $Tuple1", ); my $Tuple2 = Tuple[ $IntFromNum ]; is_deeply( $Tuple2->coerce([qw( 1.1 )]), [ 1 ], "Coercion (A) to $Tuple2", ); is_deeply( $Tuple2->coerce([qw( 1.1 2.2 )]), [ 1.1, 2.2 ], "Coercion (B) to $Tuple2 - changed in 0.003_11; the presence of an additional value cancels coercion", ); my $EvenInt = Int->create_child_type( name => 'EvenInt', constraint => sub { not $_ % 2 }, ); my $Tuple3 = Tuple[ $EvenInt->plus_coercions(Int, sub { 2 * $_ }) ]; ok( $Tuple3->check([4]) ); ok( not $Tuple3->check([3]) ); is_deeply( $Tuple3->coerce([4]), [4], "No coercion necessary to $Tuple3", ); is_deeply( $Tuple3->coerce([3]), [6], "Coercion to $Tuple3", ); my $EvenInt2 = Int->create_child_type( name => 'EvenInt2', constraint => sub { not $_ % 2 }, inlined => sub { undef, "not($_ % 2)" }, ); my $Tuple4 = Tuple[ $EvenInt2->plus_coercions(Int, q{ 2 * $_ }) ]; ok( $Tuple4->check([4]) ); ok( not $Tuple4->check([3]) ); is_deeply( $Tuple4->coerce([4]), [4], "No coercion necessary to $Tuple4", ); is_deeply( $Tuple4->coerce([3]), [6], "Coercion to $Tuple4", ); }; TUPLE: { my $IntFromStr = declare IntFromStr => as Int; coerce $IntFromStr, from Str, q{ length($_) }; is_deeply( Tuple->of(HashRef, slurpy ArrayRef[$IntFromStr])->coerce([{}, 1, 2.2, "Hello", "world"]), [{}, 1, 3, 5, 5], 'coercing Tuple with slurpy arrayref' ); }; THINGY1: { my $IntFromStr = declare IntFromStr => as Int; coerce $IntFromStr, from Str, q{ length($_) }; is_deeply( Tuple->of($IntFromStr)->coerce(["Hello","world"]), ["Hello","world"], 'inlinable coercion of Tuple with no slurpy given input with extra fields fails' ); }; THINGY2: { my $IntFromStr = declare IntFromStr => as Int; coerce $IntFromStr, from Str, sub{ length($_) }; is_deeply( Tuple->of($IntFromStr)->coerce(["Hello","world"]), ["Hello","world"], 'non-inlinable coercion of Tuple with no slurpy given input with extra fields fails' ); }; done_testing; filehandle.t000644001750001750 135113601673061 21170 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Standard=pod =encoding utf-8 =head1 PURPOSE Checks various values against C from Types::Standard. =head1 SEE ALSO L =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2018-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use Test::Requires qw( IO::String ); use Types::Standard qw( FileHandle ); should_pass('IO::String'->new, FileHandle); should_fail('IO::String', FileHandle); done_testing; lockdown.t000644001750001750 222313601673061 20714 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Standard=pod =head1 PURPOSE OK, we need to bite the bullet and lock down coercions on core type constraints and parameterized type constraints. =head1 SEE ALSO L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Types::Standard -types; use Types::Common::Numeric -types; my $frozen = qr/\AAttempt to add coercion code to a Type::Coercion/; like( exception { Str->coercion->add_type_coercions(ArrayRef, sub { "@$_" }); }, $frozen, 'Types::Standard core types are frozen', ); like( exception { PositiveInt->coercion->add_type_coercions(NegativeInt, sub { -$_ }); }, $frozen, 'Types::Common types are frozen', ); like( exception { InstanceOf->of("Foo")->coercion->add_type_coercions(HashRef, sub { bless $_, "Foo" }); }, $frozen, 'Parameterized types are frozen', ); done_testing; mxtmlb-alike.t000644001750001750 337113601673061 21467 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Standard=pod =encoding utf-8 =head1 PURPOSE Test the following types from L which were inspired by L. =over =item C<< InstanceOf >> =item C<< ConsumerOf >> =item C<< HasMethods >> =item C<< Enum >> =back Rather than checking they work directy, we check they are equivalent to known (and well-tested) type constraints generated using L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Types::Standard -types; use Type::Utils; sub same_type { my ($a, $b, $msg) = @_; $msg ||= "$a == $b"; @_ = ($a->inline_check('$x'), $b->inline_check('$x'), $msg); goto \&Test::More::is; } same_type( InstanceOf[], Object, ); same_type( InstanceOf["Foo"], class_type(Foo => {class => "Foo"}), ); same_type( InstanceOf["Foo", "Bar"], union [ class_type(Foo => {class => "Foo"}), class_type(Bar => {class => "Bar"}), ], ); same_type( ConsumerOf[], Object, ); same_type( ConsumerOf["Foo"], role_type(Foo => {role => "Foo"}), ); same_type( ConsumerOf["Foo", "Bar"], intersection [ role_type(Foo => {role => "Foo"}), role_type(Bar => {role => "Bar"}), ], ); same_type( HasMethods[], Object, ); same_type( HasMethods["foo"], duck_type(CanFoo => [qw/foo/]), ); same_type( HasMethods["foo", "bar"], duck_type(CanFooBar => [qw/foo bar/]), ); same_type( Enum[], Str, ); same_type( Enum["foo"], enum(Foo => [qw/foo/]), ); same_type( Enum["foo", "bar"], enum(Foo => [qw/foo bar/]), ); done_testing; optlist.t000644001750001750 275313601673061 20602 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Standard=pod =encoding utf-8 =head1 PURPOSE Checks various values against C from Types::Standard. Checks the standalone C coercion. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use Types::Standard qw( OptList MkOpt ); my $O = OptList; my $OM = OptList->plus_coercions(MkOpt); should_pass([], $O); should_pass([[foo=>undef]], $O); should_pass([[foo=>[]]], $O); should_pass([[foo=>{}]], $O); should_pass([], $OM); should_pass([[foo=>undef]], $OM); should_pass([[foo=>[]]], $OM); should_pass([[foo=>{}]], $OM); should_fail([[undef]], $O); should_fail([[[]]], $O); should_fail([[{}]], $O); should_fail([[undef]], $OM); should_fail([[[]]], $OM); should_fail([[{}]], $OM); ok(!$O->has_coercion, "not $O has coercion"); ok($OM->has_coercion, "$OM has coercion"); is_deeply( $OM->coerce(undef), [], '$OM->coerce(undef)', ); is_deeply( $OM->coerce([]), [], '$OM->coerce([])', ); is_deeply( $OM->coerce([foo => {}, bar => "baz"]), [ [foo => {}], [bar => undef], [baz => undef], ], 'simple $OM coercion test', ); is_deeply( $OM->coerce({foo => []}), [ [foo => []], ], 'another simple $OM coercion test', ); done_testing; overload.t000644001750001750 214313601673061 20710 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Standard=pod =encoding utf-8 =head1 PURPOSE Checks various values against C from Types::Standard. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use Types::Standard qw( Any Item Defined Ref ArrayRef Object Overload ); my $o = bless [] => do { package Local::Class; use overload q[&] => sub { 1 }, fallback => 1; __PACKAGE__; }; should_pass($o, Any); should_pass($o, Item); should_pass($o, Defined); should_pass($o, Ref); should_pass($o, Ref["ARRAY"]); should_pass($o, Object); should_pass($o, Overload); should_pass($o, Overload["&"]); should_fail($o, Ref["HASH"]); should_fail($o, Overload["|"]); should_fail("Local::Class", Overload); should_fail([], Overload); ok_subtype($_, Overload["&"]) for Item, Defined, Ref, Object, Overload; done_testing; strmatch-allow-callbacks.t000644001750001750 163513601673061 23760 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Standard=pod =encoding utf-8 =head1 PURPOSE Checks various values against C from Types::Standard when C<< $Type::Tiny::AvoidCallbacks >> is false. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( . ./t ../inc ./inc ); use Test::More; use Test::Requires '5.018'; use Types::Standard 'StrMatch'; BEGIN { eval q{ use Test::Warnings } }; $Type::Tiny::AvoidCallbacks = 0; my $z; my $complex = StrMatch->of(qr/x(?{$z})/); # closure so can't be easily inlined ok($complex->can_be_inlined, "using callbacks, this complex regexp can be inlined"); like($complex->inline_check('$_'), qr/Types::Standard::StrMatch/, '... and looks okay'); done_testing; strmatch-avoid-callbacks.t000644001750001750 164713601673061 23747 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Standard=pod =encoding utf-8 =head1 PURPOSE Checks various values against C from Types::Standard when C<< $Type::Tiny::AvoidCallbacks >> is true. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( . ./t ../inc ./inc ); use Test::More; use Test::Requires '5.018'; use Test::Requires 'Test::Warnings'; use Types::Standard 'StrMatch'; use Test::Warnings 'warning'; $Type::Tiny::AvoidCallbacks = 1; my $z; my $complex = StrMatch->of(qr/x(?{$z})/); # closure so can't be easily inlined my $warning = warning { $z = $complex->inline_check('$VALUE') }; like($z, qr/Types::Standard::StrMatch::expressions/); like($warning, qr/without callbacks/); done_testing; strmatch.t000644001750001750 460713601673061 20731 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Standard=pod =encoding utf-8 =head1 PURPOSE Checks various values against C from Types::Standard. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( . ./t ../inc ./inc ); use Test::More; use Test::TypeTiny; use Test::Fatal; use Types::Standard -all, "slurpy"; use Type::Utils; my $e = exception { StrMatch[{}] }; like($e, qr/^First parameter to StrMatch\[\`a\] expected to be a Regexp/, 'error message 1'); $e = exception { StrMatch[qr/(.)/, []] }; like($e, qr/^Second parameter to StrMatch\[\`a\] expected to be a type constraint/, 'error message 2'); my $DistanceUnit = enum DistanceUnit => [qw/ mm cm m km /]; my $Distance = declare Distance => as StrMatch[ qr{^([0-9]+)\s+(.+)$}, Tuple[Int, $DistanceUnit], ]; should_pass("mm", $DistanceUnit); should_pass("cm", $DistanceUnit); should_pass("m", $DistanceUnit); should_pass("km", $DistanceUnit); should_fail("MM", $DistanceUnit); should_fail("mm ", $DistanceUnit); should_fail(" mm", $DistanceUnit); should_fail("miles", $DistanceUnit); should_pass("5 km", $Distance) or diag($Distance->inline_check('$XXX')); should_pass("5 mm", $Distance); should_fail("4 miles", $Distance); should_fail("5.5 km", $Distance); should_fail([qw/5 km/], $Distance); my $Boolean = declare Boolean => as StrMatch[qr{^(?:true|false|0|1)$}ism]; should_pass("true", $Boolean); should_pass("True", $Boolean); should_pass("TRUE", $Boolean); should_pass("false", $Boolean); should_pass("False", $Boolean); should_pass("FALSE", $Boolean); should_pass("0", $Boolean); should_pass("1", $Boolean); should_fail("True ", $Boolean); should_fail("11", $Boolean); my $SecureUrl = declare SecureUrl => as StrMatch[qr{^https://}]; should_pass("https://www.google.com/", $SecureUrl); should_fail("http://www.google.com/", $SecureUrl); my $length_eq_3 = StrMatch[qr/\A...\z/]; should_fail('ab', $length_eq_3); should_pass('abc', $length_eq_3); should_fail('abcd', $length_eq_3); #diag( $length_eq_3->inline_check('$x') ); my $length_ge_3 = StrMatch[qr/\A.../]; should_fail('ab', $length_ge_3); should_pass('abc', $length_ge_3); should_pass('abcd', $length_ge_3); #diag( $length_ge_3->inline_check('$x') ); done_testing; structured.t000644001750001750 4263613601673061 21334 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Standard=pod =encoding utf-8 =head1 PURPOSE Checks various values against structured types from Types::Standard. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( . ./t ../inc ./inc ); use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard -all, "slurpy"; my $struct1 = Map[Int, Num]; should_pass({1=>111,2=>222}, $struct1); should_pass({1=>1.1,2=>2.2}, $struct1); should_fail({1=>"Str",2=>222}, $struct1); should_fail({1.1=>1,2=>2.2}, $struct1); my $struct2 = Tuple[Int, Num, Optional([Int]), slurpy ArrayRef[Num]]; my $struct3 = Tuple[Int, Num, Optional[Int]]; should_pass([1, 1.1], $struct2); should_pass([1, 1.1, 2], $struct2); should_pass([1, 1.1, 2, 2.2], $struct2); should_pass([1, 1.1, 2, 2.2, 2.3], $struct2); should_pass([1, 1.1, 2, 2.2, 2.3, 2.4], $struct2); should_fail({}, $struct2); should_fail([], $struct2); should_fail([1], $struct2); should_fail([1.1, 1.1], $struct2); should_fail([1, 1.1, 2.1], $struct2); should_fail([1, 1.1, 2.1], $struct2); should_fail([1, 1.1, 2, 2.2, 2.3, 2.4, "xyz"], $struct2); should_fail([1, 1.1, undef], $struct2); should_pass([1, 1.1], $struct3); should_pass([1, 1.1, 2], $struct3); should_fail([1, 1.1, 2, 2.2], $struct3); should_fail([1, 1.1, 2, 2.2, 2.3], $struct3); should_fail([1, 1.1, 2, 2.2, 2.3, 2.4], $struct3); should_fail({}, $struct3); should_fail([], $struct3); should_fail([1], $struct3); should_fail([1.1, 1.1], $struct3); should_fail([1, 1.1, 2.1], $struct3); should_fail([1, 1.1, 2.1], $struct3); should_fail([1, 1.1, 2, 2.2, 2.3, 2.4, "xyz"], $struct3); should_fail([1, 1.1, undef], $struct3); my $struct4 = Dict[ name => Str, age => Int, height => Optional[Num] ]; should_pass({ name => "Bob", age => 40, height => 1.76 }, $struct4); should_pass({ name => "Bob", age => 40 }, $struct4); should_fail({ name => "Bob" }, $struct4); should_fail({ age => 40 }, $struct4); should_fail({ name => "Bob", age => 40.1 }, $struct4); should_fail({ name => "Bob", age => 40, weight => 80.3 }, $struct4); should_fail({ name => "Bob", age => 40, height => 1.76, weight => 80.3 }, $struct4); should_fail({ name => "Bob", age => 40, height => "xyz" }, $struct4); should_fail({ name => "Bob", age => 40, height => undef }, $struct4); should_fail({ name => "Bob", age => undef, height => 1.76 }, $struct4); my $opt1 = Optional[Int]; ok( $opt1->check(1), "$opt1 check (1)"); ok(!$opt1->check('xxx'), "$opt1 check ('xxx')"); my $slurper = Tuple[ArrayRef, slurpy Map[Num, Int]]; should_pass([ [], 1.1 => 1, 2.1 => 2 ], $slurper); should_pass([ [] ], $slurper); should_fail([ [], 1.1 => 1, xxx => 2 ], $slurper); should_fail([ [], 1.1 => 1, 2.1 => undef ], $slurper); my $struct5 = Dict[ i => Maybe[Int], b => Bool ]; should_pass({ i => 42, b => undef }, $struct5); should_pass({ i => 42, b => '' }, $struct5); should_pass({ i => 42, b => 0 }, $struct5); should_pass({ i => 42, b => 1 }, $struct5); should_pass({ i => undef, b => 1 }, $struct5); should_fail({ b => 42, i => 1 }, $struct5); should_fail({ i => 42 }, $struct5); should_fail({ b => 1 }, $struct5); should_fail({ i => 42, b => 1, a => 1 }, $struct5); should_fail({ i => 42, a => 1 }, $struct5); should_fail({ a => 42, b => 1 }, $struct5); my $anyany = Tuple[Any, Any]; should_pass([1,1], $anyany); should_pass([1,undef], $anyany); should_pass([undef,undef], $anyany); should_pass([undef,1], $anyany); should_fail([1], $anyany); should_fail([undef], $anyany); should_fail([1,1,1], $anyany); should_fail([1,1,undef], $anyany); note "Tuple[] vs Tuple"; should_pass([ ], Tuple[]); should_fail([1], Tuple[]); should_pass([ ], Tuple); should_pass([1], Tuple); note "Dict[] vs Dict"; should_pass(+{ }, Dict[]); should_fail(+{foo=>1}, Dict[]); should_pass(+{ }, Dict); should_pass(+{foo=>1}, Dict); my $gazetteer = Dict[ foo => Int, bar => Optional[Int], slurpy HashRef[Num] ]; note "Dict[ ..., slurpy ... ]"; should_pass({ foo => 42 }, $gazetteer); should_pass({ foo => 42, bar => 666 }, $gazetteer); should_fail({ foo => 4.2 }, $gazetteer); should_fail({ foo => 42, bar => 6.66 }, $gazetteer); should_fail({ foo => 4.2, bar => 6.66 }, $gazetteer); should_fail({ foo => undef }, $gazetteer); should_fail({ }, $gazetteer); should_pass({ foo => 42, baz => 999 }, $gazetteer); should_pass({ foo => 42, bar => 666, baz => 999 }, $gazetteer); should_fail({ foo => 4.2, baz => 999 }, $gazetteer); should_fail({ foo => 42, bar => 6.66, baz => 999 }, $gazetteer); should_fail({ foo => 4.2, bar => 6.66, baz => 999 }, $gazetteer); should_fail({ foo => undef, baz => 999 }, $gazetteer); should_fail({ baz => 999 }, $gazetteer); should_pass({ foo => 42, baz => 9.99 }, $gazetteer); should_pass({ foo => 42, bar => 666, baz => 9.99 }, $gazetteer); should_fail({ foo => 4.2, baz => 9.99 }, $gazetteer); should_fail({ foo => 42, bar => 6.66, baz => 9.99 }, $gazetteer); should_fail({ foo => 4.2, bar => 6.66, baz => 9.99 }, $gazetteer); should_fail({ foo => undef, baz => 9.99 }, $gazetteer); should_fail({ baz => 9.99 }, $gazetteer); should_fail({ foo => 42, baz => "x" }, $gazetteer); should_fail({ foo => 42, bar => 666, baz => "x" }, $gazetteer); should_fail({ foo => 4.2, baz => "x" }, $gazetteer); should_fail({ foo => 42, bar => 6.66, baz => "x" }, $gazetteer); should_fail({ foo => 4.2, bar => 6.66, baz => "x" }, $gazetteer); should_fail({ foo => undef, baz => "x" }, $gazetteer); should_fail({ baz => "x" }, $gazetteer); my $gazetteer2 = Dict[ foo => Int, bar => Optional[Int], slurpy Map[StrMatch[qr/^...$/], Num] ]; should_pass({ foo => 99, jjj => '2.2' }, $gazetteer2); should_fail({ jjj => '2.2' }, $gazetteer2); should_fail({ foo => 99, jjjj => '2.2' }, $gazetteer2); subtest slurpy_coderef_thing => sub { my $allow_extras = 1; my $type = Tuple[Int, slurpy sub { $allow_extras }]; isa_ok($type->parameters->[-1]{slurpy}, 'Type::Tiny'); should_pass([1], $type); should_pass([1, "extra"], $type); $allow_extras = 0; should_pass([1], $type); should_fail([1, "extra"], $type); }; # this is mostly for better coverage { my $type = Any->where('1'); # needs to be inlineable but not a standard type my $dict = Dict[foo => Int, slurpy $type]; should_fail([foo=>123 ], $dict); should_pass({foo=>123 }, $dict); should_pass({foo=>123,bar=>456}, $dict); should_fail({ bar=>456}, $dict); } subtest my_dict_is_slurpy => sub { ok(!$struct5->my_dict_is_slurpy, 'On a non-slurpy Dict'); ok($gazetteer->my_dict_is_slurpy, 'On a slurpy Dict'); ok(!$struct5->create_child_type->my_dict_is_slurpy, 'On a child of a non-slurpy Dict'); ok($gazetteer->create_child_type->my_dict_is_slurpy, 'On a child of a slurpy Dict'); }; subtest my_hashref_allows_key => sub { ok(HashRef->my_hashref_allows_key('foo'), 'HashRef allows key "foo"'); ok(!HashRef->my_hashref_allows_key(undef), 'HashRef disallows key undef'); ok(!HashRef->my_hashref_allows_key([]), 'HashRef disallows key []'); ok((HashRef[Int])->my_hashref_allows_key('foo'), 'HashRef[Int] allows key "foo"'); ok(!(HashRef[Int])->my_hashref_allows_key(undef), 'HashRef[Int] disallows key undef'); ok(!(HashRef[Int])->my_hashref_allows_key([]), 'HashRef[Int] disallows key []'); ok(Map->my_hashref_allows_key('foo'), 'Map allows key "foo"'); ok(!Map->my_hashref_allows_key(undef), 'Map disallows key undef'); ok(!Map->my_hashref_allows_key([]), 'Map disallows key []'); ok(!(Map[Int,Int])->my_hashref_allows_key('foo'), 'Map[Int,Int] disallows key "foo"'); ok(!(Map[Int,Int])->my_hashref_allows_key(undef), 'Map[Int,Int] disallows key undef'); ok(!(Map[Int,Int])->my_hashref_allows_key([]), 'Map[Int,Int] disallows key []'); ok((Map[Int,Int])->my_hashref_allows_key('42'), 'Map[Int,Int] allows key "42"'); ok(Dict->my_hashref_allows_key('foo'), 'Dict allows key "foo"'); ok(!Dict->my_hashref_allows_key(undef), 'Dict disallows key undef'); ok(!Dict->my_hashref_allows_key([]), 'Dict disallows key []'); ok(!(Dict[])->my_hashref_allows_key('foo'), 'Dict[] disallows key "foo"'); ok(!(Dict[])->my_hashref_allows_key(undef), 'Dict[] disallows key undef'); ok(!(Dict[])->my_hashref_allows_key([]), 'Dict[] disallows key []'); ok(!(Dict[bar=>Int])->my_hashref_allows_key('foo'), 'Dict[bar=>Int] disallows key "foo"'); ok((Dict[bar=>Int])->my_hashref_allows_key('bar'), 'Dict[bar=>Int] allows key "bar"'); ok(!(Dict[bar=>Int])->my_hashref_allows_key(undef), 'Dict[bar=>Int] disallows key undef'); ok(!(Dict[bar=>Int])->my_hashref_allows_key([]), 'Dict[bar=>Int] disallows key []'); ok((Dict[bar=>Int, slurpy Any])->my_hashref_allows_key('foo'), 'Dict[bar=>Int,slurpy Any] allows key "foo"'); ok((Dict[bar=>Int, slurpy Any])->my_hashref_allows_key('bar'), 'Dict[bar=>Int,slurpy Any] allows key "bar"'); ok(!(Dict[bar=>Int, slurpy Any])->my_hashref_allows_key(undef), 'Dict[bar=>Int,slurpy Any] disallows key undef'); ok(!(Dict[bar=>Int, slurpy Any])->my_hashref_allows_key([]), 'Dict[bar=>Int,slurpy Any] disallows key []'); ok((Dict[bar=>Int, slurpy Ref])->my_hashref_allows_key('foo'), 'Dict[bar=>Int,slurpy Ref] allows key "foo"'); ok((Dict[bar=>Int, slurpy Ref])->my_hashref_allows_key('bar'), 'Dict[bar=>Int,slurpy Ref] allows key "bar"'); ok(!(Dict[bar=>Int, slurpy Ref])->my_hashref_allows_key(undef), 'Dict[bar=>Int,slurpy Ref] disallows key undef'); ok(!(Dict[bar=>Int, slurpy Ref])->my_hashref_allows_key([]), 'Dict[bar=>Int,slurpy Ref] disallows key []'); ok(!(Dict[bar=>Int, slurpy Map[Int,Int]])->my_hashref_allows_key('foo'), 'Dict[bar=>Int,slurpy Map[Int,Int]] disallows key "foo"'); ok((Dict[bar=>Int, slurpy Map[Int,Int]])->my_hashref_allows_key('bar'), 'Dict[bar=>Int,slurpy Map[Int,Int]] allows key "bar"'); ok(!(Dict[bar=>Int, slurpy Map[Int,Int]])->my_hashref_allows_key(undef), 'Dict[bar=>Int,slurpy Map[Int,Int]] disallows key undef'); ok(!(Dict[bar=>Int, slurpy Map[Int,Int]])->my_hashref_allows_key([]), 'Dict[bar=>Int,slurpy Map[Int,Int]] disallows key []'); ok((Dict[bar=>Int, slurpy Map[Int,Int]])->my_hashref_allows_key('42'), 'Dict[bar=>Int,slurpy Map[Int,Int]] allows key "42"'); ok(HashRef->create_child_type->my_hashref_allows_key('foo'), 'A child of HashRef allows key "foo"'); ok(!HashRef->create_child_type->my_hashref_allows_key(undef), 'A child of HashRef disallows key undef'); ok(!HashRef->create_child_type->my_hashref_allows_key([]), 'A child of HashRef disallows key []'); ok((HashRef[Int])->create_child_type->my_hashref_allows_key('foo'), 'A child of HashRef[Int] allows key "foo"'); ok(!(HashRef[Int])->create_child_type->my_hashref_allows_key(undef), 'A child of HashRef[Int] disallows key undef'); ok(!(HashRef[Int])->create_child_type->my_hashref_allows_key([]), 'A child of HashRef[Int] disallows key []'); ok(Map->create_child_type->my_hashref_allows_key('foo'), 'A child of Map allows key "foo"'); ok(!Map->create_child_type->my_hashref_allows_key(undef), 'A child of Map disallows key undef'); ok(!Map->create_child_type->my_hashref_allows_key([]), 'A child of Map disallows key []'); ok(!(Map[Int,Int])->create_child_type->my_hashref_allows_key('foo'), 'A child of Map[Int,Int] disallows key "foo"'); ok(!(Map[Int,Int])->create_child_type->my_hashref_allows_key(undef), 'A child of Map[Int,Int] disallows key undef'); ok(!(Map[Int,Int])->create_child_type->my_hashref_allows_key([]), 'A child of Map[Int,Int] disallows key []'); ok((Map[Int,Int])->create_child_type->my_hashref_allows_key('42'), 'A child of Map[Int,Int] allows key "42"'); ok(Dict->create_child_type->my_hashref_allows_key('foo'), 'A child of Dict allows key "foo"'); ok(!Dict->create_child_type->my_hashref_allows_key(undef), 'A child of Dict disallows key undef'); ok(!Dict->create_child_type->my_hashref_allows_key([]), 'A child of Dict disallows key []'); ok(!(Dict[])->create_child_type->my_hashref_allows_key('foo'), 'A child of Dict[] disallows key "foo"'); ok(!(Dict[])->create_child_type->my_hashref_allows_key(undef), 'A child of Dict[] disallows key undef'); ok(!(Dict[])->create_child_type->my_hashref_allows_key([]), 'A child of Dict[] disallows key []'); ok(!(Dict[bar=>Int])->create_child_type->my_hashref_allows_key('foo'), 'A child of Dict[bar=>Int] disallows key "foo"'); ok((Dict[bar=>Int])->create_child_type->my_hashref_allows_key('bar'), 'A child of Dict[bar=>Int] allows key "bar"'); ok(!(Dict[bar=>Int])->create_child_type->my_hashref_allows_key(undef), 'A child of Dict[bar=>Int] disallows key undef'); ok(!(Dict[bar=>Int])->create_child_type->my_hashref_allows_key([]), 'A child of Dict[bar=>Int] disallows key []'); ok((Dict[bar=>Int, slurpy Any])->create_child_type->my_hashref_allows_key('foo'), 'A child of Dict[bar=>Int,slurpy Any] allows key "foo"'); ok((Dict[bar=>Int, slurpy Any])->create_child_type->my_hashref_allows_key('bar'), 'A child of Dict[bar=>Int,slurpy Any] allows key "bar"'); ok(!(Dict[bar=>Int, slurpy Any])->create_child_type->my_hashref_allows_key(undef), 'A child of Dict[bar=>Int,slurpy Any] disallows key undef'); ok(!(Dict[bar=>Int, slurpy Any])->create_child_type->my_hashref_allows_key([]), 'A child of Dict[bar=>Int,slurpy Any] disallows key []'); ok((Dict[bar=>Int, slurpy Ref])->create_child_type->my_hashref_allows_key('foo'), 'A child of Dict[bar=>Int,slurpy Ref] allows key "foo"'); ok((Dict[bar=>Int, slurpy Ref])->create_child_type->my_hashref_allows_key('bar'), 'A child of Dict[bar=>Int,slurpy Ref] allows key "bar"'); ok(!(Dict[bar=>Int, slurpy Ref])->create_child_type->my_hashref_allows_key(undef), 'A child of Dict[bar=>Int,slurpy Ref] disallows key undef'); ok(!(Dict[bar=>Int, slurpy Ref])->create_child_type->my_hashref_allows_key([]), 'A child of Dict[bar=>Int,slurpy Ref] disallows key []'); ok(!(Dict[bar=>Int, slurpy Map[Int,Int]])->create_child_type->my_hashref_allows_key('foo'), 'A child of Dict[bar=>Int,slurpy Map[Int,Int]] disallows key "foo"'); ok((Dict[bar=>Int, slurpy Map[Int,Int]])->create_child_type->my_hashref_allows_key('bar'), 'A child of Dict[bar=>Int,slurpy Map[Int,Int]] allows key "bar"'); ok(!(Dict[bar=>Int, slurpy Map[Int,Int]])->create_child_type->my_hashref_allows_key(undef), 'A child of Dict[bar=>Int,slurpy Map[Int,Int]] disallows key undef'); ok(!(Dict[bar=>Int, slurpy Map[Int,Int]])->create_child_type->my_hashref_allows_key([]), 'A child of Dict[bar=>Int,slurpy Map[Int,Int]] disallows key []'); ok((Dict[bar=>Int, slurpy Map[Int,Int]])->create_child_type->my_hashref_allows_key('42'), 'A child of Dict[bar=>Int,slurpy Map[Int,Int]] allows key "42"'); }; # This could probably be expanded... subtest my_hashref_allows_value => sub { ok(HashRef->my_hashref_allows_value(foo => "bar"), 'HashRef allows key "foo" with value "bar"'); ok(HashRef->my_hashref_allows_value(foo => undef), 'HashRef allows key "foo" with value undef'); ok(!HashRef->my_hashref_allows_value(undef, "bar"), 'HashRef disallows key undef with value "bar"'); ok(!(HashRef[Int])->my_hashref_allows_value(foo => "bar"), 'HashRef[Int] disallows key "foo" with value "bar"'); ok((Dict[bar=>Int, slurpy Map[Int,Int]])->create_child_type->my_hashref_allows_value(bar => 42), 'A child of Dict[bar=>Int,slurpy Map[Int,Int]] allows key "bar" with value 42'); ok((Dict[bar=>Int, slurpy Map[Int,Int]])->create_child_type->my_hashref_allows_value(21, 42), 'A child of Dict[bar=>Int,slurpy Map[Int,Int]] allows key "21" with value 42'); ok(!(Dict[bar=>Int, slurpy Map[Int,Int]])->create_child_type->my_hashref_allows_value(baz => 42), 'A child of Dict[bar=>Int,slurpy Map[Int,Int]] disallows key "baz" with value 42'); }; subtest "Invalid parameters" => sub { my $e; $e = exception { ScalarRef[1] }; like($e, qr/Parameter to ScalarRef\[\`a\] expected to be a type constraint/, 'ScalarRef[INVALID]'); $e = exception { ArrayRef[1] }; like($e, qr/Parameter to ArrayRef\[\`a\] expected to be a type constraint/, 'ArrayRef[INVALID]'); $e = exception { HashRef[1] }; like($e, qr/Parameter to HashRef\[\`a\] expected to be a type constraint/, 'HashRef[INVALID]'); $e = exception { Map[1, Str] }; like($e, qr/First parameter to Map\[\`k,\`v\] expected to be a type constraint/, 'Map[INVALID, Str]'); $e = exception { Map[Str, 1] }; like($e, qr/Second parameter to Map\[\`k,\`v\] expected to be a type constraint/, 'Map[Str, INVALID]'); $e = exception { Tuple[1] }; like($e, qr/Parameters to Tuple\[\.\.\.] expected to be type constraints/, 'Tuple[INVALID]'); $e = exception { Tuple[Str, slurpy 42] }; like($e, qr/Slurpy parameter to Tuple\[\.\.\.] expected to be a type constraint/, 'Tuple[Str, slurpy INVALID]'); $e = exception { Tuple[Optional[Str], Str] }; like($e, qr/Optional parameters to Tuple\[\.\.\.] cannot precede required parameters/, 'Tuple[Optional[Str], Str]'); $e = exception { CycleTuple[1] }; like($e, qr/Parameters to CycleTuple\[\.\.\.] expected to be type constraints/, 'CycleTuple[INVALID]'); $e = exception { CycleTuple[Optional[Str]] }; like($e, qr/Parameters to CycleTuple\[\.\.\.] cannot be optional/, 'CycleTuple[Optional[Str]]'); $e = exception { CycleTuple[slurpy Str] }; like($e, qr/Parameters to CycleTuple\[\.\.\.] cannot be slurpy/, 'CycleTuple[slurpy Str]'); $e = exception { Dict[1] }; like($e, qr/Expected even-sized list/, 'Dict[INVALID]'); $e = exception { Dict[[], Str] }; like($e, qr/Key for Dict\[\.\.\.\] expected to be string/, 'Dict[INVALID => Str]'); $e = exception { Dict[foo => 1] }; like($e, qr/Parameter for Dict\[\.\.\.\] with key 'foo' expected to be a type constraint/, 'Dict[foo => INVALID]'); $e = exception { Dict[foo => Str, slurpy 42] }; like($e, qr/Slurpy parameter to Dict\[\.\.\.] expected to be a type constraint/, 'Dict[foo => Str, slurpy INVALID]'); }; done_testing; tied.t000644001750001750 461613601673061 20031 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-Standard=pod =encoding utf-8 =head1 PURPOSE Checks various values against C from Types::Standard. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Test::TypeTiny; use Types::Standard qw( Tied HashRef ); use Type::Utils qw( class_type ); my $a = do { package MyTie::Array; require Tie::Array; our @ISA = qw(Tie::StdArray); tie my(@A), __PACKAGE__; \@A; }; my $h = do { package MyTie::Hash; require Tie::Hash; our @ISA = qw(Tie::StdHash); tie my(%H), __PACKAGE__; \%H }; my $S; my $s = do { package MyTie::Scalar; require Tie::Scalar; our @ISA = qw(Tie::StdScalar); tie $S, __PACKAGE__; \$S; }; should_pass($a, Tied); should_pass($h, Tied); should_pass($s, Tied); should_fail($S, Tied); should_pass($a, Tied["MyTie::Array"]); should_fail($h, Tied["MyTie::Array"]); should_fail($s, Tied["MyTie::Array"]); should_fail($a, Tied["MyTie::Hash"]); should_pass($h, Tied["MyTie::Hash"]); should_fail($s, Tied["MyTie::Hash"]); should_fail($a, Tied["MyTie::Scalar"]); should_fail($h, Tied["MyTie::Scalar"]); should_pass($s, Tied["MyTie::Scalar"]); should_pass($a, Tied[ class_type MyTieArray => { class => "MyTie::Array" } ]); should_fail($h, Tied[ class_type MyTieArray => { class => "MyTie::Array" } ]); should_fail($s, Tied[ class_type MyTieArray => { class => "MyTie::Array" } ]); should_fail($a, Tied[ class_type MyTieHash => { class => "MyTie::Hash" } ]); should_pass($h, Tied[ class_type MyTieHash => { class => "MyTie::Hash" } ]); should_fail($s, Tied[ class_type MyTieHash => { class => "MyTie::Hash" } ]); should_fail($a, Tied[ class_type MyTieScalar => { class => "MyTie::Scalar" } ]); should_fail($h, Tied[ class_type MyTieScalar => { class => "MyTie::Scalar" } ]); should_pass($s, Tied[ class_type MyTieScalar => { class => "MyTie::Scalar" } ]); my $intersection = (Tied) & (HashRef); should_pass($h, $intersection); should_fail($a, $intersection); should_fail($s, $intersection); should_fail({foo=>2}, $intersection); my $e = exception { Tied[{}] }; like($e, qr/^Parameter to Tied\[.a\] expected to be a class name/, 'weird exception'); done_testing; basic.t000644001750001750 447113601673061 20211 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-TypeTiny=pod =encoding utf-8 =head1 PURPOSE Test the L bootstrap library. (That is, type constraints used by Type::Tiny internally.) =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny -all; use Types::TypeTiny -all; my $stringy = do { package Overloaded::String; use overload q[""] => sub { "Hello world" }, fallback => 1; bless {}; }; my $hashy = do { package Overloaded::HashRef; use overload q[%{}] => sub { +{} }, fallback => 1; bless []; }; my $arrayey = do { package Overloaded::ArrayRef; use overload q[@{}] => sub { [] }, fallback => 1; bless {}; }; my $codey = do { package Overloaded::CodeRef; use overload q[&{}] => sub { sub { 42 } }, fallback => 1; bless []; }; subtest "StringLike" => sub { my $type = StringLike; should_pass( "Hello", $type ); should_pass( "", $type ); should_pass( CodeLike, $type, 'Type::Tiny constraint object passes type constraint StringLike' ); should_pass( $stringy, $type ); should_fail( {}, $type ); should_fail( undef, $type ); }; subtest "ArrayLike" => sub { my $type = ArrayLike; should_pass( [], $type ); should_pass( $arrayey, $type ); should_fail( {}, $type ); should_fail( bless([], 'XXX'), $type ); should_fail( undef, $type ); }; subtest "HashLike" => sub { my $type = HashLike; should_pass( {}, $type ); should_pass( $hashy, $type ); should_fail( [], $type ); should_fail( bless({}, 'XXX'), $type ); should_fail( undef, $type ); }; subtest "CodeLike" => sub { my $type = CodeLike; should_pass( sub { 42 }, $type ); should_pass( CodeLike, $type, 'Type::Tiny constraint object passes type constraint CodeLike' ); should_pass( $codey, $type ); should_fail( {}, $type ); should_fail( bless(sub {42}, 'XXX'), $type ); should_fail( undef, $type ); }; subtest "TypeTiny" => sub { my $type = TypeTiny; should_pass( ArrayLike, $type, 'Type::Tiny constraint object passes type constraint TypeTiny' ); should_fail( {}, $type ); should_fail( sub { 42 }, $type ); should_fail( undef, $type ); }; done_testing; coercion.t000644001750001750 746713601673061 20741 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-TypeTiny=pod =encoding utf-8 =head1 PURPOSE Test L pseudo-coercion and the L type. =head1 DEPENDENCIES This test requires L 2.0000, L 1.00, and L 1.000000. Otherwise, it is skipped. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); # Test::Requires calls ->import on Moose/Mouse, so be sure # to import them into dummy packages. { package XXX; use Test::Requires { Moose => '2.0000' } }; { package YYY; use Test::Requires { Mouse => '1.00' } }; { package ZZZ; use Test::Requires { Moo => '1.000000' } }; use Test::More; use Test::TypeTiny -all; use Types::TypeTiny -all; use Moose::Util::TypeConstraints qw(find_type_constraint); ok(TypeTiny->has_coercion, "TypeTiny->has_coercion"); subtest "Coercion from Moose type constraint object" => sub { my $orig = find_type_constraint("Int"); my $type = to_TypeTiny $orig; should_pass($orig, _ForeignTypeConstraint); should_fail($type, _ForeignTypeConstraint); should_pass($type, TypeTiny, 'to_TypeTiny converted a Moose type constraint to a Type::Tiny one'); is($type->name, 'Int', '... which has the correct name'); ok($type->can_be_inlined, '... and which can be inlined'); note $type->inline_check('$X'); subtest "... and it works" => sub { should_pass(123, $type); should_fail(3.3, $type); }; ## We don't do this for Moose for some reason. # # is( # $type->get_message(3.3), # $orig->get_message(3.3), # '... and provides proper message', # ); }; subtest "Coercion from Mouse type constraint object" => sub { my $orig = Mouse::Util::TypeConstraints::find_type_constraint("Int"); my $type = to_TypeTiny $orig; should_pass($orig, _ForeignTypeConstraint); should_fail($type, _ForeignTypeConstraint); should_pass($type, TypeTiny, 'to_TypeTiny converted a Mouse type constraint to a Type::Tiny one'); subtest "... and it works" => sub { should_pass(123, $type); should_fail(3.3, $type); }; is( $type->get_message(3.3), $orig->get_message(3.3), '... and provides proper message', ); }; subtest "Coercion from predicate-like coderef" => sub { my $orig = sub { $_[0] =~ /\A-?[0-9]+\z/ }; my $type = to_TypeTiny $orig; should_pass($orig, _ForeignTypeConstraint); should_fail($type, _ForeignTypeConstraint); should_pass($type, TypeTiny, 'to_TypeTiny converted the coderef to a Type::Tiny object'); subtest "... and it works" => sub { should_pass(123, $type); should_fail(3.3, $type); }; }; subtest "Coercion from assertion-like coderef" => sub { my $orig = sub { $_[0] =~ /\A-?[0-9]+\z/ or die("not an integer") }; my $type = to_TypeTiny $orig; should_pass($orig, _ForeignTypeConstraint); should_fail($type, _ForeignTypeConstraint); should_pass($type, TypeTiny, 'to_TypeTiny converted the coderef to a Type::Tiny object'); subtest "... and it works" => sub { should_pass(123, $type); should_fail(3.3, $type); }; like( $type->validate(3.3), qr/\Anot an integer/, '... and provides proper message', ); }; subtest "Coercion from Sub::Quote coderef" => sub { require Sub::Quote; my $orig = Sub::Quote::quote_sub(q{ $_[0] =~ /\A-?[0-9]+\z/ }); my $type = to_TypeTiny $orig; should_pass($orig, _ForeignTypeConstraint); should_fail($type, _ForeignTypeConstraint); should_pass($type, TypeTiny, 'to_TypeTiny converted the coderef to a Type::Tiny object'); ok($type->can_be_inlined, '... which can be inlined'); note $type->inline_check('$X'); subtest "... and it works" => sub { should_pass(123, $type); should_fail(3.3, $type); }; }; done_testing; meta.t000644001750001750 260313601673061 20051 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-TypeTiny=pod =encoding utf-8 =head1 PURPOSE Test the L introspection methods. Types::TypeTiny doesn't inherit from L (because bootstrapping), so provides independent re-implementations of the most important introspection stuff. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny -all; use Types::TypeTiny; my $meta = Types::TypeTiny->meta; is_deeply( [ sort $meta->type_names ], [ sort qw( CodeLike ArrayLike StringLike HashLike TypeTiny _ForeignTypeConstraint ) ], 'type_names', ); ok( $meta->has_type('HashLike'), 'has_type(HashLike)', ); ok( $meta->get_type('HashLike')->equals(Types::TypeTiny::HashLike()), 'get_type(HashLike)', ); ok( !$meta->has_type('MonkeyNuts'), 'has_type(MonkeyNuts)', ); ok( !defined( $meta->get_type('MonkeyNuts') ), 'get_type(MonkeyNuts)', ); is_deeply( [ sort $meta->coercion_names ], [], 'coercion_names', ); ok( !$meta->has_coercion('MonkeyNuts'), 'has_coercion(MonkeyNuts)', ); ok( !defined( $meta->get_coercion('MonkeyNuts') ), 'get_coercion(MonkeyNuts)', ); done_testing; moosemouse.t000644001750001750 265513601673061 21325 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-TypeTiny=pod =encoding utf-8 =head1 PURPOSE Stuff that was originally in basic.t but was split out to avoid basic.t requiring Moose and Mouse. =head1 DEPENDENCIES This test requires L 2.0000 and L 1.00. Otherwise, it is skipped. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); # Test::Requires calls ->import on Moose/Mouse, so be sure # to import them into dummy packages. { package XXX; use Test::Requires { Moose => '2.0000' } }; { package YYY; use Test::Requires { Mouse => '1.00' } }; use Test::More; use Test::TypeTiny -all; use Types::TypeTiny -all; use Moose::Util::TypeConstraints qw(find_type_constraint); subtest "TypeTiny" => sub { my $type = TypeTiny; should_pass( ArrayLike, $type, 'Type::Tiny constraint object passes type constraint TypeTiny' ); should_fail( {}, $type ); should_fail( sub { 42 }, $type ); should_fail( find_type_constraint("Int"), $type, 'Moose constraint object fails type constraint TypeTiny' ); should_fail( Mouse::Util::TypeConstraints::find_type_constraint("Int"), $type, 'Mouse constraint object fails type constraint TypeTiny' ); should_fail( undef, $type ); }; done_testing; progressiveexporter.t000644001750001750 125313601673061 23264 0ustar00taitai000000000000Type-Tiny-1.008001/t/20-unit/Types-TypeTiny=pod =encoding utf-8 =head1 PURPOSE Checks that Types::TypeTiny avoids loading Exporter::Tiny. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2018-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; require Types::TypeTiny; ok !Exporter::Tiny->can('mkopt'); Types::TypeTiny->import(); ok !Exporter::Tiny->can('mkopt'); Types::TypeTiny->import('HashLike'); ok Exporter::Tiny->can('mkopt'); done_testing; basic.t000644001750001750 1044313601673061 21651 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Class-InsideOut=pod =encoding utf-8 =head1 PURPOSE Check type constraints work with L. =head1 DEPENDENCIES Test is skipped if Class::InsideOut 1.13 is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. Based on C<< t/14_accessor_hooks.t >> from the Class::InsideOut test suite, by David Golden. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by David Golden, Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::Requires { "Class::InsideOut" => 1.13 }; use Test::More; BEGIN { package Object::HookedTT; use Class::InsideOut ':std'; use Types::Standard -types; # $_ has the first argument in it for convenience public integer => my %integer, { set_hook => Int }; # first argument is also available directly public word => my %word, { set_hook => StrMatch[qr/\A\w+\z/] }; # Changing $_ changes what gets stored my $UC = (StrMatch[qr/\A[A-Z]+\z/])->plus_coercions(Str, q{uc $_}); public uppercase => my %uppercase, { set_hook => sub { $_ = $UC->coercion->($_) }, }; # Full @_ is available, but only first gets stored public list => my %list, { set_hook => sub { $_ = ArrayRef->check($_) ? $_ : [ @_ ] }, get_hook => sub { @$_ }, }; public reverser => my %reverser, { set_hook => sub { $_ = ArrayRef->check($_) ? $_ : [ @_ ] }, get_hook => sub { reverse @$_ } }; public write_only => my %only_only, { get_hook => sub { die "is write-only\n" } }; sub new { register( bless {}, shift ); } }; #--------------------------------------------------------------------------# my $class = "Object::HookedTT"; my $properties = { $class => { integer => "public", uppercase => "public", word => "public", list => "public", reverser => "public", write_only => "public", }, }; my ($o, @got, $got); #--------------------------------------------------------------------------# is_deeply( Class::InsideOut::_properties( $class ), $properties, "$class has/inherited its expected properties", ); ok( ($o = $class->new()) && $o->isa($class), "Creating a $class object", ); #--------------------------------------------------------------------------# eval { $o->integer(3.14) }; my $err = $@; like( $err, '/integer\(\) Value "3.14" did not pass type constraint "Int"/i', "integer(3.14) dies", ); eval { $o->integer(42) }; is( $@, q{}, "integer(42) lives", ); is( $o->integer, 42, "integer() == 42", ); #--------------------------------------------------------------------------# eval { $o->word("^^^^") }; like( $@, '/word\(\) value "\^\^\^\^" did not pass type constraint/i', "word(^^^^) dies", ); eval { $o->word("apple") }; is( $@, q{}, "word(apple) lives", ); is( $o->word, 'apple', "word() eq 'apple'", ); #--------------------------------------------------------------------------# eval { $o->uppercase("banana") }; is( $@, q{}, "uppercase(banana) lives", ); is( $o->uppercase, 'BANANA', "uppercase() eq 'BANANA'", ); #--------------------------------------------------------------------------# # list(@array) eval { $o->list(qw(foo bar bam)) }; is( $@, q{}, "list(qw(foo bar bam)) lives", ); is_deeply( [ $o->list ], [qw(foo bar bam)], "list() gives qw(foo bar bam)", ); # list(\@array) eval { $o->list( [qw(foo bar bam)] ) }; is( $@, q{}, "list( [qw(foo bar bam)] ) lives", ); is_deeply( [ $o->list ], [qw(foo bar bam)], "list() gives qw(foo bar bam)", ); #--------------------------------------------------------------------------# eval { $o->reverser(qw(foo bar bam)) }; is( $@, q{}, "reverser(qw(foo bar bam)) lives", ); # reverser in list context @got = $o->reverser; is_deeply( \@got, [qw(bam bar foo)], "reverser() in list context gives qw(bam bar foo)", ); # reverser in scalar context $got = $o->reverser; is( $got, 'mabraboof', "reverser() in scalar context gives mabraboof", ); #--------------------------------------------------------------------------# eval { $o->write_only( 23 ) }; is( $@, q{}, "write_only lives on write", ); eval { $got = $o->write_only() }; like( $@, '/write_only\(\) is write-only at/i', "write only dies on write (and was caught)", ); done_testing; basic.t000644001750001750 425513601673061 21420 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Exporter-Tiny=pod =encoding utf-8 =head1 PURPOSE Tests L has the features Type::Tiny needs. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; require Types::Standard; is( exception { "Types::Standard"->import("Any") }, undef, q {No exception exporting a legitimate function}, ); can_ok(main => "Any"); isnt( exception { "Types::Standard"->import("kghffubbtfui") }, undef, q {Attempt to export a function which does not exist}, ); isnt( exception { "Types::Standard"->import("declare") }, undef, q {Attempt to export a function which exists but not in @EXPORT_OK}, ); { my $hash = {}; "Types::Standard"->import({ into => $hash }, qw(-types)); is_deeply( [ sort keys %$hash ], [ sort "Types::Standard"->meta->type_names ], '"-types" shortcut works', ); }; { my $hash = {}; "Types::Standard"->import({ into => $hash }, qw(-coercions)); is_deeply( [ sort keys %$hash ], [ sort "Types::Standard"->meta->coercion_names ], '"-coercions" shortcut works', ); }; { my $hash = {}; "Types::Standard"->import({ into => $hash }, Str => { }); "Types::Standard"->import({ into => $hash }, Str => { -as => "String" }); "Types::Standard"->import({ into => $hash }, -types => { -prefix => "X_" }); "Types::Standard"->import({ into => $hash }, -types => { -suffix => "_Z" }); is($hash->{Str}, $hash->{String}, 'renaming works'); is($hash->{Str}, $hash->{X_Str}, 'prefixes work'); is($hash->{Str}, $hash->{Str_Z}, 'suffixes work'); }; { my $hash = {}; "Types::Standard"->import({ into => $hash }, qw(+Str)); is_deeply( [sort keys %$hash], [sort qw/ assert_Str to_Str is_Str Str /], 'plus notation works for Type::Library', ); }; my $opthash = Exporter::Tiny::mkopt_hash([ foo => [], "bar" ]); is_deeply( $opthash, { foo => [], bar => undef }, 'mkopt_hash', ) or diag explain($opthash); done_testing; installer.t000644001750001750 157213601673061 22333 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Exporter-Tiny=pod =encoding utf-8 =head1 PURPOSE Tests L libraries work with Sub::Exporter plugins. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::Requires { "Sub::Exporter::Lexical" => "0.092291" }; use Test::More; use Test::Fatal; { use Sub::Exporter::Lexical qw( lexical_installer ); use Types::Standard { installer => lexical_installer }, qw( ArrayRef ); ArrayRef->( [] ); } ok(!eval q{ ArrayRef->( [] ) }, 'the ArrayRef function was cleaned away'); ok(!__PACKAGE__->can("ArrayRef"), 'ArrayRef does not appear to be a method'); done_testing; role-conflict.t000644001750001750 233013601673061 23067 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Exporter-Tiny=pod =encoding utf-8 =head1 PURPOSE Tests exporting to two roles; tries to avoid reporting conflicts. =head1 DEPENDENCIES Requires L 5.59 and L 1.000000; test skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 THANKS This test case is based on a script provided by Kevin Dawson. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::Requires { "Exporter" => 5.59 }; use Test::Requires { "Role::Tiny" => 1.000000 }; use Test::More; use Test::Fatal; { package Local::Role1; use Role::Tiny; use Types::Standard "Str"; } { package Local::Role2; use Role::Tiny; use Types::Standard "Str"; } my $e = exception { package Local::Class1; use Role::Tiny::With; with qw( Local::Role1 Local::Role2 ); }; is($e, undef, 'no exception when trying to compose two roles that use type constraints'); use Scalar::Util "refaddr"; note refaddr(\&Local::Role1::Str); note refaddr(\&Local::Role2::Str); done_testing; basic.t000644001750001750 235613601673061 22555 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Function-Parameters=pod =encoding utf-8 =head1 PURPOSE Check type constraints work with L. =head1 DEPENDENCIES Requires Function::Parameters 1.0103, and either Moo 1.000000 or Moose 2.0000; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { "Function::Parameters" => "1.0103" }; use Test::Fatal; BEGIN { eval 'use Moo 1.000000; 1' or eval 'use Moose 2.0000; 1' or plan skip_all => "this test requires Moo 1.000000 or Moose 2.0000"; }; BEGIN { plan skip_all => 'Devel::Cover' if $INC{'Devel/Cover.pm'} }; use Types::Standard -types; use Function::Parameters qw(:strict); fun foo ((Int) $x) { return $x; } is( foo(4), 4, 'foo(4) works', ); isnt( exception { foo(4.1) }, undef, 'foo(4.1) throws', ); my $info = Function::Parameters::info(\&foo); my ($x) = $info->positional_required; is($x->name, '$x', '$x->name'); ok($x->type == Int, '$x->type'); done_testing; 80returntype.t000644001750001750 345313601673061 21574 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Kavorka=pod =encoding utf-8 =head1 PURPOSE Adopted test from Kavorka test suite. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use utf8; use warnings; use Test::More; use Test::Fatal; BEGIN { $ENV{AUTOMATED_TESTING} or $ENV{EXTENDED_TESTING} or $ENV{AUTHOR_TESTING} or $ENV{RELEASE_TESTING} or plan skip_all => 'EXTENDED_TESTING' }; use Test::Requires "Kavorka"; note "simple type constraint"; fun add1 ($a, $b → Int) { return $a + $b; } is( add1(4,5), 9 ); is( add1(4.1,4.9), 9 ); like(exception { my $r = add1(4.1, 5) }, qr{did not pass type constraint "Int" at \S+ line 48}); is_deeply( [add1(4,5)], [9] ); like(exception { my @r = add1(4.1, 5) }, qr{did not pass type constraint "ArrayRef.Int." at \S+ line 51}); note "type constraint expression"; use Types::Standard (); use constant Rounded => Types::Standard::Int()->plus_coercions(Types::Standard::Num(), q[int($_)]); fun add2 ($a, $b --> (Rounded) does coerce) { return $a + $b; } is( add2(4,5), 9 ); is( add2(4.1,4.9), 9 ); is( add2(4.1,5), 9 ); note "type constraints for list and scalar contexts"; fun add3 ($a, $b → Int, ArrayRef[Int] is list) { wantarray ? ($a,$b) : ($a+$b); } is( add3(4,5), 9 ); is( add3(4.1,4.9), 9 ); like(exception { my $r = add3(4.1, 5) }, qr{did not pass type constraint "Int" at \S+ line 74}); is_deeply( [add3(4,5)], [4,5] ); like(exception { my @r = add3(4.1,4.9) }, qr{did not pass type constraint "ArrayRef.Int." at \S+ line 77}); like(exception { my @r = add3(4.1,5) }, qr{did not pass type constraint "ArrayRef.Int." at \S+ line 78}); done_testing; basic.t000644001750001750 202013601673061 20251 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Kavorka=pod =encoding utf-8 =head1 PURPOSE Checks Type::Tiny works with L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires 'Kavorka'; use Test::Fatal; use Kavorka; use Types::Standard qw(Int Num); fun xyz ( Int $x, (Int) $y, (Int->plus_coercions(Num, 'int($_)')) $z does coerce ) { $x * $y * $z; } is( exception { is( xyz(2,3,4), 24, 'easy sub call; all type constraints should pass', ); is( xyz(2,3,4.2), 24, 'easy sub call; all type constraints should pass or coerce', ); }, undef, '... neither raise an exception', ); isnt( exception { xyz(2.1,3,4) }, undef, 'failed type constraint with no coercion raises an exception', ); done_testing; basic.t000644001750001750 270513601673061 17417 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Moo=pod =encoding utf-8 =head1 PURPOSE Check type constraints work with L. Checks values that should pass and should fail; checks error messages. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. Test is skipped if Moo 1.000000 is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { Moo => 1.000000 }; use Test::Fatal; { package Local::Class; use Moo; use BiggerLib ":all"; has small => (is => "ro", isa => SmallInteger); has big => (is => "ro", isa => BigInteger); } is( exception { "Local::Class"->new(small => 9, big => 12) }, undef, "some values that should pass their type constraint", ); isnt( exception { "Local::Class"->new(small => 100) }, undef, "direct violation of type constraint", ); isnt( exception { "Local::Class"->new(small => 5.5) }, undef, "violation of parent type constraint", ); isnt( exception { "Local::Class"->new(small => "five point five") }, undef, "violation of grandparent type constraint", ); isnt( exception { "Local::Class"->new(small => []) }, undef, "violation of great-grandparent type constraint", ); done_testing; coercion-inlining-avoidance.t000644001750001750 545113601673061 23674 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Moo=pod =encoding utf-8 =head1 PURPOSE A rather complex case of defining an attribute with a type coercion in Moo; and only then adding coercion definitions to it. Does Moo pick up on the changes? It should. =head1 DEPENDENCIES Test is skipped if Moo 1.004000 is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Requires { 'Moo' => '1.004000' }; use Test::Fatal; use Types::Standard -types; my $e; my $type = Int->create_child_type( name => 'MyInt', coercion => [ Num, q[int($_)] ], ); ok( !$type->coercion->frozen, 'created a type constraint without a frozen coercion', ); ok( !$type->coercion->can_be_inlined, '... it reports that it cannot be inlined', ); { package Foo; use Moo; has foo => (is => 'ro', isa => $type, coerce => $type->coercion); } # We need to do some quick checks before adding the coercions, # partly because this is interesting to check, and partly because # we need to ensure that the is( Foo->new(foo => 3.2)->foo, 3, 'initial use of type in a Moo constructor', ); $e = exception { Foo->new(foo => [3..4])->foo }; like( $e->message, qr/did not pass type constraint/, '... and it cannot coerce from an arrayref', ); $e = exception { Foo->new(foo => { value => 42 })->foo }; like( $e->message, qr/did not pass type constraint/, '... and it cannot coerce from an hashref', ); is( exception { $type->coercion->add_type_coercions( ArrayRef, q[scalar(@$_)], HashRef, q[$_->{value}], ScalarRef, q["this is just a talisman"], ); }, undef, 'can add coercions from ArrayRef and HashRef to the type', ); ok( !$type->coercion->frozen, '... it is still not frozen', ); ok( !$type->coercion->can_be_inlined, '... it reports that it still cannot be inlined', ); is( Foo->new(foo => 3.2)->foo, 3, 'again use of type in a Moo constructor', ); is( Foo->new(foo => [3..4])->foo, 2, '... but can coerce from ArrayRef', ); is( Foo->new(foo => { value => 42 })->foo, 42, '... and can coerce from HashRef', ); is( exception { $type->coercion->freeze }, undef, 'can freeze the coercion', ); ok( $type->coercion->frozen, '... it reports that it is frozen', ); ok( $type->coercion->can_be_inlined, '... it reports that it can be inlined', ); { package Goo; use Moo; has foo => (is => 'ro', isa => $type, coerce => $type->coercion); } Goo->new; if ( $ENV{AUTHOR_TESTING} ) { require B::Deparse; my $deparsed = B::Deparse->new->coderef2text(\&Goo::new); like($deparsed, qr/talisman/i, 'Moo inlining for coercions') or diag($deparsed); } done_testing; coercion.t000644001750001750 415113601673061 20134 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Moo=pod =encoding utf-8 =head1 PURPOSE Check coercions work with L. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. Test is skipped if Moo 1.000000 is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { Moo => 1.000000 }; use Test::Fatal; { package Local::Class; use Moo; use BiggerLib -all; ::isa_ok(BigInteger, "Type::Tiny"); has small => (is => "rw", isa => SmallInteger, coerce => SmallInteger->coercion); has big => (is => "rw", isa => BigInteger, coerce => BigInteger->coercion); } my ($e, $o); my $suffix = "mutable class"; for (0..1) { $e = exception { $o = "Local::Class"->new( small => 104, big => 9, ); }; is($e, undef, "no exception on coercion in constructor - $suffix"); is($o && $o->big, 19, "'big' attribute coerces in constructor - $suffix"); is($o && $o->small, 4, "'small' attribute coerces in constructor - $suffix"); $e = exception { $o = "Local::Class"->new( small => [], big => {}, ); }; ok($e, "'big' attribute throws when it cannot coerce in constructor - $suffix"); $e = exception { $o = "Local::Class"->new( small => {}, big => [], ); }; ok($e, "'small' attribute throws when it cannot coerce in constructor - $suffix"); $o = "Local::Class"->new; $e = exception { $o->big([]); $o->small([]); }; is($o && $o->big, 100, "'big' attribute coerces in accessor - $suffix"); is($o && $o->small, 1, "'small' attribute coerces in accessor - $suffix"); $e = exception { $o->big({}) }; ok($e, "'big' attribute throws when it cannot coerce in accessor - $suffix"); $e = exception { $o->small({}) }; ok($e, "'small' attribute throws when it cannot coerce in accessor - $suffix"); "Local::Class"->meta->make_immutable; $suffix = "im$suffix"; } done_testing; exceptions.t000644001750001750 413313601673061 20514 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Moo=pod =encoding utf-8 =head1 PURPOSE Tests L interaction with L. =head1 DEPENDENCIES Requires Moo 1.002001 or above; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Fatal; use Test::Requires { "Moo" => "1.004000" }; BEGIN { require Method::Generate::Accessor; "Method::Generate::Accessor"->can("_SIGDIE") or "Moo"->VERSION ge '1.006' or plan skip_all => "Method::Generate::Accessor exception support seems missing!!!"; }; { package Goo; use Moo; use Types::Standard qw(Int); has number => (is => "rw", isa => Int); } my $e_constructor = exception { Goo->new(number => "too") }; isa_ok($e_constructor, 'Error::TypeTiny::Assertion', '$e_constructor'); ok($e_constructor->has_attribute_name, '$e_constructor->has_attribute_name'); is($e_constructor->attribute_name, 'number', '$e_constructor->attribute_name'); ok($e_constructor->has_attribute_step, '$e_constructor->has_attribute_step'); is($e_constructor->attribute_step, 'isa check', '$e_constructor->attribute_step'); is($e_constructor->varname, '$args->{"number"}', '$e_constructor->varname'); is($e_constructor->value, "too", '$e_constructor->value'); is($e_constructor->type, Types::Standard::Int, '$e_constructor->type'); my $e_accessor = exception { Goo->new->number("too") }; isa_ok($e_accessor, 'Error::TypeTiny::Assertion', '$e_accessor'); ok($e_accessor->has_attribute_name, '$e_accessor->has_attribute_name'); is($e_accessor->attribute_name, 'number', '$e_accessor->attribute_name'); ok($e_accessor->has_attribute_step, '$e_accessor->has_attribute_step'); is($e_accessor->attribute_step, 'isa check', '$e_accessor->attribute_step'); is($e_accessor->value, "too", '$e_accessor->value'); is($e_accessor->type, Types::Standard::Int, '$e_accessor->type'); done_testing; inflation.t000644001750001750 412113601673061 20313 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Moo=pod =encoding utf-8 =head1 PURPOSE Checks that type constraints continue to work when a L class is inflated to a L class. Checks that Moo::HandleMoose correctly calls back to Type::Tiny to build Moose type constraints. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. Test is skipped if Moo 1.000000 is not available. Test is redundant if Moose 2.0000 is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { Moo => 1.000000 }; use Test::Fatal; { package Local::Class; use Moo; use BiggerLib ":all"; has small => (is => "ro", isa => SmallInteger); has big => (is => "ro", isa => BigInteger); } note explain(\%Moo::HandleMoose::TYPE_MAP); my $state = "Moose is not loaded"; for (0..1) { is( exception { "Local::Class"->new(small => 9, big => 12) }, undef, "some values that should pass their type constraint - $state", ); ok( exception { "Local::Class"->new(small => 100) }, "direct violation of type constraint - $state", ); ok( exception { "Local::Class"->new(small => 5.5) }, "violation of parent type constraint - $state", ); ok( exception { "Local::Class"->new(small => "five point five") }, "violation of grandparent type constraint - $state", ); ok( exception { "Local::Class"->new(small => []) }, "violation of great-grandparent type constraint - $state", ); eval q{ require Moose; Moose->VERSION(2.0000); "Local::Class"->meta->get_attribute("small"); "Local::Class"->meta->get_attribute("big"); $state = "Moose is loaded"; }; } $state eq 'Moose is loaded' ? is( "Local::Class"->meta->get_attribute("small")->type_constraint->name, "SmallInteger", "type constraint metaobject inflates from Moo to Moose", ) : pass("redundant test"); done_testing; inflation2.t000644001750001750 171013601673061 20376 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Moo=pod =encoding utf-8 =head1 PURPOSE A test for type constraint inflation from L to L. =head1 DEPENDENCIES Requires Moo 1.003000 and Moose 2.0800; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Fatal; use Test::Requires { 'Moo' => '1.003000' }; use Test::Requires { 'Moose' => '2.0800' }; use Types::Standard qw/Str HashRef/; my $type = HashRef[Str]; { package AAA; BEGIN { $INC{'AAA.pm'} = __FILE__ }; use Moo::Role; has foo => ( is => 'ro', isa => $type, traits => ['Hash'], ); } { package BBB; use Moose; with 'AAA'; } ok not exception { 'BBB'->new( foo => { a => 'b' } ); }; done_testing; basic.t000644001750001750 177113601673061 17764 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Moops=pod =encoding utf-8 =head1 PURPOSE Check that type constraints work in L. This file is borrowed from the Moops test suite, where it is called C<< 31types.t >>. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Requires 'Moops'; use Test::Fatal; use Moops; class Foo { has num => (is => 'rw', isa => Num); method add ( Num $addition ) { $self->num( $self->num + $addition ); } } my $foo = 'Foo'->new(num => 20); is($foo->num, 20); is($foo->num(40), 40); is($foo->num, 40); is($foo->add(2), 42); is($foo->num, 42); isnt( exception { $foo->num("Hello") }, undef, ); isnt( exception { $foo->add("Hello") }, undef, ); isnt( exception { 'Foo'->new(num => "Hello") }, undef, ); done_testing; library-keyword.t000644001750001750 212313601673061 22021 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Moops=pod =encoding utf-8 =head1 PURPOSE Check that type libraries can be declared with L. This file is borrowed from the Moops test suite, where it is called C<< 71library.t >>. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Requires { 'Moops' => '0.018' }; use Test::Fatal; use Test::TypeTiny; use Moops; library MyTypes extends Types::Standard declares RainbowColour { declare RainbowColour, as Enum[qw/ red orange yellow green blue indigo violet /]; } should_pass('indigo', MyTypes::RainbowColour); should_fail('magenta', MyTypes::RainbowColour); class MyClass types MyTypes { method capitalize_colour ( $class: RainbowColour $r ) { return uc($r); } } is('MyClass'->capitalize_colour('indigo'), 'INDIGO'); ok exception { 'MyClass'->capitalize_colour('magenta') }; done_testing; accept-moose-types.t000644001750001750 316313601673061 22406 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Moose=pod =encoding utf-8 =head1 PURPOSE Check that Moose type constraints can be passed into the Type::Tiny API where a Type::Tiny constraint might usually be expected. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. Test is skipped if Moose 2.0000 is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { Moose => 2.0000 }; use Test::Fatal; # Example from the manual { package Person; use Moose; use Types::Standard qw( Str Int ); use Type::Utils qw( declare as where inline_as coerce from ); ::isa_ok( Int, 'Moose::Meta::TypeConstraint', 'Int', ); ::isa_ok( Str, 'Moose::Meta::TypeConstraint', 'Str', ); has name => ( is => "ro", isa => Str, ); my $PositiveInt = declare as Int, where { $_ > 0 }, inline_as { "$_ =~ /^0-9]\$/ and $_ > 0" }; coerce $PositiveInt, from Int, q{ abs $_ }; ::isa_ok( $PositiveInt, 'Type::Tiny', '$PositiveInt', ); ::isa_ok( $PositiveInt->parent, 'Type::Tiny', '$PositiveInt->parent', ); has age => ( is => "ro", isa => $PositiveInt, coerce => 1, writer => "_set_age", ); sub get_older { my $self = shift; my ($years) = @_; $PositiveInt->assert_valid($years); $self->_set_age($self->age + $years); } } done_testing; basic.t000644001750001750 2025313601673061 17765 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Moose=pod =encoding utf-8 =head1 PURPOSE Check type constraints work with L. Checks values that should pass and should fail; checks error messages. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. Test is skipped if Moose 2.0000 is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; no warnings qw(once); use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { Moose => 2.0000 }; use Test::Fatal; use Test::TypeTiny qw( matchfor ); note "The basics"; { package Local::Class; use Moose; use BiggerLib -all; has small => (is => "ro", isa => SmallInteger); has big => (is => "ro", isa => BigInteger); } is( exception { "Local::Class"->new(small => 9, big => 12) }, undef, "some values that should pass their type constraint", ); is( exception { "Local::Class"->new(small => 100) }, matchfor( 'Moose::Exception::ValidationFailedForTypeConstraint', qr{^Attribute \(small\) does not pass the type constraint} ), "direct violation of type constraint", ); is( exception { "Local::Class"->new(small => 5.5) }, matchfor( 'Moose::Exception::ValidationFailedForTypeConstraint', qr{^Attribute \(small\) does not pass the type constraint} ), "violation of parent type constraint", ); is( exception { "Local::Class"->new(small => "five point five") }, matchfor( 'Moose::Exception::ValidationFailedForTypeConstraint', qr{^Attribute \(small\) does not pass the type constraint} ), "violation of grandparent type constraint", ); is( exception { "Local::Class"->new(small => []) }, matchfor( 'Moose::Exception::ValidationFailedForTypeConstraint', qr{^Attribute \(small\) does not pass the type constraint} ), "violation of great-grandparent type constraint", ); note "Coercion..."; my $coercion; { package TmpNS1; use Moose::Util::TypeConstraints; use Scalar::Util qw(refaddr); subtype 'MyInt', as 'Int'; coerce 'MyInt', from 'ArrayRef', via { scalar(@$_) }; my $orig = find_type_constraint('MyInt'); my $type = Types::TypeTiny::to_TypeTiny($orig); ::ok($type->has_coercion, 'types converted from Moose retain coercions'); ::is($type->coerce([qw/a b c/]), 3, '... which work'); ::is(refaddr($type->moose_type), refaddr($orig), '... refaddr matches'); ::is(refaddr($type->coercion->moose_coercion), refaddr($orig->coercion), '... coercion refaddr matches'); $coercion = $type->coercion; } note "Introspection, comparisons, conversions..."; require Types::Standard; isa_ok( Types::Standard::Int(), 'Class::MOP::Object', 'Int', ); isa_ok( Types::Standard::ArrayRef(), 'Moose::Meta::TypeConstraint', 'ArrayRef', ); isa_ok( Types::Standard::ArrayRef(), 'Moose::Meta::TypeConstraint::Parameterizable', 'ArrayRef', ); isa_ok( Types::Standard::ArrayRef()->of(Types::Standard::Int()), 'Moose::Meta::TypeConstraint', 'ArrayRef[Int]', ); isa_ok( Types::Standard::ArrayRef()->of(Types::Standard::Int()), 'Moose::Meta::TypeConstraint::Parameterized', 'ArrayRef[Int]', ); isa_ok( Types::Standard::ArrayRef() | Types::Standard::Int(), 'Moose::Meta::TypeConstraint', 'ArrayRef|Int', ); isa_ok( Types::Standard::ArrayRef() | Types::Standard::Int(), 'Moose::Meta::TypeConstraint::Union', 'ArrayRef|Int', ); isa_ok( $coercion, 'Moose::Meta::TypeCoercion', 'MyInt->coercion', ); $coercion = do { my $arrayref = Types::Standard::ArrayRef()->plus_coercions( Types::Standard::ScalarRef(), sub { [$$_] }, ); my $int = Types::Standard::Int()->plus_coercions( Types::Standard::Num(), sub { int($_) }, ); my $array_or_int = $arrayref | $int; $array_or_int->coercion; }; isa_ok( $coercion, 'Moose::Meta::TypeCoercion', '(ArrayRef|Int)->coercion', ); isa_ok( $coercion, 'Moose::Meta::TypeCoercion::Union', '(ArrayRef|Int)->coercion', ); ok( Types::Standard::ArrayRef->moose_type->equals( Moose::Util::TypeConstraints::find_type_constraint("ArrayRef") ), "equivalence between Types::Standard types and core Moose types", ); require Type::Utils; my $classtype = Type::Utils::class_type(LocalClass => { class => "Local::Class" })->moose_type; isa_ok( $classtype, "Moose::Meta::TypeConstraint::Class", '$classtype', ); is( $classtype->class, "Local::Class", "Type::Tiny::Class provides meta information to Moose::Meta::TypeConstraint::Class", ); isa_ok( $classtype->Types::TypeTiny::to_TypeTiny, 'Type::Tiny::Class', '$classtype->Types::TypeTiny::to_TypeTiny', ); my $roletype = Type::Utils::role_type(LocalRole => { class => "Local::Role" })->moose_type; isa_ok( $roletype, "Moose::Meta::TypeConstraint", '$roletype', ); ok( !$roletype->isa("Moose::Meta::TypeConstraint::Role"), "NB! Type::Tiny::Role does not inflate to Moose::Meta::TypeConstraint::Role because of differing notions as to what constitutes a role.", ); isa_ok( $roletype->Types::TypeTiny::to_TypeTiny, 'Type::Tiny::Role', '$roletype->Types::TypeTiny::to_TypeTiny', ); my $ducktype = Type::Utils::duck_type(Darkwing => [qw/ foo bar baz /])->moose_type; isa_ok( $ducktype, "Moose::Meta::TypeConstraint::DuckType", '$ducktype', ); is_deeply( [sort @{$ducktype->methods}], [sort qw/ foo bar baz /], "Type::Tiny::Duck provides meta information to Moose::Meta::TypeConstraint::DuckType", ); isa_ok( $ducktype->Types::TypeTiny::to_TypeTiny, 'Type::Tiny::Duck', '$ducktype->Types::TypeTiny::to_TypeTiny', ); my $enumtype = Type::Utils::enum(MyEnum => [qw/ foo bar baz /])->moose_type; isa_ok( $enumtype, "Moose::Meta::TypeConstraint::Enum", '$classtype', ); is_deeply( [sort @{$enumtype->values}], [sort qw/ foo bar baz /], "Type::Tiny::Enum provides meta information to Moose::Meta::TypeConstraint::Enum", ); isa_ok( $enumtype->Types::TypeTiny::to_TypeTiny, 'Type::Tiny::Enum', '$enumtype->Types::TypeTiny::to_TypeTiny', ); my $union = Type::Utils::union(ICU => [$classtype->Types::TypeTiny::to_TypeTiny, $roletype->Types::TypeTiny::to_TypeTiny])->moose_type; isa_ok( $union, "Moose::Meta::TypeConstraint::Union", '$union', ); is_deeply( [sort @{$union->type_constraints}], [sort $classtype, $roletype], "Type::Tiny::Union provides meta information to Moose::Meta::TypeConstraint::Union", ); isa_ok( $union->Types::TypeTiny::to_TypeTiny, 'Type::Tiny::Union', '$union->Types::TypeTiny::to_TypeTiny', ); is( [sort @{$union->type_constraints}]->[0]->Types::TypeTiny::to_TypeTiny->{uniq}, $classtype->Types::TypeTiny::to_TypeTiny->{uniq}, '$union->type_constraints->[$i]->Types::TypeTiny::to_TypeTiny provides access to underlying Type::Tiny objects' ); my $intersect = Type::Utils::intersection(Chuck => [$classtype->Types::TypeTiny::to_TypeTiny, $roletype->Types::TypeTiny::to_TypeTiny])->moose_type; isa_ok( $intersect, "Moose::Meta::TypeConstraint", '$intersect', ); isa_ok( $intersect->Types::TypeTiny::to_TypeTiny, 'Type::Tiny::Intersection', '$intersect->Types::TypeTiny::to_TypeTiny', ); is( Scalar::Util::refaddr( $intersect->Types::TypeTiny::to_TypeTiny ), Scalar::Util::refaddr( $intersect->Types::TypeTiny::to_TypeTiny->moose_type->Types::TypeTiny::to_TypeTiny->moose_type->Types::TypeTiny::to_TypeTiny ), 'round-tripping between ->moose_type and ->Types::TypeTiny::to_TypeTiny preserves reference address' ); note "Method pass-through"; { local *Moose::Meta::TypeConstraint::dummy_1 = sub { 42; }; local *Moose::Meta::TypeCoercion::dummy_3 = sub { 666; }; is(Types::Standard::Int()->dummy_1, 42, 'method pass-through'); like( exception { Types::Standard::Int()->dummy_2 }, qr/^Can't locate object method "dummy_2"/, '... but not non-existant method', ); ok( Types::Standard::Int()->can('dummy_1') && !Types::Standard::Int()->can('dummy_2'), '... and `can` works ok', ); my $int = Types::Standard::Int()->plus_coercions(Types::Standard::Any(),q[999]); is($int->coercion->dummy_3, 666, 'method pass-through for coercions'); like( exception { $int->coercion->dummy_4 }, qr/^Can't locate object method "dummy_4"/, '... but not non-existant method', ); ok( $int->coercion->can('dummy_3') && !$int->coercion->can('dummy_4'), '... and `can` works ok', ); } done_testing; coercion-more.t000644001750001750 237113601673061 21426 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Moose=pod =encoding utf-8 =head1 PURPOSE Test for the good old "You cannot coerce an attribute unless its type has a coercion" error. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. Test is skipped if Moose 2.1200 is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { Moose => '2.1200' }; use Test::Fatal; use Test::TypeTiny qw( matchfor ); my $e; { package Local::Class; use Moose; use BiggerLib -all; ::isa_ok(BigInteger, "Moose::Meta::TypeConstraint"); has small => (is => "rw", isa => SmallInteger, coerce => 1); has big => (is => "rw", isa => BigInteger, coerce => 1); $e = ::exception { has big_nc => (is => "rw", isa => BigInteger->no_coercions, coerce => 1); }; } like( $e, qr{^You cannot coerce an attribute .?big_nc.? unless its type .?\w+.? has a coercion}, "no_coercions and friends available on Moose type constraint objects", ); done_testing; coercion.t000644001750001750 573113601673061 20471 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Moose=pod =encoding utf-8 =head1 PURPOSE Check coercions work with L; both mutable and immutable classes. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. Test is skipped if Moose 2.0000 is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { Moose => '2.0000' }; use Test::Fatal; use Test::TypeTiny qw( matchfor ); my $e; my $o; { package Local::Class; use Moose; use BiggerLib -all; ::isa_ok(BigInteger, "Moose::Meta::TypeConstraint"); has small => (is => "rw", isa => SmallInteger, coerce => 1); has big => (is => "rw", isa => BigInteger, coerce => 1); has big_nc => (is => "rw", isa => BigInteger->no_coercions, coerce => 0); } my $suffix = "mutable class"; for my $i (0..1) { $e = exception { $o = "Local::Class"->new( small => 104, big => 9, ); }; is($e, undef, "no exception on coercion in constructor - $suffix"); is($o && $o->big, 19, "'big' attribute coerces in constructor - $suffix"); is($o && $o->small, 4, "'small' attribute coerces in constructor - $suffix"); $e = exception { $o = "Local::Class"->new( small => [], big => {}, ); }; is( $e, matchfor( $i # exception class thrown by constructor is dependent on immutability ? 'Moose::Exception::ValidationFailedForInlineTypeConstraint' : 'Moose::Exception::ValidationFailedForTypeConstraint', qr{^Attribute \(big\)} ), "'big' attribute throws when it cannot coerce in constructor - $suffix", ); $e = exception { $o = "Local::Class"->new( small => {}, big => [], ); }; is( $e, matchfor( $i # exception class thrown by constructor is dependent on immutability ? 'Moose::Exception::ValidationFailedForInlineTypeConstraint' : 'Moose::Exception::ValidationFailedForTypeConstraint', qr{^Attribute \(small\)} ), "'small' attribute throws when it cannot coerce in constructor - $suffix", ); $o = "Local::Class"->new; $e = exception { $o->big([]); $o->small([]); }; is($o && $o->big, 100, "'big' attribute coerces in accessor - $suffix"); is($o && $o->small, 1, "'small' attribute coerces in accessor - $suffix"); $e = exception { $o->big({}) }; is( $e, matchfor( 'Moose::Exception::ValidationFailedForInlineTypeConstraint', qr{^Attribute \(big\)} ), "'big' attribute throws when it cannot coerce in accessor - $suffix", ); $e = exception { $o->small({}) }; is( $e, matchfor( 'Moose::Exception::ValidationFailedForInlineTypeConstraint', qr{^Attribute \(small\)} ), "'small' attribute throws when it cannot coerce in accessor - $suffix", ); "Local::Class"->meta->make_immutable; $suffix = "im$suffix"; } done_testing; inflate-then-inline.t000644001750001750 212513601673061 22514 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Moose=pod =encoding utf-8 =head1 PURPOSE Check type constraint inlining works with L in strange edge cases where we need to inflate Type::Tiny constraints into full L objects. =head1 DEPENDENCIES Test is skipped if Moose 2.1210 is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More 0.96; use Test::Requires { 'Moose' => '2.1005' }; use Type::Tiny; my $type1 = Type::Tiny->new; my $type2 = $type1->create_child_type( constraint => sub { !!2 }, inlined => sub { my ($self, $var) = @_; $self->parent->inline_check($var) . " && !!2"; }, ); like( $type2->inline_check('$XXX'), qr/\(\(?!!1\)? && !!2\)/, '$type2->inline_check' ); like( $type2->moose_type->_inline_check('$XXX'), qr/\(\(?!!1\)? && !!2\)/, '$type2->moose_type->_inline_check' ); done_testing; native-attribute-traits.t000644001750001750 1561713601673061 23507 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Moose=pod =encoding utf-8 =head1 PURPOSE Check type constraints and coercions work with L native attibute traits. =head1 DEPENDENCIES Test is skipped if Moose 2.1210 is not available. (The feature should work in older versions of Moose, but older versions of Test::Moose conflict with newer versions of Test::Builder.) =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use Test::More; use Test::Requires { Moose => '2.1210' }; use Test::Fatal; use Test::TypeTiny qw( matchfor ); use Test::Moose qw( with_immutable ); use Types::Standard -types; # For testing Array trait { package MyCollection; use Moose; use Types::Standard qw( ArrayRef Object ); has things => ( is => 'ro', isa => ArrayRef[ Object ], traits => [ 'Array' ], handles => { add => 'push' }, ); } # for testing Hash trait my %attributes = ( hashref => HashRef, hashref_int => HashRef[Int], map => Map, map_strint => Map[Str, Int], ); { package MyHashes; use Moose; while (my ($attr, $type) = each %attributes) { has $attr => ( traits => ['Hash'], is => 'ro', isa => $type, handles => { "$attr\_get" => 'get', "$attr\_set" => 'set', "$attr\_has" => 'exists', }, default => sub { +{} }, ); } } # For testing coercions { package Mini::Milk; use Moose; use Types::Standard qw( Int InstanceOf ); has i => (is => 'ro', isa => Int); around BUILDARGS => sub { my $next = shift; my $class = shift; return { i => $_[0] } if @_==1 and not ref $_[0]; $class->$next(@_); } } my $minimilk = InstanceOf->of('Mini::Milk')->plus_constructors(Num, "new"); { package MyCollection2; use Moose; use Types::Standard qw( ArrayRef ); has things => ( is => 'ro', isa => ArrayRef[ $minimilk ], traits => [ 'Array' ], handles => { add => 'push' }, coerce => 1, ); } { package MyCollection3; use Moose; use Types::Standard qw( ArrayRef ); has things => ( is => 'ro', isa => (ArrayRef[ $minimilk ])->create_child_type(coercion => 1), traits => [ 'Array' ], handles => { add => 'push' }, coerce => 1, ); } { package MyHashes2; use Moose; use Types::Standard qw( HashRef Map Int ); has hash => ( traits => ['Hash'], is => 'ro', isa => HashRef[ $minimilk ], coerce => 1, handles => { "hash_get" => 'get', "hash_set" => 'set', }, default => sub { +{} }, ); has 'map' => ( traits => ['Hash'], is => 'ro', isa => Map[ Int, $minimilk ], coerce => 1, handles => { "map_get" => 'get', "map_set" => 'set', }, default => sub { +{} }, ); } { package MyHashes3; use Moose; use Types::Standard qw( HashRef Map Int ); has hash => ( traits => ['Hash'], is => 'ro', isa => (HashRef[ $minimilk ])->create_child_type(coercion => 1), coerce => 1, handles => { "hash_get" => 'get', "hash_set" => 'set', }, default => sub { +{} }, ); has 'map' => ( traits => ['Hash'], is => 'ro', isa => (Map[ Int, $minimilk ])->create_child_type(coercion => 1), coerce => 1, handles => { "map_get" => 'get', "map_set" => 'set', }, default => sub { +{} }, ); } WEIRD_ERROR: { my $c = MyCollection3 ->meta ->get_attribute('things') ->type_constraint ->coercion ->compiled_coercion; my $input = [ Mini::Milk->new(0), 1, 2, 3 ]; my $output = $c->($input); my $expected = [ map Mini::Milk->new($_), 0..3 ]; is_deeply($output, $expected) or diag( B::Deparse->new->coderef2text($c) ); } my $i = 0; with_immutable { note($i++ ? "MUTABLE" : "IMMUTABLE"); subtest "Array trait with type ArrayRef[Object]" => sub { my $coll = MyCollection->new(things => []); ok( !exception { $coll->add(bless {}, "Monkey") }, 'pushing ok value', ); is( exception { $coll->add({})}, matchfor( 'Moose::Exception::ValidationFailedForInlineTypeConstraint', qr{^A new member value for things does not pass its type constraint because:}, ), 'pushing not ok value', ); }; my %subtests = ( MyCollection2 => "Array trait with type ArrayRef[InstanceOf] and coercion", MyCollection3 => "Array trait with type ArrayRef[InstanceOf] and coercion and subtyping", ); for my $class (sort keys %subtests) { subtest $subtests{$class} => sub { my $coll = $class->new(things => []); is( exception { $coll->add( 'Mini::Milk'->new(i => 0) ); $coll->add(1); $coll->add(2); $coll->add(3); }, undef, 'pushing ok values', ); my $things = $coll->things; for my $i (0 .. 3) { isa_ok($things->[$i], 'Mini::Milk', "\$things->[$i]"); is($things->[$i]->i, $i, "\$things->[$i]->i == $i"); } }; } for my $attr (sort keys %attributes) { my $type = $attributes{$attr}; my $getter = "$attr\_get"; my $setter = "$attr\_set"; my $predicate = "$attr\_has"; subtest "Hash trait with type $type" => sub { my $obj = MyHashes->new; is_deeply($obj->$attr, {}, 'default empty hash'); $obj->$setter(foo => 666); $obj->$setter(bar => 999); is($obj->$getter('foo'), 666, 'getter'); is($obj->$getter('bar'), 999, 'getter'); $obj->$setter(bar => 42); is($obj->$getter('bar'), 42, 'setter'); ok($obj->$predicate('foo'), 'predicate'); ok($obj->$predicate('bar'), 'predicate'); ok(!$obj->$predicate('baz'), 'predicate - negatory'); is_deeply($obj->$attr, { foo => 666, bar => 42 }, 'correct hash'); like( exception { $obj->$setter(baz => 3.141592) }, qr/type constraint/, 'cannot add non-Int value', ) if $attr =~ /int$/; done_testing; }; } %subtests = ( MyHashes2 => "Hash trait with types HashRef[InstanceOf] and Map[Int,InstanceOf]; and coercion", MyHashes3 => "Hash trait with types HashRef[InstanceOf] and Map[Int,InstanceOf]; and coercion and subtyping", ); for my $class (sort keys %subtests) { subtest $subtests{$class} => sub { my $H = $class->new(); is( exception { $H->hash_set( 0, 'Mini::Milk'->new(i => 0) ); $H->hash_set( 1, 1 ); $H->hash_set( 2, 2 ); $H->hash_set( 3, 3 ); }, undef, 'adding ok values to HashRef', ); is( exception { $H->map_set( 4, 'Mini::Milk'->new(i => 4) ); $H->map_set( 5, 5 ); $H->map_set( 6, 6 ); $H->map_set( 7, 7 ); }, undef, 'adding ok values to Map', ); my $h = $H->hash; for my $i (0 .. 3) { isa_ok($h->{$i}, 'Mini::Milk', "\$h->{$i}"); is($h->{$i}->i, $i, "\$h->{$i}->i == .$i"); } my $m = $H->map; for my $i (4 .. 7) { isa_ok($m->{$i}, 'Mini::Milk', "\$m->{$i}"); is($m->{$i}->i, $i, "\$m->{$i}->i == .$i"); } }; } } qw( MyCollection MyCollection2 MyCollection3 MyHashes Mini::Milk ); done_testing; parameterized.t000644001750001750 247413601673061 21525 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Moose=pod =encoding utf-8 =head1 PURPOSE Test that parameterizable Moose types are still parameterizable when they are converted to Type::Tiny. =head1 DEPENDENCIES Test is skipped if Moose is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Requires 'Moose::Util::TypeConstraints'; use Types::TypeTiny 'to_TypeTiny'; use Test::TypeTiny; ## We want to prevent Types::TypeTiny from noticing we've loaded a ## core type, because then it will just steal from Types::Standard. ## and bypass making a new type constraint. ## sub Types::Standard::get_type { return() } $INC{'Types/Standard.pm'} = 1; my $mt_ArrayRef = Moose::Util::TypeConstraints::find_type_constraint('ArrayRef'); my $mt_Int = Moose::Util::TypeConstraints::find_type_constraint('Int'); my $tt_ArrayRef = to_TypeTiny($mt_ArrayRef); my $tt_Int = to_TypeTiny($mt_Int); ok $tt_ArrayRef->is_parameterizable; my $tt_ArrayRef_of_Int = $tt_ArrayRef->of($tt_Int); should_pass [qw/1 2 3/], $tt_ArrayRef_of_Int; should_fail [qw/a b c/], $tt_ArrayRef_of_Int; done_testing; coercion.t000644001750001750 322013601673061 22050 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/MooseX-Getopt=pod =encoding utf-8 =head1 PURPOSE Check coercions work with L; both mutable and immutable classes. =head1 DEPENDENCIES Test is skipped if Moose 2.0000, MooseX::Getopt 0.63, and Types::Path::Tiny are not available. =head1 AUTHOR Alexander Hartmaier Eabraxxa@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Alexander Hartmaier. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { 'Moose' => '2.0000' }; use Test::Requires { 'MooseX::Getopt' => '0.63' }; use Test::Requires { 'Types::Path::Tiny' => '0' }; use Test::Fatal; use Test::TypeTiny qw( matchfor ); my @warnings; BEGIN { package Local::Types; use Type::Library -base, -declare => qw( Files ); use Type::Utils -all; use Types::Standard -types; use Types::Path::Tiny qw( Path to_Path ); declare Files, as ArrayRef[ Path ], coercion => 1; coerce Files, from Str, via { [ to_Path($_) ] }; $INC{'Local/Types.pm'} = __FILE__; }; # note explain( Local::Types::Files->moose_type ); { package Local::Class; use Moose; use Local::Types -all; with 'MooseX::Getopt'; has files => (is => "rw", isa => Files, coerce => 1); } my ($e, $o); my $suffix = "mutable class"; for my $i (0..1) { $e = exception { $o = "Local::Class"->new_with_options( files => 'foo.bar', ); }; is($e, undef, "no exception on coercion in constructor - $suffix"); "Local::Class"->meta->make_immutable; $suffix = "im$suffix"; } done_testing; basic.t000644001750001750 335413601673061 21202 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/MooseX-Types=pod =encoding utf-8 =head1 PURPOSE Complex checks between Type::Tiny and L. =head1 DEPENDENCIES MooseX::Types 0.35; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Requires { "MooseX::Types::Moose" => "0.35" }; use Test::TypeTiny; use MooseX::Types::Moose -all; use Types::Standard -all => { -prefix => "My" }; my $union1 = Int | MyArrayRef; my $union2 = MyArrayRef | Int; isa_ok($union1, "Moose::Meta::TypeConstraint"); isa_ok($union2, "Moose::Meta::TypeConstraint"); isa_ok($union2, "Type::Tiny"); should_pass([], $union1); should_pass(2, $union1); should_fail({}, $union1); should_pass([], $union2); should_pass(2, $union2); should_fail({}, $union2); my $param1 = MyArrayRef[Int]; my $param2 = ArrayRef[MyInt]; should_pass([1,2,3], $param1); should_pass([], $param1); should_fail({}, $param1); should_fail(["x"], $param1); should_pass([1,2,3], $param2); should_pass([], $param2); should_fail({}, $param2); should_fail(["x"], $param2); my $param_union = MyArrayRef[Int | ArrayRef]; should_pass([], $param_union); should_pass([1,2,3], $param_union); should_pass([[],[]], $param_union); should_pass([11,[]], $param_union); should_pass([[],11], $param_union); should_fail([1.111], $param_union); use Types::TypeTiny 'to_TypeTiny'; my $moosey = ArrayRef[HashRef[Int]]; my $tt1 = to_TypeTiny($moosey); my $tt2 = to_TypeTiny($moosey); is($tt1->{uniq}, $tt2->{uniq}, "to_TypeTiny caches results"); done_testing; extending.t000644001750001750 376613601673061 22115 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/MooseX-Types=pod =encoding utf-8 =head1 PURPOSE Check that L can extend an existing L type constraint library. =head1 DEPENDENCIES MooseX::Types 0.35; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Requires { "MooseX::Types::Moose" => "0.35" }; use Test::TypeTiny; use Test::Fatal; BEGIN { package MyTypes; use Type::Library -base, -declare => qw(NonEmptyStr); use Type::Utils -all; BEGIN { extends 'MooseX::Types::Moose', 'Types::TypeTiny' }; declare NonEmptyStr, as Str, where { length($_) }; $INC{'MyTypes.pm'} = __FILE__; }; use MyTypes -types; should_pass("foo", Str); should_pass("", Str); should_pass("foo", NonEmptyStr); should_fail("", NonEmptyStr); should_pass({}, HashLike); should_fail([], HashLike); { package MyDummy; use Moose; $INC{'MyDummy.pm'} = __FILE__; package MoreTypes; use Type::Library -base; ::like( ::exception { Type::Utils::extends 'MyDummy' }, qr/not a type constraint library/, 'cannot extend non-type-library', ); } BEGIN { package MyMooseTypes; use MooseX::Types -declare => ['RoundedInt']; use MooseX::Types::Moose qw(Int Num); subtype RoundedInt, as Int; coerce RoundedInt, from Num, via { int($_) }; $INC{'MyMooseTypes.pm'} = __FILE__; }; { package Local::XYZ1234; use MyMooseTypes qw(RoundedInt); ::is( RoundedInt->coerce(3.1), 3, 'MooseX::Types coercion works as expected' ); } BEGIN { package MyTinyTypes; use Type::Library -base; use Type::Utils 'extends'; extends 'MyMooseTypes'; $INC{'MyTinyTypes.pm'} = __FILE__; }; { package Local::XYZ12345678; use MyTinyTypes qw(RoundedInt); ::is( RoundedInt->coerce(3.1), 3, 'Type::Tiny coercion works built from MooseX::Types extension' ); } done_testing; more.t000644001750001750 330513601673061 21057 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/MooseX-Types=pod =encoding utf-8 =head1 PURPOSE More checks between Type::Tiny and L. This started out as an example of making a parameterized C<< Not[] >> type constraint, but worked out as a nice test case. =head1 DEPENDENCIES MooseX::Types 0.35; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Requires { "MooseX::Types::Moose" => "0.35" }; use Test::TypeTiny; BEGIN { package MooseX::Types::Not; use Type::Library -base; use Types::TypeTiny; __PACKAGE__->add_type({ name => "Not", constraint => sub { !!0 }, inlined => sub { "!!0" }, constraint_generator => sub { Types::TypeTiny::to_TypeTiny(shift)->complementary_type }, }); $INC{"MooseX/Types/Not.pm"} = __FILE__; }; use MooseX::Types::Not qw(Not); use MooseX::Types::Moose qw(Int); isa_ok($_, "Moose::Meta::TypeConstraint", "$_") for Not, Int, Not[Int], Not[Not[Int]]; should_fail(1.1, Int); should_fail(undef, Int); should_fail([], Int); should_pass(2, Int); should_pass(1.1, Not[Int]); should_pass(undef, Not[Int]); should_pass([], Not[Int]); should_fail(2, Not[Int]); should_fail(1.1, Not[Not[Int]]); should_fail(undef, Not[Not[Int]]); should_fail([], Not[Not[Int]]); should_pass(2, Not[Not[Int]]); # 'Not' alone behaves as 'Not[Any]' should_fail(1.1, Not); should_fail(undef, Not); should_fail([], Not); should_fail(2, Not); done_testing; basic.t000644001750001750 372513601673061 17760 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Mouse=pod =encoding utf-8 =head1 PURPOSE Check type constraints work with L. Checks values that should pass and should fail; checks error messages. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. Test is skipped if Mouse 1.00 is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { Mouse => 1.00 }; use Test::Fatal; { package Local::Class; use Mouse; use BiggerLib -all; has small => (is => "ro", isa => SmallInteger); has big => (is => "ro", isa => BigInteger); } is( exception { "Local::Class"->new(small => 9, big => 12) }, undef, "some values that should pass their type constraint", ); isnt( exception { "Local::Class"->new(small => 100) }, undef, "direct violation of type constraint", ); isnt( exception { "Local::Class"->new(small => 5.5) }, undef, "violation of parent type constraint", ); isnt( exception { "Local::Class"->new(small => "five point five") }, undef, "violation of grandparent type constraint", ); isnt( exception { "Local::Class"->new(small => []) }, undef, "violation of great-grandparent type constraint", ); use Mouse::Util; ok( Mouse::Util::is_a_type_constraint(BiggerLib::SmallInteger), "Mouse::Util::is_a_type_constraint accepts Type::Tiny type constraints", ); note "Coercion..."; { package TmpNS1; use Mouse::Util::TypeConstraints; subtype 'MyInt', as 'Int'; coerce 'MyInt', from 'ArrayRef', via { scalar(@$_) }; my $type = Types::TypeTiny::to_TypeTiny(find_type_constraint('MyInt')); ::ok($type->has_coercion, 'types converted from Mouse retain coercions'); ::is($type->coerce([qw/a b c/]), 3, '... which work'); } done_testing; coercion.t000644001750001750 423213601673061 20472 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Mouse=pod =encoding utf-8 =head1 PURPOSE Check coercions work with L; both mutable and immutable classes. =head1 DEPENDENCIES Uses the bundled BiggerLib.pm type library. Test is skipped if Mouse 1.00 is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { Mouse => 1.00 }; use Test::Fatal; { package Local::Class; use Mouse; use BiggerLib -all; ::isa_ok(BigInteger, "Mouse::Meta::TypeConstraint"); has small => (is => "rw", isa => SmallInteger, coerce => 1); has big => (is => "rw", isa => BigInteger, coerce => 1); } my ($e, $o); my $suffix = "mutable class"; for (0..1) { $e = exception { $o = "Local::Class"->new( small => 104, big => 9, ); }; is($e, undef, "no exception on coercion in constructor - $suffix"); is($o && $o->big, 19, "'big' attribute coerces in constructor - $suffix"); is($o && $o->small, 4, "'small' attribute coerces in constructor - $suffix"); $e = exception { $o = "Local::Class"->new( small => [], big => {}, ); }; isnt($e, undef, "'big' attribute throws when it cannot coerce in constructor - $suffix"); $e = exception { $o = "Local::Class"->new( small => {}, big => [], ); }; isnt($e, undef, "'small' attribute throws when it cannot coerce in constructor - $suffix"); $o = "Local::Class"->new; $e = exception { $o->big([]); $o->small([]); }; is($o && $o->big, 100, "'big' attribute coerces in accessor - $suffix"); is($o && $o->small, 1, "'small' attribute coerces in accessor - $suffix"); $e = exception { $o->big({}) }; isnt($e, undef, "'big' attribute throws when it cannot coerce in accessor - $suffix"); $e = exception { $o->small({}) }; isnt($e, undef, "'small' attribute throws when it cannot coerce in accessor - $suffix"); "Local::Class"->meta->make_immutable; $suffix = "im$suffix"; } done_testing; parameterized.t000644001750001750 247413601673061 21533 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Mouse=pod =encoding utf-8 =head1 PURPOSE Test that parameterizable Mouse types are still parameterizable when they are converted to Type::Tiny. =head1 DEPENDENCIES Test is skipped if Mouse is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Requires 'Mouse::Util::TypeConstraints'; use Types::TypeTiny 'to_TypeTiny'; use Test::TypeTiny; ## We want to prevent Types::TypeTiny from noticing we've loaded a ## core type, because then it will just steal from Types::Standard. ## and bypass making a new type constraint. ## sub Types::Standard::get_type { return() } $INC{'Types/Standard.pm'} = 1; my $mt_ArrayRef = Mouse::Util::TypeConstraints::find_type_constraint('ArrayRef'); my $mt_Int = Mouse::Util::TypeConstraints::find_type_constraint('Int'); my $tt_ArrayRef = to_TypeTiny($mt_ArrayRef); my $tt_Int = to_TypeTiny($mt_Int); ok $tt_ArrayRef->is_parameterizable; my $tt_ArrayRef_of_Int = $tt_ArrayRef->of($tt_Int); should_pass [qw/1 2 3/], $tt_ArrayRef_of_Int; should_fail [qw/a b c/], $tt_ArrayRef_of_Int; done_testing; basic.t000644001750001750 307213601673061 21205 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/MouseX-Types=pod =encoding utf-8 =head1 PURPOSE Complex checks between Type::Tiny and L. =head1 DEPENDENCIES MouseX::Types 0.06; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Requires { "MouseX::Types" => "0.06" }; use Test::TypeTiny; use MouseX::Types::Moose qw(Int ArrayRef); use Types::Standard -all => { -prefix => "My" }; my $union1 = Int | MyArrayRef; my $union2 = MyArrayRef | Int; isa_ok($union1, "Mouse::Meta::TypeConstraint"); isa_ok($union1, "Mouse::Meta::TypeConstraint"); isa_ok($union2, "Type::Tiny"); should_pass([], $union1); should_pass(2, $union1); should_fail({}, $union1); should_pass([], $union2); should_pass(2, $union2); should_fail({}, $union2); note explain($union2); my $param1 = MyArrayRef[Int]; my $param2 = ArrayRef[MyInt]; should_pass([1,2,3], $param1); should_pass([], $param1); should_fail({}, $param1); should_fail(["x"], $param1); should_pass([1,2,3], $param2); should_pass([], $param2); should_fail({}, $param2); should_fail(["x"], $param2); my $param_union = MyArrayRef[Int | ArrayRef]; should_pass([], $param_union); should_pass([1,2,3], $param_union); should_pass([[],[]], $param_union); should_pass([11,[]], $param_union); should_pass([[],11], $param_union); should_fail([1.111], $param_union); done_testing; extending.t000644001750001750 246713601673061 22120 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/MouseX-Types=pod =encoding utf-8 =head1 PURPOSE Check that L can extend an existing L type constraint library. =head1 DEPENDENCIES MouseX::Types 0.06; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Requires { "MouseX::Types" => "0.06" }; use Test::TypeTiny; use Test::Fatal; BEGIN { package MyTypes; use Type::Library -base, -declare => qw(NonEmptyStr); use Type::Utils -all; BEGIN { extends 'MouseX::Types::Moose', 'Types::TypeTiny' }; declare NonEmptyStr, as Str, where { length($_) }; $INC{'MyTypes.pm'} = __FILE__; }; use MyTypes -types; should_pass("foo", Str); should_pass("", Str); should_pass("foo", NonEmptyStr); should_fail("", NonEmptyStr); should_pass({}, HashLike); should_fail([], HashLike); { package MyDummy; use Mouse; $INC{'MyDummy.pm'} = __FILE__; package MoreTypes; use Type::Library -base; ::like( ::exception { Type::Utils::extends 'MyDummy' }, qr/not a type constraint library/, 'cannot extend non-type-library', ); } done_testing; basic.t000644001750001750 245513601673061 21635 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Object-Accessor=pod =encoding utf-8 =head1 PURPOSE Check type constraints work with L. =head1 DEPENDENCIES Test is skipped if Object::Accessor 0.30 is not available. =head1 CAVEATS As of Perl 5.17.x, the Object::Accessor module is being de-cored, so will issue deprecation warnings. These can safely be ignored for the purposes of this test case. Object::Accessor from CPAN does not have these warnings. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); # Avoid warnings about core version of Object::Accessor in Perl 5.18 no warnings qw(deprecated); use Test::More; use Test::Requires { "Object::Accessor" => 0.30 }; use Test::Fatal; use Types::Standard "Int"; use Object::Accessor; my $obj = Object::Accessor->new; $obj->mk_accessors( { foo => Int->compiled_check }, ); $obj->foo(12); is($obj->foo, 12, 'write then read on accessor works'); my $e = exception { local $Object::Accessor::FATAL = 1; $obj->foo("Hello"); }; isnt($e, undef, 'exception thrown for bad value'); done_testing; basic.t000644001750001750 414413601673061 21062 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Return-Type=pod =encoding utf-8 =head1 PURPOSE Test that this sort of thing works: sub foo :ReturnType(Int) { ...; } =head1 DEPENDENCIES Requires L 0.004; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; BEGIN { plan skip_all => "Test case fails with App::ForkProve" if exists $INC{"App/ForkProve.pm"}; }; use Test::Requires { 'Return::Type' => '0.004' }; use Types::Standard qw( HashRef Int ); use Test::Fatal; if (0) { require JSON; diag("\%ENV ".JSON->new->pretty(1)->canonical(1)->encode({%ENV})); diag("\%INC ".JSON->new->pretty(1)->canonical(1)->encode({%INC})); } sub foo :ReturnType(Int) { wantarray ? @_ : $_[0]; } subtest "simple return type constraint" => sub { subtest "scalar context" => sub { is( scalar(foo(42)), 42, ); isnt( exception { scalar(foo(4.2)) }, undef, ); done_testing; }; subtest "list context" => sub { is_deeply( [ foo(4, 2) ], [ 4, 2 ], ); isnt( exception { [ foo(4, 2, 4.2) ] }, undef, ); done_testing; }; done_testing; }; my $Even; BEGIN { $Even = Int->create_child_type( name => 'Even', constraint => sub { not($_[0] % 2) }, ); }; sub bar :ReturnType(scalar => $Even, list => HashRef[Int]) { wantarray ? @_ : scalar(@_); } subtest "more complex return type constraint" => sub { subtest "scalar context" => sub { is( scalar(bar(xxx => 1, yyy => 2)), 4, ); TODO: { local $TODO = 'this seems to fail: error in Return::Type??'; isnt( exception { scalar(bar(xxx => 1, 2)) }, undef, ); } done_testing; }; subtest "list context" => sub { is_deeply( { bar(xxx => 1, yyy => 2) }, { xxx => 1, yyy => 2 }, ); isnt( exception { [ bar(xxx => 1, 2) ] }, undef, ); done_testing; }; done_testing; }; done_testing; basic.t000644001750001750 153413601673061 20106 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Specio=pod =encoding utf-8 =head1 PURPOSE Check that Specio type constraints can be converted to Type::Tiny with inlining support. =head1 DEPENDENCIES Test is skipped if Specio is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Requires 'Specio'; use Specio::Library::Builtins; use Types::TypeTiny 'to_TypeTiny'; my $Int = to_TypeTiny t('Int'); ok $Int->check('4'); ok !$Int->check('4.1'); ok $Int->can_be_inlined; my $check_x = $Int->inline_check('$x'); ok do { my $x = '4'; eval $check_x }; ok do { my $x = '4.1'; !eval $check_x }; done_testing; library.t000644001750001750 150713601673061 20471 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Specio=pod =encoding utf-8 =head1 PURPOSE Check that Specio type libraries can be extended by Type::Library. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::TypeTiny; use Test::Requires 'Specio::Library::Builtins'; BEGIN { package Local::MyTypes; use Type::Library -base; use Type::Utils; Type::Utils::extends 'Specio::Library::Builtins'; $INC{'Local/MyTypes.pm'} = __FILE__; # allow `use` to work }; use Local::MyTypes qw(Int ArrayRef); should_pass 1, Int; should_pass [], ArrayRef; should_fail 1, ArrayRef; should_fail [], Int; done_testing; basic.t000644001750001750 575313601673061 20517 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Sub-Quote=pod =encoding utf-8 =head1 PURPOSE Check type constraints can be made inlinable using L. =head1 DEPENDENCIES Test is skipped if Sub::Quote is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires "Sub::Quote"; use Test::TypeTiny; use Sub::Quote; use Type::Tiny; use Types::Standard qw( ArrayRef Int ); my $Type1 = "Type::Tiny"->new( name => "Type1", constraint => quote_sub q{ $_[0] eq q(42) }, ); should_fail(41, $Type1); should_pass(42, $Type1); ok($Type1->can_be_inlined, 'constraint built using quote_sub and $_[0] can be inlined') and note $Type1->inline_check('$value'); my $Type2 = "Type::Tiny"->new( name => "Type2", constraint => quote_sub q{ $_ eq q(42) }, ); should_fail(41, $Type2); should_pass(42, $Type2); ok($Type2->can_be_inlined, 'constraint built using quote_sub and $_[0] can be inlined') and note $Type2->inline_check('$value'); my $Type3 = "Type::Tiny"->new( name => "Type3", constraint => quote_sub q{ my ($n) = @_; $n eq q(42) }, ); should_fail(41, $Type3); should_pass(42, $Type3); ok($Type3->can_be_inlined, 'constraint built using quote_sub and @_ can be inlined') and note $Type3->inline_check('$value'); my $Type4 = "Type::Tiny"->new( name => "Type4", parent => Int, constraint => quote_sub q{ $_[0] >= 42 }, ); should_fail(41, $Type4); should_pass(42, $Type4); should_pass(43, $Type4); should_fail(44.4, $Type4); ok($Type4->can_be_inlined, 'constraint built using quote_sub and parent type can be inlined') and note $Type4->inline_check('$value'); my $Type5 = "Type::Tiny"->new( name => "Type5", parent => Int, constraint => quote_sub q{ $_[0] >= $x }, { '$x' => \42 }, ); should_fail(41, $Type5); should_pass(42, $Type5); should_pass(43, $Type5); should_fail(44.4, $Type5); TODO: { local $TODO = "captures not supported yet"; ok($Type5->can_be_inlined, 'constraint built using quote_sub and captures can be inlined'); }; my $Type6 = "Type::Tiny"->new( name => "Type6", parent => Int->create_child_type(constraint => sub { 999 }), constraint => quote_sub q{ $_[0] >= 42 }, ); should_fail(41, $Type6); should_pass(42, $Type6); should_pass(43, $Type6); should_fail(44.4, $Type6); ok(!$Type6->can_be_inlined, 'constraint built using quote_sub and non-inlinable parent cannot be inlined'); my $Type7 = ArrayRef([Int]) & quote_sub q{ @$_ > 1 and @$_ < 4 }; should_pass([1,2,3], $Type7); should_fail([1,2.1,3], $Type7); should_fail([1], $Type7); should_fail([1,2,3,4], $Type7); ok($Type7->can_be_inlined, 'constraint built as an intersection of an inlinable type constraint and a quoted sub can be inlined'); note($Type7->inline_check('$VAR')); done_testing; delayed-quoting.t000644001750001750 232713601673061 22523 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Sub-Quote=pod =encoding utf-8 =head1 PURPOSE Check type constraints can be made inlinable using L even if Sub::Quote is loaded late. =head1 DEPENDENCIES Some parts are skipped if Sub::Quote is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2018-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::TypeTiny; use Types::Standard qw( ArrayRef Int ); my $type = ArrayRef[Int]; my $coderef1 = $type->_overload_coderef; my $coderef2 = $type->_overload_coderef; is($coderef1, $coderef2, 'overload coderef gets cached instead of being rebuilt'); eval { require Sub::Quote } or do { diag "Sub::Quote required for further testing"; done_testing; exit(0); }; my $coderef3 = $type->_overload_coderef; isnt($coderef3, $coderef1, 'loading Sub::Quote triggers rebuilding overload coderef'); my $coderef4 = $type->_overload_coderef; is($coderef3, $coderef4, 'overload coderef gets cached again instead of being rebuilt'); done_testing; unquote-coercions.t000644001750001750 304413601673061 23107 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Sub-Quote=pod =encoding utf-8 =head1 PURPOSE Check type coercions can be unquoted L. =head1 DEPENDENCIES Test is skipped if Sub::Quote is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires "Sub::Quote"; use Test::TypeTiny; use Sub::Quote; use Type::Tiny; use Types::Standard qw( ArrayRef Int ); use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires "Sub::Quote"; use Test::Fatal; use Sub::Quote; use Type::Tiny; use Types::Standard qw( Int Num ArrayRef ); my $type = Int->plus_coercions( Num, q[ int($_) ], ArrayRef, q[ scalar(@$_) ], ); my $coercion = $type->coercion; my ($name, $code, $captures, $compiled_sub) = @{ Sub::Quote::quoted_from_sub( \&$coercion ); }; ok(defined($code), 'Got back code from Sub::Quote'); my $coderef = eval "sub { $code }"; is(ref($coderef), 'CODE', '... which compiles OK'); is( $coderef->(42), 42, "... which passes through values that don't need to be coerced", ); ok( $coderef->(3.1)==3 && $coderef->([qw/foo bar/])==2, "... coerces values that can be coerced", ); is_deeply( $coderef->({foo => 666}), {foo => 666}, "... and passes through any values it can't handle", ); done_testing; unquote-constraints.t000644001750001750 212713601673061 23473 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Sub-Quote=pod =encoding utf-8 =head1 PURPOSE Check type constraints can be unquoted L. =head1 DEPENDENCIES Test is skipped if Sub::Quote is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires "Sub::Quote"; use Test::Fatal; use Sub::Quote; use Type::Tiny; use Types::Standard qw( Int ); my $type = Int; my ($name, $code, $captures, $compiled_sub) = @{ Sub::Quote::quoted_from_sub( \&$type ); }; ok(defined($code), 'Got back code from Sub::Quote'); my $coderef = eval "sub { $code }"; is(ref($coderef), 'CODE', '... which compiles OK'); ok($coderef->(42), '... and seems to work'); like( exception { $coderef->([]) }, qr/\AReference \[\] did not pass type constraint "Int"/, '... and throws exceptions properly', ); done_testing; basic.t000644001750001750 147313601673061 21014 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Switcheroo=pod =encoding utf-8 =head1 PURPOSE Checks Type::Tiny works with L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires 'Switcheroo'; use Test::Fatal; use Types::Standard -all; use Switcheroo; sub what_is { my $var = shift; switch ($var) { case ArrayRef: 'ARRAY'; case HashRef: 'HASH'; default: undef; } } is( what_is([]), 'ARRAY', ); is( what_is({}), 'HASH', ); is( what_is(42), undef, ); is( what_is(\(42)), undef, ); done_testing; basic.t000644001750001750 243613601673061 20326 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Type-Tie=pod =encoding utf-8 =head1 PURPOSE Test that this sort of thing works: tie my $var, Int; =head1 DEPENDENCIES Requires L; skipped otherwise. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use Test::More; use Test::Requires 'Type::Tie'; use Types::Standard qw( ArrayRef Int ); use Test::Fatal; subtest "tied scalar" => sub { tie my($int), Int; is( exception { $int = 42 }, undef, ); isnt( exception { $int = 4.2 }, undef, ); is($int, 42); done_testing; }; subtest "tied array" => sub { tie my(@ints), Int; is( exception { $ints[0] = 1; push @ints, 2; unshift @ints, 0; }, undef, ); isnt( exception { $ints[3] = 3.5 }, undef, ); is_deeply( \@ints, [ 0..2 ], ); done_testing; }; subtest "tied hash" => sub { tie my(%ints), Int; is( exception { $ints{one} = 1; $ints{two} = 2; }, undef, ); isnt( exception { $ints{three} = 3.5 }, undef, ); is_deeply( \%ints, { one => 1, two => 2 }, ); done_testing; }; done_testing; basic.t000644001750001750 216213601673061 21501 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Types-ReadOnly=pod =encoding utf-8 =head1 PURPOSE L does some frickin weird stuff with parameterization. Check it all works! =head1 DEPENDENCIES Test is skipped if Types::ReadOnly 0.003 is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { "Types::ReadOnly" => '0.003' }; use Test::Fatal; use Types::Standard -types; use Types::ReadOnly -types; my $UnitHash = Dict->of( magnitude => Num, unit => Optional[Str], )->plus_coercions( Str ,=> q{ do { my($m,$u) = split / /; { magnitude => $m, unit => $u } } }, ); my $LockedUnitHash = Locked[$UnitHash]; my $thirtymetres = $LockedUnitHash->coerce('30 m'); is($thirtymetres->{magnitude}, 30); is($thirtymetres->{unit}, 'm'); my $e = exception { $thirtymetres->{shizzle}++ }; like($e, qr/disallowed key/); done_testing; archaic.t000644001750001750 451613601673061 23564 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Validation-Class-Simple=pod =encoding utf-8 =head1 PURPOSE Fake L 7.900017 by overriding C<< $VERSION >> variable. (There is a reason for this... C follows two different code paths depending on the version of the Validation::Class::Simple object passed to it.) =head1 DEPENDENCIES Test is skipped if Validation::Class 7.900017 is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { "Validation::Class" => "7.900017" }; use Test::TypeTiny; use Types::TypeTiny qw( to_TypeTiny ); use Validation::Class::Simple; BEGIN { $Validation::Class::Simple::VERSION = '7.900017' }; my $type = to_TypeTiny "Validation::Class::Simple"->new( fields => { name => { required => 1, pattern => qr{^\w+(\s\w+)*$}, filters => [qw/trim/] }, email => { required => 1 }, pass => { required => 1 }, pass2 => { required => 1, matches => 'pass' }, }, ); isa_ok($type, "Type::Tiny", 'can create a child type constraint from Validation::Class::Simple'); should_fail('Hello', $type); should_fail({}, $type); should_fail({ name => 'Toby', email => 'tobyink@cpan.org', pass => 'foo', pass2 => 'bar' }, $type); should_pass({ name => 'Toby', email => 'tobyink@cpan.org', pass => 'foo', pass2 => 'foo' }, $type); should_fail({ name => 'Toby ', email => 'tobyink@cpan.org', pass => 'foo', pass2 => 'foo' }, $type); my $msg = $type->get_message({ name => 'Toby', email => 'tobyink@cpan.org', pass => 'foo', pass2 => 'bar' }); like($msg, qr{pass2 does not match pass}, 'correct error message (A)'); my $msg2 = $type->get_message({ name => 'Toby ', email => 'tobyink@cpan.org', pass => 'foo', pass2 => 'foo' }); like($msg2, qr{name is not formatted properly}, 'correct error message (B)'); ok($type->has_coercion, 'the type has a coercion'); is_deeply( $type->coerce( { name => 'Toby ', email => 'tobyink@cpan.org', pass => 'foo', pass2 => 'foo', monkey => 'nuts' }, ), { name => 'Toby', email => 'tobyink@cpan.org', pass => 'foo', pass2 => 'foo' }, "... which works", ); done_testing; basic.t000644001750001750 435513601673061 23254 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/Validation-Class-Simple=pod =encoding utf-8 =head1 PURPOSE Check type constraints L objects can be used as type constraints. =head1 DEPENDENCIES Test is skipped if Validation::Class 7.900017 is not available. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires { "Validation::Class" => "7.900017" }; use Test::TypeTiny; use Types::TypeTiny qw( to_TypeTiny _ForeignTypeConstraint ); use Validation::Class::Simple; my $orig = "Validation::Class::Simple"->new( fields => { name => { required => 1, pattern => qr{^\w+(\s\w+)*$}, filters => [qw/trim/] }, email => { required => 1 }, pass => { required => 1 }, pass2 => { required => 1, matches => 'pass' }, }, ); my $type = to_TypeTiny $orig; should_pass($orig, _ForeignTypeConstraint); should_fail($type, _ForeignTypeConstraint); isa_ok($type, "Type::Tiny", 'can create a child type constraint from Validation::Class::Simple'); should_fail('Hello', $type); should_fail({}, $type); should_fail({ name => 'Toby', email => 'tobyink@cpan.org', pass => 'foo', pass2 => 'bar' }, $type); should_pass({ name => 'Toby', email => 'tobyink@cpan.org', pass => 'foo', pass2 => 'foo' }, $type); should_fail({ name => 'Toby ', email => 'tobyink@cpan.org', pass => 'foo', pass2 => 'foo' }, $type); my $msg = $type->get_message({ name => 'Toby', email => 'tobyink@cpan.org', pass => 'foo', pass2 => 'bar' }); like($msg, qr{pass2 does not match pass}, 'correct error message (A)'); my $msg2 = $type->get_message({ name => 'Toby ', email => 'tobyink@cpan.org', pass => 'foo', pass2 => 'foo' }); like($msg2, qr{name is not formatted properly}, 'correct error message (B)'); ok($type->has_coercion, 'the type has a coercion'); is_deeply( $type->coerce( { name => 'Toby ', email => 'tobyink@cpan.org', pass => 'foo', pass2 => 'foo', monkey => 'nuts' }, ), { name => 'Toby', email => 'tobyink@cpan.org', pass => 'foo', pass2 => 'foo' }, "... which works", ); done_testing; basic.t000644001750001750 131513601673061 21244 0ustar00taitai000000000000Type-Tiny-1.008001/t/30-integration/match-simple=pod =encoding utf-8 =head1 PURPOSE Checks Type::Tiny works with L. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut use strict; use warnings; use lib qw( ./lib ./t/lib ../inc ./inc ); use Test::More; use Test::Requires 'match::simple'; use Test::Fatal; use Types::Standard -all; use match::simple { replace => 1 }; ok( 42 |M| Int ); ok( 42 |M| Num ); ok not( 42 |M| ArrayRef ); ok( 42 |M| \&is_Int ); ok not( 42 |M| \&is_ArrayRef ); done_testing; Module.pm000644001750001750 735013601673061 20645 0ustar00taitai000000000000Type-Tiny-1.008001/inc/archaic/Test/Builderpackage Test::Builder::Module; use strict; use Test::Builder; require Exporter; our @ISA = qw(Exporter); our $VERSION = '0.98'; $VERSION = eval $VERSION; ## no critic (BuiltinFunctions::ProhibitStringyEval) =head1 NAME Test::Builder::Module - Base class for test modules =head1 SYNOPSIS # Emulates Test::Simple package Your::Module; my $CLASS = __PACKAGE__; use base 'Test::Builder::Module'; @EXPORT = qw(ok); sub ok ($;$) { my $tb = $CLASS->builder; return $tb->ok(@_); } 1; =head1 DESCRIPTION This is a superclass for Test::Builder-based modules. It provides a handful of common functionality and a method of getting at the underlying Test::Builder object. =head2 Importing Test::Builder::Module is a subclass of Exporter which means your module is also a subclass of Exporter. @EXPORT, @EXPORT_OK, etc... all act normally. A few methods are provided to do the C 23> part for you. =head3 import Test::Builder::Module provides an import() method which acts in the same basic way as Test::More's, setting the plan and controlling exporting of functions and variables. This allows your module to set the plan independent of Test::More. All arguments passed to import() are passed onto C<< Your::Module->builder->plan() >> with the exception of C<< import =>[qw(things to import)] >>. use Your::Module import => [qw(this that)], tests => 23; says to import the functions this() and that() as well as set the plan to be 23 tests. import() also sets the exported_to() attribute of your builder to be the caller of the import() function. Additional behaviors can be added to your import() method by overriding import_extra(). =cut sub import { my($class) = shift; # Don't run all this when loading ourself. return 1 if $class eq 'Test::Builder::Module'; my $test = $class->builder; my $caller = caller; $test->exported_to($caller); $class->import_extra( \@_ ); my(@imports) = $class->_strip_imports( \@_ ); $test->plan(@_); $class->export_to_level( 1, $class, @imports ); } sub _strip_imports { my $class = shift; my $list = shift; my @imports = (); my @other = (); my $idx = 0; while( $idx <= $#{$list} ) { my $item = $list->[$idx]; if( defined $item and $item eq 'import' ) { push @imports, @{ $list->[ $idx + 1 ] }; $idx++; } else { push @other, $item; } $idx++; } @$list = @other; return @imports; } =head3 import_extra Your::Module->import_extra(\@import_args); import_extra() is called by import(). It provides an opportunity for you to add behaviors to your module based on its import list. Any extra arguments which shouldn't be passed on to plan() should be stripped off by this method. See Test::More for an example of its use. B This mechanism is I as it feels like a bit of an ugly hack in its current form. =cut sub import_extra { } =head2 Builder Test::Builder::Module provides some methods of getting at the underlying Test::Builder object. =head3 builder my $builder = Your::Class->builder; This method returns the Test::Builder object associated with Your::Class. It is not a constructor so you can call it as often as you like. This is the preferred way to get the Test::Builder object. You should I get it via C<< Test::Builder->new >> as was previously recommended. The object returned by builder() may change at runtime so you should call builder() inside each function rather than store it in a global. sub ok { my $builder = Your::Class->builder; return $builder->ok(@_); } =cut sub builder { return Test::Builder->new; } 1; Tester.pm000644001750001750 3625713601673061 20716 0ustar00taitai000000000000Type-Tiny-1.008001/inc/archaic/Test/Builderpackage Test::Builder::Tester; use strict; our $VERSION = "1.22"; use Test::Builder; use Symbol; use Carp; =head1 NAME Test::Builder::Tester - test testsuites that have been built with Test::Builder =head1 SYNOPSIS use Test::Builder::Tester tests => 1; use Test::More; test_out("not ok 1 - foo"); test_fail(+1); fail("foo"); test_test("fail works"); =head1 DESCRIPTION A module that helps you test testing modules that are built with B. The testing system is designed to be used by performing a three step process for each test you wish to test. This process starts with using C and C in advance to declare what the testsuite you are testing will output with B to stdout and stderr. You then can run the test(s) from your test suite that call B. At this point the output of B is safely captured by B rather than being interpreted as real test output. The final stage is to call C that will simply compare what you predeclared to what B actually outputted, and report the results back with a "ok" or "not ok" (with debugging) to the normal output. =cut #### # set up testing #### my $t = Test::Builder->new; ### # make us an exporter ### use Exporter; our @ISA = qw(Exporter); our @EXPORT = qw(test_out test_err test_fail test_diag test_test line_num); sub import { my $class = shift; my(@plan) = @_; my $caller = caller; $t->exported_to($caller); $t->plan(@plan); my @imports = (); foreach my $idx ( 0 .. $#plan ) { if( $plan[$idx] eq 'import' ) { @imports = @{ $plan[ $idx + 1 ] }; last; } } __PACKAGE__->export_to_level( 1, __PACKAGE__, @imports ); } ### # set up file handles ### # create some private file handles my $output_handle = gensym; my $error_handle = gensym; # and tie them to this package my $out = tie *$output_handle, "Test::Builder::Tester::Tie", "STDOUT"; my $err = tie *$error_handle, "Test::Builder::Tester::Tie", "STDERR"; #### # exported functions #### # for remembering that we're testing and where we're testing at my $testing = 0; my $testing_num; # remembering where the file handles were originally connected my $original_output_handle; my $original_failure_handle; my $original_todo_handle; my $original_test_number; my $original_harness_state; my $original_harness_env; # function that starts testing and redirects the filehandles for now sub _start_testing { # even if we're running under Test::Harness pretend we're not # for now. This needed so Test::Builder doesn't add extra spaces $original_harness_env = $ENV{HARNESS_ACTIVE} || 0; $ENV{HARNESS_ACTIVE} = 0; # remember what the handles were set to $original_output_handle = $t->output(); $original_failure_handle = $t->failure_output(); $original_todo_handle = $t->todo_output(); # switch out to our own handles $t->output($output_handle); $t->failure_output($error_handle); $t->todo_output($output_handle); # clear the expected list $out->reset(); $err->reset(); # remember that we're testing $testing = 1; $testing_num = $t->current_test; $t->current_test(0); # look, we shouldn't do the ending stuff $t->no_ending(1); } =head2 Functions These are the six methods that are exported as default. =over 4 =item test_out =item test_err Procedures for predeclaring the output that your test suite is expected to produce until C is called. These procedures automatically assume that each line terminates with "\n". So test_out("ok 1","ok 2"); is the same as test_out("ok 1\nok 2"); which is even the same as test_out("ok 1"); test_out("ok 2"); Once C or C (or C or C) have been called, all further output from B will be captured by B. This means that you will not be able perform further tests to the normal output in the normal way until you call C (well, unless you manually meddle with the output filehandles) =cut sub test_out { # do we need to do any setup? _start_testing() unless $testing; $out->expect(@_); } sub test_err { # do we need to do any setup? _start_testing() unless $testing; $err->expect(@_); } =item test_fail Because the standard failure message that B produces whenever a test fails will be a common occurrence in your test error output, and because it has changed between Test::Builder versions, rather than forcing you to call C with the string all the time like so test_err("# Failed test ($0 at line ".line_num(+1).")"); C exists as a convenience function that can be called instead. It takes one argument, the offset from the current line that the line that causes the fail is on. test_fail(+1); This means that the example in the synopsis could be rewritten more simply as: test_out("not ok 1 - foo"); test_fail(+1); fail("foo"); test_test("fail works"); =cut sub test_fail { # do we need to do any setup? _start_testing() unless $testing; # work out what line we should be on my( $package, $filename, $line ) = caller; $line = $line + ( shift() || 0 ); # prevent warnings # expect that on stderr $err->expect("# Failed test ($0 at line $line)"); } =item test_diag As most of the remaining expected output to the error stream will be created by Test::Builder's C function, B provides a convenience function C that you can use instead of C. The C function prepends comment hashes and spacing to the start and newlines to the end of the expected output passed to it and adds it to the list of expected error output. So, instead of writing test_err("# Couldn't open file"); you can write test_diag("Couldn't open file"); Remember that B's diag function will not add newlines to the end of output and test_diag will. So to check Test::Builder->new->diag("foo\n","bar\n"); You would do test_diag("foo","bar") without the newlines. =cut sub test_diag { # do we need to do any setup? _start_testing() unless $testing; # expect the same thing, but prepended with "# " local $_; $err->expect( map { "# $_" } @_ ); } =item test_test Actually performs the output check testing the tests, comparing the data (with C) that we have captured from B against that that was declared with C and C. This takes name/value pairs that effect how the test is run. =over =item title (synonym 'name', 'label') The name of the test that will be displayed after the C or C. =item skip_out Setting this to a true value will cause the test to ignore if the output sent by the test to the output stream does not match that declared with C. =item skip_err Setting this to a true value will cause the test to ignore if the output sent by the test to the error stream does not match that declared with C. =back As a convenience, if only one argument is passed then this argument is assumed to be the name of the test (as in the above examples.) Once C has been run test output will be redirected back to the original filehandles that B was connected to (probably STDOUT and STDERR,) meaning any further tests you run will function normally and cause success/errors for B. =cut sub test_test { # decode the arguments as described in the pod my $mess; my %args; if( @_ == 1 ) { $mess = shift } else { %args = @_; $mess = $args{name} if exists( $args{name} ); $mess = $args{title} if exists( $args{title} ); $mess = $args{label} if exists( $args{label} ); } # er, are we testing? croak "Not testing. You must declare output with a test function first." unless $testing; # okay, reconnect the test suite back to the saved handles $t->output($original_output_handle); $t->failure_output($original_failure_handle); $t->todo_output($original_todo_handle); # restore the test no, etc, back to the original point $t->current_test($testing_num); $testing = 0; # re-enable the original setting of the harness $ENV{HARNESS_ACTIVE} = $original_harness_env; # check the output we've stashed unless( $t->ok( ( $args{skip_out} || $out->check ) && ( $args{skip_err} || $err->check ), $mess ) ) { # print out the diagnostic information about why this # test failed local $_; $t->diag( map { "$_\n" } $out->complaint ) unless $args{skip_out} || $out->check; $t->diag( map { "$_\n" } $err->complaint ) unless $args{skip_err} || $err->check; } } =item line_num A utility function that returns the line number that the function was called on. You can pass it an offset which will be added to the result. This is very useful for working out the correct text of diagnostic functions that contain line numbers. Essentially this is the same as the C<__LINE__> macro, but the C idiom is arguably nicer. =cut sub line_num { my( $package, $filename, $line ) = caller; return $line + ( shift() || 0 ); # prevent warnings } =back In addition to the six exported functions there exists one function that can only be accessed with a fully qualified function call. =over 4 =item color When C is called and the output that your tests generate does not match that which you declared, C will print out debug information showing the two conflicting versions. As this output itself is debug information it can be confusing which part of the output is from C and which was the original output from your original tests. Also, it may be hard to spot things like extraneous whitespace at the end of lines that may cause your test to fail even though the output looks similar. To assist you C can colour the background of the debug information to disambiguate the different types of output. The debug output will have its background coloured green and red. The green part represents the text which is the same between the executed and actual output, the red shows which part differs. The C function determines if colouring should occur or not. Passing it a true or false value will enable or disable colouring respectively, and the function called with no argument will return the current setting. To enable colouring from the command line, you can use the B module like so: perl -Mlib=Text::Builder::Tester::Color test.t Or by including the B module directly in the PERL5LIB. =cut my $color; sub color { $color = shift if @_; $color; } =back =head1 BUGS Calls C<no_ending>> turning off the ending tests. This is needed as otherwise it will trip out because we've run more tests than we strictly should have and it'll register any failures we had that we were testing for as real failures. The color function doesn't work unless B is compatible with your terminal. Bugs (and requests for new features) can be reported to the author though the CPAN RT system: L =head1 AUTHOR Copyright Mark Fowler Emark@twoshortplanks.comE 2002, 2004. Some code taken from B and B, written by by Michael G Schwern Eschwern@pobox.comE. Hence, those parts Copyright Micheal G Schwern 2001. Used and distributed with permission. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 NOTES Thanks to Richard Clamp Erichardc@unixbeard.netE for letting me use his testing system to try this module out on. =head1 SEE ALSO L, L, L. =cut 1; #################################################################### # Helper class that is used to remember expected and received data package Test::Builder::Tester::Tie; ## # add line(s) to be expected sub expect { my $self = shift; my @checks = @_; foreach my $check (@checks) { $check = $self->_translate_Failed_check($check); push @{ $self->{wanted} }, ref $check ? $check : "$check\n"; } } sub _translate_Failed_check { my( $self, $check ) = @_; if( $check =~ /\A(.*)# (Failed .*test) \((.*?) at line (\d+)\)\Z(?!\n)/ ) { $check = "/\Q$1\E#\\s+\Q$2\E.*?\\n?.*?\Qat $3\E line \Q$4\E.*\\n?/"; } return $check; } ## # return true iff the expected data matches the got data sub check { my $self = shift; # turn off warnings as these might be undef local $^W = 0; my @checks = @{ $self->{wanted} }; my $got = $self->{got}; foreach my $check (@checks) { $check = "\Q$check\E" unless( $check =~ s,^/(.*)/$,$1, or ref $check ); return 0 unless $got =~ s/^$check//; } return length $got == 0; } ## # a complaint message about the inputs not matching (to be # used for debugging messages) sub complaint { my $self = shift; my $type = $self->type; my $got = $self->got; my $wanted = join "\n", @{ $self->wanted }; # are we running in colour mode? if(Test::Builder::Tester::color) { # get color eval { require Term::ANSIColor }; unless($@) { # colours my $green = Term::ANSIColor::color("black") . Term::ANSIColor::color("on_green"); my $red = Term::ANSIColor::color("black") . Term::ANSIColor::color("on_red"); my $reset = Term::ANSIColor::color("reset"); # work out where the two strings start to differ my $char = 0; $char++ while substr( $got, $char, 1 ) eq substr( $wanted, $char, 1 ); # get the start string and the two end strings my $start = $green . substr( $wanted, 0, $char ); my $gotend = $red . substr( $got, $char ) . $reset; my $wantedend = $red . substr( $wanted, $char ) . $reset; # make the start turn green on and off $start =~ s/\n/$reset\n$green/g; # make the ends turn red on and off $gotend =~ s/\n/$reset\n$red/g; $wantedend =~ s/\n/$reset\n$red/g; # rebuild the strings $got = $start . $gotend; $wanted = $start . $wantedend; } } return "$type is:\n" . "$got\nnot:\n$wanted\nas expected"; } ## # forget all expected and got data sub reset { my $self = shift; %$self = ( type => $self->{type}, got => '', wanted => [], ); } sub got { my $self = shift; return $self->{got}; } sub wanted { my $self = shift; return $self->{wanted}; } sub type { my $self = shift; return $self->{type}; } ### # tie interface ### sub PRINT { my $self = shift; $self->{got} .= join '', @_; } sub TIEHANDLE { my( $class, $type ) = @_; my $self = bless { type => $type }, $class; $self->reset; return $self; } sub READ { } sub READLINE { } sub GETC { } sub FILENO { } 1; AllTypes.pod000644001750001750 1711213601673061 20517 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual::AllTypes - alphabetical list of all type constraints bundled with Type::Tiny =head1 MANUAL The following is a list of type constraints bundled with Type::Tiny, with very brief descriptions. For more information, see the type library's documentation, and the test cases in C<< t/21-types/ >>. GitHib link: L. =over =item * B<< Any >> in L Anything. Absolutely anything. =item * B<< ArrayLike >> in L Arrayrefs and objects overloading arrayfication. =item * B<< ArrayRef >> I<< [parameterizable] >> in L Arrayrefs. =item * B<< Bool >> I<< [has coercion] >> in L Booleans; the numbers or strings "0" and "1", the empty string, or undef. =item * B<< ClassName >> in L Any loaded package name. =item * B<< CodeLike >> in L Coderefs and objects overloading coderefification. =item * B<< CodeRef >> in L Coderefs. =item * B<< ConsumerOf >> I<< [parameterizable] >> in L An object that DOES a particular role. =item * B<< CycleTuple >> I<< [parameterizable] >> in L An arrayref with a repeating pattern of constraints on its values. =item * B<< Defined >> in L Any value other than undef. =item * B<< Dict >> I<< [parameterizable] >> in L A hashref with constraints on each of its values. =item * B<< Enum >> I<< [parameterizable] >> in L A string from an allowed set of strings. =item * B<< FileHandle >> in L A reference where Scalar::Util::openhandle returns true, or a blessed object in the IO::Handle class. =item * B<< GlobRef >> in L Globrefs =item * B<< HashLike >> in L Hashrefs and objects overloading hashrefification. =item * B<< HashRef >> I<< [parameterizable] >> in L Hashrefs. =item * B<< HasMethods >> I<< [parameterizable] >> in L An object that can do particular methods. =item * B<< InstanceOf >> I<< [parameterizable] >> in L An object that isa particular class. =item * B<< Int >> in L A whole number, either positive, negative, or zero. =item * B<< IntRange >> I<< [parameterizable] >> in L An integer within a particular numeric range. =item * B<< Item >> in L Any single item; effectively the same as Any. =item * B<< LaxNum >> in L A number; relaxed constraint that allows "inf". =item * B<< LowerCaseSimpleStr >> I<< [has coercion] >> in L A string less than 256 characters long with no line breaks or uppercase letters. =item * B<< LowerCaseStr >> I<< [has coercion] >> in L A string with no uppercase letters. =item * B<< Map >> I<< [parameterizable] >> in L A hashref with a constraint for the values and keys. =item * B<< Maybe >> I<< [parameterizable] >> in L When parameterized, the same as its parameter, but also allows undef. =item * B<< NegativeInt >> in L An integer below 0. =item * B<< NegativeNum >> in L A number below 0. =item * B<< NegativeOrZeroInt >> in L An integer below 0, or 0. =item * B<< NegativeOrZeroNum >> in L A number below 0, or 0. =item * B<< NonEmptySimpleStr >> in L A string with more than 0 but less than 256 characters with no line breaks. =item * B<< NonEmptyStr >> in L A string with more than 0 characters. =item * B<< Num >> in L The same as LaxNum or StrictNum depending on environment. =item * B<< NumericCode >> I<< [has coercion] >> in L A string containing only digits. =item * B<< NumRange >> I<< [parameterizable] >> in L A number within a particular numeric range. =item * B<< Object >> in L A blessed object. =item * B<< Optional >> I<< [parameterizable] >> in L Used in conjunction with Dict, Tuple, or CycleTuple. =item * B<< OptList >> in L An arrayref of arrayrefs, where each of the inner arrayrefs are two values, the first value being a string. =item * B<< Overload >> I<< [parameterizable] >> in L An overloaded object. =item * B<< Password >> in L A string at least 4 characters long and less than 256 characters long with no line breaks. =item * B<< PositiveInt >> in L An integer above 0. =item * B<< PositiveNum >> in L A number above 0. =item * B<< PositiveOrZeroInt >> in L An integer above 0, or 0. =item * B<< PositiveOrZeroNum >> in L An number above 0, or 0. =item * B<< Ref >> I<< [parameterizable] >> in L Any reference. =item * B<< RegexpRef >> in L A regular expression. =item * B<< RoleName >> in L Any loaded package name where there is no `new` method. =item * B<< ScalarRef >> I<< [parameterizable] >> in L Scalarrefs. =item * B<< SimpleStr >> in L A string with less than 256 characters with no line breaks. =item * B<< SingleDigit >> in L A single digit number. This includes single digit negative numbers! =item * B<< Str >> in L A string. =item * B<< StrictNum >> in L A number; strict constaint. =item * B<< StringLike >> in L Strings and objects overloading stringification. =item * B<< StrLength >> I<< [parameterizable] >> in L A string with length in a particular range. =item * B<< StrMatch >> I<< [parameterizable] >> in L A string matching a particular regular expression. =item * B<< StrongPassword >> in L A string at least 4 characters long and less than 256 characters long with no line breaks and at least one non-alphabetic character. =item * B<< Tied >> I<< [parameterizable] >> in L A reference to a tied variable. =item * B<< Tuple >> I<< [parameterizable] >> in L An arrayref with constraints on its values. =item * B<< TypeTiny >> I<< [has coercion] >> in L Blessed objects in the Type::Tiny class. =item * B<< Undef >> in L undef. =item * B<< UpperCaseSimpleStr >> I<< [has coercion] >> in L A string less than 256 characters long with no line breaks or lowercase letters. =item * B<< UpperCaseStr >> I<< [has coercion] >> in L A string with no lowercase letters. =item * B<< Value >> in L Any non-reference value, including undef. =back =head1 NEXT STEPS Here's your next step: =over =item * L Policies related to Type::Tiny development. =back =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut Coercions.pod000644001750001750 3150113601673061 20704 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual::Coercions - advanced information on coercions =head1 MANUAL This section of the manual assumes you've already read L. Type::Tiny takes a slightly different approach to type constraints from Moose. In Moose, there is a single flat namespace for type constraints. Moose defines a type constraint called B for strings and a type constraint called B for arrayrefs. If you want to define strings differently (maybe you think that the empty string doesn't really count as a string, or maybe you think objects overloading C<< q[""] >> should count as strings) then you can't call it B; you need to choose a different name. With Type::Tiny, two type libraries can each offer a string type constraint with their own definitions for what counts as a string, and you can choose which one to import, or import them both with different names: use Some::Types qw( Str ); use Other::Types "Str" => { -as => "Str2" }; This might seem to be a small advantage of Type::Tiny, but where this global-versus-local philosophy really makes a difference is coercions. Let's imagine for a part of your application that deals with reading username and password data you need to have a "username:password" string. You may wish to accept a C<< [$username, $password] >> arrayref and coerce it to a string using C<< join ":", @$arrayref >>. But another part of your application deals with slurping log files, and wants to coerce a string from an arrayref using C<< join "\n", @$arrayref >>. These are both perfectly sensible ways to coerce an arrayref. In Moose, a typical way to do this would be: package My::UserManager { use Moose; use Moose::Util::TypeConstraints; coerce 'Str', from 'ArrayRef', via { join ":", @$_ }; ...; } package My::LogReader { use Moose; use Moose::Util::TypeConstraints; coerce 'Str', from 'ArrayRef', via { join "\n", @$_ }; ...; } However, because in Moose all types and coercions are global, if both these classes are loaded, only one of them will work. One class will overrule the other's coercion. Which one "wins" will depend on load order. It is possible to solve this with Moose native types, but it requires extra work. (The solution is for My::UserManager and My::LogReader to each create a subtype of B and define the coercion on that subtype instead of on B directly.) Type::Tiny solves this in two ways: =over =item 1. Type::Tiny makes it possible for type libraries to "protect" their type constraints to prevent external code from adding new coercions to them. $type->coercion->freeze(); You can freeze coercions for your entire type library using: __PACKAGE__->make_immutable; If you try to add coercions to a type constraint that has frozen coercions, it will throw an error. use Types::Standard qw( Str ArrayRef ); Str->coercion->add_type_coercions( ArrayRef, sub { join "\n", @$_ }, ); =item 2. Type::Tiny makes the above-mentioned pattern of adding coercions to a subtype much easier. use Types::Standard ( Str ArrayRef ); my $subtype = Str->plus_coercions( ArrayRef, sub { join "\n", @$_ }, ); The C method creates a new child type, adds new coercions to it, copies any existing coercions from the parent type, and then freezes coercions for the new child type. The end result is you now have a "copy" of B that can coerce from B but other copies of B won't be affected by your coercion. =back =head2 Defining Coercions within Type Libraries Some coercions like joining an arrayref to make a string are not going to be coercions that everybody will agree on. Join with a line break in between them as above? Or with a colon, a tab, a space, some other chanaracter? It depends a lot on your application. Others, like coercing a L object from a string, are likely to be very obvious. It is this kind of coercion that it makes sense to define within the library itself so it's available to any packages that use the library. my $pt = __PACKAGE__->add_type( Type::Tiny::Class->new( name => 'Path', class => 'Path::Tiny', ), ); $pt->coercion->add_type_coercions( Str, q{ Path::Tiny::path($_) }, ); $pt->coercion->freeze; =head2 Tweak Coercions Outside Type Libraries The C method creates a new type constraint with additional coercions. If the original type already had coercions, the new coercions have a higher priority. There's also a C method which does the same as C but adds the new coercions with a lower priority than any existing ones. L provides a C method as a shortcut for coercing via a constructor method. The following two are the same: Path->plus_constructors(Str, "new") Path->plus_coercions(Str, q{ Path::Tiny->new($_) }) To create a type constraint without particular existing coercions, you can use C. The following uses the B type defined in L, removing the coercion from B but keeping the coercions from B and B. use Types::Standard qw( Int ); use Example::Types qw( Datetime ); has start_date => ( is => 'ro', isa => Datetime->minus_coercions(Int), coerce => 1, ); There's also a C method that creates a subtype with no coercions at all. This is most useful either to create a "blank slate" for C: my $Path = Path->no_coercions->plus_coercions(Str, sub { ... }); Or to disable coercions for L. Type::Params will always automatically coerce a parameter if there is a coercion for that type. use Types::Standard qw( Object ); use Types::Common::String qw( UpperCaseStr ); use Type::Params; sub set_account_name { state $check = compile( Object, UpperCaseStr->no_coercions ); my ($self, $name) = $check->(@_); $self->_account_name($name); $self->db->update($self); return $self; } # This will die instead of coercing from lowercase $robert->_set_account_name('bob'); =head2 Named Coercions A compromise between defining a coercion in the type library or defining them in the package that uses the type library is for a type library to define a named collection of coercions which can be optionally added to a type constraint. { package MyApp::Types; use Type::Library -base; use Type::Utils qw( extends ); BEGIN { extends 'Types::Standard' }; __PACKAGE__->add_coercion( name => "FromLines", type_constraint => ArrayRef, type_coercion_map => [ Str, q{ [split /\n/] }, Undef, q{ [] }, ], ); } This set of coercions has a name and can be imported and used: use MyApp::Types qw( ArrayRef FromLines ); has lines => ( is => 'ro', isa => ArrayRef->plus_coercions( FromLines ), coerce => 1, ); L defines a named coercion B designed to be used for B. use Types::Standard qw( OptList MkOpt ); my $OptList = OptList->plus_coercions(MkOpt); =head2 Parameterized Coercions Named coercions can also be parameterizable. my $ArrayOfLines = ArrayRef->plus_coercions( Split[ qr{\n} ] ); L defines B and B parameterizable coercions. Viewing the source code for L should give you hints as to how they are implemented. =head2 "Deep" Coercions Certain parameterized type constraints can automatically acquire coercions if their parameters have coercions. For example: ArrayRef[ Int->plus_coercions(Num, q{int($_)}) ] ... does what you mean! The parameterized type constraints that do this magic include the following ones from L: =over =item * B =item * B =item * B =item * B =item * B =item * B =item * B =item * B =item * B =back Imagine we're defining a type B in a type library: __PACKAGE__->add_type( name => 'Paths', parent => ArrayRef[Path], ); The B type has a coercion from B, so B should be able to coerce from an arrayref of strings, right? I<< Wrong! >> Although B<< ArrayRef[Path] >> could coerce from an arrayref of strings, B is a separate type constraint which, although it inherits from B<< ArrayRef[Path] >> has its own (currently empty) set of coercions. Because that is often not what you want, Type::Tiny provides a shortcut when declaring a subtype to copy the parent type constraint's coercions: __PACKAGE__->add_type( name => 'Paths', parent => ArrayRef[Path], coercion => 1, # inherit ); Now B can coerce from an arrayref of strings. =head3 Deep Caveat Currently there exists ill-defined behaviour resulting from mixing deep coercions and mutable (non-frozen) coercions. Consider the following: class_type Path, { class => "Path::Tiny" }; coerce Path, from Str, via { "Path::Tiny"->new($_) }; declare Paths, as ArrayRef[Path], coercion => 1; coerce Path, from InstanceOf["My::File"], via { $_->get_path }; An arrayref of strings can now be coerced to an arrayref of Path::Tiny objects, but is it also now possible to coerce an arrayref of My::File objects to an arrayref of Path::Tiny objects? Currently the answer is "no", but this is mostly down to implementation details. It's not clear what the best way to behave in this situation is, and it could start working at some point in the future. This is why you should freeze coercions. =head2 Chained Coercions Consider the following type library: package Types::Geometric { use Type::Library -base, -declare => qw( VectorArray VectorArray3D Point Point3D ); use Type::Utils; use Types::Standard qw( Num Tuple InstanceOf ); declare VectorArray, as Tuple[Num, Num]; declare VectorArray3D, as Tuple[Num, Num, Num]; coerce VectorArray3D, from VectorArray, via { [ @$_, 0 ]; }; class_type Point, { class => "Point" }; coerce Point, from VectorArray, via { Point->new(x => $_->[0], y => $_->[1]); }; class_type Point3D, { class => "Point3D" }; coerce Point3D, from VectorArray3D, via { Point3D->new(x => $_->[0], y => $_->[1], z => $_->[2]); }, from Point, via { Point3D->new(x => $_->x, y => $_->y, z => 0); }; } Given an arrayref C<< [1, 1] >> you might reasonably expect it to be coercible to a B object; it matches the type constraint B so can be coerced to B and thus to B. However, L does not automatically chain coercions like this. Firstly, it would be incompatible with Moose's type coercion system which does not chain coercions. Secondly, it's ambiguous; in our example, the arrayref could be coerced along two different paths (via B or via B); in this case the end result would be the same, but in other cases it might not. Thirdly, it runs the risk of accidentally creating loops. Doing the chaining manually though is pretty simple. Firstly, we'll take note of the C method in L. This method called as C<< VectorArray3D->coercibles >> returns a type constraint meaning "anything that can be coerced to a B". So we can define the coercions for B as: coerce Point3D, from VectorArray3D->coercibles, via { my $tmp = to_VectorArray3D($_); Point3D->new(x => $tmp->[0], y => $tmp->[1], z => $tmp->[2]); }, from Point, via { Point3D->new(x => $_->x, y => $_->y, z => 0); }; ... and now coercing from C<< [1, 1] >> will work. =head1 SEE ALSO L, L, L. =head1 NEXT STEPS After that last example, probably have a little lie down. Once you're recovered, here's your next step: =over =item * L An alphabetical list of all type constraints bundled with Type::Tiny. =back =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut Contributing.pod000644001750001750 512113601673061 21406 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual::Contributing - contributing to Type::Tiny development. =head1 MANUAL =head2 Reporting bugs Bug reports (including wishlist items) can be submitted to RT. L. Test cases written using L are always appreciated. =head2 Fixing bugs If something doesn't work as documented, or causes unexpected crashes, and you know how to fix it, then either attach a patch to the bug report (see above) or as a pull request to the project on GitHub. L. Please try to follow the coding style used in the rest of the project. (Tab indents, spaces for alignment, British English spellings, pod at the end of code but the start of test cases, etc.) =head2 Adding Test Cases New test cases for the Type::Tiny test suite are always welcome. The coveralls page for Type::Tiny should reveal what parts of the code are most needing good test cases. Any files with below 95% coverage are highest priority. L. Type::Tiny is now also on Codecov which does coverage accounting slightly differently, giving some stricter targets to aim for. L =head2 Type::Tiny::XS I'm not really a C programmer, nor am I that familiar with Perl's internals, so help with L is always appreciated. There are some type constraints in L, L, and L which don't have XS implementations, and I of L has an XS implementation. (Given that the last module is used internally by Type::Tiny a I, an XS implementation of that could provide a good speed boost!) =head2 Writing Type Libraries Though I'm unlikely to bundle many more type libraries in this distribution, uploading your own type libraries to CPAN will strengthen the Type::Tiny ecosystem. =head1 NEXT STEPS You've reached the end of the manual! But each class, type library, and other package includes more detailed documentation. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut Installation.pod000644001750001750 746713601673061 21417 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =for highlighter language=ChangeLog =head1 NAME Type::Tiny::Manual::Installation - how to install Type::Tiny =head1 MANUAL Installing Type-Tiny should be straightforward. =head2 Installation with cpanminus If you have cpanm, you only need one line: % cpanm Type::Tiny If you are installing into a system-wide directory, you may need to pass the "-S" flag to cpanm, which uses sudo to install the module: % cpanm -S Type::Tiny =head2 Installation with the CPAN Shell Alternatively, if your CPAN shell is set up, you should just be able to do: % cpan Type::Tiny =head2 Manual Installation As a last resort, you can manually install it. Download the tarball and unpack it. Consult the file META.json for a list of pre-requisites. Install these first. To build Type-Tiny: % perl Makefile.PL % make && make test Then install it: % make install If you are installing into a system-wide directory, you may need to run: % sudo make install =head2 Dependencies Type::Tiny requires at least Perl 5.6.1, though certain Unicode-related features (e.g. non-ASCII type constraint names) may work better in newer versions of Perl. Type::Tiny requires L, a module that was previously bundled in this distribution, but has since been spun off as a separate distribution. Don't worry - it's quick and easy to install. At run-time, Type::Tiny also requires the following modules: L, L, L, L, L, L, L, L and L. All of these come bundled with Perl itself. Prior to Perl 5.8, L and L do not come bundled with Perl and will need installing separately from the CPAN. Certain features require additional modules. Tying a variable to a type constraint (e.g. C<< tie my $count, Int >>) requires L; stack traces on exceptions require L. The L plugin for L requires L (obviously). L may I increase the speed of some of Type::Tiny's compiled coderefs. L is not required, but if available provides a speed boost for some type checks. (Setting the environment variable C to false, or setting C to true will suppress the use of Type::Tiny::XS, even if it is available.) The test suite additionally requires L, L and L. Test::More comes bundled with Perl, but if you are using a version of Perl older than 5.14, you will need to upgrade to at least Test::More version 0.96. Test::Requires and Test::Fatal (plus Try::Tiny which Test::Fatal depends on) are bundled with Type::Tiny in the C directory, so you do not need to install them separately. If using Type::Tiny in conjunction with L, then at least Moo 1.006000 is recommended. If using Type::Tiny with L, then at least Moose 2.0000 is recommended. If using Type::Tiny with L, then at least Mouse 1.00 is recommended. Type::Tiny is mostly untested against older versions of these packages. =head1 NEXT STEPS Here's your next step: =over =item * L Basic use of Type::Tiny with Moo, including attribute type constraints, parameterized type constraints, coercions, and method parameter checking. =back =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut Libraries.pod000644001750001750 3177713601673061 20713 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual::Libraries - defining your own type libraries =head1 MANUAL =head2 Defining a Type A type is an object and you can create a new one using the constructor: use Type::Tiny; my $type = Type::Tiny->new(%args); A full list of the available arguments can be found in the L documentation, but the most important ones to begin with are: =over =item C The name of your new type. Type::Tiny uses a convention of UpperCamelCase names for type constraints. The type name may also begin with one or two leading underscores to indicate a type intended for internal use only. Types using non-ASCII characters may cause problems on older versions of Perl (pre-5.8). Although this is optional and types may be anonymous, a name is required for a type constraint to added to a type library. =item C A code reference checking C<< $_ >> and returning a boolean. Alternatively, a string of Perl code may be provided. If you've been paying attention, you can probably guess that the string of Perl code may result in more efficient type checks. =item C An existing type constraint to inherit from. A value will need to pass the parent constraint before its own constraint would be called. my $Even = Type::Tiny->new( name => 'EvenNumber', parent => Types::Standard::Int, constraint => sub { # in this sub we don't need to check that $_ is an Int # because the parent will take care of that! $_ % 2 == 0 }, ); Although the C is optional, it makes sense whenever possible to inherit from an existing type constraint to benefit from any optimizations or XS implementations they may provide. =back =head2 Defining a Library A library is a Perl module that exports type constraints as subs. L, L, and L are type libraries that are bundled with Type::Tiny. To create a type library, create a package that inherits from L. package MyTypes { use Type::Library -base; ...; # your type definitions go here } You can add types like this: package MyTypes { use Type::Library -base; my $Even = Type::Tiny->new( name => 'EvenNumber', parent => Types::Standard::Int, constraint => sub { # in this sub we don't need to check that $_ is an Int # because the parent will take care of that! $_ % 2 == 0 }, ); __PACKAGE__->add_type($Even); } There is a shortcut for adding types if they're going to be blessed L objects and not, for example, a subclass of Type::Tiny. You can just pass C<< %args >> directly to C. package MyTypes { use Type::Library -base; __PACKAGE__->add_type( name => 'EvenNumber', parent => Types::Standard::Int, constraint => sub { # in this sub we don't need to check that $_ is an Int # because the parent will take care of that! $_ % 2 == 0 }, ); } The C method returns the type it just added, so it can be stored in a variable. my $Even = __PACKAGE__->add_type(...); This can be useful if you wish to use C<< $Even >> as the parent type to some other type you're going to define later. Here's a bigger worked example: package Example::Types { use Type::Library -base; use Types::Standard -types; use DateTime; # Type::Tiny::Class is a subclass of Type::Tiny for creating # InstanceOf-like types. It's kind of better though because # it does cool stuff like pass through $type->new(%args) to # the class's constructor. # my $dt = __PACKAGE__->add_type( Type::Tiny::Class->new( name => 'Datetime', class => 'DateTime', ) ); my $dth = __PACKAGE__->add_type( name => 'DatetimeHash', parent => Dict[ year => Int, month => Optional[ Int ], day => Optional[ Int ], hour => Optional[ Int ], minute => Optional[ Int ], second => Optional[ Int ], nanosecond => Optional[ Int ], time_zone => Optional[ Str ], ], ); my $eph = __PACKAGE__->add_type( name => 'EpochHash', parent => Dict[ epoch => Int ], ); # Can't just use "plus_coercions" method because that creates # a new anonymous child type to add the coercions to. We want # to add them to the type which exists in this library. # $dt->coercion->add_type_coercions( Int, q{ DateTime->from_epoch(epoch => $_) }, Undef, q{ DateTime->now() }, $dth, q{ DateTime->new(%$_) }, $eph, q{ DateTime->from_epoch(%$_) }, ); __PACKAGE__->make_immutable; } C freezes to coercions of all the types in the package, so no outside code can tamper with the coercions, and allows Type::Tiny to make optimizations to the coercions, knowing they won't later be altered. You should always do this at the end. The library will export types B, B, and B. The B type will have coercions from B, B, B, and B. =head2 Extending Libraries L provides a helpful function C<< extends >>. package My::Types { use Type::Library -base; use Type::Utils qw( extends ); BEGIN { extends("Types::Standard") }; # define your own types here } The C function (which you should usually use in a C<< BEGIN { } >> block not only loads another type library, but it also adds all the types from it to your library. This means code using the above My::Types doesn't need to do: use Types::Standard qw( Str ); use My::Types qw( Something ); It can just do: use My::Types qw( Str Something ); Because all the types from Types::Standard have been copied across into My::Types and are also available there. C can be passed a list of libraries; you can inherit from multiple existing libraries. It can also recognize and import types from L, L, and L libraries. =head2 Custom Error Messages A type constraint can have custom error messages. It's pretty simple: Type::Tiny->new( name => 'EvenNumber', parent => Types::Standard::Int, constraint => sub { # in this sub we don't need to check that $_ is an Int # because the parent will take care of that! $_ % 2 == 0 }, message => sub { sprintf '%s is not an even number', Type::Tiny::_dd($_); }, ); The message coderef just takes a value in C<< $_ >> and returns a string. It may use C<< Type::Tiny::_dd() >> as a way of pretty-printing a value. (Don't be put off by the underscore in the function name. C<< _dd() >> is an officially supported part of Type::Tiny's API now.) You don't have to use C<< _dd() >>. You can generate any error string you like. But C<< _dd() >> will help you make undef and the empty string look different, and will pretty-print references, and so on. There's no need to supply an error message coderef unless you really want custom error messages. The default sub should be reasonable. =head2 Inlining In Perl, sub calls are relatively expensive in terms of memory and CPU use. The B type inherits from B which inherits from B which inherits from B which inherits from B which inherits from B which inherits from B. So you might think that to check of C<< $value >> is a B, it needs to be checked all the way up the inheritance chain. But this is where one of Type::Tiny's big optimizations happens. Type::Tiny can glue together a bunch of checks with a stringy eval, and get a single coderef that can do all the checks in one go. This is why when Type::Tiny gives you a choice of using a coderef or a string of Perl code, you should usually choose the string of Perl code. A single coderef can "break the chain". But these automatically generated strings of Perl code are not always as efficient as they could be. For example, imagine that B is defined as: my $Defined = Type::Tiny->new( name => 'Defined', constraint => 'defined($_)', ); my $Ref = Type::Tiny->new( name => 'Ref', parent => $Defined, constraint => 'ref($_)', ); my $HashRef = Type::Tiny->new( name => 'HashRef', parent => $Ref, constraint => 'ref($_) eq "HASH"', ); Then the combined check is: defined($_) and ref($_) and ref($_) eq "HASH" Actually in practice it's even more complicated, because Type::Tiny needs to localize and set C<< $_ >> first. But in practice, the following should be a sufficient check: ref($_) eq "HASH" It is possible for the B type to have more control over the string of code generated. my $HashRef = Type::Tiny->new( name => 'HashRef', parent => $Ref, constraint => 'ref($_) eq "HASH"', inline => sub { my $varname = pop; sprintf 'ref(%s) eq "HASH"', $varname; }, ); The inlined coderef gets passed the name of a variable to check. This could be C<< '$_' >> or C<< '$var' >> or C<< $some{deep}{thing}[0] >>. Because it is passed the name of a variable to check, instead of always checking C<< $_ >>, this enables very efficient checking for parameterized types. Although in this case, the inlining coderef is just returning a string, technically it returns a list of strings. If there's multiple strings, Type::Tiny will join them together in a big "&&" statement. As a special case, if the first item in the returned list of strings is undef, then Type::Tiny will substitute the parent type constraint's inlined string in its place. So an inlieing coderef for even numbers might be: Type::Tiny->new( name => 'EvenNumber', parent => Types::Standard::Int, constraint => sub { $_ % 2 == 0 }, inline => sub { my $varname = pop; return (undef, "$varname % 2 == 0"); }, ); Even if you provide a coderef as a string, an inlining coderef has the potential to generate more efficient code, so you should consider providing one. =head2 Parameterizable Types This is probably the most "meta" concept that is going to be covered. Building your own type constraint that can be parameterized like B or B. The type constraint we'll build will be B<< MultipleOf[$i] >> which checks that an integer is a multiple of $i. __PACKAGE__->add_type( name => 'MultipleOf', parent => Int, # This coderef gets passed the contents of the square brackets. constraint_generator => sub { my $i = assert_Int(shift); # needs to return a coderef to use as a constraint for the # parameterized type return sub { $_ % $i == 0 }; }, # optional but recommended inline_generator => sub { my $i = shift; return sub { my $varname = pop; return (undef, "$varname % $i == 0"); }; }, # probably the most complex bit coercion_generator => sub { my $i = $_[2]; require Type::Coercion; return Type::Coercion->new( type_coercion_map => [ Num, qq{ int($i * int(\$_/$i)) } ], ); }, ); Now we can define an even number like this: __PACKAGE__->add_type( name => 'EvenNumber', parent => __PACKAGE__->get_type('MultipleOf')->of(2), coercion => 1, # inherit from parent ); Note that it is possible for a type constraint to have a C I a C. BaseType # uses the constraint BaseType[] # constraint_generator with no arguments BaseType[$x] # constraint_generator with an argument In the B example above, B<< MultipleOf[] >> with no number would throw an error because of C<< assert_Int(shift) >> not finding an integer. But it is certainly possible for B<< BaseType[] >> to be meaningful and distinct from C<< BaseType >>. For example, B is just the same as B and accepts any arrayref as being valid. But B<< Tuple[] >> will only accept arrayrefs with zero elements in them. (Just like B<< Tuple[Any,Any] >> will only accept arrayrefs with two elements.) =head1 NEXT STEPS After that last example, probably have a little lie down. Once you're recovered, here's your next step: =over =item * L How to use Type::Tiny with Moose, including the advantages of Type::Tiny over built-in type constraints, and Moose-specific features. =back =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut NonOO.pod000644001750001750 653013601673061 17734 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual::NonOO - Type::Tiny in non-object-oriented code =head1 MANUAL Although Type::Tiny was designed with object-oriented programming in mind, especially Moose-style classes and roles, it can be used in procedural and imperative programming. If you have read L, you should understand how L can be used to validate method parametters. This same technique can be applied to regular subs too; just don't C off C<< $self >>. More information about checking parameters can be found in L. The C<< is_* >> and C<< assert_* >> functions exported by type libraries may be useful in non-OO code too. See L. =head2 Type::Tiny and Smart Match Perl 5.10 introduced the smart match operator C<< ~~ >>, which has since been deprecated because though the general idea is fairly sound, the details were a bit messy. Nevertheless, Type::Tiny has support for smart match and I'm documenting it here because there's nowhere better to put it. The following can be used as to check if a value passes a type constraint: $value ~~ SomeType Where it gets weird is if C<< $value >> is an object and overloads C<< ~~ >>. Which overload of C<< ~~ >> wins? I don't know. Better to use: SomeType->check( $value ) # more reliable, probably faster is_SomeType($value) # more reliable, definitely faster It's also possible to do: $value ~~ SomeType->coercion This checks to see if C<< $value >> matches any type that can be coerced to B. But better to use: SomeType->coercion->has_coercion_for_value( $value ) =head2 C and C Related to the smart match operator is the C/C syntax. This will not do what you want it to do: use Types::Standard qw( Str Int ); given ($value) { when (Int) { ... } when (Str) { ... } } This will do what you wanted: use Types::Standard qw( is_Str is_Int ); given ($value) { when (\&is_Int) { ... } when (\&is_Str) { ... } } Sorry, that's just how Perl be. Better though: use Types::Standard qw( Str Int ); use Type::Utils qw( match_on_type ); match_on_type $value => ( Str, sub { ... }, Int, sub { ... }, ); If this is part of a loop or other frequently called bit of code, you can compile the checks once and use them many times: use Types::Standard qw( Str Int ); use Type::Utils qw( compile_match_on_type ); my $dispatch_table = compile_match_on_type( Str, sub { ... }, Int, sub { ... }, ); $dispatch_table->($_) for @lots_of_values; As with most things in Type::Tiny, those coderefs can be replaced by strings of Perl code. =head1 NEXT STEPS Here's your next step: =over =item * L Squeeze the most out of your CPU. =back =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut Optimization.pod000644001750001750 2141413601673061 21450 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual::Optimization - squeeze the most out of your CPU =head1 MANUAL Type::Tiny is written with efficiency in mind, but there are techniques you can use to get the best performance out of it. =head2 XS The simplest thing you can do to increase performance of many of the built-in type constraints is to install L, a set of ultra-fast type constraint checks implemented in C. L will attempt to load L and use its type checks. If L is not available, it will then try to use L I<< if it is already loaded >>, but Type::Tiny won't attempt to load Mouse for you. Certain type constraints can also be accelerated if you have L installed. =head3 Types that can be accelerated by Type::Tiny::XS The following simple type constraints from L will be accelerated by Type::Tiny::XS: C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, and C. (Note that C and C are I on that list.) The parameterized form of C cannot be accelerated. The parameterized forms of C, C, and C can be accelerated only if their parameters are. The parameterized form of C can be accelerated if its parameters are, it has no C components, and it does not use C. Certain type constraints may benefit partially from Type::Tiny::XS. For example, C inherits from C, so part of the type check will be conducted by Type::Tiny::XS. The parameterized C, C, and C type constraints will be accelerated. So will L, L, and L objects. (But enums will only be accelerated if the list of allowed string values consist entirely of word characters and hyphens - that is: C<< not grep /[^\w-]/, @values >>.) The C and C type constraints from L will be accelerated, as will the C type constraint from L. L and L will also be accelerated if their constituent type constraints are. =head3 Types that can be accelerated by Mouse The following simple type constraints from L will be accelerated by Type::Tiny::XS: C, C, C, C, C, C, C, C, C, C, C, C, C, and C. (Note that C, C, C, C, and C are I on that list.) The parameterized form of C cannot be accelerated. The parameterized forms of C and C can be accelerated only if their parameters are. Certain type constraints may benefit partially from Mouse. For example, C inherits from C, so part of the type check will be conducted by Mouse. The parameterized C and C type constraints will be accelerated. So will L and L objects. =head2 Inlining Type Constraints In the case of a type constraint like this: my $type = Int->where(sub { $_ >= 0 }); Type::Tiny will need to call one sub to verify a value meets the B type constraint, and your coderef to check that the value is above zero. Sub calls in Perl are relatively expensive in terms of memory and CPU usage, so it would be good if it could be done all in one sub call. The B type constraint knows how to create a string of Perl code that checks an integer. It's something like the following. (It's actually more complicated, but this is close enough as an example.) $_ =~ /^-?[0-9]+$/ If you provide your check as a string instead of a coderef, like this: my $type = Int->where(q{ $_ >= 0 }); Then Type::Tiny will be able to combine them into one string: ( $_ =~ /^-?[0-9]+$/ ) && ( $_ >= 0 ) So Type::Tiny will be able to check values in one sub call. Providing constraints as strings is a really simple and easy way of optimizing type checks. But it can be made even more efficient. Type::Tiny needs to localize C<< $_ >> and copy the value into it for the above check. If you're checking B<< ArrayRef[$type] >> this will be done for each element of the array. Things could be made more efficient if Type::Tiny were able to directly check: ( $arrayref->[$i] =~ /^-?[0-9]+$/ ) && ( $arrayref->[$i] >= 0 ) This can be done by providing an inlining sub. The sub is given a variable name and can use that in the string of code it generates. my $type = Type::Tiny->new( parent => Int, inlined => sub { my ($self, $varname) = @_; return sprintf( '(%s) && ( %s >= 0 )', $self->parent->inline_check($varname), $varname, ); } ); Because it's pretty common to want to call your parent's inline check and C<< && >> your own string with it, Type::Tiny provides a shortcut for this. Just return a list of strings to smush together with C<< && >>, and if the first one is C, Type::Tiny will fill in the blank with the parent type check. my $type = Type::Tiny->new( parent => Int, inlined => sub { my ($self, $varname) = @_; return ( undef, sprintf('%s >= 0', $varname), ); } ); There is one further optimization which can be applied to this particular case. You'll note that we're checking the string matches C<< /^-?[0-9+]$/ >> and then checking it's greater than or equal to zero. But a non-negative integer won't ever start with a minus sign, so we could inline the check to something like: $_ =~ /^[0-9]+$/ While an inlined check I call its parent type check, it is not required to. my $type = Type::Tiny->new( parent => Int, inlined => sub { my ($self, $varname) = @_; return sprintf('%s =~ /^[0-9]+$/', $varname); } ); If you opt not to call the parent type check, then you need to ensure your own check is at least as rigorous. =head2 Inlining Coercions Moo is the only object-oriented programming toolkit that fully supports coercions being inlined, but even for Moose and Mouse, providing coercions as strings can help Type::Tiny optimize its coercion features. For Moo, if you want your coercion to be inlinable, all the types you're coercing from and to need to be inlinable, plus the coercion needs to be given as a string of Perl code. =head2 Common Sense The C<< HashRef[ArrayRef] >> type constraint can probably be checked faster than C<< HashRef[ArrayRef[Num]] >>. If you find yourself using very complex and slow type constraints, you should consider switching to simpler and faster ones. (Though this means you have to place a little more trust in your caller to not supply you with bad data.) (A counter-intuitive exception to this: even though C is more restrictive than C, in most circumstances C checks will run faster.) =head2 Devel::StrictMode One possibility is to use strict type checks when you're running your release tests, and faster, more permissive type checks at other times. Devel::StrictMode can make this easier. This provides a C constant that indicates whether your code is operating in "strict mode" based on certain environment variables. =head3 Attributes use Types::Standard qw( ArrayRef Num ); use Devel::StrictMode qw( STRICT ); has numbers => ( is => 'ro', isa => STRICT ? ArrayRef[Num] : ArrayRef, default => sub { [] }, ); It is inadvisible to do this on attributes that have coercions because it can lead to inconsistent and unpredictable behaviour. =head3 Type::Params use Types::Standard qw( Num Object ); use Type::Params qw( compile ); use Devel::StrictMode qw( STRICT ); sub add_number { state $check; $check = compile(Object, Num) if STRICT; my ($self, $num) = STRICT ? $check->(@_) : @_; push @{ $self->numbers }, $num; return $self; } Again, you need to be careful to ensure consistent behaviour if you're using coercions, defaults, slurpies, etc. =head3 Ad-Hoc Type Checks ...; my $x = get_some_number(); assert_Int($x) if STRICT; return $x + 1; ...; =head1 NEXT STEPS Here's your next step: =over =item * L Advanced information on coercions. =back =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut Params.pod000644001750001750 1620313601673061 20205 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual::Params - advanced information on Type::Params =head1 MANUAL To get started with Type::Params, please read L which will cover a lot of the basics, even if you're not using Moo. =head2 C and C The generally recommended way of using Type::Params is this: sub mysub { state $check = compile( SIGNATURE ); my @args = $check->( @_ ); } But it is possible to do it in one call: sub mysub { my @args = validate( \@_, SIGNATURE ); } There is also a C function which acts as a counterpart for C. This will generally be slower and less efficient than using C first because Type::Tiny can do a lot of optimizations in that first stage to make the second stage a lot faster. (And the results of C get stored in the C variable so that only has to happen once.) There is rarely a reason to use C and C, but they exist if you want them. =head2 C Multisig allows you to allow multiple ways of calling a sub. sub repeat_string { state $check = multisig( compile( Int, Str, ), compile_named( { named_to_list => 1 }, count => Int, string => Str, ), ); my ($count, $string) = $check->(@_); return $string x $count; } repeat_string( "Hello", 42 ); # works repeat_string( string => "Hello", count => 42 ); # works repeat_string({ string => "Hello", count => 42 }); # works repeat_string( qr/hiya/ ); # dies It combines multiple checks and tries each until one works. =head2 C and C C turns the C idea inside out. Instead of this: sub foobar { state $check = compile(Int, Str); my ($foo, $bar) = @_; ...; } You do this: sub foobar { my ($foo, $bar) = @_; ...; } wrap_subs foobar => [ Int, Str ]; Or this: sub foobar { my ($foo, $bar) = @_; ...; } wrap_subs foobar => compile( Int, Str ); =head2 Mixed Named and Positional Parameters This can be faked using positional parameters and a slurpy dictionary. state $check = compile( Int, slurpy Dict[ foo => Int, bar => Optional[Int], baz => Optional[Int], ], ); @_ = (42, foo => 21); # ok @_ = (42, foo => 21, bar => 84); # ok @_ = (42, foo => 21, bar => 10.5); # not ok @_ = (42, foo => 21, quux => 84); # not ok =head2 Proper Signatures Don't you wish your subs could look like this? sub set_name (Object $self, Str $name) { $self->{name} = $name; } Well; here are a few solutions for sub signatures that work with L... =head3 Kavorka L is a sub signatures implementation written to natively use L' C for type constraints, and take advantage of Type::Tiny's features such as inlining, and coercions. method set_name (Str $name) { $self->{name} = $name; } Kavorka's signatures provide a lot more flexibility, and slightly more speed than Type::Params. (The speed comes from inlining almost all type checks into the body of the sub being declared.) Kavorka also includes support for type checking of the returned value. Kavorka can also be used as part of L, a larger framework for object oriented programming in Perl. =head3 Function::Parameters Function::Parameters offers support for Type::Tiny and MooseX::Types. use Types::Standard qw( Str ); use Function::Parameters; method set_name (Str $name) { $self->{name} = $name; } =head3 Attribute::Contract Both Kavorka and Function::Parameters require a relatively recent version of Perl. L supports older versions by using a lot less magic. You want Attribute::Contract 0.03 or above. use Attribute::Contract -types => [qw/Object Str/]; sub set_name :ContractRequires(Object, Str) { my ($self, $name) = @_; $self->{name} = $name; } Attribute::Contract also includes support for type checking of the returned value. =head2 Type::Params versus X =head3 Params::Validate L is not really a drop-in replacement for L; the API differs far too much to claim that. Yet it performs a similar task, so it makes sense to compare them. =over =item * Type::Params will tend to be faster if you've got a sub which is called repeatedly, but may be a little slower than Params::Validate for subs that are only called a few times. This is because it does a bunch of work the first time your sub is called to make subsequent calls a lot faster. =item * Params::Validate doesn't appear to have a particularly natural way of validating a mix of positional and named parameters. =item * Type::Utils allows you to coerce parameters. For example, if you expect a L object, you could coerce it from a string. =item * If you are primarily writing object-oriented code, using Moose or similar, and you are using Type::Tiny type constraints for your attributes, then using Type::Params allows you to use the same constraints for method calls. =item * Type::Params comes bundled with Types::Standard, which provides a much richer vocabulary of types than the type validation constants that come with Params::Validate. For example, Types::Standard provides constraints like C<< ArrayRef[Int] >> (an arrayref of integers), while the closest from Params::Validate is C<< ARRAYREF >>, which you'd need to supplement with additional callbacks if you wanted to check that the arrayref contained integers. Whatsmore, Type::Params doesn't just work with Types::Standard, but also any other Type::Tiny type constraints. =back =head3 Params::ValidationCompiler L does basically the same thing as L. =over =item * Params::ValidationCompiler and Type::Params are likely to perform fairly similarly. In most cases, recent versions of Type::Params seem to be I faster, but except in very trivial cases, you're unlikely to notice the speed difference. Speed probably shouldn't be a factor when choosing between them. =item * Type::Params's syntax is more compact: state $check = compile(Object, Optional[Int], slurpy ArrayRef); Versus: state $check = validation_for( params => [ { type => Object }, { type => Int, optional => 1 }, { type => ArrayRef, slurpy => 1 }, ], ); =item * L probably has slightly better exceptions. =back =head1 NEXT STEPS Here's your next step: =over =item * L Type::Tiny in non-object-oriented code. =back =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut Policies.pod000644001750001750 1006213601673061 20526 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual::Policies - Type::Tiny policies =head1 MANUAL =head2 Type::Tiny Stability Policy Type::Tiny 1.000000 is considered stable. Any changes to the API that are big enough to I changes to the test suite will be preceded by a I<< six month >> notice period, with the following exceptions: =over =item * Any changes which are necessary to maintain compatibility with new releases of L, L, and other software that Type::Tiny needs to integrate with. =item * Changes to maintain compatibility with future versions of Perl itself. =item * Where a change fixes a contradiction between the implementation and documentation of Type::Tiny. =item * Where a feature is explicitly documented as being "experimental" or "unstable". =item * Improvements to the text of error messages. =back =head2 Experimental and Unstable Type::Tiny Features The following list is currently non-exhaustive. =over =item * The following type checks result may vary based on your version of Perl and whether Type::Tiny::XS is installed. Their outcome is currently considered undefined, and may change in future versions. =over =item * Using B and similar type checks on unblessed regular expression references, the outcome is undefined. =item * On all current versions of Perl, false (C<< !!0 >>) stringifies to the empty string (but using Devel::Peek you can tell the difference between this value and a normal empty string), so B and subtypes of B do not consider it to be an integer. If Perl's behaviour ever changes, you might not be able to rely on this outcome. True (C<< !!1 >>) stringifies as "1", so is considered an integer. =item * A glob (not a globref but an actual glob) currently passes the B type constraint but not the B type constraint. =back =item * L's C attribute and the functionality it provides is experimental. =item * The L is subject to change. =item * The interaction of deep coercions and mutable coercions currently results in ill-defined behaviour. This could change at any time. =item * L's ability to import L and L type libraries is experimental. =item * These modules are considered part of Type::Tiny's internals, and not covered by the stability policy: L, L, L, L, L, L, L, L, L, L, L, L, and L. =item * L is not covered by the stability policy. =back =head2 Type::Tiny Versioning Policy As of 1.000000, this distribution follows a versioning scheme similar to L, which is based on a L-like three component version number, but with the last two components each represented by three decimal digits in the fractional part of the version number. That is, version 1.003002 of the software represents "1.3.2". Additionally, releases where the second component is an odd number will be considered unstable/trial releases. (These will also include an underscore in the version number as per the usual CPAN convention.) =head1 NEXT STEPS Here's your next step: =over =item * L Contributing to Type::Tiny development. =back =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut UsingWithClassTiny.pod000644001750001750 1024013601673061 22530 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual::UsingWithClassTiny - use of Type::Tiny with Class::Tiny =head1 MANUAL L is an even-smaller-than-Moo class builder. Let's translate the classic Horse class from Moo to Class::Tiny. Moo: package Horse { use Moo; use Types::Standard qw( Str Num ArrayRef ); use namespace::autoclean; has name => ( is => 'ro', isa => Str, required => 1 ); has gender => ( is => 'ro', isa => Str ); has age => ( is => 'rw', isa => Num ); has children => ( is => 'ro', isa => ArrayRef, default => sub { return [] }, ); } Class::Tiny: package Horse { use Class::Tiny qw( gender age ), { name => sub { die "name is required"; }, children => sub { return [] }, }; use Types::Standard qw( Str Num ArrayRef Dict Optional slurpy Any); use Type::Params qw( wrap_methods compile ); use namespace::autoclean; # type checks wrap_methods( BUILD => [Dict[ name => Str, gender => Optional[Str], age => Optional[Num], children => Optional[ArrayRef], slurpy Any, ]], name => [], gender => [], age => Optional[Num], children => [], ); } What's going on here? Well, Class::Tiny, after it has built a new object, will do this: $self->BUILD($args); (Technically, it calls C not just for the current class, but for all parent classes too.) We can hook onto this in order to check type constraints for the constructor. We use C from L to wrap the original C method (which doesn't exist, so C will just assume an empty sub) with a type check for C<< $args >>. The type check is just a B that checks the class's required and optional attributes and includes B<< slurpy Any >> at the end to be flexible for subclasses adding new attributes. Then we wrap the C, C, and C methods with checks to make sure they're only being called as getters, and we wrap C, allowing it to be called as a setter with a B. There are also a couple of CPAN modules that can help you out. =head2 Class::Tiny::ConstrainedAccessor L creates a C and accessors that enforce Type::Tiny constraints. Attribute types are passed to Class::Tiny::ConstrainedAccessor; attribute defaults are passed to Class::Tiny. package Horse { use Types::Standard qw( Str Num ArrayRef ); use Class::Tiny::ConstrainedAccessor { name => Str, gender => Str, age => Num, children => ArrayRef, }; use Class::Tiny qw( gender age ), { name => sub { die "name is required"; }, children => sub { return [] }, }; } =head2 Class::Tiny::Antlers L provides Moose-like syntax for Class::Tiny, including support for C. You do not also need to use Class::Tiny itself. package Horse { use Class::Tiny::Antlers qw(has); use Types::Standard qw( Str Num ArrayRef ); use namespace::autoclean; has name => ( is => 'ro', isa => Str, default => sub { die "name is required" }, ); has gender => ( is => 'ro', isa => Str ); has age => ( is => 'rw', isa => Num ); has children => ( is => 'ro', isa => ArrayRef, default => sub { return [] }, ); } =head1 NEXT STEPS Here's your next step: =over =item * L Using Type::Tiny with Class::InsideOut, Params::Check, and Object::Accessor. =back =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut UsingWithMoo.pod000644001750001750 6260013601673061 21360 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual::UsingWithMoo - basic use of Type::Tiny with Moo =head1 MANUAL =head2 Type Constraints Consider the following basic Moo class: package Horse { use Moo; use namespace::autoclean; has name => ( is => 'ro' ); has gender => ( is => 'ro' ); has age => ( is => 'rw' ); has children => ( is => 'ro', default => sub { [] } ); } Code like this seems simple enough: my $br = Horse->new(name => "Bold Ruler", gender => 'm', age => 16); push @{ $br->children }, Horse->new(name => 'Secretariat', gender => 'm', age => 0); However, once you step away from very simple use of the class, things can start to go wrong. When we push a new horse onto C<< @{ $br->children } >>, we are assuming that C<< $br->children >> returned an arrayref. What if the code that created the C<< $br >> horse had instantiated it like this? my $br = Horse->new(name => "Bold Ruler", children => 'no'); It is for this reason that it's useful for the Horse class to perform some basic sanity-checking on its own attributes. package Horse { use Moo; use Types::Standard qw( Str Num ArrayRef ); use namespace::autoclean; has name => ( is => 'ro', isa => Str ); has gender => ( is => 'ro', isa => Str ); has age => ( is => 'rw', isa => Num ); has children => ( is => 'ro', isa => ArrayRef, default => sub { return [] }, ); } Now, if you instantiate a horse like this, it will throw an error: my $br = Horse->new(name => "Bold Ruler", children => 'no'); The first type constraint we used here was B. This is type constraint that requires values to be strings. Note that although C is not a string, the empty string is still a string and you will often want to check that a string is non-empty. We could have done this: use Types::Common::String qw( NonEmptyStr ); has name => ( is => 'ro', isa => NonEmptyStr ); While most of the type constraints we will use in this manual are defined in L, the L type library also defines many useful type constraints. We have required the horse's age to be a number. This is also a common, useful type constraint. If we want to make sure it's a whole number, we could use: use Types::Standard qw( Int ); has age => ( is => 'rw', isa => Int ); Or because negative numbers make little sense as an age: use Types::Common::Numeric qw( PositiveOrZeroInt ); has age => ( is => 'rw', isa => PositiveOrZeroInt ); The L library defines many useful subtypes of B and B, such as B and B. The last type constraint we've used in this example is B. This requires the value to be a reference to an array. Types::Standard also provides B and B type constraints. An example of using the latter: package Task { use Moo; use Types::Standard qw( CodeRef Bool ); has on_success => ( is => 'ro', isa => CodeRef ); has on_failure => ( is => 'ro', isa => CodeRef ); has finished => ( is => 'ro', isa => Bool, default => 0 ); ...; } my $task = Task->new( on_success => sub { ... }, on_failure => sub { ... }, ..., ); The B<< Bool >> type constraint accepts "1" as a true value, and "0", "", or undef as false values. No other values are accepted. There exists an B type constraint that accepts any blessed object. package Horse { use Moo; use Types::Standard qw( Object ); use namespace::autoclean; ...; # name, gender, age, children has father => ( is => 'ro', isa => Object ); has mother => ( is => 'ro', isa => Object ); } Finally, another useful type constraint to know about is B: use Types::Standard qw( Any ); has stuff => ( is => 'rw', isa => Any ); This type constraint allows any value; it is essentially the same as not doing any type check, but makes your intent clearer. Where possible, Type::Tiny will optimize away this type check, so it should have little (if any) impact on performance. =head2 Parameterized Types Let's imagine we want to keep track of our horse's race wins: package Horse { use Moo; use Types::Standard qw( Str Num ArrayRef ); use namespace::autoclean; ...; # name, gender, age, children has wins => ( is => 'ro', isa => ArrayRef, default => sub { return [] }, ); } We can create a horse like this: my $br = Horse->new( name => "Bold Ruler", gender => 'm', age => 4, wins => ["Futurity Stakes 1956", "Juvenile Stakes 1956"], ); The list of wins is an arrayref of strings. The B type constraint prevents it from being set to a hashref, for example, but it doesn't ensure that everything in the arrayref is a string. To do that, we need to parameterize the type constraint: has wins => ( is => 'ro', isa => ArrayRef[Str], default => sub { return [] }, ); Thanks to the B<< ArrayRef[Str] >> parameterized type, the constructor will throw an error if the arrayref you pass to it contains anything non-string. An alternative way of writing this is: has wins => ( is => 'ro', isa => ArrayRef->of(Str), default => sub { return [] }, ); Which way you choose is largely a style preference. TIMTOWTDI! Note that although the constructor and any setter/accessor method will perform type checks, it is possible to bypass them using: push @{ $br->wins }, $not_a_string; The constructor isn't being called here, and although the accessor I being called, it's being called as a reader, not a writer, so never gets an opportunity to inspect the value being added. (It is possible to use C to solve this, but that will be covered later.) And of course, if you directly poke at the underlying hashref of the object, all bets are off: $br->{wins} = $not_an_arrayref; So type constraints do have limitations. Careful API design (and not circumventing the proper API) can help. The B type constraint can also be parameterized: package Design { use Moo; use Types::Standard qw( HashRef Str ); has colours => ( is => 'ro', isa => HashRef[Str] ); } my $eiffel65 = Design->new( colours => { house => "blue", little_window => "blue" }, ); The B<< HashRef[Str] >> type constraint ensures the I of the hashref are strings; it doesn't check the keys of the hashref because keys in Perl hashes are always strings! If you do need to constrain the keys, it is possible to use a parameterized B<< Map >> constraint: use Types::Common::String qw( NonEmptyStr ); use Types::Standard qw( Map ); has colours => ( is => 'ro', isa => Map[NonEmptyStr, NonEmptyStr] ); B takes two parameters; the first is a type to check keys against and the second is a type to check values against. Another useful type constraint is the B<< Tuple >> type constraint. use Types::Standard qw( ArrayRef Tuple ); use Types::Common::Numeric qw( PositiveInt ); use Types::Common::String qw( NonEmptyStr ); has wins => ( is => 'ro', isa => ArrayRef[ Tuple[PositiveInt, NonEmptyStr] ], default => sub { return [] }, ); The B<< Tuple[PositiveInt, NonEmptyStr] >> type constraint checks that a value is a two-element arrayref where the first element is a positive integer and the second element is a non-empty string. For example: my $br = Horse->new( name => "Bold Ruler", wins => [ [ 1956, "Futurity Stakes" ], [ 1956, "Juvenile Stakes" ], ], ); As you can see, parameterized type constraints may be nested to arbitrary depth, though of course the more detailed your checks become, the slower they will perform. It is possible to have tuples with variable length. For example, we may wish to include the jockey name in our race wins when it is known. use Types::Standard qw( ArrayRef Tuple Optional ); use Types::Common::Numeric qw( PositiveInt ); use Types::Common::String qw( NonEmptyStr ); has wins => ( is => 'ro', isa => ArrayRef[ Tuple[ PositiveInt, NonEmptyStr, Optional[NonEmptyStr] ] ], default => sub { return [] }, ); The third element will be checked if it is present, but forgiven if it is absent. Or we could just allow tuples to contain an arbitrary list of strings after the year and race name: use Types::Standard qw( ArrayRef Tuple Str slurpy ); use Types::Common::Numeric qw( PositiveInt ); use Types::Common::String qw( NonEmptyStr ); has wins => ( is => 'ro', isa => ArrayRef[ Tuple[ PositiveInt, NonEmptyStr, slurpy ArrayRef[Str] ] ], default => sub { return [] }, ); The C indicator will "slurp" all the remaining items in the tuple into an arrayref and check it against B<< ArrayRef[Str] >>. It's even possible to do this: use Types::Standard qw( ArrayRef Tuple Any slurpy ); use Types::Common::Numeric qw( PositiveInt ); use Types::Common::String qw( NonEmptyStr ); has wins => ( is => 'ro', isa => ArrayRef[ Tuple[ PositiveInt, NonEmptyStr, slurpy Any ] ], default => sub { return [] }, ); With this type constraint, any elements after the first two will be slurped into an arrayref and we don't check that arrayref at all. (In fact, the implementation of the B type is smart enough to not bother creating the temporary arrayref to check.) B is the equivalent of B for checking values of hashrefs. use Types::Standard qw( ArrayRef Dict Optional ); use Types::Common::Numeric qw( PositiveInt ); use Types::Common::String qw( NonEmptyStr ); has wins => ( is => 'ro', isa => ArrayRef[ Dict[ year => PositiveInt, race => NonEmptyStr, jockey => Optional[NonEmptyStr], ], ], default => sub { return [] }, ); An example of using it: my $br = Horse->new( name => "Bold Ruler", wins => [ { year => 1956, race => "Futurity Stakes", jockey => "Eddie" }, { year => 1956, race => "Juvenile Stakes" }, ], ); The slurpy indicator does work for B too: Dict[ year => PositiveInt, race => NonEmptyStr, jockey => Optional[NonEmptyStr], slurpy HashRef[Str], # other Str values allowed ] And C<< slurpy Any >> means what you probably think it means: Dict[ year => PositiveInt, race => NonEmptyStr, jockey => Optional[NonEmptyStr], slurpy Any, # allow hashref to contain absolutely anything else ] Going back to our first example, there's an opportunity to refine our B constraint: package Horse { use Moo; use Types::Standard qw( Str Num ArrayRef ); use namespace::autoclean; has name => ( is => 'ro', isa => Str ); has gender => ( is => 'ro', isa => Str ); has age => ( is => 'rw', isa => Num ); has children => ( is => 'ro', isa => ArrayRef[ InstanceOf["Horse"] ], default => sub { return [] }, ); } The B<< InstanceOf["Horse"] >> type constraint checks that a value is a blessed object in the Horse class. So the horse's children should be an arrayref of other Horse objects. Internally it just checks C<< $_->isa("Horse") >> on each item in the arrayref. It is sometimes useful to instead check C<< $_->DOES($role) >> or C<< $_->can($method) >> on an object. For example: package MyAPI::Client { use Moo; use Types::Standard qw( HasMethods ); has ua => (is => 'ro', isa => HasMethods["get", "post"] ); } The B and B parameterizable types allow you to easily check roles and methods of objects. The B parameterizable type allows you to accept a more limited set of string values. For example: use Types::Standard qw( Enum ); has gender => ( is => 'ro', isa => Enum["m","f"] ); Or if you want a little more flexibility, you can use B which allows you to test strings against a regular expression: use Types::Standard qw( StrMatch ); has gender => ( is => 'ro', isa => StrMatch[qr/^[MF]/i] ); Or B to check the maximum and minimum length of a string: use Types::Common::String qw( StrLength ); has name => ( is => 'ro', isa => StrLength[3, 100] ); The maximum can be omitted. Similarly, the maximum and minimum values for a numeric type can be expressed using B and B: use Types::Common::Numeric qw( IntRange ); # values over 200 are probably an input error has age => ( is => 'ro', isa => IntRange[0, 200] ); Parameterized type constraints are one of the most powerful features of Type::Tiny, allowing a small set of constraints to be combined in useful ways. =head2 Type Coercions It is often good practice to be liberal in what you accept. package Horse { use Moo; use Types::Standard qw( Str Num ArrayRef Bool ); use namespace::autoclean; ...; # name, gender, age, children, wins has is_alive => ( is => 'rw', isa => Bool, coerce => 1 ); } The C option indicates that if a value is given which I<< does not >> pass the B type constraint, then it should be coerced (converted) into something that does. The definition of B says that to convert a non-boolean to a bool, you just do C<< !! $non_bool >>. So all of the following will be living horses: Horse->new(is_alive => 42) Horse->new(is_alive => []) Horse->new(is_alive => "false") # in Perl, string "false" is true! B is the only type constraint in Types::Standard that has a coercion defined for it. The B, B, B, B, and B types from Types::Common::String also have conversions defined. The other built-in constraints do not define any coercions because it would be hard to agree on what it means to coerce from, say, a B to an B. Do we keep the keys? The values? Both? But it is pretty simple to add your own coercions! use Types::Standard qw( ArrayRef HashRef Str ); has things => ( is => 'rw', isa => ArrayRef->plus_coercions( HashRef, sub { [ values %$_ ] }, Str, sub { [ split /;/, $_ ] }, ), coerce => 1, ); (Don't ever forget the C<< coerce => 1 >>!) If a hashref is provided, the values will be used, and if a string is provided, it will be split on the semicolon. Of course, if an arrayref if provided, it already passes the type constraint, so no conversion is necessary. The coercions should be pairs of "from types" and code to coerce the value. The code can be a coderef (as above) or just string of Perl code (as below). Strings of Perl code can usually be optimized better by Type::Tiny's internals, so are generally preferred. Thanks to Perl's C<< q{...} >> operator, they can look just as clean and pretty as coderefs. use Types::Standard qw( ArrayRef HashRef Str ); has things => ( is => 'rw', isa => ArrayRef->plus_coercions( HashRef, q{ values %$_ }, Str, q{ [ split /;/, $_ ] }, ), coerce => 1, ); Coercions are deeply applied automatically, so the following will do what you expect. has inputs => ( is => 'ro', isa => ArrayRef->of(Bool), coerce => 1 ); I am, of course, assuming you expect something like: my $coerced = [ map { !!$_ } @$orig ]; If you were assuming that, congratulations! We are on the same wavelength. And of course you can still add more coercions to the inherited ones... has inputs => ( is => 'ro', isa => ArrayRef->of(Bool)->plus_coercions(Str, sub {...}), coerce => 1 ); =head2 Method Parameters So far we have just concentrated on the definition of object attributes, but type constraints are also useful to validate method parameters. Let's remember our attribute for keeping track of a horse's race wins: use Types::Standard qw( ArrayRef Tuple Optional ); use Types::Common::Numeric qw( PositiveInt ); use Types::Common::String qw( NonEmptyStr ); has wins => ( is => 'ro', isa => ArrayRef[ Tuple[ PositiveInt, NonEmptyStr, Optional[NonEmptyStr] ] ], default => sub { return [] }, ); Because we don't trust outside code to push new entries onto this array, let's define a method in our class to do it. package Horse { ...; sub add_win { my $self = shift; my ($year, $race, $jockey) = @_; my $win = [ $year, $race, $jockey ? $jockey : (), ]; push @{ $self->wins }, $win; return $self; } } This works pretty well, but we're still not actually checking the values of C<< $year >>, C<< $race >>, and C<< $jockey >>. Let's use L for that: package Horse { use Types::Common::Numeric qw( PositiveInt ); use Types::Common::String qw( NonEmptyStr ); use Type::Params qw( compile ); ...; sub add_win { state $check = compile( PositiveInt, NonEmptyStr, NonEmptyStr, { optional => 1 }, ); my $self = shift; my ($year, $race, $jockey) = $check->(@_); my $win = [ $year, $race, $jockey ? $jockey : (), ]; push @{ $self->wins }, $win; return $self; } } The first time this method is called, it will compile a coderef called C<< $check >>. Then every time it is run, C<< $check >> will be called to check the method's parameters. It will throw an exception if they fail. C<< $check >> will also perform coercions if types have them (and you don't even need to remember C<< coerce => 1 >>; it's always automatic) and can even add in defaults: state $check = compile( PositiveInt, NonEmptyStr, NonEmptyStr, { default => sub { "Eddie" } }, ); On older versions of Perl (prior to 5.10), C variables are not available. A workaround is to replace this: sub foo { state $x = bar(); ...; } With this: { # outer braces prevent other subs seeing $x my $x; # declare $x before sub foo() sub foo { $x = bar(); ...; } } (While we're having a general Perl syntax lesson, I'll note that C<< &$check >> with an ampersand and no parentheses is a shortcut for C<< $check->(@_) >> and actually runs slightly faster because it reuses the C<< @_ >> array for the called coderef. A lot of people dislike calling subs with an ampersand, so we will stick to the C<< $check->(@_) >> syntax in these examples. But do consider using the shortcut!) The generalized syntax for C is: state $check = compile( \%general_options, TypeForFirstParam, \%options_for_first_param, TypeForSecondParam, \%options_for_second_param, ..., ); As a shortcut for the C<< { optional => 1 }} >> option, you can just use B like in B. state $check = compile( PositiveInt, NonEmptyStr, Optional[NonEmptyStr], ); You can also use C<0> and C<1> as shortcuts for B<< Optional[Any] >> and B<< Any >>. The following checks that the first parameter is a positive integer, the second parameter is required (but doesn't care what value it is) and the third parameter is allowed but not required. state $check = compile(PositiveInt, 1, 0); It is possible to accept a variable number of values using C: package Horse { use Types::Common::Numeric qw( PositiveInt ); use Types::Common::String qw( NonEmptyStr ); use Types::Standard qw( ArrayRef slurpy ); use Type::Params qw( compile ); ...; sub add_wins_for_year { state $check = compile( PositiveInt, slurpy ArrayRef[NonEmptyStr], ); my $self = shift; my ($year, $races) = $check->(@_); for my $race (@$races) { push @{ $self->wins }, [$year, $win]; } return $self; } } It would be called like this: $bold_ruler->add_wins_for_year( 1956, "Futurity Stakes", "Juvenile Stakes", ); The additional parameters are slurped into an arrayref and checked against B<< ArrayRef[NonEmptyStr] >>. Optional parameters are only allowed after required parameters, and slurpy parameters are only allowed at the end. (And there can only be a at most one slurpy parameter!) For methods that accept more than one or two parameters, it is often a good idea to provide them as a hash. For example: $horse->add_win( year => 1956, race => "Futurity Stakes", jockey => "Eddie", ); This can make your code more readable. To accept named parameters, use C instead of C. package Horse { use Types::Common::Numeric qw( PositiveInt ); use Types::Common::String qw( NonEmptyStr ); use Type::Params qw( compile_named ); ...; sub add_win { state $check = compile_named( year => PositiveInt, race => NonEmptyStr, jockey => NonEmptyStr, { optional => 1 }, ); my $self = shift; my $args = $check->(@_); my $win = [ $args->{year}, $args->{race}, exists($args->{jockey}) ? $args->{jockey} : (), ]; push @{ $self->wins }, $win; return $self; } } C and C work pretty much the same, except the latter accepts named parameters instead of positional, and returns a hashref. It will automatically allow for a hashref to be provided instead of a full hash. The following both work, but the C<< $args >> variable will always be given a hashref. $horse->add_win({ year => 1956, race => "Juvenile Stakes", }); $horse->add_win( year => 1956, race => "Futurity Stakes", jockey => "Eddie", ); Well... I say "always" but you can tell C to accept named parameters but return a positional list of parameters: package Horse { use Types::Common::Numeric qw( PositiveInt ); use Types::Common::String qw( NonEmptyStr ); use Type::Params qw( compile_named ); ...; sub add_win { state $check = compile_named( { named_to_list => 1 }, year => PositiveInt, race => NonEmptyStr, jockey => NonEmptyStr, { optional => 1 }, ); my $self = shift; my ($year, $race, $jockey) = $check->(@_); my $win = [ $year, $race, $jockey ? $jockey : (), ]; push @{ $self->wins }, $win; return $self; } } Optional and slurpy named parameters are supported as you'd expect. With named parameters, it can be easy to misspell keys in your method definition. For example: my $win = [ $args->{year}, $args->{race}, exists($args->{jockee}) ? $args->{jockey} : (), ]; Note "jockee"! This can lead to hard-to-find bugs. There's a C function which may help and can lead to cleaner code. package Horse { use Types::Common::Numeric qw( PositiveInt ); use Types::Common::String qw( NonEmptyStr ); use Type::Params qw( compile_named_oo ); ...; sub add_win { state $check = compile_named_oo( year => PositiveInt, race => NonEmptyStr, jockey => NonEmptyStr, { optional => 1 }, ); my $self = shift; my $args = $check->(@_); my $win = [ $args->year, $args->race, $args->has_jockey ? $args->jockey : (), ]; push @{ $self->wins }, $win; return $self; } } Now C<< $args >> is a blessed object that you can call methods on. There is of course a performance penalty for this, but it's surprisingly small. For more information on Type::Params, and third-party alternatives, see L. =head1 NEXT STEPS Congratulations! I know this was probably a lot to take in, but you've covered all of the essentials. You can now set type constraints and coercions for attributes and method parameters in Moo! You are familiar with a lot of the most important and useful type constraints and understand parameterization and how it can be used to build more specific type constraints. (And I'll let you in on a secret. Using Type::Tiny with L or L instead of L is exactly the same. You can just replace C<< use Moo >> with C<< use Moose >> in any of these examples and they should work fine!) Here's your next step: =over =item * L Advanced use of Type::Tiny with Moo, including unions and intersections, C, C, C, and C. =back =head1 NOTES On very old versions of Moo C<< coerce => 1 >> is not supported. Instead you will need to provide a coderef or object overloading C<< &{} >> to coerce. Type::Tiny can provide you with an overloaded object. package Horse { use Moo; use Types::Standard qw( Str Num ArrayRef Bool ); use namespace::autoclean; ...; # name, gender, age, children, wins has is_alive => ( is => 'rw', isa => Bool, coerce => Bool->coercion, # overloaded object ); } If you have a very old version of Moo, please upgrade to at least Moo 1.006000 which was the version that added support for C<< coerce => 1 >>. =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut UsingWithMoo2.pod000644001750001750 2521113601673061 21437 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual::UsingWithMoo2 - advanced use of Type::Tiny with Moo =head1 MANUAL =head2 What is a Type? So far all the examples have shown you how to work with types, but we haven't looked at what a type actually I. use Types::Standard qw( Int ); my $type = Int; C<< Int >> in the above code is just a function called with zero arguments which returns a blessed Perl object. It is this object that defines what the B type is and is responsible for checking values meet its definition. use Types::Standard qw( HashRef Int ); my $type = HashRef[Int]; The C<< HashRef >> function, if called with no parameters returns the object defining the B type, just like the C<< Int >> function did before. But the difference here is that it's called with a parameter, an arrayref containing the B type object. It uses this to make the B<< HashRef[Int] >> type and returns that. Like any object, you can call methods on it. The most important methods to know about are: # check the value and return a boolean # $type->check($value); # return an error message about $value failing the type check # but don't actually check the value # $type->get_message($value); # coerce the value # my $coerced = $type->coerce($value); We've already seen some other methods earlier in the tutorial. # create a new type, same as the old type, but that has coercions # my $new_type = $type->plus_coercions( ... ); # different syntax for parameterized types # my $href = HashRef; my $int = Int; my $href_of_int = $href->of($int); So now you should understand this: use Types::Standard qw( ArrayRef Dict Optional ); use Types::Common::Numeric qw( PositiveInt ); use Types::Common::String qw( NonEmptyStr ); my $RaceInfo = Dict[ year => PositiveInt, race => NonEmptyStr, jockey => Optional[NonEmptyStr], ]; has latest_event => ( is => 'rw', isa => $RaceInfo ); has wins => ( is => 'rw', isa => ArrayRef[$RaceInfo] ); has losses => ( is => 'rw', isa => ArrayRef[$RaceInfo] ); This can help you avoid repetition if you have a complex parameterized type that you need to reuse a few times. =head2 C<< where >> One of the most useful methods you can call on a type object is C<< where >>. use Types::Standard qw( Int ); has lucky_number => ( is => 'ro', isa => Int->where(sub { $_ != 13 }), ); I think you already understand what it does. It creates a new type constraint on the fly, restricting the original type. Like with coercions, these restrictions can be expressed as a coderef or as a string of Perl code, operating on the C<< $_ >> variable. And like with coercions, using a string of code will result in better performance. use Types::Standard qw( Int ); has lucky_number => ( is => 'ro', isa => Int->where(q{ $_ != 13 }), ); Let's coerce a hashref of strings from an even-sized arrayref of strings: use Types::Standard qw( HashRef ArrayRef Str ); has stringhash => ( is => 'ro', isa => HashRef->of(Str)->plus_coercions( ArrayRef->of(Str)->where(q{ @$_ % 2 == 0 }), q{ my %h = @$_; \%h; }, ), coerce => 1, # never forget! ); If you understand that, you really are in the advanced class. Congratulations! =head2 Unions Sometimes you want to accept one thing or another thing. This is pretty easy with Type::Tiny. use Types::Standard qw( HashRef ArrayRef Str ); has strings => ( is => 'ro', isa => ArrayRef[Str] | HashRef[Str], ); Type::Tiny overloads the bitwise or operator so stuff like this should "just work". That said, now any code that calls C<< $self->strings >> will probably need to check if the value is an arrayref or a hashref before doing anything with it. So it may be simpler overall if you just choose one of the options and coerce the other one into it. =head2 Intersections Similar to a union is an intersection. package MyAPI::Client { use Moo; use Types::Standard qw( HasMethods InstanceOf ); has ua => ( is => 'ro', isa => (InstanceOf["MyUA"]) & (HasMethods["store_cookie"]), ); } Here we are checking that the UA is an instance of the MyUA class and also offers the C method. Perhaps C isn't provided by the MyUA class itself, but several subclasses of MyUA provide it. Intersections are not useful as often as unions are. This is because they often make no sense. C<< (ArrayRef) & (HashRef) >> would be a reference which was simultaneously pointing to an array and a hash, which is impossible. Note that when using intersections, it is good practice to put parentheses around each type. This is to disambiguate the meaning of C<< & >> for Perl, because Perl uses it as the bitwise and operator but also as the sigil for subs. =head2 Complements For any type B there is a complementary type B<< ~Foo >> (pronounced "not Foo"). package My::Class { use Moo; use Types::Standard qw( ArrayRef CodeRef ); has things => ( is => 'ro', isa => ArrayRef[~CodeRef] ); } C is now an arrayref of anything except coderefs. If you need a number that is I an integer: Num & ~Int L includes two types which are complements of each other: B and B. B might seem to be the complement of B but when you think about it, it is not. There are values that fall into neither category, such as non-integers, non-numeric strings, references, undef, etc. =head2 C and C The B type constraint provides C and C methods which are probably best explained by examples. C<< Object->numifies_to(Int) >> means any object where C<< 0 + $object >> is an integer. C<< Object->stringifies_to(StrMatch[$re]) >> means any object where C<< "$object" >> matches the regular expression. C<< Object->stringifies_to($re) >> also works as a shortcut. C<< Object->numifies_to($coderef) >> and C<< Object->stringifies_to($coderef) >> also work, where the coderef checks C<< $_ >> and returns a boolean. Other types which are also logically objects, such as parameterized B, B, and B should also provide C and C methods. C and C work on unions if I of the type constraints in the union offer the method. C and C work on intersections if I of the type constraints in the intersection offers the method. =head2 C Another one that is probably best explained using an example: package Horse { use Types::Standard qw( Enum Object ); has gender => ( is => 'ro', isa => Enum['m', 'f'], ); has father => ( is => 'ro', isa => Object->with_attribute_values(gender => Enum['m']), ); has mother => ( is => 'ro', isa => Object->with_attribute_values(gender => Enum['f']), ); } In this example when you set a horse's father, it will call C<< $father->gender >> and check that it matches B<< Enum['m'] >>. This method is in the same family as C and C, so like those, it only applies to B and similar type constraints, can work on unions/intersections under the same circumstances, and will also accept coderefs and regexps. has father => ( is => 'ro', isa => Object->with_attribute_values(gender => sub { $_ eq 'm' }), ); has mother => ( is => 'ro', isa => Object->with_attribute_values(gender => qr/^f/i), ); All of C, C, and C are really just wrappers around C. The following two are roughly equivalent: my $type1 = Object->with_attribute_values(foo => Int, bar => Num); my $type2 = Object->where(sub { Int->check( $_->foo ) and Num->check( $_->bar ) }); The first will result in better performing code though. =head2 Tied Variables It is possible to tie variables to a type constraint. use Types::Standard qw(Int); tie my $n, Int, 4; print "$n\n"; # says "4" $n = 5; # ok $n = "foo"; # dies This feature requires L which is a separate thing to install. Type::Tiny will automatically load Type::Tie in the background if it detects you're trying to tie a variable to a type. You can also tie arrays: tie my @numbers, Int; push @numbers, 1 .. 10; And hashes: tie my %numbers, Int; $numbers{lucky} = 7; $numbers{unlucky} = 13; Earlier in the manual, it was mentioned that there is a problem with code like this: push @{ $horse->children }, $non_horse; This can be solved using tied variables. tie @{ $horse->children }, InstanceOf["Horse"]; Here is a longer example using builders and triggers. package Horse { use Moo; use Types::Standard qw( Str Num ArrayRef InstanceOf ); use Type::Params qw(compile); use namespace::autoclean; my $ThisClass = InstanceOf[ __PACKAGE__ ]; has name => ( is => 'ro', isa => Str ); has gender => ( is => 'ro', isa => Str ); has age => ( is => 'rw', isa => Num ); has children => ( is => 'rw', isa => ArrayRef[$ThisClass], builder => "_build_children", trigger => sub { shift->_trigger_children(@_) }, ); # tie a default arrayref sub _build_children { my $self = shift; tie my @kids, $ThisClass; \@kids; } # this method will tie an arrayref provided by the caller sub _trigger_children { my $self = shift; my ($new) = @_; tie @$new, $ThisClass; } sub add_child { state $check = compile($ThisClass, $ThisClass); my ($self, $kid) = &$check; push @{ $self->children }, $kid; return $self; } } Now it's pretty much impossible for the caller to make a mess by adding a non-horse as a child. =head1 NEXT STEPS Here's your next step: =over =item * L There's more than one way to do it! Alternative ways of using Type::Tiny, including type registries, exported functions, and C. =back =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut UsingWithMoo3.pod000644001750001750 2045313601673061 21443 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual::UsingWithMoo3 - alternative use of Type::Tiny with Moo =head1 MANUAL =head2 Type Registries In all the examples so far, we have imported a collection of type constraints into each class: package Horse { use Moo; use Types::Standard qw( Str ArrayRef HashRef Int Any InstanceOf ); use Types::Common::Numeric qw( PositiveInt ); use Types::Common::String qw( NonEmptyStr ); has name => ( is => 'ro', isa => Str ); has father => ( is => 'ro', isa => InstanceOf["Horse"] ); ...; } This creates a bunch of subs in the Horse namespace, one for each type. We've used L to clean these up later. But it is also possible to avoid pulling all these into the Horse namespace. Instead we'll use a type registry: package Horse { use Moo; use Type::Registry qw( t ); t->add_types('-Standard'); t->add_types('-Common::String'); t->add_types('-Common::Numeric'); t->alias_type('InstanceOf["Horse"]' => 'Horsey'); has name => ( is => 'ro', isa => t('Str') ); has father => ( is => 'ro', isa => t('Horsey') ); has mother => ( is => 'ro', isa => t('Horsey') ); has children => ( is => 'ro', isa => t('ArrayRef[Horsey]') ); ...; } You don't even need to import the C<< t() >> function. Types::Registry can be used in an entirely object-oriented way. package Horse { use Moo; use Type::Registry; my $reg = Type::Registry->for_me; $reg->add_types('-Standard'); $reg->add_types('-Common::String'); $reg->add_types('-Common::Numeric'); $reg->alias_type('InstanceOf["Horse"]' => 'Horsey'); has name => ( is => 'ro', isa => $reg->lookup('Str') ); ...; } You could create two registries with entirely different definitions for the same named type. my $dracula = Aristocrat->new(name => 'Dracula'); package AristocracyTracker { use Type::Registry; my $reg1 = Type::Registry->new; $reg1->add_types('-Common::Numeric'); $reg1->alias_type('PositiveInt' => 'Count'); my $reg2 = Type::Registry->new; $reg2->add_types('-Standard'); $reg2->alias_type('InstanceOf["Aristocrat"]' => 'Count'); $reg1->lookup("Count")->assert_valid("1"); $reg2->lookup("Count")->assert_valid($dracula); } Type::Registry uses C, so things like this work: $reg->ArrayRef->of( $reg->Int ); Although you can create as many registries as you like, Type::Registry will create a default registry for each package. # Create a new empty registry. # my $reg = Type::Registry->new; # Get the default registry for my package. # It will be pre-populated with any types we imported using `use`. # my $reg = Type::Registry->for_me; # Get the default registry for some other package. # my $reg = Type::Registry->for_class("Horse"); Type registries are a convenient place to store a bunch of types without polluting your namespace. They are not the same as type libraries though. L, L, and L are type libraries; packages that export types for others to use. We will look at how to make one of those later. For now, here's the best way to think of the difference: =over =item * Type registry Curate a collection of types for me to use here in this class. This collection is an implementaion detail. =item * Type library Export a collection of types to be used across multiple classes. This collection is part of your API. =back =head2 Importing Functions We've seen how, for instance, Types::Standard exports a sub called C that returns the B type object. use Types::Standard qw( Int ); my $type = Int; $type->check($value) or die $type->get_message($value); Type libraries are also capable of exporting other convenience functions. =head3 C<< is_* >> This is a shortcut for checking a value meets a type constraint: use Types::Standard qw( is_Int ); if ( is_Int($value) ) { ...; } Calling C<< is_Int($value) >> will often be marginally faster than calling C<< Int->check($value) >> because it avoids a method call. (Method calls in Perl end up slower than normal function calls.) Using things like C in your code might be preferable to C<< ref($value) eq "ARRAY" >> because it's neater, leads to more consistent type checking, and might even be faster. (Type::Tiny can be pretty fast; it is sometimes able to export these functions as XS subs.) =head3 C<< assert_* >> While C<< is_Int($value) >> returns a boolean, C<< assert_Int($value) >> will throw an error if the value does not meet the constraint, and return the value otherwise. So you can do: my $sum = assert_Int($x) + assert_Int($y); And you will get the sum of integers C<< $x >> and C<< $y >>, and an explosion if either of them is not an integer! Assert is useful for quick parameter checks if you are avoiding L for some strange reason: sub add_numbers { my $x = assert_Num(shift); my $y = assert_Num(shift); return $x + $y; } =head3 C<< to_* >> This is a shortcut for coercion: my $truthy = to_Bool($value); It trusts that the coercion has worked okay. You can combine it with an assertion if you want to make sure. my $truthy = assert_Bool(to_Bool($value)); =head3 Shortcuts for exporting functions This is a little verbose: use Types::Standard qw( Bool is_Bool assert_Bool to_Bool ); Isn't this a little bit nicer? use Types::Standard qw( +Bool ); The plus sign tells a type library to export not only the type itself, but all of the convenience functions too. You can also use: use Types::Standard -types; # export Int, Bool, etc use Types::Standard -is; # export is_Int, is_Bool, etc use Types::Standard -assert; # export assert_Int, assert_Bool, etc use Types::Standard -to; # export to_Bool, etc use Types::Standard -all; # just export everything!!! So if you imagine the functions exported by Types::Standard are like this: qw( Str is_Str assert_Str Num is_Num assert_Num Int is_Int assert_Int Bool is_Bool assert_Bool to_Bool ArrayRef is_ArrayRef assert_ArrayRef ); # ... and more Then "+" exports a horizonal group of those, and "-" exports a vertical group. =head2 Exporting Parameterized Types It's possible to export parameterizable types like B, but it is also possible to export I types. use Types::Standard qw( ArrayRef Int ); use Types::Standard ( '+ArrayRef' => { of => Int, -as => 'IntList' }, ); has numbers => (is => 'ro', isa => IntList); Using C<< is_IntList($value) >> should be significantly faster than C<< ArrayRef->of(Int)->check($value) >>. This trick only works for parameterized types that have a single parameter, like B, B, B, etc. (Sorry, C and C!) =head2 Do What I Mean! use Type::Utils qw( dwim_type ); dwim_type("ArrayRef[Int]") C will look up a type constraint from a string and attempt to guess what you meant. If it's a type constraint that you seem to have imported with C, then it should find it. Otherwise, if you're using Moose or Mouse, it'll try asking those. Or if it's in Types::Standard, it'll look there. And if it still has no idea, then it will assume dwim_type("Foo") means dwim_type("InstanceOf['Foo']"). It just does a big old bunch of guessing. =head1 NEXT STEPS You now know pretty much everything there is to know about how to use type libraries. Here's your next step: =over =item * L Defining your own type libraries, including extending existing libraries, defining new types, adding coercions, defining parameterizable types, and the declarative style. =back =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut UsingWithMoose.pod000644001750001750 1366113601673061 21713 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual::UsingWithMoose - how to use Type::Tiny with Moose =head1 MANUAL First read L, L, and L. Everything in those parts of the manual should work exactly the same in Moose. This part of the manual will focus on Moose-specifics. =head2 Why Use Type::Tiny At All? Moose does have a built-in type constraint system which is fairly convenient to use, but there are several reasons you should consider using Type::Tiny instead. =over =item * Type::Tiny type constraints will usually be faster than Moose built-ins. Even without Type::Tiny::XS installed, Type::Tiny usually produces more efficient inline code than Moose. Coercions will usually be a lot faster. =item * Type::Tiny provides helpful methods like C and C that allow type constraints and coercions to be easily tweaked on a per-attribute basis. Something like this is much harder to do with plain Moose types: has name => ( is => "ro", isa => Str->plus_coercions( ArrayRef[Str], sub { join " ", @$_ }, ), coerce => 1, ); Moose tends to encourage defining coercions globally, so if you wanted one B attribute to be able to coerce from B<< ArrayRef[Str] >>, then I B attributes would coerce from B<< ArrayRef[Str] >>, and they'd all do that coercion in the same way. (Even if it might make sense to join by a space in some places, a comma in others, and a line break in others!) =item * Type::Tiny provides automatic deep coercions, so if type B has a coercion, the following should "just work": isa xyzlist => ( is => 'ro', isa => ArrayRef[Xyz], coerce => 1 ); =item * Type::Tiny offers a wider selection of built-in types. =item * By using Type::Tiny, you can use the same type constraints and coercions for attributes and method parameters, in Moose and non-Moose code. =back =head2 Type::Utils If you've used L, you may be accustomed to using a DSL for declaring type constraints: use Moose::Util::TypeConstraints; subtype 'Natural', as 'Int', where { $_ > 0 }; There's a module called L that provides a very similar DSL for declaring types in Type::Library-based type libraries. package My::Types { use Type::Library -base; use Type::Utils; use Types::Standard qw( Int ); declare 'Natural', as Int, where { $_ > 0 }; } Personally I prefer the more object-oriented way to declare types though. In Moose you might also declare types like this within classes and roles too. Unlike Moose, Type::Tiny doesn't keep types in a single global flat namespace, so this doesn't work quite the same with Type::Utils. It still creates the type, but it doesn't store it in any type library; the type is returned. package My::Class { use Moose; use Type::Utils; use Types::Standard qw( Int ); my $Natural = # store type in a variable declare 'Natural', as Int, where { $_ > 0 }; has number => ( is => 'ro', isa => $Natural ); } But really, isn't the object-oriented way cleaner? package My::Class { use Moose; use Types::Standard qw( Int ); has number => ( is => 'ro', isa => Int->where('$_ > 0'), ); } =head2 Type::Tiny and MooseX::Types L should be a drop-in replacement for L. And L and L should easily replace L and L. That said, if you do with to use a mixture of Type::Tiny and MooseX::Types, they should fit together pretty seamlessly. use Types::Standard qw( ArrayRef ); use MooseX::Types::Common::Numeric qw( PositiveInt ); # this should just work my $list_of_nums = ArrayRef[PositiveInt]; # and this my $list_or_num = ArrayRef | PositiveInt; =head2 C<< -moose >> Import Parameter If you have read this far in the manual, you will know that this is the usual way to import type constraints: use Types::Standard qw( Int ); And the C which is imported is a function that takes no arguments and returns the B type constraint, which is a blessed object in the L class. Type::Tiny mocks the L API so well that most Moose and MooseX code will not be able to tell the difference. But what if you need a real Moose::Meta::TypeConstraint object? use Types::Standard -moose, qw( Int ); Now the C function imported will return a genuine native Moose type constraint. This flag is mostly a throwback from when Type::Tiny native objects I<< didn't >> directly work in Moose. In 99.9% of cases, there is no reason to use it and plenty of reasons not to. (Moose native type constraints don't offer helpful methods like C and C.) =head2 C<< moose_type >> Method Another quick way to get a native Moose type constraint object from a Type::Tiny object is to call the C method: use Types::Standard qw( Int ); my $tiny_type = Int; my $moose_type = $tiny_type->moose_type; Internally, this is what the C<< -moose >> flag makes imported functions do. =head1 NEXT STEPS Here's your next step: =over =item * L How to use Type::Tiny with Mouse, including the advantages of Type::Tiny over built-in type constraints, and Mouse-specific features. =back =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut UsingWithMouse.pod000644001750001750 1504313601673061 21715 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual::UsingWithMouse - how to use Type::Tiny with Mouse =head1 MANUAL First read L, L, and L. Everything in those parts of the manual should work exactly the same in Mouse. This part of the manual will focus on Mouse-specifics. Overall, Type::Tiny is less well-tested with Mouse than it is with Moose and Moo, but there are still a good number of test cases for using Type::Tiny with Mouse, and there are no known major issues with Type::Tiny's Mouse support. =head2 Why Use Type::Tiny At All? Mouse does have a built-in type constraint system which is fairly convenient to use, but there are several reasons you should consider using Type::Tiny instead. =over =item * Type::Tiny provides helpful methods like C and C that allow type constraints and coercions to be easily tweaked on a per-attribute basis. Something like this is much harder to do with plain Mouse types: has name => ( is => "ro", isa => Str->plus_coercions( ArrayRef[Str], sub { join " ", @$_ }, ), coerce => 1, ); Mouse tends to encourage defining coercions globally, so if you wanted one B attribute to be able to coerce from B<< ArrayRef[Str] >>, then I B attributes would coerce from B<< ArrayRef[Str] >>, and they'd all do that coercion in the same way. (Even if it might make sense to join by a space in some places, a comma in others, and a line break in others!) =item * Type::Tiny provides automatic deep coercions, so if type B has a coercion, the following should "just work": isa xyzlist => ( is => 'ro', isa => ArrayRef[Xyz], coerce => 1 ); =item * Type::Tiny offers a wider selection of built-in types. =item * By using Type::Tiny, you can use the same type constraints and coercions for attributes and method parameters, in Mouse and non-Mouse code. =back =head2 Type::Utils If you've used L, you may be accustomed to using a DSL for declaring type constraints: use Mouse::Util::TypeConstraints; subtype 'Natural', as 'Int', where { $_ > 0 }; There's a module called L that provides a very similar DSL for declaring types in Type::Library-based type libraries. package My::Types { use Type::Library -base; use Type::Utils; use Types::Standard qw( Int ); declare 'Natural', as Int, where { $_ > 0 }; } Personally I prefer the more object-oriented way to declare types though. In Mouse you might also declare types like this within classes and roles too. Unlike Mouse, Type::Tiny doesn't keep types in a single global flat namespace, so this doesn't work quite the same with Type::Utils. It still creates the type, but it doesn't store it in any type library; the type is returned. package My::Class { use Mouse; use Type::Utils; use Types::Standard qw( Int ); my $Natural = # store type in a variable declare 'Natural', as Int, where { $_ > 0 }; has number => ( is => 'ro', isa => $Natural ); } But really, isn't the object-oriented way cleaner? package My::Class { use Mouse; use Types::Standard qw( Int ); has number => ( is => 'ro', isa => Int->where('$_ > 0'), ); } =head2 Type::Tiny and MouseX::Types L should be a drop-in replacement for L. And L and L should easily replace L and L. That said, if you do with to use a mixture of Type::Tiny and MouseX::Types, they should fit together pretty seamlessly. use Types::Standard qw( ArrayRef ); use MouseX::Types::Mouse qw( Int ); # this should just work my $list_of_nums = ArrayRef[Int]; # and this my $list_or_num = ArrayRef | Int; =head2 C<< -mouse >> Import Parameter If you have read this far in the manual, you will know that this is the usual way to import type constraints: use Types::Standard qw( Int ); And the C which is imported is a function that takes no arguments and returns the B type constraint, which is a blessed object in the L class. Type::Tiny mocks the L API so well that most Mouse and MouseX code will not be able to tell the difference. But what if you need a real Mouse::Meta::TypeConstraint object? use Types::Standard -mouse, qw( Int ); Now the C function imported will return a genuine native Mouse type constraint. This flag is mostly a throwback from when Type::Tiny native objects I<< didn't >> directly work in Mouse. In 99.9% of cases, there is no reason to use it and plenty of reasons not to. (Mouse native type constraints don't offer helpful methods like C and C.) =head2 C<< mouse_type >> Method Another quick way to get a native Mouse type constraint object from a Type::Tiny object is to call the C method: use Types::Standard qw( Int ); my $tiny_type = Int; my $mouse_type = $tiny_type->mouse_type; Internally, this is what the C<< -mouse >> flag makes imported functions do. =head2 Type::Tiny Performance Type::Tiny should run pretty much as fast as Mouse types do. This is because, when possible, it will use Mouse's XS implementations of type checks to do the heavy lifting. There are a few type constraints where Type::Tiny prefers to do things without Mouse's help though, for consistency and correctness. For example, the Mouse XS implementation of B is... strange... it accepts blessed objects that overload C, but only if they return false. If they return true, it's a type constraint error. Using Type::Tiny instead of Mouse's type constraints shouldn't make a significant difference to the performance of your code. =head1 NEXT STEPS Here's your next step: =over =item * L Including how to Type::Tiny in your object's C method, and third-party shims between Type::Tiny and Class::Tiny. =back =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut UsingWithOther.pod000644001750001750 1050613601673061 21705 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual::UsingWithOther - using Type::Tiny with Class::InsideOut, Params::Check, and Object::Accessor. =head1 MANUAL The antlers crew aren't the only object-oriented programming toolkits in Perl town. Although Type::Tiny might have been built with Moose, Mouse, and Moo in mind, it can be used with other toolkits. These toolkits are... well... hmm... okay... they exist. If you are starting a new project, there's very little reason not to use Class::Tiny, Moo, or Moose. So you're probably okay to skip this part of the fine manual and go straight to L. =head2 Class::InsideOut You want L 1.13 or above, which has support for blessed and overloaded objects (including Type::Tiny type constraints) for the C and C options. package Person { use Class::InsideOut qw( public ); use Types::Standard qw( Str Int ); use Types::Common::Numeric qw( PositiveInt ); use Type::Params qw( compile ); # Type checks are really easy. # Just supply the type as a set hook. public name => my %_name, { set_hook => Str, }; # Define a type that silently coerces negative values # to positive. It's silly, but it works as an example! my $Years = PositiveInt->plus_coercions(Int, q{ abs($_) }); # Coercions are more annoying, but possible. public age => my %_age, { set_hook => sub { $_ = $Years->assert_coerce($_) }, }; # Parameter checking for methods is as expected. sub get_older { state $check = compile( $Years ); my $self = shift; my ($years) = $check->(@_); $self->_set_age($self->age + $years); } } =head2 Params::Check and Object::Accessor The Params::Check C<< allow() >> function, the C option for the Params::Check C<< check() >> function, and the input validation mechanism for Object::Accessor all work in the same way, which is basically a limited pure-Perl implementation of the smart match operator. While this doesn't directly support Type::Tiny constraints, it does support coderefs. You can use Type::Tiny's C method to obtain a suitable coderef. L example: my $tmpl = { name => { allow => Str->compiled_check }, age => { allow => Int->compiled_check }, }; check($tmpl, { name => "Bob", age => 32 }) or die Params::Check::last_error(); L example: my $obj = Object::Accessor->new; $obj->mk_accessors( { name => Str->compiled_check }, { age => Int->compiled_check }, ); I<< Caveat: >> Object::Accessor doesn't die when a value fails to meet its type constraint; instead it outputs a warning to STDERR. This behaviour can be changed by setting C<< $Object::Accessor::FATAL = 1 >>. =head2 Class::Struct This is proof-of-concept of how Type::Tiny can be used to constrain attributes for Class::Struct. It's probably not a good idea to use this in production as it slows down C globally. use Types::Standard -types; use Class::Struct; { my %MAP; my $orig_isa = \&UNIVERSAL::isa; *UNIVERSAL::isa = sub { return $MAP{$1}->check($_[0]) if $_[1] =~ /^CLASSSTRUCT::TYPETINY::(.+)$/ && exists $MAP{$1}; goto $orig; }; my $orig_dn = \&Type::Tiny::display_name; *Type::Tiny::display_name = sub { if (caller(1) eq 'Class::Struct') { $MAP{$_[0]{uniq}} = $_[0]; return "CLASSSTRUCT::TYPETINY::".$_[0]{uniq}; } goto $orig_dn; }; } struct Person => [ name => Str, age => Int ]; my $bob = Person->new( name => "Bob", age => 21, ); $bob->name("Robert"); # okay $bob->name([]); # dies =head1 NEXT STEPS Here's your next step: =over =item * L Type::Tiny for test suites. =back =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut UsingWithTestMore.pod000644001750001750 511513601673061 22346 0ustar00taitai000000000000Type-Tiny-1.008001/lib/Type/Tiny/Manual=pod =encoding utf-8 =head1 NAME Type::Tiny::Manual::UsingWithTestMore - Type::Tiny for test suites =head1 MANUAL =head2 Test::TypeTiny This is a module for testing that types you've defined accept and reject the values you think they should. should_pass($value, $type); should_fail($othervalue, $type); Easy. (But yeah, I always forget whether the type goes first or second!) There's also a function to test that subtype/supertype relationships are working okay. ok_subtype($type, @subtypes); Of course you can just check a type like this: ok( $type->check($value) ); But the advantage of C is that if the C environment variable is set to true, C will also perform a strict check on the value, which involves climbing up the type's inheritance tree (its parent, its parent's parent, etc) to make sure the value passes all their constraints. If a normal check and strict check differ, this is usually a problem in the inlining code somewhere. See L for more information. =head2 Type::Tiny as a Replacement for Test::Deep Here's one of the examples from the Test::Deep documentation: my $name_re = re('^(Mr|Mrs|Miss) \w+ \w+$'); cmp_deeply( $person, { Name => $name_re, Phone => re('^0d{6}$'), ChildNames => array_each($name_re) }, "person ok" ); It's pretty easy to rewrite this to use Types::Standard: my $name = StrMatch[ qr/^(Mr|Mrs|Miss) \w+ \w+$/ ]; should_pass( $person, Dict[ Name => $name, Phone => StrMatch[ qr/^0d{6}$/ ], ChildNames => ArrayRef[$name] ] ); There's nothing especially wrong with L, but if you're already familiar with Type::Tiny's built-in types and you've maybe written your own type libraries too, it will save you having to switch between using two separate systems of checks. =head1 NEXT STEPS Here's your next step: =over =item * L Advanced information on Type::Params, and using Type::Tiny with other signature modules like Function::Parameters and Kavorka. =back =head1 AUTHOR Toby Inkster Etobyink@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is copyright (c) 2013-2014, 2017-2019 by Toby Inkster. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. =cut Scalar.pm000644001750001750 3245413601673061 21157 0ustar00taitai000000000000Type-Tiny-1.008001/inc/archaic/Test/Builder/IOpackage Test::Builder::IO::Scalar; =head1 NAME Test::Builder::IO::Scalar - A copy of IO::Scalar for Test::Builder =head1 DESCRIPTION This is a copy of IO::Scalar which ships with Test::Builder to support scalar references as filehandles on Perl 5.6. Newer versions of Perl simply use C<>'s built in support. Test::Builder can not have dependencies on other modules without careful consideration, so its simply been copied into the distribution. =head1 COPYRIGHT and LICENSE This file came from the "IO-stringy" Perl5 toolkit. Copyright (c) 1996 by Eryq. All rights reserved. Copyright (c) 1999,2001 by ZeeGee Software Inc. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut # This is copied code, I don't care. ##no critic use Carp; use strict; use vars qw($VERSION @ISA); use IO::Handle; use 5.005; ### The package version, both in 1.23 style *and* usable by MakeMaker: $VERSION = "2.110"; ### Inheritance: @ISA = qw(IO::Handle); #============================== =head2 Construction =over 4 =cut #------------------------------ =item new [ARGS...] I Return a new, unattached scalar handle. If any arguments are given, they're sent to open(). =cut sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = bless \do { local *FH }, $class; tie *$self, $class, $self; $self->open(@_); ### open on anonymous by default $self; } sub DESTROY { shift->close; } #------------------------------ =item open [SCALARREF] I Open the scalar handle on a new scalar, pointed to by SCALARREF. If no SCALARREF is given, a "private" scalar is created to hold the file data. Returns the self object on success, undefined on error. =cut sub open { my ($self, $sref) = @_; ### Sanity: defined($sref) or do {my $s = ''; $sref = \$s}; (ref($sref) eq "SCALAR") or croak "open() needs a ref to a scalar"; ### Setup: *$self->{Pos} = 0; ### seek position *$self->{SR} = $sref; ### scalar reference $self; } #------------------------------ =item opened I Is the scalar handle opened on something? =cut sub opened { *{shift()}->{SR}; } #------------------------------ =item close I Disassociate the scalar handle from its underlying scalar. Done automatically on destroy. =cut sub close { my $self = shift; %{*$self} = (); 1; } =back =cut #============================== =head2 Input and output =over 4 =cut #------------------------------ =item flush I No-op, provided for OO compatibility. =cut sub flush { "0 but true" } #------------------------------ =item getc I Return the next character, or undef if none remain. =cut sub getc { my $self = shift; ### Return undef right away if at EOF; else, move pos forward: return undef if $self->eof; substr(${*$self->{SR}}, *$self->{Pos}++, 1); } #------------------------------ =item getline I Return the next line, or undef on end of string. Can safely be called in an array context. Currently, lines are delimited by "\n". =cut sub getline { my $self = shift; ### Return undef right away if at EOF: return undef if $self->eof; ### Get next line: my $sr = *$self->{SR}; my $i = *$self->{Pos}; ### Start matching at this point. ### Minimal impact implementation! ### We do the fast fast thing (no regexps) if using the ### classic input record separator. ### Case 1: $/ is undef: slurp all... if (!defined($/)) { *$self->{Pos} = length $$sr; return substr($$sr, $i); } ### Case 2: $/ is "\n": zoom zoom zoom... elsif ($/ eq "\012") { ### Seek ahead for "\n"... yes, this really is faster than regexps. my $len = length($$sr); for (; $i < $len; ++$i) { last if ord (substr ($$sr, $i, 1)) == 10; } ### Extract the line: my $line; if ($i < $len) { ### We found a "\n": $line = substr ($$sr, *$self->{Pos}, $i - *$self->{Pos} + 1); *$self->{Pos} = $i+1; ### Remember where we finished up. } else { ### No "\n"; slurp the remainder: $line = substr ($$sr, *$self->{Pos}, $i - *$self->{Pos}); *$self->{Pos} = $len; } return $line; } ### Case 3: $/ is ref to int. Do fixed-size records. ### (Thanks to Dominique Quatravaux.) elsif (ref($/)) { my $len = length($$sr); my $i = ${$/} + 0; my $line = substr ($$sr, *$self->{Pos}, $i); *$self->{Pos} += $i; *$self->{Pos} = $len if (*$self->{Pos} > $len); return $line; } ### Case 4: $/ is either "" (paragraphs) or something weird... ### This is Graham's general-purpose stuff, which might be ### a tad slower than Case 2 for typical data, because ### of the regexps. else { pos($$sr) = $i; ### If in paragraph mode, skip leading lines (and update i!): length($/) or (($$sr =~ m/\G\n*/g) and ($i = pos($$sr))); ### If we see the separator in the buffer ahead... if (length($/) ? $$sr =~ m,\Q$/\E,g ### (ordinary sep) TBD: precomp! : $$sr =~ m,\n\n,g ### (a paragraph) ) { *$self->{Pos} = pos $$sr; return substr($$sr, $i, *$self->{Pos}-$i); } ### Else if no separator remains, just slurp the rest: else { *$self->{Pos} = length $$sr; return substr($$sr, $i); } } } #------------------------------ =item getlines I Get all remaining lines. It will croak() if accidentally called in a scalar context. =cut sub getlines { my $self = shift; wantarray or croak("can't call getlines in scalar context!"); my ($line, @lines); push @lines, $line while (defined($line = $self->getline)); @lines; } #------------------------------ =item print ARGS... I Print ARGS to the underlying scalar. B this continues to always cause a seek to the end of the string, but if you perform seek()s and tell()s, it is still safer to explicitly seek-to-end before subsequent print()s. =cut sub print { my $self = shift; *$self->{Pos} = length(${*$self->{SR}} .= join('', @_) . (defined($\) ? $\ : "")); 1; } sub _unsafe_print { my $self = shift; my $append = join('', @_) . $\; ${*$self->{SR}} .= $append; *$self->{Pos} += length($append); 1; } sub _old_print { my $self = shift; ${*$self->{SR}} .= join('', @_) . $\; *$self->{Pos} = length(${*$self->{SR}}); 1; } #------------------------------ =item read BUF, NBYTES, [OFFSET] I Read some bytes from the scalar. Returns the number of bytes actually read, 0 on end-of-file, undef on error. =cut sub read { my $self = $_[0]; my $n = $_[2]; my $off = $_[3] || 0; my $read = substr(${*$self->{SR}}, *$self->{Pos}, $n); $n = length($read); *$self->{Pos} += $n; ($off ? substr($_[1], $off) : $_[1]) = $read; return $n; } #------------------------------ =item write BUF, NBYTES, [OFFSET] I Write some bytes to the scalar. =cut sub write { my $self = $_[0]; my $n = $_[2]; my $off = $_[3] || 0; my $data = substr($_[1], $off, $n); $n = length($data); $self->print($data); return $n; } #------------------------------ =item sysread BUF, LEN, [OFFSET] I Read some bytes from the scalar. Returns the number of bytes actually read, 0 on end-of-file, undef on error. =cut sub sysread { my $self = shift; $self->read(@_); } #------------------------------ =item syswrite BUF, NBYTES, [OFFSET] I Write some bytes to the scalar. =cut sub syswrite { my $self = shift; $self->write(@_); } =back =cut #============================== =head2 Seeking/telling and other attributes =over 4 =cut #------------------------------ =item autoflush I No-op, provided for OO compatibility. =cut sub autoflush {} #------------------------------ =item binmode I No-op, provided for OO compatibility. =cut sub binmode {} #------------------------------ =item clearerr I Clear the error and EOF flags. A no-op. =cut sub clearerr { 1 } #------------------------------ =item eof I Are we at end of file? =cut sub eof { my $self = shift; (*$self->{Pos} >= length(${*$self->{SR}})); } #------------------------------ =item seek OFFSET, WHENCE I Seek to a given position in the stream. =cut sub seek { my ($self, $pos, $whence) = @_; my $eofpos = length(${*$self->{SR}}); ### Seek: if ($whence == 0) { *$self->{Pos} = $pos } ### SEEK_SET elsif ($whence == 1) { *$self->{Pos} += $pos } ### SEEK_CUR elsif ($whence == 2) { *$self->{Pos} = $eofpos + $pos} ### SEEK_END else { croak "bad seek whence ($whence)" } ### Fixup: if (*$self->{Pos} < 0) { *$self->{Pos} = 0 } if (*$self->{Pos} > $eofpos) { *$self->{Pos} = $eofpos } return 1; } #------------------------------ =item sysseek OFFSET, WHENCE I Identical to C, I =cut sub sysseek { my $self = shift; $self->seek (@_); } #------------------------------ =item tell I Return the current position in the stream, as a numeric offset. =cut sub tell { *{shift()}->{Pos} } #------------------------------ =item use_RS [YESNO] I B Obey the current setting of $/, like IO::Handle does? Default is false in 1.x, but cold-welded true in 2.x and later. =cut sub use_RS { my ($self, $yesno) = @_; carp "use_RS is deprecated and ignored; \$/ is always consulted\n"; } #------------------------------ =item setpos POS I Set the current position, using the opaque value returned by C. =cut sub setpos { shift->seek($_[0],0) } #------------------------------ =item getpos I Return the current position in the string, as an opaque object. =cut *getpos = \&tell; #------------------------------ =item sref I Return a reference to the underlying scalar. =cut sub sref { *{shift()}->{SR} } #------------------------------ # Tied handle methods... #------------------------------ # Conventional tiehandle interface: sub TIEHANDLE { ((defined($_[1]) && UNIVERSAL::isa($_[1], __PACKAGE__)) ? $_[1] : shift->new(@_)); } sub GETC { shift->getc(@_) } sub PRINT { shift->print(@_) } sub PRINTF { shift->print(sprintf(shift, @_)) } sub READ { shift->read(@_) } sub READLINE { wantarray ? shift->getlines(@_) : shift->getline(@_) } sub WRITE { shift->write(@_); } sub CLOSE { shift->close(@_); } sub SEEK { shift->seek(@_); } sub TELL { shift->tell(@_); } sub EOF { shift->eof(@_); } #------------------------------------------------------------ 1; __END__ =back =cut =head1 WARNINGS Perl's TIEHANDLE spec was incomplete prior to 5.005_57; it was missing support for C, C, and C. Attempting to use these functions with an IO::Scalar will not work prior to 5.005_57. IO::Scalar will not have the relevant methods invoked; and even worse, this kind of bug can lie dormant for a while. If you turn warnings on (via C<$^W> or C), and you see something like this... attempt to seek on unopened filehandle ...then you are probably trying to use one of these functions on an IO::Scalar with an old Perl. The remedy is to simply use the OO version; e.g.: $SH->seek(0,0); ### GOOD: will work on any 5.005 seek($SH,0,0); ### WARNING: will only work on 5.005_57 and beyond =head1 VERSION $Id: Scalar.pm,v 1.6 2005/02/10 21:21:53 dfs Exp $ =head1 AUTHORS =head2 Primary Maintainer David F. Skoll (F). =head2 Principal author Eryq (F). President, ZeeGee Software Inc (F). =head2 Other contributors The full set of contributors always includes the folks mentioned in L. But just the same, special thanks to the following individuals for their invaluable contributions (if I've forgotten or misspelled your name, please email me!): I for contributing C. I for suggesting C. I for finding and fixing the bug in C. I for his offset-using read() and write() implementations. I for his patches to massively improve the performance of C and add C and C. I for stringification and inheritance improvements, and sundry good ideas. I for the IO::Handle inheritance and automatic tie-ing. =head1 SEE ALSO L, which is quite similar but which was designed more-recently and with an IO::Handle-like interface in mind, so you could mix OO- and native-filehandle usage without using tied(). I as of version 2.x, these classes all work like their IO::Handle counterparts, so we have comparable functionality to IO::String. =cut Color.pm000644001750001750 171113601673061 21737 0ustar00taitai000000000000Type-Tiny-1.008001/inc/archaic/Test/Builder/Testerpackage Test::Builder::Tester::Color; use strict; our $VERSION = "1.22"; require Test::Builder::Tester; =head1 NAME Test::Builder::Tester::Color - turn on colour in Test::Builder::Tester =head1 SYNOPSIS When running a test script perl -MTest::Builder::Tester::Color test.t =head1 DESCRIPTION Importing this module causes the subroutine color in Test::Builder::Tester to be called with a true value causing colour highlighting to be turned on in debug output. The sole purpose of this module is to enable colour highlighting from the command line. =cut sub import { Test::Builder::Tester::color(1); } =head1 AUTHOR Copyright Mark Fowler Emark@twoshortplanks.comE 2002. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 BUGS This module will have no effect unless Term::ANSIColor is installed. =head1 SEE ALSO L, L =cut 1;