fontcustom 1.3.0.beta3 → 1.3.0.beta4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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