Class: Pinion::Server
- Inherits:
-
Object
- Object
- Pinion::Server
- Defined in:
- lib/pinion/server.rb
Instance Attribute Summary collapse
-
#mount_point ⇒ Object
readonly
Returns the value of attribute mount_point.
Instance Method Summary collapse
- #asset_inline(path) ⇒ Object
-
#asset_url(path) ⇒ Object
Helper methods for an application to generate urls (with fingerprints in production).
-
#bundle_url(name) ⇒ Object
Return the bundle url.
-
#call(env) ⇒ Object
Boilerplate mostly stolen from sprockets github.com/sstephenson/sprockets/blob/master/lib/sprockets/server.rb.
- #convert(from_and_to, &block) ⇒ Object
-
#create_bundle(name, bundle_name, paths) ⇒ Object
Create a bundle of assets.
- #css_bundle(name) ⇒ Object
- #css_inline(path) ⇒ Object
- #css_url(path) ⇒ Object
-
#initialize(mount_point) ⇒ Server
constructor
A new instance of Server.
- #js_bundle(name) ⇒ Object
- #js_inline(path) ⇒ Object
- #js_url(path) ⇒ Object
- #watch(path) ⇒ Object
Constructor Details
#initialize(mount_point) ⇒ Server
Returns a new instance of Server.
13 14 15 |
# File 'lib/pinion/server.rb', line 13 def initialize(mount_point) @mount_point = mount_point end |
Instance Attribute Details
#mount_point ⇒ Object (readonly)
Returns the value of attribute mount_point.
11 12 13 |
# File 'lib/pinion/server.rb', line 11 def mount_point @mount_point end |
Instance Method Details
#asset_inline(path) ⇒ Object
128 |
# File 'lib/pinion/server.rb', line 128 def asset_inline(path) Asset[path].contents end |
#asset_url(path) ⇒ Object
Helper methods for an application to generate urls (with fingerprints in production)
112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/pinion/server.rb', line 112 def asset_url(path) path.sub!(%r[^(#{@mount_point})?/?], "") mounted_path = "#{@mount_point}/#{path}" return mounted_path unless Pinion.environment == "production" # Add on a checksum tag in production asset = Asset[path] raise "Error: no such asset available: #{path}" unless asset mounted_path, dot, extension = mounted_path.rpartition(".") return mounted_path if dot.empty? "#{mounted_path}-#{asset.checksum}.#{extension}" end |
#bundle_url(name) ⇒ Object
Return the bundle url. In production, the single bundled result is produced; otherwise, each individual asset_url is returned.
148 149 150 151 152 153 |
# File 'lib/pinion/server.rb', line 148 def bundle_url(name) bundle = Bundle[name] raise "No such bundle: #{name}" unless bundle return bundle.paths.map { |p| asset_url(p) } unless Pinion.environment == "production" ["#{@mount_point}/#{bundle.name}-#{bundle.checksum}.#{bundle.extension}"] end |
#call(env) ⇒ Object
Boilerplate mostly stolen from sprockets github.com/sstephenson/sprockets/blob/master/lib/sprockets/server.rb
45 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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/pinion/server.rb', line 45 def call(env) # Avoid modifying the session state, don't set cookies, etc env["rack.session.options"] ||= {} env["rack.session.options"].merge! :defer => true, :skip => true root = env["SCRIPT_NAME"] path = Rack::Utils.unescape(env["PATH_INFO"].to_s).sub(%r[^/], "") if path.include? ".." return [403, { "Content-Type" => "text/plain", "Content-Length" => "9" }, ["Forbidden"]] end # Pull out the md5sum if it's part of the given path # e.g. foo/bar-a95c53a7a0f5f492a74499e70578d150.js -> a95c53a7a0f5f492a74499e70578d150 checksum_tag = bundle_name = nil matches = path.match /([^\/]+)-([\da-f]{32})\..+$/ if matches && matches.size == 3 bundle_name = matches[1] checksum_tag = matches[2] path.sub!("-#{checksum_tag}", "") end # First see if there is a bundle with this name asset = Bundle[bundle_name] if asset # If the checksum doesn't match the bundle, we want to return a 404. asset = nil unless asset.checksum == checksum_tag else # If there is no bundle with this name, find another type of Asset with the name instead. asset = Asset[path] end if asset # If the ETag matches, give a 304 return [304, {}, []] if env["HTTP_IF_NONE_MATCH"] == %Q["#{asset.checksum}"] if Pinion.environment == "production" # In production, if there is a checksum, cache for a year (because if the asset changes with a # redeploy, the checksum will change). If there is no checksum, cache for 10 minutes (this way at # worst we only serve 10 minute stale assets, and caches in front of Pinion will be able to help # out). cache_policy = checksum_tag ? "max-age=31536000" : "max-age=600" else # Don't cache in dev. cache_policy = "must-revalidate" end headers = { "Content-Type" => asset.content_type, "Content-Length" => asset.length.to_s, "ETag" => %Q["#{asset.checksum}"], "Cache-Control" => "public, #{cache_policy}", "Last-Modified" => asset.mtime.httpdate, } body = env["REQUEST_METHOD"] == "HEAD" ? [] : asset [200, headers, body] else [404, { "Content-Type" => "text/plain", "Content-Length" => "9" }, ["Not found"]] end rescue Exception => e # TODO: logging STDERR.puts "Error compiling #{path}:" STDERR.puts "#{e.class.name}: #{e.}" # TODO: render nice custom errors in the browser raise end |
#convert(from_and_to, &block) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/pinion/server.rb', line 17 def convert(from_and_to, &block) unless from_and_to.is_a?(Hash) && from_and_to.size == 1 raise Error, "Unexpected argument to convert: #{from_and_to.inspect}" end from, to = from_and_to.to_a[0] unless [from, to].all? { |s| s.is_a? Symbol } raise Error, "Expecting symbols in this hash #{from_and_to.inspect}" end if block_given? # Save new conversion type (this might overwrite an implicit or previously defined conversion) Conversion.create(from_and_to) do render { |file_contents| block.call(file_contents) } end else unless Conversion[from_and_to] raise Error, "No implicit conversion for #{from_and_to.inspect}. Must provide a conversion block." end end end |
#create_bundle(name, bundle_name, paths) ⇒ Object
Create a bundle of assets. Each asset must convert to the same final type. ‘name` is an identifier for this bundle; `bundle_name` is the # identifier for your bundle type (e.g. `:concatenate_and_uglify_js`); and `paths` are all the asset paths. In development, no bundles will be created (but the list of discrete assets will be saved for use in a subsequent `bundle_url` call).
136 137 138 139 140 141 142 143 144 |
# File 'lib/pinion/server.rb', line 136 def create_bundle(name, bundle_name, paths) if Bundle[name] raise "Error: there is already a bundle called #{name} with different component files. Each " << "bundle must have a unique name." end normalized_paths = paths.map { |path| path.sub(%r[^(#{@mount_point})?/?], "") } Bundle.create(name, bundle_name, normalized_paths) end |
#css_bundle(name) ⇒ Object
155 |
# File 'lib/pinion/server.rb', line 155 def css_bundle(name) bundle_url(name).map { |path| css_wrapper(path) }.join end |
#css_inline(path) ⇒ Object
129 |
# File 'lib/pinion/server.rb', line 129 def css_inline(path) %Q{<style type="text/css">#{asset_inline(path)}</style>} end |
#css_url(path) ⇒ Object
125 |
# File 'lib/pinion/server.rb', line 125 def css_url(path) css_wrapper(asset_url(path)) end |
#js_bundle(name) ⇒ Object
154 |
# File 'lib/pinion/server.rb', line 154 def js_bundle(name) bundle_url(name).map { |path| js_wrapper(path) }.join end |
#js_inline(path) ⇒ Object
130 |
# File 'lib/pinion/server.rb', line 130 def js_inline(path) %Q{<script>#{asset_inline(path)}</script>} end |
#js_url(path) ⇒ Object
126 |
# File 'lib/pinion/server.rb', line 126 def js_url(path) js_wrapper(asset_url(path)) end |
#watch(path) ⇒ Object
37 38 39 40 41 |
# File 'lib/pinion/server.rb', line 37 def watch(path) raise Error, "#{path} is not a directory." unless File.directory? path Asset.watch_path(path) Conversion.add_watch_directory path end |