Class: SilkLayout::CSS::Values::Length

Inherits:
Object
  • Object
show all
Defined in:
lib/silk_layout/css/values.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(type, value: 0, unit: nil, terms: []) ⇒ Length

Returns a new instance of Length.



74
75
76
77
78
79
# File 'lib/silk_layout/css/values.rb', line 74

def initialize(type, value: 0, unit: nil, terms: [])
  @type = type
  @value = value
  @unit = unit
  @terms = terms
end

Instance Attribute Details

#termsObject (readonly)

Returns the value of attribute terms.



21
22
23
# File 'lib/silk_layout/css/values.rb', line 21

def terms
  @terms
end

#typeObject (readonly)

Returns the value of attribute type.



21
22
23
# File 'lib/silk_layout/css/values.rb', line 21

def type
  @type
end

#unitObject (readonly)

Returns the value of attribute unit.



21
22
23
# File 'lib/silk_layout/css/values.rb', line 21

def unit
  @unit
end

#valueObject (readonly)

Returns the value of attribute value.



21
22
23
# File 'lib/silk_layout/css/values.rb', line 21

def value
  @value
end

Class Method Details

.parse(value) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/silk_layout/css/values.rb', line 23

def self.parse(value)
  raw = value.to_s.strip
  normalized = raw.downcase
  return new(:auto) if normalized.empty? || normalized == "auto" || normalized == "none"

  named = NAMED_LENGTHS[normalized]
  return new(:length, value: named.to_f, unit: "px") if named

  calc_match = raw.match(CALC)
  if calc_match
    parsed = parse_calc(calc_match[:expression])
    return parsed if parsed

    return new(:length, value: raw.to_f, unit: "px")
  end

  match = raw.match(LENGTH)
  return new(:length, value: match[:number].to_f, unit: (match[:unit] || "px").downcase) if match

  new(:length, value: raw.to_f, unit: "px")
end

.parse_calc(expression) ⇒ Object



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
# File 'lib/silk_layout/css/values.rb', line 45

def self.parse_calc(expression)
  scanner = StringScanner.new(expression)
  terms = []
  sign = 1

  until scanner.eos?
    scanner.skip(/\s+/)

    operator = scanner.scan(/[+-]/)
    sign = (operator == "-") ? -1 : 1 if operator
    scanner.skip(/\s+/)

    token = scanner.scan(/(?:\d+(?:\.\d+)?|\.\d+)(?:px|%)?/i)
    return nil unless token

    length = parse(token)
    return nil unless length.type == :length

    terms << Term.new(length.value * sign, length.unit)
    scanner.skip(/\s+/)

    return nil unless scanner.eos? || scanner.peek(1).match?(/[+-]/)
  end

  return nil if terms.empty?

  new(:calc, terms: terms)
end

Instance Method Details

#reference_relative?Boolean

Returns:

  • (Boolean)


100
101
102
103
104
105
# File 'lib/silk_layout/css/values.rb', line 100

def reference_relative?
  return true if type == :length && unit == "%"
  return true if type == :calc && terms.any? { |term| term.unit == "%" }

  false
end

#resolve(reference: nil, default: 0) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/silk_layout/css/values.rb', line 81

def resolve(reference: nil, default: 0)
  case type
  when :auto
    default
  when :length
    return default if unit == "%" && reference.nil?

    (unit == "%") ? reference * value / 100.0 : value
  when :calc
    return default if terms.any? { |term| term.unit == "%" } && reference.nil?

    terms.sum do |term|
      (term.unit == "%") ? reference * term.value / 100.0 : term.value
    end
  else
    default
  end
end