May 24, 2009 - IBM

jockeyropeInternet και Εφαρμογές Web

2 Φεβ 2013 (πριν από 3 χρόνια και 10 μήνες)

121 εμφανίσεις




2

Chapter 2


Learning Ruby

2.1 Learning Ruby


The big picture

Well by now you’re probably convinced that Ruby on Rails can give a fast way to create
prototypes, building enterprise level solutions on top of those prototypes. The thing that
normally scare
s people the most with Ruby on Rails is learning yet another programming
language. Nevertheless we have good news for you: Most Ruby developers love using the
language. By the end of the chapter we expect you to be convinced that the language is
not a barr
ier but a major factor in the success of the rails framework. Many concepts that
exist in rails
-

like don't repeat yourself (DRY)
-

are actually taken from the Ruby language.


So what is Ruby? And why a new language? Ruby is a multi
-
paradigm language
-

in
spired
by languages like perl, smalltalk and lisp
-

that incorporates the object
-
oriented paradigm
with functional and imperative. The language was created by Yukihiro Matsumoto that was
trying to create a language that behaves the way you expect it to beh
ave. He called this the
principle of least surprise. Ruby is a truly dynamic language that is interpreted on run time
with "duck typing". If your guessing what's duck typing one normally says that "if it walks
like a duck, quacks like a duck then it's a du
ck". With ruby's dynamic nature you just don't
make assumptions about the object until you need to call a method on it. Then if it works, it
must be the object your calling. By now the reader is thinking that this sounds dangerous
and that the language is
highly unreliable. As a matter of fact nothing could be further from
the truth. First many studies show that this does not bring significant difference in the
number of bugs when compared to other programming languages. Another thing is that
has ruby devel
opers had to defend themselves against that criticism most of them
develops quite extensive functional and unit tests. Ruby and Rails helped propel
movements like Test Driven Development, pair programming and the agile movement.

About the chapter: why you

should want to learn ruby, what will you learn, etc.




2.2 Installing Ruby

In this chapter we will give you instructions on how to set up your own ruby environment.
Ruby is multi
-
platform so we will cover the basic steps of installing it both in Windows, M
ac
and Linux.

The first step to install ruby in windows is to navigate to the official ruby website using your
favorite
browser.

Listing 1: Ruby
-
lang.org
-

The official ruby website

In this page you can see a very small sample Hello World! object written

in Ruby. From this
example you can immediately capture that constructors in ruby are made using the
initialize method and that there is no main function. The code that is supposed to run
simply appears after the class code. You can also see duck
-
typing in

action. Even though
that not type definition exists the initialize method assumes that whatever is passed as
name has a method capitalize that is reflexive
-

that is, the method will yield something that
itself has the capitalize method at the very least.


After understanding this first hello world you probably want to dig a bit further so let's click
the download ruby button.



In this page you'll find instructions on how to install Ruby on the three platforms we
previously referred or from source. Case yo
u’re not familiar with installing from source:
Ruby is an open
-
source language. So installing from source means you download the
actual source
-
code of the ruby language and compile it for your own machine. It's not
advisable to use this method unless you f
eel really comfortable with installing software from
source. In the following sections we will explain how to install ruby in different platforms.
Feel free to skip to the one you’re interested in.

2.2.1 Windows

As you can see in Listing 2. There are mult
iple options for installing Ruby. By the time this
book it's the stands Ruby 1.9 will probably have a one click installed and that's really the
one you should be downloading. Ruby 1.9 tackled several flaws that existed in previous
versions and was consider
ed by the ruby community as a milestone for the language.

Listing 2: Download the one
-
click installer

Now browse to the directory where you saved the file and double
-
click it. A standard
installing window will appear. You need to accept the Ruby license

and select the
components you want to install. SciTE is a text editor that comes bundled with the Ruby
language. You should choose whether or not to install it. Then you should install ruby
gems. Ruby gem is a package repository for ruby that makes instal
ling the libraries for your
ruby easy. For those of you familiar with Debian based Linux distributions it is quite similar
to apt
-
get for ruby. Finally chose if you need support for a European keyboard. In my own
installation I choose to install all of the

components.




Listing 3: Choose what components to install

Now choose the directory where you want to install (defaults to c:
\
ruby) and click next. In
just some moments you should be able to use your newly installed ruby environment.

If the one click in
staller package for 1.9 is not available simply install the 1.8 one, then
download the Ruby 1.9 Binary zip file and extract it to the same folder as you installed the
one click ruby 1.8. Then go to Start
-
> Control Panel
-
> System
-
> Advanced
-
>
Environmen
t Variables and make sure you have the ruby bin directory (default should be
c:
\
ruby
\
bin) in your PATH variable.

2.2.2 OS X

If your using a newer version of OS X (from Leopard on) we have good news for you. Open
a Terminal Window
-

case you never did thi
s before just write Terminal in spotlight and it
should pop
-
up. Now write ruby
-
v. Yes, ruby comes bundled with Mac OS X since leopard
and you don't need to install it

.




Listing 4: Ruby is already installed
Now the problem is that on this book we are usi
ng Ruby 1.9. As you can see in listing 4 OS
X Leopard bundles version 1.8.6. It might seem insignificant to move from 1.8.6 to 1.9.1 but
there are a lot of changes involved and you should be aware that all this book was written
and 1.9 and some things migh
t be incompatible with previous versions. You can tackle
using Mac Ports(footnote

http://www.macports.org/)
and running the following command in
your Terminal.

port install ruby19


Now if you are looking to replace

your original version of ruby with a 1.9 you can simply:

cd /usr/bin


sudo ln
-
s /opt/local/bin/ruby1.9 .


sudo mv ruby ruby1.8

sudo ln
-
s ruby1.9 ruby


If this fails you can still install from source. You can learn how in the section installing from
so
urce.

2.2.3 Linux

TBD. There are a lot of distributions.
http://amerj.info/tag/ruby19/


2.2.4 From source

TBD.

2.3 Hello Ruby!

First of all: I hope you installed ruby. You really should try all these command
s so you get a
better impression on how ruby works. Feel free to drift away from instructions, search for
related subjects and learn more about ruby. You will learn the concepts a lot better if you
keep a curious attitude to ruby. Give irb a chance and enj
oy.



The first example on almost every programming language is the Hello world program. Let’s
cover some possible implementations of it in ruby and discuss the difference and use it as
a way to introduce the next sections.

So the easiest hello world in ru
by is using the ruby one line script.

nunojob@dscape ~

$ ruby
-
e 'puts "Hello Ruby!"'

Hello Ruby!

So what happened here? So we called the ruby interpreter. Remember? Ruby is not a
compiled language, it’s interpreted on runtime. Then we passed the

e opt
ion and that
means we want to run a one line script. This is analog to other programming language like
perl or python. The script then comes enclosed in apostrophes and simply issues puts
“Hello Ruby!”. This will cause the message to appear in the screen.

Ok so this is probably the smallest hello world possible in ruby. But you can do it in many
different ways. One that you might consider is doing so in the interactive ruby (IRB). IRB is
a command line for ruby where you can make your small computations. R
uby developers
normally use irb as a preferred tool for debugging, experimentation and even systems and
database administration. In this chapter we’ll use irb a lot. The concepts that you can learn
there can be applied just as well to actual textual code s
amples and you’ll have a nice
sandbox to try all your crazy experiments.

To start irb simply issue the irb command.

irb

now to do the Hello world example once again you have a variety of options. You could
simply issue the puts “Hello Ruby!” once again.

That works. But let’s try something slightly
more advanced. Let’s create a method that does the hello world for us.

irb(main):001:0> def hello_world

irb(main):002:1> puts "Hello Ruby!"

irb(main):003:1> end

=> nil

So we defined a function with the
def keyword and we named it hello_world. The we simply
enclosed the puts function inside. After we finished the function declaration it returned nil
as there’s nothing to return from a function declaration. You might wonder is puts named


like that and not
print, in ruby. Well ruby has a print method as well. The difference is that
puts adds a newline in the end of the string you supply.

irb(main):004:0> puts "Hello Ruby!"

Hello Ruby!

=> nil

irb(main):005:0> print "Hello Ruby!"

Hello Ruby!=> nil

Ok, n
ow that we got this one let’s continue to the actual calling of the function. So in irb we
want somehow to call the function we just created called hello_world.

Doing so couldn’t be easier in ruby.

irb(main):006:0> hello_world

Hello Ruby!

=> nil

So we

covered the basics on how to do a hello world in ruby. Let us take this a little bit
further before introducing the next sections. Instead of Hello ruby let us actually ask use
the name of the person that we want to say hi to


after all some people might

get offended
when you call them ruby.

Lets define a new method, hello_name, that does exactly that.

nunojob@dscape ~

$ irb

irb(main):001:0> def hello_name name

irb(main):002:1> puts "Hello #{name}!"

irb(main):003:1> end

=> nil

irb(main):004:0> he
llo_name "Brandon"

Hello Brandon!

=> nil

There are a few things your probably noticing in this example. That is that I didn’t use any
parentheses


neither in the function definition or in the actual function call. One thing
about ruby is that in most c
ases parentheses are optional and that really makes reading
code much easier


at least for us humans. Another thing that you might notice in this
example is the fact that there are not type definitions. To actually print the information the
name will have

to “quack like a duck”. Remember duck typing? If it quacks like a duck and


swims like a duck right? Well in this case you pass something to the hello_name method.
Then the method will try to place that in the location you established by using the #{}
synt
ax. Now what you passed has to have a to_s method, allowing the object to be
serialized as a string. This is pretty much the all the quacking it needs. After that printing is
just trivial business for irb.

Ruby also supports default arguments. Se we can a
ctually use the same method hello
while passing an argument or without passing any argument. Just check this:

irb(main):001:0> def hello name="Ruby"

irb(main):002:1> puts "Hello #{name}!"

irb(main):003:1> end

=> nil

irb(main):004:0> hello

Hello Rub
y!

=> nil

irb(main):005:0> hello(:Peter)

Hello Peter!

=> nil

2.4 Everything is an object

Even though ruby is not a purely object oriented language ruby offers a unique feature that
is not present in many object oriented languages like java or c#. Thi
s might sound strange
to someone familiar with these languages but in Ruby everything is an object. That means
that you can call methods on a string, or an integer for instance.

A common example of this is the use of the upto method to iterate a finite nu
mber of times
to achieve an objective.

nunojob@dscape ~

$ irb

irb(main):001:0> 1.upto(3) { puts "Ruby Rocks!"}

Ruby Rocks!

Ruby Rocks!

Ruby Rocks!

=> 1

So we actually called a method out of an integer. In languages like java this would be
impossib
le without an explicit cast of the literal to an object of type Integer. In ruby there is
not such thing. So we call the upto method that allows you to iterate exactly three times.


Then we have a block where we put the code that needs to be executed on eac
h iteration.


Let’s dig a little further. On this upto example.

irb(main):002:0> 1.upto(3) do

irb(main):003:1* |i| puts i

irb(main):004:1> end

1

2

3

=> 1

I guess you’re wondering what’s the difference between the curly braces and using this do
end s
yntax. Well there’s no difference but normally ruby coders use the curly braces for
short one
-
liners and the do end syntax for multi
-
line blocks. Another new thing that your
noticing in this example is that we are actually printing the numbers from 1 up to

3. To
achieve that we use the |i| as a receptacle for the var in each iteration and simply print it.
As all the numbers have a string representation it’s pretty easy to call the to_s method and
print it your screen.

2.5 Basic Constructs

So let's see the
basic operations you expect a programming language to have.

Another basic construct are strings.

Don’t forget construct string with ‘

Or “

Or %q

Or etc…

View ruby in one page cheat to know everything that must be inside at the very least.

2.6 Classes

Until now you’ve been using irb to learn more about the ruby language. But I guess you’re
wondering about how to create classes in ruby and how to make it run using ruby. In this


section we are going to explain exactly that. Some topics


like inheritance



will not be
discussed in this section. I know you are enjoying learning ruby but try not to forget what
brought you here


Ruby on rails! There are a lot of good books on ruby and if you want to
learn more advanced concepts you really should consider bu
ying one of them.

We have been talking for so long about duck typing that it just seems obvious to that our
first object is


yes, you’re totally right


a Duck!

So let’s create a Duck object.

class Duck


attr_reader :stamina, :name



@@quack = "Quac
k! Quack!"



def initialize name


@name = name.capitalize


@stamina = 100


end



def quack


puts "Quack! Quack!"


end



def swim


quack


@stamina
-
=50


rest if @stamina < 10


end



private



def rest


puts "zZzZzZZzZ!"



@stamina=100


end

end


tomato_nose = Duck.new "Poopy Face Tomato Nose"

tomato_nose.swim

tomato_nose.swim



Just save this definition in a file called duck.rb, browse to the directory where you save it
and launch irb from there. So let’s go through that

code and try to understand it a little
better.

First we say that we want to define a class called Duck


what a surprise. Then we start off
with some pretty awkward attr_reader statement. What do they mean right? Well if you are
from a java background yo
ur probably used to creating getters and setters for each
variable and then making them private. That’s a basic principle in OO design. In ruby
classes variables are private by default and if you want to create getters and setters you
can use this alternat
ive syntax. In this case we are saying that we want a getter method for
both stamina and name instance variable. We’ll show you how this works when you go to
IRB. Then we defined a class variable


this is shared by all objects of type duck. The
syntax to
do so is the @@ as you can see in the example. The initialize method is analog
to a constructor in java. In this case the initialize method expects a parameter called name
and called creates two instance variables: name and stamina. Now we have two pretty
straight forward methods for swimming and quacking. The quack simply prints the
somewhat annoying duck quack. Then the swim method implies that every time our duck
swims he starts by quacking, then he looses some stamina. Then we introduce a if
statement t
hat will force the duck to call the private method rest if the stamina is too low.
Notice that the if statement is written almost as in plain English. Rest if stamina is low.
Ruby also supports the normal if syntax but this syntax can really help improve y
our code
readability. Now we define a private method to rest the duck


yes, no respectful duck can
be told when to rest. They decide when they want to! Finally we finish the class declaration.
Something that might be surprising you is the fact that there
is something after the class
declaration


specifically the birth of one loud duck. Any code that you put after the class
declaration will be run whenever you import the class. In most of the cases this functionality
is used to do something similar to the
main function in java.

Now open irb and:

$ irb

irb(main):001:0> require 'duck.rb'

Quack! Quack!

Quack! Quack!

ZZzZzZZzZ!

=> true

irb(main):002:0> require 'duck.rb'

=> false

First we start by requiring the duck.rb. Require is the same as import wit
h a small twist. If
the class as already had been imported than it will do nothing. You can see this in the
example above where the second require returns false. Remember that we instructed our


class to always create a duck whenever called. That’s what hap
pened. The duck was
created and decided to go for two swims. Then after feeling tired he decided to take a
break.


irb(main):003:0> john = Duck.new "john"

=> #<Duck:0x7ff9f928 @name="John", @stamina=100>

So we just created a new duck named john. Let’s
check how it behaves.

irb(main):004:0> john.name

=> "John"

irb(main):005:0> john.stamina

=> 100

So our getter methods are working and we can access the values of the name and stamina
instance variables. What if we try to change the name?

irb(main):0
06:0> john.name = "Steve"

NoMethodError: undefined method `name=' for


#<Duck:0x7ff9f928 @name="John", @stamina=100>


from (irb):6

It returned an error which was to be expected. You defined that you wanted that variable to
be read only and said

nothing about writing. So ruby protected the variable against writing.
If you want to create a setter method but no getter method you should use attr_writer. If
you want to create both simply do a attr_accessible.

Now let’s try the class methods:

irb(ma
in):007:0> john.quack

Quack! Quack!

=> nil

irb(main):008:0> 2.times { john.swim }

Quack! Quack!

Quack! Quack!

zZzZzZZzZ!

=> 2



So yes


john quacks, john swims. Hence john is a duck. Success my friends, you got your
very first ruby class working ex
actly like you wanted.

2.7 Arrays and Hashes

What a fun section this is. A lot to learn in ruby arrays and hashes. Remember this is just a
short introduction to ruby but if you want to really use rails you have should dig in a little
deeper into the ruby
documentation and learn a little more about this.

There are new ways of creating arrays and hashes and you can use the one you feel more
comfortable with.

irb(main):001:0> l1 = []

=> []

irb(main):002:0> l2 = Array.new

=> []

irb(main):003:0> h1 = Hash
.new

=> {}

irb(main):004:0> h2 = {}

=> {}


As you can see both return create a new object of the same type, so just choose whatever
you prefer. Now let's focus more on lists and then we will introduce how to manipulate
hashes.

irb(main):001:0> l1 = [
1,2,3]

=> [1, 2, 3]

irb(main):002:0> l1 << 4

=> [1, 2, 3, 4]

irb(main):003:0> l1.member? 5

=> false

irb(main):004:0> l1.delete l1.last

=> 4

irb(main):005:0> l1

=> [1, 2, 3]

irb(main):006:0> l1.each { |i| puts i }

1

2

3



=> [1, 2, 3]


A lot o
f functions are available and
-

yet again
-

you should really check the documentation.
One of them is inject. Here you can see how you can accumulate the result of a factorial
using the inject function.

irb(main):001:0> def fact n

irb(main):002:1> (2..n
).inject { |ac,i| ac*=i }

irb(main):003:1> end

=> nil

irb(main):004:0> fact 2

=> 2

irb(main):005:0> fact 3

=> 6

irb(main):006:0> fact 4

=> 24


As for hashes. Well we already created our first hash. So let's play around with it a little bit
a lear
n a bit more about how they work.

irb(main):001:0> profile = {:name => 'Marissa'}

=> {:name=>"Marissa"}

irb(main):002:0> profile[:name]

=> "Marissa"

irb(main):003:0> profile[:age] = 25

=> 25

irb(main):004:0> profile

=> {:age=>25, :name=>"Marissa"}

irb(main):005:0> profile.name

NoMethodError: undefined method `name' for {:age=>25,
:name=>"Marissa"}:Hash


from (irb):5


from :0

irb(main):006:0> class Hash

irb(main):007:1> def method_missing name

irb(main):008:2> self[name]

irb(m
ain):009:2> end

irb(main):010:1> end

=> nil



irb(main):011:0> profile.name

=> "Marissa"

irb(main):012:0> def print_hash h

irb(main):013:0> h.each_pair do |k,v|

irb(main):014:1* puts "#{k} => #{v.respond_to?("join") ?
v.join(", ") : v}"}

irb(m
ain):015:1* end

irb(main):016:1> end

=> nil

irb(main):017:0> print_hash :name => "Marissa", :cats =>
["Puma","CJ"]

name => Marissa

cats => Puma, CJ

=> {:name=>"Marissa", :cats=> ["Puma", "CJ"]}


What a big code listing. Let us walk through it.

So
we start by creating an hash named profile with an key pair association that maps the
key :name to 'Marissa'. Then we ask for :name in that hash and we get the assigned value.
Then we set the mapping for :age and set the value as 25. You can now see that i
t worked
as when you write profile you can see all the mappings that are available in the profile.
Now we try to extract the name using profile.name. Profile is an hash, not a class that you
created and then set up the attr_reader for a class variable. Eve
n if it was you wouldn't be
able to access it like this
-

it would be an hash stored in the variable. But if you really want
any missing method to retrieve value for the association with key = method_name there is
a way. You shouldn't do it this way
-

we a
re changing the hash class, you can learn more
about how to do this properly by simply searching for it on the internet
-

but it's a great
illustration on how dynamic ruby is. So
-

in irb
-

we just start a class declaration for Hash
and define a method cal
led method_missing. If the class doesn't respond to some method
this method will be called. Then we take the missing method name and try to extract it from
the hash. Now doing profile.name works. Once again you shouldn't do this exactly like this,
but it's

kind of fun that you can right? Now let's go for the hardest we got so far: Let's create
a function to print hash tables. So we get an hash called h, and for each key/value pair with
print the key, then the value. The twist in the value is the introductio
n of an if clause and
the join. So if the value respond to (has an method that is called) join then we print the
values joined by a comma. If not we print the value. So if we have something like a list,
were we can join items we will get a string that join

all list member separated by commas.
We call the print_hash function so you can see how it processes both strings and lists
differently. You can always see that you can pass hashes to methods without using the
curly braces.



2.8 Control structures

So if yo
ur familiar with other programming languages you probably know your way control
structures. If not, you don't need to worry. We'll show you the way. So what are control
structures? Well control structures are constructs that allow you to control the flow o
f an
algorithm. Things like if then else, switches, for and while loops are classic examples of
control structures.

Let's start with if
-
then
-
else. For that start your irb and then:

irb(main):001:0> l = [:foo, "bar", 5]

=> [:foo, "bar", 5]

irb(main):002
:0> puts "contains bar" if l.member? "bar" contains
bar

=> nil


That was easy. So we created a list with foo, bar and 5. Then we used the if statement to
print a message if bar is member of the list we constructed.

BOX: Notice the ? in the end of the me
mber method for list l? In ruby it's common practice
to use ? when a method returns true or false. Another common practice in ruby is the
usage of the exclamation mark (!) in the end of the method to mark methods that change
the variable they are methods f
or. Take as an example the delete method for lists:


irb(main):001:0> s = "Donald"

=> "Donald"

irb(main):002:0> if s.respond_to? :delete!

irb(main):003:1>


s.delete! "l"

irb(main):004:1> else

irb(main):005:1*


s.delete "l"

irb(main):006:1> end

=>
"Donad"

irb(main):007:0> s

=> "Donad"

irb(main):008:0> s = "Donald"

=> "Donald"

irb(main):009:0> s.delete "l"

=> "Donad"

irb(main):010:0> s

=> "Donald"



ENDBOX

If then else statements get too verbose when you want to check for multiple conditions.

In
those situations we normally use a case statement. An important thing to remember is that
in ruby no explicit break is necessary in case statements
-

as opposed to other
programming languages like c. More the syntax is more permissive and allows you th
ings
that wouldn't work in many of the programming languages that you're used to.


irb(main):001:0> c="n"

=> "n"

irb(main):002:0> case c

irb(main):003:1> when "a", "b", "c".."z"

irb(main):004:1> puts "lowercase alphabetic character"

irb(main):005:
1> when "A".."Z"

irb(main):006:1> puts "uppercase alphabetic character"

irb(main):007:1> default

irb(main):008:1> puts "non alphabetic character"

irb(main):009:1> end

lowercase alphabetic character

=> nil


So now two main control structures ar
e missing. While and for. If you think they are of an
major importance in ruby, think again. There are a number of ways to iterate sequences in
ruby and so many ways to do it that normally these control structures don't have the same
importance as in other

programming languages where they give the only alternative to
recursive functions.

To illustrate let's give a small example with a for loop. So we want to know if all letters in a
string are lowercase:

irb(main):001:0> def all_pair l

irb(main):002:1>

b = true

irb(main):003:1> for i in l

irb(main):004:2> b = false unless (i % 2) == 0

irb(main):005:2> end

irb(main):006:1> b

irb(main):007:1> end

=> nil

irb(main):008:0> all_pair []



=> true

irb(main):009:0> all_pair [2,4,6]

=> true

irb
(main):010:0> all_pair (1..9).to_a

=> false


A very classic c like example. Se we say that by default all members in a list are pair. Then
we iterate that list and we decide to change that truth value if the remainder of the division
between that number

and two is not zero. For that we use the unless statement that is
available in ruby. Then we test if for some lists getting the desired results.

You can also iterate the array with the each method:

irb(main):001:0> all_pair = true

=> true

irb(main):00
2:0> [1,2,3,4].each { |i| all_pair = false unless i %
2 == 0 }

=> [1, 2, 3, 4]

irb(main):003:0> all_pair

=> false


However you will see in the next sections
-

Arrays and Hashes
-

that ruby allows you to do
this in a much cleaner manner. Consider this
example:

irb(main):011:0> [].all? { |i| i % 2 == 0 }

=> true

irb(main):012:0> [2,4,6].all? { |i| i % 2 == 0 }

=> true

irb(main):013:0> (1..9).all? { |i| i % 2 == 0 }

=> false


Any type that is enumerable has the any? and all? method. In ruby
-

like

in other languages
like haskell
-

knowing the libraries can really play in your favor to hasten development
speed and get a much cleaner and easier to read code.

While loops are getting slowly out of fashion but some people still love them. And they look

great in ruby, you can even throw a while in one single line of code!



irb(main):001:0> def fact n

irb(main):002:1> r = 1

irb(main):003:1> while n > 1

irb(main):004:2> r *= n

irb(main):005:2> n
-
= 1

irb(main):006:2> end

irb(main):007:1
> r

irb(main):008:1> end

=> nil

irb(main):009:0> fact 2

=> 2

irb(main):010:0> fact 3

=> 6

irb(main):011:0> fact 4

=> 24


Memoization?

2.9 An example program

Sample (ADD IO, shell scripting, dirs). Maybe del generator

2.10 Exercises

TBD

2.11 Sum
mary

TBD

2.12 Review questions

TBD