 Okay, you can start. Alright, 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 called belt and the app itself is just an approach. One thing that really hurts me is I wanted to do an app that was just a bunch of props. But the really annoying thing was that the API for the middleware and for the actual app is slightly different. So you can't actually do that. Because the middleware is automatically instantiated by the builder. You can extend the proc class. That would be one solution. Okay, and because it's already called 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. 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. If you saw Confim.ru file, the contents of that file is actually wrapped in a wrapped builder when the code is executed. And that is everything I had time to prepare. Anyone else wants to present something before I get you to some more advanced stuff? No? See you next time now. Hello everybody, I'm new here. I just 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 I wrapped up something that we used but I didn't know anything about it. So I pulled up some recipe 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, Ruby. What puzzles me is certain things over here. So 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 positive to me over here because there's this. I'm not sure how this is different from this I guess. But otherwise I pretty much followed the tutorial and played around with it. I tried to do some vibe up 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 middleware I guess called Builder. 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. Could you increase the font size? Oh sorry yeah. So I guess how the authentication works is you just go through. Are you rack up? Rack up. Looks like I've broken my app. Well okay. Can you require a relative instead? Require underscore relative. And why I did that? Dot slash leave slash my app. Yeah that should work. Okay. Right. Is it 9292? Yeah. Here we go. And also following the tutorial you can also change the name over here. But for some reason I've already authenticated it before so it remembers. Incognito Mido? Sure that works. Yes. So I'm asking for a username and password which I've set here. Oh sorry. Not here? So let's add it. 12256. Like that. Yeah that's okay. That's my rack app. Pretty much. I can change the name. You can change the name between the display. Okay. Yeah. Yeah. What does it do that? So reloader allows you to make changes to your second server but what is the zero parameter there? That's a cooldown period. So by default rack 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. Okay. Yeah. Okay awesome. All right. Anyone else? At home I have MacBook Air and it has on the right side. Yeah. And MacBook on the left side. Okay. First I check this response class. Let's make it bigger. So this response class what it does is that a 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 are not returning an array. You are returning the object of response class. Okay. And when you do response finish what it does is just it executes some block, it did it 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. We can just return an array of any three elements. Okay. So I've got a simple app. Let me check if I can know what it is. Give me a second. Let me know what it is. Okay. So I've got applications showing that basically rack apps are nested applications. So what middleware does and actually middleware is like behaves just like an app. So you nest an app in an app in 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 one 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. 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 0.0 something. So I just do, I multiply by 1000 to show this time in milliseconds. And now my app, 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 this, 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 applications in the rack in there. 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 still. And the next one in order is Webrick. So there is a hard-coded order in the rack that will always take Puma whenever it's possible. Okay? Okay, so it shows I responded in 400 in something millisecond. And now I refresh it and 450 here. So it will always sleep between zero and one 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 of these open here. So let's start with the server, the first file that we're supposed to read. So this one, basically what it does is that it parses all the options that you pass when you start your application. It doesn't do much more. It basically takes all the options, it parses them, adjusts them to the handler's 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 print 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 types of 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.rackserver.sh, it creates the new instance of the rack server. And then it will... Then what it does, it adds certain configuration. And this is 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. 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. 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. Yeah, they have a lot of weird stuff with it. Also with numbers as well. Yes. They're like some numbered global variables that stop at a random number. Okay, 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 seven years old. 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. Yeah, I think so. The first commits are from 2009. Yeah, some of this could be refactored, could look way nicer, but it 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 later, you can change some settings. Now, it checks the PID. 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 basically return the application that consists of all the middleware that you provide. So this is wrapped up. Then it will demonize it 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 call that happens is the server run. So 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 different one is WebRub, but we can run Unicor, which is, I guess, most popular than Puma, which is one of the few multi-fragment options, etc. And each of these servers needs to have a specific handler that will adjust to their racks requirements. So we have, on one hand, we have a framework like Rails or Sinatra that is on one hand of rack, on one side of rack, and it needs to adjust to the racks syntax and the way it works. And then on the other hand, we've got the 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. That's the two-disk handler code. So the handler class itself does almost not just determine which server you are using. And that's it. 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 string. It will change all the letters to small. It will, basically, if you provide some, if your name is not perfect, it will say it's in capitalized letter or you don't use the double problems, 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 even a class, it's a module. Based on that, it will try to fetch the 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 these set, it just picks the first available from the list of Puma, then Thin, then Web Brick. So in my case it was Thin. I don't know, I think it is installed either with some framework or with Ruby 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 Puma, this try and require rescues the error. And it will only, I think if I say, if I add the warnings, it will say that it tried to load Puma, but it let it fail. 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 it registers all the basic, all the handlers that come with RAP itself. So these ones are like CGI, fast CGI. These are all, this is all stuff. So basically RAP appeared, I think, in 2009 or 2008, something like that. Before that, there was no RAP, so people were running rails and in general Ruby scripts on CGI. Then RAP 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 RAP. So then everyone switched to this mode passenger that was actually the mode for Apache. And then more servers appeared like Unicorn 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 picks 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 of 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 RAP 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 the handler. We transform the RAP syntax, the RAP options into the syntax that server understands. And then what webrick does is that it basically creates the new options with the server. It mounts the application under the root path and then it starts the server. So I will show you one more that is thin because it's a bit different. So thin 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 syntax. But thin, 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. Make it a bit bigger. And Puma is a bit longer. So Puma has this whole configuration object here. So we need to call... We basically create a configuration object that will... This is not a hash. It's a custom class. And then this config goes here. So this config contains everything. This config contains hosts and the application to see if it has custom methods. Or maybe it has custom methods that are, like, port, etc. So... Yeah, okay, yeah. And 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? No. So it actually runs server first before it runs the handler. Probably not the other way around. 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... So server here... It chooses the handler. So server in the end... And server.run calls handler.run. Right. Yes. Okay. Yeah. That's it regarding the handler.run, I guess. I will show you a few more things. 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 rack. But 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 thrown 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. It returns body. So what cookies middleware does in Rails? First, it calls the application. And then later, only later, it updates the HTTP header. And if you see the line, it's line number 570 something. So this is a huge application. There's lots of documentation, but it's quite a big application here. There's lots of stuff that is happening. Yeah, it has a bunch of custom modules and classes, et cetera. I think that this itself could be some separate library. I've seen libraries that are 50 lines of code, and this is 10 times bigger. So you can let them check the other stuff. Remote IP, for example, this... Ah, I didn't open Remote IP. 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.remoteip in your application. So all of this stuff, all 200 lines of code, what it does, it calculates, it transforms the IP to the format that we can understand. So Rails IP right now, the default stack, if you do not remove any middlewares, 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. So you can put 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.call, it will just return a bit 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, right? 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 a request and they specify the HTTP protocol, it will not get to your controller because it will need to go through all the 60 or something layers. So what it will instead, it will go through like 10 layers or so and this layer will stop it. It will try to do something else, yes. So I use, for example, I think one case that I use, middleware is translations file. So we want to fetch the translations file, file that consists of all the keys and phrases for certain language and we want it to be as fast as possible. So we just put it somewhere in the list of middlewares. So 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 I've got an example of the middleware that does, it's not really a middleware. Oh no, it does. It also does app.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. Okay, and I've got one more thing to show, which is the, I didn't mention it in the description, but I checked it 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 composes the application. So as Ted mentioned, it's already dependent. So it processes a line by line and then it runs the application in the app. 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. Okay, so it starts as an empty array and then we push more things here. So, I don't know what this map does here. I think we can map it to a certain route. Ted, you have an idea? Yeah, yeah, map is for routing. Map is for routing, yes. But this is for, this is, you can provide map for use. So I think you can map, so when you map something to a route, you can use custom middlewares for that routing. But I'm not sure. Let me go to the beginning. So you've got map that starts as nil 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, no. This middleware will be run only in this, in this route. Only you can... Yes. So for example, you can do something like admin use out. Right. 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 not to the user. And then 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 the list. 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 creates this variable and assigns this block. So executes this block in the route that we provide in the path that we provide here. So this is the second method and then the third one was run. Okay, so run basically assigns this application, the middleware application that we provide there 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 be using or I can be using builder. I can do it without or with the builder. 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 article does. If someone knows who does the article, I don't know why it reverses it. So this use will be consisting of all the middlewares, right? But then we reverse it. So it starts from the last one and then we inject. Ah, of course. So, in a second. Okay, so we need to run we need to go to the last one so that we will have something like nested how to explain it. So the random sleeper will have the hello app as it's app to run. So it will be something like this. Something like this. So that it will take 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 an 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. Okay, so that's why that's why we reverse 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? Okay, okay. Yeah, that explains a lot. Okay. So I believe that we want to before we start serving the request we need to do something for the application. So for example imagine that your application you want some data before it serves it to user. So maybe this is for warm-up use. 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. Okay, so this one maybe it checks if the application starts successfully because it creates a mock request and it just checks it's work. 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. So builder.app will basically create an instance of this builder that will later that will later create create all this nested all this nested structure. And now let's see okay. So this is already no. I never called builder.app in my code. So I don't know where it is. Okay. 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 and then it but then it calls to app. But I don't call it manually, right? Here, if I refresh the new I do not call to app. So I have no idea okay. Yeah. So if I provide just new and then I provide block. So this block will be evaluated within this instance. Okay. So what I do is okay. Let's see if maybe run does it. No. No. Okay. I'm lost here. If someone figures it out later let me know. Write some comment. I don't know why it's used up here and what is why it works with the new if it's the same with with app. Okay. 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 have a string. It works. You pass the string and it works. Yeah. But for you it didn't write. It didn't for me as well. Yeah. So I wonder if I just ended up with a server that is more forgiving or Okay. If I run all the middleware it will work. Okay. Let's see. This will work. No. It doesn't work. Okay. Which server did you get? Thing. Which version? The newest one. All the newest versions. No. I have no idea. Okay. Let me just double it. Oh. Yes. It's there. 1.6. 0.3. Okay. Okay. How do I provide the hand here? Let's see if I do it with library. But what is the option now? Uh... This step also says it was a master for straining Ruby 1.8. I'm removing Ruby 1.9. But I'm not using Ruby 1.8. Yeah. Exactly. Yeah. Yeah. 1.7 knows it. I don't like it. Okay. Let me start with library. Yeah. Because I know Aaron said for sure that the body must respond to it. For me, it's too much. No. Same here. Okay. Let's... Let's see if that will help. 1.7. Okay. 1.7. Not that. The computer is broken. I broke it. I broke it. If I just do... It needs to take the environment as an argument, I guess. Where? As an argument, I guess. What did I do wrong? I need the curly brackets. What? You need the curly brackets for your... Okay. No idea, man. This is so scary. Okay. What if I do without the builder? What if I do just this way? No? Still the same? Yeah. Are you sure you didn't override the string class to respond to each? It's still working. It's still working. We fined. 1.7. Okay. No idea. You don't like the string to try? I'm just trying to see if I do something different. Okay. It's supposed to work, right? It's supposed to come to each method. I'm not running Ruby 1.7 for sure. Runs Ruby 2.3. The version of the server is 1.7. Yeah. Is Ruby 2.1? Yeah, still works. For some reason. Which version of Ruby do you have? 2.1. I've got 2.15. Let's try another one. It's running 2.3.0. Okay. Okay, this one I will run. It shouldn't make a difference. Oh. Wait, wait. I think I... Yes. Yes. That's positive. Let's try once again. Hey, it works. So, Ruby version. Ruby 2.3? Makes it. Let's try with Ruby. I'm just glad I didn't... You didn't go crazy. Yeah. That's good. What? Now we have another question we can begin with. Is it about the basic object being arranged or something? Different implementation of each. But strings should not implement each even in Ruby. Yeah. It doesn't. It doesn't. No. Okay. Yes. Something behaves weird here. Ruby thing maybe has some special case in there. Like if you're using Ruby. I don't know. No idea. I will check later. Do you know which version you used before when you did it? 2.1.5. Yes. It's the same. Okay. We can check in the rack of actually. But I didn't know where is that. By the way. Where is that each? It's in the body proxy. No, not here. Not here. You don't see something here. Just make a special case to address the body. To what? This method is a special case to address the body square. We are applying a special case for each function. To say adding too many methods. But what is it? What is the name of the body? Or the number? 434. Yeah. So the method is Oh. There is a method missing here. Or no. But the method missing is on the body proxy class. Not on the string class. Okay. Had it. 2012. It's on the body proxy thing. Oh yeah. So it shouldn't work without a builder. And you returned just straight string. You didn't use the response class. So you used the response class. Right. Yeah. Yeah, so somehow it turns the string into a body proxy. Yes. Somewhere. But I don't know where. Yeah, but the thing is that the body proxy. Each calls the body. Each. Yes, exactly. Yeah. I think we will not figure it out now. Yeah. Just leave it as an exercise. Okay. Anyone has any more questions or want to show some piece of code or that's going to be. Okay, cool. Thanks for coming then. Thanks to Thinkabox and then for hosting us. I will add the issue on the github to Ruby SG so that we can decide what we are going to do. So far we've covered sprockets, concurrent Ruby and today we are. Thanks once again. Thank you. Thank you.