fontcustom 1.2.0 → 1.3.0.beta

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 +7 -0
  2. data/CHANGELOG.md +16 -0
  3. data/CONTRIBUTING.md +35 -15
  4. data/TODO.md +20 -0
  5. data/lib/fontcustom.rb +11 -24
  6. data/lib/fontcustom/base.rb +56 -0
  7. data/lib/fontcustom/cli.rb +13 -12
  8. data/lib/fontcustom/generator/font.rb +63 -65
  9. data/lib/fontcustom/generator/template.rb +81 -52
  10. data/lib/fontcustom/manifest.rb +42 -0
  11. data/lib/fontcustom/options.rb +93 -80
  12. data/lib/fontcustom/scripts/generate.py +116 -127
  13. data/lib/fontcustom/templates/_fontcustom-rails.scss +13 -18
  14. data/lib/fontcustom/templates/_fontcustom.scss +10 -18
  15. data/lib/fontcustom/templates/fontcustom-preview.html +17 -24
  16. data/lib/fontcustom/templates/fontcustom.css +10 -18
  17. data/lib/fontcustom/templates/fontcustom.yml +3 -3
  18. data/lib/fontcustom/utility.rb +145 -0
  19. data/lib/fontcustom/version.rb +1 -1
  20. data/lib/fontcustom/watcher.rb +1 -1
  21. data/spec/fixtures/generators/.fontcustom-manifest-corrupted.json +12 -5
  22. data/spec/fixtures/generators/.fontcustom-manifest-empty.json +0 -0
  23. data/spec/fixtures/generators/.fontcustom-manifest.json +49 -14
  24. data/spec/fixtures/generators/mixed-output/fontcustom_82a59e769bc60192484f2620570bbb59.eot +0 -0
  25. data/spec/fixtures/generators/mixed-output/fontcustom_82a59e769bc60192484f2620570bbb59.svg +56 -0
  26. data/spec/fixtures/generators/mixed-output/fontcustom_82a59e769bc60192484f2620570bbb59.ttf +0 -0
  27. data/spec/fixtures/generators/mixed-output/fontcustom_82a59e769bc60192484f2620570bbb59.woff +0 -0
  28. data/spec/fixtures/sandbox/.gitkeep +0 -0
  29. data/spec/fontcustom/base_spec.rb +58 -0
  30. data/spec/fontcustom/cli_spec.rb +15 -0
  31. data/spec/fontcustom/generator/font_spec.rb +50 -220
  32. data/spec/fontcustom/generator/template_spec.rb +30 -194
  33. data/spec/fontcustom/generator/template_spec.rb.off +215 -0
  34. data/spec/fontcustom/manifest_spec.rb +16 -0
  35. data/spec/fontcustom/options_spec.rb +206 -208
  36. data/spec/fontcustom/utility_spec.rb +163 -0
  37. data/spec/fontcustom/{watcher_spec.rb → watcher_spec.rb.off} +0 -0
  38. data/spec/spec_helper.rb +77 -19
  39. metadata +44 -54
  40. data/lib/fontcustom/templates/_fontcustom-bootstrap-ie7.scss +0 -22
  41. data/lib/fontcustom/templates/_fontcustom-bootstrap.scss +0 -63
  42. data/lib/fontcustom/templates/fontcustom-bootstrap-ie7.css +0 -22
  43. data/lib/fontcustom/templates/fontcustom-bootstrap.css +0 -63
  44. data/lib/fontcustom/util.rb +0 -62
  45. data/spec/fixtures/generators/mixed-output/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.eot +0 -0
  46. data/spec/fixtures/generators/mixed-output/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.svg +0 -102
  47. data/spec/fixtures/generators/mixed-output/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.ttf +0 -0
  48. data/spec/fixtures/generators/mixed-output/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.woff +0 -0
  49. data/spec/fontcustom/util_spec.rb +0 -82
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1abf5b322a257728ac1e293a8392f3592e9954b7
4
+ data.tar.gz: cb6b2ca5e590ae76878050e2317ab7de0cd74041
5
+ SHA512:
6
+ metadata.gz: 0476cea6aef78118bf1fd85caa008d3de5b2ab465c92619a639eec104ec98178072d4f231a3d1ffee152031f28f9814ad3f2a51fc00c2c5a6a1f1312f2093be4
7
+ data.tar.gz: 40046d513e692b44bf504969844f48fe905b79b67f7cb9c5b5fe4f5b8ef3a32cc6bde44d83f6173a876956a402d1be5c9fc637b059f532aa6803055c46360155
@@ -1,3 +1,19 @@
1
+ ## 1.3.0.beta (11/25/2013)
2
+
3
+ The big news: fixed glyph code points. Automatically assigned for now, but changing them by hand is just a matter of modifying the generated `.fontcustom-manifest.json`.
4
+
5
+ Lots of internal changes / streamlining on this one. A few breaking changes (`css_prefix`, custom template syntax, possibly others). Error messages and docs are still a bit sparse — my apologies in advance.
6
+
7
+ * Fixed glyph code points ([#56](https://github.com/FontCustom/fontcustom/issues/56))
8
+ * Changes `css_prefix` to `css_selector` to allow greater flexibility ([#126](https://github.com/FontCustom/fontcustom/pull/126))
9
+ * Skips compilation if inputs have not changed (and `force` option to bypass checks)
10
+ * Adds CSS template helpers for convenience and DRYness
11
+ * Drops bootstrap templates (maintaince overhead, unsure if anyone was using them)
12
+
13
+ Next up:
14
+
15
+ * Storing relative paths in the manifest for collaborative editing ([#149](https://github.com/FontCustom/fontcustom/pull/149))
16
+
1
17
  ## 1.2.0 (11/2/2013)
2
18
 
3
19
  * Preparation for fixed glyph code points.
@@ -1,31 +1,51 @@
1
1
  ## Help make Font Custom better!
2
2
 
3
3
  This project was born out of an overheard conversation between two devs in a
4
- NYC coffee shop — it's come a long ways thanks to your support.
4
+ NYC coffee shop — it's come a long ways thanks to your support. Here's what's
5
+ on the menu:
5
6
 
6
- ### Wishlist / Roadmap
7
-
8
- * Ruby on Rails integration
9
- * Compass integration
7
+ * **Ruby on Rails integration**
8
+ * **Compass integration**
10
9
  * Base 64 encode fonts into CSS
11
10
  * Templates for LESS, stylus, etc.
12
11
  * Ligature support
13
12
  * Windows support
14
13
  * Make better use of Thor
15
14
 
16
- ### Conventions
15
+ Just [file an issue](https://github.com/FontCustom/fontcustom/issues) if you
16
+ have an idea or would like to claim one.
17
17
 
18
- We try to follow the [Github ruby styleguide](https://github.com/styleguide/ruby)
19
- as much as possible.
18
+ ### Rules of Thumb
20
19
 
21
20
  If you catch a typo or a block of code that could be more elegant — please let
22
21
  us know. No such thing as too small of an improvement.
23
22
 
24
- ### Process
23
+ * Spaces instead of tabs, please.
24
+ * Develop in a topic branch.
25
+ * Include passing tests if applicable.
26
+ * Follow the [Github ruby styleguide](https://github.com/styleguide/ruby) as
27
+ much as possible.
28
+
29
+ ### Getting Started
30
+
31
+ You'll need:
32
+
33
+ * Fontforge with Python scripting (easiest via [Homebrew](http://brew.sh/) on Mac)
34
+ * Ruby 1.9.2+ (via [rbenv](https://github.com/sstephenson/rbenv), [RVM](https://rvm.io/), etc.)
35
+ * Rubygems
36
+ * Bundler
37
+ * Rake
38
+ * Rspec
39
+
40
+ Some helpful links:
41
+
42
+ * http://createdbypete.com/articles/ruby-on-rails-development-with-mac-os-x-mountain-lion/
43
+ * http://guides.rubygems.org/make-your-own-gem/
44
+
45
+ ---
46
+
47
+ That's all there is to it. Thanks again, and please don't hesitate to reach out:
25
48
 
26
- * Visit [issues](https://github.com/FontCustom/fontcustom/issues) for ideas.
27
- * Fork the repo.
28
- * Create a topic branch. `git checkout -b my_sweet_feature`
29
- * Add your tests. Run tests with `rake`.
30
- * Develop your feature.
31
- * Once all tests are passing, submit a pull request!
49
+ [Github Issues](https://github.com/FontCustom/fontcustom/issues)<br>
50
+ [@ezYZ](https://twitter.com/ezYZ)<br>
51
+ [@endtwist](https://twitter.com/endtwist)
data/TODO.md ADDED
@@ -0,0 +1,20 @@
1
+ ## TODO
2
+
3
+ ### 1.3.0
4
+
5
+ * tests, error messages, and docs for generate.py / SVG bugs
6
+ * tests, error messages, and docs for template generator
7
+ * store relative paths in manifest (rebuild in generator/util)
8
+ * documentation for template helpers
9
+ * redirect fontcustom.com to github repo (use wiki for documentation)
10
+
11
+ ### Low Priority
12
+
13
+ * conserve code points: http://stackoverflow.com/questions/8794430/ruby-finding-lowest-free-id-in-an-id-array
14
+ * more flexible input/ouput hashes (regex or file extensions)
15
+ * sass template with variables
16
+ * less template with variables
17
+ * more robust fontforge check than `which`
18
+ * remove redundant requires
19
+ * rename options for succintness (e.g. :project_root => :root)
20
+ * trim options specs down
@@ -1,56 +1,43 @@
1
1
  require "fontcustom/version"
2
2
  require "fontcustom/error"
3
- require "fontcustom/util"
3
+ require "fontcustom/utility"
4
+ require "fontcustom/base"
5
+ require "fontcustom/manifest"
4
6
  require "fontcustom/options"
5
7
  require "fontcustom/generator/font"
6
8
  require "fontcustom/generator/template"
7
9
 
8
10
  module Fontcustom
9
- ##
10
- # Clean Ruby API to workaround Thor
11
- def compile(options)
12
- opts = Options.new options
13
- Generator::Font.start [opts]
14
- Generator::Template.start [opts]
15
- rescue Fontcustom::Error => e
16
- opts.say_message :error, e.message, :red
17
- end
18
-
19
11
  def gem_lib
20
12
  File.expand_path(File.join(File.dirname(__FILE__), "fontcustom"))
21
13
  end
22
-
23
- module_function :compile, :gem_lib
14
+ module_function :gem_lib
24
15
 
25
16
  ##
26
- # These are used in Thor CLI but overridden when the Options class is built
17
+ # Hack to get Thor to show more helpful defaults in `fontcustom help`. These
18
+ # are overwritten in Fontcustom::Options.
27
19
  EXAMPLE_OPTIONS = {
28
20
  :project_root => "`pwd`",
29
21
  :output => "PROJECT_ROOT/FONT_NAME",
30
- :config => "PROJECT_ROOT/fontcustom.yml OR PROJECT_ROOT/config/fontcustom.yml",
22
+ :config => "PROJECT_ROOT/fontcustom.yml -or- PROJECT_ROOT/config/fontcustom.yml",
31
23
  :templates => "css preview",
32
- :manifest => "CONFIG_DIR/.fontcustom-manifest.json OR PROJECT_ROOT/.fontcustom-manifest.json"
24
+ :manifest => "CONFIG_DIR/.fontcustom-manifest.json -or- PROJECT_ROOT/.fontcustom-manifest.json"
33
25
  }
34
26
 
35
27
  DEFAULT_OPTIONS = {
36
- :project_root => Dir.pwd,
28
+ :project_root => nil,
37
29
  :input => nil,
38
30
  :output => nil,
39
31
  :config => nil,
40
32
  :templates => %w|css preview|,
41
33
  :font_name => "fontcustom",
42
- :css_prefix => "icon-",
34
+ :css_selector => ".icon-{{glyph}}",
43
35
  :manifest => nil,
44
36
  :preprocessor_path => nil,
45
37
  :autowidth => false,
46
38
  :no_hash => false,
47
39
  :debug => false,
40
+ :force => false,
48
41
  :quiet => false
49
42
  }
50
-
51
- DATA_MODEL = {
52
- :fonts => [],
53
- :templates => [],
54
- :glyphs => []
55
- }
56
43
  end
@@ -0,0 +1,56 @@
1
+ require "digest/sha2"
2
+
3
+ module Fontcustom
4
+ class Base
5
+ include Utility
6
+
7
+ def initialize(cli_options)
8
+ @cli_options = cli_options
9
+ check_fontforge
10
+ init_manifest
11
+ end
12
+
13
+ def compile
14
+ @manifest[:checksum][:current] = checksum
15
+ if @options[:force] || @manifest[:checksum][:current] != @manifest[:checksum][:previous]
16
+ save_manifest
17
+ start_generators
18
+ @manifest = get_manifest
19
+ @manifest[:checksum][:previous] = @manifest[:checksum][:current]
20
+ save_manifest
21
+ else
22
+ say_message :status, "No changes detected. Skipping compilation."
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def check_fontforge
29
+ fontforge = `which fontforge`
30
+ if fontforge == "" || fontforge == "fontforge not found"
31
+ raise Fontcustom::Error, "Please install fontforge first. Visit <http://fontcustom.com> for instructions."
32
+ end
33
+ end
34
+
35
+ def init_manifest
36
+ file = @cli_options[:manifest] || File.join(Dir.pwd, ".fontcustom-manifest.json")
37
+ @options = Fontcustom::Options.new(@cli_options).options
38
+ @manifest = Fontcustom::Manifest.new(@options).manifest
39
+ end
40
+
41
+ # Calculates a hash of vectors, options, and templates (content and filenames)
42
+ def checksum
43
+ files = Dir.glob File.join(@options[:input][:vectors], "*.svg")
44
+ files += Dir.glob File.join(@options[:input][:templates], "*")
45
+ content = files.map { |file| File.read(file) }.join
46
+ content << files.join
47
+ content << @options.flatten(2).join
48
+ Digest::SHA2.hexdigest(content).to_s
49
+ end
50
+
51
+ def start_generators
52
+ Fontcustom::Generator::Font.new(@options[:manifest]).generate
53
+ Fontcustom::Generator::Template.new(@options[:manifest]).generate
54
+ end
55
+ end
56
+ end
@@ -5,7 +5,7 @@ require "fontcustom/watcher"
5
5
 
6
6
  module Fontcustom
7
7
  class CLI < Thor
8
- include Thor::Actions
8
+ include Utility
9
9
 
10
10
  default_task :show_help
11
11
 
@@ -22,17 +22,17 @@ module Fontcustom
22
22
  :default => EXAMPLE_OPTIONS[:config]
23
23
 
24
24
  class_option :templates, :aliases => "-t", :type => :array,
25
- :desc => "Space-delinated list of templates to generate alongside fonts.",
26
- :enum => %w|preview css scss scss-rails bootstrap bootstrap-scss bootstrap-ie7 bootstrap-ie7-scss|,
25
+ :desc => "Space-delinated list of files to generate alongside fonts. Use stock templates or choose your own.",
26
+ :enum => %w|preview css scss scss-rails|,
27
27
  :default => EXAMPLE_OPTIONS[:templates]
28
28
 
29
29
  class_option :font_name, :aliases => "-f", :type => :string,
30
30
  :desc => "The font's name. Also determines the file names of generated templates.",
31
31
  :default => DEFAULT_OPTIONS[:font_name]
32
32
 
33
- class_option :css_prefix, :aliases => "-p", :type => :string,
34
- :desc => "Prefix for each glyph's CSS class.",
35
- :default => DEFAULT_OPTIONS[:css_prefix]
33
+ class_option :css_selector, :aliases => "-s", :type => :string,
34
+ :desc => "Format of generated CSS selector. \"{{glyph}}\" is substituted for the glyph name.",
35
+ :default => DEFAULT_OPTIONS[:css_selector]
36
36
 
37
37
  class_option :manifest, :aliases => "-m", :type => :string,
38
38
  :desc => "Path to a manifest of generated files. Used for garbage collection.",
@@ -50,6 +50,9 @@ module Fontcustom
50
50
  class_option :debug, :aliases => "-d", :type => :boolean,
51
51
  :desc => "Display debugging messages."
52
52
 
53
+ class_option :force, :aliases => "-F", :type => :boolean,
54
+ :desc => "Forces compilation, even if inputs have not changed."
55
+
53
56
  class_option :quiet, :aliases => "-q", :type => :boolean,
54
57
  :desc => "Hide status messages."
55
58
 
@@ -60,12 +63,10 @@ module Fontcustom
60
63
 
61
64
  desc "compile [INPUT] [OPTIONS]", "Generates webfonts and templates from *.svg and *.eps files in INPUT. Default: `pwd`"
62
65
  def compile(input = nil)
63
- opts = options.merge :input => input
64
- opts = Options.new(opts)
65
- Generator::Font.start [opts]
66
- Generator::Template.start [opts]
66
+ Base.new(options.merge(:input => input)).compile
67
67
  rescue Fontcustom::Error => e
68
- opts.say_message :error, e.message, :red
68
+ say_status :error, e.message, :red
69
+ puts e.backtrace.join("\n") if options[:debug]
69
70
  end
70
71
 
71
72
  desc "watch [INPUT] [OPTIONS]", "Watches INPUT for changes and regenerates files automatically. Ctrl + C to stop. Default: `pwd`"
@@ -78,7 +79,7 @@ module Fontcustom
78
79
  opts = Options.new(opts)
79
80
  Watcher.new(opts).watch
80
81
  rescue Fontcustom::Error => e
81
- opts.say_message :error, e.message, :red
82
+ say_status :error, e.message, :red
82
83
  end
83
84
 
84
85
  desc "config [DIR]", "Generates an annotated configuration file (fontcustom.yml) in DIR. Default: `pwd`"
@@ -1,92 +1,90 @@
1
1
  require "json"
2
2
  require "open3"
3
- require "thor"
4
- require "thor/group"
5
- require "thor/actions"
6
3
 
7
4
  module Fontcustom
8
5
  module Generator
9
- class Font < Thor::Group
10
- include Util
11
- include Thor::Actions
6
+ class Font
7
+ include Utility
12
8
 
13
- # Instead of passing each option individually we're passing the entire options hash as an argument.
14
- # This is DRYier, easier to maintain.
15
- argument :opts
9
+ attr_reader :manifest, :options
16
10
 
17
- def prepare_output_dirs
18
- dirs = opts.output.values.uniq
19
- dirs.each do |dir|
20
- unless File.directory? dir
21
- empty_directory dir, :verbose => ! opts.quiet
22
- end
23
- end
11
+ def initialize(manifest)
12
+ @manifest = get_manifest(manifest)
13
+ @options = @manifest[:options]
24
14
  end
25
15
 
26
- def get_manifest
27
- if File.exists? opts.manifest
28
- begin
29
- data = File.read opts.manifest
30
- data = JSON.parse(data, :symbolize_names => true) unless data.empty?
31
- @data = data.is_a?(Hash) ? symbolize_hash(data) : Fontcustom::DATA_MODEL.dup
32
- rescue
33
- raise Fontcustom::Error, "Couldn't parse `#{relative_to_root(opts.manifest)}`. Delete it to start from scratch. Any previously generated files will need to be deleted manually."
34
- end
35
- else
36
- @data = Fontcustom::DATA_MODEL.dup
37
- end
16
+ def generate
17
+ create_output_dirs
18
+ delete_old_fonts
19
+ set_glyph_info
20
+ create_fonts
38
21
  end
39
22
 
40
- def reset_output
41
- return if @data[:fonts].empty?
42
- begin
43
- deleted = []
44
- @data[:fonts].each do |file|
45
- remove_file file, :verbose => false
46
- deleted << file
23
+ private
24
+
25
+ def create_output_dirs
26
+ dirs = @options[:output].values.uniq
27
+ dirs.each do |dir|
28
+ unless File.directory? dir
29
+ empty_directory dir, :verbose => ! @options[:quiet]
47
30
  end
48
- ensure
49
- @data[:fonts] = @data[:fonts] - deleted
50
- json = JSON.pretty_generate @data
51
- overwrite_file opts.manifest, json
52
- say_changed :delete, deleted
53
31
  end
54
32
  end
55
33
 
56
- def generate
57
- cmd = "fontforge -script #{Fontcustom.gem_lib}/scripts/generate.py #{opts.input[:vectors]} #{opts.output[:fonts]} --name #{opts.font_name}"
58
- cmd += " --autowidth" if opts.autowidth
59
- cmd += " --nohash" if opts.no_hash
60
- cmd += " --debug" if opts.debug
61
- output, err, status = execute_and_clean(cmd)
62
- @json = output.delete_at(0)
63
- say_status :debug, "#{err}\n#{' ' * 14}#{output}", :red if opts.debug
64
- raise Fontcustom::Error, "`fontforge` compilation failed. Try again with --debug for more details." unless status.success?
34
+ def delete_old_fonts
35
+ delete_from_manifest(:fonts)
65
36
  end
66
37
 
67
- def collect_data
68
- json = JSON.parse(@json, :symbolize_names => true)
69
- @data.merge! json
70
- @data[:glyphs].map! { |glyph| glyph.gsub(/\W/, "-") }
71
- @data[:fonts].map! { |font| File.join(opts.output[:fonts], font) }
72
- end
38
+ def set_glyph_info
39
+ codepoint = if ! @manifest[:glyphs].empty?
40
+ codepoints = @manifest[:glyphs].values.map { |data| data[:codepoint] }
41
+ codepoints.max + 1
42
+ else
43
+ 0xf100
44
+ end
73
45
 
74
- def announce_files
75
- say_changed :create, @data[:fonts]
76
- end
46
+ files = Dir.glob File.join(@options[:input][:vectors], "*.svg")
47
+ glyphs = {}
48
+ files.each do |file|
49
+ name = File.basename file, ".svg"
50
+ name = name.strip.gsub(/\W/, "-").downcase
51
+ glyphs[name.to_sym] = { :source => file }
52
+ end
77
53
 
78
- def save_data
79
- json = JSON.pretty_generate @data
80
- overwrite_file opts.manifest, json
81
- end
54
+ # Dir.glob returns a different order depending on ruby
55
+ # version/platform, so we have to sort it first
56
+ glyphs = Hash[glyphs.sort_by { |key, val| key.to_s }]
57
+ glyphs.each do |name, data|
58
+ if @manifest[:glyphs].has_key? name
59
+ data[:codepoint] = @manifest[:glyphs][name][:codepoint]
60
+ else
61
+ data[:codepoint] = codepoint
62
+ codepoint = codepoint + 1
63
+ end
64
+ end
82
65
 
83
- private
66
+ @manifest[:glyphs] = glyphs
67
+ save_manifest
68
+ end
84
69
 
85
- def execute_and_clean(cmd)
70
+ def create_fonts
71
+ cmd = "fontforge -script #{Fontcustom.gem_lib}/scripts/generate.py #{@options[:manifest]}"
86
72
  stdout, stderr, status = Open3::capture3(cmd)
87
73
  stdout = stdout.split("\n")
88
74
  stdout = stdout[1..-1] if stdout[0] == "CreateAllPyModules()"
89
- [stdout, stderr, status]
75
+
76
+ debug_msg = " Try again with --debug for more details."
77
+ if @options[:debug]
78
+ say_message :debug, "#{stderr}\n#{' ' * 14}#{stdout}", :red
79
+ debug_msg = ""
80
+ end
81
+
82
+ if status.success?
83
+ @manifest = get_manifest
84
+ say_changed :create, @manifest[:fonts]
85
+ else
86
+ raise Fontcustom::Error, "`fontforge` compilation failed.#{debug_msg}"
87
+ end
90
88
  end
91
89
  end
92
90
  end