Class: Sass::Tree::Visitors::Convert

Inherits:
Base
  • Object
show all
Defined in:
lib/sass/tree/visitors/convert.rb

Overview

A visitor for converting a Sass tree into a source string.

Constant Summary

Constants inherited from Base

Base::NODE_NAME_RE

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#node_name, #visit

Constructor Details

#initialize(options, format) ⇒ Convert (protected)

Returns a new instance of Convert.



15
16
17
18
19
# File 'lib/sass/tree/visitors/convert.rb', line 15

def initialize(options, format)
  @options = options
  @format = format
  @tabs = 0
end

Class Method Details

.visit(root, options, format) ⇒ String

Runs the visitor on a tree.

Parameters:

  • root (Tree::Node)

    The root node of the Sass tree.

  • options ({Symbol => Object})

    An options hash (see CSS#initialize).

  • format (Symbol)

    :sass or :scss.

Returns:

  • (String)

    The Sass or SCSS source for the tree.



9
10
11
# File 'lib/sass/tree/visitors/convert.rb', line 9

def self.visit(root, options, format)
  new(options, format).send(:visit, root)
end

Instance Method Details

#visit_charset(node) (protected)



47
48
49
# File 'lib/sass/tree/visitors/convert.rb', line 47

def visit_charset(node)
  "#{tab_str}@charset \"#{node.name}\"#{semi}\n"
end

#visit_children(parent) (protected)



21
22
23
24
25
26
27
# File 'lib/sass/tree/visitors/convert.rb', line 21

def visit_children(parent)
  @tabs += 1
  return @format == :sass ? "\n" : " {}\n" if parent.children.empty?
  (@format == :sass ? "\n" : " {\n") + super.join.rstrip + (@format == :sass ? "\n" : " }\n")
ensure
  @tabs -= 1
end

#visit_comment(node) (protected)



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
# File 'lib/sass/tree/visitors/convert.rb', line 51

def visit_comment(node)
  value = node.value.map do |r|
    next r if r.is_a?(String)
    "\#{#{r.to_sass(@options)}}"
  end.join

  content = if @format == :sass
    content = value.gsub(/\*\/$/, '').rstrip
    if content =~ /\A[ \t]/
      # Re-indent SCSS comments like this:
      #     /* foo
      #   bar
      #       baz */
      content.gsub!(/^/, '   ')
      content.sub!(/\A([ \t]*)\/\*/, '/*\1')
    end

    content =
      unless content.include?("\n")
        content
      else
        content.gsub!(/\n( \*|\/\/)/, "\n  ")
        spaces = content.scan(/\n( *)/).map {|s| s.first.size}.min
        sep = node.silent ? "\n//" : "\n *"
        if spaces >= 2
          content.gsub(/\n  /, sep)
        else
          content.gsub(/\n#{' ' * spaces}/, sep)
        end
      end

    content.gsub!(/\A\/\*/, '//') if node.silent
    content.gsub!(/^/, tab_str)
    content.rstrip + "\n"
  else
    spaces = ('  ' * [@tabs - value[/^ */].size, 0].max)
    content = if node.silent
      value.gsub(/^[\/ ]\*/, '//').gsub(/ *\*\/$/, '')
    else
      value
    end.gsub(/^/, spaces) + "\n"
    content
  end
  if node.loud
    if node.silent
      content.gsub!(%r{^\s*(//!?)}, '//!')
    else
      content.sub!(%r{^\s*(/\*)}, '/*!')
    end
  end
  content
end

#visit_debug(node) (protected)



104
105
106
# File 'lib/sass/tree/visitors/convert.rb', line 104

def visit_debug(node)
  "#{tab_str}@debug #{node.expr.to_sass(@options)}#{semi}\n"
end

#visit_directive(node) (protected)



108
109
110
111
112
# File 'lib/sass/tree/visitors/convert.rb', line 108

def visit_directive(node)
  res = "#{tab_str}#{node.value}"
  return res + "#{semi}\n" unless node.has_children
  res + yield + "\n"
end

#visit_each(node) (protected)



114
115
116
# File 'lib/sass/tree/visitors/convert.rb', line 114

def visit_each(node)
  "#{tab_str}@each $#{dasherize(node.var)} in #{node.list.to_sass(@options)}#{yield}"
end

#visit_extend(node) (protected)



118
119
120
# File 'lib/sass/tree/visitors/convert.rb', line 118

def visit_extend(node)
  "#{tab_str}@extend #{selector_to_src(node.selector).lstrip}#{semi}\n"
end

#visit_for(node) (protected)



122
123
124
125
# File 'lib/sass/tree/visitors/convert.rb', line 122

def visit_for(node)
  "#{tab_str}@for $#{dasherize(node.var)} from #{node.from.to_sass(@options)} " +
    "#{node.exclusive ? "to" : "through"} #{node.to.to_sass(@options)}#{yield}"
end

#visit_function(node) (protected)



127
128
129
130
131
132
133
# File 'lib/sass/tree/visitors/convert.rb', line 127

def visit_function(node)
  args = node.args.map do |v, d|
    d ? "#{v.to_sass(@options)}: #{d.to_sass(@options)}" : v.to_sass(@options)
  end.join(", ")

  "#{tab_str}@function #{dasherize(node.name)}(#{args})#{yield}"
end

#visit_if(node) (protected)



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/sass/tree/visitors/convert.rb', line 135

def visit_if(node)
  name =
    if !@is_else; "if"
    elsif node.expr; "else if"
    else; "else"
    end
  str = "#{tab_str}@#{name}"
  str << " #{node.expr.to_sass(@options)}" if node.expr
  str << yield
  @is_else = true
  str << visit(node.else) if node.else
  str
ensure
  @is_else = false
end

#visit_import(node) (protected)



151
152
153
154
# File 'lib/sass/tree/visitors/convert.rb', line 151

def visit_import(node)
  quote = @format == :scss ? '"' : ''
  "#{tab_str}@import #{quote}#{node.imported_filename}#{quote}#{semi}\n"
end

#visit_media(node) (protected)



156
157
158
# File 'lib/sass/tree/visitors/convert.rb', line 156

def visit_media(node)
  "#{tab_str}@media #{node.query.join(', ')}#{yield}"
end

#visit_mixin(node) (protected)



177
178
179
180
181
182
183
184
# File 'lib/sass/tree/visitors/convert.rb', line 177

def visit_mixin(node)
  unless node.args.empty? && node.keywords.empty?
    args = node.args.map {|a| a.to_sass(@options)}.join(", ")
    keywords = node.keywords.map {|k, v| "$#{dasherize(k)}: #{v.to_sass(@options)}"}.join(', ')
    arglist = "(#{args}#{', ' unless args.empty? || keywords.empty?}#{keywords})"
  end
  "#{tab_str}#{@format == :sass ? '+' : '@include '}#{dasherize(node.name)}#{arglist}#{semi}\n"
end

#visit_mixindef(node) (protected)



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/sass/tree/visitors/convert.rb', line 160

def visit_mixindef(node)
  args =
    if node.args.empty?
      ""
    else
      '(' + node.args.map do |v, d|
        if d
          "#{v.to_sass(@options)}: #{d.to_sass(@options)}"
        else
          v.to_sass(@options)
        end
      end.join(", ") + ')'
    end
        
  "#{tab_str}#{@format == :sass ? '=' : '@mixin '}#{dasherize(node.name)}#{args}#{yield}"
end

#visit_prop(node) (protected)



186
187
188
189
190
# File 'lib/sass/tree/visitors/convert.rb', line 186

def visit_prop(node)
  res = tab_str + node.declaration(@options, @format)
  return res + semi + "\n" if node.children.empty?
  res + yield.rstrip + semi + "\n"
end

#visit_return(node) (protected)



192
193
194
# File 'lib/sass/tree/visitors/convert.rb', line 192

def visit_return(node)
  "#{tab_str}@return #{node.expr.to_sass(@options)}#{semi}\n"
end

#visit_root(node) (protected)

Ensures proper spacing between top-level nodes.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/sass/tree/visitors/convert.rb', line 30

def visit_root(node)
  Sass::Util.enum_cons(node.children + [nil], 2).map do |child, nxt|
    visit(child) +
      if nxt &&
          (child.is_a?(Sass::Tree::CommentNode) &&
            child.line + child.lines + 1 == nxt.line) ||
          (child.is_a?(Sass::Tree::ImportNode) && nxt.is_a?(Sass::Tree::ImportNode) &&
            child.line + 1 == nxt.line) ||
          (child.is_a?(Sass::Tree::VariableNode) && nxt.is_a?(Sass::Tree::VariableNode) &&
            child.line + 1 == nxt.line)
        ""
      else
        "\n"
      end
  end.join.rstrip + "\n"
end

#visit_rule(node) (protected)



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/sass/tree/visitors/convert.rb', line 196

def visit_rule(node)
  if @format == :sass
    name = selector_to_sass(node.rule)
    name = "\\" + name if name[0] == ?:
    name.gsub(/^/, tab_str) + yield
  elsif @format == :scss
    name = selector_to_scss(node.rule)
    res = name + yield
    if node.children.last.is_a?(Sass::Tree::CommentNode) && node.children.last.silent
      res.slice!(-3..-1)
      res << "\n" << tab_str << "}\n"
    end
    res
  end
end

#visit_variable(node) (protected)



212
213
214
# File 'lib/sass/tree/visitors/convert.rb', line 212

def visit_variable(node)
  "#{tab_str}$#{dasherize(node.name)}: #{node.expr.to_sass(@options)}#{' !default' if node.guarded}#{semi}\n"
end

#visit_warn(node) (protected)



216
217
218
# File 'lib/sass/tree/visitors/convert.rb', line 216

def visit_warn(node)
  "#{tab_str}@warn #{node.expr.to_sass(@options)}#{semi}\n"
end

#visit_while(node) (protected)



220
221
222
# File 'lib/sass/tree/visitors/convert.rb', line 220

def visit_while(node)
  "#{tab_str}@while #{node.expr.to_sass(@options)}#{yield}"
end