fontist 0.3.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
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