blix-assets 0.1.5

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5ae57089bbdbcfd6502c2d9971c8426586255a4741ea496203b583450ba8e9ae
4
+ data.tar.gz: e8a0acfb4dcc36a8f19825ddf1076ac205359e3e6e29e6b89f4836500f6a4761
5
+ SHA512:
6
+ metadata.gz: a31cfcb6ae272fea115afdffc9799b226633c123edd8b7e24d03048742f8691789649fd2635e75336c0c9fdb2ddeb33f5c4be46d3b8b1131bf32ec920f58fa77
7
+ data.tar.gz: 4e68d177b42d011ab740d23e7dd5068cc045f37a1f4cdd61846aae6fb36b1db909c6d0cfffac89c42092610df1b028d9cd542925e84a7d8cb09425a9ba67f0ab
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Clive Andrews
4
+
5
+
6
+ Permission is hereby granted, free of charge, to any person
7
+ obtaining a copy of this software and associated documentation
8
+ files (the "Software"), to deal in the Software without
9
+ restriction, including without limitation the rights to use,
10
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the
12
+ Software is furnished to do so, subject to the following
13
+ conditions:
14
+
15
+ The above copyright notice and this permission notice shall be
16
+ included in all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,127 @@
1
+ ## INSTALLATION
2
+
3
+ gem install blix-assets
4
+
5
+
6
+ ## Manage Asset Files
7
+
8
+ #### using the asset pipeline
9
+
10
+ the assets are served by your asset pipeline ( sprockets) and the link to the asset in your html
11
+ is the asset name pure and simple.
12
+
13
+ eg:
14
+
15
+ <script src="/assets/application.js" type="text/javascript"></script>
16
+
17
+ #### using compiled assets
18
+
19
+ a hash is added to the asset name to ensure that it is unique. This allows the asset to be cached indefinitely on the
20
+ browser.
21
+
22
+ eg:
23
+
24
+ <script src="/assets/application-59D3331242D65ECC.js" type="text/javascript"></script>
25
+
26
+ #### template helper
27
+
28
+ in order to use the relevant version user the *asset_path* helper in you template. The PRODUCTION flag should indicate
29
+ if you are in development mode (false) or in production mode/compiled assets mode (true).
30
+
31
+ eg:
32
+
33
+ <script src="<%= Blix::AssetManager.asset_path('/assets/application.js',PRODUCTION) %>" type="text/javascript"></script>
34
+
35
+ <%= Blix::AssetManager.asset_tag('/assets/application.js',PRODUCTION) %>
36
+
37
+ <%= Blix::AssetManager.asset_tag('/assets/main.css',PRODUCTION, :media=>'screen') %>
38
+
39
+ if you are using blix_rest then there is a helper defined ..
40
+
41
+ <script src="<%= asset_path('/assets/application.js') %>" type="text/javascript"></script>
42
+
43
+ or the complete tag ..
44
+
45
+ <%= asset_tag('/assets/application.js') %>
46
+
47
+ <%= asset_tag('/static/man.css', :media=>'screen') %>
48
+
49
+ to enable this helper you have to `require 'blix/rest'` first and then `require 'blix/assets'`
50
+
51
+ ##### inline assets
52
+
53
+ assets can also be inlined which results in the contents of the compiled
54
+ assets to be inlined in *production* mode only.
55
+
56
+ In development mode a link to the asset is used.
57
+
58
+ <%= asset_tag('/assets/application.js', :inline=>true ) %>
59
+
60
+ <%= asset_tag('/static/main.css', :media=>'screen', :inline=>true) %>
61
+
62
+ ## Mount points in templates
63
+
64
+ use the following helpers to expand any filenames to include a mount point
65
+ in your templates.
66
+
67
+ Blix::AssetManager.set_path_root( '/myapp')
68
+
69
+ Blix::AssetManager.full_path('/images/icon.png') ==> '/myapp/images/icon.png'
70
+
71
+ ## Compiling Assets
72
+
73
+ ensure that the destination dictory exists and that the config directory
74
+ 'config/assets' also exists !!
75
+
76
+ For the destination directory use a path relative to your applications working directory.
77
+
78
+ This will ensure that the file can be found in your production environment as well as in your
79
+ development environment.
80
+
81
+ require 'blix/assets'
82
+
83
+ DEST = File.join("www","assets") # where the asset is to be written
84
+
85
+ data = environment[name].to_s # the compiled asset data
86
+
87
+ Blix::AssetManager.write_asset(DEST,"application.js",data)
88
+
89
+ it is also possible to force a version number on the asset instead of a generated stamp
90
+
91
+ Blix::AssetManager.write_asset(DEST,"application.js",data, :version=>"1.2.3")
92
+
93
+
94
+ ## Generate a static index.html
95
+
96
+ it is possible to generate a static index.html with the correct assets within your asset compile script.
97
+
98
+ you will need an index.html.erb file with the <%= Blix::AssetManager.asset_tag .. %> code
99
+
100
+ and set your PRODUCTION variable to true in the compile script. In your config.ru set PRODUCTION to false in
101
+ development mode.
102
+
103
+ eg ...
104
+
105
+ index.html.erb
106
+
107
+ ....
108
+ ....
109
+ <head>
110
+ <%= Blix::AssetManager.asset_tag('/assets/application.js',PRODUCTION) %>
111
+ <%= Blix::AssetManager.asset_tag('/assets/main.css',PRODUCTION, :media=>'screen') %>
112
+
113
+ </head>
114
+
115
+ compile_assets.rb ..
116
+
117
+ ROOT = Dir.pwd
118
+ PRODUCTION = true
119
+ DEST = File.join("www","assets")
120
+ ....
121
+ ....
122
+ Blix::AssetManager.write_asset(DEST,"application.js",environment["application.js"].to_s)
123
+ Blix::AssetManager.write_asset(DEST,"main.css",environment["main.css"].to_s)
124
+ ....
125
+ ....
126
+
127
+ File.write File.join("www","index.html"),environment['index.html'].to_s
@@ -0,0 +1,20 @@
1
+ require 'blix/assets/asset_manager'
2
+
3
+ # add the asset_path method to the Controller if it is being used.
4
+ if defined? Blix::Rest
5
+ module Blix
6
+ module Rest
7
+ class Controller
8
+ def asset_path(partial_path)
9
+ AssetManager.asset_path(full_path(partial_path),mode_production?)
10
+ end
11
+
12
+ # make a complete html tag for an asset
13
+ def asset_tag(partial_path,opts={})
14
+ AssetManager.asset_tag(full_path(partial_path),mode_production?,opts)
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,265 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ # manage your asset names
6
+ #
7
+ # a config directory contains a file for each managed asset using its generic name. In the file
8
+ # is the unique stamp that is used to find the name of the latest version of the asset.
9
+ # config format consists of a filestamp part and md5 hash part
10
+ #
11
+ # ensure that your config dir exists (default config/assets)
12
+ # ensure that you destination dir exists ( eg public/assets )
13
+ #
14
+ # then use something like this to compile your assets...
15
+ #
16
+ # ASSETS = ['main.js', 'main.css']
17
+ # ASSETS.each do |name|
18
+ #
19
+ # str = environment[name].to_s
20
+ #
21
+ # if File.extname(name) == ".css"
22
+ # engine = Sass::Engine.new(str, :syntax => :scss, :style => :compressed)
23
+ # str = engine.render
24
+ # end
25
+ #
26
+ # AssetManager.if_modified(name,str,:rewrite=>true) do |a|
27
+ #
28
+ # filename = File.join(ROOT,"www","assets",a.newname)
29
+ # puts "writing #{name} to #{filename}"
30
+ # File.write filename,str
31
+ #
32
+ # File.unlink File.join(ROOT,"www","assets",a.oldname) if a.oldname
33
+ # end
34
+ #
35
+ # end
36
+ #
37
+ #
38
+ # then within your erb template or whatever ...
39
+ #
40
+ # <script src="<%= AssetManager.asset_path('/assets/main.js',flag) %>" type="text/javascript"></script>
41
+ #
42
+ # where flag indicates if the static compiled version should be used ( ie with hash) or the plain name ( served by sprockets pipeline)
43
+
44
+ module Blix
45
+ class AssetManager
46
+
47
+ AssetInfo = Struct.new(:newname, :oldname)
48
+ class << self
49
+
50
+ def config_dir
51
+ @config_dir || 'config/assets'
52
+ end
53
+
54
+ attr_writer :config_dir
55
+
56
+ # the name of the file to write to
57
+ def filename(name)
58
+ name
59
+ end
60
+
61
+ def asset_root
62
+ @asset_root || 'assets'
63
+ end
64
+
65
+ attr_writer :asset_root
66
+
67
+ # write the compiled asset here
68
+ def dest_path(name)
69
+ File.join(asset_dir, filename(name))
70
+ end
71
+
72
+ # write the config info here
73
+ def config_path(name)
74
+ File.join(config_dir, filename(name) + '.conf')
75
+ end
76
+
77
+ # yield the old and new name to a block if
78
+ # the asset has been modified
79
+ def if_modified(destination, name, data, opts = {})
80
+ new_hash = Digest::MD5.hexdigest data
81
+
82
+ ext = File.extname(name)[1..-1]
83
+ base = name.split('.')[0]
84
+ confname = base + '.' + ext
85
+ config = get_config(confname)
86
+
87
+ if !config ||
88
+ (config[:hash] != new_hash || (config[:destination] != destination)) ||
89
+ opts[:version] && (opts[:version] != config[:version])
90
+
91
+ stamp = get_filestamp
92
+ info = AssetInfo.new
93
+ info.newname = "#{base}-#{opts[:version] || stamp}.#{ext}"
94
+ info.oldname = config && "#{base}-#{config[:version] || config[:stamp]}.#{ext}"
95
+ set_config(destination, confname, new_hash, stamp, opts[:version])
96
+ yield(info)
97
+
98
+ elsif opts[:rewrite] # rewrite the same data to the same asset as before
99
+
100
+ info = AssetInfo.new
101
+ info.newname = config && "#{base}-#{config[:version] || config[:stamp]}.#{ext}"
102
+ info.oldname = nil
103
+ yield(info)
104
+
105
+ end
106
+ end
107
+
108
+ # generate a unique suffix for the file
109
+ def get_filestamp
110
+ now = Time.now
111
+ str = '%X' % now.to_i
112
+ str += '%X' % now.usec
113
+ str += '%X' % rand(9999)
114
+ str
115
+ end
116
+
117
+ # get config data from file or nil if file does not exist
118
+ def get_config(name)
119
+ return nil unless File.exist? config_path(name)
120
+
121
+ data = File.read config_path(name)
122
+ parts = data.split('|')
123
+ out = { :hash => parts[1], :stamp => parts[0], :destination => parts[3] }
124
+ out[:version] = parts[2] unless parts[2].empty?
125
+ out
126
+ end
127
+
128
+ # set the config data
129
+ def set_config(destination, name, hash, stamp, version = nil)
130
+ File.write(config_path(name), stamp + '|' + hash + '|' + version.to_s + '|' + destination)
131
+ true
132
+ end
133
+
134
+ # cache asset name store
135
+ def cache
136
+ @cache ||= {}
137
+ end
138
+
139
+ # retrieve and cache the full asset name
140
+ def get_asset_name(name)
141
+ cache[name] ||= begin
142
+ config = get_config(name)
143
+ raise "ERROR : config file for asset:#{name} not found !!" unless config
144
+
145
+ ext = File.extname(name)[1..-1]
146
+ base = name.split('.')[0]
147
+ base + '-' + (config[:version] || config[:stamp]) + '.' + ext
148
+ end
149
+ end
150
+
151
+ # retrieve and cache the full asset name
152
+ def get_asset_version_name(name)
153
+ cache[name] ||= begin
154
+ config = get_config(name)
155
+ raise "ERROR : config file for asset:#{name} not found !!" unless config
156
+
157
+ ext = File.extname(name)[1..-1]
158
+ base = name.split('.')[0]
159
+ base + '-' + config[:version] + '.' + ext
160
+ end
161
+ end
162
+
163
+ def set_path_root(root)
164
+ root = root.to_s
165
+ root = '/' + root if root[0, 1] != '/'
166
+ root += '/' if root[-1, 1] != '/'
167
+ @path_root = root
168
+ @path_root_length = @path_root.length - 1
169
+ end
170
+
171
+ def path_root
172
+ @path_root || '/'
173
+ end
174
+
175
+ attr_reader :path_root_length
176
+
177
+ # calculate the full path of the asset
178
+ def full_path(path)
179
+ path = path[1..-1] if path[0, 1] == '/'
180
+ path_root + path
181
+ end
182
+
183
+ # caculate the correct asset path depending on the mode of execution
184
+ def asset_path(path, mode_production = false)
185
+ partial_path = full_path(path)
186
+ if mode_production
187
+ asset_name = File.basename(partial_path)
188
+ dir_name = File.dirname(partial_path)
189
+ if dir_name == '.'
190
+ AssetManager.get_asset_name(asset_name)
191
+ else
192
+ File.join(dir_name, AssetManager.get_asset_name(asset_name))
193
+ end
194
+ else
195
+ partial_path
196
+ end
197
+ end
198
+
199
+ # return the location of the compiled asset
200
+ def file_path(path)
201
+ name = File.basename(path)
202
+ config = get_config(name)
203
+ raise "ERROR : config file for asset:#{name} not found !!" unless config
204
+
205
+ ext = File.extname(name)[1..-1]
206
+ base = name.split('.')[0]
207
+ config[:destination] + '/' + base + '-' + (config[:version] || config[:stamp]) + '.' + ext
208
+ end
209
+
210
+ # write a complete asset tag html string
211
+ def asset_tag(partial_path, mode_production = false, opts = {})
212
+ name = File.basename(partial_path)
213
+ type = File.extname(partial_path)
214
+ inline = opts.delete(:inline)
215
+ opts_str = opts.to_a.map { |v| "#{v[0]}=\"#{v[1]}\"" }.join(' ')
216
+
217
+ if type == '.css'
218
+ if mode_production && inline
219
+ content = cache['///' + name] ||= File.read(file_path(partial_path))
220
+ %(<style type="text/css" #{opts_str} >\n#{content}</style>)
221
+ else
222
+ %(<link rel="stylesheet" href="#{asset_path(partial_path, mode_production)}" type="text/css" #{opts_str} >)
223
+ end
224
+ elsif type == '.js'
225
+ if mode_production && inline
226
+ # insert js here if in production mode
227
+ content = cache['///' + name] ||= File.read(file_path(partial_path))
228
+ %(<script>\n#{content}</script>)
229
+ else
230
+ %(<script src="#{asset_path(partial_path, mode_production)}" type="text/javascript"></script>)
231
+ end
232
+ else
233
+ raise "unknown tag for file extension:#{partial_path}"
234
+ end
235
+ end
236
+
237
+ # write an asset to the destination directory
238
+ def write_asset(destination, name, str, opts = {})
239
+ opts = opts.dup
240
+ opts[:rewrite] = true unless opts.key?(:rewrite)
241
+ raise "asset destination directory must exist:#{destination}" unless Dir.exist?(destination)
242
+
243
+ puts "#{red('WARNING !')} Use a relative path to the destination directory" if destination[0] == '/' # with colour red
244
+ if_modified(destination, name, str, opts) do |a|
245
+ outfile = File.join(destination, a.newname)
246
+ File.write outfile, str
247
+ if a.oldname && (a.oldname != a.newname)
248
+ oldfilename = File.join(destination, a.oldname)
249
+ File.unlink oldfilename if File.exist?(oldfilename)
250
+ end
251
+ outfile
252
+ end
253
+ end
254
+
255
+ private
256
+
257
+ # escape text for printing in red on console.
258
+ def red(text)
259
+ "\e[31m#{text}\e[0m"
260
+ end
261
+
262
+ end
263
+
264
+ end
265
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: blix-assets
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.5
5
+ platform: ruby
6
+ authors:
7
+ - Clive Andrews
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-08-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Basic Routines for managing Compiled Assets
28
+ email:
29
+ - gems@realitybites.eu
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files:
33
+ - README.md
34
+ - LICENSE
35
+ files:
36
+ - LICENSE
37
+ - README.md
38
+ - lib/blix/assets.rb
39
+ - lib/blix/assets/asset_manager.rb
40
+ homepage: https://github.com/realbite/blix-rest
41
+ licenses:
42
+ - MIT
43
+ metadata: {}
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubygems_version: 3.1.4
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Basic Asset Management Routines
63
+ test_files: []