jekyll-assets 2.0.0.pre.beta2 → 2.0.0.pre.beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -4
  3. data/README.md +33 -40
  4. data/lib/jekyll/assets.rb +18 -16
  5. data/lib/jekyll/assets/addons/autoprefixer.rb +5 -0
  6. data/lib/jekyll/assets/addons/bootstrap.rb +1 -0
  7. data/lib/jekyll/assets/addons/compass.rb +7 -0
  8. data/lib/jekyll/assets/addons/font_awesome.rb +1 -0
  9. data/lib/jekyll/assets/{extras/es6.rb → addons/js_es6.rb} +1 -1
  10. data/lib/jekyll/assets/addons/proxies/magick.rb +92 -0
  11. data/lib/jekyll/assets/config.rb +48 -0
  12. data/lib/jekyll/assets/env.rb +110 -91
  13. data/lib/jekyll/assets/hook.rb +42 -25
  14. data/lib/jekyll/assets/hooks/cache.rb +5 -0
  15. data/lib/jekyll/assets/hooks/compression.rb +11 -0
  16. data/lib/jekyll/assets/hooks/configuration.rb +3 -0
  17. data/lib/jekyll/assets/hooks/context_patches.rb +12 -0
  18. data/lib/jekyll/assets/hooks/disable_erb.rb +6 -0
  19. data/lib/jekyll/assets/hooks/helpers.rb +8 -0
  20. data/lib/jekyll/assets/hooks/logger.rb +3 -0
  21. data/lib/jekyll/assets/hooks/sources.rb +5 -0
  22. data/lib/jekyll/assets/hooks/sprockets.rb +3 -0
  23. data/lib/jekyll/assets/hooks/version.rb +3 -0
  24. data/lib/jekyll/assets/liquid/filters.rb +16 -0
  25. data/lib/jekyll/assets/liquid/tag.rb +162 -0
  26. data/lib/jekyll/assets/liquid/tag/parser.rb +163 -0
  27. data/lib/jekyll/assets/liquid/tag/proxied_asset.rb +98 -0
  28. data/lib/jekyll/assets/liquid/tag/proxies.rb +122 -0
  29. data/lib/jekyll/assets/logger.rb +34 -11
  30. data/lib/jekyll/assets/patches/hash.rb +5 -0
  31. data/lib/jekyll/assets/patches/jekyll/cleaner.rb +2 -2
  32. data/lib/jekyll/assets/patches/kernel.rb +31 -0
  33. data/lib/jekyll/assets/patches/sprockets/asset.rb +6 -6
  34. data/lib/jekyll/assets/version.rb +1 -1
  35. data/lib/jekyll/hooks/initialize.rb +3 -0
  36. data/lib/jekyll/hooks/write_assets.rb +3 -0
  37. metadata +28 -17
  38. data/lib/jekyll/assets/configuration.rb +0 -51
  39. data/lib/jekyll/assets/context.rb +0 -23
  40. data/lib/jekyll/assets/extras/font-awesome.rb +0 -1
  41. data/lib/jekyll/assets/extras/helpers.rb +0 -6
  42. data/lib/jekyll/assets/extras/prefix.rb +0 -5
  43. data/lib/jekyll/assets/filters.rb +0 -17
  44. data/lib/jekyll/assets/helpers.rb +0 -37
  45. data/lib/jekyll/assets/hooks/post_read.rb +0 -3
  46. data/lib/jekyll/assets/hooks/post_write.rb +0 -3
  47. data/lib/jekyll/assets/tag.rb +0 -148
  48. data/lib/jekyll/assets/tag/parser.rb +0 -129
  49. data/lib/jekyll/assets/tag/proxied_asset.rb +0 -84
  50. data/lib/jekyll/assets/tag/proxies.rb +0 -86
  51. data/lib/jekyll/assets/tag/proxies/magick.rb +0 -101
@@ -2,43 +2,60 @@ module Jekyll
2
2
  module Assets
3
3
  class Hook
4
4
  class UnknownHookError < RuntimeError
5
- def initialize(base, point)
6
- super "Unknown jekyll-assets hook point (#{point}) or base (#{base}) given."
5
+ def initialize(base: nil, point: nil)
6
+ return super "Unknown hook base '#{base}'" if base
7
+ return super "Unknown hook point '#{point}' given."
7
8
  end
8
9
  end
9
10
 
10
- HOOK_POINTS = {
11
+ HookAliases = {
12
+ :env => {
13
+ :post_init => :init,
14
+ :pre_init => :init
15
+ }
16
+ }
17
+
18
+ HookPoints = {
11
19
  :env => [
12
- :pre_init, :post_init
20
+ :init
13
21
  ]
14
22
  }
15
23
 
16
- class << self
17
- def all
18
- @_all ||= {}
19
- end
24
+ def self.all
25
+ @_all ||= {}
26
+ end
27
+
28
+ # ---------------------------------------------------------------------
29
+ # Trigger a hook, giving an optional block where we pass you the,
30
+ # proc we got and then you can do as you please (such as instance eval)
31
+ # but if you do not give us one then we simply pass the args.
32
+ # ---------------------------------------------------------------------
20
33
 
21
- def trigger(base, point, *args)
22
- if all[base][point]
23
- then all[base][point].map do |v|
24
- v.call(*args)
25
- end
34
+ def self.trigger(base, _point, *args, &block)
35
+ raise ArgumentError, "Do not give args with a block" if args.size > 0 && block_given?
36
+ if all.has_key?(base) && all.fetch(base).has_key?(_point)
37
+ Set.new.merge(point(base, _point, :early)).merge(point(base, _point)).map do |v|
38
+ block_given?? block.call(v) : v.call(*args)
26
39
  end
27
40
  end
41
+ end
28
42
 
29
- def point(base, point)
30
- all[base][point] ||= Set.new
31
- end
43
+ # ---------------------------------------------------------------------
32
44
 
33
- def register(base, point, &block)
34
- if HOOK_POINTS.has_key?(base) && HOOK_POINTS[base].include?(point)
35
- all[base] ||= {}
36
- point(base, point) << \
37
- block
38
- else
39
- raise UnknownHookError.new(base, point)
40
- end
41
- end
45
+ def self.point(base, point, _when = :late)
46
+ point = all.fetch(base).fetch(point, nil) || all.fetch(base).store(point, {
47
+ :late => Set.new, :early => Set.new })
48
+ point.fetch(_when)
49
+ end
50
+
51
+ # ---------------------------------------------------------------------
52
+
53
+ def self.register(base, point, _when = :late, &block)
54
+ raise UnknownHookError.new(base: base) unless HookPoints.has_key?(base)
55
+ point = HookAliases.fetch(base).fetch(point) if HookAliases.fetch(base, {}).has_key?(point)
56
+ raise UnknownHookError.new(point: point) unless HookPoints.fetch(base).include?(point)
57
+ all.fetch(base, nil) || all.store(base, {})
58
+ point(base, point, _when).add(block)
42
59
  end
43
60
  end
44
61
  end
@@ -0,0 +1,5 @@
1
+ Jekyll::Assets::Hook.register :env, :init do
2
+ if (cache_dir = asset_config.fetch("cache", ".asset-cache"))
3
+ self.cache = Sprockets::Cache::FileStore.new(jekyll.in_source_dir(cache_dir))
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ Jekyll::Assets::Hook.register :env, :init do
2
+ if compress?("css")
3
+ self.css_compressor = :sass
4
+ end
5
+
6
+ if compress?("js")
7
+ try_require "uglifier" do
8
+ self.js_compressor = :uglify
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ Jekyll::Assets::Hook.register :env, :init, :early do
2
+ jekyll.config.store("assets", Jekyll::Assets::Config.merge(asset_config))
3
+ end
@@ -0,0 +1,12 @@
1
+ Jekyll::Assets::Hook.register :env, :init do
2
+ context_class.class_eval do
3
+ alias_method :_old_asset_path, :asset_path
4
+ def asset_path(asset, opts = {})
5
+ out = _old_asset_path asset
6
+ return unless out
7
+ path = environment.find_asset(resolve(asset))
8
+ environment.parent.used.add(path)
9
+ out
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ Jekyll::Assets::Hook.register :env, :init, :early do
2
+ self.config = hash_reassoc(config, :engines) do |hash|
3
+ hash.delete(".erb")
4
+ hash
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ require "sprockets/helpers"
2
+
3
+ Jekyll::Assets::Hook.register :env, :init do
4
+ Sprockets::Helpers.configure do |config|
5
+ config.prefix = prefix_path
6
+ config.digest = digest?
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ Jekyll::Assets::Hook.register :env, :init do
2
+ self.logger = Jekyll::Assets::Logger.new
3
+ end
@@ -0,0 +1,5 @@
1
+ Jekyll::Assets::Hook.register :env, :init do
2
+ asset_config.fetch("sources", []).each do |path|
3
+ append_path jekyll.in_source_dir(path)
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ Jekyll::Assets::Hook.register :env, :init do
2
+ jekyll.sprockets = self
3
+ end
@@ -0,0 +1,3 @@
1
+ Jekyll::Assets::Hook.register :env, :init do
2
+ self.version = Digest::MD5.hexdigest(jekyll.config.fetch("assets", {}).inspect)
3
+ end
@@ -0,0 +1,16 @@
1
+ module Jekyll
2
+ module Assets
3
+ module Liquid
4
+ module Filters
5
+ %W(js css img image javascript stylesheet style asset_path).each do |val|
6
+ define_method val do |path, args = ""|
7
+ Tag.send(:new, val, "#{path} #{args}", "").render(@context)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ # Register it with Liquid, good luck from here.
16
+ Liquid::Template.register_filter(Jekyll::Assets::Liquid::Filters)
@@ -0,0 +1,162 @@
1
+ module Jekyll
2
+ module Assets
3
+ module Liquid
4
+ class Tag < ::Liquid::Tag
5
+ require_relative "tag/proxied_asset"
6
+ require_relative "tag/parser"
7
+ attr_reader :args
8
+
9
+ class AssetNotFoundError < StandardError
10
+ def initialize(asset)
11
+ super "Could not find the asset `#{asset}'"
12
+ end
13
+ end
14
+
15
+ # ---------------------------------------------------------------------
16
+
17
+ Tags = {
18
+ "css" => %Q{<link type="text/css" rel="stylesheet" href="%s"%s>},
19
+ "js" => %Q{<script type="text/javascript" src="%s"%s></script>},
20
+ "img" => %Q{<img src="%s"%s>}
21
+ }
22
+
23
+ # ---------------------------------------------------------------------
24
+
25
+ Alias = {
26
+ "image" => "img",
27
+ "stylesheet" => "css",
28
+ "javascript" => "js",
29
+ "style" => "css"
30
+ }
31
+
32
+ # ---------------------------------------------------------------------
33
+
34
+ def initialize(tag, args, tokens)
35
+ @tokens = tokens
36
+ @tag = from_alias(tag)
37
+ @args = Parser.new(args, @tag)
38
+ @og_tag = tag
39
+ super
40
+ end
41
+
42
+ # ---------------------------------------------------------------------
43
+ # NOTE: We only attach to the regenerator if you are using digested
44
+ # assets, otherwise we forego any association with it so that we keep
45
+ # your builds ultra fast, this is ideal in dev. Disable digests and
46
+ # let us process independent so the entire site isn't regenerated
47
+ # because of a single asset change.
48
+ # ---------------------------------------------------------------------
49
+
50
+ def render(context)
51
+ site = context.registers.fetch(:site)
52
+ page = context.registers.fetch(:page, {}).fetch("path", nil)
53
+ sprockets = site.sprockets
54
+
55
+ asset = find_asset(sprockets)
56
+ add_as_jekyll_dependency(site, sprockets, page, asset)
57
+ process_tag(sprockets, asset)
58
+ rescue => e
59
+ capture_and_out_error \
60
+ site, e
61
+ end
62
+
63
+ # ---------------------------------------------------------------------
64
+
65
+ private
66
+ def from_alias(tag)
67
+ Alias.has_key?(tag) ? Alias.fetch(tag) : tag
68
+ end
69
+
70
+ # ---------------------------------------------------------------------
71
+
72
+ private
73
+ def process_tag(sprockets, asset)
74
+ sprockets.used.add(asset) unless @tag == "asset_source"
75
+ set_img_alt asset if @tag == "img"
76
+ out = get_path sprockets, asset
77
+ if @tag == "asset_path"
78
+ return out
79
+
80
+ elsif @tag == "asset" || @tag == "asset_source"
81
+ return asset.to_s
82
+
83
+ elsif @args.has_key?(:data) && @args.fetch(:data).has_key?(:uri)
84
+ return Tags.fetch(@tag) % [
85
+ asset.data_uri, @args.to_html
86
+ ]
87
+
88
+ else
89
+ return Tags.fetch(@tag) % [
90
+ out, @args.to_html
91
+ ]
92
+ end
93
+ end
94
+
95
+ # ---------------------------------------------------------------------
96
+
97
+ private
98
+ def get_path(sprockets, asset)
99
+ sprockets.prefix_path(sprockets.digest?? asset.digest_path : asset.logical_path)
100
+ end
101
+
102
+ # ---------------------------------------------------------------------
103
+
104
+ private
105
+ def set_img_alt(asset)
106
+ if !@args.has_key?(:html) || !@args.fetch(:html).has_key?("alt")
107
+ @args.fetch_or_store(:html, {}).store("alt", asset.logical_path)
108
+ end
109
+ end
110
+
111
+ # ---------------------------------------------------------------------
112
+
113
+ private
114
+ def add_as_jekyll_dependency(site, sprockets, page, asset)
115
+ if page && sprockets.digest?
116
+ site.regenerator.add_dependency(
117
+ site.in_source_dir(page), site.in_source_dir(asset.logical_path)
118
+ )
119
+ end
120
+ end
121
+
122
+ # ---------------------------------------------------------------------
123
+
124
+ private
125
+ def find_asset(sprockets)
126
+ file, _sprockets = @args.fetch(:file), @args.fetch(:sprockets, {})
127
+ if !(out = sprockets.find_asset(file, _sprockets))
128
+ raise AssetNotFoundError, @args.fetch(:file)
129
+ else
130
+ out.liquid_tags << self
131
+ !args.has_proxies?? out : ProxiedAsset.new(out, \
132
+ @args, sprockets, self)
133
+ end
134
+ end
135
+
136
+ # ---------------------------------------------------------------------
137
+ # There is no guarantee that Jekyll will pass on the error for some
138
+ # reason (unless you are just booting up) so we capture that error and
139
+ # always output it, it can lead to some double errors but I would
140
+ # rather there be a double error than no error.
141
+ # ---------------------------------------------------------------------
142
+
143
+ private
144
+ def capture_and_out_error(site, error)
145
+ if error.is_a?(Sass::SyntaxError)
146
+ file = error.sass_filename.gsub(/#{Regexp.escape(site.source)}\//, "")
147
+ Jekyll.logger.error(%Q{Error in #{file}:#{error.sass_line} #{error}})
148
+ else
149
+ Jekyll.logger.error \
150
+ "", error.to_s
151
+ end
152
+
153
+ raise error
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
159
+
160
+ %W(js css img image javascript stylesheet style asset_path asset_source asset).each do |tag|
161
+ Liquid::Template.register_tag tag, Jekyll::Assets::Liquid::Tag
162
+ end
@@ -0,0 +1,163 @@
1
+ require_relative "proxies"
2
+ require "forwardable"
3
+
4
+ module Jekyll
5
+ module Assets
6
+ module Liquid
7
+
8
+ # -----------------------------------------------------------------------
9
+ # Examples:
10
+ # - {% tag value argument:value %}
11
+ # - {% tag value "argument:value" %}
12
+ # - {% tag value argument:"I have spaces" %}
13
+ # - {% tag value argument:value\:with\:colon %}
14
+ # - {% tag value argument:"I can even escape \\: here too!" %}
15
+ # - {% tag value proxy:key:value %}
16
+ # -----------------------------------------------------------------------
17
+
18
+ class Tag
19
+ class Parser
20
+ attr_reader :args, :raw_args
21
+ extend Forwardable
22
+
23
+ def_delegator :@args, :to_h
24
+ def_delegator :@args, :has_key?
25
+ def_delegator :@args, :fetch_or_store
26
+ def_delegator :@args, :fetch
27
+ def_delegator :@args, :store
28
+ def_delegator :@args, :[]
29
+
30
+ # -------------------------------------------------------------------
31
+
32
+ Accept = {
33
+ "css" => "text/css", "js" => "application/javascript"
34
+ }
35
+
36
+ # -------------------------------------------------------------------
37
+
38
+ class UnescapedColonError < StandardError
39
+ def initialize
40
+ super "Unescaped double colon argument."
41
+ end
42
+ end
43
+
44
+ # -------------------------------------------------------------------
45
+
46
+ class UnknownProxyError < StandardError
47
+ def initialize
48
+ super "Unknown proxy argument."
49
+ end
50
+ end
51
+
52
+ # -------------------------------------------------------------------
53
+
54
+ def initialize(args, tag)
55
+ @raw_args, @tags = args, tag
56
+ @tag = tag
57
+ parse_raw
58
+ set_accept
59
+ end
60
+
61
+ # -------------------------------------------------------------------
62
+
63
+ def to_html
64
+ @args.fetch(:html, {}).map do |key, val|
65
+ %Q{ #{key}="#{val}"}
66
+ end. \
67
+ join
68
+ end
69
+
70
+ # -------------------------------------------------------------------
71
+
72
+ def proxies
73
+ keys = (args.keys - Proxies.base_keys - [:file, :html])
74
+ args.select do |key, _|
75
+ keys.include?(key)
76
+ end
77
+ end
78
+
79
+ # -------------------------------------------------------------------
80
+
81
+ def has_proxies?
82
+ proxies.any?
83
+ end
84
+
85
+ # -------------------------------------------------------------------
86
+
87
+ private
88
+ def parse_raw
89
+ @args = from_shellwords.each_with_index.inject({}) do |hash, (key, index)|
90
+ if index == 0 then hash.store(:file, key)
91
+ elsif key =~ /:/ && (key = key.split(/(?<!\\):/))
92
+ parse_col hash, key
93
+
94
+ else
95
+ hash.fetch_or_store(:html, {}). \
96
+ store(key, true)
97
+ end
98
+
99
+ hash
100
+ end
101
+ end
102
+
103
+ # -------------------------------------------------------------------
104
+
105
+ private
106
+ def parse_col(hash, key)
107
+ key.push(key.delete_at(-1).gsub(/\\:/, ":"))
108
+ if key.size == 3 then as_proxy hash, key
109
+ elsif key.size == 2 then as_bool_or_html hash, key
110
+ else raise UnescapedColonError
111
+ end
112
+ end
113
+
114
+ # -------------------------------------------------------------------
115
+
116
+ private
117
+ def as_bool_or_html(hash, key)
118
+ okey = key; key, sub_key = key
119
+ if Proxies.has?(key, @tag, "@#{sub_key}")
120
+ hash.fetch_or_store(key.to_sym, {}). \
121
+ store(sub_key.to_sym, true)
122
+ else
123
+ hash.fetch_or_store(:html, {}). \
124
+ store(key, okey.fetch(1))
125
+ end
126
+ end
127
+
128
+ # -------------------------------------------------------------------
129
+
130
+ private
131
+ def as_proxy(hash, key)
132
+ key, sub_key, val = key
133
+ if Proxies.has?(key, @tag, sub_key)
134
+ hash.fetch_or_store(key.to_sym, {}). \
135
+ store(sub_key.to_sym, val)
136
+ elsif Proxies.has?(key)
137
+ raise UnknownProxyError
138
+ end
139
+ end
140
+
141
+ # -------------------------------------------------------------------
142
+
143
+ private
144
+ def set_accept
145
+ if Accept.has_key?(@tag) && (!@args.has_key?(:sprockets) || \
146
+ !@args.fetch(:sprockets).has_Key?(:accept))
147
+
148
+ @args.fetch_or_store(:sprockets, {}). \
149
+ store(:accept, Accept.fetch(@tag))
150
+ end
151
+ end
152
+
153
+ # -------------------------------------------------------------------
154
+
155
+ private
156
+ def from_shellwords
157
+ Shellwords.shellwords(@raw_args)
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end