blog comments 1 del.icio.us bookmarks 1 diggs 0 Google results 0

3.0
PostRank

맥루비(MacRuby) - 루비 코코아의 새로운 도전

From myRuby.net, 5 months ago, 0 views

루비 코코아 프로그래밍의 새로운 장이 열렸다. 바로 맥루비(MacRuby) 덕분이다. 맥루비는 루비 코코아의 개발자이기도 한 Laurent Sansonetti씨가 최근 진행중인 오픈 소스 프로젝트로 맥OS포지에 호스팅되어 있다. 맥루비는 이제 0.1 버전이 발표되고 여전히 개발 중인 프로젝트지만, 현 상태만으로도 꽤 의미있고 재미있는 시도라 느껴져 여기서 소개한다.

 

 

맥루비, 왜 태어났니?

결론부터 이야기하면 맥루비는 루비 코코아가 가진 태생적 단점을 극복하기 위한 프로젝트다.

 

코코아 애플리케이션을 개발하려면 보통 Objective-C를 떠올리게 마련이다. Objective-C가 좋은 언어이기는 하지만, 새로운 언어가 장벽처럼 느껴진다면 자신이 익숙한 언어로도 개발할 수 있다. 그 중 한가지 방법이 루비 코코아다.

 

루비 코코아는 루비에서 코코아를 사용할 수 있게 해주는 라이브러리다. 루비 코코아 라이브러리가 중간에 다리(Bridge) 역할을 하면서 코코아 런타임에 메시지를 전달하고, 또 코코아 측의 메시지를 받아서 처리할 수 있게 해준다.  나도 몇차례 루비 코코아 프로그래밍을 해보았지만, 대부분의 경우에 이런 브리지 만으로도 애플리케이션을 작성하는데 큰 무리는 없다. 하지만, 매번 루비 객체가 Objective-C 객체로 변환되어 주고받아야하는 점은 막연한 부담으로 남곤 했다. 그리고 스몰토크의 영향을 받아 많은 부분 비슷하기는 하지만, 그래도 서로 다른 두 언어가 만나면서 어색한 문법에 적응이 안되기도 했다. 특히나 키 아큐먼트가 없는 루비인지라 URLWithString_relativeToURL 처럼 메서드 이름이 길어지는 경우 코드 가독성이 떨어지는 것은 어쩔 수 없었다.

 

그래서 언어를 가만두고 라이브러리로 접근했던 루비 코코아와는 달리, 코코아 런타임에 최적화해서 루비 자체를 바꿔보자는 시도가 바로 맥루비다. 즉, 맥루비는 맥에 최적화된 맥만을 위한 루비인 셈이다.

 

루비와의 차이점

OS X에 놀러간 루비 이야기 @ OSXDev BootCamp의 발표 자료를 인용해보자.

 

 

맥루비는 루비 1.9 개발 버전(YARV VM이 탑재된)을 수정한 것이다. 아직 한창 개발중인 버전을 가져다 쓴 것은 좀 무리지 않느냐는 지적도 있지만, 맥루비 개발팀이 현명하게 대처하리라 믿어본다.

 

가장 큰 차이점은 역시나 객체 공간이다. 맥루비 VM 위에서는 모든 객체가 Objective-C 객체다. 먼저 아래 코드를 보자.

 

  1. irb(main):032:0> "string".class
    => NSCFString

 

문자열이 String 클래스의 인스턴스가 아니라 NSCFString이라는 Objecive-C 클래스의 인스턴스다. 흥미롭다.

 

  1. irb(main):033:0> "string".class.ancestors
    => [NSCFString, NSMutableString, NSString, Comparable, Object, NSObject, Kernel]

 

상위 클래스를 살펴보니 NSObject와 Object 모두를 상속했다. 즉, Objective-C 객체의 성향과 루비 객체의 성향을 모두 이어받은 것이다. 개발자는 두 특성 중 유리한 쪽을 골라서 개발하면 된다.

 

  1. irb(main):009:0> "string".is_a?(Comparable)
    => true
    irb(main):010:0> "string" < "test"
    => true

 

그래서 유용하게 활용할 수 있는 믹스인도 고스란히 가지고 있다. 이같은 특성은 다른 데이터형에도 모두 적용된다.

 

  1. irb(main):034:0> [].class
    => NSCFArray
    irb(main):035:0> [].class.ancestors
    => [NSCFArray, NSMutableArray, NSArray, Enumerable, Object, NSObject, Kernel]

 

배열과 해시도 마찬가지다.

 

  1. irb(main):036:0> {}.class
    => NSCFDictionary
    irb(main):037:0> {}.class.ancestors

 

그리고 루비의 GC가 아니라 Objetive-C의 GC를 따른다는 사실도 흥미로운 차이점이다.

 

문법의 확장

Objective-C에는 키 파라메터가 있다. 아래와 같은 식이다.

 

  1. [person setValue:anObject forKey:identifier];

 

루비에는 없어서 이런 식의 꼼수를 사용했다.

 

  1. person.setValue_forKey(anObject, identifier)

 

하지만, 맥 루비는 문법을 확장해 Objective-C 코드를 거의 그래도 옮겨적을 수 있게 되었고, 코코아 프레임워크를 사용하는 것도 더 자연스러워졌다.

 

  1. person.setValue anObject forKey: identifier

 

이 점을 본 Matz가 루비 2개발에 참고가 될 것 같다고 말하기도 했다.

 

설치

 

이제 ruby 대신 macruby, irb 대신 macirb를 실행하는 것으로 맥루비를 사용할 수 있다.

 

  1. [deepblue:ruby/svn/MacRuby] deepblue% macruby -v
    MacRuby version 0.2 (ruby 1.9.0 2008-05-17) [universal-darwin9.0]

 

예제

아래 예제를 macirb를 실행해서 따라해봐도 좋겠다. 먼저 코코아 프레임워크를 로드한다.

 

 

  1. framework 'Cocoa'

 

고전적인(?) 예제로 NSSpeechSynthesizer를 이용해 간단한 TTS를 구현해보자.

 

  1. irb(main):027:0> NSSpeechSynthesizer.ancestors
    => [NSSpeechSynthesizer, Object, NSObject, Kernel]

 

NSSpeechSynthesizer는 NSObjecti지만 맥루비에서는 Object도 상속받고 있다.

 

  1. irb(main):028:0> syn = NSSpeechSynthesizer.new.initWithVoice(nil)
    => #<NSSpeechSynthesizer:0x1ef6e10>

 

먼저 초기화한다. 그리고, startSpeakingString을 호출한다.

 

  1. irb(main):029:0> syn.startSpeakingString('Hello MacRuby')
    => true

 

목소리도 바꿔볼 수 있다. NSSpeechSynthesizer.availableVoices의 5번째 목소리로 바꿔보자

 

  1. syn.voice = NSSpeechSynthesizer.availableVoices[5]
  2. syn.startSpeakingString 'Hello Ruby'

 

XCode를 이용한 본격적인 개발

맥루비를 설치한 다음 XCode를 실행하면 아래 그림처럼 맥루비 애플리케이션 템플릿을 볼 수 있다. 

 

 

새로운 프로젝트를 만들고 MainMenu.nib를 열어서 먼저 다이얼로그를 하나 디자인해보자. 아래 그림처럼 만든다.

 

 

그리고 다시 XCode로 돌아서 MyController 클래스(MyController.rb)를 선언한다.

 

  1. class MyController < NSObject
  2. end

 

이 클래스는 text_field와 combo를 아웃렛으로 가지고 있다.

 

  1.     ib_outlet :text_field, :combo

 

그리고 sayIt 액션을 받아서 처리한다.

 

  1.     def sayIt(sender)
            voice = NSSpeechSynthesizer.availableVoices[@combo.indexOfSelectedItem]
            NSSpeechSynthesizer.new.initWithVoice(voice).startSpeakingString(@text_field.stringValue)
        end

        ib_action :sayIt

 

Nib 파일에서 객체가 인스턴스로 만들어질 때 콤보를 초기화해주는 것도 잊지 말자.

 

  1.     def awakeFromNib
            @combo.addItemsWithTitles NSSpeechSynthesizer.availableVoices
        end

 

실제 XCode로 작업하는 과정은 루비 코코아 시절(?)보다 훨씬 매끄럽다. 루비 코드에서 아울렛과 액션을 정해주면 인터페이스 빌더에 바로 반영되기 때문에, 일이 꽤 줄어든다. 어찌보면 당연한 이 일이 루비 코코아에서는 잘 안되서 약간 짜증스럽기도 했다.

 

전체 소스 코드는 여기에 올려둔다.

 

 

맥루비의 미래

WWDC에서 맥 OS X 10.6에 대해 약간의 정보가 나올거라는 소식도 들린다. 10.5에 루비 코코아가 내장되었든, 다음 버전인 10.6에는 맥 루비가 정식으로 포함되면 어떨까? 그렇다면 더 많은 사람들이 루비로 손쉽게 더 생산적으로 맥용 애플리케이션을 개발할 수 있지 않을까? 그런 날이 오기를 고대해본다. 일단은 루비 2.0이 정식으로 나오는 것이 먼저겠지만 말이다.

 

참조

 

comments

No comments yet.

You must be logged in to add your own comment.