haml 3.1.0 → 3.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of haml might be problematic. Click here for more details.

Files changed (87) hide show
  1. data/VERSION +1 -1
  2. data/vendor/sass/Rakefile +22 -46
  3. data/vendor/sass/VERSION +1 -1
  4. data/vendor/sass/VERSION_NAME +1 -1
  5. data/vendor/sass/bin/scss +8 -0
  6. data/vendor/sass/doc-src/SASS_CHANGELOG.md +125 -9
  7. data/vendor/sass/doc-src/SASS_REFERENCE.md +84 -8
  8. data/vendor/sass/lib/sass.rb +0 -3
  9. data/vendor/sass/lib/sass/cache_stores.rb +1 -0
  10. data/vendor/sass/lib/sass/cache_stores/base.rb +2 -2
  11. data/vendor/sass/lib/sass/cache_stores/chain.rb +33 -0
  12. data/vendor/sass/lib/sass/cache_stores/filesystem.rb +6 -4
  13. data/vendor/sass/lib/sass/cache_stores/memory.rb +8 -12
  14. data/vendor/sass/lib/sass/engine.rb +65 -56
  15. data/vendor/sass/lib/sass/environment.rb +5 -2
  16. data/vendor/sass/lib/sass/exec.rb +52 -21
  17. data/vendor/sass/lib/sass/importers/filesystem.rb +32 -9
  18. data/vendor/sass/lib/sass/less.rb +1 -1
  19. data/vendor/sass/lib/sass/plugin.rb +11 -1
  20. data/vendor/sass/lib/sass/plugin/compiler.rb +21 -12
  21. data/vendor/sass/lib/sass/plugin/rails.rb +8 -82
  22. data/vendor/sass/lib/sass/plugin/staleness_checker.rb +10 -10
  23. data/vendor/sass/lib/sass/railtie.rb +3 -2
  24. data/vendor/sass/lib/sass/script.rb +2 -25
  25. data/vendor/sass/lib/sass/script/color.rb +4 -15
  26. data/vendor/sass/lib/sass/script/funcall.rb +63 -19
  27. data/vendor/sass/lib/sass/script/functions.rb +257 -19
  28. data/vendor/sass/lib/sass/script/lexer.rb +1 -4
  29. data/vendor/sass/lib/sass/script/list.rb +2 -2
  30. data/vendor/sass/lib/sass/script/node.rb +0 -27
  31. data/vendor/sass/lib/sass/script/number.rb +1 -1
  32. data/vendor/sass/lib/sass/script/operation.rb +0 -5
  33. data/vendor/sass/lib/sass/script/parser.rb +30 -12
  34. data/vendor/sass/lib/sass/script/string.rb +2 -17
  35. data/vendor/sass/lib/sass/script/string_interpolation.rb +1 -0
  36. data/vendor/sass/lib/sass/scss/parser.rb +58 -18
  37. data/vendor/sass/lib/sass/scss/rx.rb +2 -1
  38. data/vendor/sass/lib/sass/scss/script_lexer.rb +1 -1
  39. data/vendor/sass/lib/sass/selector/comma_sequence.rb +2 -3
  40. data/vendor/sass/lib/sass/selector/sequence.rb +3 -6
  41. data/vendor/sass/lib/sass/selector/simple_sequence.rb +2 -3
  42. data/vendor/sass/lib/sass/tree/charset_node.rb +0 -15
  43. data/vendor/sass/lib/sass/tree/comment_node.rb +20 -71
  44. data/vendor/sass/lib/sass/tree/debug_node.rb +4 -22
  45. data/vendor/sass/lib/sass/tree/directive_node.rb +0 -52
  46. data/vendor/sass/lib/sass/tree/each_node.rb +8 -38
  47. data/vendor/sass/lib/sass/tree/extend_node.rb +12 -48
  48. data/vendor/sass/lib/sass/tree/for_node.rb +20 -51
  49. data/vendor/sass/lib/sass/tree/function_node.rb +27 -0
  50. data/vendor/sass/lib/sass/tree/if_node.rb +22 -57
  51. data/vendor/sass/lib/sass/tree/import_node.rb +0 -56
  52. data/vendor/sass/lib/sass/tree/media_node.rb +0 -43
  53. data/vendor/sass/lib/sass/tree/mixin_def_node.rb +12 -45
  54. data/vendor/sass/lib/sass/tree/mixin_node.rb +13 -124
  55. data/vendor/sass/lib/sass/tree/node.rb +18 -304
  56. data/vendor/sass/lib/sass/tree/prop_node.rb +24 -92
  57. data/vendor/sass/lib/sass/tree/return_node.rb +18 -0
  58. data/vendor/sass/lib/sass/tree/root_node.rb +4 -133
  59. data/vendor/sass/lib/sass/tree/rule_node.rb +21 -164
  60. data/vendor/sass/lib/sass/tree/variable_node.rb +14 -23
  61. data/vendor/sass/lib/sass/tree/visitors/base.rb +75 -0
  62. data/vendor/sass/lib/sass/tree/visitors/check_nesting.rb +134 -0
  63. data/vendor/sass/lib/sass/tree/visitors/convert.rb +255 -0
  64. data/vendor/sass/lib/sass/tree/visitors/cssize.rb +175 -0
  65. data/vendor/sass/lib/sass/tree/visitors/perform.rb +301 -0
  66. data/vendor/sass/lib/sass/tree/visitors/to_css.rb +216 -0
  67. data/vendor/sass/lib/sass/tree/warn_node.rb +4 -28
  68. data/vendor/sass/lib/sass/tree/while_node.rb +5 -35
  69. data/vendor/sass/lib/sass/util.rb +0 -50
  70. data/vendor/sass/sass.gemspec +1 -1
  71. data/vendor/sass/test/sass/conversion_test.rb +53 -102
  72. data/vendor/sass/test/sass/engine_test.rb +416 -540
  73. data/vendor/sass/test/sass/functions_test.rb +306 -4
  74. data/vendor/sass/test/sass/importer_test.rb +0 -22
  75. data/vendor/sass/test/sass/plugin_test.rb +51 -21
  76. data/vendor/sass/test/sass/results/if.css +3 -0
  77. data/vendor/sass/test/sass/script_conversion_test.rb +0 -38
  78. data/vendor/sass/test/sass/script_test.rb +19 -4
  79. data/vendor/sass/test/sass/scss/scss_test.rb +32 -11
  80. data/vendor/sass/test/sass/templates/if.sass +11 -0
  81. data/vendor/sass/test/sass/templates/nested_import.sass +2 -0
  82. data/vendor/sass/test/sass/util_test.rb +0 -21
  83. data/vendor/sass/test/test_helper.rb +0 -3
  84. metadata +268 -258
  85. data/vendor/sass/bin/css2sass +0 -13
  86. data/vendor/sass/lib/sass/cache_stores/active_support.rb +0 -28
  87. data/vendor/sass/lib/sass/importers/rails.rb +0 -75
@@ -5,6 +5,9 @@ module Sass
5
5
  # The default importer, used for any strings found in the load path.
6
6
  # Simply loads Sass files from the filesystem using the default logic.
7
7
  class Filesystem < Base
8
+
9
+ attr_accessor :root
10
+
8
11
  # Creates a new filesystem importer that imports files relative to a given path.
9
12
  #
10
13
  # @param root [String] The root path.
@@ -25,8 +28,8 @@ module Sass
25
28
 
26
29
  # @see Base#mtime
27
30
  def mtime(name, options)
28
- file = find_real_file(@root, name)
29
- File.mtime(name)
31
+ file, s = find_real_file(@root, name)
32
+ File.mtime(file) if file
30
33
  rescue Errno::ENOENT
31
34
  nil
32
35
  end
@@ -44,6 +47,17 @@ module Sass
44
47
 
45
48
  protected
46
49
 
50
+ # If a full uri is passed, this removes the root from it
51
+ # otherwise returns the name unchanged
52
+ def remove_root(name)
53
+ root = @root.end_with?('/') ? @root : @root + '/'
54
+ if name.index(root) == 0
55
+ name[root.length..-1]
56
+ else
57
+ name
58
+ end
59
+ end
60
+
47
61
  # A hash from file extensions to the syntaxes for those extensions.
48
62
  # The syntaxes must be `:sass` or `:scss`.
49
63
  #
@@ -67,13 +81,12 @@ module Sass
67
81
  sorted_exts = extensions.sort
68
82
  syntax = extensions[extname]
69
83
 
70
- Sass::Util.flatten(
71
- ["#{dirname}/#{basename}", "#{dirname}/_#{basename}"].map do |name|
72
- next [["#{name}.#{extensions.invert[syntax]}", syntax]] if syntax
73
- sorted_exts.map {|ext, syn| ["#{name}.#{ext}", syn]}
74
- end, 1)
84
+ return [["#{dirname}/{_,}#{basename}.#{extensions.invert[syntax]}", syntax]] if syntax
85
+ sorted_exts.map {|ext, syn| ["#{dirname}/{_,}#{basename}.#{ext}", syn]}
75
86
  end
76
87
 
88
+
89
+ REDUNDANT_DIRECTORY = %r{#{Regexp.escape(File::SEPARATOR)}\.#{Regexp.escape(File::SEPARATOR)}}
77
90
  # Given a base directory and an `@import`ed name,
78
91
  # finds an existant file that matches the name.
79
92
  #
@@ -81,8 +94,10 @@ module Sass
81
94
  # @param name [String] The filename to search for.
82
95
  # @return [(String, Symbol)] A filename-syntax pair.
83
96
  def find_real_file(dir, name)
84
- possible_files(name).each do |f, s|
85
- if File.exists?(full_path = join(dir, f))
97
+ for (f,s) in possible_files(remove_root(name))
98
+ path = (dir == ".") ? f : "#{dir}/#{f}"
99
+ if full_path = Dir[path].first
100
+ full_path.gsub!(REDUNDANT_DIRECTORY,File::SEPARATOR)
86
101
  return full_path, s
87
102
  end
88
103
  end
@@ -101,6 +116,14 @@ module Sass
101
116
  [dirname, basename, extension]
102
117
  end
103
118
 
119
+ def hash
120
+ @root.hash
121
+ end
122
+
123
+ def eql?(other)
124
+ root.eql?(other.root)
125
+ end
126
+
104
127
  private
105
128
 
106
129
  def _find(dir, name, options)
@@ -225,7 +225,7 @@ WARNING
225
225
  class Property
226
226
  def to_sass_tree
227
227
  return if hide_in_sass
228
- Sass::Tree::PropNode.new([self], @value.to_sass_tree, :new)
228
+ Sass::Tree::PropNode.new([self], @value.to_sass_tree, false, :new)
229
229
  end
230
230
  end
231
231
 
@@ -41,7 +41,7 @@ module Sass
41
41
  # (in this Ruby instance).
42
42
  #
43
43
  # @return [Boolean]
44
- attr_reader :checked_for_updates
44
+ attr_accessor :checked_for_updates
45
45
 
46
46
  # Same as \{#update\_stylesheets}, but respects \{#checked\_for\_updates}
47
47
  # and the {file:SASS_REFERENCE.md#always_update-option `:always_update`}
@@ -114,6 +114,16 @@ module Sass
114
114
  end
115
115
  end
116
116
 
117
+ # For parity with method_missing
118
+ def respond_to?(method)
119
+ super || compiler.respond_to?(method)
120
+ end
121
+
122
+ # There's a small speedup by not using method missing for frequently delegated methods.
123
+ def options
124
+ compiler.options
125
+ end
126
+
117
127
  end
118
128
  end
119
129
 
@@ -161,17 +161,20 @@ module Sass::Plugin
161
161
  # the second is the location of the CSS file that it should be compiled to.
162
162
  def update_stylesheets(individual_files = [])
163
163
  run_updating_stylesheets individual_files
164
-
165
- individual_files.each {|t, c| update_stylesheet(t, c)}
166
-
167
- @checked_for_updates = true
164
+ Sass::Plugin.checked_for_updates = true
168
165
  staleness_checker = StalenessChecker.new(engine_options)
169
166
 
167
+ individual_files.each do |t, c|
168
+ if options[:always_update] || staleness_checker.stylesheet_needs_update?(c, t)
169
+ update_stylesheet(t, c)
170
+ end
171
+ end
172
+
170
173
  template_location_array.each do |template_location, css_location|
171
174
 
172
175
  Dir.glob(File.join(template_location, "**", "[^_]*.s[ca]ss")).sort.each do |file|
173
176
  # Get the relative path to the file
174
- name = file.sub(template_location.sub(/\/*$/, '/'), "")
177
+ name = file.sub(template_location.to_s.sub(/\/*$/, '/'), "")
175
178
  css = css_filename(name, css_location)
176
179
 
177
180
  if options[:always_update] || staleness_checker.stylesheet_needs_update?(css, file)
@@ -213,13 +216,19 @@ module Sass::Plugin
213
216
  begin
214
217
  require 'fssm'
215
218
  rescue LoadError => e
216
- e.message << "\n" <<
217
- if File.exists?(scope(".git"))
218
- 'Run "git submodule update --init" to get the recommended version.'
219
- else
220
- 'Run "gem install fssm" to get it.'
221
- end
222
- raise e
219
+ dir = Sass::Util.scope("vendor/fssm/lib")
220
+ if $LOAD_PATH.include?(dir)
221
+ e.message << "\n" <<
222
+ if File.exists?(scope(".git"))
223
+ 'Run "git submodule update --init" to get the recommended version.'
224
+ else
225
+ 'Run "gem install fssm" to get it.'
226
+ end
227
+ raise e
228
+ else
229
+ $LOAD_PATH.unshift dir
230
+ retry
231
+ end
223
232
  end
224
233
 
225
234
  unless individual_files.empty? && FSSM::Backends::Default.name == "FSSM::Backends::FSEvents"
@@ -11,18 +11,11 @@ unless defined?(Sass::RAILS_LOADED)
11
11
  :cache_location => Sass::Util.rails_root + '/tmp/sass-cache'
12
12
  }
13
13
 
14
- if Sass::Util.ap_geq?('3.1.0.beta')
15
- require 'sass/importers/rails'
16
- require 'sass/cache_stores/active_support'
17
- opts.merge!(:load_paths => [Sass::Importers::Rails.new])
18
- opts.merge!(:cache_store => Sass::CacheStores::ActiveSupport.new(Rails.cache)) if Rails.cache
19
- else
20
- opts.merge!(
21
- :always_update => false,
22
- :template_location => Sass::Util.rails_root + '/public/stylesheets/sass',
23
- :css_location => Sass::Util.rails_root + '/public/stylesheets',
24
- :always_check => Sass::Util.rails_env == "development")
25
- end
14
+ opts.merge!(
15
+ :always_update => false,
16
+ :template_location => Sass::Util.rails_root + '/public/stylesheets/sass',
17
+ :css_location => Sass::Util.rails_root + '/public/stylesheets',
18
+ :always_check => Sass::Util.rails_env == "development")
26
19
 
27
20
  @default_options = opts.freeze
28
21
  end
@@ -30,76 +23,9 @@ unless defined?(Sass::RAILS_LOADED)
30
23
 
31
24
  Sass::Plugin.options.reverse_merge!(Sass::Plugin.default_options)
32
25
 
33
- # Disable this for now, until we figure out how to get Rails
34
- # to pass in the view.
35
- if Sass::Util.ap_geq?('3.1.0.beta')
36
- class Sass::Plugin::TemplateHandler
37
- attr_reader :syntax
38
-
39
- def initialize(syntax)
40
- @syntax = syntax
41
- end
42
-
43
- def handles_encoding?; true; end
44
-
45
- def call(template, view)
46
- engine = Sass::Engine.new(template.source,
47
- Sass::Plugin.engine_options.merge(
48
- :syntax => @syntax,
49
- :filename => template.virtual_path,
50
- :_rails_lookup_context => view.lookup_context,
51
- :importer => Sass::Importers::Rails.new))
52
-
53
- template.data[:sass_importers] = engine.dependencies.map do |e|
54
- [e.options[:filename], e.options[:importer]]
55
- end
56
-
57
- stylesheet =
58
- begin
59
- engine.render
60
- rescue Sass::SyntaxError => e
61
- Sass::Plugin::TemplateHandler.munge_exception e, view.lookup_context
62
- Sass::SyntaxError.exception_to_css(e, Sass::Plugin.engine_options)
63
- end
64
-
65
- <<RUBY
66
- begin
67
- if Sass::Plugin::TemplateHandler.dependencies_changed?(
68
- @_template.data[:sass_importers], #{Time.now.to_i}, lookup_context)
69
- @_template.expire!
70
- @_template.rerender(self)
71
- else
72
- #{stylesheet.inspect}
73
- end
74
- rescue Sass::SyntaxError => e
75
- Sass::Plugin::TemplateHandler.munge_exception e, lookup_context
76
- Sass::SyntaxError.exception_to_css(e, Sass::Plugin.engine_options)
77
- end
78
- RUBY
79
- end
80
-
81
- def self.dependencies_changed?(deps, since, lookup_context)
82
- opts = Sass::Plugin.engine_options.merge(:_rails_lookup_context => lookup_context)
83
- deps.any? do |d, i|
84
- return true unless time = i.mtime(d, opts)
85
- time.to_i > since
86
- end
87
- end
88
-
89
- def self.munge_exception(e, lookup_context)
90
- importer = Sass::Importers::Rails.new
91
- opts = Sass::Plugin.engine_options.merge(:_rails_lookup_context => lookup_context)
92
- e.sass_backtrace.each do |bt|
93
- next unless engine = importer.find(bt[:filename], opts)
94
- bt[:filename] = engine.options[:_rails_filename]
95
- end
96
- end
97
- end
98
-
99
- ActionView::Template.register_template_handler(:sass, Sass::Plugin::TemplateHandler.new(:sass))
100
- ActionView::Template.register_template_handler(:scss, Sass::Plugin::TemplateHandler.new(:scss))
101
- elsif defined?(ActionController::Metal)
102
- # Rails >= 3.0
26
+ # Rails 3.1 loads and handles Sass all on its own
27
+ if defined?(ActionController::Metal)
28
+ # 3.1 > Rails >= 3.0
103
29
  require 'sass/plugin/rack'
104
30
  Rails.configuration.middleware.use(Sass::Plugin::Rack)
105
31
  elsif defined?(ActionController::Dispatcher) &&
@@ -23,7 +23,6 @@ module Sass
23
23
  # *WARNING*: It is important not to retain the instance for too long,
24
24
  # as its instance-level caches are never explicitly expired.
25
25
  class StalenessChecker
26
- DELETED = 1.0/0.0 # positive Infinity
27
26
  @dependencies_cache = {}
28
27
 
29
28
  class << self
@@ -54,15 +53,14 @@ module Sass
54
53
  # @param template_file [String] The location of the Sass or SCSS template
55
54
  # that is compiled to `css_file`.
56
55
  # @return [Boolean] Whether the stylesheet needs to be updated.
57
- def stylesheet_needs_update?(css_file, template_file)
56
+ def stylesheet_needs_update?(css_file, template_file, importer = nil)
58
57
  template_file = File.expand_path(template_file)
59
58
  begin
60
- css_mtime = File.mtime(css_file).to_i
59
+ css_mtime = File.mtime(css_file)
61
60
  rescue Errno::ENOENT
62
61
  return true
63
62
  end
64
-
65
- stylesheet_modified_since?(template_file, css_mtime)
63
+ stylesheet_modified_since?(template_file, css_mtime, importer)
66
64
  end
67
65
 
68
66
  # Returns whether a Sass or SCSS stylesheet has been modified since a given time.
@@ -88,8 +86,8 @@ module Sass
88
86
  # @param template_file [String] The location of the Sass or SCSS template
89
87
  # that is compiled to `css_file`.
90
88
  # @return [Boolean] Whether the stylesheet needs to be updated.
91
- def self.stylesheet_needs_update?(css_file, template_file)
92
- new(Plugin.engine_options).stylesheet_needs_update?(css_file, template_file)
89
+ def self.stylesheet_needs_update?(css_file, template_file, importer = nil)
90
+ new(Plugin.engine_options).stylesheet_needs_update?(css_file, template_file, importer)
93
91
  end
94
92
 
95
93
  # Returns whether a Sass or SCSS stylesheet has been modified since a given time.
@@ -130,9 +128,9 @@ module Sass
130
128
  mtime = importer.mtime(uri, @options)
131
129
  if mtime.nil?
132
130
  @dependencies.delete([uri, importer])
133
- DELETED
131
+ nil
134
132
  else
135
- mtime.to_i
133
+ mtime
136
134
  end
137
135
  end
138
136
  end
@@ -150,7 +148,9 @@ module Sass
150
148
 
151
149
  def dependency_updated?(css_mtime)
152
150
  Proc.new do |uri, importer|
153
- mtime(uri, importer) > css_mtime ||
151
+ sass_mtime = mtime(uri, importer)
152
+ !sass_mtime ||
153
+ sass_mtime > css_mtime ||
154
154
  dependencies_stale?(uri, importer, css_mtime)
155
155
  end
156
156
  end
@@ -1,5 +1,6 @@
1
- # Rails 3.0.0.beta.2+
2
- if defined?(ActiveSupport) && Sass::Util.has?(:public_method, ActiveSupport, :on_load)
1
+ # Rails 3.0.0.beta.2+, < 3.1
2
+ if defined?(ActiveSupport) && Sass::Util.has?(:public_method, ActiveSupport, :on_load) &&
3
+ !Sass::Util.ap_geq?('3.1.0.beta')
3
4
  require 'sass/plugin/configuration'
4
5
  ActiveSupport.on_load(:before_initialize) do
5
6
  require 'sass'
@@ -13,10 +13,10 @@ module Sass
13
13
  # This module contains code that handles the parsing and evaluation of SassScript.
14
14
  module Script
15
15
  # The regular expression used to parse variables.
16
- MATCH = /^[!\$](#{Sass::SCSS::RX::IDENT})\s*((?:\|\|)?=|:)\s*(.+?)(!(?i:default))?$/
16
+ MATCH = /^\$(#{Sass::SCSS::RX::IDENT})\s*:\s*(.+?)(!(?i:default))?$/
17
17
 
18
18
  # The regular expression used to validate variables without matching.
19
- VALIDATE = /^[!\$]#{Sass::SCSS::RX::IDENT}$/
19
+ VALIDATE = /^\$#{Sass::SCSS::RX::IDENT}$/
20
20
 
21
21
  # Parses a string of SassScript
22
22
  #
@@ -36,28 +36,5 @@ module Sass
36
36
  raise e
37
37
  end
38
38
 
39
- # @private
40
- def self.var_warning(varname, line, offset, filename)
41
- Sass::Util.sass_warn <<MESSAGE
42
- DEPRECATION WARNING:
43
- On line #{line}, character #{offset}#{" of '#{filename}'" if filename}
44
- Variables with ! have been deprecated and will be removed in version 3.2.
45
- Use \"$#{varname}\" instead.
46
-
47
- You can use `sass-convert --in-place --from sass2 file.sass' to convert files automatically.
48
- MESSAGE
49
- end
50
-
51
- # @private
52
- def self.equals_warning(types, name, val, guarded, line, offset, filename)
53
- Sass::Util.sass_warn <<MESSAGE
54
- DEPRECATION WARNING:
55
- On line #{line}#{", character #{offset}" if offset}#{" of '#{filename}'" if filename}
56
- Setting #{types} with #{"||" if guarded}= has been deprecated and will be removed in version 3.2.
57
- Use "#{name}: #{val}#{" !default" if guarded}" instead.
58
-
59
- You can use `sass-convert --in-place --from sass2 file.sass' to convert files automatically.
60
- MESSAGE
61
- end
62
39
  end
63
40
  end
@@ -102,7 +102,7 @@ module Sass::Script
102
102
  next if @attrs[k].nil?
103
103
  @attrs[k] = @attrs[k].to_i
104
104
  next if (0..255).include?(@attrs[k])
105
- raise Sass::SyntaxError.new("#{k.to_s.capitalize} value must be between 0 and 255")
105
+ raise ArgumentError.new("#{k.to_s.capitalize} value must be between 0 and 255")
106
106
  end
107
107
 
108
108
  [:saturation, :lightness].each do |k|
@@ -110,11 +110,11 @@ module Sass::Script
110
110
  @attrs[k] = 0 if @attrs[k] < 0.00001 && @attrs[k] > -0.00001
111
111
  @attrs[k] = 100 if @attrs[k] - 100 < 0.00001 && @attrs[k] - 100 > -0.00001
112
112
  next if (0..100).include?(@attrs[k])
113
- raise Sass::SyntaxError.new("#{k.to_s.capitalize} must be between 0 and 100")
113
+ raise ArgumentError.new("#{k.to_s.capitalize} must be between 0 and 100")
114
114
  end
115
115
 
116
116
  unless (0..1).include?(@attrs[:alpha])
117
- raise Sass::SyntaxError.new("Alpha channel must be between 0 and 1")
117
+ raise ArgumentError.new("Alpha channel must be between 0 and 1")
118
118
  end
119
119
  end
120
120
 
@@ -182,17 +182,6 @@ module Sass::Script
182
182
  alpha < 1
183
183
  end
184
184
 
185
- # @deprecated This will be removed in version 3.2.
186
- # @see #rgb
187
- def value
188
- Sass::Util.sass_warn <<END
189
- DEPRECATION WARNING:
190
- The Sass::Script::Color #value attribute is deprecated and will be
191
- removed in version 3.2. Use the #rgb attribute instead.
192
- END
193
- rgb
194
- end
195
-
196
185
  # Returns the red, green, and blue components of the color.
197
186
  #
198
187
  # @return [Array<Fixnum>] A frozen three-element array of the red, green, and blue
@@ -245,7 +234,7 @@ END
245
234
  hsl = !([:hue, :saturation, :lightness] & attrs.keys).empty?
246
235
  rgb = !([:red, :green, :blue] & attrs.keys).empty?
247
236
  if hsl && rgb
248
- raise ArgumentError.new("Color#with may not have both HSL and RGB keys specified")
237
+ raise ArgumentError.new("Cannot specify HSL and RGB values for a color at the same time")
249
238
  end
250
239
 
251
240
  if hsl
@@ -23,15 +23,6 @@ module Sass
23
23
  # @return [{String => Script::Node}]
24
24
  attr_reader :keywords
25
25
 
26
- # Don't set the context for child nodes if this is `url()`,
27
- # since `url()` allows quoted strings.
28
- #
29
- # @param context [Symbol]
30
- # @see Node#context=
31
- def context=(context)
32
- super unless @name == "url"
33
- end
34
-
35
26
  # @param name [String] See \{#name}
36
27
  # @param args [Array<Script::Node>] See \{#args}
37
28
  # @param keywords [{String => Script::Node}] See \{#keywords}
@@ -75,12 +66,16 @@ module Sass
75
66
  # @raise [Sass::SyntaxError] if the function call raises an ArgumentError
76
67
  def _perform(environment)
77
68
  args = @args.map {|a| a.perform(environment)}
78
- keywords = Sass::Util.map_hash(@keywords) {|k, v| [k, v.perform(environment)]}
69
+ if fn = environment.function(@name)
70
+ keywords = Sass::Util.map_hash(@keywords) {|k, v| [k, v.perform(environment)]}
71
+ return perform_sass_fn(fn, args, keywords)
72
+ end
73
+
79
74
  ruby_name = @name.tr('-', '_')
80
- args = construct_ruby_args(ruby_name, args, keywords)
75
+ args = construct_ruby_args(ruby_name, args, environment)
81
76
 
82
- unless Sass::Util.has?(:public_instance_method, Functions, ruby_name) && ruby_name !~ /^__/
83
- opts(Script::String.new("#{name}(#{args.join(', ')})"))
77
+ unless Functions.callable?(ruby_name)
78
+ opts(to_literal(args))
84
79
  else
85
80
  opts(Functions::EvaluationContext.new(environment.options).send(ruby_name, *args))
86
81
  end
@@ -89,30 +84,79 @@ module Sass
89
84
  raise Sass::SyntaxError.new("#{e.message} for `#{name}'")
90
85
  end
91
86
 
92
- def construct_ruby_args(name, args, keywords)
93
- return args if keywords.empty?
94
- unless signature = Functions.signature(name.to_sym, args.size, keywords.size)
87
+ # This method is factored out from `_perform` so that compass can override
88
+ # it with a cross-browser implementation for functions that require vendor prefixes
89
+ # in the generated css.
90
+ def to_literal(args)
91
+ Script::String.new("#{name}(#{args.join(', ')})")
92
+ end
93
+
94
+ private
95
+
96
+ def construct_ruby_args(name, args, environment)
97
+ unless signature = Functions.signature(name.to_sym, args.size, @keywords.size)
98
+ return args if keywords.empty?
95
99
  raise Sass::SyntaxError.new("Function #{name} doesn't support keyword arguments")
96
100
  end
101
+ keywords = Sass::Util.map_hash(@keywords) {|k, v| [k, v.perform(environment)]}
102
+
103
+ # If the user passes more non-keyword args than the function expects,
104
+ # but it does expect keyword args, Ruby's arg handling won't raise an error.
105
+ # Since we don't want to make functions think about this,
106
+ # we'll handle it for them here.
107
+ if signature.var_kwargs && !signature.var_args && args.size > signature.args.size
108
+ raise Sass::SyntaxError.new(
109
+ "#{args[signature.args.size].inspect} is not a keyword argument for `#{name}'")
110
+ elsif keywords.empty?
111
+ return args
112
+ end
97
113
 
98
114
  args = args + signature.args[args.size..-1].map do |argname|
99
115
  if keywords.has_key?(argname)
100
116
  keywords.delete(argname)
101
117
  else
102
- raise Sass::SyntaxError, "Function #{name} requires an argument named $#{argname}"
118
+ raise Sass::SyntaxError.new("Function #{name} requires an argument named $#{argname}")
103
119
  end
104
120
  end
105
121
 
106
122
  if keywords.size > 0
107
123
  if signature.var_kwargs
108
- args << Sass::Util.map_hash(keywords) {|k, v| [k.to_sym, v]}
124
+ args << keywords
109
125
  else
110
- raise Sass::SyntaxError, "Function #{name} doesn't take an argument named $#{keywords.keys.sort.first}"
126
+ raise Sass::SyntaxError.new("Function #{name} doesn't take an argument named $#{keywords.keys.sort.first}")
111
127
  end
112
128
  end
113
129
 
114
130
  args
115
131
  end
132
+
133
+ def perform_sass_fn(function, args, keywords)
134
+ # TODO: merge with mixin arg evaluation?
135
+ keywords.each do |name, value|
136
+ # TODO: Make this fast
137
+ unless function.args.find {|(var, default)| var.underscored_name == name}
138
+ raise Sass::SyntaxError.new("Function #{@name} doesn't have an argument named $#{name}")
139
+ end
140
+ end
141
+
142
+ if args.size > function.args.size
143
+ raise ArgumentError.new("Wrong number of arguments (#{args.size} for #{function.args.size})")
144
+ end
145
+
146
+ environment = function.args.zip(args).
147
+ inject(Sass::Environment.new(function.environment)) do |env, ((var, default), value)|
148
+ env.set_local_var(var.name,
149
+ value || keywords[var.underscored_name] || (default && default.perform(env)))
150
+ raise Sass::SyntaxError.new("Function #{@name} is missing parameter #{var.inspect}.") unless env.var(var.name)
151
+ env
152
+ end
153
+
154
+ val = catch :_sass_return do
155
+ function.tree.each {|c| Sass::Tree::Visitors::Perform.visit(c, environment)}
156
+ raise Sass::SyntaxError.new("Function #{@name} finished without @return")
157
+ end
158
+ val
159
+ end
116
160
  end
117
161
  end
118
162
  end