Module: Jekyll::DistorteD::Floor
- Included in:
- Invoker
- Defined in:
- lib/distorted-jekyll/floor.rb
Constant Summary collapse
- ATTRIBUTES =
Set[:lower_world, :changes, :outer_limits]
- CONFIG_ROOT =
Top-level config key (once stringified) for Jekyll and Default YAML.
:distorted- DEFAULT_CONFIG_FILE_NAME =
Filename for default config YAML. Should be a sibling of this file. Don’t move this file or the YAML defaults without changing this.
'_config_default.yml'.freeze
- DEFAULT_CONFIG_PATH =
File.join(File.dirname(__FILE__), DEFAULT_CONFIG_FILE_NAME).freeze
- PP_SEPARATOR =
Separator character for pretty-printing config hierarchy.
"\u21e2 ".encode('utf-8').freeze
- PATH_SEPARATOR =
Path separator is almost always ‘/’ internally, but support ALT_SEPARATOR platforms too. On Lunix - Ruby 2.7: irb(main):003:0> File::ALT_SEPARATOR
> nil
irb(main):004:0> File::SEPARATOR
> “/”
(File::ALT_SEPARATOR || File::SEPARATOR).freeze
Class Method Summary collapse
-
.config(*keys, **kw) ⇒ Object
Generic main config-loading function that will search, in order: - The memoized pre-transformed config data store in-memory.
-
.set_me_free(dunno) ⇒ Object
AFAICT Ruby::YAML will not give me a Ruby Set[] for a YAML Set, just a Hash with all-nil-values which is what it is internally.
-
.symbolic(dunno) ⇒ Object
Transform arbitrary configuration data structure keys from strings to symbols before memoization.
Instance Method Summary collapse
-
#changes(*keys) ⇒ Object
Load configuration telling us what media-types to generate for any given media-type input.
-
#lower_world(*keys) ⇒ Object
Loads configuration data telling us how to open certain types of files.
-
#outer_limits(*keys) ⇒ Object
Loads configuration telling us what variations to generate for any given type of file, or for an arbitrary key hierarchy.
-
#search_keys(*keys) ⇒ Object
Returns a Set of Arrays of search keys to try in config().
Class Method Details
.config(*keys, **kw) ⇒ Object
Generic main config-loading function that will search, in order:
-
The memoized pre-transformed config data store in-memory.
-
Jekyll’s Site config, for a passed-in site or for the default site.
-
DistorteD’s Gem-internal default config YAML.
Optionally provide a class to be used as a fallback for missing keys.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/distorted-jekyll/floor.rb', line 42 def self.config(*keys, **kw) # Symbolize for our internal representation of the config path. # The Jekyll config and default config are both YAML, so we want string # keys for them. Go ahead and prepend the top-level search key here too. memo_keys = keys.compact.map(&:to_sym).to_set search_keys = keys.compact.map(&:to_s).map(&:freeze) # Pretty print the config path for logging. log_key = search_keys.join(PP_SEPARATOR.to_s).freeze # Initialize memoization class variable as a Hash that will return nil # for any key access that doesn't already contain something. @@memories ||= Hash.new { |h,k| h[k] = h.class.new(&h.default_proc) } # Try to load a memoized config if we can, to skip any filesystem # access and data transformation steps. config = @@memories&.dig(*memo_keys) unless config.nil? if config.is_a?(TrueClass) || config.is_a?(FalseClass) return config elsif config.is_a?(Enumerable) unless config.empty? # Can't check this at the top level because True/FalseClass # don't respond to this message. return config end end end # The key isn't memoized. Look for it first in Jekyll's Site config. # Is it even possible to have more than one Site? Support being passed # a `site` object just in case, but taking the first one should be fine. site = kw[:site] || Jekyll.sites.first # Get the config, or nil if the queried config path doesn't exist. loaded_config = site.config.dig(*search_keys) if loaded_config.nil? # The wanted config key didn't exist in the Site config, so let's # try our defaults! # This file will always be small enough for a one-shot read. default_config = YAML.load(File.read(DEFAULT_CONFIG_PATH)) loaded_config = default_config.dig(*search_keys) unless loaded_config.nil? Jekyll.logger.debug(['Default', log_key].join(PP_SEPARATOR.to_s).concat(':'.freeze), loaded_config) end else # else Jekyll _config is not nil Jekyll.logger.debug(['_config', log_key].join(PP_SEPARATOR.to_s).concat(':'.freeze), loaded_config) end # Was the desired config key found in the Gem defaults? if loaded_config.nil? # Nope. return nil else # Symbolize any output keys and values, and convert Arrays and Ruby::YAML # Sets-as-Hashes to Ruby stdlib Sets. # Returning a Set instead of an Array should be fine since none of our # configs can (read: should) contain duplicate values for any reason. loaded_config = symbolic(set_me_free(loaded_config)) end # Memoize any of our own config, but just return anything outside our tree. if keys.first == CONFIG_ROOT @@memories.bury(*memo_keys, loaded_config) Jekyll.logger.debug(log_key, "Memoizing config: #{@@memories.dig(*memo_keys)}") # And return a config to the caller. Don't return the `new`ly fetched # data directly to ensure consistency between this first fetch and # subsequent memoized fetches, and to let callers take advantage of # the memo Hash's `default_proc` setup. return @@memories.dig(*memo_keys) else return loaded_config end end |
.set_me_free(dunno) ⇒ Object
AFAICT Ruby::YAML will not give me a Ruby Set[] for a YAML Set, just a Hash with all-nil-values which is what it is internally. distorted⇢ image Trying Jekyll _config key: 400px)”=>nil, “(min-width: 800px)”=>nil, “(min-width: 1500px)”=>nil It is possible with some sugar in the YAML files, but I don’t want to ask anyone to do that :) rhnh.net/2011/01/31/yaml-tutorial/
117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/distorted-jekyll/floor.rb', line 117 def self.set_me_free(dunno) if dunno.class == Array return dunno&.to_set.map{|d| set_me_free(d)} elsif dunno.class == Hash if dunno&.values.all?{|v| v.nil?} return dunno&.keys.to_set else return dunno&.transform_values!{|v| set_me_free(v)} end end return dunno end |
.symbolic(dunno) ⇒ Object
Transform arbitrary configuration data structure keys from strings to symbols before memoization. stackoverflow.com/a/8189435
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/distorted-jekyll/floor.rb', line 133 def self.symbolic(dunno) # Check message-handling responses to gauge emptiness since classes that # don't respond to `:empty?` might not respond to `:method_exists?` either. if dunno.nil? return dunno elsif dunno.class == Hash return dunno.transform_keys!(&:to_sym).transform_values!{|v| symbolic(v)} elsif dunno.class == Array return dunno.map{|r| symbolic(r)} elsif dunno.respond_to?(:to_sym) # Plain types return dunno.to_sym elsif dunno.respond_to?(:to_str) # Freeze string config values. # Specifically :to_str, not :to_s. Usually implemented by actual Strings. return dunno.to_str.freeze end return dunno end |
Instance Method Details
#changes(*keys) ⇒ Object
Load configuration telling us what media-types to generate for any given media-type input.
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/distorted-jekyll/floor.rb', line 194 def changes(*keys) out = Set[] # `changes` media-type[sub_type] config will contain information about # what variations output format are desired for what input format, # e.g. {:image => {:jpeg => Set['image/jpeg', 'image/webp']}} # It is not automatically implied that the source format is also # an output format! for try in search_keys(*keys) tried = Jekyll::DistorteD::Floor::config( Jekyll::DistorteD::Floor::CONFIG_ROOT, :changes, *try, ) if tried.is_a?(Enumerable) and tried.all?{|t| t.is_a?(String)} and not tried.empty? tried.each{ |t| # MIME::Type.new() won't give us a usable Type object: # # irb> MIME::Types['image/svg+xml'].first.preferred_extension # => "svg" # irb> MIME::Type.new('image/svg+xml').preferred_extension # => nil out.merge(CHECKING::YOU::IN(t)) } end end # If the config didn't give us any MIME::Type changes # then we will just output the same type we loaded. if out.empty? return type_mars else return out end end |
#lower_world(*keys) ⇒ Object
Loads configuration data telling us how to open certain types of files.
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/distorted-jekyll/floor.rb', line 174 def lower_world(*keys) # Try each set of keys until we find a match for try in search_keys(*keys) tried = Jekyll::DistorteD::Floor::config( Jekyll::DistorteD::Floor::CONFIG_ROOT, :welcome, *try, ) # Is the YAML config of the appropriate structure? if tried.is_a?(Hash) # Non-Hashes may not respond to `empty?` unless tried.empty? return tried end end end end |
#outer_limits(*keys) ⇒ Object
Loads configuration telling us what variations to generate for any given type of file, or for an arbitrary key hierarchy.
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/distorted-jekyll/floor.rb', line 231 def outer_limits(*keys) out = Set[] # See if any config data exists for each given key hierarchy, # but under the root DistorteD config key. for try in search_keys(*keys) tried = Jekyll::DistorteD::Floor::config( Jekyll::DistorteD::Floor::CONFIG_ROOT, :outer_limits, *try, ) # Is the YAML config of the appropriate structure? # Merge a shallow copy of it with the Liquid-given attrs. # If we don't take a copy the attrs will be memoized into the config. if tried.is_a?(Enumerable) and tried.all?{|t| t.is_a?(Hash)} and not tried.empty? out.merge(tried.dup.map{ |d| d.merge(@liquid_liquid) }) end end # We should output something if the config didn't give us anything. # This is kind of a mess right now with redundancies in the call sites # of things like Molecule::Image. I'll come up with a better general- # purpose fallback solution at some point, but for now this will get # non-Image StaticFiles working with no config :) if out.empty? out << { :tag => :full, } end return out end |
#search_keys(*keys) ⇒ Object
Returns a Set of Arrays of search keys to try in config()
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/distorted-jekyll/floor.rb', line 154 def search_keys(*keys) # It's likely that we will get a default argument of [nil] # here due to the output of abstract(:whatever) for unset attrs. keys = keys.compact # If a search key path was given, construct one based # on the MIME::Type union Set between the source media # and the plugged MediaMolecule. if keys.empty? or keys.all?{|k| k.nil?} try_keys = type_mars.map{ |t| # Use only the first part of complex sub_types like 'svg+xml' [t.media_type, t.sub_type.split('+').first].compact } else # Or use a user-provided config path. try_keys = Set[keys] end end |