asset-resource 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # AssetResource
2
+
3
+ Serve up your CSS and Javascript as first-class resources.
4
+
5
+ Supports in-line rendering of engines such as Sass and Less. These files will
6
+ be served with 24-hour HTTP cache expiry.
7
+
8
+ Built-in configuration and helpers for Rails 2.x, Rails 3.x and Sinatra.
9
+
10
+ ## Usage
11
+
12
+ ### Rails 2.x
13
+
14
+ # public/stylesheets/*.{css|less|sass}
15
+ # public/javascripts/*.js
16
+
17
+ # config/environment.rb
18
+ config.gem "asset-resource"
19
+
20
+ # app/views/layouts/application.html.erb
21
+ <html>
22
+ <head>
23
+ <%= asset_resource_stylesheets %>
24
+ <%= asset_resource_scripts %>
25
+ </head>
26
+ </html>
27
+
28
+ ### Rails 3.x
29
+
30
+ # public/stylesheets/*.{css|less|sass}
31
+ # public/javascripts/*.js
32
+
33
+ # Gemfile
34
+ gem "asset_resource"
35
+
36
+ # app/views/layouts/application.html.erb
37
+ <html>
38
+ <head>
39
+ <%= asset_resource_stylesheets %>
40
+ <%= asset_resource_scripts %>
41
+ </head>
42
+ </html>
43
+
44
+ ### Sinatra
45
+
46
+ # assets/styles/*.{css|less|sass}
47
+ # assets/scripts/*.js
48
+
49
+ # app.rb
50
+ require "asset_resource"
51
+
52
+ class App < Sinatra::Base
53
+ register Sinatra::AssetResource
54
+ end
55
+
56
+ __END__
57
+
58
+ @@ layout
59
+ %html
60
+ %head
61
+ = asset_resource_scripts
62
+ = asset_resource_styles
63
+
64
+ ## Technical Details
65
+
66
+ `AssetResource::Middleware` serves requests at `/assets/stylesheets.css` and
67
+ `/assets/javascripts.js`.
68
+
69
+ The gem will add appropriate view helpers to your framework of choice.
70
+
71
+ You can use the middleware yourself like this:
72
+
73
+ use AssetResource::Middleware,
74
+ :base_path => "public",
75
+ :handlers => { :javascripts => "text/javascript",
76
+ :stylesheets => "text/css" }
77
+
78
+ ## Copyright
79
+
80
+ MIT License
81
+
82
+ ## Author
83
+
84
+ David Dollar
85
+
86
+ [http://daviddollar.org](http://daviddollar.org)
data/Rakefile ADDED
@@ -0,0 +1,58 @@
1
+ require "rake"
2
+ require "rspec"
3
+ require "rspec/core/rake_task"
4
+
5
+ $:.unshift File.expand_path("../lib", __FILE__)
6
+ require "asset_resource"
7
+
8
+ task :default => :spec
9
+
10
+ desc "Run all specs"
11
+ Rspec::Core::RakeTask.new(:spec) do |t|
12
+ t.pattern = 'spec/**/*_spec.rb'
13
+ end
14
+
15
+ desc "Generate RCov code coverage report"
16
+ task :rcov => "rcov:build" do
17
+ %x{ open coverage/index.html }
18
+ end
19
+
20
+ Rspec::Core::RakeTask.new("rcov:build") do |t|
21
+ t.pattern = 'spec/**/*_spec.rb'
22
+ t.rcov = true
23
+ t.rcov_opts = [ "--exclude", Gem.default_dir , "--exclude", "spec" ]
24
+ end
25
+
26
+ ######################################################
27
+
28
+ begin
29
+ require 'jeweler'
30
+ Jeweler::Tasks.new do |s|
31
+ s.name = "asset-resource"
32
+ s.version = AssetResource::VERSION
33
+
34
+ s.summary = "Manage CSS/JS assets as dynamic resources rather than static files"
35
+ s.description = s.summary
36
+ s.author = "David Dollar"
37
+ s.email = "ddollar@gmail.com"
38
+ s.homepage = "http://github.com/ddollar/asset-resource"
39
+
40
+ s.platform = Gem::Platform::RUBY
41
+ s.has_rdoc = false
42
+
43
+ s.files = %w(Rakefile README.md) + Dir["{bin,lib}/**/*"]
44
+ s.require_path = "lib"
45
+
46
+ s.add_development_dependency 'artifice', '~> 0.5'
47
+ s.add_development_dependency 'fakefs', '~> 0.2.1'
48
+ s.add_development_dependency 'haml', '~> 3.0.9'
49
+ s.add_development_dependency 'less', '~> 1.2.21'
50
+ s.add_development_dependency 'rake', '~> 0.8.7'
51
+ s.add_development_dependency 'rest-client', '~> 1.5.1'
52
+ s.add_development_dependency 'rcov', '~> 0.9.8'
53
+ s.add_development_dependency 'rspec', '~> 2.0.0'
54
+ end
55
+ Jeweler::GemcutterTasks.new
56
+ rescue LoadError
57
+ puts "Jeweler not available. Install it with: sudo gem install jeweler"
58
+ end
@@ -0,0 +1 @@
1
+ require "asset_resource"
@@ -0,0 +1,11 @@
1
+ module AssetResource
2
+ VERSION = "0.0.1"
3
+ end
4
+
5
+ if defined?(Rails)
6
+ require "asset_resource/framework/rails#{Rails::VERSION::MAJOR}"
7
+ end
8
+
9
+ if defined?(Sinatra)
10
+ require "asset_resource/framework/sinatra"
11
+ end
@@ -0,0 +1,19 @@
1
+ require "asset_resource"
2
+ require "asset_resource/middleware"
3
+
4
+ module AssetResource::Helpers
5
+ def asset_resource_stylesheets
6
+ '<link rel="stylesheet" href="/assets/stylesheets.css" />'
7
+ end
8
+
9
+ def asset_resource_javascripts
10
+ '<script type="text/javascript" src="/assets/javascripts.js"></script>'
11
+ end
12
+ end
13
+
14
+ Rails.configuration.middleware.use AssetResource::Middleware,
15
+ :base_path => Rails.root.join("public"),
16
+ :handlers => { :javascripts => "text/javascript",
17
+ :stylesheets => "text/css" }
18
+
19
+ ActionView::Base.send :include, AssetResource::Helpers
@@ -0,0 +1,24 @@
1
+ require "asset_resource"
2
+ require "asset_resource/middleware"
3
+ require "active_support"
4
+
5
+ ActiveSupport.on_load(:before_configuration) do
6
+ Rails.application.config.middleware.use AssetResource::Middleware,
7
+ :base_path => Rails.root.join("public"),
8
+ :handlers => { :javascripts => "text/javascript",
9
+ :stylesheets => "text/css" }
10
+ end
11
+
12
+ module AssetResource::Helpers
13
+ def asset_resource_stylesheets
14
+ '<link rel="stylesheet" href="/assets/stylesheets.css" />'
15
+ end
16
+
17
+ def asset_resource_javascripts
18
+ '<script type="text/javascript" src="/assets/javascripts.js"></script>'
19
+ end
20
+ end
21
+
22
+ ActiveSupport.on_load(:action_view) do
23
+ include AssetResource::Helpers
24
+ end
@@ -0,0 +1,26 @@
1
+ require "asset_resource/middleware"
2
+
3
+ module Sinatra
4
+ module AssetResource
5
+ def self.registered(app)
6
+ app.use ::AssetResource::Middleware,
7
+ :base_path => File.join(app.root, "assets"),
8
+ :handlers => { :scripts => "text/javascript",
9
+ :styles => "text/css" }
10
+
11
+ app.helpers Sinatra::AssetResource::Helpers
12
+ end
13
+
14
+ module Helpers
15
+ def asset_resource_styles
16
+ '<link rel="stylesheet" href="/assets/styles.css" />'
17
+ end
18
+
19
+ def asset_resource_scripts
20
+ '<script type="text/javascript" src="/assets/scripts.js"></script>'
21
+ end
22
+ end
23
+ end
24
+
25
+ register AssetResource
26
+ end
@@ -0,0 +1,96 @@
1
+ require "asset_resource"
2
+
3
+ class AssetResource::Middleware
4
+
5
+ attr_reader :app, :options
6
+
7
+ def initialize(app, options={})
8
+ @app = app
9
+ @options = options
10
+
11
+ if options[:handlers] then
12
+ options[:handlers].each do |handler, mime_type|
13
+ handle handler.to_sym, mime_type
14
+ end
15
+ else
16
+ handle :scripts, "text/javascript"
17
+ handle :styles, "text/css"
18
+ end
19
+
20
+ translator :less do |filename|
21
+ begin
22
+ require "less"
23
+ Less::Engine.new(File.read(filename)).to_css
24
+ rescue LoadError
25
+ raise "Tried to translate a less file but could not find the library.\nTry adding this to your Gemfile:\n gem \"less\""
26
+ end
27
+ end
28
+
29
+ translator :sass do |filename|
30
+ begin
31
+ require "sass"
32
+ Sass::Engine.new(File.read(filename), :load_paths => [File.dirname(filename)]).render
33
+ rescue LoadError
34
+ raise "Tried to translate a sass file but could not find the library.\nTry adding this to your Gemfile:\n gem \"haml\""
35
+ end
36
+ end
37
+ end
38
+
39
+ def call(env)
40
+ if env["PATH_INFO"] =~ %r{\A/assets/(.+)\B}
41
+ type = $1.split(".").first
42
+ return app.call(env) unless handles?(type)
43
+ return [200, asset_headers(type), process_files(files_for(type))]
44
+ end
45
+ app.call(env)
46
+ end
47
+
48
+ private ######################################################################
49
+
50
+ def asset_headers(type)
51
+ headers = options[:asset_headers] || { "Cache-Control" => "public, max-age=86400" }
52
+ headers.merge("Content-Type" => handlers[type.to_sym])
53
+ end
54
+
55
+ def base_path
56
+ options[:base_path] || "public"
57
+ end
58
+
59
+ def files_for(type)
60
+ Dir.glob(File.expand_path(File.join(base_path, type, "**", "*")))
61
+ end
62
+
63
+ def process_files(files)
64
+ data = files.inject("") do |accum, file|
65
+ ext = File.extname(file)[1..-1]
66
+ accum << translator(ext).call(file)
67
+ end
68
+ StringIO.new(data)
69
+ end
70
+
71
+ def handlers
72
+ @handler ||= {}
73
+ end
74
+
75
+ def handles?(type)
76
+ handlers.keys.include?(type.to_sym)
77
+ end
78
+
79
+ def handle(type, mime_type)
80
+ handlers[type.to_sym] = mime_type
81
+ end
82
+
83
+ def default_translator
84
+ lambda { |filename| File.read(filename) }
85
+ end
86
+
87
+ def translators
88
+ @translators ||= Hash.new(default_translator)
89
+ end
90
+
91
+ def translator(type, &block)
92
+ translators[type.to_sym] = block if block_given?
93
+ translators[type.to_sym]
94
+ end
95
+
96
+ end
@@ -0,0 +1,50 @@
1
+ require "spec_helper"
2
+ require "asset_resource/middleware"
3
+
4
+ describe AssetResource::Middleware do
5
+
6
+ let(:app) { lambda { |env| [ 200, {}, ['bar'] ]} }
7
+ let(:middleware) { AssetResource::Middleware.new(app, :base_path => asset_fixture) }
8
+
9
+ before(:each) do
10
+ Artifice.activate_with(middleware)
11
+ end
12
+
13
+ it "passes unhandled requests" do
14
+ RestClient.get("http://localhost/foo").to_s.should == "bar"
15
+ end
16
+
17
+ it "serves with cache headers" do
18
+ response = RestClient.get("http://localhost/assets/scripts.js")
19
+ response.headers[:cache_control].should =~ /public/
20
+ end
21
+
22
+ it "can set custom asset headers" do
23
+ middleware.options[:asset_headers] = { "X-Foo" => "Bar" }
24
+ response = RestClient.get("http://localhost/assets/scripts.js")
25
+ response.headers[:cache_control].should_not =~ /public/
26
+ response.headers[:x_foo].should == "Bar"
27
+ end
28
+
29
+ it "serves scripts" do
30
+ data = RestClient.get("http://localhost/assets/scripts.js")
31
+ data.should include "console.log('hello!')"
32
+ end
33
+
34
+ it "serves styles" do
35
+ data = RestClient.get("http://localhost/assets/styles.css")
36
+ data.should include "color: #1e5500"
37
+ data.should include "color: #5a5500"
38
+ end
39
+
40
+ it "serves scripts with the proper mime type" do
41
+ response = RestClient.get("http://localhost/assets/scripts.js")
42
+ response.headers[:content_type].should == "text/javascript"
43
+ end
44
+
45
+ it "serves styles with the proper mime type" do
46
+ response = RestClient.get("http://localhost/assets/styles.css")
47
+ response.headers[:content_type].should == "text/css"
48
+ end
49
+
50
+ end
@@ -0,0 +1,8 @@
1
+ require "spec_helper"
2
+ require "asset_resource"
3
+
4
+ describe AssetResource do
5
+ it "has a version" do
6
+ AssetResource::VERSION.should be_a String
7
+ end
8
+ end
@@ -0,0 +1,14 @@
1
+ require "rubygems"
2
+ require "rspec"
3
+ require "artifice"
4
+ require "rest_client"
5
+
6
+ $:.unshift "lib"
7
+
8
+ def asset_fixture(name="")
9
+ File.expand_path("../fixtures/#{name}", __FILE__)
10
+ end
11
+
12
+ Rspec.configure do |config|
13
+ config.color_enabled = true
14
+ end
metadata ADDED
@@ -0,0 +1,205 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: asset-resource
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - David Dollar
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-07-25 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: artifice
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 1
30
+ segments:
31
+ - 0
32
+ - 5
33
+ version: "0.5"
34
+ type: :development
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: fakefs
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 21
45
+ segments:
46
+ - 0
47
+ - 2
48
+ - 1
49
+ version: 0.2.1
50
+ type: :development
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: haml
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ hash: 21
61
+ segments:
62
+ - 3
63
+ - 0
64
+ - 9
65
+ version: 3.0.9
66
+ type: :development
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: less
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ hash: 53
77
+ segments:
78
+ - 1
79
+ - 2
80
+ - 21
81
+ version: 1.2.21
82
+ type: :development
83
+ version_requirements: *id004
84
+ - !ruby/object:Gem::Dependency
85
+ name: rake
86
+ prerelease: false
87
+ requirement: &id005 !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ~>
91
+ - !ruby/object:Gem::Version
92
+ hash: 49
93
+ segments:
94
+ - 0
95
+ - 8
96
+ - 7
97
+ version: 0.8.7
98
+ type: :development
99
+ version_requirements: *id005
100
+ - !ruby/object:Gem::Dependency
101
+ name: rest-client
102
+ prerelease: false
103
+ requirement: &id006 !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ~>
107
+ - !ruby/object:Gem::Version
108
+ hash: 1
109
+ segments:
110
+ - 1
111
+ - 5
112
+ - 1
113
+ version: 1.5.1
114
+ type: :development
115
+ version_requirements: *id006
116
+ - !ruby/object:Gem::Dependency
117
+ name: rcov
118
+ prerelease: false
119
+ requirement: &id007 !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ hash: 43
125
+ segments:
126
+ - 0
127
+ - 9
128
+ - 8
129
+ version: 0.9.8
130
+ type: :development
131
+ version_requirements: *id007
132
+ - !ruby/object:Gem::Dependency
133
+ name: rspec
134
+ prerelease: false
135
+ requirement: &id008 !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ~>
139
+ - !ruby/object:Gem::Version
140
+ hash: 15
141
+ segments:
142
+ - 2
143
+ - 0
144
+ - 0
145
+ version: 2.0.0
146
+ type: :development
147
+ version_requirements: *id008
148
+ description: Manage CSS/JS assets as dynamic resources rather than static files
149
+ email: ddollar@gmail.com
150
+ executables: []
151
+
152
+ extensions: []
153
+
154
+ extra_rdoc_files:
155
+ - README.md
156
+ files:
157
+ - README.md
158
+ - Rakefile
159
+ - lib/asset-resource.rb
160
+ - lib/asset_resource.rb
161
+ - lib/asset_resource/framework/rails2.rb
162
+ - lib/asset_resource/framework/rails3.rb
163
+ - lib/asset_resource/framework/sinatra.rb
164
+ - lib/asset_resource/middleware.rb
165
+ - spec/asset_resource/middleware_spec.rb
166
+ - spec/asset_resource_spec.rb
167
+ - spec/spec_helper.rb
168
+ has_rdoc: false
169
+ homepage: http://github.com/ddollar/asset-resource
170
+ licenses: []
171
+
172
+ post_install_message:
173
+ rdoc_options:
174
+ - --charset=UTF-8
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ none: false
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ hash: 3
183
+ segments:
184
+ - 0
185
+ version: "0"
186
+ required_rubygems_version: !ruby/object:Gem::Requirement
187
+ none: false
188
+ requirements:
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ hash: 3
192
+ segments:
193
+ - 0
194
+ version: "0"
195
+ requirements: []
196
+
197
+ rubyforge_project:
198
+ rubygems_version: 1.3.7
199
+ signing_key:
200
+ specification_version: 3
201
+ summary: Manage CSS/JS assets as dynamic resources rather than static files
202
+ test_files:
203
+ - spec/asset_resource/middleware_spec.rb
204
+ - spec/asset_resource_spec.rb
205
+ - spec/spec_helper.rb