VinsWorldcom has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to write my own child class of Net::SSH2, call it 'Net::SSH2::Mine'. I thought I had a pretty good grasp of OO-programming until I encountered the object Net::SSH2 produces - I think it's called 'inside-out'?

Essentially, I'm trying to open a Net::SSH2 connection but take in a bunch of other parameters specific to the device so I was just going to store them in the returned object, but the 'inside-out object' (and I hope I'm using the right terminology) is boggling my brain.

Some Google-ing helped me write the following example code which "works", but I don't know what I may be doing right / wrong / breaking / whatever.

#!perl use strict; use warnings; package Net::SSH2::Mine; use Net::SSH2; our @ISA = qw( Net::SSH2 ); my %NSM; sub new { my $class = shift; my $self = $class->SUPER::new(); $NSM{$self} = { prompt => '#', host => 'host' }; return bless $self, $class; } sub prompt { my $self = shift; return $NSM{[keys %NSM]->[0]}->{prompt} } sub host { my $self = shift; return $NSM{[keys %NSM]->[0]}->{host} } 1; package main; my $ssh = Net::SSH2::Mine->new(); use Data::Dumper; print Dumper \$ssh; print $ssh->prompt . "\n"; print $ssh->host . "\n"; exit;

And running (on Windows 7 x64 / Strawberry Perl 5.18.1 64-bit - Net::SSH2 0.51 comes in vendor\lib) produces:

VinsWorldcom@C:\Users\VinsWorldcom\tmp> test.pl $VAR1 = \bless( do{\(my $o = 5182840)}, 'Net::SSH2::Mine' ); # host

So many questions:

  1. From the Data::Dumper output, is what I'm dealing with from Net::SSH2 an "inside-out object"?
  2. In my new(), should I be re-blessing to my class (Net::SSH2::Mine) - seems the only way to get the ->prompt and ->host accessors in main to work?
  3. Should I be storing parameters (e.g., prompt, host) a different way given this type of object?
  4. Any existing example code you could point me to?

Lastly, in an earlier version of non-working code, I was getting AUTOLOAD and DESTROY errors when calling the accessors and 'exit' in main respectively. I did read that inside-out-objects require DESTROY, do I need to do something in my Net::SSH2::Mine (sub DESTROY) to facilitate this especially since I'm adding parameters to the object?

Replies are listed 'Best First'.
Re: Child Net::SSH2 object trouble
by kcott (Archbishop) on Jun 29, 2015 at 19:45 UTC

    G'day VinsWorldcom,

    Yes, \bless( do{\(my $o = 5182840)}, 'Net::SSH2::Mine' ) certainly looks like an inside-out object.

    You said you did some searching, but didn't say what you'd read. If you haven't seen it already, you may benefit from reading (the not insubstantial) Introduction to Damian Conway's Class::Std module.

    I'm not familiar with the Net::SSH2 module: I'll leave others, better qualified, to discuss that further.

    -- Ken

      Thanks kcott.

      Like I said, I wasn't even sure what I was dealing with given my only experience with OO was blessing hashes. I'll read what you linked to - proving useful already!

Re: Child Net::SSH2 object trouble
by salva (Canon) on Jun 30, 2015 at 06:48 UTC
    I think it's called 'inside-out'?

    No, Net::SSH2 is not an inside-out based object.

    It is a wrapper for a C library. The only value objects of Net::SSH2 require on the Perl side is a pointer to the underlaying C structure representing the SSH connection and so a reference to a scalar is enough. That's quite common.

    In any case, using inheritance to redefine some methods in a class that was (at least a-priori) not designed to be used that way usually is not a good idea.

    A better approach is to use delegation, specially in Perl, where you can use AUTOLOAD (see perlsub) to generate proxy methods on the fly easyly.

Re: Child Net::SSH2 object trouble
by dasgar (Priest) on Jun 29, 2015 at 20:08 UTC

    For whatever reason, I personally had a difficult time understanding how to use Net::SSH2. But I have had no problems grasping how to use Control::CLI, which uses Net::SSH2 for SSH connections. That might be due to the fact that the syntax for Control::CLI is very similar to Net::Telnet and Win32::SerialPort - both of which I have used previously.

    Perhaps Control::CLI can help you accomplish what you're wanting to do or may be its source code could help point you in the right direction with your child class.

      Thanks dasgar!

      You inadvertently forced me to reveal my XY Problem. I have a script that does Net::Telnet::Cisco and I'm trying to add SSH access. While I can get Net::SSH2 to connect to a Cisco router and do what I want, the methods / accessors are all different than in N::T::C, forcing me to have two separate subs rather than an if/then creating a Telnet or SSH object. I thought I'd write a Net::SSH2::Cisco with a similar interface to N::T::C to help - thus my question about adding (N::T::C-like) attributes to the Net::SSH2 returned object.

      Control::CLI looks to have taken the other approach by creating a parent module for both (and more). I'll give it a look!

        Net::OpenSSH can be combined quite easyly with Net::Telnet and derived modules. Unfortunately, you seem to be running your scripts on a Windows box and Net::OpenSSH doesn't work there.