This file is indexed.

/usr/share/perl5/Aspect.pm is in libaspect-perl 1.04-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

   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
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
package Aspect;

=pod

=head1 NAME

Aspect - Aspect-Oriented Programming (AOP) for Perl

=head1 SYNOPSIS

  use Aspect;
  
  # Run some code "Advice" before a particular function
  before {
      print "About to call create\n";
  } call 'Person::create';
  
  # Run Advice after several methods and hijack their return values
  after {
      print "Called getter/setter " . $_->sub_name . "\n";
      $_->return_value(undef);
  } call qr/^Person::[gs]et_/;
  
  # Run Advice conditionally based on multiple factors
  before {
      print "Calling a get method in void context within Tester::run_tests";
  } wantvoid
  & ( call qr/^Person::get_/ & ! call 'Person::get_not_trapped' )
  & cflow 'Tester::run_tests';
  
  # Context-aware runtime hijacking of a method if certain condition is true
  around {
      if ( $_->self->customer_name eq 'Adam Kennedy' ) {
          # Ensure I always have cash
          $_->return_value('One meeeelion dollars');
      } else {
          # Take a dollar off everyone else
          $_->proceed;
          $_->return_value( $_->return_value - 1 );
      }
  } call 'Bank::Account::balance';
  
  # Catch and handle unexpected exceptions in a function into a formal object
  after {
      $_->exception(
          Exception::Unexpected->new($_->exception)
      );
  } throwing()
  & ! throwing('Exception::Expected')
  & ! throwing('Exception::Unexpected');
  
  # Run Advice only on the outmost of a recursive series of calls
  around {
    print "Starting recursive child search\n";
    $_->proceed;
    print "Finished recursive child search\n";
  } call 'Person::find_child' & highest;
  
  # Run Advice only during the current lexical scope
  SCOPE: {
      my $hook = before {
          print "About to call create\n";
      } call 'Person::create';
      Person->create('Bob'); # Advice will run
  }
  Person->create('Tom'); # Advice won't run
  
  # Use a pre-packaged collection "Aspect" of Advice rules to change a class
  aspect Singleton => 'Foo::new';
  
  # Define debugger breakpoints with high precision and conditionality
  aspect Breakpoint => call qr/^Foo::.+::Bar::when_/ & wantscalar & highest;

=head1 DESCRIPTION

=head2 What is Aspect-Oriented Programming?

Aspect-Oriented Programming (AOP) is a programming paradigm which aims to
increase modularity by allowing the separation of "cross-cutting "concerns.

It includes programming methods and tools that support the modularization of
concerns at the level of the source code, while "aspect-oriented software
development" refers to a whole engineering discipline.

Aspect-Oriented Programming (AOP) allows you to modularise code for issues that
would otherwise be spread across many parts of a program and be problematic to
both implement and maintain.

Logging exemplifies a crosscutting concern because a logging strategy
necessarily affects every logged part of the system. Logging thereby "crosscuts"
all logged classes and methods.

Typically, an aspect is scattered or tangled as code, making it harder to
understand and maintain. It is scattered by virtue of the function (such as
logging) being spread over a number of unrelated functions that might use its
function, possibly in entirely unrelated systems

That means to change logging can require modifying all affected modules. Aspects
become tangled not only with the mainline function of the systems in which they
are expressed but also with each other. That means changing one concern entails
understanding all the tangled concerns or having some means by which the effect
of changes can be inferred.

Because Aspect-Oritented Programming moves this scattered code into a single
module which is loaded as a single unit, another major benefit of this method
is conditional compilation.

Features implemented via Aspects can be compiled and added to you program only
in certain situations, and because of this Aspects are useful when debugging
or testing large or complex programs.

Aspects can implement features necessary for correctness of programs such as
reactivity or synchronisation, and can be used to add checking assertions
to your or other people's modules.

They can cause code to emit useful side effects not considered by the original
author of a module, without changing the original function of the module.

And, if necessary (although not recommended), they can do various types of
"Monkey Patching", hijacking the functionality of some other module in an
unexpected (by the original author) way so that the module acts differently
when used in your program, when those changes might otherwise be dangerous or
if encountered by other programs.

Aspects can be used to implement space or time optimisations. One popular use
case of AOP is to add caching to a module or function that does not natively
implement caching itself.

For more details on Aspect-Oriented Programming in general,
L<http://en.wikipedia.org/wiki/Aspect-oriented_programming> and
L<http://www.aosd.net>.

=head2 About This Implementation

The Perl B<Aspect> module tries to closely follow the terminology of the basic
Java AspectJ project wherever possible and reasonable
(L<http://eclipse.org/aspectj>).

However due to the dynamic nature of the Perl language, several C<AspectJ>
features are useless for us: exception softening, mixin support, out-of-class
method declarations, annotations, and others.

Currently the Perl B<Aspect> module is focused exclusively on subroutine
matching and wrapping.

It allows you to select collections of subroutines and conditions using a
flexible pointcut language, and modify their behavior in any way you want.

In this regard it provides a similar set of functionality to the venerable
L<Hook::LexWrap>, but with much more precision and with much more control and
maintainability as the complexity of the problems you are solving increases.

In addition, where the Java implementation of Aspect-Oriented Programming is
limited to concepts expressable at compile time, the more fluid nature of Perl
means that the B<Aspect> module can weave in aspect code at run-time. Pointcuts
in Perl can also take advantage of run-time information and Perl-specific
features like closures to implement more sophisticated pointcuts than are
possible in Java.

This allows the Perl implementation of Aspect-Oriented Programming to be
stateful and adaptive in a way that Java cannot (although the added power can
come with a significant speed cost if not used carefully).

=head2 Terminology

One of the more opaque aspects (no pun intended) of Aspect-Oriented programming
is that it has an entire unique set of terms that can be confusing for people
learning to use the B<Aspect> module.

In this section, we will attempt to define all the major terms in a way that
will hopefully make sense to Perl programmers.

=head3 What is an Aspect?

An I<Aspect> is a modular unit of cross-cutting implementation, consisting of
"Advice" on "Pointcuts" (we'll define those two shortly, don't worry if they
don't make sense for now).

In Perl, this would typically mean a package or module containing declarations
of where to inject code, the code to run at these points, and any variables or
support functions needed by the injected functionality.

The most critical point here is that the Aspect represents a collection of
many different injection points which collectively implement a single function
or feature and which should be enabled on an all or nothing basis.

For example, you might implement the Aspect B<My::SecurityMonitor> as a module
which will inject hooks into a dozen different strategic places in your
program to watch for valid-but-suspicious values and report these values to
an external network server.

Aspects can often written to be highly reusable, and be released via the CPAN.
When these generic aspects are written in the special namespace
L<Aspect::Library> they can be called using the following special shorthand.

  use Aspect;
  
  # Load and enable the Aspect::Library::NYTProf aspect to constrain profiling
  # to only the object constructors for each class in your program.
  aspect NYTProf => call qr/^MyProgram\b.*::new$/;

=head3 What is a Pointcut?

A I<Join Point> is a well-defined location at a point in the execution of a
program at which Perl can inject functionality, in effect joining two different
bits of code together.

In the Perl B<Aspect> implementation, this consists only of the execution of
named subroutines on the symbol table such as C<Foo::Bar::function_name>.

In other languages, additional join points can exist such as the instantiation
or destruction of an object or the static initialisation of a class.

A I<Pointcut> is a well-defined set of join points, and any conditions that
must be true when at these join points.

Example include "All public methods in class C<Foo::Bar>" or "Any non-recursive
call to the function C<Some::recursive_search>".

We will discuss each of the available pointcut types later in this document.

In addition to the default pointcut types it is possible to write your own
specialised pointcut types, although this is challenging due to the complex
API they follow to allow aggressive multi-pass optimisation.

See L<Aspect::Pointcut> for more information.

=head3 What is Advice?

I<Advice> is code designed to run automatically at all of the join points in
a particular pointcut. Advice comes in several types, instructing that the
code be run C<before>, C<after> or C<around> (in place of) the different join
points in the pointcut.

Advice code is introduced lexically to the target join points. That is, the
new functionality is injected in place to the existing program rather the
class being extended into some new version.

For example, function C<Foo::expensive_calculation> may not support caching
because it is unsafe to do so in the general case. But you know that in the
case of your program, the reasons it is unsafe in the general case don't apply.

So for your program you might use the L<Aspect::Library::Memoise> aspect to
"Weave" Advice code into the C<Foo> class which adds caching to the function
by integrating it with L<Memoise>.

Each of the different advice types needs to be used slightly differently, and
are best employed for different types of jobs. We will discuss the use of each
of the different advice types later in this document.

But in general, the more specific advice type you use, the more optimisation
can be applied to your advice declaration, and the less impact the advice will
have on the speed of your program.

In addition to the default pointcut types, it is (theoretically) possible to
write your own specialised Advice types, although this would be extremely
difficult and probably involve some form of XS programming.

For the brave, see L<Aspect::Advice> and the source for the different advice
classes for more information.

=head3 What is Weaving?

I<Weaving> is the installation of advice code to the subs that match a pointcut,
or might potentially match depending on certain run-time conditions.

In the Perl B<Aspect> module, weaving happens on the declaration of each
advice block. Unweaving happens when a lexically-created advice variable goes
out of scope.

Unfortunately, due to the nature of the mechanism B<Aspect> uses to hook into
function calls, unweaving can never be guarenteed to be round-trip clean.

While the pointcut matching logic and advice code will never be run for unwoven
advice, it may be necessary to leave the underlying hooking artifact in place on
the join point indefinitely (imposing a small performance penalty and preventing
clean up of the relevant advice closure from memory).

Programs that repeatedly weave and unweave during execution will thus gradually
slow down and leak memory, and so is discouraged despite being permitted.

If advice needs to be repeatedly enabled and disabled you should instead
consider using the C<true> pointcut and a variable in the aspect package or
a closure to introduce a remote "on/off" switch for the aspect.

into the advice code.

  package My::Aspect;
  
  my $switch = 1;
  
  before {
      print "Calling Foo::bar\n";
  } call 'Foo::bar' & true { $switch };
  
  sub enable {
      $switch = 1;
  }
  
  sub disable {
      $switch = 0;
  }
  
  1;

Under the covers weaving is done using a mechanism that is very similar to
the venerable L<Hook::LexWrap>, although in some areas B<Aspect> will try to
make use of faster mechanisms if it knows these are safe.

=head2 Feature Summary

=over

=item *

Create permanent pointcuts, advice, and aspects at compile time or run-time.

=item *

Flexible pointcut language: select subs to match using string equality,
regexp, or C<CODE> ref. Match currently running sub, a sub in the call
flow, calls in particular void, scalar, or array contexts, or only the highest
call in a set of recursive calls.

=item *

Build pointcuts composed of a logical expression of other pointcuts,
using conjunction, disjunction, and negation.

=item *

In advice code, you can modify parameter list for matched sub, modify return
value, throw or supress exceptions, decide whether or not to proceed to matched
sub, access a C<CODE> ref for matched sub, and access the context of any call
flow pointcuts that were matched, if they exist.

=item *

Add/remove advice and entire aspects lexically during run-time. The scope of
advice and aspect objects, is the scope of their effect (This does, however,
come with some caveats).

=item *

A basic library of reusable aspects. A base class makes it easy to create your
own reusable aspects. The L<Aspect::Library::Memoize> aspect is an
example of how to interface with AOP-like modules from CPAN.

=back

=head2 Using Aspect.pm

The B<Aspect> package allows you to create pointcuts, advice, and aspects in a
simple declarative fashion. This declarative form is a simple facade on top of
the Perl AOP framework, which you can also use directly if you need the
increased level of control or you feel the declarative form is not clear enough.

For example, the following two examples are equivalent.

  use Aspect;
  
  # Declarative advice creation
  before {
      print "Calling " . $_->sub_name . "\n";
  } call 'Function::one'
  | call 'Function::two';
  
  # Longhand advice creation
  Aspect::Advice::Before->new(
      Aspect::Pointcut::Or->new(
          Aspect::Pointcut::Call->new('Function::one'),
          Aspect::Pointcut::Call->new('Function::two'),
      ),
      sub {
          print "Calling " . $_->sub_name . "\n";
      },
  );

You will be mostly working with this package (B<Aspect>) and the
L<Aspect::Point> package, which provides the methods for getting information
about the call to the join point within advice code.

When you C<use Aspect;> you will import a family of around fifteen
functions. These are all factories that allow you to create pointcuts,
advice, and aspects.

=head2 Back Compatibility

The various APIs in B<Aspect> have changed a few times between older versions
and the current implementation.

By default, none of these changes are available in the current version of the
B<Aspect> module. They can, however, be accessed by providing one of two flags
when loading B<Aspect>.

  # Support for pre-1.00 Aspect usage
  use Aspect ':deprecated';

The C<:deprecated> flag loads in all alternative and deprecated function and
method names, and exports the deprecated C<after_returning>, C<after_throwing>
advice constructors, and the deprecated C<if_true> alias for the C<true>
pointcut.

  # Support for pre-2010 Aspect usage (both usages are equivalent)
  use Aspect ':legacy';
  use Aspect::Legacy;

The C<:legacy> flag loads in all alternative and deprecated functions as per
the C<:deprecated> flag.

Instead of exporting all available functions and pointcut declarators it exports
C<only> the set of functions that were available in B<Aspect> 0.12.

Finally, it changes the behaviour of the exported version of C<after> to add an
implicit C<& returning> to all pointcuts, as the original implementation did not
trap exceptions.

=head1 FUNCTIONS

The following functions are exported by default (and are documented as such)
but are also available directly in Aspect:: namespace as well if needed.

They are documented in order from the simplest and and most common pointcut
declarator to the highest level declarator for enabling complete aspect classes.

=cut

use 5.008002;
use strict;

# Added by eilara as hack around caller() core dump
# NOTE: Now we've switched to Sub::Uplevel can this be removed?
# -- ADAMK
use Carp::Heavy                 ();
use Carp                        ();
use Params::Util           1.00 ();
use Sub::Install           0.92 ();
use Sub::Uplevel         0.2002 ();
use Aspect::Pointcut            ();
use Aspect::Pointcut::Or        ();
use Aspect::Pointcut::And       ();
use Aspect::Pointcut::Not       ();
use Aspect::Pointcut::True      ();
use Aspect::Pointcut::Call      ();
use Aspect::Pointcut::Cflow     ();
use Aspect::Pointcut::Highest   ();
use Aspect::Pointcut::Throwing  ();
use Aspect::Pointcut::Returning ();
use Aspect::Pointcut::Wantarray ();
use Aspect::Advice              ();
use Aspect::Advice::After       ();
use Aspect::Advice::Around      ();
use Aspect::Advice::Before      ();
use Aspect::Point               ();
use Aspect::Point::Static       ();

our $VERSION = '1.04';
our %FLAGS   = ();

# Track the location of exported functions so that pointcuts
# can avoid accidentally binding them.
our %EXPORTED = ();

sub install {
	Sub::Install::install_sub( {
		into => $_[1],
		code => $_[2],
		as   => $_[3] || $_[2],
	} );
	$EXPORTED{"$_[1]::$_[2]"} = 1;
}

sub import {
	my $class  = shift;
	my $into   = caller();
	my %flag   = ();
	my @export = ();

	# Handle import params
	while ( @_ ) {
		my $value = shift;
		if ( $value =~ /^:(\w+)$/ ) {
			$flag{$1} = 1;
		} else {
			push @export, $_;
		}
	}

	# Legacy API and deprecation support
	if ( $flag{legacy} or $flag{deprecated} ) {
		require Aspect::Legacy;
		if ( $flag{legacy} ) {
			return Aspect::Legacy->import;
		}
	}

	# Custom method export list
	if ( @export ) {
		$class->install( $into => $_ ) foreach @export;
		return 1;
	}

	# Install the modern API
	$class->install( $into => $_ ) foreach qw{
		aspect
		before
		after
		around
		call
		cflow
		throwing
		returning
		wantlist
		wantscalar
		wantvoid
		highest
		true
	};

	# Install deprecated API elements
	if ( $flag{deprecated} ) {
		$class->install( $into => $_ ) foreach qw{
			after_returning
			after_throwing
			if_true
		};
	}

	return 1;
}





######################################################################
# Public (Exported) Functions

=pod

=head2 call

  my $single   = call 'Person::get_address';
  my $multiple = call qr/^Person::get_/;
  my $complex  = call sub { lc($_[0]) eq 'person::get_address' };
  my $object   = Aspect::Pointcut::Call->new('Person::get_address');

The most common pointcut is C<call>. All three of the examples will match the
calling of C<Person::get_address()> as defined in the symbol table at the
time an advice is declared.

The C<call> declarator takes a single parameter which is the pointcut spec,
and can be provided in three different forms.

B<string>

Select only the specific full resolved subroutine whose name is equal to the
specification string. 

For example C<call 'Person::get'> will only match the plain C<get> method
and will not match the longer C<get_address> method.

B<regexp>

Select all subroutines whose name matches the regular expression.

The following will match all the subs defined on the C<Person> class, but not
on the C<Person::Address> or any other child classes.

  $p = call qr/^Person::\w+$/;

B<CODE>

Select all subroutines where the supplied code returns true when passed a
full resolved subroutine name as the only parameter.

The following will match all calls to subroutines whose names are a key in the
hash C<%subs_to_match>:

  $p = call sub {
      exists $subs_to_match{$_[0]};
  }

For more information on the C<call> pointcut see L<Aspect::Pointcut::Call>.

=cut

sub call ($) {
	Aspect::Pointcut::Call->new(@_);
}

=pod

=head2 cflow

  before {
     print "Called My::foo somewhere within My::bar\n";
  } call 'My::foo'
  & cflow 'My::bar';

The C<cflow> declarator is used to specify that the join point must be somewhere
within the control flow of the C<My::bar> function. That is, at the time
C<My::foo> is being called somewhere up the call stack is C<My::bar>.

The parameters to C<cflow> are identical to the parameters to C<call>.

Due to an idiosyncracy in the way C<cflow> is implemented, they do not always
parse properly well when joined with an operator. In general, you should use
any C<cflow> operator last in your pointcut specification, or use explicit
braces for it.

  # This works fine
  my $x = call 'My::foo' & cflow 'My::bar';
  
  # This will error
  my $y = cflow 'My::bar' & call 'My::foo';
  
  # Use explicit braces if you can't have the flow last
  my $z = cflow('My::bar') & call 'My::foo';

For more information on the C<cflow> pointcut, see L<Aspect::Pointcut::Cflow>.

=cut

sub cflow ($;$) {
	Aspect::Pointcut::Cflow->new(@_);
}

=pod

=head2 wantlist

  my $pointcut = call 'Foo::bar' & wantlist;

The C<wantlist> pointcut traps a condition based on Perl C<wantarray> context,
when a function is called in list context. When used with C<call>, this
pointcut can be used to trap list-context calls to one or more functions, while
letting void or scalar context calls continue as normal.

For more information on the C<wantlist> pointcut see
L<Aspect::Pointcut::Wantarray>.

=cut

sub wantlist () {
	Aspect::Pointcut::Wantarray->new(1);
}

=pod

=head2 wantscalar

  my $pointcut = call 'Foo::bar' & wantscalar;

The C<wantscalar> pointcut traps a condition based on Perl C<wantarray> context,
when a function is called in scalar context. When used with C<call>, this
pointcut can be used to trap scalar-context calls to one or more functions,
while letting void or list context calls continue as normal.

For more information on the C<wantscalar> pointcut see
L<Aspect::Pointcut::Wantarray>.

=cut

sub wantscalar () {
	Aspect::Pointcut::Wantarray->new('');
}

=pod

=head2 wantvoid

  my $bug = call 'Foo::get_value' & wantvoid;

The C<wantvoid> pointcut traps a condition based on Perl C<wantarray> context,
when a function is called in void context. When used with C<call>, this pointcut
can be used to trap void-context calls to one or more functions, while letting
scalar or list context calls continue as normal.

This is particularly useful for methods which make no sense to call in void
context, such as getters or other methods calculating and returning a useful
result.

For more information on the C<wantvoid> pointcut see
L<Aspect::Pointcut::Wantarray>.

=cut

sub wantvoid () {
	Aspect::Pointcut::Wantarray->new(undef);
}

=pod

=head2 highest

  my $entry = call 'Foo::recurse' & highest;

The C<highest> pointcut is used to trap the first time a particular function
is encountered, while ignoring any subsequent recursive calls into the same
pointcut.

It is unusual in that unlike all other types of pointcuts it is stateful, and
so some detailed explaination is needed to understand how it will behave.

Pointcut declarators follow normal Perl precedence and shortcutting in the same
way that a typical set of C<foo() and bar()> might do for regular code.

When the C<highest> is evaluated for the first time it returns true and a
counter is to track the depth of the call stack. This counter is bound to the
join point itself, and will decrement back again once we exit the advice code.

If we encounter another function that is potentially contained in the same
pointcut, then C<highest> will always return false.

In this manner, you can trigger functionality to run only at the outermost
call into a recursive series of functions, or you can negate the pointcut 
with C<! highest> and look for recursive calls into a function when there
shouldn't be any recursion.

In the current implementation, the semantics and behaviour of pointcuts
containing multiple highest declarators is not defined (and the current
implementation is also not amenable to supporting it).

For these reasons, the usage of multiple highest declarators such as in the
following example is not support, and so the following will throw an exception.

  before {
      print "This advice will not compile\n";
  } wantscalar & (
      (call 'My::foo' & highest)
      |
      (call 'My::bar' & highest)
  );

This limitation may change in future releases. Feedback welcome.

For more information on the C<highest> pointcut see
L<Aspect::Pointcut::Highest>.

=cut

sub highest () {
	Aspect::Pointcut::Highest->new;
}

=pod

=head2 throwing

  my $string = throwing qr/does not exist/;
  my $object = throwing 'Exception::Class';

The C<throwing> pointcut is used with the C<after> to restrict the pointcut so
advice code is only fired for a specific die message or a particular exception
class (or subclass).

The C<throwing> declarator takes a single parameter which is the pointcut spec,
and can be provided in two different forms.

B<regexp>

If a regular expression is passed to C<throwing> it will be matched against
the exception if and only if the exception is a plain string.

Thus, the regexp form can be used to trap unstructured errors emitted by C<die>
or C<croak> while B<NOT> trapping any formal exception objects of any kind.

B<string>

If a string is passed to C<throwing> it will be treated as a class name and
will be matched against the exception via an C<isa> method call if and only
if the exception is an object.

Thus, the string form can be used to trap and handle specific types of
exceptions while allowing other types of exceptions or raw string errors to
pass through.

For more information on the C<throwing> pointcut see
L<Aspect::Pointcut::Throwing>.

=cut

sub throwing (;$) {
	Aspect::Pointcut::Throwing->new(@_);
}

=pod

=head2 returning

  after {
      print "No exception\n";
  } call 'Foo::bar' & returning;

The C<returning> pointcut is used with C<after> advice types to indicate the
join point should only occur when a function is returning B<without> throwing
an exception.

=cut

sub returning () {
	Aspect::Pointcut::Returning->new;
}

=pod

=head2 true

  # Intercept an adjustable random percentage of calls to a function
  our $RATE = 0.01;
  
  before {
      print "The few, the brave, the 1%\n";
  } call 'My::foo'
  & true {
      rand() < $RATE
  };

Because of the lengths that B<Aspect> goes to internally to optimise the
selection and interception of calls, writing your own custom pointcuts can
be very difficult.

When a custom or unusual pattern of interception is needed, often all that is
desired is to extend a relatively normal pointcut with an extra caveat.

To allow for this scenario, B<Aspect> provides the C<true> pointcut.

This pointcut allows you to specify any arbitrary code to match on. This code
will be executed at run-time if the join point matches all previous conditions.

The join point matches if the function or closure returns true, and does not
match if the code returns false or nothing at all.

=cut

sub true (&) {
	Aspect::Pointcut::True->new(@_);
}

=pod

=head2 before

  before {
      # Don't call the function, return instead
      $_->return_value(1);
  } call 'My::foo';

The B<before> advice declaration is used to defined advice code that will be
run instead of the code originally at the join points, but continuing on to the
real function if no action is taken to say otherwise.

When called in void context, as shown above, C<before> will install the advice
permanently into your program.

When called in scalar context, as shown below, C<before> will return a guard
object and enable the advice for as long as that guard object continues to
remain in scope or otherwise avoid being destroyed.

  SCOPE: {
      my $guard = before {
          print "Hello World!\n";
      } call 'My::foo';
  
      # This will print
      My::foo(); 
  }
  
  # This will NOT print
  My::foo();

Because the end result of the code at the join points is irrelevant to this
type of advice and the Aspect system does not need to hang around and maintain
control during the join point, the underlying implementation is done in a way
that is by far the fastest and with the least impact (essentially none) on the
execution of your program.

You are B<strongly> encouraged to use C<before> advice wherever possible for the
current implementation, resorting to the other advice types when you truly need
to be there are the end of the join point execution (or on both sides of it).

For more information, see L<Aspect::Advice::Before>.

=cut

sub before (&$) {
	Aspect::Advice::Before->new(
		lexical  => defined wantarray,
		code     => $_[0],
		pointcut => $_[1],
	);
}

=pod

=head2 after

  # Confuse a program by bizarely swapping return values and exceptions
  after {
      if ( $_->exception ) {
          $_->return_value($_->exception);
      } else {
          $_->exception($_->return_value);
      }
  } call 'My::foo' & wantscalar;

The C<after> declarator is used to create advice in which the advice code will
be run after the join point has run, regardless of whether the function return
correctly or throws an exception.

For more information, see L<Aspect::Advice::After>.

=cut

sub after (&$) {
	Aspect::Advice::After->new(
		lexical  => defined wantarray,
		code     => $_[0],
		pointcut => $_[1],
	);
}

=pod

=head2 around

  # Trace execution time for a function
  around {
      my @start   = Time::HiRes::gettimeofday();
      $_->proceed;
      my @stop    = Time::HiRes::gettimeofday();
      my $elapsed = Time::HiRes::tv_interval( \@start, \@stop );
      print "My::foo executed in $elapsed seconds\n";
  } call 'My::foo';

The C<around> declarator is used to create the most general form of advice,
and can be used to implement the most high level functionality.

It allows you to make changes to the calling parameters, to change the result
of the function, to subvert or prevent the calling altogether, and to do so
while storing extra lexical state of your own across the join point.

For example, the code shown above tracks the time at which a single function
is called and returned, and then uses the two pieces of information to track
the execution time of the call.

Similar functionality to the above is used to implement the CPAN modules
L<Aspect::Library::Timer> and the more complex L<Aspect::Library::ZoneTimer>.

Within the C<around> advice code, the C<$_-E<gt>proceed> method is used to call
the original function with whatever the current parameter context is, storing
the result (whether return values or an exception) in the context as well.

Alternatively, you can use the C<original> method to get access to a reference
to the original function and call it directly without using context
parameters and without storing the function results.

  around {
      $_->original->('alternative param');
      $_->return_value('fake result');
  } call 'My::foo';

The above example calls the original function directly with an alternative
parameter in void context (regardless of the original C<wantarray> context)
ignoring any return values. It then sets an entirely made up return value of
it's own.

Although it is the most powerful advice type, C<around> is also the slowest
advice type with the highest memory cost per join point. Where possible, you
should try to use a more specific advice type.

For more information, see L<Aspect::Advice::Around>.

=cut

sub around (&$) {
	Aspect::Advice::Around->new(
		lexical  => defined wantarray,
		code     => $_[0],
		pointcut => $_[1],
	);
}

=pod

=head2 aspect

  aspect Singleton => 'Foo::new';

The C<aspect> declarator is used to enable complete reusable aspects.

The first parameter to C<aspect> identifies the aspect library class. If the
parameter is a fully resolved class name (i.e. it contains double colons like
Foo::Bar) the value it will be used directly. If it is a simple C<Identifier>
without colons then it will be interpreted as C<Aspect::Library::Identifier>.

If the aspect class is not loaded, it will be loaded for you and validated as
being a subclass of C<Aspect::Library>.

And further parameters will be passed on to the constructor for that class. See
the documentation for each class for more information on the appropriate
parameters for that class.

As with each individual advice type complete aspects can be defined globally
by using C<aspect> in void context, or lexically via a guard object by calling
C<aspect> in scalar context.

  # Break on the topmost call to function for a limited time
  SCOPE: {
      my $break = aspect Breakpoint => call 'My::foo' & highest;
      
      do_something();
  }

For more information on writing reusable aspects, see L<Aspect::Library>.

=cut

sub aspect {
	my $class = _LIBRARY(shift);
	return $class->new(
		lexical => defined wantarray,
		args    => [ @_ ],
	);
}





######################################################################
# Private Functions

# Run-time use call
# NOTE: Do we REALLY need to do this as a use?
#       If the ->import method isn't important, change to native require.
sub _LIBRARY {
	my $package = shift;
	if ( Params::Util::_IDENTIFIER($package) ) {
		$package = "Aspect::Library::$package";
	}
	Params::Util::_DRIVER($package, 'Aspect::Library');
}

1;

=pod

=head1 OPERATORS

=head2 &

Overloading of bitwise C<&> for pointcut declarations allows a natural looking
boolean "and" logic for pointcuts. When using the C<&> operator the combined
pointcut expression will match if all pointcut subexpressions match.

In the original Java AspectJ framework, the subexpressions are considered to
be a union without an inherent order at all. In Perl you may treat them as
ordered since they are ordered internally, but since all subexpressions run 
anyway you should probably not do anything that relies on this order. The
optimiser may do interesting things with order in future, or we may move to an
unordered implementation.

For more information, see L<Aspect::Pointcut::And>.

=head2 |

Overloading of bitwise C<|> for pointcut declarations allows a natural looking
boolean "or" logic for pointcuts. When using the C<|> operator the combined
pointcut expression will match if either pointcut subexpressions match.

The subexpressions are ostensibly considered without any inherent order, and
you should treat them that way when you can. However, they are internally
ordered and shortcutting will be applied as per normal Perl expressions. So for
speed reasons, you may with to put cheap pointcut declarators before expensive
ones where you can.

The optimiser may do interesting things with order in future, or we may move to
an unordered implementation. So as a general rule, avoid things that require
order while using order to optimise where you can.

For more information, see L<Aspect::Pointcut::Or>.

=head2 !

Overload of negation C<!> for pointcut declarations allows a natural looking
boolean "not" logic for pointcuts. When using the C<!> operator the resulting
pointcut expression will match if the single subexpression does B<not> match.

For more information, see L<Aspect::Pointcut::Not>.

=head1 METHODS

A range of different methods are available within each type of advice code.

The are summarised below, and described in more detail in L<Aspect::Point>.

=head2 type

The C<type> method is a convenience provided in the situation advice code is
used in more than one type of advice, and wants to know the advice declarator
is was made form.

Returns C<"before">, C<"after"> or C<"around">.

=head2 pointcut

  my $pointcut = $_->pointcut;

The C<pointcut> method provides access to the original join point specification
(as a tree of L<Aspect::Pointcut> objects) that the current join point matched
against.

=head2 original

  $_->original->( 1, 2, 3 );

In a pointcut, the C<original> method returns a C<CODE> reference to the
original function before it was hooked by the L<Aspect> weaving process.

  # Prints "Full::Function::name"
  before {
      print $_->sub_name . "\n";
  } call 'Full::Function::name';

The C<sub_name> method returns a string with the full resolved function name
at the join point the advice code is running at.

=head2 package_name

  # Prints "Just::Package"
  before {
      print $_->package_name . "\n";
  } call 'Just::Package::name';

The C<package_name> parameter is a convenience wrapper around the C<sub_name>
method. Where C<sub_name> will return the fully resolved function name, the
C<package_name> method will return just the namespace of the package of the
join point.

=head2 short_name

  # Prints "name"
  before {
      print $_->short_name . "\n";
  } call 'Just::Package::name';

The C<short_name> parameter is a convenience wrapper around the C<sub_name>
method. Where C<sub_name> will return the fully resolved function name, the
C<short_name> method will return just the name of the function.

=head2 args

  # Get the parameters as a list
  my @list = $_->args;
  
  # Set the parameters
  $_->args( 1, 2, 3 );
  
  # Append a parameter
  $_->args( $_->args, 'more' );

The C<args> method allows you to get or set the list of parameters to a
function. It is the method equivalent of manipulating the C<@_> array.

=head2 self

  after {
      $_->self->save;
  } My::Foo::set;

The C<self> method is a convenience provided for when you are writing advice
that will be working with object-oriented Perl code. It returns the first
parameter to the method (which should be object), which you can then call
methods on.

=head2 wantarray

  # Return differently depending on the calling context
  if ( $_->wantarray ) {
      $_->return_value(5);
  } else {
      $_->return_value(1, 2, 3, 4, 5);
  }

The C<wantarray> method returns the L<perlfunc/wantarray> context of the
call to the function for the current join point.

As with the core Perl C<wantarray> function, returns true if the function is
being called in list context, false if the function is being called in scalar
context, or C<undef> if the function is being called in void context.

=head2 exception

  unless ( $_->exception ) {
      $_->exception('Kaboom');
  }

The C<exception> method is used to get the current die message or exception
object, or to set the die message or exception object.

=head2 return_value

  # Add an extra value to the returned list
  $_->return_value( $_->return_value, 'thing' );
  
  # Return null (equivalent to "return;")
  $_->return_value;

The C<return_value> method is used to get or set the return value for the
join point function, in a similar way to the normal Perl C<return> keyword.

=head2 proceed

  around {
      my $before = time;
      $_->proceed;
      my $elapsed = time - $before;
      print "Call to " . $_->sub_name . " took $elapsed seconds\n";
  } call 'My::function';

Available only in C<around> advice, the C<proceed> method is used to run the
join point function with the current join point context (parameters, scalar vs
list call, etc) and store the result of the original call in the join point
context (return values, exceptions etc).

=head1 LIBRARY

The main L<Aspect> distribution ships with the following set of libraries. These
are not necesarily recommended or the best on offer. The are shipped with
B<Aspect> for convenience, because they have no additional CPAN dependencies.

Their purpose is summarised below, but see their own documentation for more
information.

=head2 Aspect::Library::Singleton

L<Aspect::Library::Singleton> can be used to convert an existing class to
function as a singleton and return the same object for every constructor call.

=head2 Aspect::Library::Breakpoint

L<Aspect::Library::Breakpoint> allows you to inject debugging breakpoints into
a program using the full power and complexity of the C<Aspect> pointcuts.

=head2 Aspect::Library::Wormhole

L<Aspect::Library::Wormhole> is a tool for passing objects down a call flow,
without adding extra arguments to the frames between the source and the target,
letting a function implicit context.

=head2 Aspect::Library::Listenable

L<Aspect::Library::Listenable> assysts in the implementation of the "Listenable"
design pattern. It lets you define a function as emitting events that can be
registed for by subscribers, and then add/remove subscribers for these events
over time.

When the functions that are listenable are called, registered subscribers will
be notified. This lets you build a general event subscription system for your
program. This could be as part of a plugin API or just for your own convenience.

=head1 INTERNALS

Due to the dynamic nature of Perl, there is no need for processing of source
or byte code, as required in the Java and .NET worlds.

The implementation is conceptually very simple: when you create advice, its
pointcut is matched to find every sub defined in the symbol table that might
match against the pointcut (potentially subject to further runtime conditions).

Those that match, will get a special wrapper installed. The wrapper only
executes if, during run-time, a compiled context test for the pointcut
returns true.

The wrapper code creates an advice context, and gives it to the advice code.

Most of the complexity comes from the extensive optimisation that is used to
reduce the impact of both weaving of the advice and the run-time costs of the
wrappers added to your code.

Some pointcuts like C<call> are static and their full effect is known at
weave time, so the compiled run-time function can be optimised away entirely.

Some pointcuts like C<cflow> are dynamic, so they are not used to select
the functions to hook, but impose a run-time cost to determine whether or not
they match.

To make this process faster, when the advice is installed, the pointcut
will not use itself directly for the compiled run-time function but will
additionally generate a "curried" (optimised) version of itself.

This curried version uses the fact that the run-time check will only be
called if it matches the C<call> pointcut pattern, and so no C<call>
pointcuts needed to be tested at run-time unless they are in deep and
complex nested coolean logic. It also handles collapsing any boolean logic
impacted by the safe removal of the C<call> pointcuts.

Further, where possible the pointcuts will be expressed as Perl source
(including logic operators) and compiled into a single Perl expression. This
not only massively reduces the number of functions to be called, but allows
further optimisation of the pointcut by the opcode optimiser in perl itself.

If you use only C<call> pointcuts (alone or in boolean combinations)
the currying results in a null test (the pointcut is optimised away
entirely) and so the need to make a run-time point test will be removed
altogether from the generated advice hooks, reducing call overheads
significantly.

If your pointcut does not have any static conditions (i.e. C<call>) then
the wrapper code will need to be installed into every function on the symbol
table. This is highly discouraged and liable to result in hooks on unusual
functions and unwanted side effects, potentially breaking your program.

=head1 LIMITATIONS

=head2 Inheritance Support

Support for inheritance is lacking. Consider the following two classes:

  package Automobile;
  
  sub compute_mileage {
      # ...
  }
  
  package Van;
  
  use base 'Automobile';

And the following two advice:

  before {
      print "Automobile!\n";
  } call 'Automobile::compute_mileage';
  
  before {
      print "Van!\n";
  } call 'Van::compute_mileage';

Some join points one would expect to be matched by the call pointcuts
above, do not:

  $automobile = Automobile->new;
  $van = Van->new;
  $automobile->compute_mileage; # Automobile!
  $van->compute_mileage;        # Automobile!, should also print Van!

C<Van!> will never be printed. This happens because B<Aspect> installs
advice code on symbol table entries. C<Van::compute_mileage> does not
have one, so nothing happens. Until this is solved, you have to do the
thinking about inheritance yourself.

=head2 Performance

You may find it very easy to shoot yourself in the foot with this module.
Consider this advice:

  # Do not do this!
  before {
      print $_->sub_name;
  } cflow 'MyApp::Company::make_report';

The advice code will be installed on B<every> sub loaded. The advice code
will only run when in the specified call flow, which is the correct
behavior, but it will be I<installed> on every sub in the system. This
can be extremely slow because the run-time cost of checking C<cflow> will
occur on every single function called in your program.

It happens because the C<cflow> pointcut matches I<all> subs during weave-time.
It matches the correct sub during run-time. The solution is to narrow the
pointcut:

  # Much better
  before {
      print $_->sub_name;
  } call qr/^MyApp::/
  & cflow 'MyApp::Company::make_report';

=head1 TO DO

There are a many things that could be added, if people have an interest
in contributing to the project.

=head2 Documentation

* cookbook

* tutorial

* example of refactoring a useful CPAN module using aspects

=head2 Pointcuts

* New pointcuts: execution, cflowbelow, within, advice, calledby. Sure
  you can implement them today with Perl treachery, but it is too much
  work.

* We need a way to match subs with an attribute, attributes::get()
  will currently not work.

* isa() support for method pointcuts as Gaal Yahas suggested: match
  methods on class hierarchies without callbacks

* Perl join points: phasic- BEGIN/INIT/CHECK/END 

=head2 Weaving

* The current optimation has gone as far as it can, next we need to look into
  XS acceleration and byte code manipulation with B:: modules.

* A debug flag to print out subs that were matched during weaving

* Warnings when over 1000 methods wrapped

* Allow finer control of advice execution order

* Centralised hooking in wrappers so that each successive advice won't need
  to wrap around the previous one.

* Allow lexical aspects to be safely removed completely, rather than being left
  in place and disabled as in the current implementation.

=head1 SUPPORT

Please report any bugs or feature requests through the web interface at
L<http://rt.cpan.org/Public/Dist/Display.html?Name=Aspect>.

=head1 INSTALLATION

See L<perlmodinstall> for information and options on installing Perl modules.

=head1 AVAILABILITY

The latest version of this module is available from the Comprehensive Perl
Archive Network (CPAN). Visit <http://www.perl.com/CPAN/> to find a CPAN
site near you. Or see L<http://search.cpan.org/perldoc?Aspect>.

=head1 AUTHORS

Adam Kennedy E<lt>adamk@cpan.orgE<gt>

Marcel GrE<uuml>nauer E<lt>marcel@cpan.orgE<gt>

Ran Eilam E<lt>eilara@cpan.orgE<gt>

=head1 SEE ALSO

You can find AOP examples in the C<examples/> directory of the
distribution.

L<Aspect::Library::Memoize>

L<Aspect::Library::Profiler>

L<Aspect::Library::Trace>

=head1 COPYRIGHT

Copyright 2001 by Marcel GrE<uuml>nauer

Some parts copyright 2009 - 2013 Adam Kennedy.

Parts of the initial introduction courtesy Wikipedia.

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut