sinatra-sprockets-ext 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sinatra-sprockets.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Andrew Marshall
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # Sinatra::Sprockets
2
+
3
+ Sinatra extension for Sprockets integration.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'sinatra-sprockets-ext', :require => 'sinatra/sprockets'
10
+
11
+ Currently requires 1.9 (1.8 is near end-of-life anyway).
12
+
13
+ ## Usage
14
+
15
+ Register the plugin in your `app.rb`:
16
+
17
+ register Sinatra::Sprockets
18
+
19
+ In your `config.ru`, add a mapping for Sprockets:
20
+
21
+ map "/#{Sinatra::Sprockets.config.prefix}" do
22
+ run Sinatra::Sprockets.environment
23
+ end
24
+
25
+ Optionally configure as needed. Configuration is similar to Rails's Asset Pipeline.
26
+ Below is an example configuration with some options showing the default values:
27
+
28
+ Sinatra::Sprockets.configure do |config|
29
+ config.compile = false # On-the-fly compilation
30
+ config.compress = false # Compress assets
31
+ config.digest = false # Append a digest to URLs
32
+ config.css_compressor = false # CSS compressor instance
33
+ config.js_compressor = false # JS compressor instance
34
+ end
35
+
36
+ All options and their defaults are shown in `lib/sinatra-sprockets/configuration.rb`.
37
+
38
+ You'll also get helper functions that will be familiar to those who use Rails:
39
+
40
+ - `javascript_include_tag :asset_name`
41
+ - `stylesheet_link_tag :asset_name`
42
+ - `asset_path :asset_name`
43
+
44
+ ## Credits & License
45
+
46
+ Copyright ©2012 J. Andrew Marshall. All rights reserved.
47
+ License is available in the LICENSE file.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,134 @@
1
+ module Sinatra::Sprockets
2
+ module Helpers
3
+ class AssetPaths
4
+ class AssetNotPrecompiledError < StandardError; end
5
+
6
+ def initialize config
7
+ @config = config
8
+ end
9
+
10
+ def asset_for(source, ext)
11
+ source = source.to_s
12
+ return nil if is_uri?(source)
13
+ source = rewrite_extension(source, nil, ext)
14
+ asset_environment[source]
15
+ rescue Sprockets::FileOutsidePaths
16
+ nil
17
+ end
18
+
19
+ def digest_for(logical_path)
20
+ if @config.digest && @config.digests && (digest = @config.digests[logical_path])
21
+ return digest
22
+ end
23
+
24
+ if @config.compile
25
+ if @config.digest && asset = asset_environment[logical_path]
26
+ return asset.digest_path
27
+ end
28
+ return logical_path
29
+ else
30
+ raise AssetNotPrecompiledError.new("#{logical_path} isn't precompiled")
31
+ end
32
+ end
33
+
34
+ def rewrite_asset_path(source, dir, options = {})
35
+ if source[0] == ?/
36
+ source
37
+ else
38
+ source = digest_for(source) unless options[:digest] == false
39
+ source = File.join(dir, source)
40
+ source = "/#{source}" unless source =~ /^\//
41
+ source
42
+ end
43
+ end
44
+
45
+ def rewrite_extension(source, dir, ext)
46
+ if ext && File.extname(source) != ".#{ext}"
47
+ "#{source}.#{ext}"
48
+ else
49
+ source
50
+ end
51
+ end
52
+
53
+ def compute_public_path(source, dir, options = {})
54
+ source = source.to_s
55
+ unless is_uri?(source)
56
+ source = rewrite_extension(source, dir, options[:ext]) if options[:ext]
57
+ source = rewrite_asset_path(source, dir, options)
58
+ source = rewrite_relative_url_root(source, @config.relative_url_root)
59
+ source = rewrite_host_and_protocol(source, options[:protocol])
60
+ end
61
+ source
62
+ end
63
+
64
+ def is_uri?(path)
65
+ path =~ %r{^[-a-z]+://|^cid:|^//}
66
+ end
67
+
68
+ def rewrite_host_and_protocol(source, protocol = nil)
69
+ host = compute_asset_host(source)
70
+ if host && !is_uri?(host)
71
+ if (protocol || default_protocol) == :request && !has_request?
72
+ host = nil
73
+ else
74
+ host = "#{compute_protocol(protocol)}#{host}"
75
+ end
76
+ end
77
+ host ? "#{host}#{source}" : source
78
+ end
79
+
80
+ def rewrite_relative_url_root(source, relative_url_root)
81
+ relative_url_root && !source.starts_with?("#{relative_url_root}/") ? "#{relative_url_root}#{source}" : source
82
+ end
83
+
84
+ def compute_asset_host(source)
85
+ if host = @config.host
86
+ if host.respond_to?(:call)
87
+ args = [source]
88
+ arity = arity_of(host)
89
+ if arity > 1 && request.nil?
90
+ invalid_asset_host!("Remove the second argument to your asset_host Proc if you do not need the request.")
91
+ end
92
+ args << current_request if (arity > 1 || arity < 0) && has_request?
93
+ host.call(*args)
94
+ else
95
+ (host =~ /%d/) ? host % (Zlib.crc32(source) % 4) : host
96
+ end
97
+ end
98
+ end
99
+
100
+ def default_protocol
101
+ @config.default_protocol || (request.nil?? :relative : :request)
102
+ end
103
+
104
+ def compute_protocol(protocol)
105
+ protocol ||= default_protocol
106
+ case protocol
107
+ when :request
108
+ if request.nil?
109
+ invalid_asset_host!("The protocol requested was :request. Consider using :relative instead.")
110
+ end
111
+ request.protocol
112
+ when :relative
113
+ "//"
114
+ else
115
+ "#{protocol}://"
116
+ end
117
+ end
118
+
119
+ def arity_of(callable)
120
+ callable.respond_to?(:arity) ? callable.arity : callable.method(:call).arity
121
+ end
122
+
123
+ def invalid_asset_host!(help_message)
124
+ raise ActionController::RoutingError, "This asset host cannot be computed without a request in scope. #{help_message}"
125
+ end
126
+
127
+ private
128
+
129
+ def asset_environment
130
+ Sinatra::Sprockets.environment
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,28 @@
1
+ module Sinatra::Sprockets
2
+ DEFAULT_OPTIONS = {
3
+ app: nil,
4
+ debug: false,
5
+ digest: false,
6
+ compile: false,
7
+ compress: false,
8
+ host: nil,
9
+ manifest_path: 'public/assets',
10
+ paths: %w[images javascripts stylesheets],
11
+ precompile: [ /\w+\.(?!js|css).+/, /application.(css|js)$/ ],
12
+ prefix: 'assets',
13
+ relative_url_root: ENV['RACK_RELATIVE_URL_ROOT'],
14
+ css_compressor: false,
15
+ js_compressor: false
16
+ }
17
+
18
+ class Configuration < Struct.new(*DEFAULT_OPTIONS.keys)
19
+ attr_accessor *DEFAULT_OPTIONS.keys, :digests
20
+
21
+ def initialize
22
+ DEFAULT_OPTIONS.each do |key, value|
23
+ send "#{key}=".to_sym, value
24
+ end
25
+ @digests = {}
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,78 @@
1
+ module Sinatra::Sprockets
2
+ module Helpers
3
+ def asset_path source, options = {}
4
+ source = source.logical_path if source.respond_to?(:logical_path)
5
+ path = asset_paths.compute_public_path(source, config.prefix, options.merge(:body => true))
6
+ options[:body] ? "#{path}?body=1" : path
7
+ end
8
+
9
+ def image_path source, options = {}
10
+ asset_path source, { dir: 'images' }.merge(options)
11
+ end
12
+
13
+ def javascript_path source, options = {}
14
+ asset_path source, { dir: 'javascripts', ext: 'js' }.merge(options)
15
+ end
16
+
17
+ def stylesheet_path source, options = {}
18
+ asset_path source, { dir: 'stylesheets', ext: 'css' }.merge(options)
19
+ end
20
+
21
+ def javascript_include_tag(*sources)
22
+ debug = config.debug
23
+ body = false
24
+ digest = config.digest
25
+
26
+ sources.collect do |source|
27
+ if debug && asset = asset_paths.asset_for(source, 'js')
28
+ asset.to_a.map do |dep|
29
+ src = asset_path(dep, :ext => 'js', :body => true, :digest => digest)
30
+ "<script src=#{src} type='application/javascript'></script>"
31
+ end
32
+ else
33
+ src = asset_path(source, :ext => 'js', :body => body, :digest => digest)
34
+ "<script src=#{src} type='application/javascript'></script>"
35
+ end
36
+ end.join("\n")
37
+ end
38
+
39
+ def stylesheet_link_tag(*sources)
40
+ options = {}
41
+ debug = config.debug
42
+ body = false
43
+ digest = config.digest
44
+
45
+ sources.collect do |source|
46
+ if debug && asset = asset_paths.asset_for(source, 'css')
47
+ asset.to_a.map do |dep|
48
+ href = asset_path(dep, :ext => 'css', :body => true, :protocol => :request, :digest => digest)
49
+ "<link href='#{href}' media='screen' rel='stylesheet', type='text/css' />"
50
+ end
51
+ else
52
+ href = asset_path(source, :ext => 'css', :body => body, :protocol => :request, :digest => digest)
53
+ "<link href='#{href}' media='screen' rel='stylesheet', type='text/css' />"
54
+ end
55
+ end.join("\n")
56
+ end
57
+
58
+ def asset_path(source, options={})
59
+ source = source.logical_path if source.respond_to?(:logical_path)
60
+ path = asset_paths.compute_public_path(source, config.prefix, options.merge(:body => true))
61
+ options[:body] ? "#{path}?body=1" : path
62
+ end
63
+
64
+ private
65
+
66
+ def assets_environment
67
+ Sinatra::Sprockets.environment
68
+ end
69
+
70
+ def asset_paths
71
+ @asset_paths ||= AssetPaths.new Sinatra::Sprockets.config
72
+ end
73
+
74
+ def config
75
+ Sinatra::Sprockets.config
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,61 @@
1
+ require 'fileutils'
2
+
3
+ module Sinatra::Sprockets
4
+ class StaticCompiler
5
+ attr_accessor :env, :target, :paths
6
+
7
+ def initialize(env, target, paths, options = {})
8
+ @env = env
9
+ @target = target
10
+ @paths = paths
11
+ @digest = options.key?(:digest) ? options.delete(:digest) : true
12
+ @manifest = options.key?(:manifest) ? options.delete(:manifest) : true
13
+ @manifest_path = options.delete(:manifest_path) || target
14
+ end
15
+
16
+ def compile
17
+ manifest = {}
18
+ env.each_logical_path do |logical_path|
19
+ next unless compile_path?(logical_path)
20
+ if asset = env.find_asset(logical_path)
21
+ manifest[logical_path] = write_asset(asset)
22
+ end
23
+ end
24
+ write_manifest(manifest) if @manifest
25
+ end
26
+
27
+ def write_manifest(manifest)
28
+ FileUtils.mkdir_p(@manifest_path)
29
+ File.open("#{@manifest_path}/manifest.yml", 'wb') do |f|
30
+ YAML.dump(manifest, f)
31
+ end
32
+ end
33
+
34
+ def write_asset(asset)
35
+ path_for(asset).tap do |path|
36
+ filename = File.join(target, path)
37
+ FileUtils.mkdir_p File.dirname(filename)
38
+ asset.write_to(filename)
39
+ asset.write_to("#{filename}.gz") if filename.to_s =~ /\.(css|js)$/
40
+ end
41
+ end
42
+
43
+ def compile_path?(logical_path)
44
+ paths.each do |path|
45
+ case path
46
+ when Regexp
47
+ return true if path.match(logical_path)
48
+ when Proc
49
+ return true if path.call(logical_path)
50
+ else
51
+ return true if File.fnmatch(path.to_s, logical_path)
52
+ end
53
+ end
54
+ false
55
+ end
56
+
57
+ def path_for(asset)
58
+ @digest ? asset.digest_path : asset.logical_path
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,5 @@
1
+ module Sinatra
2
+ module Sprockets
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,41 @@
1
+ require "sinatra/sprockets/version"
2
+ require "sinatra/sprockets/asset_paths"
3
+ require "sinatra/sprockets/configuration"
4
+ require "sinatra/sprockets/helpers"
5
+
6
+ module Sinatra
7
+ module Sprockets
8
+ def self.configure
9
+ yield config
10
+ end
11
+
12
+ def self.config
13
+ @config ||= Configuration.new
14
+ end
15
+
16
+ def self.environment
17
+ @environment
18
+ end
19
+
20
+ def self.registered app
21
+ config.app = app
22
+
23
+ @environment = ::Sprockets::Environment.new app.root
24
+
25
+ config.paths.each do |path|
26
+ environment.append_path File.join(config.app.root, config.prefix, path)
27
+ environment.append_path File.join(config.app.root, 'lib', config.prefix, path)
28
+ end
29
+
30
+ if config.compress
31
+ environment.css_compressor = config.css_compressor
32
+ environment.js_compressor = config.js_compressor
33
+ end
34
+
35
+ app.helpers Helpers
36
+ environment.context_class.instance_eval do
37
+ include Helpers
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/sinatra/sprockets/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Andrew Marshall"]
6
+ gem.email = ["andrew@johnandrewmarshall.com"]
7
+ gem.description = %q{Sinatra plugin for Sprockets integration}
8
+ gem.summary = %q{Sinatra plugin for Sprockets integration}
9
+ gem.homepage = "http://johnandrewmarshall.com/projects/sinatra-sprockets"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "sinatra-sprockets-ext"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Sinatra::Sprockets::VERSION
17
+
18
+ gem.add_dependency "sprockets"
19
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sinatra-sprockets-ext
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Andrew Marshall
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: sprockets
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Sinatra plugin for Sprockets integration
31
+ email:
32
+ - andrew@johnandrewmarshall.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - LICENSE
40
+ - README.md
41
+ - Rakefile
42
+ - lib/sinatra/sprockets.rb
43
+ - lib/sinatra/sprockets/asset_paths.rb
44
+ - lib/sinatra/sprockets/configuration.rb
45
+ - lib/sinatra/sprockets/helpers.rb
46
+ - lib/sinatra/sprockets/static_compiler.rb
47
+ - lib/sinatra/sprockets/version.rb
48
+ - sinatra-sprockets.gemspec
49
+ homepage: http://johnandrewmarshall.com/projects/sinatra-sprockets
50
+ licenses: []
51
+ post_install_message:
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project:
69
+ rubygems_version: 1.8.23
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: Sinatra plugin for Sprockets integration
73
+ test_files: []
74
+ has_rdoc: