distorted-jekyll 0.6.0 → 0.7.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/README.md +1 -1
- data/lib/distorted-jekyll.rb +0 -4
- data/lib/distorted-jekyll/{template/13th-style.css → 13th-style.css} +0 -0
- data/lib/distorted-jekyll/13th-style.rb +1 -1
- data/lib/distorted-jekyll/_config_default.yml +3 -21
- data/lib/distorted-jekyll/invoker.rb +194 -219
- data/lib/distorted-jekyll/liquid_liquid.rb +255 -0
- data/lib/distorted-jekyll/liquid_liquid/anchor.liquid +5 -0
- data/lib/distorted-jekyll/liquid_liquid/anchor_inline.liquid +1 -0
- data/lib/distorted-jekyll/liquid_liquid/embed.liquid +1 -0
- data/lib/distorted-jekyll/liquid_liquid/img.liquid +1 -0
- data/lib/distorted-jekyll/liquid_liquid/object.liquid +5 -0
- data/lib/distorted-jekyll/liquid_liquid/picture.liquid +15 -0
- data/lib/distorted-jekyll/liquid_liquid/picture.rb +48 -0
- data/lib/distorted-jekyll/liquid_liquid/picture_source.liquid +1 -0
- data/lib/distorted-jekyll/liquid_liquid/root.liquid +5 -0
- data/lib/distorted-jekyll/liquid_liquid/video.liquid +5 -0
- data/lib/distorted-jekyll/liquid_liquid/video_source.liquid +1 -0
- data/lib/distorted-jekyll/md_injection.rb +30 -25
- data/lib/distorted-jekyll/media_molecule.rb +20 -0
- data/lib/distorted-jekyll/media_molecule/font.rb +21 -0
- data/lib/distorted-jekyll/media_molecule/image.rb +15 -0
- data/lib/distorted-jekyll/media_molecule/never_let_you_down.rb +28 -0
- data/lib/distorted-jekyll/media_molecule/pdf.rb +108 -0
- data/lib/distorted-jekyll/media_molecule/svg.rb +20 -0
- data/lib/distorted-jekyll/media_molecule/text.rb +23 -0
- data/lib/distorted-jekyll/media_molecule/video.rb +45 -0
- data/lib/distorted-jekyll/monkey_business/jekyll/cleaner.rb +68 -1
- data/lib/distorted-jekyll/static_state.rb +19 -60
- data/lib/distorted-jekyll/the_setting_sun.rb +179 -0
- metadata +26 -21
- data/lib/distorted-jekyll/floor.rb +0 -266
- data/lib/distorted-jekyll/molecule/font.rb +0 -62
- data/lib/distorted-jekyll/molecule/image.rb +0 -94
- data/lib/distorted-jekyll/molecule/lastresort.rb +0 -51
- data/lib/distorted-jekyll/molecule/pdf.rb +0 -79
- data/lib/distorted-jekyll/molecule/svg.rb +0 -47
- data/lib/distorted-jekyll/molecule/text.rb +0 -62
- data/lib/distorted-jekyll/molecule/video.rb +0 -85
- data/lib/distorted-jekyll/template/error_code.liquid +0 -3
- data/lib/distorted-jekyll/template/font.liquid +0 -32
- data/lib/distorted-jekyll/template/image.liquid +0 -32
- data/lib/distorted-jekyll/template/lastresort.liquid +0 -20
- data/lib/distorted-jekyll/template/pdf.liquid +0 -14
- data/lib/distorted-jekyll/template/svg.liquid +0 -32
- data/lib/distorted-jekyll/template/text.liquid +0 -32
- data/lib/distorted-jekyll/template/video.liquid +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5fe548492f52f0b4bb138fbd93ca2fb127f53baf7a3657d73aefc904c22a51b
|
4
|
+
data.tar.gz: 2444637db29356d306f2e1e31a41b0fe9c758574d77bc40d691f51c0ab514af5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6aff9df826afc000fea96df60f7a4305195ea4518e5c96a1c38b5899e72d47860d7866cbad2d5184cd820221d8d15bc86ed946a278345773972b5bdaccaf0008
|
7
|
+
data.tar.gz: 26efca75634c2c45d9b2d01116b96f64585b1c3a00e98471d6659adeeb0d545224911af048faef4df5afc228923f4ea44ebe2eb6e055ff2217ecf73ea6ed64d2
|
data/README.md
CHANGED
@@ -156,7 +156,7 @@ Clone the DistorteD repository and modify your Jekyll `Gemfile` to refer to your
|
|
156
156
|
gem 'distorted-jekyll', :path => '~/repos/DistorteD/DistorteD-Jekyll/'[, :branch => 'NEW-SENSATION']
|
157
157
|
```
|
158
158
|
|
159
|
-
The `DistorteD-Jekyll` Gem will automatically use its local sibling `DistorteD-
|
159
|
+
The `DistorteD-Jekyll` Gem will automatically use its local sibling `DistorteD-Floor` Gem if used in this way.
|
160
160
|
|
161
161
|
## License
|
162
162
|
|
data/lib/distorted-jekyll.rb
CHANGED
@@ -40,10 +40,6 @@ if [
|
|
40
40
|
Hash.method_defined?(:transform_keys), # 2.5
|
41
41
|
Enumerable.method_defined?(:filter_map), # 2.7
|
42
42
|
].all?
|
43
|
-
# Monkey-patch preferred_extensions iff we're going to load.
|
44
|
-
# My JPEGs coming out with a '.jpeg' file extension just annoys me so much.
|
45
|
-
require 'distorted/monkey_business/mnemoniq'
|
46
|
-
|
47
43
|
# Monkey-patch Jekyll::Cleaner to not nuke DistorteD-generated variations
|
48
44
|
# for our media files. This makes DistorteD fast!
|
49
45
|
require 'distorted-jekyll/monkey_business/jekyll/cleaner'
|
File without changes
|
@@ -35,7 +35,7 @@ module Jekyll
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def render_to_output_buffer(context, output)
|
38
|
-
css_filename = File.join(File.dirname(__FILE__), '
|
38
|
+
css_filename = File.join(File.dirname(__FILE__), '13th-style.css'.freeze)
|
39
39
|
|
40
40
|
# Use IO.foreach() to call a block on each line of our template file
|
41
41
|
# without slurping the entire file into memory like File.read() / File.readlines()
|
@@ -6,34 +6,16 @@
|
|
6
6
|
# so duplicate Array values will be compacted!
|
7
7
|
|
8
8
|
standard_image: &standard_image
|
9
|
-
-
|
10
|
-
|
11
|
-
- tag: small
|
12
|
-
width: 400
|
13
|
-
height: 400
|
14
|
-
media: "(max-width: 400px)"
|
15
|
-
- tag: medium
|
16
|
-
width: 800
|
17
|
-
height: 800
|
18
|
-
media: "(min-width: 400px) and (max-width: 800px)"
|
19
|
-
- tag: large
|
20
|
-
width: 1500
|
21
|
-
height: 1500
|
22
|
-
media: "(min-width: 800px)"
|
23
|
-
|
9
|
+
- crop: none
|
10
|
+
breaks: [333, 555, 777, 1111]
|
24
11
|
|
25
12
|
distorted:
|
26
13
|
|
27
|
-
# Liquid template caching is default as of Jekyll 4.0,
|
28
|
-
# but it can be disabled if needed.
|
29
|
-
# I just can't think of when it would be needed :)
|
30
|
-
cache_templates: true
|
31
|
-
|
32
14
|
# Should unrecognized media-types fall back to a bare
|
33
15
|
# <img> tag around the original media file?
|
34
16
|
# If not, the site build will fail when an unrecognized
|
35
17
|
# file is encountered.
|
36
|
-
|
18
|
+
never_let_you_down: true
|
37
19
|
|
38
20
|
# Configure DistorteD format changes by media_type, then by sub_type.
|
39
21
|
# The list of target formats is plain text, media_type/sub_type.
|
@@ -1,259 +1,234 @@
|
|
1
1
|
# Our custom Exceptions
|
2
2
|
require 'distorted/error_code'
|
3
3
|
|
4
|
+
# Molecule loading and plugging functionality
|
5
|
+
require 'distorted/invoker'
|
6
|
+
|
4
7
|
# MIME::Typer
|
5
8
|
require 'distorted/checking_you_out'
|
6
9
|
|
7
10
|
# Configuration-loading code
|
8
|
-
require 'distorted-jekyll/
|
11
|
+
require 'distorted-jekyll/the_setting_sun'
|
9
12
|
require 'distorted-jekyll/static_state'
|
10
13
|
|
11
|
-
# Media-type drivers
|
12
|
-
require 'distorted-jekyll/molecule/font'
|
13
|
-
require 'distorted-jekyll/molecule/image'
|
14
|
-
require 'distorted-jekyll/molecule/text'
|
15
|
-
require 'distorted-jekyll/molecule/pdf'
|
16
|
-
require 'distorted-jekyll/molecule/svg'
|
17
|
-
require 'distorted-jekyll/molecule/video'
|
18
|
-
require 'distorted-jekyll/molecule/lastresort'
|
19
|
-
|
20
|
-
# Set.to_hash
|
21
|
-
require 'distorted/monkey_business/set'
|
22
|
-
|
23
14
|
# Slip in and out of phenomenon
|
24
15
|
require 'liquid/tag'
|
25
16
|
require 'liquid/tag/parser'
|
17
|
+
require 'distorted-jekyll/liquid_liquid'
|
18
|
+
|
19
|
+
require 'distorted-jekyll/media_molecule'
|
26
20
|
|
27
21
|
# Explicitly required for l/t/parser since a1cfa27c27cf4d4c308da2f75fbae88e9d5ae893
|
28
22
|
require 'shellwords'
|
29
23
|
|
30
24
|
# Set is in stdlib but is not in core.
|
31
25
|
require 'set'
|
26
|
+
# Set.to_hash
|
27
|
+
require 'distorted/monkey_business/set'
|
32
28
|
|
33
29
|
# I mean, this is why we're here, right?
|
34
30
|
require 'jekyll'
|
35
31
|
|
36
32
|
|
37
|
-
|
38
|
-
module DistorteD
|
39
|
-
class Invoker < Liquid::Tag
|
40
|
-
|
41
|
-
GEM_ROOT = File.dirname(__FILE__).freeze
|
42
|
-
|
43
|
-
# Mix in config-loading methods.
|
44
|
-
include Jekyll::DistorteD::Floor
|
45
|
-
include Jekyll::DistorteD::StaticState
|
46
|
-
|
47
|
-
# Enabled media_type drivers. These will be attempted back to front.
|
48
|
-
# TODO: Make this configurable.
|
49
|
-
MEDIA_MOLECULES = [
|
50
|
-
Jekyll::DistorteD::Molecule::LastResort,
|
51
|
-
Jekyll::DistorteD::Molecule::Font,
|
52
|
-
Jekyll::DistorteD::Molecule::Text,
|
53
|
-
Jekyll::DistorteD::Molecule::PDF,
|
54
|
-
Jekyll::DistorteD::Molecule::SVG,
|
55
|
-
Jekyll::DistorteD::Molecule::Video,
|
56
|
-
Jekyll::DistorteD::Molecule::Image,
|
57
|
-
]
|
58
|
-
# Reduce the above to a Hash of Sets of MediaMolecules-per-Type, keyed by Type.
|
59
|
-
TYPE_MOLECULES = MEDIA_MOLECULES.reduce(
|
60
|
-
Hash.new{|hash, key| hash[key] = Set[]}
|
61
|
-
) { |types, molecule|
|
62
|
-
if molecule.const_defined?(:LOWER_WORLD)
|
63
|
-
molecule.const_get(:LOWER_WORLD).each { |t|
|
64
|
-
types.update(t => Set[molecule]) { |k,o,n| o.merge(n) }
|
65
|
-
}
|
66
|
-
end
|
67
|
-
types
|
68
|
-
}
|
33
|
+
class Jekyll::DistorteD::Invoker < Liquid::Tag
|
69
34
|
|
70
|
-
|
71
|
-
# totally arbitrary length, or if the attr key is in the plugged
|
72
|
-
# Molecule's set of attrs that take only a defined set of values.
|
73
|
-
# My chosen boundary length fits all of the outer-limit tag names I use,
|
74
|
-
# like 'medium'. It fits the longest value of Vips::Interesting too,
|
75
|
-
# though `crop` will be symbolized based on the other condition.
|
76
|
-
ARBITRARY_ATTR_SYMBOL_STRING_LENGTH_BOUNDARY = 13
|
77
|
-
|
78
|
-
|
79
|
-
# 𝘏𝘖𝘞 𝘈𝘙𝘌 𝘠𝘖𝘜 𝘎𝘌𝘕𝘛𝘓𝘌𝘔𝘌𝘕 !!
|
80
|
-
def initialize(tag_name, arguments, liquid_options)
|
81
|
-
super
|
82
|
-
# Tag name as given to Liquid::Template.register_tag().
|
83
|
-
@tag_name = tag_name.to_sym
|
84
|
-
|
85
|
-
# Liquid leaves argument parsing totally up to us.
|
86
|
-
# Use the envygeeks/liquid-tag-parser library to wrangle them.
|
87
|
-
parsed_arguments = Liquid::Tag::Parser.new(arguments)
|
88
|
-
|
89
|
-
# Filename is the only non-keyword argument our tag should ever get.
|
90
|
-
# It's spe-shul and gets its own definition outside the attr loop.
|
91
|
-
if parsed_arguments.key?(:src)
|
92
|
-
@name = parsed_arguments.delete(:src)
|
93
|
-
else
|
94
|
-
@name = parsed_arguments.delete(:argv1)
|
95
|
-
end
|
96
|
-
@liquid_liquid = parsed_arguments.select{ |attr, val|
|
97
|
-
not [nil, ''.freeze].include?(val)
|
98
|
-
}.transform_keys { |attr|
|
99
|
-
attr.length <= ARBITRARY_ATTR_SYMBOL_STRING_LENGTH_BOUNDARY ? attr.to_sym : attr.freeze
|
100
|
-
}.transform_values { |val|
|
101
|
-
if val.respond_to?(:length)
|
102
|
-
val.length <= ARBITRARY_ATTR_SYMBOL_STRING_LENGTH_BOUNDARY ? val.to_sym : val.freeze
|
103
|
-
else
|
104
|
-
val
|
105
|
-
end
|
106
|
-
}
|
35
|
+
GEM_ROOT = File.dirname(__FILE__).freeze
|
107
36
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
raise "Failed to get a usable filename from #{arguments}"
|
112
|
-
end
|
37
|
+
include Jekyll::DistorteD::Setting # Config-loading methods.
|
38
|
+
include Jekyll::DistorteD::StaticState # Jekyll::StaticFile impersonation methods.
|
39
|
+
include Cooltrainer::DistorteD::Invoker # Instance-setup methods.
|
113
40
|
|
114
|
-
end
|
115
41
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
if mime.empty?
|
122
|
-
if Jekyll::DistorteD::Floor::config(Jekyll::DistorteD::Floor::CONFIG_ROOT, :last_resort)
|
123
|
-
mime = Jekyll::DistorteD::Molecule::LastResort::LOWER_WORLD
|
124
|
-
end
|
125
|
-
end
|
126
|
-
mime
|
127
|
-
end
|
128
|
-
end
|
42
|
+
# 𝘏𝘖𝘞 𝘈𝘙𝘌 𝘠𝘖𝘜 𝘎𝘌𝘕𝘛𝘓𝘌𝘔𝘌𝘕 !!
|
43
|
+
def initialize(tag_name, arguments, liquid_options)
|
44
|
+
super
|
45
|
+
# Tag name as given to Liquid::Template.register_tag().
|
46
|
+
@tag_name = tag_name.to_sym
|
129
47
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
def user_arguments
|
134
|
-
@liquid_liquid || Hash[]
|
135
|
-
end
|
48
|
+
# Liquid leaves argument parsing totally up to us.
|
49
|
+
# Use the envygeeks/liquid-tag-parser library to wrangle them.
|
50
|
+
parsed_arguments = Liquid::Tag::Parser.new(arguments)
|
136
51
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
when 1
|
145
|
-
return TYPE_MOLECULES[available_molecules.first].first
|
146
|
-
end
|
147
|
-
end
|
52
|
+
# Filename is the only non-keyword argument our tag should ever get.
|
53
|
+
# It's spe-shul and gets its own definition outside the attr loop.
|
54
|
+
if parsed_arguments.key?(:src)
|
55
|
+
@name = parsed_arguments.delete(:src)
|
56
|
+
else
|
57
|
+
@name = parsed_arguments.delete(:argv1)
|
58
|
+
end
|
148
59
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
60
|
+
# Load contextual variables for abstract()
|
61
|
+
@tag_arguments = parsed_arguments.select{ |attr, val|
|
62
|
+
not [nil, ''.freeze].include?(val)
|
63
|
+
}.transform_keys(&:to_sym).transform_values { |val|
|
64
|
+
case val
|
65
|
+
when 'true' then true
|
66
|
+
when 'false' then false
|
67
|
+
when String then (val.length <= Jekyll::DistorteD::ARBITRARY_ATTR_SYMBOL_STRING_LENGTH_BOUNDARY) ? val.to_sym : val.freeze
|
68
|
+
else val
|
155
69
|
end
|
70
|
+
}
|
156
71
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
72
|
+
# If we didn't get one of the two above options there is nothing we
|
73
|
+
# can do but bail.
|
74
|
+
unless @name
|
75
|
+
raise "Failed to get a usable filename from #{arguments}"
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
164
79
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
# then pass it along to our StaticFile subclass.
|
172
|
-
@site = context.registers[:site]
|
173
|
-
|
174
|
-
# The rendering context's `first` page will be the one that invoked us.
|
175
|
-
page_data = context.environments.first['page'.freeze]
|
176
|
-
|
177
|
-
#
|
178
|
-
# Our subclass' additional args:
|
179
|
-
# dest - The String path to the generated `url` folder of the page HTML output
|
180
|
-
@base = @site.source
|
181
|
-
|
182
|
-
# `relative_path` doesn't seem to always exist, but `path` does? idk.
|
183
|
-
# I was testing with `relative_path` only with `_posts`, but it broke
|
184
|
-
# when I invoked DD on a _page. Both have `path`.
|
185
|
-
@dir = File.dirname(page_data['path'.freeze])
|
186
|
-
|
187
|
-
# Every one of Ruby's `File.directory?` / `Pathname.directory?` /
|
188
|
-
# `FileTest.directory?` methods actually tests that path on the
|
189
|
-
# real filesystem, but we shouldn't look at the FS here because
|
190
|
-
# this function gets called when the Site.dest directory does
|
191
|
-
# not exist yet!
|
192
|
-
# Hackily look at the last character to see if the URL is a
|
193
|
-
# directory (like configured on cooltrainer) or a `.html`
|
194
|
-
# (or other extension) like the default Jekyll config.
|
195
|
-
# Get the dirname if the url is not a dir itself.
|
196
|
-
@relative_dest = page_data['url'.freeze]
|
197
|
-
unless @relative_dest[-1] == Jekyll::DistorteD::Floor::PATH_SEPARATOR
|
198
|
-
@relative_dest = File.dirname(@relative_dest)
|
199
|
-
# Append the trailing slash so we don't have to do it
|
200
|
-
# in the Liquid templates.
|
201
|
-
@relative_dest << Jekyll::DistorteD::Floor::PATH_SEPARATOR
|
202
|
-
end
|
203
|
-
|
204
|
-
# Add our new file to the list that will be handled
|
205
|
-
# by Jekyll's built-in StaticFile generator.
|
206
|
-
@site.static_files << self
|
207
|
-
output
|
80
|
+
# Returns a Set of DD MIME::Types descriving our file,
|
81
|
+
# optionally falling through to a plain file copy.
|
82
|
+
def type_mars
|
83
|
+
@type_mars ||= (CHECKING::YOU::OUT(path, so_deep: true) & lower_world.keys.to_set).tap { |gemini|
|
84
|
+
if gemini.empty? && the_setting_sun(:never_let_you_down)
|
85
|
+
gemini << CHECKING::YOU::OUT['application/x.distorted.never-let-you-down']
|
208
86
|
end
|
87
|
+
}
|
88
|
+
raise MediaTypeNotImplementedError.new(@name) if @type_mars.empty?
|
89
|
+
@type_mars
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns an Array[Change] for every intended output Type
|
93
|
+
# and every variation (e.g. resolution, bitrate) on each Type.
|
94
|
+
def changes
|
95
|
+
# The available/desired output Media Types and (variations on those Types)
|
96
|
+
# are based on the input Type and the Molecule(s) available to service those Types.
|
97
|
+
# Use an Array, since order might be important here when generating many variations
|
98
|
+
# at multiple levels of the DistorteD stack, e.g. the actual files on the Floor level
|
99
|
+
# and the templates/markup here in the Jekyll level.
|
100
|
+
@changes ||= type_mars.each_with_object(Array[]) { |lower, wanted|
|
101
|
+
# Query our configuration for Type changes, e.g. image/webp to (image/png and image/webp).
|
102
|
+
# Handle empty sub_types by compacting and splatting a sub-Array.
|
103
|
+
change_config = the_setting_sun(:changes, *(lower.settings_paths))
|
104
|
+
# If there is no config, treat it as a change to the same Type as the input,
|
105
|
+
# otherwise instantiate each "mediatype/subtype" config String to a MIME::Type.
|
106
|
+
((change_config.nil? || change_config&.empty?) ? Set[lower] : change_config.map {|t| CHECKING::YOU::OUT[t]}).each { |type|
|
107
|
+
# Query our configuration again for variations on each Type.
|
108
|
+
# For example, one single image Type may want multiple resolutions to enable responsive <picture> tags,
|
109
|
+
# or a single video Type may want multiple bitrates for adaptive streaming.
|
110
|
+
limit_breaks = the_setting_sun(:outer_limits, *(type&.settings_paths)) || Array[Hash[]]
|
111
|
+
# Which MediaMolecule Modules support this Type as an output? Probably just one.
|
112
|
+
outer_limits.keep_if { |k, v| v.has_key?(type) }.keys.each { |molecule|
|
113
|
+
# As before, if there is nothing in the config just treat it as a Change to
|
114
|
+
# the full resolution/bitrate/whatever as the input, so this will always run at least once.
|
115
|
+
limit_breaks.each { |limit_break|
|
116
|
+
# Merge each variation's config with any/all attributes given to our Liquid Tag,
|
117
|
+
# as well as any Jekyll Stuff™ like the relative destination path.
|
118
|
+
change_arguments = limit_break.merge(Hash[:dir => @relative_dest]).merge(context_arguments)
|
119
|
+
# Each Change will carry instance Compound data in Atom Structs so we can avoid modifying
|
120
|
+
# the Compound Struct with any variation-specific values since they will be reused.
|
121
|
+
atoms = Hash.new
|
122
|
+
# We will always want an Atom from every Compound even if it only carries the :default.
|
123
|
+
Cooltrainer::DistorteD::IMPLANTATION(:OUTER_LIMITS, molecule)&.dig(type)&.each_pair { |aka, compound|
|
124
|
+
next if aka != compound.element # Skip alias Compounds since they will all be handled at once.
|
125
|
+
# Look for a user-given argument matching any supported alias of a Compound,
|
126
|
+
# and check those values against the Compound for validity.
|
127
|
+
atoms.store(compound.element, Cooltrainer::Atom.new(compound.isotopes.reduce(nil) { |value, isotope|
|
128
|
+
# TODO: valid?
|
129
|
+
value || change_arguments&.delete(isotope)
|
130
|
+
}, compound.default))
|
131
|
+
}
|
132
|
+
# After looping through the Compounds and calling :delete for matched values,
|
133
|
+
# this bag will be left with only the freeform non-Compound-associated arguments, if any.
|
134
|
+
# Separate those into arguments that match Change member names, and arguments that don't.
|
135
|
+
change_member_keys, atom_keys = change_arguments.keys.partition(&Cooltrainer::Change.members.method(:include?))
|
136
|
+
# Instantiate a no-default Atom for every remaining argument that isn't a Change member.
|
137
|
+
atom_keys.each { |attribute| atoms.store(attribute, Cooltrainer::Atom.new(change_arguments.delete(attribute), nil)) }
|
138
|
+
# Instantiate each variation of each Type into a Change struct
|
139
|
+
# that will handle some of the details like output-filename generation.
|
140
|
+
wanted.append(Cooltrainer::Change.new(type, src: @name, molecule: molecule, **change_arguments, **atoms))
|
141
|
+
}
|
142
|
+
}
|
143
|
+
}
|
144
|
+
wanted
|
145
|
+
}
|
146
|
+
end
|
209
147
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
# Use a given filename, or detect one based on media-type.
|
217
|
-
if name.nil?
|
218
|
-
# e.g. Jekyll::DistorteD::Molecule::Image -> 'image.liquid'
|
219
|
-
name = "#{self.singleton_class.instance_variable_get(:@media_molecule).name.gsub(/^.*::/, '').downcase}.liquid".freeze
|
220
|
-
elsif not name.include?('.liquid'.freeze)
|
221
|
-
# Support filename arguments with and without file extension.
|
222
|
-
# The given String might already be frozen, so concatenating
|
223
|
-
# the extension might fail. Just set a new version.
|
224
|
-
name = "#{name}.liquid"
|
225
|
-
end
|
226
|
-
template = File.join(
|
227
|
-
self.singleton_class.const_get(:GEM_ROOT),
|
228
|
-
'template'.freeze,
|
229
|
-
name,
|
230
|
-
)
|
231
|
-
|
232
|
-
# Jekyll's Liquid renderer caches in 4.0+.
|
233
|
-
if Jekyll::DistorteD::Floor::config(
|
234
|
-
Jekyll::DistorteD::Floor::CONFIG_ROOT,
|
235
|
-
:cache_templates,
|
236
|
-
)
|
237
|
-
# file(path) is the caching function, with path as the cache key.
|
238
|
-
# The `template` here will be the full path, so no versions of this
|
239
|
-
# gem should ever conflict. For example, right now during dev it's:
|
240
|
-
# `/home/okeeblow/Works/DistorteD/lib/image.liquid`
|
241
|
-
Jekyll.logger.debug('DistorteD', "Parsing #{template} with caching renderer.")
|
242
|
-
site.liquid_renderer.file(template).parse(File.read(template))
|
243
|
-
else
|
244
|
-
# Re-read the template just for this piece of media.
|
245
|
-
Jekyll.logger.debug('DistorteD', "Parsing #{template} with fresh (uncached) renderer.")
|
246
|
-
Liquid::Template.parse(File.read(template))
|
247
|
-
end
|
248
|
-
|
249
|
-
rescue Liquid::SyntaxError => l
|
250
|
-
# This shouldn't ever happen unless a new version of Liquid
|
251
|
-
# breaks syntax compatibility with our templates somehow.
|
252
|
-
l.message
|
253
|
-
end
|
254
|
-
end # parse_template
|
148
|
+
# Return any arguments given by the user to our Liquid tag.
|
149
|
+
# This method name is generic across all DD entrypoints so it can be
|
150
|
+
# referenced from lower layers in the pile.
|
151
|
+
def context_arguments
|
152
|
+
@tag_arguments ||= Hash[]
|
153
|
+
end
|
255
154
|
|
155
|
+
# Returns a context-only setting from our Liquid attributes.
|
156
|
+
def abstract(key)
|
157
|
+
context_arguments.dig(key)
|
158
|
+
end
|
256
159
|
|
160
|
+
# Called by Jekyll::Renderer
|
161
|
+
# https://github.com/jekyll/jekyll/blob/HEAD/lib/jekyll/renderer.rb
|
162
|
+
# https://jekyllrb.com/tutorials/orderofinterpretation/
|
163
|
+
def render(context)
|
164
|
+
# Get Jekyll Site object back from tag rendering context registers so we
|
165
|
+
# can get configuration data and path information from it and
|
166
|
+
# then pass it along to our StaticFile subclass.
|
167
|
+
@site = context.registers[:site]
|
168
|
+
|
169
|
+
# The rendering context's `first` page will be the one that invoked us.
|
170
|
+
page_data = context.environments.first['page'.freeze]
|
171
|
+
|
172
|
+
#
|
173
|
+
# Our subclass' additional args:
|
174
|
+
# dest - The String path to the generated `url` folder of the page HTML output
|
175
|
+
@base = @site.source
|
176
|
+
|
177
|
+
# `relative_path` doesn't seem to always exist, but `path` does? idk.
|
178
|
+
# I was testing with `relative_path` only with `_posts`, but it broke
|
179
|
+
# when I invoked DD on a _page. Both have `path`.
|
180
|
+
@dir = File.dirname(page_data['path'.freeze])
|
181
|
+
|
182
|
+
# Every one of Ruby's `File.directory?` / `Pathname.directory?` /
|
183
|
+
# `FileTest.directory?` methods actually tests that path on the
|
184
|
+
# real filesystem, but we shouldn't look at the FS here because
|
185
|
+
# this function gets called when the Site.dest directory does
|
186
|
+
# not exist yet!
|
187
|
+
# Hackily look at the last character to see if the URL is a
|
188
|
+
# directory (like configured on cooltrainer) or a `.html`
|
189
|
+
# (or other extension) like the default Jekyll config.
|
190
|
+
# Get the dirname if the url is not a dir itself.
|
191
|
+
@relative_dest = page_data['url'.freeze]
|
192
|
+
unless @relative_dest[-1] == Jekyll::DistorteD::PATH_SEPARATOR
|
193
|
+
@relative_dest = File.dirname(@relative_dest)
|
194
|
+
# Append the trailing slash so we don't have to do it
|
195
|
+
# in the Liquid templates.
|
196
|
+
@relative_dest << Jekyll::DistorteD::PATH_SEPARATOR
|
257
197
|
end
|
198
|
+
|
199
|
+
# Add our new file to the list that will be handled
|
200
|
+
# by Jekyll's built-in StaticFile generator.
|
201
|
+
@site.static_files << self
|
202
|
+
render_to_output_buffer(context, '')
|
258
203
|
end
|
204
|
+
|
205
|
+
# A future Liquid version (5.0?) will call this function directly
|
206
|
+
# instead of calling render()
|
207
|
+
def render_to_output_buffer(context, output)
|
208
|
+
roots_of_my_way = Cooltrainer::ElementalCreation.new(:root).tap { |wrapper|
|
209
|
+
wrapper.dan = "distorted #{changes.reduce(Set[]) { |classes, change|
|
210
|
+
classes.add(change.molecule&.name.split('::'.freeze).last.downcase)
|
211
|
+
classes.add(change.type.sub_type.to_s.split(MIME::Type::SUB_TYPE_SEPARATORS)[0])
|
212
|
+
}.to_a.join(' ')}"
|
213
|
+
}
|
214
|
+
|
215
|
+
changes&.each { |change|
|
216
|
+
unless self.respond_to_missing?(change.type.distorted_template_method)
|
217
|
+
Jekyll.logger.error(@name, "Missing template method #{change.type.distorted_template_method}")
|
218
|
+
raise MediaTypeOutputNotImplementedError.new(@name, type_mars, self.class.name)
|
219
|
+
end
|
220
|
+
Jekyll.logger.debug("DistorteD::#{change.type.distorted_template_method}", File.join(change.dir, change.name))
|
221
|
+
|
222
|
+
# Get an ElementalCreation Struct from the MediaMolecule's render method.
|
223
|
+
# WISHLIST: Remove the empty final positional Hash argument once we require a Ruby version
|
224
|
+
# that will not perform the implicit Change-to-Hash conversion due to Change's
|
225
|
+
# implementation of :to_hash. Ruby 2.7 will complain but still do the conversion,
|
226
|
+
# breaking downstream callers that want a Struct they can call arbitrary key methods on.
|
227
|
+
# https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/
|
228
|
+
roots_of_my_way.mad_child(self.send(change.type.distorted_template_method, change, **{}))
|
229
|
+
}
|
230
|
+
|
231
|
+
output << roots_of_my_way.render
|
232
|
+
end
|
233
|
+
|
259
234
|
end
|