diff --git a/spec/entities.spec.js b/spec/entities.spec.js index 3d6a120..70cf1c5 100644 --- a/spec/entities.spec.js +++ b/spec/entities.spec.js @@ -1,4 +1,5 @@ var entities = require( '../src/entities' ), + iconv = require( 'iconv-lite' ), nock = require( 'nock' ); describe( 'BooksList', function() { @@ -11,6 +12,67 @@ describe( 'BooksList', function() { }); + it( 'should have a .fetchAll method', function( done ) { + + var bl = new entities.BooksList(), + book = new entities.Book( 'foo' ), + body = '

Foo

' + + '

Bar

'; + + expect( typeof bl.fetchAll ).toEqual( 'function' ); + + bl.push( book ); + + nock( 'http://www.eyrolles.com' ) + .get( '/foo' ).reply( 200, iconv.encode( body, 'latin1' ) ); + + bl.fetchAll({ + callback: function( books ) { + + expect( books ).toBeDefined(); + expect( books ).not.toBeNull(); + expect( books.length ).toEqual( 1 ); + + expect( books[0].title ).toEqual( 'Foo' ); + expect( books[0].short_desc ).toEqual( 'Bar' ); + expect( books[0].exists ).toBeTruthy(); + + done(); + + } + }); + + }); + + it( 'should behave like an array', function( done ) { + + var bl = new entities.BooksList( 'Accueil/Recherche/?q=foo' ); + + expect( entities.BooksList.prototype ).toEqual( [] ); + expect( bl.length ).toEqual( 0 ); + + nock( 'http://www.eyrolles.com' ) + .get( '/Accueil/Recherche/?ajax=on&q=foo&page=1' ) + .replyWithFile( 200, + __dirname + '/mocks/search-for-foo-p1.html' ); + + bl.fetch({ + + limit: 5, + + callback: function() { + + expect( bl.length ).toEqual( 5 ); + expect( bl[0] instanceof entities.Book ).toBeTruthy(); + + done(); + + } + + }); + + }); + it( 'should use pagination to fetch large results', function( done ) { var _n = nock( 'http://www.eyrolles.com' ), p; @@ -31,8 +93,7 @@ describe( 'BooksList', function() { callback: function() { - expect( bl.books ).toBeDefined(); - expect( bl.books.length ).toEqual( 91 ); + expect( bl.length ).toEqual( 91 ); done(); @@ -61,8 +122,7 @@ describe( 'BooksList', function() { callback: function() { - expect( bl.books ).toBeDefined(); - expect( bl.books.length ).toEqual( 30 ); + expect( bl.length ).toEqual( 30 ); done(); @@ -92,8 +152,7 @@ describe( 'BooksList', function() { callback: function() { - expect( bl.books ).toBeDefined(); - expect( bl.books.length ).toEqual( 25 ); + expect( bl.length ).toEqual( 25 ); done(); @@ -155,5 +214,27 @@ describe( 'Book object', function() { }); + it( 'should not fail ' + + 'if the website doesn’t have all informations', function( done ) { + + var body = '

Foo

', + book = new entities.Book( 'foo' ); + + nock( 'http://www.eyrolles.com' ) + .get( '/foo' ) + .reply( 200, iconv.encode( body, 'latin1' ) ); + + book.fetch({ callback: function( b ) { + + expect( b ).not.toBeNull(); + expect( b.title ).toEqual( 'Foo' ); + expect( b.exists ).toBeTruthy(); + + done(); + + }}); + + }); + }); diff --git a/spec/utils.spec.js b/spec/utils.spec.js index dc2c33a..5eea0f4 100644 --- a/spec/utils.spec.js +++ b/spec/utils.spec.js @@ -133,3 +133,20 @@ describe( 'isArray function', function() { }); }); + +describe( 'noop function', function() { + + it( 'should exist', function() { + + expect( typeof utils.noop ).toEqual( 'function' ); + + }); + + it( 'should do nothing', function() { + + expect( utils.noop.length ).toEqual( 0 ); + expect( utils.noop() ).toBeUndefined(); + + }); + +}); diff --git a/src/entities.js b/src/entities.js index dfb766b..210eb2d 100644 --- a/src/entities.js +++ b/src/entities.js @@ -137,15 +137,22 @@ var Book = createEntity( '', function( book, $ ) { .map(function( _, e ) { return $( e ).text().split( colon_re ); }), - i, len, + i, len, last_minis_children, d_website_label, d_label, d_value, d_fn; book.img = no_img_re.test( img_src ) ? null : img_src; book.title = desc.find( 'h1' ).text(); book.short_desc = desc.find( 'h2' ).first().text(); - book.pages_count = parseInt( minis.last().children() - .first().text().split( ':' )[1] ); - book.date = minis.last().children()[1].children[1].data.trim(); + + if ( minis.length > 0 ) { + + last_minis_children = minis.last().children(); + + book.pages_count = parseInt( last_minis_children + .first().text().split( ':' )[1] ); + book.date = last_minis_children[1].children[1].data.trim() + + } book.publisher = new Publisher( publisher.attr( 'href' ) ); @@ -198,42 +205,94 @@ var BooksList = function BL( path, attrs ) { return new arguments.callee( path ); } + that.length = 0; + that.fetch = function( opts ) { if ( opts === undefined ) { - opts = {}; + opts = {}; - } else if ( typeof opts === 'function' ) { + } else if ( typeof opts === 'function' ) { - opts = { callback: opts }; + opts = { callback: opts }; - } + } + + requests.paginate( path, { + + limit: opts.limit, + offset: opts.offset, + parser: parseBooksList, + callback: function( books ) { + + var i = 0, + len = books.length; + + for (; i < len; i++ ) { - requests.paginate( path, { + that[ i ] = books[ i ]; - limit: opts.limit, - offset: opts.offset, - parser: parseBooksList, - callback: function( books ) { + } - that.books = books; + that.length = len; - if ( typeof opts.callback === 'function' ) { + if ( typeof opts.callback === 'function' ) { - opts.callback( that ); + opts.callback( that ); + + } + + }, + error: opts.error + + }); + + }; + + that.fetchAll = function( opts ) { + + if ( !opts ) { + opts = {}; + } + + var count = that.length, + + check_count = function() { + + if ( --count <= 0 + && typeof opts.callback === 'function' ) { + + opts.callback( that ); } }, - error: opts.error + + fetch_args = { + + callback: check_count + + }; + + if ( typeof opts.error === 'function' ) { + + fetch_args.error = opts.error; + + } + + that.forEach(function( b ) { + + b.fetch(fetch_args); }); - } + }; } +BooksList.prototype = new Array(); + var Publisher = createEntity( '', function( publisher, $ ) { diff --git a/src/requests.js b/src/requests.js index b9500c8..197b7eb 100644 --- a/src/requests.js +++ b/src/requests.js @@ -5,9 +5,7 @@ var cheerio = require( 'cheerio' ), utils = require( './utils' ), re_http = /^https?:\/\//, - re_list_len = /: \d+ . \d+ sur (\d+) livres/, - - noop = function(){}; + re_list_len = /: \d+ . \d+ sur (\d+) livres/; function makeParams( params, url ) { @@ -86,7 +84,7 @@ function parseBody( url, callback, error_callback ) { if ( '' + url !== url ) { - return (error_callback || noop)( 'No URL given.' ); + return (error_callback || utils.noop)( 'No URL given.' ); } @@ -102,10 +100,10 @@ function parseBody( url, callback, error_callback ) { if ( error || code !== 200 ) { - return ( error_callback || noop )( error || code ); + return ( error_callback || utils.noop )( error || code ); } - return ( callback || noop )( cheerio.load( page ) ); + return ( callback || utils.noop )( cheerio.load( page ) ); }); @@ -121,7 +119,7 @@ function parseBodies( urls, parser, callback, error_callback ) { results = []; if ( urls_count === 0 ) { - return ( callback || noop )( results ); + return ( callback || utils.noop )( results ); } urls.forEach( function( url, i ) { @@ -132,7 +130,7 @@ function parseBodies( urls, parser, callback, error_callback ) { urls_count--; if ( urls_count === 0 ) { - ( callback || noop )( results ); + ( callback || utils.noop )( results ); } }, function( err ) { @@ -140,10 +138,10 @@ function parseBodies( urls, parser, callback, error_callback ) { results[ i ] = null; urls_count--; - ( error_callback || noop )( err ); + ( error_callback || utils.noop )( err ); if ( urls_count === 0 ) { - ( callback || noop )( results ); + ( callback || utils.noop )( results ); } }); @@ -180,8 +178,8 @@ function paginate( url, opts ) { var params = getParams( url ), parser = opts.parser, - final_cb = opts.callback || noop, - error_cb = opts.error || noop, + final_cb = opts.callback || utils.noop, + error_cb = opts.error || utils.noop, limit, offset = opts.offset > 0 ? opts.offset : 0, bpp = opts.bpp > 0 ? opts.bpp : null; diff --git a/src/utils.js b/src/utils.js index 1f0eaa8..8d83bb9 100644 --- a/src/utils.js +++ b/src/utils.js @@ -62,3 +62,4 @@ exports.clone = clone; exports.copy = copy; exports.extends = _extends; exports.isArray = isArray; +exports.noop = function(){};