Subject: | [patch] add indices to speed up find_input on large forms |
The attached patch implements a set of indices (on input name, id, and class) to significantly speed up the find_input call for large forms. It also adds a test for a previously-untested case: that when changing the name of an input, the input is findable through the new name.
Subject: | 0001-add-indices-to-speed-up-find_input-on-large-forms.patch |
From 1a2fd8c106fd27b11706974cd82d93da40fba18b Mon Sep 17 00:00:00 2001
From: Gianni Ceccarelli <gianni.ceccarelli@net-a-porter.com>
Date: Tue, 19 May 2015 11:49:00 +0100
Subject: [PATCH] add indices to speed up find_input on large forms
---
lib/HTML/Form.pm | 50 +++++++++++++++++++++++++++++++++++++++++++-------
t/form-selector.t | 3 ++-
2 files changed, 45 insertions(+), 8 deletions(-)
mode change 100644 => 100755 t/form-selector.t
diff --git a/lib/HTML/Form.pm b/lib/HTML/Form.pm
index 0d3797f..7ec7fa0 100644
--- a/lib/HTML/Form.pm
+++ b/lib/HTML/Form.pm
@@ -490,11 +490,18 @@ input with the given name and/or type.
sub find_input
{
my($self, $name, $type, $no) = @_;
+ my $inputs;
+ if (defined $name) {
+ $name="^$name" unless $name=~m{^[#.^]};
+ $inputs=$self->{'inputs-by-key'}{$name};
+ }
+ else {
+ $inputs=$self->{inputs};
+ }
if (wantarray) {
my @res;
my $c;
- for (@{$self->{'inputs'}}) {
- next if defined($name) && !$_->selected($name);
+ for (@$inputs) {
next if $type && $type ne $_->{type};
$c++;
next if $no && $no != $c;
@@ -505,8 +512,7 @@ sub find_input
}
else {
$no ||= 1;
- for (@{$self->{'inputs'}}) {
- next if defined($name) && !$_->selected($name);
+ for (@$inputs) {
next if $type && $type ne $_->{type};
next if --$no;
return $_;
@@ -868,9 +874,27 @@ sub add_to_form
{
my($self, $form) = @_;
push(@{$form->{'inputs'}}, $self);
+ $self->{form}=$form;
+ $self->_add_to_form_by_key($form,'^',$self->name);
+ $self->_add_to_form_by_key($form,'#',$self->id);
+ $self->_add_to_form_by_key($form,'.',$self->class);
$self;
}
+sub _add_to_form_by_key {
+ my ($self,$form,$prefix,$key)=@_;
+ return unless defined $key;
+ push(@{$form->{'inputs-by-key'}{$prefix.$key}},$self);
+}
+
+sub _del_from_form_by_key {
+ my ($self,$form,$prefix,$key)=@_;
+ return unless defined $key;
+
+ @{$form->{'inputs-by-key'}{$prefix.$key}}=
+ grep {$_ ne $self} @{$form->{'inputs-by-key'}{$prefix.$key}};
+}
+
sub strict {
my $self = shift;
my $old = $self->{strict};
@@ -933,7 +957,11 @@ sub name
{
my $self = shift;
my $old = $self->{name};
- $self->{name} = shift if @_;
+ if (@_) {
+ $self->_del_from_form_by_key($self->{form},'^',$old);
+ $self->{name}=shift;
+ $self->_add_to_form_by_key($self->{form},'^',$self->{name});
+ }
$old;
}
@@ -941,7 +969,11 @@ sub id
{
my $self = shift;
my $old = $self->{id};
- $self->{id} = shift if @_;
+ if (@_) {
+ $self->_del_from_form_by_key($self->{form},'#',$old);
+ $self->{id}=shift;
+ $self->_add_to_form_by_key($self->{form},'#',$self->{id});
+ }
$old;
}
@@ -949,7 +981,11 @@ sub class
{
my $self = shift;
my $old = $self->{class};
- $self->{class} = shift if @_;
+ if (@_) {
+ $self->_del_from_form_by_key($self->{form},'.',$old);
+ $self->{class}=shift;
+ $self->_add_to_form_by_key($self->{form},'.',$self->{class});
+ }
$old;
}
diff --git a/t/form-selector.t b/t/form-selector.t
old mode 100644
new mode 100755
index 9cba445..5cdcec4
--- a/t/form-selector.t
+++ b/t/form-selector.t
@@ -3,7 +3,7 @@
use strict;
use Test qw(plan ok);
-plan tests => 12;
+plan tests => 13;
use HTML::Form;
@@ -35,6 +35,7 @@ ok(j(map $_->value, $form->find_input(".A")), "1:2");
$form->find_input("#id2")->name("n2");
$form->value("#id2", 22);
ok($form->click->uri->query, "n1=1&n2=22");
+ok($form->value('n2'),22);
# try some odd names
ok($form->find_input("##foo")->name, "#bar");
--
2.0.5