2018年2月27日 星期二
rails table_name_prefix
```rb
module Snapshot
def self.table_name_prefix
'snapshot_'
end
end
```
```rb
class Snapshot::Schedule < ActiveRecord::Base
end
```
會使用 snapshot_schesules table
2018年2月26日 星期一
想在 server 上持續性地跑個簡單的 script
screen
進到 screen
```sh
screen
```
Detach (離開 screen, 但是讓 screen 裡面的東西繼續執行)
```
ctrl+a d
```
Re-attach (重回 screen)
```sh
screen -r
```
如果有多個就先 screen -ls 找到 screen id 然後 `screen -r screen_id`, ex:
```sh
pungki@mint ~ $ screen -ls
There are screens on:
7849.pts-0.mint (10/06/2013 01:50:45 PM) (Detached)
5561.pts-0.mint (10/06/2013 11:12:05 AM) (Detached)
2 Sockets in /var/run/screen/S-pungki
```
```sh
pungki@mint ~ $ screen -r 7849
```
https://www.tecmint.com/screen-command-examples-to-manage-linux-terminals/
https://stackoverflow.com/questions/4797050/how-to-run-process-as-background-and-never-die
2018年2月24日 星期六
RSpec best practice
https://github.com/thoughtbot/guides/tree/dee16052f49cb4b41fb8d090ffdb75942512ddb1/best-practices#testing
https://robots.thoughtbot.com/lets-not
看到一個不錯的 mock example (RSpec)
之前一篇文章提到 RSpec 盡量不用 let, 那要用啥?可以用 method。
另外看到一個不錯的 mock example, 用 tap 來 return double 但是 yield Authentictor
```rb
def stub_authenticator(auth_hash)
double('authenticator').tap do |authenticator|
Authenticator.stub(:new).with(authenticator).and_return(authenticator)
end
end
def stub_find_user(attributes = {})
build_stubbed(:user, attributes).tap do |user|
User.stub(:find).with(user.to_param).and_return(user)
end
end
```
https://apidock.com/ruby/Object/tap
另外看到一個不錯的 mock example, 用 tap 來 return double 但是 yield Authentictor
```rb
def stub_authenticator(auth_hash)
double('authenticator').tap do |authenticator|
Authenticator.stub(:new).with(authenticator).and_return(authenticator)
end
end
def stub_find_user(attributes = {})
build_stubbed(:user, attributes).tap do |user|
User.stub(:find).with(user.to_param).and_return(user)
end
end
```
https://apidock.com/ruby/Object/tap
from https://thoughtbot.com/upcase/videos/rspec-best-practices
great feature spec example
```rb
feature 'User views all books' do
scenario 'list all books' do
create(:book, title: 'Practical Vim')
create(:book, title: 'The Giver')
visit books_path
expect(page).to have_book('Practical Vim')
expect(page).to have_book('The Giver')
end
# ...
def have_book(title)
have_selector('.book', text: title)
end
end
```
Mutation in Ruby, it tells why more and more people like pure functional (immutable function)
Some mind blown examples:
```rb
[1] pry(main)> list = Array.new(5, "foo")
# => ["foo", "foo", "foo", "foo", "foo"]
[2] pry(main)> list[4].clear
# => ""
[3] pry(main)> list
# => ["", "", "", "", ""]
```
因為每個 default foo 都是同一個 object
以及
```rb
[1] pry(main)> master_list = Hash.new([])
# => {}
[2] pry(main)> master_list[:evens] << 2
# => [2]
[3] pry(main)> master_list[:odds] << 3
# => [2, 3]
[4] pry(main)> master_list
# => {}
[5] pry(main)> master_list[:evens] <<= 4
# => [2, 3, 4]
[6] pry(main)> master_list
# => {:evens=>[2, 3, 4]}
[7] pry(main)> master_list[:odds] <<= 5
# => [2, 3, 4, 5]
[8] pry(main)> master_list
# => {:evens=>[2, 3, 4, 5], :odds=>[2, 3, 4, 5]}
```
一樣的原理,每個 default array 都是同一個 object
一個避免這樣的做法是用 proc 確保每個 default 值是不同 object,例如:
```rb
Array.new(5) { "foo" }
Hash.new { [] }
```
ex:
```rb
[1] pry(main)> Array.new(5) { "foo" }
=> ["foo", "foo", "foo", "foo", "foo"]
[2] pry(main)> a = Array.new(5) { "foo" }
=> ["foo", "foo", "foo", "foo", "foo"]
[3] pry(main)> a[2].clear
=> ""
[4] pry(main)> a
=> ["foo", "foo", "", "foo", "foo"]
[5] pry(main)>
```
另外還有更有趣的「以你為 freeze 了是吧?Boom~!」
```rb
[1] pry(main)> CONSTANT = ["foo"]
# => ["foo"]
[2] pry(main)> CONSTANT << "bar"
# => ["foo", "bar"]
[3] pry(main)> CONSTANT.freeze
# => ["foo", "bar"]
[4] pry(main)> CONSTANT << "baz"
# RuntimeError: can't modify frozen Array
# from (pry):4:in `__pry__'
[5] pry(main)> CONSTANT[1] << "baz"
# => "barbaz"
[6] pry(main)> CONSTANT
# => ["foo", "barbaz"]
```
這是因為 freeze 是 freeze CONSTANT 這個 Array 的 object,沒有 freeze 裡面的 string,所以 string 還是 mutable
(Ice Nine gem for deep freezing)
為了拯救 developers 於水深火熱的加班 debug 地獄中,不需要 mutate 的時候就不要 mutate,寫每個 function 都想一下「這真的有必要 mutate 嗎?」
```rb
[1] pry(main)> list = Array.new(5, "foo")
# => ["foo", "foo", "foo", "foo", "foo"]
[2] pry(main)> list[4].clear
# => ""
[3] pry(main)> list
# => ["", "", "", "", ""]
```
因為每個 default foo 都是同一個 object
以及
```rb
[1] pry(main)> master_list = Hash.new([])
# => {}
[2] pry(main)> master_list[:evens] << 2
# => [2]
[3] pry(main)> master_list[:odds] << 3
# => [2, 3]
[4] pry(main)> master_list
# => {}
[5] pry(main)> master_list[:evens] <<= 4
# => [2, 3, 4]
[6] pry(main)> master_list
# => {:evens=>[2, 3, 4]}
[7] pry(main)> master_list[:odds] <<= 5
# => [2, 3, 4, 5]
[8] pry(main)> master_list
# => {:evens=>[2, 3, 4, 5], :odds=>[2, 3, 4, 5]}
```
一樣的原理,每個 default array 都是同一個 object
一個避免這樣的做法是用 proc 確保每個 default 值是不同 object,例如:
```rb
Array.new(5) { "foo" }
Hash.new { [] }
```
ex:
```rb
[1] pry(main)> Array.new(5) { "foo" }
=> ["foo", "foo", "foo", "foo", "foo"]
[2] pry(main)> a = Array.new(5) { "foo" }
=> ["foo", "foo", "foo", "foo", "foo"]
[3] pry(main)> a[2].clear
=> ""
[4] pry(main)> a
=> ["foo", "foo", "", "foo", "foo"]
[5] pry(main)>
```
另外還有更有趣的「以你為 freeze 了是吧?Boom~!」
```rb
[1] pry(main)> CONSTANT = ["foo"]
# => ["foo"]
[2] pry(main)> CONSTANT << "bar"
# => ["foo", "bar"]
[3] pry(main)> CONSTANT.freeze
# => ["foo", "bar"]
[4] pry(main)> CONSTANT << "baz"
# RuntimeError: can't modify frozen Array
# from (pry):4:in `__pry__'
[5] pry(main)> CONSTANT[1] << "baz"
# => "barbaz"
[6] pry(main)> CONSTANT
# => ["foo", "barbaz"]
```
這是因為 freeze 是 freeze CONSTANT 這個 Array 的 object,沒有 freeze 裡面的 string,所以 string 還是 mutable
(Ice Nine gem for deep freezing)
為了拯救 developers 於水深火熱的加班 debug 地獄中,不需要 mutate 的時候就不要 mutate,寫每個 function 都想一下「這真的有必要 mutate 嗎?」
訂閱:
文章 (Atom)