distorted-jekyll 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/distorted-jekyll.rb +0 -4
  4. data/lib/distorted-jekyll/{template/13th-style.css → 13th-style.css} +0 -0
  5. data/lib/distorted-jekyll/13th-style.rb +1 -1
  6. data/lib/distorted-jekyll/_config_default.yml +3 -21
  7. data/lib/distorted-jekyll/invoker.rb +194 -219
  8. data/lib/distorted-jekyll/liquid_liquid.rb +255 -0
  9. data/lib/distorted-jekyll/liquid_liquid/anchor.liquid +5 -0
  10. data/lib/distorted-jekyll/liquid_liquid/anchor_inline.liquid +1 -0
  11. data/lib/distorted-jekyll/liquid_liquid/embed.liquid +1 -0
  12. data/lib/distorted-jekyll/liquid_liquid/img.liquid +1 -0
  13. data/lib/distorted-jekyll/liquid_liquid/object.liquid +5 -0
  14. data/lib/distorted-jekyll/liquid_liquid/picture.liquid +15 -0
  15. data/lib/distorted-jekyll/liquid_liquid/picture.rb +48 -0
  16. data/lib/distorted-jekyll/liquid_liquid/picture_source.liquid +1 -0
  17. data/lib/distorted-jekyll/liquid_liquid/root.liquid +5 -0
  18. data/lib/distorted-jekyll/liquid_liquid/video.liquid +5 -0
  19. data/lib/distorted-jekyll/liquid_liquid/video_source.liquid +1 -0
  20. data/lib/distorted-jekyll/md_injection.rb +30 -25
  21. data/lib/distorted-jekyll/media_molecule.rb +20 -0
  22. data/lib/distorted-jekyll/media_molecule/font.rb +21 -0
  23. data/lib/distorted-jekyll/media_molecule/image.rb +15 -0
  24. data/lib/distorted-jekyll/media_molecule/never_let_you_down.rb +28 -0
  25. data/lib/distorted-jekyll/media_molecule/pdf.rb +108 -0
  26. data/lib/distorted-jekyll/media_molecule/svg.rb +20 -0
  27. data/lib/distorted-jekyll/media_molecule/text.rb +23 -0
  28. data/lib/distorted-jekyll/media_molecule/video.rb +45 -0
  29. data/lib/distorted-jekyll/monkey_business/jekyll/cleaner.rb +68 -1
  30. data/lib/distorted-jekyll/static_state.rb +19 -60
  31. data/lib/distorted-jekyll/the_setting_sun.rb +179 -0
  32. metadata +26 -21
  33. data/lib/distorted-jekyll/floor.rb +0 -266
  34. data/lib/distorted-jekyll/molecule/font.rb +0 -62
  35. data/lib/distorted-jekyll/molecule/image.rb +0 -94
  36. data/lib/distorted-jekyll/molecule/lastresort.rb +0 -51
  37. data/lib/distorted-jekyll/molecule/pdf.rb +0 -79
  38. data/lib/distorted-jekyll/molecule/svg.rb +0 -47
  39. data/lib/distorted-jekyll/molecule/text.rb +0 -62
  40. data/lib/distorted-jekyll/molecule/video.rb +0 -85
  41. data/lib/distorted-jekyll/template/error_code.liquid +0 -3
  42. data/lib/distorted-jekyll/template/font.liquid +0 -32
  43. data/lib/distorted-jekyll/template/image.liquid +0 -32
  44. data/lib/distorted-jekyll/template/lastresort.liquid +0 -20
  45. data/lib/distorted-jekyll/template/pdf.liquid +0 -14
  46. data/lib/distorted-jekyll/template/svg.liquid +0 -32
  47. data/lib/distorted-jekyll/template/text.liquid +0 -32
  48. data/lib/distorted-jekyll/template/video.liquid +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5eaf5c713e61dd6cea6fee1d1cb031b7ec25331e8cdeb9aa79f1ea96c61d94a8
4
- data.tar.gz: '068625124864b575107596d9b91761171eecdb76cdaf8f34a66fa37f4d34b69e'
3
+ metadata.gz: a5fe548492f52f0b4bb138fbd93ca2fb127f53baf7a3657d73aefc904c22a51b
4
+ data.tar.gz: 2444637db29356d306f2e1e31a41b0fe9c758574d77bc40d691f51c0ab514af5
5
5
  SHA512:
6
- metadata.gz: 4b55e4771aadea12c70adf95995432b4cff70cf0548b06ae76dcb8a55f11de273531a3f2def6be56de9b7043a9f752a6f7d7cc1f66299475409ac269be80dc77
7
- data.tar.gz: 4c152988ef67bd5717429578de241169b13f7ffee38cb255979184e2b3cdf4d551d1b50d9c4472ca98bbb9695d8892f09b0b2d9d0e2a02deeeb1dd54d8415f66
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-Ruby` Gem if used in this way.
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
 
@@ -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'
@@ -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__), 'template'.freeze, '13th-style.css'.freeze)
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
- - tag: full
10
- crop: none
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
- last_resort: true
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/floor'
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
- module Jekyll
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
- # Any any attr value will get a to_sym if shorter than this
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
- # If we didn't get one of the two above options there is nothing we
109
- # can do but bail.
110
- unless @name
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
- # Returns a Set of DD MIME::Types descriving our file,
117
- # optionally falling through to a plain file copy.
118
- def type_mars
119
- @type_mars ||= begin
120
- mime = CHECKING::YOU::OUT(@name)
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
- # Return any arguments given by the user to our Liquid tag.
131
- # This method name is generic across all DD entrypoints so it can be
132
- # referenced from lower layers in the pile.
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
- # Decides which MediaMolecule is most appropriate for our file and returns it.
138
- def media_molecule
139
- available_molecules = TYPE_MOLECULES.keys.to_set & type_mars
140
- # TODO: Handle multiple molecules for the same file
141
- case available_molecules.length
142
- when 0
143
- raise MediaTypeNotImplementedError.new(@name)
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
- def plug
150
- unless self.singleton_class.instance_variable_defined?(:@media_molecule)
151
- self.singleton_class.instance_variable_set(:@media_molecule, media_molecule)
152
- self.singleton_class.prepend(media_molecule)
153
- Jekyll.logger.info(@name, "Plugging #{media_molecule}")
154
- end
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
- # Called by Jekyll::Renderer
158
- # https://github.com/jekyll/jekyll/blob/HEAD/lib/jekyll/renderer.rb
159
- # https://jekyllrb.com/tutorials/orderofinterpretation/
160
- def render(context)
161
- plug
162
- render_to_output_buffer(context, '')
163
- end
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
- # A future Liquid version (5.0?) will call this function directly
166
- # instead of calling render()
167
- def render_to_output_buffer(context, output)
168
- plug
169
- # Get Jekyll Site object back from tag rendering context registers so we
170
- # can get configuration data and path information from it and
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
- # Generic Liquid template loader that will be used in every MediaMolecule.
211
- # Callers will call `render(**{:template => vars})` on the Object returned
212
- # by this method.
213
- def parse_template(site: nil, name: nil)
214
- site = site || @site || Jekyll.sites.first
215
- begin
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