Plugins and authored theme gems

tl;dr: how do I get my plugins into my theme gem?

Stage 0: development and deployment environment

  • developing on a mac with the intention of hosting my site(s) on my own server != publishing to GitHub.

Stage 1: locally created theme

Stage 2: gemming my theme

  • packed my theme into a gem
  • figured out that paths set in the _config.yml don’t translate and you can’t get around the _sass and assets/css stuff, learn the bare minimum of sass to get the gemmed styles to work
  • removed local theme stuff from site #2 and applied gemmed theme via gem "my-theme", :path => "../my-theme/", it works, huzzah!

trying to use my plugins via gem

  • site #2 is the most basic, which is why it was selected, before moving on to site #3 which uses my plugins extensively, I just trip the switch to activate the plugins for one page. It does not work, boo!
  • I realize that even the simple filter I wrote is not working, nevermind the generator and tags
  • using gem unpack I realize that the plugins are, in fact, not in the gem
  • this post (the last comment on that thread is mine and shows my gemspec attempts) and this one and further investigation indicating that a gem is “just” a tar file makes me think that there is no reason why my correctly gemspec’d _plugins directory should not be included in the gem, nevermind whether the code works as a plugins to the gemmed theme user, the files should at least be there, no?
  • I understand that GitHub hosted sites cannot use plugins from theme gems, but I’m hosting my own sites and beyond that just developing on my desktop for now (although I would like to contribute my theme to the community as a gem, after I get it working)
  • trying to understand the hack mentioned here is-it-possible-to-pack-a-plugin-in-a-gem-based-theme/318, since I feel like it’d be a reasonable intermediate step before attempting to gem all various filters, tags, and generators in my plugin directory

So which part of my hack needs more understanding and/or doesn’t work for you?

I think you somehow expect that plugins should be stored in _plugins, which is only the case for the Jekyll site (a special loader support is present for that), not for plugin packages (or themes), where they should be stored in lib - note that you have to add our own theme to gems for plugins to be loaded (that’s the hacky part).

The following structure worked for me back then:

.
├── Gemfile
├── jekyll-moneymeets-theme.gemspec
├── lib
│   ├── jekyll-moneymeets-theme
│   │   ├── get_data.rb
│   │   ├── ...
│   └── jekyll-moneymeets-theme.rb
├── run_tests.sh
└── test
    ├── get_data_filter_test.rb
    ├── ...

run_tests.sh

#!/bin/sh

find test -name '*_test.rb' -exec sh -c 'bundle exec ruby "$0" || kill $PPID' '{}' \;

jekyll-moneymeets-theme.gemspec

...
spec.files = `git ls-files -z`.split("\x0").select { |f| f.match(%r{^(assets|_layouts|_includes|_sass|lib|test|README)}i) }
...

jekyll-moneymeets-theme.rb

require 'jekyll-moneymeets-theme/get_data'

P.S. Just by way of an example - get_data was a filter.

Yes, I was expecting plugins to be stored in _plugins. That they should be stored in lib is news to me. Max Chadwick’s plugin gem anecdotal instructions I found, does mention the lib thing, but would you know if there is a more official instruction set that mentions this? I’m curious about the interactions between a Jekyll site’s _plugin directory and lib plugins

Thanks for the clarity of your example here!

I’m still having trouble including anything but the basics, here’s my line from my gemspec

 spec.files = `git ls-files -z`.split("\x0").select do |f| f.match(%r!^(assets|lib|_(includes|layouts|sass|data|plugins)/|(LICENSE|README)((\.(txt|md|markdown)|$)))!i) end

following your example I changed it to

  spec.files  = `git ls-files -z`.split("\x0").select { |f| f.match(%r!^(assets|lib|_(includes|layouts|sass|data|plugins)/|(LICENSE|README)((\.(txt|md|markdown)|$)))!i) }

and this is the unpack

➤ ls structrdfal-0.1.17                                                                   
LICENSE.txt	README.md	_data/		_includes/	_layouts/	_sass/		assets/

I just changed my _test directory to lib just to see if I could get it to pack into the gem, but no dice.
Just as a test I added my scripts directory to the spec.files and that worked. Still no lib or _plugins directories in the gem though. wtf??

Would you know if there is a more official instruction set that mentions this?

I figured it out by looking at Jekyll source code - basically back then there was a code path that loads stuff from lib and a special case for _plugins to be treated as lib for Jekyll sites. So no, sorry, I can’t provide you with an academic reference for that. Seems to be a convention among Ruby people not specific to Jekyll.

Still no lib or _plugins directories in the gem though. wtf??

Your regex looks very weird, but I don’t have time to dig into that - start with the basics like f.match(%r{^lib}i) - lib should appear within the package - and grow from there.

staring at it like a simpleton for hours, the gem gets its files from the git archive, not the directory that it’s sitting in. regex was fine, just needed to do a commit so that the gem could find the files. poor revision control was the culprit. le sigh.

the gem gets its files from the git archive, not the directory that it’s sitting in

Well, to be pedantic, the gem gets the list of files it needs from git (which is then being filtered by the regex), and the contents thereof does come from the directory it’s sitting in - so it can in theory pick up uncommitted changes, but files have to be committed to be picked up at all:

spec.files  = `git ls-files -z`.split("\x0") ...

Which actually is a better practice as compared to something like

spec.files  = `find . -type file -print0`.split("\x0") ...

because this can possibly pick up random garbage like editor backup files and so on.

Anyways, glad that you have figured it out in the end.

1 Like