Open cboettig opened 11 years ago
Thanks for the feedback. Let me address your questions one at a time.
Ruhoh
Poirot only draws inspiration from Ruhoh. My implementation is independent of Ruhoh, and in fact differs significantly from Ruhoh on a number of fronts.
Compiling
I apologize for the lack of documentation, but all the functionality resides in the function blogify
. Here is a quick way to get started and compile the blog.
$ git clone git@github.com:ramnathv/poirotBlog
$ cd poirotBlog
$ R -e "library(slidify); blogify('.')"
$ python -m simpleHTTPServer
Blogify essentially knits and parses all Rmd files recursively and constructs a giant payload, which is then passed through a template to construct the blog. The config file site.yml
controls some metadata, while the rest are controlled by the YAML front matter and config.yml
in the posts directory.
Jekyll
I agree that a comparison with Jekyll would be good. I will try to put together an explanation in the README section.
Plugins
Mustache does not support plugins. It does support lambdas to run functions, but that functionality has not been implemented in the whisker
package, although it seems to be on the to-do list of @edwindj. I have been toying with some ideas of using knitr
and a custom %|%
function that acts like a unix filter, to implement this, but it has been trickier than I thought.
My home page has been in the works perenially! I will point it to Poirot for now.
PS. I am looking to get more people involved with development of Poirot. Let me know if you would be interested. I would be happy to set up some time to chat, since it would be easier for me to explain a lot of things about its design and clarify questions you have.
Mustache does not support plugins.
Mustache requires a different form of thinking from traditional embedded templating languages.
Mustache is really just an interface into native ruby which makes it the ultimate plugin system, because everything is a plugin. Here's an example:
Template:
{{some_crazy_calculation_plugin}}
{{ endless.method.chaining }}
{{#handle_some_data}}
apple
banana
pear
{{/handle_some_data}}
{{argument_passing_hack_within_method_call_45}}
<ul>
{{#site.navigation?to_pages}}
<li>{{title}}<li>
{{/site.navigation?to_pages}}
</ul>
View:
class View < Mustache
def some_crazy_calculation_plugin
# All the ruby code in the world can be done here
"bam"
end
class Endless
def method
Method.new
end
end
class Method
def chaining
"yay"
end
end
def endless
Endless.new
end
# Here I've managed to pass in multiple arguments to this method via newlines.
def handle_some_data(sub_context)
data = sub_context.split("\n")
"output some data"
end
## Advanced argument passing can be done via method_missing syntax
end
I do admit that argument passing is pretty hacky. But again, if you have full uninhibited access to native ruby then you can simply make a small custom method for every/any situation you need.
Mustache requires a strict mind-shift from traditional thinking of "let me just embed half of my application's code in my template". It is a little harder to instead rethink your actual need and break this need into a strict separation of:
IMO this is the use-case that Mustache was designed and optimized for. You'd have a beautiful separation of logic =)
@plusjade thanks for the clarification. Quick question: is Mustache ruby-specific in this sense?
On Thu, May 16, 2013 at 11:21 AM, Jade notifications@github.com wrote:
Mustache does not support plugins.
Mustache requires a different form of thinking from traditional embedded templating languages.
Mustache is really just an interface into native ruby which makes it the ultimate plugin system, because everything is a plugin. Here's an example:
Template:
{{some_crazy_calculation_plugin}}
{{ endless.method.chaining }}
{{#handle_some_data}} apple banana pear {{/handle_some_data}}
{{argument_passing_hack_within_method_call_45}}
{{#site.navigation?to_pages}}
- {{title}}
- {{/site.navigation?to_pages}}
View:
class View < Mustache def some_crazy_calculation_plugin
All the ruby code in the world can be done here
"bam"
end
class Endless def method Method.new end end
class Method def chaining "yay" end end
def endless Endless.new end
Here I've managed to pass in multiple arguments to this method via newlines.
def handle_some_data(sub_context) data = sub_context.split("\n") "output some data" end
Advanced argument passing can be done via method_missing syntaxend
I do admit that argument passing is pretty hacky. But again, if you have full uninhibited access to native ruby then you can simply make a small custom method for every/any situation you need.
Mustache requires a strict mind-shift from traditional thinking of "let me just embed half of my application's code in my template". It is a little harder to instead rethink your actual need and break this need into a strict separation of:
- data
- logic
- presentation
IMO this is the use-case that Mustache was designed and optimized for. You'd have a beautiful separation of logic =)
— Reply to this email directly or view it on GitHubhttps://github.com/ramnathv/poirot/issues/13#issuecomment-18019449 .
Carl Boettiger UC Santa Cruz http://carlboettiger.info/
@plusjade If I understand correctly, the version of Mustache you are referring to is the one you customized to work with plugins, correct? I don't see any of this in the Mustache specification manual.
AFAIK, mustache is logicless and intended to be so to allow clear separation of logic and view. It is language agnostic, which is beautiful, since it is then possible to seamlessly implement functionality with the same set of templates.
UPDATE. I realized that this is just the ruby implementation of lambdas
, which is mentioned in the mustache manual.
UPDATE. I realized that this is just the ruby implementation of lambdas, which is mentioned in the mustache manual.
Right, the mustache specification is just saying "I will delegate this method call to whatever object is is given to me at this endpoint"
So in simplest form, you'd just have a method respond with a string: {{ site_name }}
. But if the method returns an object then you get chaining: {{ data.name }}
The one exception is my custom implementation of "contextual helper methods"
{{#site.navigation?to_pages}}
{{name}}
{{/site.navigation?to_pages}}
You are correct in that I extended Mustache with this functionality. But it's very much the same principle of method chaining. The basic idea is that site.navigation
will return a basic data structure like a String or Array. If i wanted to support "to_pages" natively I'd have to hack String/Array object itself to respond to to_pages
.
Instead, I intercept the mustache process if the method contains ?
. In this one special case scenario I still let mustache do its thing and give me the array, as well as try to find the to_pages
method in the call stack. The only difference is I manually provide the "context" to to_pages
which is the Array in this case.
Long story less long: It's basically a convenient way to pass in arguments.
@cboettig Mustache has been implemented in many languages because the API is language-agnostic. http://mustache.github.io/ (list of supported languages and libraries)
As you may have guessed, I'm a Mustache fanboy =)
As you may have guessed, I'm a Mustache fanboy =)
Me too :)
So, if whisker
can be extended to support mustache
lambdas and maybe even contextual helpers, then we can get the plugin functionality easily.
Ramnath,
This looks fantastic. I quite like the building on Mustache and yaml. Thanks for sharing this and I look forward to seeing where it goes. A few preliminary questions, sorry if they're silly or don't make sense:
assets/layouts
is analgous to_includes
, andlibraries/frameworks
has "themes" that might be comparable to_layouts
...{{ page.date | custom_filter }}
. Can you do an analgous thing here? (From a quick look at Mustache I see how you do something like {{ page.date }} but not how you'd pass that as a variable to somecustom_filter
R function... hope that made sense.Probably more questions as I understand better what's going on here... Great work!
(p.s. github list's your homepage as http://rstats.posterous.com which appears to be broken)