Zamiast zastanawiać się jak zacząć ten wpis aby oddać jak szczęśliwy jestem, że warsztaty udało się doprowadzić do skutku i spotkały się one z moim zdaniem dużym zainteresowaniem - użyję cudzej pracy i dam link do relacji Krzysztofa Telki z warsztatów
FoldLeft wszyscy szybko załapali
I z pisaniem testów też nie było problemów.
Tu jest reszta fotek:
Kolejne spotkania
Drugą edycję wprowadzenia będę chciał zrobić pomiędzy majówką a Geeconem. Na retro były prośby o więcej zadań - także zacząłem przygotowywać plan zajęć (a być może nawet i go skończyłem)
Jak ktoś ma sugestie niech śmiało zapodaje. Później po Geeconie a przed 33Degree (konferencje to dobry punkt odniesienia w czasie bo mogę zaplanować kiedy będę trzeźwy) zorganizuję jakoś drugi moduł "Obsługa formularzy, parsery requestów i kompozycja Akcji".Layouty w Playu
W trakcie warsztatów pojawiło się pytanie, na które już umiem odpowiedzieć : "czy da się zrobić tak layouty aby dany tail nie wiedział w jakim szablonie jest używany".
O co chodzi :
Play domyślnie wygeneruje nam szablon z rozwiązaniem "tail wywołuje szablon"
@main("Naglowek") { <h1>Moj tail</h1> }Jako że szablony to zwykłe funkcje to można też w drugą stronę : "wywołać taila z szablonu"
To źródło jest footer.scala.html
@import play.api.Play.current <footer> Revision @current.configuration.getString("application.revision") </footer>A to już wywołanie w szablonie
<body> @content @footer() </body>Proste?Proste.
Ciekawy przykład z życia
Na jednym ze spotkań firmowych dyskutowaliśmy sobie po co robić w deklaracji funkcji kilka par nawiasów i co dobrego z tego może wyjść. Wymyśliliśmy sobie funkcję "policjanta", która sprawdza czy dany user może wykonać jakąś tam operację :
def withProperAccess(user:User)(operation:User=>String)={ if(user.securityLevel>2) operation(user) else "sorry ziom" }I teraz aby nawiązać do jakiejś formy dependency injection stworzymy funkcję, która z kontekstu wstrzyknie usera i wyprodukuje funkcje jednoelementową :
def injectUser(function:(zagadka))={ val contextUser=User("Roman",3) function(contextUser) }I tutaj pojawiła się zwiecha - jaki właściwie typ ma oryginalna funkcja dwuargumentowa, która jeszcze jako jeden z parametrów przyjmuje funkcje?(czyli co tam w ten nawias (zagadka) wstawić)
Okazuje się, że ów typ to : User=>(User=>String)=>String
I teraz ktoś kto to widzi po raz pierwszy w życiu może zareagować niezwykłym zdumieniem wypływającym z silnego zderzenia jego obecnego pojęcia świata z napotkanym kształtem:
Ewentualnie w twojej głowie może zabłysnąć niecodzienne zdziwienie wywołane kontrastującym konfliktem pomiędzy zmysłami a doświadczeniem:
A niepotrzebnie bo wyjaśnienie jest proste.
Co to jest?
Zaczynamy od strony lewej User=>(User=>String)=>String
Generalnie to co jest po lewej stronie strzałki to to co funkcja dostanie jako argument a to co po prawej (jak dziwne by nie było) to to co zwróci.
Tutaj po stronie lewej jest User i to jest właśnie to magiczne wstrzykniecie usera z kontekstu - function(contextUser)
i w wyniku dostajemy to po prawej.
Mamy teraz to coś : (User=>String)=>String i znowu to co jest po lewej to argument ale tym razem argument ma też strzałkę w sobie - bo toż to funkcyja jest ino. Argumentem jest funkcja, która przyjmuje Usera a zwraca String czyli np :
val funkcjaBiznesowa=(user:User)=>secretKeys.getOrElse(user.name, "nima")Zaś wywołanie funkcji
(User=>String)=>String Wygląda tak :
val securityAccesWithUserInjected=injectUser(withProperAccessFun) securityAccesWithUserInjected(funkcjaBiznesowa)
Mam nadzieję, że teraz jest trochę jaśniej.
* * *
Brak komentarzy:
Prześlij komentarz