Archive for the ‘Development’ Category

MooJoe 0.9.0 릴리즈

Thursday, October 30th, 2008

얼마 전 강규영 님은 JavaScript 객체와 DOM Element를 맵핑시켜주는 JOE공개하셨습니다. JOE는 DOM Element를 모델 스토리지로 사용할 수 있게 해주는 굉장히 유용한 프로젝트입니다.

하지만 아쉽게도 jQuery 기반으로 만들어져 MooTools 1.2를 사용하는 VLAAH나 개인 작업에는 사용할 수 없었죠. 저는 곧 바로 JOE를 MooTools 스타일로 포팅하는 MooJoe 프로젝트를 시작했는데 한참 잊고 있다가 이제서야 공개합니다.


Simple Mapping

다음과 같은 HTML 코드가 주어졌습니다.

<div id="names">
    <p class="name">
        <span class="first">Heungsub</span>
        <span class="last">Lee</span>
    </p>
    <p class="name">
        <span class="first">Alan</span>
        <span class="last">Kang</span>
    </p>
</div>

척 보기에도 서버 측에서 두 개의 Name 객체를 div#names에 출력한 모습입니다. MooJoe는 JOE와 마찬가지로 DOM Element를 JavaScript 객체에 동기화시켜줍니다. 동기화를 하기 위해 먼저 Name 클래스를 정의합니다.

var Name = new MooJoe.Class({
    first: '.first',
    last: '.last'
});

MooJoe의 클래스는 MooJoe.Class 생성자로 만들 수 있습니다. 인자로 맵핑 룰을 지정할 수 있는데 Name 클래스의 경우 first 속성에 .first라는 CSS 셀렉터를, last 속성에 .last라는 CSS 셀렉터를 지정했습니다. CSS 셀렉터를 맵핑룰로 쓰기 때문에 .last가 항상 두 번째 span이라면 다음과 같이 써도 무관합니다.

var Name = new MooJoe.Class({ first: 'span.first', last: 'span:nth-child(2)' });

이제 div#names의 내용을 방금 만든 Name 클래스의 인스턴스로 만들어봅시다.

var names = [
    $$('#names p.name')[0].toObject(Name),
    $$('#names p.name')[1].toObject(Name)
];
// [name_instance#1, name_instance#2]

MooJoe는 MooTools의 Element 클래스를 확장해 Element.prototype.toObject 메서드를 제공합니다. 이 메서드에 맵핑시킬 MooJoe 클래스를 넘기면 맵핑된 객체를 반환합니다. 물론 다른 MooTools의 Element 메서드처럼 Elements.prototype.toObject로 짧게 쓰는 것도 가능합니다. 다음 코드는 방금 전 예제와 동일합니다.

var names = $$('#names p.name').toObject(Name);

맵핑시킨 속성들에 접근해볼까요? getter/setter는 MooTools 1.2의 컨벤션을 따릅니다.

names[0].get('first');
// 'Heungsub'
names[0].get('last');
// 'Lee'

names[0].set('first', 'Haesam');
names[0].get('first');
// 'Haesam'

또한 속성 값을 변경할 경우 맵핑된 Dom Element에도 즉각 반영됩니다.

...
    <p class="name">
        <span class="first">Alan</span>
        <span class="last">Kang</span>
    </p>
...

이 Element는

$$('#names p.name .first')[1].get('html')
// 'Alan'

names[1].set('first', 'Sungryong');

$$('#names p.name .first')[1].get('html')
// 'Sungryong'

이렇게 변합니다.

...
    <p class="name">
        <span class="first">Sungryong</span>
        <span class="last">Kang</span>
    </p>
...

여기까지는 단순히 자식 Element의 내용으로 속성을 맵핑시키는 간단한 사용법이었습니다. 하지만 속성이 항상 자식 Element에 표현되지만은 않겠죠. 가령 이름과 홈페이지 주소를 표현하는 경우를 생각해볼 수 있습니다.

<a class="person" href="http://heungsub.net/">이흥섭</a>

a.person으로부터 namehomepage 속성을 갖는 Person 객체를 만들고싶습니다. 어떻게 해야할까요?

Complex Mapping

MooJoe는 복잡한 맵핑룰을 제공합니다. 위 a.person을 객체로 만들기 위해 먼저 Person 클래스를 정의합니다.

var Person = new MooJoe.Class({
    name: ['', 'text'],
    homepage: ['', 'href']
});

맵핑룰에 CSS 셀렉터 대신 배열이 쓰였습니다. 이 경우 name 속성은 “이 Element의 text 값”에 맵핑시키고 homepage 속성은 “이 Element의 href 값”에 맵핑시킨다는 뜻입니다. 배열의 첫 번째 원소인 빈 문자열이 바로 “이 Element”를 가리킵니다. texthref는 MooTools의 getter/setter로 접근 가능한 키워드로, 각각 innerHTMLhref Attribute를 의미합니다.

var hs = $$('a.person')[0].toObject(Person);
// person_instance#1

hs.get('name');
// '이흥섭'
hs.get('homepage');
// 'http://heungsub.net/'

조금 더 복잡한 Person 예제를 볼까요?

<div class="person">
    <p class="face">
        <img src="http://farm4.static.flickr.com/3122/2894552409_3439382280_s.jpg" />
    </p>
    <p class="name">
        <a href="http://heungsub.net/">
            <span class="first">Heungsub</span>
            <span class="last">Lee</span>
        </a>
    </p>
    <p class="age">18</p>
</div>

이제 Person은 이름과 홈페이지 주소 뿐 아니라 사진, 나이, 게다가 Name 객체까지 표현해야합니다. 다행히 MooJoe으로 맵핑한 각 값을 특정한 타입이나 클래스로 캐스팅해줄 수 있습니다. Person 클래스를 다시 정의해봅시다.

var Person = new MooJoe.Class({
    name: ['.name a', Name],
    homepage: ['.name a', 'href', String],
    face: ['.face img', 'src', String],
    age: ['.age', Number]
});

homepageface의 룰은 3개의 원소로 되어있습니다. 각각 맵핑할 Element, 맵핑할 Attribute, 타입(클래스)을 나타냅니다. 맵핑할 Element인 첫 번째 원소를 제외하고는 순서가 바뀌어도 상관 없으며 기본값으로 각각 'text'String을 갖기 때문에 다음과 같이 써도 동일합니다.

...
    homepage: ['.name a', String, 'href'],
    face: ['.face img', 'src'],
...

name의 캐스팅 클래스는 Simple Mapping 예제에서 정의해뒀던 Name 클래스입니다. 자 그럼 객체로 구워볼까요?

var hs = $$('.person')[0].toObject(Person);

hs.get('name');
// name_instance#3
hs.get('name').get('first');
// 'Heungsub'

hs.get('face');
// 'http://farm4.static.flickr.com/3122/2894552409_3439382280_s.jpg'

hs.get('age');
// 18

name 속성은 Name 객체로, face는 문자열로, age는 숫자로 잘 캐스팅되는군요.

참 쉽죠?
(강규영 님 블로그에서 보고 너무 재미있어서 퍼왔습니다)

Detached Object

MooJoe 클래스를 MooTools 클래스처럼 사용할 수도 있습니다. 임의의 Name 객체를 만들어보겠습니다.

var new_name = new Name('Dachimawa', 'Lee');
new_name.attached;
// []

new_name.get('first');
// 'Dachimawa'
new_name.get('last');
// 'Lee'

생성자에 보낼 인자 순서는 맵핑룰 순서와 동일합니다. first 속성이 첫 번째 룰이었으므로 'Dachimawa'first 값이 됩니다.

attach() 메서드로 연결되어있지 않은 MooJoe 객체는 언제라도 Dom Element에 동기화시킬 수 있습니다.

...
    <p class="name">
        <span class="first">Sungryong</span>
        <span class="last">Kang</span>
    </p>
...

new_name.attach($$('.name')[1]);
new_name.attached;
// [<p.name>]

동기화시키는 순간 Dom Element의 내용도 업데이트됩니다. 원래의 내용이 MooJoe 객체의 내용으로 덮어씌워집니다.

...
    <p class="name">
        <span class="first">Dachimawa</span>
        <span class="last">Lee</span>
    </p>
...

다시 뗄 때는 detach() 메서드를 사용합니다.

new_name.detach();
new_name.attached;
// []

MooJoe 0.9.0은 다음과 같이 체크아웃 받을 수 있습니다.

svn checkout http://moojoe.googlecode.com/svn/tags/0.9.0 MooJoe

개발버전을 받고싶으시면 다음을 사용해주세요.

svn checkout http://moojoe.googlecode.com/svn/trunk MooJoe

버그 리포트 및 기능 제안은 프로젝트 이슈 페이지에서 해주세요.

아직 버그가 있긴 하지만 앞으로 차근차근 발전시켜나가야겠습니다. 특히나 MooJoe 프로젝트는 저의 첫 개인프로젝트이니만큼 애정을 갖고 말이죠. 그럼 0.9.1 버전 릴리즈 소식도 기대해주세요!

Phunctional 0.9.1 릴리즈

Friday, July 18th, 2008

PHP에서의 함수형 프로그래밍을 돕는 프레임워크 Phunctional가 새로 릴리즈되었습니다. 자세한 업데이트 내용은 Phunctional Blog에 기재해두었습니다. 홍민희 선배 수고 많으셨습니다.

VLAAH 디자인 개편

Wednesday, July 9th, 2008

VLAAH Wallpaper

꽤 오랜 시간이 걸렸습니다. 그 동안 열심히 일한 성과를 드디어 여러분께도 보여드릴 수 있게 되었네요. 우리들의 취향 공유 VLAAH가 오늘 새벽에 성공적으로 디자인 개편을 마쳤습니다. 제가 개발과 디자인을 동시에 맡고있어 작업량이 많았던 만큼 이번 개편에 애착이 많이 생깁니다. 이번 개편을 통해 바뀐 점들은 VLOG에 자세히 써두었습니다.

VLAAHLunant(야간개발팀)의 첫 번째 작품으로, 회원들끼리 취향을 공유하는 Social Network Service입니다. 현재 클로즈드베타가 진행 중입니다. 제게 이메일 주소를 보내주시면 초대장을 드리겠습니다.