 Okay, you can start. All right, so I'll start by showing my awesome Hello World app in red. Why not colors? Because I normally don't use ink. Okay. Okay, so it actually uses middleware or belt. And the app itself is just a pro. And I think one thing that really hurts me is I wanted to do an app that was just a bunch of pro's. But the really annoying thing was that the API for the middleware and for the actual app is slightly different. You can't actually do that because the middleware is automatically instantiated by the builder. You can extend the pro class. That would be one solution. Okay. And because it's all ruby color right, it doesn't actually check that you're passing the end thing. So one thing you can do is you can just pass whatever you want here. And it should still work. I think I need to restart it. It's actually still working here. Maybe just a little. So yeah, I guess the thing about red is that it's really super simple. And it was probably even simpler than I thought it was before I started reading the code. But I guess one of the biggest gotchas is that the middleware can be order dependent. So if you have something like Warden, it will be depending on you having some session middleware before it in like the middleware chain. Yes, I always said that slightly different APIs for apps and middleware seem a bit unwarranted to me. If we're going to go with a super simple API anyway, then I felt like we should have the same API. It was slightly obscure to me at first as well, but if you saw a config.ru file, the contents of that file is actually wrapped in a wrapped builder when the group is executed. And that is everything I had time to prepare. Cool. Anyone else wants to present something before I get to some more advanced stuff? No? See you next time now. Come on. Hello. Hello. Can I go on the table? Yeah. On the table. Okay. Yeah. Hello everybody. I'm new here. It's my first meet-up here in Singapore. I'm also very new to Ruby. I just completed a bootcamp which ended just last Thursday. So, wrap is something that we use, but I didn't know anything about it. So, I put up some present tutorials, read some articles, and this was basically the following tutorial by Ryan Bates, which was quite a long time ago. So, what I basically done is I put most of my logic in my app, you know, Ruby. What puzzles me is certain things over here. So, just like I read a documentation that you always need to finish your response. And this was what Ryan Bates did as well. But this is slightly puzzling to me over here because there's this. I'm not sure how this is different from this, I guess. Otherwise, I pretty much followed the tutorial and played around with it. I tried to do some buy-butt to find out what the environment was and I learned a little bit about that. And one thing that I tried on this rack app was by using this wheelbarrow, I guess, called Wheelbarrow. So, it allows me to make the changes to the app without me having to restart the server. So, this is something that when I use Sinatra or Rails, it does for me and I don't know what is actually going on behind. So, I learned something new. And then I, well, there was this auth basic which allows me to just do some very simple auth authentication without using what I have to create a user model or anything like that. So, could you increase the font size? Oh, sorry, yeah. So, I guess, how the authentication works is you just go through... Where was the... Are you... Rackup, right? Rackup, yeah. It looks like I've broken my app. Well, okay. Can you require a relative instead? Require a underscore relative. Dot slash lib slash my app. Yeah, that should work. Okay. Right. Is it 9292? Yeah. We go. And also following the tutorial, you can also change the name over here. For some reason, I've already authenticated it before, so it remembers... Incognito window? Sure, it works. It's asking for username and password, which I've set here. Oh, sorry. Not here. So, that's okay. 1002456. Yeah. Yeah, it's okay. That's my record. Pretty much. I can change the name. You can change the name between the display. Okay. Yeah, something like that. Yeah. What does it do that... So, reloader allows you to make changes to what we're starting server, but what is the zero parameter there? That's a cooldown period. So, by default, red reloader... I don't know how it works, but it checks every 10 seconds by default. Oh, okay. So, if you set a zero, then it just keeps doing that. I don't know how much processing power it takes that much. Okay. Yeah. Okay. Awesome. All right. Anyone else? Okay. At home, I have MacBook Air, and it has on the right side. Okay. First, I check this response class... Let's make it bigger. So, this response class, what it does is that... Rack, every app needs to return an array of three elements. So, first element is a status. The second one is the header, and the third one will be the body. And if you just return the response, you're not returning an array. You're returning the object of response class. Okay. So, if you just return the response finish, what it does is just... It executed some block, it did some stuff, and then it returns these three elements, the array that you need. So, that's why you need to call finish, or you don't need to always create the response object. You can just return an array of any three elements. Okay. So, I've got a simple app. Check if I can hold it. Give me a second, let me download this app. So, I've got applications showing that, basically, rack apps are nested applications. So, what middleware does, and actually, middleware behaves just like an app. So, you nest an app, and an app, and an app. And then you can do... Each middleware can do something before calling the next level or after that. So, I do here two things. I use two middlewares. First middleware is a random sleeper, and it will wait a random amount of time between zero and one second, and then it will call the application. So, first it will sleep, and then it will do... It will call the next app. And the second one is time measure. First checks what is the current time. Then it calls the next application. And then it adds the text. As you see, it adds two empty lines. And then some text that shows how much time it took to run this application. So, this code is quite lame. Basically, time now minus... Time now it will return in seconds. So, because this will sleep less than one second, it will be always zero or something. So, I just do... I multiply by thousand to show this time in milliseconds. And now my app, so that... Hello. So, the Hello app, the main application does nothing. It just returns the text. Hello. I haven't managed to see why I need to return error here. I don't know. It just tries to run each method on the third value. So, it needs to be an error, apparently, or a hash. I haven't checked it. So, it will return a status 200. It will return no headers. It will just return this body. And now I build my application using the right builder. So, first, I use time measure. And I need to use time measure first to start measuring time. Because if I do it this way, then first I will sleep, and later I will start measuring time. So, it doesn't make much sense. And then I run my Hello app. So, actually, I build an app that consists of three different applications. And then I run it. So, let me... On my private computer, it runs Puma by default, because I've got Puma installed here. I don't have Puma. The next server is fin. And the next one, in order, is Webrick. So, there is a hard-coded order in the rack that it will always take Puma whenever it's possible. Okay? So, it shows I responded in 400 in a second. And now I refresh it in 450 here. So, it will always sleep between 0 and 1 second, a random number, and then it will respond. Okay, so let me... Yeah, so this app is basically very, very simple. I want to show you now the server and the handler, what it does. Okay, I've got too many views open here. So, let's start with the server, the first file, the first post to read. So, this one, basically what it does is that it parses all the options that you pass to the... when you start your application. It doesn't do much more. It basically takes all the options, it parses them, adjusts them to the handlers format and runs the application. So, the server basically, as you see, it has a bunch of these options. So, you can do Evol, you can do Builder, Warnings, you can do some path additionally, et cetera, et cetera. This is super boring code. And it goes like this. And here, this is the end of that option. No, it's not... yes. Or this is the end of parsing that option. So, this method is like 100 times a code, just to parse different options that you can pass. Now, this one, I haven't really checked, and then we've got the start method. And the start method, you just call rack, the rack server.src, it creates the new instance of the rack server, and then it will... Then what it does, it adds certain configuration, and this is a super interesting thing. So, you can call a global variable starting with a dash, but if you try to call the local variable starting with a dash, it will not work. So, let's do it. Huh! So, it works only with one letter name. I didn't check that. Yep. Okay, I have no idea if it's some special attribute of Ruby, or not. Now, if I do something like this, it says that this global variable is not initialized. Now, if I do something like this, yeah, it just doesn't work. And let's try one more thing. Yeah, this one doesn't work either. So, the only case where you can start the name with a dash is the global variable, and it's only one letter. I guess it's some very, very old legacy code. We have a lot of weird stuff with it, also with numbers as well. Yes. There are some number global variables that stop at a random number. I have no idea. It's something that I learned often when I read the code of some libraries that are, you know, quite old. The code is quite old. I guess that... Yeah, I think that's... Yeah, the first thing... The first thing I reacted to was that everything was a bit messy, and I think everything going with the approach of don't fix what's not broken in the story. Yeah, I think so. I think the first commits are from 2009. Yeah, because this code is... Yeah, some of this could be refactored, could look way nicer, but it's just not changed. So anyway, you parse all these options here once again. So first, that method that I showed you before, it parses options and it generates a hash depending on what options you add in the command line, and then depending on these options they can change some settings. Change some settings. Now, it checks the KID, so it will... If this app is already running, if you provide the process ID and it's already running, it will run you an error, then this is building application. So this is the... I think this is the builder class that we used in this example that will build the whole app and it will return the application that consists of all the middle words that you provide. So this is wrapped up, then it will if you provide it so that it will work as a demo in the background. You reserve the process ID, and then in the end the last code that is the server run. So the server actually here, it's not the... This is not the instance of a server class. The server variable is the instance of handler class, which is... to me it was very confusing because I am in a server class here, so I assume that server variable is an instance of the class where I am, but no, it's a handler. So yeah. So now we get to the handler. And handler is an adapter between the application and the server. So as we know in Ruby we use server applications to run our app. So we can run... The default one is WebRub, but we can run Unicor, which is I guess most popular than Puma, which is one of few multi-fragment options, etc. And each of these servers needs to have a specific handler that will adjust to the rack's requirements. So we have on one hand, we have a framework like Rails or Sinatra that is on one hand of rack, or on one side of rack, and it needs to adjust to the rack's syntax and the way it works. And then on the other hand, we've got a server. So basically this allows us, it's kind of like a bridge pattern. It allows us to run any framework on any server. So Sinatra will run on Puma, Rails will run on Fin or WebRub, etc. Any framework that supports rack will run on any server that supports rack. Let's get to this handler code. So the handler class itself does almost not just determine which server you are using. It doesn't do much more, but it's quite a simple class. Basically if you will provide the name of the server it will try to guess what it is. So it will manipulate the stream, it will change all the letters to small, it will basically if you provide some if your name is in capitalized letter or you don't use the double commands etc. It will try to find what was the handler that you're trying to use. And this class, this module actually, it's not in the class, it's a module, based on that it will try to fetch this server, it will try to initialize that handler that you're looking for. So here we've got default value. If it fails to understand what you meant or if you do not provide the server whichever you want to use it will just try to guess based on the environment variables. So if you don't have any environment variables and I didn't have any of this set, it just picks the first available from the list of kuma, then thing, then the library. So in my case it was thin. I think it is installed with some either with some framework or with some library right now. That's why it picks it because I've never used it actually. So I don't know why it's in my system. Anyway so picking is that there is this function called try with require. So it tries to so it changes the name of as I showed you. It will change the name and then it will require it. But if it can't, then it will not raise an error. It will just go further. So that's why even though I don't have kuma, this try with require rescues the error and it will only if I, I think if I say if I add the warnings it will say that it tried to load kuma but it failed. So then it picks the next one and the next one. And only if the last one fails then it will crash. And then with that function register so registers all the all the handlers that come with wrap itself. So these ones are like CGI these are all, this is all stuff. So basically Rack appeared I think in 2009 or 2008 something like that. Before that there was no Rack so people were running Rails and in general Ruby scripts on CGI then Rack appeared as this module, as this piece between the server and the application or framework and I think the passenger server was the first one to support Rack so then everyone switched to this mode passenger that was actually the mode for Apache and then more servers appeared like Ruby Core and standalone passenger and I don't know, there are a few more like rainbows for example so anyway this module does, but it only meets the handler and then what's more interesting is that what this handler does so each of these servers has a bit different syntax a bit different options a bit different way on starting the application but basically the goal of the handler is to start the server with the application provided there so WebRick is pretty simple here we've got just one method that is called run and we determine the environment, a few options that we need so for example WebRick requires the port option so we check if it exists and if not for WebRick the default port will be 8080 then Rack has an option called host but WebRick the server doesn't recognize it, it uses bind address so we need to change it and basically this is what we do in a handler, we transform the Rack syntax, the Rack options into the syntax that server understands and then what WebRick does is that it basically creates the new options with this server, it mounts the application under the root path and then it starts the server so I will show you one more that is fin because it's a bit different so fin doesn't mount application application is one of the arguments that you start when you create the server so we put the host port application and then options so it's a bit different in that but fin as you see it's like what 630 this is the whole class, there is nothing more 36 lines of code so this is once again very simple and then the last one that I have is Puma and Puma is a bit Puma is a bit longer so Puma has this whole configuration object here so we need to we basically create a configuration object that will, this is not a hash it's a custom class and then this comp goes here so this comp contains everything this comp contains host and the application to see if it has custom methods ah ok it has custom methods that are port etc so yeah ok then we create this launcher and then we have a bit different method we call it launcher run in other cases we have launcher.start any questions so far nope, so actually we run server first before it runs the handler because I was thinking that the handler picks the server and then it runs server.rb so it's the server.rb that calls the handler yes, yeah that's what it does so server here it chooses the handler so server in the end server.run calls handler.run yes that's it regarding the handler then I guess I will show you a few more views so here in this middleware you've got there's no middleware library here so it's hard to let them know what is really middleware in the in the rack in the rack part what you can do is you can go to rails and then in the action pack action pack consists among others of action dispatch and here you can see how different middlewares work not all of them are rack middlewares they are just from here but for example one of the bigger ones is cookies so here you've got the method call and as you see it returns in the end it returns status it returns header returns body so what cookies middleware does in rails first it calls the application and then later only later it updates the it updates the HTTP header and if you see the line line number for 570 something so this a huge there's lots of documentation but it's quite a big application here there's lots of stuff that is happening yeah it has bunch of custom modules and classes etc I think that this itself could be some separate library I've seen libraries that are 50 lines and this is 10 times bigger so you can later check the other stuff remote IP for example this I did not yes so remote IP is simpler it basically provides you IP yes so this is what it does in general this is the core of it so it adds the IP to the environment so that later you can call request.remote IP your application so all of this stuff all 200 lines of code what it does it calculates it transforms the IP to the to the format that we can understand so Rails I think right now the default stack if you do not remove any middleware it runs around 60 of them so there are 60 levels of Rails application before it gets to your controller so it will add this IP it will go through SSL for example at some point the middleware will not call your controller it will just return something up so for example you've got a middleware you can have a middleware that will return something instead of going to the controller just because you want it to be super fast this middleware somewhere between your two middlewares in the Rails app so you want the middlewares that you need to work and then the ones that are not needed you can just skip your middleware will not call the app app.call it will just return everything up I'm not sure if I know any example here the static one no it does it calls it so for example SSL you require SSL and if your request goes for SSL then you will call this application but if not you will try to redirect so if a user makes request and they specify the HTTP protocol it will not get to your controller because it will need to go for all the 60 or something layers so what it will instead 10 layers or so and this layer will stop it and it will try to do something else I use for example one case that I use middleware is translation file so we want to fetch the translation file file that consists of all the keys and phrases for certain language and we want it to be as fast as possible somewhere up in the in the list of middlewares that it doesn't need to go through SSL, middleware it doesn't need to go through a bunch of other stuff but because of that it returns in like 5, 7 milliseconds instead of standard 50 or 100 here is an example of the middleware that does it's not really a middleware oh no it does it also does up.com I think I've seen one that doesn't do it so it seems that not all of these are really behave like middlewares but I might wrong I just thought that I've seen something that doesn't behave this way ok and I've got one more thing to show which is the I didn't mention it in the description I'll take check this later and it appears to be interesting to start. So Builder is a class that allows you to build the whole application that will consist of multiple apps and middlewares this is what I use in this example so this is what I use in this example it's basically it's a small DSL that that composes the application. So as Ted mentioned it's already dependent so it processes line by line and then it runs the application in the end so let's see how it works here this is quite complicated and to be honest I do not understand everything here because it's a DSL so it tries to decognize it basically parses the code that you provide there and okay so first function is use and we've got this use instance variable that will keep all the apps that we it will keep all the applications that we are using all the middlewares that we are using let me try to find where is the first time that it appears so it starts as an empty array and then there are huge more things here so I don't know what this map does here I think we can map it to a certain route Ted idea map is for routing yes but this is you can provide map for use so I think you can map so when you map route you can use custom middlewares for that routing but I'm not sure let me go the beginning so you get map that starts as new and where do we assign it okay yes here is the example so see so we can so is it so that the routes will be available to the middleware no no this middleware will be run only in this in this route yes so for example you can do something like map admin use yeah something like that so this builder allows you to specify middlewares not only on the top level you can do top level as well so this one will be available everywhere and this one will be available only not available it will be run only on this route I don't know if it's possible to nest the mappings because let's say that I want to do admin here and then I want to do something like map to the user and that I want to use another middleware but I'm not sure if it's possible or if I need to do it here and then I need to repeat those stuff so I'm not sure about it anyway we were in this method called use so this method will add this particular middleware or app that we provided with all the arguments to that is so then it will be all will be called in an order that we provided now so this is use and there is map so map only only creates this variable and assigns this block so executes this block in the path that we provide here so this is the second method and then the third one was run so run basically assigns this application the middleware application that we provided as the main one and then and then this is what creates the application in the end so if we have some map we generate it so this generated map will be our main application and if it's not we just have the main app so in my case I can just do something like this because I will not I will not be using be there I can do it without or with the builder but if I don't have any maps like in this application I will just use this application then what we do oh I have no idea what this particle does if someone knows who does then we go I don't know why it reverses it so this use will be consisting of all the middlewares but then we reverse it so it starts from the last one and then we inject ah of course so in a second ok so we need to run we need to go to the last one so that we will have something like nest how to explain it so that the random sleeper will have the hello app as it's up to run so it will be something like this ah right something like this so that it will take ah we will initialize it with this argument and I think we need to do it from the end because if I want to provide the hello app as the new hello app the instance of hello app as a application to be called by a random sleeper I need to create it first right so first I create this object and I provide it as argument here and then because I create this one I can provide it as argument here to the time measure yes exactly yes so each next application is an argument to be run by the previous one yes ok so that's why ah that's why we will burst it and we inject it then starting from the last one and then we've got then this is our complete application and in the end we have the warm up don't know what it is no idea does it ok ok ok that explains a lot ok so I believe that we want to ah before we start serving the request we need to do something for the application so for example imagine that your application wants some data before it serves it to user so maybe this is for warm up or even caching or even caching caching yes exactly yes so this is like a preparation for the app on the start of time before it starts before it starts serving the request and this one ok so this one maybe it checks if the application starts successfully because it creates a mock request and it it just checks I don't know this is just my guess I've never read this option before so anyway we call this and then we return the application and this function to app is called in builder so builder.app will basically create an instance of this builder that will later that will later create all this nested all this nested structure and now let's see ah ok so this is already no I never call builder.app in my code so I don't know where it is ok I do builder.new if I do builder.app will it work is it just an alias no it's not an alias because I do new but then it calls to app but I don't call it manually right? here if I replace with new I do not call to app so I have no idea ah ok yeah so if I provide just new and then I provide block so this block will be evaluated within this instance ok so what I do is ok let's see if maybe run does it no no ok I will just here if someone figures it out can you later let me know write some comment I don't know why it's used up here and what why it works with the new if it's the same with app ok I think this is all I prepared for today any more questions or I'm curious now why my application works because even in Aaron's talk right he said that the body must respond to each but in my app it works even though I just pass a streaming it works you passed a stream but for you it didn't write it didn't for me as well so I wonder if I it's more forgiving or ok or if I move all the middleware I have one middleware ok let's see it doesn't work it doesn't work you see which server did you get which version the newest one all the newest versions I have no idea ok let me just double set 1.6 for 0.3 ok how do I provide a hand here let's see if I do it with web read but what is the option now step also says each was a master for training in Ruby 1.8 I am removing Ruby 1.9 but I'm not using Ruby 1.8 yeah exactly yeah yeah I have seen 1.7 though I don't like it ok let me start with web read yeah because I know Aaron said for sure that the body must hear something for me it's human no same here ok let's let's see if that will help ok 1.7 you see I'm very scared I broke the wrench if I just do yeah it needs to take the environment as an argument as an argument I guess ah what did I do wrong I'll need the curly bracket what you need to cure the brackets for your ok no idea man this is so scary ok what if I do without the bill there what if I do just this way no still the same are you sure you didn't override the string class to respond to each it's still working we fined 1.7 ok no idea you don't like the string too try and see if I do something different ok I suppose it's supposed to work right if in B1.7 it's supposed to come to each master I'm not running I'm not running Ruby 1.7 for sure runs Ruby 2.3 the version of the server is 1.7 as well but it's not Ruby 1.7 yes 2.7 yes still works for some reason but they run Ruby 2.7 Ruby 2.7 I've got 2.15 let's try running 2.3.0 ok ok this one I will run it shouldn't make a difference oh wait wait no no I think change yeah that's positive let's try once again hey it works Ruby 2.3 makes it let's try with Ruby I'm just glad I didn't you didn't go crazy yeah ok that's good this works weird what? now we have another question is it about the basic object being like a range or something the rate of limitation of each but strings should not be infinite each even in Ruby look at them up here each it doesn't no ok so in yes something behaves something behaves weird here we're feeling maybe has some special case like if you're using Ruby I don't know I don't know I will check later you know which question you used before when you did it 2.1.5 yes no here's the same ok we can check in the rack of actually but I didn't know what is that by the way where is that each it's in the body proxy but not here what if you don't just make a special case to address the problem to what this method is a special case to address the problem or we are playing a special case for each of you to save adding too many methods but why was it added what was the name of the problem 434 yeah so the method is yes there is a method missing here or no but the method missing is on the body proxy class not on the stream class ok so it's on the body proxy thing so it shouldn't work without a builder and you returned just straight stream you didn't use the response class so you used the response class correct so somehow it turns the stream into a body proxy yes somewhere but I don't know where the thing is that the body proxy that each calls the body dot each alright yes yeah I think we will not figure it out now just leave it as an exercise ok anyone has any more questions or want to show some piece of code or it's gonna be ok cool thanks for coming then thanks to thinkabox and then for hosting us we will have the issue on the github to ruby sg so that we can decide about the next library so far we've covered sprockets concurrent ruby and today thanks once again thank you