distorted-jekyll 0.5.7 → 0.6.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.
- checksums.yaml +4 -4
- data/lib/distorted-jekyll.rb +1 -1
- data/lib/distorted-jekyll/_config_default.yml +9 -7
- data/lib/distorted-jekyll/floor.rb +122 -4
- data/lib/distorted-jekyll/invoker.rb +80 -221
- data/lib/distorted-jekyll/{injection_of_love.rb → md_injection.rb} +0 -0
- data/lib/distorted-jekyll/molecule/font.rb +48 -15
- data/lib/distorted-jekyll/molecule/image.rb +11 -22
- data/lib/distorted-jekyll/molecule/lastresort.rb +51 -0
- data/lib/distorted-jekyll/molecule/pdf.rb +42 -51
- data/lib/distorted-jekyll/molecule/svg.rb +9 -21
- data/lib/distorted-jekyll/molecule/text.rb +6 -18
- data/lib/distorted-jekyll/molecule/video.rb +54 -12
- data/lib/distorted-jekyll/static_state.rb +201 -0
- data/lib/distorted-jekyll/template/13th-style.css +1 -0
- metadata +7 -44
- data/lib/distorted-jekyll/error_code.rb +0 -24
- data/lib/distorted-jekyll/molecule/abstract.rb +0 -238
- data/lib/distorted-jekyll/molecule/last-resort.rb +0 -54
- data/lib/distorted-jekyll/static/font.rb +0 -42
- data/lib/distorted-jekyll/static/image.rb +0 -55
- data/lib/distorted-jekyll/static/lastresort.rb +0 -28
- data/lib/distorted-jekyll/static/pdf.rb +0 -53
- data/lib/distorted-jekyll/static/state.rb +0 -141
- data/lib/distorted-jekyll/static/svg.rb +0 -52
- data/lib/distorted-jekyll/static/text.rb +0 -57
- data/lib/distorted-jekyll/static/video.rb +0 -90
@@ -0,0 +1,201 @@
|
|
1
|
+
|
2
|
+
require 'fileutils'
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
require 'distorted/error_code'
|
6
|
+
|
7
|
+
|
8
|
+
module Jekyll; end
|
9
|
+
module Jekyll::DistorteD; end
|
10
|
+
|
11
|
+
# This module implements the methods our tag needs in order to
|
12
|
+
# pretend to be a Jekyll::StaticFile so we don't need to
|
13
|
+
# redundantly re-implement a Generator and Jekyll::Cleaner.
|
14
|
+
module Jekyll::DistorteD::StaticState
|
15
|
+
|
16
|
+
|
17
|
+
ATTRIBUTES = Set[:title]
|
18
|
+
|
19
|
+
|
20
|
+
# Returns the to-be-written path of a single standard StaticFile.
|
21
|
+
# The value returned by this method is only the 'main' or 'original'
|
22
|
+
# (even if modified somehow) file and does not include the
|
23
|
+
# path/filenames of any variations.
|
24
|
+
# This method will be called by jekyll/lib/cleaner#new_files
|
25
|
+
# to generate the list of files that need to be build or rebuilt
|
26
|
+
# for a site. For this reason, this method shouldn't do any kind
|
27
|
+
# of checking the real filesystem, since e.g. its URL-based
|
28
|
+
# destdir might not exist yet if the Site.dest is completely blank.
|
29
|
+
def destination(dest_root)
|
30
|
+
File.join(dest_root, @relative_dest, @name)
|
31
|
+
end
|
32
|
+
|
33
|
+
# This method will be called by our monkey-patched Jekyll::Cleaner#new_files
|
34
|
+
# in place of the single-destination method usually used.
|
35
|
+
# This allows us to tell Jekyll about more than a single file
|
36
|
+
# that should be kept when regenerating the site.
|
37
|
+
# This makes DistorteD fast!
|
38
|
+
def destinations(dest_root)
|
39
|
+
wanted_files.map{|f| File.join(dest_root, @relative_dest, f)}
|
40
|
+
end
|
41
|
+
|
42
|
+
# HACK HACK HACK
|
43
|
+
# Jekyll does not pass this method a site.dest like it does write() and
|
44
|
+
# others, but I want to be able to short-circuit here if all the
|
45
|
+
# to-be-generated files already exist.
|
46
|
+
def modified?
|
47
|
+
# Assume modified for the sake of freshness :)
|
48
|
+
modified = true
|
49
|
+
|
50
|
+
site_dest = Jekyll::DistorteD::Floor::config(:destination).to_s
|
51
|
+
if Dir.exist?(site_dest)
|
52
|
+
if Dir.exist?(File.join(site_dest, @relative_dest))
|
53
|
+
extant_files = Dir.entries(File.join(site_dest, @relative_dest)).to_set
|
54
|
+
|
55
|
+
# TODO: Make this smarter. It's not enough that all the generated
|
56
|
+
# filenames should exist. Try a few more ways to detect subtler
|
57
|
+
# "changes to the source file since generation of variations.
|
58
|
+
if wanted_files.subset?(extant_files)
|
59
|
+
Jekyll.logger.debug(@name, "All variations present: #{wanted_files}")
|
60
|
+
modified = false
|
61
|
+
else
|
62
|
+
Jekyll.logger.debug(@name, "Missing variations: #{wanted_files - extant_files}")
|
63
|
+
end
|
64
|
+
|
65
|
+
end # relative_dest.exists?
|
66
|
+
end # site_dest.exists?
|
67
|
+
Jekyll.logger.debug("#{@name} modified?", modified)
|
68
|
+
return modified
|
69
|
+
end # modified?
|
70
|
+
|
71
|
+
# Whether to write the file to the filesystem
|
72
|
+
#
|
73
|
+
# Returns true unless the defaults for the destination path from
|
74
|
+
# _config.yml contain `published: false`.
|
75
|
+
def write?
|
76
|
+
publishable = defaults.fetch('published'.freeze, true)
|
77
|
+
return publishable unless @collection
|
78
|
+
|
79
|
+
publishable && @collection.write?
|
80
|
+
end
|
81
|
+
|
82
|
+
# Write the static file to the destination directory (if modified).
|
83
|
+
#
|
84
|
+
# dest - The String path to the destination dir.
|
85
|
+
#
|
86
|
+
# Returns false if the file was not modified since last time (no-op).
|
87
|
+
def write(dest_root)
|
88
|
+
plug
|
89
|
+
return false if File.exist?(path) && !modified?
|
90
|
+
|
91
|
+
# Create any directories to the depth of the intended destination.
|
92
|
+
FileUtils.mkdir_p(File.join(dest_root, @relative_dest))
|
93
|
+
# Save every desired variation of this image.
|
94
|
+
# This will be a Set of Hashes each describing the name, type,
|
95
|
+
# dimensions, attributes, etc of each output variation we want.
|
96
|
+
# Full-size outputs will have the special tag `:full`.
|
97
|
+
files.each { |variation|
|
98
|
+
type = variation&.dig(:type)
|
99
|
+
filename = File.join(dest_root, @relative_dest, variation&.dig(:name) || @name)
|
100
|
+
|
101
|
+
if self.respond_to?(type.distorted_method)
|
102
|
+
Jekyll.logger.debug("DistorteD::#{type.distorted_method}", filename)
|
103
|
+
self.send(type.distorted_method, filename, **variation)
|
104
|
+
elsif extname == ".#{type.preferred_extension}"
|
105
|
+
Jekyll.logger.debug(@name, <<~RAWCOPY
|
106
|
+
No #{type.distorted_method} method is defined,
|
107
|
+
but the intended output type #{type.to_s} is the same
|
108
|
+
as the input type, so I will fall back to copying the raw file.
|
109
|
+
RAWCOPY
|
110
|
+
)
|
111
|
+
copy_file(filename)
|
112
|
+
else
|
113
|
+
Jekyll.logger.error(@name, "Missing rendering method #{type.distorted_method}")
|
114
|
+
raise MediaTypeOutputNotImplementedError.new(filename, type, self.class.name)
|
115
|
+
end
|
116
|
+
}
|
117
|
+
end # write
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def copy_file(dest_path, *a, **k)
|
122
|
+
if @site.safe || Jekyll.env == "production"
|
123
|
+
FileUtils.cp(path, dest_path)
|
124
|
+
else
|
125
|
+
FileUtils.copy_entry(path, dest_path)
|
126
|
+
end
|
127
|
+
end # copy_file
|
128
|
+
|
129
|
+
# Basic file properties
|
130
|
+
|
131
|
+
# Filename without the dot-and-extension.
|
132
|
+
def basename
|
133
|
+
File.basename(@name, '.*')
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns the extname /!\ including the dot /!\
|
137
|
+
def extname
|
138
|
+
File.extname(@name)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Returns last modification time for this file.
|
142
|
+
def mtime
|
143
|
+
(@modified_time ||= File.stat(path).mtime).to_i
|
144
|
+
end
|
145
|
+
|
146
|
+
# Returns source file path.
|
147
|
+
def path
|
148
|
+
@path ||= begin
|
149
|
+
# Static file is from a collection inside custom collections directory
|
150
|
+
if !@collection.nil? && !@site.config['collections_dir'.freeze].empty?
|
151
|
+
File.join(*[@base, @site.config['collections_dir'.freeze], @dir, @name].compact)
|
152
|
+
else
|
153
|
+
File.join(*[@base, @dir, @name].compact)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Returns a Hash keyed by MIME::Type objects with value as a Set of Hashes
|
159
|
+
# describing the media's output variations to be generated for each Type.
|
160
|
+
def variations
|
161
|
+
changes(abstract(:changes)).map{ |t|
|
162
|
+
[t, outer_limits(abstract(:outer_limits)).map{ |d|
|
163
|
+
|
164
|
+
# Don't change the filename of full-size variations
|
165
|
+
tag = d&.dig(:tag) != :full ? '-'.concat(d&.dig(:tag).to_s) : ''.freeze
|
166
|
+
# Use the original extname for LastResort
|
167
|
+
ext = t == CHECKING::YOU::OUT('application/x.distorted.last-resort') ? File.extname(@name) : t.preferred_extension
|
168
|
+
# Handle LastResort for files that might be a bare name with no extension
|
169
|
+
dot = '.'.freeze unless ext.nil? || ext&.empty?
|
170
|
+
|
171
|
+
d.merge({
|
172
|
+
# e.g. 'SomeImage-medium.jpg` but just `SomeImage.jpg` and not `SomeImage-full.jpg`
|
173
|
+
# for the full-resolution outputs.
|
174
|
+
# The default `.jpeg` preferred_extension is monkey-patched to `.jpg` because lol
|
175
|
+
:name => "#{basename}#{tag}#{dot}#{ext}",
|
176
|
+
})
|
177
|
+
|
178
|
+
}]
|
179
|
+
}.to_h
|
180
|
+
end
|
181
|
+
|
182
|
+
# Returns a flat Set of Hashes that each describe one variant of
|
183
|
+
# media file output that should exist for a given input file.
|
184
|
+
def files
|
185
|
+
filez = Set[]
|
186
|
+
variations.each_pair{ |t,v|
|
187
|
+
# Merge the type in to each variation Hash since we will no longer
|
188
|
+
# have it as the key to this Set in its container Hash.
|
189
|
+
v.each{ |d| filez.add(d.merge({:type => t})) }
|
190
|
+
}
|
191
|
+
filez
|
192
|
+
end
|
193
|
+
|
194
|
+
# Returns a Set of just the String filenames we want for this media.
|
195
|
+
# This will be used by `modified?` among others.
|
196
|
+
def wanted_files
|
197
|
+
files.map{|f| f[:name]}.to_set
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: distorted-jekyll
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- okeeblow
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -86,28 +86,14 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: 0.
|
89
|
+
version: 0.6.0
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: 0.
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: mime-types
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - "~>"
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '3.0'
|
104
|
-
type: :runtime
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - "~>"
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '3.0'
|
96
|
+
version: 0.6.0
|
111
97
|
- !ruby/object:Gem::Dependency
|
112
98
|
name: kramdown
|
113
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,20 +108,6 @@ dependencies:
|
|
122
108
|
- - "~>"
|
123
109
|
- !ruby/object:Gem::Version
|
124
110
|
version: '2.0'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: ruby-filemagic
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - "~>"
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: '0.7'
|
132
|
-
type: :runtime
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - "~>"
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: '0.7'
|
139
111
|
description: Jekyll::DistorteD is a Liquid tag for embedding media in a Jekyll site
|
140
112
|
with automatic thumbnailing, cropping, and format conversion.
|
141
113
|
email:
|
@@ -150,27 +122,18 @@ files:
|
|
150
122
|
- lib/distorted-jekyll/13th-style.rb
|
151
123
|
- lib/distorted-jekyll/_config_default.yml
|
152
124
|
- lib/distorted-jekyll/blocks.rb
|
153
|
-
- lib/distorted-jekyll/error_code.rb
|
154
125
|
- lib/distorted-jekyll/floor.rb
|
155
|
-
- lib/distorted-jekyll/injection_of_love.rb
|
156
126
|
- lib/distorted-jekyll/invoker.rb
|
157
|
-
- lib/distorted-jekyll/
|
127
|
+
- lib/distorted-jekyll/md_injection.rb
|
158
128
|
- lib/distorted-jekyll/molecule/font.rb
|
159
129
|
- lib/distorted-jekyll/molecule/image.rb
|
160
|
-
- lib/distorted-jekyll/molecule/
|
130
|
+
- lib/distorted-jekyll/molecule/lastresort.rb
|
161
131
|
- lib/distorted-jekyll/molecule/pdf.rb
|
162
132
|
- lib/distorted-jekyll/molecule/svg.rb
|
163
133
|
- lib/distorted-jekyll/molecule/text.rb
|
164
134
|
- lib/distorted-jekyll/molecule/video.rb
|
165
135
|
- lib/distorted-jekyll/monkey_business/jekyll/cleaner.rb
|
166
|
-
- lib/distorted-jekyll/
|
167
|
-
- lib/distorted-jekyll/static/image.rb
|
168
|
-
- lib/distorted-jekyll/static/lastresort.rb
|
169
|
-
- lib/distorted-jekyll/static/pdf.rb
|
170
|
-
- lib/distorted-jekyll/static/state.rb
|
171
|
-
- lib/distorted-jekyll/static/svg.rb
|
172
|
-
- lib/distorted-jekyll/static/text.rb
|
173
|
-
- lib/distorted-jekyll/static/video.rb
|
136
|
+
- lib/distorted-jekyll/static_state.rb
|
174
137
|
- lib/distorted-jekyll/template/13th-style.css
|
175
138
|
- lib/distorted-jekyll/template/error_code.liquid
|
176
139
|
- lib/distorted-jekyll/template/font.liquid
|
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'distorted/error_code'
|
2
|
-
|
3
|
-
|
4
|
-
module Jekyll
|
5
|
-
module DistorteD
|
6
|
-
class OutOfDateLibraryError < LoadError
|
7
|
-
end
|
8
|
-
|
9
|
-
# The built-in NotImplementedError is for "when a feature is not implemented
|
10
|
-
# on the current platform", so make our own more appropriate ones.
|
11
|
-
class MediaTypeNotImplementedError < StandardDistorteDError
|
12
|
-
attr_reader :media_type, :name
|
13
|
-
def initialize(name)
|
14
|
-
super("No supported media type for #{name}")
|
15
|
-
end
|
16
|
-
end
|
17
|
-
class MediaTypeNotFoundError < StandardDistorteDError
|
18
|
-
attr_reader :media_type, :name
|
19
|
-
def initialize(name)
|
20
|
-
super("Failed to detect media type for #{name}")
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,238 +0,0 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
|
-
require 'distorted-jekyll/floor'
|
4
|
-
|
5
|
-
require 'jekyll'
|
6
|
-
require 'liquid/errors'
|
7
|
-
require 'liquid/template'
|
8
|
-
require 'mime/types'
|
9
|
-
|
10
|
-
|
11
|
-
module Jekyll
|
12
|
-
module DistorteD
|
13
|
-
module Molecule
|
14
|
-
module Abstract
|
15
|
-
|
16
|
-
# This list should contain global attributes only, as symbols.
|
17
|
-
# The final attribute set will be this + the media-type-specific set.
|
18
|
-
# https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes
|
19
|
-
GLOBAL_ATTRS = Set[:title]
|
20
|
-
|
21
|
-
|
22
|
-
# Returns a Set of Arrays of search keys to try in config()
|
23
|
-
def search_keys(*keys)
|
24
|
-
# It's likely that we will get a default argument of [nil]
|
25
|
-
# here due to the output of attr_value(:whatever) for unset attrs.
|
26
|
-
keys = keys.compact
|
27
|
-
# If a search key path was given, construct one based
|
28
|
-
# on the MIME::Type union Set between the source media
|
29
|
-
# and the plugged MediaMolecule.
|
30
|
-
if keys.empty? or keys.all?{|k| k.nil?}
|
31
|
-
try_keys = @mime.map{ |t|
|
32
|
-
# Use only the first part of complex sub_types like 'svg+xml'
|
33
|
-
[t.media_type, t.sub_type.split('+').first].compact
|
34
|
-
}
|
35
|
-
else
|
36
|
-
# Or use a user-provided config path.
|
37
|
-
try_keys = Set[keys]
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# Loads configuration data telling us how to open certain
|
42
|
-
# types of files.
|
43
|
-
def welcome(*keys)
|
44
|
-
# Try each set of keys until we find a match
|
45
|
-
for try in search_keys(*keys)
|
46
|
-
tried = Jekyll::DistorteD::Floor::config(
|
47
|
-
Jekyll::DistorteD::Floor::CONFIG_ROOT,
|
48
|
-
:welcome,
|
49
|
-
*try,
|
50
|
-
)
|
51
|
-
# Is the YAML config of the appropriate structure?
|
52
|
-
if tried.is_a?(Hash)
|
53
|
-
# Non-Hashes may not respond to `empty?`
|
54
|
-
unless tried.empty?
|
55
|
-
return tried
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# Load configuration telling us what media-types to generate
|
62
|
-
# for any given media-type input.
|
63
|
-
def changes(*keys)
|
64
|
-
out = Set[]
|
65
|
-
# `changes` media-type[sub_type] config will contain information about
|
66
|
-
# what variations output format are desired for what input format,
|
67
|
-
# e.g. {:image => {:jpeg => Set['image/jpeg', 'image/webp']}}
|
68
|
-
# It is not automatically implied that the source format is also
|
69
|
-
# an output format!
|
70
|
-
for try in search_keys(*keys)
|
71
|
-
tried = Jekyll::DistorteD::Floor::config(
|
72
|
-
Jekyll::DistorteD::Floor::CONFIG_ROOT,
|
73
|
-
:changes,
|
74
|
-
*try,
|
75
|
-
)
|
76
|
-
if tried.is_a?(Enumerable) and tried.all?{|t| t.is_a?(String)} and not tried.empty?
|
77
|
-
tried.each{ |t|
|
78
|
-
# MIME::Type.new() won't give us a usable Type object:
|
79
|
-
#
|
80
|
-
# irb> MIME::Types['image/svg+xml'].first.preferred_extension
|
81
|
-
# => "svg"
|
82
|
-
# irb> MIME::Type.new('image/svg+xml').preferred_extension
|
83
|
-
# => nil
|
84
|
-
out.merge(MIME::Types[t])
|
85
|
-
}
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
# If the config didn't give us any MIME::Type changes
|
90
|
-
# then we will just output the same type we loaded.
|
91
|
-
if out.empty?
|
92
|
-
return @mime
|
93
|
-
else
|
94
|
-
return out
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# Loads configuration telling us what variations to generate for any
|
99
|
-
# given type of file, or for an arbitrary key hierarchy.
|
100
|
-
def outer_limits(*keys)
|
101
|
-
out = Set[]
|
102
|
-
# See if any config data exists for each given key hierarchy,
|
103
|
-
# but under the root DistorteD config key.
|
104
|
-
for try in search_keys(*keys)
|
105
|
-
tried = Jekyll::DistorteD::Floor::config(
|
106
|
-
Jekyll::DistorteD::Floor::CONFIG_ROOT,
|
107
|
-
:outer_limits,
|
108
|
-
*try,
|
109
|
-
)
|
110
|
-
|
111
|
-
# Is the YAML config of the appropriate structure?
|
112
|
-
# Merge a shallow copy of it with the Liquid-given attrs.
|
113
|
-
# If we don't take a copy the attrs will be memoized into the config.
|
114
|
-
if tried.is_a?(Enumerable) and tried.all?{|t| t.is_a?(Hash)} and not tried.empty?
|
115
|
-
out.merge(tried.dup.map{ |d| d.merge(attrs) })
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
# We should output something if the config didn't give us anything.
|
120
|
-
# This is kind of a mess right now with redundancies in the call sites
|
121
|
-
# of things like Molecule::Image. I'll come up with a better general-
|
122
|
-
# purpose fallback solution at some point, but for now this will get
|
123
|
-
# non-Image StaticFiles working with no config :)
|
124
|
-
if out.empty?
|
125
|
-
out << {
|
126
|
-
:tag => :full,
|
127
|
-
:crop => :none,
|
128
|
-
}
|
129
|
-
end
|
130
|
-
|
131
|
-
return out
|
132
|
-
end
|
133
|
-
|
134
|
-
# Returns a Hash of any attribute provided to DD's Liquid tag and its value.
|
135
|
-
def attrs
|
136
|
-
# Value of every Molecule-defined attr will be nil if that attr
|
137
|
-
# is not provided to our Liquid tag.
|
138
|
-
@attrs.keep_if{|attr,val| val != nil}
|
139
|
-
end
|
140
|
-
|
141
|
-
# Returns the value for an attribute as given to the Liquid tag,
|
142
|
-
# the default value if the given value is not in the accepted Set,
|
143
|
-
# or nil for unset attrs with no default defined.
|
144
|
-
def attr_value(attribute)
|
145
|
-
# Set of all supported attributes:
|
146
|
-
# - Global output-element attributes
|
147
|
-
# - Molecule-specific output-element attributes
|
148
|
-
# - Filetype change and output-template config paths
|
149
|
-
accepted_attrs = self.singleton_class.const_get(:GLOBAL_ATTRS) + self.singleton_class.const_get(:ATTRS) + Set[:changes, :outer_limits]
|
150
|
-
|
151
|
-
# Set of acceptable values for the given attribute, e.g. Image::loading => Set[:eager, :lazy]
|
152
|
-
# Will be empty if this attribute takes freeform input (like `title` or `alt`)
|
153
|
-
accepted_vals = self.singleton_class.const_get(:ATTRS_VALUES)&.dig(attribute)
|
154
|
-
|
155
|
-
# The value, if any, provided to our Liquid tag for this attr.
|
156
|
-
liquid_val = attrs&.dig(attribute)
|
157
|
-
|
158
|
-
# Is the requested attribute name defined as an accepted attribute
|
159
|
-
# either globally or within the plugged MediaMolecule?
|
160
|
-
if accepted_attrs.include?(attribute.to_sym)
|
161
|
-
|
162
|
-
# Does this attr define a set of acceptable values?
|
163
|
-
if accepted_vals.is_a?(Set)
|
164
|
-
# Yes, it does. Is the Liquid-given value in that Set of acceptable values?
|
165
|
-
if accepted_vals.include?(liquid_val) or accepted_vals.include?(liquid_val&.to_sym) or accepted_vals.include?(liquid_val&.to_s)
|
166
|
-
|
167
|
-
# Yes, it is! Use it.
|
168
|
-
liquid_val.to_s
|
169
|
-
else
|
170
|
-
# No, it isn't. Warn and return the default.
|
171
|
-
unless liquid_val.nil?
|
172
|
-
Jekyll.logger.warn('DistorteD', "#{liquid_val.to_s} is not an acceptable value for #{attribute.to_s}: #{accepted_vals}")
|
173
|
-
end
|
174
|
-
self.singleton_class.const_get(:ATTRS_DEFAULT)&.dig(attribute).to_s
|
175
|
-
end
|
176
|
-
elsif accepted_vals.is_a?(Regexp)
|
177
|
-
if accepted_vals =~ liquid_val.to_s
|
178
|
-
liquid_val.to_s
|
179
|
-
else
|
180
|
-
unless liquid_val.nil?
|
181
|
-
Jekyll.logger.warn('DistorteD', "#{liquid_val.to_s} is not a Regexp match for #{attribute.to_s}: #{accepted_vals}")
|
182
|
-
end
|
183
|
-
self.singleton_class.const_get(:ATTRS_DEFAULT)&.dig(attribute)
|
184
|
-
end
|
185
|
-
else
|
186
|
-
# No, this attribute does not define a Set of acceptable values.
|
187
|
-
# The freeform Liquid-given value is fine, but if it's nil
|
188
|
-
# we can still try for a default.
|
189
|
-
if liquid_val.nil?
|
190
|
-
self.singleton_class.const_get(:ATTRS_DEFAULT)&.dig(attribute)
|
191
|
-
else
|
192
|
-
liquid_val
|
193
|
-
end
|
194
|
-
end
|
195
|
-
else
|
196
|
-
Jekyll.logger.error('DistorteD', "#{attribute.to_s} is not a supported attribute")
|
197
|
-
nil
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
# Returns a Hash keyed by MIME::Type objects with value as a Set of Hashes
|
202
|
-
# describing the media's output variations to be generated for each Type.
|
203
|
-
def variations
|
204
|
-
changes(attr_value(:changes)).map{ |t|
|
205
|
-
[t, outer_limits(attr_value(:outer_limits)).map{ |d|
|
206
|
-
d.merge({
|
207
|
-
# e.g. 'SomeImage-medium.jpg` but just `SomeImage.jpg` and not `SomeImage-full.jpg`
|
208
|
-
# for the full-resolution outputs.
|
209
|
-
# The default `.jpeg` preferred_extension is monkey-patched to `.jpg` because lol
|
210
|
-
:name => "#{File.basename(@name, '.*')}#{'-'.concat(d&.dig(:tag).to_s) if d&.dig(:tag) != :full}.#{t.preferred_extension}",
|
211
|
-
})
|
212
|
-
}]
|
213
|
-
}.to_h
|
214
|
-
end
|
215
|
-
|
216
|
-
# Returns a flat Set of Hashes that each describe one variant of
|
217
|
-
# media file output that should exist for a given input file.
|
218
|
-
def files
|
219
|
-
filez = Set[]
|
220
|
-
variations.each_pair{ |t,v|
|
221
|
-
# Merge the type in to each variation Hash since we will no longer
|
222
|
-
# have it as the key to this Set in its container Hash.
|
223
|
-
v.each{ |d| filez.add(d.merge({:type => t})) }
|
224
|
-
}
|
225
|
-
filez
|
226
|
-
end
|
227
|
-
|
228
|
-
# Returns a Set of just the String filenames we want for this media.
|
229
|
-
# This will be used by `modified?` among others.
|
230
|
-
def filenames
|
231
|
-
files.map{|f| f[:name]}.to_set
|
232
|
-
end
|
233
|
-
|
234
|
-
|
235
|
-
end # Abstract
|
236
|
-
end # Molecule
|
237
|
-
end # DistorteD
|
238
|
-
end # Jekyll
|