thorero-assets 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 YOUR NAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,250 @@
1
+ merb-assets
2
+ ===========
3
+
4
+ Provides extra functionality related to assets:
5
+
6
+ # Assets bundling.
7
+ # Assets hosts.
8
+ # Helpers to add asset links to views.
9
+ # Deployment-time assets processing (for instance, with YUI Compressor).
10
+
11
+ Quick overview of the API
12
+ ==============================
13
+
14
+ # asset_path generates path for asset taking type and name.
15
+ # UniqueAssetPath class handles generation of paths using subdomains.
16
+ # AbstractAssetBundler is the base asset bundlers class.
17
+
18
+ # auto_link generates conventional asset tags based on controller/action.
19
+ # link_to creates anchor tag (a tag).
20
+ # image_tag creates img tag.
21
+
22
+ # escape_js escapes JavaScript.
23
+ # js method translates object into JSON.
24
+
25
+ # require_js is smart(-er) way to do includes just once per page no matter
26
+ how many times partial use it.
27
+ # require_css is like require_js but for JavaScript.
28
+
29
+ # js_include_tag is used when you need to include script tag with bundling.
30
+ # css_include_tag works like js_include_tag but for stylesheets.
31
+ # include_required_js generates script tags for previously included files.
32
+ # include_required_css generates link tags for previously included files.
33
+
34
+ # uniq_js_path generates a script tag for path with asset subdomain.
35
+ # uniq_css_path generates a link tag for path with asset subdomain.
36
+
37
+
38
+ Examples
39
+ ===========
40
+
41
+ auto_link to include asset tags using convention:
42
+
43
+ We want all possible matches in the FileSys up to the action name
44
+ Given: controller_name = "namespace/controller"
45
+ action_name = "action"
46
+ If all files are present should generate link/script tags for:
47
+ namespace.(css|js)
48
+ namespace/controller.(css|js)
49
+ namespace/controller/action.(css|js)
50
+
51
+ link_to and image_tag to make anchor and image tags:
52
+
53
+ image_tag('foo.gif')
54
+ # => <img src='/images/foo.gif' />
55
+
56
+ image_tag('foo.gif', :class => 'bar')
57
+ # => <img src='/images/foo.gif' class='bar' />
58
+
59
+ image_tag('foo.gif', :path => '/files/')
60
+ # => <img src='/files/foo.gif' />
61
+
62
+ image_tag('http://test.com/foo.gif')
63
+ # => <img src="http://test.com/foo.gif">
64
+
65
+ image_tag('charts', :path => '/dynamic/')
66
+ or
67
+ image_tag('/dynamic/charts')
68
+ # => <img src="/dynamic/charts">
69
+
70
+ link_to("The Merb home page", "http://www.merbivore.com/")
71
+ # => <a href="http://www.merbivore.com/">The Merb home page</a>
72
+
73
+ link_to("The Ruby home page", "http://www.ruby-lang.org", {'class' => 'special', 'target' => 'blank'})
74
+ # => <a href="http://www.ruby-lang.org" class="special" target="blank">The Ruby home page</a>
75
+
76
+ link_to p.title, "/blog/show/#{p.id}"
77
+ # => <a href="/blog/show/13">The Entry Title</a>
78
+
79
+ uniq_css_tag and uniq_js_tag for paths with asset subdomains:
80
+
81
+ uniq_css_tag("my")
82
+ #=> <link href="http://assets2.my-awesome-domain.com/stylesheets/my.css" type="text/css" />
83
+
84
+ uniq_js_tag("my")
85
+ #=> <script type="text/javascript" src="http://assets2.my-awesome-domain.com/javascripts/my.js"></script>
86
+
87
+ uniq_js_path("my")
88
+ #=> "http://assets2.my-awesome-domain.com/javascripts/my.js"
89
+
90
+ uniq_js_path(["admin/secrets","home/signup"])
91
+ #=> ["http://assets2.my-awesome-domain.com/javascripts/admin/secrets.js",
92
+ "http://assets1.my-awesome-domain.com/javascripts/home/signup.js"]
93
+
94
+ re_js and require_css, include_required_js and include_requried_css
95
+ quire assets in parts/partials just once:
96
+
97
+
98
+ In your application layout:
99
+
100
+ js_include_tag :prototype, :lowpro, :bundle => :base
101
+
102
+ In your controller layout:
103
+
104
+ require_js :bundle => :posts
105
+
106
+ The require_js method can be used to require any JavaScript file anywhere
107
+ in your templates. Regardless of how many times a single script is
108
+ included with require_js, Merb will only include it once in the header.
109
+
110
+ # File: app/views/layouts/application.html.erb
111
+
112
+ <html>
113
+ <head>
114
+ <%= include_required_js %>
115
+ <%= include_required_css %>
116
+ </head>
117
+ <body>
118
+ <%= catch_content :layout %>
119
+ </body>
120
+ </html>
121
+
122
+ # File: app/views/whatever/_part1.herb
123
+
124
+ <% require_js 'this' -%>
125
+ <% require_css 'that', 'another_one' -%>
126
+
127
+ # File: app/views/whatever/_part2.herb
128
+
129
+ <% require_js 'this', 'something_else' -%>
130
+ <% require_css 'that' -%>
131
+
132
+ # File: app/views/whatever/index.herb
133
+
134
+ <%= partial(:part1) %>
135
+ <%= partial(:part2) %>
136
+
137
+ # Will generate the following in the final page...
138
+ <html>
139
+ <head>
140
+ <script src="/javascripts/this.js" type="text/javascript"></script>
141
+ <script src="/javascripts/something_else.js" type="text/javascript"></script>
142
+ <link href="/stylesheets/that.css" media="all" rel="Stylesheet" type="text/css"/>
143
+ <link href="/stylesheets/another_one.css" media="all" rel="Stylesheet" type="text/css"/>
144
+ </head>
145
+ .
146
+ .
147
+ .
148
+ </html>
149
+
150
+ # my_action.herb has a call to require_css 'style'
151
+ # File: layout/application.html.erb
152
+ include_required_css
153
+ # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
154
+
155
+ # my_action.herb has a call to require_css 'style', 'ie-specific'
156
+ # File: layout/application.html.erb
157
+ include_required_css
158
+ # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
159
+ # <link href="/stylesheets/ie-specific.css" media="all" rel="Stylesheet" type="text/css"/>
160
+
161
+ # my_action.herb has a call to require_js 'jquery'
162
+ # File: layout/application.html.erb
163
+ include_required_js
164
+ # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
165
+
166
+ # my_action.herb has a call to require_js 'jquery', 'effects', 'validation'
167
+ # File: layout/application.html.erb
168
+ include_required_js
169
+ # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
170
+ # <script src="/javascripts/effects.js" type="text/javascript"></script>
171
+ # <script src="/javascripts/validation.js" type="text/javascript"></script>
172
+
173
+ <% require_css('style') %>
174
+ # A subsequent call to include_required_css will render...
175
+ # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
176
+
177
+ <% require_css('style', 'ie-specific') %>
178
+ # A subsequent call to include_required_css will render...
179
+ # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
180
+ # <link href="/stylesheets/ie-specific.css" media="all" rel="Stylesheet" type="text/css"/>
181
+
182
+ <% require_js 'jquery' %>
183
+ # A subsequent call to include_required_js will render...
184
+ # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
185
+
186
+ <% require_js 'jquery', 'effects' %>
187
+ # A subsequent call to include_required_js will render...
188
+ # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
189
+ # <script src="/javascripts/effects.js" type="text/javascript"></script>
190
+
191
+ css_include_tag and js_include_tag that do not use asset subdomains:
192
+
193
+ css_include_tag 'style'
194
+ # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />
195
+
196
+ css_include_tag 'style.css', 'layout'
197
+ # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />
198
+ # <link href="/stylesheets/layout.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />
199
+
200
+ css_include_tag :menu
201
+ # => <link href="/stylesheets/menu.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />
202
+
203
+ css_include_tag :style, :screen
204
+ # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />
205
+ # <link href="/stylesheets/screen.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />
206
+
207
+ css_include_tag :style, :media => :print
208
+ # => <link href="/stylesheets/style.css" media="print" rel="Stylesheet" type="text/css" charset="utf-8" />
209
+
210
+ css_include_tag :style, :charset => 'iso-8859-1'
211
+ # => <link href="/stylesheets/style.css" media="print" rel="Stylesheet" type="text/css" charset="iso-8859-1" />
212
+
213
+ js_include_tag 'jquery'
214
+ # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
215
+
216
+ js_include_tag 'moofx.js', 'upload'
217
+ # => <script src="/javascripts/moofx.js" type="text/javascript"></script>
218
+ # <script src="/javascripts/upload.js" type="text/javascript"></script>
219
+
220
+ js_include_tag :effects
221
+ # => <script src="/javascripts/effects.js" type="text/javascript"></script>
222
+
223
+ js_include_tag :jquery, :validation
224
+ # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
225
+ # <script src="/javascripts/validation.js" type="text/javascript"></script>
226
+
227
+ Utility methods examples
228
+ ==========================
229
+
230
+ uniq_css_path("my")
231
+ #=> "http://assets2.my-awesome-domain.com/stylesheets/my.css"
232
+
233
+ uniq_css_path(["admin/secrets","home/signup"])
234
+ #=> ["http://assets2.my-awesome-domain.com/stylesheets/admin/secrets.css",
235
+ "http://assets1.my-awesome-domain.com/stylesheets/home/signup.css"]
236
+
237
+ uniq_path("/javascripts/my.js","/javascripts/my.css")
238
+ #=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/javascripts/my.css"]
239
+
240
+ uniq_path(["/javascripts/my.js","/stylesheets/my.css"])
241
+ #=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/stylesheets/my.css"]
242
+
243
+ uniq_path(%w(/javascripts/my.js /stylesheets/my.css))
244
+ #=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/stylesheets/my.css"]
245
+
246
+ uniq_path('/stylesheets/somearbitrary.css')
247
+ #=> "http://assets3.my-awesome-domain.com/stylesheets/somearbitrary.css"
248
+
249
+ uniq_path('/images/hostsexypicture.jpg')
250
+ #=>"http://assets1.my-awesome-domain.com/images/hostsexypicture.jpg"
data/Rakefile ADDED
@@ -0,0 +1,63 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require "extlib"
4
+ require 'merb-core/tasks/merb_rake_helper'
5
+
6
+ ##############################################################################
7
+ # Package && release
8
+ ##############################################################################
9
+ RUBY_FORGE_PROJECT = "thorero"
10
+ PROJECT_URL = "http://merbivore.com"
11
+ PROJECT_SUMMARY = "Merb plugin that provides the helpers for assets and asset bundling"
12
+ PROJECT_DESCRIPTION = PROJECT_SUMMARY
13
+
14
+ GEM_AUTHOR = "Ezra Zygmuntowicz"
15
+ GEM_EMAIL = "ez@engineyard.com"
16
+
17
+ GEM_NAME = "thorero-assets"
18
+ PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
19
+ GEM_VERSION = (Merb::MORE_VERSION rescue "0.9.4") + PKG_BUILD
20
+
21
+ RELEASE_NAME = "REL #{GEM_VERSION}"
22
+
23
+ require "extlib/tasks/release"
24
+
25
+ spec = Gem::Specification.new do |s|
26
+ s.rubyforge_project = RUBY_FORGE_PROJECT
27
+ s.name = GEM_NAME
28
+ s.version = GEM_VERSION
29
+ s.platform = Gem::Platform::RUBY
30
+ s.has_rdoc = true
31
+ s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
32
+ s.summary = PROJECT_SUMMARY
33
+ s.description = PROJECT_DESCRIPTION
34
+ s.author = GEM_AUTHOR
35
+ s.email = GEM_EMAIL
36
+ s.homepage = PROJECT_URL
37
+ s.add_dependency('merb-core', '>= 0.9.4')
38
+ s.require_path = 'lib'
39
+ s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
40
+ end
41
+
42
+ Rake::GemPackageTask.new(spec) do |pkg|
43
+ pkg.gem_spec = spec
44
+ end
45
+
46
+ desc "Install the gem"
47
+ task :install => [:package] do
48
+ sh %{#{sudo} gem install #{install_home} pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources}
49
+ end
50
+
51
+ namespace :jruby do
52
+
53
+ desc "Run :package and install the resulting .gem with jruby"
54
+ task :install => :package do
55
+ sh %{#{sudo} jruby -S gem install #{install_home} pkg/#{GEM_NAME}-#{GEM_VERSION}.gem --no-rdoc --no-ri}
56
+ end
57
+
58
+ end
59
+
60
+ desc "Run specs"
61
+ task :spec do
62
+ sh %{spec -r spec/spec_helper.rb spec/*_spec.rb}
63
+ end
data/TODO ADDED
@@ -0,0 +1,5 @@
1
+ TODO:
2
+ Fix LICENSE with your name
3
+ Fix Rakefile with your name and contact info
4
+ Add your code to lib/merb-haml.rb
5
+ Add your Merb rake tasks to lib/merb-haml/merbtasks.rb
@@ -0,0 +1,14 @@
1
+ require 'merb-assets/assets'
2
+ require 'merb-assets/assets_mixin'
3
+
4
+ Merb::BootLoader.before_app_loads do
5
+ Merb::Controller.send(:include, Merb::AssetsMixin)
6
+ end
7
+
8
+
9
+ Merb::Plugins.config[:asset_helpers] = {
10
+ :max_hosts => 4,
11
+ :asset_domain => "assets%s",
12
+ :domain => "my-awesome-domain.com",
13
+ :use_ssl => false
14
+ } if Merb::Plugins.config[:asset_helpers].nil?
@@ -0,0 +1,242 @@
1
+ module Merb
2
+ module Assets
3
+
4
+ # Check whether the assets should be bundled.
5
+ #
6
+ # ==== Returns
7
+ # Boolean::
8
+ # True if the assets should be bundled (e.g., production mode or
9
+ # :bundle_assets is explicitly enabled).
10
+ def self.bundle?
11
+ (Merb.environment == 'production') ||
12
+ (!!Merb::Config[:bundle_assets])
13
+ end
14
+
15
+ # Helpers for handling asset files.
16
+ module AssetHelpers
17
+ ASSET_FILE_EXTENSIONS = {
18
+ :javascript => ".js",
19
+ :stylesheet => ".css"
20
+ }
21
+
22
+ # Returns the URI path to a particular asset file. If +local_path+ is
23
+ # true, returns the path relative to the Merb.root, not the public
24
+ # directory. Uses the path_prefix, if any is configured.
25
+ #
26
+ # ==== Parameters
27
+ # asset_type<Symbol>:: Type of the asset (e.g. :javascript).
28
+ # filename<~to_s>:: The path to the file.
29
+ # local_path<Boolean>::
30
+ # If true, the returned path will be relative to the Merb.root,
31
+ # otherwise it will be the public URI path. Defaults to false.
32
+ #
33
+ # ==== Returns
34
+ # String:: The path to the asset.
35
+ #
36
+ # ==== Examples
37
+ # asset_path(:javascript, :dingo)
38
+ # # => "/javascripts/dingo.js"
39
+ #
40
+ # asset_path(:javascript, :dingo, true)
41
+ # # => "public/javascripts/dingo.js"
42
+ def asset_path(asset_type, filename, local_path = false)
43
+ filename = filename.to_s
44
+ if filename !~ /#{'\\' + ASSET_FILE_EXTENSIONS[asset_type]}\Z/ && filename.index('?').nil?
45
+ filename = "#{filename}#{ASSET_FILE_EXTENSIONS[asset_type]}" # don't modify receiver
46
+ end
47
+ if filename !~ %r{^(/|https?://)}
48
+ filename = "/#{asset_type}s/#{filename}"
49
+ end
50
+ if local_path
51
+ return "public#{filename}"
52
+ else
53
+ return "#{Merb::Config[:path_prefix]}#{filename}"
54
+ end
55
+ end
56
+ end
57
+
58
+ # Helper for creating unique paths to a file name
59
+ # Can increase speend for browsers that are limited to a certain number of connections per host
60
+ # for downloading static files (css, js, images...)
61
+ class UniqueAssetPath
62
+ class << self
63
+ # Builds the path to the file based on the name
64
+ #
65
+ # ==== Parameters
66
+ # filename<String>:: Name of file to generate path for
67
+ #
68
+ # ==== Returns
69
+ # String:: The path to the asset.
70
+ #
71
+ # ==== Examples
72
+ # build("/javascripts/my_fancy_script.js")
73
+ # # => "https://assets5.my-awesome-domain.com/javascripts/my_fancy_script.js"
74
+ #
75
+ def build(filename)
76
+ config = Merb::Plugins.config[:asset_helpers]
77
+ #%{#{(USE_SSL ? 'https' : 'http')}://#{sprintf(config[:asset_domain],self.calculate_host_id(file))}.#{config[:domain]}/#{filename}}
78
+ path = config[:use_ssl] ? 'https://' : 'http://'
79
+ path << sprintf(config[:asset_domain],self.calculate_host_id(filename)) << ".#{config[:domain]}"
80
+ path << "/" if filename.index('/') != 0
81
+ path << filename
82
+ end
83
+
84
+ protected
85
+
86
+ # Calculates the id for the host
87
+ def calculate_host_id(filename)
88
+ ascii_total = 0
89
+ filename.each_byte {|byte|
90
+ ascii_total += byte
91
+ }
92
+ (ascii_total % Merb::Plugins.config[:asset_helpers][:max_hosts] + 1)
93
+ end
94
+ end
95
+ end
96
+
97
+ # An abstract class for bundling text assets into single files.
98
+ class AbstractAssetBundler
99
+
100
+ class_inheritable_accessor :cached_bundles
101
+ self.cached_bundles ||= []
102
+
103
+ class << self
104
+
105
+ # Mark a bundle as cached.
106
+ #
107
+ # ==== Parameters
108
+ # name<~to_s>:: Name of the bundle
109
+ #
110
+ def cache_bundle(name)
111
+ cached_bundles.push(name.to_s)
112
+ end
113
+
114
+ # Purge a bundle from the cache.
115
+ #
116
+ # ==== Parameters
117
+ # name<~to_s>:: Name of the bundle
118
+ #
119
+ def purge_bundle(name)
120
+ cached_bundles.delete(name.to_s)
121
+ end
122
+
123
+ # Test if a bundle has been cached.
124
+ #
125
+ # ==== Parameters
126
+ # name<~to_s>:: Name of the bundle
127
+ #
128
+ # ==== Returns
129
+ # Boolean:: Whether the bundle has been cached or not.
130
+ def cached_bundle?(name)
131
+ cached_bundles.include?(name.to_s)
132
+ end
133
+
134
+ # ==== Parameters
135
+ # &block:: A block to add as a post-bundle callback.
136
+ #
137
+ # ==== Examples
138
+ # add_callback { |filename| `yuicompressor #{filename}` }
139
+ def add_callback(&block)
140
+ callbacks << block
141
+ end
142
+ alias_method :after_bundling, :add_callback
143
+
144
+ # Retrieve existing callbacks.
145
+ #
146
+ # ==== Returns
147
+ # Array[Proc]:: An array of existing callbacks.
148
+ def callbacks
149
+ @callbacks ||= []
150
+ return @callbacks
151
+ end
152
+
153
+ # The type of asset for which the bundler is responsible. Override
154
+ # this method in your bundler code.
155
+ #
156
+ # ==== Raises
157
+ # NotImplementedError:: This method is implemented by the bundler.
158
+ #
159
+ # ==== Returns
160
+ # Symbol:: The type of the asset
161
+ def asset_type
162
+ raise NotImplementedError, "should return a symbol for the first argument to be passed to asset_path"
163
+ end
164
+ end
165
+
166
+ # ==== Parameters
167
+ # name<~to_s>::
168
+ # Name of the bundle. If name is true, it will be converted to :all.
169
+ # *files<String>:: Names of the files to bundle.
170
+ def initialize(name, *files)
171
+ @bundle_name = name == true ? :all : name
172
+ @bundle_filename = asset_path(self.class.asset_type, @bundle_name, true)
173
+ @files = files.map { |f| asset_path(self.class.asset_type, f, true) }
174
+ end
175
+
176
+ # Creates the new bundled file, executing all the callbacks.
177
+ #
178
+ # ==== Returns
179
+ # Symbol:: Name of the bundle.
180
+ def bundle!
181
+ # TODO: push it out to the helper level so we don't have to create the helper object.
182
+ unless self.class.cached_bundle?(@bundle_name)
183
+ # skip regeneration of new bundled files - preventing multiple merb apps stepping on eachother
184
+ # file needs to be older than 60 seconds to be regenerated
185
+ if File.exist?(@bundle_filename) && File.mtime(@bundle_filename) >= Time.now - 60
186
+ return @bundle_name # serve the old file for now - to be regenerated later
187
+ end
188
+ bundle_files(@bundle_filename, *@files)
189
+ if File.exist?(@bundle_filename)
190
+ self.class.callbacks.each { |c| c.call(@bundle_filename) }
191
+ Merb.logger.info("Assets: bundled :#{@bundle_name} into #{File.basename(@bundle_filename)}")
192
+ self.class.cache_bundle(@bundle_name)
193
+ end
194
+ end
195
+ return @bundle_name
196
+ end
197
+
198
+ protected
199
+
200
+ include Merb::Assets::AssetHelpers # for asset_path
201
+
202
+ # Bundle all the files into one.
203
+ #
204
+ # ==== Parameters
205
+ # filename<String>:: Name of the bundle file.
206
+ # *files<String>:: Filenames to be bundled.
207
+ def bundle_files(filename, *files)
208
+ File.open(filename, "w") do |f|
209
+ f.flock(File::LOCK_EX)
210
+ files.each { |file| f.puts(File.read(file)) }
211
+ f.flock(File::LOCK_UN)
212
+ end
213
+ end
214
+
215
+ end
216
+
217
+ # Bundles javascripts into a single file:
218
+ #
219
+ # javascripts/#{name}.js
220
+ class JavascriptAssetBundler < AbstractAssetBundler
221
+
222
+ # ==== Returns
223
+ # Symbol:: The asset type, i.e. :javascript.
224
+ def self.asset_type
225
+ :javascript
226
+ end
227
+ end
228
+
229
+ # Bundles stylesheets into a single file:
230
+ #
231
+ # stylesheets/#{name}.css
232
+ class StylesheetAssetBundler < AbstractAssetBundler
233
+
234
+ # ==== Returns
235
+ # Symbol:: The asset type, i.e. :stylesheet.
236
+ def self.asset_type
237
+ :stylesheet
238
+ end
239
+ end
240
+
241
+ end
242
+ end