fontist 1.4.0 → 1.7.1

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.
@@ -95,8 +95,10 @@ module Fontist
95
95
  styles = options.fetch(:extract_styles_from_collection, [])
96
96
 
97
97
  unless styles.empty?
98
- styles.map do |type, file|
99
- { type: type, collection: file, font: temp_resource[:filename] }
98
+ styles.map do |attributes|
99
+ filenames = temp_resource.slice(:filename, :source_filename)
100
+ Fontist::Utils::Dsl::CollectionFont.new(attributes.merge(filenames))
101
+ .attributes
100
102
  end
101
103
  end
102
104
  end
@@ -109,8 +111,11 @@ module Fontist
109
111
  end
110
112
 
111
113
  def download_file(source)
114
+ url = source[:urls].first
115
+ Fontist.ui.say(%(Downloading font "#{key}" from #{url}))
116
+
112
117
  downloaded_file = Fontist::Utils::Downloader.download(
113
- source[:urls].first,
118
+ url,
114
119
  sha: source[:sha256],
115
120
  file_size: source[:file_size],
116
121
  progress_bar: is_progress_bar_enabled
@@ -121,7 +126,33 @@ module Fontist
121
126
  end
122
127
 
123
128
  def is_progress_bar_enabled
124
- options.nil? ? false : options.fetch(:progress_bar, false)
129
+ options.nil? ? true : options.fetch(:progress_bar, true)
130
+ end
131
+
132
+ def font_file?(filename)
133
+ source_files.include?(filename)
134
+ end
135
+
136
+ def source_files
137
+ @source_files ||= fonts.flat_map do |font|
138
+ font[:styles].map do |style|
139
+ style[:source_font] || style[:font]
140
+ end
141
+ end
142
+ end
143
+
144
+ def target_filename(source_filename)
145
+ target_filenames[source_filename]
146
+ end
147
+
148
+ def target_filenames
149
+ @target_filenames ||= fonts.flat_map do |font|
150
+ font[:styles].map do |style|
151
+ source = style[:source_font] || style[:font]
152
+ target = style[:font]
153
+ [source, target]
154
+ end
155
+ end.to_h
125
156
  end
126
157
  end
127
158
  end
@@ -2,6 +2,7 @@ module Fontist
2
2
  class Formula
3
3
  def initialize(options = {})
4
4
  @font_name = options.fetch(:font_name, nil)
5
+ @style_name = options.fetch(:style_name, nil)
5
6
 
6
7
  check_and_register_font_formulas
7
8
  end
@@ -18,6 +19,10 @@ module Fontist
18
19
  new(font_name: name).find_fonts
19
20
  end
20
21
 
22
+ def self.find_styles(font, style)
23
+ new(font_name: font, style_name: style).find_styles
24
+ end
25
+
21
26
  def all
22
27
  @all ||= Fontist::Registry.instance.formulas
23
28
  end
@@ -32,9 +37,19 @@ module Fontist
32
37
  fonts.empty? ? nil : fonts
33
38
  end
34
39
 
40
+ def find_styles
41
+ formulas.values.flat_map do |formula|
42
+ formula.fonts.flat_map do |f|
43
+ f.styles.select do |s|
44
+ f.name.casecmp?(font_name) && s.type.casecmp?(style_name)
45
+ end
46
+ end
47
+ end
48
+ end
49
+
35
50
  private
36
51
 
37
- attr_reader :font_name
52
+ attr_reader :font_name, :style_name
38
53
 
39
54
  def find_formula
40
55
  find_by_key || find_by_font_name || find_by_font || []
@@ -2,9 +2,10 @@ module Fontist
2
2
  class FormulaTemplate
3
3
  def self.create_formula_class(formula)
4
4
  Class.new(FontFormula) do |klass|
5
- cleanname = formula.fonts.first.name.gsub(/ /, "")
5
+ first_font = (formula.fonts || formula.font_collections.first.fonts).first
6
+ cleanname = first_font.name.gsub(/ /, "")
6
7
  resource_name = formula.resources.to_h.keys.first
7
- font_filename = formula.fonts.first.styles.first.font
8
+ font_filename = first_font.styles.first.font
8
9
 
9
10
  key formula.key&.to_sym || formula.name.gsub(/ /, "_").downcase.to_sym
10
11
  display_progress_bar formula.display_progress_bar if formula.display_progress_bar
@@ -22,31 +23,47 @@ module Fontist
22
23
  formula.font_collections.each do |collection|
23
24
  provides_font_collection do
24
25
  filename collection.filename
26
+ source_filename collection.source_filename
25
27
 
26
28
  collection.fonts.each do |font|
27
- styles = font.styles.map { |s| [s.type, s.full_name] }.to_h
28
- provides_font font.name, extract_styles_from_collection: styles
29
+ provides_font(
30
+ font.name,
31
+ extract_styles_from_collection: font.styles.map do |style|
32
+ {
33
+ family_name: style.family_name,
34
+ style: style.type,
35
+ full_name: style.full_name,
36
+ post_script_name: style.post_script_name,
37
+ version: style.version,
38
+ description: style.description,
39
+ copyright: style.copyright,
40
+ }
41
+ end
42
+ )
29
43
  end
30
44
  end
31
45
  end
32
46
  end
33
47
 
34
- formula.fonts.each do |font|
35
- provides_font(
36
- font.name,
37
- match_styles_from_file: font.styles.map do |style|
38
- {
39
- family_name: style.family_name,
40
- style: style.type,
41
- full_name: style.full_name,
42
- post_script_name: style.post_script_name,
43
- version: style.version,
44
- description: style.description,
45
- filename: style.font,
46
- copyright: style.copyright,
47
- }
48
- end
49
- )
48
+ if formula.fonts
49
+ formula.fonts.each do |font|
50
+ provides_font(
51
+ font.name,
52
+ match_styles_from_file: font.styles.map do |style|
53
+ {
54
+ family_name: style.family_name,
55
+ style: style.type,
56
+ full_name: style.full_name,
57
+ post_script_name: style.post_script_name,
58
+ version: style.version,
59
+ description: style.description,
60
+ filename: style.font,
61
+ source_filename: style.source_font,
62
+ copyright: style.copyright,
63
+ }
64
+ end
65
+ )
66
+ end
50
67
  end
51
68
 
52
69
  klass.define_method :extract do
@@ -61,8 +78,10 @@ module Fontist
61
78
  end
62
79
  end
63
80
 
64
- formula.fonts.each do |font|
65
- match_fonts(resource, font.name)
81
+ if formula.fonts
82
+ formula.fonts.each do |font|
83
+ match_fonts(resource, font.name)
84
+ end
66
85
  end
67
86
 
68
87
  if formula.font_collections
@@ -8,10 +8,6 @@ require_relative "formula_builder"
8
8
  module Fontist
9
9
  module Import
10
10
  class CreateFormula
11
- FONT_PATTERN = /(\.ttf|\.otf)$/i.freeze
12
- FONT_COLLECTION_PATTERN = /\.ttc$/i.freeze
13
- LICENSE_PATTERN = /(OFL\.txt|UFL\.txt|LICENSE\.txt)$/i.freeze
14
-
15
11
  def initialize(url, options = {})
16
12
  @url = url
17
13
  @options = options
@@ -26,41 +22,30 @@ module Fontist
26
22
  def formula
27
23
  builder = FormulaBuilder.new
28
24
  builder.url = @url
29
- builder.archive = download(@url)
30
- builder.extractor = extractor(builder.archive)
25
+ builder.archive = archive
26
+ builder.extractor = extractor
31
27
  builder.options = @options
32
- builder.font_files = font_files(builder.extractor)
33
- builder.font_collection_files = font_collection_files(builder.extractor)
34
- builder.license_text = license_texts(builder.extractor).first
28
+ builder.font_files = extractor.font_files
29
+ builder.font_collection_files = extractor.font_collection_files
30
+ builder.license_text = extractor.license_text
35
31
  builder.formula
36
32
  end
37
33
 
38
- def download(url)
39
- return url if File.exist?(url)
40
-
41
- Fontist::Utils::Downloader.download(url, progress_bar: true).path
34
+ def extractor
35
+ @extractor ||=
36
+ RecursiveExtraction.new(archive,
37
+ subarchive: @options[:subarchive],
38
+ subdir: @options[:subdir])
42
39
  end
43
40
 
44
- def extractor(archive)
45
- RecursiveExtraction.new(archive)
41
+ def archive
42
+ @archive ||= download(@url)
46
43
  end
47
44
 
48
- def font_files(extractor)
49
- extractor.extract(FONT_PATTERN) do |path|
50
- Otf::FontFile.new(path)
51
- end
52
- end
53
-
54
- def font_collection_files(extractor)
55
- extractor.extract(FONT_COLLECTION_PATTERN) do |path|
56
- Files::CollectionFile.new(path)
57
- end
58
- end
45
+ def download(url)
46
+ return url if File.exist?(url)
59
47
 
60
- def license_texts(extractor)
61
- extractor.extract(LICENSE_PATTERN) do |path|
62
- File.read(path)
63
- end
48
+ Fontist::Utils::Downloader.download(url, progress_bar: true).path
64
49
  end
65
50
 
66
51
  def save(hash)
@@ -1,3 +1,4 @@
1
+ require "extract_ttc"
1
2
  require "fontist/import/helpers/system_helper"
2
3
  require_relative "../otf/font_file"
3
4
 
@@ -5,17 +6,20 @@ module Fontist
5
6
  module Import
6
7
  module Files
7
8
  class CollectionFile
8
- STRIP_TTC_BINARY = Fontist.root_path.join("bin", "stripttc")
9
-
10
9
  attr_reader :fonts
11
10
 
12
11
  def initialize(path)
13
12
  @path = path
14
13
  @fonts = read
14
+ @extension = "ttc"
15
15
  end
16
16
 
17
17
  def filename
18
- File.basename(@path)
18
+ File.basename(@path, ".*") + "." + @extension
19
+ end
20
+
21
+ def source_filename
22
+ File.basename(@path) unless filename == File.basename(@path)
19
23
  end
20
24
 
21
25
  private
@@ -37,10 +41,10 @@ module Fontist
37
41
  end
38
42
 
39
43
  def extract_ttfs(tmp_dir)
40
- Helpers::SystemHelper.run("#{STRIP_TTC_BINARY} #{@path}")
41
-
42
- basename = File.basename(@path, ".ttc")
43
- Dir.glob(File.join(tmp_dir, "#{basename}_[0-9][0-9].ttf"))
44
+ filenames = ExtractTtc.extract(@path)
45
+ filenames.map do |filename|
46
+ File.join(tmp_dir, filename)
47
+ end
44
48
  end
45
49
  end
46
50
  end
@@ -0,0 +1,17 @@
1
+ module Fontist
2
+ module Import
3
+ module Files
4
+ class FileRequirement
5
+ def initialize
6
+ `file -v`
7
+ rescue Errno::ENOENT
8
+ abort "`file` is not available. (Or is PATH not setup properly?)"
9
+ end
10
+
11
+ def call(path)
12
+ Helpers::SystemHelper.run("file --brief '#{path}'")
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,48 @@
1
+ require_relative "file_requirement"
2
+
3
+ module Fontist
4
+ module Import
5
+ module Files
6
+ class FontDetector
7
+ REQUIREMENTS = { file: FileRequirement.new }.freeze
8
+
9
+ FONT_LABELS = ["OpenType font data",
10
+ "TrueType Font data"].freeze
11
+
12
+ COLLECTION_LABEL = "TrueType font collection data".freeze
13
+
14
+ FONT_EXTENSIONS = {
15
+ "OpenType font data" => "otf",
16
+ "TrueType Font data" => "ttf",
17
+ "TrueType font collection data" => "ttc",
18
+ }.freeze
19
+
20
+ def self.detect(path)
21
+ brief = file_brief(path)
22
+
23
+ if brief.start_with?(*FONT_LABELS)
24
+ :font
25
+ elsif brief.start_with?(COLLECTION_LABEL)
26
+ :collection
27
+ else
28
+ :other
29
+ end
30
+ end
31
+
32
+ def self.standard_extension(path)
33
+ brief = file_brief(path)
34
+
35
+ FONT_EXTENSIONS.each do |label, extension|
36
+ return extension if brief.start_with?(label)
37
+ end
38
+
39
+ raise Errors::UnknownFontTypeError.new(path)
40
+ end
41
+
42
+ def self.file_brief(path)
43
+ REQUIREMENTS[:file].call(path)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -39,7 +39,7 @@ module Fontist
39
39
 
40
40
  def group_fonts
41
41
  files = (@font_files + @font_collection_files.map(&:fonts)).flatten
42
- raise FontNotFoundError, "No font found" if files.empty?
42
+ raise Errors::FontNotFoundError, "No font found" if files.empty?
43
43
 
44
44
  files
45
45
  end
@@ -55,10 +55,51 @@ module Fontist
55
55
  def resources
56
56
  filename = name.gsub(" ", "_") + "." + @extractor.extension
57
57
 
58
- options = { urls: [@url] + (@options[:mirror] || []),
59
- sha256: Digest::SHA256.file(@archive).to_s }
58
+ { filename => resource_options }
59
+ end
60
+
61
+ def resource_options
62
+ urls = []
63
+ sha = []
64
+ downloads do |url, path|
65
+ urls << url
66
+ sha << Digest::SHA256.file(path).to_s
67
+ end
68
+
69
+ sha = prepare_sha256(sha)
70
+
71
+ { urls: urls, sha256: sha }
72
+ end
73
+
74
+ def downloads
75
+ yield @url, @archive
76
+
77
+ mirrors.each do |url|
78
+ path = download(url)
79
+ next unless path
60
80
 
61
- { filename => options }
81
+ yield url, path
82
+ end
83
+ end
84
+
85
+ def mirrors
86
+ @options[:mirror] || []
87
+ end
88
+
89
+ def download(url)
90
+ Fontist::Utils::Downloader.download(url, progress_bar: true).path
91
+ rescue Errors::InvalidResourceError
92
+ Fontist.ui.error("WARN: a mirror is not found '#{url}'")
93
+ nil
94
+ end
95
+
96
+ def prepare_sha256(input)
97
+ output = input.uniq
98
+ return output.first if output.size == 1
99
+
100
+ checksums = output.join(", ")
101
+ Fontist.ui.error("WARN: SHA256 differs (#{checksums})")
102
+ output
62
103
  end
63
104
 
64
105
  def font_collections
@@ -66,7 +107,10 @@ module Fontist
66
107
 
67
108
  collections = @font_collection_files.map do |file|
68
109
  fonts = fonts_from_files(file.fonts, :to_collection_style)
69
- { filename: file.filename, fonts: fonts }
110
+
111
+ { filename: file.filename,
112
+ source_filename: file.source_filename,
113
+ fonts: fonts }.compact
70
114
  end
71
115
 
72
116
  collections.sort_by do |x|
@@ -106,7 +150,14 @@ module Fontist
106
150
  end
107
151
 
108
152
  def open_license
109
- return unless @license_text
153
+ unless @license_text
154
+ Fontist.ui.error("WARN: please add license manually")
155
+ return
156
+ end
157
+
158
+ Fontist.ui.error("WARN: ensure it's an open license, otherwise " \
159
+ "change the 'open_license' attribute to " \
160
+ "'requires_license_agreement'")
110
161
 
111
162
  TextHelper.cleanup(@license_text)
112
163
  end