File: list.rb

package info (click to toggle)
ruby-sassc 2.4.0%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 416 kB
  • sloc: ruby: 2,277; makefile: 3
file content (136 lines) | stat: -rw-r--r-- 3,650 bytes parent folder | download | duplicates (3)
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
135
136
# frozen_string_literal: true

# A SassScript object representing a CSS list.
# This includes both comma-separated lists and space-separated lists.

class SassC::Script::Value::List < SassC::Script::Value

  # 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)
    SassC::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 SassC::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