NAME

Class::Rebless - Rebase deep data structures

SYNOPSIS

  use Class::Rebless;

  my $beat = bless({
    one => bless({
      hey => 'ho',
    }, 'AOne'),
    two => bless({
      list => [
        bless({ three => 3 }, 'AThree'),
        bless({ four  => 4 }, 'AFour'),
        5,
        "this is just noise",
      ],
    }, 'ATwo'),
    six => {
      seven => bless({ __VALUE__ => 7}, 'ASeven'),
      eight => bless({ __VALUE__ => 8}, 'AnEight'),
    },
  }, 'AOne');

  Class::Rebless->rebase($beat, 'And');

  # $beat now contains objects of type
  # And::AOne, And::ATwo .. And::AnEight!

  Class::Rebless->rebless($beat, 'Beatless');

  # All (blessed) objects in $beat now belong to package
  # Beatless.

DESCRIPTION

Class::Rebless takes a Perl data structure and recurses through its hierarchy, reblessing objects that it finds along the way into new namespaces. This is typically useful when your object belongs to a package that is too close to the main namespace for your tastes, and you want to rebless everything down to your project's base namespace.

Class::Rebless walks scalar, array, and hash references. It uses Scalar::Util::reftype to discover how to walk blessed objects of any type.

METHODS

Class::Rebless defines only class methods. There is no instance constructor, and when calling these methods you should take care not to call them in function form by mistake; that would not do at all.

Reblessing Methods

All these methods take arguments like this:

    Class::Rebless->method($root, $namespace, \%opts);

The $root object is the place where the visitor begins to crawl the structure for things to rebless.

The $namespace is used differently by different methods, generally as the class name or partial class name into which to rebless objects. Some reblessing methods may ignore it entirely.

The \%opts hashref is a container for the rest of the options. They are:

    editor  - the coderef used to rebless;  It is called for each object
              with the object and $namespace as its argument.  This option
              is set by default by the "rebless" and "rebase" methods, and
              is in fact all they do.

    revisit - If true, the visitor will descend into references it has seen
              before.  By default, it is false, and once a reference has
              been visited once, it will not be visited again.

rebless

    Class::Rebless->rebless($myobj, "New::Namespace");

Finds all blessed objects refered to by $myobj and reblesses them into New::Namespace. This completely overrides whatever blessing they had before.

rebase

    Class::Rebless->rebase($myobj, "New::Namespace::Root");

Finds all blessed objects refered to by $myobj and reblesses them into new namespaces relative to New::Namespace::Root. This overrides whatever blessing they had before, but unlike rebless, it preseves something of the original name. So if you had an object blessed into "MyClass", it will now be blessed into "New::Namespace::Root::MyClass".

custom

    Class::Rebless->custom($myobj, "MyName", { editor => \&my_editor });

Per each visited object referenced in $myobj, calls my_editor() on it. The editor routine is passed the current object in the recursion and the wanted namespace ("MyName" in the code above). This lets you to do anything you like with each object, but is (at least nominally) intended to allow filtering out objects you don't want to rebless. 3rd party objetcs, for example:

    my $fh      = IO::File->new("data") or die "open:$!";
    my $frobber = Frotz->new({ source => $fh });
    Class::Rebless->custom($frobber, "SuperFrotz", { editor => \&noio });

    sub noio {
        my($obj, $namespace) = @_;
        return if ref($obj) =~ /^IO::/;

        bless $obj, $namespace . '::' . ref $obj;
    }

(A more realistic example might actually use an inclusion filter, not an inclusion filter.)

prune

    Class::Rebless->prune("__PRUNE__");
    Class::Rebless->custom($myobj, "MyName", { editor => \&pruning_editor });

When pruning is turned on, a custom reblesser has the opportunity to prune (skip) subtrees in the recursion of $myobj. All it needs to do to signal this is to return the string set in advance with the prune method.

This feature is useful, like custom, for when you don't want to mess with members belonging to 3rd party classes that your object might be holding. Using the noio example above, the "return" can be changed to "return '__PRUNE__'". Anything the IO object refers to will not be visited by Class::Rebless.

CAVEATS

Reblessing a tied object may produce unexpected results.

AUTHOR

Gaal Yahas <gaal@forum2.org>

Gabor Szabo <szabgab@gmail.com> has contributed many tests. Thanks!

Ricardo Signes <rjbs@cpan.org> has contributed bugfixes. Thanks!

COPYRIGHT (The "MIT" License)

Copyright 2004-2011 Gaal Yahas.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.