---
# System prepended metadata

title: 認識Ruby

---

# 認識Ruby

## 印出hello world 的三種方式

#### 方法一：一行終端機指令： （要注意單引號跟雙引號）

    $ ruby -e "puts 'hello, world'"
        
#### 方法二：使用 irb。 
#### 方法三：寫在某個檔案裡： 

例如VScode檔名是 abc.rb，寫完別忘了存檔！ 
請 Ruby 來執行它： 

    $ ruby abc.rb
  
## 「print」 vs 「puts」 vs 「p」
  
#### 印出 Hello, World 字樣
```ruby=
print "Hello, World"
```

#### 印出 Hello, World 字樣，並在結尾加上換⾏
```ruby=
puts "Hello, World" # Hello, World
```

#### 印出 "Hello, World" 字樣（含雙引號），並在結尾加上換⾏
```ruby=
p "Hello, World" # "Hello, World"
```


:::info
nil代表不存在
:::

## 註解 Comment 方式
 註解不會被執行 
 在 Ruby 比較常用單行註解 
 用途： 
 說明某段程式碼的用途 
 暫時把某些程式碼「關起來」

#### 方法一
=begin
這是多⾏註解
這裡的內容不會被執⾏
這裡的內容不會被執⾏
這裡的內容不會被執⾏
=end

#### 方法二
#這是單⾏註解
#這裡的內容不會被執⾏
#這裡的內容不會被執⾏
#這裡的內容不會被執⾏

## 變數與常數

a | | =  2  同等 a = a | | 2 
如果a的值有設定或是ture就維持原貌，否則給2

---

### 變數練習

x = 2 , y = 3 將兩者資料對調

#### 方法一、暫存變數
```ruby=
x=2
y=3
a=x
x=y
y=a
```

#### 方法二、資料總和扣除
```ruby=
x=2
y=3
x= x+y
y= x-y
x= x-y
```

#### 方法三、 多重指定(ruby專用)

```ruby=
x=2
y=3

x,y = y,x
```

:::warning
在Ruby的世界常數是可以被修改的
:::

---

## 命名慣例

ruby 多用 snale_case

---

## 字串
單引號的字串不會做帶入或翻譯，雙引號的字串會

### 雙引號
```ruby=
name = "kk"
age= 18

puts "hi i am #{name}, i am #{age} years old."
```
result 

    hi i am kk, i am 18 years old.
    
### 單引號
```ruby=
puts 'hi i am #{name}, i am #{age} years old.'
```

result 

    hi i am #{name}, i am #{age} years old.
    
### 引號不夠用的狀況
舉例

```ruby=
puts 'i'm #{age} years old.'
```

解決方法
方法一、加入跳多字元「\」
```ruby=
puts 'i\'m #{age} years old.'
```

方法二、 用%Q(等同雙引號)或%q(等同單引號)

```ruby=
puts %Q(hi i am #{name}, i'm #{age} years old.)
puts %q(hi i am #{name}, i'm #{age} years old.)
```

result
        
    hi i am kk, i'm 18 years old.
    hi i am #{name}, i'm #{age} years old.
    
---

## 數字 (Ruby:數字其實也是物件)
### 整數
```ruby=
puts 3.55.round #轉成整數，四捨五入
puts 3.74.floor #轉成整數，無條件捨去
puts 3.14.ceil  #轉成整數，無條件進位
puts 3.14.to_i  #轉成整數，無條件捨去
```

#### 整數除法 (Ruby:整數除以整數會得到整數)

```ruby=
puts 10/3 # 會得到3
```
### 浮點數

要得到小數的話，只要在整入後面給予小數

```ruby=
puts 10.0/3
puts 10/3.0
pust 10.0/3.0 
```

---
## 邏輯判斷與流程控制

= => 指定
== => 比對

```ruby=
a=10
b="10"

p a==b #false
```

=== => 比對or其他事情

### 判斷
* Ruby中除了**nil**和**false**是假的，其他都是真的

### if / else

```ruby=
weather = "rain"

if weather == "rain"
  puts "stayhome"
else
  puts "GoOut"
end
```

#### if 倒裝句

```ruby=
puts "stayhome" if weather == "rain"
```

### unless

unless = if not
if = unless not

#### 寫法一
```ruby=
if not weather == "rain" #不是rain 就 GoOut
  puts "GoOut"
end
```

#### 寫法二
```ruby=
unless weather == "rain"
  puts "GoOut"
end
```

### unless 倒裝句

```ruby=
puts "GoOut" if not weather == "rain"
puts "GoOut" unless weather == "rain"
```

#### 三元運算子

原本寫法
```ruby=
if age>= 18
  status = "adult"
else
  status "notadult"
end

```

三元運算子寫法
```ruby=
status = (age>=18) ? "adult" : "notadult"
```

### if.. elsif .. else .. 
* 注意不是 else if 是 elsif

```ruby=
weather = "rain"

if weather == "rain"
  puts "HOME"
elsif weather == "sunny"
  puts "OutDoor"
else
  puts "sleep"
end
```

### case .. when .. (Ruby中類似if寫法)
判斷值符合條件

```ruby=
weather = "rain"

case weather 
when "rain"
  puts "HOME"
when "sunny" 
  puts "OutDoor"
else
  puts "sleep"
end
```
:::info
#### 範圍的shortcut寫法

原本的寫法
```ruby=
age = 10

case age
when age >= 0 && age <=3 # 0-3歲
  puts "baby"
when age >= 4 && age <=10 # 4-10歲
  puts "child"
when age >= 11 && age <=17 # 11-17歲
  puts "teenager"

else
  puts "adult"
end
```

shouthand寫法 ( .. => range )
```ruby=
age = 16

case age
when 0..3
  puts "baby"
when 4..10
  puts "child"
when 11..17
  puts "teenager"

else
  puts "adult"
end
```
:::


---

## 迴圈與迭代
:::info
差異性
迴圈: 重複做某一件事(跑5圈操場)
迭代: 每件事都做一次(5座操場各跑1次)
:::




### for 迴圈 (概念有點像迭代)

```ruby=
names = ["Amy","John","Tom","Emily"]

for name in names # 每一圈在轉的時候都有變數name可以用 
  puts name
end
```

### while 迴圈 (邪惡分身: until = while not)
#### while = until not
```ruby=
x = 0

while x < 10 
  puts x
  x +=1 #條件記得，不然會無窮迴圈
end
```

#### while not
```ruby=
x = 0

until x >= 10
  puts x
  x +=1
end
```

### loop 迴圈

```ruby=
i = 0
loop do
  puts i 
  i+=1
  break if i > 10
end
```

:::info
do .. end(Ruby特有寫法) 或 { } 為block的概念
:::

### method 迴圈 (Ruby持有)
#### .times 做幾次

範例
```ruby=
5.times do
  puts "hello, ruby"
end
```
#### .upto 向上計數 (從初始值做到設置數值)

範例

```ruby=
1.upto(10) do |i|
  puts "counts to #{i}"
end
```
#### .downto 向下計數 (從初始值做到設置數值)

```ruby=
10.downto(1) do |i|
  puts "counts to #{i}"
end
```

### 迭代式迴圈 interation (常用)

#### .each 

```ruby=
names = ["Amy","John","Tom","Emily"]

names.each do |name|
  puts name
end
```

如果想要印出索引值

```ruby=
names = ["Amy","John","Tom","Emily"]

names.each.with_index do |name , x|
  puts "#{x} #{name}"
end
```

## 陣列

### 建立方式

方式一 用[]
```ruby=
list = ["ruby","php","python"]
p list #["ruby", "php", "python"]
```
方式二 用%w，且不用逗號跟雙引號 (%w建立出來的會是字串陣列)
```ruby=

list = %w(ruby php python)
p list #["ruby", "php", "python"]
```

### 使用陣列

#### 陣列元素位子

```ruby=
list = %w(ruby php python)
p list[2] # "php"
```


```ruby=
list = %w(ruby php python)
p list[-1] # "python"
```

:::info
從0開始算，若要從後面開始哪從負值
:::

### **first** & **last**
取用第一個元素或最後一個元素
```ruby=
list = %w(ruby php python)
p list.first #ruby
p list.last #python
```
加括號裡面放入值，可以選擇拿前或後x的數值
```ruby=
list = [1,2,3,4,5,6,7,8,9,10]
p list.first(4) #[1, 2, 3, 4]
```

### 印出陣列長度 .lenght

```ruby=
list = %w(ruby php python)
puts list.length #3
```


### 加入新資料到陣列
####  <<
```ruby=
list = %w(ruby php python)

list << %q(Java)
#puts list # ruby php python Java
```

#### 用.push效果一樣 
```ruby=
list = %w(ruby php python)

list.push('Java')
puts list
```

### map or collect 
對集合裡的每個元素**進行運算**，並收集成一個新的**集合**。
```ruby=
list = [1,2,3,4,5]

p list.map{|x| x*2} #[2, 4, 6, 8, 10]
```
:::warning
這裡不用%w，印為%w輸出會是內容會是字串
:::

```ruby=
list = [1,2,3,4,5]

p list.collect{|x| x*2} #[2, 4, 6, 8, 10]
```

```ruby=
p (1..10).map{|x| x*2}
#[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
```

### select (filter用途)
從集合裡**挑選符合條件**的元素，並收集成一個新的**集合**。

相反: reject 挑選不符合條件

```ruby=
p (1..10).select {|x| x<5}
# [1, 2, 3, 4]
```
```ruby=
p (1..10).reject {|x| x<5}
# [5, 6, 7, 8, 9, 10]
```

### reduce 
對集合裡的每個元素**進行運算**，並將所有運算結果歸納成一個**單一結果**

每一圈會將前一次運算完的累加值丟回sum，然後將下一個元素丟入x繼續運算
```ruby=
p (1..10).reduce {|sum, x| sum + x} #55
```

### compact
將陣列中的nil拿掉

```ruby=
list=[1,3,4,1,7,nil,7]

p list.compact #[1,3,4,1,7,7]
```
### sort 排序(小到大)

```ruby=
list=[1,3,4,1,7,nil,7]
p list.compact.sort #[1, 1, 3, 4, 7, 7]

```
### uniq 將陣列中重複的元素拿掉

```ruby=
list=[1,3,4,1,7,nil,7]
p list.compact.sort.uniq #[1, 3, 4, 7]
```
## 範圍 

(1..10) 範圍 1 ~ 10
('a'..'z') 範圍 a ~ z
(1...10) 範圍 1 ~ 9
:::success
口訣: 多一點的少一點，少一點的多一點
:::

* .to_a 會將結果轉為陣列

印出1~10
```ruby=
for i in 1..10
    puts i
end
```

練習:
印出 1~100 的單數
```ruby=
p (1..100).select{|x| x%2 ==1}
p (1..100).select{|x| x.odd?} 
#odd:奇數 ?:詢問 odd?:詢問是否為奇數
```

印出 1~100 的總和
```ruby=
i = (1..100).to_a
p i.reduce{|sum,x| sum+x}

p (1..100).sum # sum為單純計算總合用，結果一樣

```

印出5個小於100且不重複的亂數
* shuffle 隨機打亂排序，
```ruby=
p (1..100).to_a.shuffle.first(5)
```

* simple 從陣列中隨機取樣
```ruby=
p (1..100).to_a.sample(5)
```
---

## Hash
類似字典的概念，key跟value的組合

:::warning
* key跟分號不能有空格
:::

### 建立方式
```ruby=
a = Hash.new 
```
或用 b= {} 來建立 (name 為 key ,age 為 value)
```ruby=
b = {name: 'kk', age: 18} #Ruby 1.9之後的新式寫法
```
:::info
舊式寫法
```ruby=
b = {:name => 'kk', :age => 18} 
```
:::

#### 取用key的值 (對的key拿到對的value)

```ruby=
b = {name: 'kk', age: 18}
p b[:name] #"kk"
```

#### 印出全部keys跟values的方式

```ruby=
b = { name: 'kk', age: 18} 

p b.keys #[:name, :age]
p b.values #["kk", 18]
```
---
## 符號 (symbol)
符號不是個變數，他就是一個值
1 是數字物件，"aa"是字串物件，:hello是符號物件
name = "kk" 全域變數name指定為"kk"
:name = "kk" 語法錯誤，因為兩個都是值
```ruby=
myname = "Mike"
name = :name
```
字串的內容可以變，但符號(Symbol)不行
```ruby=
name = "abcdefg"
name[1] = "x"
p name  #axcdefg
```

```ruby=
name = :abcdefg
name[1] = "x"
p name  #語法錯誤，符號(Symbol)不能改
```
字串的效能比符號差一點
印出
```ruby=
p "hello".object_id 每次都會給新的記憶體位置
p :hello.object_id 每次都會給同一個記憶體位置
```
:::info
object_id 可以印出這個物件在ruby空間的記憶體位置
:::

冷凍字串

puts "hello".freeze.object_id 固定其記憶體位置

### 字串轉符號
```ruby=
p "name".to_sym #印出:name
p "name".intern #印出:name
```

### 符號轉字串
```ruby=
p :name.to_s #印出name
p :name.id2name #印出name
```

結論: 字串 vs 符號
不可變，選擇符號or冷凍字串
需要組合需要變化，選擇字串






























