Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

16 лет назад
16 лет назад
16 лет назад
16 лет назад
16 лет назад
16 лет назад
16 лет назад
16 лет назад
16 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. // the compiler tests are the exact same as the interpreter tests
  2. // so instead of writing all the tests twice, override the to_html
  3. // method
  4. module('Compiler', {
  5. setup: function() {
  6. this._oldToHtml = Mustache.to_html;
  7. Mustache.to_html = function(template, view, partials) {
  8. var compiler = Mustache.compile(template, partials);
  9. return compiler(view);
  10. }
  11. },
  12. teardown: function() {
  13. Mustache.to_html = this._oldToHtml;
  14. }
  15. });
  16. test("Argument validation", function() {
  17. expect(4);
  18. equals(Mustache.to_html(undefined), '', 'No parameters');
  19. equals(Mustache.to_html('{{hi}}'), '', ' No View or Partials');
  20. equals(Mustache.to_html('{{hi}}', {hi:'Hi.'}), 'Hi.', 'No Partials');
  21. equals(Mustache.to_html('{{>hi}}', undefined, {hi:'{{p}}'}), '', 'Partial but no view');
  22. });
  23. test("Parser", function() {
  24. expect(4);
  25. // matches whitespace_partial.html
  26. equals(
  27. Mustache.to_html(
  28. '<h1>{{ greeting }}</h1>\n{{> partial }}\n<h3>{{ farewell }}</h3>',
  29. {
  30. greeting: function() {
  31. return "Welcome";
  32. },
  33. farewell: function() {
  34. return "Fair enough, right?";
  35. },
  36. partial: {
  37. name: "Chris",
  38. value: 10000,
  39. taxed_value: function() {
  40. return this.value - (this.value * 0.4);
  41. },
  42. in_ca: true
  43. }
  44. },
  45. {partial:'Hello {{ name}}\nYou have just won ${{value }}!\n{{# in_ca }}\nWell, ${{ taxed_value }}, after taxes.\n{{/ in_ca }}\n'}
  46. ),
  47. '<h1>Welcome</h1>\nHello Chris\nYou have just won $10000!\n\nWell, $6000, after taxes.\n\n\n<h3>Fair enough, right?</h3>',
  48. 'Whitespace in Tag names'
  49. );
  50. equals(
  51. Mustache.to_html(
  52. '{{tag1}}\n\n\n{{tag2}}\n',
  53. { tag1: 'Hello', tag2: 'World' },
  54. {}
  55. ),
  56. 'Hello\n\n\nWorld\n',
  57. 'Preservation of white space'
  58. );
  59. try {
  60. Mustache.to_html(
  61. '{{=tag1}}',
  62. { tag1: 'Hello' },
  63. {}
  64. );
  65. ok(false);
  66. } catch (e) {
  67. equals(e.message, 'Unexpected end of document.');
  68. }
  69. var partials = { 'partial' : '{{key}}' };
  70. Mustache.compile('{{>partial}}', partials );
  71. equals(partials['partial'], '{{key}}', 'Partials compiler must be non-destructive');
  72. });
  73. test("Basic Variables", function() {
  74. expect(3);
  75. // matches escaped.html
  76. equals(
  77. Mustache.to_html(
  78. '<h1>{{title}}</h1>\nBut not {{entities}}.\n',
  79. {
  80. title: function() {
  81. return "Bear > Shark";
  82. },
  83. entities: "&quot;"
  84. },
  85. {}
  86. ),
  87. '<h1>Bear &gt; Shark</h1>\nBut not &amp;quot;.\n',
  88. 'HTML Escaping'
  89. );
  90. // matches null_string.html
  91. equals(
  92. Mustache.to_html(
  93. 'Hello {{name}}\nglytch {{glytch}}\nbinary {{binary}}\nvalue {{value}}\nnumeric {{numeric}}',
  94. {
  95. name: "Elise",
  96. glytch: true,
  97. binary: false,
  98. value: null,
  99. numeric: function() {
  100. return NaN;
  101. }
  102. },
  103. {}
  104. ),
  105. 'Hello Elise\nglytch true\nbinary false\nvalue \nnumeric NaN',
  106. 'Different variable types'
  107. );
  108. // matches two_in_a_row.html
  109. equals(
  110. Mustache.to_html(
  111. '{{greeting}}, {{name}}!',
  112. {
  113. name: "Joe",
  114. greeting: "Welcome"
  115. },
  116. {}
  117. ),
  118. 'Welcome, Joe!'
  119. );
  120. });
  121. test("'{' or '&' (Unescaped Variable)", function() {
  122. expect(2);
  123. // matches unescaped.html
  124. equals(
  125. Mustache.to_html(
  126. '<h1>{{{title}}}</h1>',
  127. {
  128. title: function() {
  129. return "Bear > Shark";
  130. }
  131. },
  132. {}
  133. ),
  134. '<h1>Bear > Shark</h1>',
  135. '{ character'
  136. );
  137. equals(
  138. Mustache.to_html(
  139. '<h1>{{&title}}</h1>',
  140. {
  141. title: function() {
  142. return "Bear > Shark";
  143. }
  144. },
  145. {}
  146. ),
  147. '<h1>Bear > Shark</h1>',
  148. '& character'
  149. );
  150. });
  151. test("'#' (Sections)", function() {
  152. expect(7);
  153. // matches array_of_partials_implicit_partial.html
  154. equals(
  155. Mustache.to_html(
  156. 'Here is some stuff!\n{{#numbers}}\n{{>partial}}\n{{/numbers}}',
  157. { numbers: ['1', '2', '3', '4'] },
  158. { partial: '{{.}}' }
  159. ),
  160. 'Here is some stuff!\n\n1\n\n2\n\n3\n\n4\n',
  161. 'Array of Partials (Implicit)'
  162. );
  163. // matches array_of_partials_partial.html
  164. equals(
  165. Mustache.to_html(
  166. 'Here is some stuff!\n{{#numbers}}\n{{>partial}}\n{{/numbers}}',
  167. { numbers: [{i: '1'}, {i: '2'}, {i: '3'}, {i: '4'}] },
  168. { partial: '{{i}}' }
  169. ),
  170. 'Here is some stuff!\n\n1\n\n2\n\n3\n\n4\n',
  171. 'Array of Partials (Explicit)'
  172. );
  173. // matches array_of_strings.html
  174. equals(
  175. Mustache.to_html(
  176. '{{#array_of_strings}}{{.}} {{/array_of_strings}}',
  177. {array_of_strings: ['hello', 'world']},
  178. {}
  179. ),
  180. 'hello world ',
  181. 'Array of Strings'
  182. );
  183. // mathces higher_order_sections.html
  184. equals(
  185. Mustache.to_html(
  186. '{{#bolder}}Hi {{name}}.{{/bolder}}\n',
  187. {
  188. "name": "Tater",
  189. "helper": "To tinker?",
  190. "bolder": function() {
  191. return function(text, render) {
  192. return "<b>" + render(text) + '</b> ' + this.helper;
  193. }
  194. }
  195. },
  196. {}
  197. ),
  198. '<b>Hi Tater.</b> To tinker?\n'
  199. );
  200. // matches recursion_with_same_names.html
  201. equals(
  202. Mustache.to_html(
  203. '{{ name }}\n{{ description }}\n\n{{#terms}}\n {{name}}\n {{index}}\n{{/terms}}\n',
  204. {
  205. name: 'name',
  206. description: 'desc',
  207. terms: [
  208. {name: 't1', index: 0},
  209. {name: 't2', index: 1}
  210. ]
  211. },
  212. {}
  213. ),
  214. 'name\ndesc\n\n\n t1\n 0\n\n t2\n 1\n\n'
  215. );
  216. // matches reuse_of_enumerables.html
  217. equals(
  218. Mustache.to_html(
  219. '{{#terms}}\n {{name}}\n {{index}}\n{{/terms}}\n{{#terms}}\n {{name}}\n {{index}}\n{{/terms}}\n',
  220. {
  221. terms: [
  222. {name: 't1', index: 0},
  223. {name: 't2', index: 1}
  224. ]
  225. },
  226. {}
  227. ),
  228. '\n t1\n 0\n\n t2\n 1\n\n\n t1\n 0\n\n t2\n 1\n\n',
  229. 'Lazy match of Section and Inverted Section'
  230. );
  231. // matches section_as_context.html
  232. equals(
  233. Mustache.to_html(
  234. '{{#a_object}}\n <h1>{{title}}</h1>\n <p>{{description}}</p>\n <ul>\n {{#a_list}}\n <li>{{label}}</li>\n {{/a_list}}\n </ul>\n{{/a_object}}\n',
  235. {
  236. a_object: {
  237. title: 'this is an object',
  238. description: 'one of its attributes is a list',
  239. a_list: [{label: 'listitem1'}, {label: 'listitem2'}]
  240. }
  241. },
  242. {}
  243. ),
  244. '\n <h1>this is an object</h1>\n <p>one of its attributes is a list</p>\n <ul>\n \n <li>listitem1</li>\n \n <li>listitem2</li>\n \n </ul>\n\n',
  245. 'Lazy match of Section and Inverted Section'
  246. );
  247. });
  248. test("'^' (Inverted Section)", function() {
  249. expect(1);
  250. // matches inverted_section.html
  251. equals(
  252. Mustache.to_html(
  253. '{{#repo}}<b>{{name}}</b>{{/repo}}\n{{^repo}}No repos :({{/repo}}\n',
  254. {
  255. "repo": []
  256. },
  257. {}
  258. ),
  259. '\nNo repos :(\n'
  260. );
  261. });
  262. test("'>' (Partials)", function() {
  263. expect(5);
  264. // matches view_partial.html
  265. equals(
  266. Mustache.to_html(
  267. '<h1>{{greeting}}</h1>\n{{>partial}}\n<h3>{{farewell}}</h3>',
  268. {
  269. greeting: function() {
  270. return "Welcome";
  271. },
  272. farewell: function() {
  273. return "Fair enough, right?";
  274. },
  275. partial: {
  276. name: "Chris",
  277. value: 10000,
  278. taxed_value: function() {
  279. return this.value - (this.value * 0.4);
  280. },
  281. in_ca: true
  282. }
  283. },
  284. {partial: 'Hello {{name}}\nYou have just won ${{value}}!\n{{#in_ca}}\nWell, ${{ taxed_value }}, after taxes.\n{{/in_ca}}\n'}
  285. ),
  286. '<h1>Welcome</h1>\nHello Chris\nYou have just won $10000!\n\nWell, $6000, after taxes.\n\n\n<h3>Fair enough, right?</h3>'
  287. );
  288. // matches array_partial.html
  289. equals(
  290. Mustache.to_html(
  291. '{{>partial}}',
  292. {
  293. partial: {
  294. array: ['1', '2', '3', '4']
  295. }
  296. },
  297. { partial: 'Here\'s a non-sense array of values\n{{#array}}\n {{.}}\n{{/array}}' }
  298. ),
  299. 'Here\'s a non-sense array of values\n\n 1\n\n 2\n\n 3\n\n 4\n'
  300. );
  301. // matches template_partial.html
  302. equals(
  303. Mustache.to_html(
  304. '<h1>{{title}}</h1>\n{{>partial}}',
  305. {
  306. title: function() {
  307. return "Welcome";
  308. },
  309. partial: {
  310. again: "Goodbye"
  311. }
  312. },
  313. {partial:'Again, {{again}}!'}
  314. ),
  315. '<h1>Welcome</h1>\nAgain, Goodbye!'
  316. );
  317. // matches partial_recursion.html
  318. equals(
  319. Mustache.to_html(
  320. '{{name}}\n{{#kids}}\n{{>partial}}\n{{/kids}}',
  321. {
  322. name: '1',
  323. kids: [
  324. {
  325. name: '1.1',
  326. children: [
  327. {name: '1.1.1'}
  328. ]
  329. }
  330. ]
  331. },
  332. {partial:'{{name}}\n{{#children}}\n{{>partial}}\n{{/children}}'}
  333. ),
  334. '1\n\n1.1\n\n1.1.1\n\n\n'
  335. );
  336. try {
  337. Mustache.to_html(
  338. '{{>partial}}',
  339. {},
  340. {partal: ''}
  341. );
  342. ok(false);
  343. } catch(e) {
  344. equals(e.message, "Unknown partial 'partial'");
  345. }
  346. });
  347. test("'=' (Set Delimiter)", function() {
  348. expect(1);
  349. // matches delimiter.html
  350. equals(
  351. Mustache.to_html(
  352. '{{=<% %>=}}*\n<% first %>\n* <% second %>\n<%=| |=%>\n* | third |\n|={{ }}=|\n* {{ fourth }}',
  353. {
  354. first: "It worked the first time.",
  355. second: "And it worked the second time.",
  356. third: "Then, surprisingly, it worked the third time.",
  357. fourth: "Fourth time also fine!."
  358. },
  359. {}
  360. ),
  361. '*\nIt worked the first time.\n* And it worked the second time.\n\n* Then, surprisingly, it worked the third time.\n\n* Fourth time also fine!.',
  362. 'Simple Set Delimiter'
  363. );
  364. });
  365. test("'!' (Comments)", function() {
  366. expect(4);
  367. equals(
  368. Mustache.to_html('{{! this is a single line comment !}}'),
  369. '',
  370. 'Single Line Comments');
  371. equals(
  372. Mustache.to_html('{{!this is a multiline comment\ni said this is a multiline comment!}}'),
  373. '',
  374. 'Multiline Comments');
  375. equals(
  376. Mustache.to_html('{{!this {{is}} {{#a}} {{/multiline}} comment\ni {{^said}} ! hello !! bye!}}'),
  377. '',
  378. 'Correct tokenization');
  379. // matches comments.html
  380. equals(
  381. Mustache.to_html(
  382. '<h1>{{title}}{{! just something interesting... or not... !}}</h1>\n',
  383. {
  384. title: function() {
  385. return "A Comedy of Errors";
  386. }
  387. },
  388. {}
  389. ),
  390. '<h1>A Comedy of Errors</h1>\n'
  391. );
  392. });
  393. test("'%' (Pragmas)", function() {
  394. expect(3);
  395. // matches array_of_strings_options.html
  396. equals(
  397. Mustache.to_html(
  398. '{{%IMPLICIT-ITERATOR iterator=rob}}\n{{#array_of_strings_options}}{{rob}} {{/array_of_strings_options}}',
  399. {array_of_strings_options: ['hello', 'world']},
  400. {}
  401. ),
  402. '\nhello world ',
  403. 'IMPLICIT-ITERATOR pragma'
  404. );
  405. // matches unknown_pragma.txt
  406. try {
  407. equals(
  408. Mustache.to_html(
  409. '{{%I-HAVE-THE-GREATEST-MUSTACHE}}\n',
  410. {},
  411. {}
  412. ),
  413. 'hello world ',
  414. 'IMPLICIT-ITERATOR pragma'
  415. );
  416. ok(false);
  417. } catch (e) {
  418. equals(e.message, 'This implementation of mustache doesn\'t understand the \'I-HAVE-THE-GREATEST-MUSTACHE\' pragma');
  419. }
  420. equals(
  421. Mustache.to_html(
  422. '{{%IMPLICIT-ITERATOR}}{{#dataSet}}{{.}}:{{/dataSet}}',
  423. { dataSet: [ 'Object 1', 'Object 2', 'Object 3' ] },
  424. {}
  425. ),
  426. "Object 1:Object 2:Object 3:"
  427. );
  428. });
  429. test("Empty", function() {
  430. expect(2);
  431. // matches empty_template.html
  432. equals(
  433. Mustache.to_html(
  434. '<html><head></head><body><h1>Test</h1></body></html>',
  435. {},
  436. {}
  437. ),
  438. '<html><head></head><body><h1>Test</h1></body></html>',
  439. 'Empty Template'
  440. );
  441. // matches empty_partial.html
  442. equals(
  443. Mustache.to_html(
  444. 'hey {{foo}}\n{{>partial}}\n',
  445. {
  446. foo: 1
  447. },
  448. {partial: 'yo'}
  449. ),
  450. 'hey 1\nyo\n',
  451. 'Empty Partial'
  452. );
  453. });
  454. test("Demo", function() {
  455. expect(2);
  456. // matches simple.html
  457. equals(
  458. Mustache.to_html(
  459. 'Hello {{name}}\nYou have just won ${{value}}!\n{{#in_ca}}\nWell, ${{ taxed_value }}, after taxes.\n{{/in_ca}}',
  460. {
  461. name: "Chris",
  462. value: 10000,
  463. taxed_value: function() {
  464. return this.value - (this.value * 0.4);
  465. },
  466. in_ca: true
  467. },
  468. {}
  469. ),
  470. 'Hello Chris\nYou have just won $10000!\n\nWell, $6000, after taxes.\n',
  471. 'A simple template'
  472. );
  473. // matches complex.html
  474. var template = [
  475. '<h1>{{header}}</h1>',
  476. '{{#list}}',
  477. ' <ul>',
  478. ' {{#item}}',
  479. ' {{#current}}',
  480. ' <li><strong>{{name}}</strong></li>',
  481. ' {{/current}}',
  482. ' {{#link}}',
  483. ' <li><a href="{{url}}">{{name}}</a></li>',
  484. ' {{/link}}',
  485. ' {{/item}}',
  486. ' </ul>',
  487. '{{/list}}',
  488. '{{#empty}}',
  489. ' <p>The list is empty.</p>',
  490. '{{/empty}}'
  491. ].join('\n');
  492. var view = {
  493. header: function() {
  494. return "Colors";
  495. },
  496. item: [
  497. {name: "red", current: true, url: "#Red"},
  498. {name: "green", current: false, url: "#Green"},
  499. {name: "blue", current: false, url: "#Blue"}
  500. ],
  501. link: function() {
  502. return this["current"] !== true;
  503. },
  504. list: function() {
  505. return this.item.length !== 0;
  506. },
  507. empty: function() {
  508. return this.item.length === 0;
  509. }
  510. };
  511. var expected_result = '<h1>Colors</h1>\n\n <ul>\n \n \n <li><strong>red</strong></li>\n \n \n <li><a href=\"#Red\">red</a></li>\n \n \n \n \n <li><a href=\"#Green\">green</a></li>\n \n \n \n \n <li><a href=\"#Blue\">blue</a></li>\n \n \n </ul>\n\n';
  512. equals(
  513. Mustache.to_html(
  514. template,
  515. view,
  516. {}
  517. ),
  518. expected_result,
  519. 'A complex template'
  520. );
  521. });
  522. test("Performance", function() {
  523. expect(1);
  524. var start, end;
  525. // This performance test is copied form skymustache
  526. // (https://github.com/schuyler1d/handlebars.js/blob/sky_test/test/perf.js)
  527. // set up the templates
  528. var template = "This is the story of guys who work on a project\n" +
  529. "called {{project}}. Their names were {{#people}}{{firstName}} and {{/people}}\n" +
  530. "they both enjoyed working on {{project}}.\n\n" +
  531. "{{#people}}\n" +
  532. "{{>personPet}}\n" +
  533. "{{/people}}";
  534. var partials = {
  535. personPet: "{{firstName}} {{lastName}} {{#pet}} owned a {{species}}. Its name was {{name}}.{{/pet}}{{^pet}}didn't own a pet.{{/pet}}"
  536. };
  537. var view = {
  538. project: "Handlebars",
  539. people: [
  540. { firstName: "Yehuda", lastName: "Katz" },
  541. { firstName: "Alan", lastName: "Johnson", pet: { species: "cat", name: "Luke" } }
  542. ]
  543. }
  544. start = new Date();
  545. for (var j=0;j<1000;++j) {
  546. this._oldToHtml(template, view, partials);
  547. }
  548. end = new Date();
  549. var interpreter_time = end.getTime() - start.getTime();
  550. start = new Date();
  551. var compiler = Mustache.compile(template, partials);
  552. for (var k=0;k<1000;++k) {
  553. compiler(view);
  554. }
  555. end = new Date();
  556. var compiler_time = end.getTime() - start.getTime();
  557. ok(compiler_time<interpreter_time, 'Compiler is faster (' + compiler_time + ' vs ' + interpreter_time + ').');
  558. });
  559. test("Regression Suite", function() {
  560. expect(3);
  561. // matches bug_11_eating_whitespace.html
  562. equals(
  563. Mustache.to_html(
  564. '{{tag}} foo',
  565. { tag: "yo" },
  566. {}
  567. ),
  568. 'yo foo',
  569. 'Issue 11'
  570. );
  571. // matches delimiters_partial.html
  572. equals(
  573. Mustache.to_html(
  574. '{{#enumerate}}\n{{>partial}}\n{{/enumerate}}',
  575. { enumerate: [ { text: 'A' }, { text: 'B' } ] },
  576. { partial: '{{=[[ ]]=}}\n{{text}}\n[[={{ }}=]]' }
  577. ),
  578. '\n\n{{text}}\n\n\n\n{{text}}\n\n',
  579. 'Issue 44'
  580. );
  581. // matches bug_46_set_delimiter.html
  582. equals(
  583. Mustache.to_html(
  584. '{{=[[ ]]=}}[[#IsMustacheAwesome]]mustache is awesome![[/IsMustacheAwesome]]',
  585. {IsMustacheAwesome: true},
  586. {}
  587. ),
  588. 'mustache is awesome!',
  589. 'Issue 46'
  590. );
  591. });