fontcustom 1.0.1 → 1.1.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/README.md +1 -1
  4. data/TODO.md +6 -0
  5. data/lib/fontcustom.rb +1 -1
  6. data/lib/fontcustom/actions.rb +28 -0
  7. data/lib/fontcustom/cli.rb +16 -15
  8. data/lib/fontcustom/generator/font.rb +31 -35
  9. data/lib/fontcustom/generator/template.rb +49 -34
  10. data/lib/fontcustom/options.rb +17 -11
  11. data/lib/fontcustom/scripts/generate.py +1 -1
  12. data/lib/fontcustom/templates/_fontcustom-bootstrap-ie7.scss +4 -3
  13. data/lib/fontcustom/templates/_fontcustom-bootstrap.scss +9 -14
  14. data/lib/fontcustom/templates/_fontcustom.scss +8 -14
  15. data/lib/fontcustom/templates/fontcustom-bootstrap-ie7.css +3 -2
  16. data/lib/fontcustom/templates/fontcustom-bootstrap.css +9 -8
  17. data/lib/fontcustom/templates/fontcustom-preview.html +2 -3
  18. data/lib/fontcustom/templates/fontcustom.css +7 -7
  19. data/lib/fontcustom/templates/fontcustom.yml +25 -66
  20. data/lib/fontcustom/util.rb +108 -31
  21. data/lib/fontcustom/version.rb +1 -1
  22. data/lib/fontcustom/watcher.rb +24 -8
  23. data/spec/fixtures/{mixed-output → generators}/.fontcustom-data +0 -0
  24. data/spec/fixtures/{mixed-output → generators/mixed-output}/another-font.ttf +0 -0
  25. data/spec/fixtures/{mixed-output → generators/mixed-output}/dont-delete-me.bro +0 -0
  26. data/spec/fixtures/{mixed-output → generators/mixed-output}/fontcustom.css +0 -0
  27. data/spec/fixtures/{mixed-output → generators/mixed-output}/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.eot +0 -0
  28. data/spec/fixtures/{mixed-output → generators/mixed-output}/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.svg +0 -0
  29. data/spec/fixtures/{mixed-output → generators/mixed-output}/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.ttf +0 -0
  30. data/spec/fixtures/{mixed-output → generators/mixed-output}/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.woff +0 -0
  31. data/spec/fixtures/{not-a-dir → shared/not-a-dir} +0 -0
  32. data/spec/fixtures/shared/templates/custom.css +1 -0
  33. data/spec/fixtures/shared/templates/regular.css +1 -0
  34. data/spec/fixtures/{empty → shared/vectors-empty}/no_vectors_here.txt +0 -0
  35. data/spec/fixtures/{vectors → shared/vectors}/C.svg +0 -0
  36. data/spec/fixtures/{vectors → shared/vectors}/D.svg +0 -0
  37. data/spec/fixtures/vectors/a_R3ally-eXotic f1Le Name.svg b/data/spec/fixtures/shared/vectors/a_R3ally-eXotic f1Le → Name.svg +0 -0
  38. data/spec/fixtures/util/config-is-in-dir/fontcustom.yml +1 -0
  39. data/spec/fixtures/util/fontcustom-malformed.yml +1 -0
  40. data/spec/fixtures/{fontcustom.yml → util/fontcustom.yml} +0 -0
  41. data/spec/fixtures/util/rails-like/config/fontcustom.yml +1 -0
  42. data/spec/fontcustom/actions_spec.rb +22 -0
  43. data/spec/fontcustom/generator/font_spec.rb +107 -62
  44. data/spec/fontcustom/generator/template_spec.rb +124 -29
  45. data/spec/fontcustom/util_spec.rb +299 -53
  46. data/spec/fontcustom/watcher_spec.rb +56 -10
  47. data/spec/spec_helper.rb +8 -3
  48. metadata +46 -34
  49. data/spec/fixtures/empty-data/.fontcustom-data +0 -0
@@ -1,20 +1,14 @@
1
- <%
2
- file_name = if @opts[:font_face_path]
3
- File.join @opts[:font_face_path], @data[:file_name]
4
- else
5
- @data[:file_name]
6
- end
7
- %>/*
8
- * Font Custom: bare CSS
9
- */
1
+ //
2
+ // Icon Font: <%= @opts[:font_name] %>
3
+ //
10
4
 
11
5
  @font-face {
12
6
  font-family: "<%= @opts[:font_name] %>";
13
- src: url("<%= file_name %>.eot");
14
- src: url("<%= file_name %>.eot?#iefix") format("embedded-opentype"),
15
- url("<%= file_name %>.woff") format("woff"),
16
- url("<%= file_name %>.ttf") format("truetype"),
17
- url("<%= file_name %>.svg#<%= @opts[:font_name] %>") format("svg");
7
+ src: url("<%= @data[:paths][:preprocessor_to_fonts] %>.eot");
8
+ src: url("<%= @data[:paths][:preprocessor_to_fonts] %>.eot?#iefix") format("embedded-opentype"),
9
+ url("<%= @data[:paths][:preprocessor_to_fonts] %>.woff") format("woff"),
10
+ url("<%= @data[:paths][:preprocessor_to_fonts] %>.ttf") format("truetype"),
11
+ url("<%= @data[:paths][:preprocessor_to_fonts] %>.svg#<%= @opts[:font_name] %>") format("svg");
18
12
  font-weight: normal;
19
13
  font-style: normal;
20
14
  }
@@ -1,6 +1,7 @@
1
1
  /*
2
- * Font Custom: Bootstrap CSS for IE7
3
- */
2
+ Icon Font: <%= @opts[:font_name] %>
3
+ Bootstrap IE7 Enabler
4
+ */
4
5
 
5
6
  [class^="<%= @opts[:css_prefix] %>"],
6
7
  [class*=" <%= @opts[:css_prefix] %>"] {
@@ -1,14 +1,15 @@
1
- /*
2
- * Font Custom: Bootstrap CSS
3
- */
1
+ /*
2
+ Icon Font: <%= @opts[:font_name] %>
3
+ Bootstrap Override
4
+ */
4
5
 
5
6
  @font-face {
6
7
  font-family: "<%= @opts[:font_name] %>";
7
- src: url("<%= @data[:file_name] %>.eot");
8
- src: url("<%= @data[:file_name] %>.eot?#iefix") format("embedded-opentype"),
9
- url("<%= @data[:file_name] %>.woff") format("woff"),
10
- url("<%= @data[:file_name] %>.ttf") format("truetype"),
11
- url("<%= @data[:file_name] %>.svg#<%= @opts[:font_name] %>") format("svg");
8
+ src: url("<%= @data[:paths][:css_to_fonts] %>.eot");
9
+ src: url("<%= @data[:paths][:css_to_fonts] %>.eot?#iefix") format("embedded-opentype"),
10
+ url("<%= @data[:paths][:css_to_fonts] %>.woff") format("woff"),
11
+ url("<%= @data[:paths][:css_to_fonts] %>.ttf") format("truetype"),
12
+ url("<%= @data[:paths][:css_to_fonts] %>.svg#<%= @opts[:font_name] %>") format("svg");
12
13
  font-weight: normal;
13
14
  font-style: normal;
14
15
  }
@@ -1,9 +1,8 @@
1
- <% scale = %w|12 14 16 18 21 24 36 48 60 72| %>
2
- <!DOCTYPE html>
1
+ <% scale = %w|12 14 16 18 21 24 36 48 60 72| %><!DOCTYPE html>
3
2
  <html>
4
3
  <head>
5
4
  <title><%= @opts[:font_name] %> glyphs preview</title>
6
- <link rel="stylesheet" href="fontcustom.css" />
5
+ <link rel="stylesheet" href="<%= @data[:paths][:preview_to_css] %>" />
7
6
  <!--[if lte IE 7]><link rel="stylesheet" href="fontcustom-ie7.css" /><![endif]-->
8
7
 
9
8
  <style>
@@ -1,14 +1,14 @@
1
1
  /*
2
- * Font Custom: bare CSS
3
- */
2
+ Icon Font: <%= @opts[:font_name] %>
3
+ */
4
4
 
5
5
  @font-face {
6
6
  font-family: "<%= @opts[:font_name] %>";
7
- src: url("<%= @data[:file_name] %>.eot");
8
- src: url("<%= @data[:file_name] %>.eot?#iefix") format("embedded-opentype"),
9
- url("<%= @data[:file_name] %>.woff") format("woff"),
10
- url("<%= @data[:file_name] %>.ttf") format("truetype"),
11
- url("<%= @data[:file_name] %>.svg#<%= @opts[:font_name] %>") format("svg");
7
+ src: url("<%= @data[:paths][:css_to_fonts] %>.eot");
8
+ src: url("<%= @data[:paths][:css_to_fonts] %>.eot?#iefix") format("embedded-opentype"),
9
+ url("<%= @data[:paths][:css_to_fonts] %>.woff") format("woff"),
10
+ url("<%= @data[:paths][:css_to_fonts] %>.ttf") format("truetype"),
11
+ url("<%= @data[:paths][:css_to_fonts] %>.svg#<%= @opts[:font_name] %>") format("svg");
12
12
  font-weight: normal;
13
13
  font-style: normal;
14
14
  }
@@ -1,80 +1,39 @@
1
- ##
2
- # FONTCUSTOM CONFIG
3
- #
4
- # This file will automatically be loaded if located inside your vector dir.
5
- # Otherwise, pass it to `compile` or `watch` with:
6
- #
7
- # --config=path/to/config.yml
8
- # -c path/to/containing/dir/
9
- ##
10
-
11
1
  # ---------------------------------------------------------------------------- #
12
- # Output Directory
13
- # absolute path OR relative path from `pwd`
14
- #
15
- # default: INPUT/fontcustom
16
-
17
- #output: path/to/output
18
-
2
+ # Project Info
3
+ # Learn more about these options with `fontcustom help`.
19
4
  # ---------------------------------------------------------------------------- #
20
- # Templates
21
- # array of templates to generate alongside fonts
22
- # accepts shortcuts or paths (absolute, relative to INPUT, or relative to `pwd`)
23
- #
24
- # shortcuts:
25
- # preview
26
- # css, scss
27
- # bootstrap, bootstrap-scss
28
- # bootstrap-ie7, bootstrap-ie7-scss
29
- #
30
- # default: [ css, preview ]
31
5
 
32
- #templates: [ scss, preview, path/from/INPUT ]
6
+ #font_name: My Custom Font
7
+ #file_hash: false
8
+ #css_prefix: glyph-
9
+ #preprocessor_font_path: fonts/fontcustom
10
+ #debug: true
11
+ #verbose: false
33
12
 
34
- # ---------------------------------------------------------------------------- #
35
- # Font Name
36
- # automatically normalized to lower-spinal-case
37
- #
38
- # default: fontcustom
39
13
 
40
- #font_name: my-font
41
-
42
14
  # ---------------------------------------------------------------------------- #
43
- # Font Hash
44
- # option to attach a cache-breaking fingerprint to each font file
45
- #
46
- # default: true
47
-
48
- #file_hash: false
49
-
15
+ # Project Directories
16
+ # All paths are relative to PROJECT_ROOT (default: working directory).
17
+ # When assigned a hash, individual components can have their own paths.
18
+ # When assigned a string, all components share the same path.
50
19
  # ---------------------------------------------------------------------------- #
51
- # CSS Class Prefix
52
- #
53
- # default: icon-
54
20
 
55
- #css_prefix: glyph-
21
+ #input:
22
+ # vectors: app/assets/fontcustom/vectors
23
+ # templates: app/assets/fontcustom/templates
56
24
 
57
- # ---------------------------------------------------------------------------- #
58
- # @Font-face Path
59
- # font path used in @font-face declarations
60
- # only affects SCSS shortcut templates and custom templates
61
- #
62
- # default: none
25
+ #output:
26
+ # fonts: app/assets/fonts
27
+ # css: app/assets/stylesheets
28
+ # preview: app/views/styleguide
63
29
 
64
- #font_face_path: assets/fonts/fontcustom
65
30
 
66
31
  # ---------------------------------------------------------------------------- #
67
- # Debug
68
- # show raw output from Font Forge
69
- #
70
- # default: false
71
-
72
- #debug: true
73
-
32
+ # Templates
33
+ # Shortcuts:
34
+ # preview, css, scss, bootstrap, bootstrap-scss, bootstrap-ie7,
35
+ # bootstrap-ie7-scss
36
+ # Custom templates should be saved in the INPUT[:templates] directory.
74
37
  # ---------------------------------------------------------------------------- #
75
- # Verbose
76
- # print out all file operations
77
- #
78
- # default: true
79
38
 
80
- #verbose: false
39
+ #templates: [ scss, preview, my-custom-template.yml ]
@@ -1,8 +1,9 @@
1
1
  require "yaml"
2
+ require "thor/core_ext/hash_with_indifferent_access"
2
3
 
3
4
  module Fontcustom
4
5
  class Util
5
- class << self
6
+ class << self
6
7
  def check_fontforge
7
8
  fontforge = `which fontforge`
8
9
  if fontforge == "" || fontforge == "fontforge not found"
@@ -14,38 +15,120 @@ module Fontcustom
14
15
  # Priority: Passed args > config file > default
15
16
  def collect_options(args = {})
16
17
  options = Fontcustom::DEFAULT_OPTIONS.clone
17
- args = args.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
18
+ options[:project_root] = args[:project_root] if args[:project_root]
18
19
 
19
- options[:input] = args[:input] if args[:input]
20
- options[:config] = args[:config] if args[:config]
21
- args.delete :config # don't overwrite the return value of #get_config_path
20
+ # Parse fontcustom.yml if it exists
21
+ # Deletes :config so that it can't overwrite the output of .get_config_path
22
+ options[:config] = args.delete(:config) if args[:config]
22
23
  options[:config] = get_config_path options
23
24
 
24
25
  if options[:config]
25
- config = YAML.load File.open(options[:config])
26
- if config.is_a? Hash
27
- config = config.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
26
+ begin
27
+ config = YAML.load File.open(options[:config])
28
28
  options.merge! config
29
+ rescue
30
+ raise Fontcustom::Error, "I couldn't read your configuration file. Please check #{options[:config]} and try again."
29
31
  end
30
32
  end
31
33
 
34
+ # Override with passed arguments
35
+ args.delete(:input) unless args[:input] # allows nil input from CLI
32
36
  options.merge! args
33
- options[:output] ||= File.join(options[:input], "fontcustom")
34
- options[:templates] = get_template_paths options
35
- options[:font_name] = options[:font_name].strip.downcase.gsub(/\W/, '-')
37
+ options[:font_name] = options[:font_name].strip.gsub(/\W/, '-')
38
+
39
+ options[:input] = get_input_paths options
40
+ options[:output] = get_output_paths options
41
+ options[:templates] = get_templates options
36
42
  options
37
43
  end
38
44
 
39
- # passed path > input
40
45
  def get_config_path(options)
41
- if options[:config] && File.directory?(options[:config]) && File.exists?(File.join(options[:config], "fontcustom.yml"))
42
- File.join options[:config], "fontcustom.yml"
43
- elsif options[:config] && File.exists?(options[:config])
44
- options[:config]
45
- elsif File.exists? File.join(options[:input], "fontcustom.yml")
46
- File.join options[:input], "fontcustom.yml"
46
+ if options[:config]
47
+ config = File.expand_path File.join(options[:project_root], options[:config])
48
+
49
+ # :config is the path to fontcustom.yml
50
+ if File.exists?(config) && ! File.directory?(config)
51
+ config
52
+
53
+ # :config is a dir containing fontcustom.yml
54
+ elsif File.exists? File.join(config, "fontcustom.yml")
55
+ File.join config, "fontcustom.yml"
56
+
57
+ else
58
+ raise Fontcustom::Error, "I couldn't find your configuration file. Check #{config} and try again."
59
+ end
47
60
  else
48
- false
61
+ # fontcustom.yml is in the project_root
62
+ if File.exists? File.join(options[:project_root], "fontcustom.yml")
63
+ File.join options[:project_root], "fontcustom.yml"
64
+
65
+ # config/fontcustom.yml is in the project_root
66
+ elsif File.exists? File.join(options[:project_root], "config", "fontcustom.yml")
67
+ File.join options[:project_root], "config", "fontcustom.yml"
68
+
69
+ else
70
+ # TODO helpful warning that no config was found
71
+ false
72
+ end
73
+ end
74
+ end
75
+
76
+ def get_input_paths(options)
77
+ paths = if options[:input].is_a? Hash
78
+ input = Thor::CoreExt::HashWithIndifferentAccess.new options[:input]
79
+ raise Fontcustom::Error, "INPUT should be a string or a hash containing a \"vectors\" key." unless input[:vectors]
80
+
81
+ input[:vectors] = File.expand_path File.join(options[:project_root], input[:vectors])
82
+ raise Fontcustom::Error, "INPUT[\"vectors\"] should be a directory. Check #{input[:vectors]} and try again." unless File.directory? input[:vectors]
83
+
84
+ if input[:templates]
85
+ input[:templates] = File.expand_path File.join(options[:project_root], input[:templates])
86
+ raise Fontcustom::Error, "INPUT[\"templates\"] should be a directory. Check #{input[:templates]} and try again." unless File.directory? input[:templates]
87
+ else
88
+ input[:templates] = input[:vectors]
89
+ end
90
+ input
91
+ elsif options[:input].is_a? String
92
+ input = File.join options[:project_root], options[:input]
93
+ raise Fontcustom::Error, "INPUT should be a directory. Check #{input} and try again." unless File.directory? input
94
+ Thor::CoreExt::HashWithIndifferentAccess.new({
95
+ :vectors => input,
96
+ :templates => input
97
+ })
98
+ end
99
+
100
+ if Dir[File.join(paths[:vectors], "*.{svg,eps}")].empty?
101
+ raise Fontcustom::Error, "#{paths[:vectors]} doesn't contain any vectors (*.svg or *.eps files)."
102
+ end
103
+
104
+ paths
105
+ end
106
+
107
+ def get_output_paths(options)
108
+ if options[:output].is_a? Hash
109
+ output = Thor::CoreExt::HashWithIndifferentAccess.new options[:output]
110
+ raise Fontcustom::Error, "OUTPUT should be a string or a hash containing a \"fonts\" key." unless output[:fonts]
111
+
112
+ output.each do |key, val|
113
+ output[key] = File.expand_path File.join(options[:project_root], val)
114
+ end
115
+
116
+ output[:css] ||= output[:fonts]
117
+ output[:preview] ||= output[:fonts]
118
+ output
119
+ else
120
+ if options[:output].is_a? String
121
+ output = File.expand_path File.join(options[:project_root], options[:output])
122
+ raise Fontcustom::Error, "OUTPUT should be a directory, not a file. Check #{output} and try again." if File.exists?(output) && ! File.directory?(output)
123
+ else
124
+ # TODO friendly warning that we're defaulting to pwd/:font_name
125
+ output = File.join options[:project_root], options[:font_name]
126
+ end
127
+ Thor::CoreExt::HashWithIndifferentAccess.new({
128
+ :fonts => output,
129
+ :css => output,
130
+ :preview => output
131
+ })
49
132
  end
50
133
  end
51
134
 
@@ -54,8 +137,10 @@ module Fontcustom
54
137
  #
55
138
  # Could arguably belong in Generator::Template, however, it's nice to
56
139
  # be able to catch template errors before any generator runs.
57
- def get_template_paths(options)
140
+ def get_templates(options)
141
+ # ensure that preview has plain stylesheet to reference
58
142
  options[:templates] << "css" if options[:templates].include?("preview") && ! options[:templates].include?("css")
143
+
59
144
  options[:templates].map do |template|
60
145
  case template
61
146
  when "preview"
@@ -73,21 +158,13 @@ module Fontcustom
73
158
  when "bootstrap-ie7-scss"
74
159
  File.join gem_lib_path, "templates", "_fontcustom-bootstrap-ie7.scss"
75
160
  else
76
- if File.exists?(template)
77
- template
78
- elsif File.exists?(File.join(options[:input], template))
79
- File.join options[:input], template
80
- else
81
- raise Fontcustom::Error, "We couldn't find your custom template #{template}. Double check and try again?"
82
- end
161
+ path = File.join options[:input][:templates], template
162
+ raise Fontcustom::Error, "We couldn't find your custom template at #{path}. Double check and try again?" unless File.exists? path
163
+ path
83
164
  end
84
165
  end
85
166
  end
86
167
 
87
- def clear_file(file)
88
- File.open(file, "w") {}
89
- end
90
-
91
168
  def gem_lib_path
92
169
  File.expand_path(File.join(File.dirname(__FILE__)))
93
170
  end
@@ -1,3 +1,3 @@
1
1
  module Fontcustom
2
- VERSION = "1.0.1"
2
+ VERSION = "1.1.0.pre"
3
3
  end
@@ -5,34 +5,50 @@ module Fontcustom
5
5
  class Watcher
6
6
  def initialize(opts)
7
7
  @opts = opts
8
- @listener = Listen.to(@opts[:input]).relative_paths(true).filter(/\.(eps|svg)$/).change(&callback)
8
+ @vector_listener = Listen.to(@opts[:input][:vectors]).relative_paths(true).filter(/\.(eps|svg)$/).change(&callback)
9
+
10
+ templates = @opts[:templates].dup
11
+ templates.delete_if do |template|
12
+ template.match Util.gem_lib_path
13
+ end
14
+ unless templates.empty?
15
+ templates = templates.map do |template|
16
+ File.basename template
17
+ end
18
+ @template_listener = Listen.to(@opts[:input][:templates]).relative_paths(true).filter(/(#{templates.join("|")})/).change(&callback)
19
+ end
20
+
9
21
  @opts[:blocking] = @opts[:blocking] == false ? false : true
10
- @listener = @listener.polling_fallback_message(false) unless @opts[:blocking]
22
+ unless @opts[:blocking]
23
+ @vector_listener = @vector_listener.polling_fallback_message(false)
24
+ @template_listener = @template_listener.polling_fallback_message(false) if @template_listener
25
+ end
11
26
  end
12
27
 
13
28
  def watch
14
- puts "Font Custom is watching your icons at #{@opts[:input]}. Press Ctrl + C to stop."
29
+ puts "Font Custom is watching your icons at #{@opts[:input][:vectors]}. Press Ctrl + C to stop."
15
30
  compile unless @opts[:skip_first]
16
31
 
17
32
  if @opts[:blocking]
18
- @listener.start!
33
+ @vector_listener.start!
34
+ @template_listener.start! if @template_listener
19
35
  else
20
- @listener.start
36
+ @vector_listener.start
37
+ @template_listener.start if @template_listener
21
38
  end
22
39
 
23
40
  rescue Fontcustom::Error => e
24
41
  show_error e
25
42
 
26
43
  # Catches Ctrl + C
27
- # TODO Does the listen gem have a better way of handling this?
28
44
  rescue SignalException
29
45
  stop
30
46
  end
31
47
 
32
48
  def stop
33
- # Adding a newline so message is not prepended with ^C on SIGTERM
49
+ @vector_listener.stop
50
+ @template_listener.stop if @template_listener
34
51
  puts "\nFont Custom is signing off. Good night and good luck."
35
- @listener.stop
36
52
  end
37
53
 
38
54
  private