# [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