svg_optimizer 0.0.2
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.
Potentially problematic release.
This version of svg_optimizer might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +39 -0
- data/lib/svg_optimizer/plugins/base.rb +11 -0
- data/lib/svg_optimizer/plugins/cleanup_attribute.rb +17 -0
- data/lib/svg_optimizer/plugins/cleanup_id.rb +70 -0
- data/lib/svg_optimizer/plugins/remove_comment.rb +9 -0
- data/lib/svg_optimizer/plugins/remove_editor_namespace.rb +32 -0
- data/lib/svg_optimizer/plugins/remove_empty_attribute.rb +18 -0
- data/lib/svg_optimizer/plugins/remove_empty_container.rb +20 -0
- data/lib/svg_optimizer/plugins/remove_empty_text_node.rb +14 -0
- data/lib/svg_optimizer/plugins/remove_hidden_element.rb +29 -0
- data/lib/svg_optimizer/plugins/remove_metadata.rb +9 -0
- data/lib/svg_optimizer/plugins/remove_raster_image.rb +16 -0
- data/lib/svg_optimizer/plugins/remove_unused_namespace.rb +17 -0
- data/lib/svg_optimizer/version.rb +3 -0
- data/lib/svg_optimizer.rb +47 -0
- data/spec/fixtures/cleanup_id.svg +18 -0
- data/spec/fixtures/cleanup_id_expected.svg +18 -0
- data/spec/fixtures/green.svg +37 -0
- data/spec/fixtures/unused_namespace.svg +13 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/svg_optimizer/plugins/cleanup_attribute_spec.rb +6 -0
- data/spec/svg_optimizer/plugins/cleanup_id_spec.rb +12 -0
- data/spec/svg_optimizer/plugins/remove_comment_spec.rb +11 -0
- data/spec/svg_optimizer/plugins/remove_editor_namespace_spec.rb +8 -0
- data/spec/svg_optimizer/plugins/remove_empty_attribute_spec.rb +11 -0
- data/spec/svg_optimizer/plugins/remove_empty_container_spec.rb +8 -0
- data/spec/svg_optimizer/plugins/remove_empty_text_node_spec.rb +13 -0
- data/spec/svg_optimizer/plugins/remove_hidden_element_spec.rb +81 -0
- data/spec/svg_optimizer/plugins/remove_metadata_spec.rb +11 -0
- data/spec/svg_optimizer/plugins/remove_raster_image_spec.rb +14 -0
- data/spec/svg_optimizer/plugins/remove_unused_namespace_spec.rb +18 -0
- metadata +162 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 89a8f5445798684e296db58b8edae20833855329
|
4
|
+
data.tar.gz: 2051a95fee708a216349a60222789fbfc6f152e2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 86a2e4a9d51bebd7ea0d43aa03382a7ac977080bb0e71a9c8a192ab396d7237355d902089a7c46e09438f8f8eabe8d48d13c43724af30130ae22256a00b15e29
|
7
|
+
data.tar.gz: ea12fa839b35f17cb69cbc4d0e2acb7985344010866d4d2ded4d3feffc1e654ade5319081ad18d487f6e40bb2a55f381818d662d293817fcced05c33781f0e8c
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Nando Vieira
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# SvgOptimizer
|
2
|
+
|
3
|
+
Some small optimizations for SVG files.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'svg_optimizer'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install svg_optimizer
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
# Optimize an existing String.
|
23
|
+
xml = File.read("file.svg")
|
24
|
+
optimized = SvgOptimizer.optimize(xml)
|
25
|
+
|
26
|
+
# Optimize a file - it will override the original file.
|
27
|
+
SvgOptimizer.optimize_file("file.svg")
|
28
|
+
|
29
|
+
# Optimize a file - it saves a copy to "optimized/file.svg".
|
30
|
+
SvgOptimizer.optimize_file("file.svg", "optimized/file.svg")
|
31
|
+
```
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
1. Fork it
|
36
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
37
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
38
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
39
|
+
5. Create new Pull Request
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module SvgOptimizer
|
2
|
+
module Plugins
|
3
|
+
class CleanupAttribute < Base
|
4
|
+
def process
|
5
|
+
xml.xpath("//*[@*]").each do |node|
|
6
|
+
node.attributes.each do |_, attribute|
|
7
|
+
cleanup_attribute attribute
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def cleanup_attribute(attribute)
|
13
|
+
attribute.value = attribute.value.strip.squeeze(" ")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module SvgOptimizer
|
2
|
+
module Plugins
|
3
|
+
class CleanupId < Base
|
4
|
+
LETTERS = %w[
|
5
|
+
a b c d e f g h i j k l m n o p q r s t u v w x y z
|
6
|
+
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
7
|
+
]
|
8
|
+
|
9
|
+
IDS = LETTERS.concat(LETTERS.combination(2).to_a)
|
10
|
+
|
11
|
+
def ids
|
12
|
+
@ids ||= IDS.dup
|
13
|
+
end
|
14
|
+
|
15
|
+
def process
|
16
|
+
# If there a <script> or <style>, don't mess with ids.
|
17
|
+
return if xml.css("script, style").any?
|
18
|
+
|
19
|
+
# Replace the ids otherwise.
|
20
|
+
xml.css("[id]").each(&method(:cleanup_id))
|
21
|
+
end
|
22
|
+
|
23
|
+
def cleanup_id(node)
|
24
|
+
# Keep ids if there's no available id.
|
25
|
+
# This means that 1300+ ids have been used so far. CRAZY!
|
26
|
+
return if ids.empty?
|
27
|
+
|
28
|
+
old_id = node[:id]
|
29
|
+
new_id = ids.shift
|
30
|
+
node[:id] = new_id
|
31
|
+
|
32
|
+
remove_unused_id(
|
33
|
+
node,
|
34
|
+
replace_url_references(old_id, new_id),
|
35
|
+
replace_href_references(old_id, new_id)
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def remove_unused_id(node, has_url_refs, has_href_refs)
|
40
|
+
return if has_url_refs
|
41
|
+
return if has_href_refs
|
42
|
+
node.remove_attribute("id")
|
43
|
+
end
|
44
|
+
|
45
|
+
def replace_url_references(old_id, new_id)
|
46
|
+
nodes = xml.xpath(%{//*[@*="url(##{old_id})"]})
|
47
|
+
|
48
|
+
nodes.each do |node|
|
49
|
+
node.attributes.map(&:last).each do |attr|
|
50
|
+
attr.value = %[url(##{new_id})] if attr.value == %[url(##{old_id})]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
nodes.any?
|
55
|
+
end
|
56
|
+
|
57
|
+
def replace_href_references(old_id, new_id)
|
58
|
+
nodes = xml.css("[href='##{old_id}'], [xlink|href='##{old_id}']")
|
59
|
+
|
60
|
+
nodes.each do |node|
|
61
|
+
node.attributes.map(&:last).each do |attr|
|
62
|
+
attr.value = "##{new_id}" if attr.value == "##{old_id}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
nodes.any?
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module SvgOptimizer
|
2
|
+
module Plugins
|
3
|
+
class RemoveEditorNamespace < Base
|
4
|
+
NAMESPACES = %w[
|
5
|
+
http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd
|
6
|
+
http://www.inkscape.org/namespaces/inkscape
|
7
|
+
http://ns.adobe.com/AdobeIllustrator/10.0/
|
8
|
+
http://ns.adobe.com/Graphs/1.0/
|
9
|
+
http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/
|
10
|
+
http://ns.adobe.com/Variables/1.0/
|
11
|
+
http://ns.adobe.com/SaveForWeb/1.0/
|
12
|
+
http://ns.adobe.com/Extensibility/1.0/
|
13
|
+
http://ns.adobe.com/Flows/1.0/
|
14
|
+
http://ns.adobe.com/ImageReplacement/1.0/
|
15
|
+
http://ns.adobe.com/GenericCustomNamespace/1.0/
|
16
|
+
http://ns.adobe.com/XPath/1.0
|
17
|
+
]
|
18
|
+
|
19
|
+
def process
|
20
|
+
namespaces = xml.namespaces
|
21
|
+
xml.remove_namespaces!
|
22
|
+
|
23
|
+
namespaces.each do |name, value|
|
24
|
+
next if NAMESPACES.include?(value)
|
25
|
+
|
26
|
+
_, name = name.split(":")
|
27
|
+
xml.root.add_namespace name, value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module SvgOptimizer
|
2
|
+
module Plugins
|
3
|
+
class RemoveEmptyAttribute < Base
|
4
|
+
def process
|
5
|
+
xml.xpath("//*[@*='']").each do |node|
|
6
|
+
node.attributes.each do |name, value|
|
7
|
+
remove_if_empty node, name
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def remove_if_empty(node, attr)
|
14
|
+
node.remove_attribute(attr) if node[attr].empty?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module SvgOptimizer
|
2
|
+
module Plugins
|
3
|
+
class RemoveEmptyContainer < Base
|
4
|
+
ELEMENTS = %w[a defs g marker mask missing-glyph pattern switch symbol]
|
5
|
+
SELECTOR = ELEMENTS.map {|element| %[#{element}:empty] }.join(", ")
|
6
|
+
|
7
|
+
def process
|
8
|
+
while (nodes = xml.css(SELECTOR)).any?
|
9
|
+
nodes.each(&method(:remove_node))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
def remove_node(node)
|
15
|
+
node.children.empty? && node.remove
|
16
|
+
remove_node(node.parent) if node.parent
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module SvgOptimizer
|
2
|
+
module Plugins
|
3
|
+
class RemoveEmptyTextNode < Base
|
4
|
+
def process
|
5
|
+
xml.xpath("//text()").each(&method(:remove_if_empty))
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
def remove_if_empty(node)
|
10
|
+
node.remove if node.text.gsub(/\s/, "").empty?
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module SvgOptimizer
|
2
|
+
module Plugins
|
3
|
+
class RemoveHiddenElement < Base
|
4
|
+
SELECTOR = %w[
|
5
|
+
[display=none]
|
6
|
+
[opacity='0']
|
7
|
+
circle[r='0']
|
8
|
+
ellipse[rx='0']
|
9
|
+
ellipse[ry='0']
|
10
|
+
rect[width='0']
|
11
|
+
rect[height='0']
|
12
|
+
pattern[width='0']
|
13
|
+
pattern[height='0']
|
14
|
+
image[width='0']
|
15
|
+
image[height='0']
|
16
|
+
path[d='']
|
17
|
+
path:not([d])
|
18
|
+
polyline[points='']
|
19
|
+
polyline:not([points])
|
20
|
+
polygon[points='']
|
21
|
+
polygon:not([points])
|
22
|
+
].join(", ")
|
23
|
+
|
24
|
+
def process
|
25
|
+
xml.css(SELECTOR).remove
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module SvgOptimizer
|
2
|
+
module Plugins
|
3
|
+
class RemoveRasterImage < Base
|
4
|
+
SELECTOR = %w[
|
5
|
+
image[xlink|href$='.jpg']
|
6
|
+
image[xlink|href$='.jpeg']
|
7
|
+
image[xlink|href$='.gif']
|
8
|
+
image[xlink|href$='.png']
|
9
|
+
].join(", ")
|
10
|
+
|
11
|
+
def process
|
12
|
+
xml.css(SELECTOR).remove
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module SvgOptimizer
|
2
|
+
module Plugins
|
3
|
+
class RemoveUnusedNamespace < Base
|
4
|
+
def process
|
5
|
+
xml.root.namespace_definitions
|
6
|
+
.select(&:prefix)
|
7
|
+
.each(&method(:remove_unused_ns))
|
8
|
+
end
|
9
|
+
|
10
|
+
def remove_unused_ns(ns)
|
11
|
+
return if xml.xpath("//#{ns.prefix}:*").any?
|
12
|
+
source = xml.root.to_s.gsub(/ *xmlns:#{ns.prefix}=".*?"/, "")
|
13
|
+
xml.root = Nokogiri::XML(source).root
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
|
3
|
+
require "svg_optimizer/version"
|
4
|
+
require "svg_optimizer/plugins/base"
|
5
|
+
require "svg_optimizer/plugins/cleanup_attribute"
|
6
|
+
require "svg_optimizer/plugins/cleanup_id"
|
7
|
+
require "svg_optimizer/plugins/remove_comment"
|
8
|
+
require "svg_optimizer/plugins/remove_metadata"
|
9
|
+
require "svg_optimizer/plugins/remove_empty_text_node"
|
10
|
+
require "svg_optimizer/plugins/remove_empty_container"
|
11
|
+
require "svg_optimizer/plugins/remove_editor_namespace"
|
12
|
+
require "svg_optimizer/plugins/remove_hidden_element"
|
13
|
+
require "svg_optimizer/plugins/remove_raster_image"
|
14
|
+
require "svg_optimizer/plugins/remove_empty_attribute"
|
15
|
+
require "svg_optimizer/plugins/remove_unused_namespace"
|
16
|
+
|
17
|
+
module SvgOptimizer
|
18
|
+
PLUGINS = %w[
|
19
|
+
CleanupAttribute
|
20
|
+
CleanupId
|
21
|
+
RemoveComment
|
22
|
+
RemoveMetadata
|
23
|
+
RemoveEditorNamespace
|
24
|
+
RemoveHiddenElement
|
25
|
+
RemoveUnusedNamespace
|
26
|
+
RemoveRasterImage
|
27
|
+
RemoveEmptyAttribute
|
28
|
+
RemoveEmptyTextNode
|
29
|
+
RemoveEmptyContainer
|
30
|
+
]
|
31
|
+
|
32
|
+
def self.optimize(contents)
|
33
|
+
xml = Nokogiri::XML(contents)
|
34
|
+
PLUGINS.each do |plugin_name|
|
35
|
+
Plugins.const_get(plugin_name).new(xml).process
|
36
|
+
end
|
37
|
+
|
38
|
+
xml.root.to_xml
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.optimize_file(path, target = path)
|
42
|
+
contents = optimize(File.read(path))
|
43
|
+
|
44
|
+
File.open(target, "w") {|file| file << contents }
|
45
|
+
true
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
2
|
+
<defs>
|
3
|
+
<linearGradient id="gradient001">
|
4
|
+
<stop offset="5%" stop-color="#F60"/>
|
5
|
+
<stop offset="95%" stop-color="#FF6"/>
|
6
|
+
</linearGradient>
|
7
|
+
<text id="referencedText">
|
8
|
+
referenced text
|
9
|
+
</text>
|
10
|
+
</defs>
|
11
|
+
<g id="g001">
|
12
|
+
<circle id="circle001" fill="url(#gradient001)" cx="60" cy="60" r="50"/>
|
13
|
+
<tref xlink:href="#referencedText"/>
|
14
|
+
</g>
|
15
|
+
<g>
|
16
|
+
<tref xlink:href="#referencedText"/>
|
17
|
+
</g>
|
18
|
+
</svg>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
2
|
+
<defs>
|
3
|
+
<linearGradient id="a">
|
4
|
+
<stop offset="5%" stop-color="#F60"/>
|
5
|
+
<stop offset="95%" stop-color="#FF6"/>
|
6
|
+
</linearGradient>
|
7
|
+
<text id="b">
|
8
|
+
referenced text
|
9
|
+
</text>
|
10
|
+
</defs>
|
11
|
+
<g>
|
12
|
+
<circle fill="url(#a)" cx="60" cy="60" r="50"/>
|
13
|
+
<tref xlink:href="#b"/>
|
14
|
+
</g>
|
15
|
+
<g>
|
16
|
+
<tref xlink:href="#b"/>
|
17
|
+
</g>
|
18
|
+
</svg>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
3
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
4
|
+
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
5
|
+
width="10px" height="10px" viewBox="0 0 10 10" enable-background="new 0 0 10 10" xml:space="preserve">
|
6
|
+
<rect fill="#39B54A" width="10" height="10"/>
|
7
|
+
<g>
|
8
|
+
</g>
|
9
|
+
<g>
|
10
|
+
</g>
|
11
|
+
<g>
|
12
|
+
</g>
|
13
|
+
<g>
|
14
|
+
</g>
|
15
|
+
<g>
|
16
|
+
</g>
|
17
|
+
<g>
|
18
|
+
</g>
|
19
|
+
<g>
|
20
|
+
</g>
|
21
|
+
<g>
|
22
|
+
</g>
|
23
|
+
<g>
|
24
|
+
</g>
|
25
|
+
<g>
|
26
|
+
</g>
|
27
|
+
<g>
|
28
|
+
</g>
|
29
|
+
<g>
|
30
|
+
</g>
|
31
|
+
<g>
|
32
|
+
</g>
|
33
|
+
<g>
|
34
|
+
</g>
|
35
|
+
<g>
|
36
|
+
</g>
|
37
|
+
</svg>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<svg
|
2
|
+
xmlns="http://www.w3.org/2000/svg"
|
3
|
+
xmlns:test="http://example.com/"
|
4
|
+
xmlns:test2="http://example2.com/"
|
5
|
+
xmlns:test3="http://example3.com/"
|
6
|
+
xmlns:test4="http://example4.com/"
|
7
|
+
>
|
8
|
+
<test:elem>
|
9
|
+
<test2:elem>
|
10
|
+
test
|
11
|
+
</test2:elem>
|
12
|
+
</test:elem>
|
13
|
+
</svg>
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
require "svg_optimizer"
|
3
|
+
|
4
|
+
module RSpecHelpers
|
5
|
+
SVG = <<-XML
|
6
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
7
|
+
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
8
|
+
<?xml version="1.0" encoding="utf-8"?>
|
9
|
+
<svg xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
10
|
+
%s
|
11
|
+
</svg>
|
12
|
+
XML
|
13
|
+
|
14
|
+
def with_svg_plugin(content)
|
15
|
+
let(:file_path) { File.expand_path("../fixtures/#{content}", __FILE__) }
|
16
|
+
let(:input_xml) { Nokogiri::XML(File.file?(file_path) ? File.read(file_path) : SVG % content) }
|
17
|
+
let(:plugin) { described_class.new(input_xml) }
|
18
|
+
let(:xml) { plugin.xml }
|
19
|
+
before { plugin.process }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
RSpec.configure do |config|
|
25
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
26
|
+
config.run_all_when_everything_filtered = true
|
27
|
+
config.filter_run :focus
|
28
|
+
config.order = "random"
|
29
|
+
config.extend RSpecHelpers
|
30
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SvgOptimizer::Plugins::CleanupId do
|
4
|
+
with_svg_plugin "cleanup_id.svg"
|
5
|
+
|
6
|
+
it { expect(xml.css("linearGradient").first["id"]).to eql("a") }
|
7
|
+
it { expect(xml.css("circle").first["fill"]).to eql("url(#a)") }
|
8
|
+
it { expect(xml.css("circle[id]")).to be_empty }
|
9
|
+
it { expect(xml.css("g[id]")).to be_empty }
|
10
|
+
it { expect(xml.css("tref[xlink|href='#b']").size).to eql(2) }
|
11
|
+
it { expect(xml.css("text").first["id"]).to eql("b") }
|
12
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SvgOptimizer::Plugins::RemoveEditorNamespace do
|
4
|
+
with_svg_plugin ""
|
5
|
+
it { expect(xml.namespaces.values).not_to include("http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd") }
|
6
|
+
it { expect(xml.namespaces.values).to include("http://www.w3.org/2000/svg") }
|
7
|
+
it { expect(xml.namespaces.values).to include("http://www.w3.org/1999/xlink") }
|
8
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SvgOptimizer::Plugins::RemoveEmptyTextNode do
|
4
|
+
context "groups with empty text nodes only" do
|
5
|
+
with_svg_plugin %[<g> \n\t\r\n </g>]
|
6
|
+
it { expect(xml.css("g").children).to be_empty }
|
7
|
+
end
|
8
|
+
|
9
|
+
context "groups with non-empty nodes" do
|
10
|
+
with_svg_plugin %[<g> Hello \n\t\r\n </g>]
|
11
|
+
it { expect(xml.css("g").children).not_to be_empty }
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SvgOptimizer::Plugins::RemoveHiddenElement do
|
4
|
+
context "display: none" do
|
5
|
+
with_svg_plugin <<-SVG
|
6
|
+
<path display="none" d="..."/>
|
7
|
+
SVG
|
8
|
+
|
9
|
+
it { expect(xml.css("path")).to be_empty }
|
10
|
+
end
|
11
|
+
|
12
|
+
context "opacity: 0" do
|
13
|
+
with_svg_plugin <<-SVG
|
14
|
+
<path opacity="0" d="..."/>
|
15
|
+
SVG
|
16
|
+
|
17
|
+
it { expect(xml.css("path")).to be_empty }
|
18
|
+
end
|
19
|
+
|
20
|
+
context "circle" do
|
21
|
+
with_svg_plugin <<-SVG
|
22
|
+
<circle r="0"/>
|
23
|
+
SVG
|
24
|
+
|
25
|
+
it { expect(xml.css("circle")).to be_empty }
|
26
|
+
end
|
27
|
+
|
28
|
+
context "ellipse" do
|
29
|
+
with_svg_plugin <<-SVG
|
30
|
+
<ellipse rx="0"/>
|
31
|
+
<ellipse ry="0"/>
|
32
|
+
SVG
|
33
|
+
|
34
|
+
it { expect(xml.css("ellipse")).to be_empty }
|
35
|
+
end
|
36
|
+
|
37
|
+
context "rect" do
|
38
|
+
with_svg_plugin <<-SVG
|
39
|
+
<rect width="0"/>
|
40
|
+
<rect height="0"/>
|
41
|
+
SVG
|
42
|
+
|
43
|
+
it { expect(xml.css("rect")).to be_empty }
|
44
|
+
end
|
45
|
+
|
46
|
+
context "pattern" do
|
47
|
+
with_svg_plugin <<-SVG
|
48
|
+
<pattern width="0"/>
|
49
|
+
<pattern height="0"/>
|
50
|
+
SVG
|
51
|
+
|
52
|
+
it { expect(xml.css("pattern")).to be_empty }
|
53
|
+
end
|
54
|
+
|
55
|
+
context "image" do
|
56
|
+
with_svg_plugin <<-SVG
|
57
|
+
<image width="0"/>
|
58
|
+
<image height="0"/>
|
59
|
+
SVG
|
60
|
+
|
61
|
+
it { expect(xml.css("image")).to be_empty }
|
62
|
+
end
|
63
|
+
|
64
|
+
context "<path d=''/>" do
|
65
|
+
with_svg_plugin <<-SVG
|
66
|
+
<path d=''/>
|
67
|
+
SVG
|
68
|
+
|
69
|
+
it { expect(xml.css("path")).to be_empty }
|
70
|
+
end
|
71
|
+
|
72
|
+
context "other hidden elements" do
|
73
|
+
with_svg_plugin <<-SVG
|
74
|
+
<path/>
|
75
|
+
<polyline/>
|
76
|
+
<polygon/>
|
77
|
+
SVG
|
78
|
+
|
79
|
+
it { expect(xml.root.css("*")).to be_empty }
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SvgOptimizer::Plugins::RemoveRasterImage do
|
4
|
+
with_svg_plugin <<-SVG
|
5
|
+
<g>
|
6
|
+
<image xlink:href="raster.jpg" width="100" height="100"/>
|
7
|
+
<image xlink:href="raster.png" width="100" height="100"/>
|
8
|
+
<image xlink:href="raster.gif" width="100" height="100"/>
|
9
|
+
<image xlink:href="raster.svg" width="100" height="100"/>
|
10
|
+
</g>
|
11
|
+
SVG
|
12
|
+
|
13
|
+
it { expect(xml.css("image").size).to eql(1) }
|
14
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SvgOptimizer::Plugins::RemoveUnusedNamespace do
|
4
|
+
with_svg_plugin "unused_namespace.svg"
|
5
|
+
|
6
|
+
let(:namespaces) do
|
7
|
+
xml.root.namespace_definitions.each_with_object({}) do |ns, buffer|
|
8
|
+
next unless ns.prefix
|
9
|
+
buffer[ns.prefix] = ns.href
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it { expect(namespaces).to include("test" => "http://example.com/") }
|
14
|
+
it { expect(namespaces).to include("test2" => "http://example2.com/") }
|
15
|
+
|
16
|
+
it { expect(namespaces).not_to include("test3" => "http://example3.com/") }
|
17
|
+
it { expect(namespaces).not_to include("test4" => "http://example4.com/") }
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: svg_optimizer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nando Vieira
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: nokogiri
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry-meta
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: SVG optimization based on Node's SVGO
|
84
|
+
email:
|
85
|
+
- fnando.vieira@gmail.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- LICENSE.txt
|
91
|
+
- README.md
|
92
|
+
- lib/svg_optimizer/plugins/base.rb
|
93
|
+
- lib/svg_optimizer/plugins/cleanup_attribute.rb
|
94
|
+
- lib/svg_optimizer/plugins/cleanup_id.rb
|
95
|
+
- lib/svg_optimizer/plugins/remove_comment.rb
|
96
|
+
- lib/svg_optimizer/plugins/remove_editor_namespace.rb
|
97
|
+
- lib/svg_optimizer/plugins/remove_empty_attribute.rb
|
98
|
+
- lib/svg_optimizer/plugins/remove_empty_container.rb
|
99
|
+
- lib/svg_optimizer/plugins/remove_empty_text_node.rb
|
100
|
+
- lib/svg_optimizer/plugins/remove_hidden_element.rb
|
101
|
+
- lib/svg_optimizer/plugins/remove_metadata.rb
|
102
|
+
- lib/svg_optimizer/plugins/remove_raster_image.rb
|
103
|
+
- lib/svg_optimizer/plugins/remove_unused_namespace.rb
|
104
|
+
- lib/svg_optimizer/version.rb
|
105
|
+
- lib/svg_optimizer.rb
|
106
|
+
- spec/fixtures/cleanup_id.svg
|
107
|
+
- spec/fixtures/cleanup_id_expected.svg
|
108
|
+
- spec/fixtures/green.svg
|
109
|
+
- spec/fixtures/unused_namespace.svg
|
110
|
+
- spec/spec_helper.rb
|
111
|
+
- spec/svg_optimizer/plugins/cleanup_attribute_spec.rb
|
112
|
+
- spec/svg_optimizer/plugins/cleanup_id_spec.rb
|
113
|
+
- spec/svg_optimizer/plugins/remove_comment_spec.rb
|
114
|
+
- spec/svg_optimizer/plugins/remove_editor_namespace_spec.rb
|
115
|
+
- spec/svg_optimizer/plugins/remove_empty_attribute_spec.rb
|
116
|
+
- spec/svg_optimizer/plugins/remove_empty_container_spec.rb
|
117
|
+
- spec/svg_optimizer/plugins/remove_empty_text_node_spec.rb
|
118
|
+
- spec/svg_optimizer/plugins/remove_hidden_element_spec.rb
|
119
|
+
- spec/svg_optimizer/plugins/remove_metadata_spec.rb
|
120
|
+
- spec/svg_optimizer/plugins/remove_raster_image_spec.rb
|
121
|
+
- spec/svg_optimizer/plugins/remove_unused_namespace_spec.rb
|
122
|
+
homepage: https://github.com/fnando/svg_optimizer
|
123
|
+
licenses:
|
124
|
+
- MIT
|
125
|
+
metadata: {}
|
126
|
+
post_install_message:
|
127
|
+
rdoc_options: []
|
128
|
+
require_paths:
|
129
|
+
- lib
|
130
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - '>='
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
requirements: []
|
141
|
+
rubyforge_project:
|
142
|
+
rubygems_version: 2.0.3
|
143
|
+
signing_key:
|
144
|
+
specification_version: 4
|
145
|
+
summary: SVG optimization based on Node's SVGO
|
146
|
+
test_files:
|
147
|
+
- spec/fixtures/cleanup_id.svg
|
148
|
+
- spec/fixtures/cleanup_id_expected.svg
|
149
|
+
- spec/fixtures/green.svg
|
150
|
+
- spec/fixtures/unused_namespace.svg
|
151
|
+
- spec/spec_helper.rb
|
152
|
+
- spec/svg_optimizer/plugins/cleanup_attribute_spec.rb
|
153
|
+
- spec/svg_optimizer/plugins/cleanup_id_spec.rb
|
154
|
+
- spec/svg_optimizer/plugins/remove_comment_spec.rb
|
155
|
+
- spec/svg_optimizer/plugins/remove_editor_namespace_spec.rb
|
156
|
+
- spec/svg_optimizer/plugins/remove_empty_attribute_spec.rb
|
157
|
+
- spec/svg_optimizer/plugins/remove_empty_container_spec.rb
|
158
|
+
- spec/svg_optimizer/plugins/remove_empty_text_node_spec.rb
|
159
|
+
- spec/svg_optimizer/plugins/remove_hidden_element_spec.rb
|
160
|
+
- spec/svg_optimizer/plugins/remove_metadata_spec.rb
|
161
|
+
- spec/svg_optimizer/plugins/remove_raster_image_spec.rb
|
162
|
+
- spec/svg_optimizer/plugins/remove_unused_namespace_spec.rb
|