/scalate-core/src/test/scala/org/fusesource/scalate/jade/JadeTemplateTest.scala

http://github.com/scalate/scalate · Scala · 1251 lines · 1177 code · 33 blank · 41 comment · 10 complexity · d983b03253a9ba384b03833d0e68f961 MD5 · raw file

  1. /**
  2. * Copyright (C) 2009-2011 the original author or authors.
  3. * See the notice.md file distributed with this work for additional
  4. * information regarding copyright ownership.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. package org.fusesource.scalate
  19. package jade
  20. import org.fusesource.scalate.scaml._
  21. /**
  22. * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
  23. */
  24. class JadeTemplateTest extends JadeTestSupport {
  25. /////////////////////////////////////////////////////////////////////
  26. //
  27. // Filters
  28. //
  29. /////////////////////////////////////////////////////////////////////
  30. testRender(
  31. "You can use `:` to use filters",
  32. """
  33. html
  34. p
  35. :plain
  36. Indentation levels are not enforced in filters.
  37. #{Interpolation} is disabled by default
  38. Last line
  39. """, """
  40. <html>
  41. <p>
  42. Indentation levels are not enforced in filters.
  43. #{Interpolation} is disabled by default
  44. Last line
  45. </p>
  46. </html>
  47. """)
  48. testRender(
  49. "Use the `~` filter flag to preserve white space",
  50. """
  51. html
  52. p<
  53. :~plain
  54. Indentation levels are not enforced in filters.
  55. #{Interpolation} is disabled by default
  56. Last line
  57. """, """
  58. <html>
  59. <p> Indentation levels are not enforced in filters.&#x000A; #{Interpolation} is disabled by default&#x000A;Last line</p>
  60. </html>
  61. """)
  62. testRender(
  63. "Use the `&` filter flag to enable sanitizing interpolation",
  64. """
  65. html
  66. p
  67. :&plain
  68. I like #{ "<strong>" } cheese
  69. """, """
  70. <html>
  71. <p>
  72. I like &lt;strong&gt; cheese
  73. </p>
  74. </html>
  75. """)
  76. testRender(
  77. "Use the `!` filter flag to enable non-sanitizing interpolation",
  78. """
  79. html
  80. p
  81. :!plain
  82. I like #{ "<strong>" } cheese #{ "</strong>" }
  83. """, """
  84. <html>
  85. <p>
  86. I like <strong> cheese </strong>
  87. </p>
  88. </html>
  89. """)
  90. testRender(
  91. ":javascript filter can be used to safely insert javascript",
  92. """
  93. html
  94. head
  95. :javascript
  96. alert("Hello");
  97. """, """
  98. <html>
  99. <head>
  100. <script type='text/javascript'>
  101. //<![CDATA[
  102. alert("Hello");
  103. //]]>
  104. </script>
  105. </head>
  106. </html>
  107. """)
  108. testRender(
  109. "filters can be chained",
  110. """
  111. pre
  112. :escaped :javascript
  113. alert("Hello");
  114. """, """
  115. <pre>
  116. &lt;script type='text/javascript'&gt;
  117. //&lt;![CDATA[
  118. alert(&quot;Hello&quot;);
  119. //]]&gt;
  120. &lt;/script&gt;
  121. </pre>
  122. """)
  123. testRender(
  124. "The markdown filter",
  125. """
  126. p
  127. :markdown
  128. Markdown
  129. =======
  130. Hello, *World*
  131. """, """
  132. <p>
  133. <h1 id = "Markdown">Markdown</h1>
  134. <p>Hello, <em>World</em></p>
  135. </p>
  136. """)
  137. testRender(
  138. "The `&` flag enables sanitized interpolations.",
  139. """
  140. - var flavor = "<raspberry/>"
  141. #content
  142. :&markdown
  143. I *really* prefer #{flavor} jam.
  144. """, """
  145. <div id="content">
  146. <p>I <em>really</em> prefer &lt;raspberry/&gt; jam.</p>
  147. </div>
  148. """)
  149. testRender(
  150. "The `!` flag enables non-sanitized interpolations.",
  151. """
  152. - var flavor = "<raspberry/>"
  153. #content
  154. :!markdown
  155. I *really* prefer #{flavor} jam.
  156. """, """
  157. <div id="content">
  158. <p>I <em>really</em> prefer <raspberry/> jam.</p>
  159. </div>
  160. """)
  161. /////////////////////////////////////////////////////////////////////
  162. //
  163. // Plain Text
  164. //
  165. /////////////////////////////////////////////////////////////////////
  166. testRender(
  167. "Jade lines starting with | is taken to be plain text, and passed through unmodified. ",
  168. """
  169. gee
  170. whiz
  171. | Wow this is cool!
  172. """, """
  173. <gee>
  174. <whiz>
  175. Wow this is cool!
  176. </whiz>
  177. </gee>
  178. """)
  179. testRender(
  180. "HTML tags are passed through unmodified as well.",
  181. """
  182. p
  183. <div id="blah">Blah!</div>
  184. """, """
  185. <p>
  186. <div id="blah">Blah!</div>
  187. </p>
  188. """)
  189. testRender(
  190. "backslash character escapes the first character of a line, allowing use of otherwise interpreted characters as plain text.",
  191. """
  192. title
  193. = title
  194. \= title
  195. """, """
  196. <title>
  197. MyPage
  198. = title
  199. </title>
  200. """)
  201. testRender(
  202. "Indenting can be disabled with the ScamlOptions.indent option",
  203. """
  204. gee
  205. whiz
  206. | Wow this is cool!
  207. """, """
  208. <gee>
  209. <whiz>
  210. Wow this is cool!
  211. </whiz>
  212. </gee>
  213. """, { () =>
  214. ScamlOptions.indent = ""
  215. }, { () =>
  216. ScamlOptions.indent = ScamlOptions.DEFAULT_INDENT
  217. })
  218. testRender(
  219. "Newlines can also be disabled with the ScamlOptions.nl option",
  220. """
  221. gee
  222. whiz
  223. | Wow this is cool!
  224. """, """
  225. <gee><whiz>Wow this is cool!</whiz></gee>
  226. """, { () =>
  227. ScamlOptions.indent = ""
  228. ScamlOptions.nl = ""
  229. }, { () =>
  230. ScamlOptions.indent = ScamlOptions.DEFAULT_INDENT
  231. ScamlOptions.nl = ScamlOptions.DEFAULT_NL
  232. })
  233. /////////////////////////////////////////////////////////////////////
  234. //
  235. // HTML Elements
  236. //
  237. /////////////////////////////////////////////////////////////////////
  238. testRender(
  239. "a 'tag' can have trailing spaces and nested content",
  240. """
  241. html
  242. body
  243. """, """
  244. <html>
  245. <body></body>
  246. </html>
  247. """)
  248. testRender(
  249. "'tag' renders a start and end tag",
  250. """
  251. html
  252. """, """
  253. <html></html>
  254. """)
  255. testRender(
  256. "'tag text' render start tag, text, and end tag on same line",
  257. """
  258. html test
  259. """, """
  260. <html>test</html>
  261. """)
  262. testRender(
  263. "nested tags are rendered indented",
  264. """
  265. html
  266. body
  267. | test
  268. """, """
  269. <html>
  270. <body>
  271. test
  272. </body>
  273. </html>
  274. """)
  275. testRender(
  276. "single quoted tags can contain special characters",
  277. """
  278. 'funny.element'.test
  279. | hi
  280. """, """
  281. <funny.element class="test">
  282. hi
  283. </funny.element>
  284. """)
  285. testRender(
  286. "'tag = quality' renders a tag with nested content",
  287. """
  288. p=quality
  289. p = quality
  290. """, """
  291. <p>scrumptious</p>
  292. <p>scrumptious</p>
  293. """)
  294. /////////////////////////////////////////////////////////////////////
  295. //
  296. // HTML Elements : Attributes
  297. //
  298. /////////////////////////////////////////////////////////////////////
  299. testRender(
  300. "Brackets represent a Scala hash that is used for specifying the attributes of an element.",
  301. """
  302. html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en", :lang => "en"}
  303. """, """
  304. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"></html>
  305. """)
  306. testRender(
  307. "Attribute hashes can also be stretched out over multiple lines to accommodate many attributes.",
  308. """
  309. script{:type => "text/javascript",
  310. :src => "javascripts/script"}
  311. """, """
  312. <script type="text/javascript" src="javascripts/script"></script>
  313. """)
  314. testRender(
  315. "Jade also supports a terser, less Scala-specific attribute syntax based on HTML's attributes.",
  316. """
  317. html(xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en")
  318. """, """
  319. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"></html>
  320. """)
  321. testRender(
  322. "Scala variables can be used by omitting the quotes.",
  323. """
  324. a(title=title href=href) Stuff
  325. """, """
  326. <a title="MyPage" href="http://scalate.fusesource.org">Stuff</a>
  327. """)
  328. testRender(
  329. "You can use both syntaxes together.",
  330. """
  331. a(title="Hello"){:href => "http://scalate.fusesource.org"} Stuff
  332. """, """
  333. <a title="Hello" href="http://scalate.fusesource.org">Stuff</a>
  334. """)
  335. testRender(
  336. "HTML-style attributes can be stretched across multiple lines just like hash-style attributes",
  337. """
  338. script(type="text/javascript"
  339. src="javascripts/script")
  340. """, """
  341. <script type="text/javascript" src="javascripts/script"></script>
  342. """)
  343. testRender(
  344. "Html Attributes can use complex scala expressions",
  345. """
  346. div(count={3+4})
  347. """, """
  348. <div count="7"></div>
  349. """)
  350. testRender(
  351. "Html Attributes can use simple scala expressions",
  352. """
  353. div(count="#{3+4}")
  354. """, """
  355. <div count="7"></div>
  356. """)
  357. testRender(
  358. "Html Attributes can use scala variables",
  359. """
  360. - val count = 5
  361. div(count=count)
  362. """, """
  363. <div count="5"></div>
  364. """)
  365. testRender(
  366. "Hash Attributes can use simple scala expressions",
  367. """
  368. - val count = 5
  369. div{:count=>count}
  370. """, """
  371. <div count="5"></div>
  372. """)
  373. testRender(
  374. "Hash Attributes can use complex scala expressions",
  375. """
  376. div{:count=>{3+4}}
  377. """, """
  378. <div count="7"></div>
  379. """)
  380. testRender(
  381. "Enabled boolean attribute in hash style",
  382. """
  383. input{:selected => true}
  384. """, """
  385. <input selected="selected"/>
  386. """)
  387. testRender(
  388. "Disabled boolean attribute in hash style",
  389. """
  390. input{:selected => false}
  391. """, """
  392. <input/>
  393. """)
  394. testRender(
  395. "Enabled boolean attribute in html style",
  396. """
  397. input(selected=true)
  398. """, """
  399. <input selected="selected"/>
  400. """)
  401. testRender(
  402. "Disabled boolean attribute in html style",
  403. """
  404. input(selected=false)
  405. """, """
  406. <input/>
  407. """)
  408. testRender(
  409. "Enabled boolean attribute in html style using shorthand",
  410. """
  411. input(selected)
  412. """, """
  413. <input selected="selected"/>
  414. """)
  415. testRender(
  416. "Mixing attributes with complex expressions",
  417. """
  418. p{ :counter1=>{1 + 2}, :counter2=>10 }
  419. """, """
  420. <p counter1="3" counter2="10"></p>
  421. """)
  422. /////////////////////////////////////////////////////////////////////
  423. //
  424. // HTML Elements : Class and ID: `.` and `#`
  425. //
  426. /////////////////////////////////////////////////////////////////////
  427. testRender(
  428. "`.` and `#` are used as shortcuts to specify the `class` and `id` attributes of an element",
  429. """
  430. div#things
  431. span#rice Chicken Fried
  432. p.beans{ :food => "true" } The magical fruit
  433. h1.class.otherclass#id La La La
  434. """, """
  435. <div id="things">
  436. <span id="rice">Chicken Fried</span>
  437. <p class="beans" food="true">The magical fruit</p>
  438. <h1 id="id" class="class otherclass">La La La</h1>
  439. </div>
  440. """)
  441. testRender(
  442. "Another `.` and `#` example",
  443. """
  444. #content
  445. .articles
  446. .article.title Doogie Howser Comes Out
  447. .article.date 2006-11-05
  448. .article.entry
  449. | Neil Patrick Harris would like to dispel any rumors that he is straight
  450. """, """
  451. <div id="content">
  452. <div class="articles">
  453. <div class="article title">Doogie Howser Comes Out</div>
  454. <div class="article date">2006-11-05</div>
  455. <div class="article entry">
  456. Neil Patrick Harris would like to dispel any rumors that he is straight
  457. </div>
  458. </div>
  459. </div>
  460. """)
  461. // Edge cases
  462. testRender(
  463. "'tag#i1#i2' last id specified wins",
  464. """
  465. html#i1#i2
  466. """, """
  467. <html id="i2"></html>
  468. """)
  469. testRender(
  470. "'tag.c1' renders a tag with a class",
  471. """
  472. html.c1
  473. """, """
  474. <html class="c1"></html>
  475. """)
  476. testRender(
  477. "'tag.c1.c2' renders a tag with multiple classes",
  478. """
  479. html.c1.c2
  480. """, """
  481. <html class="c1 c2"></html>
  482. """)
  483. testRender(
  484. "Any css class/name can be used.",
  485. """
  486. .my-class
  487. ._whacky_1
  488. """, """
  489. <div class="my-class"></div>
  490. <div class="_whacky_1"></div>
  491. """)
  492. /////////////////////////////////////////////////////////////////////
  493. //
  494. // HTML Elements : Implicit Div Elements
  495. //
  496. /////////////////////////////////////////////////////////////////////
  497. testRender(
  498. "If you only define a class and/or id using `.` or `#`, a div is automatically used.",
  499. """
  500. #collection
  501. .item
  502. .description What a cool item!
  503. """, """
  504. <div id="collection">
  505. <div class="item">
  506. <div class="description">What a cool item!</div>
  507. </div>
  508. </div>
  509. """)
  510. /////////////////////////////////////////////////////////////////////
  511. //
  512. // HTML Elements : Self-Closing Tags : `/`
  513. //
  514. /////////////////////////////////////////////////////////////////////
  515. testRender(
  516. "The forward slash character, when placed at the end of a tag definition, causes the tag to be self-closed.",
  517. """
  518. br/
  519. meta{"http-equiv" => "Content-Type", :content => "text/html"}/
  520. """, """
  521. <br/>
  522. <meta http-equiv="Content-Type" content="text/html"/>
  523. """)
  524. testRender(
  525. "`meta`, `img`, `link`, `script`, `br`, and `hr` tags are closed by default.",
  526. """
  527. br/
  528. meta{"http-equiv" => "Content-Type", :content => "text/html"}/
  529. """, """
  530. <br/>
  531. <meta http-equiv="Content-Type" content="text/html"/>
  532. """)
  533. /////////////////////////////////////////////////////////////////////
  534. //
  535. // HTML Elements : Whitespace Removal: `>` and `<`
  536. //
  537. /////////////////////////////////////////////////////////////////////
  538. testRender(
  539. "'`<` will remove all whitespace immediately within a tag.",
  540. """
  541. blockquote<
  542. div
  543. | Foo!
  544. """, """
  545. <blockquote><div>
  546. Foo!
  547. </div></blockquote>
  548. """)
  549. testRender(
  550. "`>` will remove all whitespace surrounding a tag",
  551. """
  552. img/
  553. img>/
  554. img/
  555. """, """
  556. <img/><img/><img/>
  557. """)
  558. testRender(
  559. "`<` will remove all whitespace surrounding a rendered expression",
  560. """
  561. p<= "Foo\nBar"
  562. """, """
  563. <p>Foo
  564. Bar</p>
  565. """)
  566. testRender(
  567. "'tag><' trims the whitespace surrounding the tag and wrapping nested content'",
  568. """
  569. img/
  570. pre><
  571. | foo
  572. | bar
  573. img/
  574. """, """
  575. <img/><pre>foo
  576. bar</pre><img/>
  577. """)
  578. testRender(
  579. "'tag<>' trims the whitespace surrounding the tag and wrapping nested content'",
  580. """
  581. img/
  582. pre><
  583. | foo
  584. | bar
  585. img/
  586. """, """
  587. <img/><pre>foo
  588. bar</pre><img/>
  589. """)
  590. /////////////////////////////////////////////////////////////////////
  591. //
  592. // Doctype: !!!
  593. //
  594. /////////////////////////////////////////////////////////////////////
  595. testRender(
  596. "you can have a document type or XML prolog generated automatically by including the characters !!!",
  597. """
  598. !!! XML
  599. !!!
  600. html
  601. head
  602. title Myspace
  603. body
  604. h1 I am the international space station
  605. p Sign my guestbook
  606. """, """
  607. <?xml version="1.0" encoding="utf-8" ?>
  608. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  609. <html>
  610. <head>
  611. <title>Myspace</title>
  612. </head>
  613. <body>
  614. <h1>I am the international space station</h1>
  615. <p>Sign my guestbook</p>
  616. </body>
  617. </html>
  618. """)
  619. /////////////////////////////////////////////////////////////////////
  620. //
  621. // Comments
  622. //
  623. /////////////////////////////////////////////////////////////////////
  624. testRender(
  625. "The `/`, when placed at the beginning of a line, wraps all text after it in an HTML comment",
  626. """
  627. peanutbutterjelly
  628. / This is the peanutbutterjelly element
  629. | I like sandwiches!
  630. """, """
  631. <peanutbutterjelly>
  632. <!-- This is the peanutbutterjelly element -->
  633. I like sandwiches!
  634. </peanutbutterjelly>
  635. """)
  636. testRender(
  637. "The `/` can also wrap indented sections of code.",
  638. """
  639. /
  640. p This doesn't render...
  641. div
  642. h1 Because it's commented out!
  643. """, """
  644. <!--
  645. <p>This doesn't render...</p>
  646. <div>
  647. <h1>Because it's commented out!</h1>
  648. </div>
  649. -->
  650. """)
  651. testRender(
  652. "You can also use Internet Explorer conditional comments by enclosing the condition in square brackets",
  653. """
  654. /[if IE]
  655. a{ :href => "http://www.mozilla.com/en-US/firefox/" }
  656. h1 Get Firefox
  657. """, """
  658. <!--[if IE]>
  659. <a href="http://www.mozilla.com/en-US/firefox/">
  660. <h1>Get Firefox</h1>
  661. </a>
  662. <![endif]-->
  663. """)
  664. testRender(
  665. "`-#` signifies a silent comment.",
  666. """
  667. p foo
  668. -# This is a comment
  669. p bar
  670. """, """
  671. <p>foo</p>
  672. <p>bar</p>
  673. """)
  674. testRender(
  675. "You can also nest text beneath a `-#`",
  676. """
  677. p foo
  678. -#
  679. This won't be displayed
  680. Nor will this
  681. p bar
  682. """, """
  683. <p>foo</p>
  684. <p>bar</p>
  685. """)
  686. /////////////////////////////////////////////////////////////////////
  687. //
  688. // Scala Evaluation: Inserting Scala: `=`
  689. //
  690. /////////////////////////////////////////////////////////////////////
  691. testRender(
  692. "`=` is followed by Scala code. This code is evaluated and the output is inserted into the document.",
  693. """
  694. p
  695. = List("hi", "there", "reader!").mkString(" ")
  696. = "yo"
  697. """, """
  698. <p>
  699. hi there reader!
  700. yo
  701. </p>
  702. """)
  703. testRender(
  704. "`=` can also be used at the end of a tag to insert Scala code within that tag.",
  705. """
  706. p= "hello"
  707. """, """
  708. <p>hello</p>
  709. """)
  710. testRender(
  711. "'= var' expressions can acess implicitly bound variables",
  712. """
  713. html
  714. body
  715. = context.name
  716. """, """
  717. <html>
  718. <body>
  719. Hiram
  720. </body>
  721. </html>
  722. """)
  723. testRender(
  724. "'= var' expressions can access imported variables",
  725. """
  726. html
  727. body
  728. = name
  729. """, """
  730. <html>
  731. <body>
  732. Hiram
  733. </body>
  734. </html>
  735. """)
  736. testRender(
  737. "= on a NodeSeq is rendered unsanitized",
  738. """
  739. -@ val bean:Bean
  740. = bean.link
  741. """, """
  742. <a href="#size-10">red</a>
  743. """)
  744. testRender(
  745. "!= a NodeSeq is rendered unsanitized",
  746. """
  747. -@ val bean:Bean
  748. != bean.link
  749. """, """
  750. <a href="#size-10">red</a>
  751. """)
  752. // TODO should we do this???
  753. /*
  754. testRender("&= a NodeSeq is rendered sanitized",
  755. """
  756. -@ val bean:Bean
  757. &= bean.link
  758. ""","""
  759. &lt;a href=&quot;#size-10&quot;&gt;red&lt;/a&gt;
  760. """)
  761. */
  762. testRender(
  763. "&= a NodeSeq.toString is rendered sanitized",
  764. """
  765. -@ val bean:Bean
  766. &= bean.link.toString
  767. """, """
  768. &lt;a href=&quot;#size-10&quot;&gt;red&lt;/a&gt;
  769. """)
  770. /////////////////////////////////////////////////////////////////////
  771. //
  772. // Scala Evaluation: Running Scala: `-`
  773. //
  774. /////////////////////////////////////////////////////////////////////
  775. testRender(
  776. "`-` is followed by Scala code. The code is evaluated but *not* inserted into the document.",
  777. """
  778. - var foo = "hello"
  779. - foo += " there"
  780. - foo += " you!"
  781. p= foo
  782. """, """
  783. <p>hello there you!</p>
  784. """)
  785. testRender(
  786. "`-` is followed by an indented Scala code block. The code is evaluated but *not* inserted into the document.",
  787. """
  788. -
  789. var foo = "hello"
  790. // note: you can use creative indentation in the block
  791. foo += " there"
  792. foo += " you!"
  793. p= foo
  794. """, """
  795. <p>hello there you!</p>
  796. """)
  797. /////////////////////////////////////////////////////////////////////
  798. //
  799. // Scala Evaluation: Scala Blocks
  800. //
  801. /////////////////////////////////////////////////////////////////////
  802. testRender(
  803. "Nest block for case statements",
  804. """
  805. p
  806. - 2 match
  807. - case 1 =>
  808. = "one"
  809. - case 2 =>
  810. = "two"
  811. - case 3 =>
  812. = "three"
  813. """, """
  814. <p>
  815. two
  816. </p>
  817. """)
  818. testRender(
  819. "Nest block for a `for` loop",
  820. """
  821. - for(i <- 42 to 46)
  822. p= i
  823. p See, I can count!
  824. """, """
  825. <p>42</p>
  826. <p>43</p>
  827. <p>44</p>
  828. <p>45</p>
  829. <p>46</p>
  830. <p>See, I can count!</p>
  831. """)
  832. testRender(
  833. "Passing partial funtions.",
  834. """
  835. p
  836. = List(1,2,3).foldLeft("result: ")
  837. - (a,x)=>
  838. - a+x
  839. """, """
  840. <p>
  841. result: 123
  842. </p>
  843. """)
  844. testRender(
  845. "loop constructs don't need {} ",
  846. """
  847. ol
  848. li start
  849. - for( i <- 1 to 3 )
  850. - val message = "Hi "+i
  851. li= message
  852. li end
  853. """, """
  854. <ol>
  855. <li>start</li>
  856. <li>Hi 1</li>
  857. <li>Hi 2</li>
  858. <li>Hi 3</li>
  859. <li>end</li>
  860. </ol>
  861. """)
  862. testRender(
  863. "if / else constructs",
  864. """
  865. - if ( 1==2 )
  866. p alternate reality
  867. - else
  868. p still on earth
  869. """, """
  870. <p>still on earth</p>
  871. """)
  872. testRender(
  873. "try / catch constructs",
  874. """
  875. - try
  876. p in try
  877. - throw new IllegalStateException()
  878. - catch
  879. - case e:IllegalStateException =>
  880. p got the expected error
  881. - case e:Exception =>
  882. p some odd error occurred
  883. """, """
  884. <p>in try</p>
  885. <p>got the expected error</p>
  886. """)
  887. /////////////////////////////////////////////////////////////////////
  888. //
  889. // Scala Interpolation: `#{}`
  890. //
  891. /////////////////////////////////////////////////////////////////////
  892. testRender(
  893. "Scala code can be interpolated within plain text using `#{}`",
  894. """
  895. p This is #{quality} cake!
  896. """, """
  897. <p>This is scrumptious cake!</p>
  898. """)
  899. testRender(
  900. "Backslashes can be used to escape `#{` strings, but they don't act as escapes anywhere else in the string.",
  901. """
  902. p
  903. | A slash make a difference here: \#{name} is set to: \\#{name}
  904. | But is ignored for: \# or \\
  905. """, """
  906. <p>
  907. A slash make a difference here: #{name} is set to: \Hiram
  908. But is ignored for: \# or \\
  909. </p>
  910. """)
  911. /////////////////////////////////////////////////////////////////////
  912. //
  913. // Escaping HTML: `&=`
  914. //
  915. /////////////////////////////////////////////////////////////////////
  916. testRender(
  917. "'&= expression' sanitizes the rendered expression",
  918. """
  919. &= "I like cheese & crackers"
  920. """, """
  921. I like cheese &amp; crackers
  922. """)
  923. testRender(
  924. "'& text' santizes interpolated expressions",
  925. """
  926. & I like #{"cheese & crackers"}
  927. """, """
  928. I like cheese &amp; crackers
  929. """)
  930. testRender(
  931. "'= expression' is sanitized by default",
  932. """
  933. = "I feel <strong>!"
  934. """, """
  935. I feel &lt;strong&gt;!
  936. """)
  937. /////////////////////////////////////////////////////////////////////
  938. //
  939. // Unescaping HTML: `!=`
  940. //
  941. /////////////////////////////////////////////////////////////////////
  942. testRender(
  943. "'!= expression' does not santize the rendered expression",
  944. """
  945. != "I feel <strong>!"
  946. """, """
  947. I feel <strong>!
  948. """)
  949. testRender(
  950. "'! text' does not santize interpolated expressions",
  951. """
  952. ! I feel #{"<strong>"}!
  953. """, """
  954. I feel <strong>!
  955. """)
  956. testRender(
  957. "'-@ val' makes an attribute accessibe as variable",
  958. """
  959. -@ val bean:Bean
  960. | The bean is #{bean.color}
  961. """, """
  962. The bean is red
  963. """)
  964. testRender(
  965. "'-@ import val' makes an attribute's members accessibe as variables",
  966. """
  967. -@ import val bean:Bean
  968. | The bean is #{color}
  969. """, """
  970. The bean is red
  971. """)
  972. testRender(
  973. "'-@ val name:type = expression' can specify a default value if the named attribute is not set",
  974. """
  975. -@ val doesnotexist:Bean = Bean("blue", 5)
  976. | The bean is #{doesnotexist.color}
  977. """, """
  978. The bean is blue
  979. """)
  980. testRender(
  981. "'-@ val' can be used in nested tags",
  982. """
  983. html
  984. | test
  985. -@ val bean:Bean
  986. | The bean is #{bean.color}
  987. """, """
  988. <html>
  989. test
  990. The bean is red
  991. </html>
  992. """)
  993. /////////////////////////////////////////////////////////////////////
  994. //
  995. // Preserving White Space
  996. //
  997. /////////////////////////////////////////////////////////////////////
  998. testRender(
  999. "Generated content in dynamic expression are properly indented.",
  1000. """
  1001. html
  1002. p
  1003. = "line1\nline2\nline3"
  1004. """, """
  1005. <html>
  1006. <p>
  1007. line1
  1008. line2
  1009. line3
  1010. </p>
  1011. </html>
  1012. """)
  1013. testRender(
  1014. "`~` preserves white space",
  1015. """
  1016. html
  1017. p
  1018. ~ "line1\nline2\nline3"
  1019. """, """
  1020. <html>
  1021. <p>
  1022. line1&#x000A;line2&#x000A;line3
  1023. </p>
  1024. </html>
  1025. """)
  1026. testRender(
  1027. "`&~` preserves and sanitizes",
  1028. """
  1029. &~ "<tag>\n</tag>"
  1030. """, """
  1031. &lt;tag&gt;&#x000A;&lt;/tag&gt;
  1032. """)
  1033. testRender(
  1034. "`!~` preserves and does not sanitize",
  1035. """
  1036. !~ "<tag>\n</tag>"
  1037. """, """
  1038. <tag>&#x000A;</tag>
  1039. """)
  1040. testRender(
  1041. "`~~` ugly preserves white space. values are not indented at all.",
  1042. """
  1043. html
  1044. p
  1045. ~~ "line1\nline2\nline3"
  1046. """, """
  1047. <html>
  1048. <p>
  1049. line1
  1050. line2
  1051. line3
  1052. </p>
  1053. </html>
  1054. """)
  1055. testRender(
  1056. "If the ScamlOptions.ugly option is enabled, then `=` behaves like `~~`",
  1057. """
  1058. html
  1059. p
  1060. = "line1\nline2\nline3"
  1061. """, """
  1062. <html>
  1063. <p>
  1064. line1
  1065. line2
  1066. line3
  1067. </p>
  1068. </html>
  1069. """, { () =>
  1070. ScamlOptions.ugly = true
  1071. }, { () =>
  1072. ScamlOptions.ugly = ScamlOptions.DEFAULT_UGLY
  1073. })
  1074. /////////////////////////////////////////////////////////////////////
  1075. //
  1076. // Indent Handling..
  1077. // You should enable white space viewing in your editor before touching this
  1078. // section.
  1079. //
  1080. /////////////////////////////////////////////////////////////////////
  1081. testRender(
  1082. "Jade eats empty lines",
  1083. """
  1084. ul
  1085. li item 1
  1086. ul
  1087. li item 1
  1088. li item 2
  1089. li item 2
  1090. p test
  1091. """, """
  1092. <ul>
  1093. <li>item 1</li>
  1094. <ul>
  1095. <li>item 1</li>
  1096. <li>item 2</li>
  1097. </ul>
  1098. <li>item 2</li>
  1099. </ul>
  1100. <p>test</p>
  1101. """)
  1102. testRender(
  1103. "Jade does not eat empty lines in a filter",
  1104. """
  1105. :plain
  1106. item 1
  1107. item 2
  1108. p test
  1109. """, """
  1110. item 1
  1111. item 2
  1112. <p>test</p>
  1113. """)
  1114. // https://groups.google.com/group/scalate/browse_thread/thread/fb0816c388936541
  1115. testRender(
  1116. "Supports consecutive includes",
  1117. """
  1118. - include("/jade-include-1.jade")
  1119. - include("/jade-include-2.jade")
  1120. """, """
  1121. <p>1</p>
  1122. <p>2</p>
  1123. """)
  1124. }
  1125. case class Bean(color: String, size: Int) {
  1126. def link = {
  1127. <a href={ "#size-" + size }>{ color }</a>
  1128. }
  1129. }