fontcustom 1.2.0 → 1.3.0.beta

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 (49) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +16 -0
  3. data/CONTRIBUTING.md +35 -15
  4. data/TODO.md +20 -0
  5. data/lib/fontcustom.rb +11 -24
  6. data/lib/fontcustom/base.rb +56 -0
  7. data/lib/fontcustom/cli.rb +13 -12
  8. data/lib/fontcustom/generator/font.rb +63 -65
  9. data/lib/fontcustom/generator/template.rb +81 -52
  10. data/lib/fontcustom/manifest.rb +42 -0
  11. data/lib/fontcustom/options.rb +93 -80
  12. data/lib/fontcustom/scripts/generate.py +116 -127
  13. data/lib/fontcustom/templates/_fontcustom-rails.scss +13 -18
  14. data/lib/fontcustom/templates/_fontcustom.scss +10 -18
  15. data/lib/fontcustom/templates/fontcustom-preview.html +17 -24
  16. data/lib/fontcustom/templates/fontcustom.css +10 -18
  17. data/lib/fontcustom/templates/fontcustom.yml +3 -3
  18. data/lib/fontcustom/utility.rb +145 -0
  19. data/lib/fontcustom/version.rb +1 -1
  20. data/lib/fontcustom/watcher.rb +1 -1
  21. data/spec/fixtures/generators/.fontcustom-manifest-corrupted.json +12 -5
  22. data/spec/fixtures/generators/.fontcustom-manifest-empty.json +0 -0
  23. data/spec/fixtures/generators/.fontcustom-manifest.json +49 -14
  24. data/spec/fixtures/generators/mixed-output/fontcustom_82a59e769bc60192484f2620570bbb59.eot +0 -0
  25. data/spec/fixtures/generators/mixed-output/fontcustom_82a59e769bc60192484f2620570bbb59.svg +56 -0
  26. data/spec/fixtures/generators/mixed-output/fontcustom_82a59e769bc60192484f2620570bbb59.ttf +0 -0
  27. data/spec/fixtures/generators/mixed-output/fontcustom_82a59e769bc60192484f2620570bbb59.woff +0 -0
  28. data/spec/fixtures/sandbox/.gitkeep +0 -0
  29. data/spec/fontcustom/base_spec.rb +58 -0
  30. data/spec/fontcustom/cli_spec.rb +15 -0
  31. data/spec/fontcustom/generator/font_spec.rb +50 -220
  32. data/spec/fontcustom/generator/template_spec.rb +30 -194
  33. data/spec/fontcustom/generator/template_spec.rb.off +215 -0
  34. data/spec/fontcustom/manifest_spec.rb +16 -0
  35. data/spec/fontcustom/options_spec.rb +206 -208
  36. data/spec/fontcustom/utility_spec.rb +163 -0
  37. data/spec/fontcustom/{watcher_spec.rb → watcher_spec.rb.off} +0 -0
  38. data/spec/spec_helper.rb +77 -19
  39. metadata +44 -54
  40. data/lib/fontcustom/templates/_fontcustom-bootstrap-ie7.scss +0 -22
  41. data/lib/fontcustom/templates/_fontcustom-bootstrap.scss +0 -63
  42. data/lib/fontcustom/templates/fontcustom-bootstrap-ie7.css +0 -22
  43. data/lib/fontcustom/templates/fontcustom-bootstrap.css +0 -63
  44. data/lib/fontcustom/util.rb +0 -62
  45. data/spec/fixtures/generators/mixed-output/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.eot +0 -0
  46. data/spec/fixtures/generators/mixed-output/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.svg +0 -102
  47. data/spec/fixtures/generators/mixed-output/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.ttf +0 -0
  48. data/spec/fixtures/generators/mixed-output/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.woff +0 -0
  49. data/spec/fontcustom/util_spec.rb +0 -82
@@ -1,95 +1,124 @@
1
1
  require "json"
2
2
  require "pathname"
3
- require "thor"
4
- require "thor/group"
5
- require "thor/actions"
6
3
 
7
4
  module Fontcustom
8
5
  module Generator
9
- class Template < Thor::Group
10
- include Util
11
- include Thor::Actions
6
+ class Template
7
+ include Utility
12
8
 
13
- # Instead of passing each option individually we're passing the entire options hash as an argument.
14
- # This is DRYier, easier to maintain.
15
- argument :opts
9
+ attr_reader :manifest, :options
16
10
 
17
- # Required for Thor::Actions#template
18
- def self.source_root
19
- File.join Fontcustom.gem_lib, "templates"
11
+ def initialize(manifest)
12
+ @manifest = get_manifest(manifest)
13
+ @options = @manifest[:options]
20
14
  end
21
15
 
22
- def get_manifest
23
- if File.exists? opts.manifest
24
- @data = JSON.parse File.read(opts.manifest), :symbolize_names => true
16
+ def generate
17
+ if ! @manifest[:fonts].empty?
18
+ delete_old_templates
19
+ set_relative_paths
20
+ create_files
25
21
  else
26
- raise Fontcustom::Error, "`#{relative_to_root(opts.manifest)}` is missing. This file is required to generate templates."
22
+ raise Fontcustom::Error, "No generated fonts were detected - aborting template generation."
27
23
  end
28
- rescue
29
- raise Fontcustom::Error, "Couldn't parse `#{relative_to_root(opts.manifest)}`. Delete it to start from scratch. Any previously generated files will need to be deleted manually."
30
24
  end
31
25
 
32
- def reset_output
33
- return if @data[:templates].empty?
34
- begin
35
- deleted = []
36
- @data[:templates].each do |file|
37
- remove_file file, :verbose => false
38
- deleted << file
39
- end
40
- ensure
41
- @data[:templates] = @data[:templates] - deleted
42
- json = JSON.pretty_generate @data
43
- overwrite_file opts.manifest, json
44
- say_changed :delete, deleted
45
- end
26
+ private
27
+
28
+ def delete_old_templates
29
+ delete_from_manifest(:templates)
46
30
  end
47
31
 
48
- def make_relative_paths
49
- name = File.basename @data[:fonts].first, File.extname(@data[:fonts].first)
50
- fonts = Pathname.new opts.output[:fonts]
51
- css = Pathname.new opts.output[:css]
52
- preview = Pathname.new opts.output[:preview]
32
+ def set_relative_paths
33
+ name = File.basename @manifest[:fonts].first, File.extname(@manifest[:fonts].first)
34
+ fonts = Pathname.new @options[:output][:fonts]
35
+ css = Pathname.new @options[:output][:css]
36
+ preview = Pathname.new @options[:output][:preview]
53
37
  @font_path = File.join fonts.relative_path_from(css).to_s, name
54
- @font_path_alt = opts.preprocessor_path.nil? ? @font_path : File.join(opts.preprocessor_path, name)
38
+ @font_path_alt = @options[:preprocessor_path].nil? ? @font_path : File.join(@options[:preprocessor_path], name)
55
39
  @font_path_preview = File.join fonts.relative_path_from(preview).to_s, name
56
40
  end
57
41
 
58
- def generate
59
- @glyphs = @data[:glyphs]
42
+ def create_files
43
+ @glyphs = @manifest[:glyphs]
60
44
  created = []
61
45
  packaged = %w|fontcustom-bootstrap-ie7.css fontcustom.css _fontcustom-bootstrap-ie7.scss _fontcustom-rails.scss
62
46
  fontcustom-bootstrap.css fontcustom-preview.html _fontcustom-bootstrap.scss _fontcustom.scss|
63
47
  css_exts = %w|.css .scss .sass .less .stylus|
64
48
  begin
65
- opts.templates.each do |source|
49
+ @options[:templates].each do |source|
66
50
  name = File.basename source
67
51
  ext = File.extname source
68
52
  target = name.dup
69
53
 
70
- if packaged.include?(name) && opts.font_name != DEFAULT_OPTIONS[:font_name]
71
- target.sub! DEFAULT_OPTIONS[:font_name], opts.font_name
54
+ if packaged.include?(name) && @options[:font_name] != DEFAULT_OPTIONS[:font_name]
55
+ target.sub! DEFAULT_OPTIONS[:font_name], @options[:font_name]
72
56
  end
73
57
 
74
- target = if opts.output.keys.include? name.to_sym
75
- File.join opts.output[name.to_sym], target
58
+ target = if @options[:output].keys.include? name.to_sym
59
+ File.join @options[:output][name.to_sym], target
76
60
  elsif css_exts.include? ext
77
- File.join opts.output[:css], target
61
+ File.join @options[:output][:css], target
78
62
  elsif name == "fontcustom-preview.html"
79
- File.join opts.output[:preview], target
63
+ File.join @options[:output][:preview], target
80
64
  else
81
- File.join opts.output[:fonts], target
65
+ File.join @options[:output][:fonts], target
82
66
  end
83
67
 
84
- template source, target, :verbose => false
68
+ template source, target, :verbose => false, :force => true
85
69
  created << target
86
70
  end
87
71
  ensure
88
72
  say_changed :create, created
89
- @data[:templates] = (@data[:templates] + created).uniq
90
- json = JSON.pretty_generate @data
91
- overwrite_file opts.manifest, json
73
+ @manifest[:templates] = (@manifest[:templates] + created).uniq
74
+ save_manifest
75
+ end
76
+ end
77
+
78
+ #
79
+ # Template Helpers
80
+ #
81
+
82
+ def font_name
83
+ @options[:font_name]
84
+ end
85
+
86
+ def font_face(style = :normal)
87
+ case style
88
+ when :rails
89
+ url = "font-url"
90
+ path = @font_path_alt
91
+ when :preview
92
+ url = "url"
93
+ path = @font_path_preview
94
+ else
95
+ url = "url"
96
+ path = @font_path
97
+ end
98
+ %Q|@font-face {
99
+ font-family: "#{font_name}";
100
+ src: #{url}("#{path}.eot");
101
+ src: #{url}("#{path}.eot?#iefix") format("embedded-opentype"),
102
+ #{url}("#{path}.woff") format("woff"),
103
+ #{url}("#{path}.ttf") format("truetype"),
104
+ #{url}("#{path}.svg##{font_name}") format("svg");
105
+ font-weight: normal;
106
+ font-style: normal;
107
+ }|
108
+ end
109
+
110
+ def glyph_selectors
111
+ output = @glyphs.map do |name, value|
112
+ @options[:css_selector].sub("{{glyph}}", name.to_s) + ":before"
113
+ end
114
+ output.join ",\n"
115
+ end
116
+
117
+ def glyphs
118
+ output = @glyphs.map do |name, value|
119
+ %Q|#{@options[:css_selector].sub('{{glyph}}', name.to_s)}:before { content: "\\#{value[:codepoint].to_s(16)}\" }|
92
120
  end
121
+ output.join "\n"
93
122
  end
94
123
  end
95
124
  end
@@ -0,0 +1,42 @@
1
+ module Fontcustom
2
+ class Manifest
3
+ include Utility
4
+
5
+ attr_accessor :manifest
6
+
7
+ def initialize(options)
8
+ @options = options
9
+ update_or_create_manifest
10
+ end
11
+
12
+ def update_or_create_manifest
13
+ if File.exists? @options[:manifest]
14
+ update_manifest
15
+ else
16
+ create_manifest
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def update_manifest
23
+ @manifest = get_manifest
24
+ if @manifest[:options] != @options
25
+ @manifest[:options] = @options
26
+ save_manifest
27
+ end
28
+ end
29
+
30
+ def create_manifest
31
+ @manifest = {
32
+ :checksum => { :current => "", :previous => "" },
33
+ :fonts => [],
34
+ :glyphs => {},
35
+ :options => @options,
36
+ :templates => []
37
+ }
38
+ json = JSON.pretty_generate @manifest
39
+ write_file @options[:manifest], json, :create
40
+ end
41
+ end
42
+ end
@@ -1,43 +1,43 @@
1
1
  require "yaml"
2
- require "thor/shell"
3
- require "thor/shell/basic"
4
- require "thor/shell/color"
5
- require "fontcustom/util"
6
2
 
7
3
  module Fontcustom
8
4
  class Options
9
- include Util
5
+ include Utility
10
6
 
11
- attr_reader :project_root, :input, :output, :config, :templates, :font_name, :css_prefix, :manifest, :preprocessor_path, :autowidth, :no_hash, :debug, :quiet, :skip_first
7
+ attr_accessor :options
12
8
 
13
- def initialize(options = {})
14
- check_fontforge
15
- options = symbolize_hash(options)
16
-
17
- # Overwrite example defaults (used in Thor's help) with real defaults, if unchanged
18
- EXAMPLE_OPTIONS.keys.each do |key|
19
- options.delete(key) if options[key] == EXAMPLE_OPTIONS[key]
20
- end
21
- @cli_options = DEFAULT_OPTIONS.dup.merge options
22
-
23
- @shell = Thor::Shell::Color.new
24
- set_options
9
+ def initialize(cli_options = {})
10
+ @cli_options = symbolize_hash(cli_options)
11
+ parse_options
25
12
  end
26
13
 
27
14
  private
28
15
 
29
- def set_options
16
+ def parse_options
17
+ overwrite_examples
30
18
  set_config_path
31
19
  load_config
32
20
  merge_options
33
- set_data_path
21
+ clean_font_name
22
+ set_manifest_path
34
23
  set_input_paths
35
24
  set_output_paths
36
25
  set_template_paths
37
26
  end
38
27
 
28
+ # We give Thor fake defaults to generate more useful help messages.
29
+ # Here, we delete any CLI options that match those examples.
30
+ # TODO There's *got* a be a cleaner way to customize Thor help messages.
31
+ def overwrite_examples
32
+ EXAMPLE_OPTIONS.keys.each do |key|
33
+ @cli_options.delete(key) if @cli_options[key] == EXAMPLE_OPTIONS[key]
34
+ end
35
+ @cli_options = DEFAULT_OPTIONS.dup.merge @cli_options
36
+ @cli_options[:project_root] ||= Dir.pwd
37
+ end
38
+
39
39
  def set_config_path
40
- @config = if @cli_options[:config]
40
+ @cli_options[:config] = if @cli_options[:config]
41
41
  path = expand_path @cli_options[:config]
42
42
 
43
43
  # :config is the path to fontcustom.yml
@@ -49,7 +49,7 @@ module Fontcustom
49
49
  File.join path, "fontcustom.yml"
50
50
 
51
51
  else
52
- raise Fontcustom::Error, "The configuration file wasn't found. Check `#{relative_to_root(path)}` and try again."
52
+ raise Fontcustom::Error, "No configuration file found at `#{relative_to_root(path)}`."
53
53
  end
54
54
  else
55
55
  # fontcustom.yml is in the project_root
@@ -68,108 +68,116 @@ module Fontcustom
68
68
 
69
69
  def load_config
70
70
  @config_options = {}
71
- if @config
72
- say_message :status, "Loading configuration file at `#{relative_to_root(@config)}`."
71
+ if @cli_options[:config]
72
+ say_message :debug, "Using settings from `#{relative_to_root(@cli_options[:config])}`." if @cli_options[:debug]
73
73
  begin
74
- config = YAML.load File.open(@config)
74
+ config = YAML.load File.open(@cli_options[:config])
75
75
  if config # empty YAML returns false
76
76
  @config_options = symbolize_hash(config)
77
77
  else
78
- say_message :status, "Configuration file was empty. Using defaults."
78
+ say_message :warn, "`#{relative_to_root(@cli_options[:config])}` was empty. Using defaults."
79
79
  end
80
80
  rescue Exception => e
81
- raise Fontcustom::Error, "The configuration file failed to load. Message: #{e.message}"
81
+ raise Fontcustom::Error, "Error parsing `#{relative_to_root(@cli_options[:config])}`:\n#{e.message}"
82
82
  end
83
- else
84
- say_message :status, "No configuration file set. Generate one with `fontcustom config` to save your settings."
85
83
  end
86
84
  end
87
85
 
88
86
  def merge_options
89
87
  @cli_options.delete_if { |key, val| val == DEFAULT_OPTIONS[key] }
88
+ @options = DEFAULT_OPTIONS.merge(@config_options).merge(@cli_options)
89
+ end
90
90
 
91
- options = DEFAULT_OPTIONS.dup
92
- options = options.merge @config_options
93
- options = options.merge symbolize_hash(@cli_options)
94
- send :remove_instance_variable, :@config_options
95
- send :remove_instance_variable, :@cli_options
96
-
97
- # :config is excluded since it's already been set
98
- keys = %w|project_root input output manifest templates font_name css_prefix preprocessor_path skip_first autowidth no_hash debug quiet|
99
- keys.each { |key| instance_variable_set("@#{key}", options[key.to_sym]) }
100
-
101
- @font_name = @font_name.strip.gsub(/\W/, "-")
91
+ def clean_font_name
92
+ @options[:font_name] = @options[:font_name].strip.gsub(/\W/, "-")
102
93
  end
103
94
 
104
- def set_data_path
105
- @manifest = if ! @manifest.nil?
106
- expand_path @manifest
107
- elsif @config
108
- File.join File.dirname(@config), ".fontcustom-manifest.json"
95
+ def set_manifest_path
96
+ @options[:manifest] = if ! @options[:manifest].nil?
97
+ expand_path @options[:manifest]
98
+ elsif @options[:config]
99
+ File.join File.dirname(@options[:config]), ".fontcustom-manifest.json"
109
100
  else
110
- File.join @project_root, ".fontcustom-manifest.json"
101
+ File.join @options[:project_root], ".fontcustom-manifest.json"
111
102
  end
112
103
  end
113
104
 
114
105
  def set_input_paths
115
- if @input.is_a? Hash
116
- @input = symbolize_hash(@input)
117
- if @input.has_key? :vectors
118
- @input[:vectors] = expand_path @input[:vectors]
119
- unless File.directory? @input[:vectors]
120
- raise Fontcustom::Error, "INPUT[:vectors] should be a directory. Check `#{relative_to_root(@input[:vectors])}` and try again."
106
+ if @options[:input].is_a? Hash
107
+ @options[:input] = symbolize_hash(@options[:input])
108
+ if @options[:input].has_key? :vectors
109
+ @options[:input][:vectors] = expand_path @options[:input][:vectors]
110
+ unless File.directory? @options[:input][:vectors]
111
+ raise Fontcustom::Error,
112
+ "INPUT[:vectors] (`#{relative_to_root(@options[:input][:vectors])}`) should be "\
113
+ "a directory. Check `#{relative_to_root(@options[:config])}` or your CLI options."
121
114
  end
122
115
  else
123
- raise Fontcustom::Error, "INPUT (as a hash) should contain a :vectors key."
116
+ raise Fontcustom::Error,
117
+ "INPUT should have a :vectors key. Check `#{relative_to_root(@options[:config])}` "\
118
+ "or your CLI options."
124
119
  end
125
120
 
126
- if @input.has_key? :templates
127
- @input[:templates] = expand_path @input[:templates]
128
- unless File.directory? @input[:templates]
129
- raise Fontcustom::Error, "INPUT[:templates] should be a directory. Check `#{relative_to_root(@input[:templates])}` and try again."
121
+ if @options[:input].has_key? :templates
122
+ @options[:input][:templates] = expand_path @options[:input][:templates]
123
+ unless File.directory? @options[:input][:templates]
124
+ raise Fontcustom::Error,
125
+ "INPUT[:templates] (`#{relative_to_root(@options[:input][:templates])}`) "\
126
+ "should be a directory. Check `#{relative_to_root(@options[:config])}` or "\
127
+ "your CLI options."
130
128
  end
131
129
  else
132
- @input[:templates] = @input[:vectors]
130
+ @options[:input][:templates] = @options[:input][:vectors]
133
131
  end
134
132
  else
135
- input = @input ? expand_path(@input) : @project_root
133
+ input = @options[:input] ? expand_path(@options[:input]) : @options[:project_root]
136
134
  unless File.directory? input
137
- raise Fontcustom::Error, "INPUT (as a string) should be a directory. Check `#{relative_to_root(input)}` and try again."
135
+ raise Fontcustom::Error,
136
+ "INPUT (`#{relative_to_root(input)}`) should be a directory. Check "\
137
+ "`#{relative_to_root(@options[:config])}` or your CLI options."
138
138
  end
139
- @input = { :vectors => input, :templates => input }
139
+ @options[:input] = { :vectors => input, :templates => input }
140
140
  end
141
141
 
142
- if Dir[File.join(@input[:vectors], "*.svg")].empty?
143
- raise Fontcustom::Error, "`#{relative_to_root(@input[:vectors])}` doesn't contain any SVGs."
142
+ if Dir[File.join(@options[:input][:vectors], "*.svg")].empty?
143
+ raise Fontcustom::Error, "`#{relative_to_root(@options[:input][:vectors])}` doesn't contain any SVGs."
144
144
  end
145
145
  end
146
146
 
147
147
  def set_output_paths
148
- if @output.is_a? Hash
149
- @output = symbolize_hash(@output)
150
- raise Fontcustom::Error, "OUTPUT (as a hash) should contain a :fonts key." unless @output.has_key? :fonts
148
+ if @options[:output].is_a? Hash
149
+ @options[:output] = symbolize_hash(@options[:output])
150
+ unless @options[:output].has_key? :fonts
151
+ raise Fontcustom::Error,
152
+ "OUTPUT should have a :fonts key. Check `#{relative_to_root(@options[:config])}` "\
153
+ "or your CLI options."
154
+ end
151
155
 
152
- @output.each do |key, val|
153
- @output[key] = expand_path val
156
+ @options[:output].each do |key, val|
157
+ @options[:output][key] = expand_path val
154
158
  if File.exists?(val) && ! File.directory?(val)
155
- raise Fontcustom::Error, "OUTPUT[:#{key.to_s}] should be a directory, not a file. Check `#{relative_to_root(val)}` and try again."
159
+ raise Fontcustom::Error,
160
+ "OUTPUT[:#{key.to_s}] (`#{relative_to_root(@options[:output][key])}`) should be "\
161
+ "a directory. Check `#{relative_to_root(@options[:config])}` or your CLI options."
156
162
  end
157
163
  end
158
164
 
159
- @output[:css] ||= @output[:fonts]
160
- @output[:preview] ||= @output[:fonts]
165
+ @options[:output][:css] ||= @options[:output][:fonts]
166
+ @options[:output][:preview] ||= @options[:output][:fonts]
161
167
  else
162
- if @output.is_a? String
163
- output = expand_path @output
168
+ if @options[:output].is_a? String
169
+ output = expand_path @options[:output]
164
170
  if File.exists?(output) && ! File.directory?(output)
165
- raise Fontcustom::Error, "OUTPUT should be a directory, not a file. Check `#{relative_to_root(output)}` and try again."
171
+ raise Fontcustom::Error,
172
+ "OUTPUT (`#{relative_to_root(output)}`) should be a directory. Check "\
173
+ "`#{relative_to_root(@options[:config])}` or your CLI options."
166
174
  end
167
175
  else
168
- output = File.join @project_root, @font_name
169
- say_message :status, "All generated files will be saved to `#{relative_to_root(output)}/`."
176
+ output = File.join @options[:project_root], @options[:font_name]
177
+ say_message :debug, "Generated files will be saved to `#{relative_to_root(output)}/`." if @options[:debug]
170
178
  end
171
179
 
172
- @output = {
180
+ @options[:output] = {
173
181
  :fonts => output,
174
182
  :css => output,
175
183
  :preview => output
@@ -185,7 +193,7 @@ module Fontcustom
185
193
  def set_template_paths
186
194
  template_path = File.join Fontcustom.gem_lib, "templates"
187
195
 
188
- @templates = @templates.map do |template|
196
+ @options[:templates] = @options[:templates].map do |template|
189
197
  case template
190
198
  when "preview"
191
199
  File.join template_path, "fontcustom-preview.html"
@@ -204,8 +212,13 @@ module Fontcustom
204
212
  when "bootstrap-ie7-scss"
205
213
  File.join template_path, "_fontcustom-bootstrap-ie7.scss"
206
214
  else
207
- template = File.expand_path File.join(@input[:templates], template) unless template[0] == "/"
208
- raise Fontcustom::Error, "The custom template at `#{relative_to_root(template)}` does not exist." unless File.exists? template
215
+ template = File.expand_path File.join(@options[:input][:templates], template) unless template[0] == "/"
216
+ unless File.exists? template
217
+ config = @options[:config] ? " `#{relative_to_root(@options[:config])}` or" : ""
218
+ raise Fontcustom::Error,
219
+ "Custom template `#{relative_to_root(template)}` doesn't exist. "\
220
+ "Check#{config} your CLI options."
221
+ end
209
222
  template
210
223
  end
211
224
  end