fontcustom 1.3.0.beta3 → 1.3.0.beta4

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.
@@ -7,6 +7,7 @@ module Fontcustom
7
7
  attr_accessor :options
8
8
 
9
9
  def initialize(cli_options = {})
10
+ @manifest = cli_options[:manifest]
10
11
  @cli_options = symbolize_hash(cli_options)
11
12
  parse_options
12
13
  end
@@ -20,10 +21,9 @@ module Fontcustom
20
21
  merge_options
21
22
  clean_font_name
22
23
  clean_css_selector
23
- set_manifest_path
24
24
  set_input_paths
25
25
  set_output_paths
26
- set_template_paths
26
+ check_template_paths
27
27
  end
28
28
 
29
29
  # We give Thor fake defaults to generate more useful help messages.
@@ -34,33 +34,23 @@ module Fontcustom
34
34
  @cli_options.delete(key) if @cli_options[key] == EXAMPLE_OPTIONS[key]
35
35
  end
36
36
  @cli_options = DEFAULT_OPTIONS.dup.merge @cli_options
37
- @cli_options[:project_root] ||= Dir.pwd
38
37
  end
39
38
 
40
39
  def set_config_path
41
40
  @cli_options[:config] = if @cli_options[:config]
42
- path = expand_path @cli_options[:config]
43
-
44
- # :config is the path to fontcustom.yml
41
+ path = @cli_options[:config]
45
42
  if File.exists?(path) && ! File.directory?(path)
46
43
  path
47
-
48
- # :config is a dir containing fontcustom.yml
49
44
  elsif File.exists? File.join(path, "fontcustom.yml")
50
45
  File.join path, "fontcustom.yml"
51
-
52
46
  else
53
- raise Fontcustom::Error, "No configuration file found at `#{relative_path(path)}`."
47
+ raise Fontcustom::Error, "No configuration file found at `#{path}`."
54
48
  end
55
49
  else
56
- # fontcustom.yml is in the project_root
57
- if File.exists? File.join(@cli_options[:project_root], "fontcustom.yml")
58
- File.join @cli_options[:project_root], "fontcustom.yml"
59
-
60
- # config/fontcustom.yml is in the project_root
61
- elsif File.exists? File.join(@cli_options[:project_root], "config", "fontcustom.yml")
62
- File.join @cli_options[:project_root], "config", "fontcustom.yml"
63
-
50
+ if File.exists? "fontcustom.yml"
51
+ "fontcustom.yml"
52
+ elsif File.exists? File.join("config", "fontcustom.yml")
53
+ File.join "config", "fontcustom.yml"
64
54
  else
65
55
  false
66
56
  end
@@ -70,23 +60,25 @@ module Fontcustom
70
60
  def load_config
71
61
  @config_options = {}
72
62
  if @cli_options[:config]
73
- say_message :debug, "Using settings from `#{relative_path(@cli_options[:config])}`." if @cli_options[:debug]
63
+ say_message :debug, "Using settings from `#{@cli_options[:config]}`." if @cli_options[:debug]
74
64
  begin
75
65
  config = YAML.load File.open(@cli_options[:config])
76
66
  if config # empty YAML returns false
77
67
  @config_options = symbolize_hash(config)
78
68
  else
79
- say_message :warn, "`#{relative_path(@cli_options[:config])}` was empty. Using defaults."
69
+ say_message :warn, "`#{@cli_options[:config]}` was empty. Using defaults."
80
70
  end
81
71
  rescue Exception => e
82
- raise Fontcustom::Error, "Error parsing `#{relative_path(@cli_options[:config])}`:\n#{e.message}"
72
+ raise Fontcustom::Error, "Error parsing `#{@cli_options[:config]}`:\n#{e.message}"
83
73
  end
84
74
  end
85
75
  end
86
76
 
77
+ # TODO validate keys
87
78
  def merge_options
88
79
  @cli_options.delete_if { |key, val| val == DEFAULT_OPTIONS[key] }
89
80
  @options = DEFAULT_OPTIONS.merge(@config_options).merge(@cli_options)
81
+ @options.delete :manifest
90
82
  end
91
83
 
92
84
  def clean_font_name
@@ -101,21 +93,10 @@ module Fontcustom
101
93
  @options[:css_selector] = @options[:css_selector].strip.gsub(/[^\.#\{\}\w]/, "-")
102
94
  end
103
95
 
104
- def set_manifest_path
105
- @options[:manifest] = if ! @options[:manifest].nil?
106
- expand_path @options[:manifest]
107
- elsif @options[:config]
108
- File.join File.dirname(@options[:config]), ".fontcustom-manifest.json"
109
- else
110
- File.join @options[:project_root], ".fontcustom-manifest.json"
111
- end
112
- end
113
-
114
96
  def set_input_paths
115
97
  if @options[:input].is_a? Hash
116
98
  @options[:input] = symbolize_hash(@options[:input])
117
99
  if @options[:input].has_key? :vectors
118
- @options[:input][:vectors] = expand_path @options[:input][:vectors]
119
100
  check_input @options[:input][:vectors]
120
101
  else
121
102
  raise Fontcustom::Error,
@@ -123,19 +104,18 @@ module Fontcustom
123
104
  end
124
105
 
125
106
  if @options[:input].has_key? :templates
126
- @options[:input][:templates] = expand_path @options[:input][:templates]
127
107
  check_input @options[:input][:templates]
128
108
  else
129
109
  @options[:input][:templates] = @options[:input][:vectors]
130
110
  end
131
111
  else
132
- input = @options[:input] ? expand_path(@options[:input]) : @options[:project_root]
133
- check_input input
112
+ input = @options[:input] ? @options[:input] : "."
113
+ check_input input
134
114
  @options[:input] = { :vectors => input, :templates => input }
135
115
  end
136
116
 
137
117
  if Dir[File.join(@options[:input][:vectors], "*.svg")].empty?
138
- raise Fontcustom::Error, "`#{relative_path(@options[:input][:vectors])}` doesn't contain any SVGs."
118
+ raise Fontcustom::Error, "`#{@options[:input][:vectors]}` doesn't contain any SVGs."
139
119
  end
140
120
  end
141
121
 
@@ -148,10 +128,10 @@ module Fontcustom
148
128
  end
149
129
 
150
130
  @options[:output].each do |key, val|
151
- @options[:output][key] = expand_path val
131
+ @options[:output][key] = val
152
132
  if File.exists?(val) && ! File.directory?(val)
153
133
  raise Fontcustom::Error,
154
- "Output `#{relative_path(@options[:output][key])}` exists but isn't a directory. Check your options."
134
+ "Output `#{@options[:output][key]}` exists but isn't a directory. Check your options."
155
135
  end
156
136
  end
157
137
 
@@ -159,14 +139,14 @@ module Fontcustom
159
139
  @options[:output][:preview] ||= @options[:output][:fonts]
160
140
  else
161
141
  if @options[:output].is_a? String
162
- output = expand_path @options[:output]
142
+ output = @options[:output]
163
143
  if File.exists?(output) && ! File.directory?(output)
164
144
  raise Fontcustom::Error,
165
- "Output `#{relative_path(output)}` exists but isn't a directory. Check your options."
145
+ "Output `#{output}` exists but isn't a directory. Check your options."
166
146
  end
167
147
  else
168
- output = File.join @options[:project_root], @options[:font_name]
169
- say_message :debug, "Generated files will be saved to `#{relative_path(output)}/`." if @options[:debug]
148
+ output = @options[:font_name]
149
+ say_message :debug, "Generated files will be saved to `#{output}/`." if @options[:debug]
170
150
  end
171
151
 
172
152
  @options[:output] = {
@@ -177,39 +157,13 @@ module Fontcustom
177
157
  end
178
158
  end
179
159
 
180
- # Translates shorthand to full path of packages templates, otherwise,
181
- # it checks input and pwd for the template.
182
- #
183
- # Could arguably belong in Generator::Template, however, it's nice to
184
- # be able to catch template errors before any generator runs.
185
- def set_template_paths
186
- template_path = File.join Fontcustom.gem_lib, "templates"
187
-
188
- @options[:templates] = @options[:templates].map do |template|
189
- case template
190
- when "preview"
191
- File.join template_path, "fontcustom-preview.html"
192
- when "css"
193
- File.join template_path, "fontcustom.css"
194
- when "scss"
195
- File.join template_path, "_fontcustom.scss"
196
- when "scss-rails"
197
- File.join template_path, "_fontcustom-rails.scss"
198
- when "bootstrap"
199
- File.join template_path, "fontcustom-bootstrap.css"
200
- when "bootstrap-scss"
201
- File.join template_path, "_fontcustom-bootstrap.scss"
202
- when "bootstrap-ie7"
203
- File.join template_path, "fontcustom-bootstrap-ie7.css"
204
- when "bootstrap-ie7-scss"
205
- File.join template_path, "_fontcustom-bootstrap-ie7.scss"
206
- else
207
- template = File.expand_path File.join(@options[:input][:templates], template) unless template[0] == "/"
208
- unless File.exists? template
209
- raise Fontcustom::Error,
210
- "Custom template `#{relative_path(template)}` doesn't exist. Check your options."
211
- end
212
- template
160
+ def check_template_paths
161
+ @options[:templates].each do |template|
162
+ next if %w|preview css scss scss-rails|.include? template
163
+ path = File.expand_path File.join(@options[:input][:templates], template) unless template[0] == "/"
164
+ unless File.exists? path
165
+ raise Fontcustom::Error,
166
+ "Custom template `#{template}` doesn't exist. Check your options."
213
167
  end
214
168
  end
215
169
  end
@@ -217,10 +171,10 @@ module Fontcustom
217
171
  def check_input(dir)
218
172
  if ! File.exists? dir
219
173
  raise Fontcustom::Error,
220
- "Input `#{relative_path(dir)}` doesn't exist. Check your options."
174
+ "Input `#{dir}` doesn't exist. Check your options."
221
175
  elsif ! File.directory? dir
222
176
  raise Fontcustom::Error,
223
- "Input `#{relative_path(dir)}` isn't a directory. Check your options."
177
+ "Input `#{dir}` isn't a directory. Check your options."
224
178
  end
225
179
  end
226
180
  end
@@ -4,7 +4,9 @@ require "thor/shell"
4
4
  require "thor/shell/basic"
5
5
  require "thor/shell/color"
6
6
 
7
- # Requires access to @options or @cli_options
7
+ # Requires access to:
8
+ # @options or @cli_options
9
+ # @manifest
8
10
  module Fontcustom
9
11
  module Utility
10
12
  include Thor::Actions
@@ -12,30 +14,30 @@ module Fontcustom
12
14
  #
13
15
  # Hacks that allow Thor::Actions and Thor::Shell to be used in Fontcustom classes.
14
16
  #
15
-
17
+
16
18
  def self.shell
17
19
  @shell || Thor::Shell::Color.new
18
20
  end
19
21
 
20
- def behavior
21
- :invoke
22
- end
23
-
24
22
  def shell
25
23
  Fontcustom::Utility.shell
26
24
  end
27
25
 
26
+ def behavior
27
+ :invoke
28
+ end
29
+
28
30
  def say_status(*args)
29
31
  shell.say_status *args
30
32
  end
31
33
 
32
34
  def destination_root
33
- @destination_stack ||= [_options[:project_root]]
35
+ @destination_stack ||= [project_root]
34
36
  @destination_stack.last
35
37
  end
36
38
 
37
39
  def source_paths
38
- @source_paths ||= [File.join(Fontcustom.gem_lib, "templates")]
40
+ @source_paths ||= [File.join(Fontcustom.gem_lib, "templates"), Dir.pwd]
39
41
  end
40
42
 
41
43
  #
@@ -64,77 +66,39 @@ module Fontcustom
64
66
  # Paths
65
67
  #
66
68
 
67
- def expand_path(path)
68
- return path if path[0] == "/" # ignore absolute paths
69
- File.expand_path File.join(_options[:project_root], path)
70
- end
71
-
72
- # TODO Is this robust enough?
73
- def relative_path(path)
74
- path = path.sub(_options[:project_root], "")
75
- path = path[1..-1] if path[0] == "/"
76
- path = "." if path.empty?
77
- path
69
+ def project_root
70
+ if @manifest.is_a? String
71
+ File.dirname @manifest
72
+ else
73
+ File.dirname @manifest.manifest
74
+ end
78
75
  end
79
76
 
80
77
  #
81
- # Manifest / Files
78
+ # File Manipulation
82
79
  #
83
80
 
84
81
  def write_file(file, content = "", message = nil, message_body = nil)
85
82
  File.open(file, "w") { |f| f.write(content) }
86
83
  if message
87
- body = message_body || relative_path(file)
84
+ body = message_body || file
88
85
  say_message message, body
89
86
  end
90
87
  end
91
88
 
92
- def get_manifest(file = _options[:manifest])
93
- begin
94
- json = File.read file
95
- JSON.parse(json, :symbolize_names => true)
96
- rescue JSON::ParserError
97
- raise Fontcustom::Error,
98
- "Couldn't parse `#{relative_path file}`. Fix the invalid "\
99
- "JSON or delete the file to start from scratch."
100
- end
101
- end
102
-
103
- def save_manifest
104
- json = JSON.pretty_generate @manifest
105
- write_file _options[:manifest], json
106
- end
107
-
108
- def delete_from_manifest(key)
109
- files = @manifest[key]
110
- return if files.empty?
111
- begin
112
- deleted = []
113
- @manifest[key].each do |file|
114
- remove_file file, :verbose => false
115
- deleted << file
116
- end
117
- ensure
118
- @manifest[key] = @manifest[key] - deleted
119
- save_manifest
120
- say_changed :delete, deleted
121
- end
122
- end
123
-
124
89
  #
125
90
  # Messages
126
91
  #
127
92
 
128
93
  def say_message(status, message, color = nil)
129
- return if _options[:quiet] && status != :error
94
+ return if options[:quiet] && status != :error
130
95
  color = :red if [:error, :debug, :warn].include?(status)
131
96
  say_status status, message, color
132
97
  end
133
98
 
134
99
  def say_changed(status, changed)
135
- return if _options[:quiet]
136
- message = changed.map { |file| relative_path(file) }
137
- say_status status, message.join(line_break)
100
+ return if options[:quiet]
101
+ say_status status, changed.join(line_break)
138
102
  end
139
103
 
140
104
  # magic number for Thor say_status line breaks
@@ -144,7 +108,7 @@ module Fontcustom
144
108
 
145
109
  private
146
110
 
147
- def _options
111
+ def options
148
112
  @options || @cli_options
149
113
  end
150
114
  end
@@ -1,3 +1,3 @@
1
1
  module Fontcustom
2
- VERSION = "1.3.0.beta3"
2
+ VERSION = "1.3.0.beta4"
3
3
  end
@@ -1,17 +1,23 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Fontcustom::Base do
4
+ before(:each) { Fontcustom::Manifest.any_instance.stub(:write_file) }
5
+
4
6
  context "#compile" do
5
7
  context "when [:checksum][:current] equals [:checksum][:previous]" do
6
8
  it "should show 'no change' message" do
7
- Fontcustom::Base.any_instance.stub :init_manifest
8
9
  Fontcustom::Base.any_instance.stub :check_fontforge
9
- base = Fontcustom::Base.new({})
10
- base.stub(:checksum).and_return("abc")
11
- base.instance_variable_set :@manifest, {:checksum => {:previous => "abc", :current => ""}}
12
- base.instance_variable_set :@options, {:quiet => false}
10
+ options = double("options")
11
+ options.stub(:options).and_return({})
12
+ Fontcustom::Options.stub(:new).and_return options
13
13
 
14
- output = capture(:stdout) { base.compile }
14
+ output = capture(:stdout) do
15
+ base = Fontcustom::Base.new({})
16
+ manifest = base.instance_variable_get :@manifest
17
+ manifest.stub(:get).and_return :previous => "abc"
18
+ base.stub(:checksum).and_return "abc"
19
+ base.compile
20
+ end
15
21
  output.should match(/No changes/)
16
22
  end
17
23
  end
@@ -19,33 +25,15 @@ describe Fontcustom::Base do
19
25
 
20
26
  context ".check_fontforge" do
21
27
  it "should raise error if fontforge isn't installed" do
22
- Fontcustom::Base.any_instance.stub :init_manifest
23
28
  Fontcustom::Base.any_instance.stub(:"`").and_return("")
24
29
  expect { Fontcustom::Base.new(:option => "foo") }.to raise_error Fontcustom::Error, /fontforge/
25
30
  end
26
31
  end
27
32
 
28
- context ".init_manifest" do
29
- before(:each) do
30
- Fontcustom::Base.any_instance.stub :check_fontforge
31
- manifest = double("manifest")
32
- manifest.should_receive(:manifest).and_return(manifest_contents)
33
- Fontcustom::Manifest.stub(:new).and_return manifest
34
- end
35
-
36
- it "should pass CLI options to FC::Options" do
37
- opts = double "options"
38
- opts.should_receive :options
39
- Fontcustom::Options.should_receive(:new).with({:foo => "bar"}).and_return opts
40
- Fontcustom::Base.new :foo => "bar"
41
- end
42
- end
43
-
44
33
  context ".checksum" do
45
34
  it "should return hash of all vectors and templates" do
46
35
  pending "SHA2 is different on CI servers. Why?"
47
36
  Fontcustom::Base.any_instance.stub :check_fontforge
48
- Fontcustom::Base.any_instance.stub :init_manifest
49
37
  base = Fontcustom::Base.new({})
50
38
  base.instance_variable_set :@options, {
51
39
  :input => {:vectors => fixture("shared/vectors")},
@@ -8,7 +8,7 @@ describe Fontcustom::CLI do
8
8
  Fontcustom::CLI.start ["compile", "vectors", "--quiet"]
9
9
  manifest = File.join testdir, ".fontcustom-manifest.json"
10
10
  Dir.glob(File.join(testdir, "fontcustom", "fontcustom_*\.{ttf,svg,woff,eot}")).length.should == 4
11
- File.read(manifest).should match(/"fonts":.+sandbox\/test\/fontcustom\/fontcustom_.+\.ttf"/m)
11
+ File.read(manifest).should match(/"fonts":.+fontcustom\/fontcustom_.+\.ttf"/m)
12
12
  end
13
13
  end
14
14
  end
@@ -2,14 +2,15 @@ require "spec_helper"
2
2
 
3
3
  describe Fontcustom::Generator::Font do
4
4
  def generator
5
- Fontcustom::Generator::Font.any_instance.stub(:get_manifest).and_return :options => {}
5
+ Fontcustom::Manifest.any_instance.stub :write_file
6
6
  Fontcustom::Generator::Font.new("")
7
7
  end
8
8
 
9
9
  context "#generate" do
10
10
  it "should set manifest[:glyphs] (integration)", :integration => true do
11
11
  live_test do |testdir|
12
- manifest = test_manifest
12
+ test_manifest
13
+ manifest = File.join Dir.pwd, ".fontcustom-manifest.json"
13
14
  gen = Fontcustom::Generator::Font.new manifest
14
15
  gen.stub :create_fonts
15
16
  gen.generate
@@ -19,10 +20,11 @@ describe Fontcustom::Generator::Font do
19
20
 
20
21
  it "should generate fonts (integration)", :integration => true do
21
22
  live_test do |testdir|
22
- manifest = test_manifest
23
+ test_manifest
24
+ manifest = File.join Dir.pwd, ".fontcustom-manifest.json"
23
25
  Fontcustom::Generator::Font.new(manifest).generate
24
26
  Dir.glob(File.join(testdir, "fontcustom", "fontcustom_*\.{ttf,svg,woff,eot}")).length.should == 4
25
- File.read(manifest).should match(/"fonts":.+sandbox\/test\/fontcustom\/fontcustom_.+\.ttf"/m)
27
+ File.read(manifest).should match(/"fonts":.*fontcustom\/fontcustom_.+\.ttf"/m)
26
28
  end
27
29
  end
28
30
  end
@@ -45,30 +47,26 @@ describe Fontcustom::Generator::Font do
45
47
  it "should set :glyphs in manifest" do
46
48
  gen = generator
47
49
  gen.instance_variable_set :@options, :input => {:vectors => fixture("shared/vectors")}
48
- gen.instance_variable_set :@manifest, :glyphs => {}
50
+ manifest = gen.instance_variable_get(:@manifest)
49
51
 
50
- gen.should_receive(:save_manifest)
51
52
  gen.send :set_glyph_info
52
- manifest = gen.instance_variable_get(:@manifest)
53
- manifest[:glyphs][:C].should include(:codepoint => 61696)
54
- manifest[:glyphs][:D].should include(:codepoint => 61697)
55
- manifest[:glyphs][:"a_R3ally-eXotic-f1Le-Name"].should include(:codepoint => 61698)
53
+ data = manifest.instance_variable_get(:@data)
54
+ data[:glyphs][:C].should include(:codepoint => 61696)
55
+ data[:glyphs][:D].should include(:codepoint => 61697)
56
+ data[:glyphs][:"a_R3ally-eXotic-f1Le-Name"].should include(:codepoint => 61698)
56
57
  end
57
58
 
58
59
  it "should not change codepoints of existing glyphs" do
59
60
  gen = generator
60
61
  gen.instance_variable_set :@options, :input => {:vectors => fixture("shared/vectors")}
61
- gen.instance_variable_set :@manifest, :glyphs => {:C => {:source => "foo", :codepoint => 61699}}
62
+ manifest = gen.instance_variable_get(:@manifest)
63
+ manifest.set :glyphs, {:C => {:source => "foo", :codepoint => 61699}}
62
64
 
63
- gen.should_receive(:save_manifest)
64
65
  gen.send :set_glyph_info
65
- manifest = gen.instance_variable_get(:@manifest)
66
- manifest[:glyphs][:C].should include(:codepoint => 61699)
67
- manifest[:glyphs][:D].should include(:codepoint => 61700)
68
- manifest[:glyphs][:"a_R3ally-eXotic-f1Le-Name"].should include(:codepoint => 61701)
66
+ data = manifest.instance_variable_get(:@data)
67
+ data[:glyphs][:C].should include(:codepoint => 61699)
68
+ data[:glyphs][:D].should include(:codepoint => 61700)
69
+ data[:glyphs][:"a_R3ally-eXotic-f1Le-Name"].should include(:codepoint => 61701)
69
70
  end
70
71
  end
71
-
72
- #context ".run_fontforge" do
73
- #end
74
72
  end