You could eliminate my $self = shift;. After all, that's just $_[0]. You could simply use $_[0]->{session} instead of constantly doing my $session = $self->{session}. That would resolve some of the receptiveness too.
However, that repetitiveness is useful for documentation purposes. When I see my $self = shift; under the sub definition, I know immediately this is a method and not a constructor or a plain vanilla subroutine.
When I write methods and constructors, my first few lines fetch the parameters. I also hide the structure or my object from my constructors and methods. It does mean writing a few more lines of code, but that code helps document what I am attempting to do. It's a great way to catch possible errors, or to help the poor schlub who has to maintain and debug my code.
For example, here's how I would do the constructor:
sub new {
my $class = shift;
my $ip = shift;
my $username = shift;
my $password = shift;
my $self = {};
bless $self, $class;
$self->ip($ip);
$self->username($username);
$self->password($password);
$self->need_enable(0);
$self->enable('');
my $session = Net::Telnet->new( Timeout => 2, Errmode => 'return' );
$self->session($session);
return $self;
}
That's a lot more writing and maybe what you'd call repetition, but...
- The first line tell you this is a constructor (
my $class = shift;).
- The next three lines tell you I expect three parameters in that order.
- There's no indication how my object is actually stored. Instead, I use methods to set each field -- something many true object oriented languages insist upon. This may mean I have a lot more methods, but it also means that if I have to munge my class' structure, I don't have to modify each and every constructor or method in order to do it.
Here's what my session method would look like:
my session {
my $self = shift;
my $session = shift;
if ( defined $session ) {
if ( not $self->isa("Net::Telnet") ) {
croak qq(Session parameter must be a "Net::Telnet" object.);
}
$self->{session} = $session;
}
return $self->{session};
}
This is the only place in my code where I mention how the session information is actually stored in my object. By creating a separate method to set/get my session, I can do a bit of testing. For example, I want to test whether or not session is a Net::Telnet object or not. And if I decide to change the way session is stored in my object, this is the only place in the code I have to touch.
Of course, now I have a lot more repetition you wanted to eliminate:
sub _command {
my $self = shift;
my $command = shift;
my $session = $self->session;
...
Taking my advice I gave at the beginning of this answer, you could eliminate a lot of repetition:
sub _command {
my $command = $_[1];
... $_[0]->{session} ... # Some line where you need session.
But, what would you gain? How easy would it be for some poor schlub to maintain your code? What if you change the way you store your session?. For example, you decide to use inside out objects. Imagine going through your code and finding things like $[0]->{session} and modify it. Talk about boring, error prone repetitious tasks!
However, all is not entirely lost. Instead of constantly repeating getter/setter methods like this:
sub some_method {
my $self = shift;
my $some_method = shift;
if ( defined $some_method ) {
$self->{some_method} = $some_method;
}
return $some_method;
}
You can use the Class::Struct module. The nice thing about Class::Struct is that it's a standard Perl module. It's already installed.
Using Class::Struct eliminates most of the getter/setter method definitions. Instead, all you need to do is write the few methods where your code is actually doing something interesting. For example, one program I have had over 40 methods associated with it, but using Class::Struct brought it down to less than 10.
Another option is Moose which is very flexible, powerful, and probably the way Perl object usage is going. It hides a lot of the getting/setting stuff and the structure of your object. There's still a lot of controversy with Moose. It is big, slow, and bulky. It can be convoluted and complex too. There are many packages like Mouse that try to eliminate a lot of the issues while losing just a few of the more esoteric features.
$self->_command('show privilege');and$self->_check_enable();. What you have there aren't method calls.blessreturns the blessed reference. You could create an entire constructor with just one statement:bless {}, shift;.