Ruby Tutorial | Metaprogramming in Ruby - Dynamic Method Definition

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] what's up everyone steven here from techmaker.tv in this episode i want to take a look at meta programming in ruby and specifically i want to take a look at dynamic methods before we get going be sure to hit the like button if you want to see more content like this and also don't forget to subscribe to the channel we're putting out new stuff every day and i don't want you to miss anything that said let's go ahead and jump into some code so yesterday we created a little program that will analyze some new york city apartment rental data from an app called street easy and i'll link down to that in the description if you want to check that out and what we ended up with was there's essentially uh well there's this debt let me actually make this a little bit bigger there's no reason to have all that scrunched up right now so there's this data.csv file and it's got all of these attributes and then there's about five i think there's exactly 5000 entries so 5000 rows so what we were able to do with this i created this i created this rentals class which includes innumerable and does all this stuff so basically what we can do is over in our terminal if we open up irb and we require oh i hit something wrong there let me clear that again if i go irb and i require rentals.rb here and then we do rentals dot new that's going to put out a bunch of information there and then we'll say rentals equals underscore now what we can do is say rentals dot where neighborhood if i can spell let me just copy this because it's right there about that neighborhood is tribeca and that's to filter for us and then we can grab the average rent off of there and it's going to tell us there's some astronomical amount of rent required to live in tribeca so if we go back over to the code let's look at what's going on here just a little bit so um as you can see the top we're bringing in the csv data right here and then there's this initialize method inside of our rentals class which takes an optional argument of rentals and if there are no rentals it maps through all of the rows and creates a new rental object for each one it's using a splat operator to basically turn the array of fields or the array of data into an arguments list and you can see that we have this giant arguments list over here so i don't really like having all of these arguments like this and it's also kind of a missed opportunity in my opinion because the logic for parsing and loading a csv into objects is going to be basically the same all the time regardless of the csv so what i want to do is use some meta programming to make this happen without needing to declare all of these arguments explicitly so it's fine if that's not perfectly clear to be honest meta programming is not an extremely easy thing to explain verbally so let's go through some examples and hopefully it's all going to come together so let me clear this up and start a new irb session so in ruby you can write a method like this you can write a method like def hello and then puts hello and then you can just type hello and now it's going to puts out hello and then return nil so that's pretty straightforward if you know anything about ruby you know that what you can also do is something like this you can say define method hello to let's say hello2 to get something a little bit different and then we can give it a block and say um puts hello to so that actually returns back a method hello to and we can call hello too now so this may not be perfectly obvious yet why this is interesting so what we can actually do is something like this we can get a let's get an array of strings so we'll just get a b and c and inside of each one of these things let's do this so we can go dot each do letter and then inside of here we can say define method and then we can say letter.2sim so it turns it into a symbol like this and then we'll say do and then here let's just put hello from and then we'll do an interpolation and do letter and then let's end both of those and now we have a hello from a b hello from b and c hello from c so those are dynamically defined methods that we just wrote so what i want to do is refactor all of this so this rental file really doesn't know the names of all of these attributes explicitly i just wanted to figure it out from what it's given and once we're finished with the refactoring we'll be able to grab some other data files so i'll go online and find some other thing and then we'll play with a different data set and you'll see why it's useful to do this so to start though let's just kind of step through this iteratively so i'm going to let's see what we can do is open up this is kind of a esoteric way to do this in some people's opinions so there's this is a side point but let's talk about it really quick so you can define class methods in two ways so you can define a method like self dot method name this is a class method you can also do this class arrow arrow or back arrow back arrow less than less than however you want to call it self and this and then if we wrote a method in here method name these two things are identical whenever i'm going to write a group of class methods and put it at the top of a file sometimes i'll write it like this this i believe is called opening up the eigen class of this rental thing for something related to linear algebra potentially i don't know something about spaces and whatever it's been a long time since i've studied linear algebra so maybe that's not what it is in any case um we're in the eigen class here i think that's what this is called if you know better you can check me on that and leave a comment always happy to get resources but in any case i'll look it up later because i've said it and now i want to know what it is so what we're going to do in here we're going to write a method called for now let's call it define getters we're going to take in a list of attributes and so what we want to do here instead of having to write all of these things out what i'm going to do is write a method in here that says attributes dot each do attribute and what we're going to do is say define method attribute to sim do and then what we need to do is return and in in some cases like this i actually like to explicitly return because it makes the code a little bit more clear it's not necessary but i like to do it here just for making extremely obvious so we need to do is say instance variable get and then what we can do is say at and then attribute so in the case of like rental id this is going to literally translate to return at rental id so what these so ruby has a method instance variable get and another one instance variable set and basically what they as far as i understand they exist for exactly this use case where we have a varying bit of text but we want to be able to look up an instance variable based on that text so this is going to translate into that okay so now what do we need to do over in our rentals class over here the first thing i'm going to want to do is basically say i need to pull the attributes off of this somehow right so i need to say attributes equals and let's see so how can i do this i need to get data zero now we are depending right now on the fact that all of the headers on the csv are formatted properly as ruby methods which is probably on purpose in the data set um but you know in any case what we need to do so we'll need to handle that later formatting text that's coming in that's not proper for method naming so we're grabbing the attributes and then what we can do is just say rental rental dot set what is it define getters and then we'll pass in attributes but we need to give it a splat operator so it translates the array into an arguments list okay and then what we're going to do is just take away this attribute reader so if this works when i go back and reload it in irb we should still have getters and just one point so since we're defining this on the rental class itself on the first time this executes which if you didn't watch the last video i would encourage you to do it just to kind of understand what's going on here but in a nutshell um this is called for the first time without any arguments and then when you call where down here um it looks up some results and then it creates a new rentals or whatever so what's cool is the first time that this is run it's going to define those methods on the class itself so those methods will still exist down here so that's all of that in theory let's go try this so let me quit and clear again irb we're going to require rentals.rb and let's do rentals.new and i got wrong number of arguments given 20 expected one and that is coming from rental line number four let's go check that out so clearly i did something screwy define getters attributes you know what i actually don't need that splat operator um i might need no i think that's really it i think i may have over complicated that a little bit um let's try that again require rentals rentals new so everything's still fine there rentals equals underscore and let's do rentals.first and let's just do borrow and so you can see here that our getters are still working so rentals.first size square feet cool so everything works exactly as it should okay cool so let's see if we can do something similar with the initialize definition so let's write a new method def define define initialize and we're also going to take attributes again and the reason for that is the attributes are actually going to become the arguments list for initialize um so inside of here uh what we're gonna do is define uh not like that define method initialize and we're gonna say okay how do we do this do and then this one does actually need a splat operator and then inside of here so we're defining the method initialize and the splat args here is saying so we're going to back up just a tiny bit here so if we in the sorry here we go so up here on line 6 we define a method but it doesn't take any arguments if we wanted this to take an argument we would say like arg1 and this would be an argument right but this doesn't need arguments down here our initialize method needs to be able to handle an arbitrary number of arguments so let's go ahead and put splat args back and you know what before we keep going because i always like to make sure that we kind of explain things as best we can so let's come in here and let's define a method test and it's going to take splat abcd or let's stick with args we could call this whatever we want in theory and then what we're going to do is say args.each do arg and then we'll put arg like this right so then if we do test we get an empty array if we do test and we do a we get putting out a and then it's returning back an array so we can keep going and so basically put in numbers or whatever so you can see that basically the splat args right here will turn args into an array of arguments simple enough if when in doubt play around in irb and see if you can figure it out so we're basically doing that here but it's kind of got a funny look to it because it's in this do block thing um so what we want to do because the args are going to be this list of arguments coming through what we're going to want to do is say okay when we initialize you got to kind of think about what's going on with the object so this is going to require a little bit of explanation but over here when we call rental.new this is what we're calling with initialize and we're passing in data so it's basically a row of data and the splat d translates that into a list of arguments okay so we got to think about what is happening up here so when we define initialize what we want to do so the args is basically saying like accept the list of arguments provided to you so this is going to be a little bit confusing probably until we see it in person or in person until we see it in on the screen played out so let's go ahead and just kind of work through it so basically what i'm going to do is say attributes dot zip args and what this is going to do and this is essentially what this is going to do is package up well again back to irb it's easier to show than actually explained by be it via saying it so let's say i have one two three and that's an array and i want to basically mix that together with another array if i do.zip and i do a a b c what's going to happen is i'm going to get a new array that is made up basically of mixing the two arrays together bit by bit so think of it like a zipper right like these are the two sides of the zipper and you zip them together and now they're joined so what's gonna happen over here is i'm gonna say attributes. args so i'm taking this raw list of attributes and then i'm taking the argument so i'm going to have like a rental id is going to be in the first slot and then the actual rental id is going to be in the second slide building id is going to be in the next little array and then the actual building id like the number four or whatever it is is going to be in the next slot and then what we're going to do is say zip those together do attribute so now it's a um well let's see it's going to be attribute value like this i think so we're basically saying we can access the first element from the attribute val attribute variable and the value is going to be the second thing i apologize i'm not explaining this very well but let's take a look at what we can do here so if we do dot each do number letter what we can do is say puts number is number and we can put letter is letter and i need to put a pound sign there not a quote and let's see what happens so you can see what happens as we loop through the zipped thing this is our our array that we're looping through and because there's two elements i can declare them like this where this is the first element that's the second element i'm trying to take the time to kind of explain some of this stuff just in case you're following along from the tutorial yesterday and you're really confused because this is significantly more complicated so what i want to do now is say instance variable set and i'm going to do something similar to what i did above i'm going to say at and then interpolate the attribute and then i'm going to give it the value so we're defining a method with the args um so the args are going to be provided um from here so rental dot new and then this uh splat d that's the args so the args are gonna come in we're gonna take the attributes we're going to zip those together with the args and we're going to loop through that zip and we're going to end up with an attribute which we're defining and then a value which we're going to associate with that attribute so yes it does look complicated but now i believe we should be able to get rid of all of that um and make sure i haven't deleted anything i shouldn't and i think that should be good so the only thing i need to do now is say define initialize right here define initialize and you'll notice like when we run this thing we don't really know what the args are or anything like that so when we call define initialize it's just saying hey you should expect to receive some list of arguments and when you do zip those together with the attributes that you get here so this is if you really dig into what's going on it's pretty crazy what's happening but it makes our life a little bit easier so let's go back and let's quit and clear and then open up irb again and i'm going to just require instead of cycling through rentals rb and then we'll do rentals.new and you can see that we have all of our instance variables set and let's do rentals.first dot sub market and so everything works exactly as it did so this is really cool and we have not uh manually hard coded all that stuff but we're not done here so we've got a couple other things to do so let's go over to the code again and let's go down to this average rent method so what i want to actually do is rework this so i want to be able to say uh mean attribute no i don't want the yeah that is what i want just kidding i do want the mean um and let's go ahead and copy in a few things um and get it to kind of work how i wanted to so instead of just always relying on the rent what we want to do is be able to look at an attribute so rentals dot rental you'll see what i mean in just a second i'm not doing the best job explaining things today but what we're going to do this is again this is kind of this is a different sort of it's meta programming but it's a different kind of topic where we're dynamically calling methods so we're going to say rental dot send attribute like that and in here we're going to go ahead and convert this to a floating point number and so we don't need that and so what are we doing so like for example if we pass in rent this is going to say rental dot rent dot to float and then we want to reduce with the plus just like we did above and then divide by rentals.count just like that so i'm gonna go ahead and delete this average rent method okay so let's go try that mean method right so it's quick clear irb um rentals equals rentals dot new and we're gonna do rentals and let's do main rent and we get the correct answer i think let's do rentals dot where neighborhood just try becca and i think that's what we were looking at earlier pretty much i'll have to go back and check but it was something like that so my best understanding right now is that this works as we want so why do we want to do this so if we go back over to the code there's really not anything in here anymore that has to be particularly specific to rentals so this really is more of just like a data parsing library so earlier i kind of worked it worked at this a bit um just to kind of get a decent idea of what i was doing so i'm going to go ahead and copy just a couple of lines from this i'm not going to go all the way to the refactoring that i did that i did earlier today on my own but what i want to do is basically paste those in so what this is going to do is is strip any kind of special characters out of our our column headers and make sure that they're appropriate for being ruby method names and then i'm just extracting this right here into the table so we have essentially attributes at the top and then the actual table of data and then what i want to do here is say table dot map do row so this is a little bit more it's better named i'm not going to change all the naming for rentals i'm i'm actually i think what i'm going to do is roll out a little gem because this this if you take this a little bit further this is actually going to be handy for some of the work that i'm doing on some other projects so i'll make that available if anybody wants to check it out um but what i'm going to try to do is download some other data and let's see what we can find so let's just open up a new window here and let's do a chicago crime data and let's download this data set and just kind of see what happens when we pop it in maybe if it's not too slow okay so 2020 i don't want all of it i just want a little bit of it so i just want this 2020 data i think so let's save this and hopefully this doesn't take very long but i'm going to go ahead and stop the video until it's finished okay so i'm back in my code and i want to make sure i correct one thing really fast i copied this from somewhere else and that needs to be data right there and that also needs to be dollar sign data right there but you'll notice that i now have this crimes.csv i'm not even going to look at what's in there um so really this is a live experiment i don't know what's going to happen here um so let's change that to be we're going to load the crimes.csv now of course all the variables and stuff are still called rentals so that's a problem so we would need to rename all of that but let's see what happens regardless okay so let's just give it a shot i'm going to close the browser because i don't need that i'm going to pull back open eternal quit clear irb require rentals now i don't actually know how big that data set is so for all i know it's giant um and based on how long it took to load that file it may already be loaded in memory so maybe it's fine rentals.new let's see here let's just see what happens it may be too big that's a lot of data so rentals equals underscore or let's call it crimes because that's what it is right crimes equals underscore so we need to rename all the rentals nonsense um in there well it's not nonsense we just need to rename all the stuff because that's not what it is anymore so first of all let's do crimes that count so it's and twenty five thousand um so let's let's actually play around this a little bit so crimes dot first um dot public methods false dot sort so let's see what kind of methods we've got so we've got a rest beat block case number date um and so on and so forth now we don't actually have anything in here to take the average of necessarily um so that's kind of not great um but let's just get a let's just have a quick play with this so primary type battery so what we can do is crimes dot aware primary type battery dot count and you can see that this is pretty quick actually to just do some math on this stuff so um let's see we might as well just play around with this a little bit more since we've gone to all the trouble um crimes dot uh map and primary type dot unique let's do dot sort sort that's what i meant to say um so arson there's a quite a lot of stuff actually um weapons violation robbery um what do we want to look at deceptive practice homicide let's see how many homicides are been so this is going to be dark primary type is this is in 2020 so far and today is like august something 2020. so 472 homicides so far this year so yeah anyway so um i think that's about it i mean that's everything i wanted to cover like i was saying i'm gonna i think we're gonna play around with turning this into a little library um so we won't have rentals anymore it'll be something else but uh in any case i think this is kind of cool so i don't know what numbers i was thinking that dataset was going to have but i was hoping to have something where i could use this mean method but what i think i'm probably going to do is like actually work out a bunch of like kind of stats like basic stat stuff and get in here and um yeah maybe it'll be like a really simple version of something like pandas in python um and before anybody tells me yes i know you can use uh pai call and pandas in ruby and i've done that quite a bit so um and it's great but honestly deploying that stuff in production was a gigantic headache so if you don't need all of that um i would think that something like this if it works would be nice and there's probably already something like that but you know i'm building it for my channel so why not at any rate i think that's going to be it for me for today um so as always if you like this video please give it a thumbs up and if you haven't uh you've watched up to this point so you have to like me a little bit so go ahead and subscribe to the channel if you haven't and i will talk to you in the next episode tomorrow
Info
Channel: Techmaker Studio
Views: 3,212
Rating: undefined out of 5
Keywords: ruby tutorial, metaprogramming, metaprogramming ruby, learn ruby, ruby programming, ruby for beginners, ruby programming tutorial, learn ruby programming, ruby tutorial 2020, learn to code, ruby programming language, ruby course
Id: bg2KvfwxDnM
Channel Id: undefined
Length: 30min 31sec (1831 seconds)
Published: Tue Aug 18 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.