Metaprogramming

Summarized using AI

Ten Things You Didn't Know You Could Do

James Edward Gray II • October 09, 2012 • Earth

In the video titled 'Ten Things You Didn't Know You Could Do,' James Edward Gray II presents an engaging exploration of lesser-known features in the Ruby programming language. The talk aims to uncover unique and useful functionalities that even experienced Rubyists might not be aware of. Gray introduces a variety of topics, breaking them down into practical categories and showcasing how these hidden features can enhance coding efficiency and creativity.

Key Points Discussed:

  • Compiler Tricks: Gray explains how Ruby can execute code with the -X switch, the use of the special IO object 'data,' and how Ruby can treat anything under underscore underscore as ignorable junk.
  • Tail Call Optimization: He discusses Ruby's tail call optimization, which is off by default and how users can enable this feature for improved recursive method performance.
  • Syntax Shortcuts: Examples include the usage of super to pass values to parent classes, and how blocks can now take blocks, enhancing metaprogramming capabilities.
  • Regular Expressions: Ruby 1.9 introduced named groups in regex, allowing developers to refer to groups by name, simplifying pattern matching.
  • Data Structures and Methods: The ability to create nested structures, utilize hashes efficiently with the 'fetch' method, and methods like 'zip', 'chunk', and 'flat_map' to enhance data manipulation.
  • Standard Library Features: Includes discussions on the 'open-uri' module for reading web content like files and the usefulness of 'fileutils' for file handling tasks.
  • Meta Programming: Gray highlights the construction of classes and modules programmatically, and techniques like methodmissing and respondto_missing which allow for dynamic method definitions.
  • Debugging Tools: He demonstrates using the 'tap' method for easier debugging, handling errors in threads, and the importance of employing garbage collection profilers.
  • Practical Applications: Finally, Gray shares whimsical examples such as creating infinite loops and using Ruby's commands for process handling.

Conclusions:

Gray concludes with the importance of understanding these Ruby features not just for technical excellence but as a way to impress peers in programming communities. He emphasizes that knowledge of these extras can significantly improve efficiency in Ruby programming and encourages viewers to explore these features further, sharing that slides will be made available for deeper study after the talk.

Ten Things You Didn't Know You Could Do
James Edward Gray II • October 09, 2012 • Earth

There's a lot to Ruby and even experienced Rubyists are sometimes surprised to learn about parts of the language they haven't encountered before.

Do you really know all of the syntax Ruby can read? Are you familiar with all of the methods provided in Ruby's core? Have you used all of the roughly 100 standard libraries?

In this talk, I'll dig into the extras of Ruby and see if I can't turn up some features that you don't see all of the time, but that might just be handy to know about anyway. I'll make sure you come out of this able to impress your friends at the hackfest.

Help us caption & translate this video!

http://amara.org/v/FGfq/

Aloha RubyConf 2012

00:00:15.519 All right, are we ready to get started? This is the most ridiculously Hawaiian shirt I own. It seemed kind of fitting for giving a talk in Hawaii, right? How about it? I even saw it in a store after I got to Boston University with the exact same pattern, so I think it counts.
00:00:34.079 For those who don't know me, I'm James Edward Gray II, the guy that says 'awesome' all the time on the Ruby R podcast. This is my first time in Hawaii, and it's pretty great! Right before giving my talk, I was sitting outside near the beach, watching the surf. How come we're not out there? That's what I want to know.
00:00:53.079 This is actually the second talk I have given in what is kind of a related set. At RailsConf this year, I did "10 Things You Didn't Know Rails Could Do." If you caught that talk live or online, you know I didn't actually cover 10 items; I covered 42 things you didn't know Rails could do! In hindsight, that was a really silly mistake, as I still had this talk to present, and I assume you're not going to let me get away with just '10 Things You Didn't Know Ruby Could Do.' So, I guess we have to go to at least 42. Is that the minimum you’ll accept?
00:01:15.360 But we did come all this way, and here we are in paradise, so I want to make sure everybody leaves this room learning something new. What do you say we up the ante a little? You think we’ll find out? By the way, if you're one of those people who takes notes, you're about to have a very stressful 40 minutes. You might just want to let this one go, but I’ll throw my slides online afterward so you can catch up.
00:01:50.159 Everything I’m going to show you has been tested with this Ruby, so it works on this Ruby. Most things will work on most Rubies, but there are some exceptions. I'm going to break these down into categories, starting with compiler tricks. Did you know that this is actually executable Ruby code? It really is! If you pass Ruby the -X switch, it will ignore everything to the shebang line.
00:02:24.280 By default, Ruby will already ignore everything under underscore underscore, which means all junk goes away, and it will actually run your code. That 'end' token is a special deal in its own right. When it’s in your program, Ruby opens an IO object and points it at whatever comes after that. This is the special IO object called 'data,' and then you can read or perform any normal IO operations with it.
00:02:58.560 You can even use that to do dirty tricks since it supports any IO operations. You could rewind back to the beginning of the file. Eventually, you'd be looking at your code instead of the data, so you can cheat to make a client there. I actually use this trick quite a bit with the data object, and you can grab a lock on 'data,' which makes your program exclusive. Only one copy of it can be running at a time.
00:03:35.720 Just remember to leave that end token in there because if it accidentally gets deleted, your program won't run correctly. So, you might want to put a note about why it needs to stay there. You can see how it's exclusive; I can't start a second copy until I show the first one.
00:04:12.360 Another trick I've used occasionally, which probably isn't as good of an idea, is that you can store data down there since Ruby opens it to the right position. You know where to truncate the file to cut off the end of it, and then you can write the data back out. The cool thing about this trick is that the data travels around with your code, which is kind of a neat trick in scripting.
00:05:12.360 Ruby has gotten pretty good at telling you what's going on. You can ask for the AST (abstract syntax tree) that it constructs. If you want to see if it read something as a block or a hash, here is the actual method call. It’s hard to tell what these nodes are if it’s treating that as a block or not. However, there's another option you can ask for—the parse tree with comments.
00:05:48.159 Then it has these really helpful comments, explaining that this node means it was a method called with a block. It actually explains it to you, which is nice. You can also ask for the instruction sequence that the virtual machine reads. And if you're really curious and want to see how parsing works, you can get Ruby to show you its parsing through your code. This is probably only useful if you're working with Ruby itself, but it’s still kind of neat.
00:06:07.319 You might think that Ruby doesn't include tail call optimization, since it can't run code like this—it just blows the stack. That's not wholly true; Ruby does include it, but it’s off by default. If you turn it on, you’ll also want to turn off tracing instructions because that’s what tail call optimization interferes with, which is why it’s off by default.
00:06:38.440 You need to make sure your code gets compiled after you've changed those options. Here, I tucked it in an eval to make that happen, and then you can get tail call optimization, which runs this code quite quickly and spits out a very large number.
00:07:02.760 Okay, let's talk about syntax. I love 'super'; it's my favorite keyword in Ruby. Here’s a really simple example. You can use it to pass up whatever you want to the parent class. So, even though I have variables B and C, I'm only passing up A and B. If you leave everything off of super—no parentheses, no arguments—then everything gets passed up.
00:07:38.520 I imagine we all know that—it’s a pretty common usage. Everything goes up, including the block. Here’s a gotcha: if you modify those values before you use that bare super, and this first example is probably not surprising; just calling some mutating method, but even if you reassign a variable before calling super, all the modifications go up.
00:08:06.960 If you use an empty set of parentheses on super, then you can purposefully pass up nothing, no matter what you were given. And here’s a trick: if you need to get rid of the block while still passing a block but don’t want to pass it up to the parent class, you can use the ampersand (&) to essentially pass an empty block.
00:08:21.920 There’s a bunch of cool tricks with super! There's another trick you can combine super with another awesome keyword called defined? Ruby will tell you if there is a parent class method you can delegate to, so you can see, "Oh, there is a method; I’ll use that," or "No, I need to handle it myself." This works really well with Mixin.
00:08:50.080 There’s a new lambda syntax from Ruby 1.9, the arrow operator. This is what a normal bare lambda looks like; this is the full version with default arguments and blocks and all that. The gotcha here is to remember that the arguments move outside of the block, which is different from normal Ruby syntax.
00:09:14.240 If you don’t like that, you can turn on Ruby’s UTF-8 source code mode, which allows you to use UTF-8 characters, redefining Lambda as the actual symbol, so you can call the actual symbol of Lambda if you want. That's pretty cool.
00:09:42.640 Blocks can now take blocks. This is mostly useful in metaprogramming when you need to define methods programmatically or something like that, but we can have blocks take blocks, which can sometimes be hard to get your head around. However, when you're defining methods, it's really handy.
00:10:10.080 There's a new call syntax: if you just do the period and then your argument list, after that, these are all empty, but you can actually pass arguments. It will call the call method, so that’s useful for lambdas and method references, but for any object you define, as long as it has a call method, the syntax works.
00:10:44.560 Symbol to proc is worth noting because it takes arguments. The first one is the receiver of the call, but everything after that is part of the normal argument list. Thus, the proc that it builds can actually take additional arguments.
00:11:16.360 You may have heard of this from Ben's talk yesterday: you can drop the ampersand with inject because inject is now smart enough. If you pass it a symbol, it assumes that’s the method you want to call and uses that to build the block.
00:11:56.840 Case statements are intriguing because we can use anything that responds to the '===' (three equals) operator. One cool thing that does that is 'range'! You can use it to slot things into categories just by defining some ranges. If you're going to do that, an excellent application is with dates.
00:12:36.920 Creating a date object will give you the beginning of time, and date: infinity will give you essentially the end of time, so you can slot things into date ranges to determine whether you're before or after a certain point or within a specific period.
00:13:03.600 Another useful application for the three equals operator in Ruby 1.9 is proc objects or lambdas. This allows for intelligent code running to perform comparisons, which makes for some intriguing case statements.
00:13:48.760 There's this syntax that’s inspired by sprintf. There is an sprintf method in Ruby, but I prefer using it this way: you just put the format string on the left side, content on the right side, and use the percent operator in the middle. Using this, you can create formatted output.
00:14:28.160 One cool option to explore is percent P: it’s a Ruby add-on that runs inspect on whatever object you pass, letting you see the actual Ruby object and what it looks like. This format I just showed you has a whole lot of options; I'm using a ton of them right here.
00:15:10.600 Let me point out a few cool ones. You can refer to things by name now, so you can use names and then hash items to refer to the objects by name instead of position. You can set decimal places on floating points and control field sizes, meaning they can be padded out. You can left and right justify, all of which allows you to create some pretty cool output using those simple format strings.
00:15:48.919 You probably all know about Haddocks, but what you may not know is that after a Haddock, the rest of the line functions just like a normal line of Ruby, which could include anything Ruby can have—other Haddocks as well! If you have two Haddocks on the same line, they will just concatenate after the line in order.
00:16:21.360 If you’re running Ruby with warnings—which is usually a good idea—you’ll get a warning if you try to access an instance variable before it’s been assigned, helping you catch bugs. My favorite workaround for that is to switch the operator to the '||=' operator.
00:16:54.840 This operator is smart; it will check if a variable is defined before assignment, which effectively prevents the warning. When interpolating values, you can sometimes leave off the braces, as long as your variable starts with some kind of sigil, so Ruby knows it's a variable and not a number. You can leave the braces out and those values get dumped into the string.
00:17:30.000 With Ruby 1.9, you can now use named groups in your regular expressions, allowing you to refer to them by name rather than by position. Importantly, if you use it this way, Ruby will actually set local variables for you to the same names as the groups. Your regular expression needs to be on the left side of the match operator and must be a literal regex.
00:18:13.440 These are hints to Ruby to let it know that you don't mind it setting some variables for you. Ruby aims to honor conventions in many places. This particular code is an error because I've reused the same variable name twice; I'm just trying to ignore these values and use something, and the convention for ignoring a variable is the underscore.
00:18:56.160 If I use that, Ruby will allow it to go through. Even though I double assign the variable, it doesn’t care and lets it happen. Let’s look at some data structures. This one makes sense when you think about it, but it’s worth mentioning: objects just have references to other objects. One reference could point to the same object again, enabling you to create nested structures.
00:19:36.480 For instance, you can build a ring structure that keeps going back around. Another way to achieve similar functionality is by using Ruby 1.9's cycle operator, which returns an enumerable that iterates over the same set repeatedly. Be cautious when iterating with it because it literally goes on forever if you call 'each,' so it's important to manage the output.
00:20:17.520 You can use associative arrays in Ruby, which are arrays of arrays where the inner arrays contain two elements. You can access those inner arrays using the 'assoc' and 'rassoc' methods to get the one on the left and the one on the right, effectively giving you access to the full pair. This can allow control over the ordering.
00:20:57.520 There are additional tricks as well; for example, you could choose to put more than two items in there. You could only query the first two easily, but you could still retrieve the others if necessary. Another good use of these pairs is that they are automatically versioned. Since 'assoc' and 'rassoc' retrieve the first match, if you unshift something onto the beginning, you change that field and the older one will be ignored.
00:21:40.080 However, you can retrieve it later by finding the one you are getting and looking afterward. This allows you to use this structure as a version hash. Ruby’s hash can also be fun with all kinds of tricks. One that I love to exploit is that the hash block behaves like a memoization algorithm because it runs anytime a value is not present. If the value gets set while the block executes, then you’re effectively caching data.
00:22:24.040 Most of that execution is happening in C, making it incredibly quick. This is a very convenient way to perform memoization in Ruby. In a Ruby hash, you can set that default proc, and pass it down to nested hashes, allowing you to construct a deep data structure. Ruby automatically creates all the intervening levels.
00:23:07.520 Dave Copeland had a cool blog post about how you can use lambdas alongside hashes to create a dispatch table, which gets combined with a case statement to determine what code to execute. I used this example to create a trivial RPN calculator.
00:23:49.040 Now, I have to go back and face Josh sooner next week, and if I stop at that slide, he would yell at me. So, this is how you do the same thing with objects: let Ruby handle the dispatching for you. Just define a bunch of methods, then call the method, and Ruby will dispatch based on type.
00:24:35.679 If you're going to learn just one method from Ruby's Hash, make it 'fetch.' 'Fetch' is exceptional! You can retrieve values just like you do with brackets, but 'fetch' offers multiple ways to set default values. The block is lazy, meaning it won't execute if the value is already in the hash, which is great for optimizing expensive operations.
00:25:04.240 Additionally, if you try to fetch a value that doesn't exist, you will encounter an error. This feature makes it much easier to identify bugs in your programs since you’re not introducing nil, which could lead to errors later on.
00:25:56.720 You probably know you can index into a string using a couple of offsets to get the part that matches, but you can also index into a string using a regular expression to extract the matching part. I actually use this more often than the match operator. You can even ask for a specific 'group' or 'named group' to get that back.
00:26:58.160 Taking it one step further, you can actually assign to the matching portion of the string with the regular expression, effectively replacing it. You can also assign to an individual group of that matched regular expression. I don’t usually do that, but it’s quite an extraordinary feature.
00:27:33.280 By default, you get the leftmost match, which I assume most of us are aware of. However, if you want the rightmost match, Ruby’s index can take a regular expression as well. So you can simply pass a regular expression into it. Be careful how you compose your regex, as seen with the first example which matches just the two at the end because of the one or more digits.
00:28:10.560 If you need the entire last number, you'll have to use anchoring or something similar.
00:28:52.039 If you're processing binary data, you can use the unpack method. You pass in format strings which dictate how to treat the incoming binary data. For example, this one means to skip 16 bytes and pull two network order integers out of there. That's where PNGs hide their width and height, so you can peek inside and discover how large the image is.
00:29:32.760 There’s another method on arrays called 'pack,' which does the opposite: it allows you to construct binary data for output. One of the powerful iterators in Ruby is 'zip' because it allows you to iterate through two collections simultaneously, which can be tricky with Ruby’s internal iterators. 'Zip' solves that problem.
00:30:14.280 You can go through as many collections as you want at once. 'Partition' will ask a yes or no question of every item—that's what the block does—and divides the items into two groups: places where the answer is yes and places where the answer is no. You can use that to split out groups.
00:30:56.486 There’s a new method called 'chunk,' which works somewhat like partition does. 'Chunk' asks any question, not necessarily yes or no, and as long as adjacent items in the list return the same answer, they get grouped together. Though this can be difficult to grasp initially, it can be useful.
00:31:36.645 In this particular case, I’ve used it to separate out chapters. As long as there’s a leading 'one,' it’s considered chapter one; when there’s a leading 'two,' it’s chapter two.
00:32:15.799 'Flat_map' is another iterator I’m quickly picking up in Ruby 1.9. If you have arrays as the values, it will concatenate all those together, so you only get one array back at the end. It’s essentially a combination of 'map' plus 'flatten.' Another great new iterator is 'each_with_object.'
00:33:03.960 Many people use 'inject' where you have to consciously return the right object you’re carrying forward, but 'each_with_object' will ignore the return value whatever it is and just carry that object forward for you.
00:33:45.640 We'll look at four iterators that allow you to remove items from the front of a list or ignore items using blocks to make decisions about where to start and stop. Those are especially helpful for simply extracting a few items from the front or skipping a few.
00:34:29.560 I should mention that cycle returns an enumerator. If you want to step through this enumerator manually, you can call 'next' to get the next item in the list, which allows you to navigate through them meticulously. A unique feature of this is that 'next' will return an error when you run out of items, called StopIteration.
00:35:16.720 Ruby 1.9 has modified its loop mechanism to rescue 'StopIteration' and break out of the loop. Thus, you can continually call 'next,' and the loop will do the right thing when you reach the end of the list.
00:36:00.960 Most enumerators in Ruby have now been enhanced to return enumerators when called without a block, enabling you to chain them together. For example, you can chunk by three and then map and select those chunks.
00:36:48.760 You can even chain methods, so here I’m using the same trick by calling 'each_with_object' without a block, getting an enumerator and utilizing the enumerator, which has iterators available to it, such as 'with_index.' So we could always have ‘each_with_index,’ and if someone desired, you can put 'with_index' on any enumerator, allowing for inject with index or whatever is needed.
00:37:36.400 Alright, we’re about halfway there. Are you still with me? I don't know if I am! Why do this, anyway? It seemed like a good idea in the beginning. I'm trying to provide you with ideas—good ideas, weird ideas, bad ideas. I don’t really care, just ideas! Sometimes even the bad ideas can serve as cool jumping-off points that evolve into better concepts.
00:38:25.320 That's essentially why I’m here—because I hope that will lead to something interesting, but we don't have time to delve deeper into that. Let’s look at some more interesting finds.
00:39:15.840 In terms of core Ruby itself, you can programmatically construct classes in Ruby and set a parent class. The reason to do this is that the block acts as a closure, giving you access to local variables. Hence, you can programmatically decide what methods to add or something similar to that.
00:40:01.560 The same principle works with modules—of course, you can construct modules programmatically in exactly the same way. There’s no parent class in that case. One common application of this is in inheritance, considering that you can inherit from anything that is the result of a Ruby expression, as long as it yields in a class.
00:40:50.560 You can create a method that generates whatever class you want and returns it, and then you can inherit from that.
00:41:37.480 One pretty wild feature is that you can subclass a module and keep track of some state on the module itself. For instance, with a module, I defined a 'to_s' method to communicate what arguments the method was called with. From there, you can see in the output that when I asked for the ancestors, not only do I see a generic module in the list but I can also see how that module was constructed.
00:42:26.280 It’s a handy debugging trick when you require clarity about your program's state. If you want to create a type that functions as an empty class, you don't have to use the class definition block with nothing in it; you can simply use class New.
00:43:01.000 In this context, the block is optional. If you omit the block, it acts as a regular class with inheritance, behaving as normal—it's a neater syntax. Now, a lot of people implement the inherited-from-anything trick on structs.
00:43:43.480 However, you don’t need to because struct takes a block and defines whatever methods are inside. If you don’t want to assign struct to a constant, you can simply pass a string as the first argument, and struct will make a subclass in the struct namespace for you, allowing you to define all your structs without a constant assignment.
00:44:31.680 I’m reasonably sure we all know about method_missing, which we use frequently. But there’s also respond_to_missing, where you’ll receive a couple of benefits if you implement it to return the correct answer. The first and most obvious advantage is that respond_to will provide accurate results regarding your dynamic methods.
00:45:12.560 The cooler aspect is this: you can grab method references to those dynamic methods, which is useful for specific tricks I’ll show you shortly. In fact, here's how Sinatra builds its methods: it doesn’t utilize instance_eval, which is quite cool. Instead, it adopts this variation where it defines methods, grabs references to them, and subsequently removes them.
00:45:51.120 This technique is efficient since the method has already been defined, passing through the compilation phase and all that, so it’s quick. Plus, it can be applied to any object, granting you the ability to rebind it to different objects.
00:46:53.680 Let’s move on to meta programming and debugging. When debugging, one handy trick is that you can iterate over every object in the system and ask questions about them. If you want to narrow it down to specific types of objects, that’s entirely possible, too.
00:47:37.280 You can count how many objects you have by assigning the Ruby types as keys and individual counts as the values. This can be particularly beneficial for pinpointing issues like memory leaks, where the object count keeps rising without going back down.
00:48:09.360 Actually, to correctly identify memory issues, you can activate the garbage collector profiler and run code that stresses garbage collection. This way, you can view the results afterward in the form of a numerical table, allowing you to see sizes, object counts, time taken for garbage collection, and so on.
00:48:56.000 You should observe that these numbers stabilize after a while, but if they keep rising, you probably have a memory leak lurking somewhere.
00:49:31.840 If you have many chained method calls, as is customary in Ruby, and you want debugging information in between them, you can use the new 'tap' method, which allows you to intercept the call chain, run an additional piece of code, and ignore the result from your block, resuming with the original receiver.
00:50:12.480 If you’re simply trying to peek into something to print out stuff, you can skip tap altogether because the 'p' method in Ruby 1.9 has been enhanced to return the argument you pass into it. Thus, whatever you enter also gets returned, making it easy to chain together.
00:50:51.279 Another superb debugging tactic is for those of you dealing with threads: set this flag to true. If there’s an error within a thread, the program continues running until you join that thread, at which point the error is raised. This often means the error could occur far from where the actual problem originated.
00:51:33.680 If you want to track down where things went wrong, set that flag true, and as soon as there's an error, you’ll get alerted, making it easier to identify issues.
00:52:09.840 Ruby has a debug flag, and it’s important to note that while it allows you to hide some code, it also produces a lot of additional output, including warnings about uninitialized variables or exceptions that were handled, among others. This can lead to quite a noisy output.
00:52:47.760 You can hide some output by passing the -d flag as well. Let's talk about ‘between’ checks: a neat way to perform balance checks. You can do this with date ranges or any comparable object, such as numbers, dates, or strings, to check if an object lies between two other objects.
00:53:29.440 If you want to process some data line-by-line in Ruby (and you should rather than slurping it all into memory), you can use 'for each' in conjunction with 'open,' enabling you to read through the file line-by-line before closing it.
00:54:05.080 There is a similar method for writing out data: you can specify the name of a file and the data you want to insert. It will then open the file, add the data, and write it out. Optionally, if provided a position in the file, it can truncate to that point and append your data at the end.
00:54:40.560 While I’m not certain of a practical application of that, I’m sure it would be interesting to find one. Otherwise, you simply wipe out the contents and replace them with your own.
00:55:09.360 I see many developers write their own daemon methods, and it's not particularly lengthy, often just 10 to 12 lines. However, Ruby 1.9 includes a built-in 'Process.daemon,' which you can call to detach your process and run it in the background, which is quite useful.
00:55:57.760 If you are into spawning processes, check out the spawn command, which was introduced in Ruby 1.9. This command can handle almost everything. It allows control over environment variables, the command to be run, and it gives you a PID, allowing method calls on that PID.
00:56:40.520 This command offers impressive control over environment variables, including shell expansion and renaming processes in the process list. You can change the working directory and redirect IO objects all while making it synchronous or asynchronous, so please do check out the spawn functionality.
00:57:25.600 Let’s move on to the standard library. A new feature is that you can retrieve secure random numbers. I hope they are suitable for cryptography, but I’m not entirely sure since I don’t professionally work with cryptography.
00:58:06.960 What I utilize this module for is to randomly generate data; I find that particularly handy for creating hex data, random bytes, and even UUIDs. Those IDs are purely random and do not rely on the MAC address or timestamps.
00:58:49.000 Another method I absolutely love from the standard library is 'open-uri.' Once you require it, you can read from any web URL the same way that you would read from a file using normal IO methods, making it probably the easiest way to yank data off the web. This is like Ruby rogues’ list.
00:59:34.640 When dealing with external processes, eventually you'll have to manage arguments to those processes and correctly parse or quote them. There's a standard library that does just that called 'shellwords.' It makes it easy to quote an individual argument or to quote a group of arguments.
01:00:20.480 This library proves particularly useful when Ruby is used as a glue language since you won’t have to memorize all that tricky shell quoting.
01:01:05.660 Here's a feature of 'ERB' that I rarely see used. If you extend this module in your class, you gain access to define_method for ERB templates. You can provide a name for the method and the name of an ERB template, and it will effectively turn that ERB template into a method on your object.
01:01:40.760 Since it’s precompiled, it runs quickly, which is quite neat.
01:02:16.760 I also enjoy the 'fileutils' module from the standard library because the method names are all Unix commands with the corresponding arguments. This means I can guess the method name, and I’m often correct.
01:02:53.400 It’s a fantastic module to leverage when interacting with the file system. A great way to use it is to include or extend it somewhere, and then call those methods as normal. The beauty of this lies in the existence of other versions like 'verbose,' which will print out what it’s doing.
01:03:31.000 You can also access 'dry run,' which will simulate the actions without actually executing them. This allows you to double-check actions before committing, making it an incredibly useful tool.
01:04:09.760 There’s also an object-oriented way to deal with paths in the standard library that's much cleaner than conventional methods. This gives you functionalities for creating paths and checking them while still being able to execute normal IO operations.
01:04:59.080 There is also a simple database in the standard library that is incredibly easy to use. You simply point it at a file and conduct all operations within a transaction.
01:05:30.480 The appealing aspect of this database is that it allows read-on transactions, meaning you can abort one whenever you need, and the data structure is simply a hash. This means you can assign values to a hash because it’s a hash in a file.
01:06:15.680 You must consider that all the details must fit into memory, but the approach is both multi-processing and thread-safe.
01:06:50.560 You could swap it out for 'GDBMStore,' which is also in the standard library. You would concern yourself primarily with changing the `require` statement and object name, and the data will be stored in YAML, making it human-readable.
01:07:35.360 There is also a set in the standard library. Though arrays offer a variety of set functions, this version provides diverse methods to add items, check membership, super sets, subsets, and there’s even a sorted version. Thus, it’s a lot easier to navigate than always invoking `uniq` on an array.
01:08:12.840 Let’s shift attention to some tools. Ruby itself is a tool that has command line switches to build large programs for you, as it assumes your code runs in this loop.
01:08:41.760 You can even perform backups of files while you work on them, ensuring that your data changes without losing the original version. 'ARGV' is one special object that concatenates all file parameters from the command line, enabling you to treat them as a single IO object.
01:09:00.880 You can also use ARGV without the command line by grabbing its class and generating one of your own.
01:09:35.760 As for the flip-flop operator, it might be among the most confusing elements in Ruby, but it's fantastic for navigating through data in specific cases. It behaves like a state machine— the first expression gets checked against every line until it finds a match, then it turns on.
01:10:18.160 The second expression then gets checked against every line until it matches again, turning the operator off. This allows you to extract chunks of data, essentially allowing you to designate a starting point and endpoint.
01:10:56.560 Ruby also acknowledges 'begin' and 'end' blocks, which only execute at the start or end of a program, even if they reside within a loop.
01:11:34.340 This is useful for initializing elements, especially in daunting command line programs. If you’re not familiar with IRB, it's a lifesaver! The underscore signifies the last value that IRB calculated, which is something I frequently utilize in the Rails console.
01:12:11.560 You can run a query, and then still access that data or assign it to a variable. Many developers favor Pry for its capacity to focus on individual objects, but IRB has always had that ability.
01:12:59.280 You can simply invoke IRB and pass the desired object to change focus. It will reveal the currently held objects while executing each of the different threads.
01:13:36.320 You’re able to transition back into a primary job and exit out of inner jobs to return to the outer scope. IRB has consistently featured this flexibility without a hitch.
01:14:14.160 You can also utilize IRB as a library, starting it with the 'start' command. Here, I configured a signal handler that invokes IRB; just leave some way to reach back into the main program since you won’t have access to local variables.
01:14:52.760 You can see that I can run my program, activate IRB, and tweak some values, then exit while my program continues to run with those modified values.
01:15:41.920 If you ever find yourself facing a wall of JSON data you need to tidy up, if Ruby is installed, you'll have access to a utility called `prettyjson.rb`. You can simply pipe the output through the utility, and you’ll receive clean JSON.
01:16:32.720 Lastly, you can write programs that run indefinitely using a few tricks; this one program randomly executes mathematical operations until it performs something illogical, such as an infinite division by zero.
01:17:22.500 You can set an exit handler that executes code right before Ruby’s impending exit, checking the thrown exception to ensure it’s not something you approve of—like control+C or an explicit exit call—and replace your program with a pristine copy.
01:18:12.560 This will replace the faulty copy with a fresh version that contains no bugs, allowing it to keep running forever. While many of these concepts were presented simply for fun, most have roots in practical applications.
01:19:04.280 For instance, believe it or not, the feature demonstrated previously is reminiscent of one used by TextMate when executing Ruby code, which enables it to attribute errors in your program and offer an insightful hyperlink with the stack trace instead of raw program output.
01:20:00.000 I promise these slides will be made available online since I didn’t let you take notes. I’ll tweet when I upload them, so please follow me to access them. That’s what I have for you today. Thank you!
Explore all talks recorded at Aloha RubyConf 2012
+17