2020年5月28日 星期四

靜態網頁部落格工具 Ruby + Jekyll 安裝教學


一、安裝Ruby
作業系統為Ubuntu 20,指令如下:
sudo apt update
sudo apt install ruby-full build-essential zlib1g-dev
設定用戶的環境變數,應避免用root安裝Ruby Gems。
echo '# Install Ruby Gems to ~/gems' >> ~/.bashrc
echo 'export GEM_HOME="$HOME/gems"' >> ~/.bashrc
echo 'export PATH="$HOME/gems/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

二、安裝Jekyll
Ruby中使用Gem作為套件管理的工具,就像是python和pip的關係。安裝套件的方式 gem install [packageName]
gem install jekyll bundler

三、建立新專案
新增一個 myblog 的專案
jekyll new myblog
在目錄下應該會發現新的資料夾 /myblog,大致的內容可以參考一下。
├── 404.html
├── about.markdown
├── _config.yml
├── Gemfile
├── Gemfile.lock
├── index.markdown
├── _posts
│   └── 2020-05-27-welcome-to-jekyll.markdown
└── _site
    ├── 404.html
    ├── about
    ├── assets
    ├── feed.xml
    ├── index.html
    └── jekyll

四、開啟服務
進入目錄後,啟動伺服器,預設主機名稱localhost、埠號4000,可以根據需求設定:
cd myblog
bundle exec jekyll serve

// or you can ...
bundle exec jekyll serve --host=[ip address] --port=[port number]
瀏覽器開啟 http://localhost:4000 ,就可以看到預設的首頁,安裝就告一段落,可以開始進行開發。

2020年5月26日 星期二

Asciidoctor + VS Code安裝外掛套件快速開發、預覽功能


一、安裝套件
方法一
(1) 按快捷鍵 [ctrl] + [P]
(2) 輸入下面的指令:
ext install joaompinto.asciidoctor-vscode
(3) 按 [Enter] 送出



方法二
(1) [View] → [Extensions]


(2) 搜尋「AsciiDoc joaompinto」,找到後按綠色按鈕 Install




二、使用方式
打開AsciiDoc的檔案(.adoc, .ad, .asc, .asciidoc),按下快捷鍵 [ctrl]+[shift]+[v]




三、輸出HTML
快捷鍵 [ctrl]+[alt]+[s],自動在同一個目錄下產生相同檔名的 html 檔案。

參考資料:https://github.com/asciidoctor/asciidoctor-vscode


2020年5月21日 星期四

Asciidoctor 安裝及入門範例


Asciidoctor 是使用純文字編輯的文檔格式,與 Markdown 用途相近(用法比較),利用特定的標記可以呈現為HTML、PDF等其他格式,可以根據排版的需求搭配css或模板進行輸出。上一篇「ubuntu18 + python2 文件編輯 AsciiDoc 安裝說明」提到的 AsciDoc 的進化版,AsciDoc 已經停止更新,目前 Asciidoctor 更活耀,常用在電子書或Git專案文件的撰寫。[使用手冊]

安裝
安裝 Asciidoctor(作業系統 Ubuntu 18)
sudo apt-get install -y asciidoctor

完成後可以確認安裝版本
asciidoctor --version
asciidoctor -V


簡易範例
1. 建立檔案
新增一個檔案 sample.adoc,內容:
.Sample document
====
Here's a sample AsciiDoc document:

[listing]
....
= Title of Document
Doc Writer
:toc:

This guide provides...
....

The document header is useful, but not required.
====

2. 輸出 html
asciidoctor sample.adoc
在同一個目錄下會產生同檔名的HTML檔案 sample.html

預設情況都是轉成html5,並搭配css3,如果想要轉成其他格式,可以加上 -b(--backend) 來指定:
// for *.xml
asciidoctor -b docbook sample.adoc


Custom Theme
預覽剛剛的 sample.html ,發現除了標題、內文等會自動加上顏色或背景,是預設套用的 css3成果:

可利用自訂的 css 來美化頁面,以 asciidoctor-skins 寫好的主題套用作為範例。下載:
git clone https://github.com/darshandsoni/asciidoctor-skins.git

重新輸出時,-a(--attribute) 加上 css 的路徑:
asciidoctor -a stylesheet=./asciidoctor-skins/css/notebook.css sample.adoc

// or
asciidoctor -a stylesheet=notebook.css -a stylesdir=./asciidoctor-skins/css sample.adoc

開啟畫面會套用新的 stylesheet,如下:


常用參數
除了上面提到的 -a-b ,其他常見的選項:
1. 輸出檔名 -o
// -o, --out-file
asciidoctor sample.adoc -o mypage.html

2. 輸出路徑 -D
// -D, --destination-dir
asciidoctor sample.adoc -D pages
輸出檔案會在資料夾 /pages 內。

3. 僅輸出內容 -s
// -s, --no-header-footer
asciidoctor sample.adoc -o mypage.html
只會輸出html中 <body> 標籤裡的內容,方便用於嵌入式頁面。

更多參數可參考:
https://asciidoctor.org/docs/user-manual/#document-conversion

2020年5月1日 星期五

ubuntu18 + python2 文件編輯 AsciiDoc 安裝說明


基本上 AsciiDoc 已經停止更新,2017年已經發布了最終版本,並表示不再更新,當然 asciidoc 仍可繼續使用,直到停止支援 python2。既然都明寫建議用戶轉移使用 Asciidoctor(底層是Ruby) 或支援 Python3 的 asciidoc-py3,以下安裝步驟僅作為紀錄。

安裝之前請先確保主機已經安裝了Python(版本2.4以上),因為安裝的腳本是用Python寫的,多數的linux系統都已經內建,所以可以直接開始按照指令安裝asciidoc。

以下操作環境為ubuntu 18.04(server),目前ubuntu 20.04 LTS (2020/04 - 2025/04)為最新 LTS 版,但不影響下面的操作:

方法一
Step1. 下載原始碼
透過git下載原始碼,選用的版本為8.6.9
cd /bin
git clone https://github.com/asciidoc/asciidoc asciidoc-8.6.9

cd asciidoc-8.6.9
git checkout 8.6.9

Step2. 綁定指令
哈囉
(A) 綁定指令
ln -s /bin/asciidoc-8.6.9/asciidoc.py /bin/asciidoc
ln -s /bin/asciidoc-8.6.9/a2x.py /bin/a2x
(B) 編譯
autoconf
./configure
make
sudo make install


方法二
更快速的方法,可直接透過AsciiDoc Debian package安裝,指令:
apt install asciidoc

Official Site: http://asciidoc.org/

2020年3月31日 星期二

[Git] 手動安裝 git 2.6 + 新指令 sparse-checkout


sparse checkout 的功能可以讓使用者追蹤儲存庫裡特定的資料夾或檔案,不需要clone整個專案。新版本 git 2.6 有新指令 sparse-checkout 讓操作更簡單方便,關於 sparse-checkout 的設定方法可以參考「[Git] 如何使用 sparse checkout 下載 repository 內特定資料夾或檔案」進行操作,以下主要介紹如何手動安裝 git以及常用的 sparse-checkout 指令。

安裝

1. 安裝相關套件
安裝編譯 Git 所需的函式庫:curl, zlib, openssl, expat 和 libiconv
sudo apt-get install libcurl4-gnutls-dev libexpat1-dev gettext \
  libz-dev libssl-dev

2. 下載 git 原始碼
先下載 git 原始碼,接著解壓縮並進入目錄。
wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.26.0.tar.gz
tar zxvf git-2.26.0.tar.gz
git-2.26.0
※如果需要其他 git 版本 [https://mirrors.edge.kernel.org/pub/software/scm/git/]

3. 編譯與安裝
編譯的時間稍微比較久
./configure --prefix=/usr \
            --with-gitconfig=/etc/gitconfig \
            --with-python=python3 && make
安裝
sudo make install

安裝後並沒有明顯的成功訊息,所以很難確定到底有沒有裝好,所以可以透過指令查看版本:
git --version
git version 2.26.0


指令說明

◆ sparse checkout 設定初始化
git sparse-checkout init
開啟設定之後,在目錄會自動新增檔案 sparse-checkout ,預設內容是:
/*
!/*/
代表根目錄內第一層內所有的檔案都列入追蹤;換句話說,根目錄裡任何資料夾內的檔案(包含資料夾)都會被忽略。

必須先確定檔案 .git/info/sparse-checkout 已經存在,使用下列的指令才不會報錯:
◆ 列出目前追蹤的檔案
git sparse-checkout list
◆ 新增指令資料夾或檔案
語法與 .gitignore 相似,最簡單是直接列出完整的檔案路徑,根據需求可以列出複雜的規則,像是追蹤特定的檔案附檔名,或是排除特定的項目。
git sparse-checkout add [folderPath/filePath]
◆ 更新及應用
將資料夾或檔案路徑規則寫入 sparse-checkout ,並馬上採用。
git sparse-checkout set [folderPath/filePath]
◆ 取消
git sparse-checkout disable

參考資料:
https://git-scm.com/download/linux
https://git-scm.com/book/zh-tw/v2/開始-Git-安裝教學
http://www.linuxfromscratch.org/blfs/view/svn/general/git.html

[Git] 如何使用 sparse checkout 下載 repository 內特定資料夾或檔案


一般下載專案的指令會將整個 repository 下載
git clone [URL]
有時候你只需要專案部分資料,git clone 無法只下載其中一個資料夾或檔案,但是 sparse checkout 可以達到!當專案非常龐大時,既能節省硬碟容量,也能提升工作效率。

1. 在現有資料夾中初始化倉儲
先決定要把資料放在哪個目錄,並執行初始化。
mkdir myproject
cd myproject
git init

2. 新增遠端版本庫
git remote add origin [URL]

3. 開啟 sparse checkout 設定
git config core.sparseCheckout true

4. 設定指定資料夾或檔案
根據你的需求,把資料夾或檔案的路徑寫進去。
方法一
echo "path/to/your/folder/" >> .git/info/sparse-checkout
echo "myFile.example" >> .git/info/sparse-checkout
方法二
vim .git/info/sparse-checkout
# .git/info/sparse-checkout
# Please list your directory and file path here
path/to/your/folder/
myFile.example

5. 取得儲存庫分支 master 的更新
最後一個步驟,git pull下載資料。
git pull origin origin master

2020年2月28日 星期五

[Git] 客製化Git Hooks管理專案



所謂的Git Hooks指的是以腳本等方式設定執行動作,當git指令執行時,會自動觸發這些腳本的機制,時機可能是在git指令之前或是之後。根據git指令又可以分為server side和client slide兩大類:commit和merge觸發的是client side,server side則是在網路上收到推上去的commit(pushed commit)。

hooks 存放在目錄 /.git/hooks/ 裡,執行 git init 初始化時,git自動在目錄裡產生一些shell script範本,你也可以用Ruby或python等實作。範例可以直接使用,但要記得把副檔名的 .sample 拿掉。



如果需要自己新建hook,請確認一下檔案的執行權限已經開啟。
chmod +x [filePath]

常見的Hooks
Client Side
以下為4個與commit相關的hook:
  • 在commit之前會執行 pre-commit,可以運用在執行功能驗證、單元測試或是coding style的檢查,若有任何錯誤發生時,這個commit會被捨棄不執行。也可以下指令 git commit --no-verify 略過hook的執行。
  • prepare-commit-msg,這個hook對於一般commit比較不實用,多在commit訊息模板、merge commit、squash commits、amended commits等自動產生commit訊息的類型。
  • commit-msg需要commit訊息的模板檔案路徑作為參數,如果錯誤發生,git會停止進行這個commit,來確保所有的commit訊息都符合需要的格式。
  • commit結束後,會執行 post-commit ,不需要任何參數,你可以用 git log -1 HEAD 來確認剛剛commit的內容,或者通知其他類似的訊息。


Server Side
  • server端收到push時,首先執行 pre-receive ,如果錯誤發生,所有的commit將不會被受理。可以用來檢查有沒有任何non-fast-forwards。
  • updatepre-receive 有點相似。
  • post-receive 會在整個push過程結束後執行,可以用來通知專案成員或是其他服務的更新等。這個hook不會影響push過程,但在hook執行完之前,用戶端和伺服器端會持續連線,因此要避免在腳本中執行時間較長的工作。

參考資料:
https://git-scm.com/book/zh-tw/v2/Customizing-Git-Git-Hooks

2020年2月27日 星期四

[JavaScript] 安裝Jest單元測試


Jest為javascript的前端測試工具,安裝快速且不需複雜的設定,執行速度快,所有測項可以同時進行讓效能最大化,並可以搭配用在vue.js、React等進行UI component的測試。

安裝指令

npm install --save-dev jest
npm的安裝教學可以參考「教學」。


實作

以簡單的JavaScript程式來測試執行,將傳入的陣列合併成字串回傳:
// combineArray.js
const combineArray = (array, separator = ',') => {
        if (!Array.isArray(array)) {
                return new Error('Invalid input array');
        }
        if (typeof separator !== 'string') {
                return new Error('Invalid input separator');
        }

        return array.join(separator)
};

module.exports = combineArray;
測試的副檔名 *.test.js
// combineArray.test.js
const combineArray = require('./combineArray');

test('Combine array: [1, 2]', () => {
        expect(combineArray([1,2])).toBe('1,2');
});
  • 每個一測試檔案都必須至少有一個test(),第一個參數是名稱;第二個參數是執行expect實際測試內容的function。[參考]
  • expect()常用的方式expect(A).toBe(B),也就是期望A會等於B。[參考]

package.json新增內容:
{
  "scripts": {
    "test": "jest"
  }
}

執行測試

npm run test
所有的*.test.js都會跑過一次,並顯示結果,包含有多少測試項目以及成功和失敗的數量。



根據程式碼的複雜程度可以寫出許多測試項目,為了方便辨識測試內容,describe()可以將測項分類、建立群組,.toThrow()判斷錯誤發生的情形等等:
const combineArray = require('./combineArray');

describe('Combine array', () => {
        const inputArray = [1, 2];

        test('Default', () => {
                expect(combineArray([])).toBe('');
                expect(combineArray(inputArray)).toBe('1,2');
                expect(combineArray(inputArray, undefined)).toBe('1,2');
        });
        test('With custom separator', () => {
                expect(combineArray(inputArray, ' ')).toBe('1 2');
                expect(combineArray(inputArray, '*')).toBe('1*2');
                expect(combineArray(inputArray, '-')).toBe('1-2');
        });

        describe('With invalid input', () => {
                test.each(
                        [undefined, null, 1, 'string', {}]
                )('Input array: %s', (item) => {
                        expect(() => {
                                combineArray(item);
                        }).toThrow(new Error('Invalid input array'));
                });
                test.each(
                        [null, 1, [], {}]
                )('Input separator: %s', (item) => {
                        expect(() => {
                                combineArray(inputArray, item);
                        }).toThrow(new Error('Invalid input separator'));
                });
        });
});
執行結果


若有任何不符合預期的結果,console上會寫出哪一個測項失敗,預期的輸出和輸入為何。測試項目寫得越完備越好,往後即使更新主程式,也可以再以指令執行測試,確保程式運作如你所預期。

更多的方法可以前往官網參考:
https://jestjs.io/

2020年2月25日 星期二

[Vue.js] computed的set()和get()使用方式


一般情況下,為了避免在 template 中寫入過度複雜的計算,可以選擇放到 computed
<template>
    <div v-text="colorList.join(',')" />
</template>

<script>
export default {
    data() {
        return {
            colorList: ['blue', 'green', 'red'],
        };
    },
};
</script>
// Recommend
<template>
    <div v-text="displayColorList" />
</template>

<script>
export default {
    data() {
        return {
            colorList: ['blue', 'green', 'red'],
        };
    },
    computed: {
        displayColorList() {
            return this.colorList.join(',');
        },
    },
};
</script>
預設的情況下computed只有 get() ,必須要有一個return值,會根據相依的值動態計算。computeddata很像,但如果要直接修改值,必須加上 set()

如果firstNamelastName被修改時,會觸發 set() ,第一個參數為這次觸發更新輸入的值。參考範例:
<template>
    <div>
        <input v-model="firstName">
        <input v-model="lastName">
        <input v-text="fullName" />
    </div>
</template>

<script>
export default {
    data() {
        return {
            fullName: '',
        };
    },
    computed: {
        firstName: {
            get() {
                return this.fullName.split(' ')[0] || '';
            },
            set(firstName) {
                this.fullName = `${firstName} ${this.lastName}`;
            },
        },
        lastName: {
            get() {
                return this.fullName.split(' ')[1] || '';
            },
            set(lastName) {
                this.fullName = `${this.firstName} ${lastName}`;
            },
        },
    },
};
</script>

2019年12月26日 星期四

[Vue.js] 跨元件的資料傳遞 Eventbus 簡易使用範例


Eventbus可以達成跨元件的資料傳遞,這個範例只是作為Eventbus效果的示範,依據實際的應用時,不一定使用eventbus是最合適的,可以考量使用props/emit父子元件的傳遞方式,或是vuex來需要共用的資源。

先參考一下整體的檔案結構:
├── App.vue
├── components
│   ├── Button.vue
│   └── DisplayBoard.vue
├── libs
│   └── eventbus.js
└── main.js

eventbus.js
import Vue from 'vue';
export const EventBus = new Vue();

MyButton.js
傳遞eventbus的元件,當按下按鈕時,會將目前的值傳出去,以$emit發出一個 "add-count" 的事件。
<template>
  <button @click="onClickCountAdd">Click</button>
</template>

<script>
// Import the EventBus we just created.
import { EventBus } from '../libs/eventbus.js';

export default {
  data() {
    return {
      clickCount: 0,
    }
  },
  methods: {
    onClickCountAdd() {
      this.clickCount++;
      // Send the event on a channel (add-count) with a payload (the click count.)
      EventBus.$emit('add-count', this.clickCount);
    }
  }
}
</script>

DisplayBoard.js
註冊eventbus的元件,$on是註冊;$off是取消,兩者必須成雙出現,可以避免產生重複綁定。display-board註冊 "add-count" 的事件,後面的參數是時間接收到事件時,負責處理的method。
<template>
  <div v-text="displayCount" />
</template>

<script>
// Import the EventBus we just created.
import { EventBus } from '../libs/eventbus.js';

export default {
  data() {
    return {
      displayCount: 0,
    }
  },
  created() {
    this.handleClick = this.handleClick.bind(this);
    // Listen to the event.
    EventBus.$on('add-count', this.handleClick);
  },
  destroyed() {
    // Stop listening.
    EventBus.$off('add-count', this.handleClick);
  },
  methods: {
    handleClick(clickCount) {
      this.displayCount = clickCount;
    }
  }
}
</script>

App.js
<template>
  <div>
    <my-button />
    <display-board />
  </div>
</template>

<script>
import MyButton from './components/MyButton'
import DisplayBoard from './components/DisplayBoard'

export default {
  components: {
    MyButton,
    DisplayBoard,
  }
}
</script>

最終成果,隨著my-button內按鍵點擊,display-board需呈現目前的點擊數。