esvg 4.1.0 → 4.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1529e25e48e1086a9ac6756093c81e4e96192400
4
- data.tar.gz: d36d81e3e2fec5665acf2320a658d41c1579a36d
3
+ metadata.gz: 27d93663b8b9b36654390502132bf232efe68c66
4
+ data.tar.gz: 43344a22127df181e71d73602dbe0764e51d13e5
5
5
  SHA512:
6
- metadata.gz: 976ec5f1418b143edb27698ccfedc89eb48a8eda4bfa741725d9a73412bc9b7a55ce42b7dafee6b9e9636ff41d5c6a924624d2a2ded858c5e7f2fcbd8658f651
7
- data.tar.gz: 8ca64f5d17cc615f18e3202e0b2e79a5abe5c58ab80fce208fa757ce72661c6b1a053256424772e9778dc57500fbdcd461f1849e1126aa908ba6f857382ea6e6
6
+ metadata.gz: cc486ddf04d4b6692407740dc3d1c808181587ce8d92c0e3a78b33c35c4631d1913b961d649b2179e4e9378d4c230e2d8c53cf8e513568246511686387e3c7b2
7
+ data.tar.gz: 1d1e3f0476e4c2dee4eb68d2814712407b0e84eb8faf1e5bd49b9b5729bfa95181c106ce5ddd98e6053bb54245907702d8bfe07992dcb2c337d573f7eb65eb20
data/lib/esvg/helpers.rb CHANGED
@@ -10,10 +10,10 @@ module Esvg::Helpers
10
10
 
11
11
 
12
12
  def embed_svgs(*keys)
13
- if Rails.env.production?
14
- esvg.build_paths(keys).each do |path|
13
+ if !Rails.env.production?
14
+ esvg.build_paths(keys).map do |path|
15
15
  javascript_include_tag(path)
16
- end.join("\n")
16
+ end.join("\n").html_safe
17
17
  else
18
18
  esvg.embed_script(keys).html_safe
19
19
  end
data/lib/esvg/svg.rb CHANGED
@@ -22,7 +22,7 @@ module Esvg
22
22
  CONFIG_RAILS = {
23
23
  source: "app/assets/svgs",
24
24
  assets: "app/assets/javascripts",
25
- build: "public/assets",
25
+ build: "public/javascripts",
26
26
  temp: "tmp"
27
27
  }
28
28
 
@@ -77,7 +77,6 @@ module Esvg
77
77
  # Get a list of svg files and modification times
78
78
  #
79
79
  find_files
80
- write_cache
81
80
 
82
81
  @last_read = Time.now.to_i
83
82
 
@@ -90,6 +89,7 @@ module Esvg
90
89
 
91
90
  def find_files
92
91
  files = Dir[File.join(config[:source], '**/*.svg')].uniq.sort
92
+ @svg_symbols = {}
93
93
 
94
94
  # Remove deleted files from svg cache
95
95
  (svgs.keys - file_keys(files)).each { |f| svgs.delete(f) }
@@ -97,16 +97,18 @@ module Esvg
97
97
  dirs = {}
98
98
 
99
99
  files.each do |path|
100
-
101
100
  mtime = File.mtime(path).to_i
102
101
  key = file_key path
103
102
  dkey = dir_key path
104
103
 
105
104
  # Use cache if possible
106
105
  if svgs[key].nil? || svgs[key][:last_modified] != mtime
107
- svgs[key] = process_file(path, mtime, key)
106
+ svgs[key] = process_file(path, mtime)
108
107
  end
109
108
 
109
+ # Name may have changed due to flatten config
110
+ svgs[key][:name] = file_name(path)
111
+
110
112
  dirs[dkey] ||= {}
111
113
  (dirs[dkey][:files] ||= []) << key
112
114
 
@@ -117,31 +119,22 @@ module Esvg
117
119
 
118
120
  dirs = sort(dirs)
119
121
 
120
- # Remove deleted directories from svg_symbols cache
121
- (svg_symbols.keys - dirs.keys).each {|dir| svg_symbols.delete(dir) }
122
-
123
122
  dirs.each do |dir, data|
124
123
 
125
124
  # overwrite cache if
126
125
  if svg_symbols[dir].nil? || # No cache for this dir yet
127
126
  svg_symbols[dir][:last_modified] != data[:last_modified] || # New or updated file
128
- svg_symbols[dir][:optimized] != optimize? || # Cache is unoptimized
129
127
  svg_symbols[dir][:files] != data[:files] # Changed files
130
128
 
131
- symbols = data[:files].map { |f| svgs[f][:content] }.join
132
129
  attributes = data[:files].map { |f| svgs[f][:attr] }
130
+ mtimes = data[:files].map { |f| svgs[f][:last_modified] }.join
133
131
 
134
132
  svg_symbols[dir] = data.merge({
135
133
  name: dir,
136
- symbols: symbols,
137
- optimized: optimize?,
138
- version: config[:version] || Digest::MD5.hexdigest(symbols),
139
- asset: File.basename(dir).start_with?('_')
134
+ asset: File.basename(dir).start_with?('_'),
135
+ version: config[:version] || Digest::MD5.hexdigest(mtimes)
140
136
  })
141
137
 
142
- end
143
-
144
- svg_symbols.keys.each do |dir|
145
138
  svg_symbols[dir][:path] = write_path(dir)
146
139
  end
147
140
  end
@@ -152,15 +145,12 @@ module Esvg
152
145
 
153
146
  def read_cache
154
147
  @svgs = YAML.load(read_tmp '.svgs') || {}
155
- @svg_symbols = YAML.load(read_tmp '.svg_symbols') || {}
156
148
  end
157
149
 
158
150
  def write_cache
159
151
  return if production?
160
152
 
161
153
  write_tmp '.svgs', sort(@svgs).to_yaml
162
- write_tmp '.svg_symbols', sort(@svg_symbols).to_yaml
163
-
164
154
  end
165
155
 
166
156
  def sort(hash)
@@ -195,26 +185,22 @@ module Esvg
195
185
  end.map { |k| svg_symbols[k] }
196
186
  end
197
187
 
198
- def process_file(file, mtime, name)
199
- content = File.read(file)
200
- id = id(name)
188
+ def process_file(path, mtime)
189
+ content = File.read(path)
190
+ id = id(file_key(path))
201
191
  size_attr = dimensions(content)
202
192
 
203
- svg = {
204
- name: name,
193
+ {
194
+ path: path,
205
195
  use: %Q{<use xlink:href="##{id}"/>},
206
196
  last_modified: mtime,
207
- attr: { id: id }.merge(size_attr)
197
+ attr: { id: id }.merge(size_attr),
198
+ content: content
208
199
  }
209
- # Add attributes
210
- svg[:content] = prep_svg(content, svg[:attr])
211
-
212
- svg
213
200
  end
214
201
 
215
202
  def use(file, options={})
216
- if name = exist?(file, options[:fallback])
217
- svg = svgs[name]
203
+ if svg = find_svg(file, options[:fallback])
218
204
 
219
205
  if options[:color]
220
206
  options[:style] ||= ''
@@ -225,7 +211,7 @@ module Esvg
225
211
  fill: options[:fill],
226
212
  style: options[:style],
227
213
  viewBox: svg[:attr][:viewBox],
228
- class: [config[:class], svg[:attr][:id], options[:class]].compact.join(' ')
214
+ class: [config[:class], id(svg[:name]), options[:class]].compact.join(' ')
229
215
  }
230
216
 
231
217
  # If user doesn't pass a size or set scale: true
@@ -283,14 +269,17 @@ module Esvg
283
269
  end
284
270
 
285
271
  def exist?(name, fallback=nil)
272
+ !find_svg(name, fallback).nil?
273
+ end
274
+
275
+ def find_svg(name, fallback=nil)
286
276
  name = get_alias dasherize(name)
287
277
 
288
- if svgs[name].nil?
289
- exist?(fallback) if fallback
290
- else
291
- name
278
+ if svg = svgs.values.find { |v| v[:name] == name }
279
+ svg
280
+ elsif fallback
281
+ find_svg(fallback)
292
282
  end
293
-
294
283
  end
295
284
 
296
285
  alias_method :exists?, :exist?
@@ -344,7 +333,9 @@ module Esvg
344
333
  paths = []
345
334
 
346
335
  files.each do |file|
347
- write_file(file[:path], js(file[:name]))
336
+ content = js(file[:name])
337
+
338
+ write_file(file[:path], content)
348
339
  puts "Writing #{file[:path]}" if config[:print]
349
340
  paths << file[:path]
350
341
 
@@ -354,17 +345,29 @@ module Esvg
354
345
  end
355
346
  end
356
347
 
348
+ write_cache
349
+
357
350
  paths
358
351
  end
359
352
 
360
353
  def symbols(keys)
361
354
  symbols = valid_keys(keys).map { |key|
362
- svg_symbols[key][:symbols]
355
+ # Build on demand
356
+ build_symbols(svg_symbols[key][:files])
363
357
  }.join.gsub(/\n/,'')
364
358
 
365
359
  %Q{<svg id="esvg-#{key_id(keys)}" version="1.1" style="height:0;position:absolute">#{symbols}</svg>}
366
360
  end
367
361
 
362
+ def build_symbols(files)
363
+ files.map { |file|
364
+ if svgs[file][:optimized_at].nil? || svgs[file][:optimized_at] < svgs[file][:last_modified]
365
+ svgs[file][:optimized_content] = optimize(svgs[file])
366
+ end
367
+ svgs[file][:optimized_content]
368
+ }.join.gsub(/\n/,'')
369
+ end
370
+
368
371
  def js(key)
369
372
  keys = valid_keys(key)
370
373
  return if keys.empty?
@@ -471,10 +474,16 @@ module Esvg
471
474
 
472
475
  private
473
476
 
477
+ def file_key(path)
478
+ dasherize sub_path(path).sub('.svg','')
479
+ end
480
+
474
481
  def dir_key(path)
475
482
  dir = File.dirname(flatten_path(path))
476
483
 
477
484
  # Flattened paths which should be treated as assets will use '_' as their dir key
485
+ # - flatten: _foo - _foo/icon.svg will have a dirkey of _
486
+ # - filename: _icons - treats all root or flattened files as assets
478
487
  if dir == '.' && ( sub_path(path).start_with?('_') || config[:filename].start_with?('_') )
479
488
  '_'
480
489
  else
@@ -482,6 +491,10 @@ module Esvg
482
491
  end
483
492
  end
484
493
 
494
+ def file_name(path)
495
+ dasherize flatten_path(path).sub('.svg','')
496
+ end
497
+
485
498
  def sub_path(path)
486
499
  path.sub("#{config[:source]}/",'')
487
500
  end
@@ -490,10 +503,6 @@ module Esvg
490
503
  sub_path(path).sub(Regexp.new(config[:flatten]), '')
491
504
  end
492
505
 
493
- def file_key(path)
494
- dasherize flatten_path(path).sub('.svg', '')
495
- end
496
-
497
506
  def file_keys(paths)
498
507
  paths.flatten.map { |p| file_key(p) }
499
508
  end
@@ -518,31 +527,60 @@ module Esvg
518
527
  end
519
528
  end
520
529
 
521
- def prep_svg(content, attr)
522
- content = content.gsub(/<?.+\?>/,'').gsub(/<!.+?>/,'') # Get rid of doctypes and comments
530
+ def svgo?
531
+ !!(config[:optimize] && svgo_cmd)
532
+ end
533
+
534
+ def optimize(svg)
535
+ svg[:optimized_content] = pre_optimize svg[:content]
536
+ svg[:optimized_content] = sub_def_ids svg
537
+
538
+ if svgo?
539
+ response = Open3.capture3(%Q{#{} --disable=removeUselessDefs -s '#{svg[:content]}' -o -})
540
+ svg[:optimized_content] = response[0] if response[2].success?
541
+ end
542
+
543
+ svg[:optimized_at] = Time.now.to_i
544
+ svg[:optimized_content] = post_optimize svg
545
+ end
546
+
547
+ def pre_optimize(svg)
548
+ reg = %w(xmlns xmlns:xlink xml:space version).map { |m| "#{m}=\".+?\"" }.join('|')
549
+ svg.gsub(Regexp.new(reg), '') # Remove unwanted attributes
550
+ .gsub(/<?.+\?>/,'').gsub(/<!.+?>/,'') # Get rid of doctypes and comments
523
551
  .gsub(/\n/, '') # Remove endlines
524
552
  .gsub(/\s{2,}/, ' ') # Remove whitespace
525
553
  .gsub(/>\s+</, '><') # Remove whitespace between tags
526
554
  .gsub(/\s?fill="(#0{3,6}|black|rgba?\(0,0,0\))"/,'') # Strip black fill
527
555
  .gsub(/style="([^"]*?)fill:(.+?);/m, 'fill="\2" style="\1') # Make fill a property instead of a style
528
556
  .gsub(/style="([^"]*?)fill-opacity:(.+?);/m, 'fill-opacity="\2" style="\1') # Move fill-opacity a property instead of a style
557
+ end
529
558
 
530
- content = sub_def_ids content, attr[:id]
531
- content = strip_attributes content
532
- content = optimize(content) if optimize?
533
- content = set_attributes content, attr
534
- content.gsub(/<\/svg/,'</symbol') # Replace svgs with symbols
559
+ def post_optimize(svg)
560
+ svg[:optimized_content] = set_attributes(svg)
561
+ .gsub(/<\/svg/,'</symbol') # Replace svgs with symbols
535
562
  .gsub(/class="def-/,'id="def-') # Replace <def> classes with ids (classes are generated in sub_def_ids)
536
- .gsub(/\s{2,}/,'') # Remove extra spaces
537
563
  .gsub(/\w+=""/,'') # Remove empty attributes
538
564
  end
539
565
 
566
+ def set_attributes(svg)
567
+ svg[:attr].keys.each { |key| svg[:optimized_content].sub!(/ #{key}=".+?"/,'') }
568
+ svg[:optimized_content].sub(/<svg/, "<symbol #{attributes(svg[:attr])}")
569
+ end
570
+
571
+ def svgo_cmd
572
+ find_node_module('svgo')
573
+ end
574
+
540
575
  # Scans <def> blocks for IDs
541
576
  # If urls(#id) are used, ensure these IDs are unique to this file
542
577
  # Only replace IDs if urls exist to avoid replacing defs
543
578
  # used in other svg files
544
579
  #
545
- def sub_def_ids(content, name)
580
+ def sub_def_ids(svg)
581
+ content = svg[:optimized_content]
582
+ name = svg[:attr][:id]
583
+
546
584
  return content unless !!content.match(/<defs>/)
547
585
 
548
586
  content.scan(/<defs>.+<\/defs>/m).flatten.each do |defs|
@@ -562,35 +600,6 @@ module Esvg
562
600
  content
563
601
  end
564
602
 
565
- def strip_attributes(svg)
566
- reg = %w(xmlns xmlns:xlink xml:space version).map { |m| "#{m}=\".+?\"" }.join('|')
567
-
568
- svg.gsub(Regexp.new(reg), '')
569
- end
570
-
571
- def set_attributes(svg, attr)
572
- attr.keys.each { |key| svg.sub!(/ #{key}=".+?"/,'') }
573
- svg.sub(/<svg/, "<symbol #{attributes(attr)}")
574
- end
575
-
576
- def optimize?
577
- !!(config[:optimize] && svgo_cmd)
578
- end
579
-
580
- def svgo_cmd
581
- find_node_module('svgo')
582
- end
583
-
584
-
585
- def optimize(svg)
586
- path = write_tmp '.svgo-tmp', svg
587
- command = "#{svgo_cmd} --disable=removeUselessDefs '#{path}' -o -"
588
- svg = `#{command}`
589
- FileUtils.rm(path) if File.exist? path
590
-
591
- svg
592
- end
593
-
594
603
  def compress(file)
595
604
  return if !config[:compress]
596
605
 
data/lib/esvg/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Esvg
2
- VERSION = "4.1.0"
2
+ VERSION = "4.1.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: esvg
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 4.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandon Mathis
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-05-18 00:00:00.000000000 Z
11
+ date: 2017-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler