in reply to Can I share instance through Moose::Role ?

This part seems wrong because you're bypassing Moose's constructor. (And constructors are one of the key selling points for using Moose.)

sub TIEHASH { my $class = shift; my $self = bless {},$class; while(my($key,$value) = each(%ENV)) { $self->set_node($key => $value); } return $self; }

Instead, I'd write that as:

sub TIEHASH { my $class = shift; my $self = $class->new; while(my($key,$value) = each(%ENV)) { $self->set_node($key => $value); } return $self; }

So TIEHASH just becomes a wrapper for the Moose constructor.

As well as constructors, Moose also provides destructors, so you shouldn't be overriding the DESTROY method that Moose provides for you. Luckily, you've misspelt it as DESTORY, so no harm done.

To answer your question, this is how package A should be written:

package A; use Moose; has BBB => ( is => 'rw', lazy => 1, builder => '_build_BBB', handles => [qw( get_node )], ); sub _build_BBB { my $self = shift; my $instance = tie(%ENV, 'BBB'); return $instance; }

And this is how you'd use it:

my $a = A->new; print $a->get_node('TERM'), "\n";

Note that I've ditched your bind_vars method in favour of using a lazy builder for the BBB attribute. When the value of BBB is needed, Moose will automatically run the _build_BBB method to populate it. This means that code outside the A class doesn't need to remember to manually call the bind_vars method in order to bring the object into a usable state.

That said, I'm not sure why you're mucking around with trying to tie %ENV anyway. Nothing you've shown demonstrates a need for tying. This seems far simpler:

use v5.14; package MyRole { use Moose::Role; has nodes => ( traits => ['Hash'], is => 'rw', isa => 'HashRef[Item]', handles => { set_node => 'set', get_node => 'get', all_nodes => 'keys', } ); } package BBB { use Moose; with 'MyRole'; } package A { use Moose; has BBB => ( is => 'rw', lazy => 1, default => sub { BBB->new(nodes => \%ENV) }, handles => [qw( get_node )], ); } my $a = A->new; say $a->get_node('TERM');
use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

Replies are listed 'Best First'.
Re^2: Can I share instance through Moose::Role ?
by Anonymous Monk on Feb 10, 2014 at 14:06 UTC

    Hello tobyink,

    Thanks for your reply, your solution is simple and elegance. Regarding "tie" function, I was tried to track other scripts that may change %ENV in that way, and now it seems much simple to do this in modifiers. :)

      When you write \%ENV you get a "live" reference to the hash %ENV. Any further changes to %ENV will be reflected in \%ENV.

      Example:

      $ENV{FOO} = 1; my $ref = \%ENV; # Change something in %ENV $ENV{FOO} = 2; print $ref->{FOO}, "\n"; # prints 2.

      If you actually need to check other scripts changing %ENV, you're out of luck. That's not how Unix environment variables work. Each process gets its own copy of the environment, cloned from its parent process. Any changes it makes to its environment cannot be seen by its parent process, nor its sibling processes. Its child processes will of course see the changes in their own cloned copies of the environment, but they cannot pass back any of their own changes.

      If you actually need to communicate changes to %ENV between processes, then you need to look into interprocess communication (IPC). This is usually accomplished by reading from and writing to Unix sockets (which are essentially filehandles used for communication between processes on the same machine) or TCP sockets (which are Unix sockets generalized to work over the Internet).

      use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

        Hi tobyink,

        Thanks for your great help. Those details are really helpful to me and other people.