1、ruby hash

1-1、新增hash

舊版

h = { :name => "ccc", :age => 18 }

新版

h = { :name: "ccc", :age: 18 }

不過其實把 h 印出來,其實還是跟舊版一樣,新版的寫法只是語法糖,實際是沒改的

p h             # { :name => "ccc", :age => 18 }

1-2、hash取值

記得取值要特別注意要放符號,要不然value印不出來

錯誤示範

p h["name"]  # X

正確示範

p h[:name]   # "ccc"

1-3、取出所有的key、values

先創一個新hash

profile = {:name: 'ccc', :age: 18}

取keys或者values值

p profile.keys   #[:name, :age]
p profile.values   #["ccc", 18]

2、Symbol 符號

ruby中的的數字object_id,所有數字的object_id都是奇數(2n+1),因此可以推斷出所有字串的object_id都是偶數

2-1、字串的object_id

p "hello".object_id         # 60
p "hello".object_id         # 80
p "hello".object_id         # 100

2-2、符號的object_id

p :name.object_id           # 71068
p :name.object_id           # 71068
p :name.object_id           # 71068

2-3、數字的object_id -> 2n + 1

p 100.object_id             # 201
p 100.object_id             # 201
p 100.object_id             # 201

符號介紹詳解 - 點我觀看

3、簡易測驗 - 計算陣列中,所有字數出現次數

> a = [1, 2, 3, 1, 2, 1, 3, 1, 2, 3, 4, 5, 6]
> 
> p a.group_by{ |n| n }.transform_values(&:size) -> 比較複雜的解法
> 
> p a.tally   -> 正確答案是這個
> 
> 會印出 {1=>4, 2=>3, 3=>3, 4=>1, 5=>1, 6=>1}

4、區域變數的nameError

下面會印不出來喔!!! 因為a是在外面定義變數,ruby不會從外面找答案

a = 1
def hi
  p a
end

hi            # nameError

面試題
Book.find => find如果錯誤,會噴出錯誤警告,而且find後面只能接數字
Book.find_by => find_by錯誤,只會給一個nil,find_by後面可以接其他的欄位
Book.find_by! => Exception,加一個驚嘆號就如果錯誤的話,就會跳錯誤警告給你


5、rake

(1) man = manual 是看某個指令的描述
(2) 在終端機輸入,可以得知make指令在電腦是幹嘛的

> man make

(3) 要介紹rake錢,為啥會提到make,因為 rake = ruby make,輸入rake,電腦會要你產生一個rakefile的檔案

5-1、default task

如果今天有設定預設任務,那假設直接下rake指令,會直接執行hi這個task

> task :default => :hi

5-2、hello任務設定

desc "見面"                 # task的描述
task :hello do             # 任務名稱
    p "hello world"        # 任務執行內容
    p "1"
    p "2"
end

5-3、任務相依性

做hi之前,先做hello動作

desc "這是測試"
task :hi => :hello do      # 執行hi前,先執行hello
    p "hello world"
end

5-4、namespace

實作一個db:migrate
用namespace把task包住,呼叫此任務就變成這樣

namespace :db do       # namespace是用來分類的
  desc "migrate"       # 描述
  task :migrate do     # 任務名稱
    p "good"
  end
end

rake db:migrate        # 印出good(呼叫任務)

6、Block


Block是什麼?Block其實就是一段程式碼,更精確的說
block是一段不會被主動執行的程式碼


6-1、yield

Block會依附在方法後面,會不會執行要看原本宿主的臉色

6-1-1、沒有yield

> 我們先來定義一個方法(還沒有加上block)

> def say_hello            #控制權"2"
>   puts "hi,早安"         #控制權"3"
> end
> say_hello                #控制權"1"
> puts "午安"               #控制權"4"              #hi, 早安
>                                                  午安
>                                                  (照控制權印出這兩個)

> 接著讓方法加上block
> 
> def say_hello            #控制權"2"
>   puts "hi,早安"         #控制權"3"
> end
> say_hello {              #控制權"1"
>   puts "晚安"             # -沒有執行- 原因是def say_hello end沒有yield
> }                
> puts "午安"               #控制權"4"              #hi, 早安
>                                                  午安

6-1-2、加上yield

> 加上yield後的執行流程

> def say_hello            #控制權"2"
>   puts "hi,早安"         #控制權"3" ->印出 1 
>   yield                  #控制權"4"
>   puts "睡覺拉"           #控制權"6" ->印出 3
> end
> say_hello {              #控制權"1"
>   puts "晚安"             #控制權"5" ->印出 2
> }
> puts "午安"               #控制權"4" ->印出 4       
>                                                   #hi, 早安
>                                                    晚安
>                                                    睡覺拉
>                                                    午安

yield是什麼?就是把控制權轉讓給方法後面的block


6-1-3、yield帶參數

用yield轉讓的同時,也可以帶上其他的變數 or 數字

> def say_hello            
>   puts "hi,早安"         
>   yield 3                # yield 帶著其他東西
> end

> say_hello { |num|        # 控制權轉移到Block時, 3也被帶下來到 num
>   puts num               # 印出 num = 3                           # 3
> }

6-1-4 block回傳結果給yield

Block完成後,會自動回傳Block裡面的最後一行執行結果(傳回yield那邊),接著可以用if判斷要印出的東西

> 觀察控制權

> def test_three                     #      2
>   if yield(3)                      #      3
>     puts "it's 3"                         5  -true的話就是這個
>   else
>     puts "it's not 3"                     5  -false就是這個
>   end
> end

> test_three { |n|                   #控制權 1
>   n == 3                           #      4  -這一步驟會判斷true/false
> }                                            
>                                    # it's 3 - 最終印出結果

6-1-5、沒block,有yield

假設今天沒有Block,又有寫出yield的話會發生什麼事 — 會噴錯

> def say_good
>   yield
> end
> say_good                           # X (No block given)

6-2、block + yield 實戰練習

6-2-1、實作一個map功能

def my_map(arr)
    lst = []
    arr.each do |n|
        lst << yield(n)
    end
    lst
end

result = my_map([1,2,3,4,5]) {|x| x * 2}

p result

6-2-2、實作一個filter功能

def my_filter(arr)
    lst = []
    arr.each do |n|
        lst << n if yield(n)
    end
    lst
end

list = [1, 2, 3, 4, 5]
result = my_filter(list) { |x| x > 2 }

p result # [3, 4, 5]

6-3、block面試題


Q. do…end、{}兩種block哪邊不一樣
Ans.
結合率強度不同,do…end的結合率強度比較低,像是加號,{}的強度比較強,像是乘號
強度比較弱會發生什麼事,會變成被p搶走


這樣講有點抽象,舉個例子,先給一個陣列

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

6-3-1、使do…end

使用do..end的關係,p會把list.map搶走,因此會印出Enumerator這個

p list.map do |item|                # <Enumerator: [1, 2, 3, 4, 5]:map>
  item * 2
end

6-3-2、使用{}

p list.map { |item| item * 2 }      # [2, 4, 6, 8, 10]

7、Rails Scope設定

7-1、lambda沒給參數

class Book
  scope :cheap, -> {  where ("price < 50") }
end

Book.cheap

7-2、lambda有給參數

class Book
  scope :cheap, -> (n){  where ("price < n") }
end

Book.cheaper_than(100)

7-3、預設 Scope

使用預設Scope後,之後這個Book所有的查詢,都會被加上order id這一段搜尋

class Book
  default_scope {order('id DESC')}
end

7-4、取消預設 Scope

如果今天設定了預設scope,但是有一個地方的查詢不想用到預設scope怎麼辦? 可以這樣設定取消預設搜尋

Book.unscope(:order)

也可以這樣取消預設後,再增加想要新增的搜尋

Book.unscope(:order).order(:title)