 I'm going to give some people time to, I got the deck up and if you can download it if you want to follow along, but my name is John DeWise, this is my meta-moments which is a talk about my process of learning metaprogramming, a project I worked on, the concepts I needed to learn to work on that project and just kind of how to use them, how to start hacking away. So I'm going to jump to the bottom of this slide first. I have different code snippets and we're going to move through them and so if you want to see them in their entirety and be able to go back if you go to speakerdeck.com DeWise, my last name slash meta, you can download the PDF or you can just follow along. So if you move on it's my last name slash meta. So I've been a software developer at Braintree in Chicago for two years, that's about how long I've been a dev so this was a talk about I wanted to learn metaprogramming and how that came about. My GitHub is at DeWise if you want to check me out there. Required disclaimer, the views expressed in this presentation are my own and not those of PayPal or it's affiliates like Braintree. This is my first time speaking at a tech conference so I want your feedback, my hope is I spoke slowly enough, I explained topics clearly without making us too many assumptions about what people knew, I used language that was inclusive and welcoming and most importantly that you got something out of this. I'm open to compliments or criticism so if you're willing to share please find me afterwards, I would be grateful. It's not really anonymous feedback but if you hide your name tag I can't see who you are and that's kind of like anonymous feedback so that'll work. What is metaprogramming? So to start I'm going to describe some summaries and uses of metaprogramming before going into kind of the tools you can use. I know I hate it when I start going to a talk and a few minutes in realize I'm missing some basic information and too embarrassed to leave so I just sit there and nod periodically. I've tried to briefly describe any topic I talk about in case you are pretty new to some stuff I'm sure I'll miss some spots so feel free to find me afterwards if you have more questions. So what is metaprogramming? I thought about using the Wikipedia definition but that's boring when you do that. It's long and encompasses a lot more than I'm going to talk about so I'm going to talk about some ways that I view it which are not official but especially when you're learning I think they're kind of useful. The first is writing code that writes code. This is sort of a lazy definition but the idea is that you can write code in such a way that new behavior can be added at runtime or compile time. So one example if you've ever used factory girl for creating objects and testing when you have different parameters those are actually methods that you end up getting called that aren't there at time using some of the metaprogramming tools available to you. It's also writing code with incomplete information. I'll talk about this a little more later but for example if you've ever used one of these Rails magic methods fined by column name the way that is implemented is with imperfect information and we'll explain that kind of later. Finally writing code really efficiently so if we were to take this bit of code we have a user we get all the methods on the user and look for all the methods that begin with validate and then we're going to use send which we'll talk about as a way to call those methods. So these three lines can actually call a ton of lines of code without having to know what methods we're even calling. Before we go any further I want to talk a little about the perils of metaprogramming. When I told someone I on the plane I was doing the metaprogramming talk they asked oh are you just going to tell people not to do it? Not quite but there are a few caveats to be aware of. Metaprogramming can produce a lot of unexpected behavior so if you use this for example if I didn't see this call and I added a method I could be calling something that I only want to call in a very specific situation. It can be hard to test. You can be doing stuff manipulating the way the code works manipulating inheritance and ancestry that it can be sometimes hard to test without doing some really ugly stubs and mocks that are not great. It's slow if you don't know what the method cache is it stores methods that get called commonly to speed up the process and every time you add new methods you invalidate that cache. We all know what it means to invalidate a cache it's really hard to deal with. And finally metaprogramming is meta. It is clever. It often requires knowledge of the surrounding code and possibly other unseen interactions to work well and almost always clever code is the wrong code to write. It can increase the burden of other people jumping into a code base and often the more clear and readable solution even if it's going to be more lines and it's not elegant is probably the better code. That being said there are also some perks. It's efficient. So going back to that validate method I can call hundreds of methods with three lines of code. I don't need to worry if someone adds validations I know they're just going to get called. It's powerful. It can allow you to again change the behavior of a class change the way classes inherit from each other to a certain situation but not another one. You can manipulate the code base in very useful ways. I think the most important thing is it's fun which is why if you're new and someone tells you don't to not metaprogram you should metaprogram. Don't commit it to production but play around have fun enjoy it. Ruby allows some really powerful stuff that you can do and I think the curiosity that you use to explore metaprogramming should be fed and should be something that's exciting to play with. So my final caveats I think of it it's kind of like Spider-Man with a lightsaber so if you are familiar with Spider-Man or not Uncle Ben has these words with great power comes great responsibility. If any of you are like me when you were a child you probably pretended a cardboard tube with some sort of lightsaber and you learned a few lessons. Lightsabers are fun. If you actually had one you probably would have cut off all of your limbs by now. But if you have one and you haven't cut off your limbs and you know how to use it that probably means you're a Jedi which is also pretty cool. So with that I'm going to start with introducing something I call putter. It's not putter despite the picture but I'm inevitably going to mispronounce my own gem throughout this so I'm just going to go with it. I'm going to show how the gem what it does and then all the metaprogramming tools I learned and then how they got used to build this gem. It's a little bit of shameless self-promotion but I think it's a lot easier to understand concepts when they're inside of an idea inside of a you know set of code as opposed to just talking about them. So putter is a puts debugging gem. If any of you don't know what puts debugging is it's the really fancy you know advanced method where you just put put statements everywhere to figure out where you are in your code and what is going on. Has anyone else written this one before? What's my arg so you can find it at github.com to wise putter and despite the fact that I have a putter in the background it rhymes with good or not gutter. So this is a little script that uses putter so we are going to grab it we have a user class we're going to make the username read writeable initialize with a number. The username is going to be user underscore whatever that number is. We're going to find two methods they're just kind of wrappers around the built-in Ruby ones uppercase and lowercase and we're going to close them. You'll see me throughout this I use a lot of semicolons instead of new lines because that way the code can be bigger so I assure you it works it's just a way to kind of write the code a little more succinctly. After that we're going to call putter.watch there's two apis watch and follow we're going to use watch here and we'll talk about both later. We'll have a user's array and then zero to four so we'll have five users we'll create them all we'll put each user into our array and then we're going to call uppercase on that user then we're going to go through and get all the even numbered users so zero two and four indexes and we're going to call lowercase. What happens is you get this and I'll do a zoomed in version on the next slide we're going to be able to see these are some snippets in the top you see that on the user class at line 15 of watch I called the new method I passed in zero and the result was a user the next one is the first instance of user which is the one I just created on line 17 I call uppercase with no args and I get user underscore zero and capitalized and then from the bottom user instance five which is actually index four on line 20 I call lowercase so what you can do with putter is you can use some integration test or some sort of test at the outside of your code you can watch a class and you can see every single place where that class is called any class method is called or any method is called on an instance of that class what file it's called in what args was called with and what the result was I use this when I wanted to understand a code base that I had never seen before and I needed to follow one path this will tell you a giant output of all the methods that gets called through that putter also has some configurations to ignore methods from active record and object or if you want to learn how active record works active record calls id and class a lot I had no idea so I added some ways to ignore that but it's kind of interesting to see all the different things that rails does under the hood you can use this to do here the topics we're going to talk about as far as the tools and then we'll use them I'll show how I use them in putter I'm not going to read these right now but we'll go through each one some are more strictly meta than others but they all can be useful and if you haven't seen them before it's kind of important to have these tools at least under your tool belt there are other ways to do meta programming there might be right ways that I'm not discussing additionally I'm probably going to lie to you because when it comes to meta programming there's a lot of edge cases some that I found and some I haven't found yet some cases where self changes depending on what method you're in it's easier just to tell you what's going to work 90 of the time I encourage you to play with it and find those edge cases for yourself but just know that meta programming is fun but dark and full of tears so first up is send sends an extremely powerful tool is one method to call them all send will invoke a method it'll call a method using a symbol or a string of the method name it also lets you call any method so if you've ever heard of ruby that there's no such thing as private methods it's because you can use send to call anything so let's take a look at kind of how that works so i'm going to be using the pry gem here which is kind of like irb just open up a random like ruby session rebel so this is using pry and ruby 231 most things if you do this will be similar i removed a couple lines where if you define a method it returns the symbol of the method name just for ease but for the most part you can follow this code along if you want to type it yourself to see what happens we'll define a method called send me it'll let us know it was sent and we'll close it up we'll create a new instance of our sender we'll send send me and we'll see that it was sent so you can see that we can just call a method using send and if that method name were a variable that we didn't know we call methods we didn't know about next is inheritance i know most people are probably familiar with inherits a truck is a type of vehicle most of our users probably inherit from active record you may have heard the is a trick so if something is a something else it inherits if it behaves like it you know will implement and depending on what language you're in those are interfaces or whatever um so because of this like any vehicle a truck can drive it has a make and model but it's a little different because it can tow a user will have save or update attributes that come from it as a part of active record okay so that part i think most people have seen before but what i didn't know about inheritance is when you use include and extend you're actually dealing with inheritance this is changing inheritance i used to think this was composition because i was i was composing modules i was adding them in there was no less than signed inherit from but that's wrong it is definitely inheritance so if i have a television that extends broadcastable or includes watchable um it's actually inheriting from those that will change the inheritance chain so we can take a look at this one too we have a parent we'll have a parent method it's gonna say i'm parenting close that we have a child uh we'll include the parent and we'll define that parent method again and we'll just call super so because it's inheritance i will call whatever my superclasses version of that method is close it create a new child which is much more complicated than just doing this but we'll call parent method on it and we'll see i'm parenting so to explore that a little more we'll get into ancestors so how the heck do you know what you're inheriting from well we can look at the ancestors the ancestors method will show the inheritance chain and the order that it happens in almost all objects inherent from object if you've ever seen that object also will mix in kernel which is where puts comes from our chomp and eval that get included in and in the end all objects inherit from basic object which we'll talk about a little later finally the last module that gets included is the first parent so we have a grandparent we have a parent we have a child we'll include the grandparent first because they came first and then the parent close that up and then we'll take a look at the ancestors so we see our child and even though we include a parent second it's the first one we see and then grandparent comes next you also see object because we inherit from that the pp object mix in is for pretty printing it's included by pri if you were using irb you would not see that uh then there's also kernel which is where we get puts and then basic object now we're going to talk about prepend again this is not necessarily a metaprogramming thing but it can be used to do some cool metaprogramming stuff prepend functions like include except it put something before itself so you know append prepend and you know javascript it can be useful for things like proxy modules because you can actually prepend a module whose methods will be called before the class that they are prepended in and we'll see that a little later so let's make a proxy we'll have a proxy method it's going to tell us it was proxied and then notice we'll call super again i apologize for the semicolons but we're going to call super on this we'll create a test class and we'll prepend proxy to find that same method letting us know that we got here because that's how you debug create a new instance of our test and we'll call proxy we'll see first that we get proxied from the method in our proxy then we get to get there so as a result we can create things that interrupt methods and do stuff before they get called so if we were looking at the ancestors of our test class we see that proxy is now actually sitting in front of the test class itself so it's a really powerful thing that you can do to be able to stop methods interrupt them modify them as they're in flight next up is method dispatch so what is that method dispatch is the way that ruby determines what method to call there are some really great diagrams with this i didn't want to steal them so if you google method dispatch of ruby you'll see them but the idea is it'll search the ancestry train going up that list of ancestors and the first one that implements the method it will return that method so we'll take a look at how ancestry works i was trying to think of an example of something where the location of something changes and i thought a good example would be figuring out who owns my student loans so if you don't know sally may they're now called naviant so we'll have a naviant loan and a sally may loan and sally may will include the naviant loan close that up well the u.s. government loan because i think they had it at one point i don't know they might still to find an owner method they'll let us know that they own the loans we'll create a loan class which includes the u.s. government loan first and then sally may but notice not explicitly including naviant we'll close that up so now we're going to take a look at when we call this owner method and change it what happens we create a new loan have our instance we call owner and we see the message that the u.s. government loan had will create a naviant loan to find owner and if you didn't know this you can actually reopen up modules and classes add methods to them at any point rails will do stuff if you've ever used the present method you can open up the nil class that or the true class or the false class or number classes so you can add your own methods to anything this will say your loans have been sold and we'll call owner on it now and now our loans have been sold just by adding that method to the naviant loan so now we'll take a look at the ancestors so we see first is the loan then the sally may loan because we included that first but that also we include then the naviant loan because it was included by sally may which will be included before the u.s. government loan so the more often that you have things included that actually changes your ancestry train can change it a lot because you're including everything that gets included by everything else so what does this have to do with metaprogramming none of this really has been metaprogramming so far i promise we're getting there but you know knowledge is power so now we're gonna get on to some of the cooler stuff that you can actually do starting to use these tools method missing method missing if you haven't seen it before is defined like this it is called when a method cannot be found so if you've ever had a method not found there it typically means that method missing was not defined anywhere in that method dispatch chain so remember those ancestors the first method missing that is defined in the first ancestor that it finds it in will be what is used it has access to the method that was called the args passed into it and any blocks that may have been passed in if you haven't seen the ampersand block symbol uh root any ruby method can actually implement this that you can pass a block to any method you don't have to have it so we'll take a look at how to use this we have a parent we'll define method missing on the parent which we're going to ignore the block for now and when we do that we'll put the method and the arguments that we get we have a child which will include the parent then we'll do child new and we'll call do stuff and we'll pass and things notice we didn't define do stuff anywhere but what we get is method do stuff and the args are and things um and you'll notice that we get an array because that star args if you haven't seen it before splat args is a way to kind of close up any unknown number of arguments so if we would have had 10 arguments or three it you know combines them all into this one array which is why we see an array of the two arguments that we passed so this means anytime a method doesn't exist we can change behavior we can make it exist and we'll see shortly we can write code with incomplete information so a more complicated example uh you may have all seen again active record defined by a magic methods we're going to make our own version we're going to call it lazy record because it's not going to do much we'll have a method missing i use m this time just because i needed screen real estate if the method name matches find by underscore we're going to take the trait all this does is whatever comes after find by underscore it's going to grab that thing so if we did find by name it would be name find by username it would be username etc and then we're going to call self dot where and this i'm going to pretend is the same as an active record call we can call where with kind of some pseudo sequel and we're going to pass whatever the first argument passed to the method missing colors now we don't have where to find so we're going to make a fake where it's going to tell us it's doing a database lookup and regardless of what we send it's going to return to make emails and close that up so now we're going to create a user we're going to use this we have a user that inherits from lazy record we're going to find by name mickey so we're doing our database lookup now i didn't put this out there but this is basically what we do if we have this where method that can do a sequel search it's going to do something like that and it's going to return mickey mouse again to be fair if we did find by zip code we would also get mickey mouse so this isn't very helpful but if you were backed up by a database or if in any case you wanted to respond to methods that were somewhat dynamic or helpful you can do that i think active record has since deprecated the find by magic and there's actually one now find by method that takes arguments but you still may have seen this before now we're going to talk about define method we're starting to see some of the more powerful things we can do so in addition to responding to methods that don't exist we can create methods that we want to exist explicitly whenever we want we use define method it's a way to define a method with via another method so you don't need to use the def command you can actually do not even use the def command this can be also used in classes you can create methods whenever you want like on method missing you can create a new method and ultimately this takes a method name and a block and the block is the body of that method so we'll have a define class we'll define method missing and we'll say that if that block was passed in that means someone wants a custom method so we'll define it we'll do self.class.send and the reason we do self.class is because methods can't actually do they can but for this purpose they can't be defined on an instance so we're going to define it on the class and we're going to send define method it's a private method so we have to use send the method and the block that's passed in if there is no block so they didn't pass this a method body we'll define just a hello method self.class.send we'll call define method again and we're going to pass our own block so that's what the do is if you aren't familiar with blocks or I mean you've all we've all used them each do but if you haven't been familiar with how they work it's a great use of a weekend to kind of dive into how they can be passed around and you know they're like callbacks and javascript was something that kind of helped me uh that's not really an accurate definition totally but I encourage you to explore it more we're going to close everything up we'll create a new instance of define we're going to call world we'll see that we didn't pass a block so we're just defining a hello method and we'll call it again but now instead of defining it we actually have a method that's going to say hello world if I called it again it would the same thing would happen if we pass a block in we're going to revolt and pass an argument it's going to let us know it doesn't want to say hello whatever so close that up now it's going to tell us we're defining a custom method now if I call it again notice I'm not passing a block this time because I don't have a method body but I'm going to pass an argument it'll say I don't want to say hello world so you can actually define new methods with blocks that are passed in by the user you can define new methods with things that you want um being able to define new methods when methods don't exist or for other reasons gives you a lot of flexibility basic object basic object is the source of all objects it only has a handful of instance methods which makes it very useful for metaprogramming here are all the instance methods that exist on basic object all the public ones three of them begin with double underscore they're you know kind of private internal methods we're going to take a look in a little bit at instance evon exec but you see that this is mostly a blank slate almost to work with it's also the source of the method magical method missing as well as initialize those are private instance methods on basic object object has about six 56 methods or 63 if you're in pry and then basic object has I think was nine so it kind of tells you like how small and uh paired down this is versus the normal object you interact with singleton classes a singleton class might also be called a metaclass it might also be called an eigenclass to my knowledge there's not universal agreement on this there might be but people like to argue about what this is called so i'm gonna call it a singleton class the way to view it is it's a class that it itself is an object so it's not an instance of a class in it it is the instance of the class it's not like user.new so a class method is actually just an instance method on the singleton class so when you have a class user and you have an all method that gets all the users you have user.all that is actually a class method but it's an instance method on the singleton class um this is one of the harder concepts at least for me it was a little bit harder to grab but it's the idea again that that class is its own instance and we'll take a little bit of a look at it we have a greeter class says hello you can do self.hello which is i think what mostly we will see for class methods you can also define it on the class and do greeter.high and if you've ever seen this before this is actually a way to say i want to open up the singleton class and i'm going to put methods on it so i'm going to define yo but notice i don't need self and i don't need the class name close that up call hello hi and yo and if we look at the singleton methods on greeter we'll see the three ones that we defined so these are all again all class methods but they're methods defined on the single methods defined instance methods on the singleton class another way to look at it would be if we look at all the methods which returns class methods on greeter and we subtract away all the methods on object we'll see this or take greeter we get the singleton class and greeter and the instance methods on that and get rid of all the class methods on object again we see this so when i said you can't define a method of an instance you can't but you can because you can actually get a singleton class on an instance instances can have their own singleton class which is kind of a copy of the parent class that they have but a copy that can be modified and when you modify it it only affects that instance so we have a thing look at the singleton class a thing instead of saying thing like now we see kind of the ruby hashtag and then in carrots if we look at an instance of thing you've seen this before too now if we look at the singleton class of that instance we'll actually see like a it's not on a string but a you know line that looks very similar to a combination of those two and if we look at the ancestors of that singleton class on the instance we'll see that that wasn't supposed to that thing object and all through basic object um instance eval so this is the last thing we're going to talk about before we get into how putters put together there's also instance exact which we'll talk about the difference shortly this is a way to eval code in an instance or a class kind of if you've ever heard of ruby eval or don't use ruby eval it's a way to kind of evaluate code um one thing i that i apologize it's not a method eval does not take a method it actually takes an object it does not take an object an exec does so we'll take a look at whether or not you use which and why you might pass an object in so create a spy class new it up and we'll store some secrets the secret apple pie recipe inside the spy to create a new instance of spy and we get those secrets see we have an undefined method secrets because there's no public getter for that we could use this really ugly method which i would not recommend using but you can do instance variable get to see the instance variable when we see our secrets but there's another way to do it we knew up a new spy and we can do instance eval and put at secrets we see our apple pie recipe because this code is actually evaluated inside that instance and inside that instance at secrets is a method that you have you know a special way to get that instance variable so this is a little contrived so let's look at maybe a better example which was also contrived but still useful we have a neo class kiana will be our instance of neo so we have this instance now we're going to do a class exec so instead of eval exec and we're going to pass something in in this case we're passing just a method but you could actually pass an object full of data to do various things with and we're going to give an argument to the block which is that method we passed in or the argument we passed in we're going to define a method which is going to be trained in this case kiana is going to let us know he knows kung fu close it up we call it kiana dot train kano say i know kung fu so we will actually add a method to the class using the defined method and add behavior arm with this ability being able to pass the variables user input we can modify a class whose name we don't know add a method whose name we don't know and if we pass around a block our proc we can define a method body that we don't know so it's some pretty powerful stuff if you build stuff in such a way that you can take advantage to it so i'm going to show you what i did with putter to use all these tools to kind of create my puts debugging gem so first we're going to look at the method follow so follow takes an instance it can also take a class but more commonly you'll use an instance and what it does is it creates this putter follower object which inherits from basic objects so this follower has almost no methods on it and we store the user object the instance uh as an instance variable so we have this follower that is the result of putter.follow uh we saw that and what we'll do is we'll create a new proxy we're going to take our instance and we are going to get the singleton class of the instance which lets you again define methods just on that instance and we're going to prepend the proxy so we end up with something that kind of looks like this we have a follower object the wraps the user object that has a proxy that sits in front of it so we're going to call follower which is our wrapped instance i want to say do something with stuff the first thing that's going to happen is we're going to hit the method missing call in the follower object again it's a basic object so it has nothing on it unless you were to call instanceeval or exec you're going to hit this and on that method missing we're going to determine first if we should add the method to the proxy now we could have skipped this step but putter has some configuration where you can blacklist or whitelist methods or ignore methods from object or active record to kind of create down place of noise so that's why we do that but you could skip this part so we have our add method then what we're going to do is we have this data object and we're going to take that proxy and we're going to do instance exec we're going to pass that data in that data has information about how to print it has information about the method that we're calling we're going to define a method with the method that's stored in data then what we're going to do is we're going to call result equals super so what we're going to do in this case since it's a pre-pended proxy it's going to call super which is whatever method was on that object the method we were trying to call to begin with the only catch is we're going to store the result then we're going to put log info which you can actually configure with a proc you can configure it to print anything and it includes the line number it figures out where the caller is coming from and then we'll return the result so as if what you called was returning the result anyway then if we have already added the method you might hit the else either way what we end up doing then is we called to do something with stuff and then the user object and then as far as your code is concerned it got the same thing back the only difference was it printed out to the screen information about what just happened so the other side of putter is watch so with watch we have this watcher class which actually holds kind of a singleton-esque registry where the key is the singleton class of a class and the value is that data object full of methods and stuff and we'll have a user class so we're going to say putter watch the user and then what happens is this we open up the singleton class of user and we're going to prepend an instance follower describe that in a second and the result of this watcher build proxy now because we opened up that class if you see the self there that self is referring to the singleton class of user so we're now defining things on the singleton class so we can first build this instance follower normally when you create a method that allows you to change initialize or that allows you to new up an object we use initialize because new actually deals with memory allocation so what we're going to do is override new kind of we're still going to call super new because I don't want to mess with the memory allocation but the object that comes back from that we're going to store in an array of objects so we know how many are being created and then we're going to call putter.follow on that object so that object that now gets created is actually a followed object that is printing along and we've set a label to be the instance number of whatever that array size is so now we're both getting our class methods and instance methods followed putter watcher is going to build a proxy with the singleton class of user which is what self is so build proxy looks almost identical to what we did before the only difference is we're going to call proxy methods on user which is a method that putter adds that again checks the methods that are whitelisted and blacklisted and it checks the existing class methods on the user it does not if you were to add methods to user at runtime it would not get those there are hooks in Ruby you can do when a method's added if you want to add a pr to a putter to take care of that you're welcome to and then we do the same stuff we define a method we get a result of the super class and we put the info and return it so that looks something like this we have this object which has a proxy with for the methods that are proxied an instance follower and a user class so we user do something which in this case is a class method he's going to call do something on the proxy in this case it won't do anything with the instance and then it'll call do something on the user user.new is going to actually return this and let us know that we called that new method so somewhere of what this does we use method missing to call send with instance eval inside of define method we also prepend a proxy that calls super but puts a bunch of information and we're also able to override new which follows all instances so what do we do with all this stuff metaprogramming in ways like learning another language another programming language so if you're out like me you'll go learn elixir or node or haskell or whatever and then you sit there thinking I really want to make something but what I made this there's a lot of power and cool stuff that you can do with metaprogramming so you can contribute to things like rails or factory girl or you can contribute to putter it's my first open source project so I will be very nice because I don't really know what I'm doing so if you're looking for something to get into but you're afraid of people being mean I'm just as cool as PRs are welcome so I made this what will you make here's some resources I used there's an article by Thoughtbot called writing a DSL in ruby it's kind of a slim down version of how factory girl is implemented which taught me a lot about how metaprogramming can work ruby under microscope is a great book which has been mentioned at a couple other talks it talks about how ruby is implemented kind of at the c level at the vm the first three chapters if you are like me we're a little rough because they did talk about the vm and some of the c implementation which was over my head so if you get to that point you're like I don't know if this is for me you can skip the first three chapters read about the other stuff and then when you kind of got you know more experience under your feet go back and read them because they're really great and metaprogramming ruby 2 is just a book about metaprogramming and it's also fantastic it goes over a lot of this in more detail it's really useful here are all the photos I used thank you flicker and finally hopefully you have some tools to start meta hacking away I'll ask for questions I'll probably do a couple and then if anybody has questions I'll also just kind of stay up here if you don't want to ask in front of a crowd otherwise have a great RubyConf are there any questions yeah it difference between instance exec and instance eval right here you see instance exec takes this data object in so instance exec can take an object or it takes really just an argument which you could then use to load up with a bunch of data instance eval doesn't you wouldn't be able to pass anything into instance eval so it's a way to inject something from the outside world from the outside environment into that environment where you're eval is the singleton class related to the design pattern of singletons not really a singleton design pattern would be if you have one object and every time you hit new it always returns the same object wherever that's called kind of the idea that there's just this one version of that object that's also a very lazy definition of singleton design pattern but it's a way to just kind of guarantee that if I'm using a registry or a store it's the same everywhere the singleton class is not really related to that it's the idea of just that class has an object so I'm gonna stop now if anybody wants to come up and ask questions happy to take that otherwise have a great day thanks