BLOG main image
분류 전체보기 (239)
Rails (65)
Ruby (34)
이야기 (40)
스토리큐 (61)
그 밖에.. (30)
C# (6)
드리밍 인 코드
The note of Legendre
작은아이의 생각
agiletalk's me2DAY
[rails] Growl4Rails
美소년 ㅇㅅㅇ씨의 一日
마사키군의 생각
ayukawa's me2DAY
작은아이의 생각
agiletalk's me2DAY
63,407 Visitors up to today!
Today 12 hit, Yesterday 22 hit

 SUBSCRIBE

'ruby'에 해당되는 글 37건
2009/08/20 06:57

will_paginator gem은 페이지네이션을 너무나 간편하게 만들어준다. 데이터를 찾기 위해서는 find대신 paginate 메소드를 사용하기만 하면 되며, view에서는 will_paginate 라는 helper method를 이용해 pagination을 간단히 구현할 수 있다.

  1. # controller
  2. @posts = Post.paginate :page => params[:page]
  3. # view
  4. <%= will_paginate @posts %>

will_paginate 메소드는 똑똑하게 다음과 같은 식의 페이지네이터를 만들어낸다.

image

이 때 1,2,3과 같은 페이지네이터 숫자에 사용되는 URL은 현재 페이지의 URL과 기본형이 같다. 같은 protocol, host, port, controller, action, id를 사용하고 파라미터로 붙는 :page 파라미터만 적절히 변경된다. 즉 이 페이지가 http://app.com/posts 라고 하면 2 페이지의 link는 http://app.com/posts?page=2가 된다. 때때로 이 페이지네이터의 기본 URL을 페이지의 URL과 다르게 사용하고 싶은 경우가 있다. 이 때는 will_paginate method의 :params 옵션을 이용할 수 있다.

예를 들어 현재 페이지의 URL이 http://app.com/community 이고, 페이지네이터에서는 http://app.com/posts?page=2 와 같은 식의 URL을 사용하고 싶은 경우,

  1. will_paginate @posts, :params => {:controller=>”posts”}

이런 식으로 할 수 있다.

만약 posts를 routes.rb에 resouces로 정의해 놓았다면(RESTful), 그래서 :controller와 :action 에 어떤 것을 써야할지 잘 모르겠다면, hash_for_XXX_url 메소드를 이용할 수 있다.

  1. will_paginate @posts, :params => hash_for_posts_path

이번엔 host 와 port도 바꾸어야 할 필요가 있다면, 다음과 같이 :host 파라미터를 이용한다.

  1. will_paginate @posts, :params => hash_for_posts_path.merge(:host => "aaa", :only_path=>false)

only_path를 false로 해야만 host를 포함한 URL이 사용된다.

will_paginate의 소스를 따라가다 보면 :params 의 내용이 그대로 ActionView::Helpers::UrlHelper#url_for 로 넘어가고 있음을 알 수 있다.

2009/06/16 21:43

Octocat작년 github가 발표된 후부터 github는 ruby 개발자들에게 큰 인기를 얻고 있다. rails를 비롯한 많은 gem들이 repository를 github로 옮겼다. 이 글에서는 windows환경에서 github를 통해 gem을 배포하는 과정에 대해 알아본다.

msysgit 설치하기

윈도우즈에서 git을 사용하기 위해서는 msysgit이 필요하다. msysgit에서 Git-xxx 를 다운받아 설치한다.

설치 도중 물어 보는 것들 중 신경 써야 하는 것들 몇 가지는,

  • Add "Git Bash Here" 를 체크한다. 이는 탐색기에서 마우스 오른쪽 버튼으로 보여지는 메뉴에 Git Bash Here 를 추가한다.
  • Use Git Bash only 선택한다. PATH를 건드리지 않기 때문에 충돌의 염려가 없다. 그 대신 git을 이용하기 위해서는 Git Bash Here를 이용해야 한다.
  • 그리고, Use OpenSSH를 선택한다.
기본 설정

적당한 디렉토리(예를들면 C:\gitroot)를 선택해서 git bash 를 연다. 그리고 이름과 이메일을 설정한다.

  1. $ git config --global user.name "Your Name Comes Here"
    $ git config --global user.email you@yourdomain.example.com
SSH Key를 생성하기

github는 rsa를 이용해서 사용자를 인증한다. 공개키를 github에 등록해 놓고 개인키로 인증을 수행을 한다. 따라서 github를 사용하기 위해서는 rsa 키가 필요하다. 이 rsa 키를 만드는 과정은 다음과 같다.

환경 변수에 $HOME을 설정해 준다.
git bash를 연다. 그리고 다음 명령을 입력해 rsa key를 생성한다.

  1. ssh-keygen -C "username@email.com" -t rsa

Enter file in which to save the key 에는 생성된 rsa key가 저장될 파일 이름을 적어준다. 그냥 엔터를 치면 $HOME/.ssh/id_rsa 이다.

Enter passphrase 에는 사용할 암호 문구를 적는다. 보안에 대한 걱정이 없다면 안 적어도 된다. 적지 말자.

생성이 잘 완료되었다면 #HOME/.ssh 디렉토리에 키가 들어있음을 확인할 수 있다. 여기에 id_rsa.pub 라는 파일이 있는데, 이것이 공개키다. github 프로젝트에 넣어야 하니 기억하자.

더 자세한 설명은 providing your SSH keys 참조.

github에 프로젝트 만들기

github에 로그인을 하고, 프로젝트 만들자. 그리고 프로젝트의 edit을 눌러서 rubygem에 체크를 해 두자.

edit 페이지에는 또한 Deploy Keys라는 것도 보인다. 여기에 생성한 공개키(id_rsa.pub)의 내용을 복사해서 넣고, update를 누른다. 키는 여러 개를 등록할 수 있다.

프로젝트 생성해서 github에 밀어넣기

우선 개인키를 등록하는 과정이 필요하다. 이 개인키로 인증을 거쳐야 github에 push를 할 수 있다. git bash를 열고 다음 명령을 실행하자.

  1. exec ssh-agent bash
  2. ssh-add /PATH/TO/id_rsa (생성한 개인키)

매번 ssh-agent를 실행하는 것이 번거롭다면 C:\Program Files\Git\etc\profile 에 exec ssh-agent bash 를 추가해도 된다.

생성한 프로젝트에 들어가보면 친절하게도 로컬에서 프로젝트를 생성해서 git에 첫번째 push를 할때까지 일련의 명령들이 나와 있다. 이를 참조해서 github에 만든 gem을 밀어넣어 보자.

  1. cd gem_directory
  2. git init
  3. git add *
  4. git commit –m “initial commit”                 
  5. git remote add origin git@github.com:xxx # 원격지 repository인 github를 origin으로 등록
  6. git push origin master                             # origin에 변경내용 밀어넣기

제대로 되었다면 github 프로젝트에 밀어 넣은 파일들을 볼 수 있다.

git 에 대해 조금 더 알고 싶다면 git 명령어 혹은 git tutorial 혹은 Git User's Manual 이 도움이 될 것이다.

rubygem 을 github를 통해서 배포하기

github 프로젝트의 rubygem이 체크되어 있어야 한다. 그 외에는 해줄 것이 없다. 이 체크만 되어 있다면 github는 gemspec 의 내용을 참조해서 gem을 만든다. gemspec의 version이 변경되면 github는 gem을 다시 만든다. 이 경우 version이 변경됬음을 github가 감지하는 시간이 꽤 걸리는 듯 하다. 대략 한두 시간 정도.

충분히 기다린 후 gem을 찾아 보면 등록한 gem이 보인다.

  1. gem search gem_name -r
프로젝트를 Github에서 다운받기

clone을 이용한다.

  1. git clone GIT_CLONE_URL

GIT_CLONE_URL은 public url이 아닌 your clone url 로 하자. 그래야 push가 된다.

참조

github rubygems

2009/06/16 21:40

Gem은 ruby의 가장 멋진 기능 중 하나이다. 구현하고자 하는 기능이 있다면 우선 gem에 있는지 확인해 보라. 많은 것들이 누군가에 의해 이미 구현되어 있을 것이다. 원하는 것을 찾지 못한다 할지라도 이런 저런 gem들을 둘러보다 보면 좋은 생각을 얻을 수 있을 것이다. 그러다가 자신만의 생각을 구현했으면 gem으로 배포해서 다른 사람들과 공유할 수 있다. 이 글에서는 gem을 만드는 과정에 대해서 설명한다.

jeweler

jeweler는 gem 만들기를 도와주는 rubygem이다. jeweler를 이용하면 gem 의 골격을 손쉽게 만들 수 있으며, github 혹은 rubyforge로 배포도 쉽게 할 수 있다.

  1. gem install jeweler

jewler를 사용하기 전에 github config 설정을 해 주어야 한다.

  1. git config --global github.user username
  2. git config --global github.token token
새로운 gem 을 만들어 보자.
  1. jeweler GEM_NAME

git에 add할 수 없다고, 에러가 발생하는데, 왜 그런지 모르겠다.

그러면 다음과 같은 식의 gem의 파일 구조가 생긴다.(똑같지는 않다.)

  • lib : gem의 소스코드 디렉토리
  • test 혹은 spec : 테스트 코드가 있는 디렉토리
  • bin : 실행 파일이 있는 디렉토리
  • README.rdoc : gem 설명, 사용방법
  • LICENCE : 라이센스
  • Rakefile
  • .gitignore : commit할 때 무시할 파일들
  • VERSION : gem의 버전(major.minor.patch), rake task를 이용해서 관리할 수 있다.
  • gem_name.gemspec :  gem을 만들기 위한 설정 파일. rake gemspec을 통해서 만들 수 있다.
VERSION 및 gemspec 생성
  1. rake version:write
  2. rake gemspec

rake version:write 는 version을 0.0.0으로 초기화시킨다.
version을 하나 올리고 싶으면 다음과 같은 식으로 할 수 있다.

  1. rake version:bump:minor
  2. rake gemspec

version을 올린 후에는 rake gemspec을 실행해서 gemspec을 다시 만들어 주자.

gemspec 파일을 직접 수정할 일이 없다. 그 대신 gemspec에 추가하고 싶은 것들은 Rakefile에 추가를 한다. 그리고 gemspec의 변경사항이 생기면 rake gemspec을 실행하면 된다. gemspec 에 포함되는 것들 몇 가지를 살펴보면,

gem.files : gem에 포함되는 파일들

  1. gem.files.include FileList.new('lib/**/*.rb', "bin/*",
          "LICENCE", "VERSION", "README.rdoc", "Rakefile")

gem.add_dependency : 이 gem이 의존하고 있는 gem들

gem.executables : 실행파일

  1. gem.executables = ["filename"]

filenam은 bin 디렉토리에 위치한다. 이 곳에 적어준 파일은 gem을 설치할 때 ruby\bin 에 옮겨져서 실행할 수 있게 된다.

Gemspec에 대한  자세한 내용은 Gemspec Reference를 참조.

gem 빌드 및 설치

gem의 빌드는 build task를 이용할 수 있다.

  1. rake build

혹은 직접 gem 명령을 이용해도 된다.

  1. gem build gem_name.gemspec

빌드가 잘 되면 gem_name-version.gem 파일이 생성된다. zip 압축 파일이다.

gem의 설치는 다음과 같이 할 수 있다.

  1. gem install gem_name-version.gem

rake install 명령은 sudo를 사용하기 때문에 windows에서 에러를 발생시킨다.

gem의 배포

jeweler의 git관련 명령어들은 에러를 발생시킨다. 그래서 rake release라는 편리해 보이는 task가 있기는 하지만, 사용할 수가 없다.

그래서 그냥 git 명령어들을 입력해서 배포를 한다.

  1. git add *
    git commit –m “initial commit”                 
    git remote add origin git@github.com:xxx         # 원격지 repository인 github를 origin으로 등록(한번만 하면 된다)
    git push origin master                                     # origin에 변경내용 밀어넣기

windows에서 github를 사용하는 방법에 대해서는 github를 통해 gem 배포하기 를 참조.

코드의 수정이 생겨서 version을 하나 올리고 싶으면 다음과 같은 일을 하게 된다.

  1. rake version:bump:patch  # VERSION을 증가
  2. rake gemspec                 # gemspec을 다시 만든다.
  3. rake build                       # 빌드를 한다. test도 필요.
  4. git add .                        # git에 추가
  5. git commit -m 'rake'        # git에 commit
  6. git push origin master      # github에 밀어 넣는다.
2009/06/16 15:16

파란 같이 무료 문자를 제공하는 사이트가 여럿 있습니다. 컴퓨터로 문자를 보낼 수 있기 때문에 손쉽게 문자를 보낼 수 있는 꽤 유용한 서비스입니다. 다만 문자를 보내기 위해 사이트에 접속해야 하는 것이 번거롭다는 단점이 있지만요. 이런 단점을 보완하기 위해서 문자보내기 프로그램을 만드신 분도 있습니다. 꽤나 잘 만드셨어요. 이것을 사용하다가 ruby로도 한번 만들어보고 싶다는 생각이 들었습니다.

sms_client gem은 무료문자를 제공하는 사이트를 통해 무료문자를 보낼 수 있도록 해줍니다.

설치

  1. gem install aproxacs-sms_client

문자 보내기

설치를 마친 후에는 send_text 명령을 사용할 수 있습니다. 그래서 명령 프롬프트에서 다음과 같이 사용할 수 있습니다.

  1. send_text <text> <to> <from> <client> <id> <password>

text는 보내려고 하는 문자입니다. to는 문자를 보내려고 하는 전화번호, from은 보내는 사람의 전화번호 입니다. client는 사용하고자 하는 사이트의 이름입니다. 현재는 paran, joyzen, lgt, xpeed 이렇게 네 가지를 선택할 수 있습니다. id와 password는 사이트에 로그인하기 위해 사용하는 id와 password입니다.

ruby code를 이용하는 방법은 다음과 같습니다.

  1. require ‘sms_client’
  2. SMS::Client.new("xpeed") do |cli|
  3.   cli.login("ID", "PASSWORD")
  4.   cli.from = "01012344567"
  5.   cli.deliver("0107564321", "Hello~ SMS")
  6. end

더 자세한 내용은 github의 sms_client gem 페이지를 참조하세요.

2009/06/16 10:56

Mechanize gem은 웹사이트로 요청을 보내고, 받은 페이지의 링크를 따라가고, 폼을 제출하는 동작을 간편하게 준다. Mechanize는 Cookie를 저장하고, redirect를 따라가며, 방문한 사이트 목록(history)을 가지고 있다. 웹사이트와 상호작용하는 클라이언트를 만들고 싶은 경우 mechanize는 좋은 선택이 될 것이다.

간단한 사용법은 다음과 같다.

  1. require 'rubygems'
  2. require 'mechanize'
  3. WWW::Mechanize.new do |agent|
      agent.user_agent_alias = 'Windows IE 7'
      page = agent.get("http://www.google.com")
      page = page.form_with(:name => 'f') do |form|
        form.q = "cat"
      end.submit
      page.search("a.l").each do |ele|
        p ele.content
      end
    end

Mechanize의 GuildeExampe 페이지를 읽어 보면 더 좋은 이해를 할 수 있다.

조금 더 자세히 알아보자.

페이지 가져오기
  1. page = agent.get(“http://www.site.com”)

혹은 header와 referer 같은 것들을 설정하고 싶다면,

  1. page = agent.get({:url => url, :params => params, :referer => referer, :headers => headers})

가져온 페이지의 content_type이 html일 경우에 page는 WWW::Mechanize::Page 객체이다. 이 Page 객체는 기본으로 nokogiri parser를 사용한다. 그래서 다음과 같이 css로 element를 선택할 수 있다.

  1. page.search(“#element_id”)

다른 parser를 사용하고 싶다면

  1. WWW::Mechanize.html_parser = Hpricot
form 제출하기

페이지의 모든 form은 다음과 같이 확인할 수 있다.

  1. page.forms

form의 제출은 다음과 같다.

  1. page.form_with(:name => “login”) do |form|
  2.   form.action = “http://www.site.com/login”
  3.   form.login = “id”
  4.   form.passwd = “pass”
  5. end.submit
link, frame 따라가기

page의 link 목록은 다음과 같이 따라갈 수 있다.

  1. page.link_with(:text => “follow”).click

iframe이 사용되고 있는 경우 다음과 같이 iframe을 열 수 있다.

  1. page = page.iframes.first.click
파일의 저장

이미지 파일을 저장하고 싶으면

  1. file = agent.get("http://www.site.com/image/1.JPG")
    page.save_as("image.jpg")

마지막으로 구글에서 이미지 검색을 한 후 이미지들을 저장하는 코드는 다음과 같다.

  1. WWW::Mechanize.new do |agent|
      agent.user_agent_alias = 'Windows IE 7'
      page = agent.get("http://images.google.co.kr/imghp")
      page = page.form_with('f') do |form|
        form.q = 'cat'
      end.submit
      page.links.each do |l|
        next unless l.href =~ /imgurl=(.+?&)/
        url = $1.chop
        agent.get(url).save_as(File.basename(url))
      end
    end

'Ruby' 카테고리의 다른 글

[Ruby] Gem 만들기  (0) 2009/06/16
[ruby] sms_client gem  (0) 2009/06/16
[Ruby] mechanize gem을 이용해 웹사이트와 통신하기  (0) 2009/06/16
[ruby] RDOC 을 위한 주석 달기  (0) 2009/02/23
[Ruby] block expressions, 그리고 code block  (0) 2008/08/12
[Ruby] or 와 || 의 차이  (0) 2008/08/12
2009/06/11 21:56

authlogic은 restful_authentication처럼 rails에서 사용자의 인증을 처리해주는 gem이다. restful_authentication보다 더 깔끔하다는 평을 받고 있다.

authlogic의 내부에서는 I18n을 고려하고 있기 때문에 locale data(yml 파일)만 잘 설정해 주면 손쉽게 한글화를 시킬 수 있다. I18n에 대해서는 [Rails] I18n을 이용하기 를 참조.
다음과 같은 번역을 ko.yml 파일에 추가하자.

  1.   authlogic:
        error_messages:
          login_blank: "은 비워두면 안됩니다"
          login_not_found: "을 찾을 수 없습니다"
          login_invalid: "은 영어 문자와 숫자, 그리고 .-_@ 만 사용할 수 있습니다"
          consecutive_failed_logins_limit_exceeded: "연속되는 로그인 실패로 인해 계정이 사용중지 되었습니다"
          email_invalid: "은 올바르지 않은 이메일 형식입니다"
          password_blank: "은 비워두면 안됩니다"
          password_invalid: "은 올바른 형식이 아닙니다"
          not_active: "계정이 사용중지되어 사용할 수 없습니다"
          not_confirmed: "계정이 아직 활성화되지 않았습니다"
          not_approved: "계정이 아직 승인되지 않았습니다"
          no_authentication_details: "로그인 정보를 입력하지 않았습니다"
        models:
          user_session: "사용자 세션"
        attributes:
          user_session:
            login: "로그인 ID"
            email: "이메일"
            password: "비밀번호"
            remember_me: "아이디 기억하기"

끝.

2009/06/11 21:46

Rails 2.3을 보면 config 밑에 locales라는 디렉토리가 보인다. 이것이 무엇일까?
Rails 2.2 부터 Internationalization(I18n) 이 activesupport에 포함되었다. I18n을 이용하면 비교적 쉽게 한글/영문을 동시에 지원하는 서비스를 만들 수 있다.

목표

rails 2.3을 이용해서 한글과 영문을 동시에 지원하는 서비스 만들기.
한글 페이지의 url은 http://site.com/ko/users 와 같은 식이고 영문 페이지는 http://site.com/en/users와 같은 식이다.

구현

우선 environment.rb를 열어서 기본으로 사용하는 언어에 대해 설정을 해 주자.

  1. config.i18n.default_locale = :ko
  2. config.i18n.load_path += Dir[Rails.root.join('config', 'locales', 'ko', '*.yml')]
  3. config.i18n.load_path += Dir[Rails.root.join('config', 'locales', 'en', '*.yml')]

기본으로 사용하는 언어는 한국어다. 그리고 한국어에 대한 파일은 config/locales/ko 디렉토리에 yml 형식으로 들어 있다.

rails에서 사용하는 기본적인 것들, 즉 시간 같은 것들에 대한 번역은 Locale data for Ruby on Rails I18n 에서 찾아볼 수 있다. 여기서 ko.yml 파일을 복사해서 config/locales/ko 디렉토리에 추가하자. en.yml 파일은 없는데, rails에 영문에 대한 것은 디폴트로 포함되어 있다.

authlogic 같은 인증 관련 gem을 통해서 user model을 만들고, ko 및 en 디렉토리에 user.yml 파일을 생성한다. 파일을 생성한 후에는 서버를 재시작해 주어야 한다. 그러나 파일이 수정될 때마다 재시작 해줄 필요는 없다. 개발환경에서는 재시작하지 않아도 파일 내용의 수정이 반영 된다.

activerecord

user.yml 파일에 activerecord에서 참조할 내용들을 적어주자.

  1. ko:
      activerecord:
        models:
          user: "사용자"
        attributes:
          user:
            login: "로그인 ID" 
            email: "이메일"

이렇게 함으로써 activerecord에서 발생하는 validation error가 한글로 번역되어서 보인다. 조사에 약간 문제가 있지만..

clip_image001

  view 와 controller

view와 controller에서는 다음과 같이 t를 이용해서 i18n을 사용할 수 있다. model에서는 I18n.t 을 이용한다.

  1. flash[:notice] = "Login successful!"

대신

  1. flash[:notice] = t "login.success"

라고 해주면 된다.

그리고 user.yml에 다음과 같이 적어준다.

  1. ko:
  2.   login:
  3.     :success: "로그인 성공"
시간 포맷

시간 포맷은 다음과 같이 l 을 이용해서 현지화를 시킬 수 있다.

  1. l Time.now, :format => :short

ko.yml 에 선언된 형식에 의해 시간포맷이 출력된다.

  1. time:
      formats:
        default: "%Y/%m/%d %H:%M:%S"
        short: "%y/%m/%d %H:%M"
I18n.translate

I18.translate(I18.t) 메소드에 대해서 좀 더 자세히 알아보자.

yml 파일이 다음과 같을 때, 

  1. hello: “안녕하세요”
  2. hi: “안녕”
  3. user:
  4.   name: “이름”
  5.   hello: “{{name}}님 안녕하세요”
  6.   total:
  7.     zero: "no one"
  8.     one: "1 person"
  9.     other: "{{size}} people"

배열울 파라미터로 주면 배열의 항목을 번역해 준다.

  1. I18n.t [:hello, :hi]
  2. => [“안녕하세요”, “안녕”]

depth가 있는 경우 다 써줘도 되고, scope을 이용해도 된다.

  1. I18n.t "user.name"
  2. I18n.t :name, :scope => [:user]

interpolation이 가능하다.

  1. I18n.t "user.hello", :name => user.name

count을 주면 영리하게 복수화를 시킨다.

  1. I18n.t "user.total", :count => User.size, :size=>User.size

요청 URL에 locale 정보 포함시키기

http://site.com/en/users 와 같은 식으로 locale정보가 url에 포함되도록 하자. 그리고 이 locale 정보에 맞도록 rails가 응답하도록 하자.

우선 route.rb에 path_prefix를 이용해서 locale의 패턴을 지정해 준다.

  1. map.resources :users, :path_prefix => '/:locale'

root에 대해서도 locale을 지정할 수 있도록 해 준다. 지정하지 않으면 ko를 사용한다.

  1. map.locale_root '/:locale', :controller => "records"
  2. map.root :controller => "records", :locale=>"ko"

그리고 application_controller.rb에 before_filter를 하나 만들어 준다.

  1. before_filter :set_locale
    private
      def set_locale
        I18n.locale = params[:locale] if params[:locale]
      end

마법처럼 간단하다.

참고 페이지

rails cast : http://railscasts.com/episodes/138-i18n

아주 잘 되어있는 문서화 : http://guides.rubyonrails.org/i18n.html

2008/08/12 01:43

bs는 궁금하다.

begin/end 와 do/end는 무었이 다른가?

=> begin/end는 block expression이고, do/end는 code block이다.

 

blcok expressions

  • begin 과 end 사이에 포함된 표현식들(expressions). 
  • block expressions의 결과값은 마지막 expression의 수행 결과이다.
  • 예외 처리에서 많이 볼 수 있다.
  1. begin
  2.   expressions
  3. rescue
  4. handles exception
  5. end
  • 메쏘드를 정의할 때는 begin을 생략할 수 있는데, 그것은 def 에 begin이 포함되어 있기 때문이다.
  1. def method
  2. expressions

  3. rescue
  4. handles exception

  5. end
  • 코드가 바로 수행된다.

 

code block

  • do와 end 사이에 있는 루비 표현식들
  • || 안에 argument들을 가질 수 있다.
  • 단독으로 사용될 수 없으며, 메쏘드 호출(method invocation) 바로 뒤에 나와야만 한다.
  1. invocation do |arg|
  2. end
  • 메쏘드 안에서 yield 를 이용해서 code block을 수행할 수 있다.
  • code block이 주어진 경우 메쏘드의 마지막 파라미터로 code block을 얻어올 수 있다. 또한 Proc#call을 이용해서 블록을 수행할 수 있다.
  1. def invocation *args, &block
  2. block.call

  3. yield

  4. end
  • closuer 로 동작한다.(블록이 정의된 부분의 환경(예를 들면 메쏘드 안의 변수)을 기억한다.)
  • 코드의 수행이 지연된다. yield 혹은 Proc#call 이 불려지는 시점에서 코드가 수행된다.

 

Proc

  • code block은 Proc.new 나 Kernel#proc을 이용해서 Proc 클래스의 객체로 변환된다. 위에서 메쏘드의 마지막 파라미터로 전해지는 것도 Proc 객체이다.
  • Proc 객체의 code block은 Proc#call을 이용해 실행할 수 있다.

 

 

이 글은 스프링노트에서 작성되었습니다.

2008/08/12 01:39

bs 는 궁금하다.

다음 코드가 에러를 발생하는 이유는?

  1. def method
  2. false || return 0

  3. end
  4. SyntaxError: compile error
    (irb):2: syntax error, unexpected tINTEGER, expecting kEND
            from (irb):3

 

연산자 우선순위 때문인 것으로 생각된다.

and, or 와 &&, || 는 연산자 우선순위만 빼고 모든 것이 동일하다.

 

위 코드는 ruby에서 다음과 같이 해석하는 것으로 생각된다.

  1. def method
  2. (false || return) 0

  3. end

왜 그럴까?

 

위 코드에 에러를 발생하지 않도록 하기 위해서는

  1. def method
  2. false || (return 0)

  3. end

혹은

  1. def method
  2. false or return 0

  3. end

와 같이 할 수 있다.

 

추가로 and, or와 &&, || 의 연산자 우선순위 사이에는 assignment 가 있다. 그래서 다음과 같은 코드도 원치 않는 결과를 보여줄 것이다. 이 글을 참조.

  1. total = shopping_cart.empty? and shopping_cart.total

 

이 글은 스프링노트에서 작성되었습니다.

2008/08/06 02:14

wxRubywxWidget을 ruby로 포팅한 ruby용 GUI 라이브러리다. 

 

wxRuby를 gem을 통해 설치한다.

  1. gem install wxruby

 

XRC(XML Resource) 를 생성하기

XRC 는 무엇인가?

XRC 는 wxWidget에 의해 사용되는 크로스 플랫폼 XML기반의 User Interface Markup Language 이다. 다시 말해 애플리케이션의 UI(User Interface) 정보를 가지고 있는 XML 이다. UI 정보가 모두 XML을 통해 표현되고 저장되어 있기에 애플리케이션을 구현하는 언어나 애플리케이션이 구동되는 플랫폼에 영향을 받지 않는다. ruby 같이 다이나믹 언어를 사용하는 애플리케이션은 실행하면서 XRC 를 읽어들여서 UI 를 생성할 수 있고, C++같이 컴파일이 필요한 언어는 XRC를 컴파일할 때 불러들여 UI 코드를 생성할 수 있다.

 

XRC 생성하기

UI 디자인을 간편하게 수행하고 그로부터 XRC를 생성해 주는 많은 디자인 툴들이 있다. 그 중 무료 툴인 wxFormBuilder를 사용해 보자.

 

간단한 목표를 가지고 시작하자.

여기서는 개인 PC에서 스토리큐에 파일을 업로드하는 애플리케이션 storyq_uploader을 만들 것이다.

 

wxFormBuilder에서 project생성

storyq_uploader라는 디렉토리를 하나 만들어서 애플리케이션의 기본 디렉토리로 삼자.

wxFormBuilder를 실행시키고, 프로젝트를 생성하자. 그러면 오른쪽에 Object Properties라는 창이 보이는데 프로젝트 이름을 sq_uploader 라고 하자. path와 file은 프로젝트의 결과(XRC) 가 생설될 디렉토리와 파일이름이다. path를 storyq_uploader 디렉토리로, 그리고 file을 uploader_frame이라고 해 주자. code_generation은 Generate Code 명령을 수행했을 때 어떤 결과가 생길지를 지정하는 것이다. XRC로 하자.  relative_path는 디자인 내부에서 사용하는 이미지 같은 외부 파일들에 대한 경로를 상대적으로 할 것인지를 말한다. 체크를 해 두자.

01_new.jpg

 

기본 frame 만들기

이제 업로드를 위한 간단한 frame을 만들자. UI 프로그램을 해본 개발자는 편안함을 느낄지도 모르겠다. 나는 경험이 별로 없는지라 약간 불편하다.

Component Palette 창에 Forms라는 탭을 누르면 아래에 Frame, Panel, Dialog 아이콘이 보인다. Frame을 눌러 기본 윈도우 프래임을 하나 만들자. 그리고 Object Properties에서 tiltle, name을 적당히 써 주고, 맨 밑에 subclass에 UploaderFrameBase 라고 써주자. 나중에 ruby code에서 이 클래스를 상속 받아서 이벤트 같은 것을 처리할 것이다.

02.jpg

 

layout 생성

그 다음은 frame안에 layout을 넣어주자. 레이아웃은 위젯들의 배치에 대한 것이다. 예를 들어, wxBoxSizer 레이아웃은 가로 방향 혹은 세로 방향으로 위젯들이 줄지어 들어가게 된다. uploader는 이것으로 충분할 것 같다.

xwBoxSizer를 uploader_frame 안에 하나 만든다. 세로방향(Vertical)의 BoxSizer가 생긴다. Sizer 밑에 다시 wxBoxSizer를 만든다. 이번에는 Object Properties에서 orient를 Horizontal로 변경시켜 가로 방향으로 위젯이 들어가게 하자. 이 layout 에 file 선택하는 버튼을 넣을 것이다.

 

참고로 최상단의 메뉴바를 보면 정렬 아이콘과 Expand, Strech 아이콘이 있는데, 이것들을 적당히 이용해서 위젯들의 배치를 원하는 형태로 할 수 있다. Expand는 위젯을 좌우로 꽉 차게 만들어 주고, Strech는 상하로 꽉차게 만들어 준다. 난 layout에 대한 개념들이 꽤 혼동스러웠는데, 사실 처음 기대는 마우스 드래그 드롭으로 위젯들을 위치시키는 것이었다.

03.jpg

 

위젯들을 이용해 모양 꾸미기

Additional을 보면 File Picker가 있는데, wxRuby API 에는 wxFilePickerCtrl이 없다. 아마 Additional에 있는 위젯들은 사용할 수 없나보다. 그냥 Common 탭의 TextCtrl과 Button을 사용해서 파일을 선택하는 UI를 만들자.

TextCtrl 위젯을 만들어 넣고, file_text라고 이름을 적어주자.

Button 위젯을 만들어 넣고, label을 Browse, 이름을 browse_btn라고 해 주자.

다시 Button 위젯을 하나 넣고, label을 Upload, 이름을 upload_btn이라고 해 주자. 참고로 button style의 wxBU_EXACTFIT를 선택하면 label의 크기에 맞게 버튼의 크기가 변경된다.

04.jpg

 

이제 하단에는 업로드 목록을 보여주는 list를 만들자. wxBoxSizer를 하나 더 추가해서 ListCtrl을 추가한다. ListCtrl의 Expand와 Strech를 모두 눌러서 layout에 리스트 위젯이 꽉 차도록 한다. 리스트 위젯의 이름을 item_list로 하고 subclass를 ItemListCtrl로 하자.

05.jpg

 

애플리케이션의 디자인을 대강 마쳤으니 이 디자인을 XRC 파일로 저장하자. 그것은 File > Generate를 이용하거나 단축키 F8을 눌러도 된다. storyq_uploader/uploader_frame.xrc가 생성된다.

 

XRC 로 ruby code 생성하기

wx_suger는 wxWiget를 좀더 Ruby 스럽게 사용할 수 있게 해 준다고 한다. 여기에서는 XRCise를 사용하기 위해 wx_sugar를 설치한다.

  1. gem install wx_sugar

 

XRCise 는 XRC를 Ruby code로 손쉽게 변경시켜 준다. uploader_frame.xrc가 있는 디렉토리로 이동해서 다음 명령을 수행한다.

  1. xrcise -o uploader_frame.rb uploader_frame.xrc

위 명령은 uploader_frame.rb라는 ruby 파일을 생성시킨다. 파일을 열어보면 내가 만든 wxRuby 위젯 클래스들이 선언되어 있다. 좋구나~~

 

Evnet 엮어주기

main.rb 파일을 storyq_uploader 폴더에 생성해서 다음과 같이 만들자.

  1. require "rubygems"
  2. require "storyq_client"
    require "wx"
    require "uploader_frame"
    require "iconv"
      
    module ItemListCtrl
      def add_box(box)
        item = Wx::ListItem.new
        item.set_data(box)
        item.set_text(box.title || "")
        insert_item(item)
      end
    end

    class UploaderFrame < UploaderFrameBase
      attr_accessor :storyq
     
      def initialize
        super
        @storyq = StoryQ(:consumer_token => "un2BidBxRoNQEGsyRFCHcA",
          :consumer_secret => "To6CrYQTMYtxBeQJGn3W9CIBoWAdasoxmpe09w5xE",
          :site => "http://www.storyq.com")   
        evt_button(browse_btn) { |event| choose_file(event) }
        evt_button(upload_btn) { |event| upload_file(event) }
      end
     
      def show_upload_dialog
        @upload_dialog = UploadFormDialog.new(self)
        @upload_dialog.show_modal
        @upload_dialog.destroy
        show_my_boxes
      end
     
      def choose_file(event)
        file_dialog = Wx::FileDialog.new(self, "업로드할 파일을 선택하세요" )
        if file_dialog.show_modal == Wx::ID_OK
          file_text.value = file_dialog.get_path
        end
      end 
     
      def upload_file(event)
        return show_message("파일을 선택하지 않았네요~~") if file_text.is_empty
       
        box = @storyq.slide_boxes.create("filename" => Iconv.iconv("EUC-KR", "UTF-8", file_text.value).to_s)
        item_list.add_box(box)
      end 
    end

    Wx::App.run do
      UploaderFrame.new.show
    end

 

코드 설명

browse_btn이 클릭될 때 choose_file 메쏘드가 호출되어 FileDialog 위젯을 부르도록 한다. 다양한 event들을 다룰 수 있다.

  1. evt_button(browse_btn) { |event| choose_file(event) }

파일 선택이 제대로 이루어지면 file_text.value를 선택한 파일의 path로 채운다.

  1. file_text.value = file_dialog.get_path

 

upload_btn이 클릭될 때 upload_file 메쏘드가 호출되어 스토리큐에 선택한 파일을 업로드하도록 한다.

  1. evt_button(upload_btn) { |event| upload_file(event) }

참고로, storyq_client는 storyq에 upload를 수행할 수 있는 라이브러리다. 이것을 사용하면

  1. @storyq.slide_boxes.create("filename" => "file.ppt", "title"=>"hello") 

와 같은 식으로 스토리큐에 파일 업로드를 수행할 수 있다. 주의할 점은 선택한 파일에 한글에 한글이 포함되어 있는 경우 에러가 발생할 수 있다. 이것을 방지하기 위해 file_text.value를 Iconv를 이용해 UTF-8로 변경해 준다.

 

업로드를 마친 후 item_list 에 업로드한 box를 추가한다.

  1. item_list.add_box(box)

add_box를 ItemListCtrl에 구현한다. ItemListCtrl은 wxFormBuilder로 디자인을 할 때 item_list 위젯에서 subclass로 적어준 것이다. xrcise에 의해 생성된 uploader_frame.rb를 보면 item_list가 ItemListCtrl을 extend하고 있음을 알 수있다.

  1. # in uploader_frame.rb
  2. @item_list.extend(ItemListCtrl)

 

업로드할 파일을 드래그 앤 드롭으로 추가하기

좀 더 편리해지기 위해 업로드할 파일을 item_list 에 드래그 드롭하면 업로드가 되도록 해 보자. 이 기능을 위해서 set_drop_target 메쏘드를 이용할 수 있다.

UploaderFrame 의 initialize에 다음을 추가하자.

  1. item_list.set_drop_target(MyFileDropTarget.new(self))

 

그리고 MyFileDropTarget을 다음과 같이 만들자.

  1. class MyFileDropTarget < Wx::FileDropTarget
      def initialize(parent)
        super()
        @parent = parent
      end
     
      def on_drop_files(x, y, filename)
  2.   filename.each do |file|
  3.      box = @parent.storyq.slide_boxes.create("filename" => file)
         @parent.item_list.add_box(box)
  4.    end  
      end
    end

filename에는 드롭되는 파일들이 배열로 들어 있다.

 

exe로 만들기

rubyscript2exe 를 이용해서 exe로 만들 수 있다. 그런데 잘 안되는군.

 다음과 같은 에러 발생, gem 1.2에서는 안되는듯.

  1. c:/ruby/lib/ruby/site_ruby/1.8/rubygems/remote_fetcher.rb:19: uninitialized constant Gem::Exception (NameError)

 

다음에 설명이 있는데, 뭔소린지..

http://xslforum.com/29865-about-circular-dependencies-rubygems-library-about-theorder.html

 

써보니

즐겁기는 한데, 감탄할 만큼 멋지지는 않은듯.

 

 

 

이 글은 스프링노트에서 작성되었습니다.