Codebase list libmoops-perl / HEAD
HEAD

Tree @HEAD (Download .tar.gz)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
NAME
    Moops - Moops Object-Oriented Programming Sugar

SYNOPSIS
       use Moops;
   
       role NamedThing {
          has name => (is => "ro", isa => Str);
       }
   
       class Person with NamedThing;
   
       class Company with NamedThing;
   
       class Employee extends Person {
          has job_title => (is => "rwp", isa => Str);
          has employer  => (is => "rwp", isa => InstanceOf["Company"]);
      
          method change_job ( Object $employer, Str $title ) {
             $self->_set_job_title($title);
             $self->_set_employer($employer);
          }
      
          method promote ( Str $title ) {
             $self->_set_job_title($title);
          }
       }

STATUS
    Unstable.

    Will probably never be stable.

    A lot of the modules that Moops is built on have problems. In particular,
    Devel::CallParser is broken on a lot of Perl versions, and Parse::Keyword
    has *fundamental errors in the way it handles closures* (which Moops works
    around using PadWalker).

    Moops will remain on CPAN for the foreseeable future and I'll continue to
    accept patches that fix bugs, but don't expect any new features to be
    added.

    For a replacement, consider Zydeco. It's not a drop-in replacement but it
    has a similar syntax to Moops, and provides many of the same features.

DESCRIPTION
    Moops is sugar for declaring and using roles and classes in Perl.

    The syntax is inspired by MooseX::Declare, and Stevan Little's
    p5-mop-redux project (which is in turn partly inspired by Perl 6).

    Moops has fewer than half of the dependencies as MooseX::Declare, loads in
    about 25% of the time, and the classes built with it run significantly
    faster. Moops does not use Devel::Declare, instead using Perl's pluggable
    keyword API; *this requires Perl 5.14 or above*.

    Moops uses Moo to build classes and roles by default, but allows you to
    use Moose if you desire. (And Mouse experimentally.)

  Classes
    The `class` keyword declares a class:

       class Foo {
          # ...
       }

    A version number can be provided:

       class Foo 1.2 {
          # ...
       }

    If no version is provided, your class' $VERSION variable is set to the
    empty string; this helps the package be seen by Class::Load.

    If your class extends an existing class through inheritance, or consumes
    one or more roles, these can also be provided when declaring the class.

       class Foo::Bar 1.2 extends Foo 1.1 with Magic::Monkeys {
          # ...
       }

    If you use Moops within a package other than `main`, then package names
    used within the declaration are "qualified" by that outer package, unless
    they contain "::". So for example:

       package Quux;
       use Moops;
   
       class Foo { }       # declares Quux::Foo
   
       class Xyzzy::Foo    # declares Xyzzy::Foo
          extends Foo { }  # ... extending Quux::Foo
   
       class ::Baz { }     # declares Baz

    If you wish to use Moose or Mouse instead of Moo; include that in the
    declaration:

       class Foo using Moose {
          # ...
       }

    It's also possible to create classes `using Tiny` (Class::Tiny), but
    there's probably little point in it, because Moops uses Moo internally, so
    the more capable Moo is already loaded and in memory.

    (The `using` option is exempt from the package qualification rules
    mentioned earlier.)

    Moops uses MooseX::MungeHas in your classes so that the `has` keyword
    supports some Moo-specific features, even when you're using Moose or
    Mouse. Specifically, it supports `is => 'rwp'`, `is => 'lazy'`, `builder
    => 1`, `clearer => 1`, `predicate => 1`, and `trigger => 1`. If you're
    using Moo, the MooX::late extension is enabled too, which allows
    Moose-isms in Moo too. With the combination of these features, there
    should be very little difference between Moo, Mouse and Moose `has`
    keywords.

    Moops uses Lexical::Accessor to provide you with private (lexical)
    attributes - that is, attributes accessed via a coderef method in a
    lexical variable.

       class Foo {
          lexical_has foo => (
             isa      => Int,
             accessor => \(my $_foo),
             default  => 0,
          );
          method increment_foo () {
             $self->$_foo( 1 + $self->$_foo );
          }
          method get_foo () {
             return $self->$_foo;
          }
       }
   
       my $x = Foo->new;
       $x->increment_foo();     # ok
       say $x->get_foo();       # says "1"
       $x->$_foo(42);           # dies; $_foo does not exist in this scope

    Moose classes are automatically accelerated using MooseX::XSAccessor if
    it's installed.

    Note that it is possible to declare a class with an empty body; use a
    trailing semicolon.

       class Employee extends Person with Employment;

    If using Moose or Mouse, classes are automatically made immutable.

    namespace::autoclean is automatically used in all classes.

    Between the class declaration and its body, Attribute::Handlers-style
    attributes may be provided:

       class Person :mutable {
          # ...
       }
   
       class Employee extends Person with Employment :mutable;

    The following attributes are defined for classes:

    *   `:assertions` - enables assertion checking (see below)

    *   `:dirty` - suppresses namespace::autoclean

    *   `:fp` - use Function::Parameters instead of Kavorka

    *   `:mutable` - suppresses making Moose classes immutable

    *   `:ro` - make attributes declared with `has` default to 'ro'

    *   `:rw` - make attributes declared with `has` default to 'rw'

    *   `:rwp` - make attributes declared with `has` default to 'rwp'

  Roles
    Roles can be declared similarly to classes, but using the `role` keyword.

       role Stringable
          using Moose     # we know you meant Moose::Role
       {
          # ...
       }

    Roles do not support the `extends` option.

    Roles can be declared to be `using` Moo, Moose, Mouse or Tiny. (Note that
    if you're mixing and matching role frameworks, there are limitations to
    which class builders can consume which roles. Mouse is generally the least
    compatible; Moo and Moose classes should be able to consume each others'
    roles; Moo can also consume Role::Tiny roles.)

    If roles use Moo, the MooX::late extension is enabled.

    namespace::autoclean is automatically used in all roles.

    Roles take similar Attribute::Handlers-style attributes to classes, but
    don't support `:mutable`.

   A note on consuming roles
    In a standard:

       class MyClass with MyRole {
          ...;
       }

    You should note that role composition is delayed to happen at the *end* of
    the class declaration. This is usually what you want.

    However the interaction between method modifiers and roles is complex, and
    *sometimes* you'll want the role to be applied to the class part-way
    through the declaration. In this case you can use a `with` statement
    *inside* the class declaration:

       class MyClass {
          ...;
          with "MyRole";
          ...;
       }

  Namespaces
    The `namespace` keyword works as above, but declares a package without any
    class-specific or role-specific semantics.

       namespace Utils {
          # ...
       }

    namespace::autoclean is not automatically used in namespaces.

    Attribute::Handlers-style attributes are supported for namespaces, but
    most of the built-in attributes make any sense without class/role
    semantics. (`:assertions` does.) Traits written as Moops extensions may
    support namespaces.

  Functions and Methods
    Moops uses Kavorka to declare functions and methods within classes and
    roles. Kavorka provides the `fun` and `method` keywords.

       class Person {
          use Scalar::Util 'refaddr';
      
          has name => (is => 'rwp');    # Moo attribute
      
          method change_name ( Str $newname ) {
             $self->_set_name( $newname )
                unless $newname eq 'Princess Consuela Banana-Hammock';
          }
      
          fun is_same_as ( Object $x, Object $y ) {
             refaddr($x) == refaddr($y)
          }
       }
   
       my $phoebe = Person->new(name => 'Phoebe');
       my $ursula = Person->new(name => 'Ursula');
   
       Person::is_same_as($phoebe, $ursula);   # false

    Note function signatures use type constraints from Types::Standard;
    MooseX::Types and MouseX::Types type constraints should also work,
    *provided you use their full names, including their package*.

    The `is_same_as` function above could have been written as a class method
    like this:

       class Person {
          # ...
          method is_same_as ( $class: Object $x, Object $y ) {
             refaddr($x) == refaddr($y)
          }
       }
   
       # ...
       Person->is_same_as($phoebe, $ursula);   # false

    The `method` keyword is not provided within packages declared using
    `namespace`; only within classes and roles.

    See also Kavorka::Manual::Methods and Kavorka::Manual::Functions.

    Within Moose classes and roles, the MooseX::KavorkaInfo module is loaded,
    to allow access to method signatures via the meta object protocol. (This
    is currently broken for `around` method modifiers.)

    In Moops prior to 0.025, Function::Parameters was used instead of Kavorka.
    If you wish to continue to use Function::Parameters in a class you can use
    the `:fp` attribute:

       class Person :fp {
          ...;
       }

    Or to do so for all classes in a lexical scope:

       use Moops function_parameters_everywhere => 1;
       class Person {
          ...;
       }

    Or the environment variable `MOOPS_FUNCTION_PARAMETERS_EVERYWHERE` can be
    set to true to enable it globally, but this feature is likely to be
    removed eventually.

  Method Modifiers
    Within classes and roles, `before`, `after` and `around` keywords are
    provided for declaring method modifiers. These use the same syntax as
    `method`.

    If your class or role is using Moose or Mouse, then you also get `augment`
    and `override` keywords.

    See also Kavorka::Manual::MethodModifiers.

  Multi Methods
    Moops uses Kavorka to implement multi subs and multi methods.

    See also Kavorka::Manual::MultiSubs.

  Type Constraints
    The Types::Standard type constraints are exported to each package declared
    using Moops. This allows the standard type constraints to be used as
    barewords.

    Type constraints can be used in attribute definitions (`isa`) and method
    signatures. Because Types::Standard is based on Type::Tiny, the same type
    constraints may be used whether you build your classes and roles with Moo,
    Moose our Mouse.

    Alternative libraries can be imported using the `types` option; a la:

       class Document types Types::XSD::Lite {
          has title => (is => 'rw', isa => NormalizedString);
       }

    Note that if an alternative type constraint library is imported, then
    Types::Standard is *not* automatically loaded, and needs to be listed
    explicitly:

       class Document types Types::Standard, Types::XSD::Lite {
          # ...
       }

    Type libraries built with Type::Library, MooseX::Types and MouseX::Types
    should all work.

    Bear in mind that type constraints from, say, a MooseX::Types library
    won't be usable in, say, Moo attribute definitions. However, it's possible
    to wrap them with Type::Tiny, and make them usable:

       class Foo types MooseX::Types::Common::Numeric using Moo {
          use Types::TypeTiny qw( to_TypeTiny );
      
          has favourite_number => (
             is  => 'rwp',
             isa => to_TypeTiny(PositiveInt)
          );
       }

  Type Libraries
    You can use the `library` keyword to declare a new type library:

       library MyTypes
          extends Types::Standard
          declares EmptyString, NonEmptyString {
      
          declare EmptyString,
             as Str,
             where { length($_) == 0 };
      
          declare NonEmptyString,
             as Str,
             where { length($_) > 0 };
       }
   
       class StringChecker types MyTypes {
          method check ( Str $foo ) {
             return "empty" if EmptyString->check($foo);
             return "non-empty" if NonEmptyString->check($foo);
             return "impossible?!";
          }
       }

    Libraries declared this way can extend existing type libraries written
    with Type::Library, MooseX::Types or MouseX::Types.

    Note that this also provides a solution to the previously mentioned
    problem of using MooseX::Types type libraries in Moo classes:

       library MyWrapper
          extends MooseX::Types::Common::Numeric;
   
       class Foo types MyWrapper using Moo {
          has favourite_number => (
             is  => 'rwp',
             isa => PositiveInt,
          );
       }

  Constants
    The useful constants `true` and `false` are imported into all declared
    packages. (Within classes and roles, namespace::autoclean will later
    remove them from the symbol table, so they don't form part of your
    package's API.) These constants can help make attribute declarations more
    readable.

       has name => (is => 'ro', isa => Str, required => true);

    Further constants can be declared using the `define` keyword (see
    PerlX::Define):

       namespace Maths {
          define PI = 3.2;
       }

    Constants declared this way will *not* be swept away by
    namespace::autoclean, and are considered part of your package's API.

  Assertions
    Declared packages can contain assertions (see PerlX::Assert). These are
    normally optimized away at compile time, but you can force them to be
    checked using the `:assertions` attribute.

       class Foo {
          assert(false);    # not checked; optimized away
       }
   
       class Bar :assertions {
          assert(false);    # checked; fails; throws exception
       }

  More Sugar
    strict and FATAL warnings are imported into all declared packages. However
    the `uninitialized`, `void`, `once` and `numeric` warning categories are
    explicitly excluded, as are any warnings categories added to Perl after
    version 5.14.

    Perl 5.14 features, including the `state` and `say` keywords, and sane
    Unicode string handling are imported into all declared packages.

    Try::Tiny is imported into all declared packages.

    Scalar::Util's `blessed` and Carp's `confess` are imported into all
    declared packages.

  Outer Sugar
    The "outer" package, where the `use Moops` statement appears also gets a
    little sugar: strict, the same warnings as "inner" packages, and Perl 5.14
    features are all switched on.

    true is loaded, so you don't need to do this at the end of your file:

       1;

  Custom Sugar
    It is possible to inject other functions into all inner packages using:

       use Moops imports => [
          'List::Util'      => [qw( first reduce )],
          'List::MoreUtils' => [qw( any all none )],
       ];

    This is by far the easiest way to extend Moops with project-specific
    extras.

    There is a shortcut for injecting strictures into all inner packages:

       use Moops -strict;

EXTENDING
    Moops is written to hopefully be fairly extensible.

  Extending Moops via imports
    The easiest way to extend Moops is to inject additional imports into the
    inner packages using the technique outlined in "Custom Sugar" above. You
    can wrap all that up in a module:

       package MoopsX::Lists;
       use base 'Moops';
       use List::Util ();
       use List::MoreUtils ();
   
       sub import {
          my ($class, %opts) = @_;
      
          push @{ $opts{imports} ||= [] }, (
             'List::Util'      => [qw( first reduce )],
             'List::MoreUtils' => [qw( any all none )],
          );
      
          $class->SUPER::import(%opts);
       }
   
       1;

    Now people can do `use MoopsX::Lists` instead of `use Moops`.

  Extending Moops via keyword traits
    Roles in the `Moops::TraitFor::Keyword` namespace are automatically loaded
    and applied to keyword objects when a corresponding
    Attribute::Handlers-style attribute is seen.

    For examples extending Moops this way, see the
    Moops::TraitFor::Keyword::dirty, Moops::TraitFor::Keyword::mutable,
    Moops::TraitFor::Keyword::ro, Moops::TraitFor::Keyword::rw and
    Moops::TraitFor::Keyword::rwp traits.

  Extending Moops via parser traits
    For more complex needs, you can create a trait which will be applied to
    Moops::Parser.

    Parser traits might want to override:

    *   The `keywords` class method, which returns the list of keywords the
        parser can handle.

    *   The `class_for_keyword` object method, which returns the name of a
        subclass of Moops::Keyword which will be used for translating the
        result of parsing the keyword into a string using Perl's built-in
        syntax.

    Hopefully you'll be able to avoid overriding the `parse` method itself, as
    it has a slightly messy API.

    Your `class_for_keyword` subclass can either be a direct subclass of
    Moops::Keyword, or of Moops::Keyword::Class or Moops::Keyword::Role.

    The keyword subclass might want to override:

    *   The `known_relationships` class method, which returns a list of valid
        inter-package relationships such as `extends` and `using` for the
        current keyword.

    *   The `qualify_relationship` class method, which, when given the name of
        an inter-package relationship, indicates whether it should be
        subjected to package qualification rules (like `extends` and `with`
        are, but `using` is not).

    *   The `version_relationship` class method, which, when given the name of
        an inter-package relationship, indicates whether it should accept a
        version number.

    *   The `generate_package_setup` object method which returns a list of
        strings to inject into the package.

    *   The `arguments_for_function_parameters` object method which is used by
        the default `generate_package_setup` method to set up the arguments to
        be passed to Function::Parameters.

    *   The `check_prerequisites` method which performs certain pre-flight
        checks and may throw an exception.

    Hopefully you'll be able to avoid overriding the `generate_code` method.

    You can apply your trait using:

       use Moops traits => [
          'Moops::TraitFor::Parser::FooKeyword',
          'Moops::TraitFor::Parser::BarKeyword',
       ];

BUGS
    If seeing test failures on threaded Perl 5.21+, it may be a bug in
    Devel::CallParser 0.002. Try installing
    Alt::Devel::CallParser::ButWorking.

    Please report any other bugs to
    <http://rt.cpan.org/Dist/Display.html?Queue=Moops>.

GOTCHAS
    Certain software (like the CPAN indexer!) greps Perl source code looking
    for `package` statements to determine which packages a module provides.
    Moops uses `class` and `role` keywords to declare packages, so it may be
    necessary to provide some dummy `package` statements at the end of your
    module if you need to support such software.

SUPPORT
    IRC: support is available through in the *#moops* channel on irc.perl.org
    <http://www.irc.perl.org/channels.html>.

    For general Moose/Moo queries which don't seem to be related to Moops'
    syntactic sugar, your question may be answered more quickly in the
    *#moose* channel.

    Web: if you ask a question on PerlMonks in Seekers of Perl Wisdom
    <http://www.perlmonks.org/?node_id=479> with "Moops" in the subject line,
    it should be answered pretty quickly.

    There is a moops tag <http://stackoverflow.com/questions/tagged/moops> on
    StackOverflow.

SEE ALSO
    Similar: MooseX::Declare, <https://github.com/stevan/p5-mop-redux>.

    Main functionality exposed by this module: Moo/MooX::late, Kavorka,
    Try::Tiny, Types::Standard, namespace::autoclean, true, PerlX::Assert.

    Internals fueled by: Keyword::Simple, Module::Runtime, Import::Into,
    Attribute::Handlers.

    <http://en.wikipedia.org/wiki/The_Bubble_Boy_(Seinfeld)>.

AUTHOR
    Toby Inkster <tobyink@cpan.org>.

COPYRIGHT AND LICENCE
    This software is copyright (c) 2013-2014 by Toby Inkster.

    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.