Changeset 351

Show
Ignore:
Timestamp:
03/12/08 21:17:38 (2 months ago)
Author:
ingy
Message:
v0.03
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/ingy/pQuery/Changes

    r347 r351  
     1--- 
     2version: 0.03 
     3date:    Thu Mar 13 04:14:09 GMT 2008 
     4changes: 
     5- Added PQUERY 
     6- Ported and documented more methods 
     7- Implemented the previous state stack 
     8 
    19--- 
    210version: 0.02 
  • trunk/src/ingy/pQuery/README

    r347 r351  
    1919    the same goal. 
    2020 
    21     pQuery exports a single function called "pQuery". This function acts a 
     21    pQuery exports a single function called "pQuery". (Actually, it also 
     22    exports the special "PQUERY" function. Read below.) This function acts a 
    2223    constructor and does different things depending on the arguments you 
    2324    give it. This is discussed in the CONSTRUCTORS section below. 
     
    3536    object or a new derived object. All pQuery METHODS are described below. 
    3637 
     38THE ROYAL PQUERY 
     39    The power of jQuery is that single method calls can apply to many DOM 
     40    objects. pQuery does the exact same thing but can take this one step 
     41    further. A single PQUERY object can contain several DOMs! 
     42 
     43    Consider this example: 
     44 
     45        > perl -MpQuery -le 'PQUERY(\ 
     46            map "http://search.cpan.org/~$_/", qw(ingy gugod miyagawa))\ 
     47            ->find("table")->eq(1)->find("tr")\ 
     48            ->EACH(sub{\ 
     49                printf("%40s - %s Perl distributions\n", $_->url, $_->length - 1)\ 
     50            })' 
     51                   http://search.cpan.org/~ingy/ - 88 Perl distributions 
     52                  http://search.cpan.org/~gugod/ - 86 Perl distributions 
     53               http://search.cpan.org/~miyagawa/ - 138 Perl distributions 
     54 
     55    The power lies in "PQUERY", a special constructor that creates a wrapper 
     56    object for many pQuery objects, and applies all methods called on it to 
     57    all the pQuery objects it contains. 
     58 
    3759CONSTRUCTORS 
    3860    The pQuery constructor is an exported function called "pQuery". It does 
    3961    different things depending on the arguments you pass it. 
    4062 
    41   A URL 
     63  URL 
    4264    If you pass pQuery a URL, it will attempt to get the page and use its 
    4365    HTML to create a pQuery::DOM object. The pQuery object will contain the 
     
    5779        pQuery("<p>Hello <b>world</b>.</p>"); 
    5880 
     81  FILE 
     82    If you pass pQuery a string that ends with .html and contains no 
     83    whitespace, pQuery will assume it is the name of a file containing html 
     84    and will read the contents and parse the HTML into a new DOM. 
     85 
     86        pQuery("my/webpage.html"); 
     87 
    5988  Selector String 
    6089    You can create a pQuery object with a selector string just like in 
     
    90119        my $html = pQuery->get("http://google.com")->content; 
    91120 
     121  PQUERY(@list_of_pQuery_constructor_args) 
     122    The PQUERY constructor takes a list of any of the above pQuery forms and 
     123    creates a PQUERY object with one pQuery object per argument. 
     124 
    92125METHODS 
    93126    This is a reference of all the methods you can call on a pQuery object. 
    94127    They are almost entirely ported from jQuery. 
     128 
     129  pquery() 
     130    Returns the version number of the pQuery module. 
     131 
     132    =size() 
     133 
     134    Returns the number of elements in the pQuery object. 
     135 
     136    =length() 
     137 
     138    Also returns the number of elements in the pQuery object. 
    95139 
    96140  each($sub) 
     
    108152    The "each" method returns the pQuery object that called it. 
    109153 
     154  EACH($sub) 
     155    This method can only be called on PQUERY objects. The sub is called once 
     156    for every pQuery object within the PQUERY object. If you call "each()" 
     157    on a PQUERY object, it iterates on all the DOM objects of each pQuery 
     158    object (as you would expect). 
     159 
    110160  find($selector) 
    111161    This method will search all the pQuery::DOM elements of the its caller 
     
    160210            ->each(sub { ... });  # Do something with the tables 
    161211 
    162     NOTE: Not implemented yet. :( 
    163  
    164   get($url) 
     212  get($index) get($url) 
     213    If this method is passed an integer, it will return that specific 
     214    element from the array of elements in the pQuery object. 
     215 
    165216    This method will fetch the HTML content of the URL and return a 
    166217    HTML::Response object. 
    167218 
    168219        my $html = pQuery.get("http://google.com")->content; 
     220 
     221  index($elem) 
     222    This method returns the index number of its argument if the elem is in 
     223    the current pQuery object. Otherwise it returns -1. 
    169224 
    170225UNDER CONSTRUCTION 
  • trunk/src/ingy/pQuery/lib/pQuery.pm

    r347 r351  
    99use base 'Exporter'; 
    1010 
    11 our $VERSION = '0.02'; 
    12  
    13 our @EXPORT = qw(pQuery); 
     11our $VERSION = '0.03'; 
     12 
     13our @EXPORT = qw(pQuery PQUERY); 
    1414 
    1515our $document; 
     
    2525} 
    2626 
     27sub PQUERY { 
     28    return 'PQUERY'->new(@_); 
     29} 
     30 
     31################################################################################ 
     32# Playing around stuffs 
     33################################################################################ 
     34sub url { 
     35    my $this = shift; 
     36    return $my->{$this}{url} 
     37        if $my->{$this}{url}; 
     38    while ($this = $my->{$this}{prevObject}) { 
     39        return $my->{$this}{url} 
     40            if $my->{$this}{url}; 
     41    } 
     42    return; 
     43} 
     44 
     45sub eq { 
     46    my ($this, $i) = @_; 
     47    return $this->_pushStack($this->[$i]); 
     48} 
     49 
     50 
     51################################################################################ 
     52# Truly ported from jQuery stuff 
     53################################################################################ 
    2754sub new { 
    2855    my $class = shift; 
    29     my $self = bless [], $class; 
    30     $my->{$self} = {}; 
    31     return $self->_init(@_); 
     56    my $this = bless [], $class; 
     57    $my->{$this} = {}; 
     58    return $this->_init(@_); 
    3259} 
    3360 
    3461sub _init { 
    35     my ($self, $selector, $context) = @_; 
    36  
    37     $selector ||= $document or return $self
     62    my ($this, $selector, $context) = @_; 
     63 
     64    $selector ||= $document or return $this
    3865 
    3966    if (ref($selector) eq $dom_element_class) { 
    40         @$self = $selector; 
    41         return $self
     67        @$this = $selector; 
     68        return $this
    4269    } 
    4370    elsif (not ref($selector)) { 
     
    4774            if ($1) { 
    4875                $selector = [pQuery::DOM->fromHTML($1)]; 
    49 #                 $selector = $self->_clean([$1], $context); 
     76#                 $selector = $this->_clean([$1], $context); 
    5077            } 
    5178            else { 
    5279                my $elem = $document->getElementById($3); 
    5380                if ($elem) { 
    54                     @$self = $elem; 
    55                     return $self
     81                    @$this = $elem; 
     82                    return $this
    5683                } 
    5784                else { 
     
    6289        else { 
    6390            if ($selector =~ /^\s*(https?|file):/) { 
    64                 return $document = $self->_new_from_url($selector); 
     91                $my->{$this}{url} = $selector; 
     92                return $document = $this->_new_from_url($selector); 
    6593            } 
    66             return pQuery($context)->find($selector); 
     94            elsif ($selector =~ /^\S+\.html?$/) { 
     95                $my->{$this}{file} = $selector; 
     96                open FILE, $selector; 
     97                my $html = do {local $/; <FILE>}; 
     98                close FILE; 
     99                $selector = [pQuery::DOM->fromHTML($html)]; 
     100            } 
     101            else { 
     102                return pQuery($context)->find($selector); 
     103            } 
    67104        } 
    68105    } 
    69     @$self = (ref($selector) eq 'ARRAY' or ref($selector) eq 'pQuery') 
     106    @$this = (ref($selector) eq 'ARRAY' or ref($selector) eq 'pQuery') 
    70107        ? @$selector 
    71108        : $selector; 
    72     return $self; 
    73 
    74  
    75 sub _new_from_url { 
    76     my $self = shift; 
    77     my $url = shift; 
    78     my $response = $self->get($url); 
    79     return $self 
    80         unless $response->is_success; 
    81     @$self = pQuery::DOM->fromHTML($response->content); 
    82     return $self; 
    83 
     109    return $this; 
     110
     111 
     112sub pquery { return $VERSION } 
     113 
     114sub size { return $#{$_[0]} + 1 } 
     115sub length { return $#{$_[0]} + 1 } 
     116 
     117sub get { 
     118    my $this = shift; 
     119 
     120    # Get could be for Ajax URL or Object Member 
     121    return $this->_web_get(@_) 
     122        if @_ and $_[0] !~ /^\d+$/; 
     123 
     124    return @_ 
     125        ? $this->[$_[0]] 
     126        : wantarray ? (@$this) : $this->[0]; 
     127
     128 
     129sub _pushStack { 
     130    my ($this, $elems) = @_; 
     131    my $ret = pQuery($elems); 
     132    $ret->_prevObject($this); 
     133    return $ret; 
     134
     135 
     136sub _prevObject { 
     137    my $this = shift; 
     138    return @_ 
     139        ? ($my->{$this}{prevObject} = $_[0]) 
     140        : $my->{$this}{prevObject}; 
     141
     142 
     143# Not needed in Perl 
     144# sub _setArray { 
     145#     my ($this, $elems) = @_; 
     146#     @$this = @$elems; 
     147#     return $this; 
     148# } 
     149 
     150sub each { 
     151    my ($this, $sub) = @_; 
     152    my $i = 0; 
     153    &$sub($i++) for @$this; 
     154    return $this; 
     155
     156 
     157# XXX Needs test 
     158sub index { 
     159    my ($this, $elem) = @_; 
     160    my $ret = -1; 
     161    $this->each(sub { 
     162        $ret = shift 
     163            if (ref($_) && ref($elem)) ? ($_ == $elem) : ($_ eq $elem); 
     164    }); 
     165    return $ret; 
     166
     167 
     168# sub attr { 
     169# } 
    84170 
    85171sub html { 
    86     my $self = shift; 
    87     return unless @$self
     172    my $this = shift; 
     173    return unless @$this
    88174    if (@_) { 
    89         for (@$self) { 
     175        for (@$this) { 
    90176            next unless ref($_); 
    91177            $_->innerHTML(@_); 
    92178        } 
    93         return $self
    94     } 
    95     return $self->[0]->innerHTML(@_); 
     179        return $this
     180    } 
     181    return $this->[0]->innerHTML(@_); 
    96182} 
    97183 
    98184sub toHtml { 
    99     my $self = shift; 
    100     return unless @$self
    101     return $self->[0]->toHTML; 
     185    my $this = shift; 
     186    return unless @$this
     187    return $this->[0]->toHTML; 
    102188} 
    103189 
    104190sub text { 
    105     my $self = shift; 
     191    my $this = shift; 
    106192    my $text = ''; 
    107193 
    108     $self->each(sub { 
     194    $this->each(sub { 
    109195        _to_text($_, \$text); 
    110196    }); 
     
    116202} 
    117203 
    118 sub each { 
    119     my ($self, $sub) = @_; 
    120     my $i = 0; 
    121     &$sub($i++) for @$self; 
    122     return $self; 
    123 } 
    124  
    125204sub find { 
    126     my $self = shift; 
     205    my $this = shift; 
    127206    my $selector = shift or return; 
    128207    my $elems = []; 
    129     $self->each(sub { 
     208    $this->each(sub { 
    130209        _find_elems($_, $selector, $elems); 
    131210    }); 
    132     return pQuery($elems); 
     211    return $this->_pushStack($elems); 
    133212} 
    134213 
    135214sub end { 
    136     my $self = shift; 
    137     die "not implemented yet"; 
    138 
    139  
    140 sub get { 
    141     my $self = shift; 
     215    my $this = shift; 
     216    return $this->_prevObject; 
     217
     218 
     219################################################################################ 
     220# Helper functions (not methods) 
     221################################################################################ 
     222sub _new_from_url { 
     223    my $this = shift; 
     224    my $url = shift; 
     225    my $response = $this->get($url); 
     226    return $this 
     227        unless $response->is_success; 
     228    @$this = pQuery::DOM->fromHTML($response->content); 
     229    return $this; 
     230
     231 
     232sub _web_get { 
     233    my $this = shift; 
    142234    my $url = shift; 
    143235    require LWP::UserAgent; 
     
    149241} 
    150242 
    151 # Helper functions (not methods) 
    152243sub _to_text { 
    153244    my ($elem, $text) = @_; 
     
    178269} 
    179270 
     271################################################################################ 
     272# THE AMAZING PQUERY 
     273################################################################################ 
     274package PQUERY; 
     275 
     276sub new { 
     277    my $class = shift; 
     278    my $this = bless [], $class; 
     279    @$this = map 'pQuery'->new($_), @_; 
     280    return $this; 
     281} 
     282 
     283sub AUTOLOAD { 
     284    (my $method = $PQUERY::AUTOLOAD) =~ s/.*:://; 
     285    my $this = shift; 
     286    my @args = @_; 
     287    $this->EACH(sub { 
     288        my $i = shift; 
     289        $this->[$i] = $_->$method(@args); 
     290    }); 
     291    return $this; 
     292} 
     293 
     294sub EACH { 
     295    my ($this, $sub) = @_; 
     296    my $index = 0; 
     297    &$sub($index++) for @$this; 
     298    return $this; 
     299} 
     300 
     301sub DESTROY {} 
     302 
    1803031; 
    181304 
     
    203326the same goal. 
    204327 
    205 pQuery exports a single function called C<pQuery>. This function acts a 
    206 constructor and does different things depending on the arguments you 
     328pQuery exports a single function called C<pQuery>. (Actually, it also 
     329exports the special C<PQUERY> function. Read below.) This function acts 
     330a constructor and does different things depending on the arguments you 
    207331give it. This is discussed in the L<CONSTRUCTORS> section below. 
    208332 
     
    220344described below. 
    221345 
     346=head1 THE ROYAL PQUERY 
     347 
     348The power of jQuery is that single method calls can apply to many DOM 
     349objects. pQuery does the exact same thing but can take this one step 
     350further. A single PQUERY object can contain several DOMs! 
     351 
     352Consider this example: 
     353 
     354    > perl -MpQuery -le 'PQUERY(\ 
     355        map "http://search.cpan.org/~$_/", qw(ingy gugod miyagawa))\ 
     356        ->find("table")->eq(1)->find("tr")\ 
     357        ->EACH(sub{\ 
     358            printf("%40s - %s Perl distributions\n", $_->url, $_->length - 1)\ 
     359        })' 
     360               http://search.cpan.org/~ingy/ - 88 Perl distributions 
     361              http://search.cpan.org/~gugod/ - 86 Perl distributions 
     362           http://search.cpan.org/~miyagawa/ - 138 Perl distributions 
     363 
     364The power lies in C<PQUERY>, a special constructor that creates a 
     365wrapper object for many pQuery objects, and applies all methods called 
     366on it to all the pQuery objects it contains. 
     367 
    222368=head1 CONSTRUCTORS 
    223369 
     
    225371different things depending on the arguments you pass it. 
    226372 
    227 =head2 A URL 
     373=head2 URL 
    228374 
    229375If you pass pQuery a URL, it will attempt to get the page and use its 
     
    245391    pQuery("<p>Hello <b>world</b>.</p>"); 
    246392 
     393=head2 FILE 
     394 
     395If you pass pQuery a string that ends with .html and contains no 
     396whitespace, pQuery will assume it is the name of a file containing html 
     397and will read the contents and parse the HTML into a new DOM. 
     398 
     399    pQuery("my/webpage.html"); 
     400 
    247401=head2 Selector String 
    248402 
     
    282436    my $html = pQuery->get("http://google.com")->content; 
    283437 
     438=head2 PQUERY(@list_of_pQuery_constructor_args) 
     439 
     440The PQUERY constructor takes a list of any of the above pQuery forms and 
     441creates a PQUERY object with one pQuery object per argument. 
     442 
    284443=head1 METHODS 
    285444 
    286445This is a reference of all the methods you can call on a pQuery object. They 
    287446are almost entirely ported from jQuery. 
     447 
     448=head2 pquery() 
     449 
     450Returns the version number of the pQuery module. 
     451 
     452=size() 
     453 
     454Returns the number of elements in the pQuery object. 
     455 
     456=length() 
     457 
     458Also returns the number of elements in the pQuery object. 
    288459 
    289460=head2 each($sub) 
     
    302473The C<each> method returns the pQuery object that called it. 
    303474 
     475=head2 EACH($sub) 
     476 
     477This method can only be called on PQUERY objects. The sub is called once 
     478for every pQuery object within the PQUERY object. If you call C<each()> 
     479on a PQUERY object, it iterates on all the DOM objects of each pQuery 
     480object (as you would expect). 
     481 
    304482=head2 find($selector) 
    305483 
     
    358536        ->each(sub { ... });  # Do something with the tables 
    359537 
    360 NOTE: Not implemented yet. :( 
    361  
    362 =head2 get($url) 
     538=head2 get($index) get($url) 
     539 
     540If this method is passed an integer, it will return that specific 
     541element from the array of elements in the pQuery object. 
    363542 
    364543This method will fetch the HTML content of the URL and return a 
     
    366545 
    367546    my $html = pQuery.get("http://google.com")->content; 
     547 
     548=head2 index($elem) 
     549 
     550This method returns the index number of its argument if the elem is in the 
     551current pQuery object. Otherwise it returns -1. 
    368552 
    369553=head1 UNDER CONSTRUCTION 
  • trunk/src/ingy/pQuery/lib/pQuery/DOM.pm

    r347 r351  
    22use strict; 
    33use warnings; 
     4use Carp; 
    45 
    56use base 'HTML::TreeBuilder'; 
     
    254255 
    255256################################################################################ 
     257# Common pQuery method mistakes 
     258################################################################################ 
     259# sub text { 
     260#     confess "Invalid method 'text' called on pQuery::DOM object"; 
     261# } 
     262 
     263################################################################################ 
    256264# Helper Functions 
    257265################################################################################ 
  • trunk/src/ingy/pQuery/t/contructors.t

    r347 r351  
    1 use Test::More tests => 13; 
     1use t::TestpQuery tests => 13; 
    22use strict; 
    33