bunto-assets 1.0.0.pre.alpha

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 (48) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +19 -0
  3. data/LICENSE +21 -0
  4. data/README.md +275 -0
  5. data/Rakefile +3 -0
  6. data/lib/bunto/assets/addons/autoprefixer.rb +13 -0
  7. data/lib/bunto/assets/addons/bootstrap.rb +7 -0
  8. data/lib/bunto/assets/addons/font_awesome.rb +7 -0
  9. data/lib/bunto/assets/addons/javascript.rb +11 -0
  10. data/lib/bunto/assets/cached.rb +20 -0
  11. data/lib/bunto/assets/config.rb +76 -0
  12. data/lib/bunto/assets/env.rb +207 -0
  13. data/lib/bunto/assets/hook.rb +78 -0
  14. data/lib/bunto/assets/hooks/bunto/drops.rb +9 -0
  15. data/lib/bunto/assets/hooks/bunto/setup.rb +13 -0
  16. data/lib/bunto/assets/hooks/bunto/write.rb +9 -0
  17. data/lib/bunto/assets/hooks/cache.rb +15 -0
  18. data/lib/bunto/assets/hooks/compression.rb +17 -0
  19. data/lib/bunto/assets/hooks/configuration.rb +12 -0
  20. data/lib/bunto/assets/hooks/context.rb +11 -0
  21. data/lib/bunto/assets/hooks/erb.rb +15 -0
  22. data/lib/bunto/assets/hooks/helpers.rb +14 -0
  23. data/lib/bunto/assets/hooks/logger.rb +9 -0
  24. data/lib/bunto/assets/hooks/sources.rb +13 -0
  25. data/lib/bunto/assets/hooks/sprockets.rb +9 -0
  26. data/lib/bunto/assets/hooks/version.rb +11 -0
  27. data/lib/bunto/assets/hooks.rb +20 -0
  28. data/lib/bunto/assets/liquid/drop.rb +76 -0
  29. data/lib/bunto/assets/liquid/filters.rb +28 -0
  30. data/lib/bunto/assets/liquid/tag/defaults/image.rb +69 -0
  31. data/lib/bunto/assets/liquid/tag/defaults.rb +23 -0
  32. data/lib/bunto/assets/liquid/tag/parser.rb +200 -0
  33. data/lib/bunto/assets/liquid/tag/proxied_asset.rb +114 -0
  34. data/lib/bunto/assets/liquid/tag/proxies.rb +118 -0
  35. data/lib/bunto/assets/liquid/tag.rb +203 -0
  36. data/lib/bunto/assets/liquid.rb +15 -0
  37. data/lib/bunto/assets/logger.rb +59 -0
  38. data/lib/bunto/assets/patches/bunto/cleaner.rb +16 -0
  39. data/lib/bunto/assets/patches/bunto/site.rb +11 -0
  40. data/lib/bunto/assets/patches/kernel.rb +29 -0
  41. data/lib/bunto/assets/patches/sprockets/asset.rb +21 -0
  42. data/lib/bunto/assets/patches.rb +10 -0
  43. data/lib/bunto/assets/processors/liquid.rb +42 -0
  44. data/lib/bunto/assets/proxies/magick.rb +155 -0
  45. data/lib/bunto/assets/version.rb +11 -0
  46. data/lib/bunto/assets.rb +24 -0
  47. data/lib/bunto-assets.rb +7 -0
  48. metadata +197 -0
@@ -0,0 +1,114 @@
1
+ # ----------------------------------------------------------------------------
2
+ # Frozen-string-literal: true
3
+ # Copyright: 2016-present - MIT License
4
+ # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
6
+
7
+ require "forwardable"
8
+
9
+ module Bunto
10
+ module Assets
11
+ module Liquid
12
+ class Tag
13
+ class ProxiedAsset
14
+ attr_reader :args, :asset, :env
15
+ extend Forwardable
16
+
17
+ # ------------------------------------------------------------------
18
+
19
+ def_delegator :@asset, :liquid_tags
20
+ def_delegator :@asset, :filename, :source_filename
21
+ def_delegator :@asset, :content_type
22
+ def_delegator :@asset, :mtime
23
+
24
+ # ------------------------------------------------------------------
25
+
26
+ def initialize(asset, args, env, tag)
27
+ @env = env
28
+ @asset = asset
29
+ @args = args
30
+ @tag = tag
31
+
32
+ cache_file
33
+ proxy_file
34
+ end
35
+
36
+ # ------------------------------------------------------------------
37
+
38
+ def cached?
39
+ @_cached
40
+ end
41
+
42
+ # ------------------------------------------------------------------
43
+
44
+ def write_to(name)
45
+ FileUtils.mkdir_p File.dirname(name)
46
+ Sprockets::PathUtils.atomic_write(name) do |f|
47
+ f.write source
48
+ end
49
+ end
50
+
51
+ # ------------------------------------------------------------------
52
+
53
+ def source
54
+ File.binread(filename)
55
+ end
56
+
57
+ # ------------------------------------------------------------------
58
+
59
+ def filename
60
+ env.in_cache_dir(digest_path)
61
+ end
62
+
63
+ # ------------------------------------------------------------------
64
+
65
+ def digest
66
+ Digest::SHA2.hexdigest(args.proxies.to_s)
67
+ end
68
+
69
+ # ------------------------------------------------------------------
70
+ # We always digest a proxied asset so it's uniq based on what
71
+ # proxies you give us, it would be ignorant to treat it otherwise,
72
+ # we also make sure they are URL safe by digesting the args.
73
+ # ------------------------------------------------------------------
74
+
75
+ def logical_path
76
+ digest_path
77
+ end
78
+
79
+ # ------------------------------------------------------------------
80
+
81
+ def digest_path
82
+ name = asset.logical_path
83
+ ext = File.extname(name)
84
+ "#{name.chomp(ext)}-#{digest}#{ext}"
85
+ end
86
+
87
+ # ------------------------------------------------------------------
88
+
89
+ private
90
+ def proxy_file
91
+ unless cached?
92
+ args.proxies.each do |key, val|
93
+ Proxies.get(key).first[:class].new(self, val, @args).process
94
+ end
95
+ end
96
+ end
97
+
98
+ # ------------------------------------------------------------------
99
+
100
+ private
101
+ def cache_file
102
+ @_cached = File.file?(filename)
103
+ return @_cached if @_cached
104
+
105
+ dir = File.dirname(filename)
106
+ FileUtils.mkdir_p dir unless dir == env.in_cache_dir
107
+ FileUtils.cp asset.filename, filename
108
+ true
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,118 @@
1
+ # ----------------------------------------------------------------------------
2
+ # Frozen-string-literal: true
3
+ # Copyright: 2016-present - MIT License
4
+ # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
6
+
7
+ module Bunto
8
+ module Assets
9
+ module Liquid
10
+ class Tag
11
+ module Proxies
12
+ def self.add_by_class(class_, name, tag, *args)
13
+ proc_ = proc { |v| [v.to_s, v, v.to_sym] }
14
+ all << {
15
+ :name => proc_.call(name).uniq,
16
+ :args => [args].flatten.map(&proc_).flatten.uniq,
17
+ :tags => [ tag].flatten.map(&proc_).flatten.uniq,
18
+ :class => class_
19
+ }
20
+
21
+ all
22
+ end
23
+
24
+ # ------------------------------------------------------------------
25
+
26
+ def self.add(name, tag, *args, &block)
27
+ add_by_class(*generate_class(name, tag, &block), *args)
28
+ end
29
+
30
+ # ------------------------------------------------------------------
31
+
32
+ def self.keys
33
+ all.select { |val| !val[:class].is_a?(Symbol) }.map do |val|
34
+ val[:name]
35
+ end.flatten
36
+ end
37
+
38
+ # ------------------------------------------------------------------
39
+
40
+ def self.base_keys
41
+ all.select { |val| val[:class].is_a?(Symbol) }.map do |val|
42
+ val[:name]
43
+ end.flatten
44
+ end
45
+
46
+ # ------------------------------------------------------------------
47
+
48
+ def self.has?(name, tag = nil, arg = nil)
49
+ get(name, tag, arg).any?
50
+ end
51
+
52
+ # ------------------------------------------------------------------
53
+
54
+ def self.get(name, tag = nil, arg = nil)
55
+ if name && tag && arg then get_by_name_and_tag_and_arg(name, tag, arg)
56
+ elsif name && tag
57
+ get_by_name_and_tag(name, tag)
58
+
59
+ else
60
+ all.select do |val|
61
+ val[:name].include?(name)
62
+ end
63
+ end
64
+ end
65
+
66
+ # ------------------------------------------------------------------
67
+
68
+ def self.get_by_name_and_tag_and_arg(name, tag, arg)
69
+ all.select do |val|
70
+ val[:name].include?(name) && (val[:tags].include?(:all) || val[:tags] \
71
+ .include?(tag)) && val[:args].include?(arg)
72
+ end
73
+ end
74
+
75
+ # ------------------------------------------------------------------
76
+
77
+ def self.get_by_name_and_tag(name, tag)
78
+ all.select do |val|
79
+ val[:name].include?(name) && (val[:tags].include?(:all) || val[:tags] \
80
+ .include?(tag))
81
+ end
82
+ end
83
+
84
+ # ------------------------------------------------------------------
85
+
86
+ def self.all
87
+ @_all ||= Set.new
88
+ end
89
+
90
+ # ------------------------------------------------------------------
91
+
92
+ private
93
+ def self.generate_class(name, tag, &block)
94
+ class_ = const_set(random_name, Class.new)
95
+ class_.class_eval(&block)
96
+ return class_, name, tag
97
+ end
98
+
99
+ # ------------------------------------------------------------------
100
+
101
+ private
102
+ def self.random_name
103
+ (0...12).map { ("a".."z").to_a.values_at(rand(26)) }.join.capitalize
104
+ end
105
+
106
+ # ------------------------------------------------------------------
107
+ # TODO: Put in a better place.
108
+ # ------------------------------------------------------------------
109
+
110
+ add_by_class :internal, :data, :all, ["@uri"]
111
+ add_by_class :internal, :sprockets, :all, [
112
+ "accept", "write_to"
113
+ ]
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,203 @@
1
+ # ----------------------------------------------------------------------------
2
+ # Frozen-string-literal: true
3
+ # Copyright: 2016-present - MIT License
4
+ # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
6
+
7
+ require "fastimage"
8
+
9
+ module Bunto
10
+ module Assets
11
+ module Liquid
12
+ class Tag < ::Liquid::Tag
13
+ require_relative "tag/proxies"
14
+ require_relative "tag/proxied_asset"
15
+ require_relative "tag/defaults"
16
+ require_relative "tag/parser"
17
+ attr_reader :args
18
+
19
+ # --------------------------------------------------------------------
20
+
21
+ class << self
22
+ public :new
23
+ end
24
+
25
+ # --------------------------------------------------------------------
26
+
27
+ class AssetNotFoundError < StandardError
28
+ def initialize(asset)
29
+ super "Could not find the asset `#{asset}'"
30
+ end
31
+ end
32
+
33
+ # --------------------------------------------------------------------
34
+ # Tags that we allow our users to use.
35
+ # --------------------------------------------------------------------
36
+
37
+ AcceptableTags = %W(
38
+ img
39
+ image
40
+ javascript
41
+ asset_source
42
+ stylesheet
43
+ asset_path
44
+ style
45
+ asset
46
+ css
47
+ js
48
+ ).freeze
49
+
50
+ # --------------------------------------------------------------------
51
+ # The HTML version of every tag that we accept.
52
+ # --------------------------------------------------------------------
53
+
54
+ Tags = {
55
+ "css" => %{<link type="text/css" rel="stylesheet" href="%s"%s>},
56
+ "js" => %{<script type="text/javascript" src="%s"%s></script>},
57
+ "img" => %{<img src="%s"%s>}
58
+ }.freeze
59
+
60
+ # --------------------------------------------------------------------
61
+ # Allows us to normalize tags so we can simplify logic.
62
+ # --------------------------------------------------------------------
63
+
64
+ Alias = {
65
+ "image" => "img",
66
+ "stylesheet" => "css",
67
+ "javascript" => "js",
68
+ "style" => "css"
69
+ }.freeze
70
+
71
+ # --------------------------------------------------------------------
72
+
73
+ def initialize(tag, args, tokens)
74
+ tag = tag.to_s
75
+ @tokens = tokens
76
+ @tag = from_alias(tag)
77
+ @args = Parser.new(args, @tag)
78
+ @og_tag = tag
79
+ super
80
+ end
81
+
82
+ # --------------------------------------------------------------------
83
+ # NOTE: We only attach to the regenerator if you are using digested
84
+ # assets, otherwise we forego any association with it so that we keep
85
+ # your builds ultra fast, this is ideal in dev. Disable digests and
86
+ # let us process independent so the entire site isn't regenerated
87
+ # because of a single asset change.
88
+ # --------------------------------------------------------------------
89
+
90
+ def render(context)
91
+ site = context.registers[:site]
92
+ page = context.registers.fetch(:page, {})
93
+ args = @args.parse_liquid(context)
94
+ sprockets = site.sprockets
95
+ page = page["path"]
96
+
97
+ asset = find_asset(args, sprockets)
98
+ add_as_bunto_dependency(site, sprockets, page, asset)
99
+ process_tag(args, sprockets, asset)
100
+
101
+ rescue => e
102
+ capture_and_out_error(
103
+ site, e
104
+ )
105
+ end
106
+
107
+ # --------------------------------------------------------------------
108
+
109
+ private
110
+ def from_alias(tag)
111
+ Alias.key?(tag) ? Alias[tag] : tag
112
+ end
113
+
114
+ # --------------------------------------------------------------------
115
+
116
+ private
117
+ def process_tag(args, sprockets, asset)
118
+ sprockets.used.add(asset) unless @tag == "asset_source"
119
+ Defaults.set_defaults_for!(@tag, args ||= {}, asset, sprockets)
120
+ build_html(args, sprockets, asset)
121
+ end
122
+
123
+ # --------------------------------------------------------------------
124
+
125
+ private
126
+ def build_html(args, sprockets, asset, path = get_path(sprockets, asset))
127
+ return path if @tag == "asset_path"
128
+ return asset.to_s if @tag == "asset" || @tag == "asset_source"
129
+ return format(Tags[@tag], asset.data_uri, args.to_html) if args.key?(:data) && args[:data].key?(:uri)
130
+ format(Tags[@tag], path, args.to_html)
131
+ end
132
+
133
+ # --------------------------------------------------------------------
134
+
135
+ private
136
+ def get_path(sprockets, asset)
137
+ sprockets.prefix_path(
138
+ sprockets.digest?? asset.digest_path : asset.logical_path
139
+ )
140
+ end
141
+
142
+ # --------------------------------------------------------------------
143
+
144
+ private
145
+ def add_as_bunto_dependency(site, sprockets, page, asset)
146
+ if page && sprockets.digest?
147
+ site.regenerator.add_dependency(
148
+ site.in_source_dir(page), site.in_source_dir(asset.logical_path)
149
+ )
150
+ end
151
+ end
152
+
153
+ # --------------------------------------------------------------------
154
+
155
+ private
156
+ def find_asset(args, sprockets)
157
+ sprockets_, file = args[:sprockets] ||= {}, args[:file]
158
+ if !(out = sprockets.find_asset(file, sprockets_))
159
+ raise(
160
+ AssetNotFoundError, args[:file]
161
+ )
162
+
163
+ else
164
+ out.liquid_tags << self
165
+ !args.proxies?? out : ProxiedAsset.new(
166
+ out, args, sprockets, self
167
+ )
168
+ end
169
+ end
170
+
171
+ # --------------------------------------------------------------------
172
+ # There is no guarantee that Bunto will pass on the error for some
173
+ # reason (unless you are just booting up) so we capture that error and
174
+ # always output it, it can lead to some double errors but I would
175
+ # rather there be a double error than no error.
176
+ # --------------------------------------------------------------------
177
+
178
+ private
179
+ def capture_and_out_error(site, error)
180
+ if error.is_a?(Sass::SyntaxError)
181
+ file = error.sass_filename.gsub(/#{Regexp.escape(site.source)}\//, "")
182
+ Bunto.logger.error(%{Error in #{file}:#{error.sass_line} #{
183
+ error
184
+ }})
185
+
186
+ else
187
+ Bunto.logger.error(
188
+ "", error.to_s
189
+ )
190
+ end
191
+
192
+ raise error
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
198
+
199
+ # ----------------------------------------------------------------------------
200
+
201
+ Bunto::Assets::Liquid::Tag::AcceptableTags.each do |tag|
202
+ Liquid::Template.register_tag tag, Bunto::Assets::Liquid::Tag
203
+ end
@@ -0,0 +1,15 @@
1
+ # ----------------------------------------------------------------------------
2
+ # Frozen-string-literal: true
3
+ # Copyright: 2016-present - MIT License
4
+ # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
6
+
7
+ module Bunto
8
+ module Assets
9
+ module Liquid
10
+ require_relative "liquid/drop"
11
+ require_relative "liquid/filters"
12
+ require_relative "liquid/tag"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,59 @@
1
+ # ----------------------------------------------------------------------------
2
+ # Frozen-string-literal: true
3
+ # Copyright: 2016-present - MIT License
4
+ # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
6
+
7
+ module Bunto
8
+ module Assets
9
+ class Logger
10
+ PREFIX = "Bunto Assets:"
11
+
12
+ def log
13
+ @_log ||= Bunto.logger
14
+ end
15
+
16
+ # ----------------------------------------------------------------------
17
+ # Log Level: 1
18
+ # ----------------------------------------------------------------------
19
+
20
+ def warn(msg = nil, &block)
21
+ msg = (block_given?? block.call : msg)
22
+ log.warn(PREFIX, msg)
23
+ end
24
+
25
+ # ----------------------------------------------------------------------
26
+ # Log Level: 1
27
+ # ----------------------------------------------------------------------
28
+
29
+ def error(msg = nil, &block)
30
+ msg = (block_given?? block.call : msg)
31
+ log.error(PREFIX, msg)
32
+ end
33
+
34
+ # ----------------------------------------------------------------------
35
+ # Log Level: 2
36
+ # ----------------------------------------------------------------------
37
+
38
+ def info(msg = nil, &block)
39
+ msg = (block_given?? block.call : msg)
40
+ log.info(PREFIX, msg)
41
+ end
42
+
43
+ # ----------------------------------------------------------------------
44
+ # Log Level: 3
45
+ # ----------------------------------------------------------------------
46
+
47
+ def debug(msg = nil, &block)
48
+ msg = (block_given?? block.call : msg)
49
+ log.debug(PREFIX, msg)
50
+ end
51
+
52
+ # ----------------------------------------------------------------------
53
+
54
+ def log_level=(*)
55
+ raise RuntimeError, "Please set log levels on Bunto.logger"
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,16 @@
1
+ # ----------------------------------------------------------------------------
2
+ # Frozen-string-literal: true
3
+ # Copyright: 2016-present - MIT License
4
+ # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
6
+
7
+ module Bunto
8
+ class Cleaner
9
+ alias _old_obsolete_files obsolete_files
10
+ def obsolete_files
11
+ _old_obsolete_files.delete_if do |path|
12
+ path =~ %r!\A#{Regexp.escape(site.in_dest_dir("assets"))}(\/.*)?\Z!
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ # ----------------------------------------------------------------------------
2
+ # Frozen-string-literal: true
3
+ # Copyright: 2016-present - MIT License
4
+ # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
6
+
7
+ module Bunto
8
+ class Site
9
+ attr_accessor :sprockets
10
+ end
11
+ end
@@ -0,0 +1,29 @@
1
+ # ----------------------------------------------------------------------------
2
+ # Frozen-string-literal: true
3
+ # Copyright: 2016-present - MIT License
4
+ # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
6
+
7
+ module Kernel
8
+ def try_require(file)
9
+ require file
10
+ if block_given?
11
+ yield
12
+ end
13
+ rescue LoadError
14
+ return nil
15
+ end
16
+
17
+ # --------------------------------------------------------------------------
18
+
19
+ def try_require_if_javascript(file)
20
+ ["execjs", file].map(&method(:require))
21
+ if block_given?
22
+ yield
23
+ end
24
+ rescue LoadError, ExecJS::RuntimeUnavailable
25
+ Bunto.logger.debug("ExecJS, JS Runtime or `#{file}' not available." \
26
+ " Skipping the loading of libraries.")
27
+ return
28
+ end
29
+ end
@@ -0,0 +1,21 @@
1
+ # ----------------------------------------------------------------------------
2
+ # Frozen-string-literal: true
3
+ # Copyright: 2016-present - MIT License
4
+ # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
6
+
7
+ module Sprockets
8
+ class Asset
9
+ def liquid_tags
10
+ metadata[:liquid_tags] ||= Set.new
11
+ end
12
+
13
+ # ------------------------------------------------------------------------
14
+
15
+ def data_uri
16
+ "data:#{content_type};base64,#{Rack::Utils.escape(
17
+ Base64.encode64(to_s)
18
+ )}"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ # ----------------------------------------------------------------------------
2
+ # Frozen-string-literal: true
3
+ # Copyright: 2016-present - MIT License
4
+ # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
6
+
7
+ require_relative "patches/bunto/cleaner"
8
+ require_relative "patches/sprockets/asset"
9
+ require_relative "patches/bunto/site"
10
+ require_relative "patches/kernel"
@@ -0,0 +1,42 @@
1
+ module Bunto
2
+ module Assets
3
+ module Processors
4
+ class Liquid
5
+ FOR = %W(
6
+ text/css text/sass text/less application/javascript
7
+ text/scss text/coffeescript text/javascript).freeze
8
+ EXT = %W(.liquid .js.liquid .css.liquid .scss.liquid).freeze
9
+
10
+ # --------------------------------------------------------------------
11
+
12
+ def self.call(context, bunto = context[:environment].bunto)
13
+ if context[:environment].parent.asset_config["features"]["liquid"] || \
14
+ File.extname(context[:filename]) == ".liquid"
15
+
16
+ payload_ = bunto.site_payload
17
+ renderer = bunto.liquid_renderer.file(context[:filename])
18
+ context[:data] = renderer.parse(context[:data]).render! payload_, :registers => {
19
+ :site => bunto
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ # ----------------------------------------------------------------------------
29
+ # There might be a few missing, if there is please do let me know.
30
+ # ----------------------------------------------------------------------------
31
+
32
+ Bunto::Assets::Processors::Liquid::EXT.each do |ext|
33
+ Sprockets.register_engine(
34
+ ext, Bunto::Assets::Processors::Liquid
35
+ )
36
+ end
37
+
38
+ Bunto::Assets::Processors::Liquid::FOR.each do |val|
39
+ Sprockets.register_preprocessor(
40
+ val, Bunto::Assets::Processors::Liquid
41
+ )
42
+ end