fontcustom 1.1.0.pre → 1.1.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/TODO.md +20 -5
  3. data/lib/fontcustom.rb +42 -4
  4. data/lib/fontcustom/cli.rb +65 -25
  5. data/lib/fontcustom/generator/font.rb +26 -26
  6. data/lib/fontcustom/generator/template.rb +29 -30
  7. data/lib/fontcustom/options.rb +207 -23
  8. data/lib/fontcustom/templates/_fontcustom-bootstrap-ie7.scss +9 -9
  9. data/lib/fontcustom/templates/_fontcustom-bootstrap.scss +19 -19
  10. data/lib/fontcustom/templates/_fontcustom-rails.scss +28 -0
  11. data/lib/fontcustom/templates/_fontcustom.scss +11 -11
  12. data/lib/fontcustom/templates/fontcustom-bootstrap-ie7.css +9 -9
  13. data/lib/fontcustom/templates/fontcustom-bootstrap.css +19 -19
  14. data/lib/fontcustom/templates/fontcustom-preview.html +34 -7
  15. data/lib/fontcustom/templates/fontcustom.css +11 -11
  16. data/lib/fontcustom/templates/fontcustom.yml +11 -6
  17. data/lib/fontcustom/util.rb +38 -159
  18. data/lib/fontcustom/version.rb +1 -1
  19. data/lib/fontcustom/watcher.rb +16 -14
  20. data/spec/fixtures/generators/.fontcustom-data-corrupted +18 -0
  21. data/spec/fixtures/generators/fontcustom.yml +1 -0
  22. data/spec/fixtures/{util/fontcustom.yml → options/any-file-name.yml} +0 -0
  23. data/spec/fixtures/{util → options}/config-is-in-dir/fontcustom.yml +0 -0
  24. data/spec/fixtures/options/fontcustom-empty.yml +1 -0
  25. data/spec/fixtures/{util → options}/fontcustom-malformed.yml +0 -0
  26. data/spec/fixtures/options/fontcustom.yml +1 -0
  27. data/spec/fixtures/options/no-config-here/.gitkeep +0 -0
  28. data/spec/fixtures/{util → options}/rails-like/config/fontcustom.yml +0 -0
  29. data/spec/fontcustom/generator/font_spec.rb +31 -15
  30. data/spec/fontcustom/generator/template_spec.rb +20 -18
  31. data/spec/fontcustom/options_spec.rb +428 -0
  32. data/spec/fontcustom/util_spec.rb +38 -336
  33. data/spec/fontcustom/watcher_spec.rb +7 -2
  34. data/spec/spec_helper.rb +1 -2
  35. metadata +23 -13
  36. data/lib/fontcustom/actions.rb +0 -28
  37. data/spec/fontcustom/actions_spec.rb +0 -22
@@ -1,63 +1,63 @@
1
1
  /*
2
- Icon Font: <%= @opts[:font_name] %>
2
+ Icon Font: <%= @opts.font_name %>
3
3
  Bootstrap Override
4
4
  */
5
5
 
6
6
  @font-face {
7
- font-family: "<%= @opts[:font_name] %>";
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");
7
+ font-family: "<%= @opts.font_name %>";
8
+ src: url("<%= @font_path %>.eot");
9
+ src: url("<%= @font_path %>.eot?#iefix") format("embedded-opentype"),
10
+ url("<%= @font_path %>.woff") format("woff"),
11
+ url("<%= @font_path %>.ttf") format("truetype"),
12
+ url("<%= @font_path %>.svg#<%= @opts.font_name %>") format("svg");
13
13
  font-weight: normal;
14
14
  font-style: normal;
15
15
  }
16
16
 
17
- [class^="<%= @opts[:css_prefix] %>"]:before, [class*=" <%= @opts[:css_prefix] %>"]:before {
18
- font-family: "<%= @opts[:font_name] %>";
17
+ [class^="<%= @opts.css_prefix %>"]:before, [class*=" <%= @opts.css_prefix %>"]:before {
18
+ font-family: "<%= @opts.font_name %>";
19
19
  font-weight: normal;
20
20
  font-style: normal;
21
21
  display: inline-block;
22
22
  text-decoration: inherit;
23
23
  }
24
24
 
25
- a [class^="<%= @opts[:css_prefix] %>"], a [class*=" <%= @opts[:css_prefix] %>"] {
25
+ a [class^="<%= @opts.css_prefix %>"], a [class*=" <%= @opts.css_prefix %>"] {
26
26
  display: inline-block;
27
27
  text-decoration: inherit;
28
28
  }
29
29
 
30
- .<%= @opts[:css_prefix] %>large:before {
30
+ .<%= @opts.css_prefix %>large:before {
31
31
  vertical-align: top;
32
32
  font-size: 1.333em;
33
33
  }
34
34
 
35
- .btn [class^="<%= @opts[:css_prefix] %>"], .btn [class*=" <%= @opts[:css_prefix] %>"] {
35
+ .btn [class^="<%= @opts.css_prefix %>"], .btn [class*=" <%= @opts.css_prefix %>"] {
36
36
  line-height: 0.9em;
37
37
  }
38
38
 
39
- li [class^="<%= @opts[:css_prefix] %>"], li [class*=" <%= @opts[:css_prefix] %>"] {
39
+ li [class^="<%= @opts.css_prefix %>"], li [class*=" <%= @opts.css_prefix %>"] {
40
40
  display: inline-block;
41
41
  width: 1.25em;
42
42
  text-align: center;
43
43
  }
44
44
 
45
- li .<%= @opts[:css_prefix] %>large[class^="<%= @opts[:css_prefix] %>"], li .<%= @opts[:css_prefix] %>large[class*=" <%= @opts[:css_prefix] %>"] {
45
+ li .<%= @opts.css_prefix %>large[class^="<%= @opts.css_prefix %>"], li .<%= @opts.css_prefix %>large[class*=" <%= @opts.css_prefix %>"] {
46
46
  width: 1.875em;
47
47
  }
48
48
 
49
- li[class^="<%= @opts[:css_prefix] %>"], li[class*=" <%= @opts[:css_prefix] %>"] {
49
+ li[class^="<%= @opts.css_prefix %>"], li[class*=" <%= @opts.css_prefix %>"] {
50
50
  margin-left: 0;
51
51
  list-style-type: none;
52
52
  }
53
53
 
54
- li[class^="<%= @opts[:css_prefix] %>"]:before, li[class*=" <%= @opts[:css_prefix] %>"]:before {
54
+ li[class^="<%= @opts.css_prefix %>"]:before, li[class*=" <%= @opts.css_prefix %>"]:before {
55
55
  text-indent: -2em;
56
56
  text-align: center;
57
57
  }
58
58
 
59
- li[class^="<%= @opts[:css_prefix] %>"].<%= @opts[:css_prefix] %>large:before, li[class*=" <%= @opts[:css_prefix] %>"].<%= @opts[:css_prefix] %>large:before {
59
+ li[class^="<%= @opts.css_prefix %>"].<%= @opts.css_prefix %>large:before, li[class*=" <%= @opts.css_prefix %>"].<%= @opts.css_prefix %>large:before {
60
60
  text-indent: -1.333em;
61
61
  }
62
- <% @data[:glyphs].each_with_index do |name, index| %>
63
- .<%= @opts[:css_prefix] + name %>:before { content: "\<%= (61696+index).to_s(16) %>"; }<% end %>
62
+ <% @glyphs.each_with_index do |name, index| %>
63
+ .<%= @opts.css_prefix + name %>:before { content: "\<%= (61696+index).to_s(16) %>"; }<% end %>
@@ -1,11 +1,11 @@
1
1
  <% scale = %w|12 14 16 18 21 24 36 48 60 72| %><!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <title><%= @opts[:font_name] %> glyphs preview</title>
5
- <link rel="stylesheet" href="<%= @data[:paths][:preview_to_css] %>" />
6
- <!--[if lte IE 7]><link rel="stylesheet" href="fontcustom-ie7.css" /><![endif]-->
4
+ <title><%= @opts.font_name %> glyphs preview</title>
7
5
 
8
6
  <style>
7
+ /* Page Styles */
8
+
9
9
  * {
10
10
  -moz-box-sizing: border-box;
11
11
  -webkit-box-sizing: border-box;
@@ -86,6 +86,33 @@
86
86
  font-size: 12px;
87
87
  padding: 20px 0;
88
88
  }
89
+
90
+ /* Icon Font: <%= @opts.font_name %> */
91
+
92
+ @font-face {
93
+ font-family: "<%= @opts.font_name %>";
94
+ src: url("<%= @data[:paths][:preview_to_fonts] %>.eot");
95
+ src: url("<%= @data[:paths][:preview_to_fonts] %>.eot?#iefix") format("embedded-opentype"),
96
+ url("<%= @data[:paths][:preview_to_fonts] %>.woff") format("woff"),
97
+ url("<%= @data[:paths][:preview_to_fonts] %>.ttf") format("truetype"),
98
+ url("<%= @data[:paths][:preview_to_fonts] %>.svg#<%= @opts.font_name %>") format("svg");
99
+ font-weight: normal;
100
+ font-style: normal;
101
+ }
102
+
103
+ <%= @glyphs.map {|name| ".#{@opts.css_prefix + name}:before"}.join(",\n") %> {
104
+ font-family: "<%= @opts.font_name %>";
105
+ font-style: normal;
106
+ font-weight: normal;
107
+ font-variant: normal;
108
+ text-transform: none;
109
+ line-height: 1;
110
+ -webkit-font-smoothing: antialiased;
111
+ display: inline-block;
112
+ text-decoration: inherit;
113
+ }
114
+ <% @glyphs.each_with_index do |name, index| %>
115
+ .<%= @opts.css_prefix + name %>:before { content: "\<%= (61696+index).to_s(16) %>"; }<% end %>
89
116
  </style>
90
117
 
91
118
  <!--[if lte IE 8]><script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
@@ -93,18 +120,18 @@
93
120
 
94
121
  <body>
95
122
  <div class="container">
96
- <h1><%= @opts[:font_name] %> contains <%= @data[:glyphs].length %> glyphs:</h1>
123
+ <h1><%= @opts.font_name %> contains <%= @glyphs.length %> glyphs:</h1>
97
124
 
98
- <% @data[:glyphs].each_with_index do |name, index| %>
125
+ <% @glyphs.each_with_index do |name, index| %>
99
126
  <div class="glyph">
100
127
  <div class="preview-glyphs">
101
- <% scale.each do |n| %><i class="step <%= @opts[:css_prefix] + name %> size-<%= n %>"></i><% end %>
128
+ <% scale.each do |n| %><i class="step <%= @opts.css_prefix + name %> size-<%= n %>"></i><% end %>
102
129
  </div>
103
130
  <div class="preview-scale">
104
131
  <% scale.each do |n| %><span class="step"><%= n %></span><% end %>
105
132
  </div>
106
133
  <div class="usage">
107
- <input class="class" type="text" readonly="readonly" onClick="this.select();" value=".<%= @opts[:css_prefix] + name %>" />
134
+ <input class="class" type="text" readonly="readonly" onClick="this.select();" value=".<%= @opts.css_prefix + name %>" />
108
135
  <input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#x<%= (61696+index).to_s(16) %>;" />
109
136
  </div>
110
137
  </div>
@@ -1,20 +1,20 @@
1
1
  /*
2
- Icon Font: <%= @opts[:font_name] %>
2
+ Icon Font: <%= @opts.font_name %>
3
3
  */
4
4
 
5
5
  @font-face {
6
- font-family: "<%= @opts[:font_name] %>";
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");
6
+ font-family: "<%= @opts.font_name %>";
7
+ src: url("<%= @font_path %>.eot");
8
+ src: url("<%= @font_path %>.eot?#iefix") format("embedded-opentype"),
9
+ url("<%= @font_path %>.woff") format("woff"),
10
+ url("<%= @font_path %>.ttf") format("truetype"),
11
+ url("<%= @font_path %>.svg#<%= @opts.font_name %>") format("svg");
12
12
  font-weight: normal;
13
13
  font-style: normal;
14
14
  }
15
15
 
16
- <%= @data[:glyphs].map {|name| ".#{@opts[:css_prefix] + name}:before"}.join(",\n") %> {
17
- font-family: "<%= @opts[:font_name] %>";
16
+ <%= @glyphs.map {|name| ".#{@opts.css_prefix + name}:before"}.join(",\n") %> {
17
+ font-family: "<%= @opts.font_name %>";
18
18
  font-style: normal;
19
19
  font-weight: normal;
20
20
  font-variant: normal;
@@ -24,5 +24,5 @@
24
24
  display: inline-block;
25
25
  text-decoration: inherit;
26
26
  }
27
- <% @data[:glyphs].each_with_index do |name, index| %>
28
- .<%= @opts[:css_prefix] + name %>:before { content: "\<%= (61696+index).to_s(16) %>"; }<% end %>
27
+ <% @glyphs.each_with_index do |name, index| %>
28
+ .<%= @opts.css_prefix + name %>:before { content: "\<%= (61696+index).to_s(16) %>"; }<% end %>
@@ -1,23 +1,27 @@
1
1
  # ---------------------------------------------------------------------------- #
2
2
  # Project Info
3
- # Learn more about these options with `fontcustom help`.
3
+ # Learn more about these options by running `fontcustom help` or visit
4
+ # <http://fontcustom.com>.
4
5
  # ---------------------------------------------------------------------------- #
5
6
 
6
7
  #font_name: My Custom Font
7
8
  #file_hash: false
8
9
  #css_prefix: glyph-
9
- #preprocessor_font_path: fonts/fontcustom
10
+ #preprocessor_path: fonts/fontcustom
10
11
  #debug: true
11
12
  #verbose: false
12
13
 
13
14
 
14
15
  # ---------------------------------------------------------------------------- #
15
- # Project Directories
16
+ # Project Paths
16
17
  # 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.
18
+ # PROJECT_ROOT can be configured (absolute path recommended).
19
+ # For finer control, assign INPUT and OUTPUT as hashes instead of a strings.
20
+ # The OUPUT hash can route custom templates according to their filename.
19
21
  # ---------------------------------------------------------------------------- #
20
22
 
23
+ #project_root: some/other/place
24
+
21
25
  #input:
22
26
  # vectors: app/assets/fontcustom/vectors
23
27
  # templates: app/assets/fontcustom/templates
@@ -26,11 +30,12 @@
26
30
  # fonts: app/assets/fonts
27
31
  # css: app/assets/stylesheets
28
32
  # preview: app/views/styleguide
33
+ # my-custom-template.yml: config
29
34
 
30
35
 
31
36
  # ---------------------------------------------------------------------------- #
32
37
  # Templates
33
- # Shortcuts:
38
+ # Included in Font Custom:
34
39
  # preview, css, scss, bootstrap, bootstrap-scss, bootstrap-ie7,
35
40
  # bootstrap-ie7-scss
36
41
  # Custom templates should be saved in the INPUT[:templates] directory.
@@ -1,172 +1,51 @@
1
- require "yaml"
2
- require "thor/core_ext/hash_with_indifferent_access"
3
-
1
+ ##
2
+ # Needs access to @shell and an Options instance
3
+ # (@opts in thor, @cli_options or self in Options)
4
4
  module Fontcustom
5
- class Util
6
- class << self
7
- def check_fontforge
8
- fontforge = `which fontforge`
9
- if fontforge == "" || fontforge == "fontforge not found"
10
- raise Fontcustom::Error, "Please install fontforge first. Visit http://fontcustom.com for more details."
11
- end
12
- end
13
-
14
- # Converts all options into symbol-accessible hashes
15
- # Priority: Passed args > config file > default
16
- def collect_options(args = {})
17
- options = Fontcustom::DEFAULT_OPTIONS.clone
18
- options[:project_root] = args[:project_root] if args[:project_root]
19
-
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]
23
- options[:config] = get_config_path options
24
-
25
- if options[:config]
26
- begin
27
- config = YAML.load File.open(options[:config])
28
- options.merge! config
29
- rescue
30
- raise Fontcustom::Error, "I couldn't read your configuration file. Please check #{options[:config]} and try again."
31
- end
32
- end
33
-
34
- # Override with passed arguments
35
- args.delete(:input) unless args[:input] # allows nil input from CLI
36
- options.merge! args
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
42
- options
5
+ module Util
6
+ def check_fontforge
7
+ fontforge = `which fontforge`
8
+ if fontforge == "" || fontforge == "fontforge not found"
9
+ raise Fontcustom::Error, "Please install fontforge. Visit http://fontcustom.com for instructions."
43
10
  end
11
+ end
44
12
 
45
- def get_config_path(options)
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
60
- else
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
13
+ def say_changed(status, changed)
14
+ return unless base(:verbose)
15
+ message = changed.map { |file| relative_to_root(file) }
16
+ @shell.say_status status, message.join(" ")
17
+ end
103
18
 
104
- paths
105
- end
19
+ def say_message(status, message)
20
+ return unless base(:verbose)
21
+ @shell.say_status status, message
22
+ end
106
23
 
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]
24
+ def relative_to_root(path)
25
+ path = path.sub(base(:project_root), "")
26
+ path = path[1..-1] if path[0] == "/"
27
+ path
28
+ end
111
29
 
112
- output.each do |key, val|
113
- output[key] = File.expand_path File.join(options[:project_root], val)
114
- end
30
+ def overwrite_file(file, content = "")
31
+ File.open(file, "w") { |f| f.write(content) }
32
+ say_changed :update, [ file ]
33
+ end
115
34
 
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
- })
132
- end
133
- end
35
+ private
134
36
 
135
- # Translates shorthand to full path of packages templates, otherwise,
136
- # it checks input and pwd for the template.
137
- #
138
- # Could arguably belong in Generator::Template, however, it's nice to
139
- # be able to catch template errors before any generator runs.
140
- def get_templates(options)
141
- # ensure that preview has plain stylesheet to reference
142
- options[:templates] << "css" if options[:templates].include?("preview") && ! options[:templates].include?("css")
37
+ def base(sym)
38
+ # Generators have @opts
39
+ if @opts
40
+ @opts.send sym
143
41
 
144
- options[:templates].map do |template|
145
- case template
146
- when "preview"
147
- File.join gem_lib_path, "templates", "fontcustom-preview.html"
148
- when "css"
149
- File.join gem_lib_path, "templates", "fontcustom.css"
150
- when "scss"
151
- File.join gem_lib_path, "templates", "_fontcustom.scss"
152
- when "bootstrap"
153
- File.join gem_lib_path, "templates", "fontcustom-bootstrap.css"
154
- when "bootstrap-scss"
155
- File.join gem_lib_path, "templates", "_fontcustom-bootstrap.scss"
156
- when "bootstrap-ie7"
157
- File.join gem_lib_path, "templates", "fontcustom-bootstrap-ie7.css"
158
- when "bootstrap-ie7-scss"
159
- File.join gem_lib_path, "templates", "_fontcustom-bootstrap-ie7.scss"
160
- else
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
164
- end
165
- end
166
- end
42
+ # Options (before merge) uses @cli_options
43
+ elsif @cli_options
44
+ @cli_options[sym]
167
45
 
168
- def gem_lib_path
169
- File.expand_path(File.join(File.dirname(__FILE__)))
46
+ # Options (after merge) has its own methods
47
+ else
48
+ send sym
170
49
  end
171
50
  end
172
51
  end