foo(String... names) {
67 | return Arrays.stream(names)
68 | .map(n -> new Person(n, n.length()))
69 | .toList();
70 | }
71 | }
72 |
73 | // “C-x C-j” shows me “human readable” results
74 | Person.foo("Hamid", "Jaafar");
75 |
76 | // “C-u C-x C-j” shows me “java readable” code that can be used for
77 | // regression tests
78 | Person.foo("Hamid", "Jaafar");
79 |
80 | // We can also interactively navigate large data-dumps…
81 | // …when overlay output is cramped
82 | Person.foo("Hamid", "Jaafar", "Musa", "Montather");
83 |
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/snippets/growing-a-webserver.js:
--------------------------------------------------------------------------------
1 | // C-x C-j now evaluates arbitrary JavaScript code ♥‿♥
2 | // (repl-driven-development [C-x C-j] javascript)
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | [...Array(40).keys()]
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | .map(x => x % 3 == 0 ? "Fizz" : x)
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 | .map(x => x % 3 == 5 ? "Buzz" : x)
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 | .map(x => x % 3 == 0 && x % 5 == 0 ? "FizzBuzz" : x)
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 | // C-x C-j now evaluates arbitrary JavaScript code, I'd also like docs for JS and Express
246 | // (repl-driven-development [C-x C-j] "node" :docs "javascript express")
247 |
248 | // npm install -g express axios@0.21.1
249 |
250 | let app = require('/usr/local/lib/node_modules/express')()
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 | let server = app.listen(3030) // 📚
307 |
308 | // Now visit http://localhost:3030/
309 | // ... and see “Cannot GET /”
310 | // ... Neat, it works but it does nothing! Importantly it works!
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 | // Let's add a route...
368 | let visited = 1
369 | app.get('/hi', (_req, res) => res.send(`Hello × ${visited++}`))
370 |
371 | // Now visit: http://localhost:3030/hi
372 | // Refresh the page a few times 😉
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 | // Notice the local values of “visited” has changed, for each refresh
431 | visited
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 | // Excellent; let's add an end-point to return info about the user
487 | app.get('/about', (_req, res) => res.send(html()))
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 | // Whoops, there's no “html”! So we see an error!
545 | // Let's define that!
546 | let html = _ => "" + info() + "
"
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 | // Whoops, there's no “info”! So we see an error!
604 | // Let's define that!
605 | let info = function() { return { visited, user: process.env.USER, time: new Date() } }
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 | // Uh-oh, we see “[object Object]” since we didn't convert the
663 | // JS object into a JSON string, so let's fix that!
664 | html = _ => "" + JSON.stringify(info(), null, 3 /* indentation */) + "
"
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 | // Uh-oh, the output doesn't look good; let's redefine `html` using tags.
722 | html = _ => `Welcome, visitor ${visited++}!
723 |
724 | ${ JSON.stringify(info(), null, 3 /* indentation */) }
725 |
`
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 |
745 |
746 |
747 |
748 |
749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 | // 🤩 Notice how we built this end-point from the top-down:
785 | // 🥰 We knew what we wanted, and saw some errors
786 | // ---on the client side--- then fixed them right here,
787 | // with no reloading! 🥳
788 |
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 |
800 |
801 |
802 |
803 |
804 |
805 |
806 |
807 |
808 |
809 |
810 |
811 |
812 |
813 |
814 |
815 |
816 |
817 |
818 |
819 |
820 |
821 |
822 |
823 |
824 |
825 |
826 |
827 |
828 |
829 |
830 |
831 |
832 |
833 |
834 |
835 |
836 |
837 |
838 |
839 |
840 |
841 |
842 |
843 | // Actually, let's get info about a JS cheat sheet repo
844 | var axios = require('axios')
845 | let repo = (await axios
846 | .get('https://api.github.com/repos/alhassy/JavaScriptCheatSheet')).data
847 | info = _ => ({ url: repo.html_url,
848 | description: repo.description,
849 | stars: repo.watchers,
850 | forks: repo.forks,
851 | topics: repo.topics
852 | })
853 |
854 |
855 |
856 |
857 |
858 |
859 |
860 |
861 |
862 |
863 |
864 |
865 |
866 |
867 |
868 |
869 |
870 |
871 |
872 |
873 |
874 |
875 |
876 |
877 |
878 |
879 |
880 |
881 |
882 |
883 |
884 |
885 |
886 |
887 |
888 |
889 |
890 |
891 |
892 |
893 |
894 |
895 |
896 |
897 |
898 |
899 |
900 |
901 |
902 |
903 |
904 |
905 |
906 |
907 |
908 |
909 |
910 |
911 |
912 |
913 |
914 | // So cool!
915 |
916 | // Eventually, consider closing the server!
917 | server.close()
918 |
919 | // Bye! ᕦ( ᴼ ڡ ᴼ )ᕤ
920 |
921 |
922 |
923 |
924 |
925 |
926 |
927 |
928 |
929 |
930 |
931 |
932 |
933 |
934 |
935 |
936 |
937 |
938 |
939 |
940 |
941 |
942 |
943 |
944 |
945 |
946 |
947 |
948 |
949 |
950 |
951 |
952 |
953 |
954 |
955 |
956 |
957 |
958 |
959 |
960 |
961 |
962 |
963 |
964 |
965 |
966 |
967 |
968 |
969 |
970 |
971 |
972 |
973 |
974 |
975 |
976 |
977 |
978 |
979 |
980 |
981 |
982 |
983 |
984 |
985 |
986 |
987 |
988 |
989 |
990 |
991 |
992 |
993 |
994 |
995 |
996 |
997 |
998 |
999 |
1000 |
1001 |
1002 |
1003 |
1004 |
1005 |
1006 |
1007 |
1008 |
1009 |
1010 |
1011 |
1012 |
1013 |
1014 |
1015 |
1016 |
1017 |
1018 |
1019 |
1020 |
1021 |
1022 |
1023 |
1024 |
1025 |
1026 |
1027 |
1028 |
1029 |
1030 |
1031 |
1032 |
1033 |
1034 |
1035 |
1036 |
1037 |
1038 | /*
1039 | (setq frame-title-format "REPL Driven Development with JavaScript: FizzBuzz ᕦ( ᴼ ڡ ᴼ )ᕤ
1040 | ")
1041 |
1042 | M-x goto-address-mode ;; makes all URLs clickable
1043 | http://localhost:3030/
1044 |
1045 |
1046 |
1047 | (defun doom-modeline-buffer-file-name () "⇒ www.alhassy.com/repl-driven-development ⇐")
1048 |
1049 |
1050 | (flymake-mode -1)
1051 | (minions-mode 1)
1052 | (flyspell-mode -1)
1053 |
1054 | (bind-key "M-SPC" (cl-defun my/delete-vertical-space ()
1055 | (interactive)
1056 | (delete-all-space)
1057 | (insert "\n")
1058 | (indent-for-tab-command)))
1059 |
1060 | Note: If you forget to close the sever, run “lso -i :3030” to find the pid
1061 | then run “kill -9 PROCESS_ID”.
1062 |
1063 |
1064 | (setq prettify-symbols-alist '(("=>" . 8658)))
1065 | (prettify-symbols-mode -1)
1066 | (prettify-symbols-mode +1)
1067 | */
1068 |
--------------------------------------------------------------------------------
/snippets/testing.el:
--------------------------------------------------------------------------------
1 | (when nil ⨾⨾ Rich Comment consisting of executable code to try things out.
2 |
3 | ⨾⨾ Testing setup ⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾
4 |
5 | (load-file "./testing-setup.el") ;; See my init.el
6 | (eval-buffer "repl-driven-development.el")
7 | ;; Style errors, package errors
8 | (my/show-errors)
9 | ;; Byte-compiles the file with all warnings enabled.
10 | (elisp-lint--byte-compile (buffer-file-name))
11 | ;; Show me references to unbound symbols
12 | (elint-current-buffer)
13 | (my/load-file-in-new-emacs)
14 | (progn (outshine-mode) (outline-minor-mode))
15 |
16 | ⨾⨾ A simple terminal REPL works as expected ⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾
17 |
18 | (repl-driven-development [C-x C-t] "bash" :blink 'pulsar-green)
19 | echo -e "$(whoami): On $(date), I sit at $(pwd) pondering ... \n $(ls)"
20 |
21 | ;; Nice docs
22 | (documentation #'bash-eval)
23 |
24 | ;; The output is echoed via an overlay; however on the source to see it
25 | ;; in a tooltip; invoke C-h e to see it in the *Messages* buffer;
26 | ;; Or see it in its own buffer with M-x ...
27 | (bash-eval-display-output) ;; i.e., (rdd@ "bash" output)
28 |
29 | ;; Insert the result of the above shell command with C-u C-x C-t.
30 |
31 | ;; We can also restart the repl... let's set some state
32 | export X=123
33 | echo $X
34 | ;; Now restart it with C-u -1 C-x C-t
35 | echo $X
36 | ;; C-x C-t on the above line emits no value
37 |
38 | ;; Init code works upon initialisation, neato!
39 | (repl-driven-development [C-x C-t] "bash" :init "echo $(fortune)")
40 |
41 | ;; We can get rid of the prompt at the end with :prompt
42 | (repl-driven-development [C-x C-t] "bash" :prompt "^bash.*?\\$")
43 | pwd
44 | echo "bye$"
45 |
46 | (repl-driven-development [C-x C-t] terminal)
47 |
48 | ⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾
49 | ;; We can change the blinking colours via rdd@.
50 | (repl-driven-development [C-x C-n] "node" :blink 'pulsar-blue)
51 | [...Array(14).keys()].map(x => x % 3 == 0 ? "Fizz" : x)
52 | ;; Change colour with C-x C-e, then C-x C-n on the line after.
53 | (setf (rdd@ "node" blink) 'pulsar-green)
54 | Object.keys({name: "mikle", 1: "one"})
55 |
56 | ⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾
57 | ;; We can use a preconfigured REPL.
58 | ;;
59 | ;; Notice associated buffer's name involves only the command "jshell",
60 | ;; not the args. See it via C-u 0 C-x C-j.
61 | (repl-driven-development [C-x C-j] java)
62 | ;;
63 | ;; This allows us to submit multi-line input seamlessly.
64 | ;; Select the following 6 lines, then submit this region with C-x C-j
65 | IntStream
66 | /* a multi-line
67 | * comment */
68 | .range(0, 23)
69 | // Now print it out
70 | .forEach(x -> System.out.println(x))
71 |
72 | ;; There is no repetation of input via output
73 | ;; https://github.com/alhassy/repl-driven-development/issues/5
74 | System.out.println("Hi")
75 |
76 | IntStream.range(0, 40) .mapToObj(i -> i % 15 == 0 ? "FizzBuzz" : i % 3 == 0 ? "Fizz" : i % 5 == 0 ? "Buzz" : String.valueOf(i)).toList()
77 |
78 | // Let's make a type to model stuff we're working with
79 | record Person(String name, int age) { }
80 |
81 | // Let's write a super duper complex algorithm
82 | List foo(String... names) { return Arrays.stream(names).map(n -> new Person(n, n.length())).toList(); }
83 |
84 | // Let's run our algorithm and get *executable* outputs that can then be used for regression tests
85 | foo("musa", "hamid") // C-x C-j shows me “human readable” results
86 | // C-u C-x C-j shows me “java readable” code that can be used for regression tests
87 | foo("musa", "hamid")
88 | // ⇒ List.of(new Person("musa", 4), new Person("hamid", 5))
89 |
90 |
91 | ⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾
92 | ;; Likewise for NodeJS
93 | (repl-driven-development [C-x C-n] javascript)
94 | ;; Then submit:
95 | [...Array(40).keys()]
96 | // yay, a comment in the middle
97 | .map(x => x % 3 == 0 ? "Fizz" : x)
98 |
99 | ⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾⨾
100 | ;; Likewise for Python
101 | (repl-driven-development [C-x C-p] python)
102 | ;; Send each line, one at a time.
103 | "
104 | 1 + 2 * 3
105 |
106 | def foo(x): return x*x
107 |
108 | foo(5)
109 |
110 | list(map(lambda i: 'Fizz'*(not i%3)+'Buzz'*(not i%5) or i, range(1,101)))
111 |
112 | # (Above shows Result Truncated due to my use of eros, which has this limit.
113 | # TODO[Low Priority]: Fix this.)
114 | #
115 | # We can do multi-line def ---The quotes are to allow me to indent,
116 | # otherwise my aggressive-formatter strips the whitespace away.
117 |
118 | def square(x):
119 | return x * x
120 |
121 | square(5)
122 |
123 | # Likewise for class-es:
124 |
125 | class MyClass():
126 | i = 12345
127 |
128 | def f(self):
129 | return 'hello world'
130 |
131 |
132 | x = MyClass()
133 | x.i
134 | x.f()
135 | "
136 | ;; Notice that the code is indented nicely.
137 | )
138 |
139 |
140 | (cl-flet ((java-read (str)
141 | (thread-last
142 | str
143 | repl-driven-development--parse-pretty-printed-java
144 | repl-driven-development--lisp-to-java)))
145 | (require 'ert)
146 | ;; Non-record *values* are read literally
147 | (should (equal (java-read "123") "123"))
148 | ;; Records with a single field become constructor calls on that field: As a number (if possible), otherwise as a string.
149 | (should (equal (java-read "Person[name=Jaafar]") "new Person(\"Jaafar\")"))
150 | (should (equal (java-read "Person[age=31.2]") "new Person(31.2)"))
151 | ;; Record payloads can include spaces and commas
152 | (should (equal (java-read "Person[name=AsSaddiq, Jaafar, the first, age=thirty and one, years=31]")
153 | "new Person(\"AsSaddiq, Jaafar, the first\", \"thirty and one\", 31)"))
154 | ;; We can read nested records.
155 | ;; For arbitrarly deep nesting, we cannot use regular expressions, and so we need to move to using PEGs.
156 | (should (equal (java-read "Person[name=Jaafar, child=Person[name=Yacoub]]") "new Person(\"Jaafar\", new Person(\"Yacoub\"))"))
157 | (should (equal (java-read "Person[name=Jaafar, child=Person[name=Yacoub], child=Person[name=Jasim]]")
158 | "new Person(\"Jaafar\", new Person(\"Yacoub\"), new Person(\"Jasim\"))"))
159 | (should (equal (java-read "Person[name=Hamid, child=Person[name=Jaafar, child=Person[name=Yacoub]]]")
160 | "new Person(\"Hamid\", new Person(\"Jaafar\", new Person(\"Yacoub\")))"))
161 | (should (equal (java-read "Person[name=hamid, child=Person[name=Jaafar, age=12]]") "new Person(\"hamid\", new Person(\"Jaafar\", 12))"))
162 | ;; We can read lists.
163 | (should (equal (java-read "[1, 2, 3]") "List.of(1, 2, 3)"))
164 | (should (equal (java-read "[]") "List.of()"))
165 | (should (equal (java-read "[Person[name=Jasim, age=72, zindex=0.5], Person[name=Kathy, age=82, zindex=2.78], Person[name=Jaafar, age=31, zindex=3]]")
166 | "List.of(new Person(\"Jasim\", 72, 0.5), new Person(\"Kathy\", 82, 2.78), new Person(\"Jaafar\", 31, 3))"))
167 | (should (equal (java-read "[[1], [2, 3], [4, 5, 6]]") "List.of(List.of(1), List.of(2, 3), List.of(4, 5, 6))"))
168 | ;; We can mix the various structures (records & lists)
169 | ;; TODO: (java-read "Person[children=[]]")
170 | (should (equal (java-read "A[a=[B[b=[C[c=D[d=[E[e=hello]]]]]]]]")
171 | "new A(List.of(new B(List.of(new C(new D(List.of(new E(\"hello\"))))))))"))
172 | ;; Null is known
173 | (should (equal (java-read "Person[name=null]") "new Person(null)"))
174 | ;; Maps are known
175 | (should (equal (java-read "{}") "Map.of()"))
176 | (should (equal (java-read "{a=1, b=2, c=3}") "Map.of(a, 1, b, 2, c, 3)"))
177 | (should (equal (java-read "{a=Alice, b=Bob, c=Kathy}") "Map.of(a, \"Alice\", b, \"Bob\", c, \"Kathy\")"))
178 | ;; TODO: Allow numbers as keys.
179 | ;; {1=hello, 2=world}
180 | ;; TODO: (java-read "Person[]")
181 | )
182 |
183 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
184 | ;; TODO: Document the `emacs' function in the javascript repl.
185 | ;;
186 | ;; emacs.eval(`user-full-name`)
187 | ;; emacs.eval(`(load-theme 'spacemacs-dark)`)
188 | ;; emacs.eval(`(load-theme 'spacemacs-light)`)
189 | ;; emacs.eval(`(message-box "hi")`)
190 | ;; // Multi-line also works fine
191 | ;; emacs.eval(`(progn
192 | ;; (message-box "Hello")
193 | ;; (message-box "World")
194 | ;; )`)
195 |
196 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
197 | ;;
198 | ;; TODO: Add to main rdd.el macro: Mention connecting to JS Server via C-x C-t telnet.
199 |
200 | ;; Something to consider using
201 | ;;
202 | ;; Current bug: It makes C-x C-t insert unexpected text, the docstring of C-x C-t!
203 |
204 | (defmacro rdd-defun (repl name args-list doc-string &rest body)
205 | "Defun NAME with ARGS_LIST and DOC-STRING and BODY, in the REPL namespace.
206 |
207 | This is like `defun' but the source code, excluding DOC-STRING,
208 | is appended to the function's docstring."
209 | ;; TODO: fun-name keyword of main rdd.el macro should be replace by a new :name keyword,
210 | ;; then fun-name is just “⟨name⟩-eval”, and derived methods are “⟨name⟩-eval-⟨derivation⟩”.
211 | (let* ( (name-sym (intern (format "%s" name)))
212 | (fun-name-sym (intern (format "%s" (rdd@ repl fun-name))))
213 | (command-name (if (equal name-sym fun-name-sym) name-sym (intern (format "%s-%s" fun-name-sym name-sym)))))
214 | `(progn
215 | (setf (rdd@ ,repl ,command-name)
216 | ;; restart repl, [then send to repl --does not work since REPLs take a sec
217 | ;; to load. That's OK, not a deal-breaker!]
218 | (-cons* 'defun (quote ,command-name) (quote ,args-list) (quote ,body)))
219 |
220 | (eval (rdd@ ,repl ,command-name))
221 |
222 | ;; TODO: Add to requires
223 | (require 'cl-extra)
224 |
225 |
226 |
227 | (put (quote ,command-name)
228 | 'function-documentation
229 | (concat
230 | ,doc-string
231 | (format "\n\n\t\t﴾Source Code of “%s”﴿\n\n" (quote ,command-name))
232 | (with-temp-buffer (cl-prettyprint (rdd@ ,repl ,command-name)) (buffer-substring-no-properties (point-min) (point-max)))
233 | )))))
234 | ;; MA: For testing.
235 | ;; (insert (pp-to-string (macroexpand '(rdd-defun "bash" restart-NEW1 (x y) "6 hola amigos ~ Restart the REPL process." (interactive) 'BYE))))
236 |
237 | ;; Intended usage sites:
238 |
239 | - ;; restart repl, [then send to repl --does not work since REPLs take a sec
240 | - ;; to load. That's OK, not a deal-breaker!]
241 | - (defun ,(intern (format "%s-restart" (rdd@ repl fun-name))) ()
242 | "Restart the REPL process."
243 | (interactive)
244 | (kill-buffer (process-buffer (rdd@ ,repl process)))
245 | (repl-driven-development (rdd@ ,repl keybinding)
246 | (rdd@ ,repl cmd)
247 | :prompt (rdd@ ,repl prompt)
248 | :docs (rdd@ ,repl docs)
249 | :init (rdd@ ,repl init)
250 | :blink (rdd@ ,repl blink)))
251 |
252 | ;; and
253 |
254 | (eval (rdd-defun
255 | ,repl
256 | ,(rdd@ repl fun-name)
257 | (region-beg region-end)
258 | ,(repl-driven-development--make-eval-function-docstring repl)
259 | (interactive "r")
260 |
261 | (require 'pulsar)
262 | (-let [pulsar-face (rdd@ ,repl blink)]
263 | (pulsar-mode +1)
264 | (pulsar-pulse-line))
265 |
266 | (pcase current-prefix-arg
267 | (0 (,(intern (format "%s-display-output"
268 | (rdd@ repl fun-name)))))
269 | (-1 (,(intern (format "%s-restart" (rdd@ repl fun-name)))))
270 | ;; ('(4) (insert " " output)) ;; C-u ;; handled when we actually have
271 | ;; the output; see the process filter below
272 | ('(16) ;; C-u C-u ⇒ documentation lookup
273 | (,(intern (format "%s-docs-at-point" (rdd@ repl fun-name)))))
274 | (_
275 | (when (called-interactively-p 'interactive)
276 | (if (use-region-p)
277 | (deactivate-mark)
278 | (beginning-of-line)
279 | (setq region-beg (point))
280 | (end-of-line)
281 | (setq region-end (point))))
282 | (setf (rdd@ ,repl input/start) region-beg)
283 | (setf (rdd@ ,repl input/end) region-end)
284 | (,(intern (format "%s-string" (rdd@ repl fun-name)))
285 | (s-trim-left (buffer-substring-no-properties
286 | region-beg
287 | region-end))))))))))
288 |
--------------------------------------------------------------------------------