# [Ruby]ruby簡易筆記(含rails特定語法)
###### tags: `ruby`
## class & module
### 使用nested module class內的function
this_is_some_class.rb
```ruby
module Module1
module Module2
class ThisIsSomeClass
# ...
def fn1(params1)
end
end
end
end
```
呼叫方式:
```ruby
::Module1::Module2::ThisIsSomeClass.fn1(params1)
```
## Scope
### public,private & protected
https://kaochenlong.com/2011/07/26/public-protected-and-private-method-in-ruby/
## Loop
### 繼續下一個迴圈: 用next
https://stackoverflow.com/questions/4230322/in-ruby-how-do-i-skip-a-loop-in-a-each-loop-similar-to-continue
```ruby
(1..10).each do |a|
next if a.even?
puts a
end
```
## Enumerable
### max_by
https://apidock.com/ruby/Enumerable/max_by
Returns the object in enum that gives the maximum value from the given block.
If no block is given, an enumerator is returned instead.
```ruby!
p ["t","tt","ttt"].max_by{|x| x.length} #=>"ttt"
p ["t","tt","ttt"].max_by(&:length) #=>"ttt"
p [*1..10].max_by{|x| x} #=>10
p [*1..10].max_by().max #=>10
```
### group_by
https://apidock.com/ruby/Enumerable/group_by
group_by() public
Groups the collection by result of the block.
Returns a hash where the keys are the evaluated result
from the block and the values are arrays of elements
in the collection that correspond to the key.
If no block is given an enumerator is returned.
```ruby!
p (1..6).group_by(&:even?) #=>{false=>[1, 3, 5], true=>[2, 4, 6]}
p (1..6).group_by(&:odd?) #=>{true=>[1, 3, 5], false=>[2, 4, 6]}
p (1..6).group_by{|x| x > 3 } #=>{false=>[1, 2, 3], true=>[4, 5, 6]}
p (1..6).group_by{|x| x % 2 } #=>{1=>[1, 3, 5], 0=>[2, 4, 6]}
```
#### group_by延伸: group_by_hash
https://apidock.com/ruby/Enumerable/group_by
```ruby
def group_by_hash hash, value
hash.group_by do |k,v|
v > value ? "Big" : "Small"
end
end
marks = {"Chair" => 30, "Table" => 40, "Bed" => 60, "stool" => 20}
group_by_hash(marks, 30)
#=>{"Small"=>[["Chair", 30], ["stool", 20]], "Big"=>[["Table", 40], ["Bed", 60]]}
```
---
## regex
### =~用法簡例
```ruby
s = "how now brown cow"
p s =~ /how/ #=>0
p s =~ /now/ #=>4
p s =~ /brown/ #=>8
p s =~ /xxx/ #=>nil
```
### scan用法簡例
```ruby
#ex1
str1="apple"
p str1.scan(/./) #=>["a", "p", "p", "l", "e"]
p str1.scan(/../) #=>["ap", "pl"]
p str1.scan(/.../) #=>["app"]
#ex2
str2 = "cruel world"
arr =[]
str2.scan(/\w+/){|x| arr << "<<#{x}>>"}
p arr #=>["<<cruel>>", "<<world>>"]
```
### 除去url後面的hash
https://www.codewars.com
```ruby
url="www.codewars.com#about"
p url[/[^#]+/] #=>"www.codewars.com"
```
### 取代所有非英文的字元
```ruby
txt="這是中文abcde"
txt=txt.gsub(/\P{ASCII}/, '')
p txt #=>"abcde"
```
### 解析Hash字串值
https://stackoverflow.com/questions/1667630/how-do-i-convert-a-string-object-into-a-hash-object
```ruby!
require 'json'
# Example ruby hash string which exercises all of the permutations of position and type
# See http://json.org/
ruby_hash_text='{"alpha"=>{"first second > third"=>"first second > third", "after comma > foo"=>:symbolvalue, "another after comma > foo"=>10}, "bravo"=>{:symbol=>:symbolvalue, :aftercomma=>10, :anotheraftercomma=>"first second > third"}, "charlie"=>{1=>10, 2=>"first second > third", 3=>:symbolvalue}, "delta"=>["first second > third", "after comma > foo"], "echo"=>[:symbol, :aftercomma], "foxtrot"=>[1, 2]}'
#puts ruby_hash_text
# Transform object string symbols to quoted strings
ruby_hash_text.gsub!(/([{,]\s*):([^>\s]+)\s*=>/, '\1"\2"=>')
# Transform object string numbers to quoted strings
ruby_hash_text.gsub!(/([{,]\s*)([0-9]+\.?[0-9]*)\s*=>/, '\1"\2"=>')
# Transform object value symbols to quotes strings
ruby_hash_text.gsub!(/([{,]\s*)(".+?"|[0-9]+\.?[0-9]*)\s*=>\s*:([^,}\s]+\s*)/, '\1\2=>"\3"')
# Transform array value symbols to quotes strings
ruby_hash_text.gsub!(/([\[,]\s*):([^,\]\s]+)/, '\1"\2"')
# Transform object string object value delimiter to colon delimiter
ruby_hash_text.gsub!(/([{,]\s*)(".+?"|[0-9]+\.?[0-9]*)\s*=>/, '\1\2:')
#puts ruby_hash_text
puts JSON.parse(ruby_hash_text)
```
---
## numeric
### 判定是否為浮點數
https://stackoverflow.com/questions/1034418/determine-if-a-string-is-a-valid-float-value
```ruby=
!!Float(ur_var) rescue false
```
### ruby數學運算特性:互除取整數
```ruby
p 6/5 #=>1
p 4/5 #=>0
```
可用此觀念配合三元運算子做出判斷式:
```ruby
n/65>= 1 ? "elderly" : n/18>= 1 ? "adult" : n/13 >= 1 ? "teeanger"
```
### >> : 除以2的次數
```ruby
p 8 >> 1 #=>8/2=4
p 8 >> 2 #=>8/4=2
p 8 >> 3 #=>8/8=1
p 8 >> 4 #=>8/16=0.5,取整數部份0
p 18 >> 1 #=>18/2=9
p 18 >> 2 #=>18/4=4.5,取整數部份4
p 18 >> 3 #=>18/8=2.25,取整數部份2
```
### 判定n可否被args整除
```ruby
def fn(n,*args)
args.all?{|x| (n%x).zero?}
end
p fn(10,5,3,1) #=>false
p fn(10,5,2) #=>true
```
### 判定奇數偶數:使用all? ,any?
```ruby
p [1,3,5].all?{|x| x.odd?} #=>true
p [1,2,4].any?{|x| x.odd?} #=>true
```
### to_i,floor,div
```ruby
p 1.4.to_i #=>1
p 1.4.floor #=>1
p 1.6.to_i #=>1
p 1.6.floor #=>1
p 10.4.div(2) #=>5
p 10.6.div(2) #=>5
```
---
## Hash & Hash Array
### 根據value找hash的key
https://makandracards.com/makandra/30959-ruby-find-a-hash-key-given-it-s-value
```ruby
hash = { "a" => 100, "b" => 200, "c" => 300, "d" => 300 }
hash.key(200) #=> "b"
hash.key(300) #=> "c"
hash.key(999) #=> nil
```
### 保留hash陣列的特定keys
https://stackoverflow.com/questions/9096649/delete-array-of-keys-in-ruby-hash
```ruby
hash_array = { a: 100, b: 200, c: 300, d: 400 , e: 500}
key_to_preserve = [:a, :b, :c]
p hash_array.slice(*key_to_preserve)
```
### 檢查hash某值是否存在hash array的hash中
https://stackoverflow.com/questions/1514883/determine-if-a-value-exists-in-an-array-of-hashes
```ruby
array_of_hashes.any? {|h| h[:a] == 11}
```
### 迭代hash array
https://stackoverflow.com/questions/23718284/how-do-i-iterate-over-an-array-of-hashes-and-return-the-values-in-a-single-strin
```ruby
hash_arr = [
{"id1"=>"1"},
{"id2"=>"2"},
{"id3"=>"3"},
]
hash_arr.each{|hash|
hash.each{|k,v|
p k,v
}
}
```
### 用中括號+symbol呼叫hash值
```ruby
user={id:1, name:'user'}
p user.name #=>error
p user[:name] #=>"user"
```
### 將偶數數量的陣列轉為Hash(偶數元素為鍵,奇數元素為值)
```ruby
a=["key1","value1","key2","value2"]
p Hash[*a]
#=>{"key1"=>"value1", "key2"=>"value2"}
```
### 依據hash的值排序hash array
https://stackoverflow.com/questions/13216092/how-to-sort-a-hash-by-value-in-descending-order-and-output-a-hash-in-ruby
https://stackoverflow.com/questions/5483889/how-to-sort-an-array-of-hashes-in-ruby
```ruby
# 反向排序並取前五個值
array_of_hashes = array_of_hashes.sort_by{|x| x[1]}[0..4]
# 正向排序並取前五個值
array_of_hashes = array_of_hashesh.sort_by{|k, v| v}.reverse[0..4]
# 正向排序
array_of_hashes.sort_by { |hsh| hsh[:zip] }
# 反向排序
array_of_hashes.sort_by { |hsh| hsh[:zip] }.reverse
```
### 計算hash array中某key值相同的hash的數量
```ruby
arr=[
{a:"aaa"},
{a:"aaa"},
{a:"aaa"},
{a:"bbb"},
{a:"bbb"},
{a:"bbb"},
{a:"bbb"},
{a:"ccc"},
{a:"ccc"},
{a:"ccc"},
{a:"ccc"},
{a:"ccc"},
]
new_hash={}
arr.each{|hash|
new_hash[hash[:a]] = 1 if new_hash[hash[:a]].nil?
new_hash[hash[:a]] += 1
}
p new_hash #=>{"aaa"=>3, "bbb"=>4, "ccc"=>5}
```
### 根據hash array中某key的值相同的hash加總另一個key的值
```ruby
arr=[
{a:"aaa",b:1},
{a:"aaa",b:2},
{a:"aaa",b:3},
{a:"bbb",b:10},
{a:"bbb",b:20},
{a:"bbb",b:30},
{a:"ccc",b:100},
{a:"ccc",b:200},
{a:"ccc",b:300},
]
new_hash={}
arr.each{|hash|
new_hash[hash[:a]] = hash[:b] if new_hash[hash[:a]].nil?
new_hash[hash[:a]] += hash[:b]
}
p new_hash #=>{"aaa"=>6, "bbb"=>60, "ccc"=>600}
```
### 取出特定key的hash
https://icook.engineering/ruby-hash-%E7%9A%84%E4%B8%80%E4%BA%9B%E6%87%89%E7%94%A8%E6%8A%80%E5%B7%A7-9fad96c758dd
```ruby
h = { a: 1, b: 2, c: 3, d: 4 }
keys = [:a,:b]
p h.select {|k,v| keys.include? k }
```
---
## string
### %w
```ruby
p %w[aaa bbb ccc] #=>['aaa','bbb','ccc']
```
### 計算字元數
```ruby
p "abc".size #=>3
p "a b c".size #=>5
```
### 將字串轉換成以字元為元素的陣列
```ruby
p "abc".chars #=>["a", "b", "c"]
```
### 迭代字串中的每個字元
```ruby
"abc".each_char.with_index{|v,i|
p "the #{i+1}th char is #{v}"
}
=begin
"the 1th char is a"
"the 2th char is b"
"the 3th char is c"
=end
```
---
## Array & Range
### 空陣列特性
```ruby
p [].all? #=>true
```
### 判定數字是否在range範圍內:使用between?
https://www.codewars.com/kata/be-concise-i-the-ternary-operator
```ruby
p 5.between?(1,5) #=>true
```
### 清空陣列
```ruby
arr=[1,2,3]
arr.clear
```
### 合併陣列並去除重複值
交集
```ruby
arr = [1,2,3] & [2,3,4]
p arr #=>[2,3]
```
聯集
```ruby
p ([1,2,3]+[2,3,4]).sort.uniq #=>[1,2,3,4]
```
### flatten方法
```ruby
p [[1,2],[3,4]].flatten #=>[1, 2, 3, 4]
p [[1,2],[3,4,[5,6]]].flatten(1) #=>[1, 2, 3, 4, [5, 6]]
```
### flatten.map方法
#### ex1: 將陣列內所有元素字串全部轉換成symbol
```ruby
arr1 = ["a","b","c",["d","e",["f","g"]]]
p arr1.flatten.map(&:to_sym)
# [:a, :b, :c, :d, :e, :f, :g]
```
### 陣列排序: 使用sort跟<=>
```ruby
arr=["aa","bb","cc"]
p arr.sort{|x,y| y<=>x} #=>["cc", "bb", "aa"]
p arr #=>["aa", "bb", "cc"]
```
### 取出陣列最大值:使用reduce
```ruby
arr=[3,11,7,5,9]
p arr.inject(0){|a,b| a > b ? a : b} #=>11
p arr.reduce(0){|a,b| a > b ? a : b} #=>11
```
>reduce = inject
---
## Block,Proc & lambda
### 直接呼叫block
```ruby
def fn(&block)
#以下方式均可行:
#block.()
# block[]
#block.call
#block.yield
block===nil
end
fn{p "block here"} #=>"block here"
```
### 將block轉為物件
#### 使用Proc
```ruby
b1=Proc.new{|x| p x}
[*1..3].each(&b1)
#1
#2
#3
```
#### 使用lambda
```ruby
#方1
succ_lamda=lambda{|x| x+2}
p succ_lamda.call(3) #=>5
#方2
succ_arrow=->(x){x+2}
p succ_arrow.call(3) #=>5
```
### 直接呼叫Proc物件/lambda物件
```ruby
b1=Proc.new{|x| p x}
b2=Proc.new{'block here'}
b1.call("ttt") #=>"ttt"
b1.("ttt") #=>"ttt"
b1==="ttt" #=>"ttt"
b1.yield "ttt" #=>"ttt"
b2.call() #=>nil
b1.() #=>""
b1==="" #=>""
b1.yield "" #=>""
```
### lambda與proc差別
https://pjchender.github.io/2017/09/26/ruby-%E7%A8%8B%E5%BC%8F%E7%A2%BC%E5%8D%80%E5%A1%8A%EF%BC%88block%EF%BC%89-proc-%E5%92%8C-lambda/
>lambda會檢查傳入參數的數目,proc不會
>lambda遇到return後會將控制權交還給呼叫它的方法;
>Proc遇到return後會立即跳出該方法
---
## debug
### 設定中斷點: 使用binding.pry