 Hello. Good evening, everyone. So I think Sam has given a very good talk on designing, because personally, I stuck at UI design, so I was completely blown away. Thanks, Sam, for sharing. Today, I'm going to talk about, like, just share five random Ruby tips. And in case you're wondering who I am, my name is Shen Law, and that's my Twitter handler, code, underscore SSL. I actually work for IDA, but I don't have the opportunity to work at this office, and it's very nice. I'm actually seconded to Ministry of Manpower to work on an HR project. So, my first tip is tip number zero, not because, like, normally people say, you know, a programmer starts from zero, but because I actually have five other tips, this is just something extra that I want to highlight. So I'm using this tool called Rabbit, which is a Ruby gem. So what is Rabbit? Rabbit is actually a presentation tool for Ruby. And you can write your slides in RD, Markdown, or HIKI. Personally, I use Markdown, so I can write my slides in bin. Ah, so... And I can run, I can launch my slide using rake. How cool is that? And there are many themes. This is actually a default theme, and you can find out more from the website rabbit-shocker.org. And, um... How did I come to know this tool? It's, you know, at Red Dot Ruby conference this year, Matt was the keynote speaker, and he used this tool, and I was like, wow, it's actually quite interesting because there is a tortoise and rabbit underneath there. And the tortoise is actually the time that you allocate for this talk. So I actually allocated, like, 15 minutes. And Rabbit is actually the actual progress, like, how far have you come to this presentation? Yeah, it's a very cute picture on duck typing. So, tip number one. I guess Ruby is... We are very familiar with Immunerables. Like, we use a lot of methods like select, reject, reduce, um, yeah, et cetera. Um, what I want to share today is something less commonly used. So the more it takes a while, so what it does... So the documentation says that passes elements to a block until the block returns 0 or 4, then stops iterating and return an array of all prior elements. We are programmers, so it's easier for us to read the code and understand what it does. So there is an array, 1, 2, 3, 4, 5, 0, and we just call dot take while and then pass in a block that says i less than 3. So what it does is it iterates over all the elements, until it reaches an element that actually returns 0 or 4 from that block, then it will just stop and then return all the prior elements. So this is actually returning 1 and 2. Likewise, there is a counterpart called drop while, which is quite similar, but it actually drops elements until it reaches an element that for which the block actually returns 0 or 4 and then it just return the remaining elements. And tips number two. Active record validation context. So, like, we... How many of you actually use Rails? Like, okay, so quite... So I'm sure you guys are familiar with active record. So normally we have a lot of rules in our active record models. But the thing is that sometimes rules may be applicable at certain stage of an application flow. So normally what we do is that we can pass in an if or unless option to specify whether when should a rule be applicable. But I learned that there is actually an option called on, whereby you can specify the context or an array of context to specify when the validation rule should be applicable. So this is an example. So as you can see the username and password are actually less than 8 characters. So when I call dot valid, you actually return true. Because in the previous slide, I specified that those validation rules are actually on context one, and the second one should be effective on these two contexts, context one and two. So if you don't specify context, then you say, okay, it's valid. But you can actually pass in, like, oh, context one. Then you will say that, oh, actually both username and password are like, yeah, context two. Then it will say password is not valid. This is very useful. So for example, you can instantiate a form, and then maybe you want to save route. But at that point of time, when you save the draft, you may not want to have the full validation rules to be invoked. So you may want to only have a subset of it. So you might want to define different contexts. Yeah, in my opinion, it's cleaner than conditional validation, but it really depends on what you want to do. The client code can decide what context to be passed in. So it's easier for the client code to decide, you know, what rules I want to use. Tips number three, active support. So if you know active record, I hope you know what active support is. It actually provides a lot of useful methods. And for active record, we can actually use delegate, which is, well, a macro, a method that allows you to delegate function call to an associated object or model. So in this case, a person belongs to a household. Yeah. So normally, if you want to retrieve information from the household of that person, you probably have to do person.household.information. But by using delegation, I can just call person.information. And this would actually delegate a method call to the information object that this household is dedicated to the household object that this person is associated with. Of course, person.information sounds very strange, right? Because what I want is really household information. It turns out that there is an option called prefix. So if you set it through, by default you will use the model name, sorry, the name of that symbol that you're delegating to as the prefix. You can call .household.information which makes more sense. If you want to have something more custom, you don't call household or you'll call something else, then you can specify a different string, then you can have a different prefix. Of course, to make it more robust in the event where the associated object that you're delegating to is not available, you don't want the program to crash, then you can specify allow nil to be true. You will just return nil. This can be good and bad depending on what you want to achieve. Tips number four is on bundle install. So we use bundler to configure the gems that you want to use. Sometimes, you are deploying to an environment that is so secure that you don't have outgoing internet connectivity. When that happens, when you try to run bundle install then you encounter a problem because you cannot crash ruby gems from rubygems.org. What normally we would do is we would run bundle package.sh and this would package all the gems and put it in your vendor folder. Remember, there is a vendor folder in your Rails app. You might not have decent advice there. You can actually check in, push this code to your repository and when you push it to production, you can just run bundle install dash dash local then you won't connect to the internet. It will just install whatever gems that you have in that vendor folder. What are the advantages of doing so you can install gems offline. It's certainly fast because you don't have to download anything. Another advantage is there is no need to host custom gems on the server. For example, if you have multiple Rails applications it's very likely that you will create a custom gem to share your ruby code across different projects. When that happens, generally you would actually host your custom gems on the gem server. This is a very quick and dirty way. You just have to put a gem file into your project and then just run bundle install. Tips number five is parallel tests. How many of you write tests? Can I have a show hand? Very good. In our project, we write a lot of unit tests as well as function tests. Sometimes it might take a while to run. We actually use this gem called parallel tests and what it allows us to do is that we can run our tests in parallel. We actually split all the tests and then allocate to different processors and then you just use different CPU calls to run the tests. The website actually says that if you have two CPUs you have two X testing speed but in my experience it's not always true. There are a lot of other factors. It works for RSpec, TestUnit, and Qcumbo. It's not just for unit tests. If you write a lot of Qcumbo tests you know that Qcumbo tests can run quite slowly so you may want to reuse this to split out things a little bit. That is the github link if you want to find out more. Personally, I can't show you what I'm working on but I'll give you an example. You can find out from my github account. I'll share this later on. I created a Rails app that has got over 15k RSpec examples by using a very simple sim link. I created 1,000 sim links to link to the same RSpec file. When I run RSpec in serial it took me 1 minute and 40 seconds but when I reuse this gem in parallel this MacBook Air has got only 2 logical CPUs but it has got 2 physical CPUs but it has got 4 logical CPUs so by default it checks the number of logical CPUs and then just run the test in 4 parallel processes and it took me 1 minute so it's effectively 40% reduction in test time so if you have a more powerful machine maybe you use a MacBook Pro with 8 cores and perhaps you'll cut down the test time even further and that is the report if you are interested in. So at this very special venue, Saint Croix and I feel that force is very strong in you guys thank you very much for listening to my talk any questions? Yes Selenium I'm not entirely sure because it says Cucumber aspect in test unit but there may be other equivalent gem out there that you can use but not that I know of any other question? then if not then thank you very much