Sean's Note

2018年1月6日 星期六

Ruby on Rails 學習筆記 (一) - 安裝與指令

如何安裝 Ruby on Rails?

1. 安裝 Homebrew
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

2. 安裝 RVM(Ruby Version Manager)
\curl -L https://get.rvm.io | bash -s stable
重開 terminal 看 RVM 是否載入成功
rvm | head -n 1

3. 透過 RVM 安裝 Ruby
rvm use ruby --install --default ruby -v

4. 安裝 Rails
gem install rails --no-ri --no-rdoc
Ref: http://installrails.com/

Rails 指令

rails new

範例:新建 rails my app 專案
rails new myApp

rails generate

範例:自動產生 Greetings controller 樣板
rails generate controller Greetings hello
即會自動產生六個檔案:
  1. greetings_controller.rb - 內定義了擁有 hello action 的 GreetingsController 
  2. hello.html.erb
  3. greetings_controller_test.rb
  4. greetings_helper.rb
  5. greetings.coffee
  6. greetings.scss

rails console

範例:操作 rails application
rails console
rails c
  • 常用於直接讀寫資料庫的資料。
  • 可存取 app 與 helper 實體。

rails dbconsole

範例: 進入 rails application 所使用的資料庫 shell
rails dbconsole
rails db

rails server

範例:啟動 web server
rails server
rails s -b 0.0.0.0

rails runner

範例:執行 Ruby 程式碼
rails runner "Model.long_running_method"

rails destroy

範例:刪除 GreetingsController 樣板(rails generate 的反向操作)
rails destroy controller Greetings

至從 Rails 5.0 開始,rake 的指令集也被直接包進去了:

rails routes

範例: 輸出當前專案的 routes
rails routes
>>         Prefix Verb URI Pattern                Controller#Action
>> greetings_hello GET  /greetings/hello(.:format) greetings#hello

rails generate migration

範例: 建立資料表結構異動的 migration 檔案
rails generate migration add_admin_to_users
rails 便會在 db/migrate 的資料夾下產生像是 20180106022954_add_admin_to_users.rb 的檔案

rails db::migrate

範例: 根據 migration 檔來更新資料表結構與現有資料
rails db::migrate
schema.rb 原本所定義的資料表便會有所更新

更多指令詳見:
Ref: http://guides.rubyonrails.org/command_line.html

如何安裝與更新套件? 

Rails 使用了一套 Bundler 的套件管理工具,可以把它想像成 Node.js 的 npm 或 iOS 的 CocoaPods。只要在 Gemfile 裡增加或修改套件版本時,就可以執行:
bundle instasll
Note: 每次執行完,都要重啟 server。

2017年4月30日 星期日

Node.js 學習筆記(三) - 使用 Mocha, Expect 和 SuperTest 來做測試 Testing with Mocha, Expect and SuperTest

Mocha

Mocha 是一套 JavaScript 的測試 framework。透過 npm 安裝:
npm install mocha --save
範例:
const math_utils = require ('./math_utils')

it('add two numbers', () => {
  var res = math_utils.add(1, 2);

  if (res !== 3) {
    throw new Error(`Expected 3, but got ${res}.`);
  }
});

it('add two numbers', () => {
  var res = math_utils.add(1, 2);

  if (res !== 4) {
    throw new Error(`Expected 4, but got ${res}.`);
  }
});
然後透過修改 package.json 來增加測試的腳本:
{
  ...
  "scripts": {
    "test": "mocha **/**.test.js"
  },
  ...
}
之後在 console 上執行:
npm test
就可以看到 test 的結果如圖1,有一個成功一個失敗。

圖1. npm test

Expect

Expect 是一套 Assertion Library。
npm install expect --save
有了 Expect,我們就可以把上面的範例改寫成:
const expect = require ('expect')
const math_utils = require ('./math_utils')

it('add two numbers', () => {
  var res = math_utils.add(1, 2);

  expect(res).toBe(3);
});

it('add two numbers', () => {
  var res = math_utils.add(1, 2);

  expect(res).toNotBe(4);
});
GitHub 的文件有更多的範例可以參考。

非同步的測試 Testing Asynchronous Code

const expect = require ('expect')
const math_utils = require ('./math_utils')

it('add two numbers', () => {
  var res = math_utils.addAsync(1, 2, (sum) => {
  expect(sum).toBe(4);
});
上面的測試是會成功 pass 的,因為 Mocha 跑完 addAsync 就結束了,根本沒有等 callback 回來,所以為了告訴 Mocha 等待,必須使用 done:
const expect = require ('expect')
const math_utils = require ('./math_utils')

it('add two numbers', (done) => {
  var res = math_utils.addAsync(1, 2, (sum) => {
  expect(sum).toBe(4);
  done();
});
這樣就可以讓此測試預期是失敗的。

SuperTest

SuperTest 是一套用來測試 HTTP Request 的 Assertion Library。
npm install supertest --save
可以直接參考 GitHub 的文件範例。

2017年4月14日 星期五

[GitHub] 如何調整 PR 上圖片的大小與增加邊框

  • 調整圖片的大小:
    <img src="..." width="300">

  • 為圖片增加增加邊框:
    <kbd>
        <img ...>
    </kbd>

2017年3月5日 星期日

Node.js 學習筆記 (二)

Express

Express 是最小又靈活的 Node.js Web 應用程式架構。
以下是一個簡單的 Hello World Web Application 範例:
var express = require('express');
var app = express();

app.get('/', function (req, res) {
  res.send('Hello Express!');
});

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});
第四行指的是設定了一個 handler,用來處理 "/" 的網頁請求,結果如圖 1。
圖1. Hello Express!

使用中介軟體 (Middleware)

在 express app 回傳任何請求前,可以透過 middleware function 來截斷請求,這裡可以用來印一些資訊到 console 上,或處理驗證請求的合法性。之後呼叫 next 函式,讓請求繼續被處理,否則程式會停擺在那。
範例,在任何請求之前印出當前的時間資訊:
var app = express()

app.use(function (req, res, next) {
  console.log('Time:', Date.now())
  next()
})

Handlebars

Handlebars 是一套模板引擎,且相容於 Mustache 的格式,可以用來動態渲染 HTML 的內容。
透過 npm 安裝:
npm install hbs --save
範例:
var express = require('express');
var hbs = require('hbs');

var app = express();
app.set('view engine', 'hbs');
app.get('/about', function (req, res) {
  res.render('about.hbs', {
    pageTitle: 'This is About Page!'
  });
});

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});
// about.hbs
<pre class="brush: html">
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>{{pageTitle}}</title>
</head>
<body>
    <h1>About Page</h1>
</body>
</html>
在網址列上輸入 localhost:3000/about 後,就可以看到顯示 "This is About Page!",表示 pageTitle 有正確被傳遞給 about.hbs 了。

部署網頁應用程式

網路上有很多平台,可以幫助開發者或企業部署網頁應用程式,如 HEROKU, Amazon S3 等等。

2017年2月21日 星期二

Node.js 學習筆記 (一)

Node.js 的幾個特點:
1.  Runtime 是建立於 Chrome 的 V8 JavaScript 引擎之上的。
2. Event-driven 和 non-blocking I/O 的模型架構

npm

學 Node.js 不能不知道 npm 這個套件管理程式,npm 如同於 iOS 的 CocoaPods 抑或是 Python 的 pip 和 setuptools,透過一行指令就可以讓你方便下載別人已經寫好的套件,來加速開發應用程式。Node.js 會吸引了廣大的開發者,一部分也是因為 npm 上廣大的社群和擁有許多強大好用的套件。

用什麼編輯器來開發 Node.js?

Atom, Visual Studio Code, Sublime Text 都是不錯的選擇。

如何執行?

安裝好 node 後,只要執行以下的指令,就可以執行已經寫好的 app.js。
node app.js

常用的內建套件

常用的內建套件如:
  • File System - require('fs'),用來讀寫檔案
  • Process - no require needed,process.argv 用來讀取命令列的參數
  • ...etc.
參考更多:https://nodejs.org/dist/latest-v7.x/docs/api/

如何使用第三方套件

有些好用的套件 Node.js 本身不提供,但透過 npm 就可以很方便的下載,使用前必須先將專案初始化:
npm init
此時,專案裡就會產生一個 package.json:
{
  "name": "notes",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Sean",
  "license": "ISC"
}
這時還看不出來這個檔案有什麼用途,一旦我們安裝了一個套件之後
npm install lodash --save
檔案裡就會多了一個 dependencies 的欄位紀錄了這個專案所用到的套件。而下載過的這些套件也是不需要上傳到 repository 的,一起開發的夥伴們只需要下載原始碼,並且在本機端執行 npm install 就可以把所有專案用到的套件給下載下來。
{
  "name": "notes",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Sean",
  "license": "ISC",
  "dependencies": {
    "lodash": "^4.17.4"
  }
}

Lodash

Lodash makes JavaScript easier by taking the hassle out of working with arrays, numbers, objects, strings, etc.

yargs

Yargs helps you build interactive command line tools by parsing arguments and generating an elegant user interface.

request

Request is designed to be the simplest way possible to make http calls. It supports HTTPS and follows redirects by default.

nodemon

nodemon will watch the files in the directory in which nodemon was started, and if any files change, nodemon will automatically restart your node application.

如何除錯 debug?

Node.js 除了可以用 console.log() 的方法來觀察物件的值(對於寫 C/C++ 的人來說就是 printf 大法),也可以透過下斷點 (Break Point) 的方式來逐行除錯,只是不像 iOS 有 XCode,Android 有 Android Studio 一般,有友善的 IDE 介面來幫助除錯,而是透過指令的方式。例如輸入 next(n) 就是在往下一行執行。
node debug app.js

< Debugger listening on 127.0.0.1:5858
connecting to 127.0.0.1:5858 ... ok
break in app.js:1
> 1 console.log("Starting...");
  2
  3 const fs = require('fs');
debug> n
< Starting...
break in app.js:3
  1 console.log("Starting...");
  2
> 3 const fs = require('fs');
  4 const notes = require('./notes');
  5 const _ = require('lodash');
debug>


2017年2月13日 星期一

How to scroll TextView smoothly to bottom

 
   private void scrollToTop() {
        textViewLog.scrollTo(0, 0);
    }

   private void scrollToBottom() {
        final int scrollAmount = textViewLog.getLineCount() * textViewLog.getLineHeight() - (textViewLog.getBottom() - textViewLog.getTop());
        textViewLog.scrollTo(0, Math.max(0, scrollAmount));
    }
不過 TextView 的 scroll 並不是很 smooth,可以用 ScrollView 包覆 TextView 的方式來解決,並改用 ScrollView 的 Scroll 方法。
 
    private void scrollToTop() {
        scrollView.scrollTo(0, 0);
    }

    private void scrollToBottom() {
        scrollView.fullScroll(ScrollView.FOCUS_DOWN);
    }