On Sun, Aug 14, 2016 at 11:33 PM, Adrian Salceanu <adrian.salce...@gmail.com > wrote:
> Huhm... so re > > > defining globals > > According to the API docs: > > *include_string**(code::AbstractString**[**, filename**]**)* > > Like include, except reads code from the given string rather than from a > file. Since there is no file path involved, no path processing or fetching > from node 1 is done. > > > But then I think you're right, the code is included / eval'd in Main - so > it's not really like include(), which provides for mixin behavior? :-O > > Not sure what do you mean by `mixin`. all of `include_string`, `eval` and `include` works in the scope of current module, none of them will see anything in the scope of the function that calls them. > duminică, 14 august 2016, 17:13:28 UTC+2, Adrian Salceanu a scris: >> >> Thanks >> >> Maybe I wasn't clear enough - otherwise, can you please elaborate, I'm >> definitely still poking around, any clarifications would be highly >> appreciated. >> >> > creating a new module >> -> the module is available at compile time (the users of the templating >> system will place the vars in there, by convention). >> >> > parse julia code >> -> it's not really parsing julia code, it has no meaning at the point. >> It's simply basic string processing and it's fast - tried with a 10K lines >> HTML file, no sweat. >> >> > defining globals >> -> why are they globals? include_string() is used inside a function, >> inside a module within the app. >> >> > eval in a module >> -> true, but then what can we do? That's the way of doing metaprogramming >> in Julia, and it's widely used, isn't it? >> I guess that would be the price for not having to do >> print("<html><head>...") like our ancestors used to in PHP or ASP, when not >> being chased by tigers (or something around that age). >> >> >> duminică, 14 august 2016, 15:01:47 UTC+2, Yichao Yu a scris: >>> >>> >>> >>> On Sun, Aug 14, 2016 at 6:13 PM, Adrian Salceanu <adrian....@gmail.com> >>> wrote: >>> >>>> Variables contained in a module and then parsed Julia code included >>>> within a function using include_string(). >>>> >>>> Any obvious performance issues with this approach? >>>> >>> >>> Everything about it? >>> Literally every steps are hitting the slow path that is only meant to >>> execute at compile time and not runtime. Including >>> >>> Creating a new module, parse julia code, eval in a module, defining >>> globals. >>> >>> >>>> >>>> >>>> duminică, 14 august 2016, 12:11:06 UTC+2, Adrian Salceanu a scris: >>>>> >>>>> OK, actually, that's not nearly half as bad. Variables contained in a >>>>> module >>>>> >>>>> include("src/Ejl_str.jl") >>>>> using Ejl >>>>> >>>>> >>>>> module _ >>>>> couñtry = "España" >>>>> lang = "en" >>>>> end >>>>> >>>>> >>>>> function render_template() >>>>> tpl_data = ejl""" >>>>> <% if _.lang == "en" :> >>>>> Hello from me, ... >>>>> <: else :> >>>>> Hola >>>>> <: end %> >>>>> >>>>> >>>>> %= _.couñtry == "España" ? "Olé" : "Aye" >>>>> moo >>>>> """ >>>>> >>>>> >>>>> include_string(join(tpl_data, "\n")) >>>>> join(____output, "\n") >>>>> end >>>>> >>>>> >>>>> render_template() |> println >>>>> >>>>> Hello from me, ... >>>>> >>>>> >>>>> Olé >>>>> moo >>>>> >>>>> >>>>> duminică, 14 august 2016, 11:20:37 UTC+2, Adrian Salceanu a scris: >>>>>> >>>>>> Thanks >>>>>> >>>>>> Yes, I've thought about a few ways to mitigate some of these issues: >>>>>> >>>>>> 1. in the app I can setup a module (like Render) and evaluate into >>>>>> this module exclusively. >>>>>> Hence, another approach might be to have some helper methods that >>>>>> setup the variables in the module and then eval the template itself >>>>>> inside >>>>>> the module too (must try though). So something in the lines of: >>>>>> set(:foo, "foo") >>>>>> set(:bar, [1, 2, 3]) >>>>>> parse_tpl(ejl"""$(foo) and $(bar)""") >>>>>> # all the above gets parsed in Render >>>>>> >>>>>> 2. break the parsing in 2 steps: >>>>>> a. reading the template string and parse it to generated Julia code >>>>>> (as strings) (an array of Julia code lines) - cache it >>>>>> b. (load strings from cache and) eval the code together with the vars >>>>>> >>>>>> === >>>>>> >>>>>> Another approach (which is how it's done in one of the Ruby >>>>>> templating engine) is to generate a full function definition, whose body >>>>>> parses the template and takes the variables as params. And then eval and >>>>>> execute the function with its params. However, I'm still struggling with >>>>>> the metaprogramming API as for instance parse() chokes on multiple lines, >>>>>> and I couldn't find a functional equivalent of a quote ... end blocks. >>>>>> But >>>>>> I'm hoping include_string() will do the trick (must test though). >>>>>> >>>>>> >>>>>> sâmbătă, 13 august 2016, 15:20:01 UTC+2, Yichao Yu a scris: >>>>>>> >>>>>>> >>>>>>> >>>>>>> On Sat, Aug 13, 2016 at 8:06 PM, Adrian Salceanu < >>>>>>> adrian....@gmail.com> wrote: >>>>>>> >>>>>>>> That's pretty difficult as my goal is to use embedded Julia as the >>>>>>>> templating language. Similar to Ruby's ERB, ex: >>>>>>>> http://www.stuartellis.eu/articles/erb/ >>>>>>>> >>>>>>>> So say in the template I have something like >>>>>>>> >>>>>>>> <% if foo == "bar" %> >>>>>>>> Bar >>>>>>>> <% else %> >>>>>>>> Baz >>>>>>>> <% end %> >>>>>>>> >>>>>>>> The idea is to use Julia itself to parse the code block and Julia >>>>>>>> will raise an error is foo is not defined. So I can't really look it >>>>>>>> up. >>>>>>>> >>>>>>> >>>>>>> It's ok to use the julia syntax and parser but it's a pretty bad >>>>>>> idea to use the julia runtime to actually evaluating the expression, and >>>>>>> absolutely not by making them reference to local variables. >>>>>>> >>>>>>> For a start you are not allowed to reference local variables by >>>>>>> names anyway. >>>>>>> You also shouldn't allow reference to/overwrite of other local >>>>>>> variables (i.e. the template namespace should be fully isolated and >>>>>>> independent of any scope in the template engine). >>>>>>> >>>>>>> Since you want to eval, it seems that efficiency is not an issue, in >>>>>>> which case you can create an anonymous module and eval/create globals in >>>>>>> that module. This should also be reasonably fast if you are only using >>>>>>> the >>>>>>> template once. >>>>>>> >>>>>>> If you want to use it multiple time and compile the template, you >>>>>>> should then scan for variable references in the expressions and process >>>>>>> it >>>>>>> from there. >>>>>>> >>>>>>> >>>>>>>> >>>>>>>> I can either do >>>>>>>> >>>>>>>> <% if _[:foo] == "bar" %> >>>>>>>> >>>>>>>> or >>>>>>>> >>>>>>>> <% if _(:foo) == "bar" %> >>>>>>>> >>>>>>>> but it's not that nice. >>>>>>>> >>>>>>>> >>>>>>>> sâmbătă, 13 august 2016, 13:24:18 UTC+2, Yichao Yu a scris: >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> On Sat, Aug 13, 2016 at 7:13 PM, Adrian Salceanu < >>>>>>>>> adrian....@gmail.com> wrote: >>>>>>>>> >>>>>>>>>> Thanks >>>>>>>>>> >>>>>>>>>> It's for a templating engine. The user creates the document (a >>>>>>>>>> string) which contains interpolated variables placeholders and >>>>>>>>>> markup. When >>>>>>>>>> the template is rendered, the placeholders must be replaced with the >>>>>>>>>> corresponding values from the dict. >>>>>>>>>> >>>>>>>>>> The lines in the template are eval-ed and so Julia will look for >>>>>>>>>> the variables in the scope. So the vars should be already defined. >>>>>>>>>> >>>>>>>>> >>>>>>>>> You should explicitly look up those variables in the dict instead. >>>>>>>>> >>>>>>>>> >>>>>>>>>> >>>>>>>>>> Yes, ultimately I can force the user to use a dict (or rather a >>>>>>>>>> function for a bit of semantic sugar) - which is preferable from a >>>>>>>>>> performance perspective, but less pretty end error prone from the >>>>>>>>>> user >>>>>>>>>> perspective. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>> >>>