thorero-assets 0.9.4

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/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