fontist 0.3.0 → 1.2.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.
Files changed (75) 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 +91 -5
  6. data/lib/fontist.rb +26 -12
  7. data/lib/fontist/errors.rb +3 -1
  8. data/lib/fontist/font.rb +78 -0
  9. data/lib/fontist/font_formula.rb +123 -0
  10. data/lib/fontist/formula.rb +90 -0
  11. data/lib/fontist/formulas.rb +10 -3
  12. data/lib/fontist/formulas/andale_font.rb +80 -0
  13. data/lib/fontist/formulas/arial_black_font.rb +79 -0
  14. data/lib/fontist/formulas/cleartype_fonts.rb +227 -0
  15. data/lib/fontist/formulas/comic_font.rb +78 -0
  16. data/lib/fontist/formulas/courier_font.rb +81 -0
  17. data/lib/fontist/formulas/euphemia_font.rb +85 -0
  18. data/lib/fontist/formulas/georgia_font.rb +80 -0
  19. data/lib/fontist/formulas/impact_font.rb +78 -0
  20. data/lib/fontist/formulas/montserrat_font.rb +132 -0
  21. data/lib/fontist/formulas/ms_truetype_fonts.rb +125 -0
  22. data/lib/fontist/formulas/open_sans_fonts.rb +263 -0
  23. data/lib/fontist/formulas/overpass_font.rb +73 -0
  24. data/lib/fontist/formulas/source_fonts.rb +109 -0
  25. data/lib/fontist/formulas/stix_fonts.rb +108 -0
  26. data/lib/fontist/formulas/tahoma_font.rb +147 -0
  27. data/lib/fontist/formulas/webding_font.rb +78 -0
  28. data/lib/fontist/registry.rb +42 -0
  29. data/lib/fontist/{data/source.yml → system.yml} +5 -6
  30. data/lib/fontist/system_font.rb +27 -11
  31. data/lib/fontist/utils.rb +9 -0
  32. data/lib/fontist/utils/downloader.rb +75 -0
  33. data/lib/fontist/utils/dsl.rb +77 -0
  34. data/lib/fontist/utils/exe_extractor.rb +72 -0
  35. data/lib/fontist/utils/zip_extractor.rb +38 -0
  36. data/lib/fontist/version.rb +1 -1
  37. data/spec/fontist/font_formula_spec.rb +67 -0
  38. data/spec/fontist/font_spec.rb +87 -0
  39. data/spec/fontist/formula_spec.rb +67 -0
  40. data/spec/fontist/formulas/andale_font_spec.rb +29 -0
  41. data/spec/fontist/formulas/arial_black_font_spec.rb +29 -0
  42. data/spec/fontist/formulas/cleartype_fonts_spec.rb +38 -0
  43. data/spec/fontist/formulas/comic_font_spec.rb +29 -0
  44. data/spec/fontist/formulas/courier_font_spec.rb +29 -0
  45. data/spec/fontist/formulas/euphemia_font_spec.rb +29 -0
  46. data/spec/fontist/formulas/georgia_font_spec.rb +29 -0
  47. data/spec/fontist/formulas/impact_font_spec.rb +29 -0
  48. data/spec/fontist/formulas/montserrat_font_spec.rb +29 -0
  49. data/spec/fontist/formulas/ms_truetype_fonts_spec.rb +29 -0
  50. data/spec/fontist/formulas/open_sans_fonts_spec.rb +29 -0
  51. data/spec/fontist/formulas/overpass_font_spec.rb +29 -0
  52. data/spec/fontist/formulas/source_fonts_spec.rb +31 -0
  53. data/spec/fontist/formulas/stix_fonts_spec.rb +29 -0
  54. data/spec/fontist/formulas/tahoma_font_spec.rb +29 -0
  55. data/spec/fontist/formulas/webding_font_spec.rb +29 -0
  56. data/spec/fontist/registry_spec.rb +47 -0
  57. data/spec/fontist/system_font_spec.rb +17 -1
  58. data/spec/fontist/{downloader_spec.rb → utils/downloader_spec.rb} +6 -5
  59. data/spec/spec_helper.rb +4 -2
  60. data/spec/support/fontist_helper.rb +4 -2
  61. metadata +50 -20
  62. data/lib/fontist/data/formulas/ms_vista.yml +0 -39
  63. data/lib/fontist/data/formulas/source_font.yml +0 -51
  64. data/lib/fontist/downloader.rb +0 -70
  65. data/lib/fontist/finder.rb +0 -47
  66. data/lib/fontist/formulas/base.rb +0 -25
  67. data/lib/fontist/formulas/ms_vista.rb +0 -74
  68. data/lib/fontist/formulas/source_font.rb +0 -48
  69. data/lib/fontist/installer.rb +0 -47
  70. data/lib/fontist/source.rb +0 -58
  71. data/spec/fontist/finder_spec.rb +0 -41
  72. data/spec/fontist/formulas/ms_vista_spec.rb +0 -27
  73. data/spec/fontist/formulas/source_font_spec.rb +0 -18
  74. data/spec/fontist/installer_spec.rb +0 -48
  75. data/spec/fontist/source_spec.rb +0 -24
@@ -6,16 +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/source_font.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: [])
@@ -13,6 +11,8 @@ module Fontist
13
11
 
14
12
  def find
15
13
  paths = font_paths.grep(/#{font}/i)
14
+ paths = lookup_using_font_name || [] if paths.empty?
15
+
16
16
  paths.empty? ? nil : paths
17
17
  end
18
18
 
@@ -20,28 +20,32 @@ module Fontist
20
20
 
21
21
  attr_reader :font, :user_sources
22
22
 
23
- def check_or_create_fontist_path
24
- unless fontist_fonts_path.exist?
25
- require "fileutils"
26
- 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
27
29
  end
28
30
  end
29
31
 
30
32
  def font_paths
31
33
  Dir.glob((
32
34
  user_sources +
33
- default_sources["paths"] +
35
+ normalize_default_paths +
34
36
  [fontist_fonts_path.join("**")]
35
37
  ).flatten.uniq)
36
38
  end
37
39
 
40
+ def lookup_using_font_name
41
+ font_names = map_name_to_valid_font_names || []
42
+ font_paths.grep(/#{font_names.join("|")}/i) unless font_names.empty?
43
+ end
44
+
38
45
  def fontist_fonts_path
39
46
  @fontist_fonts_path ||= Fontist.fonts_path
40
47
  end
41
48
 
42
- def default_sources
43
- @default_sources ||= Source.all.system[user_os.to_s]
44
- end
45
49
 
46
50
  def user_os
47
51
  @user_os ||= (
@@ -50,7 +54,7 @@ module Fontist
50
54
  when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
51
55
  :windows
52
56
  when /darwin|mac os/
53
- :macosx
57
+ :macos
54
58
  when /linux/
55
59
  :linux
56
60
  when /solaris|bsd/
@@ -61,5 +65,17 @@ module Fontist
61
65
  )
62
66
  end
63
67
 
68
+ def map_name_to_valid_font_names
69
+ fonts = Formula.find_fonts(font)
70
+ fonts.map { |font| font.styles.map(&:font) }.flatten if fonts
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
64
80
  end
65
81
  end
@@ -0,0 +1,9 @@
1
+ require "fontist/utils/dsl"
2
+ require "fontist/utils/downloader"
3
+ require "fontist/utils/zip_extractor"
4
+ require "fontist/utils/exe_extractor"
5
+
6
+ module Fontist
7
+ module Utils
8
+ end
9
+ end
@@ -0,0 +1,75 @@
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
+ @progress_bar = progress_bar
8
+ @sha = [sha].flatten.compact
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 download_file
46
+ bar = ProgressBar.new(file_size / byte_to_megabyte)
47
+
48
+ Down.download(
49
+ @file,
50
+ open_timeout: 10,
51
+ read_timeout: 10,
52
+ progress_proc: -> (progress) {
53
+ bar.increment(progress / byte_to_megabyte) if @progress_bar === true
54
+ }
55
+ )
56
+
57
+ rescue Down::NotFound
58
+ raise(Fontist::Errors::InvalidResourceError.new("Invalid URL: #{@file}"))
59
+ end
60
+ end
61
+
62
+ class ProgressBar
63
+ def initialize(total)
64
+ @counter = 1
65
+ @total = total
66
+ end
67
+
68
+ def increment(progress)
69
+ complete = sprintf("%#.2f%%", ((@counter.to_f / @total.to_f) * 100))
70
+ print "\r\e[0KDownloads: #{@counter}MB/#{@total}MB (#{complete})"
71
+ @counter = progress
72
+ end
73
+ end
74
+ end
75
+ 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,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.3.0".freeze
2
+ VERSION = "1.2.1".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