jekyll-minibundle 0.2.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.md CHANGED
@@ -1,3 +1,10 @@
1
+ ### 1.0.0 / 2013-02-15
2
+
3
+ * Add development mode, where `minibundle` block will copy each asset
4
+ as-is to the destination directory
5
+ * Clarify documentation
6
+ * Increase test coverage
7
+
1
8
  ### 0.2.0 / 2012-12-15
2
9
 
3
10
  * Escape the values of custom attributes given in `minibundle` block
data/Readme.md CHANGED
@@ -50,8 +50,7 @@ this line:
50
50
 
51
51
  Asset stamping is intended to be used together with
52
52
  [Compass](http://compass-style.org/) and other similar asset
53
- generation tools where you do not want to include unprocessed input
54
- assets in the generated site.
53
+ generation tools that have their own configuration for input sources.
55
54
 
56
55
  Configure Compass to take inputs from `_assets/styles/*.scss` and to
57
56
  put output to `_tmp/site.css`. Use `ministamp` tag to copy the
@@ -59,7 +58,7 @@ processed style asset to the generated site:
59
58
 
60
59
  <link href="{% ministamp _tmp/site.css assets/site.css %}" rel="stylesheet" media="screen, projection">
61
60
 
62
- Output, containing the MD5 digest in the filename:
61
+ Output, containing the MD5 digest of the file in the filename:
63
62
 
64
63
  <link href="assets/site-390be921ee0eff063817bb5ef2954300.css" rel="stylesheet" media="screen, projection">
65
64
 
@@ -67,13 +66,17 @@ This feature does not require any external tools.
67
66
 
68
67
  ## Asset bundling
69
68
 
70
- A straightforward way to bundle assets with any tool that supports
71
- reading input files from STDIN and writing the output to STDOUT. The
72
- bundled file has MD5 digest in the filename.
69
+ This is a straightforward way to bundle assets with any tool that
70
+ supports reading input from STDIN and writing the output to STDOUT.
71
+ You write the configuration for input sources directly into the
72
+ content file where you want the markup tag for the bundle file to
73
+ appear. The outcome will be a markup tag containing the path to the
74
+ bundle file, and the generated site will have the bundle file in that
75
+ path. The MD5 digest of the file will be included in the filename.
73
76
 
74
- Place `minibundle` block with configuration to your content file where
75
- you want the generated markup to appear. For example, for bundling
76
- JavaScript sources:
77
+ Place `minibundle` block with configuration into your content file
78
+ where you want the generated markup to appear. For example, to bundle
79
+ a set of JavaScript sources:
77
80
 
78
81
  {% minibundle js %}
79
82
  source_dir: _assets/scripts
@@ -89,12 +92,12 @@ Then, specify the command for launching your favorite bundling tool in
89
92
  `$JEKYLL_MINIBUNDLE_CMD_JS` environment variable. For example, when
90
93
  launching Jekyll:
91
94
 
92
- $ JEKYLL_MINIBUNDLE_CMD_JS="./node_modules/.bin/uglifyjs --" jekyll
95
+ $ JEKYLL_MINIBUNDLE_CMD_JS='./node_modules/.bin/uglifyjs --' jekyll
93
96
 
94
97
  You can pass custom attributes to the generated markup with
95
98
  `attributes` map in the configuration.
96
99
 
97
- Output:
100
+ Output in the content file:
98
101
 
99
102
  <script src="assets/site-8e764372a0dbd296033cb2a416f064b5.js" type="text/javascript" id="my-scripts"></script>
100
103
 
@@ -113,6 +116,16 @@ For bundling CSS assets, you use `css` as the argument to `minibundle` block:
113
116
  And then specify the command for launching bundling in
114
117
  `$JEKYLL_MINIBUNDLE_CMD_CSS` environment variable.
115
118
 
119
+ ## Development mode
120
+
121
+ For your development workflow, asset bundling can get in the way. To
122
+ remedy this, you can instruct the library into development mode. Then,
123
+ `minibundle` block will not bundle assets, but copy each asset as-is
124
+ to the destination directory under the path specified in
125
+ `destination_path` configuration setting.
126
+
127
+ $ JEKYLL_MINIBUNDLE_MODE=development jekyll --auto --server
128
+
116
129
  # Example site
117
130
 
118
131
  See the contents of `test/fixture/site` directory.
@@ -1,7 +1,7 @@
1
1
  require 'fileutils'
2
2
 
3
3
  module Jekyll::Minibundle
4
- module AssetFileSupport
4
+ module AssetFileOperations
5
5
  def static_file!(site)
6
6
  static_file_exists = site.static_files.find { |f| f.path == path }
7
7
  site.static_files << self unless static_file_exists
@@ -0,0 +1,27 @@
1
+ module Jekyll::Minibundle
2
+ module AssetFilePaths
3
+ def path
4
+ asset_source_path
5
+ end
6
+
7
+ def asset_path
8
+ File.join asset_destination_dir, asset_destination_basename
9
+ end
10
+
11
+ def destination(site_destination_dir)
12
+ File.join site_destination_dir, asset_destination_dir, asset_destination_basename
13
+ end
14
+
15
+ def destination_exists?(site_destination_dir)
16
+ File.exists? destination(site_destination_dir)
17
+ end
18
+
19
+ def mtime
20
+ File.stat(path).mtime.to_i
21
+ end
22
+
23
+ def modified?
24
+ last_mtime_of(path) != mtime
25
+ end
26
+ end
27
+ end
@@ -1,7 +1,7 @@
1
1
  require 'cgi'
2
2
 
3
3
  module Jekyll::Minibundle
4
- module BundleMarkup
4
+ module AssetTagMarkup
5
5
  def self.make_markup(type, path, attributes)
6
6
  case type
7
7
  when :js
@@ -1,12 +1,13 @@
1
1
  require 'jekyll/minibundle/asset_bundle'
2
- require 'jekyll/minibundle/asset_file_support'
3
- require 'jekyll/minibundle/bundle_markup'
2
+ require 'jekyll/minibundle/asset_file_operations'
3
+ require 'jekyll/minibundle/asset_stamp'
4
+ require 'jekyll/minibundle/asset_tag_markup'
4
5
 
5
6
  module Jekyll::Minibundle
6
7
  class BundleFile
7
- include AssetFileSupport
8
+ include AssetFileOperations
8
9
 
9
- @@mtimes = Hash.new
10
+ @@mtimes = {}
10
11
 
11
12
  def initialize(config)
12
13
  @type = config['type']
@@ -15,7 +16,6 @@ module Jekyll::Minibundle
15
16
  @assets = config['assets'].map { |asset_path| File.join asset_source_dir, "#{asset_path}.#{@type}" }
16
17
  @asset_destination_path = config['destination_path']
17
18
  @attributes = config['attributes']
18
- update_mtime
19
19
  end
20
20
 
21
21
  def path
@@ -39,19 +39,21 @@ module Jekyll::Minibundle
39
39
  end
40
40
 
41
41
  def write(site_destination_dir)
42
- rebundle_assets if modified?
43
- destination_path = destination site_destination_dir
42
+ is_modified = modified?
44
43
 
45
- return false if File.exist?(destination_path) and !modified?
44
+ rebundle_assets if is_modified
46
45
 
47
- update_mtime
48
- write_destination site_destination_dir
49
-
50
- true
46
+ if File.exists?(destination(site_destination_dir)) && !is_modified
47
+ false
48
+ else
49
+ update_mtime
50
+ write_destination site_destination_dir
51
+ true
52
+ end
51
53
  end
52
54
 
53
55
  def markup
54
- BundleMarkup.make_markup @type, asset_path, @attributes
56
+ AssetTagMarkup.make_markup @type, asset_path, @attributes
55
57
  end
56
58
 
57
59
  private
@@ -0,0 +1,39 @@
1
+ require 'jekyll/minibundle/asset_file_operations'
2
+ require 'jekyll/minibundle/asset_file_paths'
3
+
4
+ module Jekyll::Minibundle
5
+ class DevelopmentFile
6
+ include AssetFileOperations
7
+ include AssetFilePaths
8
+
9
+ @@mtimes = {}
10
+
11
+ attr_reader :asset_source_path, :asset_destination_dir, :asset_destination_basename
12
+
13
+ def initialize(asset_source_path, asset_destination_path)
14
+ @asset_source_path = asset_source_path
15
+ @asset_destination_dir = File.dirname asset_destination_path
16
+ @asset_destination_basename = File.basename asset_destination_path
17
+ end
18
+
19
+ def last_mtime_of(path)
20
+ @@mtimes[path]
21
+ end
22
+
23
+ def write(site_destination_dir)
24
+ if destination_exists?(site_destination_dir) && !modified?
25
+ false
26
+ else
27
+ update_mtime
28
+ write_destination site_destination_dir
29
+ true
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def update_mtime
36
+ @@mtimes[path] = mtime
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,34 @@
1
+ require 'jekyll/minibundle/asset_tag_markup'
2
+ require 'jekyll/minibundle/development_file'
3
+
4
+ module Jekyll::Minibundle
5
+ class DevelopmentFileCollection
6
+ def initialize(config)
7
+ @type = config['type']
8
+ asset_source_dir = File.join config['site_dir'], config['source_dir']
9
+ asset_destination_path = config['destination_path']
10
+
11
+ @files = config['assets'].map do |asset_path|
12
+ asset_basename = "#{asset_path}.#{@type}"
13
+ asset_source = File.join asset_source_dir, asset_basename
14
+ asset_destination = File.join asset_destination_path, asset_basename
15
+ DevelopmentFile.new asset_source, asset_destination
16
+ end
17
+
18
+ @attributes = config['attributes']
19
+ end
20
+
21
+ def static_file!(site)
22
+ # NOTE: We could optimize here by iterating over site's static
23
+ # files only once instead of per each of our file. Seems like a
24
+ # premature optimization for now, however.
25
+ @files.each { |f| f.static_file! site }
26
+ end
27
+
28
+ def markup
29
+ @files.
30
+ map { |f| AssetTagMarkup.make_markup @type, f.asset_path, @attributes }.
31
+ join('')
32
+ end
33
+ end
34
+ end
@@ -1,5 +1,6 @@
1
1
  require 'yaml'
2
2
  require 'jekyll/minibundle/bundle_file'
3
+ require 'jekyll/minibundle/development_file_collection'
3
4
 
4
5
  module Jekyll::Minibundle
5
6
  class MiniBundleBlock < Liquid::Block
@@ -9,12 +10,15 @@ module Jekyll::Minibundle
9
10
  end
10
11
 
11
12
  def render(context)
12
- current_config = YAML.load super
13
13
  site = context.registers[:site]
14
- config = default_config.
15
- merge(current_config).
16
- merge({ 'type' => @type, 'site_dir' => site.source})
17
- file = BundleFile.new config
14
+ config = get_current_config YAML.load(super), site
15
+
16
+ file = if ENV['JEKYLL_MINIBUNDLE_MODE'] == 'development'
17
+ DevelopmentFileCollection.new config
18
+ else
19
+ BundleFile.new config
20
+ end
21
+
18
22
  file.static_file! site
19
23
  file.markup
20
24
  end
@@ -27,6 +31,14 @@ module Jekyll::Minibundle
27
31
  'attributes' => {}
28
32
  }
29
33
  end
34
+
35
+ private
36
+
37
+ def get_current_config(user_config, site)
38
+ default_config.
39
+ merge(user_config).
40
+ merge({ 'type' => @type, 'site_dir' => site.source })
41
+ end
30
42
  end
31
43
  end
32
44
 
@@ -1,50 +1,39 @@
1
- require 'jekyll/minibundle/asset_file_support'
1
+ require 'jekyll/minibundle/asset_file_operations'
2
+ require 'jekyll/minibundle/asset_file_paths'
2
3
  require 'jekyll/minibundle/asset_stamp'
3
4
 
4
5
  module Jekyll::Minibundle
5
6
  class StampFile
6
- include AssetFileSupport
7
+ include AssetFileOperations
8
+ include AssetFilePaths
7
9
 
8
- @@mtimes = Hash.new
10
+ @@mtimes = {}
11
+
12
+ attr_reader :asset_source_path, :asset_destination_dir
9
13
 
10
14
  def initialize(asset_source_path, asset_destination_path)
11
15
  @asset_source_path = asset_source_path
12
16
  @asset_destination_dir = File.dirname asset_destination_path
13
17
  @asset_destination_extension = File.extname asset_destination_path
14
18
  @asset_destination_base_prefix = File.basename(asset_destination_path)[0 .. -(@asset_destination_extension.size + 1)]
15
- update_mtime
16
- end
17
-
18
- def path
19
- @asset_source_path
20
- end
21
-
22
- def asset_path
23
- File.join @asset_destination_dir, asset_destination_basename
24
19
  end
25
20
 
26
- def destination(site_destination_dir)
27
- File.join site_destination_dir, @asset_destination_dir, asset_destination_basename
28
- end
29
-
30
- def mtime
31
- File.stat(path).mtime.to_i
32
- end
33
-
34
- def modified?
35
- @@mtimes[path] != mtime
21
+ def last_mtime_of(path)
22
+ @@mtimes[path]
36
23
  end
37
24
 
38
25
  def write(site_destination_dir)
39
- clear_asset_stamp if modified?
40
- destination_path = destination site_destination_dir
41
-
42
- return false if File.exist?(destination_path) and !modified?
26
+ is_modified = modified?
43
27
 
44
- update_mtime
45
- write_destination site_destination_dir
28
+ clear_asset_stamp if is_modified
46
29
 
47
- true
30
+ if destination_exists?(site_destination_dir) && !is_modified
31
+ false
32
+ else
33
+ update_mtime
34
+ write_destination site_destination_dir
35
+ true
36
+ end
48
37
  end
49
38
 
50
39
  private
@@ -1,5 +1,5 @@
1
1
  module Jekyll
2
2
  module Minibundle
3
- VERSION = '0.2.0'
3
+ VERSION = '1.0.0'
4
4
  end
5
5
  end
@@ -0,0 +1,121 @@
1
+ require 'support/test_case'
2
+ require 'support/fixture_config'
3
+
4
+ module Jekyll::Minibundle::Test
5
+ class MiniBundleDevelopmentModeTest < TestCase
6
+ include FixtureConfig
7
+
8
+ EXPECTED_CSS_ASSET_PATHS = %w{reset common}.map { |f| File.join(CSS_BUNDLE_DESTINATION_DIR, "#{f}.css") }
9
+ EXPECTED_JS_ASSET_PATHS = %w{dependency app}.map { |f| File.join(JS_BUNDLE_DESTINATION_DIR, "#{f}.js") }
10
+
11
+ def test_css_assets_have_tags_in_configured_order
12
+ with_precompiled_site :development do
13
+ assert_equal EXPECTED_CSS_ASSET_PATHS, find_css_paths_from_index
14
+ end
15
+ end
16
+
17
+ def test_js_assets_have_tags_in_configured_order
18
+ with_precompiled_site :development do
19
+ assert_equal EXPECTED_JS_ASSET_PATHS, find_js_paths_from_index
20
+ end
21
+ end
22
+
23
+ def test_css_assets_are_copied_to_destination_dir
24
+ with_precompiled_site :development do
25
+ EXPECTED_CSS_ASSET_PATHS.each do |path|
26
+ expect_file_exists_and_is_equal_to(destination_path(path), site_fixture_path(CSS_BUNDLE_SOURCE_DIR, File.basename(path)))
27
+ end
28
+ end
29
+ end
30
+
31
+ def test_js_assets_are_copied_to_destination_dir
32
+ with_precompiled_site :development do
33
+ EXPECTED_JS_ASSET_PATHS.each do |path|
34
+ expect_file_exists_and_is_equal_to(destination_path(path), site_fixture_path(JS_BUNDLE_SOURCE_DIR, File.basename(path)))
35
+ end
36
+ end
37
+ end
38
+
39
+ def test_changing_css_asset_copies_it_to_destination_dir
40
+ with_site do
41
+ destination = destination_path CSS_BUNDLE_DESTINATION_DIR, 'common.css'
42
+ source = source_path CSS_BUNDLE_SOURCE_DIR, 'common.css'
43
+
44
+ generate_site :development
45
+ ensure_file_mtime_change { File.write source, 'h1 {}' }
46
+ refute_equal File.read(destination), File.read(source)
47
+ generate_site :development
48
+ assert_equal File.read(destination), File.read(source)
49
+ end
50
+ end
51
+
52
+ def test_changing_js_asset_copies_it_to_destination_dir
53
+ with_site do
54
+ destination = destination_path JS_BUNDLE_DESTINATION_DIR, 'app.js'
55
+ source = source_path JS_BUNDLE_SOURCE_DIR, 'app.js'
56
+
57
+ generate_site :development
58
+ ensure_file_mtime_change { File.write source, '(function() {})()' }
59
+ refute_equal File.read(destination), File.read(source)
60
+ generate_site :development
61
+ assert_equal File.read(destination), File.read(source)
62
+ end
63
+ end
64
+
65
+ def test_supports_relative_and_absolute_destination_paths
66
+ with_site do
67
+ expected_css_path = destination_path CSS_BUNDLE_DESTINATION_DIR, 'common.css'
68
+ expected_js_path = destination_path JS_BUNDLE_DESTINATION_DIR, 'app.js'
69
+
70
+ generate_site :development
71
+
72
+ assert File.exists?(expected_css_path)
73
+ assert File.exists?(expected_js_path)
74
+ assert_equal 'assets/site/common.css', find_css_paths_from_index.last
75
+ assert_equal 'assets/site/app.js', find_js_paths_from_index.last
76
+
77
+ find_and_gsub_in_file source_path('index.html'), 'destination_path: assets/site', 'destination_path: /assets/site'
78
+
79
+ generate_site :development
80
+
81
+ assert File.exists?(expected_css_path)
82
+ assert File.exists?(expected_js_path)
83
+ assert_equal '/assets/site/common.css', find_css_paths_from_index.last
84
+ assert_equal '/assets/site/app.js', find_js_paths_from_index.last
85
+ end
86
+ end
87
+
88
+ def test_do_not_require_bundling_cmds
89
+ with_site do
90
+ with_env 'JEKYLL_MINIBUNDLE_CMD_CSS' => nil, 'JEKYLL_MINIBUNDLE_CMD_JS' => nil do
91
+ generate_site :development
92
+ pass
93
+ end
94
+ end
95
+ end
96
+
97
+ private
98
+
99
+ def find_css_paths_from_index
100
+ find_html_elements_from_index('head link[media="projection"]').map { |el| el['href'] }
101
+ end
102
+
103
+ def find_js_paths_from_index
104
+ find_html_elements_from_index('body script').map { |el| el['src'] }
105
+ end
106
+
107
+ def find_html_elements_from_index(css)
108
+ find_html_element(File.read(destination_path('index.html')), css)
109
+ end
110
+
111
+ def expect_file_exists_and_is_equal_to(actual, expected)
112
+ assert File.exists?(actual)
113
+ assert_equal File.read(expected), File.read(actual)
114
+ end
115
+
116
+ def ensure_file_mtime_change(&block)
117
+ sleep 1.5 # ensures file mtime gets changed
118
+ yield
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,157 @@
1
+ require 'support/test_case'
2
+ require 'support/fixture_config'
3
+
4
+ module Jekyll::Minibundle::Test
5
+ class MiniBundleProductionModeTest < TestCase
6
+ include FixtureConfig
7
+
8
+ EXPECTED_CSS_ASSET_PATH = 'assets/site-b2e0ecc1c100effc2c7353caad20c327.css'
9
+ EXPECTED_JS_ASSET_PATH = 'assets/site-4782a1f67803038d4f8351051e67deb8.js'
10
+
11
+ def test_css_asset_bundle_has_configured_attributes
12
+ with_precompiled_site :production do
13
+ element = find_html_element_from_index %{head link[href="#{EXPECTED_CSS_ASSET_PATH}"]}
14
+ assert_equal 'my-styles', element['id']
15
+ assert_equal 'projection', element['media']
16
+ end
17
+ end
18
+
19
+ def test_js_asset_bundle_has_configured_attributes
20
+ with_precompiled_site :production do
21
+ element = find_html_element_from_index %{body script[src="#{EXPECTED_JS_ASSET_PATH}"]}
22
+ assert_equal 'my-scripts', element['id']
23
+ end
24
+ end
25
+
26
+ def test_css_asset_bundle_has_stamp
27
+ with_precompiled_site :production do
28
+ assert_equal EXPECTED_CSS_ASSET_PATH, find_css_path_from_index
29
+ end
30
+ end
31
+
32
+ def test_js_asset_bundle_has_stamp
33
+ with_precompiled_site :production do
34
+ assert_equal EXPECTED_JS_ASSET_PATH, find_js_path_from_index
35
+ end
36
+ end
37
+
38
+ def test_css_asset_bundle_is_copied_to_destination_dir
39
+ with_precompiled_site :production do
40
+ assert File.exists?(destination_path(EXPECTED_CSS_ASSET_PATH))
41
+ end
42
+ end
43
+
44
+ def test_js_asset_bundle_is_copied_to_destination_dir
45
+ with_precompiled_site :production do
46
+ assert File.exists?(destination_path(EXPECTED_JS_ASSET_PATH))
47
+ end
48
+ end
49
+
50
+ def test_css_asset_bundle_is_concatenated_in_configured_order
51
+ with_precompiled_site :production do
52
+ bundle = File.read(destination_path(EXPECTED_CSS_ASSET_PATH))
53
+ assert_operator bundle.index('html { margin: 0; }'), :<, bundle.index('p { margin: 0; }')
54
+ end
55
+ end
56
+
57
+ def test_js_asset_bundle_is_concatenated_in_configured_order
58
+ with_precompiled_site :production do
59
+ bundle = File.read(destination_path(EXPECTED_JS_ASSET_PATH))
60
+ assert_operator bundle.index('root.dependency = {};'), :<, bundle.index('root.app = {};')
61
+ end
62
+ end
63
+
64
+ def test_js_asset_bundle_has_inserted_semicolons_between_assets
65
+ with_precompiled_site :production do
66
+ bundle = File.read(destination_path(EXPECTED_JS_ASSET_PATH))
67
+ assert_match(%r|}\)\(window\)\n;\n\(function|, bundle)
68
+ end
69
+ end
70
+
71
+ def test_css_asset_bundle_is_minified
72
+ with_precompiled_site :production do
73
+ source_contents_size = source_assets_size(CSS_BUNDLE_SOURCE_DIR, %w{reset common}, 'css')
74
+ destination_contents_size = File.read(destination_path(EXPECTED_CSS_ASSET_PATH)).size
75
+ assert_operator destination_contents_size, :<, source_contents_size
76
+ end
77
+ end
78
+
79
+ def test_js_asset_bundle_is_minified
80
+ with_precompiled_site :production do
81
+ source_contents_size = source_assets_size(JS_BUNDLE_SOURCE_DIR, %w{dependency app}, 'js')
82
+ destination_contents_size = File.read(destination_path(EXPECTED_JS_ASSET_PATH)).size
83
+ assert_operator destination_contents_size, :<, source_contents_size
84
+ end
85
+ end
86
+
87
+ def test_changing_css_assets_changes_bundle
88
+ with_site do
89
+ generate_site :production
90
+ assert File.exists?(destination_path(EXPECTED_CSS_ASSET_PATH))
91
+ File.write source_path('_assets/styles/common.css'), 'h1 {}'
92
+ generate_site :production
93
+ refute File.exists?(destination_path(EXPECTED_CSS_ASSET_PATH))
94
+ expected_new_path = 'assets/site-9fd3995d6f0fce425db81c3691dfe93f.css'
95
+ assert_equal expected_new_path, find_css_path_from_index
96
+ assert File.exists?(destination_path(expected_new_path))
97
+ end
98
+ end
99
+
100
+ def test_changing_js_assets_changes_bundle
101
+ with_site do
102
+ generate_site :production
103
+ assert File.exists?(destination_path(EXPECTED_JS_ASSET_PATH))
104
+ File.write source_path('_assets/scripts/app.js'), '(function() {})()'
105
+ generate_site :production
106
+ refute File.exists?(destination_path(EXPECTED_JS_ASSET_PATH))
107
+ expected_new_path = 'assets/site-375a0b430b0c5555d0edd2205d26c04d.js'
108
+ assert_equal expected_new_path, find_js_path_from_index
109
+ assert File.exists?(destination_path(expected_new_path))
110
+ end
111
+ end
112
+
113
+ def test_supports_relative_and_absolute_destination_paths
114
+ with_site do
115
+ expected_css_path = destination_path EXPECTED_CSS_ASSET_PATH
116
+ expected_js_path = destination_path EXPECTED_JS_ASSET_PATH
117
+
118
+ generate_site :production
119
+
120
+ assert File.exists?(expected_css_path)
121
+ assert File.exists?(expected_js_path)
122
+ assert_equal EXPECTED_CSS_ASSET_PATH, find_css_path_from_index
123
+ assert_equal EXPECTED_JS_ASSET_PATH, find_js_path_from_index
124
+
125
+ find_and_gsub_in_file source_path('index.html'), 'destination_path: assets/site', 'destination_path: /assets/site'
126
+
127
+ generate_site :production
128
+
129
+ assert File.exists?(expected_css_path)
130
+ assert File.exists?(expected_js_path)
131
+ assert_equal "/#{EXPECTED_CSS_ASSET_PATH}", find_css_path_from_index
132
+ assert_equal "/#{EXPECTED_JS_ASSET_PATH}", find_js_path_from_index
133
+ end
134
+ end
135
+
136
+ private
137
+
138
+ def find_css_path_from_index
139
+ find_html_element_from_index('head link[media="projection"]')['href']
140
+ end
141
+
142
+ def find_js_path_from_index
143
+ find_html_element_from_index('body script')['src']
144
+ end
145
+
146
+ def find_html_element_from_index(css)
147
+ find_html_element(File.read(destination_path('index.html')), css).first
148
+ end
149
+
150
+ def source_assets_size(source_subdir, assets, type)
151
+ assets.
152
+ map { |f| File.read site_fixture_path(source_subdir, "#{f}.#{type}") }.
153
+ join('').
154
+ size
155
+ end
156
+ end
157
+ end
@@ -1,22 +1,67 @@
1
1
  require 'support/test_case'
2
+ require 'support/fixture_config'
2
3
 
3
4
  module Jekyll::Minibundle::Test
4
5
  class MiniStampTest < TestCase
6
+ include FixtureConfig
7
+
5
8
  EXPECTED_ASSET_PATH = 'assets/screen-390be921ee0eff063817bb5ef2954300.css'
6
9
 
7
10
  def test_asset_path_has_stamp
8
- actual = find_html_element(read_from_destination('index.html'), 'head link').first['href']
9
- assert_equal EXPECTED_ASSET_PATH, actual
11
+ with_precompiled_site :production do
12
+ assert_equal EXPECTED_ASSET_PATH, find_css_path_from_index
13
+ end
10
14
  end
11
15
 
12
16
  def test_asset_file_is_copied_to_destination_dir
13
- assert File.exists?(destination_path(EXPECTED_ASSET_PATH))
17
+ with_precompiled_site :production do
18
+ assert File.exists?(destination_path(EXPECTED_ASSET_PATH))
19
+ end
14
20
  end
15
21
 
16
22
  def test_asset_file_is_equal_to_source_file
17
- source_contents = File.read source_path('_tmp/site.css')
18
- destination_contents = File.read destination_path(EXPECTED_ASSET_PATH)
19
- assert_equal source_contents, destination_contents
23
+ with_precompiled_site :production do
24
+ source_contents = File.read site_fixture_path(CSS_STAMP_SOURCE_FILE)
25
+ destination_contents = File.read destination_path(EXPECTED_ASSET_PATH)
26
+ assert_equal source_contents, destination_contents
27
+ end
28
+ end
29
+
30
+ def test_change_asset_file
31
+ with_site do
32
+ generate_site :production
33
+ assert File.exists?(destination_path(EXPECTED_ASSET_PATH))
34
+ File.write source_path(CSS_STAMP_SOURCE_FILE), 'h1 {}'
35
+ generate_site :production
36
+ refute File.exists?(destination_path(EXPECTED_ASSET_PATH))
37
+ expected_new_path = 'assets/screen-0f5dbd1e527a2bee267e85007b08d2a5.css'
38
+ assert_equal expected_new_path, find_css_path_from_index
39
+ assert File.exists?(destination_path(expected_new_path))
40
+ end
41
+ end
42
+
43
+ def test_supports_relative_and_absolute_destination_paths
44
+ with_site do
45
+ expected_path = destination_path EXPECTED_ASSET_PATH
46
+
47
+ generate_site :production
48
+
49
+ assert File.exists?(expected_path)
50
+ assert_equal EXPECTED_ASSET_PATH, find_css_path_from_index
51
+
52
+ find_and_gsub_in_file(source_path('index.html'), %r{assets/screen.css}, '/\0')
53
+
54
+ generate_site :production
55
+
56
+ assert File.exists?(expected_path)
57
+ assert_equal "/#{EXPECTED_ASSET_PATH}", find_css_path_from_index
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def find_css_path_from_index
64
+ find_html_element(File.read(destination_path('index.html')), 'head link').first['href']
20
65
  end
21
66
  end
22
67
  end
@@ -0,0 +1,11 @@
1
+ module Jekyll::Minibundle::Test
2
+ module FixtureConfig
3
+ CSS_STAMP_SOURCE_FILE = '_tmp/site.css'
4
+
5
+ CSS_BUNDLE_DESTINATION_DIR = 'assets/site'
6
+ CSS_BUNDLE_SOURCE_DIR = '_assets/styles'
7
+
8
+ JS_BUNDLE_DESTINATION_DIR = 'assets/site'
9
+ JS_BUNDLE_SOURCE_DIR = '_assets/scripts'
10
+ end
11
+ end
@@ -10,24 +10,29 @@ module Jekyll::Minibundle::Test
10
10
  include ::Jekyll::Minibundle
11
11
 
12
12
  FIXTURE_DIR = File.expand_path(File.join(File.dirname(__FILE__), '../fixture'))
13
- SOURCE_DIR = File.join(FIXTURE_DIR, 'site')
14
13
 
15
- def source_path(*args)
16
- File.join(SOURCE_DIR, *args)
14
+ def site_fixture_path(*args)
15
+ File.join(FIXTURE_DIR, 'site', *args)
17
16
  end
18
17
 
19
- def destination_path(*args)
20
- File.join(_destination_dir, *args)
18
+ def source_path(*args)
19
+ File.join(Dir.pwd, *args)
21
20
  end
22
21
 
23
- def read_from_destination(*args)
24
- File.read destination_path(*args)
22
+ def destination_path(*args)
23
+ File.join(Dir.pwd, '_site', *args)
25
24
  end
26
25
 
27
26
  def find_html_element(file, css)
28
27
  Nokogiri::HTML(file).css(css)
29
28
  end
30
29
 
30
+ def find_and_gsub_in_file(file, pattern, replacement)
31
+ old_content = File.read file
32
+ new_content = old_content.gsub pattern, replacement
33
+ File.write file, new_content
34
+ end
35
+
31
36
  def with_env(env)
32
37
  org_env = {}
33
38
  env.each do |k, v|
@@ -39,24 +44,52 @@ module Jekyll::Minibundle::Test
39
44
  org_env.each { |k, v| ENV[k] = v }
40
45
  end
41
46
 
47
+ def with_site(&block)
48
+ Dir.mktmpdir "jekyll-minibundle-test-site-" do |dir|
49
+ Dir.chdir dir do
50
+ _copy_fixture_site_dir Dir.pwd
51
+ yield dir
52
+ end
53
+ end
54
+ end
55
+
56
+ def with_precompiled_site(mode, &block)
57
+ Dir.chdir(_get_precompiled_site(mode), &block)
58
+ end
59
+
60
+ def generate_site(mode)
61
+ with_env 'JEKYLL_MINIBUNDLE_MODE' => mode.to_s do
62
+ _generate_site Dir.pwd, '_site'
63
+ end
64
+ end
65
+
42
66
  private
43
67
 
44
- def _destination_dir(&block)
45
- @@_destination_dir ||= begin
46
- dir = Dir.mktmpdir('jekyll-minibundle-test-')
68
+ def _copy_fixture_site_dir(dir)
69
+ FileUtils.cp_r site_fixture_path('.'), dir
70
+ end
71
+
72
+ @@_precompiled_site_dirs = {}
73
+
74
+ def _get_precompiled_site(mode)
75
+ @@_precompiled_site_dirs[mode] ||= begin
76
+ dir = Dir.mktmpdir("jekyll-minibundle-test-precompiled-site-#{mode}-")
47
77
  at_exit do
48
78
  FileUtils.rm_rf dir
49
- puts "\nCleaned generated site for tests: #{dir}"
79
+ puts "\nCleaned precompiled site for tests: #{dir}"
80
+ end
81
+ Dir.chdir(dir) do
82
+ _copy_fixture_site_dir Dir.pwd
83
+ generate_site mode
50
84
  end
51
- Dir.chdir(dir) { _generate_site dir }
52
- puts "\nGenerated site for tests: #{dir}"
85
+ puts "\nGenerated precompiled site in #{mode} mode for tests: #{dir}"
53
86
  dir
54
87
  end
55
88
  end
56
89
 
57
- def _generate_site(destination)
90
+ def _generate_site(source, destination)
58
91
  options = {
59
- 'source' => source_path,
92
+ 'source' => source,
60
93
  'destination' => destination
61
94
  }
62
95
  capture_io { Jekyll::Site.new(Jekyll.configuration(options)).process }
@@ -5,7 +5,7 @@ module Jekyll::Minibundle::Test
5
5
  class AssetBundleTest < TestCase
6
6
  def test_raise_exception_if_bundle_command_fails
7
7
  capture_io do
8
- with_env('JEKYLL_MINIBUNDLE_CMD_JS' => 'false') do
8
+ with_env 'JEKYLL_MINIBUNDLE_CMD_JS' => 'false' do
9
9
  err = assert_raises(RuntimeError) { make_bundle }
10
10
  assert_equal 'Bundling js assets failed with exit status 1, command: false', err.to_s
11
11
  end
@@ -13,13 +13,13 @@ module Jekyll::Minibundle::Test
13
13
  end
14
14
 
15
15
  def test_raise_exception_if_bundle_command_not_found
16
- with_env('JEKYLL_MINIBUNDLE_CMD_JS' => 'no-such-jekyll-minibundle-cmd') do
16
+ with_env 'JEKYLL_MINIBUNDLE_CMD_JS' => 'no-such-jekyll-minibundle-cmd' do
17
17
  assert_raises(Errno::ENOENT) { make_bundle }
18
18
  end
19
19
  end
20
20
 
21
21
  def test_raise_exception_if_bundle_command_not_configured
22
- with_env('JEKYLL_MINIBUNDLE_CMD_JS' => nil) do
22
+ with_env 'JEKYLL_MINIBUNDLE_CMD_JS' => nil do
23
23
  err = assert_raises(RuntimeError) { make_bundle }
24
24
  assert_equal 'You need to set bundling command in $JEKYLL_MINIBUNDLE_CMD_JS', err.to_s
25
25
  end
@@ -28,7 +28,7 @@ module Jekyll::Minibundle::Test
28
28
  private
29
29
 
30
30
  def make_bundle
31
- bundle = AssetBundle.new :js, [source_path('_assets/scripts/dependency.js')], source_path
31
+ bundle = AssetBundle.new :js, [site_fixture_path('_assets/scripts/dependency.js')], site_fixture_path
32
32
  bundle.make_bundle
33
33
  end
34
34
  end
@@ -1,11 +1,11 @@
1
1
  require 'support/test_case'
2
- require 'jekyll/minibundle/bundle_markup'
2
+ require 'jekyll/minibundle/asset_tag_markup'
3
3
 
4
4
  module Jekyll::Minibundle::Test
5
- class BundleMarkupTest < TestCase
5
+ class AssetTagMarkupTest < TestCase
6
6
  def test_escape_attribute_value
7
7
  attributes = { media: 'screen, projection', extra: '">attack<br' }
8
- actual = BundleMarkup.make_markup :css, 'http://localhost', attributes
8
+ actual = AssetTagMarkup.make_markup :css, 'http://localhost', attributes
9
9
  expected = %{<link rel="stylesheet" href="http://localhost" media="screen, projection" extra="&quot;&gt;attack&lt;br">}
10
10
  assert_equal expected, actual
11
11
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-minibundle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-15 00:00:00.000000000 Z
12
+ date: 2013-02-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: jekyll
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: 0.11.2
21
+ version: 0.12.0
22
22
  type: :development
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- version: 0.11.2
29
+ version: 0.12.0
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: minitest
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -34,7 +34,7 @@ dependencies:
34
34
  requirements:
35
35
  - - ~>
36
36
  - !ruby/object:Gem::Version
37
- version: 4.3.3
37
+ version: 4.6.0
38
38
  type: :development
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,7 +42,7 @@ dependencies:
42
42
  requirements:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
- version: 4.3.3
45
+ version: 4.6.0
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: nokogiri
48
48
  requirement: !ruby/object:Gem::Requirement
@@ -50,7 +50,7 @@ dependencies:
50
50
  requirements:
51
51
  - - ~>
52
52
  - !ruby/object:Gem::Version
53
- version: 1.5.5
53
+ version: 1.5.6
54
54
  type: :development
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
@@ -58,7 +58,7 @@ dependencies:
58
58
  requirements:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
- version: 1.5.5
61
+ version: 1.5.6
62
62
  - !ruby/object:Gem::Dependency
63
63
  name: rake
64
64
  requirement: !ruby/object:Gem::Requirement
@@ -91,16 +91,19 @@ files:
91
91
  - License.txt
92
92
  - Rakefile
93
93
  - Readme.md
94
- - lib/jekyll/minibundle.rb
95
94
  - lib/jekyll/minibundle/asset_bundle.rb
96
- - lib/jekyll/minibundle/asset_file_support.rb
95
+ - lib/jekyll/minibundle/asset_file_operations.rb
96
+ - lib/jekyll/minibundle/asset_file_paths.rb
97
97
  - lib/jekyll/minibundle/asset_stamp.rb
98
+ - lib/jekyll/minibundle/asset_tag_markup.rb
98
99
  - lib/jekyll/minibundle/bundle_file.rb
99
- - lib/jekyll/minibundle/bundle_markup.rb
100
+ - lib/jekyll/minibundle/development_file.rb
101
+ - lib/jekyll/minibundle/development_file_collection.rb
100
102
  - lib/jekyll/minibundle/mini_bundle_block.rb
101
103
  - lib/jekyll/minibundle/mini_stamp_tag.rb
102
104
  - lib/jekyll/minibundle/stamp_file.rb
103
105
  - lib/jekyll/minibundle/version.rb
106
+ - lib/jekyll/minibundle.rb
104
107
  - test/fixture/site/_assets/scripts/app.js
105
108
  - test/fixture/site/_assets/scripts/dependency.js
106
109
  - test/fixture/site/_assets/styles/common.css
@@ -109,11 +112,13 @@ files:
109
112
  - test/fixture/site/_plugins/minibundle.rb
110
113
  - test/fixture/site/_tmp/site.css
111
114
  - test/fixture/site/index.html
112
- - test/integration/minibundle_test.rb
115
+ - test/integration/minibundle_development_mode_test.rb
116
+ - test/integration/minibundle_production_mode_test.rb
113
117
  - test/integration/ministamp_test.rb
114
- - test/unit/asset_bundle_test.rb
115
- - test/unit/bundle_markup_test.rb
118
+ - test/support/fixture_config.rb
116
119
  - test/support/test_case.rb
120
+ - test/unit/asset_bundle_test.rb
121
+ - test/unit/asset_tag_markup_test.rb
117
122
  homepage: https://github.com/tkareine/jekyll-minibundle
118
123
  licenses:
119
124
  - MIT
@@ -140,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
145
  version: '0'
141
146
  requirements: []
142
147
  rubyforge_project:
143
- rubygems_version: 1.8.24
148
+ rubygems_version: 1.8.25
144
149
  signing_key:
145
150
  specification_version: 3
146
151
  summary: A minimalistic asset bundling plugin for Jekyll
@@ -153,9 +158,11 @@ test_files:
153
158
  - test/fixture/site/_plugins/minibundle.rb
154
159
  - test/fixture/site/_tmp/site.css
155
160
  - test/fixture/site/index.html
156
- - test/integration/minibundle_test.rb
161
+ - test/integration/minibundle_development_mode_test.rb
162
+ - test/integration/minibundle_production_mode_test.rb
157
163
  - test/integration/ministamp_test.rb
158
- - test/unit/asset_bundle_test.rb
159
- - test/unit/bundle_markup_test.rb
164
+ - test/support/fixture_config.rb
160
165
  - test/support/test_case.rb
166
+ - test/unit/asset_bundle_test.rb
167
+ - test/unit/asset_tag_markup_test.rb
161
168
  has_rdoc:
@@ -1,77 +0,0 @@
1
- require 'support/test_case'
2
-
3
- module Jekyll::Minibundle::Test
4
- class MiniBundleTest < TestCase
5
- EXPECTED_CSS_ASSET_PATH = 'assets/site-b2e0ecc1c100effc2c7353caad20c327.css'
6
- EXPECTED_JS_ASSET_PATH = 'assets/site-4782a1f67803038d4f8351051e67deb8.js'
7
-
8
- def test_css_asset_bundle_has_configured_attributes
9
- element = find_html_element_from_index(%{head link[href="#{EXPECTED_CSS_ASSET_PATH}"]}).first
10
- assert_equal 'my-styles', element['id']
11
- assert_equal 'projection', element['media']
12
- end
13
-
14
- def test_js_asset_bundle_has_configured_attributes
15
- element = find_html_element_from_index(%{body script[src="#{EXPECTED_JS_ASSET_PATH}"]}).first
16
- assert_equal 'my-scripts', element['id']
17
- end
18
-
19
- def test_css_asset_bundle_has_stamp
20
- actual = find_html_element_from_index('head link[media="projection"]').first['href']
21
- assert_equal EXPECTED_CSS_ASSET_PATH, actual
22
- end
23
-
24
- def test_js_asset_bundle_has_stamp
25
- actual = find_html_element_from_index('body script').first['src']
26
- assert_equal EXPECTED_JS_ASSET_PATH, actual
27
- end
28
-
29
- def test_css_asset_bundle_is_copied_to_destination_dir
30
- assert File.exists?(destination_path(EXPECTED_CSS_ASSET_PATH))
31
- end
32
-
33
- def test_js_asset_bundle_is_copied_to_destination_dir
34
- assert File.exists?(destination_path(EXPECTED_JS_ASSET_PATH))
35
- end
36
-
37
- def test_css_asset_bundle_is_concatenated_in_configured_order
38
- bundle = File.read(destination_path(EXPECTED_CSS_ASSET_PATH))
39
- assert bundle.index('html { margin: 0; }') < bundle.index('p { margin: 0; }')
40
- end
41
-
42
- def test_js_asset_bundle_is_concatenated_in_configured_order
43
- bundle = File.read(destination_path(EXPECTED_JS_ASSET_PATH))
44
- assert bundle.index('root.dependency = {};') < bundle.index('root.app = {};')
45
- end
46
-
47
- def test_js_asset_bundle_has_inserted_semicolons_between_assets
48
- bundle = File.read(destination_path(EXPECTED_JS_ASSET_PATH))
49
- assert_match(%r|}\)\(window\)\n;\n\(function|, bundle)
50
- end
51
-
52
- def test_css_asset_bundle_is_minified
53
- source_contents_size = source_assets_size('_assets/styles', %w{reset common}, 'css')
54
- destination_contents_size = File.read(destination_path(EXPECTED_CSS_ASSET_PATH)).size
55
- assert destination_contents_size < source_contents_size
56
- end
57
-
58
- def test_js_asset_bundle_is_minified
59
- source_contents_size = source_assets_size('_assets/scripts', %w{dependency app}, 'js')
60
- destination_contents_size = File.read(destination_path(EXPECTED_JS_ASSET_PATH)).size
61
- assert destination_contents_size < source_contents_size
62
- end
63
-
64
- private
65
-
66
- def find_html_element_from_index(css)
67
- find_html_element(read_from_destination('index.html'), css)
68
- end
69
-
70
- def source_assets_size(source_subdir, assets, type)
71
- assets.
72
- map { |f| File.read source_path(source_subdir, "#{f}.#{type}") }.
73
- join('').
74
- size
75
- end
76
- end
77
- end