Class: Jekyll::DistorteD::Invoker
- Inherits:
-
Liquid::Tag
- Object
- Liquid::Tag
- Jekyll::DistorteD::Invoker
- Includes:
- Floor, StaticState
- Defined in:
- lib/distorted-jekyll/invoker.rb
Constant Summary collapse
- GEM_ROOT =
File.dirname(__FILE__).freeze
- MEDIA_MOLECULES =
Enabled media_type drivers. These will be attempted back to front. TODO: Make this configurable.
[ Jekyll::DistorteD::Molecule::LastResort, Jekyll::DistorteD::Molecule::Font, Jekyll::DistorteD::Molecule::Text, Jekyll::DistorteD::Molecule::PDF, Jekyll::DistorteD::Molecule::SVG, Jekyll::DistorteD::Molecule::Video, Jekyll::DistorteD::Molecule::Image, ]
- TYPE_MOLECULES =
Reduce the above to a Hash of Sets of MediaMolecules-per-Type, keyed by Type.
MEDIA_MOLECULES.reduce( Hash.new{|hash, key| hash[key] = Set[]} ) { |types, molecule| if molecule.const_defined?(:LOWER_WORLD) molecule.const_get(:LOWER_WORLD).each { |t| types.update(t => Set[molecule]) { |k,o,n| o.merge(n) } } end types }
- ARBITRARY_ATTR_SYMBOL_STRING_LENGTH_BOUNDARY =
Any any attr value will get a to_sym if shorter than this totally arbitrary length, or if the attr key is in the plugged Molecule’s set of attrs that take only a defined set of values. My chosen boundary length fits all of the outer-limit tag names I use, like ‘medium’. It fits the longest value of Vips::Interesting too, though ‘crop` will be symbolized based on the other condition.
13
Constants included from StaticState
Constants included from Floor
Floor::ATTRIBUTES, Floor::CONFIG_ROOT, Floor::DEFAULT_CONFIG_FILE_NAME, Floor::DEFAULT_CONFIG_PATH, Floor::PATH_SEPARATOR, Floor::PP_SEPARATOR
Instance Method Summary collapse
-
#initialize(tag_name, arguments, liquid_options) ⇒ Invoker
constructor
𝘏𝘖𝘞 𝘈𝘙𝘌 𝘠𝘖𝘜 𝘎𝘌𝘕𝘛𝘓𝘌𝘔𝘌𝘕 !!.
-
#media_molecule ⇒ Object
Decides which MediaMolecule is most appropriate for our file and returns it.
-
#parse_template(site: nil, name: nil) ⇒ Object
Generic Liquid template loader that will be used in every MediaMolecule.
- #plug ⇒ Object
-
#render(context) ⇒ Object
Called by Jekyll::Renderer github.com/jekyll/jekyll/blob/HEAD/lib/jekyll/renderer.rb jekyllrb.com/tutorials/orderofinterpretation/.
-
#render_to_output_buffer(context, output) ⇒ Object
A future Liquid version (5.0?) will call this function directly instead of calling render().
-
#type_mars ⇒ Object
Returns a Set of DD MIME::Types descriving our file, optionally falling through to a plain file copy.
-
#user_arguments ⇒ Object
Return any arguments given by the user to our Liquid tag.
Methods included from StaticState
#destination, #destinations, #modified?, #write, #write?
Methods included from Floor
#changes, config, #lower_world, #outer_limits, #search_keys, set_me_free, symbolic
Constructor Details
#initialize(tag_name, arguments, liquid_options) ⇒ Invoker
𝘏𝘖𝘞 𝘈𝘙𝘌 𝘠𝘖𝘜 𝘎𝘌𝘕𝘛𝘓𝘌𝘔𝘌𝘕 !!
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 110 111 112 113 114 |
# File 'lib/distorted-jekyll/invoker.rb', line 80 def initialize(tag_name, arguments, ) super # Tag name as given to Liquid::Template.register_tag(). @tag_name = tag_name.to_sym # Liquid leaves argument parsing totally up to us. # Use the envygeeks/liquid-tag-parser library to wrangle them. parsed_arguments = Liquid::Tag::Parser.new(arguments) # Filename is the only non-keyword argument our tag should ever get. # It's spe-shul and gets its own definition outside the attr loop. if parsed_arguments.key?(:src) @name = parsed_arguments.delete(:src) else @name = parsed_arguments.delete(:argv1) end @liquid_liquid = parsed_arguments.select{ |attr, val| not [nil, ''.freeze].include?(val) }.transform_keys { |attr| attr.length <= ARBITRARY_ATTR_SYMBOL_STRING_LENGTH_BOUNDARY ? attr.to_sym : attr.freeze }.transform_values { |val| if val.respond_to?(:length) val.length <= ARBITRARY_ATTR_SYMBOL_STRING_LENGTH_BOUNDARY ? val.to_sym : val.freeze else val end } # If we didn't get one of the two above options there is nothing we # can do but bail. unless @name raise "Failed to get a usable filename from #{arguments}" end end |
Instance Method Details
#media_molecule ⇒ Object
Decides which MediaMolecule is most appropriate for our file and returns it.
138 139 140 141 142 143 144 145 146 147 |
# File 'lib/distorted-jekyll/invoker.rb', line 138 def media_molecule available_molecules = TYPE_MOLECULES.keys.to_set & type_mars # TODO: Handle multiple molecules for the same file case available_molecules.length when 0 raise MediaTypeNotImplementedError.new(@name) when 1 return TYPE_MOLECULES[available_molecules.first].first end end |
#parse_template(site: nil, name: nil) ⇒ Object
Generic Liquid template loader that will be used in every MediaMolecule. Callers will call ‘render(**=> vars)` on the Object returned by this method.
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/distorted-jekyll/invoker.rb', line 213 def parse_template(site: nil, name: nil) site = site || @site || Jekyll.sites.first begin # Use a given filename, or detect one based on media-type. if name.nil? # e.g. Jekyll::DistorteD::Molecule::Image -> 'image.liquid' name = "#{self.singleton_class.instance_variable_get(:@media_molecule).name.gsub(/^.*::/, '').downcase}.liquid".freeze elsif not name.include?('.liquid'.freeze) # Support filename arguments with and without file extension. # The given String might already be frozen, so concatenating # the extension might fail. Just set a new version. name = "#{name}.liquid" end template = File.join( self.singleton_class.const_get(:GEM_ROOT), 'template'.freeze, name, ) # Jekyll's Liquid renderer caches in 4.0+. if Jekyll::DistorteD::Floor::config( Jekyll::DistorteD::Floor::CONFIG_ROOT, :cache_templates, ) # file(path) is the caching function, with path as the cache key. # The `template` here will be the full path, so no versions of this # gem should ever conflict. For example, right now during dev it's: # `/home/okeeblow/Works/DistorteD/lib/image.liquid` Jekyll.logger.debug('DistorteD', "Parsing #{template} with caching renderer.") site.liquid_renderer.file(template).parse(File.read(template)) else # Re-read the template just for this piece of media. Jekyll.logger.debug('DistorteD', "Parsing #{template} with fresh (uncached) renderer.") Liquid::Template.parse(File.read(template)) end rescue Liquid::SyntaxError => l # This shouldn't ever happen unless a new version of Liquid # breaks syntax compatibility with our templates somehow. l. end end |
#plug ⇒ Object
149 150 151 152 153 154 155 |
# File 'lib/distorted-jekyll/invoker.rb', line 149 def plug unless self.singleton_class.instance_variable_defined?(:@media_molecule) self.singleton_class.instance_variable_set(:@media_molecule, media_molecule) self.singleton_class.prepend(media_molecule) Jekyll.logger.info(@name, "Plugging #{media_molecule}") end end |
#render(context) ⇒ Object
Called by Jekyll::Renderer github.com/jekyll/jekyll/blob/HEAD/lib/jekyll/renderer.rb jekyllrb.com/tutorials/orderofinterpretation/
160 161 162 163 |
# File 'lib/distorted-jekyll/invoker.rb', line 160 def render(context) plug render_to_output_buffer(context, '') end |
#render_to_output_buffer(context, output) ⇒ Object
A future Liquid version (5.0?) will call this function directly instead of calling render()
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/distorted-jekyll/invoker.rb', line 167 def render_to_output_buffer(context, output) plug # Get Jekyll Site object back from tag rendering context registers so we # can get configuration data and path information from it and # then pass it along to our StaticFile subclass. @site = context.registers[:site] # The rendering context's `first` page will be the one that invoked us. page_data = context.environments.first['page'.freeze] # # Our subclass' additional args: # dest - The String path to the generated `url` folder of the page HTML output @base = @site.source # `relative_path` doesn't seem to always exist, but `path` does? idk. # I was testing with `relative_path` only with `_posts`, but it broke # when I invoked DD on a _page. Both have `path`. @dir = File.dirname(page_data['path'.freeze]) # Every one of Ruby's `File.directory?` / `Pathname.directory?` / # `FileTest.directory?` methods actually tests that path on the # real filesystem, but we shouldn't look at the FS here because # this function gets called when the Site.dest directory does # not exist yet! # Hackily look at the last character to see if the URL is a # directory (like configured on cooltrainer) or a `.html` # (or other extension) like the default Jekyll config. # Get the dirname if the url is not a dir itself. @relative_dest = page_data['url'.freeze] unless @relative_dest[-1] == Jekyll::DistorteD::Floor::PATH_SEPARATOR @relative_dest = File.dirname(@relative_dest) # Append the trailing slash so we don't have to do it # in the Liquid templates. @relative_dest << Jekyll::DistorteD::Floor::PATH_SEPARATOR end # Add our new file to the list that will be handled # by Jekyll's built-in StaticFile generator. @site.static_files << self output end |
#type_mars ⇒ Object
Returns a Set of DD MIME::Types descriving our file, optionally falling through to a plain file copy.
118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/distorted-jekyll/invoker.rb', line 118 def type_mars @type_mars ||= begin mime = CHECKING::YOU::OUT(@name) if mime.empty? if Jekyll::DistorteD::Floor::config(Jekyll::DistorteD::Floor::CONFIG_ROOT, :last_resort) mime = Jekyll::DistorteD::Molecule::LastResort::LOWER_WORLD end end mime end end |
#user_arguments ⇒ Object
Return any arguments given by the user to our Liquid tag. This method name is generic across all DD entrypoints so it can be referenced from lower layers in the pile.
133 134 135 |
# File 'lib/distorted-jekyll/invoker.rb', line 133 def user_arguments @liquid_liquid || Hash[] end |