jekyll-favicon 0.2.7 → 1.0.0.pre.3

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 (65) hide show
  1. checksums.yaml +5 -5
  2. data/.devcontainer/Dockerfile +22 -0
  3. data/.devcontainer/devcontainer.json +42 -0
  4. data/.github/ISSUE_TEMPLATE/bug_report.md +10 -13
  5. data/.github/PULL_REQUEST_TEMPLATE.md +11 -9
  6. data/.github/workflows/gem-push.yml +40 -0
  7. data/.github/workflows/test.yml +38 -0
  8. data/.gitignore +4 -0
  9. data/.reek.yml +25 -0
  10. data/.vscode/launch.json +16 -0
  11. data/.vscode/settings.json +7 -0
  12. data/.vscode/tasks.json +15 -0
  13. data/CHANGELOG.md +38 -0
  14. data/Gemfile +3 -1
  15. data/README.md +77 -22
  16. data/Rakefile +9 -7
  17. data/bin/console +1 -0
  18. data/bin/debug +22 -0
  19. data/config/jekyll/favicon.yml +115 -0
  20. data/config/jekyll/favicon/static_file.yml +3 -0
  21. data/config/jekyll/favicon/static_file/convertible.yml +41 -0
  22. data/config/jekyll/favicon/static_file/mutable.yml +22 -0
  23. data/config/jekyll/favicon/static_file/referenceable.yml +15 -0
  24. data/config/jekyll/favicon/static_file/sourceable.yml +3 -0
  25. data/config/jekyll/favicon/static_file/taggable.yml +22 -0
  26. data/jekyll-favicon.gemspec +24 -24
  27. data/lib/jekyll-favicon.rb +7 -16
  28. data/lib/jekyll/favicon.rb +19 -16
  29. data/lib/jekyll/favicon/configuration.rb +73 -0
  30. data/lib/jekyll/favicon/configuration/defaults.rb +49 -0
  31. data/lib/jekyll/favicon/generator.rb +10 -84
  32. data/lib/jekyll/favicon/hooks.rb +12 -10
  33. data/lib/jekyll/favicon/static_data_file.rb +17 -0
  34. data/lib/jekyll/favicon/static_file.rb +97 -0
  35. data/lib/jekyll/favicon/static_file/convertible.rb +129 -0
  36. data/lib/jekyll/favicon/static_file/mutable.rb +81 -0
  37. data/lib/jekyll/favicon/static_file/referenceable.rb +22 -0
  38. data/lib/jekyll/favicon/static_file/sourceable.rb +73 -0
  39. data/lib/jekyll/favicon/static_file/taggable.rb +53 -0
  40. data/lib/jekyll/favicon/static_graphic_file.rb +21 -0
  41. data/lib/jekyll/favicon/tag.rb +14 -17
  42. data/lib/jekyll/favicon/utils.rb +48 -0
  43. data/lib/jekyll/favicon/utils/configuration/compact.rb +58 -0
  44. data/lib/jekyll/favicon/utils/configuration/merge.rb +70 -0
  45. data/lib/jekyll/favicon/utils/configuration/patch.rb +49 -0
  46. data/lib/jekyll/favicon/utils/convert.rb +39 -0
  47. data/lib/jekyll/favicon/utils/tag.rb +70 -0
  48. data/lib/jekyll/favicon/version.rb +3 -1
  49. metadata +69 -67
  50. data/.rubocop.yml +0 -5
  51. data/.ruby-version +0 -1
  52. data/.travis.yml +0 -21
  53. data/Gemfile.lock +0 -97
  54. data/lib/browserconfig.rb +0 -54
  55. data/lib/hash.rb +0 -12
  56. data/lib/image.rb +0 -33
  57. data/lib/jekyll/favicon/config/defaults.yml +0 -54
  58. data/lib/jekyll/favicon/icon.rb +0 -73
  59. data/lib/jekyll/favicon/metadata.rb +0 -12
  60. data/lib/jekyll/favicon/templates/chrome.html.erb +0 -5
  61. data/lib/jekyll/favicon/templates/classic.html.erb +0 -8
  62. data/lib/jekyll/favicon/templates/ie.html.erb +0 -4
  63. data/lib/jekyll/favicon/templates/safari.html.erb +0 -8
  64. data/lib/string.rb +0 -14
  65. data/lib/webmanifest.rb +0 -30
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
5
+ module Jekyll
6
+ module Favicon
7
+ ROOT = Pathname.new File.dirname(File.dirname(File.dirname(File.dirname(__dir__))))
8
+
9
+ module Configuration
10
+ # Create configurable for include
11
+ module Defaults
12
+ def self.included(base)
13
+ *modules, class_or_module_name = base_name_to_parts base.name
14
+ method_name = "#{class_or_module_name}_defaults"
15
+ define_defaults base, method_name do
16
+ Defaults.load_defaults(*modules, class_or_module_name)
17
+ end
18
+ end
19
+
20
+ def self.load_defaults(*parts)
21
+ load_file "config", *parts
22
+ end
23
+
24
+ def self.load_file(*parts)
25
+ path = Favicon::ROOT.join(*parts).to_s
26
+ path = "#{path}.yml"
27
+ YAML.load_file path
28
+ end
29
+
30
+ def self.define_defaults(base, method_name, &block)
31
+ base.define_singleton_method("defaults", &block)
32
+ define_method(method_name, &block)
33
+ end
34
+
35
+ def self.base_name_to_parts(name)
36
+ name.split("::").collect do |module_or_class|
37
+ camelcase_to_snakecase module_or_class
38
+ end
39
+ end
40
+
41
+ def self.camelcase_to_snakecase(camelcase)
42
+ camelcase.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
43
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
44
+ .downcase
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,91 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jekyll/plugin"
4
+ require "jekyll/generator"
5
+ require "jekyll/favicon"
6
+
1
7
  module Jekyll
2
8
  module Favicon
3
- # Extended generator that creates all the stastic icons and metadata files
9
+ # New generator that creates all the stastic icons and metadata files
4
10
  class Generator < Jekyll::Generator
5
- priority :high
6
-
7
- attr_accessor :template
8
-
9
11
  def generate(site)
10
- @site = site
11
- if File.file? source_path Favicon.config['source']
12
- @template = favicon_tempfile source_path Favicon.config['source']
13
- generate_icons && generate_metadata
14
- else
15
- Jekyll.logger.warn 'Jekyll::Favicon: Missing ' \
16
- "#{Favicon.config['source']}, not generating " \
17
- 'favicons.'
18
- end
19
- end
20
-
21
- def clean
22
- return unless @template
23
- @template.close
24
- @template.unlink
25
- end
26
-
27
- private
28
-
29
- def source_path(path = nil)
30
- File.join(*[@site.source, path].compact)
31
- end
32
-
33
- def favicon_tempfile(source)
34
- tempfile = Tempfile.new(['favicon-template', '.png'])
35
- options = { background: 'none' }
36
- if source.svg?
37
- options[:density] = Favicon.config['svg']['density']
38
- options[:resize] = Favicon.config['svg']['dimensions']
39
- elsif source.png?
40
- options[:resize] = Favicon.config['png']['dimensions']
41
- end
42
- Image.convert source, tempfile.path, options
43
- tempfile
44
- end
45
-
46
- def generate_icons
47
- @site.static_files.push ico_icon
48
- @site.static_files.push(*png_icons)
49
- @site.static_files.push(*svg_icons)
50
- end
51
-
52
- def ico_icon
53
- target = Favicon.config['ico']['target']
54
- Icon.new @site, Favicon.config['source'], @template.path, target
55
- end
56
-
57
- def png_icons
58
- Favicon.config.deep_find('sizes').uniq.collect do |size|
59
- target = File.join Favicon.config['path'], "favicon-#{size}.png"
60
- Icon.new @site, Favicon.config['source'], @template.path, target
61
- end
62
- end
63
-
64
- def svg_icons
65
- return [] unless Favicon.config['source'].svg?
66
- source = Favicon.config['source']
67
- %w[safari-pinned-tab.svg].collect do |name|
68
- target = File.join Favicon.config['path'], name
69
- Icon.new @site, source, source_path(source), target
70
- end
71
- end
72
-
73
- def generate_metadata
74
- @site.pages.push metadata Browserconfig.new,
75
- Favicon.config['ie']['browserconfig']
76
- @site.pages.push metadata Webmanifest.new,
77
- Favicon.config['chrome']['manifest']
78
- end
79
-
80
- def metadata(document, config)
81
- page = Metadata.new @site, @site.source,
82
- File.dirname(config['target']),
83
- File.basename(config['target'])
84
- favicon_path = File.join (@site.baseurl || ''), Favicon.config['path']
85
- document.load source_path(config['source']), config, favicon_path
86
- page.content = document.dump
87
- page.data = { 'layout' => nil }
88
- page
12
+ Favicon.assets(site)
13
+ .select(&:generable?)
14
+ .each { |asset| site.static_files << asset }
89
15
  end
90
16
  end
91
17
  end
@@ -1,14 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jekyll/hooks"
4
+
1
5
  Jekyll::Hooks.register :site, :after_init do |site|
2
- Jekyll::Favicon.merge site.config['favicon']
3
- favicon_config = Jekyll::Favicon.config
4
- site.config['exclude'] << favicon_config['source']
5
- site.config['exclude'] << favicon_config['chrome']['manifest']['source']
6
- site.config['exclude'] << favicon_config['ie']['browserconfig']['source']
7
- end
6
+ static_files = Jekyll::Favicon.assets(site)
7
+ .uniq(&:path)
8
+ excludes = site.config["exclude"]
9
+ static_files.each do |static_file|
10
+ source = static_file.source_relative_path
11
+ excludes << source and next if static_file.generable?
8
12
 
9
- Jekyll::Hooks.register :site, :post_write do |site|
10
- favicon_generators = site.generators.select do |generator|
11
- generator.is_a? Jekyll::Favicon::Generator
13
+ Jekyll.logger.warn Jekyll::Favicon,
14
+ "Missing #{source}, not generating favicons."
12
15
  end
13
- favicon_generators.each(&:clean)
14
16
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jekyll/favicon/static_file"
4
+ require "jekyll/favicon/static_file/mutable"
5
+
6
+ module Jekyll
7
+ module Favicon
8
+ # StaticFile extension for data exchange formats
9
+ class StaticDataFile < StaticFile
10
+ include StaticFile::Mutable
11
+
12
+ def generable?
13
+ true
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+ require "forwardable"
5
+ require "jekyll/static_file"
6
+ require "jekyll/favicon/static_file/sourceable"
7
+ require "jekyll/favicon/static_file/taggable"
8
+ require "jekyll/favicon/static_file/referenceable"
9
+ require "jekyll/favicon/utils"
10
+ require "jekyll/favicon/configuration"
11
+
12
+ module Jekyll
13
+ module Favicon
14
+ # Class for static files from with spec dictionary
15
+ # Modify source from spec source
16
+ # Enable tags from spec tags
17
+ # Enable refer
18
+ class StaticFile < Jekyll::StaticFile
19
+ include StaticFile::Sourceable
20
+ include StaticFile::Taggable
21
+ include StaticFile::Referenceable
22
+
23
+ attr_reader :spec, :site
24
+
25
+ def initialize(site, spec = {})
26
+ raise StandardError unless spec.include? "name"
27
+
28
+ @spec = spec
29
+ spec_dir, spec_name = File.split spec_relative_path
30
+ super site, site.source, spec_dir, spec_name
31
+ end
32
+
33
+ def generable?
34
+ sourceable?
35
+ end
36
+
37
+ def taggable?
38
+ generable? && super
39
+ end
40
+
41
+ def patch(configuration)
42
+ taggable_patch spec_patch configuration
43
+ end
44
+
45
+ def href
46
+ Pathname.new("/")
47
+ .join(*[site.baseurl, url].compact)
48
+ .to_s
49
+ end
50
+
51
+ private
52
+
53
+ def spec_patch(configuration)
54
+ Utils.patch configuration do |value|
55
+ case value
56
+ when :site_dir then site_dir
57
+ when :background then site_background
58
+ when :href then href
59
+ else value
60
+ end
61
+ end
62
+ end
63
+
64
+ def site_dir
65
+ site_configuration.fetch("dir", ".")
66
+ end
67
+
68
+ def site_background
69
+ site_configuration.fetch("background", "transparent")
70
+ end
71
+
72
+ def site_configuration
73
+ Configuration.merged site
74
+ end
75
+
76
+ def spec_relative_path
77
+ spec_relative_pathname.cleanpath
78
+ end
79
+
80
+ def spec_relative_pathname
81
+ return spec_pathname if spec_pathname.relative?
82
+
83
+ pathname.relative_path_from "/"
84
+ end
85
+
86
+ def spec_pathname
87
+ Pathname.new(site_dir)
88
+ .join(*spec_dir_name)
89
+ end
90
+
91
+ def spec_dir_name
92
+ spec.values_at("dir", "name")
93
+ .compact
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jekyll/favicon/configuration/defaults"
4
+ require "jekyll/favicon/utils"
5
+
6
+ module Jekyll
7
+ module Favicon
8
+ class StaticFile < Jekyll::StaticFile
9
+ # Create static file based on a source file
10
+ module Convertible
11
+ include Configuration::Defaults
12
+
13
+ def convertible?
14
+ convert.any? || convert_allow_empty?
15
+ end
16
+
17
+ def convert
18
+ convert_defaults = convertible_defaults.dig File.extname(path), @extname
19
+ convert_normalized = convert_normalize convert_spec
20
+ convert_consolidated = Utils.merge convert_defaults, convert_normalized
21
+ patch convert_patch(convert_consolidated || {})
22
+ end
23
+
24
+ def convertible_patch(configuration)
25
+ Utils.patch configuration do |value|
26
+ case value
27
+ when :sizes then sizes.join " "
28
+ else value
29
+ end
30
+ end
31
+ end
32
+
33
+ def convert_odd_source?
34
+ img = MiniMagick::Image.open path
35
+ Utils.odd? img.dimensions
36
+ end
37
+
38
+ def convert_size(size, separator = "x")
39
+ return size unless convert_odd_source? || Utils.odd?(size)
40
+ min_dimension = size.split(separator).min
41
+ [min_dimension, min_dimension].join(separator)
42
+ end
43
+
44
+ def sizes
45
+ if (match = Utils.name_to_size(name)) then [match[1]]
46
+ elsif (define = Utils.define_to_size(convert_spec["define"])) then define
47
+ elsif (resize = convert_spec["resize"]) then [resize]
48
+ elsif (size = convert_spec["size"]) then [size]
49
+ end
50
+ end
51
+
52
+ # Jekyll::StaticFile method
53
+ # asks if dest mtime is older than source mtime after original modified?
54
+ def modified?
55
+ super || self.class.mtimes.fetch(href, -1) < mtime
56
+ end
57
+
58
+ # Jekyll::StaticFile method
59
+ # adds dest mtime to list after original write
60
+ def write(dest)
61
+ super(dest) && self.class.mtimes[href] = mtime
62
+ end
63
+
64
+ private
65
+
66
+ # Jekyll::StaticFile method
67
+ # add file creation instead of copying
68
+ def copy_file(dest_path)
69
+ case @extname
70
+ when ".svg" then super(dest_path)
71
+ when ".ico", ".png"
72
+ Utils.convert path, dest_path, convert
73
+ else Jekyll.logger.warn "Jekyll::Favicon: Can't generate " \
74
+ " #{dest_path}. Extension not supported."
75
+ end
76
+ end
77
+
78
+ def convert_allow_empty?
79
+ @extname == ".svg" && @extname == File.extname(path)
80
+ end
81
+
82
+ def convert_spec
83
+ spec.fetch "convert", {}
84
+ end
85
+
86
+ def convertible_keys
87
+ convertible_defaults["defaults"].keys
88
+ end
89
+
90
+ def convert_normalize(options)
91
+ return {} unless options
92
+
93
+ Utils.slice_and_compact options, convertible_keys
94
+ end
95
+
96
+ def convert_patch(options)
97
+ patched_options = convert_patch_options options
98
+ Utils.slice_and_compact patched_options, convertible_keys
99
+ end
100
+
101
+ def convert_patch_options(options)
102
+ %w[size extent].each_with_object(options) do |name, memo|
103
+ method = "convert_patch_option_#{name}".to_sym
104
+ memo[name] = send(method, options[name])
105
+ end
106
+ end
107
+
108
+ def convert_patch_option_size(size)
109
+ case size
110
+ when :auto
111
+ convert_size size if (size = sizes.first)
112
+ else size
113
+ end
114
+ end
115
+
116
+ def convert_patch_option_extent(extent)
117
+ case extent
118
+ when :auto
119
+ if (size = sizes.first)
120
+ width, height = size.split "x"
121
+ size if width != height
122
+ end
123
+ else extent
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rexml/document"
4
+ require "jekyll/favicon/utils"
5
+ require "jekyll/favicon/static_graphic_file"
6
+
7
+ module Jekyll
8
+ module Favicon
9
+ class StaticFile < Jekyll::StaticFile
10
+ # Create static file based on a source file
11
+ module Mutable
12
+ def mutable?
13
+ mutation.any? || super
14
+ end
15
+
16
+ def mutation
17
+ refers = case @extname
18
+ when ".xml"
19
+ mutation_refers.select { |refer| refer.key? "browserconfig" }
20
+ else
21
+ mutation_refers.collect { |refer| refer["webmanifest"] }
22
+ .compact
23
+ end
24
+ patch(Utils.merge(*refers) || {})
25
+ end
26
+
27
+ # overrides Jekyll::StaticFile method
28
+ def mtime
29
+ return super if File.file? path
30
+ end
31
+
32
+ private
33
+
34
+ # overrides Jekyll::StaticFile method
35
+ def copy_file(dest_path)
36
+ # return unless mutable?
37
+ # return super(dest_path) unless mutation.any?
38
+
39
+ File.write dest_path, mutated_content
40
+ end
41
+
42
+ def mutated_content
43
+ case @extname
44
+ when ".json", ".webmanifest", ".manifest" then mutated_content_json
45
+ when ".xml" then mutated_content_xml
46
+ end
47
+ end
48
+
49
+ def mutated_content_json
50
+ mutated = Jekyll::Utils.deep_merge_hashes (mutable || {}), mutation
51
+ JSON.pretty_generate mutated
52
+ end
53
+
54
+ def mutated_content_xml
55
+ mutated = Utils.mutate_element (mutable || REXML::Document.new), mutation
56
+ output = +""
57
+ mutated.write output
58
+ output
59
+ end
60
+
61
+ def mutable
62
+ return unless File.file? path
63
+
64
+ content = File.read path
65
+ case File.extname path
66
+ when ".xml" then REXML::Document.new content
67
+ else JSON.parse content
68
+ end
69
+ end
70
+
71
+ def mutation_refers
72
+ site.static_files
73
+ .select { |static_file| static_file.is_a? StaticFile }
74
+ .select(&:referenceable?)
75
+ .collect(&:refer)
76
+ .flatten
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end