user3767853
user3767853

Reputation: 293

Using a function to retrieve values from an object or hash

How can I break down the values and return them separately so I can access them separately?

I have a forum system with a database that keeps track of all posts in a thread. I have a sub called notice_value:

sub notice_value {
    my ($self,$prefid,$value,$others_post,$clients_post,$assigned_tasks) = @_;

    $self->{PREFS}->{$prefid} = { VALUE => $value,
                                  OTHERS_POST => $others_post,
                                  CLIENTS_POST => $clients_post,
                                  ASSIGNED_TASKS => $assigned_tasks };
    return $self->{PREFS}->{$prefid};
}

EDIT- original notice_value

sub notice_value {
    my $self = shift;
    my $prefid = shift;
    $self->{PREFS}->{$prefid} = shift if(@_);
    return $self->{PREFS}->{$prefid};
} 

-------------------------------------------------------------

Which retrieves the user's preferences, one of which is the markup type VALUE. When I call on the markup type I use $self->markup it calls on this - sub markup_type which is a method in Taskman::Post:

sub markup_type {
    my $self = shift;
    $self->{MARKUP_TYPE} = shift if(@_);
    $self->{MARKUP_TYPE};
}

My problem is that I only want to retrieve the VALUE from notice_value but instead it returns the whole thing like so -- When I dumped $self I got:

$VAR1 = bless( {
                 'POST_TYPE_ID' => 1,
                 'MINUTES' => '0',
                 'DEADLINE' => '2014-05-19 18:04:00',
                 'ESTIMATE' => 300,
                 'COMMENT' => 'sd',
                 'POSTER' => 1286,
                 'STATE_ID' => 14,
                 'CONTRACTID' => 546,
                 'PRIORITY' => '3',
                 'MARKUP_TYPE' => {
                                    'VALUE' => 1,
                                    'OTHERS_POST' => 1,
                                    'CLIENTS_POST' => 1,
                                    'ASSIGNED_TASKS' => 1
                                  },
                 'TID' => 23133,
                 'OWNER' => '1286'
               }, 'Taskman::Post' );

I want to be able to access the other values(OTHERS_POST,CLIENTS_POST,ASSIGNED_TASKS) separately as well for other functions.

I'm kind of new to Perl and am a little confused on how to break up the notice_value sub so that I can retrieve what I want from it more efficiently and correctly. If you can show an example too that would be great.

EDIT

this is the sub that calls on the notice_value:

sub __populate {
    my $self = shift;

    my $sth = $self->{dbh}->prepare("select prefid, value, others_post, clients_post, assigned_tasks from user_preferences where userid=?");
    $sth->execute($self->userid);
    while(my $href = $sth->fetchrow_hashref()) {

        $self->notice_value($href->{PREFID}, $href->{VALUE}, $href->{OTHERS_POST}, $href->{CLIENTS_POST}, $href->{ASSIGNED_TASKS});
    }
    $sth->finish();
}

the original __populate only had:

$self->notice_value($href->{PREFID}, $href->{VALUE});

Upvotes: 2

Views: 237

Answers (3)

David W.
David W.

Reputation: 107040

I noticed that your dump has Taskman::Post on the end of the dump. This means that this is a Taskman::Post object, and thus should have methods that will pull out the various piece of data that it contains. There might be a markup method that will pull out the information in this object.

The question is where did this object come from. Was this something you wrote? Is this a Perl module installed with your system. Was it written correctly, so that it includes POD documentation.

Try the following command:

$ perldoc Taskman::Post

If this works, it will pull up information on how to access the data contained in this Taskman::Post object that you've retrieved.

If nothing comes up, then try this command:

$ perldoc -l Taskman::Post

This will tell you if the Taskman::Post module is installed and where it exists on your system. You may have to look at this source to finagle the various methods it contains. These methods will be subroutines inside this module. Subroutines that start with an underscore are considered private and you shouldn't use them directly.

If this doesn't work, you'll need to find where this class is defined. Sometimes, people define non-module classes for use in a single program. For example, I write a program to track my employees. I create an Employee class, but instead of installing in as a separate Perl module, I simply append it to my Perl program. Look for:

package Taskman::Post

in the code. If you find it, see if the code contains POD documentation. You'll see =pod or =head1 throughout the document. If so, you can try:

$ perldoc program.pl

Where program.pl is your Perl program.

Getting back to your subroutine, are you writing this as a class? I keep seeing $self all around. This usually means that you're working with an object, so the question is what type of object is $self. For example, what does:

print "The reference \$self " . ref( $self ) . "\n";

print out?

Again, you shouldn't be manipulating an object as if it's just a reference to a hash. In fact, some developers write what are called inside out classes to prevent people from doing Data::Dumper and manipulating their classes without going through the correct methods.

I found your post a bit confusing because it sounds like you're writing non-object oriented code, but your data looks object oriented.

Are you writing object oriented code? Do you know how Perl object oriented programming works?

If you're working with everything as objects. Try to get your methods straighten out. In your markup_type subroutine, what type of object is $self. Print out ref $self and see what type of object it is.

This should help clarifying what you're working with, and should help you understand what you're actually pulling out.

Upvotes: 1

Joe McMahon
Joe McMahon

Reputation: 3382

It looks to me like you want $thing->notice_value(@all_those_arguments)->{VALUE}.

This is because the return value is

{ VALUE => $value,
  OTHERS_POST => $others_post,
  CLIENTS_POST => $clients_post,
  ASSIGNED_TASKS => $assigned_tasks }

and $thing->notice_value(@all_those_arguments) returns just this value. Will that work for you?

Upvotes: 0

G. Cito
G. Cito

Reputation: 6378

TL;DR broad guess/conclusion to a broad question: fix the return value of notice_value or the fix the way that value is used in other functions.

This question is very general and does not offer much sample code: in fact it can't post sample code almost by definition due to the wide scope of the question. It might be better to post the question as one focused on general debugging strategies (though I am not sure how well accepted those kinds of queries are on SO) or - once you have narrowed down your problem - post more specific questions about techniques for fixing what is going wrong.

And a number of things could be going wrong: shouldn't the return value of your notice_value subroutine be something like return $self->{PREFS}->{$prefid}->{VALUE};? i.e. if - guessing from the name - the subroutine is supposed to "notice" the "value" of the hash/object's MARKUP key anonymous hash key called VALUE (i.e. it is a "getter" method/function that does nothing but access values). The way it gets those values (defreferencing, accessing database etc.) is left as a implementation detail for the function. If dereferencing a data structure full of preferences is not working, and your expected behaviour changes when you change the function that access your preferences, then you are right on the right track to focus there :)

If I create a function as follows and pass it an array (leaving out the object you pass in, so I'm leaving out the $self):

sub notice_value{ 
        my ($prefid,$value,$others_post,$clients_post,$assigned_tasks) = @_; 
        $_->{PREFS}->{$prefid} = { VALUE => $value,
                                   OTHERS_POST => $others_post,
                                   CLIENTS_POST => $clients_post, 
                                   ASSIGNED_TASKS => $assigned_tasks };

        return $_->{PREFS}->{$prefid}; 
}

Now some preference and data gunk:

my @pref_and_data_goo = qw( 21323 42 213 214 2 );

Now let's see what the function does with that it creates a PREFS hash key and gives it an an anonymous hash as its value:

notice_value(@pref_and_data_goo)
    $HASH1 = {
              ASSIGNED_TASKS => 2,
              CLIENTS_POST   => 214,
              OTHERS_POST    => 213,
              VALUE          => 42
              };

What about the value of the VALUE key (I'm easily confused by the naming scheme here) or other keys in PREFS key's anonymous hash:

 notice_value(@pre_and_data_goo)->{VALUE}
 42 
 notice_value(@pre_and_data_goo)->{ASSIGNED_TASKS}
 214

If you want wrap up notice_value so it only returns the value of the VALUE key you need to tell the code of that function how to get at that nested anonymous hash key.


Now to pass a hash/object to your other function markup_type with a quick cut and paste to the re.pl (thus the odd markup e.g. re.pl$ and >):

         re.pl$ my $whacky_hash = {
              > 'POST_TYPE_ID' => 1,
              > 'MINUTES' => '0',
              > 'DEADLINE' => '2014-05-19 18:04:00',
              > 'ESTIMATE' => 300,
              > 'COMMENT' => 'sd',
              > 'POSTER' => 1286,
              > 'STATE_ID' => 14,
              > 'CONTRACTID' => 546,
              > 'PRIORITY' => '3',
              > 'MARKUP_TYPE' => {
              >                   'VALUE' => 42,
              >                   'OTHERS_POST' => 1,
              >                   'CLIENTS_POST' => 1,
              >                   'ASSIGNED_TASKS' => 1
              >                 },
              > 'TID' => 23133,
              > 'OWNER' => '1286'
              > }
         re.pl$ sub markup_type {my $self = shift; 
              > $self->{MARKUP_TYPE} = shift if(@_); 
              > $self->{MARKUP_TYPE}; }
         re.pl$ markup_type($whacky_hash)
         $HASH1 = {
                    ASSIGNED_TASKS => 1,
                    CLIENTS_POST   => 1,
                    OTHERS_POST    => 1,
                    VALUE          => 1
                    };            
         re.pl$ sub markup_type2 {my $self = shift ; 
              > $self->{MARKUP_TYPE}->{VALUE}; }            
         re.pl$ markup_type2($whacky_hash)
         42

Are you sure a change similar to this doesn't work? If you change your markup_type function to:

sub markup_type {
     my $self = shift ; 
     $self->{MARKUP_TYPE}->{VALUE}; 
}

you should get the value you want returned from that function. If this breaks other code then track down where it is used and try to find the most suitable place to try changing things. Unfortunately there's not much we can do to help you directly.

Your notice_value function takes a long set of assignments as an argument:

my ($self,$prefid,$value,$others_post,$clients_post,$assigned_tasks) = @_;

I tend not to like functions that have long list assignments since it can be hard to track values back to where they came from. Is $value supposed to be a hash reference or a code reference to the return value of markup_type or something else again? That is probably just me being easily confused since many people prefer list assignment style. Still though, this function takes a lot of arguments if all it is supposed to do is to notice_value? Are your trying If you check how notice_value gets and uses its arguments you'll be able to spot the source of the error more easily. Your EDIT addition still leaves me wondering: why $href->{VALUE} is used rather than $href->{MARKUP_TYPE}->{VALUE}.

Upvotes: 1

Related Questions