Ruby for Rails phần 8 pdf

48 406 0
Ruby for Rails phần 8 pdf

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

The eval family of methods 349 13.2.2 instance_eval instance_eval is a specialized cousin of eval . It evaluates the string or code block you give it, changing self to be the receiver of the call to instance_eval . This code p self a = [] a.instance_eval { p self } outputs two different self s: main [] instance_eval is mostly useful for breaking in to what would normally be another object’s private data—particularly instance variables. Here’s how to see the value of an instance variable belonging to any old object (in this case, the instance vari- able of @x of a C object): class C def initialize @x = 1 end end c = C.new c.instance_eval { puts @x } This kind of prying into another object’s state is generally considered impolite; if an object wants you to know something about its state, it provides methods through which you can inquire. Nevertheless, because Ruby dynamics are based on the changing identity of self , it’s not a bad idea for the language to give us a technique for manipulating self directly. We’ve saved the most useful of the eval family of methods for last: class_eval (synonym: module_eval ). 13.2.3 The most useful eval: class_eval (a.k.a. module_eval) In essence, class_eval puts you inside a class definition body: c = Class.new c.class_eval do def some_method puts "Created in class_eval" end end c = C.new c.some_method Output: Created in class_eval 350 CHAPTER 13 Ruby dynamics However, you can do some things with class_eval that you can’t do with the regu- lar class keyword: ■ Evaluate a string in class-definition context ■ Open the class definition of an anonymous class (other than a singleton class) ■ Gain access to variables in the surrounding scope The third item on this list is particularly worthy of note. When you open a class with the class keyword, you start a new local variable scope. The block you use with class_eval , however, can see the variables created in the scope surrounding it. Look at the difference between the treatment of var , an outer-scope local variable, as between a regular class definition body and a block given to class_eval : >> var = "initialized variable" => "initialized variable" >> class C >> puts var >> end NameError: undefined local variable or method `var' for C:Class from (irb):3 >> C.class_eval { puts var } initialized variable The variable var is out of scope inside the standard class definition block, but still in scope in the code block passed to class_eval . The plot thickens a little when you define an instance method inside the class_eval block: >> C.class_eval { def talk; puts var; end } => nil >> C.new.talk NameError: undefined local variable or method `var' for #<C:0x350ba4> Like any def , the def inside the block starts a new scope—so the variable var is no longer visible. If you want to shoehorn an outer-scope variable into an instance method, you have to use a different technique for creating the method: the method define_method . You hand define_method the name of the method you want to cre- ate (as a symbol or a string) and provide a code block; the code block serves as the body of the method. To get the outer variable var into an instance method of class C, you therefore do this: >> C.class_eval { define_method("talk") { puts var } } => #<Proc:0x003452f4@(irb):8> Callable objects 351 (The return value you’re seeing is a Proc object created from the code block given to define_method .) At this point, the talk instance method of C will, indeed, have access to the outer-scope variable var : >> C.new.talk initialized variable You won’t see techniques like this used as frequently as the standard class- and method-definition techniques. But when you see them, you’ll know that they imply a flattened scope for local variables rather than the new scope triggered by the more common class and def keywords. define_method is an instance method of the class Module , so you can call it on any instance of Module or Class . You can thus use it inside a regular class defini- tion body (where the default receiver self is the class object) if there’s a variable local to the body that you want to sneak into an instance method. That’s not a fre- quently encountered scenario, but it’s not unheard of. We’re going to turn next to a broad but unified category: callable objects. 13.3 Callable objects A callable object is an object to which you can send the message call , with the expectation that some code defined in the object (usually in a code block) will be executed. The main callable objects in Ruby are methods (which you’ve already seen), Proc objects, and lambdas. Proc objects are self-contained code sequences that you can create, store, pass around as method arguments, and, when you wish, execute with the call method. Lambdas are similar to Proc objects. The differ- ences will emerge as we examine each in turn. 13.3.1 Proc objects You create a Proc object by instantiating the Proc class, including a code block: pr = Proc.new { puts "Inside a Proc's block" } Note that the code block isn’t executed at this point. Instead, it’s saved as the body of the Proc object. If you want to execute the block (the Proc object), you must call it explicitly: pr.call It will report: Inside a Proc's block 352 CHAPTER 13 Ruby dynamics That’s the basic scenario: A code block, supplied to a call to Proc.new , becomes the body of the Proc object and gets executed when you call that object. Every- thing else that happens, or that can happen, involves additions to and variations on this theme. Proc objects as closures You’ve already seen that the local variables you use inside a method body aren’t the same as the local variables you use in the scope of the method call: def talk dda = "Hello" ddputs a end a = "Goodbye" talk puts a The identifier a has been assigned to twice, but the two assignments (the two a variables) are unrelated to each other. Proc objects put a slightly different spin on scope. When you construct the code block for a call to Proc.new , the local variables you’ve created are still in scope (as with any code block). Furthermore, those variables remain in scope inside the Proc object, no matter where or when you call it. Look at listing 13.2, and keep your eye on the two variables called a . def call_some_proc(pr) a = "irrelevant 'a' in method scope" puts a pr.call end a = "'a' to be used in Proc block" pr = Proc.new { puts a } pr.call call_some_proc(pr) As in the previous example, there’s an a in the method definition dd and an a in the outer (calling) scope dd. Inside the method is a call to a Proc object. The code for that Proc object, we happen to know, consists of puts a . Notice that when the Proc is called from inside the method dd, the a that is printed out isn’t the a defined in the method; it’s the a from the scope where the Proc object was originally created: Listing 13.2 Example of preservation of local context by a Proc object Output: Goodbye B C D B D C Callable objects 353 'a' to be used in Proc block irrelevant 'a' in method scope 'a' to be used in Proc block The Proc object carries its context around with it. Part of that context is a variable called a , to which particular string is assigned. That variable lives on inside the Proc. A piece of code that carries its creation context around with it like this is called a closure. Creating a closure is like packing a suitcase: Wherever you open the suit- case, it contains what you put in when you packed it. When you open a closure (by calling it), it contains what you put into it when it was created. Arguments for Proc objects Like any code block, the block you provide when you create a Proc object can take arguments: pr = Proc.new {|x| puts "Called with argument #{x}" } pr.call(100) Proc objects handle their arguments in a subtle (some might say complicated) way. If the Proc takes only one argument, as in the previous example, and you send it some number of arguments other than one, you get a warning. If you give it no arguments, the single variable is initialized to nil , and you get a warning: >> pr = Proc.new {|x| p x } => #<Proc:0x401f326c@(irb):1> >> pr.call (irb):1: warning: multiple values for a block parameter (0 for 1) from (irb):2 nil If you call the one-argument Proc with more than one argument, you get a warn- ing, and the arguments are all put into an array: >> pr.call(1,2,3) (irb):1: warning: multiple values for a block parameter (3 for 1) from (irb):3 [1, 2, 3] If your Proc takes more than one argument, the arguments you call it with are assigned to the variables in its argument list. Extra arguments on either end of the transaction are ignored: >> pr = Proc.new {|x,y,z| p x,y,z } => #<Proc:0x001b5598@(irb):1> >> pr.call(1,2) 1 2 nil Output: Called with argument 100 B 354 CHAPTER 13 Ruby dynamics => nil >> pr.call(1,2,3,4) 1 2 3 => nil The first time we call pr , we provide three arguments; inside pr , the third argument, z , gets nothing assigned to it and defaults to nil dd. (Note that the second nil that irb prints out is the return value of the execution of pr , which returns nil because it ends with a puts statement!) The second time we call pr , all three variables are assigned values; the fourth value, 4, is discarded, because there’s no variable left to assign it to. You can also sponge up all the arguments into a single argument, with the star ( * ) operator: pr = Proc.new {|*x| p x } pr.call pr.call(1) pr.call(1,2) As you’ll see if you run this snippet, x is set to an array on each call to the Proc. Each time, the array contains all the arguments you’ve called the Proc with: [] [1] [1, 2] If you have multiple arguments and put the sponge last, it’s assigned an array of all the arguments that haven’t been assigned to other variables already. Here’s an example: pr = Proc.new {|x,*y| p x, y } pr.call(1,2,3) The output 1 [2, 3] represents x , which was assigned the 1, and y , which was assigned the remaining arguments (2,3) as an array. The bottom line is that Procs are a little less fussy than methods about their argument count—their arity. Ruby offers several variations on the callable method-or-function theme. We’ll look next at another form of anonymous function: the lambda. B Callable objects 355 13.3.2 Creating anonymous functions with the lambda keyword The lambda keyword lets you create an anonymous function. All you have to do is provide lambda with a code block; that block becomes the function. You can then send it a “call” message, and the function executes: >> lam = lambda { puts "A lambda!" } => #<Proc:0x00330cb4@(irb):31> >> lam.call A lambda! Lambdas, as you can see from irb’s evaluative printout dd, aren’t objects of a class called Lambda ; rather, they’re objects of class Proc : >> lam.class => Proc Like all Proc objects, they are closures; they carry the local context of their cre- ation around with them. However, there’s a difference between Procs you create with lambda and those you created with Proc.new . It’s a subtle difference, but one you may need to be aware of at some point. It involves the return keyword. return inside a lambda returns from the lambda. return inside a Proc returns from the surrounding method. NOTE THE PROC/LAMBDA/BLOCK REALM IN FLUX In recent versions of Ruby— and in future versions, judging by discussions on various mailing lists and forums—the matter of how Proc objects, code blocks, and lambdas relate to each other has been, and still is, in a certain amount of flux. Don’t be surprised if you see other differences, or even the elimination of differ- ences, from one version of Ruby to another. Here’s an illustration of the difference: def return_test l = lambda { return } l.call puts "Still here!" p = Proc.new { return } p.call puts "You won't see this message!" end return_test The output of this snippet is “Still here!” You’ll never see the second message dd printed out because the call to the Proc object dd triggers a return from the B B C D B D C 356 CHAPTER 13 Ruby dynamics method. The call to the lambda dd, however, triggers a return from the lambda; execution of the method continues where it left off. Before we leave lambda , it’s worth mentioning that lambda has a synonym: proc . However, because proc and Proc.new look and sound so similar, but don’t do exactly the same thing, Matz has agreed in principle to phase out proc , leaving just Proc.new and lambda as the techniques for creating anonymous functions. You’ll probably continue to see the proc keyword in use for a while; just remem- ber that it’s a synonym for lambda . We’re now going to take another look at code blocks, in light of what we’ve dis- cussed about anonymous functions. 13.3.3 Code blocks, revisited A code block (the thing you type after a method call and to which the method yields) exists only in the syntax of Ruby. There is no such thing as a Block class or Block object. The block is just some code that floats in front of the method inside curly braces (or do/end ), waiting to be used. However, you can convert a code block into a Proc object, inside the method. You do this by capturing the block in a variable. This variable is part of the argu- ment list of the method, but it has an ampersand ( & ) at the beginning: def grab_block(&block) block.call end grab_block { puts "This block will end up in the variable 'block'" } The &var variable must be the last item in the argument list: def grab_block(x,y,*z,&block) You can also convert a Proc object or lambda to a code block. You do this with the ampersand: lam = lambda { puts "This lambda will serve as a code block" } grab_block &lam Here’s another example: grab_block &lambda { puts "This lambda will serve as a code block" } The & symbol serves in all of these cases as a signal that conversion back and forth is going on, as between lambda/Proc on the one hand and code blocks on the other. B Callable objects 357 13.3.4 Methods as objects In practice, the things you call most often in Ruby aren’t Procs or lambdas but methods. So far, we’ve viewed the calling of methods as something we do at one level of remove: We send messages to objects, and the objects execute the appro- priately named method. But it’s possible to handle methods as objects. You’re not likely to need this technique often, but it’s interesting to know that it’s possible. You get hold of a method object by using the method method, with the name of the method as an argument (in string or symbol form): class C def talk puts "Method-grabbing test! self is #{self}." end end c = C.new meth = c.method(:talk) At this point, you have a method object. In this case, it’s a bound method object; it isn’t the method talk in the abstract, but rather the method talk specifically bound to the object c . If you send a “call” message to meth , it knows to call itself with c in the role of self : meth.call Here’s the output: Method-grabbing test! self is #<C:0x353854>. You can also unbind the method from its object and then bind it to another object, as long as that other object is of the same class as the original object (or a subclass): class D < C end d = D.new unbound = meth.unbind unbound.bind(d).call Here, the output tells you that the method was, indeed, bound to a D object ( d ) at the time it was executed: Method-grabbing test! self is #<D:0x32d7bc>. To get hold of an unbound method object directly, without having to call unbind on a bound method, you can get it from the class rather than from a specific 358 CHAPTER 13 Ruby dynamics instance of the class, using the instance_method method. This single line is equiva- lent to a method call plus an unbind call: unbound = C.instance_method(:talk) Once you have the unbound method in captivity, so to speak, you can use bind to bind it to any instance of either C or a C subclass like D . But why? There’s no doubt that unbinding and binding methods is a specialized technique, and you’re not likely to need more than a reading knowledge of it. However, aside from the principle that at least a reading knowledge of anything in Ruby can’t be a bad idea, on some occasions the best answer to a “how to” question is, “With unbound methods.” Here’s an example. The following question comes up periodically in Ruby forums: “Suppose I’ve got a class hierarchy where a method gets redefined: class A def a_method puts "Definition in class A" end end class B < A def a_method puts "Definition in class B (subclass of A)" end end class C < B end “And I’ve got an instance of the subclass: c = C.new “Is there any way to get that instance of the lowest class to respond to the message (‘a_method’) by executing the version of the method in the class two classes up the chain?” By default, of course, the instance doesn’t do that; it executes the first match- ing method it finds as it traverses the method search path: c.a_method You can, however, force the issue through an unbind and bind operation: A.instance_method(:a_method).bind(c).call Output: Definition in class B (subclass of A) Output: Definition in class A [...]... level Part 4 Rails through Ruby, Ruby through Rails T he purpose of this part of the book is to bring to full fruition the book’s overall plan: helping you get more out of Rails by knowing more about Ruby The goals here are the goals of the book itself: ■ Learning the Ruby foundations of specific Rails techniques ■ Using your Ruby knowledge to add programming value and power to your Rails applications... expressed in Rails- friendly SQL with a special, separate table Unlike most other tables, this table doesn’t correspond directly to a Rails model or Ruby class Instead, it provides a way for Rails to track and record each case of a relationship between an edition and an author We’ll use standard Rails- compliant naming for this table: It’s called instruments_works It has two fields: one for the ID field... of Ruby) The automatic creation of methods based on the names of database fields is the Rails (or ActiveRecord, strictly speaking) way of giving you a familiar Ruby idiom—getter and setter methods, in pairs for manipulating database properties (If you get lulled into forgetting you’re dealing with a database as well as a bunch of in-memory Ruby Composer and Edition objects, you’ll be reminded 3 78 CHAPTER... you forget to perform an explicit save operation and all your attribute settings disappear! In some respects, despite the Ruby orientation of Rails, you still have to be database-aware.) We’ve now looked at inherited behaviors and automatically assigned behaviors Moving up the scale of programmer presence (or down the scale of Rails automation, if you prefer) we’ll next examine the way Rails performs... process of using Ruby code to enhance ActiveRecord model functionality This chapter doesn’t draw a sharp line between developing the application, learning Rails techniques, and bringing Ruby techniques to bear on the Rails application for the sake of added value The point is that it’s all one process 14.1 Tracking the capabilities of an ActiveRecord model instance Rails entity models are Ruby classes When... intertwined.) TIP Chapter 17 includes detailed discussion of navigating the online Rails API documentation at http://api.rubyonrails.org But even now, don’t hesitate to look at that site at any time—especially the links (on the left side of the screen) to information about specific method in the Rails framework LOOK AT THE ONLINE RAILS API DOCUMENTATION The two lives of the ActiveRecord object We’re looking... glass ceiling separating the Rails person” from the Ruby person” is gone This is where we bring the threads together: knowing what’s really happening when you use standard Rails techniques, and devising ways to go beyond those techniques—all thanks to your knowledge of Ruby The first section of this chapter provides a roadmap of how to understand Rails entity models in Ruby terms From there, we’ll... the class Ticket gets subclassed, you have to write the appropriate method specifically for class Ticket 360 CHAPTER 13 Ruby dynamics What follows are descriptions of each of these runtime event hooks The Rails framework uses several of them; we’ll see a couple of examples from the Rails source here and examine Rails hooks in more detail later 13.4.1 Intercepting unrecognized messages with method_missing... destroy have variants ending in _all (update_all, and so on), which perform the given operation on all existing database records and/or corresponding Ruby instances As always, for complete details on all available methods, see the Rails API documentation Web site The two-life nature of ActiveRecord model objects means you need to be both Ruby- aware and database-aware when you’re manipulating those objects,... Gaining skill and experience in examining the Rails source code Over the course of the four chapters that make up part 4, we’ll revisit and revise R4RMusic, the music store application from chapter 2 Along the way, we’ll use selected features and components of the application as windows onto the inner workings of both Ruby and Rails and, of course, Ruby and Rails together The new version of R4RMusic will . encounters with Ruby. method_missing looms large in the Rails framework. Much of what you do in Rails involves making calls to nonexistent methods and then having those calls inter- preted by Rails in. more meta aspects of Ruby: techniques for manipulating not only your program’s data but also the pro- gramming environment. We’ve looked at singleton classes, Ruby s mechanism for making per-object. in Ruby can’t be a bad idea, on some occasions the best answer to a “how to” question is, “With unbound methods.” Here’s an example. The following question comes up periodically in Ruby forums:

Ngày đăng: 06/08/2014, 09:20

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan