1. C 표준 라이브러리 함수

int getDayOfWeek(int year, int month, int day)
{
struct tm *pResultTime;
struct tm targetTime = { 0, 0, 0, day, month-1, year - 1900 };
time_t targetSec = mktime(&targetTime);
pResultTime = localtime(&targetSec);
return pResultTime->tm_wday;
}

 
2. Cocoa 클래스

참조: NSDateComponents Class Reference

- (int)getDayOfWeek:(int)year month:(int)month day:(int)day

{
    NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
    [dateComponents setYear:year];
    [dateComponents setMonth:month];
    [dateComponents setDay:day];
    
    NSCalendar *gregorian = [[NSCalendar alloc]
                             initWithCalendarIdentifier:NSGregorianCalendar];
    NSDate *date = [gregorian dateFromComponents:dateComponents];
    NSDateComponents *weekdayComponents = [gregorian components:NSWeekdayCalendarUnit fromDate:date];
    
    return [weekdayComponents weekday] - 1;
}


3.  첼러의 공식

참조: WikiPedia - Zeller's congruence

int getDayOfWeek2(int year, int month, int day)
{
    if(month <= 2) {
        year--;
        month += 12;
    }
    
    int year1 = year/100;
    int year2 = year%100;
    
    int weekDay =  (day + 26*(month+1)/10 + year2 + year2/4 + year1/4 - year1*2) % 7 - 1;
    if (weekDay < 0) {
        weekDay += 7;
    }
    
    return weekDay;


참조: Determination of the day of the week # Sakamoto's method

int dow(int y, int m, int d)
{
   static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};

    y -= m < 3;   
    
    return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;


저작자 표시 비영리 변경 금지
신고

기타 2011.07.19 17:35
블로그에 그나마 드문드문 쓰던 글도 올린지가 벌써 1년이 넘었네요. 방치해 놓고 그동안 댓글과 방명록에 글을 올려 주신 분들께 답변을 못드려 죄송하다는 말씀을 드립니다.

그동안 자주 찾아 오지 못한 것이 'OS X에서 cocoa 맛보기'란 이름에 맞는 주제의 글들을 올려야 하지 않나 하는 생각에 부담스럽고 멀게 느껴진 이유인 것 같기도 하고요. 이제는 그냥 편하게 쓸려고 합니다. 꼭 개발이나 프로그래밍에 관련된 이야기가 아니더라도 관심과 호기심이 가는 내용, 생각들과 책, 영화와 같은 일상적이고 개인적인 주제로도 글을 올려 볼려고 합니다. 너무 일기 같은 내용들은 혼자 노는 다른 블로그에 올리겠지만요.

그동안 존댓말로 글을 쓰던 것도 자신보다는 타인에게 이야기하는 느낌이 들기 때문에 조금은 부담이 되었던 것 같습니다. 그래서 그냥 혼자 생각하듯이 반말로 자유로운 주제로 글을 써보자는 생각이 들었습니다.

제 블로그이긴 하지만 오랜 시간 비워두었다가 갑자기 반말로 글을 쓰는 것이 머쓱하기도 해서 먼저 글을 올려 봅니다.
저작자 표시 비영리 변경 금지
신고

'기타' 카테고리의 다른 글

다시 글쓰기  (2) 2011.07.19
아두이노와 놀기  (4) 2010.07.01
참고할만한 좋은 아이폰 소스  (19) 2010.05.04
세계지도 앱 - World Atlas  (2) 2010.04.21
모토로이  (6) 2010.02.11
역시 그냥 껐다 키는 것이...  (8) 2009.09.24

기타 2010.07.01 16:24
1. 아두이노

아두이노는 마이크로 프로세스를 탑재한 보드와 개발툴을 제공하는 오픈 프로젝트입니다. 보드가 USB와 연결된 상태에서 프로세싱에 기반한 통합개발환경에서 소스코드를 작성하고 Upload 버튼을 클릭함으로써 보드로 간편하게 업로드 할 수 있습니다. 아래는 티스토리 블로그에서 댓글이 등록되면 LED가 5초동안 켜지는 간단한 샘플을 실행한 모습입니다.


아두이노는 국내에서는 플러그 하우스나 기타 하드웨어를 취급하는 쇼핑몰등에서 보드와 관련 모듈, 부품들을 구입할 수 있습니다. 전기적인 지식이 조금 있으신 분들은 아두이노 공식 사이트에 공개된 하드웨어 메뉴얼을 참조하여 직접 만드는 것도 어렵지 않습니다.

아두이노
카테고리 컴퓨터/IT > 컴퓨터공학 > 마이크로프로세서 > 마이크로프로세서일반
지은이 마시모 밴지 (인사이트, 2010년)
상세보기

아두이노와 관련된 번역서도 나와 있고 공식 사이트의 Leaning, Reference 페이지와 인터넷에 공개되어 있는 많은 자료들을 참고하면 쉽게 익숙해질 수 있습니다. 브레드보드를 이용하여 LED, 모터, 스위치, 센서와 저항들을 연결하여 사용하면 기판을 만들 필요도 없고 납땜도 필요없이 손쉽게 원하는 회로를 만들어 볼 수 있습니다.

요즘은 아이가 로봇교실에서 사용하던 각종 센서와 모터를 물려서 시간날때 마다 이것저것 만들어 보고 있는데 재미있습니다.

물론 지금 쓰고 있는 컴퓨터 보다 1,000배는 더 열등한(?) 하드웨어이고 간단한 코드들로 간단한 동작들만 하지만 직접 하드웨어를 구성하고 제어하는 물리적인 재미와 함께 어린시절 전자키트를 가지고 놀던 향수도 느낄 수 있습니다. 직접 회로를 만들 수도 있지만 판매되는 전용 이더넷 쉴드모터쉴드직비 쉴드등을 이용해 쉽게 기능을 추가할 수 있으며 로봇 교재 사이트등에서 판매하는 부품들도 대부분 사용이 가능합니다. 아두이노는 소프트웨어 개발자를 위한 저렴(?)하고 재미있는 장난감중 하나인 것 같습니다.

아두이노는 스크래치에서도 바로 인식이 가능하기 때문에 스크래치의 센서보드로도 사용할 수있습니다. 관찰 메뉴에서 하단의 센서 관련 블록에서 우클릭 후에 'ScratchBoard 감시판 보이기'를 클릭하고 다시 감시판에서 우클릭 후에 '시리얼/USB 포트 선택'을 클릭하면 아래와이 아두이노 보드가 인식됩니다.


이를 이용하면 스크래치의 리모콘, 게임 컨트롤러를 쉽게 만들 수 있으면 촉각, 광, 온도, 적외선, 소리 센서등을 이용해 실제 환경을 스크래치에 반영시키는 것이 가능합니다. 스크래치뿐만 아니라 여러 개발환경에서 아두이노와 통신할 수 있는 방법들이 많이 공개되어 있습니다.


2. 샘플

이전에 포스팅한 블로그의 새 댓글을 확인하는 스크래치를 아두이노 버젼으로 만들어 보겠습니다. 이번도 마찬가지지만 정확한 파싱없이 대충 새 댓글을 판별하는 것이기 때문에 뭔가 쓸만한게 만들어 보실려면 코드를 많이 수정하셔야 할 것 입니다.

1) 아두이노 코드
아두이노 통합개발환경은 아두이노 공식 사이트의 다운로드 페이지에서 사용하는 OS별로 다운 받으실 수 있습니다. IDE의 에디터에서 아래의 코드를 입력한 후에 상단의 Upload 버튼을 클릭하면 보드로 업로드됩니다.

  1. #define LED_PIN    13
  2. #define DELAY_SEC  5
  3.  
  4. void setup() {
  5.   Serial.begin(9600);
  6.   pinMode(LED_PIN, OUTPUT);
  7. }
  8.  
  9. void loop() {
  10.   if (Serial.available() > 0) {
  11.    
  12.     byte b = Serial.read();
  13.     if (== 'O') {
  14.       digitalWrite(LED_PIN, HIGH);
  15.       delay(1000 * DELAY_SEC);
  16.       digitalWrite(LED_PIN, LOW);
  17.     }
  18.   }
  19. }

2) 프로세싱 코드
아두이노에서는 별도의 이더넷 모듈 없이는 직접적인 인터넷 연결이 불가능하기 때문에 프로세싱과 연동하여 블로그의 내용을 가져오도록 합니다. 프로세싱 IDE에서 아래의 코드를 입력하고 실행합니다.

  1. import processing.net.*;
  2. import processing.serial.*;
  3.  
  4. final String BLOG_URL = "www.cocoadev.co.kr";
  5. final int DELAY_SEC = 5;
  6.  
  7. String prevCommentID = "";
  8. Serial port;
  9.  
  10. void setup() {
  11.   size(400, 140);
  12.   background(10);
  13.  
  14.   port = new Serial(this, Serial.list()[0], 9600);
  15. }
  16.  
  17. void draw() {
  18.   background(10);
  19.   text(String.format("* URL: %s", BLOG_URL), 10, 25);
  20.  
  21.   Client webClient = new Client(this, BLOG_URL, 80);
  22.  
  23.   webClient.write("GET / HTTP/1.1\n");
  24.   webClient.write(String.format("HOST: %s\n\n", BLOG_URL));
  25.  
  26.   delay(1000 * DELAY_SEC);
  27.  
  28.   if (webClient.available() > 0) {
  29.     String data = webClient.readString();
  30.     String[] comment = match(data, "/[0-9]*#comment[0-9]*");
  31.    
  32.     text(String.format("* Received: %02d:%02d", hour(), minute()), 10, 50);
  33.    
  34.     String statusTitle;
  35.     if (comment != null && comment.length > 0) {
  36.       String recentCommentID = comment[0];
  37.      
  38.       if (prevCommentID.equals(recentCommentID)) {
  39.         statusTitle = "None";
  40.       } else {
  41.         statusTitle = "New";  
  42.        
  43.         port.write("O");
  44.       }
  45.      
  46.       prevCommentID = recentCommentID;
  47.     } else {
  48.       statusTitle = "Error";
  49.     }
  50.      
  51.     text(String.format("* Status: %s", statusTitle), 10, 75);
  52.   }
  53. }

아래와 같이 실행되는 모습을 확인할 수 있습니다. 급조한 소스에 나와있다시피 실행한 후 5초 후에 최초로 한번 LED가 한번 켜지고 그후에는 댓글에 변경이 있을때마다 켜집니다.
아두이노는 몇년전 마소와 같은 잡지에도 소개되고 사용하는 분들이 많으실 것 같습니다. 저야 신호등 놀이나 하는 수준이지만 인터넷을 찾아보니 기발한 아이디어로 재미있는 것들을 만드시는 분들이 많더군요. 재미있는 것을 하나 만들어봐야 겠다는 생각이 드는데 딱히 떠오르는 것은 없습니다. 그냥 이렇게 살살 가지고 놀다 끝날 수도 있을 것 같네요.

저작자 표시 비영리 변경 금지
신고

'기타' 카테고리의 다른 글

다시 글쓰기  (2) 2011.07.19
아두이노와 놀기  (4) 2010.07.01
참고할만한 좋은 아이폰 소스  (19) 2010.05.04
세계지도 앱 - World Atlas  (2) 2010.04.21
모토로이  (6) 2010.02.11
역시 그냥 껐다 키는 것이...  (8) 2009.09.24

재미로 만들었다가 몇몇분들과 만나게되어 이런저런 이야기나 하면서 노는 커뮤니티 사이트가 하나 있습니다. 이번에 서버쪽에서는 제가 api를 제공하고 아이폰 클라이언트 어플리케이션은 장대훈(사진중독)님이 만들고 소스까지 공개해 주셨습니다. 어플리케이션의 용도는 특정 커뮤니티에 특화되었고 일반적으로는 사용할 수 없습니다. 하지만 아이폰 어플리케이션 개발시 필요한 왠만한 UI와 구현들이 포함되어 있어 한번 살펴 보시면 많은 도움이 되실 것 같습니다.


코드에 포함된 중요 구현들은 아래와 같습니다. 그외에도 탭바, 네비게이션바, 이미지피커뷰, 검색, 키보드 입력등 다양한 구현 코드가 있습니다.

  • 다양한 UI 구현
  • 테이블뷰셀 커스터마이징
  • HTTP GET/POST 요청
  • XML 파싱
  • 사진 앨범, 카메라, 지도 이미지 접근
  • 맵뷰 및 위치정보
  • 푸시 노티피케이션


※ 서버쪽은 현재 폐쇠되어 있습니다. 소스코드의 라이센스는 GNU GPL을 따르고 있으며 소스코드와 관련된 질문과 데모 사이트의 구현과 API에 관련된 질문과 소스요청은 받지않습니다.

좋은 소스를 공개해주신 장대훈님께 감사의 말씀 드립니다.


저작자 표시 비영리 변경 금지
신고

'기타' 카테고리의 다른 글

다시 글쓰기  (2) 2011.07.19
아두이노와 놀기  (4) 2010.07.01
참고할만한 좋은 아이폰 소스  (19) 2010.05.04
세계지도 앱 - World Atlas  (2) 2010.04.21
모토로이  (6) 2010.02.11
역시 그냥 껐다 키는 것이...  (8) 2009.09.24

터치부터 아이폰까지 구매한 유료 어플이 2개인데 그중에 하나입니다. 다른 것은 아이에게 보여주기 위해 구입했으니 제가 쓰기 위해 구입한 유일한 유료 어플이네요. 네셔널지오그래픽에서 나오 세계지도를 볼 수 잇는 World Atlas란 어플입니다.

 가격은 1.99달러이며 책을 볼때 지명등이 나오면 바로 찾아 볼 수가 있어 좋습니다. 심심할때도 슬금 슬금 세계 구석구석을 구경하는 재미도 괜찮습니다. 지도와 컨텐츠도 괜찮을뿐 아니라 런칭속도와 어플리케이션 실행 속도도 빠르기 때문에 아주 만족스러운 어플인 것 같습니다.


기본인 Executive 모드와 Political, Satellite 모드가 있고 확대/축소를 지원하고 있습니다.  지도들은 보기 편하게 잘 만들어져 있는 것 같습니다. Executive 모드에선 각 모서리 부분에서 극지방 상세지도와 인구밀도, 식생, 인구밀도, 면적과 인구가 많은 나라들 등의 정보가 있습니다.



확대를 해서 볼 수 있으며 상세하게 확대해서 볼려면 네트워크에 연결하여 마이크로소프트의 Bing에서 지도를 가지고 와서 보여줍니다. 이 상태가 되면 하단 네셔널지오그래픽 로고가 Bing으로 변경됩니다. Nation 버튼을 클릭하면 국기와 함께 각 나라들의 목록이 나옵니다. 해당 국가를 클릭하면 그나라의 수도, 인구, 면적, 언어, 종교, 문해율, 회망수명, GDP등과 함께 간단한 설명을 볼 수 있습니다.



상세지도를 다운로드 받으면 네트워크 연결을 줄일 수 있습니다. 앱 설치후에 Index / Map Library에서 다운로드 받을 수 있습니다. Index에서 Major Cities of the World란 메뉴를 클릭하면 주요도시들의 목록을 볼 수 있습니다. 클릭하면 지도상의 해당위치로 이동하면 북마크를 할 수 있습니다.

어플의 단점이라기 보다는 아이폰의 디스플레이 크기로 인해 세계지도를 보는데는 답답한 부분이 있습니다. 이럴때 가장 생각나는 것이 아이패드인 것 같습니다. 네셔널지오그래픽에서도 이미 아이패드용 앱을 올려놓았고 아이폰과는 달리 HD라고 되어 있는 것을 보니 해상도도 더 좋아진 것 같습니다. 아이패드가 더욱 기다려 집니다.
저작자 표시 비영리 변경 금지
신고

'기타' 카테고리의 다른 글

아두이노와 놀기  (4) 2010.07.01
참고할만한 좋은 아이폰 소스  (19) 2010.05.04
세계지도 앱 - World Atlas  (2) 2010.04.21
모토로이  (6) 2010.02.11
역시 그냥 껐다 키는 것이...  (8) 2009.09.24
아이폰 3GS  (2) 2009.09.17

기타 2010.02.11 10:42
몇일전 주문한 모토로이를 받아 조금 사용해 보았습니다. 넥서스원이면 모를까 모토로이는 전혀 구매할 의사가 없었지만 현재 진행하고 있는 안드로이드 프로젝트 때문에 어쩔 수 없이 구입했습니다. 이전에 테스트용으로 잠시 써본적이 있어 전혀 관심이 가지 않는 제품이었습니다. 하지만 개발할 때도 쓰겠지만 집사람 핸드폰으로 구입한 것이고 집사람은 DMB만 되면 되니 괜찮을 것 같고 당장은 선택의 여지가 없어 바로 예약판매시 신청했습니다.


휴대용 젠더/DMB 안테나, 크래들, USB, 헤드셋, 차량용 충전기 등 구성품은 푸짐했습니다. 특히 크래들과 차량용 충전기는 아주 괜찮은 것 같습니다.

아이폰을 사용할때와 비해서 반응속도도 느리고 정확하지 않으며 스크롤시 딱딱 끊기는 느낌이 있습니다. 넥서스원을 사용해본 분의 이야기를 들어보면 같은 안드로이드지만 전혀 다른 OS라는 생각이들정도로 차이가 많이나고 모토로이가 부족하다고 했습니다. 내장되어 있는 문자인식 어플리케이션으로 책표지의 안드로이드란 큰 글씨를 인식시켜 보았는데 안드로메다로 인식하더군요. 묘한 기분이 들었습니다.

그나저나 안드로이드 개발을 하면서 구형 맥북의 한계를 느끼게 되는 일이 종종 있네요. 이로인해 조만간 아이맥을 구입하지 않을까 하는 걱정이 드는데 현실이 될 것 같습니다.
저작자 표시 비영리 변경 금지
신고

'기타' 카테고리의 다른 글

참고할만한 좋은 아이폰 소스  (19) 2010.05.04
세계지도 앱 - World Atlas  (2) 2010.04.21
모토로이  (6) 2010.02.11
역시 그냥 껐다 키는 것이...  (8) 2009.09.24
아이폰 3GS  (2) 2009.09.17
블로그를 또 다시 이전했습니다.  (4) 2009.05.11

파이썬에서 사용할 수 있는 BeautifulSoup을 이용해 xml 데이터를 sqlite3 DB에 넣는 툴을 만들는 간단한 예입니다.

1. BeautifulSoup 다운로드 및 설치
필요한 파일은 BeautifulSoup 사이트에서 다운로드 받으실 수있습니다. 파이썬 버젼이 2.*이면 3.0* 버젼을 3.*이면 3.1* 버젼중 최신버젼을 다운로드 받습니다. 다운로드가 완료되면 압축을 풀고 터미널에서 아래와 같이 setup.py를 실행합니다.

>python ./setup.py install

2. BeautifulSoup 사용예
1) 셈플 xml 파일 (test.xml)
테스트를 위해 간단히 작성해본 XML 입니다.
<?xml version='1.0' encoding='UTF-8'?>
<alcohol>
    <cate1 tt="술">
        <cate2 tt="소주">  
            <item>참이슬</item>
            <item>처음처럼</item>
            <item>잎새주</item>
        </cate2>   
        <cate2 tt='맥주'>  
            <item>카스</item>
            <item>라거</item>
            <item>하이트</item>
        </cate2>   
    </cate1>    
    <cate1 tt="안주">  
        <cate2 tt="고가">
            <item>회</item>
            <item>등심</item>
            <item>양곱창</item>
        </cate2>
        <cate2 tt="저가">
            <item>참치캔</item>
            <item>날계란</item>
            <item>새우깡</item>
        </cate2>
    </cate1>   
</alcohol>

2) 파이썬 소스파일 (con_data.py)
  1. #!/usr/bin/python
  2. #  -*- coding: utf-8 -*-
  3.  
  4. import sys
  5. import sqlite3
  6. from BeautifulSoup import BeautifulStoneSoup
  7.  
  8. argCount = len(sys.argv)
  9. if argCount is not 3:
  10.     print 'Usage:con_data.py [xml file] [db file]'
  11.     sys.exit(0)
  12.  
  13. xml_file = sys.argv[1]
  14. db_file = sys.argv[2]
  15.  
  16. #XML open
  17. src = open(xml_file)
  18. soup = BeautifulStoneSoup(src)
  19.  
  20. #DB & Table create
  21. db = sqlite3.connect(db_file)
  22. cursor = db.cursor()
  23.  
  24. cursor.execute("CREATE TABLE item(cate1, cate2, name)");
  25.  
  26. #Insert data
  27. for cate1 in soup.alcohol('cate1'):
  28.     query1 = 'INSERT INTO item VALUES("' + cate1['tt'] + '", "'
  29.     print 'CATE1: ' + cate1['tt']
  30.    
  31.     for cate2 in cate1('cate2'):
  32.         query2 = query1 + cate2['tt'] + '", "'
  33.         print   '\tcate2: ' + cate2['tt']
  34.      
  35.         for item in cate2('item'):
  36.             query3 = query2 + item.string + '")'
  37.             print '\t\t' + item.string
  38.  
  39.             cursor.execute(query3)
  40.     print "---------------------"
  41.  
  42. #Close
  43. cursor.close()
  44. db.commit()
  45. db.close()

3) 테스트
아래와 같이 실행하면 test.db가 생성되어 있음을 확인하실 수 있습니다.


해당 사이트에서 문서 페이지를 읽어 보시면 보다 세부적인 기능과 상세한 사용법을 확인하실 수  있습니다.  사용한 con_data.py외 test.xml은 압축하여 첨부하였습니다. 테스트 시에는 터미널에서 chmod +x ./con_data.py로 실행권한을 설정하셔야 합니다.


저작자 표시 비영리 변경 금지
신고

여지껏 아이폰으로 잘 개발하고 있다가 오늘 Xcode를 실행해보니, 빌드가 안되는 것이었습니다. 빌드가 잘될 때랑 지금이랑 Xcode도 그렇고 아이폰도 그렇고 바뀐 것은 아무것도 없었습니다. 오거나이즈를 열어 보니 아래와 같은 메시지가 나타났습니다.


Provisioning과 Application 정보가 나와야 할 곳에 "Could not support developement"란 오류메시지가 보였습니다. "Xcode cannot find the software image to install this version"는 말그대로 Xcode가 인스톨할 새로운 OS 이미지가 없다는 것으로 이전부터 나온 메시지였습니다.

인터넷에서 검색을 해보기에 앞서 이전부터 뜬금없이 나오는 프로비저닝 오류에서도 리부팅을 하면 된적이 있어 리부팅을 해보았습니다. 결과는 성공이고 초록색불과 함께 정상적으로 기기를 사용할 수 있었습니다.

한번은 오거나이즈에서 "This device is not currently connected."란 메시지가 나왔습니다. 그때는 Xcode를 재실행하니까 되더군요. 우연인지 모르겠지만 터치로 개발할 때보다 아이폰으로 개발할 때 이런 일들이 더 자주 일어 나는 것 같습니다.

이유는 모릅니다만 "안되면 껐다 켜라"라는 컴퓨터 사용시의 진리가 아이폰과 터치에서도 통하는 것 같습니다.

저작자 표시 비영리 변경 금지
신고

'기타' 카테고리의 다른 글

세계지도 앱 - World Atlas  (2) 2010.04.21
모토로이  (6) 2010.02.11
역시 그냥 껐다 키는 것이...  (8) 2009.09.24
아이폰 3GS  (2) 2009.09.17
블로그를 또 다시 이전했습니다.  (4) 2009.05.11
실버라이트2 동영상 재생 속도  (0) 2009.02.13

기타 2009.09.17 11:23
일때문에 아이폰 3GS를 잠시 가지고 있게 되었습니다. 다들 아시다시피 터치와 다른점은 조금 더 두껍고 카메라가 달렸다는 것입니다. 어플리케이션은 전화, 메시지와  나침반 정도가 눈에 뜁니다.

제가 만든 사전을 돌려보니 터치 2세대에서는 검색시 약간의 멈춤이 있었는데 3GS에서는 멈춤없이 바로 실행되더군요. 정확한 스펙은 보지 않았지만 속도도 많이 빨라진 것 같습니다.

전화는 개통되지 않았기 때문에 화면의 버튼들만 눌러 보았습니다. 제가 그동안 블랙잭만 써서 그런지 번호를 누르기가 정말 편하게 되어 있는 것 같았습니다.

카메라와 동영상의 화질도 블로그에 올리는 등 웹상에서 사용하기에 전혀 무리가 없을 정도로 괜찮았습니다. 혐오스러운 사진일 수도 있겠지만 3GS를 들고 다니며 찍은 사진이 없어 이것으로 올려 봅니다.


제 개인 블로그에는 주로 먹고 마시는 소소한 일상들을 많이 올리고 있습니다. 주로 블랙잭으로 많이 찍어 화질이 조금 아쉬웠는데 이정도면 괜찮을 것 같다는 생각이 듭니다. 한달전쯤 집사람의 핸드폰이 고장났습니다. 9월 초 아이폰이 나온다는 소문이 있어서, 아이의 핸드폰을 사용하며 기다려 보다가 출시되면 같이 아이폰을 사기로 했습니다.

늘 그렇듯이 역시나 잘못된 소문이었네요. 집사람은 다른 핸드폰을 사고 전 계속 아이폰을 기다리고 있습니다. 아이폰 하나면 되는데 항상 블랙잭과 터치, 두개를 가지고 다니기 번거롭고 빨리 나와주었으면 좋겠는데, 늘 소문만 무성하네요. 애플의 아이폰 발매 국가 페이지의 Coming Soon에 나오기전까지는 잊고 살자고 했는데, 막상 실제 아이폰을 보니 가지고 싶은 마음에 또 조급해집니다.

저작자 표시 비영리 변경 금지
신고

'기타' 카테고리의 다른 글

모토로이  (6) 2010.02.11
역시 그냥 껐다 키는 것이...  (8) 2009.09.24
아이폰 3GS  (2) 2009.09.17
블로그를 또 다시 이전했습니다.  (4) 2009.05.11
실버라이트2 동영상 재생 속도  (0) 2009.02.13
sqlite3 둘러보기  (3) 2009.02.02

sqlite3에서 csv(comma separated values) 포맷의 파일을 불러오고 내보내는 간단한 방법입니다.

1. Import
sqlite>.separator ,
sqlite>.import [csv 파일명] [테이블명]

또는 쉘상에서 아래와 같이 실행하여 입력할 수 있습니다.
$ sqlite3 -separator , [sqltie3 db 파일명] ".import [csv 파일명] [테이블명]"


2. Export
sqlite>.mode csv
sqlite>.output [csv 파일명]
sqlite>select * from [테이블명];
sqlite>.quit

* '[' 와 ']'는 입력하지 않습니다.
저작자 표시 비영리 변경 금지
신고

python에서 sqlite3를 사용하는 샘플입니다. mysql등 다른 데이터베이스를 사용하는 방법과 동일하며 간단한 스크립트이기 때문에 보시면 쉽게 이해가 되실 것입니다.

#!/usr/bin/python
#  -*- coding: utf-8 -*-

import sqlite3

# DB 연결
db = sqlite3.connect("test.db")
cursor = db.cursor()

datas = [(1, "cheetah"), (2, "puma"), (3, "leopard")]

# 테이블 생성
cursor.execute("create table animal (no, name)")

# 데이터 INSERT
cursor.executemany("insert into animal values (?, ?)", datas)

# 최종 INSERT된 rowid 출력
print 'Last rowid: ' + str(cursor.lastrowid)
# Row count 출력
print 'Row count: ' + str(cursor.rowcount)

# 쿼리
cursor.execute("select * from animal")
for row in cursor:
    print row[1]

cursor.execute("update animal set name='jaguar' where no=3");

cursor.execute("select * from animal")
print cursor.fetchall()

cursor.execute("select * from animal where no=1")
row = cursor.fetchone()
print 'No 1 is ' + row[1];

# 종료
cursor.close()

db.commit()
db.close()

스크립트를 실행하면 아래와 같이 출력되는 것을 확인하실 수 있습니다.

저작자 표시 비영리 변경 금지
신고

지인의 소개로 알게된 텍스트큐브 서비스로 옮겼다가 다시 티스토리로 돌아 오기로 했습니다. 왔다 갔다 해서 죄송합니다. 분위기도 한번 바꾸어 볼겸 구글에서 하는 서비스의 장점도 있을 것 같고해서 옮겼다가 몇시간도 안되어 돌아 왔습니다. 네임서버에서 cocoadev.co.kr를 다시 티스토리 서버로 변경하였습니다. 다시 돌아온 이유는 두가지입니다.

첫번째 이유는 티스토리에서 정이 많이 들은 것 같습니다. 블로거, 테터툴즈, 이글루스, 티스토리등 자주 옮겨 다녔던 개인블로그를 텍스트큐브로 옮겼을 때는 아무 감정이 없었습니다. 하지만 티스토리에서 시작해 지금까지 하고 있는 이 블로그는 좀 틀리네요. 비슷하긴 하지만 관리자 페이지를 몇번 들어가 본후 고향 생각이 났다고 할까요? 이 블로그가 있어야 할 곳은 티스토리다라는 생각이 들었습니다.

두번째 이유는 텍스트큐브에서 하는 우수 블로그 지원 이벤트 때문이었습니다. 제 블로그는 되지도 않을 뿐더러 지원도 하지 않았지만 왠지 들어가는 시점이 묘하기 때문입니다. 마치 상품에 눈이 멀어 블로그를 옮기는 모양새가 되어버리는 것 같습니다. 흔히 이야기하는 파워블로그를 유치할려는 목적이겠지만, 이런 이벤트는 자의적으로 옮길려는 사람들에겐 오히려 악재가 되는 것이 아닌가 하는 생각이 듭니다.

아무튼 잠시 가출 소동을 벌여 죄송합니다.

저작자 표시 비영리 변경 금지
신고

'기타' 카테고리의 다른 글

역시 그냥 껐다 키는 것이...  (8) 2009.09.24
아이폰 3GS  (2) 2009.09.17
블로그를 또 다시 이전했습니다.  (4) 2009.05.11
실버라이트2 동영상 재생 속도  (0) 2009.02.13
sqlite3 둘러보기  (3) 2009.02.02
버그추적 시스템 Mantis 설치  (6) 2009.01.07

이 부분에 대해서 방법을 찾고 있는데 현재는 미디어 플레이어의 rate를 설정하는 것처럼 실버라이트2에선 재생 속도를 변경하는 방법이 없는 것 같습니다. 꽁수로 재생시간을 조금씩 더 해보았는데 자연스럽지 않고 소리가 끊기면서 나와 옛날 비디오의 빨리감기를 보는 정도까지만 가능했습니다. 아래는 관련부분 소스입니다.

static double TIMER_INTERVAL = 300;
static double MOVE_MSECONDS = 10000;
static int MOVE_FF = 1;
static int MOVE_RW = -1;

public Page()
{
   
    /** 타이머 설정 */
    timerStoryboard.BeginTime = TimeSpan.Zero;
    timerStoryboard.Duration = new Duration(TimeSpan.FromMilliseconds(TIMER_INTERVAL));
    timerStoryboard.Completed += new EventHandler(timerCompleted);
}

private void ChangeSpeed()
{
    if (playSpeed == 0)
        return;

    double currentPos = mediaPlayer.Position.TotalMilliseconds;
    double newPos = currentPos + (MOVE_MSECONDS * playSpeed);
    double maxPos = mediaPlayer.NaturalDuration.TimeSpan.TotalMilliseconds;
    double downloadPos = Math.Floor(mediaPlayer.DownloadProgress * maxPos);

    mediaPlayer.Pause();
    
    /* 유효범위 검사 */
    if (newPos >= 0 && newPos < downloadPos)
    {
        mediaPlayer.Position = TimeSpan.FromMilliseconds(newPos);
        mediaPlayer.Play();

        timerStoryboard.Begin();
    }
    else
    {
        playSpeed = 0;
    }
}

private void timerCompleted(object sender, EventArgs e)
{
    ChangeSpeed();
}

/** 뒤로보기 클릭 */
private void btnRewind_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    playSpeed = MOVE_RW;
    ChangeSpeed();
}

/** 빨리보기 클릭 */
private void btnFast_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    playSpeed = MOVE_FF;
    ChangeSpeed();
}

ChangeSpeed()에서 mediaPlayer.Pause()와 mediaPlayer.Play()를 하지않고 빨리보기를 하면  어느정도 괜찮게 보이지만 역시 소리 부분은 부드럽게 재생이 안되네요. Position을 다시 설정하는 부분에 부하가 있어 밀리세컨드 단위의 세세한 제어는 힘든 것 같습니다. 또한 Progressive Download가 아닌 Streaming일 경우에는 저 방법으로는 대책이 없습니다. 저만 방법을 모르고 삽질중이라는 불길한 예감도 듭니다. ㅠㅠ

저작자 표시 비영리 변경 금지
신고

'기타' 카테고리의 다른 글

아이폰 3GS  (2) 2009.09.17
블로그를 또 다시 이전했습니다.  (4) 2009.05.11
실버라이트2 동영상 재생 속도  (0) 2009.02.13
sqlite3 둘러보기  (3) 2009.02.02
버그추적 시스템 Mantis 설치  (6) 2009.01.07
애플스크립트(AppleScript) 둘러보기  (4) 2009.01.06

기타 2009.02.02 14:03
iPhone SDK를 사용하면서 데이터베이스로는 내장된 sqlite3를 조금 사용해 보았습니다. ruby on rails나 이전에 조금 본적은 있지만, 실제로 사용하다 보니 기존의 일반적인인 데이터베이스에 비해 몇가지 재미있고 색다른 부분이 있는 것 같습니다.

1. 특징 & 둘러보기
1) ROWID
SQLite3의 테이블등은 생성시 기본적으로 rowid란 칼럼을 가지고 있습니다. auto increment되는 primary key와 같은 역활을 하지만 vacuum에 의해 변경될 수가 있다고 하니, 이런 용도로는 테이블의 특성에 맞게 사용해야 될 것 같습니다.


select *로는 rowid가 출력되지 않고 명시를 해주어야지 값을 확인할 수있습니다. 마지막으로 인서트된 항목의 rowid는 sqlite3_last_insert_rowid 함수의 반환값으로 확인할 수 있습니다.

2) 데이터 타입
타입이 컬럼에 일괄적으로 적용되는 다른 데이터베이스와는 달리 sqlite3는 각각의 로우별로 동적으로 타입이 결정됩니다. 그렇기 때문에 칼럼타입에 어떤 문자를 주던지 혹은 생략하더라도 테이블 생성이 가능합니다. 아래와 같이 테이블을 만든 후에 어떤 타입의 값들을 넣더라도 모두 저장이 가능합니다.


아래와 같이 각 컬럼의 값들에 따라 데이터타입이 결정됩니다.


한 컬럼에는 기본으로 1GB까지 저장이 가능하며 컴파일시에 SQLITE_MAX_LENGTH 값을 설정하여 2GB까지 가능합니다. 하지만 이전에 간단히 테스트를 해보았는데 OS X에서는 3MB 정도까지만 가능했습니다. 아마 애플에서 제한크기를 낮추어 설치하지 않았나 짐작을 하고 있습니다. 리눅스에서는 몇 백MB까지 인서트가 가능했습니다.

2. 기본 명령어
1) 시작
sqlite는 파일을 기반으로 한 컴팩트한 DB입니다. 대부분의 DB들이 파일을 기반으로 하지만 sqlite3는 데이터베이스 오픈시 인자로 파일을 받습니다.

> sqlite3 [file-name]
파일이 존재할 경우에는 기존 db파일을 열고 존재하지 않을 경우에는 새로 생성합니다. 쉘에서는 쿼리와 구별하여 명령어에 '.'이 접두사로 사용됩니다.

2) 종료
.quit 또는 .exit는 sqlite3를 종료하는 명령어입니다.
sqlite3>.quit
sqlite3>.exit

3) 도움말
sqlite3>.help
sqlite3 쉘에서 사용가능한 명령어들을 보여 줍니다.

4) 테이블 목록
sqlite3>.tables
현재 데이터베이스에 등록된 테이블들의 목록을 확인할 수 있습니다.

5) 스키마 정보
sqlite3>.schema [table-name]
지정된 테이블의 스키마를 확인할 수 있습니다. 테이블명을 입력하지 않으면 모든 테이블의 스키마가 출력됩니다. "ALTER TABLE"도 있는데 add와 rename만 가능한 것 같습니다.

6) 쿼리결과를 파일로 저장
sqlite3>.mode insert
sqlite3>.output db.sql
sqlite3>select * from mytable;
sqlite3>.quit
mode는 출력될 타입을 지정하며 csv, column, html, insert, line, list, tabs, tcl등으로 설정할 수 있습니다. output은 저장될 파일을 지정합니다. 위와 같이 실행 후 종료하면 mytable의 데이터들이 insert로된 sql문으로 db.sql 파일로 저장되어 있습니다.

7) 테이블 변경
sqlite3>alter table [table_name] rename to [new_table_name];
sqlite3>alter table [table_name] add [new_column_name];
alter는 테이블명의 변경과 테이블 컬럼의 추가만 가능한 것 같습니다.

8) vacuum
sqlite3>vacuum
데이터베이스의 테이블의 로우를 재정렬하고 delete, drop으로 인한 빈공간을 제거하는 최적화 작업을 수행합니다. insert, delete, drop등의 명령을 자주 수행하는 DB들은 정기적으로 vacuum을 실행해 주는 것이 좋습니다.

3. 자주 사용되는 C 함수
1) Open & Close
int sqlite3_open(const char *filename, sqlite3 **ppDb);
int sqlite3_close(sqlite3 *pDb);

sqlite3 데이터베이스 파일을 열고 닫는 함수 입니다.

사용 예)
sqlite3 *db;
NSString* path = @"./mydb.sqlite3";

if (sqlite3_open([path UTF8String], &db) != SQLITE_OK)
    NSLog(@"Fail to open sqlite3: %s", sqlite3_errmsg(db));
    sqlite3_close(db);
   
    return NULL;
}

2) 쿼리 실행
nt sqlite3_prepare_v2(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail);
int sqlite3_step(sqlite3_stmt* stmt);
int sqlite3_finalize(sqlite3_stmt *pStmt);

쿼리는 prepare -> step -> finalize의 단계로 실행되고 종료됩니다. prepare는 쿼리실행에 앞서 쿼리를 컴파일하여 바이트코드로 변경합니다. step은 prepare에서 준비된 코드를 실행하며 실행될때 마다 다음 데이터를 가지고 옵니다. finalize는 prepare와 쌍으로 할당된 sqlite3_stmt의 메모리를 해제합니다.

사용 예)
if (sqlite3_prepare_v2(prevDB, "SELECT * FROM cross_temp", -1, &statement, NULL) == SQLITE_OK) {
    while (sqlite3_step(statement) == SQLITE_ROW) {
        int pid = sqlite3_column_int(statement, 0);
        NSLog(@"pid %d", pid);
    }
}
sqlite3_finalize(statement);

3) 결과값
int sqlite3_column_int(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);

스텝에서 각 컬럼의 값들은 column_ 함수로 가져올 수 있습니다. 위는 int와 char*의 예이며 이외에도 각 타입에 맞는 함수들이 제공됩니다.

4) 쿼리 실행 - exec
int sqlite3_exec(sqlite3*, const char *sql, int (*callback)(void*,int,char**,char**), void *, char **errmsg);

exec은 위의 prepare, step, finalize를 동시에 실행하여 편리하게 사용할 수 있습니다. select와 같은 쿼리에서 각 단계의 데이터들은 콜백함수를 구현하여 처리할 수 있습니다.

사용 예)
if (sqlite3_exec(db, "SELECT * FROM item_info limit 10", setData, NULL, &error)) {
    NSLog(@"EXEC ERROR: %s", error);
    sqlite3_free(error);
}

콜백함수의 첫번째 인자는 sqlite3_exec의 4번째 인자에서 넘긴 사용자 데이터가 넘어 옵니다. cols는 전체 컬럼의 갯수이며 value, name에 각각 값과 컬럼명이 넘어 옵니다.
int setData(void* data,int cols, char** value, char** name) {

    for (int i = 0; i < cols; i++) {
        NSLog(@"%s, %s", value[i], name[i]);
    }
    return 0;
}


* 아이폰에서 쓰기 가능한 DB
어플리케이션은 실행시에 번들 내부의 파일에는 쓰기 권한이 없습니다. 그렇기 때문에 번들 내부에 있는 sqlite3 파일은 insert, update, delete와 같은 DB를 변경하는 쿼리가 실행되지 않습니다.

이를 해결하기 위해서는 Documents 디렉토리로 DB파일을 복사하고 이곳의 파일로 열어야 쓰기가 가능합니다. 애플의 아이폰 개발자 센터에 있는 SQLiteBooks 샘플에서 AppDelegate.m의 createEditableCopyOfDatabaseIfNeeded 메소드를 확인하시면 구현에 대해서 잘 나와있습니다. 그리고 아이폰에서 sqlite3 구현에 대한 간단한 내용은 이전 아이폰 SQLite3 샘플이란 포스팅에서 확인하실 수 있습니다.
저작자 표시 비영리 변경 금지
신고

맨티스 1.1.1 버젼을 사용하다가 이번에 1.1.6 버젼으로 업그레이드를 했습니다. ChangeLog를 살펴보니 1년동안 업그레이드를 착실히 해온 것 같습니다. 새로운 버젼을 설치 하면서 과정과 사용법을 간단히 정리해 보았습니다.

맨티스 설치사양은 아래와 같습니다.

  • MySQL 4.1.1 이상
  • PHP 4.3.0 이상
  • 아파치, IIS등의 웹서버

1. 다운로드 및 설치
1) 다운로드
맨티스 다운로드 페이지나 혹은 프롬프트 상태에서 아래와 같이 맨티스 설치 파일을 다운로드 받은 후에 압축을 풉니다.
 
> wget http://downloads.sourceforge.net/mantisbt/mantisbt-1.1.6.tar.gz?modtime=1228833846&big_mirror=0
> tar xvzf mantisbt-1.1.6.tar.gz

2) 링크
mantis로 접근하기 위해 압축이 풀린 디렉토리에 심볼릭링크를 걸어줍니다.

> ln -s ./mantisbt-1.1.6 mantis

3) 설치
웹브라우져에서 http://[YOUR-DOMAIN]/mantis/admin/install.php를 실행하여 설치를 시작합니다. 먼저 아래와 같은 첫화면에서 DB 접속정보를 입력합니다.


MySQL 관리자 권한이 있는 계정을 'Admin Username'과 'Admin Password' 필드에 입력하시면 설정한대로 Database와 계정을 생성합니다. 입력을 완료한 후에 'Install/Upgrade Database' 버튼을 클릭합니다.

다음단계에서는 'Write Configuration File(s)'에 오류가 발생합니다. 이는 mantis 루트에 config_inc.php 파일을 생성할 권한이 없어서 입니다. 아래의 작업으로 해결할 수 있습니다.

4) config_inc.php 설정
기존 샘플 파일(config_inc.php.sample)을 아래와 같이 복사합니다.

> mv config_inc.php.sample ./config_inc.php

config_inc.php 파일을 열어 오류메시지에 있는 내용대로 아래와 같이 DB를 설정합니다.
$g_hostname = 'localhost';
$g_db_type = 'mysql';
$g_database_name = 'bugtracker';
$g_db_username = '[USER-NAME]';
$g_db_password = '[USER-PASSWORD]';

기본 메일계정을 설정합니다.
# --- email variables -------------
$g_administrator_email  = 'admin@YOUR-DOMAIN';
$g_webmaster_email      = 'admin@YOUR-DOMAIN';

# the "From: " field in emails
$g_from_email           = 'noreply@YOUR-DOMAIN';

# the return address for bounced mail
$g_return_path_email    = 'admin@YOUR-DOMAIN';

기본으로 한글사용을 위해 아래와 같이 추가합니다.
$g_default_language = "korean";

* admin 디렉토리 삭제
마지막으로 ./admin 디렉토리를 삭제합니다. admin 디렉토리는 초기설치와 관련된 파일들이 위치해 있어 설치후에는 필요가 없이 권한없이 접근할 수 있기 때문에 삭제합니다. 삭제하지 않으면 로그인 화면에서 오류가 표시됩니다.

> rm -dfr ./admin/

5) 로그인
웹브라우져에서 http://YOUR-DOMAIN/mantis 로 들어 갑니다. 아래와 같이 맨티스 사이트가 나오면 오류없이 설치된 것 입니다.

관리자 아이디인 'administrator'와 초기 기본 패스워드인 'root'를 입력하고 로그인 합니다. 관리자 패스워드는 계정관리로 들어가 반드시 변경해야 합니다.

2. 사용자 계정
'관리/사용자 관리' 메뉴로 들어가 '계정생성' 버튼을 클릭하여 사용자를 추가합니다. 계정 생성후에 상세한 옵션이나 권한을 설정할 수 있습니다.


이메일로 계정등록이 발송되기 때문에 이메일 주소를 정확히 입력하셔야 합니다. 테스트를 하여보니 제 서버에서는 이메일이 발송 되지 않았습니다. 

* 이메일 발송 오류
맨티스 루트디렉토리에 있는 config_defaults_inc.php에서 아래의 g_phpMailer_method를 0으로설정되어 있던 것을 아래와 같이 1로 변경하였더니 이메일이 정상적으로 발송되었습니다.

# select the method to mail by:
# 0 - mail()
# 1 - sendmail
# 2 - SMTP
$g_phpMailer_method     = 1;
 
같은서버에 있던 이전 버젼은 0으로 mail()을 사용해도 발송되었는데 이번 버젼에 문제가 있는 것인지 다른 문제가 있는 것인지 모르겠습니다. 저는 0일 경우에는 발송이 안되고 1과 2일 경우에는 발송이 되었습니다.

3. 프로젝트
1) 프로젝트 생성
'관리/프로젝트 관리' 메뉴로 들어가 새로운 프로젝트를 생성합니다. 역시 등록 후에 아래와 같은 상세한 설정을 할 수 있습니다.


2) 서브 프로젝트
연관된 서브프로젝트를 생성하고 관리할 수 있습니다.

3) 버젼
버젼을 등록하고 관리합니다.

3) 분류
이슈등록시 지정할 분류를 관리합니다.

4) 사용자
프로젝트에 관련된 사용자를 추가하고 권한을 설정할 수 있습니다.


4. 이슈 등록 및 확인
1) 사용자 등록
사용자 계정(testID)로 로그인하여 '이슈보고하기' 메뉴를 클릭합니다. 해당 프로젝트를 선택하고 버튼을 클릭하여 필드를 입력하고 등록합니다.


아래는 등록된 이슈목록입니다.

2) 관리자 확인
다시 관리자로 로그인 하면 메인화면에서 새로운 이벤트를 확인할 수 있습니다. 할당되지 않은 이슈에는 담당자를 할당하거나 바로 처리할 수 있습니다.


5. 기타
1) 위키
위키설정은 사실 큰 의미는 없습니다. config_default_inc.php파일에서 g_wiki_enable 속성을 ON으로 하면 메뉴에서 wiki의 링크가 추가됩니다.

#####################
# Wiki Integration
#####################
 
 # Wiki Integration Enabled?
 $g_wiki_enable = ON;

 # Wiki Engine (supported engines: 'dokuwiki', 'mediawiki', 'xwiki')
 $g_wiki_engine = 'dokuwiki';

 # Wiki namespace to be used as root for all pages relating to this mantis installation.
 $g_wiki_root_namespace = 'mantis';

 # URL under which the wiki engine is hosted.  Must be on the same server.
 $g_wiki_engine_url = $t_protocol . '://' . $t_host . '/%wiki_engine%/';

2) 사용자화
웹에서 관리 메뉴와 config_default_inc.php 파일을 변경하여 용도에 맞게 변경할 수 있습니다.

* 커스텀 필드 등록
아래와 같이 사용자 필드를 등록할 수 있습니다. 이외에 권한등 다양한 옵션이 있습니다.

등록된 필드를 프로젝트에 링크하며 해당 프로젝트의 이슈 등록시 사용자 등록필드가 출력됩니다.

* 디자인 변경
core 디렉토리의 html_api.php의 함수들을 수정하여 페이지마다 공통적인 top, bottom과 그외 다른 디자인을 변경할 수 있습니다.

이외에도 공지사항, 문서관리등과 함께 편리하게 이용할 수 있는 기능들이 많이 있습니다. 장단점이 있지만 개인적으로는 Trac보다는 Mantis가 편한 것 같습니다.

저작자 표시 비영리 변경 금지
신고

그동안 OS X와 Xcode를 사용하면서 애플스크립트(AppleScript)란 단어를 간혹 들어 보고 샘플 코드를 본적은 있지만 실제 사용해 본적은 없었습니다. 코코아와 Objective-C를 둘러 보기도 벅찬데 애플스크립트까지 볼 여유가 안나서 차일피일 미루고 있었던 것 같습니다.

하지만 아무래도 맥을 잘 사용하고 어플리케이션을 효율적으로 만들기 위해서는 애플스크립트를 알고 있어야 할 것 같아 간단히 살펴 보았습니다. 아래는 애플스크립트 Example 폴더에 있는 'Finder Windows - Hide All'이란 샘플코드입니다.
보시다시피 프로그래밍 언어라기 보다는 일반 영어문장에 더 가까운 것 같습니다. 애플스크립트를 지원하는 여러 어플리케이션들의 기능과 조합하여 사용하면 다양한 작업을 할 수 있습니다. 이전까지는 그냥 쉘스크립트에서 확장된 언어인줄만 알았는데, 쉽고 재미있는 문법과 함께 편리하게 맥을 사용하고 개발을 할 수 있는 막강한 기능을 가지고 있는 것 같습니다.

 
1. 스크립트 편집기
애플스크립트를 작성하기 위해서는 스크립트 편집기를 사용합니다. 위치는 응용프로그램 / AppleScript 폴더 내에 있습니다. 이 폴더내의 Example Scripts를 보시면 각종 예제들을 확인하실 수 있습니다. 스크립트 편집기를 실행하면 아래와 같이 스크립트 편집기가 오픈됩니다.


1) 사전
애플스크립트의 장점은 애플과 다른 서드파티의 OS X 어플리케이션에서 제공하는 애플스크립트 지원기능을 사용하여 편리하게 어플리케이션을 조작할 수 있다는 것입니다. 지원하는 어플리케이션과 기능은 스크립트 에디터의 사전 목록에서 확인하실 수 있습니다. 스크립트 에디터의 메뉴에서 '파일/사전열기'를 클릭하거나 단축키(Command + Shift + O)을 입력합니다.
해당 어플리케이션을 더블클릭하면 속성과 기능들을 아래와 같이 확인하실 수 있습니다. 클릭하면 포함된 속성과 명령어들이 나오며 하단에서 항목에 대한 간단한 설명을 보실 수 있습니다. 

2) 코드 자동입력
스크립트 에디터에서 마우스 우클릭을 하면 아래와 같이 항목별로 자주 사용되는 코드들이 나열되어 있습니다. 필요한 항목을 선택하면 자동으로 에디터에 입력됩니다.

아래는 Tell Blocks의 Tell "Finder"를 클릭후에 자동으로 생성된 코드입니다.
tell application "Finder"
    -- insert actions here
end tell

3) 기록
스크립트 에디터의 툴바를 보면 '기록'이란 버튼이 있습니다. 기록은 지원하는 어플리케이션일 경우 사용자의 동작을 자동으로 스크립트로 변환해 주는 기능입니다. 사용방법은 '기록' 버튼을 클릭하고 해당 어플리케이션에서 스크립트로 생성될 행동을 하고 완료 후에는 '중단' 버튼을 클릭합니다.

아래는 파인더에서 어플리케이션 폴더를 열고 스크립트 에디터를 실행하는 과정이 스크립트로 자동으로 기록된 내용입니다. 
tell application "Finder"
    activate
    set target of Finder window 1 to folder "Applications" of startup disk
    set target of Finder window 1 to folder "AppleScript" of folder "Applications" of startup disk
    open application file "Script Editor.app" of folder "AppleScript" of folder "Applications" of startup disk
end tell

자동으로 소스코드를 생성해주는 것도 편하지만 문법을 잘 모를 경우에 이 '기록' 기능을 이용하여 확인하면 편리할 것 같습니다.


2. 예제
1) Hello World!
간단히 다이알로그박스를 열고 Hello World를 읽어주는 스크립트를 작성해 보겠습니다. 아래의 내용을 스크립트 에디터 상단의 편집창에 입력하고 컴파일 버튼을 클릭합니다.

display dialog "Hellow World!" buttons {"닫기", "말하기"} default button "말하기"
if the button returned of the result is "말하기" then
    say "Hellow World"
end if

컴파일전에는 보라색으로 소스가 출력되지만 오류가 없이 컴파일이 완료되면 아래와 같이 문법이 컬러링 되어 출력됩니다.

이제 스크립트 에디터의 실행버튼을 클릭하면 아래와 같이 다이알로그박스가 열리며, 우측의 말하기 버튼을 클릭하면 Hello World 음성이 출력됩니다.

2) 새 메시지
메일에서 새로운 메시지를 작성하는 간단한 애플스크립트를 작성해 보겠습니다. outgoing messqage의 subject, content, visible 프로퍼티를 설정하여 메일의 새로운 메시지 창을 오픈하는 스크립트 입니다.
(*
아래의 내용으로 새로운 메일을 생성합니다.

제목: 안녕하세요?
내용: 반갑습니다.
수신: zzerrrrr@gmail.com
*)
tell application "Mail"
    -- 새로운 메일 생성
    set newMessage to make new outgoing message with properties {subject:"안녕하세요?", content:"반갑습니다", visible:true}
   
    -- 수신자를 설정한다   
    tell newMessage
        make new to recipient with properties {name:"zzerr", address:"zzerrrrr@gmail.com"}
    end tell
   
    activate
end tell

* 주석
주석은 (*로 시작하여 *)로 종료됩니다. 다른 언어의 '/* */' 방식과 동일합니다. 한줄 주석은 '--'를 앞에 붙여 사용합니다.

* tell 
tell은 메시지를 수신할 해당 객체를 지정합니다. 각 구문은 'tell'로 시작하여 'end tell'로 종료합니다. tell application "Mail"은 메일 어플리케이션에 메시지를 발송한다는 의미입니다.

* set ~ to ~ 
객체에 값을 설정합니다. set A to B는 말 그대로 A를 B로 설정한다는 의미입니다.
 
* with properties {name:value, ...}
생성된 오브젝트 속성들의 값을 지정합니다.

실행버튼을 클릭하면 아래와 같이 스크립트에서 지정한 속성으로 새로운 메시지를 보내는 창이 오픈됩니다. 

3. 기타
1) 실행파일로 저장
스크립트 편집기의 메뉴에서 파일/별도저장을 클릭하면 아래와 같이 몇가지 파일포맷을 지정하여 저장할 수 있습니다.


파일포맷중 응용 프로그램이나 응용 프로그램 번들로 저장하면 스크립트 에디터 없이 바로 실행할 수 있는 실행파일로 저장할 수 있습니다.

2) 참고 자 및 사이트
저도 잠시 사용해보고 글을 올리는 것이라 부정확하고 틀린 내용이 많이 있을 것 같습니다. 자세하고 정확한 내용은 아래의 관련 문서와 사이트들을 참조하시기 바랍니다.

저작자 표시 비영리 변경 금지
신고

안드로이드 개발환경을 조금 더 살펴 볼려고 간단히 어플리케이션을 만들어 보았습니다. 처음 대쉬보드 바이오리듬을 시작한뒤로 바이오리듬을 너무 우려먹고 있는 것 같습니다. SDK의 설치나 사용방법은 이전에 포스팅한 구글 Android 개발환경 둘러 보기를 참조하시면 좋을 것 같습니다. 아래의 이미지는 에뮬레이터에서 실행한 모습입니다.


요즘 개발환경으로는 드물게 마우스 사용없이 GUI를 구현해야 하지만 레이아웃을 편집하면서 확인할 수 있으니 큰 불편은 없는 것 같습니다. 아래는 사용한 소스들과 간단한 설명입니다. 이클립스에서 안드로이드 프로젝트로 Biorhythm을 생성하고 각각의 소스를 아래와 같이 수정하시고, BioView.java를 추가하시면 위와 같이 실행해 보실 수 있습니다.

* Biorhythm.java
package com.zzerr;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class Biorhythm extends Activity {
    private BioView bioView;
    private EditText inputYear, inputMonth, inputDay;
   
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        setContentView(R.layout.main);
       
        bioView = (BioView)findViewById(R.id.myView);
       
        inputYear = (EditText)findViewById(R.id.inputYear);
        inputMonth = (EditText)findViewById(R.id.inputMonth);
        inputDay = (EditText)findViewById(R.id.inputDay);
       
        /** 버튼이 클릭되었을 경우 바이오리듬 출력 */
        Button button = (Button)findViewById(R.id.showButton);
        button.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                bioView.setBirthDay(Integer.parseInt(inputYear.getText().toString()),
                        Integer.parseInt(inputMonth.getText().toString()),
                        Integer.parseInt(inputDay.getText().toString()));
               
                bioView.invalidate();
            }
        });
    }
}


* BioView.java
View 클래스에서 상속 받아 main.xml에서 정의한 myView를 서브클래싱하는 클래스입니다. 바이오리듬을 계산한 후에 출력을 합니다.
package com.zzerr;

import android.view.View;
import android.content.Context;
import android.util.AttributeSet;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.Log;

import java.util.Date;

public class BioView extends View {
    /** 상수 */
    private static final int mMaxDays = 30;
    private static final int mMaxType = 3;
    private static final long mTDV = (60*60*24*1000);
    private static final double mPI = 3.14159;
   
    private static final double mBioValues[] = { 23.0, 28.0, 33.0 };
    private static final int mColors[] = { 0xff0000ff, 0xffff00ff, 0xff00ffff };
   
    /** 멤버변수 */
    private Paint mPaint;
    private Rect mRect;
    private double mStartDays;
    private Date mBirthDate, mTodayDate;
       
    public BioView(Context context, AttributeSet attrs) {
        super(context, attrs);
       
        mRect = new Rect();
        mPaint = new Paint();
       
        mRect.top = 0;
        mRect.bottom = getWidth();
        mRect.left = 0;
        mRect.right = getHeight();

        mTodayDate = new Date();
        Date startDate = new Date(mTodayDate.getYear(), mTodayDate.getMonth(), 1);
       
        mStartDays = startDate.getTime()/mTDV;
        mBirthDate = new Date();
       
        mBirthDate.setYear(0);
    }
   
    public void setBirthDay(int year, int month, int day) {
        mBirthDate.setYear(year);
        mBirthDate.setMonth(month);
        mBirthDate.setDate(day);
    }

   @Override
   protected void onDraw(Canvas canvas) {
        int cellWidth = getWidth()/mMaxDays;
       
        mRect.top = 0;
        mRect.bottom = getWidth();
        mRect.left = 0;
        mRect.right = getHeight();
       
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(0xFFFFFFFF);

        int x = 0, y = 0, oldY = 0;
         
        // 세로줄 출력
        for (int i = 0; i <= mMaxDays; i++) {
            x += cellWidth;
            canvas.drawLine(x, mRect.top, x, mRect.bottom, mPaint);
        }
         
        // 가로줄 출력
        canvas.drawLine(0, mRect.bottom/2, mRect.right, mRect.bottom/2, mPaint);
      
        // 오늘 날짜 출력
        mPaint.setColor(0xFFFFFF00);
        x = cellWidth * mTodayDate.getDate();
        canvas.drawLine(x, mRect.top, x, mRect.bottom, mPaint);
              
        // 바이오리듬 출력
        if (mBirthDate.getYear() != 0) {
            Log.e("LOG", "year:" + mBirthDate.getYear() +
                    "month:" + mBirthDate.getMonth() +
                    "day:" + mBirthDate.getDate());
           
            double startDays = mStartDays;
            double birthDays = mBirthDate.getTime()/mTDV;
                 
            for (int k = 0; k < mMaxType; k++) {
                x = 0;
             
                mPaint.setColor(mColors[k]);
             
                for (int i = 0; i <= mMaxDays; i++) {
                    double gab = birthDays - startDays;
                    double p = (int)(Math.sin((gab/mBioValues[k]) * 2.0 * mPI) * 100.0);
   
                    y = mRect.bottom/2 + (int)(p * ((mRect.bottom/2.0)/100.0));
                   
                    if (i != 0)
                        canvas.drawLine(x, oldY, x + cellWidth, y, mPaint);
                   
                    oldY = y;
                    startDays++;
                    x += cellWidth;
                }
            }
        }
        
        super.onDraw(canvas);
    }
}

* main.xml
GUI를 정의하는 곳입니다. 이곳에서의 수정은 아래의 R.java의 R 클래스에 자동으로 적용이 됩니다. com.zzerr.BioView와 같이 사용자 클래스도 정의하여 사용할 수 있습니다.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#666666"
    >

<com.zzerr.BioView android:id="@+id/myView"
    android:layout_width="fill_parent"
    android:layout_height="330px"
    android:background="#000000"
    />
   
<TextView android:id="@+id/helpLabel"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/myView"
    android:layout_marginTop="20px"
    android:text="생년월일을 입력후에 보기버튼을 클릭해 주세요."
    />

<EditText android:id="@+id/inputYear"
    android:layout_width="80px"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:text=""
    />

<EditText android:id="@+id/inputMonth"
    android:layout_width="60px"
    android:layout_height="wrap_content"
    android:layout_toRightOf="@id/inputYear"
    android:layout_alignTop="@id/inputYear"
    android:text=""
    />

<EditText android:id="@+id/inputDay"
    android:layout_width="60px"
    android:layout_height="wrap_content"
    android:layout_below="@id/myView"
    android:layout_toRightOf="@id/inputMonth"
    android:layout_alignTop="@id/inputMonth"
    android:text=""
    />
       
<Button android:id="@+id/showButton"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_alignParentRight="true"
     android:layout_marginLeft="10px"
     android:layout_toRightOf="@id/inputDay"
     android:layout_alignTop="@id/inputDay"
     android:text="보기"
     />

</RelativeLayout>

* R.java
주석에 설명되어 있는 것과 같이 자동으로 생성해 주는 파일입니다. main.xml을 편집하면 자동으로 그에 맞게 내용이 변경됩니다.
/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */

package com.zzerr;

public final class R {
    public static final class attr {
    }
    public static final class drawable {
        public static final int icon=0x7f020000;
    }
    public static final class id {
        public static final int helpLabel=0x7f050001;
        public static final int inputDay=0x7f050004;
        public static final int inputMonth=0x7f050003;
        public static final int inputYear=0x7f050002;
        public static final int myView=0x7f050000;
        public static final int showButton=0x7f050005;
    }
    public static final class layout {
        public static final int main=0x7f030000;
    }
    public static final class string {
        public static final int app_name=0x7f040001;
        public static final int hello=0x7f040000;
    }
}

Xcode와 Objective-C를 사용하는 아이폰 개발과는 달리 많은 개발자들에게 익숙한 이클립스와 Java를 사용하고, 윈도우 PC에서도 개발이 가능하니 시작하기는 더 쉬울 것 같다는 생각이 듭니다. 개발자 등록도 25달러로 더 저렴하고요. ^^
저작자 표시 비영리 변경 금지
신고

이번 장에서는 어느 페이지로 이동하던지 사이트 전체에서 상단과 하단의 내용을 동일하게 유지하기 위해, 사이트의 기본 레이아웃을 설정해 보겠습니다.   

1. 레이아웃 설정
어플리케이션 루트폴더에서 레이아웃 폴더(/app/views/layouts)로 이동합니다.

1) general.html.erb 생성
기본 레이아웃인 general.html.erb 파일을 작성합니다. ApplicationController에서 layout을 이 파일로 지정함으로써 모든 페이지에 적용되어 사용할 수 있습니다.

* general.html.erb
<%= render :partial => "layouts/header" %>
<%= @content_for_layout %>
<%= render :partial => "layouts/footer" %>

여기서는 공용으로 사용되는 헤더와 푸터를 출력하고 그 사이에 해당 View의 컨텐츠를 출력합니다. erb 파일에서는 "<%"와  "%>"내에서 eRuby 문법을 사용할 수 있습니다. "<%="는 해당 내용을 출력합니다.

<%= render :partial => "layouts/header" %>
partial의 layouts/header는 app/views/layouts 폴더에서 이름에 밑줄을 붙인 _header.html.erb 파일의 내용을 출력합니다.


2) _header.html.erb 생성
상단에 공통으로 보여질 헤더 템플릿입니다.

* _header.html.erb
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="ko">
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<META http-equiv="Pragma" content="no-cache">
    <title>:: 내 ROR 홈페이지</title>
    <%= stylesheet_link_tag 'default' %>
    <%= javascript_include_tag :defaults %>
</head>
<body>
<h1 id="site-title">내 ROR 홈페이지</h1>
<ul id="main-menu">
    <li>소개</li>
    <li>앨범</li>
    <li>게시판</li>
</ul>
<div id="contents-body">

타이틀과 메타태그와 기본 스타일시트와 자바스크립트의 링크를 지정하고 상단에서 항상 출력할 사이트 제목과 메뉴목록을 지정합니다.

<%= stylesheet_link_tag 'default' %>
/public/stylesheets의 default.css 파일을 스타일시트의 링크를 생성합니다.

<%= javascript_include_tag :defaults %>
/public/javascripts에는 레일즈가 생성해 놓은 기본으로 사용하는 자바스크립트 파일들이 있습니다. 위의 설정으로 모든 기본 자바스크립트의 링크가 생성됩니다.


3) _footer.html.erb 생성
페이지의 하단에서 공통적으로 출력될 내용입니다. 여기서는 간단한 인사말만 출력해 봅니다.

* _footer.html.erb
</div>
<div id='footer'>반갑습니다. 여기는 제 홈페이지입니다.</div>
</body>
</html>


4) 레이아웃 지정
app/controllers/application.rb을 열어 아래와 같이 layout 'general'을 추가하여, 위에서 작성한 general 템플릿 파일을 기본 레이아웃으로 지정합니다.

* ApplicationController.rb
class ApplicationController < ActionController::Base
  layout 'general'
  helper :all # include all helpers, all the time

  protect_from_forgery # :secret => 'ccc2786e4f2c9f0b9fd22843cd5fc608'
end


5) 확인
리로드를 하여 현재까지의 작업을 확인합니다.


2. public 폴더 작업
위에서 기본 레이아웃을 위한 템플릿 파일들을 만들어 보았습니다. 이제 스타일시트를 작성해 보겠습니다.
 
1) 자바스크립트
public 폴더의 javascripts 폴더에는 기본적인 자바스크립트 파일들이 ROR에 의해서 생성되어 있습니다. 빈 application.js와 프로토타입, 스크립타큘러스의 js 파일들이 있습니다. 이 파일들은 erb에서 'javascript_include_tag :defaults'를 사용하여 간편하게 모든 자바스크립트 파일들을 링크할 수 있습니다.

* 프로토타입
프로토타입은 1.6.0.1버젼입니다. 최신버젼은 1.6.0.3이며 필요하시면 해당사이트에서 최신버젼을 다운로드 받아 교체할 수 있습니다.

* 스크립타큘러스
기본적인 controls.js, dragdrop.js, effects.js 파일이 설치되며, 몇가지 파일들은 빠져 있습니다. 필요하시면 해당사이트에서 최신버젼을 다운로드 받아 설치할 수 있습니다. 다운로드 받은 후에 압축을 풀고 test 폴더를 웹에서 확인하시면 쉽게 사용방법을 익힐 수 있습니다. 


2) 스타일시트 작성
public 폴더의 stylesheet 폴더에서 기본 레이아웃으로 사용할 default.css를 아래와 같이 또는 변경하여 작성합니다.

* default.css
body {
    padding:10px;
    color:#3f3f3f;
    font-size:10pt;
    font-family:돋움, Gulim, Arial, sans-serif;
}

#site-title {
    color:#64A8C3;
}

#main-menu {
    float:left;
    padding:0;
}

#main-menu li {
    float:left;
    font-size:1.2em;
    font-weight:bold;
    list-style:none;
    margin-right:12px;
}

#contents-body {
    clear:both;
    width:600px;
    margin:20px 0;
    padding:10px;
    border:2px dotted #efefef;
    background-color:#f5f5f5;
}

#footer {
    width:600px;
    text-align:center;
}

3) 확인
이제 리로드를 하여 지금까지의 작업을 확인합니다.

 
사진을 올릴 수 있는 앨범과 간단한 게시판을 하나 만들어 보고 삽질기를 끝낸 후에, 실무 프로젝트에 도입을 해볼려고 합니다. 구현방법이나 용어등에 모두 자신이 없네요. 역시나 많은 지도편달 부탁 드립니다.
저작자 표시 비영리 변경 금지
신고

구글이 안드로이드 플랫폼 소스를 공개하였습니다. 플랫폼 전체 를 오픈소스로 만들어 버리는 것을 보면 과연 구글이라는 생각이 듭니다. 좌측은 안드로이드 캐릭터의 오픈소스 버젼입니다. 뚜껑을 열어 머릿속을 훤히 보여 주고 있습니다. ^^

다운로드 받아 볼까 했는데 파일크기가 2.1GB이고 6GB의 공간이 필요하기 때문에 다음 기회로 미루었습니다. '설치를 위해서는 Linux 또는 OS X가 필요하고 윈도우즈는 아직 지원하지 않는다'는 흔히 볼 수 없는 문구도 재미있습니다. 

이와 함께 안드로이드 개발자 블로그를 보면 Android Market: Now available for users란 제목으로 애플의 앱스토어와 유사한 어플리케이션 마켓을 런칭했다는 포스팅이 올라왔습니다. 현재까지는 50개의 어플리케이션이 올라와 있고 10월 27일 부터는 일반 개발자들도 어플리케이션을 등록할 수 있다고 합니다.

흥미로운 것은 개발자들에게 70%의 수익이 돌아 가는 부분은 애플의 앱스토어와 같지만, 나머지 30%에서도 구글은 수익을 가지고 가지 않는다고 합니다. 아무리 구글의 모토가 "Don't be evil"이지만 어지간히 통 큰 기업이 아닐 수 없네요.

개발자는 쉽게 유통시킬 수 있고 사용자는 경쟁적인 저렴한 가격에 소프트웨어를 구입할 수 있으니, SDK를 제공하고 온라인 상점을 이용해 개발자와 사용자를 직접 이어주는 이런 서비스가 많이 생기는 것은 양쪽 모두가 반길만한 일이라고 생각됩니다. 요즘 경제위기와 함께 IT의 빙하기가 도래한 우리나라 개발자들에게는 더 반가운 소식일 것 같습니다.

아이폰을 기다리다 지쳐 아이팟을 구입했는데, 문득 잘 한 것 같다는 생각이 듭니다. 휴대폰은 구글폰으로 구입해서 구글폰과 아이폰을 같이 가지고 다니면 심심할 일이 별로 없을 것 같습니다.
저작자 표시 비영리 변경 금지
신고

이전에 생성한 어플리케이션을 브라우져에서 확인해 보기위해 웹서버를 구동합니다. 어플리케이션 폴더에서 아래와 같이 실행합니다.

> script/server

레일즈의 웹서버는 일반적으로 3000 포트를 사용하기 때문에 "URL:3000/"과 같이 주소창에 입력하셔야 합니다. 브라우져에서 Rails의 기본페이지가 보이며, 아래와 같이 해야할 작업들이 나와 있습니다.

1. Use script/generate to create your models and controllers
To see all available options, run it without parameters.

2. Set up a default route and remove or rename this file
Routes are set up in config/routes.rb.

3. Create your database
Run rake db:migrate to create your database. If you're not using SQLite (the default), edit config/database.yml with your username and password.

위에서 지시하는대로 작업을 해보겠습니다.

1. Home 컨트롤러 생성
1) HomeController 를 생성
script내의 generate는 이름 그대로 레일즈에서 컨트롤러, 모델, 스케폴드등을 간편하게 생성할 수 있게 합니다. 시작 페이지를 만들기 위해 아래와 같이 index 뷰를 가진 home 컨트롤러를 생성합니다.

> script/generate controller Home index
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/home
      exists  test/functional/
      create  app/controllers/home_controller.rb
      create  test/functional/home_controller_test.rb
      create  app/helpers/home_helper.rb
      create  app/views/home/index.html.erb

실행이 되면 위와 같이 생성되는 디렉토리와 파일들을 확인할 수 있습니다. app/controllers 디렉토리에서 home_controller.rb가 아래와 같이 생성되어 있습니다.

class HomeController < ApplicationController
  def index
  end

end

2) index.html 삭제
public 디렉토리 아래의 index.html을 삭제합니다. index.html이 존재하면 아래에서 작업할 routes.rb에서의 설정이 무효화됩니다.

> rm public/index.html


2. routes.rb 설정
config 디렉토리 아래의 routes.rb 파일을 오픈합니다. 주석으로 처리된 부분을 제외하면 아래와 같습니다. map.root를 home 컨트롤러로 설정하도록 푸른색으로 된 부분을 추가합니다.

ActionController::Routing::Routes.draw do |map|
  map.root :controller => "home"
  map.connect ':controller/:action/:id'
  map.connect ':controller/:action/:id.:format'
end

이제 웹 루트('/') 요청을 받게 되면 /home/index로 연결됩니다.

3. 데이터 베이스 설정

1) 데이터베이스, 계정 생성
mysql에서 개발, 테스트, 배포에 필요한 데이터베이스와 계정을 생성합니다.

mysql> create database www_development;
mysql> create database www_test;
mysql> create database www;
mysql> grant all privileges on www_development.* to www_user@'localhost'  identified by '1111';
mysql> grant all privileges on www_test.* to www_user@'localhost'  identified by '1111';
mysql> grant all privileges on www.* to www_user@'localhost'  identified by '1111';

2) database.yml 수정
이제 config 폴더 밑의 database.yml을 오픈하여 위에서 생성한 정보로 변경합니다.

development:
  adapter: mysql
  encoding: utf8
  database: www_development
  username: www_user
  password: 1111
  socket: /tmp/mysql.sock

test:
  adapter: mysql
  encoding: utf8
  database: www_test
  username: www_user
  password: 1111
  socket: /tmp/mysql.sock

production:
  adapter: mysql
  encoding: utf8
  database: www
  username: www_user
  password: 1111
  socket: /tmp/mysql.sock

위의 파일에서 주석으로 되어 있는 부분을 보면 테스트를 위한 데이터베이스는 테스트 실행시 디비를 초기화 하기 때문에 개발과 배포를 위한 데이터베이스는 별도로 만들어야 한다고 경고하고 있습니다.

4. index.html.erb 파일
1) erb
index.html.erb 파일은 HTML과 eRuby 문법을 같이 사용할 수 있는 템플릿 파일입니다. eRuby는 템플릿 파일에서 사용할 수 있는 루비입니다. '<%' 와 '%>'의 사이에서 루비코드를 사용할 수 있습니다.

레일즈에 의해 이전에 생성된 app/views/home/index.html.erb의 내용은 아래와 같습니다.

<h1>Home#index</h1>
<p>Find me in app/views/home/index.html.erb</p>

2) 동작 확인
db등 변경된 부분을 새로 적용하기 위해 실행되고 있는 script/server를 컨트롤+C를 눌러 종료한 후에 script/server를 재시동합니다. 

브라우져에서 리로드를 하면 아래와 같이 위에서 작업된 내용들이 적용되어 초기화면이 아래와 같이 Home 컨트롤러로 연결되어 있는 것을 확인할 수 있습니다.

제가 루비온레일즈에서 해본 것중 70% 정도까지 온 것 같습니다. 해본 것도 이해를 정확히 못하고 있는데 조금만 있으면 진짜 삽질기로 들어 갈 것 같습니다.

저작자 표시 비영리 변경 금지
신고