frontsau 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +21 -0
  5. data/README.md +30 -0
  6. data/Rakefile +2 -0
  7. data/bin/frontsau +15 -0
  8. data/bin/frontsau-phaml-compiler +35 -0
  9. data/example/.frontsau +12 -0
  10. data/example/assets/head.jpg +0 -0
  11. data/example/assets/script.js +4 -0
  12. data/example/assets/style.css +6 -0
  13. data/example/css/includes.sass +2 -0
  14. data/example/css/style.sass +6 -0
  15. data/example/image/head.jpg +0 -0
  16. data/example/index.html +0 -0
  17. data/example/js/script.coffee +1 -0
  18. data/frontsau.gemspec +41 -0
  19. data/lib/Phamlp/Phamlp.php +72 -0
  20. data/lib/Phamlp/PhamlpException.php +31 -0
  21. data/lib/Phamlp/haml/HamlException.php +29 -0
  22. data/lib/Phamlp/haml/HamlHelpers.php +199 -0
  23. data/lib/Phamlp/haml/HamlParser.php +1250 -0
  24. data/lib/Phamlp/haml/filters/HamlBaseFilter.php +30 -0
  25. data/lib/Phamlp/haml/filters/HamlCdataFilter.php +29 -0
  26. data/lib/Phamlp/haml/filters/HamlCssFilter.php +30 -0
  27. data/lib/Phamlp/haml/filters/HamlEscapedFilter.php +32 -0
  28. data/lib/Phamlp/haml/filters/HamlJavascriptFilter.php +31 -0
  29. data/lib/Phamlp/haml/filters/HamlPhpFilter.php +27 -0
  30. data/lib/Phamlp/haml/filters/HamlPlainFilter.php +28 -0
  31. data/lib/Phamlp/haml/filters/HamlPreserveFilter.php +29 -0
  32. data/lib/Phamlp/haml/filters/HamlSassFilter.php +37 -0
  33. data/lib/Phamlp/haml/filters/HamlScssFilter.php +37 -0
  34. data/lib/Phamlp/haml/filters/_HamlMarkdownFilter.php +50 -0
  35. data/lib/Phamlp/haml/filters/_HamlTextileFilter.php +50 -0
  36. data/lib/Phamlp/haml/messages/_i18n.php +32 -0
  37. data/lib/Phamlp/haml/messages/de.php +32 -0
  38. data/lib/Phamlp/haml/messages/fr.php +32 -0
  39. data/lib/Phamlp/haml/renderers/HamlCompactRenderer.php +32 -0
  40. data/lib/Phamlp/haml/renderers/HamlCompressedRenderer.php +48 -0
  41. data/lib/Phamlp/haml/renderers/HamlExpandedRenderer.php +58 -0
  42. data/lib/Phamlp/haml/renderers/HamlNestedRenderer.php +77 -0
  43. data/lib/Phamlp/haml/renderers/HamlRenderer.php +137 -0
  44. data/lib/Phamlp/haml/tree/HamlCodeBlockNode.php +58 -0
  45. data/lib/Phamlp/haml/tree/HamlCommentNode.php +41 -0
  46. data/lib/Phamlp/haml/tree/HamlDoctypeNode.php +27 -0
  47. data/lib/Phamlp/haml/tree/HamlElementNode.php +52 -0
  48. data/lib/Phamlp/haml/tree/HamlFilterNode.php +50 -0
  49. data/lib/Phamlp/haml/tree/HamlHelperNode.php +73 -0
  50. data/lib/Phamlp/haml/tree/HamlNode.php +253 -0
  51. data/lib/Phamlp/haml/tree/HamlNodeExceptions.php +19 -0
  52. data/lib/Phamlp/haml/tree/HamlRootNode.php +58 -0
  53. data/lib/Phamlp/sass/SassException.php +29 -0
  54. data/lib/Phamlp/sass/SassFile.php +164 -0
  55. data/lib/Phamlp/sass/SassParser.php +848 -0
  56. data/lib/Phamlp/sass/extensions/compass/config.php +65 -0
  57. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/_blueprint.scss +47 -0
  58. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/_buttons.scss +101 -0
  59. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/_colors.scss +32 -0
  60. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/_debug.scss +11 -0
  61. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/_fancy-type.scss +86 -0
  62. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/_form.scss +68 -0
  63. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/_grid.scss +249 -0
  64. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/_ie.scss +109 -0
  65. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/_interaction.scss +57 -0
  66. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/_link-icons.scss +37 -0
  67. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/_liquid.scss +147 -0
  68. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/_print.scss +93 -0
  69. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/_reset.scss +3 -0
  70. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/_rtl.scss +133 -0
  71. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/_scaffolding.scss +54 -0
  72. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/_typography.scss +104 -0
  73. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/_utilities.scss +37 -0
  74. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/stylesheets/blueprint/reset/_utilities.scss +58 -0
  75. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/basic/grid.png +0 -0
  76. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/basic/ie.sass +4 -0
  77. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/basic/manifest.rb +30 -0
  78. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/basic/partials/_base.sass +10 -0
  79. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/basic/print.sass +4 -0
  80. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/basic/screen.sass +12 -0
  81. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/buttons/buttons/cross.png +0 -0
  82. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/buttons/buttons/key.png +0 -0
  83. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/buttons/buttons/tick.png +0 -0
  84. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/buttons/buttons.sass +49 -0
  85. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/buttons/manifest.rb +17 -0
  86. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/link_icons/link_icons/doc.png +0 -0
  87. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/link_icons/link_icons/email.png +0 -0
  88. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/link_icons/link_icons/external.png +0 -0
  89. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/link_icons/link_icons/feed.png +0 -0
  90. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/link_icons/link_icons/im.png +0 -0
  91. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/link_icons/link_icons/pdf.png +0 -0
  92. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/link_icons/link_icons/visited.png +0 -0
  93. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/link_icons/link_icons/xls.png +0 -0
  94. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/link_icons/link_icons.sass +13 -0
  95. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/link_icons/manifest.rb +23 -0
  96. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/project/grid.png +0 -0
  97. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/project/ie.sass +16 -0
  98. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/project/manifest.rb +30 -0
  99. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/project/partials/_base.sass +11 -0
  100. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/project/print.sass +8 -0
  101. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/project/screen.sass +45 -0
  102. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/semantic/grid.png +0 -0
  103. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/semantic/ie.sass +16 -0
  104. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/semantic/manifest.rb +33 -0
  105. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/semantic/partials/_base.sass +10 -0
  106. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/semantic/partials/_form.sass +6 -0
  107. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/semantic/partials/_page.sass +18 -0
  108. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/semantic/partials/_two_col.sass +38 -0
  109. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/semantic/print.sass +5 -0
  110. data/lib/Phamlp/sass/extensions/compass/frameworks/blueprint/templates/semantic/screen.sass +14 -0
  111. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/_compass.scss +2 -0
  112. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/_css3.scss +15 -0
  113. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/_layout.scss +1 -0
  114. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/_reset.scss +3 -0
  115. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/_utilities.scss +6 -0
  116. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/css3/_background-clip.scss +43 -0
  117. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/css3/_background-origin.scss +42 -0
  118. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/css3/_background-size.scss +14 -0
  119. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/css3/_border-radius.scss +135 -0
  120. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/css3/_box-shadow.scss +50 -0
  121. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/css3/_box-sizing.scss +13 -0
  122. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/css3/_box.scss +112 -0
  123. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/css3/_columns.scss +55 -0
  124. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/css3/_font-face.scss +33 -0
  125. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/css3/_gradient.scss +82 -0
  126. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/css3/_inline-block.scss +12 -0
  127. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/css3/_opacity.scss +27 -0
  128. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/css3/_shared.scss +47 -0
  129. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/css3/_text-shadow.scss +25 -0
  130. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/css3/_transform.scss +85 -0
  131. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/css3/_transition.scss +85 -0
  132. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/layout/_sticky-footer.scss +23 -0
  133. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/reset/_utilities.scss +133 -0
  134. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/_general.scss +6 -0
  135. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/_links.scss +3 -0
  136. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/_lists.scss +4 -0
  137. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/_print.scss +17 -0
  138. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/_sprites.scss +1 -0
  139. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/_tables.scss +3 -0
  140. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/_text.scss +3 -0
  141. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/general/_clearfix.scss +31 -0
  142. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/general/_float.scss +15 -0
  143. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/general/_hacks.scss +35 -0
  144. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/general/_min.scss +16 -0
  145. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/general/_reset.scss +2 -0
  146. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/general/_tabs.scss +1 -0
  147. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/general/_tag-cloud.scss +18 -0
  148. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/links/_hover-link.scss +5 -0
  149. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/links/_link-colors.scss +28 -0
  150. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/links/_unstyled-link.scss +7 -0
  151. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/lists/_bullets.scss +34 -0
  152. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/lists/_horizontal-list.scss +52 -0
  153. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/lists/_inline-block-list.scss +47 -0
  154. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/lists/_inline-list.scss +29 -0
  155. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/sprites/_sprite-img.scss +56 -0
  156. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/tables/_alternating-rows-and-columns.scss +20 -0
  157. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/tables/_borders.scss +27 -0
  158. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/tables/_scaffolding.scss +9 -0
  159. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/text/_ellipsis.scss +25 -0
  160. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/text/_nowrap.scss +2 -0
  161. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/stylesheets/compass/utilities/text/_replacement.scss +34 -0
  162. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/templates/ellipsis/ellipsis.sass +9 -0
  163. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/templates/ellipsis/manifest.rb +27 -0
  164. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/templates/ellipsis/xml/ellipsis.xml +14 -0
  165. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/templates/extension/manifest.rb +20 -0
  166. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/templates/extension/stylesheets/main.sass +1 -0
  167. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/templates/extension/templates/project/manifest.rb +2 -0
  168. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/templates/extension/templates/project/screen.sass +2 -0
  169. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/templates/project/USAGE.markdown +32 -0
  170. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/templates/project/ie.sass +6 -0
  171. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/templates/project/manifest.rb +4 -0
  172. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/templates/project/print.sass +6 -0
  173. data/lib/Phamlp/sass/extensions/compass/frameworks/compass/templates/project/screen.sass +7 -0
  174. data/lib/Phamlp/sass/extensions/compass/functions/colourStops.php +268 -0
  175. data/lib/Phamlp/sass/extensions/compass/functions/constants.php +44 -0
  176. data/lib/Phamlp/sass/extensions/compass/functions/fontFiles.php +30 -0
  177. data/lib/Phamlp/sass/extensions/compass/functions/imageSize.php +39 -0
  178. data/lib/Phamlp/sass/extensions/compass/functions/inlineData.php +84 -0
  179. data/lib/Phamlp/sass/extensions/compass/functions/lists.php +47 -0
  180. data/lib/Phamlp/sass/extensions/compass/functions/selectors.php +128 -0
  181. data/lib/Phamlp/sass/extensions/compass/functions/urls.php +143 -0
  182. data/lib/Phamlp/sass/extensions/compass/stylesheets/_compass.scss +2 -0
  183. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/_css3.scss +15 -0
  184. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/_layout.scss +1 -0
  185. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/_reset.scss +3 -0
  186. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/_utilities.scss +6 -0
  187. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/css3/_background-clip.scss +43 -0
  188. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/css3/_background-origin.scss +42 -0
  189. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/css3/_background-size.scss +14 -0
  190. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/css3/_border-radius.scss +135 -0
  191. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/css3/_box-shadow.scss +50 -0
  192. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/css3/_box-sizing.scss +13 -0
  193. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/css3/_box.scss +112 -0
  194. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/css3/_columns.scss +55 -0
  195. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/css3/_font-face.scss +33 -0
  196. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/css3/_gradient.scss +96 -0
  197. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/css3/_inline-block.scss +12 -0
  198. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/css3/_opacity.scss +27 -0
  199. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/css3/_shared.scss +47 -0
  200. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/css3/_text-shadow.scss +25 -0
  201. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/css3/_transform.scss +85 -0
  202. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/css3/_transition.scss +85 -0
  203. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/layout/_sticky-footer.scss +23 -0
  204. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/reset/_utilities.scss +133 -0
  205. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/_general.scss +6 -0
  206. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/_links.scss +3 -0
  207. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/_lists.scss +4 -0
  208. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/_print.scss +17 -0
  209. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/_sprites.scss +1 -0
  210. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/_tables.scss +3 -0
  211. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/_text.scss +3 -0
  212. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/general/_clearfix.scss +31 -0
  213. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/general/_float.scss +15 -0
  214. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/general/_hacks.scss +35 -0
  215. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/general/_min.scss +16 -0
  216. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/general/_reset.scss +2 -0
  217. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/general/_tabs.scss +1 -0
  218. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/general/_tag-cloud.scss +18 -0
  219. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/links/_hover-link.scss +5 -0
  220. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/links/_link-colors.scss +28 -0
  221. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/links/_unstyled-link.scss +7 -0
  222. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/lists/_bullets.scss +34 -0
  223. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/lists/_horizontal-list.scss +52 -0
  224. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/lists/_inline-block-list.scss +47 -0
  225. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/lists/_inline-list.scss +29 -0
  226. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/sprites/_sprite-img.scss +56 -0
  227. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/tables/_alternating-rows-and-columns.scss +20 -0
  228. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/tables/_borders.scss +27 -0
  229. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/tables/_scaffolding.scss +9 -0
  230. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/text/_ellipsis.scss +25 -0
  231. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/text/_nowrap.scss +2 -0
  232. data/lib/Phamlp/sass/extensions/compass/stylesheets/compass/utilities/text/_replacement.scss +34 -0
  233. data/lib/Phamlp/sass/messages/_i18n.php +122 -0
  234. data/lib/Phamlp/sass/messages/de.php +70 -0
  235. data/lib/Phamlp/sass/messages/fr.php +70 -0
  236. data/lib/Phamlp/sass/renderers/SassCompactRenderer.php +130 -0
  237. data/lib/Phamlp/sass/renderers/SassCompressedRenderer.php +102 -0
  238. data/lib/Phamlp/sass/renderers/SassExpandedRenderer.php +62 -0
  239. data/lib/Phamlp/sass/renderers/SassNestedRenderer.php +61 -0
  240. data/lib/Phamlp/sass/renderers/SassRenderer.php +51 -0
  241. data/lib/Phamlp/sass/script/SassScriptFunction.php +169 -0
  242. data/lib/Phamlp/sass/script/SassScriptFunctions.php +751 -0
  243. data/lib/Phamlp/sass/script/SassScriptLexer.php +114 -0
  244. data/lib/Phamlp/sass/script/SassScriptOperation.php +151 -0
  245. data/lib/Phamlp/sass/script/SassScriptParser.php +192 -0
  246. data/lib/Phamlp/sass/script/SassScriptParserExceptions.php +40 -0
  247. data/lib/Phamlp/sass/script/SassScriptVariable.php +57 -0
  248. data/lib/Phamlp/sass/script/literals/SassBoolean.php +67 -0
  249. data/lib/Phamlp/sass/script/literals/SassColour.php +886 -0
  250. data/lib/Phamlp/sass/script/literals/SassLiteral.php +359 -0
  251. data/lib/Phamlp/sass/script/literals/SassLiteralExceptions.php +47 -0
  252. data/lib/Phamlp/sass/script/literals/SassNumber.php +503 -0
  253. data/lib/Phamlp/sass/script/literals/SassString.php +106 -0
  254. data/lib/Phamlp/sass/tree/SassCommentNode.php +64 -0
  255. data/lib/Phamlp/sass/tree/SassContext.php +120 -0
  256. data/lib/Phamlp/sass/tree/SassDebugNode.php +84 -0
  257. data/lib/Phamlp/sass/tree/SassDirectiveNode.php +76 -0
  258. data/lib/Phamlp/sass/tree/SassElseNode.php +28 -0
  259. data/lib/Phamlp/sass/tree/SassExtendNode.php +47 -0
  260. data/lib/Phamlp/sass/tree/SassForNode.php +99 -0
  261. data/lib/Phamlp/sass/tree/SassIfNode.php +95 -0
  262. data/lib/Phamlp/sass/tree/SassImportNode.php +69 -0
  263. data/lib/Phamlp/sass/tree/SassMixinDefinitionNode.php +88 -0
  264. data/lib/Phamlp/sass/tree/SassMixinNode.php +91 -0
  265. data/lib/Phamlp/sass/tree/SassNode.php +342 -0
  266. data/lib/Phamlp/sass/tree/SassNodeExceptions.php +117 -0
  267. data/lib/Phamlp/sass/tree/SassPropertyNode.php +239 -0
  268. data/lib/Phamlp/sass/tree/SassRootNode.php +100 -0
  269. data/lib/Phamlp/sass/tree/SassRuleNode.php +337 -0
  270. data/lib/Phamlp/sass/tree/SassVariableNode.php +90 -0
  271. data/lib/Phamlp/sass/tree/SassWhileNode.php +64 -0
  272. data/lib/frontsau/assets/rack.rb +12 -0
  273. data/lib/frontsau/assets/sprockets.rb +59 -0
  274. data/lib/frontsau/assets/static_assets_compiler.rb +50 -0
  275. data/lib/frontsau/assets/url_rewriter.rb +22 -0
  276. data/lib/frontsau/assets/watcher.rb +60 -0
  277. data/lib/frontsau/thor_app.rb +118 -0
  278. data/lib/frontsau/version.rb +3 -0
  279. data/lib/frontsau.rb +64 -0
  280. metadata +578 -0
@@ -0,0 +1,1250 @@
1
+ <?php
2
+ /* SVN FILE: $Id: HamlParser.php 117 2010-09-21 09:41:58Z chris.l.yates@gmail.com $ */
3
+ /**
4
+ * HamlParser class file.
5
+ * HamlParser allows you to write view files in
6
+ * {@link http://haml-lang.com/ Haml}.
7
+ *
8
+ * Please see the {@link http://haml-lang.com/docs/yardoc/file.Haml_REFERENCE.html#plain_text Haml documentation} for the syntax.
9
+ *
10
+ * Credits:
11
+ * This is a port of Haml to PHP. All the genius comes from the people that
12
+ * invented and develop Haml; in particular:
13
+ * + {@link http://hamptoncatlin.com/ Hampton Catlin},
14
+ * + {@link http://nex-3.com/ Nathan Weizenbaum},
15
+ * + {@link http://chriseppstein.github.com/ Chris Eppstein}
16
+ *
17
+ * The bugs are mine. Please report any found at {@link http://code.google.com/p/phamlp/issues/list}
18
+ *
19
+ * Notes
20
+ * <ul>
21
+ * <li>Debug (addition)<ul>
22
+ * <li>Source debug - adds comments to the output showing each source line above
23
+ * the result - ?#s+ to turn on, ?#s- to turn off, ?#s! to toggle</li>
24
+ * <li>Output debug - shows the output directly in the browser - ?#o+ to turn on, ?#o- to turn off, ?#o! to toggle</li>
25
+ * <li>Control both at once - ?#so+ to turn on, ?#so- to turn off, ?#so! to toggle</li>
26
+ * <li>Ugly mode can be controlled by the template</li>
27
+ * <liUugly mode strips comments in the output by default</li>
28
+ * <li>Ugly mode is turned off when in debug</li></ul></li>
29
+ * <li>"-" command (notes)<ul>
30
+ * <li>PHP does not require ending ";"</li>
31
+ * <li>PHP control blocks are automatically bracketed</li>
32
+ * <li>Switch Case statements do not end with ":"
33
+ * <li>do-while control blocks are written as "do (expression)"</li></ul></li>
34
+ * </ul>
35
+ * Comes with filters that run "out of the box":
36
+ * + <b>plain</b>: useful for large chunks of text to ensure Haml doesn't do anything.
37
+ * + <b>escaped</b>: like plain but the output is (x)html escaped.
38
+ * + <b>preserve</b>: like plain but preserves the whitespace.
39
+ * + <b>cdata</b>: wraps the content in CDATA tags.
40
+ * + <b>javascript</b>: wraps the content in <script> and CDATA tags. Useful for adding inline JavaScript.
41
+ * + <b>css</b>: wraps the content in <style> and CDATA tags. Useful for adding inline CSS.
42
+ * + <b>php</b>: wraps the content in <?php tags. The content is PHP code.
43
+ * There are two filters that require external classes to work. See {@link http://code.google.com/p/phamlp/wiki/PredefinedFilters PredefinedFilters on the PHamlP wiki} for details of how to use them.
44
+ * + <b>markdown</b>: Parses the filtered text with Markdown.
45
+ * + <b>textile</b>: Parses the filtered text with Textile.
46
+ * PHP can be used in all the filters (except php) by wrapping expressions in #().
47
+ *
48
+ * @author Chris Yates <chris.l.yates@gmail.com>
49
+ * @copyright Copyright (c) 2010 PBM Web Development
50
+ * @license http://phamlp.googlecode.com/files/license.txt
51
+ * @package PHamlP
52
+ * @subpackage Haml
53
+ */
54
+
55
+ require_once('tree/HamlNode.php');
56
+ require_once('HamlHelpers.php');
57
+ require_once('HamlException.php');
58
+
59
+ /**
60
+ * HamlParser class.
61
+ * Parses {@link http://haml-lang.com/ Haml} view files.
62
+ * @package PHamlP
63
+ * @subpackage Haml
64
+ */
65
+ class HamlParser {
66
+ /**#@+
67
+ * Debug modes
68
+ */
69
+ const DEBUG_NONE = 0;
70
+ const DEBUG_SHOW_SOURCE = 1;
71
+ const DEBUG_SHOW_OUTPUT = 2;
72
+ const DEBUG_SHOW_ALL = 3;
73
+ /**#@-*/
74
+
75
+ /**#@+
76
+ * Regexes used to parse the document
77
+ */
78
+ const REGEX_HAML = '/(?m)^([ \x09]*)((?::(\w*))?(?:%([\w:-]*))?(?:\.((?:(?:[-_:a-zA-Z]|#\{.+?\})+(?:[-:\w]|#\{.+?\})*(?:\.?))*))?(?:#((?:[_:a-zA-Z]|#\{.+?\})+(?:[-:\w]|#\{.+?\})*))?(?:\[(.+)\])?(?:(\()((?:(?:html_attrs\(.*?\)|data[\t ]*=[\t ]*\{.+?\}|(?:[_:a-zA-Z]+[-:\w]*)[\t ]*=[\t ]*.+)[\t ]*)+\)))?(?:(\{)((?::(?:html_attrs\(.*?\)|data[\t ]*=>[\t ]*\{.+?\}|(?:[_:a-zA-Z]+[-:\w]*)[\t ]*=>?[\t ]*.+)(?:,?[\t ]*)?)+\}))?(\|?>?\|?<?) *((?:\?#)|!!!|\/\/|\/|-#|!=|&=|!|&|=|-|~|\\\\\\\\)? *(.*?)(?:\s(\|)?)?)$/'; // Haml line
79
+ const REGEX_ATTRIBUTES = '/:?(?:(data)\s*=>?\s*([({].*?[})]))|(\w+(?:[-:]\w*)*)\s*=>?\s*(?(?=\[)(?:\[(.+?)\])|(?(?=([\'"]))(?:[\'"](.*?)\5)|([^\s,]+)))/';
80
+ const REGEX_ATTRIBUTE_FUNCTION = '/^\$?[_a-zA-Z]\w*(?(?=->)(->[_a-zA-Z]\w*)+|(::[_a-zA-Z]\w*)?)\(.+\)$/'; // Matches functions and instantiated and static object methods
81
+ const REGEX_WHITESPACE_REMOVAL = '/(.*?)\s+$/s';
82
+ const REGEX_WHITESPACE_REMOVAL_DEBUG = '%(.*?)(?:<br />\s)$%s'; // whitespace control when showing output
83
+ //const REGEX_CODE_INTERPOLATION = '/(?:(?<!\\\\)#{(.+?(?:\(.*?\).*?)*)})/';
84
+ /**#@-*/
85
+ const MATCH_INTERPOLATION = '/(?<!\\\\)#\{(.*?)\}/';
86
+ const INTERPOLATE = '<?php echo \1; ?>';
87
+ const HTML_ATTRS = '/html_attrs\(\s*((?(?=\')(?:.*?)\'|(?:.*?)"))(?:\s*,\s*(.*?))?\)/';
88
+
89
+
90
+ /**#@+
91
+ * Haml regex match positions
92
+ */
93
+ const HAML_HAML = 0;
94
+ const HAML_INDENT = 1;
95
+ const HAML_SOURCE = 2;
96
+ const HAML_FILTER = 3;
97
+ const HAML_TAG = 4;
98
+ const HAML_CLASS = 5;
99
+ const HAML_ID = 6;
100
+ const HAML_OBJECT_REFERENCE = 7;
101
+ const HAML_OPEN_XML_ATTRIBUTES = 8;
102
+ const HAML_XML_ATTRIBUTES = 9;
103
+ const HAML_OPEN_RUBY_ATTRIBUTES = 10;
104
+ const HAML_RUBY_ATTRIBUTES = 11;
105
+ const HAML_WHITESPACE_REMOVAL = 12;
106
+ const HAML_TOKEN = 13;
107
+ const HAML_CONTENT = 14;
108
+ const HAML_MULTILINE = 15;
109
+ /**#@-*/
110
+
111
+ /**#@+
112
+ * Haml tokens
113
+ */
114
+ const DOCTYPE = '!!!';
115
+ const HAML_COMMENT = '!(-#|//)!';
116
+ const XML_COMMENT = '/';
117
+ const SELF_CLOSE_TAG = '/';
118
+ const ESCAPE_XML = '&=';
119
+ const UNESCAPE_XML = '!=';
120
+ const INSERT_CODE = '=';
121
+ const INSERT_CODE_PRESERVE_WHITESPACE = '~';
122
+ const RUN_CODE = '-';
123
+ const INNER_WHITESPACE_REMOVAL = '<';
124
+ const OUTER_WHITESPACE_REMOVAL = '>';
125
+ const BLOCK_LEFT_OUTER_WHITESPACE_REMOVAL = '|>';
126
+ const BLOCK_RIGHT_OUTER_WHITESPACE_REMOVAL = '>|';
127
+ /**#@-*/
128
+
129
+ const MULTILINE= ' |';
130
+
131
+ /**#@+
132
+ * Attribute tokens
133
+ */
134
+ const OPEN_XML_ATTRIBUTES = '(';
135
+ const CLOSE_XML_ATTRIBUTES = ')';
136
+ const OPEN_RUBY_ATTRIBUTES = '{';
137
+ const CLOSE_RUBY_ATTRIBUTES = '}';
138
+ /**#@-*/
139
+
140
+ /**#@+
141
+ * Directives
142
+ */
143
+ const DIRECTIVE = '?#';
144
+ const SOURCE_DEBUG = 's';
145
+ const OUTPUT_DEBUG = 'o';
146
+ /**#@-*/
147
+
148
+ const IS_XML_PROLOG = 'XML';
149
+ const XML_PROLOG = "<?php echo \"<?xml version='1.0' encoding='{encoding}' ?>\n\"; ?>";
150
+ const DEFAULT_XML_ENCODING = 'utf-8';
151
+ const XML_ENCODING = '{encoding}';
152
+
153
+ /**
154
+ * @var string Doctype format. Determines how the Haml Doctype declaration is
155
+ * rendered.
156
+ * @see doctypes
157
+ */
158
+ private $format = 'xhtml';
159
+ /**
160
+ * @var string Custom Doctype. If not null and the Doctype declaration in the
161
+ * Haml Document is not a built in Doctype this will be used as the Doctype.
162
+ * This allows Haml to be used for non-(X)HTML documents that are XML compliant.
163
+ * @see doctypes
164
+ * @see emptyTags
165
+ * @see inlineTags
166
+ * @see minimizedAttributes
167
+ */
168
+ private $doctype;
169
+ /**
170
+ * @var boolean whether or not to escape X(HT)ML-sensitive characters in script.
171
+ * If this is true, = behaves like &=; otherwise, it behaves like !=.
172
+ * Note that if this is set, != should be used for yielding to subtemplates
173
+ * and rendering partials. Defaults to false.
174
+ */
175
+ private $escapeHtml = false;
176
+ /**
177
+ * @var boolean Whether or not attribute hashes and scripts designated by
178
+ * = or ~ should be evaluated. If true, the scripts are rendered as empty strings.
179
+ * Defaults to false.
180
+ */
181
+ private $suppressEval = false;
182
+ /**
183
+ * @var string The character that should wrap element attributes. Characters
184
+ * of this type within attributes will be escaped (e.g. by replacing them with
185
+ * &apos;) if the character is an apostrophe or a quotation mark.
186
+ * Defaults to " (an quotation mark).
187
+ */
188
+ private $attrWrapper = '"';
189
+ /**
190
+ * @var array available output styles:
191
+ * nested: output is nested according to the indent level in the source
192
+ * expanded: block tags have their own lines as does content which is indented
193
+ * compact: block tags and their content go on one line
194
+ * compressed: all unneccessary whitepaces is removed. If ugly is true this style is used.
195
+ */
196
+ private $styles = array('nested', 'expanded', 'compact', 'compressed');
197
+ /**
198
+ * @var string output style. Note: ugly must be false to allow style.
199
+ */
200
+ private $style = 'nested';
201
+ /**
202
+ * @var boolean if true no attempt is made to properly indent or format
203
+ * the output. Reduces size of output file but is not very readable;
204
+ * equivalent of style == compressed. Note: ugly must be false to allow style.
205
+ * Defaults to true.
206
+ * @see style
207
+ */
208
+ private $ugly = true;
209
+ /**
210
+ * @var boolean if true comments are preserved in ugly mode. If not in
211
+ * ugly mode comments are always output. Defaults to false.
212
+ */
213
+ private $preserveComments = false;
214
+ /**
215
+ * @var integer Initial debug setting:
216
+ * no debug, show source, show output, or show all.
217
+ * Debug settings can be controlled in the template
218
+ * Defaults to DEBUG_NONE.
219
+ */
220
+ private $debug = self::DEBUG_NONE;
221
+ /**
222
+ * @var string Path to the directory containing user defined filters. If
223
+ * specified this dirctory will be searched before PHamlP looks for the filter
224
+ * in it's collection. This allows the default filters to be overridden and
225
+ * new filters to be installed. Note: No trailing directory separator.
226
+ */
227
+ private $filterDir;
228
+ /**
229
+ * @var string Path to the file containing user defined Haml helpers.
230
+ */
231
+ private $helperFile;
232
+ /**
233
+ * @var string Haml helper class. This must be an instance of HamlHelpers.
234
+ */
235
+ private $helperClass = 'HamlHelpers';
236
+
237
+ /**
238
+ * @var array built in Doctypes
239
+ * @see format
240
+ * @see doctype
241
+ */
242
+ private $doctypes = array (
243
+ 'html4' => array (
244
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">', //HTML 4.01 Transitional
245
+ 'Strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD 4.01 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">', //HTML 4.01 Strict
246
+ 'Frameset' => '<!DOCTYPE html PUBLIC "-//W3C//DTD 4.01 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">', //HTML 4.01 Frameset
247
+ ),
248
+ 'html5' => array (
249
+ '<!DOCTYPE html>', // XHTML 5
250
+ ),
251
+ 'xhtml' => array (
252
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">', //XHTML 1.0 Transitional
253
+ 'Strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">', //XHTML 1.0 Strict
254
+ 'Frameset' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">', //XHTML 1.0 Frameset
255
+ '5' => '<!DOCTYPE html>', // XHTML 5
256
+ '1.1' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">', // XHTML 1.1
257
+ 'Basic' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">', //XHTML Basic 1.1
258
+ 'Mobile' => '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">', //XHTML Mobile 1.2
259
+ )
260
+ );
261
+ /**
262
+ * @var array A list of tag names that should be automatically self-closed
263
+ * if they have no content.
264
+ */
265
+ private $emptyTags = array('meta', 'img', 'link', 'br', 'hr', 'input', 'area', 'param', 'col', 'base');
266
+ /**
267
+ * @var array A list of inline tags.
268
+ */
269
+ private $inlineTags = array('a', 'abbr', 'accronym', 'b', 'big', 'cite', 'code', 'dfn', 'em', 'i', 'kbd', 'q', 'samp', 'small', 'span', 'strike', 'strong', 'tt', 'u', 'var');
270
+ /**
271
+ * @var array attributes that are minimised
272
+ */
273
+ private $minimizedAttributes = array('compact', 'checked', 'declare', 'readonly', 'disabled', 'selected', 'defer', 'ismap', 'nohref', 'noshade', 'nowrap', 'multiple', 'noresize');
274
+ /**
275
+ * @var array A list of tag names that should automatically have their newlines preserved.
276
+ */
277
+ private $preserve = array('pre', 'textarea');
278
+ /**#@-*/
279
+
280
+ /**
281
+ * @var string the character used for indenting. Space or tab.
282
+ * @see indentSpaces
283
+ */
284
+ private $indentChar;
285
+ /**
286
+ * @var array allowable characters for indenting
287
+ */
288
+ private $indentChars = array(' ', "\t");
289
+ /**
290
+ * @var integer number of spaces for indentation.
291
+ * Used on source if {@link indentChar} is space.
292
+ * Used on output if {@link ugly} is false.
293
+ */
294
+ private $indentSpaces;
295
+ /**
296
+ * @var array loaded filters
297
+ */
298
+ private $filters = array();
299
+ /**
300
+ * @var boolean whether line is in a filter
301
+ */
302
+ private $inFilter = false;
303
+ /**
304
+ * @var boolean whether to show the output in the browser for debug
305
+ */
306
+ private $showOutput;
307
+ /**
308
+ * @var boolean whether to show the source in the browser for debug
309
+ */
310
+ private $showSource;
311
+ /**
312
+ * @var integer line number of source being parsed
313
+ */
314
+ private $line;
315
+ /**
316
+ * @var string name of file being parsed
317
+ */
318
+ private $filename;
319
+ /**
320
+ * @var mixed source
321
+ */
322
+ private $source;
323
+
324
+ /**
325
+ * HamlParser constructor.
326
+ * @param array options
327
+ * @return HamlParser
328
+ */
329
+ public function __construct($options = array()) {
330
+ if (isset($options['language'])) {
331
+ Phamlp::$language = $options['language'];
332
+ unset($options['language']);
333
+ }
334
+ foreach ($options as $name => $value) {
335
+ $this->$name = $value;
336
+ } // foreach
337
+
338
+ if ($this->ugly) {
339
+ $this->style = 'compressed';
340
+ }
341
+
342
+ $this->format = strtolower($this->format);
343
+ if (is_null($this->doctype) &&
344
+ !array_key_exists($this->format, $this->doctypes)) {
345
+ throw new HamlException('Invalid {what} ({value}). Must be one of "{options}"', array('{what}'=>'format', '{value}'=>$this->format, '{options}'=>join(', ', array_keys($this->doctypes))), $this);
346
+ }
347
+
348
+ $this->showSource = $this->debug & HamlParser::DEBUG_SHOW_SOURCE;
349
+ $this->showOutput = $this->debug & HamlParser::DEBUG_SHOW_OUTPUT;
350
+
351
+ require_once dirname(__FILE__).DIRECTORY_SEPARATOR.'HamlHelpers.php';
352
+ if (isset($this->helperFile)) {
353
+ require_once $this->helperFile;
354
+ $this->helperClass = basename($this->helperFile, ".php");
355
+ if (!is_subclass_of($this->helperClass, 'HamlHelpers')) {
356
+ throw new HamlException('{what} must extend {base} class', array('{what}'=>$this->helperClass, '{base}'=>'HamlHelpers'), $this);
357
+ }
358
+ }
359
+ }
360
+
361
+ /**
362
+ * Getter.
363
+ * @param string name of property to get
364
+ * @return mixed return value of getter function
365
+ */
366
+ public function __get($name) {
367
+ $getter = 'get' . ucfirst($name);
368
+ if (method_exists($this, $getter)) {
369
+ return $this->$getter();
370
+ }
371
+ throw new HamlException('No getter function for {what}', array('{what}'=>$name));
372
+ }
373
+
374
+ public function getFilename() {
375
+ return $this->filename;
376
+ }
377
+
378
+ public function getLine() {
379
+ return $this->line;
380
+ }
381
+
382
+ public function getSource() {
383
+ return $this->source;
384
+ }
385
+
386
+ /**
387
+ * Parses a Haml file.
388
+ * If an output directory is given the resulting PHP is cached.
389
+ * @param string path to file to parse
390
+ * @param mixed boolean: true to use the default cache directory, false to use
391
+ * the source file directory. string: path to the cache directory.
392
+ * null: disable caching
393
+ * @param string output file extension
394
+ * @param integer permission for the output directory and file
395
+ * @return mixed string: the resulting PHP if no output directory is specified
396
+ * or the output filename if the output directory is specified.
397
+ * boolean: false if the output file could not be written.
398
+ */
399
+ public function parse($sourceFile, $cacheDir=null, $permission=0755, $sourceExtension='.haml', $outputExtension='.php') {
400
+ if (is_string($cacheDir) || is_bool($cacheDir)) {
401
+ if (is_bool($cacheDir)) {
402
+ $cacheDir =
403
+ ($cacheDir ? dirname(__FILE__).DIRECTORY_SEPARATOR.'haml-cache' :
404
+ dirname($sourceFile));
405
+ }
406
+ $outputFile = $cacheDir.DIRECTORY_SEPARATOR.
407
+ basename($sourceFile, $sourceExtension).$outputExtension;
408
+ if (@filemtime($sourceFile) > @filemtime($outputFile)) {
409
+ if (!is_dir($cacheDir)) {
410
+ @mkdir($cacheDir, $permission);
411
+ }
412
+ $return = (file_put_contents($outputFile, $this->haml2PHP($sourceFile))
413
+ === false ? false : $outputFile);
414
+ if ($return !== false) {
415
+ @chmod($outputFile, $permission);
416
+ }
417
+ }
418
+ else {
419
+ $return = $outputFile;
420
+ }
421
+ }
422
+ else {
423
+ $return = $this->haml2PHP($sourceFile);
424
+ }
425
+ return $return;
426
+ }
427
+
428
+ /**
429
+ * Parses a Haml file into PHP.
430
+ * @param string path to file to parse
431
+ * @return string the resulting PHP
432
+ */
433
+ public function haml2PHP($sourceFile) {
434
+ $this->line = 0;
435
+ $this->filename = $sourceFile;
436
+ $helpers = "<?php ";
437
+ //"<?php\nrequire_once '".dirname(__FILE__).DIRECTORY_SEPARATOR."HamlHelpers.php';\n";
438
+ if (isset($this->helperFile)) {
439
+ $helpers .= "require_once '{$this->helperFile}';\n";
440
+ }
441
+ $helpers .= "?>";
442
+ return $helpers . $this->toTree(file_get_contents($sourceFile))->render();
443
+ }
444
+
445
+ /**
446
+ * Parse Haml source into a document tree.
447
+ * @param string Haml source
448
+ * @return HamlRootNode the root of this document tree
449
+ */
450
+ private function toTree($source) {
451
+ $this->source = explode("\n", $source);
452
+ $this->setIndentChar();
453
+
454
+ preg_match_all(self::REGEX_HAML, $source, $this->source, PREG_SET_ORDER);
455
+ unset($source);
456
+ $root = new HamlRootNode(array(
457
+ 'format' => $this->format,
458
+ 'style' => $this->style,
459
+ 'attrWrapper' => $this->attrWrapper,
460
+ 'minimizedAttributes' => $this->minimizedAttributes
461
+ ));
462
+ $this->buildTree($root);
463
+ return $root;
464
+ }
465
+
466
+ /**
467
+ * Builds a parse tree under the parent node.
468
+ * @param HamlNode the parent node
469
+ */
470
+ private function buildTree($parent) {
471
+ while (!empty($this->source) && $this->isChildOf($parent, $this->source[0])) {
472
+ $line = $this->getNextLine();
473
+ if (!empty($line)) {
474
+ $node = ($this->inFilter ?
475
+ new HamlNode($line[self::HAML_SOURCE], $parent) :
476
+ $this->parseLine($line, $parent));
477
+
478
+ if (!empty($node)) {
479
+ $node->token = $line;
480
+ $node->showOutput = $this->showOutput;
481
+ $node->showSource = $this->showSource;
482
+ $this->addChildren($node, $line);
483
+ }
484
+ }
485
+ }
486
+ }
487
+
488
+ /**
489
+ * Adds children to a node if the current line has children.
490
+ * @param HamlNode the node to add children to
491
+ * @param array line to test
492
+ */
493
+ private function addChildren($node, $line) {
494
+ if ($node instanceof HamlFilterNode) {
495
+ $this->inFilter = true;
496
+ }
497
+ if ($this->hasChild($line, $this->inFilter)) {
498
+ $this->buildTree($node);
499
+ if ($node instanceof HamlFilterNode) {
500
+ $this->inFilter = false;
501
+ }
502
+ }
503
+ }
504
+
505
+ /**
506
+ * Returns a value indicating if the next line is a child of the parent line
507
+ * @param array parent line
508
+ * @param boolean whether to all greater than the current indent
509
+ * Used if the source line is a comment or a filter.
510
+ * If true all indented lines are regarded as children; if not the child line
511
+ * must only be indented by 1 or blank. Defaults to false.
512
+ * @return boolean true if the next line is a child of the parent line
513
+ * @throws Exception if the indent is invalid
514
+ */
515
+ private function hasChild($line, $allowGreater = false) {
516
+ if (!empty($this->source)) {
517
+ $i = 0;
518
+ $c = count($this->source);
519
+ while (empty($nextLine[self::HAML_SOURCE]) && $i <= $c) {
520
+ $nextLine = $this->source[$i++];
521
+ }
522
+
523
+ $level = $this->getLevel($nextLine, $line['line'] + $i);
524
+
525
+ if (($level == $line['level'] + 1) ||
526
+ ($allowGreater && $level > $line['level'])) {
527
+ return true;
528
+ }
529
+ elseif ($level <= $line['level']) {
530
+ return false;
531
+ }
532
+ else {
533
+ throw new HamlException('Illegal indentation level ({level}); indentation level can only increase by one', array('{level}'=>$level), $this);
534
+ }
535
+ }
536
+ else {
537
+ return false;
538
+ }
539
+ }
540
+
541
+ /**
542
+ * Returns a value indicating if $line is a child of a node.
543
+ * A blank line is a child of a node.
544
+ * @param HamlNode the node
545
+ * @param array the line to check
546
+ * @return boolean true if the line is a child of the node, false if not
547
+ */
548
+ private function isChildOf($node, $line) {
549
+ $haml = trim($line[self::HAML_HAML]);
550
+ return empty($haml) || $this->getLevel($line, $this->line) >
551
+ $node->level;
552
+ }
553
+
554
+ /**
555
+ * Determine the indent character and indent spaces.
556
+ * The first character of the first indented line determines the character.
557
+ * If this is a space the number of spaces determines the indentSpaces; this
558
+ * is always 1 if the indent character is a tab.
559
+ * @throws HamlException if the indent is mixed
560
+ */
561
+ private function setIndentChar() {
562
+ foreach ($this->source as $l=>$source) {
563
+ if (!empty($source) && in_array($source[0], $this->indentChars)) {
564
+ $this->indentChar = $source[0];
565
+ for ($i = 0, $len = strlen($source); $i < $len && $source[$i] == $this->indentChar; $i++);
566
+ if ($i < $len && in_array($source[$i], $this->indentChars)) {
567
+ $this->line = ++$l;
568
+ $this->source = $source;
569
+ throw new HamlException('Mixed indentation not allowed', array(), $this);
570
+ }
571
+ $this->indentSpaces = ($this->indentChar == ' ' ? $i : 1);
572
+ return;
573
+ }
574
+ } // foreach
575
+ $this->indentChar = ' ';
576
+ $this->indentSpaces = 2;
577
+ }
578
+
579
+ /**
580
+ * Gets the next line.
581
+ * @param array remaining source lines
582
+ * @return array the next line
583
+ */
584
+ private function getNextLine() {
585
+ $line = array_shift($this->source);
586
+ // Blank lines ore OK
587
+ $haml = trim($line[self::HAML_HAML]);
588
+ if (empty($haml)) {
589
+ $this->line++;
590
+ return null;
591
+ }
592
+ // The regex will strip off a '<' at the start of a line
593
+ if ($line[self::HAML_WHITESPACE_REMOVAL] ===
594
+ self::INNER_WHITESPACE_REMOVAL && empty($line[self::HAML_TAG])) {
595
+ $line[self::HAML_CONTENT] =
596
+ $line[self::HAML_WHITESPACE_REMOVAL].$line[self::HAML_TOKEN].$line[self::HAML_CONTENT];
597
+ }
598
+ // The regex treats lines starting with [.+] as an object reference; they are just content
599
+ if (!empty($line[self::HAML_OBJECT_REFERENCE]) && empty($line[self::HAML_TAG])) {
600
+ unset($line[self::HAML_OBJECT_REFERENCE]);
601
+ $line[self::HAML_CONTENT] = $line[self::HAML_SOURCE];
602
+ }
603
+ $line['line'] = $this->line++;
604
+ $line['level'] = $this->getLevel($line, $this->line);
605
+ $line['filename'] = $this->filename;
606
+ if ($this->isMultiline($line)) {
607
+ $line = $this->getMultiline($line);
608
+ }
609
+ return $line;
610
+ }
611
+
612
+ /**
613
+ * Returns the indent level of the line.
614
+ * @param array the line
615
+ * @param integer line number
616
+ * @return integer the indent level of the line
617
+ * @throws Exception if the indent level is invalid
618
+ */
619
+ private function getLevel($line, $n) {
620
+ if ($line[self::HAML_INDENT] && $this->indentChar === ' ') {
621
+ $indent = strlen($line[self::HAML_INDENT]) / $this->indentSpaces;
622
+ }
623
+ else {
624
+ $indent = strlen($line[self::HAML_INDENT]);
625
+ }
626
+
627
+ if (!is_integer($indent) ||
628
+ preg_match("/[^{$this->indentChar}]/", $line[self::HAML_INDENT])) {
629
+ throw new HamlException('Invalid indentation', array(), $this);
630
+ }
631
+ return $indent;
632
+ }
633
+
634
+ /**
635
+ * Parse a line of Haml into a HamlNode for the document tree
636
+ * @param array line to parse
637
+ * @param HamlNode parent node
638
+ * @return HamlNode
639
+ */
640
+ private function parseLine($line, $parent) {
641
+ if ($this->isHamlComment($line)) {
642
+ return $this->parseHamlComment($line);
643
+ }
644
+ elseif ($this->isXmlComment($line)) {
645
+ return $this->parseXmlComment($line, $parent);
646
+ }
647
+ elseif ($this->isElement($line)) {
648
+ return $this->parseElement($line, $parent);
649
+ }
650
+ elseif ($this->isHelper($line)) {
651
+ return $this->parseHelper($line, $parent);
652
+ }
653
+ elseif ($this->isCode($line)) {
654
+ return $this->parseCode($line, $parent);
655
+ }
656
+ elseif ($this->isDirective($line)) {
657
+ return $this->parseDirective($line, $parent);
658
+ }
659
+ elseif ($this->isFilter($line)) {
660
+ return $this->parseFilter($line, $parent);
661
+ }
662
+ elseif ($this->isDoctype($line)) {
663
+ return $this->parseDoctype($line, $parent);
664
+ }
665
+ else {
666
+ return $this->parseContent($line, $parent);
667
+ }
668
+ }
669
+
670
+ /**
671
+ * Return a value indicating if the line has content.
672
+ * @param array line
673
+ * @return boolean true if the line has a content, false if not
674
+ */
675
+ private function hasContent($line) {
676
+ return !empty($line[self::HAML_CONTENT]);
677
+ }
678
+
679
+ /**
680
+ * Return a value indicating if the line is code to be run.
681
+ * @param array line
682
+ * @return boolean true if the line is code to be run, false if not
683
+ */
684
+ private function isCode($line) {
685
+ return $line[self::HAML_TOKEN] === self::RUN_CODE;
686
+ }
687
+
688
+ /**
689
+ * Return a value indicating if the line is a directive.
690
+ * @param array line
691
+ * @return boolean true if the line is a directive, false if not
692
+ */
693
+ private function isDirective($line) {
694
+ return $line[self::HAML_TOKEN] === self::DIRECTIVE;
695
+ }
696
+
697
+ /**
698
+ * Return a value indicating if the line is a doctype.
699
+ * @param array line
700
+ * @return boolean true if the line is a doctype, false if not
701
+ */
702
+ private function isDoctype($line) {
703
+ return $line[self::HAML_TOKEN] === self::DOCTYPE;
704
+ }
705
+
706
+ /**
707
+ * Return a value indicating if the line is an element.
708
+ * Will set the tag to div if it is an implied div.
709
+ * @param array line
710
+ * @return boolean true if the line is an element, false if not
711
+ */
712
+ private function isElement(&$line) {
713
+ if (empty($line[self::HAML_TAG]) && (
714
+ !empty($line[self::HAML_CLASS]) ||
715
+ !empty($line[self::HAML_ID]) ||
716
+ !empty($line[self::HAML_XML_ATTRIBUTES]) ||
717
+ !empty($line[self::HAML_RUBY_ATTRIBUTES]) ||
718
+ !empty($line[self::HAML_OBJECT_REFERENCE])
719
+ )) {
720
+ $line[self::HAML_TAG] = 'div';
721
+ }
722
+
723
+ return !empty($line[self::HAML_TAG]);
724
+ }
725
+
726
+ /**
727
+ * Return a value indicating if the line starts a filter.
728
+ * @param array line to test
729
+ * @return boolean true if the line starts a filter, false if not
730
+ */
731
+ private function isFilter($line) {
732
+ return !empty($line[self::HAML_FILTER]);
733
+ }
734
+
735
+ /**
736
+ * Return a value indicating if the line is a Haml comment.
737
+ * @param array line to test
738
+ * @return boolean true if the line is a Haml comment, false if not
739
+ */
740
+ private function isHamlComment($line) {
741
+ return preg_match(self::HAML_COMMENT, $line[self::HAML_TOKEN]) > 0;
742
+ }
743
+
744
+ /**
745
+ * Return a value indicating if the line is a HamlHelper.
746
+ * @param array line to test
747
+ * @return boolean true if the line is a HamlHelper, false if not
748
+ */
749
+ private function isHelper($line) {
750
+ return (preg_match(HamlHelperNode::MATCH, $line[self::HAML_CONTENT], $matches)
751
+ ? method_exists($this->helperClass, $matches[HamlHelperNode::NAME]) : false);
752
+ }
753
+
754
+ /**
755
+ * Return a value indicating if the line is an XML comment.
756
+ * @param array line to test
757
+ * @return boolean true if theline is an XML comment, false if not
758
+ */
759
+ private function isXmlComment($line) {
760
+ return $line[self::HAML_SOURCE][0] === self::XML_COMMENT;
761
+ }
762
+
763
+ /**
764
+ * Returns a value indicating whether the line is part of a multilne group
765
+ * @param array the line to test
766
+ * @return boolean true if the line os part of a multiline group, false if not
767
+ */
768
+ private function isMultiline($line) {
769
+ return substr($line[self::HAML_SOURCE], -2) === self::MULTILINE;
770
+ }
771
+
772
+ /**
773
+ * Return a value indicating if the line's tag is a block level tag.
774
+ * @param array line
775
+ * @return boolean true if the line's tag is is a block level tag, false if not
776
+ */
777
+ private function isBlock($line) {
778
+ return (!in_array($line[self::HAML_TAG], $this->inlineTags));
779
+ }
780
+
781
+ /**
782
+ * Return a value indicating if the line's tag is self-closing.
783
+ * @param array line
784
+ * @return boolean true if the line's tag is self-closing, false if not
785
+ */
786
+ private function isSelfClosing($line) {
787
+ return (in_array($line[self::HAML_TAG], $this->emptyTags) ||
788
+ $line[self::HAML_TOKEN] == self::SELF_CLOSE_TAG);
789
+ }
790
+
791
+ /**
792
+ * Gets a filter.
793
+ * Filters are loaded on first use.
794
+ * @param string filter name
795
+ * @throws HamlException if the filter does not exist or does not extend HamlBaseFilter
796
+ */
797
+ private function getFilter($filter) {
798
+ static $firstRun = true;
799
+ $imported = false;
800
+
801
+ if (empty($this->filters[$filter])) {
802
+ if ($firstRun) {
803
+ require_once('filters/HamlBaseFilter.php');
804
+ $firstRun = false;
805
+ }
806
+
807
+ $filterclass = 'Haml' . ucfirst($filter) . 'Filter';
808
+ if (isset($this->filterDir)) {
809
+ $this->filterDir = (substr($this->filterDir, -1) == DIRECTORY_SEPARATOR?
810
+ substr($this->filterDir, 0, -1):$this->filterDir);
811
+ if (file_exists($this->filterDir.DIRECTORY_SEPARATOR."$filterclass.php")) {
812
+ require_once($this->filterDir.DIRECTORY_SEPARATOR."$filterclass.php");
813
+ $imported = true;
814
+ }
815
+ }
816
+
817
+ if (!$imported && file_exists(dirname(__FILE__).DIRECTORY_SEPARATOR.'filters'.DIRECTORY_SEPARATOR."$filterclass.php")) {
818
+ require_once("filters/$filterclass.php");
819
+ $imported = true;
820
+ }
821
+
822
+ if (!$imported) {
823
+ throw new HamlException('Unable to find {what}: {filename}', array('{what}'=>$filter.' filter', '{filename}'=>$filterclass.'.php'), $this);
824
+ }
825
+
826
+ $this->filters[$filter] = new $filterclass();
827
+
828
+ if (!($this->filters[$filter] instanceof HamlBaseFilter)) {
829
+ throw new HamlException('{what} must extend {base} class', array('{what}'=>$filter, '{base}'=>'HamlBaseFilter'), $this);
830
+ }
831
+
832
+ $this->filters[$filter]->init();
833
+ }
834
+ return $this->filters[$filter];
835
+ }
836
+
837
+ /**
838
+ * Gets the next line.
839
+ * @param array first line
840
+ * @return array the next line
841
+ */
842
+ private function getMultiline($line) {
843
+ do {
844
+ $multiLine = array_shift($this->source);
845
+ $line[self::HAML_CONTENT] .= substr($multiLine[self::HAML_SOURCE], 0, -2);
846
+ } while(!empty($this->source) && $this->isMultiline($this->source[0]));
847
+ return $line;
848
+ }
849
+
850
+ /**
851
+ * Parse attributes.
852
+ * @param array line to parse
853
+ * @return array attributes in name=>value pairs
854
+ */
855
+ private function parseAttributes($line) {
856
+ $attributes = array();
857
+ if (!empty($line[self::HAML_OPEN_XML_ATTRIBUTES])) {
858
+ if (empty($line[self::HAML_XML_ATTRIBUTES])) {
859
+ $line[self::HAML_XML_ATTRIBUTES] = $line[self::HAML_CONTENT];
860
+ unset($line[self::HAML_CONTENT]);
861
+ do {
862
+ $multiLine = array_shift($this->source);
863
+ $line[self::HAML_XML_ATTRIBUTES] .= $multiLine[self::HAML_CONTENT];
864
+ } while (substr($line[self::HAML_XML_ATTRIBUTES], -1) !==
865
+ self::CLOSE_XML_ATTRIBUTES);
866
+ }
867
+ if (preg_match(self::HTML_ATTRS, $line[self::HAML_XML_ATTRIBUTES], $htmlAttrs)) {
868
+ $line[self::HAML_XML_ATTRIBUTES] = preg_replace(self::HTML_ATTRS, '', $line[self::HAML_XML_ATTRIBUTES]);
869
+ $attributes = array_merge($attributes, $this->htmlAttrs($htmlAttrs));
870
+ }
871
+ $attributes = array_merge(
872
+ $attributes,
873
+ $this->parseAttributeHash($line[self::HAML_XML_ATTRIBUTES])
874
+ );
875
+ }
876
+ if (!empty($line[self::HAML_OPEN_RUBY_ATTRIBUTES])) {
877
+ if (empty($line[self::HAML_RUBY_ATTRIBUTES])) {
878
+ $line[self::HAML_RUBY_ATTRIBUTES] = $line[self::HAML_CONTENT];
879
+ unset($line[self::HAML_CONTENT]);
880
+ do {
881
+ $multiLine = array_shift($this->source);
882
+ $line[self::HAML_RUBY_ATTRIBUTES] .= $multiLine[self::HAML_CONTENT];
883
+ } while (substr($line[self::HAML_RUBY_ATTRIBUTES], -1) !==
884
+ self::CLOSE_RUBY_ATTRIBUTES);
885
+ }
886
+ if (preg_match(self::HTML_ATTRS, $line[self::HAML_RUBY_ATTRIBUTES], $htmlAttrs)) {
887
+ $line[self::HAML_RUBY_ATTRIBUTES] = preg_replace(self::HTML_ATTRS, '', $line[self::HAML_RUBY_ATTRIBUTES]);
888
+ $attributes = array_merge($attributes, $this->htmlAttrs($htmlAttrs));
889
+ }
890
+ $attributes = array_merge(
891
+ $attributes,
892
+ $this->parseAttributeHash($line[self::HAML_RUBY_ATTRIBUTES])
893
+ );
894
+ }
895
+ if (!empty($line[self::HAML_OBJECT_REFERENCE])) {
896
+ $objectRef = explode(',', preg_replace('/,\s*/', ',', $line[self::HAML_OBJECT_REFERENCE]));
897
+ $prefix = (isset($objectRef[1]) ? $objectRef[1] . '_' : '');
898
+ $class = "strtolower(str_replace(' ', '_', preg_replace('/(?<=\w)([ A-Z])/', '_\1', get_class(" . $objectRef[0] . '))))';
899
+ $attributes['class'] = "<?php echo '$prefix' . $class; ?>";
900
+ $attributes['id'] = "<?php echo '$prefix' . $class . '_' . {$objectRef[0]}->id; ?>";
901
+ }
902
+ else {
903
+ if (!empty($line[self::HAML_CLASS])) {
904
+ $classes = explode('.', $line[self::HAML_CLASS]);
905
+ foreach ($classes as &$class) {
906
+ if (preg_match(self::MATCH_INTERPOLATION, $class)) {
907
+ $class = $this->interpolate($class);
908
+ }
909
+ } // foreach
910
+ $attributes['class'] = join(' ', $classes) .
911
+ (isset($attributes['class']) ? " {$attributes['class']}" : '');
912
+ }
913
+ if (!empty($line[self::HAML_ID])) {
914
+ $attributes['id'] =
915
+ (preg_match(self::MATCH_INTERPOLATION, $line[self::HAML_ID]) ?
916
+ $this->interpolate($line[self::HAML_ID]) : $line[self::HAML_ID]) .
917
+ (isset($attributes['id']) ? "_{$attributes['id']}" : '');
918
+ }
919
+ }
920
+
921
+ ksort($attributes, SORT_STRING);
922
+ return $attributes;
923
+ }
924
+
925
+ /**
926
+ * Parse attributes.
927
+ * @param string the attributes
928
+ * @return array attributes in name=>value pairs
929
+ */
930
+ private function parseAttributeHash($subject) {
931
+ $subject = substr($subject, 0, -1);
932
+ $attributes = array();
933
+ if (preg_match(self::REGEX_ATTRIBUTE_FUNCTION, $subject)) {
934
+ $attributes[0] = "<?php echo $subject; ?>";
935
+ return $attributes;
936
+ }
937
+
938
+ preg_match_all(self::REGEX_ATTRIBUTES, $subject, $attrs, PREG_SET_ORDER);
939
+ foreach ($attrs as $attr) {
940
+ if (!empty($attr[1])) { // HTML5 Custom Data Attributes
941
+ $dataAttributes = $this->parseAttributeHash(substr($attr[2], 1));
942
+ foreach ($dataAttributes as $key=>$value) {
943
+ $attributes["data-$key"] = $value;
944
+ } // foreach
945
+ }
946
+ elseif (!empty($attr[4])) {
947
+ $values = array_map('trim', explode(',', $attr[4]));
948
+ if ($attr[3] !== 'class' && $attr[3] !== 'id') {
949
+ throw new HamlException('Attribute must be "class" or "id" with array value', array(), $this);
950
+ }
951
+ $attributes[$attr[3]] = '<?php echo ' . join(($attr[3] === 'id' ? ".'_'." : ".' '."), $values) . '; ?>';
952
+ }
953
+ elseif (!empty($attr[6])) {
954
+ $attributes[$attr[3]] = $this->interpolate($attr[6]);
955
+ }
956
+ elseif ($attr[6] === '') {
957
+ $attributes[$attr[3]] = $attr[6];
958
+ }
959
+ else {
960
+ switch ($attr[7]) {
961
+ case 'true':
962
+ $attributes[$attr[3]] = $attr[3];
963
+ break;
964
+ case 'false':
965
+ break;
966
+ default:
967
+ $attributes[$attr[3]] = "<?php echo {$attr[7]}; ?>";
968
+ break;
969
+ }
970
+ }
971
+ } // foreach
972
+ return $attributes;
973
+ }
974
+
975
+ /**
976
+ * Returns an array of attributes for the html element.
977
+ * @param array arguments for HamlHelpers::html_attrs
978
+ * @return array attributes for the html element
979
+ */
980
+ private function htmlAttrs($htmlAttrs) {
981
+ if (empty($htmlAttrs[1]) && empty($htmlAttrs[2])) {
982
+ return HamlHelpers::html_attrs();
983
+ }
984
+ else {
985
+ $htmlAttrs[1] = substr($htmlAttrs[1], 1, -1);
986
+ if (substr($htmlAttrs[1], -1) == ';') {
987
+ $htmlAttrs[1] = eval("return {$htmlAttrs[1]}");
988
+ }
989
+ if (isset($htmlAttrs[2])) {
990
+ return HamlHelpers::html_attrs($htmlAttrs[1], eval($htmlAttrs[2] . ';'));
991
+ }
992
+ else {
993
+ return HamlHelpers::html_attrs($htmlAttrs[1]);
994
+ }
995
+ }
996
+ }
997
+
998
+ /**
999
+ * Parse code
1000
+ * @param array line to parse
1001
+ * @param HamlNode parent node
1002
+ * @return HamlCodeBlockNode
1003
+ */
1004
+ private function parseCode($line, $parent) {
1005
+ if (preg_match('/^(if|foreach|for|switch|do|while)\b(.*)$/',
1006
+ $line[self::HAML_CONTENT], $block)) {
1007
+ if ($block[1] === 'do') {
1008
+ $node = new HamlCodeBlockNode('<?php do { ?>', $parent);
1009
+ $node->doWhile = 'while' . $block[2] . ';';
1010
+ }
1011
+ elseif ($block[1] === 'switch') {
1012
+ $node = new HamlCodeBlockNode("<?php {$line[self::HAML_CONTENT]} {", $parent);
1013
+ }
1014
+ else {
1015
+ $node = new HamlCodeBlockNode("<?php {$line[self::HAML_CONTENT]} { ?>", $parent);
1016
+ }
1017
+ }
1018
+ elseif (strpos($line[self::HAML_CONTENT], 'else') === 0) {
1019
+ $node = new HamlCodeBlockNode("<?php } {$line[self::HAML_CONTENT]} { ?>", null);
1020
+ $node->token = $line;
1021
+ $node->showOutput = $this->showOutput;
1022
+ $node->showSource = $this->showSource;
1023
+ $parent->getLastChild()->addElse($node);
1024
+ $this->addChildren($node, $line);
1025
+ $node = null;
1026
+ }
1027
+ elseif (strpos($line[self::HAML_CONTENT], 'case') === 0) {
1028
+ $node = new HamlNode(($parent->hasChildren() ? '<?php ' : '') .
1029
+ "{$line[self::HAML_CONTENT]}: ?>", $parent);
1030
+ }
1031
+ else {
1032
+ $node = new HamlNode("<?php {$line[self::HAML_CONTENT]}; ?>", $parent);
1033
+ }
1034
+ return $node;
1035
+ }
1036
+
1037
+ /**
1038
+ * Parse content
1039
+ * @param array line to parse
1040
+ * @param HamlNode parent node
1041
+ * @return HamlNode
1042
+ */
1043
+ private function parseContent($line, $parent) {
1044
+ switch ($line[self::HAML_TOKEN]) {
1045
+ case self::INSERT_CODE:
1046
+ $content = ($this->suppressEval ? '' :
1047
+ '<?php echo ' . ($this->escapeHtml ?
1048
+ 'htmlentities(' . $line[self::HAML_CONTENT] . ')' :
1049
+ $line[self::HAML_CONTENT]) .
1050
+ "; ?>" .
1051
+ ($this->style == HamlRenderer::STYLE_EXPANDED ||
1052
+ $this->style == HamlRenderer::STYLE_NESTED ? "\n" : ''));
1053
+ break;
1054
+ case self::INSERT_CODE_PRESERVE_WHITESPACE:
1055
+ $content = ($this->suppressEval ? '' :
1056
+ '<?php echo str_replace("\n", \'&#x000a\', ' . ($this->escapeHtml ?
1057
+ 'htmlentities(' . $line[self::HAML_CONTENT] . ')' :
1058
+ $line[self::HAML_CONTENT]) .
1059
+ "; ?>" .
1060
+ ($this->style == HamlRenderer::STYLE_EXPANDED ||
1061
+ $this->style == HamlRenderer::STYLE_NESTED ? "\n" : ''));
1062
+ break;
1063
+ default:
1064
+ $content = $line[self::HAML_CONTENT];
1065
+ break;
1066
+ } // switch
1067
+
1068
+ return new HamlNode($this->interpolate($content), $parent);
1069
+ }
1070
+
1071
+ /**
1072
+ * Parse a directive.
1073
+ * Various options are set according to the directive
1074
+ * @param array line to parse
1075
+ * @return null
1076
+ */
1077
+ private function parseDirective($line) {
1078
+ preg_match('/(\w+)(\+|-)?/', $line[self::HAML_CONTENT], $matches);
1079
+ switch ($matches[1]) {
1080
+ case 's':
1081
+ $this->showSource = ($matches[2] == '+' ? true :
1082
+ ($matches[2] == '-' ? false : $this->showSource));
1083
+ break;
1084
+ case 'o':
1085
+ $this->showOutput = ($matches[2] == '+' ? true :
1086
+ ($matches[2] == '-' ? false : $this->showOutput));
1087
+ break;
1088
+ case 'os':
1089
+ case 'so':
1090
+ $this->showSource = ($matches[2] == '+' ? true :
1091
+ ($matches[2] == '-' ? false : $this->showSource));
1092
+ $this->showOutput = ($matches[2] == '+' ? true :
1093
+ ($matches[2] == '-' ? false : $this->showOutput));
1094
+ break;
1095
+ default:
1096
+ if (!in_array($matches[1], $this->styles)) {
1097
+ throw new HamlException('Invalid {what} ({value})', array('{what}'=>'directive', '{value}'=>self::DIRECTIVE.$matches[0]), $this);
1098
+ }
1099
+ $this->style = $matches[1];
1100
+ break;
1101
+ } // switch
1102
+ }
1103
+
1104
+ /**
1105
+ * Parse a doctype declaration
1106
+ * @param array line to parse
1107
+ * @param HamlNode parent node
1108
+ * @return HamlDoctypeNode
1109
+ */
1110
+ private function parseDoctype($line, $parent) {
1111
+ $content = explode(' ', $line[self::HAML_CONTENT]);
1112
+ if (!empty($content)) {
1113
+ if ($content[0] === self::IS_XML_PROLOG) {
1114
+ $encoding = isset($content[1]) ? $content[1] : self::DEFAULT_XML_ENCODING;
1115
+ $output = str_replace(self::XML_ENCODING, $encoding, self::XML_PROLOG);
1116
+ }
1117
+ elseif (empty($content[0])) {
1118
+ $output = $this->doctypes[$this->format][0];
1119
+ }
1120
+ elseif (array_key_exists($content[0],
1121
+ $this->doctypes[$this->format])) {
1122
+ $output = $this->doctypes[$this->format][$content[0]];
1123
+ }
1124
+ elseif (!empty($this->doctype)) {
1125
+ $output = $this->doctype;
1126
+ }
1127
+ else {
1128
+ $_doctypes = array_keys($this->doctypes[$this->format]);
1129
+ array_shift($_doctypes);
1130
+ throw new HamlException('Invalid {what} ({value}); must be one of "{options}"', array('{what}'=>'doctype', '{value}'=>$content[0], '{options}'=>join(', ', $_doctypes).' or empty'), $this);
1131
+ }
1132
+ }
1133
+ return new HamlDoctypeNode($output, $parent);
1134
+ }
1135
+
1136
+ /**
1137
+ * Parse a Haml comment.
1138
+ * If the comment is an empty comment eat all child lines.
1139
+ * @param array line to parse
1140
+ */
1141
+ private function parseHamlComment($line) {
1142
+ if (!$this->hasContent($line)) {
1143
+ while ($this->hasChild($line, true)) {
1144
+ array_shift($this->source);
1145
+ $this->line++;
1146
+ }
1147
+ }
1148
+ }
1149
+
1150
+ /**
1151
+ * Parse a HamlHelper.
1152
+ * @param array line to parse
1153
+ * @param HamlNode parent node
1154
+ * @return HamlHelperNode
1155
+ */
1156
+ private function parseHelper($line, $parent) {
1157
+ preg_match(HamlHelperNode::MATCH, $line[self::HAML_CONTENT], $matches);
1158
+ $node = new HamlHelperNode($this->helperClass, $matches[HamlHelperNode::PRE], $matches[HamlHelperNode::NAME], $matches[HamlHelperNode::ARGS], $parent);
1159
+ if (isset($matches[HamlHelperNode::BLOCK])) {
1160
+ new HamlNode($matches[HamlHelperNode::BLOCK], $node);
1161
+ }
1162
+ return $node;
1163
+ }
1164
+
1165
+ /**
1166
+ * Parse an element.
1167
+ * @param array line to parse
1168
+ * @param HamlNode parent node
1169
+ * @return HamlElementNode tag node and children
1170
+ */
1171
+ private function parseElement($line, $parent) {
1172
+ $node = new HamlElementNode($line[self::HAML_TAG], $parent);
1173
+ $node->isSelfClosing = $this->isSelfClosing($line);
1174
+ $node->isBlock = $this->isBlock($line);
1175
+ $node->attributes = $this->parseAttributes($line);
1176
+ if ($this->hasContent($line)) {
1177
+ $child = $this->parseContent($line, $node);
1178
+ $child->showOutput = $this->showOutput;
1179
+ $child->showSource = $this->showSource;
1180
+ $child->token = array(
1181
+ self::HAML_SOURCE => $line[self::HAML_SOURCE],
1182
+ 'filename' => $line['filename'],
1183
+ 'line' => $line['line'],
1184
+ 'level' => ($line['level'] + 1)
1185
+ );
1186
+ }
1187
+ $node->whitespaceControl = $this->parseWhitespaceControl($line);
1188
+ return $node;
1189
+ }
1190
+
1191
+ /**
1192
+ * Parse a filter.
1193
+ * @param array line to parse
1194
+ * @param HamlNode parent node
1195
+ * @return HamlNode filter node
1196
+ */
1197
+ private function parseFilter($line, $parent) {
1198
+ $node = new HamlFilterNode($this->getFilter($line[self::HAML_FILTER]), $parent);
1199
+ if ($this->hasContent($line)) {
1200
+ $child = $this->parseContent($line);
1201
+ $child->showOutput = $this->showOutput;
1202
+ $child->showSource = $this->showSource;
1203
+ $child->token = array(
1204
+ 'level' => ($line['level'] + 1),
1205
+ 'line' => $line['line']
1206
+ );
1207
+ }
1208
+ return $node;
1209
+ }
1210
+
1211
+ /**
1212
+ * Parse an Xml comment.
1213
+ * @param array line to parse
1214
+ * @param HamlNode parent node
1215
+ * @return HamlCommentNode
1216
+ */
1217
+ private function parseXmlComment($line, $parent) {
1218
+ return new HamlCommentNode($line[self::HAML_CONTENT], $parent);
1219
+ }
1220
+
1221
+ private function parseWhitespaceControl($line) {
1222
+ $whitespaceControl = array('inner' => false, 'outer' => array('left' => false, 'right' => false));
1223
+
1224
+ if (!empty($line[self::HAML_WHITESPACE_REMOVAL])) {
1225
+ $whitespaceControl['inner'] =
1226
+ (strpos($line[self::HAML_WHITESPACE_REMOVAL],
1227
+ self::INNER_WHITESPACE_REMOVAL) !== false);
1228
+
1229
+ if (strpos($line[self::HAML_WHITESPACE_REMOVAL],
1230
+ self::OUTER_WHITESPACE_REMOVAL) !== false) {
1231
+ $whitespaceControl['outer']['left'] =
1232
+ (strpos($line[self::HAML_WHITESPACE_REMOVAL],
1233
+ self::BLOCK_LEFT_OUTER_WHITESPACE_REMOVAL) === false);
1234
+ $whitespaceControl['outer']['right'] =
1235
+ (strpos($line[self::HAML_WHITESPACE_REMOVAL],
1236
+ self::BLOCK_RIGHT_OUTER_WHITESPACE_REMOVAL) === false);
1237
+ }
1238
+ }
1239
+ return $whitespaceControl;
1240
+ }
1241
+
1242
+ /**
1243
+ * Replace interpolated PHP contained in '#{}'.
1244
+ * @param string the text to interpolate
1245
+ * @return string the interpolated text
1246
+ */
1247
+ protected function interpolate($string) {
1248
+ return preg_replace(self::MATCH_INTERPOLATION, self::INTERPOLATE, $string);
1249
+ }
1250
+ }