> > I think that the best solution is to add a new return value, e.g.
> > {meta, Val}, to controller functions. ErlyWeb will accumulate those
> > values in a list and pass it to the 'phased' Fun as an extra
> > parameter. So, you could write
> > {phased, {ewc, A},
> > fun(ExpandedEwc, MetaVals, Rendered) ->
> > {ewc, html_container, [A, MetaVals, Rendered]}
> > end}.
> > This would simplify setting the Title, Header, etc from the
> > controllers without using Bryan's clever ErlTL tricks (which may be
> > less-than-intuitive for some people :) ), add too much magic to the
> > framework, or even changing it much. It would also work trivially even
> > when subcomponents are rendered in parallel because this is
> > effectively a side-effect-free accumulator.
> That sounds good, and it avoids breaking backwards compatibility as
> well. I do agree about changes to yaws_arg being a bad idea (although
> it is currently possible for programs to change it before passing it
> to children, that would be to be deliberate).
> The only problem I see is that if my controller function returns:
> [{add_property,{title,"The Title!"}},
> {data,"foo"}]
> Then what does my view function look like? These could both make sense:
> <%@ fun([_,Data]) %> <!-- pass it through -->
> <%@ fun([Data]) %> <!-- pretend it didn't exist -->
> I wouldn't mind passing it through, but that does seem a bit strange
> for children to be getting data intended for parents. Pretending it
> didn't exist seems even stranger.
I don't think that the view function should receive the meta Vals. The
'phased' Fun. If you need to pass the same value to the view function
it again as a {data, Data} tuple. Maybe to make things clearer,
...
{meta, [Val1, Val2], [{data, Data}, {ewc, ..}... ]}.
> >> I really like the component system, so I'd definitely like to get
> >> your feedback on my ideas since it's already going in a good
> >> direction.
> >> I wouldn't expect the siblings to be guaranteed to receive it (since
> >> clearly you can't guarantee that they all do, since some may have
> >> already been evaluated, or may be being evaluated at the same time),
> >> but I wouldn't expect them to be guaranteed to *not* receive it.
> >> Since the yaws_arg is being re-vamped anyway, maybe this should be
> >> carried around on the yaws_arg. A simple plist is probably fine for
> >> it. Then as the yaws_arg is returned changed it can be passed through
> >> changed. Then make all subcomponents pass the yaws_arg implicitly: so
> >> instead of {ewc,controller,func,[A,Foo]} calling func(A,Foo), make
> >> {ewc,controller,func,[Foo]]} call fun(A,Foo). That way you're not
> >> passing a stale yaws_arg accidentally. This is of course a backwards-
> >> breaking change, but not a difficult one to fix, since all of the
> >> erlyweb code that I've seen and written passes it to the sub-
> >> components anyway (even if it's not necessarily used).
> >> Otherwise, you end up all of the components doing something like
> >> this:
> >> show(A,Foo)
> >> NewA=yaws_arg:add_meta(A,[{title,get_the_title()}]),
> >> {return_with_meta,[{ewc,func,[NewA,Foo]}],
> >> NewA}.
> >> (once again, with better names than return_with_meta and add_meta)
> >> The worry here is that the subcomponents have to be called with NewA
> >> instead of A, which seems ripe for forgetting to me (especially if
> >> the yaws_arg some some validation before it passes it on; you could
> >> pass invalid data to sub-components this way).
> >> I haven't looked at the contents of the yaws_arg, but if it's tagged
> >> with a type, then you could just do this:
> >> show(A,Foo)
> >> [_New_yaws_arg=yaws_arg:add_property(A,[{title,get_the_title()}]),
> >> {ewc,func,[Foo]}].
> >> Since erlyweb already knows to check the returned list for {ewc} and
> >> whatnot, it could just check for a new yaws_arg and start using that
> >> one. The problem there is that it forces {ewc}s to be processed
> >> serially (since what do you do when you get two conflicting
> >> yaws_args?), which my erlyweb does not (and given your blog post on a
> >> potential {concurrent,[{ewc,...}]}, I suspect this won't be a
> >> guarantee forever). Another idea is to just add another return value
> >> from controller functions:
> >> show(A,Foo)
> >> [{add_property,{title,get_the_title()}},
> >> {add_property,{time_to_live,two_weeks()}}
> >> {ewc,controller,func,[Foo]},
> >> {ewc,controller,fun2,[yaws_arg:get_property(cookies)]].
> >> (this was has my implicit-passing of yaws_args, but it's not
> >> necessary; not doing so does preclude children retrieving properties
> >> from parents, but if they need that they should pass it as an
> >> argument anyway). That doesn't carry the assumption that they are
> >> processed serially. It prevents parents from getting to children's
> >> properties without using {phased,Ewcs,...}, but that's probably not a
> >> problem, and isn't very avoidable. (I think all of these options do,
> >> if they want to do post-processing of any kind).
> >> Personally, I like the last option, but it looks like it would
> >> require quite a few changes to the way that the erlyweb:ewc/N
> >> functions work
> >> Any other ideas? How does that last one look?
> >>>>> Btw, just curious, what parts of ErlyWeb are you rewriting?
> >>>> [...]
> >>>> Mostly large swaths of erlydb and erlydb_mnesia (in ways that
> >>>> make it
> >>>> work better with mnesia, but that make it incompatible with other
> >>>> DBMSs, which of course the current incarnation avoids). I may
> >>>> end up
> >>>> having to revert this if mnesia can't handle millions of objects,
> >>>> with which it seems to be having trouble once they start to become
> >>>> larger objects than simple tuples. I've hacked in a few return and
> >>>> 'EXIT' handlers from controller functions for special
> >>>> circumstances,
> >>>> like when I want to return a 400- or 500-level HTTP response along
> >>>> with other information. I might try to hack in some WebDAV handling
> >>>> stuff, as I'm considering writing a desktop client for my app in
> >>>> the
> >>>> future and that seems the easiest way to get the data to and
> >>>> from the
> >>>> desktop client. I haven't decided what that's going to look like
> >>>> yet.
> >>>> It looks like I may be hacking in a return value to return extended
> >>>> information to parent controller functions, like <title> tags.
> >>>> but I
> >>>> want to decide how it should work, first. It sounds like it's just
> >>>> not a concern to the two biggest users of erlyweb
> >>> If you want to contribute this feature (or any other feature that
> >>> you
> >>> think will be useful to other ErlyWeb users) I'll be happy to accept
> >>> your code.
> >>> Yariv
> >>>>> Yariv
> >>>>> On Nov 16, 2007 10:19 AM, David King <dk...@ketralnis.com> wrote:
> >>>>>> erlyweb uses a component system for rendering pages. It makes
> >>>>>> most of
> >>>>>> my controller functions return lists like this:
> >>>>>> [{data,post:title(Post)},
> >>>>>> {ewc,post,contents,[A,Post]},
> >>>>>> {ewc,comment,comments,[A,post:comments(Post)]}]
> >>>>>> The view function then looks like:
> >>>>>> <%@ show([Title,Contents,Comments]) %>
> >>>>>> <h1><% Title %></h1>
> >>>>>> <div class="post_contents"><% Contents %></div>
> >>>>>> <ul class="comments><% Comments %></ul>
> >>>>>> I really like this, because it allows me to separate the view-
> >>>>>> logic
> >>>>>> for things like contents and comments out from each other, which
> >>>>>> makes changing the behaviour of these quite simple, localised,
> >>>>>> and
> >>>>>> re-
> >>>>>> useable. (In fact, as I re-write portions of erlyweb for my
> >>>>>> purposes,
> >>>>>> the component system is something that I haven't touched at all
> >>>>>> because it works quite well.) However, it has an inherent
> >>>>>> limitation:
> >>>>>> none of those functions can return data to be rendered outside of
> >>>>>> their components. In my case, I'd like to be able to set <title>
> >>>>>> tags, which means that the top-level controller function (by top-
> >>>>>> level, I mean the one referenced in the URL; like in /post/
> >>>>>> show/12,
> >>>>>> the top-level controller function would be show/2) needs to
> >>>>>> somehow
> >>>>>> return information to be rendered outside its little sandbox.
> >>>>>> I see that Vimagi doesn't set <title> tags (neither <http://
> >>>>>> vimagi.com/p/0PXmMRe6hGV> nor <http://vimagi.com/users/
> >>>>>> feeling3_4>
> >>>>>> set one, at least, and those are where I'd expect to see
> >>>>>> them), but
> >>>>>> BeerRiot does (<http://beerriot.com/beer/view/1751>; BTW I do
> >>>>>> love
> >>>>>> the idea of having a controller called "beer_controller").
> >>>>>> It isn't limited to <title>s (for instance, I may want to
> >>>>>> alert the
> >>>>>> browser that an RSS equivalent of this page exists, or what the
> >>>>>> caching TTL is for this page in the HTTP headers). Conceptually,
> >>>>>> how
> >>>>>> would one go about returning this extra information, while still
> >>>>>> using the component system (I now have a lot of code that uses it
> >>>>>> that I'd like to not re-write :) )?