Là ruby dev chắc bạn biết đến gem therubyracer (là gem dùng làm javascript interpreter trên ruby thông qua v8, gem này thường dùng làm javascript headless test hay để sử dụng một số module của nodejs trên ruby) Tuy nhiên khi cài đặt gem này trên mac os (kể cả từ 10.6 đến 10.8) thì rất hay bị gặp lỗi:
error error.sh
1234567891011121314151617181920212223242526
$ gem install therubyracer
Building native extensions. This could take a while...
ERROR: Error installing therubyracer:
ERROR: Failed to build gem native extension.
/Users/david/.rvm/rubies/ruby-1.9.3-p194/bin/ruby extconf.rb
checking for main() in -lobjc... yes
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers. Check the mkmf.log file for more
details. You may need configuration options.
Provided configuration options:
--with-opt-dir
--with-opt-include
--without-opt-include=${opt-dir}/include
--with-opt-lib
--without-opt-lib=${opt-dir}/lib
--with-make-prog
--without-make-prog
--srcdir=.
--curdir
--ruby=/Users/david/.rvm/rubies/ruby-1.9.3-p194/bin/ruby
--with-objclib
--without-objclib
extconf.rb:15:in `<main>': undefined method `include_path'for Libv8:Module (NoMethodError)
Bị lỗi này hình như là do version của v8 đang cài trong máy bị conflict với version v8 therubyracer reference đến, để fix thì có 2 cách: Cách đầu tiên là uninstall bản gem libv8 đang có trong máy đi, rồi install lại therubyracer
fix1 fix1.sh
12
$ gem uninstall libv8
$ gem install therubyracer
Khi install therubyracer thì gem sẽ tự động install lại bản v8 thích hợp vào đúng chỗ.
Hoặc bạn có thể dùng cách thứ 2 là update lại bản libv8 mới nhất, rồi tiến hành cài đặt như bình thường
Hẳn là một github user, hẳn bạn biết github hỗ trợ cho user tạo một static blog trên domain của github (xxx.github.io). Để tạo blog cá nhân thì bạn có thể tham khảo chi tiết ở đây. Hiện tại thì để tạo github page thì đã có giao diện rất dễ sử dụng nên mình sẽ không nói thêm ở đây. Về mặt bản chất thì github page chỉ là một repo trên github, trong đấy có chứa các static file, và được trỏ đến domain xxx.github.io.
2. Jekyll và github page
Khi bạn push bất kì thứ gì lên repo của github page, github sẽ chạy site generator sử dụng jekyll. Tại sao phải sử dụng site generator? Vì github không chỉ hỗ trợ html mà còn hộ trợ markdown, một markup language khá đơn giản và dễ sử dụng ( bạn có thể tham khảo thêm ở đây. Vậy bạn có thể đoán ra jekyll là gì: jekyll là một sản phẩm của Tom Preston-Werner, ceo của github. Jekyll sẽ nhận input là một template directory, chạy qua một cái converter engine để convert từ (Textile | Markdown | Liquid) sang html, tạo ra một static website. Như vậy bạn đã có thể hình dung ra cách để tạo ra một github page:
3. Sử dụng octopress để gen blog trên github page
Octopress là một framework design cho jekyll. Gọi là framework nghe hơi lớn, nhưng nói một cách ngắn gọn, octopress là một bộ template/tools/ plugin giúp cho việc generate static site đơn giản hơn. Những tính năng chính của octopress bao gồm:
Responsive design template (gồm css, js, html)
Build-in 3rd supports cho một số mạng xã hội (như like button của facebook, tweet button của twitter), và đặc biệt có comment của disqus khá tiện
Build-in web server để review sau khi generate qua jekyll
Hệ thống theming rất tốt với Compass và Sass
Nói lý thuyết nhiều quá, giờ vào cụ thể về cách cài đặt và sử dụng:
Prerequisite: máy bạn phải install git và ruby, cách install các bạn có thể google :D Sau đấy bạn clone octopress về máy, install bundler rồi install các dependencies như sau:
Ok, như vậy bạn đã có một môi trường đẹp đẽ để chuẩn bị viết blog rồi. Về mặt trình tự thì để có 1 blog trên github page bạn sẽ phải: Viết blog (dùng markdown/..) => generate qua jekyll => deploy lên github page
Octopress đã chuẩn bị sẵn cho bạn một Rakefile (bạn có thể tìm hiểu về rake ở đây .Trong đấy có rất nhiều task octopress đã chuẩn bị sẵn cho bạn để giúp cho việc cài theme, deploy lên github page trở nên đơn giản hơn bao giờ hết.
Đầu tiên bạn sử dụng
theme theme.sh
1
rake install
để instal theme.
Sau khi đã install xong theme, chúng ta sẽ viết blog. Bước đầu tiên là setup repository để cho việc deploy lên github pages thuận tiện hơn:
theme theme.sh
1
rake setup_github_pages
Khi làm bước này thì octopress sẽ prompt ra một cái để hỏi về repo của github pages của bạn (repo của cái xxx.github.io mà mình đã nói ở trên)
Như hướng dẫn đã ghi, bạn sẽ phải điền repo của bạn với format git@github:your_username/your_username.github.com Ví dụ như trong trường hợp blog ktmt thì sẽ là git@github:ktmt/ktmt.github.com.git Bạn điền vào, press OK, như vậy là đã xong bước setup. Sau bước này thì thì octopress sẽ tạo ra một cái git repo trong octopress/_deploy/.git/ link đến git@github:ktmt/ktmt.github.com.git. Như vậy bạn có thể hình dung là sau này khi deploy thì octopress sẽ gen ra file vào trong _deploy và git push lên git@github:ktmt/ktmt.github.com.git . Một chú ý nữa là sau bước này octopress sẽ:
Đổi tên remote branch hiện tại của bạn từ ‘origin’ sang ‘octopress’
Add git@github:your_username/your_username.github.com vào remote branch và đổi thành ‘origin’
Note là octopress branch của mình đang không phải là git://github.com/imathis/octopress.git như các bạn mà đang là https://github.com/ktmt/ktmtblog-octopress.git. Thực ra cái ktmtblog-octopress chỉ là một bản được fork về của octopress, và được tạo nên để giữ các bài viết trên github của bọn mình thôi.
Vậy là setup xong, tiếp theo là việc quan trọng nhất, viết blog. Để viết blog thì đầu tiên bạn sẽ phải generate ra file markdown thông qua
theme theme.sh
1
rake new_post["post_title"]
Kết quả là một file markdown đã được tạo ra ở thư mục _source/_post
Sau khi đã hoàn thành việc viết blog, việc tiếp theo bạn phải làm là generate cái file markdown đó + đống template thành static page thông qua jekyll. Octopress đã chuẩn bị sẵn cho bạn một rake task là generate, nên việc bạn phải làm chỉ là
theme theme.sh
1
rake generate
Kết quả là
Để preview thành quả của mình, octopress cung cấp cho bạn cả httpserver để preview, bạn gõ
theme theme.sh
1
rake preview
Và truy cập vào localhost:4000 thông qua browser là đã có thể preview thành quả của mình rồi.
Cuối cùng, bạn sẽ deploy lên github page thông qua
theme theme.sh
1
rake deploy
Và như thế là bạn đã deploy thành công blog của bạn lên github page (với điều kiện là bạn không viết sai syntax markdown :D). Chú ý là khi bạn rake deploy thì octopress sẽ copy đè “toàn bộ” cái repo your_username/your_username.github.com của bạn thay bằng cái thư mục _deploy của nó, kể cả commit tree. Vậy nên để lưu giữ các bài viết của cá nhân thì các bạn nên làm như mình là: fork octopress về thành một repo cá nhân, và mỗi lần viết xong thì bạn push ngược lại vào octopress repo đó. Lưu ý là octopress repo nhé:
theme theme.sh
1
git push octopress master
Cá nhân mình thì mình viết thêm 1 cái task vào Rakefile để cho đỡ bị nhầm lẫn repo:
rake Rakefile.rb
123456789
desc"push to octopress also"task:push_octopressdoputs"pushing to octopress repo"system"git checkout master"system"git pull octopress master"system"git add ."system"git commit -m ¥"Octopresspushnewpost¥""system"git push octopress master"end
Và như vậy sau mỗi lần deploy bạn chỉ cần
theme theme.sh
1
rake push_octopress
Là đã synchronize thành công.
Kết luận:
Như vậy sau lần đầu setting có vẻ loằng ngoằng, từ bây giờ khi muốn viet blog bạn chỉ cần:
Bạn đã nghe ở đâu đó “In python everything is object”.
Điều đó có nghĩa là gì? Liệu nó có giống các ngôn ngữ lập trình khác, mọi thứ trong Python đều là instance của BaseClass? Tôi đã nghe về object class trong Python, liệu đó có phải là Base Class của Python
Python có hai mô hình old-style và new-style. Thực tế trong các phiên bản cũ của Python, không có một class cụ thể nào cho mọi object cả. Nhưng từ Python 2.2, với sự giới thiệu của new-style class, chúng ta có thể biến mọi object là instance của object
Từ Python 2.1 trở về trước, old-style class là lựa chọn duy nhất cho các lập trình viên. Khái niệm old-style class là không liên quan tới khái niệm kiểu. Nếu x là một instance của old-style class, x.class sẽ trỏ tới class của x, nhưng type(x) thì không.
python.py
12345678910111213141516171819
# old-style class was define by statement:# class <class-name>: <class definition body>>>>classA:pass# type of class A is 'type' because 'type' is base-class in Python>>>type(A)<type'type'># make an instance of A>>>a=A()# a.__class__ reference to class A>>>a.__class__<class__main__.Aat0x10aea6ce8># bute type of a is not A but 'instance'>>>type(a)<type'instance'># 'instance' still is 'type' class>>>type(type(a))<type'type'>
new-style class được giới thiệu với động lực tạo ra một mô hình object thống nhất cho Python. Mọi đối tượng sẽ được kế thừa từ object
new-style class được định nghĩa bằng cách kế thừa từ object class. Khác với old-style class, nếu x là một instance của new-style class, cả x.class và type(x) đều trỏ về class của x
Để tương thích với các phiên bản của của Python, class mặc định vẫn được để ở old-style. Nếu chúng ta muốn sử dụng new-style, chúng ta bắt buộc phải định nghĩa class là subclass của object
2. Điểm khác biệt giữa old-style và new-style class
Điểm khác biệt rõ nhất được nhìn thấy trong hệ thống kiểu. Hãy xem làm thế nào old-style class và new-style class thực hiện việc đa kế thừa. “Đa kế thừa” là khả năng một class có thể kế thừa từ nhiều class khác nhau. Nếu A kế thừa từ B, A là subclass(child class, derived class) của B, còn B là superclass (base class, parent class của A)
Đa kế thừa cho phép một class A có thể có nhiều cha (theo tôi, đa kế thừa không thực sự tốt. có nhiều cách để giải quyết vấn đề đa kế thừa, hãy xem Ruby với mixins hay Java với interface thực hiện điều đó. tôi thực sự rất thích mô hình mixins của Ruby)
Trong mô hình object của Python, mọi class đều có thuộc tình bases để lưu lại tất cả các class cha của nó, theo thứ tự xuất hiện của việc thừa kế.
Vấn đề của đa kế thừa đó là thự tự của các superclass.
Khi một instance của một subclass truy cập vào một thuộc tính (hoặc một method), đầu tiên, nó sẽ tìm kiếm các thuộc tính được định nghĩa trong không gian của nó. Nếu thuộc tình (hoặc method) không được tìm thấy, nó sẽ tìm đến không gian của class (thuộc tính của class, hàm của class). Nếu vẫn không tìm thấy, nó sẽ tìm kiếm tiếp trong không gian của các super class. Khi một class có nhiều super class, thứ tự của các super class chính là thứ tự khi tìm kiếm
Trong old-style class, thứ tự của các superclass là depth-first, left-to-right theo thứ tự xuất hiện trong bases list
python.py
1234567891011121314151617181920212223242526272829
>>>classA:deftest(self):print"A">>>classB(A):deftest(self):print"B">>>classC(A)deftest(self):print"C">>>classD(B,C):pass# order of D.__bases__ is (B, C) so D.test => B.test>>>D().test()"B">>>classE(C,B):pass# order of E.__bases__ is (C, B) so E.test => C.test>>>E().test()"C"# so what if we make an class is inherited from D, E# note that, D and E are inherited from 2 class B, C with reverse order>>>classF(D,E):pass# in old-style class, it does not matter, the searching method# only care about order of superclass in __bases__# so now F.test => D.test => B.test>>>F().test()"B"# even if we make an class is inherited from A, D, E# it still works and test() method will be test() method of A>>>classG(A,D,E):pass>>>G().test()"A"
Cách phân giải method của old-style khá đơn giản và dễ hiểu. Nhưng nếu chúng ta áp dụng quy luật này, đôi khi chúng ta sẽ phạm phải sai lầm khi kế thừa. Giả sử, một class G được kế thừa từ A, D và E, trong khi A là parent class của D và E. Rõ ràng, một lỗi nên được Python ném ra trong trường hợp này để bảo về việc kế thừa vòng tròn như vậy
new-stlye giải quyết vấn đề này. new-style sử dụng MRO (Method Resolution Order) được giới thiệu từ Python 2.3
defmro(cls):""" Return ordering of superclass of cls This ordering was used when we want to access class instance atrribute `cls`: class type we want to resolve @raise `TypeError` if cannot resolution superclass order @return `list` of class """bases_cls=cls.__bases__mro_base_lists=[mro(base_cls)forbase_clsinbases_cls]mro_list=[cls]whilemro_base_lists:# find the good head# good head is head of a list which is not is tail of any list in mro_base_listslist_head=(x[0]forxinmro_base_lists)set_tails=set()forxinmro_base_lists:set_tails.update(x[1:])good_head=Noneforheadinlist_head:ifheadnotinset_tails:good_head=headbreak# if cannot find good_head, raise TypeErrorifnotgood_head:raiseTypeErrorelse:# add to mro_listmro_list.append(good_head)# remove good_head in all list and add to mro_listforalistinmro_base_lists:try:alist.remove(good_head)exceptException:passmro_base_lists=[xforxinmro_base_listsifx]returnmro_listclassA:passclassB(A):passclassC(A):passclassD(B,C):passclassE(C,B):passclassF(D,E):passdeftest_mro():assertmro(A)==[A]print"Test1 passed"assertmro(B)==[B,A]print"Test2 passed"assertmro(C)==[C,A]print"Test 3 passed"assertmro(D)==[D,B,C,A]print"Test 4 passed"assertmro(E)==[E,C,B,A]print"Test 5 passed"try:mro(F)exceptExceptionase:assertisinstance(e,TypeError)print"Test 6 passed"test_mro()
Ý tướng của MRO là sắp xếp các super class với điều kiện:
+ Nếu B là cha của C, B luôn luôn đứng trước C trong list.
Với điều kiện đó, Python sẽ ném ra một lỗi nếu chúng ta cố gắng định nghĩa class D kế thừa từ (B, C), E kế thừa từ (C, B) và F kế thừa từ (D, E)