noft 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,30 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ module Noft
16
+ module Base
17
+ class AssetsTemplate < Reality::Generators::SingleDirectoryOutputTemplate
18
+ def initialize(template_set, facets, target, template_key, output_directory_pattern, helpers, options = {})
19
+ super(template_set, facets, target, template_key, output_directory_pattern, helpers, options)
20
+ end
21
+
22
+ protected
23
+
24
+ def generate_to_directory!(output_directory, element)
25
+ FileUtils.rm_rf output_directory
26
+ Noft::Generator.generate_assets(element.name, output_directory)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,87 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ module Noft
16
+ class FontBlast < Schmooze::Base
17
+ dependencies fontBlast: 'font-blast'
18
+
19
+ method :blast, 'function(fontFile, destinationFolder, userConfig) {fontBlast(fontFile, destinationFolder, userConfig);}'
20
+ end
21
+
22
+ module Generator
23
+ EXTENSION = '.noft.json'
24
+
25
+ class << self
26
+ def generate_assets(icon_set_name, output_directory)
27
+ icon_set = Noft.icon_set_by_name(icon_set_name)
28
+ FileUtils.rm_rf output_directory
29
+
30
+ metadata_file = "#{output_directory}/#{icon_set_name}#{EXTENSION}"
31
+
32
+ FileUtils.mkdir_p File.dirname(metadata_file)
33
+
34
+ icon_set.write_to(metadata_file)
35
+
36
+ # Generate filename mapping
37
+ filenames = {}
38
+ icon_set.icons.each { |icon| filenames[icon.unicode] = icon.name }
39
+
40
+ # Actually run the font blast to extract out the svg files
41
+ Noft::FontBlast.new('.').blast(icon_set.font_file, output_directory, { :filenames => filenames })
42
+
43
+ # Node writes the file asynchronously. This needs to be in place to ensure
44
+ # all the files are written as it is the last file to be generated
45
+ wait_until { File.exist?("#{output_directory}/verify.html") }
46
+
47
+ FileUtils.rm "#{output_directory}/verify.html"
48
+ FileUtils.mv "#{output_directory}/source-font.ttf", "#{output_directory}/font.ttf"
49
+ FileUtils.mv Dir["#{output_directory}/svg/*.svg"], output_directory
50
+ FileUtils.rmdir "#{output_directory}/svg"
51
+
52
+ reset_state_if_unchanged(output_directory)
53
+
54
+ output_directory
55
+ end
56
+
57
+ private
58
+
59
+ # if the assets are stored in git and the only file that is modified is font.ttf
60
+ # then we can assume that there is no actual change, just a result of the underlying svg2ttf
61
+ # tool not giving a stable output given stable input. Unclear where the fault lies. In this
62
+ # scenario just reset the file.
63
+ # Note: svg2ttf uses current date for some fields even if you pass in a date. Also font-blast
64
+ # does not pass in a date.
65
+ def reset_state_if_unchanged(output_directory)
66
+ output = `git status -s #{output_directory}`
67
+ if output.split("\n").size == 1 && !(output =~ /^ M (.*\/)?font.ttf$/).nil?
68
+ `git checkout #{output_directory}/font.ttf`
69
+ end
70
+ end
71
+
72
+ def wait_until(count = 100000, &block)
73
+ i = count
74
+ while i > 0
75
+ if block.call
76
+ break
77
+ else
78
+ i -= 1
79
+ Thread.pass
80
+ sleep 1
81
+ end
82
+ end
83
+ Noft.error('Node failed to generate the required files within an expected time frame') unless block.call
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,132 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ module Noft
16
+ Reality::Mda.define_system(Noft) do |r|
17
+ r.model_element(:icon_set)
18
+ r.model_element(:icon, :icon_set)
19
+ end
20
+
21
+ class << self
22
+ def read_model(filename, filter = nil)
23
+ data = JSON.parse(IO.read(filename))
24
+ name = data['name']
25
+ Noft.error("Noft icon model configuration file '#{filename}' is missing a name") unless name
26
+ icon_set = Noft.icon_set(name.to_sym)
27
+ icon_set.read_from(data, filter)
28
+ icon_set
29
+ end
30
+ end
31
+
32
+ module Model #nodoc
33
+ class IconSet
34
+ # A human readable name for icon set
35
+ attr_accessor :display_string
36
+ attr_accessor :description
37
+ # The version of the source library from which this was extracted
38
+ attr_accessor :version
39
+ # The url to the source library
40
+ attr_accessor :url
41
+ # The license of the library
42
+ attr_accessor :license
43
+ # The url of the license
44
+ attr_accessor :license_url
45
+ # The local filename of the font file
46
+ attr_accessor :font_file
47
+
48
+ def font_file?
49
+ !(@font_file ||= nil).nil?
50
+ end
51
+
52
+ def write_to(filename)
53
+ File.write(filename, JSON.pretty_generate(to_h) + "\n")
54
+ end
55
+
56
+ def read_from(data, filter = nil)
57
+ self.display_string = data['displayString'] if data['displayString']
58
+ self.description = data['description'] if data['description']
59
+ self.version = data['version'] if data['version']
60
+ self.url = data['url'] if data['url']
61
+ self.license = data['license'] if data['license']
62
+ self.license_url = data['licenseUrl'] if data['licenseUrl']
63
+
64
+ data['icons'].each_pair do |icon_name, icon_data|
65
+ if filter.nil? || (filter.is_a?(Proc) && filter.call(icon_name)) || (filter.is_a?(Array) && filter.include?(icon_name))
66
+ self.icon(icon_name.to_sym).read_from(icon_data)
67
+ end
68
+ end if data['icons']
69
+ end
70
+
71
+ def to_h
72
+ data = {}
73
+ data[:name] = self.name
74
+ data[:displayString] = self.display_string if self.display_string
75
+ data[:description] = self.description if self.description
76
+ data[:version] = self.version if self.version
77
+ data[:url] = self.url if self.url
78
+ data[:license] = self.license if self.license
79
+ data[:licenseUrl] = self.license_url if self.license_url
80
+
81
+ data[:icons] = {}
82
+ self.icons.each do |icon|
83
+ data[:icons][icon.name] = icon.to_h
84
+ end
85
+
86
+ data
87
+ end
88
+ end
89
+
90
+ class Icon
91
+ # A human readable name for icon
92
+ attr_accessor :display_string
93
+ attr_accessor :description
94
+
95
+ # The unicode that it was assigned inside the font.
96
+ attr_accessor :unicode
97
+
98
+ # Categories which this Icon exists. Useful when displaying an icon sheet.
99
+ def categories
100
+ @categories ||= []
101
+ end
102
+
103
+ # Alternative aliases under which this icon may be known.
104
+ def aliases
105
+ @aliases ||= []
106
+ end
107
+
108
+ def read_from(data)
109
+ self.display_string = data['displayString'] if data['displayString']
110
+ self.description = data['description'] if data['description']
111
+ self.unicode = data['unicode'] if data['unicode']
112
+ data['aliases'].each do |a|
113
+ self.aliases << a
114
+ end if data['aliases']
115
+ data['categories'].each do |c|
116
+ self.categories << c
117
+ end if data['categories']
118
+ end
119
+
120
+ def to_h
121
+ data = {}
122
+ data[:displayString] = self.display_string if self.display_string
123
+ data[:description] = self.description if self.description
124
+ data[:aliases] = self.aliases unless self.aliases.empty?
125
+ data[:categories] = self.categories unless self.categories.empty?
126
+ data[:unicode] = self.unicode if self.unicode
127
+
128
+ data
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,20 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ require 'uri'
16
+ require 'net/http'
17
+
18
+ require 'noft'
19
+
20
+ require 'noft_plus/util'
@@ -0,0 +1,29 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ module NoftPlus
16
+ module Util
17
+ class << self
18
+
19
+ # Download file to target unless it is already present
20
+ # Typically used to download font libraries from a remote location
21
+ def download_file(url, target_filename)
22
+ unless File.exist?(target_filename)
23
+ FileUtils.mkdir_p File.dirname(target_filename)
24
+ File.write(target_filename, Net::HTTP.get(URI(url)))
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{noft}
5
+ s.version = '1.0.0'
6
+ s.platform = Gem::Platform::RUBY
7
+
8
+ s.authors = ['Peter Donald']
9
+ s.email = %q{peter@realityforge.org}
10
+
11
+ s.homepage = %q{https://github.com/realityforge/noft}
12
+ s.summary = %q{A tool to extract svg icons from icon fonts and generate helpers to render the icons.}
13
+ s.description = %q{A tool to extract svg icons from icon fonts and generate helpers to render the icons.}
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
18
+ s.default_executable = []
19
+ s.require_paths = %w(lib)
20
+
21
+ s.has_rdoc = false
22
+ s.rdoc_options = %w(--line-numbers --inline-source --title noft)
23
+
24
+ s.add_dependency 'reality-mda', '>= 1.8.0'
25
+ s.add_dependency 'reality-core', '>= 1.8.0'
26
+ s.add_dependency 'reality-facets', '>= 1.9.0'
27
+ s.add_dependency 'reality-generators', '>= 1.13.0'
28
+ s.add_dependency 'reality-naming', '>= 1.9.0'
29
+ s.add_dependency 'reality-model', '>= 1.3.0'
30
+ s.add_dependency 'reality-orderedhash', '>= 1.0.0'
31
+ s.add_dependency 'schmooze', '= 0.1.6'
32
+
33
+ s.add_development_dependency(%q<minitest>, ['= 5.9.1'])
34
+ s.add_development_dependency(%q<test-unit>, ['= 3.1.5'])
35
+ end
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M473.093 32.314c2.517 1.882 3.768 4.497 3.774 7.842v100.39c0 3.345-1.256 5.96-3.768 7.844-1.674 1.462-3.772 2.195-6.276 2.195-.835 0-1.565-.105-2.192-.318l-140.548-30.114c-2.3-.417-4.183-1.567-5.652-3.45-1.463-1.883-2.193-3.975-2.193-6.277h-80.31v32.003c23.213 4.81 42.402 16.42 57.568 34.82 15.162 18.408 22.742 39.636 22.742 63.686v250.98c0 5.438-1.99 10.15-5.957 14.117-3.977 3.972-8.687 5.967-14.116 5.967h-160.63c-5.434 0-10.143-1.996-14.118-5.967-3.97-3.968-5.96-8.68-5.96-14.117v-250.98c0-22.168 6.535-42.09 19.606-59.765 13.076-17.673 29.963-29.645 50.667-35.917v-34.826h-10.035c-12.343 0-24.368 2.46-36.08 7.374-11.715 4.913-21.281 10.459-28.708 16.622-7.423 6.178-14.329 13.123-20.707 20.862-6.375 7.74-10.611 13.336-12.702 16.786s-3.554 6.015-4.395 7.686c-3.552 7.316-9.518 10.981-17.881 10.981-3.347 0-6.38-.732-9.099-2.194-4.813-2.51-8.105-6.38-9.88-11.61-1.78-5.23-1.414-10.352 1.096-15.372 1.044-2.09 2.565-4.81 4.549-8.156 1.987-3.347 5.91-8.94 11.763-16.784A201.868 201.868 0 0 1 72.63 114.66c6.8-6.794 15.69-13.803 26.668-21.016 10.981-7.216 22.327-12.706 34.04-16.468-5.232-8.784-7.844-17.78-7.844-26.983 0-13.805 4.91-25.621 14.744-35.45C150.065 4.913 161.885 0 175.69 0s25.62 4.913 35.452 14.744c9.83 9.829 14.745 21.645 14.745 35.45 0 6.9-1.466 13.594-4.395 20.08h94.746c0-2.305.726-4.395 2.189-6.273 1.465-1.884 3.35-3.036 5.655-3.45l140.548-30.117c.619-.21 1.352-.316 2.187-.316 2.51 0 4.6.731 6.277 2.196zM189.81 64.315c3.97-3.973 5.96-8.68 5.96-14.114 0-5.439-1.99-10.148-5.96-14.121-3.976-3.972-8.68-5.962-14.117-5.962s-10.147 1.99-14.121 5.962c-3.974 3.973-5.96 8.682-5.96 14.12 0 5.436 1.986 10.142 5.96 14.115 3.971 3.975 8.68 5.962 14.12 5.962s10.143-1.987 14.118-5.962z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M156.566 351.57c-8.57-12.28-15.477-26.62-20.717-43.002-5.238-16.38-7.851-33.904-7.851-52.572 0-14.855 2.336-28.57 7-41.143 4.669-12.57 10.761-23.285 18.285-32.143 7.525-8.855 15.857-17.238 25-25.14 9.141-7.905 18.286-15.288 27.431-22.143 9.143-6.86 17.475-13.717 25-20.573 7.524-6.86 13.617-14.62 18.286-23.286 4.667-8.665 7-17.856 7-27.571C256 46.095 249.716 24.76 237.147 0l.857.288-.285-.288c17.141 7.81 32.378 15.715 45.714 23.715 13.335 7.998 26.52 17.521 39.569 28.57 13.055 11.043 23.863 22.712 32.431 34.996 8.569 12.283 15.474 26.62 20.713 42.999 5.234 16.383 7.857 33.905 7.857 52.573 0 14.855-2.336 28.57-7 41.143-4.672 12.571-10.763 23.285-18.288 32.143-7.524 8.858-15.859 17.242-25 25.146-9.15 7.9-18.291 15.281-27.431 22.142-9.14 6.858-17.473 13.714-25 20.57-7.525 6.85-13.617 14.618-18.282 23.289-4.67 8.661-7.005 17.852-7.005 27.57 0 18.286 6.379 39.616 19.142 64l-1.144-.288.287.287c-17.142-7.814-32.38-15.716-45.716-23.72-13.338-8-26.523-17.523-39.572-28.567-13.046-11.046-23.857-22.718-32.428-34.998zM454.43 478.143c1.813 1.81 2.716 3.952 2.716 6.428v18.286c0 2.48-.908 4.62-2.716 6.431-1.812 1.813-3.952 2.713-6.425 2.713H63.997c-2.475 0-4.617-.9-6.428-2.713-1.81-1.811-2.713-3.951-2.713-6.431V484.57c0-2.476.904-4.619 2.713-6.428 1.81-1.804 3.953-2.705 6.428-2.705h384.008c2.473 0 4.613.9 6.425 2.705z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M158.874 512C50.247 450.78 21.649 392.832 38 313.689c12.07-58.44 56.647-105.986 60.437-164.314 16.884 30.726 18.888 52.882 20.775 84.99C172.912 168.572 228.602 80.521 216.56 0c0 0 101.81 32 142.986 188.14 24.325-21.639 22.04-66.226 10-92.563 36.122 26.338 243.61 260.159-32.578 416.424 51.928-101.104 13.396-237.527-76.761-300.532 6.023 27.092-1.504 97.833-41.39 142.233 9.031-45.906-13.546-75.255-13.546-75.255S197.87 320 169.15 361.979c-26.226 38.332-44.398 79.018-10.275 150.021z"/></svg>
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "sample1",
3
+ "displayString": "Sample 1",
4
+ "description": "Sample fonts downloaded from FlatIcon",
5
+ "version": "1",
6
+ "url": "http://www.flaticon.com/",
7
+ "icons": {
8
+ "fire-extinguisher": {
9
+ "unicode": "f100"
10
+ },
11
+ "fire-symbol": {
12
+ "unicode": "f101"
13
+ },
14
+ "fire": {
15
+ "unicode": "f102"
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,55 @@
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
3
+ <!--
4
+ 2017-5-7: Created with FontForge (http://fontforge.org)
5
+ -->
6
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
7
+ <metadata>
8
+ Created by FontForge 20160405 at Sun May 7 06:58:20 2017
9
+ By Apache
10
+ Copyright (c) 2017, Apache
11
+ </metadata>
12
+ <defs>
13
+ <font id="Flaticon" horiz-adv-x="512" >
14
+ <font-face
15
+ font-family="Flaticon"
16
+ font-weight="400"
17
+ font-stretch="normal"
18
+ units-per-em="512"
19
+ panose-1="2 0 5 3 0 0 0 0 0 0"
20
+ ascent="448"
21
+ descent="-64"
22
+ bbox="33.7305 -64.001 478.27 448"
23
+ underline-thickness="25.6"
24
+ underline-position="-51.2"
25
+ unicode-range="U+0020-F102"
26
+ />
27
+ <missing-glyph />
28
+ <glyph glyph-name="space" unicode=" " horiz-adv-x="200"
29
+ />
30
+ <glyph glyph-name="uniF102" unicode="&#xf102;"
31
+ d="M158.874 -64c-108.627 61.2197 -137.225 119.168 -120.874 198.311c12.0703 58.4404 56.6465 105.986 60.4365 164.314c16.8848 -30.7256 18.8887 -52.8818 20.7754 -84.9902c53.7002 65.793 109.39 153.844 97.3477 234.365c0 0 101.811 -32 142.986 -188.139
32
+ c24.3252 21.6377 22.041 66.2256 10 92.5625c36.1221 -26.3379 243.61 -260.159 -32.5771 -416.424c51.9277 101.104 13.3955 237.527 -76.7617 300.532c6.02344 -27.0928 -1.50391 -97.833 -41.3906 -142.233c9.03223 45.9053 -13.5449 75.2549 -13.5449 75.2549
33
+ s-7.40234 -41.5537 -36.1221 -83.5322c-26.2266 -38.332 -44.3984 -79.0176 -10.2754 -150.021z" />
34
+ <glyph glyph-name="uniF100" unicode="&#xf100;"
35
+ d="M473.093 415.686c2.5166 -1.88184 3.76758 -4.49707 3.77441 -7.8418v-100.39c0 -3.34473 -1.25684 -5.95996 -3.76855 -7.84375c-1.67383 -1.46289 -3.77148 -2.19531 -6.27539 -2.19531c-0.835938 0 -1.56543 0.104492 -2.19238 0.317383l-140.548 30.1143
36
+ c-2.30078 0.416992 -4.18262 1.56738 -5.65234 3.4502c-1.46289 1.88281 -2.19238 3.97461 -2.19238 6.27734h-80.3096v-32.0029c23.2119 -4.80957 42.4014 -16.4199 57.5674 -34.8213c15.1621 -18.4072 22.7422 -39.6348 22.7422 -63.6855v-250.98
37
+ c0 -5.4375 -1.99023 -10.1494 -5.95703 -14.1162c-3.97754 -3.97266 -8.6875 -5.96777 -14.1162 -5.96777h-160.631c-5.43359 0 -10.1426 1.99609 -14.1172 5.96777c-3.96973 3.96777 -5.95996 8.67969 -5.95996 14.1162v250.98c0 22.168 6.53516 42.0898 19.6064 59.7656
38
+ c13.0752 17.6729 29.9629 29.6445 50.667 35.917v34.8262h-10.0352c-12.3428 0 -24.3682 -2.46094 -36.0811 -7.37402c-11.7139 -4.91309 -21.2803 -10.459 -28.707 -16.6221c-7.42285 -6.17871 -14.3291 -13.123 -20.707 -20.8623
39
+ c-6.375 -7.74023 -10.6113 -13.3359 -12.7021 -16.7861s-3.55371 -6.01465 -4.39453 -7.68555c-3.55273 -7.31641 -9.51855 -10.9814 -17.8818 -10.9814c-3.34668 0 -6.37988 0.732422 -9.09863 2.19434c-4.81348 2.50977 -8.10547 6.37891 -9.88086 11.6104
40
+ c-1.7793 5.22949 -1.41309 10.3516 1.09668 15.3711c1.04395 2.09082 2.56543 4.80957 4.54883 8.15625c1.9873 3.34668 5.91016 8.94043 11.7637 16.7842c5.85645 7.83984 12.1807 15.1631 18.9775 21.9609c6.80078 6.79395 15.6895 13.8027 26.668 21.0156
41
+ c10.9814 7.21582 22.3271 12.7061 34.04 16.4678c-5.23145 8.78418 -7.84375 17.7803 -7.84375 26.9834c0 13.8047 4.91016 25.6211 14.7441 35.4502c9.82812 9.83105 21.6475 14.7441 35.4521 14.7441s25.6191 -4.91309 35.4521 -14.7441
42
+ c9.8291 -9.8291 14.7441 -21.6455 14.7441 -35.4502c0 -6.90039 -1.46582 -13.5938 -4.39453 -20.0791h94.7461c0 2.30371 0.725586 4.39453 2.18848 6.27246c1.46582 1.88379 3.34961 3.03516 5.65527 3.4502l140.548 30.1162
43
+ c0.619141 0.210938 1.35254 0.316406 2.1875 0.316406c2.50879 0 4.59961 -0.731445 6.27637 -2.19629zM189.81 383.685c3.9707 3.97266 5.95996 8.67969 5.95996 14.1143c0 5.43848 -1.98926 10.1475 -5.95996 14.1211c-3.97559 3.97168 -8.67969 5.96191 -14.1172 5.96191
44
+ s-10.1465 -1.99023 -14.1211 -5.96191c-3.97363 -3.97363 -5.95996 -8.68262 -5.95996 -14.1211c0 -5.43555 1.98633 -10.1416 5.95996 -14.1143c3.97168 -3.97461 8.67969 -5.96191 14.1211 -5.96191s10.1426 1.9873 14.1172 5.96191z" />
45
+ <glyph glyph-name="uniF101" unicode="&#xf101;"
46
+ d="M156.566 96.4297c-8.57031 12.2812 -15.4766 26.6211 -20.7168 43.002c-5.23828 16.3809 -7.85156 33.9043 -7.85156 52.5723c0 14.8545 2.33594 28.5703 7 41.1426c4.66895 12.5713 10.7617 23.2852 18.2852 32.1436c7.52539 8.85449 15.8574 17.2373 25 25.1406
47
+ c9.1416 7.9043 18.2861 15.2871 27.4316 22.1426c9.14258 6.85938 17.4746 13.7168 25 20.5723c7.52344 6.85938 13.6162 14.6201 18.2852 23.2861c4.66699 8.66504 7 17.8564 7 27.5713c0 17.9023 -6.2832 39.2373 -18.8525 63.9971l0.856445 -0.288086l-0.28418 0.288086
48
+ c17.1406 -7.80957 32.3779 -15.7148 45.7139 -23.7148c13.335 -7.99805 26.5205 -17.5215 39.5684 -28.5703c13.0557 -11.043 23.8633 -22.7119 32.4316 -34.9961c8.56836 -12.2832 15.4736 -26.6191 20.7129 -42.999c5.2334 -16.3828 7.85645 -33.9053 7.85645 -52.5732
49
+ c0 -14.8545 -2.33594 -28.5703 -7 -41.1426c-4.67188 -12.5713 -10.7627 -23.2852 -18.2881 -32.1436c-7.52344 -8.85742 -15.8584 -17.2412 -24.999 -25.1455c-9.15137 -7.90039 -18.292 -15.2812 -27.4316 -22.1426c-9.14062 -6.85742 -17.4727 -13.7139 -25 -20.5693
50
+ c-7.52539 -6.85059 -13.6172 -14.6182 -18.2822 -23.2891c-4.66895 -8.66113 -7.00488 -17.8525 -7.00488 -27.5693c0 -18.2871 6.37891 -39.6172 19.1426 -64l-1.14453 0.287109l0.287109 -0.287109c-17.1416 7.81445 -32.3799 15.7158 -45.7158 23.7197
51
+ c-13.3379 8 -26.5234 17.5234 -39.5723 28.5674c-13.0459 11.0459 -23.8574 22.7178 -32.4277 34.998zM454.43 -30.1426c1.81348 -1.80957 2.71582 -3.95215 2.71582 -6.42871v-18.2852c0 -2.48047 -0.908203 -4.62012 -2.71582 -6.43164
52
+ c-1.8125 -1.8125 -3.95215 -2.71289 -6.4248 -2.71289h-384.008c-2.47559 0 -4.61719 0.900391 -6.42773 2.71289c-1.80957 1.81152 -2.71387 3.95117 -2.71387 6.43164v18.2852c0 2.47656 0.904297 4.61914 2.71387 6.42871
53
+ c1.80957 1.80371 3.95215 2.70508 6.42773 2.70508h384.008c2.47266 0 4.6123 -0.901367 6.4248 -2.70508z" />
54
+ </font>
55
+ </defs></svg>
@@ -0,0 +1,188 @@
1
+ $:.unshift File.expand_path('../../lib', __FILE__)
2
+
3
+ require 'securerandom'
4
+ require 'minitest/autorun'
5
+ require 'test/unit/assertions'
6
+ require 'noft'
7
+
8
+ module Noft
9
+ class << self
10
+ def reset
11
+ self.send(:icon_set_map).clear
12
+ end
13
+ end
14
+ end
15
+
16
+ class Noft::TestCase < Minitest::Test
17
+ include Test::Unit::Assertions
18
+
19
+ def setup
20
+ @cwd = Dir.pwd
21
+
22
+ FileUtils.mkdir_p self.working_dir
23
+ Dir.chdir(self.working_dir)
24
+ File.write("#{self.working_dir}/package.json", package_json)
25
+
26
+ self.setup_node_modules
27
+
28
+ Noft.reset
29
+ end
30
+
31
+ def teardown
32
+ self.unlink_node_modules
33
+ Dir.chdir(@cwd)
34
+ if passed?
35
+ FileUtils.rm_rf self.working_dir if File.exist?(self.working_dir)
36
+ else
37
+ $stderr.puts "Test #{self.class.name}.#{name} Failed. Leaving working directory #{self.working_dir}"
38
+ end
39
+ end
40
+
41
+ def setup_node_modules
42
+ node_modules_present = File.exist?(self.node_modules_dir)
43
+ FileUtils.mkdir_p self.node_modules_dir
44
+ FileUtils.ln_s(self.node_modules_dir, self.local_node_modules_dir)
45
+ system('npm install') unless node_modules_present
46
+ end
47
+
48
+ def unlink_node_modules
49
+ FileUtils.rm(self.local_node_modules_dir) if File.exist?(self.local_node_modules_dir)
50
+ end
51
+
52
+ def create_file(filename, content)
53
+ expanded_filename = "#{working_dir}/#{filename}"
54
+ FileUtils.mkdir_p File.dirname(expanded_filename)
55
+ File.write(expanded_filename, content)
56
+ expanded_filename
57
+ end
58
+
59
+ def create_filename(extension = '')
60
+ "#{working_dir}/#{::SecureRandom.hex}#{extension}"
61
+ end
62
+
63
+ def local_dir(directory)
64
+ "#{working_dir}/#{directory}"
65
+ end
66
+
67
+ def working_dir
68
+ @working_dir ||= "#{workspace_dir}/#{::SecureRandom.hex}"
69
+ end
70
+
71
+ def workspace_dir
72
+ @workspace_dir ||= ENV['TEST_TMP_DIR'] || File.expand_path("#{File.dirname(__FILE__)}/../tmp/workspace")
73
+ end
74
+
75
+ def node_modules_dir
76
+ @node_modules_dir ||= "#{workspace_dir}/node_modules"
77
+ end
78
+
79
+ def local_node_modules_dir
80
+ "#{self.working_dir}/node_modules"
81
+ end
82
+
83
+ # The base test directory
84
+ def test_dir
85
+ @test_dir ||= File.expand_path("#{File.dirname(__FILE__)}")
86
+ end
87
+
88
+ # The fixtures directory
89
+ def fixture_dir
90
+ "#{test_dir}/fixtures"
91
+ end
92
+
93
+ def fixture(fixture_name)
94
+ "#{fixture_dir}/#{fixture_name}"
95
+ end
96
+
97
+ def load_sample1_icon_set
98
+ # Load data from fixture json and make sure we link up all the non persisted attributes
99
+
100
+ icon_set = Noft.read_model(fixture('sample1/dist/sample1.noft.json'))
101
+ icon_set.font_file = fixture('sample1/webfont.svg')
102
+
103
+ icon_set.icon_by_name('fire-extinguisher').unicode = 'f100'
104
+ icon_set.icon_by_name('fire-symbol').unicode = 'f101'
105
+ icon_set.icon_by_name('fire').unicode = 'f102'
106
+
107
+ icon_set
108
+ end
109
+
110
+ def assert_sample1_dist_output(output_directory)
111
+ assert_dist_output(output_directory, 'sample1')
112
+ end
113
+
114
+ def assert_dist_output(output_directory, fixture_name)
115
+ assert_fixture_matches_output("#{fixture_name}/dist/fire.svg", "#{output_directory}/fire.svg")
116
+ assert_fixture_matches_output("#{fixture_name}/dist/fire-extinguisher.svg", "#{output_directory}/fire-extinguisher.svg")
117
+ assert_fixture_matches_output("#{fixture_name}/dist/fire-symbol.svg", "#{output_directory}/fire-symbol.svg")
118
+ assert_fixture_matches_output("#{fixture_name}/dist/sample1.noft.json", "#{output_directory}/sample1.noft.json")
119
+
120
+ assert_true File.exist?("#{output_directory}/font.ttf")
121
+ assert_false File.exist?("#{output_directory}/verify.html")
122
+ assert_false File.exist?("#{output_directory}/source-font.ttf")
123
+ assert_false File.exist?("#{output_directory}/svg")
124
+ end
125
+
126
+ def assert_fixture_matches_output(fixture_name, output_filename)
127
+ assert_equal true, File.exist?(output_filename), "Expected filename to be created #{output_filename}"
128
+ assert_equal IO.read(fixture(fixture_name)), IO.read(output_filename), "Content generated into #{output_filename}"
129
+ end
130
+
131
+ def run_generators(template_set_keys, icon_set, options = {})
132
+ target_dir = options[:target_dir] || local_dir(::SecureRandom.hex)
133
+ filter = options[:filter]
134
+ Noft::TemplateSetManager.generator.generate(:icon_set, icon_set, target_dir, template_set_keys, filter)
135
+ target_dir
136
+ end
137
+
138
+ def in_dir(dir)
139
+ Dir.chdir(dir)
140
+ yield
141
+ end
142
+
143
+ def run_command(command)
144
+ output = `#{command}`
145
+ raise "Error executing command: #{command}\nOutput: #{output}" unless $?.success?
146
+ output
147
+ end
148
+
149
+ def update_dir_from_fixture(dir, fixture_name)
150
+ FileUtils.mkdir_p(dir)
151
+ FileUtils.cp_r("#{fixture(fixture_name)}/.", dir)
152
+ end
153
+
154
+ def create_git_repo_from_fixture(fixture_name, options = {})
155
+ git_repo = options[:directory].nil? ? local_dir(fixture_name) : options[:directory]
156
+ create_git_repo(git_repo) do |dir|
157
+ update_dir_from_fixture(dir, fixture_name)
158
+ end
159
+ end
160
+
161
+ def create_git_repo(directory, &block)
162
+ FileUtils.mkdir_p directory
163
+ in_dir(directory) do
164
+ run_command('git init')
165
+ run_command("git config --local user.email \"user@example.org\"")
166
+ run_command("git config --local user.name \"A User\"")
167
+ block.call(directory)
168
+ run_command('git add *')
169
+ run_command("git commit -m \"initial commit\"")
170
+ end
171
+ end
172
+
173
+ def package_json
174
+ <<JSON
175
+ {
176
+ "name": "test-project",
177
+ "version": "1.0.0",
178
+ "description": "A project used to test",
179
+ "author": "",
180
+ "license": "Apache-2.0",
181
+ "repository": ".",
182
+ "devDependencies": {
183
+ "font-blast": "^0.6.1"
184
+ }
185
+ }
186
+ JSON
187
+ end
188
+ end