iPhone 에서는 실행파일 과 번들이 속한 디렉토리가 Read-only 기 때문에 읽고-쓸 수 있는 Sqlite 파일을 만들어 줄려면 수동으로 복사해 줘야 하는 코드가 필요합니다. 
즉 앱스가 읽고 쓸 수 있는 'Documents' 디렉토리에 번들로 포함된 Sqlite 파일을 옮겨주기만 하면 되는 것입니다. 

해결방법
- (void) createEditableCopyOfDatabaseIfNeeded {

    // test for existance

    NSFileManager * fileManager = [NSFileManager defaultManager];
    NSString *documentsDirectory = [self applicationDocumentsDirectory];
    NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:@"OhReading.sqlite"];

    BOOL dbexists = [fileManager fileExistsAtPath:writableDBPath];

    if(!dbexists)
    {
        NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"OhReading.sqlite"];

        NSError * error;

        BOOL success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];

        if (!success) {

            NSAssert1(0, @"Failed to create writable database file with message '%@', ", [error localizedDescription]);
        }
    }

}


- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    
    if (persistentStoreCoordinator_ != nil) {
        return persistentStoreCoordinator_;
    }
    
    NSURL *storeURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"OhReading.sqlite"]];
    NSError *error = nil;

    	[self createEditableCopyOfDatabaseIfNeeded];

    persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {





중간에 
[self createEditableCopyOfDatabaseIfNeeded]; 
라는 식으로 persistentStoreCoordinator 함수 중간에 추가해 주면 번들에 있는 OhReading.sqlite 파일을 읽고-쓸 수 있는 Documents 디렉토리에 복사해줍니다. 

매우 쉽게 해결하기는 했지만, 막상 저는 고생했습니다. 예전에 참조했던 책인 'Head First iPhone Development - 2009' 에서 해결하는 방법이 몸에 익어버렸기 때문입니다. (Chapter 07 , 359 page)


iOS (3.1.3) 해결 방법 (책에 나온 방법)

- (void)applicationDidFinishLaunching:(UIApplication *)application {    
    
    // Override point for customization after app launch    
	[self createEditableCopyOfDatabaseIfNeeded];
}

- (void) createEditableCopyOfDatabaseIfNeeded {

    // test for existance

    NSFileManager * fileManager = [NSFileManager defaultManager];
    NSString *documentsDirectory = [self applicationDocumentsDirectory];
    NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:@"OhReading.sqlite"];

    BOOL dbexists = [fileManager fileExistsAtPath:writableDBPath];

    if(!dbexists)
    {
        NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"OhReading.sqlite"];

        NSError * error;

        BOOL success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];

        if (!success) {

            NSAssert1(0, @"Failed to create writable database file with message '%@', ", [error localizedDescription]);
        }
    }

}




하지만 이제 안되는 이유는 

applicationDidFinishLaunching  함수가 사라졌(?)습니다. 사실 존재하는 것 같기는 하지만 숨긴 것 같습니다. 대신 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  

함수가 대신해서 생긴 것 같습니다. 하는 일이 비슷한 것 같다는 것이죠. 
그렇다고 이렇게 만들면 문제가 발생합니다. 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    
    // Override point for customization after application launch.

    [self createEditableCopyOfDatabaseIfNeeded];

    // Add the navigation controller's view to the window and display.
    [window addSubview:navigationController.view];
    [window makeKeyAndVisible];

    return YES;
}



createEditableCopyOfDatabaseIfNeeded 

함수가 호출 되기 전에 이미 Documents 디렉토리에 sqlite 파일이 생기는 문제인데요. 대체 이유가 뭔가 해서 스택에 호출된 함수를 일일이 뒤지다가 시간이 다 지나갔습니다. 결국 '오컴의 면도날(클릭)' 을 생각해 냈습니다. '스택을 다 뒤지는 것 같이 복잡한 것이 아닐 것이다. 쉬운 해결 방법이 있을 것이다' 그래서 다른 접근 방법을 통해서
persistentStoreCoordinator 가 호출되기 전에 sqlite 파일이 존재하는지 체크해서 존재 안하면 생성 시켜버렸습니다. 






snow leopard 의 세상이 왔습니다. 

EDITED: 온지는 한참 됐습니다.... 예전 글 갱신한 것이라서요

진짜 왔는가는 별도로 하고 배달된 스노우 레오파드를 깔아줬습니다. 저는 맥빠가 아니니 표범 그려진 껍데기 보면서 하앍거리는 일은 전혀 없었구요

기존의 깔려 있는 osx leopard 위에 걍 덮어서 씌웠습니다. 처음에는 별 감흥없이 돌아가더군요 메뉴바 같은게 바뀐거 같긴 한데 잘 모르겠고 암튼 그냥 새로운 '맥'이겠거니 하고 사용하고 있었는데 결국 문제가 발생했습니다.

svn 이 깔리면서 기존에 제가 패치해둔게 동작을 안하더군요. 스노우 레오파드가 되면서도 그 문제 많은 utf-8 문제를 해결을 안했더군요 (아마 영원히 안할듯 싶네요..) 그래서 깔려있던 subversion source 를 컴파일 해서 다시 사용하려고 했는데 기존에 깔려 있던 라이브러리들이 32bit 라 링크에서 문제가 생기더군요.

이거저거 하다가 귀찮아서 가비얍게 기존 버젼을 포맷해주고 다시 '스노우 레오파드'를 깔아줬습니다. 그리고 다시 시작하는 마음으로 경건하게 svn 을 돌려봤는데 기존에 제가 포스팅 했던 문제가 고쳐지지 않았더군요. 그래서 다시 subversion 을 다운 받았습니다.

1. subversion 소스만 받아서 컴파일을 해보니 컴파일이 되지가 않더군요.

2. subversion - depends 소스 까지 받아서 합쳐서 컴파일 하니 'svn st' 쓸 때마다 segmentation fault 가
발생하더군요.

3. mac port 를 이용해서 subversion 을 설치하면 새로 컴파일 된 버젼이 깔리기는 하는데 snow leopard 안에
포함된 버젼과 똑 같은 svn 이 설치되더군요.

자 여기까지는 사족이고 이제부터가 진짜입니다.

== snow leopard 에 한글 파일 문제 없는 subversion 설치하기 == 

EDITED: subversion 1.6.15 로 업그레이드에 맞춰서 다시 적용합니다

1. mac port 로 dependency 문제를 해결한다.  snow leopard 안에 포함된 subversion 과 같은 svn 이
설치됩니다. (1.6.15 버젼이 설치됨)

sudo port install subversion

2. 이곳 에서 소스를  받습니다. subversion-deps-1.6.15.tar.gz 와 subversion-1.6.15.tar.gz 를 각각 다운 받고 다른 폴더 에 저장합니다.

subversion-1.6.15 가 각각 생기는데 subversion-deps-1.6.15.tar.gz 를 압축 풀었을 때 생기는 subversion-1.6.15 밑의 neon 디렉토리를 subversion-1.6.15.tar.gz 를 압축 풀었을 때 생기는 디렉토리로 이동시킨다.

neon 을 포함시켜주는 이유는 http 나 https 방식으로 접근이 가능한 클라이언트를 만들기 위해서 입니다.

3. 예전 방식 을 이용해서 소스를 패치해줍니다. (아래쪽에 1.6.15 버젼에 맞춘 패치 파일 있음)

patch -p0 < utf8_mac.patch
cd subversion-1.6.15
./configure --with-ssl
make
sudo make install

make 에서 테스트 진행중에 error 가 발생해서 build 가 멈추지만 무시하시고 바로 다음 명령을 진행하시면
됩니다. (버클리 디비 없다고 어쩌구 에러 생기면 무시해 주세요)


매번 패치하는 것도 지겨운데 애플이나 subverion 이나 한국이 관심 대상 밖인 것은 알지만 이 문제는 CJK
들의 공통적인 문제일텐데 왜 아무런 대책이 없나 궁금합니다.





코딩에 좋다는 10가지 폰트를 다 써봤지만 개인적으로는 Consolas 를 추천합니다. 그 미묘하게 휘어지는 곡선의 느낌이 참 좋습니다. -ㅅ-... 



일단 폰트 모습입니다. 프로그래밍 하루 이틀 해온 것도 아니고, 앞으로도 수도 없이 할 것 같은데요. 기분 좋게 생긴 폰트를 가지고 작업을 하면 여러모로 기분이 좋습니다. 

OSX 에서 Monaco 폰트를 썼는데 이 폰트 알게 된 후로 전부 다 수정하고 있습니다. 단 단점이라면 우분투를 버추얼 박스(VitualBox)에서 돌리고 있는데 거기서 기본 폰트로 쓰기에는 크기가 안 맞더군요. 17 pt 까지 크기를 키워야지만 이쁘게 보입니다. ClearType 폰트는 하드웨어 가속이 되야지만 작을 때 이쁘게 보이는 건갈까요? 


이거 저거 직접 타이핑 하면서 폰트 모습을 볼 수 있게 해주는 사이트 입니다. 위의 그림도 거기서 타이핑해서 캡쳐했습니다. 






ACE 는 훌륭한 네트워크 프레임 워크 입니다. 서버를 작성할 때 신경써야 할 귀찮은 것들을 알아서 처리를 해줍니다. 그러한 ACE를 이용해서 우분투에서 간단한 에코서버(Echo Server)를 작성하는 방법을 알아보겠습니다. 

1. 설치 

그 귀찮은 ACE 받고 , 압축 풀고, 컴파일 하는 과정이 우분투에서는 간단한 명령 몇번이면 다 됩니다. 

sudo apt-get install libace-5.6.3 libace-dev libace-doc mpc-ace 

각각의 설명입니다. 
i   libace-5.6.3                    - C++ network programming framework         
i   libace-dev                      - C++ network programming framework develop
i   libace-doc                      - C++ network programming framework document
i   mpc-ace                         - makefile, project and workspace creator 

libace* 들은 ACE 관련 라이브러리와 헤더들입니다. mpc-ace 는 편하게 ACE 관련한 프로젝트 make 해주는 관리 툴입니다. (진짜 편합니다. 예전에 직접 작성해줄려고 하면 여러가지로 귀찮았습니다)


2. 환경 설정

.bashrc

export ACE_ROOT=/usr/share/ace
export LD_LIBRARY_PATH=/usr/lib:$ACE_ROOT/lib:$LD_LIBRARY_PATH 

라고 추가 설정해 주고 

source ~/.bashrc 

라고 입력해줍니다. 

3. 에코 서버 (Echo Server)

메아리 서버라고도 부르지요, 뭔가를 입력하면 똑같은 말을 돌려주는 기능을 가진 서버로 거의 모든 서버의 기본입니다. (서버 세계의 Hello World 라고나 할까요?)

이 소스는 어디선가 봐서 따온 것인데요. 누구것인지 기억이 안납니다. 혹시나 이 게시물을 보시게 되면 연락주세요 (__ 

9088 포트에 에코서버를 띄우고 클라이언트의 접속을 기다립니다. 

#include <ace/OS.h>
#include <ace/Log_Msg.h>
#include <ace/Message_Block.h>
#include <ace/INET_Addr.h>
#include <ace/Svc_Handler.h>
#include <ace/SOCK_Acceptor.h>
#include <ace/SOCK_Stream.h>
#include <ace/Synch_Traits.h>
#include <ace/Reactor.h>
#include <ace/Acceptor.h>
#include <ace/Reactor_Notification_Strategy.h>

class Stream_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> {
private :
	typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> super;
	
	ACE_INET_Addr remote_addr_;
	ACE_Reactor_Notification_Strategy noti_;

public :
	Stream_Handler()
		: noti_(0, this, ACE_Event_Handler::WRITE_MASK)
	{ /* empty */ }

	//override
	virtual int open(void * = 0)
	{
		ACE_TRACE("Stream_Handler::open");
		if( super::open() == -1 )
			return -1;
		noti_.reactor(this->reactor());
		this->msg_queue()->notification_strategy(¬i_);
		if( this->peer().get_remote_addr(remote_addr_) == 0 )
		{
			ACE_DEBUG((LM_INFO, "[DEBUG%T](%N:%l) ### New client accepted: %s:%u\n", 
				remote_addr_.get_host_addr(), remote_addr_.get_port_number()));
		}
		return 0;
	}

	//override
	virtual int handle_input(ACE_HANDLE handle = ACE_INVALID_HANDLE)
	{
		ACE_TRACE("Stream_Handler::override");
		char buf[1024];
		ssize_t recv_cnt;
		if( (recv_cnt = this->peer().recv(buf, 1024)) <= 0 )
			return -1;
		ACE_Message_Block *mb;
		ACE_NEW_RETURN(mb, ACE_Message_Block(buf, recv_cnt), -1);
		mb->wr_ptr(recv_cnt);
		this->putq(mb);
		return 0;
	}

	//override
	virtual int handle_output(ACE_HANDLE handle = ACE_INVALID_HANDLE)
	{
		ACE_TRACE("Stream_Handler::handle_output");
		ACE_Message_Block *mb;
		ACE_Time_Value nowait(ACE_OS::gettimeofday());
		while( this->getq(mb, &nowait) != -1 )
		{
			ssize_t send_cnt = this->peer().send(mb->rd_ptr(), mb->length());
			if( send_cnt == -1 )
				ACE_ERROR((LM_ERROR, "[ERROR%T](%N:%l) ### %p\n", 
                                "Stream_Handler::handle_output"));
			else
				mb->rd_ptr(send_cnt);
			if( mb->length() > 0 )
			{
				this->ungetq(mb);
				break;
			}
			mb->release();
		}
		if( this->msg_queue()->is_empty() )
			this->reactor()->cancel_wakeup(this, ACE_Event_Handler::WRITE_MASK);
		else
			this->reactor()->schedule_wakeup(this, ACE_Event_Handler::WRITE_MASK);
		return 0;
	}
	
	//override
	virtual int handle_close(ACE_HANDLE handle, ACE_Reactor_Mask close_mask)
	{
		ACE_TRACE("Stream_Handler::handle_close");
		ACE_DEBUG((LM_INFO, "[DEBUG%T](%N:%l) ### Connection close %s:%u\n", 
				remote_addr_.get_host_addr(), remote_addr_.get_port_number()));
		return super::handle_close(handle, close_mask);
	}
	
};


int ACE_TMAIN(int argc, ACE_TCHAR *argv[])
{
	ACE_INET_Addr listen;
	listen.set(9088);
	ACE_Acceptor<Stream_Handler, ACE_SOCK_ACCEPTOR> acceptor;
	acceptor.open(listen);
	ACE_Reactor::instance()->run_reactor_event_loop();
	ACE_RETURN(0);
}



또한 이 소스는 Reactor 를 쓰고 있는데 그것에 관한 설명은 다음으로 미루기로 하지요. 설명하자면 끝도 없을 테니까요. 위 내용을 server.cpp 로 저장합니다. 

4. mpc-ace 

mpc 는 복잡하게 작성해야만 했던 ACE 관련한 makefile 을 정말 편하게 만들어 주는 관리 툴입니다. 기본적으로 확장자가 mpc 인 파일이 필요합니다. 

server.mpc

project(server) : aceexe {
  exename = server
//  includes += directory_name other_directory
//  libpaths += /usr/X11R6/lib
 
  Header_Files {
    }
 
  Source_Files {
          server.cpp
  }
}

project(server) 를 보면 ( ) 안의 이름으로 make 파일이 만들어 집니다. 
aceexe 라고 쓰여진 것은 ace 관련된 실행파일로 만들라는 이야깁니다. 
exename = server 는 server 라는 이름의 실행파일이 만들어 집니다. 
includes 와 libpaths 는 추가되는 참조 디렉토리와 라이브러리를 더할 때 쓰입니다. 여기서는 안 쓰니 코멘트 처리합니다. 
Source_Files 에 컴파일할 대상을 적어줍니다. 현재 server.cpp 밖에 없습니다. 

mpc-ace server.mpc -type gnuace 

로 입력하면 GNUMakefile.server 라고 메이크파일이 하나 생성됩니다. 

make -f GNUMakefile.server 

로 입력하면 바로 컴파일 되고 실행파일이 생성됩니다. 





현상

function thisMovie(movieName) {
    if (navigator.appName.indexOf("Microsoft") != -1) {
        return window[movieName];
    } else {
        return document[movieName];
    }
}

자바스크립트 (Javascript) 에서 플래시 객체를 가져올려고 호출할 때마다 에러가 발생 
파이어폭스 (FireFox) 에서는 잘 돌아가지만 구글크롬 과 사파리에서 에러가 남 


해결

function thisMovie(movieName) {
    if (navigator.appName.indexOf("Microsoft") != -1) {
        return window[movieName];
    } else {
        return document.getElementById(movieName);
    }
}

파이어폭스(FireFox)와 구글크롬(Chrome)에서 잘 돌아감 , 사파리는? 사파리는. 사파리는.. 







OSX Snow Leopard 에서 Rails 개발하게 됐습니다. 환경 세팅이 되야 본격적으로 개발을 진행 할 테니 이 글은 개발 환경 세팅에 관한 글입니다. 

1. Emacs Client 는 OSX 에서 사용하는 Aquamacs 입니다. Ruby-mode 는 내장된 것을 사용함 
2. 색 배정은 Color Theme 를 사용합니다. 
3. Rails Helper 는 Rinari 를 사용합니다. 
4. snippet 기능은 yasnippets 를 사용합니다. 
5. ruby-mode 에서 complete 기능은 ri-emacs 기능을 사용합니다. 


Aquamacs 는 설치가 되어 있다고 가정합니다. 

1. ~/Library/Preferences/Aquamacs Emacs/http://github.com/zhannes/Aquamacs-Emacs 에서 받은 파일들을 복사해 넣습니다. 



2. ~/Library/Preferences/Aquamacs Emacs/Preferences.el 을 열어서 다음과 같이 수정해 줍니다. 



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; load ruby-mode.el                 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;loads ruby-mode.el - activate with M-x ruby-mode
(add-to-list 'load-path "~/Library/Preferences/Aquamacs Emacs/emacs_includes/plugins/ruby-mode.el")

; loads ruby mode when a .rb file is opened.
(autoload 'ruby-mode "ruby-mode" "Major mode for editing ruby scripts." t)
(setq auto-mode-alist  (cons '("\\.rb$" . ruby-mode) auto-mode-alist))
;;(setq auto-mode-alist  (cons '(".rhtml$" . html-mode) auto-mode-alist))
(setq auto-mode-alist  (cons '(".rhtml$" . rhtml-mode) auto-mode-alist))

(add-to-list 'load-path "~/Library/Preferences/Aquamacs Emacs/emacs_includes/plugins/ruby-electric.el")


rhtml 확장자 파일이면 rhtml-mode 로 연결될 수 있도록 수정합니다.




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; load emacs-code-browser           ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;Allows syntax highlighting to work, among other things

;; ;These lines are required for ECB
;; (add-to-list 'load-path "~/Library/Preferences/Aquamacs Emacs/emacs_includes/plugins/eieio")
;; (add-to-list 'load-path "~/Library/Preferences/Aquamacs Emacs/emacs_includes/plugins/speedbar")
;; (add-to-list 'load-path "~/Library/Preferences/Aquamacs Emacs/emacs_includes/plugins/semantic")
;; (setq semantic-load-turn-everything-on t)
;; (require 'semantic-load)
;; ; This installs ecb - it is activated with M-x ecb-activate
;; (add-to-list 'load-path "~/Library/Preferences/Aquamacs Emacs/emacs_includes/plugins/ecb")
;; (require 'ecb)

ECB 관련해서는 전부 comment 처리합니다. ECB 버젼이 낮아서 최신 버젼을 깔아주는 것이 좋겠더군요. 
 


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; load rails-mode.el                ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


; needed for rails mode
(require 'snippet)
(require 'find-recursive)
; The rails require needs to go after ECB
; otherwise it loads a new incompatible speedbar
; (add-to-list 'load-path "~/Library/Preferences/Aquamacs Emacs/emacs_includes/plugins/emacs-rails")

; blik.it's rhtml enhancements
;; (add-to-list 'load-path "~/Library/Preferences/Aquamacs Emacs/emacs_includes/plugins/rhtml/")
;;(add-to-list 'load-path "~/Library/Preferences/Aquamacs Emacs/emacs_includes/plugins/emacs-rails/")
(require 'nxml-mode)
;; (require 'rhtml-mode)
;;(require 'rails)


기존에 포함된 emacs-rails 헬퍼부분을 comment 처리합니다. 이렇게 하는 이유는 Rinari 를 헬퍼로 사용하기 위해서 입니다. 

rhtml-mode 는 사용하는 모드인데 .emacs 에서 최신버젼으로 설정해 주기 위해서 기존 것을 로딩하는 부분을 comment 처리해 줍니다.

;(load "~/Library/Preferences/Aquamacs Emacs/nxhtml/autostart.el")

nxhtml-mode 는 검은색을 바탕으로 하는 색 테마에는 어울리지가 않더군요. comment 처리해 줍니다. 


(cua-mode t) -> (cua-mode nil) 

로 수정해 줍니다. 

3. ri-emacs 는 http://rubyforge.org/projects/ri-emacs/ 에서 다운 받아서 "~/.emacs.d/ri-emacs" 안에 내용을 풀어줍니다. 
.emacs 안에 


(add-to-list 'load-path "~/.emacs.d/ri-emacs")
(autoload 'ri "~/.emacs.d/ri-emacs/ri-ruby.el" nil t)
(setq ri-ruby-script (expand-file-name "~/.emacs.d/ri-emacs/ri-emacs.rb"))


와 같이 세팅해 줍니다. 

4.yasnippet 은 http://code.google.com/p/yasnippet/ 에서 다운 받을 수 있습니다. 오른쪽 중간쯤에 필요한 파일들이 나열되어 있는데요. yasnippet-bundle-0.6.1c.el.tgz 파일을 받아서 푸시고 "~/.emacs.d/plugins" 에 복사합니다. 그리고 .emacs 파일에 



(add-to-list 'load-path
             "~/.emacs.d/plugins")
(require 'yasnippet-bundle)

와 같이 지정해 주면 됩니다. 

5. rhtml-modehttp://github.com/eschulte/rhtml 에서 다운 받아서 "~/.emacs.d/rhtml" 에 압축을 풀어 줍니다. 그리고 .emacs 에 



(add-to-list 'load-path
             "~/.emacs.d/rhtml")
(require 'rhtml-mode)
(add-hook 'rhtml-mode-hook
          (lambda () (rinari-launch)))

와 같이 설정해 줍니다. 

6. yasnippet 모드에서 Rails 를 지원하기 위한 추가 팩입니다. http://github.com/eschulte/yasnippets-rails 에서 다운 받아서  "~/.emacs.d/plugins" 에 풀어줍니다
. 그리고 .emacs 에 


(load-file "~/.emacs.d/plugins/setup.el")
(add-hook 'rinari-minor-mode-hook
          #'(lambda ()
              (setq yas/mode-symbol 'rails-mode)))

와 같이 설정해 줍니다. 

7. ECB 파일을 따로 설치해 줍니다. 굳이 따로 설명을 드리지 않겠습니다. 다만 제 .emacs 파일에서는 



(add-to-list 'load-path "~/.emacs.d/cedet/common")
(add-to-list 'load-path "~/.emacs.d/cedet/contrib")
(require 'cedet)

(add-to-list 'load-path
                   "~/.emacs.d/ecb")
(require 'ecb)


이렇게 설정되어 있습니다. 

8. Rinari 모드를 설치해야 합니다. 이건 ELPA 방식으로 설치하는 것이 가장 편합니다. *scrach* 버퍼로 이동해서 모드를 lisp-interaction-mode 로 변경합니다. 그리고 다음 과 같은 내용을 버퍼에 삽입합니다. 



(let ((buffer (url-retrieve-synchronously
      "http://tromey.com/elpa/package-install.el")))
  (save-excursion
    (set-buffer buffer)
    (goto-char (point-min))
    (re-search-forward "^$" nil 'move)
    (eval-region (point) (point-max))
    (kill-buffer (current-buffer))))

내용 마지막에 커서를 위치시키고 C-xC-e 를 눌러서 버퍼를 실행시킵니다. 그리고 M-x package-list-packages 를 실행합니다. 


인스톨하고 싶은 패키치에 마우스나 커서를 위치시키고 (여기서는 Rinari) 'I' 키로 인스톨 대상을 확인 시키고 'X' 키로 인스톨을 실행합니다. 

9. html.erb 확장자 를 rhtml 모드로 동작시키기 위해서 .emacs 에 다음과 같은 내용을 채워 줍니다. 



(setq auto-mode-alist
      (cons '("\\.rhtml$" . rhtml-mode)
   auto-mode-alist))
(setq auto-mode-alist
      (cons '("\\.erb$" . rhtml-mode)
   auto-mode-alist))
(setq auto-mode-alist
      (cons '("\\.html\\.erb$" . rhtml-mode)
   auto-mode-alist))

10. ruby-mode 에서 yasnippets 확장을 쓰기 위해서 TAB 키에 바인딩된 함수 기능을 풀어줍니다. .emacs 에서 다음 과 같은 내용을 추가합니다. 


(add-hook 'ruby-mode-hook
          #'(lambda ()
              (define-key ruby-mode-map (kbd "TAB") nil)
              (define-key ruby-mode-map [(control return)]  'ri-ruby-complete-symbol)
              (define-key ruby-mode-map [(shift return)]  'ri-ruby-show-args)
              ))



여기까지 세팅을 하면 기본적으로 잘 동작이 될 것입니다. yasnippets 에 자주 쓰는 기능들을 등록시켜가면서 (추후에 몇개 공개하겠음) Rails 개발을 하면 Emacs 사용자로서 보람도 느끼고 상용 Rails 개발툴이 안 부러울 것입니다. (왜냐하면 우리는 이맥션 이기 때문이지요 캬오!!) 그런데 발생하는 중대한 문제가 있습니다. rhtml-mode 로 yasnippets 로 사용하다 보면 erb block 안에 { } <-- 이게 들어갈 때 문제가 발생하기 시작합니다. unclosed tag 에러가 발생하기 시작하는데 이거 수정이 매우 어렵습니다. 처음에 정규표현식을 바꿔서 수정해 볼까 하다가, 나중에는 포기하고 그냥 rhtml-mode 자체를 수정하기로 결심했습니다. 

rhtml-mode.el 파일을 열어줍니다. 제 경우에는 ~/.emacs.d/rhtml/rhtml-mode.el 에 있습니다. 


(define-derived-mode rhtml-mode
;  html-mode "RHTML"
  html-helper-mode "RHTML"
  "Embedded Ruby Mode (RHTML)"
  (interactive)
  (abbrev-mode)
  ;; disable if you don't want it...
  (rhtml-activate-fontification))

html-mode "RHTML" 을 
html-helper-mode  "RHTML" 로 수정

rhtml-mode 가 html-mode 에서 상속받은 형태의 mode 였는데 이것을 html-helper-mode 에서 상속받게 바꾸어 주기만 하면 됩니다. 에 게다가 바꾸는 김에 조금 더 바꿔줍니다. rhtml-mode 일때 erb-block 을 highlight 시키는데 이게 눈에 상당히 거슬립니다. 

rhtml-fonts.el 파일을 열어줍니다. 제 경우에는 ~/.emacs.d/rhtml/rhtml-fonts.el 에 있습니다. 



(defface erb-face
  '((((class color) (min-colors 88) (background dark))
;     :background "#383838")
    :background "black")
    (((class color) (min-colors 88) (background light))
     ;; :background "azure")
     :background "snow2")
    (((class color) (min-colors 16) (background dark))
     :background "blue3")
    (((class color) (min-colors 16) (background light))
     :background "azure")
    (((class color) (min-colors 8))
     :background "blue")
    (((type tty) (class mono))
     :inverse-video t)
    (t :background "gray"))
  "Default inherited face for ERB tag body"
  :group 'rhtml-faces)

이렇게 수정해 줍니다. 즉 

:background "#383838") 을 
:background "black") 으로 수정

자 이제 마지막으로 erb block 이 시작되는 델리미터까지 깔끔하게 수정해 주기로 합니다. rhtml-fonts.el 파일에서 



;; (defface erb-out-delim-face
;;   `((((background dark)) :foreground "#aaffff" :background "#383838")
;;     (t (:inherit erb-delim-face :weight bold :foreground "darkred")))
;;   "Basic face for Ruby embedded into HTML"
;;   :group 'rhtml-faces)

(defface erb-out-delim-face
  `((((background dark)) :foreground "#aaffff" :background "black")
    (t (:inherit erb-delim-face :weight bold :foreground "darkred")))
  "Basic face for Ruby embedded into HTML"
  :group 'rhtml-faces)


전체를 comment 처리한 것으로 보이지만 :background "#383838" 부분을 "black" 으로 바꿔주기만 한 것입니다. 

조금 길지만 충분히 따라할 만한 설정입니다. 즐겁게 Rails 코딩하세요 ~ 



책에서 나온대로 레일즈 프로젝트 따라하기 중인데 

depot> rake db:migrate 

명령을 치라는 부분을 치니, gem 에 mysql 이 기본으로 포함이 안되어 있다는 메시지가 발생 하더군요. 
시키는 대로 해도 몇몇 에러가 발생하더군요. 이래저래 돌아다니면서 알아보니 

처음에 발생한 에러 메시지 입니다. 

(in /Users/crazia/Documents/workspace/rails/depot)
!!! The bundled mysql.rb driver has been removed from Rails 2.2. Please install the mysql gem and try again: gem install mysql.
rake aborted!
no such file to load -- mysql

그래서 

gem install mysql 

라고 입력했습니다. 

crazia$ gem install mysql
WARNING:  Installing to ~/.gem since /Library/Ruby/Gems/1.8 and
 /usr/bin aren't both writable.
WARNING:  You don't have /Users/crazia/.gem/ruby/1.8/bin in your PATH,
 gem executables will not run.
Building native extensions.  This could take a while...
ERROR:  Error installing mysql:
ERROR: Failed to build gem native extension.

이런 에러가 발생하더군요. 

그래서 ~/.bash_profile 에 

export PATH=$PATH:/opt/local/bin:/opt/local/sbin:/usr/local/mysql/lib:~/.gem/ruby/1.8/bin

추가해줬습니다. 그리고 다시  gem install mysql 을 실행 

 gem install mysql
Password:
Building native extensions.  This could take a while...
ERROR:  Error installing mysql:
ERROR: Failed to build gem native extension.

다시 에러 입니다. 잠깐의 구글링을 통해서 헤더랑 라이브러리를 지정해줘야 하는것 같더군요. 

gem install mysql -- --with-mysql-include=/usr/local/mysql/include/mysql --with-mysql-lib=/usr/local/mysql/lib --with-mysql-config=/usr/local/mysql/bin/mysql_config 

이런식으로 입력하니 다시 에러 찾아보니 스노우레오파드의 아키텍쳐를 명시해줘야 한다고 합니다. 

env ARCHFLAGS="-arch x86_64" gem install mysql -- --with-mysql-include=/usr/local/mysql/include/mysql --with-mysql-lib=/usr/local/mysql/lib --with-mysql-config=/usr/local/mysql/bin/mysql_config 

이렇게 등록해 주면 됩니다. mysql 은 스노우레오파드에 디폴트로 포함되어 있는 버젼입니다. 

그리고 다시  rake db:migrate 

crazia$ rake db:migrate
(in /Users/crazia/Documents/workspace/rails/depot)

성공!! 즐겁게 레일즈 코딩하세요 ~









Rails 개발을 시작하게 된 김에, 스타일을 텍스트 메이트 스타일로 바꿔줬습니다. 레일즈 개발하기에는 Textmate 가 정말 좋다고 하더군요. (텍메 살돈은 없으니 그냥 손에 익은 이맥스로 쿨럭..)



"웹상에서 보이는 모습"




플래시 사진 갤러리를 만들었으면 실제로 웹 사이트에 적용해 보기로 합니다. 제일 먼저 생각해야 할 것은 네트워 크상에 올리는 방안에 관해서 입니다. 시나리오는 다음과 같습니다. 

1. 기존 이미지 파일들이 나열된 XML 파일을 네트워크상에서 읽어온다. 
2. XML 파일을 읽어서 사진이 저장된 사진의 URL을 가져온다. 
3. 기존과 동일하게 플래시에 적용 시킨다. 

더 간단하게 이야기 하자면 'XML 파일을 네트워크상에서 읽어오게 하는 일'입니다. 

기존 FLA 파일에서 ActionScript 부분만 수정해 주면 됩니다. 

var urlXML:String = "http://192.168.10.16:8080/pub/imagelist.xml";
//var hardcodedXML:String="<photos><image title='2or0'>2or0.jpg</image><image title='conan'>conan.jpg</image><image title='Girls_gene'>Girls_gene.jpg</image><image title='Mystery'>mystery.jpg</image></photos>";
var loader:URLLoader = new URLLoader();

urlXML 변수는 XML 파일이 저장된 위치를 지정해주는 변수입니다. 
hardcodedXML 은 외부 파일로 저장하기로 했기 때문에 comment 처리 해줬습니다. 기존의 쓰여진 내용은 urlXML 에 지정된 XML 파일에 저장되어 있습니다. 
외우에 있는 XML 파일을 로딩하기 위해서 loader 를 선언해 줍니다. 


loader.addEventListener(Event.COMPLETE, loadCompleteHandler);
loader.load(new URLRequest(urlXML));

loader 에서 load 가 끝났을 때 실행되는 이벤트 핸들러를 지정해 줍니다. (필수)
urlXML 이 지정하고 있는 XML 파일을 읽어오게 loader.load 로 수행해줍니다. 

// CODE FOR HARDCODED XML =====
// imageList = XML(hardcodedXML);
// fl_parseImageXML(imageList);
// END CODE FOR HARDCODED XML

기존 XML 에서 이미지리스트를 얻어오는 부분은 Comment 처리 해줍니다. 

function loadCompleteHandler (evt:Event) :void {
var hardcodedXML:String = loader.data;

imageList = XML(hardcodedXML);
fl_parseImageXML(imageList);

}

XML 로딩이 끝났을 때 불려지는 이벤트 핸들러 함수 입니다. 로딩이 끝나면 loader.data 에 읽어온 XML 내용이 들어 있습니다. 이것을 기존에 쓰던 hardcodedXML 에 저장하고 기존 이미지리스트 분리하는 함수를 로딩해 줍니다. 

이렇게만 바꿔주고 imagelist.xml 파일과 플래시에서 불러오는 image 들을 적절한 위치에 복사해주면 됩니다. (저는 http://192.168.10.16:8080/pub 밑에 몰아 넣습니다)

Flash CS4 용 소스로 변환해 뒀습니다.  
imagelist.xml 예시 입니다. 

[관련포스트]

Using past sample "Advanced Photo Album" , I'll add dynamic created button on it. If you would press button,
then the transition effect has changed.

1. Let's change the layout of 'stage' , just down the focus of layout for adding buttons.



2. Click Menu item , "Window" - > "Component" and Drag "Button" from "User Interface" to "Library" 


 and Change contents of ActionScript

3. On the "Actions" Layer of First Frame, click right mouse button and select "Actions" menu item. (If
you use 'windows'  press 'F9' key , if you use 'OSX' , press 'option-F9')

4. Setting transition type 'Blinds' when start first.

var transitionType:String = "Blinds"

5. Save Words that used by transition effects to Array, for button label

var labels:Array = new Array( "Blinds", "Fade", "Fly", "Iris", "Photo", "PixelDissolve", "Rotate",
"Squeeze", "Wipe", "Zoom", "Random");

6. for Rembering last selection button 

var oldSelectButton:Button ;

7. Creating Dynamic Buttons 

for(var i=0; i < labels.length ; i++){
    var myButton:Button = new Button();

    myButton.label = labels[i] ; // 
    myButton.width = 80;
    var posY = 10;
    var posX = i;
    
    if (i > 5)
{
        posX = i - 6;
        posY = 40;
}
    myButton.move(20 + posX * (myButton.width + 10), posY);
    myButton.addEventListener(MouseEvent.CLICK , onMyButtonClick);

    addChild(myButton);
if (i == 0) {
myButton.emphasized = true;
oldSelectButton = myButton;
}
 }


Let's verify some details.

myButton.width = 80;

set button width '80' pixels.

   if (i > 5)
   {
      posX = i - 6;
      posY = 40;
   }

if button's count is bigger than '6' , then next button's place is under one row. 

myButton.move(20 + posX * (myButton.width + 10), posY);

setting button's position 

myButton.addEventListener(MouseEvent.CLICK , onMyButtonClick);

register button 'click' event handler.

addChild(myButton);

Actually draw button on the stage.


if (i == 0) {
   myButton.emphasized = true;
   oldSelectButton = myButton;
}

Emphasize the First Button (labeled by 'Blinds') and save it to last selection.

8. Implements Button Click Event Handler.

function onMyButtonClick(evt:MouseEvent):void
{
    oldSelectButton.emphasized = false;
    var selButton:Button = Button(evt.target) ;
    transitionType = selButton.label ;
    selButton.emphasized = true;
    oldSelectButton = selButton;
}


Let's see the output.



I transformed the source for 'Flash CS4'  



+ Recent posts