Output Available Objects and Properties in Liquid Templates - ruby

Is there a way to output (for debugging/informational purposes) the available objects and object properties in a liquid template?
That is, say I'm using the jekyll site generation tool, and I'm in my index.html template (which is, to my understanding, a liquid template). It might look something like this
{% for post in site.posts %}
<li><span>{{ post.date | date_to_string }}</span> ยป {{ post.title }}</li>
{% endfor %}
Are there any template tags I could use that would tell me/output a variable named post was available in this template (as well as the other templates). Also, are there any template tags I could use that would tell me the post object has the keys date, title, url, excerpt, permalink, etc.

There's no way to do this from a Liquid template that I'm aware of. I used the following bit of Ruby code to do it in a test for Jekyll though (setup_post is a helper method in Jekyll's test suite)
post = setup_post("2008-11-21-complex.textile")
classes = []
Liquid::Template.parse(post.content).root.nodelist.each do |token|
classes << token.name if token.is_a?(Liquid::Variable)
end
It should be possible to write a Jekyll plugin that could output this stuff on your page based on the above code.

Related

Is there a way to define custom Go Template Actions

Is there a way to define custom "Actions" (like range, if, block, etc) with either text or html go templates. I would like to achieve something like the following:
{{ component "blog_post" . }}
{{ template "title" . }}
{{ component "content" . }}
My Content
{{ end }}
{{ end }}
Where "component" is my custom action.
I have achieved the above functionally using custom functions but it is pretty clunky and hard to read. I am particularly interested in the ability to use a custom action that takes both a normal argument (such as .) as well as arbitrary "children" (much like a react component).
This is not possible in the current implementation of Go templates.
Actions are handled by the internal text/template/parse package, and are all defined in https://golang.org/src/text/template/parse/node.go. You will find that there is no mechanism for creating new actions, as the Tree.action method in parse.go has a hardcoded switch case for them.
This is sad because the text/template package has a lot of missed opportunities for reusable features. For example, there's an entire built-in LISP parser that's unusable unless you use it through the template parser.

Pass class object from ruby to liquid (via Jekyll)

UPDATE FOR CLARIFICATION.
I deleted the original question because it was confusing. Maybe this one is better?
I currently have something like this (simplified for brevity):
module Jekyll
module TOCGenerator
def toc(html)
...via nokogiri, get all <h3> tags, make table of contents entry
for each.
end
def contentWithTocAnchorLinks(html)
...make "back to top" anchor links under each <h3> tag that will
take the user back up to the table of contents
end
end
end
Then in the template:
<section>{{ content | toc }}</section>
<section>{{ content | contentWithTocAnchorLinks }} </section>
This works fine, but it seems sloppy. I've also tried stuffing both toc and contentWithAnchorLinks into an array and then doing something like {{ content | tocArray | first }} which also worked, but not very well (in some cases there is no table of contents and it was confusing). Anyway, what I would like to be able to do is something like this:
{% capture toc_content %}{{ content | toc_generate }}{% endcapture %}
<section> {{ toc_content.toc }} </section>
<section> {{ toc_content.content }}</section>
Jekyll does this all the time, as in {{ page.title }} but I'm not clear on how to replicate it. I only assume that a Ruby class is involved somewhere.
Does that make more sense?
If I understand your question, you want to parse a content, get some customers infos from it, and render a table of content.
From the Information Architecture point of view, you are supposed to store your customer datas in an atomic manner. For this, Jekyll offers you data files and collections that can be very helpful in your case.
If you need to make some basic transformations on your "objects" you can use liquid or jekyll filters.

Jekyll: Can I combine collections and data files?

Short version: How do I reference a collection by variable in Liquid?
I'm building a site on Jekyll which is documentation with multiple different parts. It consists of collections of articles and there are no blogposts. Right now I have a three level menu structure defined with data files, where the third level is the actual articles. The data file look like this.
menu.yml
- title: Book
url: book
subpages:
- title: Volume 1
url: book/vol1
- title: Volume 2
url: book/vol2
- title: The Library
url: library
subpages:
- title: Getting started
url: library/getting-started
- title: Components
url: library/components
- title: Theme
url: theme
subpages:
- title: Tutorials
url: theme/tutorials
- title: Reference
url: theme/reference
Additionally, I have collections defined that match the top level items by url.
_config.yml
...
collections:
book:
output: true
library:
output: true
theme:
output: true
Right now I use the menu YML to construct myself a nice two level structure and put the articles into them to form the third level. The problem is that I don't know how to call the collections dynamically when I am constructing the menu. For example when I am creating the 'Book' menu item, I'd like to loop over site.book data collection with something like this:
{% assign collection = 'book' %}
{% for p in site.{{collection}} %}
<p>{{p.title}}</p>
{% endfor %}
site.{{collection}} doesn't work there but for example calling directly site.book does. I don't know how to pass the variable in Liquid.
What I do to get around this problem is that for every menu item that I create i loop through the whole {{site.pages}} which contains all the articles in the whole site, and match their url against the menu item url. These feels like bad programming on so many levels and I'm taking a huge performance hit when looping through everything multiple times. Generation of files goes up four times, from 5 seconds to 20 seconds right now, and it will get even worse when I make the menu even larger.
So I'm open to hearing how I could loop dynamically through the collections, or hearing about other options to create such a menu. As I have the relative url at hand, for example /book/vol1, the optimal would to find a way to get a reference to all articles within that folder (excluding those in subfolders but that is not a must-have).
The syntax for using a liquid variable inside a liquid tag looks a bit different than {% for p in site.{{collection}} %}. You can try either:
{% assign collection = 'book' %}
{% for p in site.[collection] %}
or you simply use:
{% assign books = site.book %}
{% for p in books %}

Cannot modify site.tags from Jekyll plugin

I'm developing a plugin to facilitate multilingual Jekyll sites, and as part of this I have to categorise posts according to their language.
I'm trying to tag the post according to its language, so I have overwritten the aggregate_post_info method, but when I print the site.tags variable, it is empty.
module Jekyll
class Site
alias_method :_aggregate_post_info, :aggregate_post_info
def aggregate_post_info(post)
_aggregate_post_info(post)
#tags[post.data['lang']] << post
end
end
end
I have achieved something similar by defining my own language specific variables, like in this simplified example:
for post in site.posts.docs do
lang = post.data['lang']
for tag in post.data['tags'] do
slug = jekyll_tagging_slug(tag)
site.config['t'][lang]['tagnames'] = slug
end
end
I also automatically generate tag pages (and category pages using a different approach without plug-ins), avoid name collisions for multiple languages, and precompute aggregate counts for better performance. The whole thing is described in two blog posts http://www.guido-flohr.net/multilang-with-jekyll/ and http://www.guido-flohr.net/jekyll-multilang-tags/.
You can simply add the post language as a tag, i.e. tags: [english, ruby, etc], avoiding altogether the monkey patching. So, when you want to show only lang-tagged posts, you simply filter them:
<ul class="posts">
{% for post in site.tags.english %}
<li>
{{ post.title }}
</li>
{% endfor %}
</ul>
This way, most of the work is done by Jekyll, saving you some time and effort. :)

symfony2 sessions, cookies, or something completely different?

I am currently making a time-clock system that is inside of a custom-built application (CRM) that a previous developer did. I've got the timeclock coming along nicely but have just a few questions..
Upon clocking in I set a session like so: $this->get('session')->set('clockedin', 'true');
I set a session so that I in order to show the clockin or clockout button I figured the easiest method would be to just read a session variable to determine which button to show using a twig if/else statement in the templates (i have the buttons show in 2 places, 1 is in every page and 1 is only in the timeclock system itself)
So, is this the best way to go about doing this or is there a better recommended way of going about it?
The next thing I wondered about is session expiration... in my config.yml I see:
session:
cookie_lifetime: 43200
auto_start: true
So, does this mean that the way i've set it lasts for 12 hours? Or in order for that to be true, would I need to use a cookie instead? I think that a cookie might be better, because if the browser closes (many of the employees aren't technologically inclined) I'd need this to be a persistent upon the next page load..
Thanks for any help..
If another indefinitely later operation depends on clockedin state I would not rely on sessions. If user logs him/herself out session gets invalidated (whole session), so clockedin would be lost.
I would rather use {% include %} or {% render %} to determine state every time you need to display that button. For example:
/**
* #Template()
*/
public function clockedInAction(){
.... // do some login here
$clocked_in = ....;
return array(
'clockedin' => $clockedin
);
}
and in your Twig:
{% render "AcmeBundle:SomeController:clockedIn" %}
Template of this controller would contains that {% if .... %} you wanted originally:
{# AcmeBundle:SomeController:clockedIn.html.twig #}
{% if clockedIn %}
display "Clocked In" button
{% else %}
display "Clocked Out" button
{% endif %}
Now, this is more expensive since on each request you have to assess the situation and then print appropriate template, but it's always consistent with a system...

Resources