Must exist, right?

2008-06-18 Thread Andy Armstrong

I assume there's a module that works like this?

package MyFoo;

use Data::Auto::Objectify::Thing qw( my_data_field );

sub new {
bless {
my_data_field = {
foo = [ 1, 2, 3 ],
bar = { eat = 'drink', sleep = 'wake' },
}
  },
  shift;
}

package main;

my $my_foo = MyFoo-new;

my $two = $my_foo-foo( 1 );
my $eat = $my_foo-bar-eat;

In other words I want it to synthesise accessors based on the contents  
of a complex data structure. For bonus points it might also allow


# Can use subscript notation for hashes
my $eat = $my_foo-bar('eat');

And maybe allow multiple subscripts so that, for example, if I had a  
field called 'grid' that contained a rectangular array I could then do


my $point = $my_bar-grid(3, 5);

It's got to exist, right? I had a look but there are so many  
^(?:Object|Data)::.* modules that it's a bit hard to see the wood for  
the trees :)


--
Andy Armstrong, Hexten



Re: Must exist, right?

2008-06-18 Thread Andy Armstrong

On 19 Jun 2008, at 00:35, Andy Armstrong wrote:
It's got to exist, right? I had a look but there are so many  
^(?:Object|Data)::.* modules that it's a bit hard to see the wood  
for the trees :)



Ah. I see:

 http://search.cpan.org/dist/Class-AutoAccess/

But that creates accessor/mutators. I want to generate read only  
accessors and have any arguments to them interpreted as a path into  
the data structure below the point referred to by the accessor.


--
Andy Armstrong, Hexten






Re: Must exist, right?

2008-06-18 Thread Eric Wilhelm
# from Andy Armstrong
# on Wednesday 18 June 2008 16:35:

use Data::Auto::Objectify::Thing qw( my_data_field );

     sub new {
         bless {
             my_data_field = {
                 foo = [ 1, 2, 3 ],
                 bar = { eat = 'drink', sleep = 'wake' },
...

     my $two = $my_foo-foo( 1 );
     my $eat = $my_foo-bar-eat;

You want something like Object::Accessor, but without needing to 
actually create the object?

Assuming you could be bothered to call new() for the sub-object (passing 
it to the contructor, etc), just about anything including Moose would 
work ;-)  I'll let the more Moose-enabled folks comment on how 
a 'default' sub (or some other setup) would do exactly what you want.

--Eric
-- 
It ain't those parts of the Bible that I can't understand that
bother me, it's the parts that I do understand.
--Mark Twain
---
http://scratchcomputing.com
---


Re: Must exist, right?

2008-06-18 Thread David Nicol
Considering that Data::Dumper is entirely regular in how it will
present a deconstruction of the data structure, and you have a clear
concept of how you wish the example structure === accessor set thing
to work, it's certainly possible, and would take maybe two hacking
sessions to get right (provided you don't get swept into the lake by a
mini-tsunami.)

It seems like something that might not exist already, as the need to
share that kind of meta-abstraction is felt by only extreme show-offs
(such as various people on this list)

To make your example DWITYM, Data::Auto::Objectify::Thing would presume that
the structure returned by its caller has a Cnew that will return a
fully populated example object when called with no arguments, and
would postpone defining the accessors until the INIT phase, because
the {caller()::'new'} does not exist yet at Cimport time.

I would have Data::Auto::Objectify::Thing take an optional C example
= ...  import arg in addition to the wait-until-INIT trick, and
would bless the substructures into constructed-named packages under
Data::Auto::Objectify::Thing::Packages::... for example.

Tipjar::fields creates accessors for named fields by imposing array
object semantics on its calling package; recently I prefer to use
:lvalue subroutines for accessors rather than defining both get* and
put* s.

In your example, you are planning on subclassing MyFoo into a whole
family of kinds of hash-based objects that share this accessor set, or
something.  It's not clear if the elements are supposed to be
extensible or not.  If they aren't extensible, and there is a fixed
set of them, using an array-based object and naming all the slots with
lvalue accessors is the way I would do it

sub new { bless [], shift };
BEGIN{
   my $counter = -1;
   eval join '' map {$counter++; ACCESSOR} (qw/one two three eat sleep/)
   sub $_ : lvalue { shift()-[$counter] }
ACCESSOR
};

but of course I don't know exactly what you are trying to do.


Re: Must exist, right?

2008-06-18 Thread Andy Armstrong

On 19 Jun 2008, at 01:14, Eric Wilhelm wrote:

You want something like Object::Accessor, but without needing to
actually create the object?


Yup. I want a read-only object with dynamically generated per object  
methods that reflect the internal data structure.


Assuming you could be bothered to call new() for the sub-object  
(passing

it to the contructor, etc), just about anything including Moose would
work ;-)  I'll let the more Moose-enabled folks comment on how
a 'default' sub (or some other setup) would do exactly what you want.



I really /must/ look at Moose properly soon :)

--
Andy Armstrong, Hexten






Re: Must exist, right?

2008-06-18 Thread Andy Armstrong

On 19 Jun 2008, at 01:18, David Nicol wrote:

Considering that Data::Dumper is entirely regular in how it will
present a deconstruction of the data structure, and you have a clear
concept of how you wish the example structure === accessor set thing
to work, it's certainly possible, and would take maybe two hacking
sessions to get right (provided you don't get swept into the lake by a
mini-tsunami.)


Yeah, I've been sort of passively thinking about how to do it for a  
little while. I don't think it's too hard but I don't want to reinvent  
the wheel.



It seems like something that might not exist already, as the need to
share that kind of meta-abstraction is felt by only extreme show-offs
(such as various people on this list)


:)

To make your example DWITYM, Data::Auto::Objectify::Thing would  
presume that

the structure returned by its caller has a Cnew that will return a
fully populated example object when called with no arguments, and
would postpone defining the accessors until the INIT phase, because
the {caller()::'new'} does not exist yet at Cimport time.


I was thinking the accessors would be completely dynamic - AUTOLOADed.  
So creation of the data structure can happen at any time before you  
start calling accessors.



I would have Data::Auto::Objectify::Thing take an optional C example
= ...  import arg in addition to the wait-until-INIT trick, and
would bless the substructures into constructed-named packages under
Data::Auto::Objectify::Thing::Packages::... for example.


I wasn't thinking of making dynamic packages at all. See above.


Tipjar::fields creates accessors for named fields by imposing array
object semantics on its calling package; recently I prefer to use
:lvalue subroutines for accessors rather than defining both get* and
put* s.

In your example, you are planning on subclassing MyFoo into a whole
family of kinds of hash-based objects that share this accessor set, or
something.  It's not clear if the elements are supposed to be
extensible or not.  If they aren't extensible, and there is a fixed
set of them, using an array-based object and naming all the slots with
lvalue accessors is the way I would do it



I basically want to be able to create read only 'value' objects that  
wrap a data structure that's created dynamically at runtime. A  
concrete example: I've just written some code that parses a formatted  
summary of memory usage for a server product. There are five named  
metrics for each of around 30 named categories of memory usage. My  
code just parses what it finds - it doesn't know any of the names  
ahead of time and the names might change as the product evolves.


I'd like the object that falls out of the end to let me do e.g.:

 print $mem-relay_buffer-allocations;

instead of

 print $mem-get('relay_buffer', 'allocations');

which is how it looks at the moment.

--
Andy Armstrong, Hexten






Re: Must exist, right?

2008-06-18 Thread Chris Dolan

On Jun 18, 2008, at 6:35 PM, Andy Armstrong wrote:


I assume there's a module that works like this?


[snip]

It's got to exist, right? I had a look but there are so many ^ 
(?:Object|Data)::.* modules that it's a bit hard to see the wood  
for the trees :)


--
Andy Armstrong, Hexten



Implemented!  See the attached .pm file and the test.pl file that  
verifies the four snipped use cases.  It could certainly be made more  
readable, but my interest is waning quickly.  :-)  I hereby grant  
anyone permission to use/extend this crappy code under the same  
license terms as Perl itself.


Chris


package MyFoo;

use Data::Auto::Objectify::Thing qw( my_data_field );

sub new {
   bless {
  my_data_field = {
 foo = [ 1, 2, 3 ],
 bar = { eat = 'drink', sleep = 'wake' },
 grid = [
[1,2,3,4,5,6], [7,8,9,10,11,12],
[13,14,15,16,17,18], [19,20,21,22,23,24],
 ],
  }
   },
   shift;
}

package main;
use Test::More tests = 4;

my $my_foo = MyFoo-new;

is($my_foo-foo( 1 ), 2);
is($my_foo-bar-eat, 'drink');
is($my_foo-bar('eat'), 'drink');
is($my_foo-grid(3, 5), 24);


package Data::Auto::Objectify::Thing;
use warnings;
use strict;
use Carp;
use Data::Dumper;

sub import {
   my ($pkg, $fieldname) = @_;
   my $caller_pkg = caller(0);
   no strict 'refs';
   *{$caller_pkg . '::AUTOLOAD'} = sub {
  my ($self, @args) = @_;
  my $autoload = do {
 no strict 'vars';
 $AUTOLOAD;
  };
  return if $autoload =~ /::DESTROY$/;
  my ($fn) = $autoload =~ m/([^:]+)\z/xms;
  if (defined $fieldname) {
 $self = $self-{$fieldname};
  }
  if (!exists $self-{$fn}) {
 croak 'No such field ' . $fn;
  }
  my $field = $self-{$fn};
  if (!ref $field) {
 return $field;
  }
  if ('ARRAY' eq ref $field) {
 $field = $field-[$_] for @args;
 return $field;
  }
  my $obj = bless {xyzzy = $field}, 'Data::Auto::Objectify::Thing::anon';
  $obj = $obj-$_() for @args;
  return $obj;
   };
   return;
}

package Data::Auto::Objectify::Thing::anon;
Data::Auto::Objectify::Thing-import('xyzzy');
1;