w1d4 Flashcards
What are blocks useful for?
To allow the user to customize what a method will do.
T/F: Use single-line {braces} for one-line blocks, and do-end for multi-line blocks.
T
T/F: When blocks are passed to a method, they are given in the list of arguments.
F; They are given OUTSIDE the argument:
- times { puts “Hey, friend!” } # don’t need parens when no args
- times() { puts “Hey, friend!” } # if parens used block is given outside parens
Explain the following code:
def maybe(flag, &prc)
prc.call if flag
end
Declares a method, ‘maybe’, which takes a ‘flag’ argument as well as a block argument.
The ‘&prc’ is the special syntax for setting up a method to take a block. ‘prc.call’ runs the code inside the block.
What is the difference between a block and a proc?
A block is the Ruby code you write; it is not a real Ruby object.
How can you pass multiple procs as arguments?
Only add the ampersand to the last proc:
def chain_blocks(start_val, proc1, proc2, &proc3)
What happens when you call a proc with arguments?
Any arguments are passed into a |piped| variable(s) in the block, if they were declared. Any excess arguments are ignored.
What is the advantage of ‘yield’ ?
It allows us to pass a block to a method without needing to declare it:
def maybe(flag) yield if flag end
What are the two methods to check if a block was given as an argument?
prc.nil? - used if a block has explicity been declared as a parameter
block_given? - used if a block has not been explicitly declared.
T/F: You should explicitly return from within a block.
F; Do not do this; the last value is implicitly returned from the block. Return will exit from the whole function, not just the block where it is called.
If we want to pass a named block to a function, what syntax should we use?
Add an ampersand to the block name:
1, 2, 3].map(&add_one) # => [2, 3, 4]
What does the following shorthand stand for:
[“a”, “b”, “c”].map(&:upcase)
[“a”, “b”, “c”].map { |s| s.upcase }
How can we convert a named method to a proc?
proc_name = :method_name.to_proc
proc_name.call(param)
[“Hello”, “Goodbye”].map(&:proc_name) # => [[“H”, “o”], [“G”, “e”]]
What are the three uses of ‘&’
Converts blocks to procs
Converts method names (passed as symbols) to procs
Converts procs to blocks
How can we override the ‘method_missing(method_name)’ method, and what does this accomplish?
It allows us to redefine what a method does when it receives a method which is not defined. By default, it sends an error. This, in essence, can allow us to define an infinite number of methods, if we change the return value of method_missing.
What is a ‘dynamic finder’?
Rather than create a method for every single possible way to search (which is almost infinite), Rails overrides the #method_missing method, and for find_by_* methods, it then parses the method name and figures out how it should perform the search.
Explain the following code:
class User def method_missing(method_name, *args) method_name = method_name.to_s if method_name.start_with?("find_by_") # attributes_string is, e.g., "first_name_and_last_name" attributes_string = method_name[("find_by_".length)..-1]
# attribute_names is, e.g., ["first_name", "last_name"] attribute_names = attributes_string.split("_and_")
unless attribute_names.length == args.length raise "unexpected # of arguments" end search_conditions = {} attribute_names.each_index do |i| search_conditions[attribute_names[i]] = args[i] end # Imagine search takes a hash of search conditions and finds # objects with the given properties. self.search(search_conditions) else # complain about the missing method super end end end
A dynamic finder in Rails; used for methods that contain ‘find_by’ as well as ‘and’. This allows you to use just about any search method you can define to return a logical result (by searching for what is in the method you define by its title)
What is a base case?
The smallest (most trivial and direct) subproblem in a recursive method.
What is the key to use inductive reasoning for recursion?
The key to applying inductive reasoning to solve problems is to (a) identify how you can grow a smaller solution into a bigger solution, and (b) identify base cases which will be the “foundation” of your tower of recursion.
How should you decide when to use recursion?
Decide if it would be better to solve it iteratively or recursively in your own mind.
What is a stack frame, and what happens when you have too many?
Each function call in a recursive method adds a stack frame, and when there is not enough memory to hold any more, your program crashes due to stack overflow.
What are four strategies for programming recursively?
Map out a recursive decomposition (sketch it out)
Identify the base case(s)
Think one level up from the base case (will the call one level up from the base case return the right thing?)
Ensure that your return values from any case (base case or otherwise) are always of the same type (everything is returning from the same method)