shared.rb 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. module Sass
  2. # This module contains functionality that's shared between Haml and Sass.
  3. module Shared
  4. extend self
  5. # Scans through a string looking for the interoplation-opening `#{`
  6. # and, when it's found, yields the scanner to the calling code
  7. # so it can handle it properly.
  8. #
  9. # The scanner will have any backslashes immediately in front of the `#{`
  10. # as the second capture group (`scan[2]`),
  11. # and the text prior to that as the first (`scan[1]`).
  12. #
  13. # @yieldparam scan [StringScanner] The scanner scanning through the string
  14. # @return [String] The text remaining in the scanner after all `#{`s have been processed
  15. def handle_interpolation(str)
  16. scan = Sass::Util::MultibyteStringScanner.new(str)
  17. yield scan while scan.scan(/(.*?)(\\*)\#\{/m)
  18. scan.rest
  19. end
  20. # Moves a scanner through a balanced pair of characters.
  21. # For example:
  22. #
  23. # Foo (Bar (Baz bang) bop) (Bang (bop bip))
  24. # ^ ^
  25. # from to
  26. #
  27. # @param scanner [StringScanner] The string scanner to move
  28. # @param start [Character] The character opening the balanced pair.
  29. # A `Fixnum` in 1.8, a `String` in 1.9
  30. # @param finish [Character] The character closing the balanced pair.
  31. # A `Fixnum` in 1.8, a `String` in 1.9
  32. # @param count [Fixnum] The number of opening characters matched
  33. # before calling this method
  34. # @return [(String, String)] The string matched within the balanced pair
  35. # and the rest of the string.
  36. # `["Foo (Bar (Baz bang) bop)", " (Bang (bop bip))"]` in the example above.
  37. def balance(scanner, start, finish, count = 0)
  38. str = ''
  39. scanner = Sass::Util::MultibyteStringScanner.new(scanner) unless scanner.is_a? StringScanner
  40. regexp = Regexp.new("(.*?)[\\#{start.chr}\\#{finish.chr}]", Regexp::MULTILINE)
  41. while scanner.scan(regexp)
  42. str << scanner.matched
  43. count += 1 if scanner.matched[-1] == start
  44. count -= 1 if scanner.matched[-1] == finish
  45. return [str.strip, scanner.rest] if count == 0
  46. end
  47. end
  48. # Formats a string for use in error messages about indentation.
  49. #
  50. # @param indentation [String] The string used for indentation
  51. # @param was [Boolean] Whether or not to add `"was"` or `"were"`
  52. # (depending on how many characters were in `indentation`)
  53. # @return [String] The name of the indentation (e.g. `"12 spaces"`, `"1 tab"`)
  54. def human_indentation(indentation, was = false)
  55. if !indentation.include?(?\t)
  56. noun = 'space'
  57. elsif !indentation.include?(?\s)
  58. noun = 'tab'
  59. else
  60. return indentation.inspect + (was ? ' was' : '')
  61. end
  62. singular = indentation.length == 1
  63. if was
  64. was = singular ? ' was' : ' were'
  65. else
  66. was = ''
  67. end
  68. "#{indentation.length} #{noun}#{'s' unless singular}#{was}"
  69. end
  70. end
  71. end