japr 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YTVjZTZkZWFlYmQ5ZGNkYzliZDlkOWIyODVkMWU0NDZlMDJiNGZmNw==
5
+ data.tar.gz: !binary |-
6
+ YmE5ZDViOTMzOTM4NjFkMjdiZmQ5M2E5MjI5YjNiMmE0ZGQ5ZDk1Yg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NGQzYmJkNmFmMTU0YTdjZWY3MTNlMmExYTZjNGQ1ZTNhMGEwNjQ1NjdmOGY0
10
+ MmZkMzFkYzllYjk5Zjk5ZTUwN2UwZjVkOWM3Y2RiZTNiZDJjMzkzYmU0ZjI5
11
+ MjkwYzI0YWM0ZTM0OTVkYzM2OTNhYjIyNTcyZjYzYmU3ZDE5ZDg=
12
+ data.tar.gz: !binary |-
13
+ NTJkNTBiMzFjN2M3MDkwNmYxODAyZGI4ZjIxOWYwNWQ5Njg0M2RmOGJlMDg0
14
+ ZjdhY2FkZWNjYzZlODZkMDc5NTRjYWI5ZDRmZWNiMWIxZGM3NjA3MmQxMWU5
15
+ NWU0YWIxNjZmZTNlZTk0NzJiNWIyNGQxMGQ1ZTRhMGM1MTM4YTI=
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2012 Matt Hodan (http://www.matthodan.com)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the 'Software'), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,329 @@
1
+ # Jekyll Asset Pipeline Reborn
2
+
3
+ Jekyll Asset Pipeline Reborn is a powerful asset pipeline that automatically collects, converts and compresses / minifies your site's JavaScript and CSS assets when you compile your Jekyll site.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Features](#features)
8
+ - [How It Works](#how-it-works)
9
+ - [Getting Started](#getting-started)
10
+ - [Asset Preprocessing](#asset-preprocessing)
11
+ - [Asset Compression](#asset-compression)
12
+ - [Templates](#templates)
13
+ - [Configuration](#configuration)
14
+ - [Octopress](#octopress)
15
+ - [Contribute](#contribute)
16
+ - [Community](#community)
17
+ - [Code Status](#code-status)
18
+ - [Credits](#credits)
19
+ - [License](#license)
20
+
21
+ ## Features
22
+
23
+ - Declarative dependency management via asset manifests
24
+ - Asset preprocessing/conversion (supports [CoffeeScript](http://coffeescript.org/), [Sass / Scss](http://sass-lang.com/), [Less](http://lesscss.org/), [Erb](http://ruby-doc.org/stdlib-1.9.3/libdoc/erb/rdoc/ERB.html), etc.)
25
+ - Asset compression (supports [YUI Compressor](http://developer.yahoo.com/yui/compressor/), [Closure Compiler](https://developers.google.com/closure/compiler/), etc.)
26
+ - Fingerprints bundled asset filenames with MD5 hashes for better browser caching
27
+ - Automatic generation of HTML "link" and "script" tags that point to bundled assets
28
+ - Integrates seamlessly into Jekyll's workflow, including auto site regeneration
29
+
30
+ ## How It Works
31
+
32
+ Jekyll Asset Pipeline's workflow can be summarized as follows:
33
+
34
+ 1. Review site markup for instances of the `css_asset_tag` and `javascript_asset_tag` Liquid tags. Each occurrence of either of these tags identifies when a new bundle needs to be created and outlines (via a manifest) which assets to include in the bundle.
35
+ 2. Collect raw assets based on the manifest and run them through converters/preprocessors (if necessary) to convert them into valid CSS or JavaScript.
36
+ 3. Combine the processed assets into a single bundle, compress the bundled assets (if desired), and save the compressed bundle to the "_site" output folder.
37
+ 4. Replace `css_asset_tag` and `javascript_asset_tag` Liquid tags with HTML "link" and "script" tags, respectively, that link to finished bundles.
38
+
39
+ ## Getting Started
40
+
41
+ Jekyll Asset Pipeline is extremely easy to add to your Jekyll project and has no incremental dependancies beyond those required by Jekyll. Once you have a basic Jekyll site up and running, follow the steps below to install and configure Jekyll Asset Pipeline.
42
+
43
+ 1. Install the "japr" gem via [Rubygems](http://rubygems.org/).
44
+
45
+ ``` bash
46
+ $ gem install japr
47
+ ```
48
+
49
+ > *If you are using [Bundler](http://gembundler.com/) to manage your project's gems, you can just add "japr" to your Gemfile and run `bundle install`.*
50
+
51
+ 2. Add a "\_plugins" folder to your project if you do not already have one. Within the "\_plugins" folder, add a file named "jekyll\_asset\_pipeline.rb" with the following require statement as its contents.
52
+
53
+ ``` ruby
54
+ require 'japr'
55
+ ```
56
+
57
+ 3. Move your assets into a Jekyll ignored folder (i.e. a folder that begins with an underscore "\_") so that Jekyll won't include these raw assets in the site output. I recommend using an "\_assets" folder to hold your site's assets.
58
+
59
+ 4. Add the following [Liquid](http://liquidmarkup.org/) blocks to your site's HTML "head" section. These blocks will be converted into HTML "link" and "script" tags that point to bundled assets. Within each block is a manifest of assets to include in the bundle. Assets are included in the same order that they are listed in the manifest. Replace the "foo" and "bar" assets with your site's assets. At this point we are just using plain old javascript and css files (hence the ".js" and ".css" extensions). See the [Asset Preprocessing](#asset-preprocessing) section to learn how to include files that must be preprocessed (e.g. CoffeeScript, Sass, Less, Erb, etc.). Name the bundle by including a string after the opening tag. We've named our bundles "global" in the below example.
60
+
61
+ ``` html
62
+ {% css_asset_tag global %}
63
+ - /_assets/foo.css
64
+ - /_assets/bar.css
65
+ {% endcss_asset_tag %}
66
+
67
+ {% javascript_asset_tag global %}
68
+ - /_assets/foo.js
69
+ - /_assets/bar.js
70
+ {% endjavascript_asset_tag %}
71
+ ```
72
+ > *Asset manifests must be formatted as YAML arrays and include full paths to each asset from the root of the project. YAML [does not allow tabbed markup](http://www.yaml.org/faq.html), so you must use spaces when indenting your YAML manifest or you will get an error when you compile your site. If you are using assets that must be preprocessed, you should append the appropriate extension (e.g. '.js.coffee', '.css.less') as discussed in the [Asset Preprocessing](#asset-preprocessing) section.*
73
+
74
+ 5. Run the `jekyll build` command to compile your site. You should see an output that includes the following Jekyll Asset Pipeline status messages.
75
+
76
+ ``` bash
77
+ $ jekyll build
78
+ Generating...
79
+ Asset Pipeline: Processing 'css_asset_tag' manifest 'global'
80
+ Asset Pipeline: Saved 'global-md5hash.css' to 'yoursitepath/assets'
81
+ Asset Pipeline: Processing 'javascript_asset_tag' manifest 'global'
82
+ Asset Pipeline: Saved 'global-md5hash.js' to 'yoursitepath/assets'
83
+ ```
84
+
85
+ > *If you do not see these messages, check that you have __not__ set Jekyll's "safe" option to "true" in your site's "_config.yml". If the "safe" option is set to "true", Jekyll will not run plugins.*
86
+
87
+ That is it! You should now have bundled assets. Look in the "_site" folder of your project for an "assets" folder that contains the bundled assets. HTML tags that point to these assets have been placed in the HTML output where you included the Liquid blocks. *You may notice that your assets have not been converted or compressed-- we will add that functionality next.*
88
+
89
+ ## Asset Preprocessing
90
+
91
+ Asset preprocessing (i.e. conversion) allows us to write our assets in languages such as [CoffeeScript](http://coffeescript.org/), [Sass](http://sass-lang.com/), [Less](http://lesscss.org/), [Erb](http://ruby-doc.org/stdlib-1.9.3/libdoc/erb/rdoc/ERB.html) or any other language. One of Jekyll Asset Pipeline's key strengths is that it works with __any__ preprocessing library that has a ruby wrapper. Adding a preprocessor is straightforward, but requires a small amount of additional code.
92
+
93
+ In the following example, we will add a preprocessor that converts CoffeeScript into JavaScript.
94
+
95
+ ### CoffeeScript
96
+
97
+ 1. In the "jekyll\_asset\_pipeline.rb" file that we created in the [Getting Started](#getting-started) section, add the following code to the end of the file (i.e. after the "require" statement).
98
+
99
+ ``` ruby
100
+ module JAPR
101
+ class CoffeeScriptConverter < JAPR::Converter
102
+ require 'coffee-script'
103
+
104
+ def self.filetype
105
+ '.coffee'
106
+ end
107
+
108
+ def convert
109
+ return CoffeeScript.compile(@content)
110
+ end
111
+ end
112
+ end
113
+ ```
114
+
115
+ > The above code adds a CoffeeScript converter. You can name a converter anything as long as it inherits from "JAPR::Converter". The "self.filetype" method defines the type of asset a converter will process (e.g. ".coffee" for CoffeeScript) based on the extension of the raw asset file. A "@content" instance variable that contains the raw content of our asset is made available within the converter. The converter should process this content and return the processed content (as a string) via a "convert" method.
116
+
117
+ 2. If you haven't already, you should now install any dependancies that are required by your converter. In our case, we need to install the "coffee-script" gem.
118
+
119
+ ``` bash
120
+ $ gem install coffee-script
121
+ ```
122
+
123
+ > *If you are using [Bundler](http://gembundler.com/) to manage your project's gems, you can just add "coffee-script" to your Gemfile and run `bundle install`.*
124
+
125
+ 3. Append a ".coffee" extension to the filename of any asset that should be converted with the `CoffeeScriptConverter`. For example, "foo.js" would become "foo.js.coffee".
126
+
127
+ 4. Run the `jekyll build` command to compile your site.
128
+
129
+ That is it! Your asset pipeline has converted any CoffeeScript assets into JavaScript before adding them to a bundle.
130
+
131
+ ### SASS/SCSS
132
+
133
+ You probably get the gist of how converters work, but I thought I'd add an example of a SASS converter for quick reference.
134
+
135
+ ``` ruby
136
+ module JAPR
137
+ class SassConverter < JAPR::Converter
138
+ require 'sass'
139
+
140
+ def self.filetype
141
+ '.scss'
142
+ end
143
+
144
+ def convert
145
+ return Sass::Engine.new(@content, syntax: :scss).render
146
+ end
147
+ end
148
+ end
149
+ ```
150
+
151
+ > *Don't forget to install the "sass" gem or add it to your Gemfile and run `bundle install` before you run the `jekyll build` command since the above SASS converter requires the "sass" library as a dependency.*
152
+
153
+ ### Successive Preprocessing
154
+
155
+ If you would like to run an asset through multiple preprocessors successively, you can do so by naming your assets with nested file extensions. Nest the extensions in the order (right to left) that the asset should be processed. For example, `.css.scss.erb` would first be processed by an "erb" preprocessor then by a "scss" preprocessor before being rendered. This convention is very similar to the convention used by the [Ruby on Rails asset pipeline](http://guides.rubyonrails.org/asset_pipeline.html#preprocessing).
156
+
157
+ > *Don't forget to define preprocessors for the extensions you use in your filenames, otherwise Jekyll Asset Pipeline will not process your asset.*
158
+
159
+ ## Asset Compression
160
+
161
+ Asset compression allows us to decrease the size of our assets and increase the speed of our site. One of Jekyll Asset Pipeline's key strengths is that it works with __any__ compression library that has a ruby wrapper. Adding asset compression is straightforward, but requires a small amount of additional code.
162
+
163
+ In the following example, we will add a compressor that uses Yahoo's YUI Compressor to compress our CSS and JavaScript assets.
164
+
165
+ ### Yahoo's YUI Compressor
166
+
167
+ 1. In the "jekyll\_asset\_pipeline.rb" file that we created in the "Getting Started" section, add the following code to the end of the file (i.e. after the "require" statement).
168
+
169
+ ``` ruby
170
+ module JAPR
171
+ class CssCompressor < JAPR::Compressor
172
+ require 'yui/compressor'
173
+
174
+ def self.filetype
175
+ '.css'
176
+ end
177
+
178
+ def compress
179
+ return YUI::CssCompressor.new.compress(@content)
180
+ end
181
+ end
182
+
183
+ class JavaScriptCompressor < JAPR::Compressor
184
+ require 'yui/compressor'
185
+
186
+ def self.filetype
187
+ '.js'
188
+ end
189
+
190
+ def compress
191
+ return YUI::JavaScriptCompressor.new(munge: true).compress(@content)
192
+ end
193
+ end
194
+ end
195
+ ```
196
+
197
+ > The above code adds a CSS and a JavaScript compressor. You can name a compressor anything as long as it inherits from "JAPR::Compressor". The "self.filetype" method defines the type of asset a compressor will process (either '.js' or '.css'). The "compress" method is where the magic happens. A "@content" instance variable that contains the raw content of our bundle is made available within the compressor. The compressor should process this content and return the processed content (as a string) via a "compress" method.
198
+
199
+ 2. If you haven't already, you should now install any dependencies that are required by your compressor. In our case, we need to install the "yui-compressor" gem.
200
+
201
+ ``` ruby
202
+ $ gem install yui-compressor
203
+ ```
204
+
205
+ > *If you are using [Bundler](http://gembundler.com/) to manage your project's gems, you can just add "yui-compressor" to your Gemfile and run `bundle install`.*
206
+
207
+ 3. Run the `jekyll build` command to compile your site.
208
+
209
+ That is it! Your asset pipeline has compressed your CSS and JavaScript assets. You can verify that this is the case by looking at the contents of the bundles generated in the "\_site/assets" folder of your project.
210
+
211
+ ### Google's Closure Compiler
212
+
213
+ You probably get the gist of how compressors work, but I thought I'd add an example of a Google Closure Compiler compressor for quick reference.
214
+
215
+ ``` ruby
216
+ class JavaScriptCompressor < JAPR::Compressor
217
+ require 'closure-compiler'
218
+
219
+ def self.filetype
220
+ '.js'
221
+ end
222
+
223
+ def compress
224
+ return Closure::Compiler.new.compile(@content)
225
+ end
226
+ end
227
+ ```
228
+ > *Don't forget to install the "closure-compiler" gem before you run the `jekyll build` command since the above compressor requires the "closure-compiler" library as a dependency.*
229
+
230
+ ## Templates
231
+
232
+ When Jekyll Asset Pipeline creates a bundle, it returns an HTML tag that points to the bundle. This tag is either a "link" tag for CSS or a "script" tag for JavaScript. Under most circumstances the default tags will suffice, but you may want to customize this output for special cases (e.g. if you want to add a CSS media attribute).
233
+
234
+ In the following example, we will override the default CSS link tag by adding a custom template that produces a link tag with a "media" attribute.
235
+
236
+ 1. In the "jekyll\_asset\_pipeline.rb" file that we created in the "Getting Started" section, add the following code.
237
+
238
+ ``` ruby
239
+ module JAPR
240
+ class CssTagTemplate < JAPR::Template
241
+ def self.filetype
242
+ '.css'
243
+ end
244
+
245
+ def html
246
+ "<link href='/#{@path}/#{@filename}' rel='stylesheet' type='text/css' media='screen' />\n"
247
+ end
248
+ end
249
+ end
250
+ ```
251
+
252
+ > *If you already added a compressor and/or a converter, you can include your template class alongside your compressor and/or converter within the same JAPR module.*
253
+
254
+ > The “self.filetype” method defines the type of bundle a template will target (either ".js" or ".css"). The “html” method is where the magic happens. “@path” and "@filename" instance variables are available within the class and contain the path and filename of the generated bundle, respectively. The template should return a string that contains an HTML tag pointing to the generated bundle via an "html" method.
255
+
256
+ 2. Run the `jekyll` command to compile your site.
257
+
258
+ That is it! Your asset pipeline used your template to generate an HTML "link" tag that includes a media attribute with the value "screen". You can verify that this is the case by viewing the generated source within your project's "\_site" folder.
259
+
260
+ ## Configuration
261
+
262
+ Jekyll Asset Pipeline provides the following configuration options that can be controlled by adding the following to the end of your project's "\_config.yml" file.
263
+
264
+ ``` yaml
265
+ asset_pipeline:
266
+ bundle: true # Default = true
267
+ compress: true # Default = true
268
+ output_path: assets # Default = assets
269
+ display_path: nil # Default = nil
270
+ gzip: false # Default = false
271
+ ```
272
+
273
+ > *If you don't have a "\_config.yml" file, consider reading the [configuration section](https://github.com/mojombo/jekyll/wiki/Configuration) of the Jekyll documentation.*
274
+ >
275
+ > - The "bundle" setting controls whether Jekyll Asset Pipeline bundles the assets defined in each manifest. If "bundle" is set to false, each asset will be saved individually and individual html tags pointing to each unbundled asset will be produced when you compile your site. It is useful to set this to false while you are debugging your site.
276
+ > - The "compress" setting tells Jekyll Asset Pipeline whether or not to compress the bundled assets. It is useful to set this setting to "false" while you are debugging your site.
277
+ > - The "output\_path" setting defines where generated bundles should be saved within the "\_site" folder of your project.
278
+ > - The "display\_path" setting overrides the path to assets in generated html tags. This is useful if you are hosting your site at a path other than the root of your domain (e.g. "http://example.com/blog/").
279
+ > - The "gzip" setting controls whether Jekyll Asset Pipeline saves gzipped versions of your assets alongside un-gzipped versions.
280
+
281
+ ## Octopress
282
+
283
+ [Octopress](http://octopress.org/) is a popular framework for Jekyll that can help you get a blog up and running quickly. Jekyll Asset Pipeline can be added to an Octopress site using the [Getting Started](#getting-started) steps above with the following modifications:
284
+
285
+ 1. Octopress uses Bundler to manage your site's dependencies. You should add `gem "japr"` to your Gemfile and then run `bundle install` to install.
286
+
287
+ 2. Instead of adding a "\_plugins" folder, you should put "jekyll\_asset\_pipeline.rb" in the "plugins" folder included by default in the root of your Octopress site.
288
+
289
+ 3. You should still store your assets in an Jekyll ignored folder (i.e. a folder that begins with an underscore "\_"), but note that this folder should be located within the "source" folder of your Octopress site (e.g. "source/\_assets").
290
+
291
+ 4. No change to this step.
292
+
293
+ 5. Instead of running the `jekyll` command to compile your site, you should use Octopress' rake commands (e.g. `rake generate`) as outlined [here](http://octopress.org/docs/blogging/).
294
+
295
+ If you have any difficulties using Jekyll Asset Pipeline with Octopress, please [open an issue](http://github.com/kitsched/japr/issues).
296
+
297
+ ## Contribute
298
+
299
+ You can contribute to the Jekyll Asset Pipeline by submitting a pull request [via GitHub](https://github.com/matthodan/japr). I have identified the following areas for improvement:
300
+
301
+ - __Tests, tests, tests.__ I'm embarrassed to say that I didn't write a single test while building Jekyll Asset Pipeline. This started as a hack for my blog and quickly grew into a library as I tweaked it to support my own needs. **This project is now fully tested.**
302
+ - __Handle remote assets.__ Right now, Jekyll Asset Pipeline does not provide any way to include remote assets in bundles unless you save them locally before generating your site. Moshen's [Jekyll Asset Bundler](https://github.com/moshen/jekyll-asset_bundler) allows you to include remote assets, which I thought was pretty interesting. That said, I think it is generally better to keep remote assets separate so that they load asynchronously. **After some thought, I've decided that this is not a priority. If you disagree, let me know.**
303
+ - __Successive preprocessing.__ Currently you can only preprocess a file once. It would be better if you could run an asset through multiple preprocessors before it gets compressed and bundled. **As of v0.1.0, Jekyll Asset Pipeline now supports successive preprocessing.**
304
+
305
+ Feel free to message me on [Twitter](http://twitter.com/matthodan) or [Facebook](http://facebook.com/matthodan).
306
+
307
+ ## Community
308
+
309
+ - Here is a list of [sites that use Jekyll Asset Pipeline](http://github.com/kitsched/japr/wiki/Sites-that-use-Jekyll-Asset-Pipeline). Feel free to add your site to the list if you want.
310
+
311
+ ## Code Status
312
+
313
+ - [![Build Status](https://secure.travis-ci.org/kitsched/japr.png)](https://travis-ci.org/kitsched/japr)
314
+ - [![Dependency Status](https://gemnasium.com/kitsched/japr.png)](https://gemnasium.com/kitsched/japr)
315
+ - [![Code Climate](https://codeclimate.com/github/kitsched/japr.png)](https://codeclimate.com/github/kitsched/japr)
316
+
317
+ ## Credits
318
+
319
+ As I was building Jekyll Asset Pipeline, I came across a number of tools that I was able to draw inspiration and best practices from, but one stood out in particular... I have to give credit to [Moshen](https://github.com/moshen/) for creating the [Jekyll Asset Bundler](https://github.com/moshen/jekyll-asset_bundler).
320
+
321
+ I also have to give credit to [Mojombo](https://github.com/mojombo) for creating [Jekyll](https://github.com/mojombo/jekyll) in the first place.
322
+
323
+ ## License
324
+
325
+ Jekyll Asset Pipeline is released under the [MIT License](http://opensource.org/licenses/MIT).
326
+
327
+ ---
328
+
329
+ Like this project? You may want to read [my blog](http://www.matthodan.com).
data/lib/japr.rb ADDED
@@ -0,0 +1,54 @@
1
+ # Stdlib dependencies
2
+ require 'digest/md5'
3
+ require 'fileutils'
4
+ require 'time'
5
+ require 'yaml'
6
+ require 'zlib'
7
+
8
+ # Third-party dependencies
9
+ require 'jekyll'
10
+ require 'liquid'
11
+
12
+ # Jekyll extensions
13
+ require 'japr/extensions/jekyll/site_extensions'
14
+ require 'japr/extensions/jekyll/site'
15
+
16
+ # Liquid extensions
17
+ require 'japr/extensions/liquid/liquid_block_extensions'
18
+ require 'japr/extensions/liquid/asset_tag'
19
+ require 'japr/extensions/liquid/asset_tags/css_asset_tag'
20
+ require 'japr/extensions/liquid/asset_tags/javascript_asset_tag'
21
+
22
+ # Ruby extensions
23
+ require 'japr/extensions/ruby/subclass_tracking'
24
+
25
+ # Jekyll Asset Pipeline
26
+ require 'japr/version'
27
+ require 'japr/asset'
28
+ require 'japr/converter'
29
+ require 'japr/compressor'
30
+ require 'japr/template'
31
+ require 'japr/templates/javascript_tag_template'
32
+ require 'japr/templates/css_tag_template'
33
+ require 'japr/pipeline'
34
+
35
+ module JAPR
36
+ # Default configuration settings for Jekyll Asset Pipeline
37
+ # Strings used for keys to play nice when merging with _config.yml
38
+ #
39
+ # 'output_path' Destination for bundle file (within the '_site' directory)
40
+ # 'display_path' Optional. Override path to assets for output HTML refs
41
+ # 'staging_path' Destination for staged assets (within project root directory)
42
+ # 'bundle' true = Bundle assets, false = Leave assets unbundled
43
+ # 'compress' true = Minify assets, false = Leave assets unminified
44
+ # 'gzip' true = Create gzip versions, false = Do not create gzip versions
45
+ #
46
+ DEFAULTS = {
47
+ 'output_path' => 'assets',
48
+ 'display_path' => nil,
49
+ 'staging_path' => '.asset_pipeline',
50
+ 'bundle' => true,
51
+ 'compress' => true,
52
+ 'gzip' => false
53
+ }
54
+ end
data/lib/japr/asset.rb ADDED
@@ -0,0 +1,10 @@
1
+ module JAPR
2
+ class Asset
3
+ def initialize(content, filename)
4
+ @content = content
5
+ @filename = filename
6
+ end
7
+
8
+ attr_accessor :content, :filename, :output_path
9
+ end
10
+ end
@@ -0,0 +1,30 @@
1
+ module JAPR
2
+ class Compressor
3
+ extend JAPR::SubclassTracking
4
+
5
+ def initialize(content)
6
+ @content = content
7
+ @compressed = self.compress
8
+ end
9
+
10
+ # Returns compressed content
11
+ def compressed
12
+ @compressed
13
+ end
14
+
15
+ # Filetype to process (e.g. '.js')
16
+ def self.filetype
17
+ ''
18
+ end
19
+
20
+ # Logic to compress assets
21
+ #
22
+ # Available instance variables:
23
+ # @content Content to be compressed
24
+ #
25
+ # Returns compressed string
26
+ def compress
27
+ @content
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,32 @@
1
+ module JAPR
2
+ class Converter
3
+ extend JAPR::SubclassTracking
4
+
5
+ def initialize(asset)
6
+ @content = asset.content
7
+ @type = File.extname(asset.filename).downcase
8
+ @converted = self.convert
9
+ end
10
+
11
+ def converted
12
+ @converted
13
+ end
14
+
15
+ # Filetype to process (e.g. '.coffee')
16
+ def self.filetype
17
+ ''
18
+ end
19
+
20
+ # Logic to convert assets
21
+ #
22
+ # Available instance variables:
23
+ # @file File to be converted
24
+ # @content Contents of @file as a string
25
+ # @type Filetype of file (e.g. '.coffee')
26
+ #
27
+ # Returns converted string
28
+ def convert
29
+ @content
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,5 @@
1
+ module Jekyll
2
+ class Site
3
+ include JAPR::JekyllSiteExtensions
4
+ end
5
+ end
@@ -0,0 +1,36 @@
1
+ module JAPR
2
+ module JekyllSiteExtensions
3
+ def self.included(base)
4
+ base.class_eval do
5
+ # Store the original Jekyll::Site#cleanup method
6
+ old_cleanup_method = instance_method(:cleanup)
7
+
8
+ # Override Jekyll::Site#cleanup
9
+ define_method(:cleanup) do
10
+ # Run the Jekyll::Site#cleanup method
11
+ original_return_val = old_cleanup_method.bind(self).call()
12
+
13
+ # Clear Jekyll Asset Pipeline cache
14
+ Pipeline.clear_cache
15
+
16
+ original_return_val
17
+ end
18
+
19
+ # Store the original Jekyll::Site#write method
20
+ old_write_method = instance_method(:write)
21
+
22
+ # Override Jekyll::Site#write
23
+ define_method(:write) do
24
+ # Run the Jekyll::Site#write method
25
+ original_return_value = old_write_method.bind(self).call()
26
+
27
+ # Clear Jekyll Asset Pipeline staged assets
28
+ config = self.config['asset_pipeline'] || {}
29
+ Pipeline.remove_staged_assets(self.source, config)
30
+
31
+ original_return_value
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,6 @@
1
+ module JAPR
2
+ class AssetTag < ::Liquid::Block
3
+ extend JAPR::LiquidBlockExtensions::ClassMethods
4
+ include JAPR::LiquidBlockExtensions
5
+ end
6
+ end
@@ -0,0 +1,14 @@
1
+ module JAPR
2
+ class CssAssetTag < JAPR::AssetTag
3
+ def self.tag_name
4
+ 'css_asset_tag'
5
+ end
6
+
7
+ def self.output_type
8
+ '.css'
9
+ end
10
+ end
11
+
12
+ # Register CssAssetTag tag with Liquid
13
+ ::Liquid::Template.register_tag(JAPR::CssAssetTag.tag_name, JAPR::CssAssetTag)
14
+ end
@@ -0,0 +1,14 @@
1
+ module JAPR
2
+ class JavaScriptAssetTag < JAPR::AssetTag
3
+ def self.tag_name
4
+ 'javascript_asset_tag'
5
+ end
6
+
7
+ def self.output_type
8
+ '.js'
9
+ end
10
+ end
11
+
12
+ # Register JavaScriptAssetTag tag with Liquid
13
+ ::Liquid::Template.register_tag(JAPR::JavaScriptAssetTag.tag_name, JAPR::JavaScriptAssetTag)
14
+ end
@@ -0,0 +1,38 @@
1
+ module JAPR
2
+ module LiquidBlockExtensions
3
+ module ClassMethods
4
+ def output_type
5
+ ''
6
+ end
7
+
8
+ def tag_name
9
+ ''
10
+ end
11
+ end
12
+
13
+ def render(context)
14
+ site = context.registers[:site]
15
+ config = site.config['asset_pipeline'] || {}
16
+
17
+ # Run Jekyll Asset Pipeline
18
+ pipeline, cached = Pipeline.run(@nodelist.first, @markup.strip, site.source,
19
+ site.dest, self.class.tag_name, self.class.output_type, config)
20
+
21
+ if pipeline.is_a?(Pipeline)
22
+ # Prevent Jekyll from cleaning up saved assets if new pipeline
23
+ pipeline.assets.each do |asset|
24
+ config = JAPR::DEFAULTS.merge(config)
25
+ staging_path = File.expand_path(File.join(site.source, config['staging_path']))
26
+ site.static_files << Jekyll::StaticFile.new(site, staging_path,
27
+ asset.output_path, asset.filename)
28
+ end unless cached
29
+
30
+ # Return HTML tag pointing to asset
31
+ return pipeline.html
32
+ else
33
+ # Return nothing
34
+ return nil
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,13 @@
1
+ module JAPR
2
+ module SubclassTracking
3
+ # Record subclasses of this class (this method is automatically called by ruby)
4
+ def inherited(base)
5
+ subclasses << base
6
+ end
7
+
8
+ # Return an array of classes that are subclasses of this object
9
+ def subclasses
10
+ @subclasses ||= []
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,233 @@
1
+ module JAPR
2
+ class Pipeline
3
+ class << self
4
+ # Generate hash based on manifest
5
+ def hash(source, manifest, options = {})
6
+ options = DEFAULTS.merge(options)
7
+ begin
8
+ Digest::MD5.hexdigest(YAML::load(manifest).map! do |path|
9
+ "#{path}#{File.mtime(File.join(source, path)).to_i}"
10
+ end.join.concat(options.to_s))
11
+ rescue Exception => e
12
+ puts "Failed to generate hash from provided manifest."
13
+ raise e
14
+ end
15
+ end
16
+
17
+ # Run pipeline
18
+ def run(manifest, prefix, source, destination, tag, type, config)
19
+ # Get hash for pipeline
20
+ hash = hash(source, manifest, config)
21
+
22
+ # Check if pipeline has been cached
23
+ if cache.has_key?(hash)
24
+ # Return cached pipeline and cached status
25
+ return cache[hash], true
26
+ else
27
+ begin
28
+ puts "Processing '#{tag}' manifest '#{prefix}'"
29
+
30
+ # Create and process new pipeline
31
+ pipeline = self.new(manifest, prefix, source, destination, type, config)
32
+ pipeline.assets.each do |asset|
33
+ puts "Saved '#{asset.filename}' to '#{destination}/#{asset.output_path}'"
34
+ end
35
+
36
+ # Add processed pipeline to cache
37
+ cache[hash] = pipeline
38
+
39
+ # Return newly processed pipeline and cached status
40
+ return pipeline, false
41
+ rescue Exception => e
42
+ # Add exception to cache
43
+ cache[hash] = e
44
+
45
+ # Re-raise the exception
46
+ raise e
47
+ end
48
+ end
49
+ end
50
+
51
+ # Cache processed pipelines
52
+ def cache
53
+ @cache ||= {}
54
+ end
55
+
56
+ # Empty cache
57
+ def clear_cache
58
+ @cache = {}
59
+ end
60
+
61
+ # Remove staged assets
62
+ def remove_staged_assets(source, config)
63
+ begin
64
+ config = DEFAULTS.merge(config)
65
+ staging_path = File.join(source, config['staging_path'])
66
+ FileUtils.rm_rf(staging_path)
67
+ rescue Exception => e
68
+ puts "Failed to remove staged assets."
69
+
70
+ # Re-raise the exception
71
+ raise e
72
+ end
73
+ end
74
+
75
+ # Add prefix to output
76
+ def puts(message)
77
+ $stdout.puts("Asset Pipeline: #{message}")
78
+ end
79
+ end
80
+
81
+ # Initialize new pipeline
82
+ def initialize(manifest, prefix, source, destination, type, options = {})
83
+ @manifest = manifest
84
+ @prefix = prefix
85
+ @source = source
86
+ @destination = destination
87
+ @type = type
88
+ @options = JAPR::DEFAULTS.merge(options)
89
+
90
+ process
91
+ end
92
+
93
+ attr_reader :assets, :html
94
+
95
+ private
96
+
97
+ # Process the pipeline
98
+ def process
99
+ collect
100
+ convert
101
+ bundle if @options['bundle']
102
+ compress if @options['compress']
103
+ gzip if @options['gzip']
104
+ save
105
+ markup
106
+ end
107
+
108
+ # Collect assets based on manifest
109
+ def collect
110
+ begin
111
+ @assets = YAML::load(@manifest).map! do |path|
112
+ File.open(File.join(@source, path)) do |file|
113
+ JAPR::Asset.new(file.read, File.basename(path))
114
+ end
115
+ end
116
+ rescue Exception => e
117
+ puts "Asset Pipeline: Failed to load assets from provided manifest."
118
+ raise e
119
+ end
120
+ end
121
+
122
+ # Convert assets based on the file extension if converter is defined
123
+ def convert
124
+ @assets.each do |asset|
125
+ # Convert asset multiple times if more than one converter is found
126
+ finished = false
127
+ while finished == false
128
+ # Find a converter to use
129
+ klass = JAPR::Converter.subclasses.select do |c|
130
+ c.filetype == File.extname(asset.filename).downcase
131
+ end.last
132
+
133
+ # Convert asset if converter is found
134
+ unless klass.nil?
135
+ begin
136
+ # Convert asset content
137
+ converter = klass.new(asset)
138
+
139
+ # Replace asset content and filename
140
+ asset.content = converter.converted
141
+ asset.filename = File.basename(asset.filename, '.*')
142
+
143
+ # Add back the output extension if no extension left
144
+ asset.filename = "#{asset.filename}#{@type}" if File.extname(asset.filename) == ''
145
+ rescue Exception => e
146
+ puts "Asset Pipeline: Failed to convert '#{asset.filename}' with '#{klass.to_s}'."
147
+ raise e
148
+ end
149
+ else
150
+ finished = true
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ # Bundle multiple assets into a single asset
157
+ def bundle
158
+ content = @assets.map do |a|
159
+ a.content
160
+ end.join("\n")
161
+
162
+ hash = JAPR::Pipeline.hash(@source, @manifest, @options)
163
+ @assets = [JAPR::Asset.new(content, "#{@prefix}-#{hash}#{@type}")]
164
+ end
165
+
166
+ # Compress assets if compressor is defined
167
+ def compress
168
+ @assets.each do |asset|
169
+ # Find a compressor to use
170
+ klass = JAPR::Compressor.subclasses.select do |c|
171
+ c.filetype == @type
172
+ end.last
173
+
174
+ unless klass.nil?
175
+ begin
176
+ asset.content = klass.new(asset.content).compressed
177
+ rescue Exception => e
178
+ puts "Asset Pipeline: Failed to compress '#{asset.filename}' with '#{klass.to_s}'."
179
+ raise e
180
+ end
181
+ end
182
+ end
183
+ end
184
+
185
+ # Create Gzip versions of assets
186
+ def gzip
187
+ @assets.map! do |asset|
188
+ gzip_content = Zlib::Deflate.deflate(asset.content)
189
+ [asset, JAPR::Asset.new(gzip_content, "#{asset.filename}.gz")]
190
+ end.flatten!
191
+ end
192
+
193
+ # Save assets to file
194
+ def save
195
+ output_path = @options['output_path']
196
+ staging_path = @options['staging_path']
197
+
198
+ @assets.each do |asset|
199
+ directory = File.join(@source, staging_path, output_path)
200
+ FileUtils::mkpath(directory) unless File.directory?(directory)
201
+
202
+ begin
203
+ # Save file to disk
204
+ File.open(File.join(directory, asset.filename), 'w') do |file|
205
+ file.write(asset.content)
206
+ end
207
+ rescue Exception => e
208
+ puts "Asset Pipeline: Failed to save '#{asset.filename}' to disk."
209
+ raise e
210
+ end
211
+
212
+ # Store output path of saved file
213
+ asset.output_path = output_path
214
+ end
215
+ end
216
+
217
+ # Generate html markup pointing to assets
218
+ def markup
219
+ # Use display_path if defined, otherwise use output_path in url
220
+ display_path = @options['display_path'] || @options['output_path']
221
+
222
+ @html = @assets.map do |asset|
223
+ klass = JAPR::Template.subclasses.select do |t|
224
+ t.filetype == File.extname(asset.filename).downcase
225
+ end.sort! { |x, y| x.priority <=> y.priority }.last
226
+
227
+ html = klass.new(display_path, asset.filename).html unless klass.nil?
228
+
229
+ html
230
+ end.join
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,31 @@
1
+ module JAPR
2
+ class Template
3
+ extend JAPR::SubclassTracking
4
+
5
+ def initialize(path, filename)
6
+ @path = path
7
+ @filename = filename
8
+ end
9
+
10
+ # Filetype to process (e.g. '.js')
11
+ def self.filetype
12
+ ''
13
+ end
14
+
15
+ # Priority of template (to override default templates)
16
+ def self.priority
17
+ 0
18
+ end
19
+
20
+ # HTML output to return
21
+ #
22
+ # Available instance variables:
23
+ # @filename Name of bundle file
24
+ # @path Path to bundle file
25
+ #
26
+ # Returns string
27
+ def html
28
+ "#{@path}/#{@filename}\n"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,16 @@
1
+ module JAPR
2
+ # Default output for CSS assets
3
+ class CssTagTemplate < JAPR::Template
4
+ def self.filetype
5
+ '.css'
6
+ end
7
+
8
+ def self.priority
9
+ -1
10
+ end
11
+
12
+ def html
13
+ "<link href='/#{@path}/#{@filename}' rel='stylesheet' type='text/css' />\n"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module JAPR
2
+ # Default output for JavaScript assets
3
+ class JavaScriptTagTemplate < JAPR::Template
4
+ def self.filetype
5
+ '.js'
6
+ end
7
+
8
+ def self.priority
9
+ -1
10
+ end
11
+
12
+ def html
13
+ "<script src='/#{@path}/#{@filename}' type='text/javascript'></script>\n"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ module JAPR
2
+ VERSION = '0.2.1'
3
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: japr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Matt Hodan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jekyll
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: liquid
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '2.4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '2.4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '5.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '5.2'
69
+ description: Adds asset preprocessing (CoffeeScript, Sass, Less, ERB, etc.) and asset
70
+ compression/minification/gzip (Yahoo YUI Compressor, Google Closure Compiler, etc.)
71
+ to Jekyll.
72
+ email: japr@clicktrackheart.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - LICENSE
78
+ - README.md
79
+ - lib/japr.rb
80
+ - lib/japr/asset.rb
81
+ - lib/japr/compressor.rb
82
+ - lib/japr/converter.rb
83
+ - lib/japr/extensions/jekyll/site.rb
84
+ - lib/japr/extensions/jekyll/site_extensions.rb
85
+ - lib/japr/extensions/liquid/asset_tag.rb
86
+ - lib/japr/extensions/liquid/asset_tags/css_asset_tag.rb
87
+ - lib/japr/extensions/liquid/asset_tags/javascript_asset_tag.rb
88
+ - lib/japr/extensions/liquid/liquid_block_extensions.rb
89
+ - lib/japr/extensions/ruby/subclass_tracking.rb
90
+ - lib/japr/pipeline.rb
91
+ - lib/japr/template.rb
92
+ - lib/japr/templates/css_tag_template.rb
93
+ - lib/japr/templates/javascript_tag_template.rb
94
+ - lib/japr/version.rb
95
+ homepage: https://github.com/kitsched/japr
96
+ licenses:
97
+ - MIT
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ! '>='
106
+ - !ruby/object:Gem::Version
107
+ version: 1.9.3
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.2.1
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: A powerful asset pipeline for Jekyll that bundles, converts, and minifies
119
+ CSS and JavaScript assets.
120
+ test_files: []