Class: Compass::Compiler

Inherits:
Object
  • Object
show all
Includes:
Actions
Defined in:
lib/compass/compiler.rb

Instance Attribute Summary collapse

Attributes included from Actions

#logger

Instance Method Summary collapse

Methods included from Actions

#basename, #copy, #directory, #log_action, #process_erb, #relativize, #remove, #separate, #strip_trailing_separator, #write_file

Constructor Details

#initialize(working_path, from, to, options) ⇒ Compiler

Returns a new instance of Compiler.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/compass/compiler.rb', line 8

def initialize(working_path, from, to, options)
  self.working_path = working_path.to_s
  self.from, self.to = File.expand_path(from), to
  self.logger = options.delete(:logger)
  sass_opts = options.delete(:sass) || {}
  self.options = options
  self.sass_options = options.dup
  self.sass_options.delete(:quiet)
  self.sass_options.update(sass_opts)
  self.sass_options[:cache_location] ||= determine_cache_location
  self.sass_options[:importer] = self.importer = Sass::Importers::Filesystem.new(from)
  self.sass_options[:compass] ||= {}
  self.sass_options[:compass][:logger] = self.logger
  self.sass_options[:compass][:environment] = Compass.configuration.environment
  self.staleness_checker = Sass::Plugin::StalenessChecker.new(sass_options)
end

Instance Attribute Details

#fromObject

Returns the value of attribute from.



6
7
8
# File 'lib/compass/compiler.rb', line 6

def from
  @from
end

#importerObject

Returns the value of attribute importer.



6
7
8
# File 'lib/compass/compiler.rb', line 6

def importer
  @importer
end

#optionsObject

Returns the value of attribute options.



6
7
8
# File 'lib/compass/compiler.rb', line 6

def options
  @options
end

#sass_optionsObject

Returns the value of attribute sass_options.



6
7
8
# File 'lib/compass/compiler.rb', line 6

def sass_options
  @sass_options
end

#staleness_checkerObject

Returns the value of attribute staleness_checker.



6
7
8
# File 'lib/compass/compiler.rb', line 6

def staleness_checker
  @staleness_checker
end

#toObject

Returns the value of attribute to.



6
7
8
# File 'lib/compass/compiler.rb', line 6

def to
  @to
end

#working_pathObject

Returns the value of attribute working_path.



6
7
8
# File 'lib/compass/compiler.rb', line 6

def working_path
  @working_path
end

Instance Method Details

#clean!Object



81
82
83
84
85
86
# File 'lib/compass/compiler.rb', line 81

def clean!
  remove options[:cache_location]
  css_files.each do |css_file|
    remove css_file
  end
end

#compile(sass_filename, css_filename) ⇒ Object

Compile one Sass file



136
137
138
139
140
141
142
143
144
145
# File 'lib/compass/compiler.rb', line 136

def compile(sass_filename, css_filename)
  css_content = logger.red do
    timed do
      engine(sass_filename, css_filename).render
    end
  end
  duration = options[:time] ? "(#{(css_content.__duration * 1000).round / 1000.0}s)" : ""
  write_file(css_filename, css_content, options.merge(:force => true, :extra => duration))
  Compass.configuration.run_stylesheet_saved(css_filename)
end

#compile_if_required(sass_filename, css_filename) ⇒ Object



116
117
118
119
120
121
122
# File 'lib/compass/compiler.rb', line 116

def compile_if_required(sass_filename, css_filename)
  if should_compile?(sass_filename, css_filename)
    compile sass_filename, css_filename
  else
    logger.record :unchanged, basename(sass_filename) unless options[:quiet]
  end
end

#corresponding_css_file(sass_file) ⇒ Object



50
51
52
# File 'lib/compass/compiler.rb', line 50

def corresponding_css_file(sass_file)
  "#{to}/#{stylesheet_name(sass_file)}.css"
end

#css_filesObject



46
47
48
# File 'lib/compass/compiler.rb', line 46

def css_files
  @css_files ||= sass_files.map{|sass_file| corresponding_css_file(sass_file)}
end

#determine_cache_locationObject



25
26
27
# File 'lib/compass/compiler.rb', line 25

def determine_cache_location
  Compass.configuration.cache_path || Sass::Plugin.options[:cache_location] || File.join(working_path, ".sass-cache")
end

#engine(sass_filename, css_filename) ⇒ Object

A sass engine for compiling a single file.



152
153
154
155
156
# File 'lib/compass/compiler.rb', line 152

def engine(sass_filename, css_filename)
  syntax = (sass_filename =~ /\.(s[ac]ss)$/) && $1.to_sym || :sass
  opts = sass_options.merge(:filename => sass_filename, :css_filename => css_filename, :syntax => syntax)
  Sass::Engine.new(File.read(sass_filename), opts)
end

#error_contents(e, sass_filename) ⇒ Object

Haml refactored this logic in 2.3, this is backwards compatibility for either one



172
173
174
175
176
177
178
179
180
# File 'lib/compass/compiler.rb', line 172

def error_contents(e, sass_filename)
  if Sass::SyntaxError.respond_to?(:exception_to_css)
    e.sass_template = sass_filename
    Sass::SyntaxError.exception_to_css(e, :full_exception => show_full_exception?)
  else
    Sass::Plugin.options[:full_exception] ||= show_full_exception?
    Sass::Plugin.send(:exception_string, e)
  end
end

#handle_exception(sass_filename, css_filename, e) ⇒ Object

Place the syntax error into the target css file, formatted to display in the browser (in development mode) if there’s an error.



161
162
163
164
165
166
167
168
169
# File 'lib/compass/compiler.rb', line 161

def handle_exception(sass_filename, css_filename, e)
  exception_file = basename(e.sass_filename)
  file = basename(sass_filename)
  exception_file = nil if exception_file == file
  formatted_error = "(Line #{e.sass_line}#{ " of #{exception_file}" if exception_file}: #{e.message})"
  logger.record :error, file, formatted_error
  Compass.configuration.run_stylesheet_error(sass_filename, formatted_error)
  write_file css_filename, error_contents(e, sass_filename), options.merge(:force => true)
end

#needs_update?(css_filename, sass_filename) ⇒ Boolean

Returns:

  • (Boolean)


66
67
68
# File 'lib/compass/compiler.rb', line 66

def needs_update?(css_filename, sass_filename)
  staleness_checker.stylesheet_needs_update?(css_filename, File.expand_path(sass_filename), importer)
end

#new_config?Boolean

Determines if the configuration file is newer than any css file

Returns:

  • (Boolean)


71
72
73
74
75
76
77
78
79
# File 'lib/compass/compiler.rb', line 71

def new_config?
  config_file = Compass.detect_configuration_file
  return false unless config_file
  config_mtime = File.mtime(config_file)
  css_files.each do |css_filename|
    return config_file if File.exists?(css_filename) && config_mtime > File.mtime(css_filename)
  end
  nil
end

#out_of_date?Boolean

Returns the sass file that needs to be compiled, if any.

Returns:

  • (Boolean)


59
60
61
62
63
64
# File 'lib/compass/compiler.rb', line 59

def out_of_date?
  sass_files.zip(css_files).each do |sass_filename, css_filename|
    return sass_filename if needs_update?(css_filename, sass_filename)
  end
  false
end

#relative_stylesheet_name(sass_file) ⇒ Object



34
35
36
# File 'lib/compass/compiler.rb', line 34

def relative_stylesheet_name(sass_file)
  sass_file[(from.length + 1)..-1]
end

#runObject



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
# File 'lib/compass/compiler.rb', line 88

def run
  failure_count = 0
  if new_config?
    # Wipe out the cache and force compilation if the configuration has changed.
    remove options[:cache_location] if options[:cache_location]
    options[:force] = true
  end

  # Make sure the target directories exist
  target_directories.each {|dir| directory dir}

  # Compile each sass file.
  result = timed do
    sass_files.zip(css_files).each do |sass_filename, css_filename|
      begin
        compile_if_required sass_filename, css_filename
      rescue Sass::SyntaxError => e
        failure_count += 1
        handle_exception(sass_filename, css_filename, e)
      end
    end
  end
  if options[:time]
    puts "Compilation took #{(result.__duration * 1000).round / 1000.0}s"
  end
  return failure_count
end

#sass_files(options = {}) ⇒ Object



29
30
31
32
# File 'lib/compass/compiler.rb', line 29

def sass_files(options = {})
  exclude_partials = options.fetch(:exclude_partials, true)
  @sass_files = self.options[:sass_files] || Dir.glob(separate("#{from}/**/#{'[^_]' if exclude_partials}*.s[ac]ss"))
end

#should_compile?(sass_filename, css_filename) ⇒ Boolean

Returns:

  • (Boolean)


147
148
149
# File 'lib/compass/compiler.rb', line 147

def should_compile?(sass_filename, css_filename)
  options[:force] || needs_update?(css_filename, sass_filename)
end

#show_full_exception?Boolean

We don’t want to show the full exception in production environments.

Returns:

  • (Boolean)


183
184
185
# File 'lib/compass/compiler.rb', line 183

def show_full_exception?
  Compass.configuration.environment == :development
end

#stylesheet_name(sass_file) ⇒ Object



38
39
40
41
42
43
44
# File 'lib/compass/compiler.rb', line 38

def stylesheet_name(sass_file)
  if sass_file.index(from) == 0
    sass_file[(from.length + 1)..-6].sub(/\.css$/,'')
  else
    raise Compass::Error, "You must compile individual stylesheets from the project directory."
  end
end

#target_directoriesObject



54
55
56
# File 'lib/compass/compiler.rb', line 54

def target_directories
  css_files.map{|css_file| File.dirname(css_file)}.uniq.sort.sort_by{|d| d.length }
end

#timedObject



124
125
126
127
128
129
130
131
132
133
# File 'lib/compass/compiler.rb', line 124

def timed
  start_time = Time.now
  res = yield
  end_time = Time.now
  res.instance_variable_set("@__duration", end_time - start_time)
  def res.__duration
    @__duration
  end
  res
end