2017年5月10日 星期三

第三次上五倍紅寶石rails課 5/10 - TDD

今天上的是TDD,範例其實很簡單,但就算這樣想當初第一次上的時候我因為完全沒有這個概念,所以滿頭問號,畢竟那個時候我連更基礎的東西其實都還沒搞懂。

所以我其實很羨慕現在幾乎旁邊都有排一個實習生坐在旁邊的設計。
(不過我當初那個樣子我其實也不知道該從哪邊問起好,大概就像一個一般國中數學也2266的人你突然講微積分給他聽,就算他聽不懂也不知道該從哪問好差不多(?))

不過TDD讓我覺得很有親近感,大概因為我是QA出身?,雖然這是兩個不同的概念(p.s QA要做什麼依公司不同可能沒有有些人想的那麼單純,不過這邊省略介紹XD)

http://railsbook.tw/chapters/24-testing-with-rspec-part-2.html
存錢功能 原本帳戶有 10 元,存入 5 元之後,帳戶餘額變 15 元 原本帳戶有 10 元,存入 -5 元之後,帳戶餘額還是 10
元(不能存入小於等於零的金額) 領錢功能 原本帳戶有 10 元,領出 5 元之後,帳戶餘額變 5 元 原本帳戶有 10 元,試圖領出 20
元,帳戶餘額還是 10 元,但無法領出(餘額不足) 原本帳戶有 10 元,領出 -5 元之後,帳戶餘額還是 10
元(不能領出小於或等於零的金額)
RSpec.describe BankAccount do 

end
執行會出現下面錯誤,因為還沒有BankAccount這個class
NameError:
  uninitialized constant BankAccount

硬讓他過的方法

既然他是說找不到BankAccount這個常數,那我給他一個不就好了==+
反正他就只是一個會指到BankAccount這個class的常數
但是這樣寫code review的時候大概會被打…
BankAccount = 1

RSpec.describe BankAccount do 

end

番外篇

讓class用小寫的方法,雖然實務上用不到..
這邊cc就只是一個指向class的變數
同理上面的RSpec.describe BankAccount的BankAccount也是一樣的概念,就一個指到BankAccount class的常數
cc = Class.new do 
    def hello
        puts "hello"
    end
end

c = cc.new
c.hello

開始寫吧

上面class也用好之後執行rspec會看到很多像下面那種訊息,說找不到method
NoMethodError:
       undefined method `deposit' for #<BankAccount:0x007f9b0b6121c0 @amount=10>
要解決很簡單~給他一個就好了~就算裡面是空的也可以
def deposit(amount)
end
把該加的method都給他之後,現在錯誤訊息應該會像下面這樣
       expected #<Fixnum:31> => 15
            got #<Fixnum:21> => 10
原因也很簡單,因為現在method都是空的,裡面沒有做任何的運算,當然數字不會變成15,正確應該要改成這樣
class BankAccount

  def initialize(amount)
    @amount = amount
  end

  def deposit(amount)
    @amount += amount
  end

  def balance
    @amount
  end
end
這樣子”原本帳戶有 10 元,存入 5 元之後,帳戶餘額變 15 元“就會pass了
可是存款不可能存負得值進去,所以要加一下判斷
 def deposit(amount)
    @amount += amount if amount > 0
  end
這樣子“存錢功能”兩個就都會pass了。
領錢和提錢的概念差不多,下面是完整的樣子
class BankAccount
  def initialize(amount)
    @amount = amount
  end

  def deposit(amount)
    @amount += amount if amount > 0
  end

  def balance
    @amount
  end

  def withdraw(amount)
    # ">0"可以用positive?代替,可是這樣多打好多字
    if amount > 0 && enough?(amount)
      @amount -= amount
    end
  end

  private
  def enough?(amount)
    balance >= amount
  end
end


RSpec.describe BankAccount do 

  describe "存錢功能" do 
    it "原本帳戶有 10 元,存入 5 元之後,帳戶餘額變 15 元" do 
      account = BankAccount.new(10)
      account.deposit 5
      expect(account.balance).to be 15
    end

    it "原本帳戶有 10 元,存入 -5 元之後,帳戶餘額還是 10 元(不能存入小於等於零的金額)" do 
      account = BankAccount.new(10)
      account.deposit -5
      expect(account.balance).to be 10
    end
  end

  describe "領錢功能" do 
    it "原本帳戶有 10 元,領出 5 元之後,帳戶餘額變 5 元" do 
      account = BankAccount.new(10)
      account.withdraw 5
      expect(account.balance).to be 5
    end
    it "原本帳戶有 10 元,試圖領出 20 元,帳戶餘額還是 10 元,但無法領出(餘額不足)" do
      account = BankAccount.new(10)
      account.withdraw 20
      expect(account.balance).to be 10
    end

    it "原本帳戶有 10 元,領出 -5 元之後,帳戶餘額還是 10 元(不能領出小於或等於零的金額)" do 
      account = BankAccount.new(10)
      account.withdraw -5
      expect(account.balance).to be 10
    end
  end

end

哎~可是好像很多一樣的code出現了好幾次,看起來好討厭

let

可以用let解決這個問題
let(:account) { BankAccount.new(10) }
雖然看起來像是變數,實際上他是幫你定義一個account方法所以如果你把測項裡的account改成account(),他還是會動,所以他真的是個method,只是在ruby裡面小括號是可以被省略的。
    it "原本帳戶有 10 元,存入 -5 元之後,帳戶餘額還是 10 元(不能存入小於等於零的金額)" do 
      account().deposit -5
      expect(account.balance).to be 10
    end

before

也可以用before來解決這個問題,但是因為必須要用實體變數下面的測項才有辦法用,所以要記得除了把本來每個測試裡面的account = BankAccount.new(10)刪掉以外,也要記得把account改成@account
  before :each do 
    @account = BankAccount.new(10)  #要用實體變數
  end

all

另外除了before也有all可以用,但all只會在最一開始被執行一次

完整版
class BankAccount
  def initialize(amount)
    @amount = amount
  end

  def deposit(amount)
    @amount += amount if amount > 0
  end

  def balance
    @amount
  end

  def withdraw(amount)
    # ">0"可以用positive?代替
    if amount > 0 && enough?(amount)
      @amount -= amount
    end
  end

  private
  def enough?(amount)
    balance >= amount
  end
end


RSpec.describe BankAccount do 

  let(:account) { BankAccount.new(10) }
  # def account
  #   @tmp ||= BankAccount.new(10)
  # end

  # #all只會跑一次
  # before :all do 
  #   puts "hi @ all"
  # end

  describe "存錢功能" do 
    it "原本帳戶有 10 元,存入 5 元之後,帳戶餘額變 15 元" do 
      account.deposit 5
      expect(account.balance).to be 15
    end

    it "原本帳戶有 10 元,存入 -5 元之後,帳戶餘額還是 10 元(不能存入小於等於零的金額)" do 
      account.deposit -5
      expect(account.balance).to be 10
    end
  end

  describe "領錢功能" do 
    it "原本帳戶有 10 元,領出 5 元之後,帳戶餘額變 5 元" do 
      account.withdraw 5
      expect(account.balance).to be 5
    end
    it "原本帳戶有 10 元,試圖領出 20 元,帳戶餘額還是 10 元,但無法領出(餘額不足)" do
      account.withdraw 20
      expect(account.balance).to be 10
    end

    it "原本帳戶有 10 元,領出 -5 元之後,帳戶餘額還是 10 元(不能領出小於或等於零的金額)" do 
      account.withdraw -5
      expect(account.balance).to be 10
    end
  end

end
Written with StackEdit.

ARGV

很一開始就會學到的東西,不過因為我不常用所以還是忘了,簡單筆記一下順便恢復一下記憶。
借一下範例
http://www.rubyist.net/~slagell/ruby/examples.html
# Program to find the factorial of a number
# Save this as fact.rb

def fact(n)
  if n == 0
    1
  else
    n * fact(n-1)
  end
end

puts fact(ARGV[0].to_i)
執行的時候
% ruby fact.rb 1
1
% ruby fact.rb 5
120
ARGV會把執行的時候後面給他的參數以字串存成陣列
所以就算上面只傳一個1給他,在程式裡面還是要ARGV[0],然後因為通通會被存在字串,所以還要to_i轉成數字才可以
Written with StackEdit.

2017年5月9日 星期二

MemeMaker

長輩圖製作(誤)
總之就是可以動態組合圖片和文字的東西(果然就是長輩圖啊)
https://github.com/telsaiori/memeMaker/blob/master/MemeMaker.html
主要就是redrawMeme裡面的code
    function redrawMeme(image, topLine, bottomLine) {
      // Get Canvas2DContext
      var canvas = document.querySelector('canvas');
      var ctx = canvas.getContext("2d");
      // Your code here
      if(image != null){
        ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
      }
        //text attributes
      ctx.font = '30pt Impact';
      ctx.textAlign = 'center';
      ctx.strokeStyle = 'black';
      ctx.lineWidth = 3;
      ctx.fillStyle = 'white';
      if (topLine != null) {
        ctx.fillText(topLine, canvas.width / 2, 40);
        ctx.strokeText(topLine, canvas.width / 2, 40);
      }
      if(bottomLine != null){
        ctx.fillText(bottomLine, canvas.width / 2, canvas.height - 20);
        ctx.strokeText(bottomLine, canvas.width / 2, canvas.height - 20);
      }
    }
先判斷有沒有圖,有的話就畫出來
設定文字字型和顏色……
topLine有輸入字的話就畫出來
bottomLine同上
其實這部份很短,但我用了很久…….
不知道為什麼寫javascript的時候我的錯字率高到有點可怕(遠目)
然後
關於下面這兩行
   window.topLineText = "";
   window.bottomLineText = "";
我其實不懂為什麼我需要給他們一個”“,於是跑去論壇問了一下,下面是他們給我的回答
This is considered “good practice” to initialize variables which are
supposed to hold a string with an empty string. It also prevents
errors when we pass the variable as an argument and the argument is
supposed to be a string.

然後因為這個題目我才知道
原來javascript的if如果只有一行的話不一定要有{},雖然大家都強烈建議不要省略{}
http://stackoverflow.com/questions/7117873/do-if-statements-in-javascript-require-curly-braces
Written with StackEdit.

2017年5月8日 星期一

碎唸碎唸

老實說當初我說我想要學ruby的時候,有些人會和我說
“為什麼要學那個”
“你以後是用的到嗎”
“你要想你學了之後能幹嘛”

其實我當然知道如果是php或是c#能找到的工作比較多,用的人也比較多。
但既然我已經不像當學生一樣選課只能從學校開的課裡面選,那我當然是選一個讓我有動力的東西去學。

不過我有時候還是會想,叫別人不要去學某個東西是對的嗎。
或者說用一副“蛤?那是什麼?可以吃嗎?”的語氣是對的嗎?
就是一種潑冷水的概念。
當然你用的語言是真的比較多人學,工作也多很多啦。
只是我覺得實在也沒必要對想要學東西的人那樣說,
至少在我身邊那種真的很喜歡程式,
喜歡到你聽他在講相關東西的時候會覺得眼睛在發光,
頭上有音符在跳的人反而都不太會這樣子講。

不過,我在大學的時候就覺得就算一樣是寫程式的人,有些人其實真的很愛”文人相輕“,用詞正不正確我不清楚,但我想這種感覺很好理解。

番外篇:
不過勒,其實有人在我找工作一直撞牆的時候和我講過一些特例,像剛學rails的某人因為一直找不到rails的工作,因為門實在太窄,然後跑去投PHP結果反而上了的例子。
應該是因為php的工作多,人也比較好找,所以願意帶新人的公司也比較多吧。
然後說我也可以去試看看php或是node.js之類的。
當然站在他們公司的角度講這種情形其實某種程度上是很反應現實的。
我也真的認真想過我要不要也試看看好了,不過...........
對我的頭腦來說有困難
因為我是個有點難回頭的人XD
該怎麼說好勒,就是我覺得這樣子突然轉彎好像對不起我自己(?)
而且我都花那麼久時間了(還有錢)
我可以接受穩定之後學別的語言,但是要我在ruby on rails還沒搞好之前突然轉彎去別的同類型的語言,我還是不太願意這樣....
對我來說那可能回去老本行意願還高一點




HTML5 Canvas

下面是課程裡面最初步的code,就只是用canvas顯示一張圖出來而已
不過對我這種javascript菜鳥還是有一些不明白的地方,我一直都不確定到底什麼東西會在什麼時候被執行
也就是我搞不清楚程式執行的順序,就會傻傻以為都上到下

image.src = "222050-22rdf.jpg";
比方我不懂上面這個為什麼要放在onload的下面

這是一開始我心中最上面那段程式的的定義

  1. 建立image object
  2. 用onload去設定圖片讀完之後要做什麼事
  3. 用用canvas顯示在網頁上
  4. 然後最後才和他講圖片在哪裡?_?(黑人問號臉)
然後去論壇找一找有人問了類似的問題,發覺我最根本上會錯意了囧
因為,你沒有和他講圖片在哪裡之前圖片根本不會被load,所以onload根本不會執行
也就是
image.src = "222050-22rdf.jpg";本來就該放在後面啊~傻傻der~
借用一下udacity論壇上老師的解釋




2017年5月7日 星期日

還是不太好在blogger上用markdown

本來是覺得用stackedit的話可以很方便發佈文章到這裡,不過還是會因為這邊css的關係讓排版跑掉變很醜。
上一次想說乾脆整篇都用gist,但是會有外框好醜。
而且blogger的app只要上傳圖就會當掉,實在很悲劇。
但是又不知道哪邊比較好orz

第三次上五倍紅寶石rails課 5/7