Class: Sinatra::AssetPack::Options

Inherits:
Object
  • Object
show all
Includes:
Builder, Configurator
Defined in:
lib/sinatra/assetpack/options.rb

Overview

Assets.

Common usage

SinatraApp.assets {
  # dsl stuff here
}

a = SinatraApp.assets

Getting options:

a.js_compression
a.output_path

Served:

a.served         # { '/js' => '/var/www/project/app/js', ... }
                 # (URL path => local path)

Packages:

a.packages       # { 'app.css' => #<Package>, ... }
                 # (name.type => package instance)

Build:

a.build! { |path| puts "Building #{path}" }
a.build_packages! { |path| puts "Building package #{path}" }
a.build_files! { |path| puts "Building files #{path}" }

Lookup:

a.local_path_for('/images/bg.gif')
a.served?('/images/bg.gif')

a.glob(['/js/*.js', '/js/vendor/**/*.js'])
# Returns a HashArray of (local => remote)

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Configurator

included

Methods included from Builder

#build!, #build_files!, #build_packages!

Constructor Details

#initialize(app, &blk) ⇒ Options

Returns a new instance of Options.



46
47
48
49
50
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
# File 'lib/sinatra/assetpack/options.rb', line 46

def initialize(app, &blk)
  unless app.root?
    raise Error, "Please set :root in your Sinatra app."
  end

  @app             = app
  @js_compression  = :jsmin
  @css_compression = :simple
  @reload_files_cache = true

  begin
    @output_path   = app.public
  rescue NoMethodError
    @output_path   = app.public_folder
  end

  @js_compression_options  = Hash.new
  @css_compression_options = Hash.new
  @dynamic_asset_cache     = Hash.new

  @ignored = Array.new

  reset!

  # Defaults!
  serve '/css',    :from => 'app/css'     rescue Errno::ENOTDIR
  serve '/js',     :from => 'app/js'      rescue Errno::ENOTDIR
  serve '/images', :from => 'app/images'  rescue Errno::ENOTDIR

  ignore '.*'
  ignore '_*'

  blk.arity <= 0 ? instance_eval(&blk) : yield(self)  if block_given?
end

Instance Attribute Details

#appObject (readonly)

Sinatra::Base instance



162
163
164
# File 'lib/sinatra/assetpack/options.rb', line 162

def app
  @app
end

#packagesObject (readonly)

Hash, keys are “foo.js”, values are Packages



163
164
165
# File 'lib/sinatra/assetpack/options.rb', line 163

def packages
  @packages
end

#servedObject (readonly)

Stuff



201
202
203
# File 'lib/sinatra/assetpack/options.rb', line 201

def served
  @served
end

Instance Method Details

#cache!(&blk) ⇒ Object

Caches the packages.



204
205
206
207
208
209
210
211
212
# File 'lib/sinatra/assetpack/options.rb', line 204

def cache!(&blk)
  return if app.reload_templates

  session = Rack::Test::Session.new app
  packages.each { |_, pack|
    yield pack.path if block_given?
    session.get(pack.path)
  }
end

#clear_ignores!Object

Makes nothing ignored. Use this if you don’t want to ignore dotfiles and underscore files.



118
119
120
# File 'lib/sinatra/assetpack/options.rb', line 118

def clear_ignores!
  @ignored  = Array.new
end

#css(name, *args) ⇒ Object

Adds some CSS packages.

css :app, [ '/css/screen.css', ... ]
css :app, '/css/app.css', [ '/css/screen.css', ... ]


141
142
143
# File 'lib/sinatra/assetpack/options.rb', line 141

def css(name, *args) #path, files=[])
  js_or_css :css, name, *args
end

#css_compression(name = nil, options = nil) ⇒ Object



192
193
194
195
196
# File 'lib/sinatra/assetpack/options.rb', line 192

def css_compression(name=nil, options=nil)
  @css_compression = name unless name.nil?
  @css_compression_options = options if options.is_a?(Hash)
  @css_compression
end

#dyn_local_file_for(request, from) ⇒ Object

Returns the local file for a given URI path. (for dynamic files) Returns nil if a file is not found.



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/sinatra/assetpack/options.rb', line 234

def dyn_local_file_for(request, from)
  file = request.dup
  extension = File.extname(request)
  # Remove extension
  file.gsub!(/#{extension}$/, "")
  # Remove cache-buster (/js/app.28389 => /js/app)
  file.gsub!(/\.[a-f0-9]{32}$/, "")

  matches = Dir[File.join(expand_from(from), "#{file}.*")]

  # Fix for filenames with dots (can't do this with glob)
  matches = matches.select { |f| f =~ /#{file}\.[^.]+$/ }

  # Sort static file match, weighting exact file extension matches
  # first, then registered Tilt formats
  matches.sort! do |candidate, _|
    cfmt = File.extname(candidate)[1..-1]
    efmt = extension[1..-1]
    (cfmt == efmt or AssetPack.tilt_formats[cfmt] == efmt) ? -1 : 1
  end
  matches.first
end

#expires(*args) ⇒ Object



178
179
180
181
182
183
184
# File 'lib/sinatra/assetpack/options.rb', line 178

def expires(*args)
  if args.empty?
    @expires
  else
    @expires = args
  end
end

#fetch_dynamic_asset(path) ⇒ Object

Fetches the contents of a dynamic asset. If ‘cache_dynamic_assets` is set, check file mtime and potentially return contents from cache instead of re-compiling. Yields to a block to compile & render the asset.



301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/sinatra/assetpack/options.rb', line 301

def fetch_dynamic_asset(path)
  return yield unless cache_dynamic_assets

  mtime = File.mtime(path)
  cached_mtime, contents = @dynamic_asset_cache[path]

  if cached_mtime.nil? || mtime != cached_mtime
    @dynamic_asset_cache[path] = [mtime, yield]
    @dynamic_asset_cache[path][1]
  else
    contents
  end
end

#files(match = nil) ⇒ Object

Returns the files as a hash.



258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'lib/sinatra/assetpack/options.rb', line 258

def files(match=nil)
  return @files unless @reload_files_cache

  # All
  # A buncha tuples
  tuples = @served.map { |prefix, local_path|
    path = File.expand_path(File.join(@app.root, local_path))
    spec = File.join(path, '**', '*')

    Dir[spec].map { |f|
      [ to_uri(f, prefix, path), f ]  unless File.directory?(f)
    }
  }.flatten.compact

  @reload_files_cache = false
  @files = Hash[*tuples]
end

#glob(match) ⇒ Object

Returns an array of URI paths of those matching given globs.

glob('spec')
glob(['spec1', 'spec2' ...])


281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/sinatra/assetpack/options.rb', line 281

def glob(match)
  paths = Array.new(match) # Force array-ness

  paths.map! do |spec|
    if spec.include?('*')
      files.select do |file, _|
        # Dir#glob like source matching
        File.fnmatch?(spec, file, File::FNM_PATHNAME | File::FNM_DOTMATCH)
      end.sort
    else
      [spec, files[spec]]
    end
  end

  Hash[*paths.flatten]
end

#ignore(spec) ⇒ Object

Ignores a given path spec.



107
108
109
110
111
112
113
114
115
# File 'lib/sinatra/assetpack/options.rb', line 107

def ignore(spec)
  if spec[0] == '/'
    @ignored << "#{spec}"
    @ignored << "#{spec}/**"
  else
    @ignored << "**/#{spec}"
    @ignored << "**/#{spec}/**"
  end
end

#ignored?(fn) ⇒ Boolean

Checks if a given path is ignored.

Returns:

  • (Boolean)


123
124
125
# File 'lib/sinatra/assetpack/options.rb', line 123

def ignored?(fn)
  @ignored.any? { |spec| File.fnmatch spec, fn }
end

#js(name, *args) ⇒ Object

Adds some JS packages.

js :foo, [ '/js/vendor/jquery.*.js', ... ]
js :foo, '/js/foo.js', [ '/js/vendor/jquery.*.js', ... ]


132
133
134
# File 'lib/sinatra/assetpack/options.rb', line 132

def js(name, *args)
  js_or_css :js, name, *args
end

#js_compression(name = nil, options = nil) ⇒ Object



186
187
188
189
190
# File 'lib/sinatra/assetpack/options.rb', line 186

def js_compression(name=nil, options=nil)
  @js_compression = name unless name.nil?
  @js_compression_options = options if options.is_a?(Hash)
  @js_compression
end

#js_or_css(type, name, *args) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/sinatra/assetpack/options.rb', line 145

def js_or_css(type, name, *args)
  # Account for "css :name, '/path/to/css', [ files ]"
  if args[0].is_a?(String) && args[1].respond_to?(:each)
    path, files = args

  # Account for "css :name, [ files ]"
  elsif args[0].respond_to?(:each)
    path  = "/assets/#{name}.#{type}" # /assets/foobar.css by default
    files = args[0]

  else
    raise ArgumentError
  end

  @packages["#{name}.#{type}"] = Package.new(self, name, type, path, files)
end

#local_file_for(request) ⇒ Object

Returns the local file for a given URI path. Returns nil if a file is not found.



220
221
222
223
224
225
226
227
228
229
230
# File 'lib/sinatra/assetpack/options.rb', line 220

def local_file_for(request)
  request = request.squeeze('/')
  serve_path, from = served.detect { |path, _| request.start_with?(path) }

  return if !from

  path = File.join(expand_from(from), request.sub(serve_path, ''))
  return if !File.file?(path)

  path
end

#reset!Object

Undo defaults.



100
101
102
103
104
# File 'lib/sinatra/assetpack/options.rb', line 100

def reset!
  @served   = Hash.new
  @packages = Hash.new
  @reload_files_cache = true
end

#serve(path, options = {}) ⇒ Object

DSL methods



84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/sinatra/assetpack/options.rb', line 84

def serve(path, options={})
  unless from = options[:from]
    raise ArgumentError, "Parameter :from is required" 
  end

  expanded = expand_from(from)

  unless File.directory? expanded
    raise Errno::ENOTDIR, expanded
  end

  @served[path] = from
  @reload_files_cache = true
end

#served?(path) ⇒ Boolean

Returns:

  • (Boolean)


214
215
216
# File 'lib/sinatra/assetpack/options.rb', line 214

def served?(path)
  !! local_file_for(path)
end