Class: Less::Node::Element

Inherits:
Object show all
Includes:
Enumerable, Entity
Defined in:
lib/less/engine/nodes/element.rb

Overview

Element

div …

TODO: Look into making @rules its own hash-like class TODO: Look into whether selector should be child by default

Direct Known Subclasses

Mixin::Def

Instance Attribute Summary collapse

Attributes included from Entity

#parent

Instance Method Summary collapse

Methods included from Entity

#path, #root

Constructor Details

#initialize(name = "", selector = '') ⇒ Element

Returns a new instance of Element.



18
19
20
21
22
23
# File 'lib/less/engine/nodes/element.rb', line 18

def initialize name = "", selector = ''
  @name = name
  @set, @imported = [], []
  @rules = [] # Holds all the nodes under this element's hierarchy
  @selector = Selector[selector.strip].new  # descendant | child | adjacent
end

Instance Attribute Details

#fileObject

Returns the value of attribute file.



15
16
17
# File 'lib/less/engine/nodes/element.rb', line 15

def file
  @file
end

#importedObject

Returns the value of attribute imported.



15
16
17
# File 'lib/less/engine/nodes/element.rb', line 15

def imported
  @imported
end

#nameObject

Returns the value of attribute name.



15
16
17
# File 'lib/less/engine/nodes/element.rb', line 15

def name
  @name
end

#rulesObject

Returns the value of attribute rules.



15
16
17
# File 'lib/less/engine/nodes/element.rb', line 15

def rules
  @rules
end

#selectorObject

Returns the value of attribute selector.



15
16
17
# File 'lib/less/engine/nodes/element.rb', line 15

def selector
  @selector
end

#setObject

Returns the value of attribute set.



15
16
17
# File 'lib/less/engine/nodes/element.rb', line 15

def set
  @set
end

Instance Method Details

#<<(obj) ⇒ Object

Add an arbitrary node to this element



127
128
129
130
131
132
133
134
# File 'lib/less/engine/nodes/element.rb', line 127

def << obj
  if obj.kind_of? Node::Entity
    obj.parent = self
    @rules << obj
  else
    raise ArgumentError, "argument can't be a #{obj.class}"
  end
end

#==(other) ⇒ Object



96
97
98
# File 'lib/less/engine/nodes/element.rb', line 96

def == other
  name == other.name
end

#[](key) ⇒ Object

Select a child element TODO: Implement full selector syntax & merge with descend()



86
87
88
89
90
91
92
93
94
# File 'lib/less/engine/nodes/element.rb', line 86

def [] key
  case key
    when Entity
      @rules.find {|i| i.eql? key }
    when String
      @rules.find {|i| i.to_s == key }
    else raise ArgumentError
  end
end

#class?Boolean

Returns:

  • (Boolean)


25
# File 'lib/less/engine/nodes/element.rb', line 25

def class?;     name =~ /^\./ end

#descend(selector, element) ⇒ Object

Same as above, except with a specific selector TODO: clean this up or implement it differently



113
114
115
116
117
118
119
120
121
122
# File 'lib/less/engine/nodes/element.rb', line 113

def descend selector, element
  if selector.is_a? Child
    s = self[element.name].selector
    self[element.name] if s.is_a? Child or s.is_a? Descendant
  elsif selector.is_a? Descendant
    self[element.name]
  else
    self[element.name] if self[element.name].selector.class == selector.class
  end
end

#each(path = [], &blk) ⇒ Object

Traverse the whole tree, returning each leaf (recursive)



186
187
188
189
190
191
192
193
194
# File 'lib/less/engine/nodes/element.rb', line 186

def each path = [], &blk
  elements.each do |element|
    path << element
    yield element, path if element.leaf?
    element.each path, &blk
    path.pop
  end
  self
end

#elementsObject



80
# File 'lib/less/engine/nodes/element.rb', line 80

def elements;    @rules.select {|r| r.kind_of?     Element    } end

#empty?Boolean

Returns:

  • (Boolean)


38
39
40
# File 'lib/less/engine/nodes/element.rb', line 38

def empty?
  @rules.empty?
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/less/engine/nodes/element.rb', line 100

def eql? other
  super and self.equiv? other
end

#equiv?(other) ⇒ Boolean

Returns:

  • (Boolean)


104
105
106
107
108
109
# File 'lib/less/engine/nodes/element.rb', line 104

def equiv? other
  rules.size == other.rules.size and
  !rules.zip(other.rules).map do |a, b|
    a.to_css == b.to_css
  end.include?(false)
end

#firstObject



137
# File 'lib/less/engine/nodes/element.rb', line 137

def first; elements.first end

#groupObject

Group similar rulesets together This is horrible, horrible code, but it’ll have to do until I find a proper way to do it.



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/less/engine/nodes/element.rb', line 50

def group
  elements = self.elements.reject {|e| e.is_a?(Mixin::Def) }
  return self unless elements.size > 1

  stack, result, matched = elements.dup, [], false

  elements.each do
    e = stack.first
    result << e unless matched

    matched = stack[1..-1].each do |ee|
      if e.equiv? ee and e.elements.size == 0
        self[e].set << ee
        stack.shift
      else
        stack.shift
        break false
      end
    end if stack.size > 1
  end
  @rules -= (elements - result)
  self
end

#id?Boolean

Returns:

  • (Boolean)


26
# File 'lib/less/engine/nodes/element.rb', line 26

def id?;        name =~ /^#/  end

#identifiersObject

Accessors for the different nodes in @rules



77
# File 'lib/less/engine/nodes/element.rb', line 77

def identifiers; @rules.select {|r| r.kind_of?     Property   } end

#inspect(depth = 0) ⇒ Object



196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/less/engine/nodes/element.rb', line 196

def inspect depth = 0
  indent = lambda {|i| '.  ' * i }
  put    = lambda {|ary| ary.map {|i| indent[ depth + 1 ] + i.inspect } * "\n"}

  (root?? "\n" : "") + [
    indent[ depth ] + self.to_s,
    put[ variables ],
    put[ properties ],
    put[ mixins ],
    elements.map {|i| i.inspect( depth + 1 ) } * "\n"
  ].reject(&:empty?).join("\n") + "\n" + indent[ depth ]
end

#lastObject



136
# File 'lib/less/engine/nodes/element.rb', line 136

def last;  elements.last  end

#leaf?Boolean

Returns:

  • (Boolean)


42
43
44
# File 'lib/less/engine/nodes/element.rb', line 42

def leaf?
  elements.empty?
end

#mixinsObject



81
# File 'lib/less/engine/nodes/element.rb', line 81

def mixins;      @rules.select {|r| r.instance_of? Mixin::Call} end

#nearest(ident, type = nil) ⇒ Object

Find the nearest node in the hierarchy or raise a NameError



174
175
176
177
178
179
180
181
# File 'lib/less/engine/nodes/element.rb', line 174

def nearest ident, type = nil
  ary = type || ident =~ /^[.#]/ ? :elements : :variables
  path.map do |node|
    node.send(ary).find {|i| i.to_s == ident }
  end.compact.first.tap do |result|
    raise VariableNameError, ("#{ident} in #{self.to_s}") if result.nil? && type != :mixin
  end
end

#parametersObject



82
# File 'lib/less/engine/nodes/element.rb', line 82

def parameters;  []                                             end

#propertiesObject



78
# File 'lib/less/engine/nodes/element.rb', line 78

def properties;  @rules.select {|r| r.instance_of? Property   } end

#root?Boolean

Top-most node?

Returns:

  • (Boolean)


34
35
36
# File 'lib/less/engine/nodes/element.rb', line 34

def root?
  parent.nil?
end

#tag?Boolean

Returns:

  • (Boolean)


29
30
31
# File 'lib/less/engine/nodes/element.rb', line 29

def tag?
  not id? || class? || universal?
end

#to_css(path = [], env = nil) ⇒ Object

Entry point for the css conversion



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/less/engine/nodes/element.rb', line 143

def to_css path = [], env = nil
  path << @selector.to_css << name unless root?

#       puts "to_css env: #{env ? env.variables : "nil"}"
  content = @rules.select do |r|
    r.is_a?(Mixin::Call) || r.instance_of?(Property)
  end.map do |i|
    ' ' * 2 + i.to_css(env)
  end.compact.reject(&:empty?) * "\n"

  content = content.include?("\n") ? "\n#{content}\n" : " #{content.strip} "

  ruleset = if is_a?(Mixin::Def)
    content.strip
  else
    !content.strip.empty??
      "#{[path.reject(&:empty?).join.strip,
      *@set.map(&:name)].uniq * ', '} {#{content}}\n" : ""
  end

  ruleset + elements.reject {|e| e.is_a?(Mixin::Def) }.map do |i|
    i.to_css(path, env)
  end.reject(&:empty?).join

ensure
  2.times { path.pop }
end

#to_sObject



138
# File 'lib/less/engine/nodes/element.rb', line 138

def to_s; root?? '*' : name end

#universal?Boolean

Returns:

  • (Boolean)


27
# File 'lib/less/engine/nodes/element.rb', line 27

def universal?; name == '*'   end

#variablesObject



79
# File 'lib/less/engine/nodes/element.rb', line 79

def variables;   @rules.select {|r| r.instance_of? Variable   } end