fontist 0.4.0 → 1.3.0

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/macosx.yml +1 -1
  3. data/.github/workflows/ubuntu.yml +1 -1
  4. data/.gitignore +4 -2
  5. data/README.md +87 -25
  6. data/fontist.gemspec +1 -0
  7. data/lib/fontist.rb +30 -13
  8. data/lib/fontist/errors.rb +3 -1
  9. data/lib/fontist/font.rb +113 -0
  10. data/lib/fontist/font_formula.rb +123 -0
  11. data/lib/fontist/formula.rb +90 -0
  12. data/lib/fontist/formulas.rb +10 -5
  13. data/lib/fontist/formulas/andale_font.rb +80 -0
  14. data/lib/fontist/formulas/arial_black_font.rb +79 -0
  15. data/lib/fontist/formulas/cleartype_fonts.rb +227 -0
  16. data/lib/fontist/formulas/comic_font.rb +78 -0
  17. data/lib/fontist/formulas/courier_font.rb +68 -12
  18. data/lib/fontist/formulas/euphemia_font.rb +85 -0
  19. data/lib/fontist/formulas/georgia_font.rb +80 -0
  20. data/lib/fontist/formulas/impact_font.rb +78 -0
  21. data/lib/fontist/formulas/montserrat_font.rb +132 -0
  22. data/lib/fontist/formulas/ms_truetype_fonts.rb +125 -0
  23. data/lib/fontist/formulas/open_sans_fonts.rb +263 -0
  24. data/lib/fontist/formulas/overpass_font.rb +73 -0
  25. data/lib/fontist/formulas/source_fonts.rb +109 -0
  26. data/lib/fontist/formulas/stix_fonts.rb +108 -0
  27. data/lib/fontist/formulas/tahoma_font.rb +147 -0
  28. data/lib/fontist/formulas/webding_font.rb +78 -0
  29. data/lib/fontist/registry.rb +43 -0
  30. data/lib/fontist/{data/source.yml → system.yml} +5 -8
  31. data/lib/fontist/system_font.rb +19 -14
  32. data/lib/fontist/utils.rb +10 -0
  33. data/lib/fontist/utils/downloader.rb +79 -0
  34. data/lib/fontist/utils/dsl.rb +77 -0
  35. data/lib/fontist/utils/exe_extractor.rb +72 -0
  36. data/lib/fontist/utils/ui.rb +15 -0
  37. data/lib/fontist/utils/zip_extractor.rb +38 -0
  38. data/lib/fontist/version.rb +1 -1
  39. data/spec/fontist/font_formula_spec.rb +67 -0
  40. data/spec/fontist/font_spec.rb +113 -0
  41. data/spec/fontist/formula_spec.rb +67 -0
  42. data/spec/fontist/formulas/andale_font_spec.rb +29 -0
  43. data/spec/fontist/formulas/arial_black_font_spec.rb +29 -0
  44. data/spec/fontist/formulas/cleartype_fonts_spec.rb +38 -0
  45. data/spec/fontist/formulas/comic_font_spec.rb +29 -0
  46. data/spec/fontist/formulas/courier_font_spec.rb +18 -19
  47. data/spec/fontist/formulas/euphemia_font_spec.rb +29 -0
  48. data/spec/fontist/formulas/georgia_font_spec.rb +29 -0
  49. data/spec/fontist/formulas/impact_font_spec.rb +29 -0
  50. data/spec/fontist/formulas/montserrat_font_spec.rb +29 -0
  51. data/spec/fontist/formulas/ms_truetype_fonts_spec.rb +29 -0
  52. data/spec/fontist/formulas/open_sans_fonts_spec.rb +29 -0
  53. data/spec/fontist/formulas/overpass_font_spec.rb +29 -0
  54. data/spec/fontist/formulas/source_fonts_spec.rb +31 -0
  55. data/spec/fontist/formulas/stix_fonts_spec.rb +29 -0
  56. data/spec/fontist/formulas/tahoma_font_spec.rb +29 -0
  57. data/spec/fontist/formulas/webding_font_spec.rb +29 -0
  58. data/spec/fontist/registry_spec.rb +47 -0
  59. data/spec/fontist/system_font_spec.rb +12 -7
  60. data/spec/fontist/{downloader_spec.rb → utils/downloader_spec.rb} +6 -5
  61. data/spec/spec_helper.rb +4 -2
  62. data/spec/support/fontist_helper.rb +4 -2
  63. metadata +62 -27
  64. data/lib/fontist/data/formulas/courier.yml +0 -26
  65. data/lib/fontist/data/formulas/ms_system.yml +0 -68
  66. data/lib/fontist/data/formulas/ms_vista.yml +0 -118
  67. data/lib/fontist/data/formulas/source_font.yml +0 -163
  68. data/lib/fontist/downloader.rb +0 -70
  69. data/lib/fontist/finder.rb +0 -45
  70. data/lib/fontist/formula_finder.rb +0 -94
  71. data/lib/fontist/formulas/base.rb +0 -72
  72. data/lib/fontist/formulas/helpers/exe_extractor.rb +0 -45
  73. data/lib/fontist/formulas/helpers/zip_extractor.rb +0 -36
  74. data/lib/fontist/formulas/ms_system.rb +0 -29
  75. data/lib/fontist/formulas/ms_vista.rb +0 -42
  76. data/lib/fontist/formulas/source_font.rb +0 -25
  77. data/lib/fontist/installer.rb +0 -42
  78. data/lib/fontist/source.rb +0 -58
  79. data/spec/fontist/finder_spec.rb +0 -41
  80. data/spec/fontist/formula_finder_spec.rb +0 -54
  81. data/spec/fontist/formulas/ms_system_spec.rb +0 -31
  82. data/spec/fontist/formulas/ms_vista_spec.rb +0 -27
  83. data/spec/fontist/formulas/source_font_spec.rb +0 -18
  84. data/spec/fontist/installer_spec.rb +0 -48
  85. data/spec/fontist/source_spec.rb +0 -24
@@ -6,18 +6,15 @@ system:
6
6
  windows:
7
7
  paths:
8
8
  - C:/Windows/Fonts/**/**.{ttc,ttf}
9
+ - C:/Users/{username}/AppData/Local/Microsoft/Windows/Fonts/**/**.{ttc,ttf}
9
10
 
10
- macosx:
11
+ macos:
11
12
  paths:
13
+ - /Library/Fonts/**/**.{ttf,ttc}
12
14
  - /System/Library/Fonts/**/**.{ttf,ttc}
15
+ - /Users/{username}/Library/Fonts/**.{ttf,ttc}
16
+ - /Applications/Microsoft**/Contents/Resources/**/**.{ttf,ttc}
13
17
 
14
18
  unix:
15
19
  paths:
16
20
  - /usr/share/fonts/**/**.{ttf,ttc}
17
-
18
- remote:
19
- formulas:
20
- - ./formulas/ms_vista.yml
21
- - ./formulas/ms_system.yml
22
- - ./formulas/source_font.yml
23
- - ./formulas/courier.yml
@@ -3,8 +3,6 @@ module Fontist
3
3
  def initialize(font:, sources: nil)
4
4
  @font = font
5
5
  @user_sources = sources || []
6
-
7
- check_or_create_fontist_path
8
6
  end
9
7
 
10
8
  def self.find(font, sources: [])
@@ -22,33 +20,32 @@ module Fontist
22
20
 
23
21
  attr_reader :font, :user_sources
24
22
 
25
- def check_or_create_fontist_path
26
- unless fontist_fonts_path.exist?
27
- require "fileutils"
28
- FileUtils.mkdir_p(fontist_fonts_path)
23
+ def normalize_default_paths
24
+ @normalize_default_paths ||= default_sources["paths"].map do |path|
25
+ require "etc"
26
+ passwd = Etc.getpwuid
27
+
28
+ passwd ? path.gsub("{username}", passwd.name) : path
29
29
  end
30
30
  end
31
31
 
32
32
  def font_paths
33
33
  Dir.glob((
34
34
  user_sources +
35
- default_sources["paths"] +
35
+ normalize_default_paths +
36
36
  [fontist_fonts_path.join("**")]
37
37
  ).flatten.uniq)
38
38
  end
39
39
 
40
40
  def lookup_using_font_name
41
- font_names = map_name_to_valid_font_names
42
- font_paths.grep(/#{font_names.join("|")}/i) if font_names
41
+ font_names = map_name_to_valid_font_names || []
42
+ font_paths.grep(/#{font_names.join("|")}/i) unless font_names.empty?
43
43
  end
44
44
 
45
45
  def fontist_fonts_path
46
46
  @fontist_fonts_path ||= Fontist.fonts_path
47
47
  end
48
48
 
49
- def default_sources
50
- @default_sources ||= Source.all.system[user_os.to_s]
51
- end
52
49
 
53
50
  def user_os
54
51
  @user_os ||= (
@@ -57,7 +54,7 @@ module Fontist
57
54
  when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
58
55
  :windows
59
56
  when /darwin|mac os/
60
- :macosx
57
+ :macos
61
58
  when /linux/
62
59
  :linux
63
60
  when /solaris|bsd/
@@ -69,8 +66,16 @@ module Fontist
69
66
  end
70
67
 
71
68
  def map_name_to_valid_font_names
72
- fonts = FormulaFinder.find_fonts(font)
69
+ fonts = Formula.find_fonts(font)
73
70
  fonts.map { |font| font.styles.map(&:font) }.flatten if fonts
74
71
  end
72
+
73
+ def system_path_file
74
+ File.open(Fontist.lib_path.join("fontist", "system.yml"))
75
+ end
76
+
77
+ def default_sources
78
+ @default_sources ||= YAML.load(system_path_file)["system"][user_os.to_s]
79
+ end
75
80
  end
76
81
  end
@@ -0,0 +1,10 @@
1
+ require "fontist/utils/ui"
2
+ require "fontist/utils/dsl"
3
+ require "fontist/utils/downloader"
4
+ require "fontist/utils/zip_extractor"
5
+ require "fontist/utils/exe_extractor"
6
+
7
+ module Fontist
8
+ module Utils
9
+ end
10
+ end
@@ -0,0 +1,79 @@
1
+ module Fontist
2
+ module Utils
3
+ class Downloader
4
+ def initialize(file, file_size: nil, sha: nil, progress_bar: nil)
5
+ # TODO: If the first mirror fails, try the second one
6
+ @file = file
7
+ @sha = [sha].flatten.compact
8
+ @progress_bar = set_progress_bar(progress_bar)
9
+ @file_size = (file_size || default_file_size).to_i
10
+ end
11
+
12
+ def download
13
+ file = download_file
14
+
15
+ if !sha.empty? && !sha.include?(Digest::SHA256.file(file).to_s)
16
+ raise(Fontist::Errors::TamperedFileError.new(
17
+ "The downloaded file from #{@file} doesn't " \
18
+ "match with the expected sha256 checksum!"
19
+ ))
20
+ end
21
+
22
+ file
23
+ end
24
+
25
+ def self.download(file, options = {})
26
+ new(file, options).download
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :file, :sha, :file_size
32
+
33
+ def default_file_size
34
+ 5 * byte_to_megabyte
35
+ end
36
+
37
+ def byte_to_megabyte
38
+ @byte_to_megabyte ||= 1024 * 1024
39
+ end
40
+
41
+ def download_path
42
+ options[:download_path] || Fontist.root_path.join("tmp")
43
+ end
44
+
45
+ def set_progress_bar(progress_bar)
46
+ ENV.fetch("TEST_ENV", "") === "CI" ? false : progress_bar
47
+ end
48
+
49
+ def download_file
50
+ bar = ProgressBar.new(file_size / byte_to_megabyte)
51
+
52
+ Down.download(
53
+ @file,
54
+ open_timeout: 10,
55
+ read_timeout: 10,
56
+ progress_proc: -> (progress) {
57
+ bar.increment(progress / byte_to_megabyte) if @progress_bar === true
58
+ }
59
+ )
60
+
61
+ rescue Down::NotFound
62
+ raise(Fontist::Errors::InvalidResourceError.new("Invalid URL: #{@file}"))
63
+ end
64
+ end
65
+
66
+ class ProgressBar
67
+ def initialize(total)
68
+ @counter = 1
69
+ @total = total
70
+ end
71
+
72
+ def increment(progress)
73
+ complete = sprintf("%#.2f%%", ((@counter.to_f / @total.to_f) * 100))
74
+ print "\r\e[0KDownloads: #{@counter}MB/#{@total}MB (#{complete})"
75
+ @counter = progress
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,77 @@
1
+ module Fontist
2
+ module Utils
3
+ module Dsl
4
+ def key(key)
5
+ instance.key = key
6
+ end
7
+
8
+ def desc(description)
9
+ instance.description = description
10
+ end
11
+
12
+ def homepage(homepage)
13
+ instance.homepage = homepage
14
+ end
15
+
16
+ def resource(resource_name, &block)
17
+ instance.resources[resource_name] ||= {}
18
+ instance.temp_resource = instance.resources[resource_name]
19
+
20
+ yield(block) if block_given?
21
+ instance.temp_resource = {}
22
+ end
23
+
24
+ def url(url)
25
+ instance.temp_resource.merge!(urls: [url])
26
+ end
27
+
28
+ def urls(urls = [])
29
+ instance.temp_resource.merge!(urls: urls)
30
+ end
31
+
32
+ def sha256(sha256)
33
+ instance.temp_resource.merge!(sha256: sha256)
34
+ end
35
+
36
+ def file_size(file_size)
37
+ instance.temp_resource.merge!(file_size: file_size )
38
+ end
39
+
40
+ def provides_font_collection(name = nil, &block)
41
+ instance.temp_resource = {}
42
+ yield(block) if block_given?
43
+ instance.temp_resource = {}
44
+ end
45
+
46
+ def filename(name)
47
+ instance.temp_resource.merge!(filename: name)
48
+ end
49
+
50
+ def provides_font(font, options = {})
51
+ font_styles = instance.extract_font_styles(options)
52
+ instance.font_list.push(name: font, styles: font_styles)
53
+ end
54
+
55
+ def test
56
+ end
57
+
58
+ def requires_license_agreement(license)
59
+ instance.license = license
60
+ instance.license_required = true
61
+ end
62
+
63
+ def open_license(license)
64
+ instance.license = license
65
+ instance.license_required = false
66
+ end
67
+
68
+ def license_url(url)
69
+ instance.license_url = url
70
+ end
71
+
72
+ def display_progress_bar(value )
73
+ instance.options = (instance.options || {}).merge(progress_bar: value )
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,72 @@
1
+ module Fontist
2
+ module Utils
3
+ module ExeExtractor
4
+ def cab_extract(exe_file, download: true, font_ext: /.tt|.ttc/i)
5
+ download = @downloaded === true ? false : download
6
+
7
+ exe_file = download_file(exe_file).path if download
8
+ cab_file = decompressor.search(exe_file)
9
+ cabbed_fonts = grep_fonts(cab_file.files, font_ext) || []
10
+ fonts_paths = extract_cabbed_fonts_to_assets(cabbed_fonts)
11
+
12
+ yield(fonts_paths) if block_given?
13
+ end
14
+
15
+ def exe_extract(source)
16
+ cab_file = decompressor.search(download_file(source).path)
17
+ yield(build_cab_file_hash(cab_file.files)) if block_given?
18
+ end
19
+
20
+ private
21
+
22
+ def decompressor
23
+ @decompressor ||= (
24
+ require "libmspack"
25
+ LibMsPack::CabDecompressor.new
26
+ )
27
+ end
28
+
29
+ def grep_fonts(file, font_ext)
30
+ Array.new.tap do |fonts|
31
+ while file
32
+ fonts.push(file) if file.filename.match(font_ext)
33
+ file = file.next
34
+ end
35
+ end
36
+ end
37
+
38
+ def extract_cabbed_fonts_to_assets(cabbed_fonts)
39
+ Array.new.tap do |fonts|
40
+ cabbed_fonts.each do |font|
41
+ font_path = fonts_path.join(font.filename).to_s
42
+ decompressor.extract(font, font_path)
43
+
44
+ fonts.push(font_path)
45
+ end
46
+ end
47
+ end
48
+
49
+ def build_cab_file_hash(file)
50
+ Hash.new.tap do |cab_files|
51
+ while file
52
+ filename = file.filename
53
+ if filename.include?("cab")
54
+ file_path = temp_dir.join(filename).to_s
55
+
56
+ decompressor.extract(file, file_path)
57
+ cab_files[filename.to_s] = file_path
58
+ end
59
+
60
+ file = file.next
61
+ end
62
+ end
63
+ end
64
+
65
+ def temp_dir
66
+ @temp_dir ||= raise(
67
+ NotImplementedError.new("You must implement this method"),
68
+ )
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,15 @@
1
+ require "thor"
2
+
3
+ module Fontist
4
+ module Utils
5
+ class UI < Thor
6
+ def self.say(message)
7
+ new.say(message)
8
+ end
9
+
10
+ def self.ask(message, options = {})
11
+ new.ask(message, options)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,38 @@
1
+ require "zip"
2
+ require "pathname"
3
+
4
+ module Fontist
5
+ module Utils
6
+ module ZipExtractor
7
+ def zip_extract(resource, download: true, fonts_sub_dir: "")
8
+ zip_file = download_file(resource) if download
9
+ zip_file ||= resource.urls.first
10
+
11
+ fonts_paths = unzip_fonts(zip_file, fonts_sub_dir)
12
+ block_given? ? yield(fonts_paths) : fonts_paths
13
+ end
14
+
15
+ alias_method :unzip, :zip_extract
16
+
17
+ private
18
+
19
+ def unzip_fonts(file, fonts_sub_dir = "")
20
+ Zip.on_exists_proc = true
21
+ Array.new.tap do |fonts|
22
+
23
+ Zip::File.open(file) do |zip_file|
24
+ zip_file.glob("#{fonts_sub_dir}*.{ttf,ttc,otf}").each do |entry|
25
+ if entry.name
26
+ filename = Pathname.new(entry.name).basename
27
+ font_path = fonts_path.join(filename.to_s)
28
+ fonts.push(font_path.to_s)
29
+
30
+ entry.extract(font_path)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,3 +1,3 @@
1
1
  module Fontist
2
- VERSION = "0.4.0".freeze
2
+ VERSION = "1.3.0".freeze
3
3
  end
@@ -0,0 +1,67 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "Fontist::Formulas::DemoFormula" do
4
+ describe "initialization" do
5
+ it "registers formula resources through the DSL" do
6
+ formula = Fontist::Formulas::DemoFormula.instance
7
+ resource = formula.resources["demo-formula"]
8
+ demo_font = formula.font_list.first
9
+
10
+ expect(formula.key).to eq(:demo_formula)
11
+ expect(formula.license_required).to be_truthy
12
+ expect(formula.description).to eq("Demo font formula")
13
+ expect(formula.license).to eq("Vendor specific font licences")
14
+ expect(formula.homepage).to eq("https://github.com/fontist/fontist")
15
+
16
+ expect(resource[:file_size]).to eq("1234567890")
17
+ expect(resource[:urls].first).to eq("https://github.com/fontist/fontist")
18
+ expect(resource[:sha256]).to eq("594e0f42e6581add4dead70c1dfb9")
19
+
20
+ expect(demo_font[:styles].count).to eq(2)
21
+ expect(demo_font[:name]).to eq("Demo font")
22
+ expect(demo_font[:styles].first[:font]).to eq("demo-font.ttf")
23
+ end
24
+ end
25
+
26
+ describe "method invokation" do
27
+ it "invokes the correct method for installation" do
28
+ expect {
29
+ Fontist::Formulas::DemoFormula.fetch_font("Demo font", confirmation: "yes")
30
+ }.not_to raise_error
31
+ end
32
+ end
33
+
34
+ module Fontist
35
+ module Formulas
36
+ class DemoFormula < FontFormula
37
+ key :demo_formula
38
+ desc "Demo font formula"
39
+ homepage "https://github.com/fontist/fontist"
40
+ requires_license_agreement "Vendor specific font licences"
41
+
42
+ resource "demo-formula" do
43
+ urls [ "https://github.com/fontist/fontist" ]
44
+ sha256 "594e0f42e6581add4dead70c1dfb9"
45
+ file_size "1234567890"
46
+ end
47
+
48
+ provides_font "Demo font", match_styles_from_file: {
49
+ "Regular" => "demo-font.ttf",
50
+ "Italic" => "demo-fonti.ttf"
51
+ }
52
+
53
+ provides_font_collection("Meiryo Bold") do |coll|
54
+ filename "demo-font.ttc"
55
+ provides_font "Demo collection", extract_styles_from_collection: {
56
+ "Regular" => "demo-col-font.ttf",
57
+ "Italic" => "demo-col-fonti.ttf"
58
+ }
59
+ end
60
+
61
+ def extract
62
+ []
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end