Ruby的基础知识

Ruby

Interpreted vs Compiled

Depending on the programming language you’re using, it will either be a compiled language or an https://desk-fd.zol-img.com.cn/t_s960x600c5/g5/M00/0B/05/ChMkJlcgb6mIY7cbAAg5YZ7Q3FwAAQrzAAWO2sACDl5956.jpg[interpreted language](http://en.wikipedia.org/wiki/Interpreted_language). Compiled programs will first be converted to machine code and then you will be able to run the program. Interpreted languages will be interpreted and converted to machine code at run time.

puts&&print

you need to use the method puts which is short for “output string.” And because Hello World! is a string, you need to surround your text with "".

both “” and ‘’ is ok

differenece

The primary difference between them is that puts adds a new line after executing, and print does not.

return

both of print and puts will return nil

example

To both print and return your name, you could write:

def print_and_return_name  
  puts "Guy Fieri"  "Guy Fieri"
end

There is one other way to return a value from a method and that is to use the return keyword.

Let’s take a look:

def stylish_chef  
  best_hairstyle = "Guy Fieri"  
  return "Martha Stewart"  
  "Guy Fieri"
end

it will just return the first value following return

Sanitizing User Input: The strip and chomp Methods

One thing to know about the #gets method is that it captures a new line character at the end of whatever input it is storing. We don’t want extra whitespace or new lines to be appended to the user input we are trying to store. So, we can chain a call to the #stripmethod to remove any new lines or leading and trailing whitespace.

The #chomp method works similarly, and you are likely to see #gets.chomp used in some examples online. The #chomp method removes any new lines at the end of a string while the #strip method removes whitespace (leading and trailing) and new lines.

IRB

What is IRB?

IRB stands for “Interactive Ruby.” It’s a Ruby shell or REPL.

How do you use it?

IRB allows you to execute ruby in the terminal .To access IRB, just type irb in the terminal. IRB allows you to do anything you can do in a Ruby file.use exit to leave IRB.


Four Common Error Types

Name Errors

NameErrors are caused when a given name is invalid or undefined. Whenever the Ruby interpreter encounters a word it doesn’t recognize, it assumes that word is the name of a variable or a method. If that word was never defined as either a variable or a method, it will result in a name error.

Syntax Errors

Syntax errors are pretty self-explanatory: they’re the result of incorrect syntax. Thankfully, they’re usually followed by a guess about the location of the error. For instance:

2.times do  puts "hi"

Will result in:

2: syntax error, unexpected end-of-input, expecting keyword_end

Here, Ruby is saying that on line 2, there is a missing end (every do keyword must be followed by some code and then an end keyword). Always read the full details of syntax errors and look for line numbers, which usually appear at the beginning of the error message.

Type Errors

When you try and do a mathematical operation on two objects of a different type, you will receive a TypeError. For example if you try and add a string to an integer, Ruby will complain.

1 + "1"

Will produce the following error:

TypeError: String can't be coerced into Fixnum

Division Errors

DivisionErrors are caused when a given number is divided by 0.


variable

Note: The syntax of #{current_president} simply injects the value of the variable current_president into the string. This is called Interpolation .where you are simply adding together multiple strings.

In Ruby, a variable can point to almost any type of value including numbers, strings, arrays, and hashes.

  • Variable names should start with a lowercase letter. A variable that begins with an uppercase letter is known as a constant and has different characteristics.
  • There is strong convention among Rubyists to use what is known as snake case this_is_an_example_of_snake_case words are separated by underscores.
  • A Ruby variable cannot start with a number, be a Ruby reserved word, or have punctuation or space characters.
  • Ruby is what is known as a dynamically typed language. That means the value of a variable can change its type and does not need to be explicitly and permanently defined.
  • It is also a strongly typed language. This means a variable will never be automatically coerced to another type without you explicitly changing the type.

How You Interpolate Variables into Strings

To interpolate, you wrap the variable like #{this}.

Another Way to Interpolate Variables into Strings

Some Rubyists write this another way, like this:

answer = "Flamboyance"
puts "A group of flamingos is called a " + answer + "."

Single quotes: '' do not support string interpolation


Ruby Data Types

Creating Strings

There are two ways to create a string. In fact, we’ve already created a string just by typing "hello".

Try it out by opening up IRB, and typing "hello".class

You should see a return value of => String. You can actually call .class on any object to find out what type of data, i.e. what class, it is.

The Literal Constructor: This is the method through which we created our “hello” string.

The Class Constructor: You can also create a string with String.new. This will create an empty string.

String.new("hello") on the other hand, will create this string: "hello". For the most part, you will create strings using the first method discussed here––simply by enclosing whatever text you want in quotes.

Because every string is based on Ruby’s String class, there are certain behaviors, or methods, available to us for operating on them. You can learn more about the many String methods by reading the Ruby documentation on Strings. For now, we’ll just take a look at a few examples.

"hello".size   => 5
"hello".upcase   => "HELLO"
"hello".reverse   => "olleh"

Booleans

There are only two values of the Boolean data type: true and false. In Ruby, however, there is no such thing as a Boolean class. Instead, every appearance, or instance, of true and false in your program are instances of TrueClass and FalseClass respectively.

Unlike strings, there is not a way to create a Boolean value, other than to explicitly write true or false. Later, we will see that we can write lines of code that evaluate to or return true and false,

In Ruby only false and nil are falsey. Everything else is truthy (yes, even 0 is truthy).

What are Boolean Operators?

Boolean operators are really methods which means that they have return values. What do they return? true or false of course!

In Ruby there are three main boolean operators:

  • ! (“single-bang”) which represents “NOT”,
  • && (“double-ampersand”) which represents “AND”, and
  • || (“double-pipe”) which represents “OR”

Comparison Operators

Operator Operation
== If the values of the two operands are equal, then the evaluation is true.
!= If the values of the two operands are not equal, then the evaluation is true.
> If the value of the left operand is greater than the value of the right operand, then the evaluation is true.
< If the value of the left operand is less than the value of the right operand, then the evaluation is true.
>= If the value of the left operand is greater than or equal to the value of the right operand, then the evaluation is true.
<= If the left operand is less than or equal to the value of the right operand, then the evaluation is true.

number

You can read more about Fixnums here and more about Floats here.

7.5.floor  => this method will round the float down to the nearest fixnum. Here it will return 7 
7.5.ceil  => 8
10.next  => 11

change: '5'.to_i.

Symbols

A symbol is a representation of a piece of data. Symbols look like this :my_symbol. If I make a symbol, :my_symbol, and then use that symbol later on in my code, my program will refer to the same area of memory in both cases. This is different from, for example, strings, which take up new areas of memory every time they are used.

You write symbols by placing a : in front of the symbol name.

:this_is_a_symbol

Arrays

Arrays are collections of Ruby objects. You can store any type of data in an array.

There are a number of ways to create an array. Just like with creating strings, you can use the literal constructor or the class constructor.

The Literal Constructor:[1, 3, 400, 7] is an array of integers. Any set of comma separated data enclosed in brackets is an array. So, by simply writing something like the above, you can create an array.

The Class Constructor: You can also create an array with the Array.new syntax. Just typing Array.new will create an empty array (=> []).

For now, we’ll preview a few array methods, and you can check out more here.

[5, 100, 234, 7, 2].sort   => [2, 5, 7, 100, 234]
[1, 2, 3].reverse  => [3, 2, 1]

more ways

The shovel method employs the “shovel” operator << and allows you to add (“shovel”) items onto the end of an array:

famous_cats = ["lil' bub", "grumpy cat", "Maru"] 
famous_cats << "nala cat" 
famous_cats #=> ["lil' bub", "grumpy cat", "Maru", "nala cat"]

The shovel method << is the preferred syntax for adding elements to an array, however you might see other methods used in examples online:

The .push Method

Calling .push on an array with an argument of the element you wish to add to that array, will also add that element to the end of the array. It has the same effect as the shovel method explained above. However the .push will also let you add multiple elements to an array, whereas the shovel method will only add one element.

famous_cats = ["lil' bub", "grumpy cat", "Maru"] 
famous_cats.push("nala cat") 
famous_cats #=> ["lil' bub", "grumpy cat", "Maru", "nala cat"]

The .unshift Method

To add an element to the front of an array, you can call the .unshift method on it with an argument of the element you wish to add:

famous_cats = ["lil' bub", "grumpy cat", "Maru"]
famous_cats.unshift("nala cat")
famous_cats.inspect #=> ["nala cat", "lil' bub", "grumpy cat", "Maru"]

Removing Items From an Array

The .pop Method

Calling .pop on an array will remove the last item from the end of the array. The .pop method will also supply the removed element as its return:

famous_cats = ["lil' bub", "grumpy cat", "Maru"]
maru_cat = famous_cats.pop 
famous_cats #=> ["lil' bub", "grumpy cat"]
maru_cat #=> Maru

The .shift Method

Calling .shift on an array will remove the first item from the front of the array. The .shift method will also supply the removed element as a return:

famous_cats = ["lil' bub", "grumpy cat", "Maru"]
lil_bub = famous_cats.shift 
famous_cats #=> ["grumpy cat", "Maru"]
lil_bub #=> lil' bub

The .reverse Method

This method reverses an array.

famous_wizards = ["Dumbledore", "Gandalf", "Merlin"]
famous_wizards.reverse #=> ["Merlin", "Gandalf", "Dumbledore"]

The .include? Method

This method will return a boolean of whether or not the array contains (or includes) the element submitted to it inside the parentheses:

famous_cats = ["lil' bub", "grumpy cat", "Maru"]
famous_cats.include?("Garfield") #=> false
famous_cats.include?("Maru") #=> true

Additional Resources

nested array

A nested, or multidimensional array, is an array whose individual elements are also arrays.

Adding Data to a Nested Array

To add data to a nested array, we can use the same <<, or shovel, method we use to add data to a one-dimensional array.

To add another student to our students array:

students = ["Mike", "Tim", "Monique"]
students << "Sarah"students 
#=> ["Mike", "Tim", "Monique", "Sarah"]

To add an element to an array that is nested inside of another array, we first use the same bracket notation as above to dig down to the nested array, and then we can use the << on it. To illustrate, let’s add another piece of info, "Class President", to the nested array that describes Monique.

First, we have to access Monique’s array.

nested_students[2]

Then – bam! – we hit it with the shovel, <<.

nested_students[2] << "Class President"

Now, our nested_students array looks like this:

nested_students = [ 
["Mike", "Grade 10", "A average"], 
["Tim", "Grade 10", "C average"],  
["Monique", "Grade 11", "B average", "Class President"]
]

Iterating Over Nested Arrays

What if we want to add data to every array that is nested within the parent array? It would be very tedious if we had to calculate the length of the array and then, one-by-one, modify each individual child array using bracket notation and the << method.

When we are dealing with a one-dimensional array and want to do something to every element, we iterate, using methods like #each and #collect. If, for example, we wanted to puts out every member of the students array, we could do so like this:

students.each do |student|  
    puts student
end

In order to manipulate or operate on each element of a nested array, we must first dig down into that level of the array. For example, run the following code in IRB:

nested_students = [  
    ["Mike", "Grade 10", "A average"],  
    ["Tim", "Grade 10", "C average"],  
    ["Monique", "Grade 11", "B average", "Class President"]
    ] 
nested_students.each do |student_array|  
    # #inspect returns a human-readable representation of the array 
    puts student_array.inspect
end

The .each method prints out each nested array separately and then returns the original array:

["Mike", "Grade 10", "A average"]
["Tim", "Grade 10", "C average"]
["Monique", "Grade 11", "B average", "Class President"]
#  => [["Mike", "Grade 10", "A average"], ["Tim", "Grade 10", "C average"], ["Monique", "Grade 11", "B average", "Class President"]]

In the example above, we are iterating through the list of arrays that make up the top level of the nested_students array. If we want to iterate through the elements inside each child array, we add a second layer of iteration inside the first:

nested_students = [  ["Mike", "Grade 10", "A average"],  ["Tim", "Grade 10", "C average"],  ["Monique", "Grade 11", "B average", "Class President"]] nested_students.each do |student_array|  
    student_array.each do |student_detail|    
        puts student_detail  
        end
end

Copy and paste the above code into IRB. You should see the following output:

Mike
Grade 10
A average
TimGrade 10
C average
Monique
Grade 11
B average
Class President

album_element.class != Array

Boolean Enumerables

  • all?
  • none?
  • any?
  • include?

examples

[1,3].none?&#123;|i| i.even?&#125; #=> true
[1,2,100].any?&#123;|i| i > 99&#125; #=> true
the_numbers = [4,8,15,16,23,42]
the_numbers.include?(42)   #=> true
the_numbers.include?(6)   #=> false

search enumerables

  • select
  • detect or find(detect and find are two names for the same method)
  • reject
[1,2,3,4,5].select&#123;|i| i.odd?&#125; #=> [1,3,5]
 
[1,2,3].select&#123;|i| i.is_a?(String)&#125; #=> []
[1,2,3,4].detect&#123;|i| i.even?&#125; #=> 2
[1,2,3,4].detect&#123;|i| i.is_a?(String)&#125; #=> nil

Notice also that #detect will always return a single object where #select will always return an array.

[1,2].reject&#123;|i| i.even?&#125; #=> [1]

Hashes

Hashes also store objects in Ruby. However, they differ from arrays in that they function like dictionaries. Instead of a simple comma separated list, hashes are composed of key/value pairs. Each key points to a specific value––just like a word and a definition in a regular dictionary.

Hashes look like this: {"i'm a key" => "i'm a value!", "key2" => "value2"}

The curly brackets denote the hash and this particular hash has two key/value pairs.

Creating Hashes

Hashes can be created with literal constructors and class constructors.

The Literal Constructor: You can create a hash by simply writing key/value pairs enclosed in curly braces.

The Class Constructor: Or, you can use the Hash.new syntax, which would create an empty hash, {}.

Operating on Hashes

There are many methods for operating on hashes and their individual key/value pairs. We will learn much more about them later, but you can preview some methods here.

Method

Defining a Method

You can define a method in Ruby with the def keyword. A method’s name can begin with any lowercase letter. Here’s a quick example:

def greeting # Method Signature  
puts "Hello World" # Method Body
end # Method Closing

That first line, def greeting, is called the method signature, it defines the basic properties of the method including the name of the method, greeting.

Once you open a method definition with the def keyword, all subsequent lines in your program are considered the method’s body, the actual procedure or code that your method will run every time it’s called.

You must terminate every opening def of a method with a corresponding end in order to close the method body.The body of a method should be indented two (2) spaces, placing it visually within the method.(just for beauty)

Excute it

greeting

no()

control flow

  • if, else, and elsif statements,
  • case statements,
  • loops.

if

dog = "thirsty"
 
if dog == "hungry"
  puts "Refilling food bowl."
elsif dog == "thirsty"
  puts "Refilling water bowl."
else
  puts "Reading newspaper."
end

Loops

10.times do 
  puts "Hi! Welcome to my very repetitive program"
end
counter = 0
 
loop do 
  counter += 1
  puts "Iteration #&#123;counter&#125; of the loop"
  if counter >= 10 
    break
  end
end

while

counter = 0
while counter < 20
  puts "The current number is less than 20."
  counter += 1
end

until

Until is simply the inverse of a while loop. An until keyword will keep executing a block until a specific condition is true. In other words, the block of code following until will execute while the condition is false. One helpful way to think about it is to read until as “if not”.

counter = 0
until counter == 20
  puts "The current number is less than 20."
  counter += 1
end

Iteration vs. Looping

In previous readings we discussed the four loop types, loop, times, while, and until. Now we’re going to discuss the difference between looping and iteration. Looping occurs when you tell your program to do something a certain number of times. Iteration occurs when you have a collection of data (for example, an array), and you operate on each member of that collection.

For example, if I tell my program to print out the phrase “I love programming!” five times, that’s looping. If I tell my program to enumerate over the array [1, 2, 3, 4, 5] and add 10 to each number, that’s iteration.

each - The Most Abstract
Being abstract is something profoundly different from being vague…. The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise.
— Edsger Dijkstra

Using #each

The #each method is a prime example of an iterator. Here’s a boilerplate example of its usage:

primary_colors = ["Red", "Yellow", "Blue"]
primary_colors.each do |color|
    puts "Primary Color #&#123;color&#125; is #&#123;color.length&#125; letters long."
end

#each is called on the collection primary_colors, which is an array containing 3 individual strings.

A block is passed to #each, opened by the code that starts with do and closed by the end. Every do needs a closing end.

primary_colors = ["Red", "Yellow", "Blue"]
primary_colors.each do |color| # do begins a block  
# the lines between the do/end are the block's body
    puts "Primary Color #&#123;color&#125; is #&#123;color.length&#125; letters long."
end # end terminates the block

The output from this code is:

Primary Color Red is 3 letters long.
Primary Color Yellow is 6 letters long.
Primary Color Blue is 4 letters long.

We can see that the block passed to each is executed once for each element in the original collection. If there were 5 colors in primary_colors, the block would have run 5 times. We call each run, each execution, of the block passed to the iterator (#each in this case), an iteration. It’s a word used to refer to each ‘step’, or each ‘execution’, of a block. An iteration is the singular execution of a sequence of code (that we call a block) within a loop.

When we iterate over a collection of elements using #each (and also in other iterators and enumerables we’ll soon learn about),** the iterator #each yields each element one at a time to every iteration via a variable declared with the opening of the block.**

After the opening do of our code above, we see |color|. | is called a pipe. After do, we declare a local variable color by enclosing it in | | pipes. This variable’s value is automatically assigned the element from the array for the current iteration. So on the first iteration of the each above, the variable color would be equal to "Red". But on the next iteration of the block, color will be reassigned the value of the next element in the primary_colors array, "Yellow".

The { } Syntax

Another way of establishing a code block that you may encounter is to use curly brackets, { }, instead of the do/end keywords. Let’s take a look:

brothers = ["Tim", "Tom", "Jim"]
brothers.each{|brother| puts "Stop hitting yourself #{brother}!"}

It is appropriate to use the { } syntax when the code in the block is short and can fit on one line.

rsepc

rspec --fail-fast

describe

The first thing RSpec allows you to do with its DSL is to define what it is you are describing.

it

Now that we’ve created a structure to group our tests together using the describe method, we can move on to actually describing the desired functionality. Every specification in RSpec begins with the it method.

expect, to, and eq.

expect() is a method that accepts our unknown value or variable, the thing we’re testing. So for instance, in a simple math equation, imagine the following:

x = 1 + 1expect(x)

Since x is the unknown variable, we’d be testing the expectation of the value of x, so we pass that value to the expect method. I can imagine it’s weird to think of the variable x as an unknown value worth confirming. You’re thinking, “It’s obviously 2!” But the truth is, you’re making the assumption that Ruby has a correct notion of arithmetic. As our programs become more complex and we use more variables, it’s very important to constantly validate our assumptions with expectations and testing. Let’s finish the example.

In addition to the expect(x) call, we need to communicate what we expect x to be equal to. To accomplish this, we chain a to()method to the expect(), so it simply looks like:

x = 1 + 1expect(x).to

Then finally we use what is known as a matcher, eq, to specify our expectation: that we expect the value of x, passed to the expectmethod, to equal (to eq) 2.

x = 1 + 1expect(x).to eq(2)

You won’t have to write your own tests for a while, so don’t worry about mastering the expect, to, and eq usage. The important part is that you can read the DSL and understand what it is trying to suggest.

  1. RSpec looks in a directory named spec for all files that end with the pattern _spec.rb. Why the spec folder and the _spec.rb pattern? No reason, just convention.
  2. RSpec then executes the Ruby code within each _spec.rb file.

class

class Dog
end
 
fido = Dog.new
fido #=> #<Dog:0x007fc52c2d7d20>
 
snoopy = Dog.new
snoopy #=> #<Dog:0x007fc52c2d4170>
 
snoopy == fido #=> false - these dogs are not the same.

Implementing Instance Variables

We define an instance variable by prefacing the variable name with an @ symbol.

Instance variables are bound to an instance of a class. That means that the value held by an instance variable is specific to whatever instance of the class it happens to belong to. Instance variables hold information about an instance, usually an attribute of that instance, and can be called on throughout the class, without needing to be passed into other methods as arguments (as would be the case with local variables).

Let’s refactor our Dog class to use an instance variable instead of a local variable to set and get an individual dog’s name.

Open up dog.rb and change the Dog class in the following way:

class Dog   
def name=(dogs_name)  
    @this_dogs_name = dogs_name 
end   
def name   
    @this_dogs_name 
end
end 
lassie = Dog.new
lassie.name = "Lassie" 
puts lassie.name 

initialize

require certain arguments to be passed when instantiating the class to provide it with initial data

class Person
  def initialize(name)
    @name = name
  end
 
  def name
    @name
  end
end
 
kanye = Person.new("Kanye")
kanye.name #=> "Kanye"

Setter vs. Getter Methods

Our Person class’ #name method is referred to as a “getter” or reader method. It returns information stored in an instance variable. In order to make a person’s name attribute writable, we need to define a “setter” or writer method.

Defining a Setter Method

class Person 
    def initialize(name)  
        @name = name 
    end   
    def name 
        @name 
    end  
    def name=(new_name)  
        @name = new_name  
    end 
end

A setter method is defined with an =, equals sign, appended to the name of the method. The = is followed by the (argument_name). Now that we’ve defined our setter method on the Person class, we can change Kanye’s name.

Calling a Setter Method

To call a setter method, you use the . notation (dot notation) to call the method and set it equal to a new value.

kanye = Person.new("Kanye")
kanye.name  => "Kanye" 
kanye.name = "Yeezy"
kanye.name  => "Yeezy"

You can also call a setter method like this:

kanye.name=("Yeezy")

But we prefer the first notation.

The Abstraction of Instance Methods

kanye.instance_variable_set(:@name, "Yeezy")
kanye.instance_variable_get(:@name)
  => "Yeezy"

Since this is the case, why do we even use instance setter and getter methods?

  • , we care about our program’s readability and design. The above method is ugly. It places a verb at the end of the method name.

  • It exposes it directly to the person executing our code. This is bad practice because it forces our program to rely directly on the @name variable.

  • for example:We’ll initialize our Person instances with both a first and last name.

    class Person   
        def initialize(first_name, last_name)  
            @first_name = first_name  
            @last_name = last_name  
        end  
        #... end
    

    With this change, our program has some added functionality. We could imagine collecting all of our instances of Person and sorting them by last name, for example.

    BUT, now, any other part of our program that was calling instance_variable_get(:@name) is broken!

    Let’s create our abstraction: the #name= and #name setter and getter instance methods:

    class Person   
        def initialize(first_name, last_name)   
            @first_name = first_name   
            @last_name = last_name  
        end  
        def name=(full_name)  
            first_name, last_name = full_name.split   
            @first_name = first_name   
            @last_name = last_name  
        end  
        def name   
            "#&#123;@first_name&#125; #&#123;@last_name&#125;".strip  
        end
    end
    

    Now, even if the content of the #name method changes, for example, Kanye changes his mind again and wants to be referred to only as “Yeezy” (using our interface this change would be kanye.name = “Yeezy”), the interface, how our application uses that content, remains constant. In other words, we can change the content of these methods according to our needs, without needing to hunt down every appearance of them in our program and change them as well, like we would need to do with our instance_method_set and instance_method_get usages.


上一篇
js的基本操作 js的基本操作
定义变量声明var 变量名; 即使不声明也可以使用,先声明后使用更规范 定义函数声明function 函数名 {} 使用函数名(); 如何输出空格在写JS代码的时候,大家可以会发现这样现象: document.write(“ 1
2018-11-29
下一篇
隐藏和覆盖的区别和用法 隐藏和覆盖的区别和用法
隐藏和覆盖的区别和用法 以下内容来自隐藏和覆盖的区别和用法 静态类型和动态类型任何一个引用变量都有两个类型:一个叫静态类型,也就是定义该引用变量的类型;另一个叫动态类型,也就是该引用实际指向的对象类型。 比如对于两个类A和类B,有:A a
2018-11-23
目录