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)