35
36:- module(swish_examples, []). 37:- use_module(library(http/http_dispatch)). 38:- use_module(library(http/http_json)). 39:- use_module(library(http/json)). 40:- use_module(library(http/http_path)). 41:- use_module(library(filesex)). 42:- use_module(library(apply)). 43:- use_module(library(option)). 44:- use_module(library(lists)). 45:- if(exists_source(library(atom))). 46:- use_module(library(atom)). 47:- endif. 48
49:- use_module(storage). 50:- use_module(md_eval).
67:- multifile
68 user:file_search_path/2,
69 swish_config:config/2,
70 swish_config:source_alias/2. 71
73user:file_search_path(example, swish(examples)).
75swish_config:source_alias(example, [access(read), search('*.{pl,swinb}')]).
76
77:- http_handler(swish(list_examples),
78 list_examples, [id(swish_examples)]).
86list_examples(_Request) :-
87 examples(AllExamples, [community(true)]),
88 example_menu(AllExamples, Menu),
89 reply_json(Menu).
90
(AllExamples, Menu) :-
92 include(pos_ranked, AllExamples, ForMenu),
93 insert_group_dividers(ForMenu, Menu).
94
95pos_ranked(Ex) :-
96 Rank = Ex.get(grank),
97 Rank > 0.
98
99insert_group_dividers([], []).
100insert_group_dividers([H1,H2|T], List) :-
101 !,
102 ( H1.grank // 10000 =\= H2.grank // 10000
103 -> List = [H1, json{type:divider}|Rest]
104 ; List = [H1|Rest]
105 ),
106 insert_group_dividers([H2|T], Rest).
107insert_group_dividers([H], [H]).
121examples(AllExamples, Options) :-
122 swish_examples(SWISHExamples),
123 ( option(community(true), Options)
124 -> community_examples(CommunityEx)
125 ; CommunityEx = json{}
126 ),
127 join_examples([CommunityEx|SWISHExamples], AllExamples).
128
129:- dynamic
130 swish_example_cache/2. 131
132swish_examples(SWISHExamples) :-
133 swish_example_cache(SWISHExamples, Time),
134 get_time(Now),
135 Now - Time < 60,
136 !.
137swish_examples(SWISHExamples) :-
138 swish_examples_no_cache(SWISHExamples),
139 get_time(Now),
140 retractall(swish_example_cache(_,_)),
141 assertz(swish_example_cache(SWISHExamples, Now)).
142
143swish_examples_no_cache(SWISHExamples) :-
144 http_absolute_location(swish(example), HREF, []),
145 findall(Index,
146 absolute_file_name(example(.), Index,
147 [ access(read),
148 file_type(directory),
149 file_errors(fail),
150 solutions(all)
151 ]),
152 ExDirs),
153 maplist(index_json(HREF), ExDirs, SWISHExamples).
154
155
156join_examples(PerDir, Files) :-
157 menu_groups(PerDir, Groups),
158 maplist(get_or(files, []), PerDir, FilesPerDir),
159 append(FilesPerDir, Files0),
160 maplist(add_grank(Groups), Files0, Files1),
161 sort(grank, =<, Files1, Files).
162
163add_grank(Groups, File0, File) :-
164 get_or(rank, 500, File0, FRank),
165 GroupName = File0.get(group),
166 member(Group, Groups),
167 Group.get(group) == GroupName,
168 GRank is FRank + Group.get(rank), !,
169 File = File0.put(grank, GRank).
170add_grank(_, File0, File) :-
171 File = File0.put(grank, -1).
172
(PerDir, Groups) :-
174 maplist(get_or(menu, []), PerDir, GroupsPerDir),
175 append(GroupsPerDir, Groups0),
176 sort(group, @>, Groups0, Groups1),
177 sort(rank, =<, Groups1, Groups).
178
179get_or(Key, Default, Dict, Value) :-
180 ( is_dict(Dict),
181 Value = Dict.get(Key)
182 -> true
183 ; Value = Default
184 ).
194index_json(HREF, Dir, JSON) :-
195 directory_file_path(Dir, 'index.json', File),
196 access_file(File, read), !,
197 read_file_to_json(File, JSON0),
198 add_examples_href(HREF, JSON0, JSON1),
199 add_other_files(HREF, Dir, JSON1, JSON).
200index_json(HREF, Dir, json{menu:[json{group:examples, rank:10000}],
201 files:Files}) :-
202 example_files(HREF, Dir, Files0),
203 maplist(add_group(examples), Files0, Files).
204
205example_files(HREF, Dir, JSON) :-
206 string_concat(Dir, "/*.{pl,swinb}", Pattern),
207 expand_file_name(Pattern, Files),
208 maplist(ex_file_json(HREF), Files, JSON).
209
210read_file_to_json(File, JSON) :-
211 setup_call_cleanup(
212 open(File, read, In, [encoding(utf8)]),
213 json_read_dict(In, JSON, [default_tag(json)]),
214 close(In)).
221add_examples_href(HREF, JSON0, JSON) :-
222 Files0 = JSON0.get(files), !,
223 convlist(add_href(HREF), Files0, Files),
224 JSON = JSON0.put(files, Files).
225add_examples_href(_, JSON, JSON).
226
227
228add_href(HREF0, Dict, Dict2) :-
229 is_dict(Dict),
230 directory_file_path(HREF0, Dict.get(file), HREF),
231 Dict2 = Dict.put(href, HREF).
232
233add_group(Group, Dict0, Dict) :-
234 is_dict(Dict0), !,
235 Dict = Dict0.put(group, Group).
236add_group(_, Dict, Dict).
237
238add_other_files(HREF, Dir, JSON0, JSON) :-
239 example_files(HREF, Dir, Files),
240 get_or(files, [], JSON0, Files0),
241 exclude(in_ex_list(Files0), Files, New),
242 append(Files0, New, AllFiles),
243 JSON = JSON0.put(files, AllFiles).
244
245in_ex_list(Examples, Ex) :-
246 File = Ex.file,
247 member(Ex2, Examples),
248 is_dict(Ex2),
249 File = Ex2.get(file),
250 !.
256ex_file_json(HREF0, Path, json{file:File, href:HREF, title:Title}) :-
257 file_base_name(Path, File),
258 file_name_extension(Base, _, File),
259 file_name_to_title(Base, Title),
260 directory_file_path(HREF0, File, HREF).
261
262:- if(current_predicate(restyle_identifier/3)). 263file_name_to_title(Base, Title) :-
264 restyle_identifier(style(true,false,' '), Base, Title).
265:- else. 266file_name_to_title(Base, Base).
267:- endif.
281:- multifile
282 md_eval:provides/1. 283
284md_eval:provides(example(Name, Group, Example)) :-
285 examples(Examples, []),
286 ( var(Name)
287 -> member(Example0, Examples),
288 atom_string(Name, Example0.get(file))
289 ; member(Example0, Examples),
290 atom_string(Name, Example0.get(file))
291 -> true
292 ),
293 atom_string(Group, Example0.get(group)),
294 active_example(Example0, Example).
295
296active_example(Example0, Example) :-
297 term_string(Cond, Example0.get(requires)),
298 \+ swish_provides(Cond),
299 ( cond_reason(Cond, Fmt, Args)
300 -> format(string(Reason), Fmt, Args)
301 ; format(string(Reason), 'missing requirement: ~q', [Cond])
302 ),
303 Example = Example0.put(blocked, Reason).
304active_example(Example, Example).
305
306cond_reason(plugin(Name), 'missing plugin: ~w', [Name]).
307
308
309
310
318community_examples(json{menu:[json{group:community, rank:50000}],
319 files:Files}) :-
320 swish_config:config(community_examples, true),
321 !,
322 findall(Ex, community_example(Ex), Files).
323community_examples(json{}).
324
(json{title:Title, file:File, group:community, type:store}) :-
326 storage_file(File),
327 storage_meta_data(File, Meta),
328 Meta.get(example) == true,
329 ( Title = Meta.get(title), Title \== ""
330 -> true
331 ; file_name_extension(Base, _, File),
332 file_name_to_title(Base, Title)
333 )
Serve example files
Locate and serve files for the Examples menu as well as examples included from overview notebooks. The examples come from two sources:
examples
. Such files are distributed with SWISH.example
. Such files can be created by the users.This module also makes the known examples available through swish_provides/1 for supporting conditional statements on example overview notebooks. */