PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/bundle/ruby/1.9.1/gems/haml-3.1.4/lib/haml/helpers.rb

https://bitbucket.org/mulligan/extractext
Ruby | 608 lines | 231 code | 48 blank | 329 comment | 21 complexity | 0bca20c032d4f61542dbea1a188a3746 MD5 | raw file
Possible License(s): Apache-2.0, MIT, GPL-3.0, GPL-2.0, BSD-3-Clause, MPL-2.0-no-copyleft-exception, BSD-2-Clause, JSON
  1. module Haml
  2. # This module contains various helpful methods to make it easier to do various tasks.
  3. # {Haml::Helpers} is automatically included in the context
  4. # that a Haml template is parsed in, so all these methods are at your
  5. # disposal from within the template.
  6. module Helpers
  7. # An object that raises an error when \{#to\_s} is called.
  8. # It's used to raise an error when the return value of a helper is used
  9. # when it shouldn't be.
  10. class ErrorReturn
  11. # @param message [String] The error message to raise when \{#to\_s} is called
  12. def initialize(method)
  13. @message = <<MESSAGE
  14. #{method} outputs directly to the Haml template.
  15. Disregard its return value and use the - operator,
  16. or use capture_haml to get the value as a String.
  17. MESSAGE
  18. end
  19. # Raises an error.
  20. #
  21. # @raise [Haml::Error] The error
  22. def to_s
  23. raise Haml::Error.new(@message)
  24. rescue Haml::Error => e
  25. e.backtrace.shift
  26. # If the ErrorReturn is used directly in the template,
  27. # we don't want Haml's stuff to get into the backtrace,
  28. # so we get rid of the format_script line.
  29. #
  30. # We also have to subtract one from the Haml line number
  31. # since the value is passed to format_script the line after
  32. # it's actually used.
  33. if e.backtrace.first =~ /^\(eval\):\d+:in `format_script/
  34. e.backtrace.shift
  35. e.backtrace.first.gsub!(/^\(haml\):(\d+)/) {|s| "(haml):#{$1.to_i - 1}"}
  36. end
  37. raise e
  38. end
  39. # @return [String] A human-readable string representation
  40. def inspect
  41. "Haml::Helpers::ErrorReturn(#{@message.inspect})"
  42. end
  43. end
  44. self.extend self
  45. @@action_view_defined = false
  46. # @return [Boolean] Whether or not ActionView is loaded
  47. def self.action_view?
  48. @@action_view_defined
  49. end
  50. # Note: this does **not** need to be called when using Haml helpers
  51. # normally in Rails.
  52. #
  53. # Initializes the current object as though it were in the same context
  54. # as a normal ActionView instance using Haml.
  55. # This is useful if you want to use the helpers in a context
  56. # other than the normal setup with ActionView.
  57. # For example:
  58. #
  59. # context = Object.new
  60. # class << context
  61. # include Haml::Helpers
  62. # end
  63. # context.init_haml_helpers
  64. # context.haml_tag :p, "Stuff"
  65. #
  66. def init_haml_helpers
  67. @haml_buffer = Haml::Buffer.new(@haml_buffer, Haml::Engine.new('').send(:options_for_buffer))
  68. nil
  69. end
  70. # Runs a block of code in a non-Haml context
  71. # (i.e. \{#is\_haml?} will return false).
  72. #
  73. # This is mainly useful for rendering sub-templates such as partials in a non-Haml language,
  74. # particularly where helpers may behave differently when run from Haml.
  75. #
  76. # Note that this is automatically applied to Rails partials.
  77. #
  78. # @yield A block which won't register as Haml
  79. def non_haml
  80. was_active = @haml_buffer.active?
  81. @haml_buffer.active = false
  82. yield
  83. ensure
  84. @haml_buffer.active = was_active
  85. end
  86. # Uses \{#preserve} to convert any newlines inside whitespace-sensitive tags
  87. # into the HTML entities for endlines.
  88. #
  89. # @param tags [Array<String>] Tags that should have newlines escaped
  90. #
  91. # @overload find_and_preserve(input, tags = haml_buffer.options[:preserve])
  92. # Escapes newlines within a string.
  93. #
  94. # @param input [String] The string within which to escape newlines
  95. # @overload find_and_preserve(tags = haml_buffer.options[:preserve])
  96. # Escapes newlines within a block of Haml code.
  97. #
  98. # @yield The block within which to escape newlines
  99. def find_and_preserve(input = nil, tags = haml_buffer.options[:preserve], &block)
  100. return find_and_preserve(capture_haml(&block), input || tags) if block
  101. re = /<(#{tags.map(&Regexp.method(:escape)).join('|')})([^>]*)>(.*?)(<\/\1>)/im
  102. input.to_s.gsub(re) do |s|
  103. s =~ re # Can't rely on $1, etc. existing since Rails' SafeBuffer#gsub is incompatible
  104. "<#{$1}#{$2}>#{preserve($3)}</#{$1}>"
  105. end
  106. end
  107. # Takes any string, finds all the newlines, and converts them to
  108. # HTML entities so they'll render correctly in
  109. # whitespace-sensitive tags without screwing up the indentation.
  110. #
  111. # @overload perserve(input)
  112. # Escapes newlines within a string.
  113. #
  114. # @param input [String] The string within which to escape all newlines
  115. # @overload perserve
  116. # Escapes newlines within a block of Haml code.
  117. #
  118. # @yield The block within which to escape newlines
  119. def preserve(input = nil, &block)
  120. return preserve(capture_haml(&block)) if block
  121. input.to_s.chomp("\n").gsub(/\n/, '&#x000A;').gsub(/\r/, '')
  122. end
  123. alias_method :flatten, :preserve
  124. # Takes an `Enumerable` object and a block
  125. # and iterates over the enum,
  126. # yielding each element to a Haml block
  127. # and putting the result into `<li>` elements.
  128. # This creates a list of the results of the block.
  129. # For example:
  130. #
  131. # = list_of([['hello'], ['yall']]) do |i|
  132. # = i[0]
  133. #
  134. # Produces:
  135. #
  136. # <li>hello</li>
  137. # <li>yall</li>
  138. #
  139. # And
  140. #
  141. # = list_of({:title => 'All the stuff', :description => 'A book about all the stuff.'}) do |key, val|
  142. # %h3= key.humanize
  143. # %p= val
  144. #
  145. # Produces:
  146. #
  147. # <li>
  148. # <h3>Title</h3>
  149. # <p>All the stuff</p>
  150. # </li>
  151. # <li>
  152. # <h3>Description</h3>
  153. # <p>A book about all the stuff.</p>
  154. # </li>
  155. #
  156. # @param enum [Enumerable] The list of objects to iterate over
  157. # @yield [item] A block which contains Haml code that goes within list items
  158. # @yieldparam item An element of `enum`
  159. def list_of(enum, &block)
  160. to_return = enum.collect do |i|
  161. result = capture_haml(i, &block)
  162. if result.count("\n") > 1
  163. result = result.gsub("\n", "\n ")
  164. result = "\n #{result.strip}\n"
  165. else
  166. result = result.strip
  167. end
  168. "<li>#{result}</li>"
  169. end
  170. to_return.join("\n")
  171. end
  172. # Returns a hash containing default assignments for the `xmlns`, `lang`, and `xml:lang`
  173. # attributes of the `html` HTML element.
  174. # For example,
  175. #
  176. # %html{html_attrs}
  177. #
  178. # becomes
  179. #
  180. # <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en-US' lang='en-US'>
  181. #
  182. # @param lang [String] The value of `xml:lang` and `lang`
  183. # @return [{#to_s => String}] The attribute hash
  184. def html_attrs(lang = 'en-US')
  185. {:xmlns => "http://www.w3.org/1999/xhtml", 'xml:lang' => lang, :lang => lang}
  186. end
  187. # Increments the number of tabs the buffer automatically adds
  188. # to the lines of the template.
  189. # For example:
  190. #
  191. # %h1 foo
  192. # - tab_up
  193. # %p bar
  194. # - tab_down
  195. # %strong baz
  196. #
  197. # Produces:
  198. #
  199. # <h1>foo</h1>
  200. # <p>bar</p>
  201. # <strong>baz</strong>
  202. #
  203. # @param i [Fixnum] The number of tabs by which to increase the indentation
  204. # @see #tab_down
  205. def tab_up(i = 1)
  206. haml_buffer.tabulation += i
  207. end
  208. # Decrements the number of tabs the buffer automatically adds
  209. # to the lines of the template.
  210. #
  211. # @param i [Fixnum] The number of tabs by which to decrease the indentation
  212. # @see #tab_up
  213. def tab_down(i = 1)
  214. haml_buffer.tabulation -= i
  215. end
  216. # Sets the number of tabs the buffer automatically adds
  217. # to the lines of the template,
  218. # but only for the duration of the block.
  219. # For example:
  220. #
  221. # %h1 foo
  222. # - with_tabs(2) do
  223. # %p bar
  224. # %strong baz
  225. #
  226. # Produces:
  227. #
  228. # <h1>foo</h1>
  229. # <p>bar</p>
  230. # <strong>baz</strong>
  231. #
  232. #
  233. # @param i [Fixnum] The number of tabs to use
  234. # @yield A block in which the indentation will be `i` spaces
  235. def with_tabs(i)
  236. old_tabs = haml_buffer.tabulation
  237. haml_buffer.tabulation = i
  238. yield
  239. ensure
  240. haml_buffer.tabulation = old_tabs
  241. end
  242. # Surrounds a block of Haml code with strings,
  243. # with no whitespace in between.
  244. # For example:
  245. #
  246. # = surround '(', ')' do
  247. # %a{:href => "food"} chicken
  248. #
  249. # Produces:
  250. #
  251. # (<a href='food'>chicken</a>)
  252. #
  253. # and
  254. #
  255. # = surround '*' do
  256. # %strong angry
  257. #
  258. # Produces:
  259. #
  260. # *<strong>angry</strong>*
  261. #
  262. # @param front [String] The string to add before the Haml
  263. # @param back [String] The string to add after the Haml
  264. # @yield A block of Haml to surround
  265. def surround(front, back = front, &block)
  266. output = capture_haml(&block)
  267. "#{front}#{output.chomp}#{back}\n"
  268. end
  269. # Prepends a string to the beginning of a Haml block,
  270. # with no whitespace between.
  271. # For example:
  272. #
  273. # = precede '*' do
  274. # %span.small Not really
  275. #
  276. # Produces:
  277. #
  278. # *<span class='small'>Not really</span>
  279. #
  280. # @param str [String] The string to add before the Haml
  281. # @yield A block of Haml to prepend to
  282. def precede(str, &block)
  283. "#{str}#{capture_haml(&block).chomp}\n"
  284. end
  285. # Appends a string to the end of a Haml block,
  286. # with no whitespace between.
  287. # For example:
  288. #
  289. # click
  290. # = succeed '.' do
  291. # %a{:href=>"thing"} here
  292. #
  293. # Produces:
  294. #
  295. # click
  296. # <a href='thing'>here</a>.
  297. #
  298. # @param str [String] The string to add after the Haml
  299. # @yield A block of Haml to append to
  300. def succeed(str, &block)
  301. "#{capture_haml(&block).chomp}#{str}\n"
  302. end
  303. # Captures the result of a block of Haml code,
  304. # gets rid of the excess indentation,
  305. # and returns it as a string.
  306. # For example, after the following,
  307. #
  308. # .foo
  309. # - foo = capture_haml(13) do |a|
  310. # %p= a
  311. #
  312. # the local variable `foo` would be assigned to `"<p>13</p>\n"`.
  313. #
  314. # @param args [Array] Arguments to pass into the block
  315. # @yield [args] A block of Haml code that will be converted to a string
  316. # @yieldparam args [Array] `args`
  317. def capture_haml(*args, &block)
  318. buffer = eval('_hamlout', block.binding) rescue haml_buffer
  319. with_haml_buffer(buffer) do
  320. position = haml_buffer.buffer.length
  321. haml_buffer.capture_position = position
  322. block.call(*args)
  323. captured = haml_buffer.buffer.slice!(position..-1)
  324. return captured if haml_buffer.options[:ugly]
  325. captured = captured.split(/^/)
  326. min_tabs = nil
  327. captured.each do |line|
  328. tabs = line.index(/[^ ]/) || line.length
  329. min_tabs ||= tabs
  330. min_tabs = min_tabs > tabs ? tabs : min_tabs
  331. end
  332. captured.map do |line|
  333. line[min_tabs..-1]
  334. end.join
  335. end
  336. ensure
  337. haml_buffer.capture_position = nil
  338. end
  339. # Outputs text directly to the Haml buffer, with the proper indentation.
  340. #
  341. # @param text [#to_s] The text to output
  342. def haml_concat(text = "")
  343. unless haml_buffer.options[:ugly] || haml_indent == 0
  344. haml_buffer.buffer << haml_indent <<
  345. text.to_s.gsub("\n", "\n" + haml_indent) << "\n"
  346. else
  347. haml_buffer.buffer << text.to_s << "\n"
  348. end
  349. ErrorReturn.new("haml_concat")
  350. end
  351. # @return [String] The indentation string for the current line
  352. def haml_indent
  353. ' ' * haml_buffer.tabulation
  354. end
  355. # Creates an HTML tag with the given name and optionally text and attributes.
  356. # Can take a block that will run between the opening and closing tags.
  357. # If the block is a Haml block or outputs text using \{#haml\_concat},
  358. # the text will be properly indented.
  359. #
  360. # `name` can be a string using the standard Haml class/id shorthand
  361. # (e.g. "span#foo.bar", "#foo").
  362. # Just like standard Haml tags, these class and id values
  363. # will be merged with manually-specified attributes.
  364. #
  365. # `flags` is a list of symbol flags
  366. # like those that can be put at the end of a Haml tag
  367. # (`:/`, `:<`, and `:>`).
  368. # Currently, only `:/` and `:<` are supported.
  369. #
  370. # `haml_tag` outputs directly to the buffer;
  371. # its return value should not be used.
  372. # If you need to get the results as a string,
  373. # use \{#capture\_haml\}.
  374. #
  375. # For example,
  376. #
  377. # haml_tag :table do
  378. # haml_tag :tr do
  379. # haml_tag 'td.cell' do
  380. # haml_tag :strong, "strong!"
  381. # haml_concat "data"
  382. # end
  383. # haml_tag :td do
  384. # haml_concat "more_data"
  385. # end
  386. # end
  387. # end
  388. #
  389. # outputs
  390. #
  391. # <table>
  392. # <tr>
  393. # <td class='cell'>
  394. # <strong>
  395. # strong!
  396. # </strong>
  397. # data
  398. # </td>
  399. # <td>
  400. # more_data
  401. # </td>
  402. # </tr>
  403. # </table>
  404. #
  405. # @param name [#to_s] The name of the tag
  406. # @param flags [Array<Symbol>] Haml end-of-tag flags
  407. #
  408. # @overload haml_tag(name, *flags, attributes = {})
  409. # @yield The block of Haml code within the tag
  410. # @overload haml_tag(name, text, *flags, attributes = {})
  411. # @param text [#to_s] The text within the tag
  412. def haml_tag(name, *rest, &block)
  413. ret = ErrorReturn.new("haml_tag")
  414. text = rest.shift.to_s unless [Symbol, Hash, NilClass].any? {|t| rest.first.is_a? t}
  415. flags = []
  416. flags << rest.shift while rest.first.is_a? Symbol
  417. attrs = Haml::Util.map_keys(rest.shift || {}) {|key| key.to_s}
  418. name, attrs = merge_name_and_attributes(name.to_s, attrs)
  419. attributes = Haml::Compiler.build_attributes(haml_buffer.html?,
  420. haml_buffer.options[:attr_wrapper],
  421. haml_buffer.options[:escape_attrs],
  422. attrs)
  423. if text.nil? && block.nil? && (haml_buffer.options[:autoclose].include?(name) || flags.include?(:/))
  424. haml_concat "<#{name}#{attributes} />"
  425. return ret
  426. end
  427. if flags.include?(:/)
  428. raise Error.new("Self-closing tags can't have content.") if text
  429. raise Error.new("Illegal nesting: nesting within a self-closing tag is illegal.") if block
  430. end
  431. tag = "<#{name}#{attributes}>"
  432. if block.nil?
  433. text = text.to_s
  434. if text.include?("\n")
  435. haml_concat tag
  436. tab_up
  437. haml_concat text
  438. tab_down
  439. haml_concat "</#{name}>"
  440. else
  441. tag << text << "</#{name}>"
  442. haml_concat tag
  443. end
  444. return ret
  445. end
  446. if text
  447. raise Error.new("Illegal nesting: content can't be both given to haml_tag :#{name} and nested within it.")
  448. end
  449. if flags.include?(:<)
  450. tag << capture_haml(&block).strip << "</#{name}>"
  451. haml_concat tag
  452. return ret
  453. end
  454. haml_concat tag
  455. tab_up
  456. block.call
  457. tab_down
  458. haml_concat "</#{name}>"
  459. ret
  460. end
  461. # Characters that need to be escaped to HTML entities from user input
  462. HTML_ESCAPE = { '&'=>'&amp;', '<'=>'&lt;', '>'=>'&gt;', '"'=>'&quot;', "'"=>'&#039;', }
  463. # Returns a copy of `text` with ampersands, angle brackets and quotes
  464. # escaped into HTML entities.
  465. #
  466. # Note that if ActionView is loaded and XSS protection is enabled
  467. # (as is the default for Rails 3.0+, and optional for version 2.3.5+),
  468. # this won't escape text declared as "safe".
  469. #
  470. # @param text [String] The string to sanitize
  471. # @return [String] The sanitized string
  472. def html_escape(text)
  473. Haml::Util.silence_warnings {text.to_s.gsub(/[\"><&]/n) {|s| HTML_ESCAPE[s]}}
  474. end
  475. # Escapes HTML entities in `text`, but without escaping an ampersand
  476. # that is already part of an escaped entity.
  477. #
  478. # @param text [String] The string to sanitize
  479. # @return [String] The sanitized string
  480. def escape_once(text)
  481. Haml::Util.silence_warnings do
  482. text.to_s.gsub(/[\"><]|&(?!(?:[a-zA-Z]+|(#\d+));)/n) {|s| HTML_ESCAPE[s]}
  483. end
  484. end
  485. # Returns whether or not the current template is a Haml template.
  486. #
  487. # This function, unlike other {Haml::Helpers} functions,
  488. # also works in other `ActionView` templates,
  489. # where it will always return false.
  490. #
  491. # @return [Boolean] Whether or not the current template is a Haml template
  492. def is_haml?
  493. !@haml_buffer.nil? && @haml_buffer.active?
  494. end
  495. # Returns whether or not `block` is defined directly in a Haml template.
  496. #
  497. # @param block [Proc] A Ruby block
  498. # @return [Boolean] Whether or not `block` is defined directly in a Haml template
  499. def block_is_haml?(block)
  500. eval('_hamlout', block.binding)
  501. true
  502. rescue
  503. false
  504. end
  505. private
  506. # Parses the tag name used for \{#haml\_tag}
  507. # and merges it with the Ruby attributes hash.
  508. def merge_name_and_attributes(name, attributes_hash = {})
  509. # skip merging if no ids or classes found in name
  510. return name, attributes_hash unless name =~ /^(.+?)?([\.#].*)$/
  511. return $1 || "div", Buffer.merge_attrs(
  512. Haml::Parser.parse_class_and_id($2), attributes_hash)
  513. end
  514. # Runs a block of code with the given buffer as the currently active buffer.
  515. #
  516. # @param buffer [Haml::Buffer] The Haml buffer to use temporarily
  517. # @yield A block in which the given buffer should be used
  518. def with_haml_buffer(buffer)
  519. @haml_buffer, old_buffer = buffer, @haml_buffer
  520. old_buffer.active, old_was_active = false, old_buffer.active? if old_buffer
  521. @haml_buffer.active, was_active = true, @haml_buffer.active?
  522. yield
  523. ensure
  524. @haml_buffer.active = was_active
  525. old_buffer.active = old_was_active if old_buffer
  526. @haml_buffer = old_buffer
  527. end
  528. # The current {Haml::Buffer} object.
  529. #
  530. # @return [Haml::Buffer]
  531. def haml_buffer
  532. @haml_buffer
  533. end
  534. # Gives a proc the same local `_hamlout` and `_erbout` variables
  535. # that the current template has.
  536. #
  537. # @param proc [#call] The proc to bind
  538. # @return [Proc] A new proc with the new variables bound
  539. def haml_bind_proc(&proc)
  540. _hamlout = haml_buffer
  541. _erbout = _hamlout.buffer
  542. proc { |*args| proc.call(*args) }
  543. end
  544. end
  545. end
  546. # @private
  547. class Object
  548. # Haml overrides various `ActionView` helpers,
  549. # which call an \{#is\_haml?} method
  550. # to determine whether or not the current context object
  551. # is a proper Haml context.
  552. # Because `ActionView` helpers may be included in non-`ActionView::Base` classes,
  553. # it's a good idea to define \{#is\_haml?} for all objects.
  554. def is_haml?
  555. false
  556. end
  557. end