fontcustom 1.0.1 → 1.1.0.pre

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 +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