Tag ruby

在 RSpec 裡測試 Rake Task

最近被 Rake Task 的測試設定搞得一頭霧水,簡單記錄一下測試 Rake Task 的測試設定,以及各種鬼打牆的血淚史: TL;DR 為了避免各種 task 載入、執行狀態等相互干擾導致 test case 會偶發性失敗,每一次執行 test case 時就去做「載入」、「卸載」會比較沒有鬼打牆狀況出現。 # spec_helper.rb config.before(:each, rake: true) do Rails.application.load_tasks end config.after(:each, rake: true) do Rake::Task.clear end 把 Rails.application.load_tasks 放在 before(:each) 確保每次載入 test case 前都有正確 load 到要測試的那隻 task ,並在 after(:each) 時用 Rake::Task.clear 去清空剛剛載入的 Rake Task。 透過 rake: true 這個 flag 可以避免其他不相關的單元測試也去載入 Rake Task。 透過每個 each 都做載入跟卸載 Rake Task 後,就可以在 test case 單純使用 Rake::Task['task_name'].invoke 來手動執行 Task 而不用另外去作載入或卸載。

工具 | Kindle "My Clippings.txt" 的轉檔 gem KCFU

Kindle 的剪貼簿功能雖然在 Kindle 上很好用,但真的要抽出來另外處理書摘的時候還真的麻煩,因為 My Clippings.txt 就是一個很簡單的純文字檔,每次在 Kindle 上面 hightlight / bookmark / notes 時就會依照書的 title 去新增一段特定格式的文字段落,所以如果同時看很多本的時候,打開 My Clippings.txt 會發現裡面就依照 clippings 時序夾雜著來自不同書裡的內容,得再經過一些處理才能分成不同的來源。 原先有找到 firewood 這個套件,不過沒辦法在我的電腦上使用 QQ,乾脆就自己刻個輪子吧。 GitHub 上面的 kindleclippings 是用 Ruby 寫的,簡單又方便使用,站在小巨人的肩膀上刻了一個 kcfu 來做基本的拆分檔案,另外加配了一個陽春的 Markdown 格式轉換器方便做書摘。 最簡單的用法是開一個資料夾,把你的 My Clippings.txt 放到裡面,再寫個小 Ruby 檔: # kcfu.rb require 'kcfu' parser = Kcfu::FileUtil.new parser.parse_file(File.expand_path("#{File.dirname(__FILE__)}/My Clippings.txt"), convert: :markdown) 然後安裝 KCFU(沒有安裝 Ruby 的同學若要服用請先安裝 rbenv 跟 ruby ) gem install kcfu # Under folder of your kcfu.rb and 'My Clippings.

在 Trailblazer 的 Policy 中透過客制 Exception 來處理複雜的「錯誤回應」

為了盡量貼近 Trailblazer 的設計概念,許多原先會透過 Controller before_action 去處理的權限管控,盡量都搬進 Trailblazer 的 Policy 裡。 Policy 採用類似 Pundit 的語法,典型的 Policy 如下: class Thing::Policy def initialize(user, thing) @user, @thing = user, thing end def create? (admin? || approved?) && @thing.persisted? end private def admin? @user.admin == true end def approved? @user.is_approved end end 在 Operation 中若要調用這隻 Policy 的話要宣告: class Thing::Create < Trailblazer::Operation builds -> (params) { dispatched_class_accroding_to(params) } def self.dispatched_class_accroding_to(params) Thing::Create end include Trailblazer::Operation::Policy policy Thing::Policy, :create?

初探 Trailblazer 框架

最近公司的 Rails 專案試用了 Trailblazer 這套整理 Rails 程式碼的框架。(目前使用的是 1.1 版) Trailblazer 是擺在 Rails 上的一套工具,雖然有本專書可以翻找,但實際上就是個自成一格的整理程式碼套路,除了要學新的 DSL 外,在 API 文件沒有寫得非常詳細,加上使用者也沒多到可以 stackoverflow 的情況下,假如開發需求和設計者 Nick Sutterer 設想的情況不一樣時,小小撞牆是難免的。 Trailblazer 是模組化設計,所以並非所有模組需要安裝才能開始享受 Trailblazer 帶來的方便感,除了主要的 Operation / Policy / Contract / Cell 等稍微有摸過外,其他的眉眉角角尚待開發。稍微整理一下截至目前為止使用這套框架的個人認知,這套 Trailblazer 的目的是將原先 Rails 單純 MVC 架構下可能會散亂在 Controller / Model 層的商業邏輯,集中起來包在 Operation 的概念裡,(在理想狀況下)分別簡化日益肥大的 Controller / Model / View 邏輯: Controller 讓 controller 單純負責傳送 current_user / resource 到正確的 operation 並視操作結果導向相對應的路由 權限控管交給 Policy 處理,用 controller 塞給 operation 的 current_user 配合 operation 的 model!

筆記 | Practical Object-Oriented Design in Ruby (POODR)

Practical Object-Oriented Design in Ruby (POODR) 不會很厚,循序漸進地介紹物件導向設計的各種重要概念,而且範例用的是 Ruby 來解說,挺親切的。 除了各種設計原則之外,也簡要解釋了 Inheritance / Module / Composition 的使用時機與差異。 最後一章介紹測試原則,除了說明一般的測試原則之外(例如主要應測試 public interface / incoming message / outgoing command ),也很清楚地說明要怎樣去分別把不同的測試責任分在 module / test double / test class 上,以及讓 test double 與實際的程式碼同步的技巧,可以反覆閱讀的參考書。 Chapter 1 - Object-Oriented Design P.4 Practical design does not anticipate what will happen to your application, it merely accepts that something will and that, in the present, you cannot know what. It doesn’t guess the future; it preserves your options for accommodating the future.

程設風格 | 早期終止執行

剛開始寫程式的時候,以為所謂邏輯判斷就是很多個若 A 則 B 包起來的複雜地圖。這樣的程式碼,很容易因為邏輯判斷太過複雜,很難一眼就看到到底目前程式會跑到哪一個 if 分支裡面執行。 taget = Dog.new if target.is_a?(Animal) if target.has_four_legs? if target.is_a?(Dog) puts "wolf!" else puts "four leg animal can say yeah" end else puts "don't know what that is" end else puts "don't know what that is" end => "wolf!" 如果透過層層過濾只是要剔除一些情況讓程式不處理,例如有很多個分支其實是「不處理」或是「同樣的簡單處理」,例如上面的 puts "don't know what that is" ,可以改用「早期終止」的模式來改寫。 def what_it_says(target) # 如果不符合條件的參數就會在此提早回傳值 return "don't know what that is" unless target.is_a?(Animal) && target.has_four_legs? # 符合資格的參數才會進入真正的必要判斷 if target.