Class: Palimpsest::Assets

Inherits:
Object
  • Object
show all
Defined in:
lib/palimpsest/assets.rb

Overview

Flexible asset pipeline using Sprockets. Paths are loaded into a Sprockets::Environment (relative to #directory if given). Asset tags are used in source code and replaced with generated asset path or compiled source if inline is used.

For example, if type is set to :javascripts the following replacements would be made:

[% javascript app %] -> app-9413c7f112033f0c6f2a8e8dd313399c18d93878.js
[% javascript lib/jquery %] -> lib/jquery-e2a8cde3f5b3cdb011e38a673556c7a94729e0d1.js
[% javascript inline tracking %] -> <compiled source of tracking.js asset>

Constant Summary collapse

DEFAULT_OPTIONS =

Default #options.

{
  # default path to output all saved assets (relative to directory)
  output: '',

  # assume assets will be served under this url
  # e.g. `https://cdn.example.com/`
  cdn: '',

  # keyword to use in asset tag for inline assets
  inline: 'inline',

  # if true, use sprockets-image_compressor with pngcrush and jpegoptim
  image_compression: false,

  # if true, also generate a gzipped asset
  gzip: false,

  # include hash in asset name
  hash: true,

  # opening and closing brackets for asset source tags
  src_pre: '[%',
  src_post: '%]',

  # allowed options for `Sprockets::Environment`
  sprockets_options: [:js_compressor, :css_compressor]
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(directory: '', options: {}, paths: {}) ⇒ Assets

Returns a new instance of Assets.



59
60
61
62
63
# File 'lib/palimpsest/assets.rb', line 59

def initialize directory: '', options: {}, paths: {}
  self.options options
  self.directory = directory
  self.paths = paths
end

Instance Attribute Details

#directoryString

Returns directory which all paths will be relative to if set.

Returns:

  • (String)

    directory which all paths will be relative to if set



57
58
59
# File 'lib/palimpsest/assets.rb', line 57

def directory
  @directory
end

#pathsArray

Returns paths to load into sprockets environment.

Returns:

  • (Array)

    paths to load into sprockets environment



57
# File 'lib/palimpsest/assets.rb', line 57

attr_accessor :directory, :paths, :type

#typeSymbol

Returns type of asset.

Returns:

  • (Symbol)

    type of asset



57
# File 'lib/palimpsest/assets.rb', line 57

attr_accessor :directory, :paths, :type

Class Method Details

.find_tags(path, type = nil, options = {}) ⇒ Object

Scans all non-binary files under path for asset tags. (see #find_tags)

Parameters:

  • path (String)

    where to look for source files

  • type (String, nil) (defaults to: nil)

    only look for asset tags with this type (or any type if nil)

  • options (Hash) (defaults to: {})

    merged with DEFAULT_OPTIONS



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/palimpsest/assets.rb', line 175

def self.find_tags path, type=nil, options={}
  fail ArgumentError, 'path cannot be empty' if path.empty?

  options = DEFAULT_OPTIONS.merge options
  pre = Regexp.escape options[:src_pre]
  post= Regexp.escape options[:src_post]

  cmd = ['grep']
  cmd.concat %w(-l -I -r -E)
  cmd <<
    if type.nil?
      pre + '(.*?)' + post
    else
      pre + '\s+' + type.to_s + '\s+(.*?)' + post
    end
  cmd << path

  files = []
  Open3.capture2(*cmd).first.each_line { |l| files << l.chomp unless l.empty? }
  files
end

Instance Method Details

#assetsSprockets::Environment

Returns sprockets environment with #options and #paths loaded.

Returns:

  • (Sprockets::Environment)

    sprockets environment with #options and #paths loaded



102
103
104
105
106
107
108
109
# File 'lib/palimpsest/assets.rb', line 102

def assets
  unless @loaded
    load_options
    load_paths
  end
  @loaded = true
  sprockets
end

#find_tags(path: directory) ⇒ Array

Scans all non-binary files under path (#directory by default) for asset tags. Uses current asset #type (if set) and #options.

Parameters:

  • path (String) (defaults to: directory)

    where to look for source files

Returns:

  • (Array)

    files with asset tags



166
167
168
# File 'lib/palimpsest/assets.rb', line 166

def find_tags path: directory
  self.class.find_tags path, type, options
end

#load_optionsObject

Load options into the sprockets environment. Values are loaded from #options.



80
81
82
83
84
85
86
87
88
89
90
# File 'lib/palimpsest/assets.rb', line 80

def load_options
  options[:sprockets_options].each do |opt|
    sprockets.send "#{opt}=".to_sym, options[opt] if options[opt]
  end

  if options[:image_compression]
    Sprockets::ImageCompressor::Integration.setup sprockets
  end

  self
end

#load_pathsObject

Load paths into the sprockets environment. Values are loaded from #paths.



94
95
96
97
98
99
# File 'lib/palimpsest/assets.rb', line 94

def load_paths
  paths.each do |path|
    sprockets.append_path "#{directory + '/' unless directory.empty?}#{path}"
  end
  self
end

#options(options = {}) ⇒ Hash

Uses DEFAULT_OPTIONS as initial value.

Parameters:

  • options (Hash) (defaults to: {})

    merged with current options

Returns:

  • (Hash)

    current options



68
69
70
71
# File 'lib/palimpsest/assets.rb', line 68

def options options={}
  @options ||= DEFAULT_OPTIONS
  @options = @options.merge options
end

#sprocketsSprockets::Environment

Returns the current sprockets environment.

Returns:

  • (Sprockets::Environment)

    the current sprockets environment



74
75
76
# File 'lib/palimpsest/assets.rb', line 74

def sprockets
  @sprockets ||= Sprockets::Environment.new
end

#update_source(source) ⇒ String

Replaces all asset tags in source string with asset path or asset source. Writes any referenced assets to disk.

Parameters:

  • source (String)

    code to find and replace asset tags

Returns:

  • (String)

    copy of source with asset tags replaced



156
157
158
159
160
# File 'lib/palimpsest/assets.rb', line 156

def update_source source
  s = source
  update_source! s
  s
end

#update_source!(source) ⇒ String

Note:

this modifies the source String in place

Replaces all asset tags in source string with asset path or asset source. Writes any referenced assets to disk.

Parameters:

  • source (String)

    code to find and replace asset tags

Returns:

  • (String)

    copy of source with asset tags replaced



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/palimpsest/assets.rb', line 134

def update_source! source
  # e.g. /\[%\s+javascript\s+((\S+)\s?(\S+))\s+%\]/
  regex = /#{Regexp.escape options[:src_pre]}\s+#{type.to_s.singularize}\s+((\S+)\s?(\S+))\s+#{Regexp.escape options[:src_post]}/
  source.gsub! regex do
    if $2 == options[:inline]
      assets[$3].to_s
    else
      asset = write $1

      # @todo raise warning or error if asset not found
      p "asset not found: #{$1}" and next if asset.nil?

      options[:cdn].empty? ? asset : options[:cdn] + asset
    end
  end
  return true
end

#write(target, gzip: , hash: ) ⇒ String?

Write a target asset to file with a hashed name.

Parameters:

  • target (String)

    logical path to asset

  • gzip (Boolean) (defaults to: )

    if the asset should be gzipped

  • hash (Boolean) (defaults to: )

    if the asset name should include the hash

Returns:

  • (String, nil)

    the relative path to the written asset or nil if no such asset



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/palimpsest/assets.rb', line 116

def write target, gzip: options[:gzip], hash: options[:hash]
  asset = assets[target]

  return if asset.nil?

  name = hash ? asset.digest_path : asset.logical_path.to_s
  name = "#{options[:output]}/#{name}" unless options[:output].empty?

  path = directory.empty? ? '' : "#{directory}/"
  path << name

  asset.write_to "#{path}.gz", compress: true if gzip
  asset.write_to path
  name
end