00:00:15.000
so everybody here wants to learn how to build basic desktop applications in Ruby uh so I'll help you walk through this
00:00:21.439
Workshop it's a 2hour uh hour Workshop which will involve uh some Theory and some exercises as well as even tests um
00:00:30.199
before I get started though I want to mention that I gave this workshop last year a different version of it uh which
00:00:36.640
we've I've improved quite a bit for this year but uh after I finished the workshop last year Mike peram who is the
00:00:43.399
owner of the sidekick project reached out to me and told me that he built a sidekick UI using glimmer DSL for libui
00:00:50.079
so this is like a product of uh the workshop of last year so it's just giving you a real example of real apps
00:00:57.280
that you could build by uh using the knowledge that you would learn in this Workshop so quick is a UI for sidekick
00:01:04.040
that is an open source Ubie Jem it was built built by Mike peram initially and then he had me help him with the rest of
00:01:10.640
its features he built that like one screen MVP of it and then I helped him with the rest um and also as a result of
00:01:17.320
that project I extracted a glimmer libui gem for graphs and charts so that was also a product of you know somebody
00:01:23.960
attending my workshop last year building a real app and then we extracted a gem out of it so now everybody can use
00:01:29.400
graphs and charts arts in libui so uh as far as the outline of the workshop uh we're going to start with
00:01:36.520
the guei basics uh and then we're going to move on to the MVC software architecture um and then we'll go into
00:01:43.880
uh MVP and data binding so to clarify mvc's model view controller it's a very famous pattern in guy apps or user
00:01:50.920
interface apps in general it's even used in rails web application development MVP is like a more advanced version of it
00:01:57.600
model view presenter uh which lever is the idea of data binding or the feature of data binding uh after that I'll given
00:02:04.439
that this is a basic desktop development workshop I'll just go quickly through Advanced Data binding uh without
00:02:10.280
spending too much time there and then bonus if we have extra time at the end these are outside the scope of this
00:02:15.560
Workshop but if we have extra time I'll go through them uh custom components and Scaffolding uh and if uh we don't go
00:02:23.239
through them then the hack Day event in the afternoon for glimmer DSL for libui
00:02:28.480
can be used to learn those two other Concepts so uh before we get started I
00:02:34.040
want to make sure everybody has access to the GitHub repo the workshop so you can SC scan this QR code uh but
00:02:41.319
hopefully everybody did that before the workshop because that was one of the prerequisites of the workshop so if
00:02:46.480
everybody has done this already we can just move on um has anybody not
00:02:52.319
downloaded the GitHub repo uh very few people uh so what I'll
00:02:58.560
do is uh you have the same QR code here you just
00:03:03.720
have to zoom but uh you can also copy those instructions so we cannot wait for
00:03:09.760
people that don't have the workshop because that was one of the prerequisites but you can ask your neighbors uh to give you the link and
00:03:16.480
they could give you the link on how to access the repo so basically you're going to get clone this URL you're going
00:03:22.120
to enter the repo and bundle uh and then the repo contains the link to the presentation slides so you can click on
00:03:28.400
the link and follow with me if you have an online connection if for whatever reason your Wi-Fi connection is down uh
00:03:34.439
the repo uh should include uh a copy of the slides in hard form so if the Wi-Fi
00:03:40.720
connection is good now but it it falls like uh it basically crashes later you can always use the repo presentation
00:03:47.920
slides um so I'm going to move on from here please ask your neighbors for help
00:03:54.640
if you need access to the slides
00:04:00.360
okay um so yeah part of the instructions is to install the glimmer DSL for libui Gem so this is uh the simplest glimmer
00:04:07.720
uh DSL for building desktop applications so glimmer started as a library that supported uh s the S swt goey toolkit
00:04:15.120
which is used in the Eclipse IDE and it supported it through jruby so it was originally A J ruby gem eventually I uh
00:04:22.800
the the idea of a glimmer DSL for building desktop apps proved itself so I ended up making seven other glimmer
00:04:30.120
libraries one of which is the lib UI Library uh other libraries will cover the gtk toolkit the TK toolkit FX Ruby
00:04:37.840
etc etc all of the glimmer libraries are similar So today we're going to use the glimmer DSL for liui library that won
00:04:43.639
the Fukuoka Awards uh as an educational exercise uh this is a very good educ
00:04:49.120
Educational Library on building desktop apps because all you have to do is install the gem and get started you
00:04:54.160
launch the examples you will get an app like this this has all the examples uh
00:04:59.479
and and uh if you launch any of the examples in it it'll give you apps like hello world like hello world with a
00:05:05.240
button uh some graphs and charts uh a table with a form and uh a control
00:05:11.479
gallery and a game here like snake so we're not going to get more into that we're just going to dive into the basics
00:05:17.000
because we want to get started with exercises so to present glimmer it's basically the simplest DSL possible for
00:05:22.080
building an app as you saw I said window open and it gave us the window uh now I can open a Ruby block it's a DSL and I
00:05:29.120
can customize the text of the window so so now it says hello world now I can add a label within the window and customize
00:05:36.479
the text to hello world as well and you'll see here it'll show a label within the window so it's really the
00:05:42.479
simplest code possible that you could think of to build guey here we can customize the font of the label uh and
00:05:49.720
then here we customize it again so it's very very simple here is a more sophisticated example so we have a
00:05:55.560
button counter uh before it basically is a glimmer libui application so in more
00:06:02.000
serious app development that's how we build apps we include this uh mix in and
00:06:07.039
then we declare a before body block where we initialize variables so here we just have a counter model and the
00:06:13.680
counter model is here it's just a counter that has a count attribute accessor uh so just to zoom in on it a
00:06:19.800
bit there it is uh and it's initializing the count to zero uh and then here we
00:06:25.960
just have a body uh and the body is just a window with a title and dimensions it's got a button uh the text of the
00:06:33.319
button is data bound unidirectionally to the count on a counter and uh if I click
00:06:39.039
the button onclicked it'll increment the count by one on the model however given that it's datab bound by
00:06:45.440
unidirectionally here every time the count updates on the model it'll automatically using this Arrow update
00:06:51.039
the text of the button so this is just a DSL declaration that's saying I want to bind this unidirectionally to copy data
00:06:57.840
into the text of the button and I have an onread converter so this will convert the data and it'll add a prefix that
00:07:05.440
says count so here we start with a button that says count zero we click it it becomes count one we click it again
00:07:12.520
it becomes count two so I mean I'm just diving into a more sophisticated example right off the bat just to give you an
00:07:18.039
idea of how we build apps with this but we're not going to start with this at all we're going to start with much simpler
00:07:23.639
exercises uh so I only included the glimmer DSL filii design principles here
00:07:29.680
so that you have a an idea about them but I'm not going to cover them we're going to this is a workshop so we're
00:07:34.919
just going to dive into exercises but you can read it on your own um so to start with the basics the
00:07:41.639
guey DSL Basics the the first thing you want to learn is the control keyword so uh lib UI lets you build U elements in a
00:07:49.680
user interface uh as controls so controls enable users to either see data
00:07:55.919
or Control Data manipulate data like for example inter ing text into a field or
00:08:01.280
selecting an option from a combo box uh or uh entering a number into a spin Box
00:08:07.120
Etc so think of controls as elements they're very similar to the idea of
00:08:12.240
elements in HTML so this is like the desktop version of what HTML does uh in
00:08:18.360
fact HTML actually copyed desktop development but yeah desktop apps usually call these controls Widgets or
00:08:25.400
uh components so anyways you need to know the control key words to get started so there's a word that's window
00:08:32.440
uh there's a word that's button label entry so this is a label so just to zoom
00:08:38.399
in hereit a bit this is a label this is an entry uh this is a button and the
00:08:43.880
entire thing is a window so that's the first concept you want to learn is controls uh they're usually underscored
00:08:50.720
and they're declarative they're a declarative way of building UI so there are many controls you can check the
00:08:56.680
glimmer DSL liui supported keywords in the in the libui repository the glimmer
00:09:02.440
libui repository sorry because uh this is uh it has a table that has a list of
00:09:08.200
all the controls that are available we're not going to you know worry about mastering like memorizing every control
00:09:14.640
right now we're just going to use the simplest controls in the exercises but I just wanted to give you an idea about
00:09:20.040
them there are even more controls like menus radio buttons scrolling area tab tabe items
00:09:26.279
Etc so next the next concept you want to learn is control arguments when you construct a control you use uh the
00:09:33.560
control name and then you can open parentheses and pass it arguments every control has its own Arguments for
00:09:39.640
example a window will take the title of the window as an argument optionally um
00:09:45.120
and uh so it builds a window that says hello world uh also you can pass some
00:09:50.200
some controls take extra arguments like this one takes uh the width and height of the window so it'll build a window
00:09:56.079
that's 300 by 200 uh so that's what that is the third concept you want to know is
00:10:02.120
the control content block so if you put curly braces in front of a control name
00:10:08.040
you open the basically the content of the block of the control so like we I showed you already we we had a window
00:10:14.480
with a label inside it so that the label is within the content of the window uh
00:10:19.640
so this is a way of basically so you can add nested controls or you can uh
00:10:24.880
specify properties for the window like I can say the text of the window is hello world that would be a way of specifying
00:10:31.839
a property or the third thing you want uh that that you can put inside a window is
00:10:37.079
listeners um so now if we go into a window you can
00:10:42.240
still pass arguments and open a block so you can do
00:10:47.680
both uh and here's an example of properties so I have a window it has a title property of hello world a Content
00:10:54.639
Siz property of 300 comma 200 so all you do is put the property name space the value that's it it's that simple it's
00:11:01.399
the simplest way of thinking about guey basically doesn't get any simpler than that uh control properties uh vary
00:11:08.880
between controls but I mean you can set the text of an entry or a label the checked property of a
00:11:15.120
checkbox uh this uh selected property of a combo Box Etc like there are many many
00:11:20.680
properties you can check them in the glimmer DSL for libui supported keywords table uh the next concept is listeners
00:11:28.200
so listeners always begin with oncore so uh listeners is a way of implementing The Observer pattern by Ena
00:11:36.079
you enabling you to observe part of the view to do uh work if something changes
00:11:41.800
so for example if a window closes I can say unclosing print a statement to the
00:11:47.120
user that says bye-bye uh so that's a way of basically hooking a listener to a window uh and this is an imperative code
00:11:54.959
block so it takes a do end block by the way for uh control when you put content
00:12:00.800
you intentionally don't want to do end here I'm using curly braces because we're declaring controls and we're
00:12:06.839
declaring their contents so we want to be declarative not imperative when you say do end that's imperative so that's
00:12:13.160
why glimmer has its own standards for blocks it's not the same standards that you use in in Ruby in general uh only
00:12:19.399
when you're doing imperative code like on closing that's when you say do end but when you're doing declarative code
00:12:25.079
you just open curly braces because you're just doing a declaration um here here's another example of a button that has the title
00:12:31.720
click and on clicked it does something so these are examples of listeners and there are many listeners onchanged on
00:12:37.959
toggled on closing on draw Etc on Mouse up on Mouse down Etc um okay
00:12:46.000
so next we have uh nested controls which I already mentioned it's basically
00:12:52.440
nesting a button within a window uh but also uh one form of nested controls is layouts so you can have a
00:12:58.720
vertical box it lay out uh controls in a vertical manner or you can have a horizontal box uh so it'll put controls
00:13:05.880
in a in a horizontal manner uh or horizontal way and then there's a form which builds a form and then there's a
00:13:11.800
grid the grid is currently unstable in glimmer DS in sorry in the libui toolkit
00:13:17.120
that glimmer covers uh so glimmer runs on top of libui and libui is a CA library and right now grid is unstable
00:13:23.800
in it so I advise against using it but usually you could almost do everything with vertical box and horizontal box um
00:13:31.360
So within layouts once you put a control inside a layout the control can specify
00:13:36.720
layout properties so all of a sudden label now can customize how it's laid out within a vertical Box by using the
00:13:43.639
stretchy property so stretchy if I say stretchy false here it means I don't want the label to stretch to take as
00:13:50.519
much space as possible I want the label to take only the minimum size needed uh and then the form will take the rest of
00:13:56.759
the space so by default stretchy is true on on any uh controls within a vertical
00:14:02.320
box or horizontal box but uh if I say stretchy false here I'm basically saying I don't want the label to take the to
00:14:09.240
take a lot of space just to take I just want it to take the minimum amount of space um
00:14:17.279
so um another thing that uh nested controls does is basically for a table
00:14:23.920
you can Nest columns so I want to specify that this table has an animal column a sound column a description
00:14:30.759
column and a guey column and here you basically say Okay I want a Tex a text
00:14:36.720
color column a checkbox test text color column image text color column Etc so
00:14:43.160
this is a way of basically uh most of the time we will only use text column
00:14:48.240
which is the simplest column in a table but there are many kinds of columns on a table so that's another form of vestic
00:14:54.279
control uh finally the last concept you want to know about the guey Basics is control operations so any control that
00:15:01.600
you declare in glimmer like a window will return an object and the object is a window proxy like it's a window uh
00:15:09.600
representation uh of the window that's rendered on the screen so this window object has methods and one of the
00:15:15.600
methods methods is show so I can basically show a window by calling the show on the
00:15:21.639
object um and the show uh method will
00:15:27.959
actually start the guey event Loop for you automatically so that you don't have to do the work yourself um so uh usually
00:15:36.519
in also you you might assign those objects to variables and then do the
00:15:41.639
things with those variables later on and I'll show you that in later
00:15:47.000
exercises um so another example of control operations is I I created a checkbox here and then I'm checking if
00:15:53.600
it's checked it says false and then I check it intentionally and now on in the user interface it should show a check
00:15:59.120
checkbox then if I check it again it's it's true so these are examples of operations invoked on the object that
00:16:05.480
was assigned from glimmer DSL keyword so let's get started with
00:16:11.000
exercises um so the first thing we want to do is launch The Meta example so
00:16:16.680
that's just running glimmer examples so if if you go to the directory of where
00:16:21.800
uh how to build desktop applications in Ruby is the directory of the repo we just say glimmer examples
00:16:31.639
uh there it is so this gave us the meta example which has a lot of examples and it shows us the code here like for
00:16:37.839
example I have a window with a button in it and on closing is going to say bye-bye and uh if I launch
00:16:44.880
it I can go here and press a button and it show does something so what I want
00:16:50.720
you to do is actually delete this code so I actually asked for basic window I
00:16:56.360
believe there you go basic window uh and then we're going to delete this code up to include glimmer so we're going to
00:17:02.440
keep those two statements uh and then here we're going to add new code so what
00:17:07.520
I'll do is basically I want you to follow with me just a second sorry I have it zoomed
00:17:14.400
in uh so I want you to follow with me uh in doing all the exercises up to the
00:17:20.439
section two uh uh up to section two basically so we're in section one uh so
00:17:26.600
we have exercise 1 2 3 4 5 6 7 8 9 10 11 uh they they get progressively more
00:17:33.360
complicated and then in the end we have a section one test so I want you to do all the exercises and then do the
00:17:40.039
section one test and you can get ahead of me if you want but what I'll do is I'll slowly go through the exercises
00:17:46.480
myself as well uh while you guys are going through the exercises uh but you can you can beat me basically and I want
00:17:54.039
you to keep keep going forward till you stop at section two
00:17:59.840
so uh for the first exercise we're just going to do uh window show so I'm going
00:18:05.200
to go here after I deleted the code I'm going to add uh window.
00:18:12.039
show and then launch and now it gave me a window here
00:18:17.360
that is empty so this is the simplest thing you could do with glimmer is Just Launch a window so I just took said
00:18:23.799
window show and I I launched a window so that's exercise one exercise two is how to pass arguments to un uh like a
00:18:31.600
control so I'll go here and do hello
00:18:38.159
world doesn't matter that much how you spell it but um there it is so it gave me a Hello World
00:18:45.520
window so now I delete that code so after every exercise delete the code and to be ready for the next exercise uh
00:18:52.520
Delete the code up to include glimmer so keep exclusive so keep include glimmer
00:18:58.159
in the codes um so next this is an alternative way of of creating a window so instead of using
00:19:04.600
arguments I'm going to use properties uh so I'll pass the title as a
00:19:10.799
property the benefit of this approach is uh when you have when you use properties you can use more advanced ways of
00:19:17.360
setting the property uh like data binding which we're not going to do right now but that's the benefit of properties over
00:19:25.559
arguments so I'm going to declare a window
00:19:31.240
and set a text say hello world and then I'm going to invoke show
00:19:36.919
on
00:19:46.840
it uh there it is my bad uh text is an incorrect property I
00:19:53.760
made a mistake so so I need to use title that's why it showed up without a title but if I run it again there it is it's
00:20:00.280
good so it's got a title of Hello World um okay so this is an example
00:20:08.640
including a label within a window with arguments so let's do so I'm going to zoom in just so you
00:20:15.640
can see I'll do um I'll clear the properties and I'll put a label here and it's also
00:20:22.720
Hello World um and then I'll launch it
00:20:30.880
there it is uh so now we have a window that has a title of hello world and it has a label within it that says hello
00:20:42.159
World um the next one is using properties for both so what I'll do is
00:20:48.320
uh I'm going to stop and let you continue uh till you reach the test uh
00:20:54.480
once you reach the test uh I want all of you to uh I so I want to stop because in
00:21:00.240
case people have questions I want to help them uh so before I continue I want to ask does anybody have any questions
00:21:07.880
so far okay anybody does anybody need
00:21:14.159
help okay awesome so I'll let you continue till till you finish uh all the
00:21:22.080
exercises up to section one the section one test
00:21:30.559
okay uh it looked like uh everybody's doing very well so I'm going to continue going through
00:21:37.080
the exercises on my machine while you guys keep going through the rest of them so
00:21:43.440
um okay so the next one was the one where we set properties inside the
00:21:48.840
widgets or controls so going to set a title on the window
00:22:00.600
and I'll open a block for the label and I'll set the text of the
00:22:08.080
label and launch it there it is it
00:22:17.279
worked okay this one starts getting more sophisticated it has a listener um so
00:22:23.520
let's do this one hello button with a listener
00:22:42.960
the button title is greet it's the first argument for the
00:22:48.720
button onclicked it's going to open a do end
00:22:56.000
block and then finally it's going to put a
00:23:09.320
so I'm going to launch it and we'll hit the Greet button and it
00:23:15.559
it gave us a greeting um okay so let's go with the
00:23:20.679
next exercise so this one is doing a a layout
00:23:34.440
and it's setting more properties like content size I'm going to set set content
00:23:48.000
true and then we'll open a horizontal box but we'll put two elements in
00:23:56.360
it a label with a full name or as a full
00:24:03.760
name and an entry that says John Smith and we'll hit launch so this
00:24:11.440
launched a window that has a margin margin around everything so one of the nice things
00:24:17.640
about desktop development is usually you follow the operating system standards you don't customize the view that much
00:24:23.400
so you don't waste that much time on The View uh you can get more you can focus on the business requirements without
00:24:29.840
worrying about such details so if you need margins you just say I want the standard margin so that's what margin
00:24:35.279
did and then we set the content size and then we have a horizontal box that puts a full name and then horizontally it
00:24:41.399
puts an entry next to it so that's what that was so let me go with the next
00:24:49.000
exercise um okay so this one is going to have a vertical box as well
00:24:59.799
you know I am cheating and not deleting everything I suppose that is a good idea you don't have to always delete
00:25:09.640
everything okay and the vertical box is going to contain two horizontal
00:25:15.360
boxes the first one is full name and the second one is do OB date of birth the date of birth is going to use
00:25:22.679
a date picker instead of an entry and the T date picker is gonna get
00:25:28.520
a Time property with the year being 2004 the month being 11 and the month day
00:25:34.640
being 17 so let's launch that one there it is so now we have
00:25:40.760
a uh an app that lays out things both vertically and horizontally so uh
00:25:47.880
horizont like vertically we have two rows of uh fields and then horizontally
00:25:53.159
in the first row we have a full name and the value and then in the second row it's a date of birth and the value and
00:25:58.320
and this is uh like a date picker it's a special widget or special control that customizes dates so
00:26:06.760
let's close that
00:26:12.240
one okay next one is using stretchy so I want to show what stretchy does so
00:26:18.840
basically only the labels are going to get stretchy false so I'll open the label
00:26:26.840
block and I'll put stretchy false and I'll copy this and paste it
00:26:33.080
here that's it so now when I launch it something changed so you can see that the labels
00:26:40.679
are like do is only taking as much space as needed for the doob uh word uh or
00:26:47.200
acronym but but and then the rest of the space is given to the next control so when you say stretchy false basically
00:26:53.600
we're preventing this from stretching all the way
00:26:58.679
so I mean show it to you on the slides before full name and do were taking
00:27:04.679
exactly as as much space as the next uh control uh so they end up sharing the
00:27:10.240
space breaking the space into two halves uh and each taking 50% of it the issue
00:27:15.799
with that is uh if like if there's a lot of empty space here that's wasted it's not a good idea to do like to lay things
00:27:22.880
out this way so the next Improvement is you can make stretchy fs and make each one of those labels not take all the way
00:27:29.919
uh however this comes with its own issue so one of the recommendations of user experience uh development or user
00:27:36.200
usability is basically to have alignment between Fields so this made them unaligned so I'm going to show you the
00:27:42.279
next option this option will align them and we avoid taking extra space beyond
00:27:48.200
what the longest field will take that's by using a new layout which is called the form layout uh form will simplify
00:27:55.200
things I will not need a horizontal or a vertical box anymore I can just take the form put uh controls in it and for each
00:28:02.480
control label becomes a property instead of a separate control so when I uh
00:28:07.559
specify an inry i specify the label for it and then the form the form layout will take uh will take uh
00:28:15.120
basically uh well will it it'll control where to put the label for you so that you don't have to worry about it so let
00:28:21.960
me get back here and write that that code
00:28:29.960
instead so this code is going to be a simplification so I'll remove the
00:28:35.039
vertical box make it a form I'll move the horizontal box and I'll take the
00:28:40.200
labels and basically I'll remove the labels but I'll make in properties
00:28:46.200
instead so this can be deleted and then it becomes a property
00:28:56.360
here same same here I can delete this and then make it a property here because the form layout can use the information
00:29:05.320
of what of the label property to automatically lay the label for you out in the guei so let's execute this there
00:29:13.519
it is this one looks much nicer everything is aligned um and um yeah you get the
00:29:19.640
nicest version of the form here um it's still good to know about stretchy false because it's useful for other kinds
00:29:26.039
kinds of user interfaces that's why went through it uh but in any case let's move on so the most complicated sample in
00:29:33.240
section one is uh the option selector so the option selector is showing you so
00:29:40.799
basically we have three options options one two and three um and if I select one
00:29:49.120
of them or or two of them for example I want to see a summary of the selected options on top as a string so this is a
00:29:56.000
label that puts option one comma my option three um and uh if I if if
00:30:01.799
nothing is selected it'll show it'll show none but if I select something I want it to show me option one comma
00:30:06.880
option three uh so to make this work um basically well I mean let me run
00:30:14.080
it first let me copy that code want it so for the purposes of saving time
00:30:20.159
I'm not going to type this out I hope you typed it out but um before I started talking about it but I'm actually just
00:30:26.960
going to cheat and and take it from here if you feel like you're out of time
00:30:32.159
you can cheat it's not the end of the world but basically yeah gooey
00:30:37.480
Basics that's the section one directory and then you can go to
00:30:42.640
exercise 11 and then option
00:30:49.840
selector so let me just copy this
00:30:56.279
code and paste it here okay let me launch it okay that
00:31:04.679
worked so basically as you see it started with the summary of the selected options being none meaning none are
00:31:11.159
selected I select this one now it says option one I select option three now it says option one comma option three then
00:31:17.679
if I add two all of them are selected um and then I can unselect all of them again so
00:31:24.919
um the way this works is basically
00:31:32.440
Bally um so we have a vertical box to lay things
00:31:37.480
out vertically first as far as a label and options so we have two rows a label
00:31:43.320
row and an options row uh and then the label was assigned to a variable called selected options label uh and then we
00:31:50.600
have a horizontal box that lays out all the checkboxes and we're assigning all of them to a checkboxes array so Ruby
00:31:57.200
gives you a nice method called three times like times the times method on Integer or fix num so I can say three
00:32:03.519
times uh run this block and map it into an array that will get stored as
00:32:08.799
checkboxes and then here I have a for each run of the uh block it'll basically
00:32:15.559
create a checkbox control with the title being option and the option number and
00:32:21.799
then we use a listener so we have an on toggled listener uh on toling of the checkbox it'll basically do this work so
00:32:29.519
what what it will do is print the the checkbox that was toggled Let's ignore that the put statement is not that
00:32:35.440
important here but then we're going to take uh the checkboxes array that was assigned here and we're going to select
00:32:41.880
all the checked ones so this is uh like basic Ruby is I'm using a select
00:32:48.240
iterator and it's picking all the checked checkboxes uh and then here I say if this array is empty then just
00:32:55.080
print none otherwise uh take the checkboxes map them to their text so
00:33:00.639
every checkbox has a text at property and then join them with a comma so this
00:33:07.279
is showing you how to do things if we only have GUI uh with no MVC
00:33:12.440
architecture uh typically with MVC architecture you want to divide uh and conquer the complexity of this code by
00:33:19.760
having a model view in a controller or just a model in a view uh but here we're I'm just showing you the pain that we go
00:33:26.440
through if we don't have MV so without MVC we have all the logic in one place and that's that's how things
00:33:33.360
happen without MVC uh but uh again I'm trying to graduate you gradually through
00:33:39.360
you know we start with a view and then we move into MVC and we do model controller then after that we're going to do MVP which is a model view
00:33:45.799
presenter and data binding so for now we're going to just stick to writing views so I'm going to ask you in section
00:33:51.519
one test the section one test to basically do the same thing we just did except for a an address uh form so we
00:33:58.919
have an address form that has um six Fields so a label that says full name
00:34:07.120
okay a field of a full name with label and entry and then Street and then city state and zip uh and that's just to keep
00:34:14.000
things simple I could have actually asked you to use some sophisticated widgets here but for now I'm keeping them entry except for the last one this
00:34:20.760
one's going to be a checkbox and it will not have a label uh it's it's going to be billing and shipping and basically at
00:34:27.399
the bottom bottom there's a label that will print a summary of the address so here uh you know it's going to say John
00:34:33.399
do comma One Park comma Chicago comma Illinois comma 60654 and if I check the billing and
00:34:39.960
shipping checkbox it will add a suffix at the end that says billing and shipping so this is going to be your
00:34:45.480
first test uh so it's going to test your knowledge with this it's an exercise uh so you will implement this like just
00:34:52.960
open a ruby file locally on your machine and put all the code there and obviously at the top you have to add require
00:34:59.240
require glimmer DSL libui and include glimmer before you write your code uh
00:35:04.480
but then you're going to have to do this exercise uh one thing to note is that
00:35:09.520
you're going to have to use two listeners so every time a user types stuff in here you want to listen to The
00:35:14.960
onchanged Listener for every entry and then for the checkbox a checkbox has a
00:35:20.480
different listener it's called on toled so every time the checkbox is checked or unchecked the UN toogle listener is
00:35:26.800
triggered and when either of them get triggered you want to make sure to update this label with the summary of
00:35:32.320
the address so when there is no uh when the checkbox is unchecked you get this
00:35:38.280
when it's checked you get this so I'll give you 10 minutes to do this exercise and you're welcome to ask your neighbors
00:35:45.119
for help or ask me for help with it uh but yeah this is the simplest way of building desktop apps we're going to get
00:35:50.680
into more sophisticated ways in section two and section three section three will show us how to do real serious app
00:35:57.040
development uh but this is we're going to start with the simplest way of doing things so I'll give you 10
00:36:04.200
minutes and yeah you can flip between those two slides on your machine if you want to read the details you all of you
00:36:10.839
should have the slides on your machine
00:36:18.119
already it just occurred to me that this way of writing apps where the view mixes the code of the model and the controller
00:36:24.880
in the same place is how shoes application development happens in the past so glimmer improves over shoes uh
00:36:31.400
shoes was an old uh it's one of the oldest Ruby libraries for building goys
00:36:36.480
which stopped getting maintained and that's why glimmer took over and tried to do better than shoes one of the things that it does do better is
00:36:42.720
basically gives you a very nice uh structure for building apps with MVC or
00:36:48.000
MVP uh instead of doing things this way this is how shoes used to do apps in the past so it's good to learn more basic
00:36:55.960
ways of development because glimmer was inspired by shoes as well but it also improved upon it significantly so that's
00:37:02.480
why I'm showing you this approach first before I move into more sophisticated
00:37:09.079
approaches the irony is that the more sophisticated approaches will end up yielding simpler code to reason about
00:37:15.079
even though uh they're more sophisticated so you'll see that in section two and section
00:37:24.560
three um actually I do need to colle clarify something though my bad so the
00:37:30.560
test does not need you to write the code in The Meta example I wanted you to create your own Ruby file and run it uh
00:37:37.240
by saying Ruby and then the file that's it so actually for that it's simpler you
00:37:43.040
can run it from the command line you don't have to be
00:37:49.240
here yeah because you want to save your changes you don't want to lose them if here everything uh gets lost after
00:37:55.640
you've closed the app okay so okay so so yeah if you if you written
00:38:01.280
anything in the glimmer meta example for the for the test itself copy it into a file and save it because the glimmer
00:38:07.520
meta example right now does not support saving it's outside its scope to
00:38:16.040
save okay we're out of time so I'm going to have to go through the section one
00:38:21.240
test myself so for the rest of the exercises
00:38:27.640
will mostly execute them from the repo uh except for the tests so the tests will be uh code that you have to write
00:38:35.200
but the rest of the exercises will be executed from the
00:38:47.880
repo um okay my internet connection is a bit bad so I'm just going to use my IDE
00:38:53.839
so by the way I built this IDE in glimmer this is built in Ruby this ID is 100% built-in Ruby including uh syntax
00:39:04.599
highlighting like uh this stuff it's all done in Ruby so that's just giving you a real example of what you could do with
00:39:10.480
glimmer uh but yeah um so if I go to test one and open it up
00:39:19.760
um so basically I saw a few people uh do a near complete version of this so I
00:39:27.160
think some people got it but I'll go through it for the rest or for everybody even uh so we have an address form so
00:39:35.280
you can t put the address form as the title of the window you you can give it some dimensions and make it margined but
00:39:41.280
the key part is here we have a form and it has an entry that says full name and
00:39:47.520
onchanged it's going to update the address summary um so
00:39:54.240
basically how about I just run it so if we go to the repo
00:40:01.440
here um one way of running glimmer apps is to say glimmer and then the name of the app
00:40:08.319
so um if you go down into some exercises I give examples of that so you can say rubby or you can say glimmer uh but
00:40:17.520
basically I typically will will use glimmer uh because glimmer will automatically load the glimmer Library
00:40:23.920
even if your script didn't have require glimmer DSL lii so anyways I'll uh do
00:40:29.160
section one test and address form so let's run it
00:40:34.760
there it is so it gave us an address form um so we need to build the address
00:40:40.400
form but also on onchanged of every entry for example unchanged the full name I put John Doe and you can see here
00:40:47.040
it immediately updated a label that says John Doe which is the summary of the address um so if we go back here
00:40:58.599
into the code you can see here it said update address summary it goes here and it calculates the new address from all
00:41:05.319
the fields so every field got assigned to a variable so you see we have a full name entry a street entry a city entry
00:41:12.760
state ZIP and the billing and shipping checkbox so uh it's very simple it's
00:41:18.520
just you know you assign variables you go into you execute this method it grabs their data uh and it joins them it joins
00:41:27.720
all the ones that are not empty uh and then if the checkbox is checked so here
00:41:32.800
we check if the checkbox is checked it'll basically append this suffix uh and then it'll give you uh the
00:41:41.520
address summary and then finally you set it as the text of the summary label so at the very bottom I have a summary
00:41:47.760
label that's empty so you don't really have to put any value in it uh I mean I saw some people that put TBD that's okay
00:41:54.680
you can put TBD but you don't even need to put anything if you want to you could just do this and
00:42:00.160
um this will give us uh a summary at the bottom so now um on on in invocation of
00:42:07.800
every field we're calling this method to update the address so then if I type in here the name of the sorry yeah the
00:42:14.200
street name um Chicago let's just say Chicago
00:42:20.200
Illinois some zip code and then if I put billing shipping see it bumped it added
00:42:25.319
billing shipping here if I remove it got removed so um a simpler way of writing
00:42:31.079
this example would have been to duplicate the code so for example I could have just to taken this originally
00:42:36.280
when I wrote it I duplicated the code so I like I I noticed that I had to do this on every changed listener
00:42:44.359
so on every one of them I ended up doing this then I realized you know we can refactor this and extract a method out
00:42:50.440
of this so the next advancement would be to then take this code refactor it uh
00:42:56.920
and and put it in the method and then now the method does
00:43:02.040
everything and that's because we have variables that are assigned kind of like the summary label variable so that's
00:43:08.000
what variables enable you to do uh so that's pretty much it for test one so
00:43:13.559
let's continue into section two so section two is MVC software
00:43:18.920
architecture this is now getting closer to how you build real apps um so MVC was
00:43:24.559
a pattern that was uh invented by the people people that came up with small talk uh it was an old pattern called
00:43:30.319
Small Talk MVC and it basically had a view model and controller uh this is uh
00:43:36.720
the correct way of doing MVC it's not the rails way the rails way is a bit incorrect the clean correct way is
00:43:42.280
basically the view observe the model data for changes and if the model attributes change the view will update
00:43:49.119
itself uh and then the controller enables a user to interact with a view by observing uh user control U
00:43:55.960
mechanisms like Mouse up key up selection onclick stuff like that and
00:44:01.599
when those events fire the controller will manipulate the models and make uh
00:44:07.079
make a change in them but then given that the view is observing the model when the model is updated the view will
00:44:12.319
reflect those changes in itself so this is the correct way of doing MVC which will will result in the most
00:44:17.599
maintainable code uh rails unfortunately doesn't do it that way they they have the controller push data into the view
00:44:23.280
which is incorrect uh so but so you need to learn that and do the right wave MVC
00:44:29.720
for desktop development because it is simpler it will enable you to build better apps um and yeah it relies on the
00:44:36.760
Observer design pattern I already went through this now for the view to observe the model uh there is a keyword observe
00:44:44.480
that lets you observe a model attribute and then pass it a block afterwards and then the block will let you do some work
00:44:51.280
if the attribute of a model changes and I'll show you an example of that in a moment yeah like here's an example so we
00:44:57.400
have we observe a model attribute and then we pass it a block and then we do some work uh behind the scenes is
00:45:03.240
constructing a glimmer datab binding Observer object with the proc method and then it's invoking observe model
00:45:09.880
attribute uh if we're not using the glimmer DSL but we we have the library we can do it this way this is useful in
00:45:16.520
the model layer if you need to do observations but in the view layer we have the DSL so you can just do this um
00:45:23.240
so for example here uh so let's so there are two ways of doing MVC there's the explicit controller approach which is uh
00:45:30.839
more similar to uh the old Small Talk MVC so basically we have a model Class A
00:45:37.000
View class and a controller class The View class will have an on toggled listener that will uh basically uh when
00:45:44.359
the checkbox is toggled it'll it'll send work to the controller the the controller will toggle the option with
00:45:50.520
the option number for example um and also the view will observe the model uh
00:45:56.280
that's behind the controller so here we have an option selector model it'll say observe the selected options and if they
00:46:02.079
change I want my summary label the selected options label uh text to get
00:46:08.079
updated with a summary from the model uh so we delegate work to the model to calculate the summary so we separate
00:46:15.040
that logic into the model and then the view though will observe this uh array and if it changes it'll automatically
00:46:21.079
update its own label so that's a way of uh having the view uh observe the model and then update itself
00:46:27.680
uh uh Ruby gives us a simpler approach we can do implicit controller instead of explicit because the un toggled uh
00:46:35.119
listener and glimmer uh which takes a block basically the block of it is a controller so you can think of the block
00:46:41.960
as an implicit controller so that way you can cut out the middle man and not even create a real controller class and
00:46:48.480
just have this implicit controller call the model directly so it's going to call the option selector model and toggle the
00:46:53.839
option with the option number uh and then the view part doesn't change so um
00:47:00.160
for the rest of the exercises we're going to follow on GitHub uh and we're just going to run them from GitHub
00:47:05.599
directly before we get to the test so basically I want you to go through here
00:47:11.280
so skip through section one in the read me so we're going to go to the readme page uh which is the homepage of the
00:47:17.920
GitHub rep repository so we're going to skip all the way to section two and uh
00:47:23.599
for every example so all the examples live here so if I open this directory it's going to show
00:47:28.800
me uh all the exercises will live there but basically for every exercise I want you to copy this a glimmer and then this
00:47:36.559
uh file name so I I can just press the copy button here and then go to the command line paste it and boom it ran
00:47:45.520
the exercise so this is the simplest way of doing uh MVC right now it does the
00:47:50.880
behavior is exactly the same this was just a refactoring uh so the behavior is the same but uh the the code is much
00:47:59.280
better now because we have MVC architecture in the code uh so after you run it successfully uh you can look at
00:48:06.359
the code so if I click here to see the code actually it's easier just open it in my IDE so let me go to my IDE and
00:48:15.680
open it here there it is so we have an option selector model we have an option
00:48:20.800
selector controller and we have an option selector view uh typically you would separate them into different fil
00:48:27.160
but for the purposes of just doing an exercise here were keeping them all in the same file uh the view however became
00:48:33.240
a class so this is new for you so now we're doing something more advanced and more correct when you build real apps is
00:48:40.000
you want to create a view class and include glimmer into it that's the simplest way to do things there we're
00:48:46.720
going to learn an even better way uh eventually but this is the simplest way to get started you include glimmer in
00:48:53.240
the initialized method you just initialize a bunch of variables like the model and the control roller and then you create the guey body and then you
00:48:59.799
register observers because you want the view to observe the model for changes uh create the guey body has the old code
00:49:05.440
that we were working with just a moment ago so it's got a a window uh and usually you want to assign the window to
00:49:11.880
a global window variable or like an instance variable sorry uh but the rest is like just basic glimmer DSL so we
00:49:18.160
have a window it's got a vertical box uh it's got a horizontal box and then three times meaning for every checkbox it's
00:49:25.559
generating a checkbox here here uh and on toggle of a checkbox I'm basically calling the controller and telling it
00:49:32.040
toggle the option so uh in this approach we don't need to assign the checkboxes
00:49:37.559
to an array anymore uh that got simplified away now the controller takes
00:49:43.720
care of uh knowing about an array of checkboxes the controller and the model take care of those details so here all
00:49:50.040
we have to do is have the view toggle an option on the controller and that's it that's the simplest uh way of the old MV
00:49:57.000
approach how to do it basically have the view delegate to the controller and then the controller delegates to the model so
00:50:02.440
if we go here to the controller the toggle option will delegate to the model toggle option and then the model toggle
00:50:08.880
option will do the real work so that way this is like correct business app developments you have the model handling
00:50:14.520
the business logic uh you have the controller sitting as a glue between the view and the model and then the view
00:50:20.839
lets the user see the user interface and interact with the model and the model also has the summary method now so this
00:50:26.960
got refactored as well uh this will enable you to you know do the logic of checking of rendering the summary here
00:50:33.559
in the model uh so yeah the code is a lot better now um so let's jump into the next
00:50:41.319
exercise so now if we go to exercise two under section two again we copy the code
00:50:46.680
from here um we paste it here we run it and it's going
00:51:01.520
example uh and this will behave the same exact
00:51:07.040
way so um what's the what's different though let's open the code and see what
00:51:12.960
changed in exercise two so the the key thing that's different is we don't have a we have a an option selector model and
00:51:20.079
we have an option selector view the controller is no longer needed because we're using such a cool language called Ruby that lets you bypass the need for
00:51:27.920
an explicit controller by using implicit controllers as Ruby blocks so here what we did is basically we're like you know
00:51:34.720
we we're in Ruby on toogle is already taking a block this block is the controller it's an implicit one so I
00:51:40.799
don't need to create a class so we can cut out the middle man and this will then delegate immediately to the model
00:51:47.240
and it'll toggle the right option that's it and when the options are toggled um
00:51:52.400
register observers you know I forgot to go over this earlier it's also it's also on the other class register observers
00:51:58.559
will have the view observing the selected options array on the model and
00:52:03.880
uh it'll basically summarize the options and send set them in the label so that's
00:52:09.400
pretty much it this made things a lot cleaner and better so let's go through
00:52:14.760
the next exercise so the next exercise is
00:52:20.319
basically we're going to refactor the address form that we built in exercise one uh in order to make it follow MVC so
00:52:28.000
we're going to create an address class that will store uh text or buan values
00:52:33.400
basically all the uh all the fields are text except the checkbox this one's going to be a Boolean and then we're
00:52:39.240
going to have an address form view that will wire listeners uh just like we did
00:52:44.319
before to the model uh and we'll delegate the work to the model um so
00:52:50.040
I'll give you 10 minutes for this as well we should have 10 minutes for this and by the way this is the only the
00:52:56.920
tip of the iceberg there's much cooler stuff coming later uh so the coolest stuff will come at the end uh so I mean
00:53:04.720
there were three problems in shoes that glimmer solved one of them was uh mixing a view concern with the model concerns
00:53:11.880
glimmer solves that completely the second issue in shoes was H tables and trees didn't have their own widget like
00:53:17.599
I I didn't have a table or a tree widget which is important to business apps uh glimmer solves that it does give you a
00:53:23.040
table uh and in certain glimmer toolkits there are there is a tree widget as well and then the third issue that shoes had
00:53:29.240
was uh it didn't give you an easy way of building custom components glimmer does support that completely which I'll go
00:53:34.760
over in the hack Day event in the afternoon because it's outside the scope of the workshop unless we finish early
00:53:40.200
then I I can cover it in the
00:53:51.799
workshop but yeah in section three we're going to build an even uh smaller version of this we're going to refactor
00:53:57.680
this again it'll be even smaller it'll look very very cool by using uh Advanced features in
00:54:05.760
Ruby uh it just occurred to me you don't need to use your own code for the first
00:54:11.160
address form that we built if you didn't finish it it's better to actually take the one that was in the repo so it's
00:54:18.280
actually this one that that's in the test01 directory under section one uh so
00:54:23.599
I wanted you to take this and refactor it don't you don't have to start with the one that you built in case you
00:54:29.319
didn't finish it what I what I personally did is I
00:54:36.119
literally copied this code pasted it in a different file and then refactored it into
00:54:52.960
MVC one thing I might have glanced over quickly um yeah I did when I was showing the MVC
00:55:00.480
examples is that uh when you build the create guey body sorry yeah when you build the body inside create guy body
00:55:07.040
you're going to assign it to a window attribute uh or window instance variable
00:55:13.160
uh in order to launch the W show the window we need an extra method here show
00:55:19.119
uh and then it'll enable me to uh show the window so here then I can instantiate the view and then call the
00:55:25.680
launch method then that would launch the app uh that's one way of doing it I an alternative way is that if window was an
00:55:32.640
an attribute then I could have done here. window. show but it's actually cleaner to just have a launch method
00:55:39.119
hiding it hiding the details uh so you will likely need this as I mean you'll
00:55:45.119
definitely need the launch method as well in order to start your app unless you have a different way of starting the
00:55:50.480
app I mean a different trick for this would be to uh put this as the last
00:55:55.920
method and then invoke show directly here but it's not very clean it's better not it's better not to do that it's
00:56:02.680
better to just have a launch
00:56:08.559
method yeah we're actually out of time so I'm just going to go through uh the details of this uh test exercise and by
00:56:16.079
the way we're going to have a hack Day event in the afternoon so if you didn't get to finish the any of the exercises
00:56:22.079
or tests you will have enough time to go through all of them in the hack Day event afterwards um
00:56:29.440
so let me launch the test two implementation it's actually section two
00:56:35.920
test one sorry there it is let me just launch it just to show that it works so
00:56:41.880
typically you can say Ruby and the file name that should work or you can say glimmer and the file name glimmer is the
00:56:47.359
more default way in glimmer apps but we I already launched it you know now it's
00:56:53.039
it's summarizing the address as you can see C uh and then if I check the checkbox it
00:57:00.520
has a suffix so it definitely works um the code is basically uh we're doing
00:57:06.160
implicit controller MVC so we only have an address and an address form view the address has all the attributes needed
00:57:12.599
for an address like uh full name uh Street city state ZIP billing and
00:57:17.839
shipping uh I'm aliasing billing and shipping as a question mark method because it's a Boolean this is just
00:57:23.680
optional uh and then here the summary method does the work of uh calculating the summary of the address so this is
00:57:30.000
the same work that we did earlier in here inside this method update address summary uh except this one this method
00:57:37.200
was mixing model and view concerns because it was updating it was calculating the summary and then it was
00:57:43.359
setting it on The View label uh whereas here it's divided now the model is only doing calculating the summary that's it
00:57:50.000
and it gives us a pure string it doesn't talk to the view uh but then the view here it's observing the model
00:57:57.240
uh under register observers and it's saying observe address full name and uh if anything changes execute this block
00:58:04.400
and so if we look at this block it's basically taking the summary of the address that I just showed you and it
00:58:09.599
set it as the text of the label um and uh one more piece of the puzzle is that
00:58:15.760
for every field like full name we're going to call it unchanged listener and
00:58:21.599
have it copy the the entry text into the the model full name attribute so that
00:58:28.960
means whenever I yeah let me run it again whenever whenever I change any
00:58:34.920
field like I I type in John here it's basically copying this value and storing
00:58:40.319
it in the model attribute uh and then the view is observing the model attributes so then later the view here
00:58:46.520
at the bottom will actually uh this Lambda is going to fire on any changes that happen
00:58:52.839
to full name so this Lambda will fire it will take the address summary and it'll store it on the summary label and that's
00:58:59.920
why we see things updating here in the bottom as I'm typing through as you can see there you go so
00:59:08.079
that's pretty much it this is like a a clean uh MVC approach with an implicit
00:59:13.400
uh controller because like basically those unchanged blocks are the controllers they're implicit controllers
00:59:19.640
and here we have an un toogle this one will actually read the checked property for the check box and store it on the
00:59:25.440
model nice thing is that the GUI uh controls are all objects so you're just not doing normal object oriented
00:59:31.760
programming here so it's very simple um so that's pretty much it let's dive into uh section three now we have
00:59:39.799
about 40 minutes left or a bit less so um okay so now we're going to talk about MVP and datab binding so MVP is an
00:59:48.160
advanced a more advanced version of MVC it's like an evolution of it uh that I
00:59:53.559
believe Microsoft came up with it uh with the innovation of data binding so the idea is that there would be a
00:59:59.440
presenter sitting between the view and the model and the presenter could be implicit or explicit if it's implicit uh
01:00:05.520
basically a presenter will let you bind any field you see on the view to attributes that that that are on the
01:00:11.839
model so that way if the model changes the view will update and if the view changes the model will update uh so this
01:00:18.359
will simplify code significantly because then you can declaratively wire the view to the model you don't have to use
01:00:23.960
listeners like on toggled uh manually anymore except for certain op actions
01:00:29.720
like clicking a button so let's get into it so if I have an entry and it's got a
01:00:34.920
text I want a data binding basically bidirectionally to first name user so this is this syntax is completely
01:00:40.599
unheard of there's no I I don't know of any other programming language that has this only Ruby can do this Ruby is so
01:00:46.440
amazing it lets us do operator overloading uh within a DSL context and
01:00:52.000
here like basically uh the spaceship operator will give us a very intuitive
01:00:58.280
expressive way of saying I want a data bind first name to text on Entry bidirectionally um dat date time picker
01:01:06.760
also does the same thing on its time property and it's datab bound by direction to event time on reservation
01:01:12.880
um a button a button text however uh so you need bir directional data binding
01:01:18.880
when the view allows the user to make changes to the data however the button text cannot change usually once you set
01:01:25.799
up a button's text and it says submit in general uh the the pressing the button will not change the text however you can
01:01:32.760
have the model change the text so if the model updates you can uh so here you used unidirectional data binding and you
01:01:38.559
say if the count on a counter updates I wanted to propagate that change to the text and you can even set a converter
01:01:44.680
here I have a converter that will convert it to a string so assume here it's an integer it'll get converted to a
01:01:50.480
string and set as the text of the button so this is unidirectional data binding there are cases where unidirection data
01:01:56.119
binding uh is the better option uh or it works better it's when you don't have two changes happening at the same time
01:02:03.760
uh label text is the same way you use uni directional data binding with it um and then MVC MVP uh sorry like you can
01:02:12.520
apply MVC and MVP at the same time for example I can use data binding for most of the fields and then on click of the
01:02:19.079
button I can do an action and on click it's basically going to update the count on the counter but then given that the
01:02:25.359
entry text given that the view is observing the model to update itself here with an implicit presenter it'll
01:02:31.599
basically on read of the count it'll store the new value in here in this in this text box so every time I click the
01:02:38.640
button it'll update the value here automatically for me and also the button text is unidirectionally data bound to
01:02:44.400
the same uh attribute on the model so every time I click the button it's going to update both this 11 and this 11 it'll
01:02:50.960
become 12 on both of them so I mean yeah this is amazing like an amazing uh
01:02:56.319
possibility in Ruby is the ability to do operator overloading with and build dsls
01:03:02.880
and when you combine the two together I have the simplest code possible to describe the problem you cannot write
01:03:08.400
any code simpler than that to describe the problem I mean right now I'm I actually last year uh took the glimmer
01:03:15.000
project and built a web version of it so now we can use it in the web to build user interfaces for rails and I took a
01:03:21.960
reactjs uh application at work and I refactored a page I rewrote it it was a
01:03:27.480
500 line of lines of code of react code I refactored it using glimmer DSL for
01:03:32.559
web and it became 50 lines of code with this code and is super expressive way simpler than react way better like uh
01:03:39.880
way easier to maintain I would say a doubles productivity at least meaning you could do 12 months of work in other
01:03:46.000
Technologies in six months only in Ruby because Ruby is so much better than other Technologies so anyways uh let's
01:03:52.119
move on this is table data binding table is a bit more sophisticated because when you bind to the attribute on a model
01:03:58.319
like contacts the attribute has to be an array because every every element in the array is going to represent a row in the
01:04:04.000
table uh and the amazing thing here is with this very short sentence like in in one line of code uh you can it will
01:04:12.279
automatically datab bind all the attributes on every contact to every column on the table by convention so
01:04:18.720
glimmer does convention by configur con convention over configuration just like rails so here it's basically if we have
01:04:25.440
a name column it'll assume there's a name attribute on contacts and it'll try to use it uh and then it'll datab bind
01:04:32.279
automatically so with this tiny line it does everything for you uh in in other Technologies I usually have to write
01:04:38.319
lines of code to data bind data to a table here here it's a lot simpler uh here's an example where you can
01:04:44.119
customize the attributes so it's convention over configuration but you can also configure if needed so here
01:04:49.319
we're customizing the names of the attributes to different to map to different attributes so I'm just going
01:04:55.079
over this quick because these are Advanced datab binding approaches uh content datab binding is very Advanced
01:05:00.559
it's basically um you can datab bind the content of a control so I mentioned earlier that you can Nest controls
01:05:06.920
within each other and if I have a vertical box and its content might change dynamically you can use content
01:05:12.520
data binding so I can say I can put this content block within the vertical box
01:05:18.039
and bind it to an attribute on a model and every time an attribute changes it'll rerender that uh the entire
01:05:24.640
vertical box uh so here for example I have a dynamic form so if I have all of
01:05:30.039
those checkboxes checked I will see all the entries but if I go here and I say I don't want to enter an email and I don't
01:05:35.240
want to enter a street this part is has content data binding so the content will
01:05:41.799
get refreshed with the new entries that uh are selected only so it'll exclude
01:05:47.760
email Street and Country so this with data so this now updated dynamically so
01:05:53.000
this is a very Advanced feature of data binding uh you don't use it all the time but for the few problems it solves it's
01:05:59.000
very good so uh we're going to go through uh again a few exercises and then it we're
01:06:05.039
going to have two tests so test one is going to be uh refactoring the address
01:06:11.680
form that we just built again to to follow the MVP pattern uh and then uh
01:06:18.319
section test two is going to be uh a very Advanced example of using datab binding table data binding uh form data
01:06:25.680
binding and then wiring everything together let's not go there yet though let's go through the exercises
01:06:32.079
um let me just see how much time I have we don't have a lot of time and we need
01:06:37.920
about 20 minutes for the exercises we only have about 25 minutes so what I'll do is I'm going to Breeze through those
01:06:43.880
exercises and show you the code of each so the first one is uh whoops let me go
01:06:50.160
through the GitHub repo and go to section three there it is
01:06:56.319
so let's run option selector MVP so now we're refactoring option selector to be
01:07:11.200
now it's doing uh data binding so let's look at the
01:07:18.079
code um so the key difference here is that we don't have an uh an on toggled
01:07:24.920
listener any anymore now what we're doing is taking the checked property on a checkbox and data binding it to an
01:07:31.520
option attribute on a model so for every option there's going to be an option number here attribute so now if you look
01:07:37.599
at the model see I have attribute accessors option one two and three so that means the benefit of datab binding
01:07:43.880
is instead of keeping them in an array like we did before we can split them into their own attributes and you data
01:07:49.920
bind every checkbox to an attribute and that and you're done that's it uh however one um Wrinkle In This is that
01:07:56.640
we need to make sure that every time they're checked the summary is refreshed for the model
01:08:02.520
so what you do here is you override the writer for each one of them so I'm overriding the the attribute writer for
01:08:09.520
option one uh the one that takes an equal sign and I'm telling it to update the summary at the end uh so that way
01:08:17.640
every time we update one of them the update summary method will get triggered and we'll update the summary attribute
01:08:24.080
and then the set summary attribute is also datab bound except this one is unidirectional so the summary attribute
01:08:30.120
is datab bound unidirectionally to the text of the label and that's the reason why uh when I ran it every time I check
01:08:37.480
one of those you can see the label here updating because this text is getting uh receiving updates through uni
01:08:43.600
unidirectional data binding um so that's pretty much it now it would be nice if
01:08:50.640
we can get rid of those methods if we don't have to do update summary ourselves that would be very cool so
01:08:56.600
let's see the next exercise the next exercise is going to improve on this so this one's going to use a model
01:09:02.159
Observer so let me run this
01:09:07.520
one so there you go it works by the way you
01:09:15.040
can follow with me on your computer if you want to run the exercises feel free to do it uh but I'm going to keep
01:09:21.520
talking just to uh Breeze through the rest of the exercises so now let's open the next exercise that I just ran okay
01:09:29.080
notice there's an improvement right away uh the methods for option one equal option two equal option three equal are
01:09:35.359
gone now now what we we're doing is using a model Observer so at the model
01:09:40.600
layer if you want to do an observer you can use this class which comes with glimmer and uh if you use the proc
01:09:46.719
version of it it will basically build an observer that will trigger this proc or block on every change so it'll update
01:09:53.360
summary and then I'm taking the Observer and I'm telling it observe myself I am the object that I want to be observed
01:09:59.480
but I want to observe option one option two and option three that means if any changes happen to them this will get
01:10:04.880
triggered and it will update the summary and then the update summary method will then get called and then will update
01:10:10.960
this attribute and this attribute fortunately is data bound you need directionally to the label so it'll
01:10:16.440
happen it'll get uh reflected in the view so that's how this one works so it
01:10:21.679
actually improved the code a bit now the updates are happening indirectly it's still not the best code though it would
01:10:27.239
be cool if if the app if glimmer can know how to do this automatically for you so that you don't have to write that
01:10:33.640
code even uh so fortunately there is a way to go further and improve further Beyond this so let's go to the next
01:10:39.239
exercise so here's the next exercise it works
01:10:44.560
just wanted to show that it works but then here we go to um the code now boom now it's smaller
01:10:51.440
all of the sudden we don't have any Observer code here and we just have the three options we don't even have an
01:10:57.159
update summary method anymore we removed the summary attribute and made it a method and now if you call summary it'll
01:11:02.960
give you the summary uh and that's the simplest version of the model possible it doesn't get any simpler than that uh
01:11:09.000
and the the nice thing about following MVP with data binding with glimmer is that the model is unaware of the view so
01:11:14.719
you can write much cleaner model code that is not uh mixing view concerns unlike code that was written with shoes
01:11:20.640
in the past it would always mix view concerns here you don't have to worry about that so for example if um I go to
01:11:27.800
the view now I'm just using datab binding here and data binding here however there is one more one
01:11:35.040
change to the data binding if you look at the summary method that is showing Cal recalculating the summary it it's
01:11:42.199
using computed data binding now it has a new Option called computed buy so if you know that the summary will change every
01:11:48.920
time option one option two or option three changes you can declare it so you can tell that glimmer that is the that
01:11:54.960
is the the truth of the situation so what we're going to do is we're going to say computed by option one option two
01:12:01.159
option three and now glimmer has this information it knows okay every time option one option two or option three
01:12:06.320
changes we're going to update the sum summary automatically so now the code is as clean as possible it's like the model
01:12:12.760
is super clean very lightweight the view is super lightweight we just have a couple of data bindings that's it and
01:12:18.159
then for this one we just have a computed buy and that's the simplest uh version possible so this is the this is
01:12:24.480
the version I know normally use when I build real apps so that's the amazing thing about this like I uh I play drums
01:12:30.639
as a hobby uh I play drums in a rock band as well and uh I needed a metronome one time because my app on the my phone
01:12:38.120
received an update that broke the metronome so I built my own metronome and glimmer in like 10 minutes because of how awesome the syntax is like the
01:12:45.080
productivity here is actually better than even rails uh but both rails and glimmer run on Ruby and so thanks to
01:12:50.840
Ruby the the awesomeness all come comes from Ruby so um
01:12:56.159
so let's move on to the next exercise so now we're going to add a reset button where we can click the reset and will
01:13:02.120
reset all options so let me run that example so uh now I can select the
01:13:09.800
options and then I can click the reset button it resets all of them now the nice thing about data binding is the way
01:13:16.080
I would implement the reset is the reset button doesn't have to go and update each one of those checkboxes to empty
01:13:22.040
instead um let me close it go to the code
01:13:28.159
code um the model is still the same it has an option one option two option three and a summary however now we add a
01:13:34.400
new method reset and it's very simple all it does is it takes each one of the options and it sets it to false you have
01:13:40.760
to use by the way the setter method because glimmer listens to those methods it it you like Ruby uh allows meta
01:13:47.800
programming meta programming we can have a glimmer can listen to any changes that happen through any of the attributes on
01:13:53.080
a model so you need to use the syntax and not the syntax of not the instance variable syntax but it doesn't matter
01:13:59.239
once you do this uh that's all what glimmer needs to update the view now the
01:14:04.639
view is basically doing uh so in the view we just have a button it has an
01:14:10.199
onclicked listener and it triggers the reset method and that's it so once this gets triggered uh given that we have the
01:14:17.960
checkboxes data bound B directionally here they will automatically receive the update so you don't have to do anything
01:14:23.280
else all I did in the view is added this code that's it and then all and then the model does the actual Logic the model is
01:14:30.080
describing how we think about it in at the business layer so in the business layer I'm just clearing the options I'm
01:14:35.760
setting all of them to false and by doing that it it happens in The View like you already saw like uh I I can
01:14:43.400
check the checkboxes and then I click reset and it all got reset automatically
01:14:48.440
so again that's pretty amazing because then you can write code that is very minimal and you can be a lot more
01:14:54.159
productive uh and I mean the sky is the limit once this hits the web I only
01:14:59.199
started the Ruby uh the glimmer web project last year and I finished the first beta earlier this year so uh
01:15:07.040
things will be amazing in rails apps once we start using glimmer in the front end of rails apps as well uh so next
01:15:13.440
we're going to go through a more advanced example that shows table data binding uh let me just check the
01:15:22.239
time I think we have about 20 minutes so uh or 15 minutes but um so table data
01:15:29.520
binding will enable you to update let me see there you go let me run the example
01:15:36.520
it enable you to make updates to a table's data basically so this is a very
01:15:42.159
sophisticated example it's a a much closer reflection on what real apps might be so we have a form here uh that
01:15:48.960
you can fill in and when you save it'll save a contact in a contact table and
01:15:54.000
then here we have a search box and it lets you search through the table so let me add a new person here John Doe John
01:16:02.159
um let's just say host.com uh so if I don't fill all the fields and
01:16:08.639
I try to save it'll tell me validation error so I have to save I have to fill all the fields so I'm going to I just
01:16:15.719
Sav the contact boom there it is it got added to the table um and then uh here I
01:16:21.560
can I can click and type anything to filter the table There He Go Skai so it found Lisa Skai uh or I can let's just
01:16:29.880
say I want everybody in uh let's say Jordan there you go
01:16:36.120
Jordan ma multiple people yeah so anyways it's it's basically a basic
01:16:41.520
filter so this is a very sophisticated app uh desktop app uh and it it uses all
01:16:46.719
sorts of uh all different kinds of datab binding so let's get into it so it's a form table the main model here is a
01:16:53.679
contact uh you can use Ruby struct to build models it simplifies declaring
01:16:59.639
attributes and also declares an equals method for them I believe in a duplicate
01:17:04.760
method that will enable you to duplicate all attributes automatically so that's why I use the struct here um and then I
01:17:11.360
have a valid method that will validate the fields and a reset method that will reset the fields and that's it it's a very simple model uh the presenter so
01:17:19.400
here I'm using an explicit presenter so sometimes when the view is very complicated you want to use an
01:17:25.880
intermediary model between the view and the models that's basically an explicit presenter the presenter is almost like a
01:17:32.920
kind of a controller but not exactly but it's sort of like a controller uh so the presenter is like a mirror image of the
01:17:38.960
view but at the model layer so in the view like if I click here and look at
01:17:45.199
the user interface we have a form here so the form will let you enter a new contact so here we have a new contact
01:17:52.440
method on the presenter uh also The View H has a Save contact button so in the
01:17:58.199
presenter I have a Save contact method that will get triggered when the button is pressed and then the view Has a Field
01:18:04.679
uh for filtering here so here we have a method that says filter table that will
01:18:10.159
execute filtering also we have an attribute called filter value which will store the
01:18:15.520
filter value that the user types and then when filter table is executed it will filter the results and it keeps
01:18:21.639
unfiltered contacts as part of the results um and also we have yeah unfiltered
01:18:27.639
contacts and when initializing the presenter we initialize it with a set of contacts so in a real app you would load
01:18:33.480
those contacts from the database and load them into this array but if I'm not using a database for now I'm just faking
01:18:38.960
my own data so I faked a few contacts um and filter table will do some logic that will uh look through all the attributes
01:18:46.159
of the contacts we're not going to worry about the details for now but what matters is these four methods that I showed you that map to the view uh so
01:18:53.960
that way when we go to to the view now it's got the form that has all of
01:18:59.159
the fields and all of them are data bound to the presenter new contact model so the name the email the phone the city
01:19:05.840
the state uh and then the safe contact uh action button will onclicked will
01:19:11.400
trigger validation and if validation is successful it'll save the contact if not it'll show a message box uh and then
01:19:18.400
finally there's a search entry field which will let us enter a filter value that is data bound to the filter value
01:19:24.080
attribute on the presenter and after writing so this is a a datab binding Advanced feature you can use hooks so I
01:19:30.480
after write to the model I want to trigger filter table on the presenter so we're saying after the value gets
01:19:36.400
updated in the filter field we want to trigger filter table on the presenter and finally we have a table and it's
01:19:42.800
very like simple thanks to glimmer data binding we just have cell rows that are datab bound to contact and our presenter
01:19:48.199
that's it usually logic like this if I were to build this app in Java I mean right now it's about 130 lines in Java I
01:19:54.480
would take a thousand lines that would say like in in other Technologies it's a lot more cumbersome to build something
01:19:59.520
like this um but uh yeah this is it this is like the simplest way possible of
01:20:05.560
building this uh in Ruby finally Dynamic form is what I
01:20:11.440
showed you an example of uh in the slides it's basically a form that uses
01:20:17.360
content data binding and as I type these on as I toggle these on and off it
01:20:22.719
updates the form because here it's using content data binding so if I were to look through the
01:20:30.639
code the key thing about content data binding is that you have a like a control here and then the contents of
01:20:37.600
the control uh you Nest within it a Content uh basically control that will data bind
01:20:44.600
to an attribute on a Model customizable attributes on user and this this block
01:20:49.760
will get rendered every time a change happens so that's that's a dynamic part of it and it will change the content of
01:20:55.520
the form dynamically basically um and within it you can use standard data binding as well like I'm
01:21:01.639
using standard data binding for attributes on every one of the attributes that are selected by the user
01:21:06.920
so um that's pretty much it um so let's get to test one and test
01:21:16.040
two um I would say I don't think we're going to get to test two so let's just
01:21:21.480
do test one refactor the last address form example we're going to take 10 minutes for this um and after that I'll
01:21:31.440
I'll close with a few other slides and then we'll do the rest of the workshop and the hack Day event in the afternoon
01:21:56.199
by the way just like before you don't have to start from your code you can start from the test one code that you
01:22:03.080
find in the repo under section two so this is the older version wait this is the oldest version this is the newer one
01:22:10.239
that used MVC so you want to take the one that did used MVC and update it and make it use make it become MVP instead
01:22:17.280
of MVC by using data mining
01:22:33.719
uh one thing to keep in mind is uh you do want to follow incremental development when you're doing your work
01:22:39.440
for example if I start with this MVC version and I want to convert it to MVP uh I might go here and like add a text
01:22:47.199
and data bind it B directionally to let's just say address full name
01:22:55.239
uh and then I can delete this code and then I I I can run it you don't have to wait to till till you typed all the code
01:23:02.120
before you run it it's recommended to run it incrementally see it works even though I
01:23:09.239
refactored it it works so it's just uh that's one nice thing about desktop apps
01:23:14.480
is they start instantly and you can restart them as many times as you need so I typically do incremental
01:23:20.800
development um which is highly recommended
01:23:52.800
okay we're out of time so so I'm just going to go through this
01:23:58.239
quickly so let me open the test Code test one
01:24:04.800
MVP um so the model uh we have just have an address model now that has a bunch of
01:24:10.760
attributes that are dynamically declared with attribute accessor and then in the summary I'm using some Ruby Wizardry
01:24:18.360
here to uh delegate each each attribute name to the send method to call it and
01:24:25.239
get grab its value and then I I'm compacting the results meaning removing any nails and then rejecting any empty
01:24:31.639
strings and then joining them together with a comma uh so this part doesn't
01:24:36.679
matter it's just basic Ruby but uh as far as the view now it got simplified
01:24:41.880
significantly so now we have the attributes datab Bound by directionally like that so we Loop through address
01:24:48.440
attributes in a in an each iterator and for each attribute we declare a label and then we data bind the value to the
01:24:55.159
text uh and then here uh we simply take the label which is the summary label and
01:25:01.560
we datab bind it to the summary on the address and then you can do computed by to do computed data binding and pass it
01:25:07.560
the names of the attributes that are that it depends on so in this case it's the address attributes so that's the
01:25:13.920
benefit of putting all of them within a a constant here is I was able to reuse that constant in multiple places like
01:25:19.760
here here uh here and here which shortens the code significantly so this
01:25:25.119
is a much shorter version of the app the the same app now it's about 50 lines of code so um
01:25:32.480
yeah that's what that one is uh let me show you test two very quickly test two is a movie reviews app that will uh
01:25:40.040
basically lets you enter a movie review for each person uh so like you put the reviewer name a movie name and a in a
01:25:47.159
rating like a rating of eight it's from 0o to 10 and as you enter them one by
01:25:52.360
one it actually will update uh will summarize the information in a table for you and give you the average rating of
01:25:59.679
of the movie with all the reviewers so for example three people entered Matrix
01:26:05.159
uh the average ended up being 9.33 and it's Josh Sarah and Dwayne uh
01:26:11.639
so yeah different people can enter different movies so um you can look at this example after the workshop uh given
01:26:19.280
that you didn't have time for it but let me just open the code of it and run it
01:26:32.199
so basically uh I'm going to enter let's just say
01:26:37.960
Andy Matrix 10 save immediately it showed up over
01:26:43.440
here um then here I'll put uh Sarah Matrix I say nine save now it's 9.5 and
01:26:51.480
it puts it puts reviewers here Bob Terminator
01:26:58.639
2 save Etc so uh the the key thing about this app is that the model that shows up
01:27:04.560
here is different from the model that's being entered here so that's why this app is more complicated um but yeah you can uh dive
01:27:13.080
into it uh on your own time uh yeah I mean this is the code
01:27:20.239
I'll let you dive into it on your own time but again the table of code is super simple it's just a basic data
01:27:25.360
binding with computed data binding that's it um let's look
01:27:31.159
into the remaining material we only have about two minutes
01:27:39.000
left uh Advanced Data binding I'm just going to cover what we have so data binding supports converters if you need
01:27:45.159
them uh convert them on read to the from the model and right to the model you have hooks you have computer data
01:27:50.920
binding which we use today uh nested data binding index data binding key data binding so there are a lot of advanced
01:27:56.440
features in data binding which are a bit outside the scope of a basic desktop development Workshop but I just wanted
01:28:02.960
to cover them also components we we do support components of course obviously because you have to support components
01:28:09.080
for example if you want to build a name and address form you're going to build it as a component and then reuse it um
01:28:15.000
you can even have custom windows and reuse as reusable components uh sometimes they're known as apps so you
01:28:22.000
can encapsulate an entire apps a component and use it in another app if you want so there is full component
01:28:28.000
support there is scaffolding support just like rails uh you can scaffold components or you can scaffold an entire
01:28:34.280
app and it will generate uh like the whole MVC structure for you it'll assume
01:28:40.840
uh implicit controllers so just a view and model uh and it'll generate a rake file so you can package your app as a
01:28:46.560
gem and it generates a hello world version of an app and then you can customize it and do whatever you want
01:28:51.639
with it um so we're going to continue hacking uh at
01:28:57.880
the main stage Ball Room south from 3:45 to 545 so you can come there and continue uh finishing the exercises of
01:29:04.800
the workshop building an app that uses memory or a database or a flat file uh
01:29:10.320
you know the sky is the limit so hit me up there but as far as next steps I recommend checking out glimmer DSL for
01:29:16.639
swt this one runs on J Ruby and it and it has a much more uh stable toolkit it's 100% feature complete it can do
01:29:23.639
anything and you can package it as a as a native app on Mac Windows Linux like a DMG file
01:29:29.159
or exe or MSI installer Etc and you give people an installer they don't have to install Ruby or anything they just
01:29:35.080
install your app and they're ready uh glimmer DSL for WX is the newest glimmer it supports another toolkit that is
01:29:41.119
native I think this is going to start replacing libui in the future because it's more stable than libui and then
01:29:47.199
glimmer d alpha web is all of the awesomeness you saw today in rails now in the front end of rails apps so you
01:29:53.080
could do that uh um you can build this like too MVC app completely with uh like
01:29:59.440
let me jump through it there we go this is glimmer on the web so this is all this is CSS written in glimmer DSL this
01:30:06.320
is uh HTML in glimmer DSL and there's even uh JavaScript you can WR JavaScript in Ruby using a ruby to JavaScript
01:30:22.960
much for