haml 3.1.0.alpha.33 → 3.1.0.alpha.36

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 (61) hide show
  1. data/EDGE_GEM_VERSION +1 -1
  2. data/VERSION +1 -1
  3. data/vendor/sass/doc-src/SASS_CHANGELOG.md +177 -2
  4. data/vendor/sass/doc-src/SASS_REFERENCE.md +140 -3
  5. data/vendor/sass/lib/sass/cache_stores.rb +14 -0
  6. data/vendor/sass/lib/sass/cache_stores/active_support.rb +28 -0
  7. data/vendor/sass/lib/sass/cache_stores/base.rb +84 -0
  8. data/vendor/sass/lib/sass/cache_stores/filesystem.rb +56 -0
  9. data/vendor/sass/lib/sass/cache_stores/memory.rb +51 -0
  10. data/vendor/sass/lib/sass/cache_stores/null.rb +25 -0
  11. data/vendor/sass/lib/sass/engine.rb +86 -25
  12. data/vendor/sass/lib/sass/exec.rb +10 -1
  13. data/vendor/sass/lib/sass/importers/rails.rb +75 -0
  14. data/vendor/sass/lib/sass/less.rb +1 -1
  15. data/vendor/sass/lib/sass/plugin/compiler.rb +4 -1
  16. data/vendor/sass/lib/sass/plugin/configuration.rb +4 -2
  17. data/vendor/sass/lib/sass/plugin/rack.rb +15 -2
  18. data/vendor/sass/lib/sass/plugin/rails.rb +89 -9
  19. data/vendor/sass/lib/sass/plugin/staleness_checker.rb +30 -2
  20. data/vendor/sass/lib/sass/script/css_parser.rb +1 -1
  21. data/vendor/sass/lib/sass/script/functions.rb +126 -5
  22. data/vendor/sass/lib/sass/script/lexer.rb +1 -1
  23. data/vendor/sass/lib/sass/script/list.rb +76 -0
  24. data/vendor/sass/lib/sass/script/literal.rb +10 -1
  25. data/vendor/sass/lib/sass/script/number.rb +1 -1
  26. data/vendor/sass/lib/sass/script/operation.rb +3 -2
  27. data/vendor/sass/lib/sass/script/parser.rb +25 -12
  28. data/vendor/sass/lib/sass/scss/css_parser.rb +0 -5
  29. data/vendor/sass/lib/sass/scss/parser.rb +46 -7
  30. data/vendor/sass/lib/sass/scss/static_parser.rb +1 -1
  31. data/vendor/sass/lib/sass/tree/charset_node.rb +37 -0
  32. data/vendor/sass/lib/sass/tree/directive_node.rb +2 -2
  33. data/vendor/sass/lib/sass/tree/each_node.rb +54 -0
  34. data/vendor/sass/lib/sass/tree/if_node.rb +19 -0
  35. data/vendor/sass/lib/sass/tree/media_node.rb +75 -0
  36. data/vendor/sass/lib/sass/tree/prop_node.rb +1 -1
  37. data/vendor/sass/lib/sass/tree/root_node.rb +37 -5
  38. data/vendor/sass/lib/sass/tree/rule_node.rb +4 -6
  39. data/vendor/sass/lib/sass/util.rb +18 -1
  40. data/vendor/sass/test/sass/cache_test.rb +7 -7
  41. data/vendor/sass/test/sass/conversion_test.rb +28 -0
  42. data/vendor/sass/test/sass/engine_test.rb +214 -11
  43. data/vendor/sass/test/sass/functions_test.rb +69 -0
  44. data/vendor/sass/test/sass/plugin_test.rb +13 -4
  45. data/vendor/sass/test/sass/results/import_charset.css +4 -0
  46. data/vendor/sass/test/sass/results/import_charset_1_8.css +4 -0
  47. data/vendor/sass/test/sass/results/import_charset_ibm866.css +4 -0
  48. data/vendor/sass/test/sass/script_conversion_test.rb +27 -25
  49. data/vendor/sass/test/sass/script_test.rb +12 -1
  50. data/vendor/sass/test/sass/scss/css_test.rb +27 -8
  51. data/vendor/sass/test/sass/scss/scss_test.rb +77 -0
  52. data/vendor/sass/test/sass/templates/_imported_charset_ibm866.sass +4 -0
  53. data/vendor/sass/test/sass/templates/_imported_charset_utf8.sass +4 -0
  54. data/vendor/sass/test/sass/templates/import_charset.sass +7 -0
  55. data/vendor/sass/test/sass/templates/import_charset_1_8.sass +4 -0
  56. data/vendor/sass/test/sass/templates/import_charset_ibm866.sass +9 -0
  57. data/vendor/sass/test/sass/templates/script.sass +2 -2
  58. data/vendor/sass/test/test_helper.rb +8 -0
  59. metadata +27 -10
  60. data/REVISION +0 -1
  61. data/vendor/sass/lib/sass/cache_store.rb +0 -208
@@ -0,0 +1,75 @@
1
+ module Sass
2
+ module Importers
3
+ # An importer that wraps the Rails 3.1 view infrastructure.
4
+ # Loads Sass files as though they were views in Rails.
5
+ # Currently doesn't support caching.
6
+ #
7
+ # This is different from standard Rails rendering
8
+ # in that Sass doesn't have a concept of importing partials
9
+ # as a distinct action from importing other Sass files.
10
+ # Imports within Rails behave more like Sass imports:
11
+ # they will first attempt to find a non-partial file,
12
+ # and failing that will fall back on a partial.
13
+ #
14
+ # Each importer instance is local to a single request for a single view.
15
+ # It contains the ActionView::LookupContext for that request,
16
+ # as well as the controller prefix for the view being generated.
17
+ class Rails < Base
18
+ # Creates a new Rails importer that imports files as Rails views.
19
+ def initialize; end
20
+
21
+ # @see Base#find_relative
22
+ def find_relative(uri, base, options)
23
+ find_(uri, base.split('/')[0...-1].join('/'), options)
24
+ end
25
+
26
+ # @see Base#find
27
+ def find(uri, options)
28
+ find_(uri, nil, options)
29
+ end
30
+
31
+ # @see Base#mtime
32
+ def mtime(uri, options)
33
+ return unless template =
34
+ find_template(uri, nil, !:partial, options) ||
35
+ find_template(uri, nil, :partial, options)
36
+ template.updated_at
37
+ end
38
+
39
+ # @see Base#key
40
+ def key(uri, options)
41
+ [self.class.name + ":" + uri.split('/')[0...-1].join('/'),
42
+ uri.split('/')[-1] + "." + options[:syntax].to_s]
43
+ end
44
+
45
+ # @see Base#to_s
46
+ def to_s
47
+ "(Rails importer)"
48
+ end
49
+
50
+ private
51
+
52
+ def find_(uri, prefix, options)
53
+ prepare_template(
54
+ find_template(uri, prefix, !:partial, options) ||
55
+ find_template(uri, prefix, :partial, options),
56
+ options)
57
+ end
58
+
59
+ def find_template(uri, prefix, partial, options)
60
+ return options[:_rails_lookup_context].
61
+ find_all(uri, prefix, partial).
62
+ find {|t| t.handler.is_a?(Sass::Plugin::TemplateHandler)}
63
+ end
64
+
65
+ def prepare_template(template, options)
66
+ return unless template
67
+ options[:syntax] = template.handler.syntax
68
+ options[:filename] = template.virtual_path
69
+ options[:_rails_filename] = template.identifier
70
+ options[:importer] = self
71
+ Sass::Engine.new(template.source, options)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -251,7 +251,7 @@ WARNING
251
251
  e, rest = _to_sass_tree_plus_minus_eq(arr)
252
252
  until rest.empty?
253
253
  e2, rest = _to_sass_tree_plus_minus_eq(rest)
254
- e = Sass::Script::Operation.new(e, e2, :concat)
254
+ e = Sass::Script::Operation.new(e, e2, :space)
255
255
  end
256
256
  return e
257
257
  end
@@ -318,7 +318,10 @@ module Sass::Plugin
318
318
  # Finally, write the file
319
319
  flag = 'w'
320
320
  flag = 'wb' if Sass::Util.windows? && options[:unix_newlines]
321
- File.open(css, flag) {|file| file.print(result)}
321
+ File.open(css, flag) do |file|
322
+ file.set_encoding(result.encoding) unless Sass::Util.ruby1_8?
323
+ file.print(result)
324
+ end
322
325
  end
323
326
 
324
327
  def try_delete_css(css)
@@ -31,7 +31,7 @@ module Sass
31
31
  # @return [{Symbol => Object}]
32
32
  def options
33
33
  @options ||= default_options.dup
34
- @options[:cache_store] ||= Sass::FileCacheStore.new(@options[:cache_location])
34
+ @options[:cache_store] ||= Sass::CacheStores::Filesystem.new(@options[:cache_location])
35
35
  @options
36
36
  end
37
37
 
@@ -113,7 +113,9 @@ module Sass
113
113
  return if options[:template_location].is_a?(Array)
114
114
  options[:template_location] =
115
115
  case options[:template_location]
116
- when nil; [[File.join(options[:css_location], 'sass'), options[:css_location]]]
116
+ when nil
117
+ options[:css_location] ?
118
+ [[File.join(options[:css_location], 'sass'), options[:css_location]]] : []
117
119
  when String; [[options[:template_location], options[:css_location]]]
118
120
  else; options[:template_location].to_a
119
121
  end
@@ -24,11 +24,21 @@ module Sass
24
24
  # The locations and frequency {file:SASS_REFERENCE.md#options can be customized}.
25
25
  # That's all there is to it!
26
26
  class Rack
27
+ # The delay, in seconds, between update checks.
28
+ # Useful when many resources are requested for a single page.
29
+ # `nil` means no delay at all.
30
+ #
31
+ # @return [Float]
32
+ attr_accessor :dwell
33
+
27
34
  # Initialize the middleware.
28
35
  #
29
36
  # @param app [#call] The Rack application
30
- def initialize(app)
37
+ # @param dwell [Float] See \{#dwell}
38
+ def initialize(app, dwell = 1.0)
31
39
  @app = app
40
+ @dwell = dwell
41
+ @check_after = Time.now.to_f
32
42
  end
33
43
 
34
44
  # Process a request, checking the Sass stylesheets for changes
@@ -37,7 +47,10 @@ module Sass
37
47
  # @param env The Rack request environment
38
48
  # @return [(#to_i, {String => String}, Object)] The Rack response
39
49
  def call(env)
40
- Sass::Plugin.check_for_updates
50
+ if @dwell.nil? || Time.now.to_f > @check_after
51
+ Sass::Plugin.check_for_updates
52
+ @check_after = Time.now.to_f + @dwell if @dwell
53
+ end
41
54
  @app.call(env)
42
55
  end
43
56
  end
@@ -4,21 +4,101 @@ unless defined?(Sass::RAILS_LOADED)
4
4
  module Sass::Plugin::Configuration
5
5
  # Different default options in a rails envirionment.
6
6
  def default_options
7
- @default_options ||= {
8
- :always_update => false,
9
- :template_location => Sass::Util.rails_root + '/public/stylesheets/sass',
10
- :css_location => Sass::Util.rails_root + '/public/stylesheets',
11
- :cache_location => Sass::Util.rails_root + '/tmp/sass-cache',
12
- :always_check => Sass::Util.rails_env == "development",
7
+ return @default_options if @default_options
8
+ opts = {
13
9
  :quiet => Sass::Util.rails_env != "production",
14
- :full_exception => Sass::Util.rails_env != "production"
15
- }.freeze
10
+ :full_exception => Sass::Util.rails_env != "production",
11
+ :cache_location => Sass::Util.rails_root + '/tmp/sass-cache'
12
+ }
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
26
+
27
+ @default_options = opts.freeze
16
28
  end
17
29
  end
18
30
 
19
31
  Sass::Plugin.options.reverse_merge!(Sass::Plugin.default_options)
20
32
 
21
- if defined?(ActionController::Metal)
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)
22
102
  # Rails >= 3.0
23
103
  require 'sass/plugin/rack'
24
104
  Rails.configuration.middleware.use(Sass::Plugin::Rack)
@@ -53,6 +53,7 @@ module Sass
53
53
  # @param css_file [String] The location of the CSS file to check.
54
54
  # @param template_file [String] The location of the Sass or SCSS template
55
55
  # that is compiled to `css_file`.
56
+ # @return [Boolean] Whether the stylesheet needs to be updated.
56
57
  def stylesheet_needs_update?(css_file, template_file)
57
58
  template_file = File.expand_path(template_file)
58
59
  begin
@@ -61,8 +62,19 @@ module Sass
61
62
  return true
62
63
  end
63
64
 
64
- dependency_updated?(css_mtime).call(
65
- template_file, @options[:filesystem_importer].new("."))
65
+ stylesheet_modified_since?(template_file, css_mtime)
66
+ end
67
+
68
+ # Returns whether a Sass or SCSS stylesheet has been modified since a given time.
69
+ #
70
+ # @param template_file [String] The location of the Sass or SCSS template.
71
+ # @param mtime [Fixnum] The modification time to check against.
72
+ # @param importer [Sass::Importers::Base] The importer used to locate the stylesheet.
73
+ # Defaults to the filesystem importer.
74
+ # @return [Boolean] Whether the stylesheet has been modified.
75
+ def stylesheet_modified_since?(template_file, mtime, importer = nil)
76
+ importer ||= @options[:filesystem_importer].new(".")
77
+ dependency_updated?(mtime).call(template_file, importer)
66
78
  end
67
79
 
68
80
  # Returns whether or not a given CSS file is out of date
@@ -75,10 +87,26 @@ module Sass
75
87
  # @param css_file [String] The location of the CSS file to check.
76
88
  # @param template_file [String] The location of the Sass or SCSS template
77
89
  # that is compiled to `css_file`.
90
+ # @return [Boolean] Whether the stylesheet needs to be updated.
78
91
  def self.stylesheet_needs_update?(css_file, template_file)
79
92
  new(Plugin.engine_options).stylesheet_needs_update?(css_file, template_file)
80
93
  end
81
94
 
95
+ # Returns whether a Sass or SCSS stylesheet has been modified since a given time.
96
+ #
97
+ # The distinction between this method and the instance-level \{#stylesheet\_modified\_since?}
98
+ # is that the instance method preserves mtime and stale-dependency caches,
99
+ # so it's better to use when checking multiple stylesheets at once.
100
+ #
101
+ # @param template_file [String] The location of the Sass or SCSS template.
102
+ # @param mtime [Fixnum] The modification time to check against.
103
+ # @param importer [Sass::Importers::Base] The importer used to locate the stylesheet.
104
+ # Defaults to the filesystem importer.
105
+ # @return [Boolean] Whether the stylesheet has been modified.
106
+ def self.stylesheet_modified_since?(template_file, mtime, importer = nil)
107
+ new(Plugin.engine_options).stylesheet_modified_since?(template_file, mtime, importer)
108
+ end
109
+
82
110
  private
83
111
 
84
112
  def dependencies_stale?(uri, importer, css_mtime)
@@ -22,7 +22,7 @@ module Sass
22
22
  end
23
23
 
24
24
  # Short-circuit all the SassScript-only productions
25
- alias_method :interpolation, :concat
25
+ alias_method :interpolation, :space
26
26
  alias_method :or_expr, :div
27
27
  alias_method :unary_div, :ident
28
28
  alias_method :paren, :string
@@ -113,6 +113,17 @@ module Sass::Script
113
113
  # \{#abs abs($value)}
114
114
  # : Returns the absolute value of a number.
115
115
  #
116
+ # ## List Functions {#list-functions}
117
+ #
118
+ # \{#length length($list)}
119
+ # : Returns the length of a list.
120
+ #
121
+ # \{#nth nth($list, $n)}
122
+ # : Returns a specific item in a list.
123
+ #
124
+ # \{#join join($list1, $list2, \[$separator\])}
125
+ # : Joins together two lists into one.
126
+ #
116
127
  # ## Introspection Functions
117
128
  #
118
129
  # \{#type_of type-of($value)}
@@ -705,7 +716,7 @@ module Sass::Script
705
716
  # mix(#f00, #00f) => #7f007f
706
717
  # mix(#f00, #00f, 25%) => #3f00bf
707
718
  # mix(rgba(255, 0, 0, 0.5), #00f) => rgba(63, 0, 191, 0.75)
708
- # @overload mix(color1, color2, weight = 50%)
719
+ # @overload mix(color1, color2, weight: 50%)
709
720
  # @param color1 [Color]
710
721
  # @param color2 [Color]
711
722
  # @param weight [Number] between 0% and 100%
@@ -912,7 +923,7 @@ module Sass::Script
912
923
  # round(10.6px) => 11px
913
924
  # @param value [Number] The number
914
925
  # @return [Number] The rounded number
915
- # @raise [Sass::SyntaxError] if `value` isn't a number
926
+ # @raise [ArgumentError] if `value` isn't a number
916
927
  def round(value)
917
928
  numeric_transformation(value) {|n| n.round}
918
929
  end
@@ -925,7 +936,7 @@ module Sass::Script
925
936
  # ciel(10.6px) => 11px
926
937
  # @param value [Number] The number
927
938
  # @return [Number] The rounded number
928
- # @raise [Sass::SyntaxError] if `value` isn't a number
939
+ # @raise [ArgumentError] if `value` isn't a number
929
940
  def ceil(value)
930
941
  numeric_transformation(value) {|n| n.ceil}
931
942
  end
@@ -938,7 +949,7 @@ module Sass::Script
938
949
  # floor(10.6px) => 10px
939
950
  # @param value [Number] The number
940
951
  # @return [Number] The rounded number
941
- # @raise [Sass::SyntaxError] if `value` isn't a number
952
+ # @raise [ArgumentError] if `value` isn't a number
942
953
  def floor(value)
943
954
  numeric_transformation(value) {|n| n.floor}
944
955
  end
@@ -951,12 +962,122 @@ module Sass::Script
951
962
  # abs(-10px) => 10px
952
963
  # @param value [Number] The number
953
964
  # @return [Number] The absolute value
954
- # @raise [Sass::SyntaxError] if `value` isn't a number
965
+ # @raise [ArgumentError] if `value` isn't a number
955
966
  def abs(value)
956
967
  numeric_transformation(value) {|n| n.abs}
957
968
  end
958
969
  declare :abs, [:value]
959
970
 
971
+ # Return the length of a list.
972
+ #
973
+ # @example
974
+ # length(10px) => 1
975
+ # length(10px 20px 30px) => 3
976
+ # @param list [Literal] The list
977
+ # @return [Number] The length
978
+ def length(list)
979
+ Sass::Script::Number.new(list.to_a.size)
980
+ end
981
+ declare :length, [:list]
982
+
983
+ # Gets the nth item in a list.
984
+ #
985
+ # Note that unlike some languages, the first item in a Sass list is number 1,
986
+ # the second number 2, and so forth.
987
+ #
988
+ # @example
989
+ # nth(10px 20px 30px, 1) => 10px
990
+ # nth((Helvetica, Arial, sans-serif), 3) => sans-serif
991
+ # @param list [Literal] The list
992
+ # @param n [Number] The index into the list
993
+ # @return [Literal] The nth item in the list
994
+ # @raise [ArgumentError] If `n` isn't an integer between 1 and the list's length.
995
+ def nth(list, n)
996
+ assert_type n, :Number
997
+ if !n.int?
998
+ raise ArgumentError.new("List index #{n} must be an integer")
999
+ elsif n.to_i < 1
1000
+ raise ArgumentError.new("List index #{n} must be greater than or equal to 1")
1001
+ elsif n.to_i > (size = list.to_a.size)
1002
+ raise ArgumentError.new("List index is #{n} but list is only #{size} item#{'s' if size != 1} long")
1003
+ end
1004
+
1005
+ list.to_a[n.to_i - 1]
1006
+ end
1007
+ declare :nth, [:list, :n]
1008
+
1009
+ # Joins together two lists into a new list.
1010
+ #
1011
+ # Unless the `$separator` argument is passed,
1012
+ # if one list is comma-separated and one is space-separated,
1013
+ # the first parameter's separator is used for the resulting list.
1014
+ # If the lists have only one item each, spaces are used for the resulting list.
1015
+ #
1016
+ # @example
1017
+ # join(10px 20px, 30px 40px) => 10px 20px 30px 40px
1018
+ # join((blue, red), (#abc, #def)) => blue, red, #abc, #def
1019
+ # join(10px, 20px) => 10px 20px
1020
+ # join(10px, 20px, comma) => 10px, 20px
1021
+ # join((blue, red), (#abc, #def), space) => blue red #abc #def
1022
+ # @overload join(list1, list2, separator: auto)
1023
+ # @param list1 [Literal] The first list to join
1024
+ # @param list2 [Literal] The second list to join
1025
+ # @param separator [String] How the list separator (comma or space) should be determined.
1026
+ # If this is `comma` or `space`, that is always the separator;
1027
+ # if this is `auto` (the default), the separator is determined as explained above.
1028
+ def join(list1, list2, separator = Sass::Script::String.new("auto"))
1029
+ assert_type separator, :String
1030
+ unless %w[auto space comma].include?(separator.value)
1031
+ raise ArgumentError.new("Separator name must be space, comma, or auto")
1032
+ end
1033
+ sep1 = list1.separator if list1.is_a?(Sass::Script::List)
1034
+ sep2 = list2.separator if list2.is_a?(Sass::Script::List)
1035
+ Sass::Script::List.new(
1036
+ list1.to_a + list2.to_a,
1037
+ if separator.value == 'auto'
1038
+ sep1 || sep2 || :space
1039
+ else
1040
+ separator.value.to_sym
1041
+ end)
1042
+ end
1043
+ declare :join, [:list1, :list2]
1044
+ declare :join, [:list1, :list2, :separator]
1045
+
1046
+ # Appends a single value onto the end of a list.
1047
+ #
1048
+ # Unless the `$separator` argument is passed,
1049
+ # if the list has only one item,
1050
+ # the resulting list will be space-separated.
1051
+ #
1052
+ # @example
1053
+ # append(10px 20px, 30px) => 10px 20px 30px
1054
+ # append((blue, red), green) => blue, red, green
1055
+ # append(10px 20px, 30px 40px) => 10px 20px (30px 40px)
1056
+ # join(10px, 20px, comma) => 10px, 20px
1057
+ # join((blue, red), green, space) => blue red green
1058
+ # @overload join(list, val, separator: auto)
1059
+ # @param list1 [Literal] The first list to join
1060
+ # @param list2 [Literal] The second list to join
1061
+ # @param separator [String] How the list separator (comma or space) should be determined.
1062
+ # If this is `comma` or `space`, that is always the separator;
1063
+ # if this is `auto` (the default), the separator is determined as explained above.
1064
+ def append(list, val, separator = Sass::Script::String.new("auto"))
1065
+ assert_type separator, :String
1066
+ unless %w[auto space comma].include?(separator.value)
1067
+ raise ArgumentError.new("Separator name must be space, comma, or auto")
1068
+ end
1069
+ sep = list.separator if list.is_a?(Sass::Script::List)
1070
+ Sass::Script::List.new(
1071
+ list.to_a + [val],
1072
+ if separator.value == 'auto'
1073
+ sep || :space
1074
+ else
1075
+ separator.value.to_sym
1076
+ end)
1077
+ end
1078
+ declare :append, [:list, :val]
1079
+ declare :append, [:list, :val, :separator]
1080
+
960
1081
  private
961
1082
 
962
1083
  # This method implements the pattern of transforming a numeric value into