1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
module Sass::Script::Value
# A SassScript object representing a CSS list.
# This includes both comma-separated lists and space-separated lists.
class List < Base
# The Ruby array containing the contents of the list.
#
# @return [Array<Value>]
attr_reader :value
alias_method :to_a, :value
# The operator separating the values of the list.
# Either `:comma` or `:space`.
#
# @return [Symbol]
attr_reader :separator
# Whether the list is surrounded by square brackets.
#
# @return [Boolean]
attr_reader :bracketed
# Creates a new list.
#
# @param value [Array<Value>] See \{#value}
# @param separator [Symbol] See \{#separator}
# @param bracketed [Boolean] See \{#bracketed}
def initialize(value, separator: nil, bracketed: false)
super(value)
@separator = separator
@bracketed = bracketed
end
# @see Value#options=
def options=(options)
super
value.each {|v| v.options = options}
end
# @see Value#eq
def eq(other)
Sass::Script::Value::Bool.new(
other.is_a?(List) && value == other.value &&
separator == other.separator && bracketed == other.bracketed)
end
def hash
@hash ||= [value, separator, bracketed].hash
end
# @see Value#to_s
def to_s(opts = {})
if !bracketed && value.empty?
raise Sass::SyntaxError.new("#{inspect} isn't a valid CSS value.")
end
members = value.
reject {|e| e.is_a?(Null) || e.is_a?(List) && e.value.empty?}.
map {|e| e.to_s(opts)}
contents = members.join(sep_str)
bracketed ? "[#{contents}]" : contents
end
# @see Value#to_sass
def to_sass(opts = {})
return bracketed ? "[]" : "()" if value.empty?
members = value.map do |v|
if element_needs_parens?(v)
"(#{v.to_sass(opts)})"
else
v.to_sass(opts)
end
end
if separator == :comma && members.length == 1
return "#{bracketed ? '[' : '('}#{members.first},#{bracketed ? ']' : ')'}"
end
contents = members.join(sep_str(nil))
bracketed ? "[#{contents}]" : contents
end
# @see Value#to_h
def to_h
return {} if value.empty?
super
end
# @see Value#inspect
def inspect
(bracketed ? '[' : '(') +
value.map {|e| e.inspect}.join(sep_str(nil)) +
(bracketed ? ']' : ')')
end
# Asserts an index is within the list.
#
# @private
#
# @param list [Sass::Script::Value::List] The list for which the index should be checked.
# @param n [Sass::Script::Value::Number] The index being checked.
def self.assert_valid_index(list, n)
if !n.int? || n.to_i == 0
raise ArgumentError.new("List index #{n} must be a non-zero integer")
elsif list.to_a.size == 0
raise ArgumentError.new("List index is #{n} but list has no items")
elsif n.to_i.abs > (size = list.to_a.size)
raise ArgumentError.new(
"List index is #{n} but list is only #{size} item#{'s' if size != 1} long")
end
end
private
def element_needs_parens?(element)
if element.is_a?(List)
return false if element.value.length < 2
return false if element.bracketed
precedence = Sass::Script::Parser.precedence_of(separator || :space)
return Sass::Script::Parser.precedence_of(element.separator || :space) <= precedence
end
return false unless separator == :space
return false unless element.is_a?(Sass::Script::Tree::UnaryOperation)
element.operator == :minus || element.operator == :plus
end
def sep_str(opts = options)
return ' ' if separator == :space
return ',' if opts && opts[:style] == :compressed
', '
end
end
end
|