Skip to content

Commit

Permalink
Merge pull request #699 from kraih/less_autoload
Browse files Browse the repository at this point in the history
Deprecate Mojo::DOM::AUTOLOAD and Mojo::Collection::AUTOLOAD
  • Loading branch information
kraih committed Oct 29, 2014
2 parents 6a06ad6 + d60d8f5 commit 6c8e9fa
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 203 deletions.
16 changes: 5 additions & 11 deletions lib/Mojo/Collection.pm
Expand Up @@ -6,18 +6,23 @@ use Carp 'croak';
use Exporter 'import';
use List::Util;
use Mojo::ByteStream;
use Mojo::Util 'deprecated';
use Scalar::Util 'blessed';

our @EXPORT_OK = ('c');

# DEPRECATED in Tiger Face!
sub AUTOLOAD {
deprecated 'Mojo::Collection::AUTOLOAD is DEPRECATED '
. 'in favor of Mojo::Collection::pluck';
my $self = shift;
my ($package, $method) = our $AUTOLOAD =~ /^(.+)::(.+)$/;
croak "Undefined subroutine &${package}::$method called"
unless blessed $self && $self->isa(__PACKAGE__);
return $self->pluck($method, @_);
}

# DEPRECATED in Tiger Face!
sub DESTROY { }

sub c { __PACKAGE__->new(@_) }
Expand Down Expand Up @@ -331,17 +336,6 @@ Alias for L<Mojo::Base/"tap">.
Create a new collection without duplicate elements.
=head1 AUTOLOAD
In addition to the L</"METHODS"> above, you can also call methods provided by
all elements in the collection directly and create a new collection from the
results, similar to L</"pluck">.
# "<h2>Test1</h2><h2>Test2</h2>"
my $collection = Mojo::Collection->new(
Mojo::DOM->new("<h1>1</h1>"), Mojo::DOM->new("<h1>2</h1>"));
$collection->at('h1')->type('h2')->prepend_content('Test')->join;
=head1 OPERATORS
L<Mojo::Collection> overloads the following operators.
Expand Down
68 changes: 25 additions & 43 deletions lib/Mojo/DOM.pm
Expand Up @@ -14,22 +14,25 @@ use List::Util 'first';
use Mojo::Collection;
use Mojo::DOM::CSS;
use Mojo::DOM::HTML;
use Mojo::Util 'squish';
use Mojo::Util qw(deprecated squish);
use Scalar::Util qw(blessed weaken);

# DEPRECATED in Tiger Face!
sub AUTOLOAD {
deprecated
'Mojo::DOM::AUTOLOAD is DEPRECATED in favor of Mojo::DOM::children';
my $self = shift;

my ($package, $method) = our $AUTOLOAD =~ /^(.+)::(.+)$/;
croak "Undefined subroutine &${package}::$method called"
unless blessed $self && $self->isa(__PACKAGE__);

# Search children of current element
my $children = $self->children($method);
return @$children > 1 ? $children : $children->[0] if @$children;
croak qq{Can't locate object method "$method" via package "$package"};
}

# DEPRECATED in Tiger Face!
sub DESTROY { }

sub all_contents { $_[0]->_collect(_all(_nodes($_[0]->tree))) }
Expand Down Expand Up @@ -186,7 +189,8 @@ sub val {
if $type eq 'option';

# "select"
return $self->find('option[selected]')->val->flatten if $type eq 'select';
return $self->find('option[selected]')->pluck('val')->flatten
if $type eq 'select';

# "textarea"
return Mojo::Collection->new($self->text) if $type eq 'textarea';
Expand Down Expand Up @@ -416,12 +420,8 @@ Mojo::DOM - Minimalistic HTML/XML DOM parser with CSS selectors
# Find
say $dom->at('#b')->text;
say $dom->find('p')->text;
say $dom->find('[id]')->attr('id');
# Walk
say $dom->div->p->[0]->text;
say $dom->div->children('p')->first->{id};
say $dom->find('p')->pluck('text');
say $dom->find('[id]')->pluck(attr => 'id');
# Iterate
$dom->find('p[id]')->reverse->each(sub { say $_->{id} });
Expand All @@ -432,8 +432,8 @@ Mojo::DOM - Minimalistic HTML/XML DOM parser with CSS selectors
}
# Modify
$dom->div->p->last->append('<p id="c">456</p>');
$dom->find(':not(p)')->strip;
$dom->find('div p')->last->append('<p id="c">456</p>');
$dom->find(':not(p)')->pluck('strip');
# Render
say "$dom";
Expand All @@ -451,14 +451,12 @@ are lowercased and selectors need to be lowercase as well.
my $dom = Mojo::DOM->new('<P ID="greeting">Hi!</P>');
say $dom->at('p')->text;
say $dom->p->{id};
If XML processing instructions are found, the parser will automatically switch
into XML mode and everything becomes case sensitive.
my $dom = Mojo::DOM->new('<?xml version="1.0"?><P ID="greeting">Hi!</P>');
say $dom->at('P')->text;
say $dom->P->{ID};
XML detection can also be disabled with the L</"xml"> method.
Expand All @@ -480,8 +478,8 @@ Return a L<Mojo::Collection> object containing all nodes in DOM structure as
L<Mojo::DOM> objects.
# "<p><b>123</b></p>"
$dom->parse('<p><!-- Test --><b>123<!-- 456 --></b></p>')
->all_contents->grep(sub { $_->node eq 'comment' })->remove->first;
$dom->parse('<p><!-- Test --><b>123<!-- 456 --></b></p>')->all_contents
->grep(sub { $_->node eq 'comment' })->pluck('remove')->first;
=head2 all_text
Expand All @@ -492,10 +490,10 @@ Extract all text content from DOM structure, smart whitespace trimming is
enabled by default.
# "foo bar baz"
$dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->div->all_text;
$dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->at('div')->all_text;
# "foo\nbarbaz\n"
$dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->div->all_text(0);
$dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->at('div')->all_text(0);
=head2 ancestors
Expand All @@ -507,7 +505,7 @@ L<Mojo::Collection> object containing these elements as L<Mojo::DOM> objects.
All selectors from L<Mojo::DOM::CSS/"SELECTORS"> are supported.
# List types of ancestor elements
say $dom->ancestors->type;
say $dom->ancestors->pluck('type');
=head2 append
Expand Down Expand Up @@ -561,7 +559,7 @@ from L<Mojo::DOM::CSS/"SELECTORS"> are supported.
This element's attributes.
# List id attributes
say $dom->find('*')->attr('id')->compact;
say $dom->find('*')->pluck(attr => 'id')->compact;
=head2 children
Expand All @@ -584,7 +582,7 @@ Return this node's content or replace it with HTML/XML fragment (for C<root>
and C<tag> nodes) or raw content.
# "<b>Test</b>"
$dom->parse('<div><b>Test</b></div>')->div->content;
$dom->parse('<div><b>Test</b></div>')->at('div')->content;
# "<div><h1>123</h1></div>"
$dom->parse('<div><h1>Test</h1></div>')->at('h1')->content('123')->root;
Expand Down Expand Up @@ -627,10 +625,10 @@ All selectors from L<Mojo::DOM::CSS/"SELECTORS"> are supported.
my $id = $dom->find('div')->[23]{id};
# Extract information from multiple elements
my @headers = $dom->find('h1, h2, h3')->text->each;
my @headers = $dom->find('h1, h2, h3')->pluck('text')->each;
# Count all the different tags
my $hash = $dom->find('*')->type->reduce(sub { $a->{$b}++; $a }, {});
my $hash = $dom->find('*')->reduce(sub { $a->{$b->type}++; $a }, {});
# Find elements with a class that contains dots
my @divs = $dom->find('div.foo\.bar')->each;
Expand Down Expand Up @@ -800,7 +798,7 @@ L<Mojo::Collection> object containing these elements as L<Mojo::DOM> objects.
All selectors from L<Mojo::DOM::CSS/"SELECTORS"> are supported.
# List types of sibling elements
say $dom->siblings->type;
say $dom->siblings->pluck('type');
=head2 strip
Expand All @@ -826,10 +824,10 @@ Extract text content from this element only (not including child elements),
smart whitespace trimming is enabled by default.
# "foo baz"
$dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->div->text;
$dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->at('div')->text;
# "foo\nbaz\n"
$dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->div->text(0);
$dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->at('div')->text(0);
=head2 to_string
Expand All @@ -838,7 +836,7 @@ smart whitespace trimming is enabled by default.
Render this node and its content to HTML/XML.
# "<b>Test</b>"
$dom->parse('<div><b>Test</b></div>')->div->b->to_string;
$dom->parse('<div><b>Test</b></div>')->at('div b')->to_string;
=head2 tree
Expand All @@ -856,7 +854,7 @@ carefully since it is very dynamic.
This element's type.
# List types of child elements
say $dom->children->type;
say $dom->children->pluck('type');
=head2 val
Expand Down Expand Up @@ -916,22 +914,6 @@ children of the first innermost element.
Disable HTML semantics in parser and activate case sensitivity, defaults to
auto detection based on processing instructions.
=head1 AUTOLOAD
In addition to the L</"METHODS"> above, many child elements are also
automatically available as object methods, which return a L<Mojo::DOM> or
L<Mojo::Collection> object, depending on number of children. For more power
and consistent results you can also use L</"children">.
# "Test"
$dom->parse('<p>Test</p>')->p->text;
# "123"
$dom->parse('<div>Test</div><div>123</div>')->div->[2]->text;
# "Test"
$dom->parse('<div>Test</div>')->div->text;
=head1 OPERATORS
L<Mojo::DOM> overloads the following operators.
Expand Down
4 changes: 2 additions & 2 deletions lib/Mojo/Message.pm
Expand Up @@ -488,11 +488,11 @@ whole message body needs to be loaded into memory to parse it, so you have to
make sure it is not excessively large, there's a 10MB limit by default.
# Perform "find" right away
say $msg->dom('h1, h2, h3')->text;
say $msg->dom('h1, h2, h3')->pluck('text');
# Use everything else Mojo::DOM has to offer
say $msg->dom->at('title')->text;
say $msg->dom->html->body->children->type->uniq;
say $msg->dom->at('body')->children->pluck('type')->uniq;
=head2 error
Expand Down
4 changes: 2 additions & 2 deletions lib/Mojo/UserAgent.pm
Expand Up @@ -378,10 +378,10 @@ Mojo::UserAgent - Non-blocking I/O HTTP and WebSocket user agent
->res->json('/results/0/title');
# Extract data from HTML and XML resources
say $ua->get('www.perl.org')->res->dom->html->head->title->text;
say $ua->get('www.perl.org')->res->dom->at('title')->text;
# Scrape the latest headlines from a news site with CSS selectors
say $ua->get('blogs.perl.org')->res->dom('h2 > a')->text->shuffle;
say $ua->get('blogs.perl.org')->res->dom->find('h2 > a')->pluck('text');
# Search DuckDuckGo anonymously through Tor
$ua->proxy->http('socks://127.0.0.1:9050');
Expand Down
2 changes: 1 addition & 1 deletion lib/Mojolicious/Guides/Cookbook.pod
Expand Up @@ -1197,7 +1197,7 @@ This can be an invaluable tool for testing your applications.
For quick hacks and especially testing, L<ojo> one-liners are also a great
choice.

$ perl -Mojo -E 'say g("mojolicio.us")->dom->html->head->title->text'
$ perl -Mojo -E 'say g("mojolicio.us")->dom->at("title")->text'

=head1 APPLICATIONS

Expand Down
6 changes: 3 additions & 3 deletions lib/Mojolicious/Lite.pm
Expand Up @@ -874,7 +874,7 @@ L<Mojo::JSON> and L<Mojo::DOM> this can be a very powerful tool.
my $c = shift;
my $url = $c->param('url') || 'http://mojolicio.us';
my $dom = $c->ua->get($url)->res->dom;
$c->render(json => [$dom->find('h1, h2, h3')->text->each]);
$c->render(json => [$dom->find('h1, h2, h3')->pluck('text')->each]);
};
# Non-blocking
Expand All @@ -898,8 +898,8 @@ L<Mojo::JSON> and L<Mojo::DOM> this can be a very powerful tool.
sub {
my ($delay, $mojo, $cpan) = @_;
$c->render(json => {
mojo => $mojo->res->dom->html->head->title->text,
cpan => $cpan->res->dom->html->head->title->text
mojo => $mojo->res->dom->at('title')->text,
cpan => $cpan->res->dom->at('title')->text
});
}
);
Expand Down
2 changes: 1 addition & 1 deletion lib/Mojolicious/Plugin/PODRenderer.pm
Expand Up @@ -42,7 +42,7 @@ sub _html {
my $perldoc = $c->url_for('/perldoc/');
$_->{href} =~ s!^https://metacpan\.org/pod/!$perldoc!
and $_->{href} =~ s!::!/!gi
for $dom->find('a[href]')->attr->each;
for $dom->find('a[href]')->pluck('attr')->each;

# Rewrite code blocks for syntax highlighting and correct indentation
for my $e ($dom->find('pre > code')->each) {
Expand Down
2 changes: 1 addition & 1 deletion lib/ojo.pm
Expand Up @@ -125,7 +125,7 @@ resulting L<Mojo::Message::Response> object.
Perform C<GET> request with L<Mojo::UserAgent/"get"> and return resulting
L<Mojo::Message::Response> object.
$ perl -Mojo -E 'say g("mojolicio.us")->dom("h1, h2, h3")->text'
$ perl -Mojo -E 'say g("mojolicio.us")->dom("h1, h2, h3")->pluck("text")'
=head2 h
Expand Down
1 change: 0 additions & 1 deletion t/mojo/bytestream.t
Expand Up @@ -112,7 +112,6 @@ is $stream->split('/')->map(sub { $_->quote })->join(', '), '"1", "2", "3"',
'right result';
is $stream->split('/')->map(sub { shift->quote })->join(', '),
'"1", "2", "3"', 'right result';
is $stream->split('/')->quote->join(', '), '"1", "2", "3"', 'right result';

# length
is b('foo bar baz')->size, 11, 'size is 11';
Expand Down
15 changes: 0 additions & 15 deletions t/mojo/collection.t
Expand Up @@ -149,26 +149,11 @@ is c({foo => 'bar'}, {foo => 'baz'})->pluck('foo')->join, 'barbaz',
$collection = c(c(1, 2, 3), c(4, 5, 6), c(7, 8, 9));
is $collection->pluck('reverse'), "3\n2\n1\n6\n5\n4\n9\n8\n7", 'right result';
is $collection->pluck(join => '-'), "1-2-3\n4-5-6\n7-8-9", 'right result';
$collection = c(b('one'), b('two'), b('three'));
is $collection->camelize, "One\nTwo\nThree", 'right result';
is $collection->url_escape('^netwhr')->reverse, "%54hree\n%54w%6F\n%4Fne",
'right result';

# uniq
$collection = c(1, 2, 3, 2, 3, 4, 5, 4);
is_deeply [$collection->uniq->each], [1, 2, 3, 4, 5], 'right result';
is_deeply [$collection->uniq->reverse->uniq->each], [5, 4, 3, 2, 1],
'right result';

# Missing method and function (AUTOLOAD)
eval { Mojo::Collection->new(b('whatever'))->missing };
like $@,
qr/^Can't locate object method "missing" via package "Mojo::ByteStream"/,
'right error';
eval { Mojo::Collection->new(undef)->missing };
like $@, qr/^Can't call method "missing" on an undefined value/, 'right error';
eval { Mojo::Collection::missing() };
like $@, qr/^Undefined subroutine &Mojo::Collection::missing called/,
'right error';

done_testing();

0 comments on commit 6c8e9fa

Please sign in to comment.