fill example code stubbed out, pluss more docs;
[catagits/HTML-Zoom.git] / t / fill.t
index 4c2901e..715fc7d 100644 (file)
--- a/t/fill.t
+++ b/t/fill.t
@@ -57,4 +57,447 @@ ok my $title = sub {
   return $z;
 };
 
+{
+  ok my $z = HTML::Zoom
+    ->from_html(q[<ul><li>Test</li></ul>])
+    ->select('ul')
+    ->repeat_content(
+      [
+        sub { $_->select('li')->replace_content('Real Life1') },
+        sub { $_->select('li')->replace_content('Real Life2') },
+        sub { $_->select('li')->replace_content('Real Life3') },
+      ],
+    )
+    ->to_html;
+
+  is $z, '<ul><li>Real Life1</li><li>Real Life2</li><li>Real Life3</li></ul>',
+    'Got correct from repeat_content';
+}
+
+{
+  ok my $z = HTML::Zoom
+    ->from_html(q[<ul><li>Test</li></ul>])
+    ->select('ul')
+    ->repeat_content([
+      map { my $i = $_; +sub {$_->select('li')->replace_content("Real Life$i")} } (1,2,3)
+    ])
+    ->to_html;
+
+  is $z, '<ul><li>Real Life1</li><li>Real Life2</li><li>Real Life3</li></ul>',
+    'Got correct from repeat_content';
+}
+
+
+use HTML::Zoom::CodeStream;
+sub code_stream (&) {
+  my $code = shift;
+  return sub {
+    HTML::Zoom::CodeStream->new({
+      code => $code,
+    });
+  }
+}
+
+{
+  my @list = qw(foo bar baz);
+  ok my $z = HTML::Zoom
+    ->from_html(q[<ul><li>Test</li></ul>])
+    ->select('ul')
+    ->repeat_content(code_stream {
+      if (my $name = shift @list) {
+        return sub { $_->select('li')->replace_content($name) };
+      } else {
+        return
+      }
+    })
+    ->to_html;
+  
+  is $z, '<ul><li>foo</li><li>bar</li><li>baz</li></ul>',
+    'Got correct from repeat_content';
+}
+
+{
+  my @list = qw(foo bar baz);
+  ok my $z = HTML::Zoom
+    ->from_html(q[<ul><li>Test</li></ul>])
+    ->select('ul')
+    ->repeat_content(sub {
+      HTML::Zoom::CodeStream->new({
+        code => sub {
+          if (my $name = shift @list) {
+            return sub { $_->select('li')->replace_content($name) };
+          } else {
+            return
+          }
+        }
+      });
+    })
+    ->to_html;
+  
+  is $z, '<ul><li>foo</li><li>bar</li><li>baz</li></ul>',
+    'Got correct from repeat_content';
+}
+
+{
+  use Scalar::Util ();
+  my $next_item_from_array = sub {
+    my @items = @_;
+    return sub { shift @items };      
+  };
+  
+  my $next_item_from_proto = sub {
+    my $proto = shift;
+    if (
+      ref $proto eq 'ARRAY' ||
+      ref $proto eq 'HASH' ||
+      Scalar::Util::blessed($proto)
+    ) {
+      return $next_item_from_array->($proto, @_);
+    } elsif(ref $proto eq 'CODE' ) {
+      return $proto;
+    } else {
+      die "Don't know what to do with $proto, it's a ". ref($proto);
+    }
+  };
+  
+  my $normalize_targets = sub {
+    my $targets = shift;
+    my $targets_type = ref $targets;
+    return $targets_type eq 'ARRAY' ? $targets
+      : $targets_type eq 'HASH' ? [ map { +{$_=>$targets->{$_}} } keys %$targets ]
+        : die "targets data structure ". ref($targets). " not understood";
+  };
+  
+  my $replace_from_hash_or_object = sub {
+    my ($datum, $value) = @_;
+    return ref($datum) eq 'HASH' ?
+      $datum->{$value} : $datum->$value; 
+  };
+  
+  my $fill = sub {
+    my ($zoom, $targets, @rest) = @_;
+    $zoom->repeat_content(sub {
+      my $itr = $next_item_from_proto->(@rest);
+      $targets = $normalize_targets->($targets);
+      HTML::Zoom::CodeStream->new({
+        code => sub {
+          my $cnt = 0;
+          if(my $datum = $itr->($zoom, $cnt)) {
+            $cnt++;
+            return sub {
+              for my $idx(0..$#{$targets}) {
+                my $target = $targets->[$idx];
+                my ($match, $replace) = do {
+                  my $type = ref $target;
+                  $type ? ($type eq 'HASH' ? do { 
+                      my ($match, $value) = %$target;
+                      ref $value eq 'CODE' ?
+                        ($match, $value->($datum, $idx, $_))
+                        : ($match, $replace_from_hash_or_object->($datum, $value));
+                    } : die "What?")
+                    : do {
+                        ref($datum) eq 'ARRAY' ?
+                        ($target, $datum->[$idx]) :
+                        ( '.'.$target, $replace_from_hash_or_object->($datum, $target));
+                      };
+                };
+                $_ = $_->select($match)
+                  ->replace_content($replace);                
+              } $_;
+            };
+          } else {
+            return;
+          }
+        },
+      });
+    });
+  };
+  
+  {
+    ok my $z = HTML::Zoom
+      ->from_html(q[<ul><li class="even">Even</li><li class="odd">Odd</li></ul>])
+      ->select('ul')
+      ->$fill(
+        ['.even','.odd'],
+        [0,1],
+        [2,3],
+      ), 'Made Zoom object from array';
+      
+    is(
+      $z->to_html,
+      '<ul><li class="even">0</li><li class="odd">1</li><li class="even">2</li><li class="odd">3</li></ul>',
+      'Got correct from repeat_content'
+    );  
+  }
+  
+  {
+    my @items = ( [0,1], [2,3] );
+    ok my $z = HTML::Zoom
+      ->from_html(q[<ul><li class="even">Even</li><li class="odd">Odd</li></ul>])
+      ->select('ul')
+      ->$fill(
+        ['.even','.odd'],
+        sub { shift @items }
+      ), 'Made Zoom object from itr';
+      
+    for my $cnt (1..2) {
+      is(
+        $z->to_html,
+        '<ul><li class="even">0</li><li class="odd">1</li><li class="even">2</li><li class="odd">3</li></ul>',
+        'Got correct from repeat_content: '.$cnt
+      );
+      ok(
+         (@items = ( [0,1], [2,3] )),
+         'Reset the items array'
+      );
+    }
+  }
+  
+  {
+    ok my $z = HTML::Zoom
+      ->from_html(q[<ul><li class="even">Even</li><li class="odd">Odd</li></ul>])
+      ->select('ul')
+      ->$fill(
+        [
+          {'.even' => sub { my ($i,$cnt,$z) = @_; return $i->[0]; } },
+          {'.odd' => sub { my ($i,$cnt,$z) = @_; return $i->[1]; } },         
+        ],
+        [0,1],
+        [2,3],
+      ), 'Made Zoom object from code style';
+
+    for my $cnt (1..2) {
+      is(
+        $z->to_html,
+        '<ul><li class="even">0</li><li class="odd">1</li><li class="even">2</li><li class="odd">3</li></ul>',
+        'Got correct from repeat_content: '.$cnt
+      );
+    }
+  }
+  
+  {
+    ok my $z = HTML::Zoom
+      ->from_html(q[<ul><li class="even">Even</li><li class="odd">Odd</li></ul>])
+      ->select('ul')
+      ->$fill(
+        [
+          {'.even' => sub { my ($i,$cnt,$z) = @_; return $i->{even}; } },
+          {'.odd' => sub { my ($i,$cnt,$z) = @_; return $i->{odd}; } },         
+        ],
+        { even => 0, odd => 1},
+        { even => 2, odd => 3},        
+      ), 'Made Zoom object from code style';
+
+    for my $cnt (1..2) {
+      is(
+        $z->to_html,
+        '<ul><li class="even">0</li><li class="odd">1</li><li class="even">2</li><li class="odd">3</li></ul>',
+        'Got correct from repeat_content: '.$cnt
+      );
+    }
+  }
+  
+  {
+    ok my $even_or_odd = sub {
+      my ($i,$cnt,$z) = @_;
+      return $cnt % 2 ? $i->{odd} : $i->{even};
+    };
+    
+    ok my $z = HTML::Zoom
+      ->from_html(q[<ul><li class="even">Even</li><li class="odd">Odd</li></ul>])
+      ->select('ul')
+      ->$fill(
+        [
+          {'.even' => $even_or_odd },
+          {'.odd' => $even_or_odd },         
+        ],
+        { even => 0, odd => 1},
+        { even => 2, odd => 3},        
+      ), 'Made Zoom object from code style';
+
+    for my $cnt (1..2) {
+      is(
+        $z->to_html,
+        '<ul><li class="even">0</li><li class="odd">1</li><li class="even">2</li><li class="odd">3</li></ul>',
+        'Got correct from repeat_content: '.$cnt
+      );
+    }
+  }
+  
+  {
+    ok my $even_or_odd = sub {
+      my ($i,$cnt,$z) = @_;
+      return $cnt % 2 ? $i->{odd} : $i->{even};
+    };
+    
+    ok my $z = HTML::Zoom
+      ->from_html(q[<ul><li class="even">Even</li><li class="odd">Odd</li></ul>])
+      ->select('ul')
+      ->$fill(
+        [
+          map { +{$_ => $even_or_odd} } qw(.even .odd),
+        ],
+        { even => 0, odd => 1},
+        { even => 2, odd => 3},        
+      ), 'Made Zoom object from code style';
+
+    for my $cnt (1..2) {
+      is(
+        $z->to_html,
+        '<ul><li class="even">0</li><li class="odd">1</li><li class="even">2</li><li class="odd">3</li></ul>',
+        'Got correct from repeat_content: '.$cnt
+      );
+    }
+  }
+  
+  {
+    {
+      package Test::HTML::Zoom::EvenOdd;
+        
+      sub new {
+        my $class = shift;
+        bless { _e=>$_[0], _o=>$_[1] }, $class; 
+      }
+        
+      sub even { shift->{_e} }
+      sub odd { shift->{_o} }
+    }
+    
+    ok my $even_or_odd = sub {
+      my ($i,$cnt,$z) = @_;
+      return $cnt % 2 ? $i->odd : $i->even;
+    };
+    
+    ok my $z = HTML::Zoom
+      ->from_html(q[<ul><li class="even">Even</li><li class="odd">Odd</li></ul>])
+      ->select('ul')
+      ->$fill(
+        [
+          map { +{$_ => $even_or_odd} } qw(.even .odd),
+        ],
+        Test::HTML::Zoom::EvenOdd->new(0,1),
+        Test::HTML::Zoom::EvenOdd->new(2,3),
+      ), 'Made Zoom object from code style';
+
+    for my $cnt (1..2) {
+      is(
+        $z->to_html,
+        '<ul><li class="even">0</li><li class="odd">1</li><li class="even">2</li><li class="odd">3</li></ul>',
+        'Got correct from repeat_content: '.$cnt
+      );
+    }
+  }
+
+  {
+    ok my $z = HTML::Zoom
+      ->from_html(q[<ul><li class="even">Even</li><li class="odd">Odd</li></ul>])
+      ->select('ul')
+      ->$fill(
+        [
+          { '.even' => 'even'},
+          { '.odd' => 'odd'},
+        ],
+        { even => 0, odd => 1},
+        { even => 2, odd => 3},        
+      ), 'Made Zoom object from declare accessors style';
+
+    for my $cnt (1..2) {
+      is(
+        $z->to_html,
+        '<ul><li class="even">0</li><li class="odd">1</li><li class="even">2</li><li class="odd">3</li></ul>',
+        'Got correct from repeat_content: '.$cnt
+      );
+    }
+  }
+
+  {
+    ok my $z = HTML::Zoom
+      ->from_html(q[<ul><li class="even">Even</li><li class="odd">Odd</li></ul>])
+      ->select('ul')
+      ->$fill(
+        [
+          { '.even' => 'even'},
+          { '.odd' => 'odd'},
+        ],
+        Test::HTML::Zoom::EvenOdd->new(0,1),
+        Test::HTML::Zoom::EvenOdd->new(2,3),        
+      ), 'Made Zoom object from declare accessors style';
+
+    for my $cnt (1..2) {
+      is(
+        $z->to_html,
+        '<ul><li class="even">0</li><li class="odd">1</li><li class="even">2</li><li class="odd">3</li></ul>',
+        'Got correct from repeat_content: '.$cnt
+      );
+    }
+  }
+
+  {
+    ok my $z = HTML::Zoom
+      ->from_html(q[<ul><li class="even">Even</li><li class="odd">Odd</li></ul>])
+      ->select('ul')
+      ->$fill(
+        {
+          '.even' => 'even',
+          '.odd' => 'odd'
+        },
+        Test::HTML::Zoom::EvenOdd->new(0,1),
+        Test::HTML::Zoom::EvenOdd->new(2,3),        
+      ), 'Made Zoom object from declare accessors style';
+
+    for my $cnt (1..2) {
+      is(
+        $z->to_html,
+        '<ul><li class="even">0</li><li class="odd">1</li><li class="even">2</li><li class="odd">3</li></ul>',
+        'Got correct from repeat_content: '.$cnt
+      );
+    }
+  }
+  
+  ## Helper for when you have a list of object or hashs and you just want to map
+  ## target classes to accessors
+  
+  {
+    ok my $z = HTML::Zoom
+      ->from_html(q[<ul><li class="even">Even</li><li class="odd">Odd</li></ul>])
+      ->select('ul')
+      ->$fill(
+        { map { ".".$_ => $_ } qw(even odd) },
+        Test::HTML::Zoom::EvenOdd->new(0,1),
+        Test::HTML::Zoom::EvenOdd->new(2,3),        
+      ), 'Made Zoom object from declare accessors style';
+
+    for my $cnt (1..2) {
+      is(
+        $z->to_html,
+        '<ul><li class="even">0</li><li class="odd">1</li><li class="even">2</li><li class="odd">3</li></ul>',
+        'Got correct from repeat_content: '.$cnt
+      );
+    }
+  }
+
+  ## if the target is arrayref but the data is a list of objects or hashes, we
+  ## guess the target is a class form of the target items, but use the value of
+  ## the item as the hash or object accessor
+  
+  {
+    ok my $z = HTML::Zoom
+      ->from_html(q[<ul><li class="even">Even</li><li class="odd">Odd</li></ul>])
+      ->select('ul')
+      ->$fill(
+        [qw(even odd)],
+        Test::HTML::Zoom::EvenOdd->new(0,1),
+        Test::HTML::Zoom::EvenOdd->new(2,3),        
+      ), 'Made Zoom object from declare accessors style';
+
+    for my $cnt (1..2) {
+      is(
+        $z->to_html,
+        '<ul><li class="even">0</li><li class="odd">1</li><li class="even">2</li><li class="odd">3</li></ul>',
+        'Got correct from repeat_content: '.$cnt
+      );
+    }
+  }
+}
+
 done_testing;