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

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