Class: Sasso::Rails::Compiler

Inherits:
Object
  • Object
show all
Defined in:
lib/sasso/rails/compiler.rb

Overview

Compiles configured Sass/SCSS entrypoints to plain CSS files under the builds directory. Deliberately Rails-free so it can be unit-tested with a plain temp ‘root:` — the Engine just wires `Rails.root` and config in.

Sasso::Rails::Compiler.new(
  root:       Rails.root,
  builds:     { "application.scss" => "application.css" },
  style:      :expanded,
  load_paths: [],            # extra dirs, in addition to the source dir
  source_dir: "app/assets/stylesheets",
  build_dir:  "app/assets/builds",
).build

Constant Summary collapse

Error =
Class.new(StandardError)
ALLOWED_STYLES =
%i[expanded compressed].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root:, builds:, style: :expanded, load_paths: [], source_dir: "app/assets/stylesheets", build_dir: "app/assets/builds", source_map: false) ⇒ Compiler

Returns a new instance of Compiler.



28
29
30
31
32
33
34
35
36
37
38
# File 'lib/sasso/rails/compiler.rb', line 28

def initialize(root:, builds:, style: :expanded, load_paths: [],
               source_dir: "app/assets/stylesheets",
               build_dir: "app/assets/builds", source_map: false)
  @root       = File.expand_path(root.to_s)
  @builds     = normalize_builds(builds)
  @style      = normalize_style(style)
  @load_paths = Array(load_paths).map(&:to_s)
  @source_dir = source_dir.to_s
  @build_dir  = build_dir.to_s
  @source_map = source_map ? true : false
end

Instance Attribute Details

#build_dirObject (readonly)

Returns the value of attribute build_dir.



26
27
28
# File 'lib/sasso/rails/compiler.rb', line 26

def build_dir
  @build_dir
end

#buildsObject (readonly)

Returns the value of attribute builds.



26
27
28
# File 'lib/sasso/rails/compiler.rb', line 26

def builds
  @builds
end

#load_pathsObject (readonly)

Returns the value of attribute load_paths.



26
27
28
# File 'lib/sasso/rails/compiler.rb', line 26

def load_paths
  @load_paths
end

#rootObject (readonly)

Returns the value of attribute root.



26
27
28
# File 'lib/sasso/rails/compiler.rb', line 26

def root
  @root
end

#source_dirObject (readonly)

Returns the value of attribute source_dir.



26
27
28
# File 'lib/sasso/rails/compiler.rb', line 26

def source_dir
  @source_dir
end

#source_mapObject (readonly)

Returns the value of attribute source_map.



26
27
28
# File 'lib/sasso/rails/compiler.rb', line 26

def source_map
  @source_map
end

#styleObject (readonly)

Returns the value of attribute style.



26
27
28
# File 'lib/sasso/rails/compiler.rb', line 26

def style
  @style
end

Instance Method Details

#buildObject

Compile every entrypoint; returns the list of written output paths.



41
42
43
# File 'lib/sasso/rails/compiler.rb', line 41

def build
  builds.map { |input, output| build_one(input, output) }
end

#build_one(input, output) ⇒ Object

Compile a single ‘input` (relative to source_dir) to `output` (relative to build_dir), returning the absolute path written.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/sasso/rails/compiler.rb', line 47

def build_one(input, output)
  src = File.join(@root, @source_dir, input)
  unless File.file?(src)
    raise Error, "sasso-rails: input stylesheet not found: #{src}"
  end

  dest = File.join(@root, @build_dir, output)
  FileUtils.mkdir_p(File.dirname(dest))

  # `Sasso.compile` already searches the entry file's own directory first
  # (for sibling @use/@import); pass any extra include dirs after it.
  if @source_map
    result = ::Sasso.compile(src, style: @style, load_paths: @load_paths, source_map: true)
    write_source_map(dest, result.source_map)
    File.write(dest, result.css + source_map_footer(File.basename(dest)))
  else
    File.write(dest, ::Sasso.compile(src, style: @style, load_paths: @load_paths))
  end
  dest
end

#watch(interval: 1.0) ⇒ Object

Recompile whenever a watched source file changes. Dependency-free poll loop (no ‘listen` gem): cheap mtime scan of the source + load_path trees. Blocks. A compile error (including on the FIRST pass) is reported and the loop keeps running — the watcher must survive a mid-edit broken file.



72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/sasso/rails/compiler.rb', line 72

def watch(interval: 1.0)
  safe_build
  snapshot = source_mtimes
  loop do
    sleep interval
    current = source_mtimes
    next if current == snapshot

    snapshot = current
    safe_build
  end
end