almost 7 years ago

最近花了點時間練習 React, 順便拿 audio player 介面當練習。
React 寫起來直覺順手,比起 angularjs 學習曲線平滑許多。難怪一堆人棄坑跳到 React wwwww

online demo: React Audio Player Demo
source: github source

也在 react.rocks 搜尋得到囉~

 
about 7 years ago

主要是用 class_eval + %Q 去製作方法樣板, 然後再用回圈倒出方法

test.rb
class Test
    def self.create_method(method_name)
        class_eval %Q{
            def #{method_name}
                puts "this is method #{method_name}!"
            end
        }
    end

    [:a, :b, :c].each do |name|
        self.create_method(name)
    end

end

t = Test.new
t.a
t.b
t.c

延伸閱讀 :

Metaprogramming Ruby: class_eval and instance_eval

 
about 7 years ago

livescript 的 n 個好棒啊wwww

今天被問到 livescript 的好處在哪, 其實沒有講得很仔細, 乾脆立馬寫一篇列出常用的 livescript 特色好了 ... XD

Cascades chaining!

直接使用 .. 運算子來做 chaining

cat = new Cat!
 ..name = \kuro
 ..age = 5
 ..owner
   ..name = \Luc

編譯結果:

var x$, cat, y$;
x$ = cat = new Cat();
x$.name = 'kuro';
x$.age = 5;
y$ = x$.owner;
y$.name = 'Luc';

Define Function is easy!

hello = (msg) !-> console.log msg
hello 'Hellowrld!'

add = (a, b) -> a + b
console.log add 2, 2

編譯結果:

var hello;
hello = function(msg){
  console.log(msg);
};
hello('Hellowrld!');

var add;
add = function(a, b){
  return a + b;
};
console.log(add(2, 2));

Default parameter!

設定函數參數的預設值

say-hello = (name = 'someone', msg = 'hello!') -> "#{name}: #{msg}"
console.log say-hello!
console.log say-hello \luc, \morning!

編譯結果:

var sayHello;
sayHello = function(name, msg){
  name == null && (name = 'someone');
  msg == null && (msg = 'hello!');
  return name + ": " + msg;
};
console.log(sayHello());
console.log(sayHello('luc', 'morning!'));

Flat Backcalls!

使用 backcalls 的扁平化來避免 callback hell

response1 <-! service.callA
response2 <-! service.callB
response3 <-! service.callC
# get all results here
console.log response1, response2, response3

編譯結果:

service.callA(function(response1){
  service.callB(function(response2){
    service.callC(function(response3){
      console.log(response1, response2, response3);
    });
  });
});

語意化!

console.log 'TURE!!' if true
is-adult = if age >= 20 then true else false

編譯結果:

var isAdult;
if (true) {
  console.log('TURE!!');
}
isAdult = age >= 20 ? true : false;

一次取出多個變數!

{ name, age, weight } = cat

編譯結果:

var name, age, weight;
name = cat.name, age = cat.age, weight = cat.weight;

Defined implicit list and objects!

example1

tree = 
  * 1
    * 2
      3
    4
  * 5
    6
    * 7
      8

編譯結果:

var tree;
tree = [[1, [2, 3], 4], [5, 6, [7, 8]]];

example2

cats = 
  * name: \kuro
    age: 6
  * name: \ann
    age: 7

編譯結果:

var cats;
cats = [
  {
    name: 'kuro',
    age: 6
  }, {
    name: 'ann',
    age: 7
  }
];

Use ~> Define bound method to get 'this' lexically bound!

使用 ~> 綁定 this 物件的參考對象.

class Test 
  method-bind: ~> console.log "#{@}: call!"
  method: -> console.log "#{@}: call!"

test = new Test!

set-timeout test.method-bind, 0
set-timeout test.method, 0

編譯結果:

var Test, test;
Test = (function(){
  Test.displayName = 'Test';
  var prototype = Test.prototype, constructor = Test;
  prototype.methodBind = function(){
    return console.log(this + ": call!");
  };
  prototype.method = function(){
    return console.log(this + ": call!");
  };
  function Test(){
    this.methodBind = bind$(this, 'methodBind', prototype);
  }
  return Test;
}());
test = new Test();
setTimeout(test.methodBind, 0);
setTimeout(test.method, 0);
function bind$(obj, key, target){
  return function(){ return (target || obj)[key].apply(obj, arguments) };
}

Define Curry is easy!

multiplie = (a, b) --> a * b
multiplie-base2 = multiplie 2

console.log multiplie-base2 5
console.log multiplie-base2 10

編譯結果:

var multiplie, multiplieBase2;
multiplie = curry$(function(a, b){
  return a * b;
});
multiplieBase2 = multiplie(2);
console.log(multiplieBase2(4));
console.log(multiplieBase2(10));
function curry$(f, bound){
  var context,
  _curry = function(args) {
    return f.length > 1 ? function(){
      var params = args ? args.concat() : [];
      context = bound ? context || this : this;
      return params.push.apply(params, arguments) <
          f.length && arguments.length ?
        _curry.call(context, params) : f.apply(context, params);
    } : f;
  };
  return _curry();
}

使用 >? <? 兩數值相比取最大最小!

a = 2
b = 5

a >? b 
a <? b

編譯結果:

var a, b;
a = 2;
b = 5;
a > b ? a : b;
a < b ? a : b;

使用 <<< 匯入另一個物件屬性

cat = name: \kuro age: 17 weight: 10
obj = {} <<< cat
console.log obj

編譯結果:

var cat, obj;
cat = {
  name: 'kuro',
  age: 17,
  weight: 10
};
obj = import$({}, cat);
console.log(obj);
function import$(obj, src){
  var own = {}.hasOwnProperty;
  for (var key in src) if (own.call(src, key)) obj[key] = src[key];
  return obj;
}

延伸閱讀 :

10 Reasons to Switch from CoffeeScript to LiveScript
LiveScript do keyword

 
about 7 years ago

AutoLayout 也不是啥新梗了 .. 記得是從 XCode 5 所引進的功能,不一一介紹只節錄自己覺得易用的做法。

interface builder 設定

  1. 在 storyboard 選定某個 UI Component, 右下角 有個 |-□-| 的圖案點下去即可以設定 Constraints
  2. 在 storyboard 選定某個 UI Component, 滑鼠右鍵會延伸一條線並拉到你想要做 Constraints 的 component, 預設會先圈選 super uiview

code 設定

新增一個 button 對 superview 做 top/left Constraints

use NSLayoutConstraint
// create button

var btn = UIButton(frame: CGRectMake(0, 0, 400, 50))
btn.setTitle("button", forState: .Normal)
btn.backgroundColor = UIColor.grayColor()
btn.setTranslatesAutoresizingMaskIntoConstraints(false)
self.view.addSubview(btn)

// add Constraints

// Top

let c1 = NSLayoutConstraint(item: btn, attribute: .Top, relatedBy: .Equal, toItem: self.view, attribute: .Top, multiplier: 1, constant: 200)
// Left        

let c2 = NSLayoutConstraint(item: btn, attribute: .Left, relatedBy: .Equal, toItem: self.view, attribute: .Left, multiplier: 1, constant: 200)
// fixed width

let c3 = NSLayoutConstraint(item: btn, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 200)

view.addConstraint(c1)
view.addConstraint(c2)
view.addConstraint(c3)
use NSLayoutConstraint.constraintsWithVisualFormat
let viewsDict = ["btn": btn]
let c1 = NSLayoutConstraint.constraintsWithVisualFormat("V:|-400-[btn(30)]", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict)
let c2 = NSLayoutConstraint.constraintsWithVisualFormat("H:|-200-[btn(100)]", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict)
view.addConstraints(c1)
view.addConstraints(c2)
 
about 7 years ago

Swift 各種 block / closure 真是靈活斃了~
先來速記一下wwww

var numsForSort = [10, 3, 5, 7, 2, 1]
func sortFunc(a:Int, b:Int) -> Bool {
    return a > b
}
// way 1

var sortArr:[Int] = numsForSort.sorted(sortFunc)
sortArr = sorted(numsForSort, sortFunc)

// way 2

sortArr = numsForSort.sorted({
    (a:Int, b:Int) -> Bool in
    return a > b
})

// way 3

sortArr = numsForSort.sorted({ s1, s2 in s1 > s2 })

// way 4

sortArr = numsForSort.sorted({ $0 > $1 })

// way 4-1

sortArr = numsForSort.sorted({
    println("hello")
    return $0 > $1
})

// way 5

sortArr = numsForSort.sorted(>)

// way 6 

sortArr = numsForSort.sorted(){ $0 > $1 }

 
about 7 years ago

webpack 是個強大的模塊打包工具, 支援 amd / commonjs, 也可以利用 loader 編譯 json, jade, coffee, css, less ..., minify js/css 甚至可以把 css, png embed 進 js 當作模塊之一使用.

研究一下關於 webpack 如何打包獨立的 js libray 引用, 本來想用 multiple-commons-chunks 來做打包應用, 不過他必須連專案主要的 js 也得綁在一起打包... 似乎無法把 lib.js 獨立出來, 於是參考另一個做法 multi-part-library .

我的做法是建一個 lib.js 並引入所有需要的 js/css, 接著使用 webpack 打包, 在其他專案的 js 就能引入這個打包好的 js 來使用, 採用的是 commonjs 規範.

範例已放在 github 上 :

獨立打包 js library 的目的

  1. 可獨立於專案之外, 打包後為獨立模塊供其他專案使用
  2. 打包自家 js
  3. 打包 vendor 類 js
  4. 打包共用的 css

打包自家寫的 js

lib.js require 所需要的檔案即可

打包 vendor 類型的 js

也是 lib.js require 所需要的檔案即可, 但有鑒於 vendor 類型的 js 檔案名稱常常會因為升級而改變 ex: jquery-2.x.x.min.js, 可以使用 resolve.alias 來對檔案命名與引用路徑做統一管理.

打包共用 css

要編譯 css 為模塊, 須在 webpack.config.js 加上 module css-loader, url-loader, 接著在於 lib.js require css 進來

需要注意的是, 假使你的 css 有使用圖片, 而編譯出來的 lib.js 可能會因為資料夾所放的相對路徑而讀取不到圖片, 此時可以在 output.publicpath 設置讀取路徑.

output 設定

另外, 在 lib.js 的 webpack.config.js output 上設定 :
output.library : lib.js bundle 輸出後的 library 名稱 (在 app.js require 的名稱)
output.libraryTarget: library 輸出後的 format.

app.js 在使用 webpack 打包的 webpack-app.config.js 下會設定引用 lib.js 為 externals

可開啟 test.html 看運行結果.
github example

 
over 7 years ago

在使用 UglifyJS 最小化後會出現 angularjs inject not working 的問題.

在 gulpjs 設定參數 mangle 為 false

.pipe(uglify({
    mangle: false
}))

另外 angularjs module 的宣告方式改為陣列

mod.Test-ctrl = [
  \$scope
  \$timeout
  ($scope, $timeout) !->
    console.log \TestCtrl
]

參考來源 :

Angular.module minification bug
Angularjs minify best practice

 
over 7 years ago

快速排序法
選擇一個基準值為支點, 將值依序與基準值比對排序在支點的左與右做 swap, 比對完後再將兩側的數列持續遞迴演算.

快速排序法 - 以最左邊索引為基準值。

data = [9 1 4 6 2 5 8 7 3]

swap = (data, i, j) !->
  temp = data[i]
  data[i] = data[j]
  data[j] = temp

quick-sort = (data, left, right) ->
  if left >= right
    return

  # 取最左邊當為基準值
  pivot = data[left]
  console.log 'pivot:', pivot
  i = left + 1
  j = right

  while true

      # 從左至右找出比基準值大的索引
      while i <= right
        if data[i] > pivot
          break
        i++

      # 從右至左找出比基準值小的索引
      while j > left
        if data[j] < pivot
          break
        j--

      # 當 i > j 代表索引交叉, 比對停止
      if i > j
        break

      swap data, i, j

  # 將基準值移至中間位置
  swap data, left, j

  # 左右側兩邊數列遞迴分支執行 sort
  quick-sort data, left, j - 1
  quick-sort data, j + 1, right

  data

console.log 'before compare' data
sorted-arr = quick-sort data, 0, data.length - 1
console.log sorted-arr

快速排序法 - 以中間索引為基準值。

data = [1 4 6 2 5 9 7 3 8]

swap = (data, a, b) !->
  temp = data[a]
  data[a] = data[b]
  data[b] = temp


quick-search2 = (data, left, right) ->
  if left >= right
    return

  pivotIndex = (left + right) / 2 .|. 0
  pivot = data[pivotIndex]
  console.log 'pivotIndex:', pivotIndex, 'pivot:', pivot

  i = left
  j = right

  while true

      while data[i] < pivot
        i++

      while data[j] > pivot
        j--

      if i == j
        break
      else
        swap data, i, j

  #console.log i, j
  quick-search2 data, left, i - 1
  quick-search2 data, i + 1, right

  data

console.log 'before compare' data
arr = quick-search2 data, 0, data.length - 1
console.log arr

相關資料

【演算】快速排序法 - Quicksort
[演算法] 快速排序法(Quick Sort)
快速排序法(一)

 
over 7 years ago

演算法忘得差不多了囧.. 開始逐步複習並順便練習 livescirpt 的手感。

汽泡排序法
每遍歷陣列時會對 index, index + 1 做比較排序, 假設數值越大往右排, 第一次遍歷後最大值已經被排至最右

bubbles = [4 6 2 5 8 7 1 3 9]

bubble-sort = (arr) ->
  for i from arr.length - 1 to 1 by -1
    for j from 0 to i - 1
      if arr[j + 1] < arr[j]
        temp = arr[j]
        arr[j] = arr[j + 1]
        arr[j + 1] = temp
  arr
  
console.log 'before compare' bubbles
bubble-sort bubbles |> console.log  
  

選擇排序法
每遍歷陣列找出最小元素的 index, 每 loop 後於目前跑到的 min-index 作 swap, 再繼續下一個 loop

selects = [4 6 2 5 8 7 1 3 9]

select-sort = (arr) ->
  min-index = 0
  for i from 0 to arr.length - 1
    min-index = i
    for j from i + 1 to arr.length - 1
      if arr[min-index] > arr[j]
        min-index = j
    temp = arr[i]
    arr[i] = arr[min-index]
    arr[min-index] = temp
  arr

console.log 'before compare' selects
select-sort selects |> console.log  
  

插入排序法
第一個元素開始當作已排序部分, 逐步對前面元素跟已排序的部分做遍歷比對, 找到比目標值還小的數值後將目標值做 swap

insert-data = [4 6 2 5 8 7 1 3 9]

insert-sort = (arr) ->
  for i from 1 to arr.length - 1
    temp = arr[i]
    j = i - 1
    while j >= 0 and arr[j] > temp
      arr[j+1] = arr[j]
      arr[j] = temp
      --j
  arr

console.log 'before compare' insert-data
insert-sort insert-data |> console.log

相關資料

wiki 汽泡排序
wiki 選擇排序
wiki 插入排序

 
almost 8 years ago

此文不定期更新
寫程式碼就要養成好習慣,追求 clean code 之道乃道路上的你我應有之責。

Objective-C / Swift

紐約時報行動軟體團隊的Objective-C程式碼撰寫風格手冊
The official raywenderlich.com Objective-C style guide.
Clean, Modern Objective-C
Xcode 底下如何統一程式碼風格
Coding conventions for Objective-C projects ( Github )
The Official raywenderlich.com Swift Style Guide.

JavaScript

Principles of Writing Consistent, Idiomatic JavaScript
Google JavaScript Style Guide

AngularJS

An AngularJS Style Guide for Closure Users at Google
Best Practice Recommendations for Angular App Structure

LiveScript

LiveScript Style Guide

Ruby

Ruby 風格指南

JSON
JSONStyleGuide

CSS
[译]Google HTML/CSS Style Guide 谷歌代码风格指南