Skip to content

Instantly share code, notes, and snippets.

/clone.diff Secret

Created October 23, 2015 14:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/37bdd5888b4a9a91d5d0 to your computer and use it in GitHub Desktop.
Save anonymous/37bdd5888b4a9a91d5d0 to your computer and use it in GitHub Desktop.
diff --git a/Changes b/Changes
index d508b80..84af113 100644
--- a/Changes
+++ b/Changes
@@ -1,5 +1,7 @@
6.26 2015-10-23
+ - Improved performance of DOM manipulation methods in Mojo::DOM significantly
+ when working with existing Mojo::DOM objects.
6.25 2015-10-21
- Deprecated Mojo::Message::Request::proxy with boolean and string arguments
diff --git a/lib/Mojo/DOM.pm b/lib/Mojo/DOM.pm
index 2bda8b1..39ff943 100644
--- a/lib/Mojo/DOM.pm
+++ b/lib/Mojo/DOM.pm
@@ -15,6 +15,7 @@ use Mojo::DOM::CSS;
use Mojo::DOM::HTML;
use Mojo::Util 'squish';
use Scalar::Util qw(blessed weaken);
+use Storable 'dclone';
sub all_text { shift->_all_text(1, @_) }
@@ -280,7 +281,17 @@ sub _offset {
sub _parent { $_[0]->tree->[$_[0]->type eq 'tag' ? 3 : 2] }
-sub _parse { Mojo::DOM::HTML->new(xml => shift->xml)->parse(shift)->tree }
+sub _parse {
+ my ($self, $html) = @_;
+
+ return Mojo::DOM::HTML->new(xml => $self->xml)->parse($html)->tree
+ unless blessed $html && $html->isa('Mojo::DOM');
+
+ my $clone = dclone $html->tree;
+ return $clone if $clone->[0] eq 'root';
+ _link(['root', $clone], my $parent = ['root', $clone]);
+ return $parent;
+}
sub _replace {
my ($self, $parent, $tree, $new) = @_;
@@ -499,6 +510,7 @@ All selectors from L<Mojo::DOM::CSS/"SELECTORS"> are supported.
=head2 append
+ $dom = $dom->append(Mojo::DOM->new);
$dom = $dom->append('<p>I ♥ Mojolicious!</p>');
Append HTML/XML fragment to this node.
@@ -513,6 +525,7 @@ Append HTML/XML fragment to this node.
=head2 append_content
+ $dom = $dom->append_content(Mojo::DOM->new);
$dom = $dom->append_content('<p>I ♥ Mojolicious!</p>');
Append HTML/XML fragment (for C<root> and C<tag> nodes) or raw content to this
@@ -583,6 +596,7 @@ All selectors from L<Mojo::DOM::CSS/"SELECTORS"> are supported.
=head2 content
my $str = $dom->content;
+ $dom = $dom->content(Mojo::DOM->new);
$dom = $dom->content('<p>I ♥ Mojolicious!</p>');
Return this node's content or replace it with HTML/XML fragment (for C<root>
@@ -766,6 +780,7 @@ node as L<Mojo::DOM> objects.
=head2 prepend
+ $dom = $dom->prepend(Mojo::DOM->new);
$dom = $dom->prepend('<p>I ♥ Mojolicious!</p>');
Prepend HTML/XML fragment to this node.
@@ -780,6 +795,7 @@ Prepend HTML/XML fragment to this node.
=head2 prepend_content
+ $dom = $dom->prepend_content(Mojo::DOM->new);
$dom = $dom->prepend_content('<p>I ♥ Mojolicious!</p>');
Prepend HTML/XML fragment (for C<root> and C<tag> nodes) or raw content to this
@@ -836,6 +852,7 @@ Remove this node and return L</"root"> (for C<root> nodes) or L</"parent">.
=head2 replace
+ my $parent = $dom->replace(Mojo::DOM->new);
my $parent = $dom->replace('<div>I ♥ Mojolicious!</div>');
Replace this node with HTML/XML fragment and return L</"root"> (for C<root>
@@ -970,6 +987,7 @@ if none could be found.
=head2 wrap
+ $dom = $dom->wrap(Mojo::DOM->new);
$dom = $dom->wrap('<div></div>');
Wrap HTML/XML fragment around this node, placing it as the last child of the
@@ -989,6 +1007,7 @@ first innermost element.
=head2 wrap_content
+ $dom = $dom->wrap_content(Mojo::DOM->new);
$dom = $dom->wrap_content('<div></div>');
Wrap HTML/XML fragment around this node's content, placing it as the last
diff --git a/t/mojo/dom.t b/t/mojo/dom.t
index b6c01a9..8f9d058 100644
--- a/t/mojo/dom.t
+++ b/t/mojo/dom.t
@@ -462,7 +462,7 @@ $dom = Mojo::DOM->new('<div>foo<p>lalala</p>bar</div>');
is $dom->at('p')->replace('<foo>bar</foo>'), '<div>foo<foo>bar</foo>bar</div>',
'right result';
is "$dom", '<div>foo<foo>bar</foo>bar</div>', 'right result';
-$dom->at('foo')->replace(Mojo::DOM->new('text'));
+$dom->at('foo')->replace(Mojo::DOM->new('text')->child_nodes->first);
is "$dom", '<div>footextbar</div>', 'right result';
$dom = Mojo::DOM->new('<div>foo</div><div>bar</div>');
$dom->find('div')->each(sub { shift->replace('<p>test</p>') });
@@ -490,7 +490,8 @@ is $dom->at('div')->replace('<p>♥</p>')->root, '<p>♥</p>', 'right result';
is $dom->to_string, '<p>♥</p>', 'right result';
is $dom->replace('<b>whatever</b>')->root, '<b>whatever</b>', 'right result';
is $dom->to_string, '<b>whatever</b>', 'right result';
-$dom->at('b')->prepend('<p>foo</p>')->append('<p>bar</p>');
+$dom->at('b')->prepend(Mojo::DOM->new('<p>foo</p>')->at('p'))
+ ->append(Mojo::DOM->new('<p>bar</p>')->at('p'));
is "$dom", '<p>foo</p><b>whatever</b><p>bar</p>', 'right result';
is $dom->find('p')->map('remove')->first->root->at('b')->text, 'whatever',
'right result';
@@ -1268,7 +1269,8 @@ is "$dom", <<EOF, 'right result';
</ul>
<div>D</div>works
EOF
-$dom->at('li')->prepend_content('A3<p>A2</p>')->prepend_content('A4');
+$dom->at('li')->prepend_content('A3<p>A2</p>')
+ ->prepend_content(Mojo::DOM->new('A4')->child_nodes->first);
is $dom->at('li')->text, 'A4A3 A', 'right text';
is "$dom", <<EOF, 'right result';
<ul>
@@ -2100,7 +2102,8 @@ is $dom->wrap('<b></b>')->type, 'root', 'right type';
is "$dom", '<b><a>Test</a></b>', 'right result';
is $dom->at('b')->strip->at('a')->wrap('A')->tag, 'a', 'right tag';
is "$dom", '<a>Test</a>', 'right result';
-is $dom->at('a')->wrap('<b></b>')->tag, 'a', 'right tag';
+is $dom->at('a')->wrap(Mojo::DOM->new('<b></b>')->at('b'))->tag, 'a',
+ 'right tag';
is "$dom", '<b><a>Test</a></b>', 'right result';
is $dom->at('a')->wrap('C<c><d>D</d><e>E</e></c>F')->parent->tag, 'd',
'right tag';
@@ -2110,7 +2113,8 @@ is "$dom", '<b>C<c><d>D<a>Test</a></d><e>E</e></c>F</b>', 'right result';
$dom = Mojo::DOM->new('<a>Test</a>');
is $dom->at('a')->wrap_content('A')->tag, 'a', 'right tag';
is "$dom", '<a>Test</a>', 'right result';
-is $dom->wrap_content('<b></b>')->type, 'root', 'right type';
+is $dom->wrap_content(Mojo::DOM->new('<b></b>')->at('b'))->type, 'root',
+ 'right type';
is "$dom", '<b><a>Test</a></b>', 'right result';
is $dom->at('b')->strip->at('a')->tag('e:a')->wrap_content('1<b c="d"></b>')
->tag, 'e:a', 'right tag';
@@ -2440,7 +2444,7 @@ is $dom->at(' :not( #foo ) ')->text, 'works', 'right text';
# "0"
$dom = Mojo::DOM->new('0');
is "$dom", '0', 'right result';
-$dom->append_content('☃');
+$dom->append_content(Mojo::DOM->new('☃')->child_nodes->first);
is "$dom", '0☃', 'right result';
is $dom->parse('<!DOCTYPE 0>'), '<!DOCTYPE 0>', 'successful roundtrip';
is $dom->parse('<!--0-->'), '<!--0-->', 'successful roundtrip';
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment