NAME

Para::Frame::List - Methods for list manipulation

SYNOPSIS

# The right way:

  my $list = Para::Frame::List->new( \@biglist );
  my( $value, $error ) = $list->get_first;
  while(! $error )
  {
    # ... my code
  }
  continue
  {
    ( $value, $error ) = $list->get_next;
  }

# The risky way, for lists that doesn't contain false values:

  my $list = Para::Frame::List->new( \@biglist );
  $list->reset; # if used before...
  while( my $value = $list->get_next_nos )
  {
    # ... my code
  }

# The lazy way:

  my $list = Para::Frame::List->new( \@biglist );
  foreach my $value ( $list->as_array )
  {
    # ... my code
  }

DESCRIPTION

LOOK! REDEFINES shift, push, pop, unshift, splice, join, index

The object is overloaded to be used as a ref to the list it contains. All list operations can be used as usual. Example:

  my $l = Para::Frame::List->new( \@biglist );
  my $first_element = $l->[0];
  my $last_element = pop @$l;

The iteration methods is compatible with (and inherits from) Template::Iterator. (The iterator status codes are taken from Template::Constants.)

CGI query parameters reserved for use with some methods are:

  order
  direction
  table_page

BACKGROUND

Since Para::Frame is built for use with Template, it implements the Template::Iterator class.

But this class is extanded to provide more useful things. Primarely:

 * Iteration
 * Initialize list elements on demand
 * Split list into pages
 * Access metadata about the list
 * Modify the list

There are a large amount of diffrent implementation of iterators and List classes. I will try to keep the method names clear and mention choises from other modules.

This module is subclassable.

We should implement all methods in a way that allow subclasses to only initiate and hold the specified used parts in memory, maby by using tie.

TODO: Implement the rest of the array modification methods()

TODO: Use a tied array var for overload, in order to update metadata on change.

Subclasses that don't want to load the whole list in memory should implement:

  max()
  size()
  get_next_raw()
  get_prev_raw()

Subclasses that want to construct the list on demand should implement:

  populate_all()

new

  $l = $class->new( \@list )

  $l = $class->new( \@list, \%params )

Availible params are:

  page_size      (default is 20 )
  display_pages  (default is 10 )
  limit_pages    (default is 0 == unlimited)
  limit          (default is 0 == unlimited)
  limit_display  (default is 0 == unlimited)
  materializer   (default is undef == list is material)
  type           (default is undef)
  allow_undef    (default is undef)

The first argument may be a Para::Frame::List object, in which case it's content is copied to this new list.

If the first argument is undef, the list is marked as unpopulated

See also: /set_materializer

Compatible with Template::Iterator/new.

Returns:

A an object blessed in $class

new_any

  $l = $class->new( $any )

  $l = $class->new( $any, \%params )

The same as /new but accepts more forms of lists.

If $any is a Para::Frame::List object, or an array ref, it will be sent to the /new constructor.

For all other defined values of $any, it will be taken as a list of that single element and sent to /new as [$any].

If $any is undef, the constructor /new_empty will be used.

new_empty

  $l = $class->new_empty()

This is an optimized form of /new that is faster and more memory efficient than /new but should behave in the same way.

init

  $l->init

Called by /new for additional initializing. Subclasses can use this for filling the list with data or adding more properties.

set_materializer

  $l->set_materializer( $materializer )

The materializer can be used to format an element before it's returned from the list. This can be used for turning a record id to an object. With a materializer, the objectification or formatting of the data can be done on demand which will save a lot of computation in the case of large lists like search results.

$materializer should be a subref that takes the params $l, $i where $i is the index of the element to materialize. The materializer sub should return the materialized form of the element.

See /materialize_all and /new.

Returns:

The given $materializer subref.

as_arrayref

  $l->as_arrayref()

See also /get_all and /as_list. Most other modules misses a comparable method.

This method is used by the array dereferencing overload.

Returns:

A ref to the internal list of elements returned by /materialize_all.

concatenate

implemented concatenate_by_overload()

stringify

stringify_by_overload() method defined

as_raw_arrayref

  $l->as_arrayref()

Returns the internal arrayref to the unmaterialized elements.

as_list

  $l->as_list()

Compatible with Template::Iterator.

See also /get_all and /elements.

Returns:

A ref to the internal list of elements returned by /materialize_all.

as_listobj

  $l->as_listobj()

Retruns: the object itself

as_array

  $l->as_array()

Similar to List::Object/array and IO::Handle/getlines. See also /get_all and /as_list.

Returns:

The list as a list. (Not a ref) (And not realy an array either...)

as_raw_array

  $l->as_raw_array()

Returns the unmaterialized list as a list of elements (not ref).

populate_all

  $l->populate_all()

Reimplement this if the content should be set on demand in a subclass.

Returns:

The raw data listref of unmateralized elements.

on_populate_all

  $l->on_populate_all()

materialize_all

  $l->materialize_all()

If /materializer is set, calls it for each unmaterialized element and returns a ref to an array of the materialized elements

In no materialization is needed, just returns the existing data as an array ref.

from_page

  $l->from_page( $pagenum )
  $l->from_page

Returns a ref to a list of elements corresponding to the given $page based on the /page_size. If no $pagenum is given, takes the value from query param table_page or 1.

... I have looked at Array::Window but will not use it.

slice

  $l->slice( $start )
  $l->slice( $start, $end )
  $l->slice( $start, $end, \%args )

Similar to Class::DBI::Iterator/slice.

If %args is not given, clones the args of $l.

Uses /set_index and /get_next_raw and /index.

Returns:

A Para::Frame::List created with the same /type, /allow_undef and /materializer args.

set_index

  $l->set_index($pos)

Similar to Tie::Array::Iterable/set_index and IO::Seekable/seek. Most iterator classes doesn't have a comparable method.

Valid positions range from -1 (before first element) to $size + 1 (after last element).

If $pos is -1, calls /reset.

store

  $l->store

Stores the object in the session for later retrieval by Para::Frame::Session/list

id

DEPRECATED

  $l->id

Returns the id given to this object from /store in the Para::Frame::Session.

list_id

  $l->list_id

Returns the id given to this object from /store in the Para::Frame::Session.

pages

  $l->pages

Returns the number of pages this list will take given /page_size.

page_size

  $l->page_size

Returns the page_size set for this object.

pagelist

  $l->pagelist( $pagenum )
  $l->pagelist

Returns a widget for navigating between the pages. If no $pagenum is given, takes the value from query param table_page or 1.

If only one page, returns an empty string.

Example:

  [% USE Sorted_table('created','desc') %]
  [% usertable = cached_select_list("from users order by $order $direction") %]
  <table>
    <tr>
      <th>[% sort("Skapad",'created','desc') %]</th>
      <th>[% sort("Namn",'username') %]</th>
    </tr>
    <tr><th colspan="2">[% usertable.size %] users</th></tr>
    <tr><th colspan="2"> [% usertable.pagelist %]</th></tr>
  [% FOREACH user IN usertable.from_page %]
    [% tr2 %]
      <td>[% user.created %]</td>
      <td>[% user.name %]</td>
    </tr>
  [% END %]
  </table>

This uses Para::Frame::Template::Plugin::Sorted_table, Para::Frame::DBIx/cached_select_list, Para::Frame::Template::Components/sort, /size, this pagelist, Template::Manual::Directives/Loop Processing and Para::Frame::Template::Components/tr2.

pagenum

  $l->pagenum

Returns the current page number, as given by the query param table_page.

set_page_size

  $l->set_page_size( $page_size )

Sets and returns the given $page_size

display_pages

  $l->display_pages

Returns how many pages that should be listed by /pagelist.

set_display_pages

Sets and returns the given /display_pages.

set_limit_pages

Sets and returns the given /limit_pages.

limit_pages

  $l->limit_pages

Returns the last page number that should be listed by /pagelist.

limit_display

  $l->limit_display

Returns how many results that will be shown then listed as pages

set_limit_display

Sets and returns the given /limit_display.

as_string

  $l->as_string

Returns a string representation of the list. Using as_string for elements that isn't plain scalars.

set_limit

  $l->set_limit( $limit )

Limit the number of elements in the list.

A limit of $limit or undef means no limit.

Setting a limit smaller than the original length will make the elements beyond the limit unavailible, if they already was populated. Later setting a larger limit will not make more of the elements availible.

The limit is applied directly.

The number of elements before the applied limit, if known, can be retrieved from /original_size.

The limit may be larger than the elements in the list.

Similar to IO::Seekable/truncate except that it doesn't delete anything. Similar to limit in SQL.

TODO: Check for limit on array change

Returns:

The limit set, or 0

limit

  $l->limit()

Returns:

The current limit set by /set_limit

get_first

  $l->get_first

The first record is returned, if defined, along with the STATUS_OK value. If there is no target data, or the data is an empty set, then undef is returned with the STATUS_DONE value as the second element in the return list.

Compatible with Template::Iterator. Similar to List::Object/first and Class::DBI::Iterator/first. Not the same as ouer /first.

Calls /reset if the iterator index isn't at the start (at -1).

get_first_nos

  $l->get_first_nos

The same as /get_first except that it only returns ONE value, that may be undef.

get_last

  $l->get_last

The last record is returned, if defined, along with the STATUS_OK value. If there is no target data, or the data is an empty set, then undef is returned with the STATUS_DONE value as the second element in the return list.

Similar to List::Object/last. Not the same as ouer /last.

get_last_nos

  $l->get_last_nos

The same as /get_last except that it only returns ONE value, that may be undef.

reset

  $l->reset()

Sets the index to -1, before the first element.

Similar to Array::Iterator::Reusable/reset, Class::DBI::Iterator/reset, Class::PObject::Iterator/reset, Tie::Array::Iterable/from_start and List::Object/rewind.

Returns:

true

get_next

  $l->get_next()

Called repeatedly to access successive elements in the data set. Is usually called after calling /get_first.

Compatible with Template::Iterator/get_next. Most other Iterator classes call this method next(). But our /next is not the same.

Similar to List::Object/next, Array::Iterator/getNext, Class::DBI::Iterator/next, Class::PObject::Iterator/next, Tie::Array::Iterable/next, Iterator/value, IO::Seekable/getline and Java next().

This method is implemented with /get_next_raw and /materialize.

Returns

The next element and a status as the two elements in the return list

get_next_nos

  $l->get_next_nos()

The same as /get_next except that it only returns ONE value, that may be undef. (Get Next with NO Status)

get_next_raw

  $l->get_next_raw()

Used as a backend for /get_next.

Increments the index.

Returns:

The next element and a status

get_prev

  $l->get_prev()

May be called after calling /get_last.

Similar to Array::Iterator::BiDirectional/getPrevious, Tie::Array::Iterable/prev and Java previous().

See also /prev.

This method is implemented with /get_prev_raw and /materialize.

Returns

The prev element and a status as the two elements in the return list

get_prev_nos

  $l->get_prev_nos()

The same as /get_prev except that it only returns ONE value, that may be undef.

get_prev_raw

  $l->get_prev_raw()

Used as a backend for /get_prev.

Returns:

The prev element and decrement the index.

get_all

  $l->get_all

Method which returns all remaining items in the iterator as a Perl list reference. May be called at any time in the life-cycle of the iterator. The /get_first method will be called automatically if necessary, and then subsequent /get_next calls are made, storing each returned result until the list is exhausted.

Compatible with Template::Iterator/get_all.

Sets the index on the last element. (Not the place after the element.)

Returns:

A ref to an array of the remaining elements, materialized.

If iterator already at the last index or later, returns undef as the first value and Template::Constants/STATUS_DONE as the second.

size

  $l->size()

Similar to List::Object/count, Array::Iterator/getLength, Class::DBI::Iterator/count, Class::MakeMethods::Template::Generic/count and java getSize().

Compatible with Template::Iterator/size and Template::Manual::VMethods/List Virtual Methods

Returns:

The number of elements in this list

size_limited

  $l->size_limited()

Returns: the /size, constraining to given /limit_display

original_size

max

  $l->max

Returns the maximum index number (i.e. the index of the last element) which is equivalent to size() - 1.

Compatible with Template::Iterator/max and Template::Manual::VMethods/List Virtual Methods

max_limited

  $l->max_limited()

Returns: the /max, constraining to given /limit_display

index

  $l->index()

Returns the current index number which is in the range 0 to max().

Template::Iterator/index has the range 0 to /max. This module allows the range -1 to /max+1.

Similar to Array::Iterator/currentIndex, Tie::Array::Iterable/index, IO::Seekable/tell and Java getPosition.

Heres hoping that nothing breaks...

count

  $l->count()

Returns the current iteration count in the range 1 to size(). This is equivalent to index() + 1.

Compatible with Template::Iterator/count.

first

  $l->first

Returns a boolean value to indicate if the iterator is currently on the first iteration of the set. Ie, index 0.

Compatible with Template::Iterator/first and Template::Manual::VMethods/List Virtual Methods

.

Similar to Array::Iterator::Circular/isStart and Tie::Array::Iterable/at_start.

See also /get_first.

last

  $l->last

Returns a boolean value to indicate if the iterator is currently on the last iteration of the set.

Compatible with Template::Iterator/last and Template::Manual::VMethods/List Virtual Methods

Similar to Array::Iterator::Circular/isEnd, Iterator/is_exhausted, Tie::Array::Iterable/at_end and IO::Seekable/eof.

See also /get_last.

prev

  $l->prev

Returns the previous item in the data set, or undef if the iterator is on the first item.

This does not change the iterator index.

Compatible with Template::Iterator/prev.

Similar to Array::Iterator::BiDirectional/lookBack.

See also /get_prev.

next

  $l->next

Returns the next item in the data set or undef if the iterator is on the last item.

This does not change the iterator index.

Compatible with Template::Iterator/next.

has_next

 $l->has_next

Similar to List::Object/has_next, Array::Iterator/hasNext and Java hasNext.

Returns:

A bool

has_prev

 $l->has_prev

Similar to Array::Iterator::BiDirectional/hasPrevious and Java hasPrevious.

Returns:

A bool

current

  $l->current()

Similar to Array::Iterator/current and Tie::Array::Iterable/value.

Implemented with /get_next

Returns:

The element (materialized) at the current index.

get_by_index

  $l->get_by_index( $index )

Similar to List::Object/get.

Implemented with /set_index and /get_next.

Returns:

The element (materialized) at $index. (First element has index 0).

Or undef

clear

  $l->clear()

Similar to List::Object/clear

obj_as_string

randomized

  $l->randomized

Doesn't modify the object

Returns:

A new list with the content in random order, but with the same properties

set_type

The class or datatype of all the content in the list

 TODO: Validate content with this

clone_props

shift

pop

unshift

push

  $l->push( @elements )

Returns: The number of elements added

push_uniq

  $l->push_uniq( @elements )

Only add elements not already in the list

Returns: The number of elements added

unshift_uniq

  $l->unshift_uniq( @elements )

Only add elements not already in the list

Returns: The number of elements added

join

  $l->join()

  $l->join($separator)

$separator defaults to the empty string.

Returns: A scalar string of all elements concatenated

Compatible with Template::Manual::VMethods/List Virtual Methods

complement

  $l->complement($l2)

Returns a list with the elements from $l not found in $l2

uniq

  $l->uniq()

Returns a list with multiple list items filtered out. Operates on the unmaterialized items. If nothing filtered, returns the same object.

merge

  $l->merge( $list2, $list3, ... )

Returns a list composed of zero or more other lists. The original lists are not modified. Filters out parametrs that are not lists. Always returns a new list, even if it has the same content as the calling list.

Uses the cloned args of the calling list.

Compatible with Template::Manual::VMethods/List Virtual Methods

reverse

  $l->reverse()

Returns a list composed of the items in reverse order.

Uses the cloend args of the calling list.

Compatible with Template::Manual::VMethods/List Virtual Methods

flatten

  $l->flatten()

Creates a new list with any list elements flatten to it's elements. Recursively. Flattens Para::Frame::List objs and unblessed arrayrefs.

Always returns a new list object of the same class and with the same properties.

TODO: Make this a materializer function, to handle large lists

sorted_on

resort

  $list->resort( ... )

Same as /sorted, but modifies the existing object, rather than creating a new object.

If no params given, the cgi params order and direction will be used.

Will not resort if the object sortkey property is the same

Returns:

The same list object

sysdesig

  $l->sysdesig

Return a SCALAR string with the elements sysdesignation concatenated with ' / '.

sum

  $l->sum

sorted

  $list->sorted()

  $list->sorted( $attr )

  $list->sorted( $attr, $dir, $type )

  $list->sorted( [$attr1, $attr2, ...] )

  $list->sorted( [$attr1, $attr2, ...], $dir, $type )

  $list->sorted( { on => $attr, dir => $dir, type => $type } )

  $list->sorted( [{ on => $attr1, dir => $dir1, type => $type1 },
                  { on => $attr2, dir => $dir2, type => $type2 },
                  ...
                 ] )

Returns a list of object, sorted by the selected proprty of the object.

This method assumes that the list only contains objects and that all of them has a similar interface.

The default sorting attribute is the stringification of the object (or the string itself if it's not an object).

$dir is the direction of the sort. It can be asc or desc.

$attr can be of the form a1.a2.a3 which translates to an attribute lookup in several steps. For example; $list-sorted('email.host')>

The sorting will be done as strings with <cmp>. You can get a string sort by using $type numeric.

Examples:

Loop over the name arcs of a node, sorted by firstly on the is_of_language code and secondly on the weight in reverse order:

  [% FOREACH arc IN n.arc_list('name').sorted(['obj.is_of_language.code',{on='obj.weight' dir='desc'}]) %]

Returns:

A List object with 0 or more elements.

Exceptions:

Dies if given faulty parameters.

AUTOLOAD

  $l->$method( @args )

SEE ALSO

Para::Frame, DBI