Bulilder로 한글 xml 만들기

배치 작업을 통해 오라클 db에서 데이타를 가져와서 xml을 만들 일이 생겼습니다. 언제나 그렇지만 AcriveRecord로 데이타를 가져오고 거기에 xml은 Builder로 만들면 편하겠구나 하는 생각에 1시간정도 뚝딱 거려서 만들어냈습니다. 딴짓(미투데이?) 안 하고 집중하니 정말 1시간도 안 걸리더군요. 로컬에서 만들어 나가면서 테스트 할 때에는 한글이 깨져 나오길래 로컬 LANG이 UTF-8이라 깨지겠거니 했습니다만 웬걸 서버에 직접 올리고 돌려봐도 한글은 깨지는 겁니다.

먼저 가장 의심가는 것은 오라클 디비 커넥션의 인코딩 문제였습니다. 구글을 열심히 돌아다녀 보니 오라클의 LANG 환경 변수를 셋팅하라는 조언이 많이 보이네요. 그래서 데이타를 담는 AR 모델에 오라클 환경 변수를 설정해넣었습니다.

ENV[‘NLS_LANG’]=’Korean’

하지만 계속 깨집니다. 분명히 오라클 연결의 문제일거야 라는 생각에 빌더를 빼버리고 파일에 syswrite로 한줄 한줄 써넣어봤습니다. 결과는 안 깨진다입니다.

결국 Builder의 문제로 결론을 짓고 문제를 따라가보기 시작했습니다. xml을 만들때 보통 method_missing을 이용할 것이라는 생각에 grep 으로 Builder 소스를 뒤져봤습니다. method_missing은 lib/builder/xmlbase.rb 에 정의돼 있습니다.

    def method_missing(sym, *args, &block)
      text = nil
      attrs = nil
      sym = "#{sym}:#{args.shift}" if args.first.kind_of?(Symbol)
      args.each do |arg|
        case arg
        when Hash
          attrs ||= {}
          attrs.merge!(arg)
        else
          text ||= ''
          text << arg.to_s
        end
      end
중략

대충 보니 args로 받은 값을 블럭으로 돌면서 해쉬인지 텍스트인지 판단해서 to_s를 이용해서 계속 붙여나가는 듯이 보이네요. 일단 제가 보내는 값이 어디까지 제대로 넘어오는지 확인하기 위해 arg들을 puts로 죽 찍어 보니 안 깨지고 제대로 나오는 겁니다. 그래서 arg의 to_s 메소드를 의심하고 제거해봤습니다. 그랬더니 to_s가 없는 Sting 객체를 제외한 것들이 메소드가 없다고 아우성을 칩니다.

더 아래로 들어가봐야겠습니다. xchar.rb는 Sam Ruby가 만든 xml을 위한 라이브러리입니다. 여기서 볼 수 있습니다. 문제는 String 클래스에 정의한 to_xs 메소드입니다. 문자열을 인코딩에 따라 unpack 하여 캐릭터를 변환하는 메소드 같아 보입니다. 여기서 euc-kr 코드는 rescue에서 처리되는데 제대로 동작하지 xchr이 제대로 동작하지 않습니다. 그래서 그냥 캐릭터를 리턴하도록 n.xchr을 n.chr로 수정했습니다. 이제 잘 나옵니다.

def to_xs
 unpack('U*').map {|n| n.xchr}.join # ASCII, UTF-8
rescue
 unpack('C*').map {|n| n.chr}.join # ISO-8859-1, WIN-1252
end

아무래도 루비 샘이 한글 코드에 잘 알지 못 해 발생하는 문제 같습니다만 아직 제대로 이해하지 못 하니 여러분의 조언 부탁드립니다.

Advertisements

RubyOnRails에서 Oracle 사용하기

개인적으로 RubyOnRails(이하 ROR)를 배우면서 ActiveRecord(이하 AR)에 많은 관심을 가지고 보고 있습니다. 웹개발에서만이 아니라 단독으로 사용 할 때도 상당한 효과를 볼 수 있으리라 생각합니다. 예를 들어 코코아Ruby 기반의 맥 어플리케이션을 만든다고 할 때 사용자 데이터를 로컬의 sqlite3에 저장하고 CRUD 작업을 AR로 한다면 상당한 효과를 볼 수 있겠죠. 실제로 배치 작업을 위해 AR을 조금씩 사용하고 있습니다.

서론은 여기서 그만하고 오늘의 이야기는 AR에서 Oracle 사용하기 입니다. AR은 mysql, sqlite3 같은 오픈소스로 만들어지는 디비에 대한 지원은 잘 되어있습니다. 관련 gem과 라이브러리들을 설치만 하면 되니깐요. 윈도우즈에서는 해당 디비 클라이언트의 라이브러리를 찾아 설치하는 과정이 번거로워서 좀 불편할지도 모르겠네요. (사실 이런 점에서 개발자들에게 최고의 플랫폼은 리눅스라고 생각하지만 많은 맥 사용자들은 어떻게 반응하실지 모르겠군요.)

  1. oracle을 사용하기 위한 네이티브 클라이언트 라이브러리가 필요합니다. oracle instant client이나 oracle database Express을 설치하면 됩니다. 제 경우에는 oracle에서 debian용 리파지토리 저장소를 제공해서 저장소를 통해 express client를 설치했습니다.
  2. 환경 변수에 ORACLE_HOME을 설정합니다. 우분투나 데비안의 경우 다음과 같은 위치가 되겠습니다.
    /usr/lib/oracle/xe/app/oracle/product/10.2.0/client

    다음에 설치해야 할 ruby-oci8의 설치 파일이 ORACLE_HOME 변수를 확인한 후 하위 디렉토리 중 lib을 뒤지는 것 같습니다.

  3. oracle client의 ruby 인터페이스인 ruby-oci8을 설치합니다. 압축파일에 함께 있는 README 파일을 읽어보세요. 일반적인 ruby 라이브러리와 동일합니다.
  4. 마지막으로 AR이 ruby-oci8을 사용하기 위해 oracle 아답타가 필요합니다. AR이 직접적으로 지원하지 않는 상용 디비(db2, oracle, sql-server 등)는 아답타를 통해 구현이 됩니다. 현재 구글에게 물어보면 gem 리파지토리에서 제공된다고 나오지만 gem install 해보면 없다고 나옵니다. 직접 svn 에서 체크아웃해서 rake로 빌드하는 수 밖에 없습니다.
    svn co http://svn.rubyonrails.org/rails/adapters/oracle/
    cd oracle
    rake gem

    rake를 통해 gem을 빌드하면 pkg 디렉토리 안에 gem 파일이 생성됩니다. 저도 gem을 만들어보기는 처음이네요.

이상으로 AR이 oracle을 사용 할 수 있는 환경을 만드는 것이 끝났습니다. 하지만 이 아답타의 소소를 2007년 10월 이후로 커밋이 없는 상태입니다. gem 저장소에 언제 정식으로 올라올지 궁금하네요. 이런 것은 차라리 벤더에서 직접 지원해주면 좋겠는데요. 더 좋은 아답타나 편리한 방법을 알고 계시면 알려주세요.

tddbe로 배우는 ruby – 1

요즘 한창 보고 있는 것 중에 하나가 루비 언어입니다. 책을 사놓고 보기 시작한 것은 꽤 된 것 같습니다만 그동안 별로 진척이 없다가 요즘 들어 시스템을 관리하거나 배포를 위한 스크립트로 사용하기 시작하면서 제대로 보고 있습니다. 넷빈즈6 에서 루비를 제대로 지원하기 시작한 것도 이유 중에 하나이고요.

제가 루비 공부를 시작하기 위해 선택한 첫 책은 programing ruby 였습니다. 아마 다른 많은 분들도 이 책으로 시작하셨을거예요. 그런데 이 책을 보고 있으니 뒤로 갈수록 자세한 설명에 질려서 진도가 잘 나가지 않아 고민하던 중 kent beck의 명저 중에 하나인 tdd by example 을 가지고 루비를 보면 어떨까 하는 생각으로 출발해서 1부를 끝내고 2부인 xunit 까지 왔습니다.

1부인 다중 통화 계산(multi currency money) 문제는 예제가 자바로 진행됩니다. 물론 저는 자바 개발자로 먹고 살기 때문에 이해하는데 문제가 없었지만 루비로 옮기려니 기존 자바 객체와 다른 점으로 인해 더 많은 테스트코드를 만들어보고 책을 많이 뒤져봐야 했습니다.

그래서 기록한다는 의미에서 ttdbe를 보면서 루비의 재미있는 점이나 자바와 다른 점들을 코드와 함께 설명해 볼까 합니다.

서론부터 뭔가 장황했습니다만 보시는 분들께서 더 나은 루비스러운 방법을 알고 계신다면 많이 알려주시면 감사하겠습니다. 굽슨굽슨