Ruby
===
###### tags: `Programming Language` `QCT`
## Bundler
### How to use Bundler in a single Ruby script
* Ruby
```
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'json', require: false
gem 'nap', require: 'rest'
gem 'cocoapods', '~> 0.34.1'
end
puts 'Gems installed and loaded!'
puts "The nap gem is at version #{REST::VERSION}"
```
* Ruby on Rails
```
bundle exec ruby tools/log_processing/split_log_by_pid_tid.rb log/development.log
```
## RubyGems
* [gem install 之後,那些 gem 安裝到哪裡去了?](https://kaochenlong.com/2016/04/29/where-are-the-installed-gems/)
* 刪除特定版本的gem
```
gem uninstall -i /usr/local/rvm/gems/ruby-2.5.5@global rake -v 12.3.0
```
* [使用套件(Gem)讓開發更有效率](https://railsbook.tw/chapters/09-using-gems.html)
* ```~> 4.1.0```: 選用 4.1.0 以上,但 4.2 以下(不包括 4.2)的最新版本
* 更新Gemfile檔案內容後,要到該專案目錄底下執行```bundle install```指令
## Ruby on Rails
- RubyGems vs. Bundler
[RubyGems](http://guides.rubygems.org) is a Ruby dependency manager for whole environment, and [Bundler](https://bundler.io/) is a Ruby dependency manager for Ruby app that can even pass arguments to make needed gems installed in whatever folder for development, staging, and production.
- Binstub
```bin/rails server```=```bundle exec rails server```
```bin/rails s -b 10.103.3.73```
- [Model、View、Controller 三分天下](https://railsbook.tw/chapters/10-mvc.html)
* view
* index.html.erb
ERB(Embedded Ruby)是由Ruby標準函式庫中的ERB樣版引擎進行解讀Ruby語法,最後會被輸出成HTML
* index.json.jbuilder
jbuilder是用以產生JSON的工具
* controller
* 用```private```區分非action
- [Routes](https://railsbook.tw/chapters/11-routes.html)
* 使用PUT或PATCH方法表示是更新資料
* 使用DELETE方法則是表示刪除資料
* 使用POST方法存取表示是新增資料
```
# rails routes
Prefix Verb URI Pattern Controller#Action
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
```
```ruby
Rails.application.routes.draw do
get "/posts", to: "posts#index"
get "/posts/:id", to: "posts#show"
end
```
:::info
當使用者輸入```/posts/123```這個網址之後,它會轉由```PostsController```上的```show```方法,並且把```123```當做參數(:id)傳給Controller。
:::
- [Rake is the make of ruby.](https://medium.com/@pk60905/%E5%9C%A8ruby%E5%92%8Crails%E4%B8%AD%E7%9A%84rake%E6%98%AF%E4%BB%80%E9%BA%BC-2eeefe99d7ce)
- 多重環境: Development, Test, Production
* config/database.yml
* config/environments/development.rb
* config/environments/test.rb
* config/environments/production.rb
- Ruby on Rails 自習手冊
* 資料庫之旅
* ```rails dbconsole```: 打開所使用的資料庫命令列介面(支援 MySQL、PostgreSQL、SQLite以及SQLite3)
* ```rails console```: irb環境,預先載入rails環境,用來操作model類別。
* ```rake db:migrate```: 執行migration files(檔名包含流水號)。
* 前端之旅
* view helper本身是Ruby的方法,有URL helper, form helper, tag helper, 自訂helper。
* URL helper: 由網址路由動態產生,有別於其他helper已經寫在Rails原始碼,會是prefix_path或prefix_url。
* 自訂helper: 在app/helpers目錄下的檔案定義module方法,由於Rails是利用mixin擴展到view,所以無法規劃namespace,應避免撞名。
* 後端之旅
* REST(Representational State Transfer)是軟體架構的設計風格(網站只是其中一種應用),並非只是網址規範。
* POST送出的表單變數和GET網址上的變數,都會進params Hash。
- [RSpec](https://ihower.tw/rails/testing.html)
* 軟體測試層面
* Unit Test:最小的測試粒度,由開發者負責
* Integration Test:測試多個元件之間的互動正確
* Acceptance Test:最大的測試粒度,由測試工程師負責
* RSpec是Ruby的BDD(Behavior-driven development)測試框架,強調用spec思維,描述程式應該有什麼行為。
* spec目錄放測試程式,本來的test目錄就用不著了。
* ```describe```和```context```
* 用於組織分類,可任意套疊,通常最外層是想要測試的類別,然後下一層是哪一個方法,然後是不同的情境。
* 它的參數可以是一個類別,或是一個字串描述。
* ```specify```=```example```=```it```
* [Matcher](https://relishapp.com/rspec/rspec-expectations/docs/built-in-matchers)
* [ActiveSupport::Inflector.constantize](https://apidock.com/rails/String/constantize)
- [Rails ERD](https://github.com/voormedia/rails-erd)
## Ruby
### Hook Methods
* Included
When you include the module in a class, the included hook will be called.
```
class MyClass
include MyModule
end
```
```
# non-Rails version
module MyModule
def self.included(base)
base.class_eval do
# somecode
end
end
end
# Rails version with ActiveSupport::Concerns
module MyModule
included do
# somecode
end
end
```
### [Ruby 程式語言入門](https://ihower.tw/rails/ruby.html)
* Ruby是個動態強分型的直譯式程式語言
:::info
Dynamic Type: 不需先宣告變數型別
Strong Type: 不會自動轉換型別
:::
* Symbol
* Symbol只要內容相同,就是相同的物件(相同記憶體編號)
* 雖然可以使用任何物件當作Key,通常使用Symbol當作物件的Key
* 只有false和nil是假,其他都為真
* 方法中的return是可以省略的,Ruby就會回傳最後一行運算的值
* 方法以```?```結尾表示會回傳boolean值;以```!```結尾暗示會有某種副作用(side-effect)
* 類別其實也是一種常數,所以也是大寫開頭
* 類別中的方法預設是public的,宣告private或protected的話,該行以下的方法就會套用
* [Ruby 語法放大鏡之「attr_accessor 是幹嘛的?」](https://kaochenlong.com/2015/03/21/attr_accessor/)
* ```attr_reader```只會幫你產生getter,```attr_writer```只會幫你產生setter,而```attr_accessor```則會幫你產生getter及setter
* 類別方法 vs. 類別變數
* [attr_accessor, validates, before_action, private, protected是類別方法](https://kaochenlong.com/2016/04/28/class-method/)
```
class Person
@@name = “ihower” # 類別變數
def self.say # 類別方法
puts @@name
end
end
Person.say # 輸出 ihower
```
* Module
* 第一個用途是當做namespace來放一些工具方法,如[兩個冒號](https://kaochenlong.com/2015/04/19/namespace/)。
```
class A
def self.global?
true
end
end
module B
class A
def self.global?
false
end
end
def self.a
puts A.global?
puts ::A.global?
end
end
B::a
```
prints
```
false
true
```
* 第二個用途是mixin,讓class直接include module,class就會擁有此module的方法,可以解決class多重繼承的問題。
* [Iterators](http://blog.blackninjadojo.com/ruby/2019/02/09/using-select-reject-collect-inject-and-detect.html)
* [Block](https://railsbook.tw/chapters/07-ruby-basic-3.html)
* Block通常得像寄生蟲一樣依附其它的方法或物件
* Block透過```Proc```物件化
* Block依附在呼叫方法時,透過```yield```執行
* Block最後一行的執行結果也會自動變成Block的回傳值
* 如果Block的內容有多行,通常會建議使用```do```...```end```寫法,如果只有一行,則建議使用```{```...```}```寫法
* Proc
In a method argument list, the **&** operator takes its operand, converts it to a ```Proc``` object if it isn't already (by calling ```to_proc``` on it).
```
my_proc = Proc.new { puts "foo" }
my_method_call(&my_proc)
```
* Try
如果```current_user```是```nil```,便不會呼叫```is_admin?```
```
if current_user.try(:is_admin?)
# do something
end
```
### Others
- [Ruby can be leveraged to create an internal DSL by metaprogramming techniques.](https://medium.com/@admios/understanding-ruby-metaprogramming-and-dsls-a7e9928665be)
:::info
```instance_eval``` evaluates a string containing Ruby source code, or the given block, within the context of the receiver (obj).
:::
- [Ruby的錯誤處理機制begin、rescue和Exception](https://medium.com/@pk60905/rails%E7%9A%84%E9%8C%AF%E8%AA%A4%E8%99%95%E7%90%86%E6%A9%9F%E5%88%B6begin-rescue%E5%92%8Cexception-ab71156a24a2)
- [基础 Ruby 中 Include, Extend, Load, Require 的使用区别](https://ruby-china.org/topics/25706)