package Data::AsObject;

use warnings;
use strict;
use Carp;
use Scalar::Util qw(reftype blessed);
use Data::AsObject::Hash;
use Data::AsObject::Array;

use base 'Exporter';
our @EXPORT = qw(dao);

our $VERSION = '0.01';

our $__check_type = sub {
	my $data = shift;
	return unless $data;

	my $type = reftype($data);

	if (defined $type) {
		if ( $type eq "ARRAY" && ( !blessed($data) || ref($data) eq "Data::AsObject::Array" ) ) {
			return "ARRAY";
		} elsif ( $type eq "HASH" && ( !blessed($data) || ref($data) eq "Data::AsObject::Hash" ) ) {
			return "HASH";
		} else {
			return "";
		}
	} else {
		return "";
	}
};

sub dao {
	my @args = @_;
	my @result;

	foreach my $data (@args) {

		my $type = reftype($data);
		my $dao;
	
		if ($type eq "ARRAY") {
			$dao = bless $data, "Data::AsObject::Array"
			push @result, $dao;
		} elsif ($type eq "HASH") {
			$dao = bless $data, "Data::AsObject::Hash";
		} else {
			carp "Invalid argument to dao: must be hashref or arrayref!";
			$dao = undef;
		}
		push @result, $dao;
	}

	return @result;

}

1; 

=head1 NAME

Data::AsObject - Easy OO access to complex perl data structures

=head1 VERSION

Version 0.01

=head1 SYNOPSIS

	use Data::AsObject qw(dao);
	
	my $book = dao { 
		name      => "Programming Perl",
		authors   => ["Larry Wall", "Tom Christiansen", "Jon Orwant"],
	};
    
	print $book->name              # prints "Programming Perl"
	print $book->authors(0)        # prints "Larry Wall"
	my $array_ref = $book->authors # $array_ref is ["Larry Wall", "Tom Christiansen", "Jon Orwant"]
	my @array = $book->authors     # @array is ("Larry Wall", "Tom Christiansen", "Jon Orwant")
	$book->{publisher} = "O'Reilly";
	print $book->publisher         # prints "O'Reilly"

=head1 DESCRIPTION

C<Data::AsObject> provides easy object-oriented access to complex and arbitrarily nested perl data structures. It is particulary suitable for working with hash-based representation of XML data, as generated by modules like L<XML::Complie> or L<XML::TreePP>.

=head1 FUNCTIONS

=head2 dao

Takes as input one or more hash or array references, and returns one or more objects (C<Data::AsObject::Hash> or C<Data::AsObject::Array> respectively) that can be used to access the data structures via an object oriented interface. Exported by default.

=head1 USAGE

=head2 Working with hashes

To access hash elements by key, use the hash key as method name:

	my $data = dao { three => { two => { one => "kaboom" } } };
	print $data->three->two->one; # kaboom

In scalar context, a hash reference is returned as a reference, and in list context, as a list:

	my $data = dao { 
		one => { en => "one", de => "ein", es => "uno" }, 
		two => { en => "two", de => "zwei", es => "dos" },
	};

	my $hasref = $data->one; # { en => "one", de => "ein", es => "uno" }, 
	my %hash = $data->two; # ( en => "two", de => "zwei", es => "dos" ),

So if you want to pass a hashref as an argument to a subroutine, you will have to put some extra effort and do one of the following:

	foo( {$data->one} );

or

	my $hashref = $data->one;
	foo($hashref);

Alternatively you ca do:

	foo( $data->{one} );

but you get no guarantee whether this will fetch you a plain hashref or a C<Data::AsObject::Hash> object.

=head2 Working with arrays

To access array items pass the item index as an argument to the hash that contains the array:

	my $data = dao {
		uk => ["one", "two", "three", "four"],
		spain => [ 
			{ name => 'spanish', numbers => ["uno", "dos", "tres", "cuatro"] },
			{ name => 'catalan', numbers => ["un", "dos", "tres", "quatre"] },
		];
	};

	print $data->en(1) # two
	print $data->spain(0)->numbers(3); # cuatro

In scalar context, an array reference is returned as a reference, and in list context, as a list:

	foreach my $n ( $data->spain(1)->numbers ) {
		print $n . " ";
	} # un dos tres quatre

Array of array structures are a little bit clumsier to work with. You will need to use the C<get> method of C<Data::AsObject::Array> and pass it the index of the item you want to access:

	my $data = dao [
		["one", "two", "three", "four"]
		["uno", "dos", "tres", "cuatro"],
		["un", "dos", "tres", "quatre"],
	];

	print $data->get(2)->get(0); # un

If your base reference is an arrayref, you can fetch all its elements in list context via the C<all> method:

	my $data = dao [1, 2, 3];
	my @array = $data->all # same as: my @array = @$data

=head2 Modifying data

C<Data::AsObject> only provides accessor functions. To modify data, access the respective hash or array element directly:

	my $data = dao {};
	$data->{one} = "uno";
	print $data->one # uno

Note that the accessor methods return references to the underlying data structure rather than clones:

	my $data = dao {};
	my $copy = $data;

	$data->{one} = "uno";
	print $copy->one # uno

=head2 Autovivification

No autovivification is performed. An attempt to access a hash or array element that does not exist will issue a warning and return undef.

=head2 C<Data::AsObject::Hash> and special methods

If C<$data> isa C<Data::AsObject::Hash>:

=over

=item can

Attempts to call C<$data-E<gt>can("some_method_name")> will always return C<undef>, regardless of whether a C<$data-E<gt>{"some_method_name"}> hash key exists or not.

=item others special methods

All other special methods and functions (C<isa>, C<ref>, C<DESTROY>) should behave as expected.

=back

=head1 AUTHOR

Petar Shangov, C<< <pshangov at yahoo.com> >>

=head1 BUGS

This is still considered alpha-stage software, so problems are expected. Please report any bugs or feature requests to C<bug-data-object at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Data-Object>.  I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.


=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Data::Object

You can also look for information at:

=over 4

=item * RT: CPAN's request tracker

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Data-Object>

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/Data-Object>

=item * CPAN Ratings

L<http://cpanratings.perl.org/d/Data-Object>

=item * Search CPAN

L<http://search.cpan.org/dist/Data-Object/>

=back


=head1 SEE ALSO

L<Hash::AsObject>

=head1 COPYRIGHT & LICENSE

Copyright 2009 Petar Shangov, all rights reserved.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

=cut


