distorted-jekyll 0.5.3 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +661 -0
- data/README.md +6 -10
- data/lib/distorted-jekyll.rb +79 -0
- data/lib/distorted-jekyll/13th-style.rb +58 -0
- data/lib/distorted-jekyll/_config_default.yml +81 -0
- data/lib/distorted-jekyll/blocks.rb +16 -0
- data/lib/distorted-jekyll/floor.rb +266 -0
- data/lib/distorted-jekyll/invoker.rb +259 -0
- data/lib/distorted-jekyll/md_injection.rb +305 -0
- data/lib/distorted-jekyll/molecule/font.rb +62 -0
- data/lib/distorted-jekyll/molecule/image.rb +94 -0
- data/lib/distorted-jekyll/molecule/lastresort.rb +51 -0
- data/lib/distorted-jekyll/molecule/pdf.rb +79 -0
- data/lib/distorted-jekyll/molecule/svg.rb +47 -0
- data/lib/distorted-jekyll/molecule/text.rb +62 -0
- data/lib/distorted-jekyll/molecule/video.rb +85 -0
- data/lib/distorted-jekyll/monkey_business/jekyll/cleaner.rb +54 -0
- data/lib/distorted-jekyll/static_state.rb +201 -0
- data/lib/distorted-jekyll/template/13th-style.css +79 -0
- data/lib/distorted-jekyll/template/error_code.liquid +3 -0
- data/lib/distorted-jekyll/template/font.liquid +32 -0
- data/lib/distorted-jekyll/template/image.liquid +32 -0
- data/lib/distorted-jekyll/template/lastresort.liquid +20 -0
- data/lib/distorted-jekyll/template/pdf.liquid +14 -0
- data/lib/distorted-jekyll/template/svg.liquid +32 -0
- data/lib/distorted-jekyll/template/text.liquid +32 -0
- data/lib/distorted-jekyll/template/video.liquid +11 -0
- metadata +32 -34
data/README.md
CHANGED
@@ -1,19 +1,16 @@
|
|
1
|
-
#
|
1
|
+
# Jekyll::DistorteD
|
2
2
|
|
3
|
-
`DistorteD` is a multimedia framework for Jekyll websites.
|
4
|
-
|
5
|
-
Right now this repo contains two Gems:
|
6
|
-
- [`DistorteD-Jekyll`](https://rubygems.org/gems/distorted-jekyll) contains anything and everything that depends on Jekyll.
|
7
|
-
- [`DistorteD-Ruby`](https://rubygems.org/gems/distorted) contains just the abstract media file format handling code. It's separate so I can use those functions in other contexts and/or easily replace the Ruby core if necessary.
|
3
|
+
`DistorteD-Jekyll` is a multimedia framework for Jekyll websites.
|
8
4
|
|
9
5
|
## Motivation
|
10
6
|
|
11
|
-
|
7
|
+
DistorteD is my solution for displaying photos, videos, and other types of media on [cooltrainer.org](https://cooltrainer.org) due to my dissatisfaction with every other solution I could find.
|
12
8
|
|
13
9
|
My previous approach was similar to what's [described here](https://eduardoboucas.com/blog/2014/12/07/including-and-managing-images-in-jekyll.html), with small/medium/large image size variations generated with [Jekyll-MiniMagick](https://github.com/MattKevan/Jekyll-MiniMagick-new).
|
14
10
|
|
15
11
|
Here are some already-existing ways to put pictures on your Jekyll site that are worth your consideration before choosing DistorteD:
|
16
12
|
|
13
|
+
- Octopress' [image_tag](https://github.com/imathis/octopress/blob/master/plugins/image_tag.rb) plugin.
|
17
14
|
- [jekyll-responsive-image](https://github.com/wildlyinaccurate/jekyll-responsive-image)
|
18
15
|
- [jekyll_picture_tag](https://rbuchberger.github.io/jekyll_picture_tag/)
|
19
16
|
- [jekyll-gallery-generator](https://github.com/ggreer/jekyll-gallery-generator)
|
@@ -95,7 +92,7 @@ will be transformed into.
|
|
95
92
|
%}
|
96
93
|
```
|
97
94
|
|
98
|
-
|
95
|
+
or, for a DD grid:
|
99
96
|
|
100
97
|
```
|
101
98
|
{% distort %}
|
@@ -157,11 +154,10 @@ Clone the DistorteD repository and modify your Jekyll `Gemfile` to refer to your
|
|
157
154
|
|
158
155
|
```
|
159
156
|
gem 'distorted-jekyll', :path => '~/repos/DistorteD/DistorteD-Jekyll/'[, :branch => 'NEW-SENSATION']
|
160
|
-
gem 'distorted', :path => '~/repos/DistorteD/DistorteD-Ruby/'[, :branch => 'NEW-SENSATION']
|
161
157
|
```
|
162
158
|
|
163
159
|
The `DistorteD-Jekyll` Gem will automatically use its local sibling `DistorteD-Ruby` Gem if used in this way.
|
164
160
|
|
165
161
|
## License
|
166
162
|
|
167
|
-
|
163
|
+
The gem is available as open source under the terms of the [GNU Affero General Public License version 3](https://opensource.org/licenses/AGPL-3.0).
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'distorted-jekyll/13th-style'
|
2
|
+
require 'distorted-jekyll/blocks'
|
3
|
+
require 'distorted-jekyll/md_injection'
|
4
|
+
require 'distorted-jekyll/invoker'
|
5
|
+
|
6
|
+
|
7
|
+
FATAL_FURY = true
|
8
|
+
UPDATE_RUBY = "Please use DistorteD with Ruby 2.7.0 or later"
|
9
|
+
def update_ruby
|
10
|
+
if defined? RUBY_PLATFORM
|
11
|
+
if (/freebsd/ =~ RUBY_PLATFORM) != nil
|
12
|
+
return 'pkg install lang/ruby27'
|
13
|
+
elsif (/darwin/ =~ RUBY_PLATFORM) != nil
|
14
|
+
return 'brew upgrade ruby'
|
15
|
+
elsif (/win/ =~ RUBY_PLATFORM) != nil
|
16
|
+
return 'https://rubyinstaller.org/'
|
17
|
+
elsif (/linux/ =~ RUBY_PLATFORM) != nil
|
18
|
+
if File.exists?('/etc/lsb-release')
|
19
|
+
lsb = File.read('/etc/lsb-release')
|
20
|
+
if (/Ubuntu|LinuxMint/ =~ lsb) != nil
|
21
|
+
return 'https://www.brightbox.com/docs/ruby/ubuntu/#installation'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
return 'https://github.com/rbenv/ruby-build'
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
# I want to be able to use:
|
31
|
+
# - Array#dig and Hash#dig (Ruby 2.3): https://bugs.ruby-lang.org/issues/11643
|
32
|
+
# - Lonely operator (Ruby 2.3): https://bugs.ruby-lang.org/issues/11537
|
33
|
+
# - Hash#transform_keys (Ruby 2.5): https://bugs.ruby-lang.org/issues/13583
|
34
|
+
# - Enumerable#filter_map (Ruby 2.7): https://bugs.ruby-lang.org/issues/5663
|
35
|
+
# https://blog.saeloun.com/2019/05/25/ruby-2-7-enumerable-filter-map.html
|
36
|
+
# - 'Real' kwargs in preparation for Ruby 3: https://bugs.ruby-lang.org/issues/14183
|
37
|
+
# https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/
|
38
|
+
if [
|
39
|
+
Hash.method_defined?(:dig), # 2.3
|
40
|
+
Hash.method_defined?(:transform_keys), # 2.5
|
41
|
+
Enumerable.method_defined?(:filter_map), # 2.7
|
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
|
+
# Monkey-patch Jekyll::Cleaner to not nuke DistorteD-generated variations
|
48
|
+
# for our media files. This makes DistorteD fast!
|
49
|
+
require 'distorted-jekyll/monkey_business/jekyll/cleaner'
|
50
|
+
|
51
|
+
# Register DistorteD's entrypoint class with Liquid.
|
52
|
+
# `Invoker` will mix in the proper handler module for the given media.
|
53
|
+
Liquid::Template.register_tag('distorted', Jekyll::DistorteD::Invoker)
|
54
|
+
|
55
|
+
# Register a block version for arranging multiple pieces of media.
|
56
|
+
Liquid::Template.register_tag('distort', Jekyll::DistorteD::BLOCKS)
|
57
|
+
|
58
|
+
# Register a tag for basic DistorteD CSS.
|
59
|
+
Liquid::Template.register_tag('13th_style', Jekyll::DistorteD::ThirteenthStyle)
|
60
|
+
|
61
|
+
# Transform Markdown image syntax ![alt](url.jpg "title")
|
62
|
+
# to instances of our liquid tag {% distorted %}
|
63
|
+
# Available hooks can be seen here:
|
64
|
+
# https://github.com/jekyll/jekyll/blob/master/lib/jekyll/hooks.rb
|
65
|
+
# `:documents` does not seem to include `_pages` but does include `_posts`.
|
66
|
+
Jekyll::Hooks.register(:pages, :pre_render, &md_injection)
|
67
|
+
Jekyll::Hooks.register(:posts, :pre_render, &md_injection)
|
68
|
+
|
69
|
+
else
|
70
|
+
# Example of how this looks with the outdated Ruby 2.5 on my Mint 19 laptop:
|
71
|
+
#
|
72
|
+
# Bundler::GemRequireError: There was an error while trying to load the gem 'distorted-jekyll'.
|
73
|
+
# Gem Load Error is: Please use DistorteD with Ruby 2.7.0 or later: https://www.brightbox.com/docs/ruby/ubuntu/#installation
|
74
|
+
if FATAL_FURY
|
75
|
+
raise RuntimeError.new("#{UPDATE_RUBY}: #{update_ruby}")
|
76
|
+
else
|
77
|
+
Jekyll.logger.info('DistorteD', "#{UPDATE_RUBY}: #{update_ruby}")
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
|
2
|
+
# Slip in and out of phenomenon
|
3
|
+
require 'liquid/tag'
|
4
|
+
require 'liquid/tag/parser'
|
5
|
+
|
6
|
+
# Explicitly required for l/t/parser since a1cfa27c27cf4d4c308da2f75fbae88e9d5ae893
|
7
|
+
require 'shellwords'
|
8
|
+
|
9
|
+
|
10
|
+
module Jekyll
|
11
|
+
module DistorteD
|
12
|
+
class ThirteenthStyle < Liquid::Tag
|
13
|
+
|
14
|
+
TAB_SEQUENCE = ' '.freeze # two spaces
|
15
|
+
|
16
|
+
def initialize(tag_name, arguments, liquid_options)
|
17
|
+
super
|
18
|
+
|
19
|
+
# Liquid leaves argument parsing totally up to us.
|
20
|
+
# Use the envygeeks/liquid-tag-parser library to wrangle them.
|
21
|
+
parsed_arguments = Liquid::Tag::Parser.new(arguments)
|
22
|
+
|
23
|
+
# Specify how many levels to indent printed output.
|
24
|
+
# Indentation will apply to all lines after the first,
|
25
|
+
# because the first line's output will fall at the same
|
26
|
+
# place as our Liquid tag invocation.
|
27
|
+
@tabs = parsed_arguments[:tabs] || 0
|
28
|
+
end
|
29
|
+
|
30
|
+
# This is going to go away in a future Liquid version
|
31
|
+
# and render_to_output_buffer will be the standard approach.
|
32
|
+
# I'm going ahead and using it since we are building strings here.
|
33
|
+
def render(context)
|
34
|
+
return render_to_output_buffer(context, '')
|
35
|
+
end
|
36
|
+
|
37
|
+
def render_to_output_buffer(context, output)
|
38
|
+
css_filename = File.join(File.dirname(__FILE__), 'template'.freeze, '13th-style.css'.freeze)
|
39
|
+
|
40
|
+
# Use IO.foreach() to call a block on each line of our template file
|
41
|
+
# without slurping the entire file into memory like File.read() / File.readlines()
|
42
|
+
File.foreach(css_filename).with_index do |line, line_num|
|
43
|
+
# Don't indent the first line of the CSS file, because the first line
|
44
|
+
# will print starting at the position of our {% 13thStyle %} Liquid tag.
|
45
|
+
unless line_num == 0
|
46
|
+
output << TAB_SEQUENCE * @tabs
|
47
|
+
end
|
48
|
+
output << line
|
49
|
+
end
|
50
|
+
# Remove CSS comments from output so I can leave notes there
|
51
|
+
# without bloating up my output.
|
52
|
+
# Based on C-shebang-style comment regex from MRE3
|
53
|
+
return output.gsub(/\/\*[^*]*\*+(?:[^*\/][^*]*\*+)*\//, '')
|
54
|
+
end
|
55
|
+
|
56
|
+
end # ThirteenthStyle
|
57
|
+
end # DistorteD
|
58
|
+
end # Jekyll
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Override any or all of this default configuration in your Jekyll site's `_config.yml`!
|
2
|
+
|
3
|
+
# Is it possible to do a Set of Hashes using the Set syntax in YAML?
|
4
|
+
# It works with the Array syntax, so that's what I'm using here,
|
5
|
+
# but keep in mind any Arrays will be converted to Sets when loaded,
|
6
|
+
# so duplicate Array values will be compacted!
|
7
|
+
|
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
|
+
|
24
|
+
|
25
|
+
distorted:
|
26
|
+
|
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
|
+
# Should unrecognized media-types fall back to a bare
|
33
|
+
# <img> tag around the original media file?
|
34
|
+
# If not, the site build will fail when an unrecognized
|
35
|
+
# file is encountered.
|
36
|
+
last_resort: true
|
37
|
+
|
38
|
+
# Configure DistorteD format changes by media_type, then by sub_type.
|
39
|
+
# The list of target formats is plain text, media_type/sub_type.
|
40
|
+
# These are mostly based on IANA's official Media Types list:
|
41
|
+
# https://www.iana.org/assignments/media-types/media-types.xhtml
|
42
|
+
# but with some custom additions like using 'gif-sequence' for
|
43
|
+
# animated GIF and leaving 'image/gif' to refer to single-frame GIFs.
|
44
|
+
changes:
|
45
|
+
image:
|
46
|
+
jpeg:
|
47
|
+
? image/jpeg
|
48
|
+
? image/webp
|
49
|
+
png:
|
50
|
+
? image/png
|
51
|
+
? image/webp
|
52
|
+
gif:
|
53
|
+
? image/gif
|
54
|
+
? image/png
|
55
|
+
? image/webp
|
56
|
+
gif-sequence:
|
57
|
+
? image/gif-sequence
|
58
|
+
svg:
|
59
|
+
? image/svg+xml
|
60
|
+
? image/png
|
61
|
+
? image/webp
|
62
|
+
text:
|
63
|
+
plain:
|
64
|
+
? text/plain
|
65
|
+
? image/png
|
66
|
+
? image/webp
|
67
|
+
x-nfo:
|
68
|
+
? text/x-nfo
|
69
|
+
? image/png
|
70
|
+
? image/webp
|
71
|
+
font:
|
72
|
+
ttf:
|
73
|
+
? font/ttf
|
74
|
+
? image/png
|
75
|
+
? image/webp
|
76
|
+
|
77
|
+
outer_limits:
|
78
|
+
image:
|
79
|
+
jpeg: *standard_image
|
80
|
+
png: *standard_image
|
81
|
+
webp: *standard_image
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
module Jekyll
|
3
|
+
module DistorteD
|
4
|
+
class BLOCKS < Liquid::Block
|
5
|
+
|
6
|
+
def initialize(tag_name, arguments, liquid_options)
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def render(context)
|
11
|
+
"<div class=\"distorted-block\">#{super}</div>"
|
12
|
+
end
|
13
|
+
|
14
|
+
end # BLOCKS
|
15
|
+
end # DistorteD
|
16
|
+
end # Jekyll
|
@@ -0,0 +1,266 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'jekyll'
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
require 'distorted/monkey_business/hash'
|
6
|
+
require 'distorted/checking_you_out'
|
7
|
+
|
8
|
+
|
9
|
+
module Jekyll
|
10
|
+
module DistorteD
|
11
|
+
module Floor
|
12
|
+
|
13
|
+
ATTRIBUTES = Set[:lower_world, :changes, :outer_limits]
|
14
|
+
|
15
|
+
# Top-level config key (once stringified) for Jekyll and Default YAML.
|
16
|
+
CONFIG_ROOT = :distorted
|
17
|
+
|
18
|
+
# Filename for default config YAML. Should be a sibling of this file.
|
19
|
+
# Don't move this file or the YAML defaults without changing this.
|
20
|
+
DEFAULT_CONFIG_FILE_NAME = '_config_default.yml'.freeze
|
21
|
+
DEFAULT_CONFIG_PATH = File.join(File.dirname(__FILE__), DEFAULT_CONFIG_FILE_NAME).freeze
|
22
|
+
|
23
|
+
# Separator character for pretty-printing config hierarchy.
|
24
|
+
PP_SEPARATOR = "\u21e2 ".encode('utf-8').freeze
|
25
|
+
|
26
|
+
# Path separator is almost always '/' internally, but support
|
27
|
+
# ALT_SEPARATOR platforms too.
|
28
|
+
# On Lunix - Ruby 2.7:
|
29
|
+
# irb(main):003:0> File::ALT_SEPARATOR
|
30
|
+
# => nil
|
31
|
+
# irb(main):004:0> File::SEPARATOR
|
32
|
+
# => "/"
|
33
|
+
PATH_SEPARATOR = (File::ALT_SEPARATOR || File::SEPARATOR).freeze
|
34
|
+
|
35
|
+
|
36
|
+
# Generic main config-loading function that will search, in order:
|
37
|
+
# - The memoized pre-transformed config data store in-memory.
|
38
|
+
# - Jekyll's Site config, for a passed-in site or for the default site.
|
39
|
+
# - DistorteD's Gem-internal default config YAML.
|
40
|
+
#
|
41
|
+
# Optionally provide a class to be used as a fallback for missing keys.
|
42
|
+
def self.config(*keys, **kw)
|
43
|
+
# Symbolize for our internal representation of the config path.
|
44
|
+
# The Jekyll config and default config are both YAML, so we want string
|
45
|
+
# keys for them. Go ahead and prepend the top-level search key here too.
|
46
|
+
memo_keys = keys.compact.map(&:to_sym).to_set
|
47
|
+
search_keys = keys.compact.map(&:to_s).map(&:freeze)
|
48
|
+
# Pretty print the config path for logging.
|
49
|
+
log_key = search_keys.join(PP_SEPARATOR.to_s).freeze
|
50
|
+
# Initialize memoization class variable as a Hash that will return nil
|
51
|
+
# for any key access that doesn't already contain something.
|
52
|
+
@@memories ||= Hash.new { |h,k| h[k] = h.class.new(&h.default_proc) }
|
53
|
+
# Try to load a memoized config if we can, to skip any filesystem
|
54
|
+
# access and data transformation steps.
|
55
|
+
config = @@memories&.dig(*memo_keys)
|
56
|
+
unless config.nil?
|
57
|
+
if config.is_a?(TrueClass) || config.is_a?(FalseClass)
|
58
|
+
return config
|
59
|
+
elsif config.is_a?(Enumerable)
|
60
|
+
unless config.empty?
|
61
|
+
# Can't check this at the top level because True/FalseClass
|
62
|
+
# don't respond to this message.
|
63
|
+
return config
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# The key isn't memoized. Look for it first in Jekyll's Site config.
|
69
|
+
# Is it even possible to have more than one Site? Support being passed
|
70
|
+
# a `site` object just in case, but taking the first one should be fine.
|
71
|
+
site = kw[:site] || Jekyll.sites.first
|
72
|
+
# Get the config, or nil if the queried config path doesn't exist.
|
73
|
+
loaded_config = site.config.dig(*search_keys)
|
74
|
+
if loaded_config.nil?
|
75
|
+
# The wanted config key didn't exist in the Site config, so let's
|
76
|
+
# try our defaults!
|
77
|
+
# This file will always be small enough for a one-shot read.
|
78
|
+
default_config = YAML.load(File.read(DEFAULT_CONFIG_PATH))
|
79
|
+
loaded_config = default_config.dig(*search_keys)
|
80
|
+
unless loaded_config.nil?
|
81
|
+
Jekyll.logger.debug(['Default', log_key].join(PP_SEPARATOR.to_s).concat(':'.freeze), loaded_config)
|
82
|
+
end
|
83
|
+
else # else Jekyll _config is not nil
|
84
|
+
Jekyll.logger.debug(['_config', log_key].join(PP_SEPARATOR.to_s).concat(':'.freeze), loaded_config)
|
85
|
+
end
|
86
|
+
# Was the desired config key found in the Gem defaults?
|
87
|
+
if loaded_config.nil?
|
88
|
+
# Nope.
|
89
|
+
return nil
|
90
|
+
else
|
91
|
+
# Symbolize any output keys and values, and convert Arrays and Ruby::YAML
|
92
|
+
# Sets-as-Hashes to Ruby stdlib Sets.
|
93
|
+
# Returning a Set instead of an Array should be fine since none of our
|
94
|
+
# configs can (read: should) contain duplicate values for any reason.
|
95
|
+
loaded_config = symbolic(set_me_free(loaded_config))
|
96
|
+
end
|
97
|
+
# Memoize any of our own config, but just return anything outside our tree.
|
98
|
+
if keys.first == CONFIG_ROOT
|
99
|
+
@@memories.bury(*memo_keys, loaded_config)
|
100
|
+
Jekyll.logger.debug(log_key, "Memoizing config: #{@@memories.dig(*memo_keys)}")
|
101
|
+
# And return a config to the caller. Don't return the `new`ly fetched
|
102
|
+
# data directly to ensure consistency between this first fetch and
|
103
|
+
# subsequent memoized fetches, and to let callers take advantage of
|
104
|
+
# the memo Hash's `default_proc` setup.
|
105
|
+
return @@memories.dig(*memo_keys)
|
106
|
+
else
|
107
|
+
return loaded_config
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# AFAICT Ruby::YAML will not give me a Ruby Set[] for a YAML Set,
|
112
|
+
# just a Hash with all-nil-values which is what it is internally.
|
113
|
+
# distorted⇢ image Trying Jekyll _config key: {"(max-width: 400px)"=>nil, "(min-width: 800px)"=>nil, "(min-width: 1500px)"=>nil}
|
114
|
+
# It is possible with some sugar in the YAML files, but I don't
|
115
|
+
# want to ask anyone to do that :)
|
116
|
+
# https://rhnh.net/2011/01/31/yaml-tutorial/
|
117
|
+
def self.set_me_free(dunno)
|
118
|
+
if dunno.class == Array
|
119
|
+
return dunno&.to_set.map{|d| set_me_free(d)}
|
120
|
+
elsif dunno.class == Hash
|
121
|
+
if dunno&.values.all?{|v| v.nil?}
|
122
|
+
return dunno&.keys.to_set
|
123
|
+
else
|
124
|
+
return dunno&.transform_values!{|v| set_me_free(v)}
|
125
|
+
end
|
126
|
+
end
|
127
|
+
return dunno
|
128
|
+
end
|
129
|
+
|
130
|
+
# Transform arbitrary configuration data structure keys from
|
131
|
+
# strings to symbols before memoization.
|
132
|
+
# https://stackoverflow.com/a/8189435
|
133
|
+
def self.symbolic(dunno)
|
134
|
+
# Check message-handling responses to gauge emptiness since classes that
|
135
|
+
# don't respond to `:empty?` might not respond to `:method_exists?` either.
|
136
|
+
if dunno.nil?
|
137
|
+
return dunno
|
138
|
+
elsif dunno.class == Hash
|
139
|
+
return dunno.transform_keys!(&:to_sym).transform_values!{|v| symbolic(v)}
|
140
|
+
elsif dunno.class == Array
|
141
|
+
return dunno.map{|r| symbolic(r)}
|
142
|
+
elsif dunno.respond_to?(:to_sym)
|
143
|
+
# Plain types
|
144
|
+
return dunno.to_sym
|
145
|
+
elsif dunno.respond_to?(:to_str)
|
146
|
+
# Freeze string config values.
|
147
|
+
# Specifically :to_str, not :to_s. Usually implemented by actual Strings.
|
148
|
+
return dunno.to_str.freeze
|
149
|
+
end
|
150
|
+
return dunno
|
151
|
+
end
|
152
|
+
|
153
|
+
# Returns a Set of Arrays of search keys to try in config()
|
154
|
+
def search_keys(*keys)
|
155
|
+
# It's likely that we will get a default argument of [nil]
|
156
|
+
# here due to the output of abstract(:whatever) for unset attrs.
|
157
|
+
keys = keys.compact
|
158
|
+
# If a search key path was given, construct one based
|
159
|
+
# on the MIME::Type union Set between the source media
|
160
|
+
# and the plugged MediaMolecule.
|
161
|
+
if keys.empty? or keys.all?{|k| k.nil?}
|
162
|
+
try_keys = type_mars.map{ |t|
|
163
|
+
# Use only the first part of complex sub_types like 'svg+xml'
|
164
|
+
[t.media_type, t.sub_type.split('+').first].compact
|
165
|
+
}
|
166
|
+
else
|
167
|
+
# Or use a user-provided config path.
|
168
|
+
try_keys = Set[keys]
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Loads configuration data telling us how to open certain
|
173
|
+
# types of files.
|
174
|
+
def lower_world(*keys)
|
175
|
+
# Try each set of keys until we find a match
|
176
|
+
for try in search_keys(*keys)
|
177
|
+
tried = Jekyll::DistorteD::Floor::config(
|
178
|
+
Jekyll::DistorteD::Floor::CONFIG_ROOT,
|
179
|
+
:welcome,
|
180
|
+
*try,
|
181
|
+
)
|
182
|
+
# Is the YAML config of the appropriate structure?
|
183
|
+
if tried.is_a?(Hash)
|
184
|
+
# Non-Hashes may not respond to `empty?`
|
185
|
+
unless tried.empty?
|
186
|
+
return tried
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# Load configuration telling us what media-types to generate
|
193
|
+
# for any given media-type input.
|
194
|
+
def changes(*keys)
|
195
|
+
out = Set[]
|
196
|
+
# `changes` media-type[sub_type] config will contain information about
|
197
|
+
# what variations output format are desired for what input format,
|
198
|
+
# e.g. {:image => {:jpeg => Set['image/jpeg', 'image/webp']}}
|
199
|
+
# It is not automatically implied that the source format is also
|
200
|
+
# an output format!
|
201
|
+
for try in search_keys(*keys)
|
202
|
+
tried = Jekyll::DistorteD::Floor::config(
|
203
|
+
Jekyll::DistorteD::Floor::CONFIG_ROOT,
|
204
|
+
:changes,
|
205
|
+
*try,
|
206
|
+
)
|
207
|
+
if tried.is_a?(Enumerable) and tried.all?{|t| t.is_a?(String)} and not tried.empty?
|
208
|
+
tried.each{ |t|
|
209
|
+
# MIME::Type.new() won't give us a usable Type object:
|
210
|
+
#
|
211
|
+
# irb> MIME::Types['image/svg+xml'].first.preferred_extension
|
212
|
+
# => "svg"
|
213
|
+
# irb> MIME::Type.new('image/svg+xml').preferred_extension
|
214
|
+
# => nil
|
215
|
+
out.merge(CHECKING::YOU::IN(t))
|
216
|
+
}
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# If the config didn't give us any MIME::Type changes
|
221
|
+
# then we will just output the same type we loaded.
|
222
|
+
if out.empty?
|
223
|
+
return type_mars
|
224
|
+
else
|
225
|
+
return out
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# Loads configuration telling us what variations to generate for any
|
230
|
+
# given type of file, or for an arbitrary key hierarchy.
|
231
|
+
def outer_limits(*keys)
|
232
|
+
out = Set[]
|
233
|
+
# See if any config data exists for each given key hierarchy,
|
234
|
+
# but under the root DistorteD config key.
|
235
|
+
for try in search_keys(*keys)
|
236
|
+
tried = Jekyll::DistorteD::Floor::config(
|
237
|
+
Jekyll::DistorteD::Floor::CONFIG_ROOT,
|
238
|
+
:outer_limits,
|
239
|
+
*try,
|
240
|
+
)
|
241
|
+
|
242
|
+
# Is the YAML config of the appropriate structure?
|
243
|
+
# Merge a shallow copy of it with the Liquid-given attrs.
|
244
|
+
# If we don't take a copy the attrs will be memoized into the config.
|
245
|
+
if tried.is_a?(Enumerable) and tried.all?{|t| t.is_a?(Hash)} and not tried.empty?
|
246
|
+
out.merge(tried.dup.map{ |d| d.merge(@liquid_liquid) })
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
# We should output something if the config didn't give us anything.
|
251
|
+
# This is kind of a mess right now with redundancies in the call sites
|
252
|
+
# of things like Molecule::Image. I'll come up with a better general-
|
253
|
+
# purpose fallback solution at some point, but for now this will get
|
254
|
+
# non-Image StaticFiles working with no config :)
|
255
|
+
if out.empty?
|
256
|
+
out << {
|
257
|
+
:tag => :full,
|
258
|
+
}
|
259
|
+
end
|
260
|
+
|
261
|
+
return out
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|