jekyll-minibundle 0.2.0 → 1.0.0

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