CPAN module Devel::PerlySense
Perl Other
Switch branches/tags
Pull request Compare This branch is 90 commits ahead, 216 commits behind jplindstrom:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
bin
doc
lib/Devel
notes
releases
source
t
.cvsignore
.gitignore
Build.PL
Changes
MANIFEST
MANIFEST.SKIP
META.yml
Makefile.PL
README
dist.sh
reinstall.sh

README

NAME
    Devel::PerlySense - Perl IDE backend with Emacs frontend

DESCRIPTION
    PerlySense is a Perl IDE backend that integrates with editor frontends,
    currently Emacs.

    (While no one has written a Vim frontend, PerlySense can emit Vim style
    data structures.)

    Conveniently navigate and browse the code and documentation of your
    project and Perl installation. Navigate between tests and source, and
    between related files.

    Search through the project for method declarations, invocants or free
    text using Ack.

    Run tests and scripts with easy navigation to errors/warnings/failing
    tests.

    Automate common editing tasks related to source code, tests, regular
    expressions, etc.

    Highlight syntax errors, warnings, Perl::Critic complaints, and
    Devel::Cover test coverage in the source while editing.

    PerlySense has a plugin system for understanding custom syntax, e.g.
    Moose.

SYNOPSIS
  From Emacs
    Overview -- "C-o C-o" -- Show information about the Class at point or
    the current Class. There are also shortcuts to show a single section:

    *   C-o o i -- Inheritance

    *   C-o o a -- API

    *   C-o o b -- Bookmarks

    *   C-o o u -- Uses

    *   C-o o h -- NeighbourHood

    Docs -- "C-o C-d" -- Show docs (POD/signature/etc) for the symbol
    (module/method/sub) at point. A doc hint is displayed in the echo area
    (for methods and subs), or a new POD buffer is created (for modules).

    Document Inheritance -- "C-o d i" -- Show the Inheritance hierarchy for
    the current Class in the echo area.

    "C-o d u" -- Document 'use Module' statements in the echo area.

    Go To -- "C-o C-g" -- Open file at proper location for module,
    method/sub declaration for the symbol (module/method/sub) at point. If
    no sub declaration is available (like for generated getters/setters),
    any appropriate POD is used instead.

    Go to Use -- "C-o g u" -- Go to the 'use Module' section of the current
    buffer.

    Go To 'new' -- "C-o g n" -- Go to the 'new' method of the current class.

    Go To Base Class -- "C-o g b" -- Open the file of the base class of the
    current class. This will take you up one level in the inheritance
    hierarchy.

    Go To Module -- "C-o g m" -- Open the source file of the module at
    point.

    Go To Version Control -- "C-o g v" -- Go to the Project view of the
    current Version Control system.

    Go To Tests - Other Files -- "C-o g t o" -- Go to any related test or
    source files given a Devel::CoverX::Covered covered db.

    Go To Project's Other Files -- "C-o g p o" -- Go to *corresponding*
    files given a ".corresponding_file" config file (see
    File::Corresponding).

    Find with Ack -- "C-o f a" -- Search for the selected text, or word at
    point, or whatever, using Ack.

    Find sub declarations -- "C-o f s" -- Search for sub declarations of the
    method name, or word at point.

    Find method calls -- "C-o f c" -- Search for method calls of the method
    name, or word at point.

    Run file -- "C-o C-r" -- Run the current file using the Compilation mode
    and the settings appropriate for the source type (Test, Module, etc.).
    Highlight errors and jump to source with C-c C-c.

    Edit - Move Use Statement -- "C-o e m u" -- Move the 'use Module'
    statement at point to the 'use Module' section at the top.

    Edit Test Count -- "C-o e t c" -- Increase the test count (e.g. "tests
    => 43")

    Assist With Test Count -- "C-o a t" -- Synchronize invalid test count in
    .t file with the *compilation* buffer.

    Flymake may be used to highlight syntax errors, warnings, and
    Perl::Critic violations in the source while editing (continously or at
    every save).

  From Vim
    There is no integraton with Vim available. Well, not properly anyway. If
    you pass the option

     --io_type=editor_vim

    to perly_sense, the output will be serialized to Vim <Dictionary data
    structures>.

  From other editors
    Any editor that is programmable and that can call a shell script could
    take advantage of at least some parts of PerlySense to implement
    something similar to the Emacs functionality. And most editors are
    programmable by the authors, if not by the users.

  From the command line
    *   Create Project

          perly_sense create_project [--dir=DIR]

        Create a PerlySense project in DIR (default is current dir).

        If there is already a project.yml file, back it up with a datestamp
        first.

        (Note that you don't need to create a project before start using
        PerlySense. Read more below).

    *   Process Project Source Files

          perly_sense process_project [--dir=.]

        Cache all modules in the project that --dir belongs to.

    *   Process Source Files in @INC

          perly_sense process_inc

        Cache all the modules in @INC.

        This is a useful thing to do after installation (and after each
        upgrade), but it will take a wile so put it in the background and
        let it churn away at those modules.

        *   Unix

              perly_sense process_inc &        # (well, you knew that already)

        *   Windows

              start /MIN perly_sense process_inc

    *   Get Info

          perly_sense info

        Display useful information about what the current project directory,
        user home directory, etc. is.

INSTALLATION
  Module Installation
    Install the Devel::PerlySense module and accompanying elisp by using a
    configured CPAN shell, like this:

      cpan Devel::PerlySense

    When everything is installed, verify by running

      perly_sense info

    The elisp is installed next to the Perl source (so it works to install
    as an unpriviliged user, and you don't *have* to have Emacs installed,
    and the elisp and Perl source are always in sync).

  Supporting modules
    These aren't needed to begin with, but may be very useful.

    *   Devel::CoverX::Covered

        If you have a lot of tests to navigate and run a nightly build with
        Devel::Cover to generate test coverage.

    *   File::Corresponding

        If you have an MVC style class structure with the same entity
        represented in different directories (e.g. Controller::Aeroplane,
        Model::Aeroplane, etc.).

  Emacs installation
    Make sure the Devel::PerlySense CPAN module is installed, it contains
    the required elisp files which will be loaded automatically with the
    following in your .emacs config file:

        ;; *** PerlySense Config ***

        ;; ** PerlySense **
        ;; The PerlySense prefix key (unset only if needed, like for \C-o)
        (global-unset-key "\C-o")
        (setq ps/key-prefix "\C-o")


        ;; ** Flymake **
        ;; Load flymake if t
        ;; Flymake must be installed.
        ;; It is included in Emacs 22
        ;;     (or http://flymake.sourceforge.net/, put flymake.el in your load-path)
        (setq ps/load-flymake t)
        ;; Note: more flymake config below, after loading PerlySense


        ;; *** PerlySense load (don't touch) ***
        (setq ps/external-dir (shell-command-to-string "perly_sense external_dir"))
        (if (string-match "Devel.PerlySense.external" ps/external-dir)
            (progn
              (message
               "PerlySense elisp files  at (%s) according to perly_sense, loading..."
               ps/external-dir)
              (setq load-path (cons
                               (expand-file-name
                                (format "%s/%s" ps/external-dir "emacs")
                                ) load-path))
              (load "perly-sense")
              )
          (message "Could not identify PerlySense install dir.
        Is Devel::PerlySense installed properly?
        Does 'perly_sense external_dir' give you a proper directory? (%s)" ps/external-dir)
          )


        ;; ** Flymake Config **
        ;; If you only want syntax check whenever you save, not continously
        (setq flymake-no-changes-timeout 9999)
        (setq flymake-start-syntax-check-on-newline nil)

        ;; ** Code Coverage Visualization **
        ;; If you have a Devel::CoverX::Covered database handy and want to
        ;; display the sub coverage in the source, set this to t
        (setq ps/enable-test-coverage-visualization nil)

        ;; ** Color Config **
        ;; Emacs named colors: http://www.geocities.com/kensanata/colors.html
        ;; The following colors work fine with a white X11
        ;; background. They may not look that great on a console with the
        ;; default color scheme.
        (set-face-background 'flymake-errline "antique white")
        (set-face-background 'flymake-warnline "lavender")
        (set-face-background 'dropdown-list-face "lightgrey")
        (set-face-background 'dropdown-list-selection-face "grey")


        ;; ** Misc Config **

        ;; Run calls to perly_sense as a prepared shell command. Experimental
        ;; optimization, please try it out.
        (setq ps/use-prepare-shell-command t)

        ;; *** PerlySense End ***

  Emacs Configuration
    The most important config you can change is the prefix key.

    The default, \C-o, seemed to have a rater low useful-to-keystroke ratio
    and so was a strong candidate for stealing for this much more important
    purpose :) Now, the *proper* way of doing this is of course to some kind
    of C-c prefix. You decide.

    If you want to use flymake to do background syntax and Perl::Critic
    checks, set ps/load-flymake to t (this is a very nifty thing, so yes you
    want to do this) and configure the colors to your liking.

    Note: This also needs to be enabled on a per-project basis (see below).

    Once you have restarted Emacs, you might want to browse around the
    customizations by doing

      M-x customize-group perly-sense

GETTING STARTED WITH EMACS
    This is quite a handfull of new features, and you're not likely to be
    able to use them efficiently from day one. Remember, Emacs is all about
    acquiring finger memory, one feature at a time.

    These are the ones I use every day so they may be a good start:

    *   Go to Module

    *   Go to base class

    *   Document Class Hierarchy

    *   Go to Version Control

    *   Find with Ack

    *   Find sub declerations

    *   Run tests, Re-run tests

    *   Assist with Test count

  Reading Docs
   Smart docs
    "C-o C-d" is the "Smart docs" command. It brings up POD documentation
    for what's at point.

    Put the cursor on the "method" word of a "$self->method" call and press
    "C-o C-d" and wait until a documentation hint for the method call is
    displayed briefly in the echo area. PerlySense will look in base classes
    if the method can't be found in the current class.

    Put the cursor on the "method" word of an $object->method call and press
    "C-o C-d" to see the docs hint. PerlySense will look through all your
    "use"d modules (and their base classes) for the method call and try to
    identify the best match.

    Note! The first time each module is parsed this will take a second or
    two, and the very first time you run the command with lots of "use"
    modules it's bound to take a lot longer than that.

    Put the cursor on a module name and press "C-o C-d" to bring up a new
    buffer with the POD for that module (this is similar to the cperl-mode
    feature, only a) not as good, but b) it works on Windows).

    Press "C-o C-d" with nothing under the cursor brings up a POD buffer for
    the current file.

   Document Inheritance
    "C-o d i" will briefly display the Inheritance hierarchy for the current
    Class in the echo area. Example:

        [ DBIx::Class::Componentised        ]
        [ DBIx::Class                       ] --> [ Class::Data::Accessor ]
        [<CatalystX::FeedMe::DBIC::FeedItem>]

   Document Used Modules
    "C-o d u" will briefly display the list of modules used from the current
    buffer in the echo area. Example:

        [ Carp               ] [ File::Spec ] [ Win32::OLE::Const          ]
        [ Class::MethodMaker ] [ File::Temp ] [ Win32::Word::Writer::Table ]
        [ Data::Dumper       ] [ Win32::OLE ]

  Browsing Code
   Smart go to
    "C-o C-g" is the "Smart go to" command. It's similar to Smart Docs, but
    instead of bringing the docs to you, it brings you to the definition of
    what's at point.

    The definition can be either the sub declaration, or if the declaration
    can't be found (like for auto-generated getters/setters, autoloaded subs
    etc), the POD documentation for the sub.

    Before you go anywhere the mark is set. Go back to earlier marks
    globally with C-x C-SPC, or locally with C-u C-SPC.

   Go to Module
    "C-o g m" -- Go to Module at point. Useful if "Smart go to" can't
    identify what's at point.

   Go to Base Class
    "C-o g b" takes you up one level in the inheritance hierarchy. If the
    current class has many base classes, you'll have to choose which one to
    go to.

    If the current method is implemented in that base class, go to the sub
    definition.

    After going to the Base Class, the Inheritance tree of that class is
    displayed in the echo area so you can see where you ended up.

   Go to the 'new' method
    "C-o g n" takes you to the definition of the 'new' method of the current
    class (in this class, or a parent class). But if you're unlucky, it
    might take you to your OO helper module's default new.

   Go To 'use Module' section
    "C-o g u" takes you to the line below the last 'use Module' statement in
    the the current buffer.

   Go to Version Control
    "C-o g v" -- Go to the Project view for the current Version Control
    system. This typically displays the change status of the files in the
    project. A dired of the Project dir is used in lieu of a VCS.

    First, try to go to any existing VC project buffer.

    If there is no VC buffer open, find out what VCS is used, and display
    the Project view.

    Supported VC systems:

    *   Subversion -- Quick intro to *svn-status*

        _ (underscore) - display only the changed files (toggle)

        n, p, m, u -- next, previous, mark, unmark

        E -- diff the changes in the current file

        c -- commit file(s)

        r -- revert file(s)

        X v -- resolve conflict (or X X, I'm not sure what the difference
        is)

        etc, etc, etc, do a C-h m to see all the goodies.

        See also:

        *   <http://www.credmp.org/index.php/2007/12/08/emacs-hidden-gems-ve
            rsion-control/>,

        *   <http://www.emacsblog.org/2007/05/17/package-faves-psvn/>

    *   Git -- Magit

        This requires you to have Magit installed. Download and manual at:
        <http://zagadka.vm.bytemark.co.uk/magit/>.

        When you switch to an existing Magit status buffer the status is
        refreshed automatically to display the current status.

        If there are many *magit: NAME* buffers open, the first existing one
        will be used (whichever that might be).

   Go to Project's Other Files
    "C-o g p o" -- Navigate to *other* source files in the project that
    correspond to the current file.

    This is useful if you have similarly named files in different parts of
    the source tree that belong to each other, as is common in projects with
    an MVC structure (e.g. those based on Catalyst).

    This requires that you have a ".corresponding_file" config file in the
    ".PerlySenseProject" or project root directory (or your home directory).

    See File::Corresponding for details.

  Finding Code
   Find with Ack
    "C-o f a" -- Ack through the source and display the hits in a *grep*
    buffer. ack is like grep, but more suitable for development.

    The search takes place from the Project directory. Before running ack
    you'll get to edit the command line with a sensible default chosen from:

    *   the active region

    *   the word at point (with the "-w" whole word option)

    For details, refer to the ack documentation (the program was installed
    as a dependency of PerlySense).

    Remember that earlier searches are available in the command history,
    just like with grep.

    Tip: You can jump from a source file to the next hit with "C-c C-c"
    (type "C-h m" in the *grep* buffer to see the mode documentation).

    Tip: if you need to find something else while browsing the *grep*
    buffer, you can easily rename the current *grep* buffer to something
    else using "M-x rename-buffer".

   Find sub declarations
    "C-o f s" -- Ack the Project for *sub declarations* of the method, or
    word at point.

    I.e. look for lines with "sub NAME".

    The point can be either on the method ("$self->st|ore"), or on the
    object ("$us|er_agent->get()").

   Find method calls
    "C-o f c" -- Ack the Project for *method calls* to the method, or word
    at point.

    I.e. look for lines with "->NAME".

  Class Overview
    Pressing "C-o C-o" will bring up the Class Overview of the Class name at
    point (not yet implemented), or otherwise the current Class (the active
    Package).

    Example class CatalystX::FeedMe::Controller::Feed

      * Inheritance *
           [ Class::Accessor                     ]
        +> [ Class::Accessor::Fast               ] <-----+
        |  [ Catalyst::AttrContainer             ] ------+---------------------------+
        |    |                                           |                           v
        +- [ Catalyst::Base                      ] --> [ Catalyst::Component ] --> [ Class::Data::Inheritable ]
           [ Catalyst::Controller                ]
           [<CatalystX::FeedMe::Controller::Feed>]

      * Uses *
      [ Data::Dumper      ] [ XML::Atom::Syndication::Content ] [ XML::Atom::Syndication::Feed ]
      [ Template::Filters ] [ XML::Atom::Syndication::Entry   ] [ XML::Atom::Syndication::Link ]

      * NeighbourHood *
      [ CatalystX::FeedMe::DBIC ] [<CatalystX::FeedMe::Controller::Feed    >] -none-
                                  [ CatalystX::FeedMe::Controller::FeedItem ]
                                  [ CatalystX::FeedMe::Controller::Homepage ]
                                  [ CatalystX::FeedMe::Controller::Root     ]

      * Bookmarks *
      - Todo
      Feed.pm:83: remove duplication

      * API *
      \>mutator_name_for
      ->new
      ->path_prefix
      ...

   Overview sections
    In addition to the full Overview, each section may be displayed
    individually:

    *   C-o o i -- Inheritance

    *   C-o o a -- API

    *   C-o o b -- Bookmarks

    *   C-o o u -- Uses

    *   C-o o h -- NeighbourHood

    The Inheritance section shows all Base classes of the Class. Inheriting
    from something like Catalyst is hopefully the hairiest you'll see.
    Classes inherit from their parents upwards in the diagram unless there
    is an arrow pointing elsewhere.

    The Uses section shows all used modules in the Class.

    The NeighbourHood section shows three columns (1: parent dir, 2: current
    dir, 3: subdir for the current class) with Classes located nearby (this
    can be bizarrely huge (and take a long time) if you browse your site_lib
    or similar).

    (This was disabled for having a bad time/useful ratio. Use C-o o h to
    bring up only the NeighbourHood).

    The Bookmarks section shows matches for bookmark definitions you have
    defined in the Project config (see below).

    the API section shows things that look like methods and properties of
    the class (sub declarations, $self method calls,
    $self->{hash_ref_keys}):

      ->method_in_this_class
      \>method_in_base_class  (note the arrow coming from above)

    Private methods (named with a leading _) are displayed as regular
    methods. Same goes for private methods in base classes, except when the
    base class is outside of your Project (like for CPAN modules).

    Why is this?

    If it's your code base you're interested in everything, but if you
    inherit from a CPAN module, you don't care (you even shouldn't care)
    about the implementation of that module.

    Note that you can still see the private methods of those modules by
    doing a Class Overview on them, or any of the modules outside your
    current Project (thereby changing the current Project to the directory
    where those modules are installed).

   Key bindings
    When in the Class Overview buffer:

    g -- Go to the file of the thing at point (Module/Method/Bookmark)

    d -- Documentation for the thing at point (Module/Method)

    c -- Class Overview for the thing at point. RET does the same.

    I -- Move point to the Inheritance heading in the buffer.

    U -- Move point to the Uses heading in the buffer.

    H -- Move point to the NeighbourHood heading (mnemonic: 'Hood).

    B -- Move point to the Bookmarks heading.

    A -- Move point to the API heading.

    N -- Move point to the '->new' method in the buffer (if any).

    q -- Quit the Class Overview buffer.

  Testing
   Run File
    "C-o C-r" -- Run the file of the current buffer using the Compilation
    mode.

    Files are run according to the source type, which is determined by the
    file name (see the config file). The default for .t files is to run
    "prove -v", for .pm files "perl -c", etc. This can be configured per
    Project (see below).

    The file is run from the Project root directory or from the file
    directory depending on the file type, and the @INC is set appropriately.
    You can also specify additional @INC directories in the Project config.

    Note that you can configure whatever type of run profile you like, not
    just Perl source files.

    As a taste of what's possible, imagine that you have a test framework
    with .yml acceptance test data files and a corresponding yml-runner.pl
    script. You can set up the config so you can type "C-o C-r" while
    editing the .yaml file to run that test. Refer to the
    Devel::PerlySense::Cookbook for details.

    If any warnings, errors or test failures are encountered, they are
    highlighted in the *compilation* buffer. Press RET on a highlighted line
    to go to the source. Jump between errors with Tab.

    Use C-c C-c to move from one error to the next while editing.

    If you wish to start many runs at the same time, rename the compilation
    buffer with "M-x rename-buffer".

   Re-run File
    Invoke "C-o C-r" from within the *compilation* buffer to re-run ("M-x
    recompile") the file. Useful when you have skipped around the source
    fixing errors and the .t file isn't visible.

    "C-o r r" -- If not even the *compilation* buffer is visible, issue
    Re-Run File from anywhere to bring it up and re-run.

   Go to Run-buffer
    Invoke "C-o g r" to go to the *compilation* buffer.

   Edit Test Count
    "C-o e t c" -- Increase the test count number in the line resembling

      use Test::More tests => 43;

    without moving point. The current and new test count is reported in the
    echo area.

    Increase with the numeric argument (e.g. "C-u -2 C-o e t c"), or default
    1.

   Assist With Test Count
    "C-o a t" -- If the test count in a .t file is out of sync with what's
    correctly reported when running the test in the *compilation* buffer
    (see Run File), use this command to update the .t file.

    This updates the

      use Test::More tests => 43;

    line in the current buffer, so be sure to only run this when the
    *compilation* buffer contains the run result of this buffer.

   Run Single Test::Class Method
    If you use Test::Class to write your tests, you may sometimes want to
    run just a single test method.

    Hit "C-o r m" to mark the current sub as the current test method, and
    "C-o r m" again to unmark it. This will set the $TEST_METHOD environment
    variable during program runs, so when you run this test class, only the
    marked method will be run.

    The current test method is indicated with a "Test::Class -->" next to
    it.

   Go to Tests - Other Files
    "C-o g t o" -- In a test file, navigate to the source files that are
    covered by that test file.

    In a source file, navigate to test files covering the file. If the point
    is on a line with a sub declaration, the list of test files is limited
    to those that cover that particular sub.

    This requires that Devel::CoverX::Covered is installed and a
    Devel::Cover cover_db in the project root directory.

    See Devel::CoverX::Covered for details.

   Go to Error line
    If you run tests in a regular shell (inside Emacs or in a terminal
    window), this may be handy.

    "C-o g e" -- If point is located on an error line from a syntax error,
    or a stack trace from the debugger or similar, go to that file+line.

    If no file name can be found, prompt for a piece of text that contains
    the file+line spec. The kill ring or clipboard text is used as default
    if available (so it's easy to just copy the error line from the
    terminal, run this command and hit return to accept the default text).

  Debugging Code
   Run File in Debugger
    "C-o r d" -- Run the file of the current buffer using the Emacs
    integrated Perl debugger. This the same as the excellent "M-x perldb",
    except a few annoyances are fixed, like the include directories, the
    working directory, the default command line etc.

    Note that if you have spaces in your file names, this might not work
    (it's a perldb thing).

    The debugger is started according to the file source type, which is
    determined by the file name (see the config file). This can be
    configured similar to how files are run (see above).

    Most files are run from the Project root directory by default.

   Commands and key bindings
    Commonly used commands:

        |-------------+------+-------------------------|
        | Source      | DB   | Command                 |
        |-------------+------+-------------------------|
        | C-x C-a C-n | n    | Next line (step over)   |
        | C-x C-a C-s | s    | Step into               |
        |             | RET  | Repeat last n or s      |
        | C-x C-a C-r | r    | Return from sub         |
        | C-x C-a C-u |      | Run to (Until) point    |
        |             | x $v | Dump variable $v        |
        |             | T    | Stack trace             |
        |             | y    | Dump lexicals (mY vars) |
        |             | R    | Restart                 |
        |             | m $o | List methods of $o      |
        |-------------+------+-------------------------|

   Dumping objects
      x $VAR

    to print/dump objects.

    See <http://use.perl.org/~jplindstrom/journal/34427> for how to deal
    with large objects (put the ".perldb" file in $HOME or the project root
    dir).

   Breakpoints
    Create a programmatic breakpoint like this

      $DB::single = 1;

   More Documentation
    Once the debugger is started, refer to the Gud menu for a few useful
    commands and key bindings (gud = Grand Unified Debugger). See also:
    <http://www.gnu.org/software/emacs/manual/html_node/emacs/Debuggers.html
    >

    Since the Perl debugger command line is available, make sure you read up
    on that too: <http://perldoc.perl.org/perldebug.html> (especially the
    <<, {{, etc. are more useful than they might seem at first).

  Displaying Code
   Flymake Introduction
    "Flymake performs on-the-fly syntax checks of the files being edited
    using the external syntax check tool (usually the compiler). Highlights
    erroneous lines and displays associated error messages."

    Flymake is included in Emacs 22 (or available from
    http://flymake.sourceforge.net/, put flymake.el somewhere in your
    load-path. [[[explain how to fix brokenness?]]] ).

    PerlySense uses flymake to check syntax, Perl Critic, etc.

    Having Perl::Critic enabled will also speed up other operations by
    caching information.

    Three inconveniences with vanilla Flymake are fixed:

    *   no proper @INC

    *   only .pl files

    *   "perl -c" warns about redefined subs for recursively used modules
        (which is perfectly fine Perl)

    Syntax errors and warnings both use the error face.

    Perl::Critic violations use the warning face.

   Enabling Flymake
    First off, flymake itself needs to be enabled. Refer to the Emacs
    Installation description above.

    This will enable Flymake for all cperl-mode buffers, causing Emacs to
    call perly_sense for each check.

    *PerlySense won't do anything at this point though*. You still need to
    configure what should happen during a flymake.

    Create a PerlySense Project directory (see below) and look in the
    project.yml file for instructions on how to configure Flymake
    activities.

    Set "syntax" and/or "critic" to 1 to enable them.

    The primary reason "syntax" is turned off by default is that it's a
    potential security hole; running "perl -c" on a file will not only check
    the syntax; BEGIN and CHECK blocks are also executed. Doing that on
    random code may be considered... baaad.

    This way you can have Flymake enabled globally and still not run "perl
    -c" on everything that happens to be in a buffer.

   Using Flymake
    In the Project config file there are some hints on how to customize
    Flymake, when it should run, etc. You can also customize it with "M-x
    customize-group flymake".

    (Personally I find the nagging while I type very distracting, but I
    welcome the immediate feedback whenever I save the file. YMMV.)

    Look in the mode line for hints on whether there are any errors or
    warnings.

    "C-o s n" -- Go to the next Source error/warning.

    Display the error in the minibuffer. If the warning is from a
    Perl::Critic module, copy the module name into the kill-ring, so you
    easily can yank it into the .perlcritic config file to disable it. (not
    implemented)

    "C-o s p" -- Go to the previous Source error/warning.

    "C-o s s" -- Display the error/warning text of the current line in a
    popup. Or display the error in the minibuffer if the display isn't
    graphical, or if the ps/flymake-prefer-errors-in-minibuffer variable is
    customized to a true value.

   Code Coverage Visualization Introduction
    If you have a test suite, you might like this. You should have tests.

    If you run Devel::Cover, you'll be happy. You should know your code
    coverage.

    PerlySense can display the code coverage in the source buffer.

    Currently supported is subroutine coverage, i.e. whether a sub is
    covered by tests or not.

    Covered subs are displayed with a discreet green underline, uncovered
    subs get a red underline.

   Coverage Visualization Setup
    PerlySense uses Devel::CoverX::Covered to manage the coverage data.
    Refer to that documentation for how to run your test suite with
    Devel::Cover and generate a "covered" database.

    The "covered" database should reside in your project root dir and
    contain files with file names relative to the project root dir (that's
    ordinarily the case).

    Note: Running the test suite with Devel::Cover can be very, very slow. A
    nightly build is usually a good idea.

   Using Coverage Visualization
    You can toggle Visualization with "C-o C-v" at any time when editing.

    You can also enable Visualization by default in the install script (see
    above), or via "M-x customize-variable
    ps/enable-test-coverage-visualization".

    Whenever Visualization is enabled, PerlySense will try to fetch coverage
    information just after a file is opened and highlight the word "sub" for
    each subroutine in the buffer.

    *   A green underline means that the sub was entered at least once. This
        does not mean all lines in the sub was covered.

    *   A red underline means the sub wasn't covered at all. Time to write
        more tests!

    *   No underline means that the sub isn't in the coverage database.
        Maybe the sub was added after the test run, maybe Devel::Cover
        didn't manage to capture any coverage information for the sub.

        If you really think the sub should be covered, generate a HTML
        report with Devel::Cover and investigate further.

    The point of the visualization is to provide an ambient feeling of
    what's covered or not. Too much detail and color all over the place and
    the source turns into a christmas tree! But if you browse past a complex
    method and see that it isn't tested, that should ring a bell.

    To increase this effect you may want to only highlight subs with bad
    coverage (customize the variable "ps/only-highlight-bad-sub-coverage")

    Note that you can hit "C-o g t o" -- "Go To Tests - Other Files" to see
    what test files are covering *this file*. If you run the command with
    the cursor on a "sub" line, you'll get only the tests that cover *that
    particular subroutine*.

  Editing Code
   Edit Move 'use Module' Statement
    "C-o e m u" -- If point is on a line with a single 'use Module'
    statement, set mark and move that statement to the end of the 'use
    Module' section at the top of the file.

    This is typically useful when you realize you need a module, e.g.
    Data::Dumper, in the middle of the file, but you don't want to leave
    where you are just to fiddle with adding it.

    So type the 'use Module' statement, hit "C-o e m u" to move it, see that
    it got moved to a good place and hit C-u C-SPC to return to where you
    were, and continue doing what you where doing.

   Assist With -- Regex
    Hit "C-o a r" to bring up the Regex Tool which will let you compose a
    Perl regular expression interactively with matching text highlighed.

    The Regex Tool appears in a new frame with three buffers: *Regex*,
    *Text* and *Groups*.

    If point is on a regular expression in the source code, that regex will
    be used to pre-populate the *Regex* buffer. (Not yet implemented)

    If there is a comment block just above the regex, it will be used to
    pre-populate the *Text* buffer. Note that it is very handy to document
    the regex with some sample input, so this is a good idea in general.
    (Not yet implemented)

    The contents of the *Regex* buffer should look e.g. like this:

      / part \s (\w+) \s no:(\d) /xgm

    *   You can use all the usual delimiters, such as / | {} () ", etc.

    *   You can put Perl comments below the regex to temporarily store
        chunks of regex code during prototyping.

    *   The modifiers work as expected, including /x and /g .

    The results in the *Groups* buffer are updated as you type in either the
    *Regex* or *Text* buffer.

    Use C-c C-c to force an update.

    Use C-c C-k to quit all the regex-tool buffers and remove the frame.

THE PERLYSENSE USER DIRECTORY
    PerlySense keeps a per-user directory to store cache files, logs, etc.
    The ".PerlySense" user directory is located under the first available of
    these environment variables:

      $APPDATA
      $ALLUSERSPROFILE
      $USERPROFILE
      $HOME
      $TEMP
      $TMP

    Run

      perly_sense info

    to see which directory is actually being used.

PROJECTS
    PerlySense has the concept of a Project root directory.

    Basically, this is where all the source lives, and where your program
    can go to find modules that are used. This is from where tests are run
    and files are found.

    You can specify the Project root dir explicitly for your applications.
    But if you don't, PerlySense will try and figure out what the Project
    root directory is from the context of the surrounding code.

    This means you can browse source code anywhere on your hard drive (e.g.
    @INC) without any special setup or configuration. Most things will just
    work, without any hassle.

    If you follow the standard directory structure for CPAN modules, the
    Project directory is typically the one which contains the Makefile.PL,
    the lib, bin, and t directory, etc.

  Identifying a Project root directory
    The fastest and most solid way for PerlySense to know which is the
    Project directory is to create a ".PerlySenseProject" directory with a
    config file in it. This is highly recommended for all of your own
    projects.

    The complete project identification strategy is as follows:

    *   First, if there is any directory upwards in the dirctory path with a
        ".PerlySenseProject" dir in it, that is the Project directory.

    *   Second, PerlySense will try figure out from where the current file
        (if any) was being required/used given the contained package names
        or used modules.

    *   Third, if that doesn't work, PerlySense will look for "lib" and "t"
        directories.

    If that doesn't work, PerlySense is lost and you really do need to
    create an explicit Project directory by running the following command in
    your intended Project root directory (that would typically be the
    directory which has a "lib" directory in it):

      perly_sense create_project

    Any existing ".PerlySenseProject/project.yml" config file will be
    renamed.

    Note that this all means that the current Project depends on which file
    you are looking at. If it's a file within the directory tree under a
    ".PerlySenseProject" directory, that's what the current Project is. But
    if you from that file do a Class Overview on an installed CPAN module,
    the current Project is deduced from that .pm file, typically making the
    current Project be the "lib" or "site_lib" of your local CPAN
    installation.

  Project Configuration
    The Project has a .PerlySenseProject/project.yml config file. Here you
    can change the name of the Project, add extra @INC directories, etc.

    There is a yaml-mode for Emacs, but I haven't got it to work properly
    (unless an infinite loop counts as "properly" these days). The
    shell-script-mode is good enough.

    The config file documentation is where it belongs, in the config file,
    so just take a look at it.

  perly_sense Project commands
      perly_sense create_project [--dir=DIR]

    Create a PerlySense project in DIR (default is current dir).

      perly_sense process_project

    Cache all modules in the project. (not implemented)

BOOKMARKS
    Bookmarks are regexes that may match against a single line. Each
    bookmark definition has a name/moniker under which the matches are
    grouped in the Class Overview display.

    The primary point of Bookmarks is to highlight unusual things in the
    source. The secondary to make it easy for you go navigate to them.

    This can be anything you like, but things that come to mind are:

    *   TODO comments

    *   FIXME/XXX/HACK comments

    *   Things you don't want left in the code, like

        Breakpoints ($DB::single = 1)

        Debugging warn/print statements

  Configuration
    Bookmarks are defined in the Project Config file (technical details are
    documented there).

KEY BINDING CONVENTIONS
    There is a system behind the chosen key bindings in PerlySense. Knowing
    the conventions will make it easier to remember everything.

  Convention: Action based
    The first level after the prefix key ("C-o" by default) is always an
    Action, e.g. Run, or Document.

    (In the case of "C-o C-d" for Document you can either think of it as
    "Document this for me!" or "Give me Documentation!".)

    With a verb at the first level rather than a noun, the Action can be
    context sensitive, "smart", or DWIMy.

    Smart Goto goes to whatever is under the cursor, be it a module name, a
    method call, a file name, or an error message.
    Run runs the file differently depending on what kind of file is open
    (tests are "proved", modules are syntax checked, scripts are run, etc).

  Convention: The Action as a Gateway
    The first level indicates the Action to perform, and has the Ctrl
    modifier as a "Smart" / DWIMy modifier. This is both so it's easy to
    type "C-o C-r" without releasing the Ctrl key, and to provide a gateway
    to more specific actions when typing the key without Ctrl.

    E.g. "C-o C-r" means "Run file", "C-o r r" means "Run - Re-run".

    E.g. "C-o C-g" means "Smart Goto", "C-o g b" means "Goto - Base Class",
    C-o g s means "Goto - SUPER Method".

  The Main Actions Areas
    (some of the main areas have no implementations yet)

    *   r -- Run

        Run files in various ways.

    *   g -- Go to

        Navigate to various locations in the source.

    *   d -- Document

        Bring up documentation.

    *   f -- Find

        Find/search and display things in the source.

    *   o -- Overview

        Bring up an overview of things.

    *   m -- forMat

        Reformat source.

    *   e -- Edit

        Perform smaller convenience editing task.

    *   E -- rEfactor

        Perform restructuring edits that don't impact
        functionality/behaviour.

    *   A -- Assist

        Solve very context sensitive problems.

  Explore Emacs key bindings
    Remember that you can use the usual Emacs feature to display possible
    key stroke completions by hitting C-h whenever in the key stroke
    sequence.

    E.g. Hitting "C-o g C-h" will list all available key strokes starting
    wiht "C-o g".

  Changing key bindings
    Some key bindings may change over time as I figure out what works and
    what doesn't. Some key bindings may be reorganized to make more sense or
    to just work better.

IN CLOSING -- ON PARSING PERL
    Since Perl is so dynamic, a perfect static analysis of the source is
    impossible. But not unusably so. Well, hopefully. Most of the time.

    Because of this PerlySense is not about exact rules, but about
    heuristics and a 90% solution that isn't perfect, but good-enough.

    PerlySense tries to take advantage of the fact that Perl code is more
    than the plain source file. The source lives in a context of POD and a
    directory structure and common Perl idioms.

    Sometimes when PerlySense can't make a decision, you're expected to chip
    in and tell it what you meant.

    Sometimes it won't work at all.

    Such is the way of dynamic languages.

    If it works for you, brilliant, use it to be more productive. If not...
    well, there's always Java >:)

  Syntax Parsing Modules
    PerlySense provides a plugin architecture for supporting custom syntax
    provided by OO modules such as Moose, or Class::Accessor.

    Currently Moose is supported via the
    Devel::PerlySense::Plugin::Syntax::Moose module.

MORE DOCUMENTATION
    Devel::PerlySense::Cookbook

SEE ALSO
    sepia - similar effort

    PPI - excellent for parsing Perl

    CPANXR - also uses PPI for cross referencing the CPAN

    <http://www.DarSerMan.com/Perl/Oasis/> - Win32 class browser/IDE.
    Earlier (a lot) work by me.

    <http://www.perl.com/lpt/a/955> - Article "Perl Needs Better Tools"

    <http://media.pragprog.com/articles/mar_02_archeology.pdf> - Article
    "Software Archeology"

    <http://www.newartisans.com/downloads_files/regex-tool.el> - Regex Tool

    <http://vimdoc.sourceforge.net/htmldoc/eval.html#Dictionaries> - Vim
    native data structure

AUTHOR
    Johan Lindström, "<johanl[ÄT]DarSerMan.com>"

BUGS AND CAVEATS
  BUG REPORTS
    Please report any bugs or feature requests to
    "bug-devel-perlysense@rt.cpan.org", or through the web interface at
    <http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Devel-PerlySense>. I
    will be notified, and then you'll automatically be notified of progress
    on your bug as I make changes.

  CAVEATS
    Tab/space isn't supported by PPI yet, but it's supposed to be. So using
    Tab instead of spaces won't work properly.

  KNOWN BUGS
    PPI is kinda slow for large documents. Lots of objects being created
    etc.

    There are certainly edge cases. Bug reports with failing tests
    appreciated :)

    There is one known infinite loop.

ACKNOWLEDGEMENTS
    Peter Liljenberg and Phil Jackson for their elisp fu.

    Jonathan Rockway for cool ideas:
    <http://blog.jrock.us/articles/Increment%20test%20counter.pod>

    John Wiegley for the regex-tool
    <http://www.newartisans.com/downloads_files/regex-tool.el>

    Jaeyoun Chung for dropdown-list
    <http://www.emacswiki.org/cgi-bin/wiki/dropdown-list.el>

COPYRIGHT & LICENSE
    Copyright 2007 Johan Lindström, All Rights Reserved.

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

*** THE FOLLOWING IS DEVELOPER DOCUMENTATION ***
PROPERTIES
  oCache
    Cache::Cache object, or undef if no cache is active.

    Default: undef

  oProject
    Devel::PerlySense::Project object.

    Default: A Devel::PerlySense::Project::Unknown object.

  oHome
    Devel::PerlySense::Home object.

    Default: A newly created Home object.

  rhConfig
    Hash ref with the current config.

    If there is a known Project, it reflects the Project's config, otherwise
    it's the default config.

    Readonly. Note that the _entire_ data structure is readonly. Each time
    you change/add/remove a value from it, a kitten is slain. So, dude, just
    don't go there!

  oBookmarkConfig
    Devel::PerlySense::BookmarkConfig object.

  rhFileDocumentCache
    Hash ref with (keys: absolute file names; keys: Document objects).

API METHODS
  new()
    Create new PerlySense object.

  setFindProject([file => $file], [dir => $dir])
    Identify a project given the $file or $dir, and set the oProject
    property.

    If there is already a project defined, don't change it.

    If no project was found, don't change oProject.

    Return 1 if there is a valid project, else 0.

    Die on errors.

  oDocumentParseFile($file)
    Parse $file into a new PerlySense::Document object.

    Return the new object.

    If $file was already parsed by this PerlySense object, cache that
    instance of the Document and return that instead of parsing it again.

    Die on errors (like if the file wasn't found).

  clearInMemoryDocumentCache()
    Clear the rhFileDocumentCache property.

    Return 1.

  podFromFile(file => $file)
    Return the pod in $file as text, or die on errors.

    Die if $file doesn't exist.

  oLocationSmartGoTo(file => $fileOrigin, row => $row, col => $row)
    Look in $file at location $row/$col and determine what is there.
    Depending on what's there, find the source declaration/whatever, find it
    and return an Devel::PerlySense::Document::Location object.

    Currently supported:

      $self->method, look in current file and base classes. If no sub can
      be found, look for POD.

      $object->method, look in current file and used modules. If no sub
      can be found, look for POD.

      Module::Name (bareword)

      Module::Name (as the only contents of a string literal)

    If there's nothing at $row/col, or if the source can't be found, return
    undef.

    Die if $file doesn't exist, or on other errors.

  oLocationSmartDoc(file => $fileOrigin, row => $row, col => $row)
    Look in $file at location $row/$col and determine what is there.
    Depending on what's there, find the documentation for it and return a
    Document::Location object with the following rhProperty keys set:

      text - the docs text
      found - "method" | "module"
      docType - "hint" | "document"
      name - the name of the thing found

    Currently supported:

      Same as for oLocationSmartGoTo

    If there's nothing at $row/col, use the current document.

    Die if $file doesn't exist, or on other errors.

  oLocationMethodDocFromDocument($oDocument, $method)
    Look in $oDocument and find the documentation for it and return a
    Document::Location object with the following rhProperty keys set:

      text - the docs text
      found - "method" | "module"
      docType - "hint" | "document"
      name - the name of the thing found

    If possible, also set "pod" and "podHeading".

    Return undef if no doc could be found.

    Currently, only POD is regarded as documentation. Todo: fail to listing
    an example/abstracted invocation of the method.

    Die on errors.

  oLocationMethodDefinitionFromDocument(oDocument => $oDocument, nameClass => $nameClass, nameMethod => $method)
    Look in $oDocument and find the declaration for $nameMmethod and return
    a Document::Location object.

    Return undef if no declaration could be found.

    Die on errors.

  rhRegexExample(file => $fileOrigin, row => $row, col => $row)
    Look in $file at location $row/$col and find the regex located there,
    and possibly the example comment preceeding it.

    Return hash ref with (keys: regex, example; values: source string). The
    source string is an empty string if nothing found.

    If there is an example string in a comment, return the example without
    the comment #

    Die if $file doesn't exist, or on other errors.

  raFileTestOther(file => $fileSource, [sub => $sub])
    Return array ref with file names of files related to $file and possibly
    $sub, i.e. the "other" files related to $file.

    If $file is a source file, return test files, and vice verca.

    $sub is only ever active when $fileSource is a source file.

    Die if Devel::CoverX::Covered isn't installed.

  raFileProjectOther(file => $fileSource)
    Return array ref with file names of files related to $file, i.e. the
    files corresponding to $file according to the .corresponding_files
    config file..

    Die if there is no config file.

  rhRunFile(file => $fileSource)
    Figure out what type of source file $fileSource is, and how it should be
    run.

    The settings in the Project's config->{run_file} is used to determine
    the details.

    Return hash ref with (keys: "dir_run_from", "command_run",
    "type_source_file"), or die on errors (like if no Project could be
    found).

    dir_run_from is an absolute file name which should be the cwd when
    command_run is executed.

    type_source_file is something like "Test", "Module".

  rhDebugFile(file => $fileSource)
    Figure out what type of source file $fileSource is, and how it should be
    debugged.

    The settings in the Project's config->{debug_file} is used to determine
    the details.

    Return hash ref with (keys: "dir_debug_from", "command_debug",
    "type_source_file"), or die on errors (like if no Project could be
    found).

    dir_debug_from is an absolute file name which should be the cwd when
    command_debug is executed.

    type_source_file is something like "Test", "Module".

  flymakeFile(file => $fileSource)
    Do a flymake run with $fileSource according to the flymake config and
    output the result to STDOUT and STDERR.

  rhSubCovered(file => $fileSource)
    Do a "covered subs" call with $fileSource in the current project.

    Return hash ref with (keys: sub name; keys: quality).

  createProject(dir => $dir)
    Create a new PerlySense Project in $dir.

    Return 1 on success, or die on errors.

  classNameAt(file => $fileOrigin, row => $row, col => $row)
    Look in $file at location $row/$col and determine what class name that
    is.

    Return the class name or "" if it's package main.

    Die if $file doesn't exist, or on other errors.

  classAt(file => $fileOrigin, row => $row, col => $row)
    Look in $file at location $row/$col and determine what PerlySelse::Class
    that is.

    Return the Class object or undef if it's package main.

    Die if $file doesn't exist, or on other errors.

  classByName(name => $name, dirOrigin => $dirOrigin)
    Find the file that contains the Class $name, starting at $dirOrigin.

    Return the Class object or undef if it couldn't be found.

    Die on errors.

  fileFindModule(nameModule => $nameModule, dirOrigin => $dirOrigin)
    Find the file containing the $nameModule given the $dirOrigin.

    Return the absolute file name, or undef if none could be found. Die on
    errors.

  oDocumentFindModule(nameModule => $nameModule, dirOrigin => $dirOrigin)
    Find the file containing the $nameModule given the $dirOrigin.

    Return a parsed PerlySense::Document, or undef if none could be found.
    Die on errors.

  isFileInProject(file => $fileSource, fileProjectOf => $fileProjectOf)
    Determine whether $fileSource is located within the current Project.

    If there is no current Project, figure it out using $fileProjectOf (that
    file should be located in the current project).

    Return true if $fileSource is in the project, else false. Die on errors.

IMPLEMENTATION METHODS
  fileFindLookingAround($fileModuleBase, $dirOrigin)
    Find the file containing the $fileModuleBase given the $dirOrigin.

    Return the file name relative to $dirOrigin, or undef if none could be
    found. Die on errors.

  dirFindLookingAround($fileModuleBase, $dirOrigin, [$raDirSub = [".", "lib", "bin"]])
    Find the dir containing the $fileModuleBase (relative file path) given
    the $dirOrigin. For all directories, also look in subdirectories in
    $raDirSub.

    Return the absolute dir name, or undef if none could be found. Die on
    errors.

  fileFindLookingInInc($fileModuleBase)
    Find the file containing the $nameModule in @INC.

    Return the absolute file name, or undef if none could be found. Die on
    errors.

  fileFromModule($nameModule)
    Return the $nameModule converted to a file name (i.e. with dirs and .pm
    extension).

  fileFoundInDir($dir, $fileModuleBase)
    Check if $fileModuleBase is located in $dir.

    Return the absolute file name, or "" if not found at $dir.

  textFromPod($pod)
    Return $pod rendered as text, or die on errors.

  oLocationRenderPodToText($oLocation)
    Render the $oLocation->rhProperty->{pod} and put it in
    rhProperty->{text}.

    Return the same (modified) $oLocation object, or undef if no
    rhProperty->{pod} property ended up as text (after this operation, there
    is content in rhProperty->{text}).

    Return undef if $oLocation is undef.

    Die on errors.

  aDocumentFindModuleWithInterface(raNameModule => $raNameModule, raMethodRequired => $raMethodRequired, raMethodNice => $raMethodNice, dirOrigin => $dirOrigin)
    Return a list with Devel::PerlySense::Document objects that support all
    of the methods in $raMethodRequired and possibly the methods in
    $raMethodNice. Look in modules in $raNameModule.

    The list is sorted with the best match first.

    If the document APIs have one or more base classes, look in the @ISA
    (depth-first, just like Perl (see perldoc perltoot)).

    Warn on some failures to find the location. Die on errors.

  aApiOfClass(file => $fileOrigin, row => $row, col => $row)
    Look in $file at location $row/$col and determine what package is there.

    Return a two item array with (Package name,
    Devel::PerlySense::Document::Api object with the likely API of that
    class), or () if none was found.

    Die if $file doesn't exist, or on other errors.

  aDocumentGrepInDir(dir => $dir, rsGrepFile => $rsGrepFile, rsGrepDocument => $rsGrepDocument)
    Return a list with Devel::PerlySense::Document objects found under the
    $dir, and that return true for the grep sub $rsGrepFile and
    $rsGrepDocument.

    If any found file couldn't be parsed, skip it silently from the list.

CACHE METHODS
  cacheSet(file => $file, key => $key, value => $valuex)
    If the oCache isn't undef, store the $value in the cache under the total
    key of ($file, $file's timestamp, $key, and the PerlySense VERSION).

    $value should be a scalar or reference which can be freezed.

    $file must be an existing file.

    Return 1 if the $value was stored, else 0. Die on errors.

  cacheGet(file => $file, key => $key)
    If the oCache isn't undef, get the value in the cache under the total
    key of ($file, $file's timestamp, $key) and return it.

    $file must be an existing file.

    Return the value, or undef if the value could not be fetched. Die on
    errors.

  cacheKeyTotal($file, $key)
    If oCache is undef, return undef.

    Otherwise, return the total key of ($file, $file's timestamp, $key, and
    the PerlySense VERSION).

    $file must be an existing file.

    Die on errors.

POD ERRORS
    Hey! The above document had some coding errors, which are explained
    below:

    Around line 357:
        Unknown directive: =over4

    Around line 359:
        '=item' outside of any '=over'

    Around line 363:
        Unknown directive: =over4

    Around line 365:
        '=item' outside of any '=over'

    Around line 371:
        Unknown directive: =over4

    Around line 373:
        '=item' outside of any '=over'

    Around line 574:
        Unknown directive: =over4

    Around line 576:
        '=item' outside of any '=over'