drnic-haml 2.3.0

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 (190) hide show
  1. data/.yardopts +5 -0
  2. data/CONTRIBUTING +4 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +347 -0
  5. data/REVISION +1 -0
  6. data/Rakefile +371 -0
  7. data/VERSION +1 -0
  8. data/VERSION_NAME +1 -0
  9. data/bin/css2sass +7 -0
  10. data/bin/haml +9 -0
  11. data/bin/html2haml +7 -0
  12. data/bin/sass +8 -0
  13. data/extra/haml-mode.el +663 -0
  14. data/extra/sass-mode.el +205 -0
  15. data/extra/update_watch.rb +13 -0
  16. data/init.rb +8 -0
  17. data/lib/haml.rb +40 -0
  18. data/lib/haml/buffer.rb +307 -0
  19. data/lib/haml/engine.rb +301 -0
  20. data/lib/haml/error.rb +22 -0
  21. data/lib/haml/exec.rb +470 -0
  22. data/lib/haml/filters.rb +341 -0
  23. data/lib/haml/helpers.rb +560 -0
  24. data/lib/haml/helpers/action_view_extensions.rb +40 -0
  25. data/lib/haml/helpers/action_view_mods.rb +176 -0
  26. data/lib/haml/herb.rb +96 -0
  27. data/lib/haml/html.rb +308 -0
  28. data/lib/haml/precompiler.rb +997 -0
  29. data/lib/haml/shared.rb +78 -0
  30. data/lib/haml/template.rb +51 -0
  31. data/lib/haml/template/patch.rb +58 -0
  32. data/lib/haml/template/plugin.rb +71 -0
  33. data/lib/haml/util.rb +244 -0
  34. data/lib/haml/version.rb +64 -0
  35. data/lib/sass.rb +24 -0
  36. data/lib/sass/css.rb +423 -0
  37. data/lib/sass/engine.rb +491 -0
  38. data/lib/sass/environment.rb +79 -0
  39. data/lib/sass/error.rb +162 -0
  40. data/lib/sass/files.rb +133 -0
  41. data/lib/sass/plugin.rb +170 -0
  42. data/lib/sass/plugin/merb.rb +57 -0
  43. data/lib/sass/plugin/rails.rb +23 -0
  44. data/lib/sass/repl.rb +58 -0
  45. data/lib/sass/script.rb +55 -0
  46. data/lib/sass/script/bool.rb +17 -0
  47. data/lib/sass/script/color.rb +183 -0
  48. data/lib/sass/script/funcall.rb +50 -0
  49. data/lib/sass/script/functions.rb +199 -0
  50. data/lib/sass/script/lexer.rb +191 -0
  51. data/lib/sass/script/literal.rb +177 -0
  52. data/lib/sass/script/node.rb +14 -0
  53. data/lib/sass/script/number.rb +381 -0
  54. data/lib/sass/script/operation.rb +45 -0
  55. data/lib/sass/script/parser.rb +222 -0
  56. data/lib/sass/script/string.rb +12 -0
  57. data/lib/sass/script/unary_operation.rb +34 -0
  58. data/lib/sass/script/variable.rb +31 -0
  59. data/lib/sass/tree/comment_node.rb +84 -0
  60. data/lib/sass/tree/debug_node.rb +30 -0
  61. data/lib/sass/tree/directive_node.rb +70 -0
  62. data/lib/sass/tree/for_node.rb +48 -0
  63. data/lib/sass/tree/if_node.rb +54 -0
  64. data/lib/sass/tree/import_node.rb +69 -0
  65. data/lib/sass/tree/mixin_def_node.rb +29 -0
  66. data/lib/sass/tree/mixin_node.rb +48 -0
  67. data/lib/sass/tree/node.rb +252 -0
  68. data/lib/sass/tree/prop_node.rb +106 -0
  69. data/lib/sass/tree/root_node.rb +56 -0
  70. data/lib/sass/tree/rule_node.rb +220 -0
  71. data/lib/sass/tree/variable_node.rb +34 -0
  72. data/lib/sass/tree/while_node.rb +31 -0
  73. data/rails/init.rb +1 -0
  74. data/test/benchmark.rb +99 -0
  75. data/test/haml/engine_test.rb +1129 -0
  76. data/test/haml/helper_test.rb +282 -0
  77. data/test/haml/html2haml_test.rb +258 -0
  78. data/test/haml/markaby/standard.mab +52 -0
  79. data/test/haml/mocks/article.rb +6 -0
  80. data/test/haml/results/content_for_layout.xhtml +12 -0
  81. data/test/haml/results/eval_suppressed.xhtml +9 -0
  82. data/test/haml/results/filters.xhtml +62 -0
  83. data/test/haml/results/helpers.xhtml +93 -0
  84. data/test/haml/results/helpful.xhtml +10 -0
  85. data/test/haml/results/just_stuff.xhtml +68 -0
  86. data/test/haml/results/list.xhtml +12 -0
  87. data/test/haml/results/nuke_inner_whitespace.xhtml +40 -0
  88. data/test/haml/results/nuke_outer_whitespace.xhtml +148 -0
  89. data/test/haml/results/original_engine.xhtml +20 -0
  90. data/test/haml/results/partial_layout.xhtml +5 -0
  91. data/test/haml/results/partials.xhtml +21 -0
  92. data/test/haml/results/render_layout.xhtml +3 -0
  93. data/test/haml/results/silent_script.xhtml +74 -0
  94. data/test/haml/results/standard.xhtml +162 -0
  95. data/test/haml/results/tag_parsing.xhtml +23 -0
  96. data/test/haml/results/very_basic.xhtml +5 -0
  97. data/test/haml/results/whitespace_handling.xhtml +89 -0
  98. data/test/haml/rhtml/_av_partial_1.rhtml +12 -0
  99. data/test/haml/rhtml/_av_partial_2.rhtml +8 -0
  100. data/test/haml/rhtml/action_view.rhtml +62 -0
  101. data/test/haml/rhtml/standard.rhtml +54 -0
  102. data/test/haml/spec_test.rb +44 -0
  103. data/test/haml/template_test.rb +217 -0
  104. data/test/haml/templates/_av_partial_1.haml +9 -0
  105. data/test/haml/templates/_av_partial_1_ugly.haml +9 -0
  106. data/test/haml/templates/_av_partial_2.haml +5 -0
  107. data/test/haml/templates/_av_partial_2_ugly.haml +5 -0
  108. data/test/haml/templates/_layout.erb +3 -0
  109. data/test/haml/templates/_layout_for_partial.haml +3 -0
  110. data/test/haml/templates/_partial.haml +8 -0
  111. data/test/haml/templates/_text_area.haml +3 -0
  112. data/test/haml/templates/action_view.haml +47 -0
  113. data/test/haml/templates/action_view_ugly.haml +47 -0
  114. data/test/haml/templates/breakage.haml +8 -0
  115. data/test/haml/templates/content_for_layout.haml +8 -0
  116. data/test/haml/templates/eval_suppressed.haml +11 -0
  117. data/test/haml/templates/filters.haml +66 -0
  118. data/test/haml/templates/helpers.haml +95 -0
  119. data/test/haml/templates/helpful.haml +11 -0
  120. data/test/haml/templates/just_stuff.haml +83 -0
  121. data/test/haml/templates/list.haml +12 -0
  122. data/test/haml/templates/nuke_inner_whitespace.haml +32 -0
  123. data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
  124. data/test/haml/templates/original_engine.haml +17 -0
  125. data/test/haml/templates/partial_layout.haml +3 -0
  126. data/test/haml/templates/partialize.haml +1 -0
  127. data/test/haml/templates/partials.haml +12 -0
  128. data/test/haml/templates/render_layout.haml +2 -0
  129. data/test/haml/templates/silent_script.haml +40 -0
  130. data/test/haml/templates/standard.haml +42 -0
  131. data/test/haml/templates/standard_ugly.haml +42 -0
  132. data/test/haml/templates/tag_parsing.haml +21 -0
  133. data/test/haml/templates/very_basic.haml +4 -0
  134. data/test/haml/templates/whitespace_handling.haml +87 -0
  135. data/test/haml/util_test.rb +92 -0
  136. data/test/linked_rails.rb +12 -0
  137. data/test/sass/css2sass_test.rb +294 -0
  138. data/test/sass/engine_test.rb +956 -0
  139. data/test/sass/functions_test.rb +126 -0
  140. data/test/sass/more_results/more1.css +9 -0
  141. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  142. data/test/sass/more_results/more_import.css +29 -0
  143. data/test/sass/more_templates/_more_partial.sass +2 -0
  144. data/test/sass/more_templates/more1.sass +23 -0
  145. data/test/sass/more_templates/more_import.sass +11 -0
  146. data/test/sass/plugin_test.rb +229 -0
  147. data/test/sass/results/alt.css +4 -0
  148. data/test/sass/results/basic.css +9 -0
  149. data/test/sass/results/compact.css +5 -0
  150. data/test/sass/results/complex.css +87 -0
  151. data/test/sass/results/compressed.css +1 -0
  152. data/test/sass/results/expanded.css +19 -0
  153. data/test/sass/results/import.css +29 -0
  154. data/test/sass/results/line_numbers.css +49 -0
  155. data/test/sass/results/mixins.css +95 -0
  156. data/test/sass/results/multiline.css +24 -0
  157. data/test/sass/results/nested.css +22 -0
  158. data/test/sass/results/parent_ref.css +13 -0
  159. data/test/sass/results/script.css +16 -0
  160. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  161. data/test/sass/results/subdir/subdir.css +3 -0
  162. data/test/sass/results/units.css +11 -0
  163. data/test/sass/script_test.rb +261 -0
  164. data/test/sass/templates/_partial.sass +2 -0
  165. data/test/sass/templates/alt.sass +16 -0
  166. data/test/sass/templates/basic.sass +23 -0
  167. data/test/sass/templates/bork1.sass +2 -0
  168. data/test/sass/templates/bork2.sass +2 -0
  169. data/test/sass/templates/bork3.sass +2 -0
  170. data/test/sass/templates/compact.sass +17 -0
  171. data/test/sass/templates/complex.sass +307 -0
  172. data/test/sass/templates/compressed.sass +15 -0
  173. data/test/sass/templates/expanded.sass +17 -0
  174. data/test/sass/templates/import.sass +11 -0
  175. data/test/sass/templates/importee.sass +19 -0
  176. data/test/sass/templates/line_numbers.sass +13 -0
  177. data/test/sass/templates/mixins.sass +76 -0
  178. data/test/sass/templates/multiline.sass +20 -0
  179. data/test/sass/templates/nested.sass +25 -0
  180. data/test/sass/templates/nested_bork1.sass +2 -0
  181. data/test/sass/templates/nested_bork2.sass +2 -0
  182. data/test/sass/templates/nested_bork3.sass +2 -0
  183. data/test/sass/templates/parent_ref.sass +25 -0
  184. data/test/sass/templates/script.sass +101 -0
  185. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  186. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  187. data/test/sass/templates/subdir/subdir.sass +6 -0
  188. data/test/sass/templates/units.sass +11 -0
  189. data/test/test_helper.rb +44 -0
  190. metadata +298 -0
@@ -0,0 +1,57 @@
1
+ unless defined?(Sass::MERB_LOADED)
2
+ Sass::MERB_LOADED = true
3
+
4
+ version = Merb::VERSION.split('.').map { |n| n.to_i }
5
+ if version[0] <= 0 && version[1] < 5
6
+ root = MERB_ROOT
7
+ env = MERB_ENV
8
+ else
9
+ root = Merb.root.to_s
10
+ env = Merb.environment
11
+ end
12
+
13
+ Sass::Plugin.options.merge!(:template_location => root + '/public/stylesheets/sass',
14
+ :css_location => root + '/public/stylesheets',
15
+ :cache_location => root + '/tmp/sass-cache',
16
+ :always_check => env != "production",
17
+ :full_exception => env != "production")
18
+ config = Merb::Plugins.config[:sass] || Merb::Plugins.config["sass"] || {}
19
+
20
+ if defined? config.symbolize_keys!
21
+ config.symbolize_keys!
22
+ end
23
+
24
+ Sass::Plugin.options.merge!(config)
25
+
26
+ if version[0] > 0 || version[1] >= 9
27
+
28
+ class Merb::Rack::Application
29
+ def call_with_sass(env)
30
+ if !Sass::Plugin.checked_for_updates ||
31
+ Sass::Plugin.options[:always_update] || Sass::Plugin.options[:always_check]
32
+ Sass::Plugin.update_stylesheets
33
+ end
34
+
35
+ call_without_sass(env)
36
+ end
37
+ alias_method :call_without_sass, :call
38
+ alias_method :call, :call_with_sass
39
+ end
40
+
41
+ else
42
+
43
+ class MerbHandler
44
+ def process_with_sass(request, response)
45
+ if !Sass::Plugin.checked_for_updates ||
46
+ Sass::Plugin.options[:always_update] || Sass::Plugin.options[:always_check]
47
+ Sass::Plugin.update_stylesheets
48
+ end
49
+
50
+ process_without_sass(request, response)
51
+ end
52
+ alias_method :process_without_sass, :process
53
+ alias_method :process, :process_with_sass
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,23 @@
1
+ unless defined?(Sass::RAILS_LOADED)
2
+ Sass::RAILS_LOADED = true
3
+
4
+ Sass::Plugin.options.merge!(:template_location => RAILS_ROOT + '/public/stylesheets/sass',
5
+ :css_location => RAILS_ROOT + '/public/stylesheets',
6
+ :cache_location => RAILS_ROOT + '/tmp/sass-cache',
7
+ :always_check => RAILS_ENV != "production",
8
+ :full_exception => RAILS_ENV != "production")
9
+
10
+ module ActionController
11
+ class Base
12
+ alias_method :sass_old_process, :process
13
+ def process(*args)
14
+ if !Sass::Plugin.checked_for_updates ||
15
+ Sass::Plugin.options[:always_update] || Sass::Plugin.options[:always_check]
16
+ Sass::Plugin.update_stylesheets
17
+ end
18
+
19
+ sass_old_process(*args)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,58 @@
1
+ require 'readline'
2
+
3
+ module Sass
4
+ # Runs a SassScript read-eval-print loop.
5
+ # It presents a prompt on the terminal,
6
+ # reads in SassScript expressions,
7
+ # evaluates them,
8
+ # and prints the result.
9
+ class Repl
10
+ # @param options [Hash<Symbol, Object>] An options hash.
11
+ def initialize(options = {})
12
+ @options = options
13
+ end
14
+
15
+ # Starts the read-eval-print loop.
16
+ def run
17
+ environment = Environment.new
18
+ environment.set_var('important', Script::String.new('!important'))
19
+ @line = 0
20
+ loop do
21
+ @line += 1
22
+ unless text = Readline.readline('>> ')
23
+ puts
24
+ return
25
+ end
26
+
27
+ Readline::HISTORY << text
28
+ parse_input(environment, text)
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def parse_input(environment, text)
35
+ case text
36
+ when Script::MATCH
37
+ name = $1
38
+ guarded = $2 == '||='
39
+ val = Script::Parser.parse($3, @line, text.size - $3.size)
40
+
41
+ unless guarded && environment.var(name)
42
+ environment.set_var(name, val.perform(environment))
43
+ end
44
+
45
+ p environment.var(name)
46
+ else
47
+ p Script::Parser.parse(text, @line, 0).perform(environment)
48
+ end
49
+ rescue Sass::SyntaxError => e
50
+ puts "SyntaxError: #{e.message}"
51
+ if @options[:trace]
52
+ e.backtrace.each do |e|
53
+ puts "\tfrom #{e}"
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,55 @@
1
+ require 'strscan'
2
+ require 'sass/script/node'
3
+ require 'sass/script/variable'
4
+ require 'sass/script/funcall'
5
+ require 'sass/script/operation'
6
+ require 'sass/script/literal'
7
+ require 'sass/script/parser'
8
+
9
+ module Sass
10
+ # SassScript is code that's embedded in Sass documents
11
+ # to allow for property values to be computed from variables.
12
+ #
13
+ # This module contains code that handles the parsing and evaluation of SassScript.
14
+ module Script
15
+ # The character that begins a variable.
16
+ VARIABLE_CHAR = ?!
17
+
18
+ # The regular expression used to parse variables.
19
+ MATCH = /^!([a-zA-Z_]\w*)\s*((?:\|\|)?=)\s*(.+)/
20
+
21
+ # The regular expression used to validate variables without matching.
22
+ VALIDATE = /^![a-zA-Z_]\w*$/
23
+
24
+ # Parses and evaluates a string of SassScript.
25
+ #
26
+ # @param value [String] The SassScript
27
+ # @param line [Fixnum] The number of the line on which the SassScript appeared.
28
+ # Used for error reporting
29
+ # @param offset [Fixnum] The number of characters in on `line` that the SassScript started.
30
+ # Used for error reporting
31
+ # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
32
+ # @return [String] The string result of evaluating the SassScript
33
+ def self.resolve(value, line, offset, environment)
34
+ parse(value, line, offset).perform(environment).to_s
35
+ end
36
+
37
+ # Parses a string of SassScript
38
+ #
39
+ # @param value [String] The SassScript
40
+ # @param line [Fixnum] The number of the line on which the SassScript appeared.
41
+ # Used for error reporting
42
+ # @param offset [Fixnum] The number of characters in on `line` that the SassScript started.
43
+ # Used for error reporting
44
+ # @param filename [String] The path to the file in which the SassScript appeared.
45
+ # Used for error reporting
46
+ # @return [Script::Node] The root node of the parse tree
47
+ def self.parse(value, line, offset, filename = nil)
48
+ Parser.parse(value, line, offset, filename)
49
+ rescue Sass::SyntaxError => e
50
+ e.message << ": #{value.inspect}." if e.message == "SassScript error"
51
+ e.modify_backtrace(:line => line, :filename => filename)
52
+ raise e
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,17 @@
1
+ require 'sass/script/literal'
2
+
3
+ module Sass::Script
4
+ # A SassScript object representing a boolean (true or false) value.
5
+ class Bool < Literal
6
+ # The Ruby value of the boolean.
7
+ #
8
+ # @return [Boolean]
9
+ attr_reader :value
10
+ alias_method :to_bool, :value
11
+
12
+ # @return [String] "true" or "false"
13
+ def to_s
14
+ @value.to_s
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,183 @@
1
+ require 'sass/script/literal'
2
+
3
+ module Sass::Script
4
+ # A SassScript object representing a CSS color.
5
+ class Color < Literal
6
+ class << self; include Haml::Util; end
7
+
8
+ # A hash from color names to [red, green, blue] value arrays.
9
+ HTML4_COLORS = map_vals({
10
+ 'black' => 0x000000,
11
+ 'silver' => 0xc0c0c0,
12
+ 'gray' => 0x808080,
13
+ 'white' => 0xffffff,
14
+ 'maroon' => 0x800000,
15
+ 'red' => 0xff0000,
16
+ 'purple' => 0x800080,
17
+ 'fuchsia' => 0xff00ff,
18
+ 'green' => 0x008000,
19
+ 'lime' => 0x00ff00,
20
+ 'olive' => 0x808000,
21
+ 'yellow' => 0xffff00,
22
+ 'navy' => 0x000080,
23
+ 'blue' => 0x0000ff,
24
+ 'teal' => 0x008080,
25
+ 'aqua' => 0x00ffff
26
+ }) {|color| (0..2).map {|n| color >> (n << 3) & 0xff}.reverse}
27
+ # A hash from [red, green, blue] value arrays to color names.
28
+ HTML4_COLORS_REVERSE = map_hash(HTML4_COLORS) {|k, v| [v, k]}
29
+
30
+ # @param rgb [Array<Fixnum>] A three-element array of the red, green, and blue values (respectively)
31
+ # of the color
32
+ # @raise [Sass::SyntaxError] if any color value isn't between 0 and 255
33
+ def initialize(rgb)
34
+ rgb = rgb.map {|c| c.to_i}
35
+ raise Sass::SyntaxError.new("Color values must be between 0 and 255") if rgb.any? {|c| c < 0 || c > 255}
36
+ super(rgb)
37
+ end
38
+
39
+ # The SassScript `+` operation.
40
+ # Its functionality depends on the type of its argument:
41
+ #
42
+ # {Number}
43
+ # : Adds the number to each of the RGB color channels.
44
+ #
45
+ # {Color}
46
+ # : Adds each of the RGB color channels together.
47
+ #
48
+ # {Literal}
49
+ # : See {Literal#plus}.
50
+ #
51
+ # @param other [Literal] The right-hand side of the operator
52
+ # @return [Color] The resulting color
53
+ # @raise [Sass::SyntaxError] if `other` is a number with units
54
+ def plus(other)
55
+ if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
56
+ piecewise(other, :+)
57
+ else
58
+ super
59
+ end
60
+ end
61
+
62
+ # The SassScript `-` operation.
63
+ # Its functionality depends on the type of its argument:
64
+ #
65
+ # {Number}
66
+ # : Subtracts the number from each of the RGB color channels.
67
+ #
68
+ # {Color}
69
+ # : Subtracts each of the other color's RGB color channels from this color's.
70
+ #
71
+ # {Literal}
72
+ # : See {Literal#minus}.
73
+ #
74
+ # @param other [Literal] The right-hand side of the operator
75
+ # @return [Color] The resulting color
76
+ # @raise [Sass::SyntaxError] if `other` is a number with units
77
+ def minus(other)
78
+ if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
79
+ piecewise(other, :-)
80
+ else
81
+ super
82
+ end
83
+ end
84
+
85
+ # The SassScript `*` operation.
86
+ # Its functionality depends on the type of its argument:
87
+ #
88
+ # {Number}
89
+ # : Multiplies the number by each of the RGB color channels.
90
+ #
91
+ # {Color}
92
+ # : Multiplies each of the RGB color channels together.
93
+ #
94
+ # {Literal}
95
+ # : See {Literal#times}.
96
+ #
97
+ # @param other [Literal] The right-hand side of the operator
98
+ # @return [Color] The resulting color
99
+ # @raise [Sass::SyntaxError] if `other` is a number with units
100
+ def times(other)
101
+ if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
102
+ piecewise(other, :*)
103
+ else
104
+ raise NoMethodError.new(nil, :times)
105
+ end
106
+ end
107
+
108
+ # The SassScript `/` operation.
109
+ # Its functionality depends on the type of its argument:
110
+ #
111
+ # {Number}
112
+ # : Divides each of the RGB color channels by the number.
113
+ #
114
+ # {Color}
115
+ # : Divides each of this color's RGB color channels by the other color's.
116
+ #
117
+ # {Literal}
118
+ # : See {Literal#div}.
119
+ #
120
+ # @param other [Literal] The right-hand side of the operator
121
+ # @return [Color] The resulting color
122
+ # @raise [Sass::SyntaxError] if `other` is a number with units
123
+ def div(other)
124
+ if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
125
+ piecewise(other, :/)
126
+ else
127
+ super
128
+ end
129
+ end
130
+
131
+ # The SassScript `%` operation.
132
+ # Its functionality depends on the type of its argument:
133
+ #
134
+ # {Number}
135
+ # : Takes each of the RGB color channels module the number.
136
+ #
137
+ # {Color}
138
+ # : Takes each of this color's RGB color channels modulo the other color's.
139
+ #
140
+ # {Literal}
141
+ # : See {Literal#mod}.
142
+ #
143
+ # @param other [Literal] The right-hand side of the operator
144
+ # @return [Color] The resulting color
145
+ # @raise [Sass::SyntaxError] if `other` is a number with units
146
+ def mod(other)
147
+ if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
148
+ piecewise(other, :%)
149
+ else
150
+ raise NoMethodError.new(nil, :mod)
151
+ end
152
+ end
153
+
154
+ # Returns a string representation of the color.
155
+ # This is usually the color's hex value,
156
+ # but if the color has a name that's used instead.
157
+ #
158
+ # @return [String] The string representation
159
+ def to_s
160
+ return HTML4_COLORS_REVERSE[@value] if HTML4_COLORS_REVERSE[@value]
161
+ red, green, blue = @value.map { |num| num.to_s(16).rjust(2, '0') }
162
+ "##{red}#{green}#{blue}"
163
+ end
164
+ alias_method :inspect, :to_s
165
+
166
+ private
167
+
168
+ def piecewise(other, operation)
169
+ other_num = other.is_a? Number
170
+ other_val = other.value
171
+ if other_num && !other.unitless?
172
+ raise Sass::SyntaxError.new("Cannot add a number with units (#{other}) to a color (#{self}).")
173
+ end
174
+
175
+ rgb = []
176
+ for i in (0...3)
177
+ res = @value[i].send(operation, other_num ? other_val : other_val[i])
178
+ rgb[i] = [ [res, 255].min, 0 ].max
179
+ end
180
+ Color.new(rgb)
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,50 @@
1
+ require File.join(File.dirname(__FILE__), 'functions')
2
+ module Sass
3
+ module Script
4
+ # A SassScript parse node representing a function call.
5
+ #
6
+ # A function call either calls one of the functions in {Script::Functions},
7
+ # or if no function with the given name exists
8
+ # it returns a string representation of the function call.
9
+ class Funcall < Node
10
+ # The name of the function.
11
+ #
12
+ # @return [String]
13
+ attr_reader :name
14
+
15
+ # The arguments to the function.
16
+ #
17
+ # @return [Array<Script::Node>]
18
+ attr_reader :args
19
+
20
+ # @param name [String] See \{#name}
21
+ # @param name [Array<Script::Node>] See \{#args}
22
+ def initialize(name, args)
23
+ @name = name
24
+ @args = args
25
+ end
26
+
27
+ # @return [String] A string representation of the function call
28
+ def inspect
29
+ "#{name}(#{args.map {|a| a.inspect}.join(', ')})"
30
+ end
31
+
32
+ # Evaluates the function call.
33
+ #
34
+ # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
35
+ # @return [Literal] The SassScript object that is the value of the function call
36
+ # @raise [Sass::SyntaxError] if the function call raises an ArgumentError
37
+ def perform(environment)
38
+ args = self.args.map {|a| a.perform(environment)}
39
+ unless Haml::Util.has?(:public_instance_method, Functions, name) && name !~ /^__/
40
+ return Script::String.new("#{name}(#{args.map {|a| a.perform(environment)}.join(', ')})")
41
+ end
42
+
43
+ return Functions::EvaluationContext.new(environment.options).send(name, *args)
44
+ rescue ArgumentError => e
45
+ raise e unless e.backtrace.first =~ /:in `(block in )?(#{name}|perform)'$/
46
+ raise Sass::SyntaxError.new("#{e.message} for `#{name}'")
47
+ end
48
+ end
49
+ end
50
+ end