reply to Joey
[ikiwiki] / doc / todo / pagespec_aliases.mdwn
1 [[!template id=gitbranch branch=jon/pagespec_alias author="[[Jon]]"]]
2 [[!tag patch wishlist]]I quite often find myself repeating a boiler-plate
3 [[ikiwiki/pagespec]] chunk, e.g.
4
5     and !*.png and !*.jpg...
6
7 it would be quite nice if I could conveniently bundle them together into a
8 pagespec "alias", and instead write
9
10     and !image()...
11
12 I wrote the following plugin to achieve this:
13
14     <snip old patch; see git branch outlined above>
15
16 I need to reflect on this a bit more before I send a pull request.  In
17 particular I imagine the strict/warnings stuff will make you puke.  Also, I'm
18 not sure whether I should name-grab 'alias' since [[todo/alias_directive]] is
19 an existing wishlist item.
20
21 > I think it would make sense to have "pagespec" in the name somehow.
22
23 >> Good idea, how about `pagespecalias`? — [[Jon]]
24
25 > No, the strict/warnings does not make me puke. Have you read my perl
26 > code? :-P
27
28 > Note that your XXX is right. It would be a security hole to not validate
29 > `$key`, as anyone with websetup access could cause it to run arbitrary
30 > perl code.
31
32 > Well, except that websetup doesn't currently support configuring hashes
33 > like used here. Which is a pity, but has led me to try to avoid using
34 > such hashes in the setup file.
35
36 > > If I removed the `getsetup` subroutine, it would not be exposed via
37 > > website, is that right?  I suppose it doesn't hurt to validate key, even if
38 > > this risk was not there.  Is the use of a hash here a blocker for adoption?
39 > > — [[Jon]]
40
41 > Have you considered not defining the pagespec aliases in the setup file, but
42 > instead as directives on pages in the wiki? Using pagestate could store
43 > up the aliases that have been defined. It could however, be hard to get
44 > the dependencies right; any page that uses a pagespec containing 
45 > an alias `foo` would need to somehow depend on the page where the alias
46 > was defined. --[[Joey]] 
47
48 > > I haven't thought the dependency issue through beyond "that might be hard".
49 > > Personally, I don't like defining stuff like this in pages, but I appreciate
50 > > some do.  There could be some complex scenarios where some pages rely on a
51 > > pagespec alias defined on others; and could have their meanings changed by
52 > > changing the definition.  A user might have permission to edit a page with a
53 > > definition on it but not on the pages that use it, and similar subtle permission
54 > > bugs.  I'm also not sure what the failure mode is if someone redefines an alias,
55 > > and whether there'd be an unpredictable precedence problem.
56 > > How about both methods? — [[Jon]]
57
58 Here's an example setup chunk:
59
60      pagespec_aliases:
61        image: "*.png or *.jpg or *.jpeg or *.gif or *.ico"
62        helper: "*.css or *.js"
63        boring: "image() or helper()"
64
65 The above demonstrates self-referential dynamic pagespec aliases.  It doesn't work,
66 however, to add ' or internal()' to `boring`, for some reason.
67
68 -- [[Jon]]
69
70 > Probably needs to be `or internal(*)` --[[Joey]] 
71
72 > > Ah yes, could be, thanks. — [[Jon]]
73
74 > another useful pagespec alias for large maps:
75
76        basewiki: "sandbox or templates or templates/* or ikiwiki or ikiwiki/* or shortcuts or recentchanges or wikiicons/*"
77
78 > -- [[Jon]]
79
80 >> Useful indeed! --[[Joey]] 
81
82
83 >>> I've tweaked my patch in light of your above feedback:  The plugin has been
84 >>> renamed, and I now validate keys.  I've also added documentation and tests
85 >>> to the branch.  I haven't read rubykat's code properly yet, and don't have
86 >>> access at the time of writing (I'm on a beach in Greece ☺), but I expect it
87 >>> would be possible to extend what I've got here to support defining the
88 >>> aliases in a PageSpec, once the dependency stuff has been reasoned out
89 >>> properly.
90 >>>
91 >>> I'd like to solve the issue of this not being web-configurable by
92 >>> implementing support for more nested datatypes in [[plugins/websetup]]. —
93 >>> [[Jon]]
94
95 >>>> Well, it's a difficult problem. websetup builds a form using
96 >>>> CGI::FormBuilder, which makes it easy to build the simple UI we have
97 >>>> now, but sorta precludes anything more complicated. And anything with
98 >>>> a nested datatype probably needs a customized UI for users to be able
99 >>>> to deal with it. I don't think websetupability need be a deal-breaker
100 >>>> for this patch. I personally like special pages like Kathryn is doing
101 >>>> more than complex setup files. --[[Joey]]
102
103 >>>>> I've ran out of time to keep working on this, so I'm just going to
104 >>>>> submit it as a 'contrib' plugin and leave things at that for now.
105 >>>>> — [[Jon]]
106
107 ---------------------------
108
109 Based on the above, I have written an experimental plugin called "subset".
110 It's in my "ikiplugins" repo on github, in the "experimental" branch.
111 <https://github.com/rubykat/ikiplugins/blob/experimental/IkiWiki/Plugin/subset.pm>
112
113 It takes Joey's suggestion of defining the subsets (aliases) as directives;
114 I took the example of the [[plugins/shortcut]] plugin and designated a single special page as the one where the directives are defined,
115 though unlike "shortcut" I haven't hardcoded the name of the page; it defaults to "subsets" but it can be re-defined in the config.
116
117 I've also added a feature which one might call subset-caching; I had to override `pagespec_match_list` to do it, however.
118 An extra parameter added to `pagespec_match_list` called `subset` which
119
120 * limits the result to look *only* within the set of pages defined by the subset (uses the "list" option to pagespec_match_list to do this)
121 * caches the result of the subset search so that the second time subset "foo" is used, it uses the stored result of the first search for "foo".
122
123 This speeds things up if one is using a particular subset more than once, which one probably is if one bothered to define the subset in the first place.
124 The speed increase is most dramatic when the site has a large number of pages and the number of pages in the subset is small.
125 (this is similar to the "trail" concept I used in my [[plugins/contrib/report]] plugin, but not quite the same)
126
127 Note that things like [[plugins/map]] can't make use of "subset" (yet) because they don't pass along all the parameters they're given.
128 But [[plugins/contrib/report]] actually works without alteration because it does pass along all the parameters.
129
130 Unfortunately I haven't figured out how to do the dependencies - I'd really appreciate help on that.
131
132 --[[KathrynAndersen]]
133
134 > > Cool!  I like the caching idea.  I'm not sure about the name.  I don't like defining
135 > > stuff in pages, but I appreciate this is a matter of taste, and would be happy with
136 > > supporting both. — [[Jon]]
137
138 >>> I've now gone and completely re-done "subset" so that it is less like an alias, but it a bit clearer and simpler:
139 >>> instead of having a separate "match_" function for every alias, I simply have one function, "match_subset"
140 >>> which takes the name of the subset.  Thus a \[[!subset name="foo"...]] would be called `subset(foo)` rather than `foo()`.
141
142 >>> There are a few reasons for this:<br/>
143 >>> (a) it's more secure not to be evaluating code on the fly<br/>
144 >>> (b) it's simpler<br/>
145 >>> (c) (and this was my main reason) it makes it possible to do caching without having to have a separate "subset" argument.
146 >>> I've done a bit of a hack for this: basically, the PageSpec is checked to see if the very start of the PageSpec is `subset(foo) and` or if the whole pagespec is just `subset(foo)` and if either of those is true, then it does the subset caching stuff.
147 >>> The reason I check for "and" is that if it is "subset(foo) or something" then it would be an error to use the subset cache in that case.
148 >>> The reason I just check the start of the PageSpec is because I don't want to have to do complex parsing of the PageSpec.
149
150 >>> As for defining subsets in the config rather than on pages, I perfectly understand that desire, and I could probably add that in.
151
152 >>> As for the name "subset"... well, it's even less like an alias now, and "alias" is already a reserved name.  What other names would you suggest?
153
154 >>>--[[KathrynAndersen]]
155
156 >>>> Regarding my comments:  I wasn't clear what you are/were intending to
157 >>>> achieve with your modifications.  I've aimed for a self-contained plugin
158 >>>> which could be merged with ikiwiki proper.  I think I initially took your
159 >>>> developments as being an evolution of that with the same goal, which is
160 >>>> why I commented on the (change of) name.  However, I guess your work is
161 >>>> more of a fork than a continuation,  in which case you can call it
162 >>>> whatever you like ☺  I like some of the enhancements you've made, but
163 >>>> having the aliases/subsets/"things" work in any pagespec (inside map, or
164 >>>> inline) is a deal-breaker for me. — [[Jon]]
165
166 >>>>> I'm a bit confused by your statement "having the aliases/subsets/"things" work in any pagespec (inside map, or inline) is a deal-breaker for me".
167 >>>>> Do you mean that you want them to work in any pagespec, or that you *don't* want them to work in any pagespec? -- [[KathrynAndersen]]
168
169 >>>>>> I mean I would want them to work in any pagespec. — [[Jon]]