Rails 2.1 : Gem Dependencies

Last Modified on 2008/04/04 21:29 by 크레이지DK

Rails와 Gem

Rails를 개발하다보면 외부의 Gem에 의존하게 되는 경우가 있다. 예를 들어 RSS를 읽어와서 item의 title과 link를 추출하는 경우에, 빠르고 간편한 처리를 위해 hpricot을 사용할 수 있을 것이다. 또한 업로드하는 파일의 thumbnail을 생성하기 위해서 rmagick gem을 필요로 하게된다. 이 경우 Rails Application은 hpricotrmagick이라는 gem에 의존적이게 된다. 따라서 해당 gem이 설치되어 있지 않거나, 필요로 하는 버전 이하의 gem이 설치되어 있을 경우, 정상적인 결과를 보장할 수 없게 된다. 기존의 Rails에서는 이러한 Gem 의존성 문제를 프로그램적으로 해결할 수 있는 방법이 없었다. 그래서 Rails 2.1에서 Gem 의존성을 정의하고, 그에 따라서 Gem을 자동으로 로드해주는 기능이 추가되게 되었다.

 

다음 코드는 Rails 2.1에서의 config/environments.rb 파일 중, 초기화와 관련된 부분이다.

  1. Rails::Initializer.run do |config|
      config.gems "bj"
      config.gems "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
      config.gems "aws-s3", :lib => "aws/s3"
    end

 

위와 같이 초기화 블럭에서 config.gems GEMNAME <options> 형식으로 Gem 의존성을 정의할 수 있다. 위의 코드를 통해서 이 Rails Application은 "bj", "hpricot", "aws-s3" 이라는 gem들에 의존하고 있다는 것을 알 수 있다. #gems는 Rails::Configuration 클래스에 새로 추가된 메소드로서 주어진 옵션으로 Rails::GemDependency 클래스의 인스턴스를 생성해주는 메소드이다. 위와 같이 의존성이 정의된 gem은 Rails Application이 가동될 때, 해당 gem의 존재 여부와 버전의 적합성을 판단하여 gem을 로드할 수 없을 경우, 에러 메시지를 발생시킨게 된다.

 

Rails::GemDependency

다음은 Rails::GemDependeny의 initialize 메소드다. 아래의 코드에서 Gem 의존성을 설정할 때 설정할 수 있는 옵션의 종류를 알 수 있다.

  1. def initialize(name, options = {})
      @name     = name.to_s
      if options[:version]
        @requirement = Gem::Requirement.create(options[:version])
        @version     = @requirement.instance_variable_get("@requirements").first.last
      end
      @lib      = options[:lib]
      @source   = options[:source]
      @loaded   = false
      @load_paths_added = false
      @unpack_directory = nil
    end

 

  1. :version

    우선 version 정보를 설정할 수 있다. Ruby 코드에서 특정 버전의 gem을 필요로 하는 경우, 다음과 같이 표기하였다. 위 코드에서 '~>3.0' 부분이 gem에 대한 버전 정보로서, GemDependency에서도 동일한 표기법으로 버전 정보를 설정한다.

    1. gem 'RedCloth', '~> 3.0'   # gem을 $LOAD_PATH에 추가.
    2. require 'RedCloth'

    version 정보로 Gem::Requirement create 메소드(factory method)인스턴스를생성한후에, 인스턴수변수에서 Gem::Version 정보를추출한다.

     

     

  2. :lib

    gem 이름과 require로 불러오는 이름이 다를 경우, :lib으로 라이브러리명을 명시할 수 있다.

    1. gem 'aws-s3', '>= 0.4.0'
      # require 'aws/s3'
      config.gem 'aws-s3', :lib => 'aws/s3', :version => '>= 0.4.0'

     

  3. :source

    gem을 특정 repository에서 install해야하는 경우, :source로 명시할 수 있다. 명시한 source 정보는 gems:install rake task에서 사용되게 된다.

    1. config.gems "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"

 

Gems Rake Task

정의된 gem 의존성을 통해서, 설치되지 않은 gem을 확인하고, 설치할 수 있는 Rake Task도 추가되었다. 특히 신규 서버에 Rails Application을 설치하는 경우(ex. App. server 추가), 기존에는 Capistrano 등의 배포툴에서 Gem 의존성을 보장하는 코드를 작성해서 일괄적으로 gem을 설치하곤 했다. 하지만 gems rake task를 통해서 보다 간편하고 정확하게 Gem 의존성을 보장할 수 있게 되었다. 아래의 이미지에서 rake -T 명령어로 gems rake task가 추가된 것을 볼 수 있다.

 

rake_gems(2).png

 

  1. rake gems

    Rails에서 의존하고있는 gem의 목록을 보여준다. 아래의 이미지에서 Rails Application이 hpricotspringnote_resources gem에 의존하고 있다는 것을 볼 수 있다. 만약 의존하고 있는 gem을 발견하지 못 할 경우, gem 이름 앞의 체크표시([*])가 표시되지 않으며, 에러 메시지를 보여준다.

    rake_gems(1).png

     

  2. rake gems:install

    필요로 하는 모든 gem을 설치한다. 만약 source 정보를 명시하였다면 해당 source로 부터 gem을 설치한다.

     

  3. rake gems:unpack <GEM=[GEMNAME]>

    vendor/gems 디렉토리에 gem을 unpack한다. 특정 Gem의 source 코드가 궁금한 경우, gem repository에 직접 접근해서 소스코드를 보지 않고, 현재 디렉토리에 unpack해서 확인하는 경우가 많다.

    1. gem unpack GEMNAME

    그와 같이 repository에 있는 gem을 수정해서 자신만의 버전으로 사용하거나 하는 경우, unpack을 통해서 따로 설치한 gem을 사용할 수 있다. 이 경우 우선순위는 vendor/gems 에 설치된 gem이 갖게된다.

     

    Changeset 9140까지는 GEM=[GEMNAME]을 명시하여, 특정 Gem만 unpack할 수 있었으나, Changeset 9215부터 gem 이름을 명시하지 않을 경우, 모든 gem을 unpack하도록 기능 추가되었다.

     

  4. rake gems:build <GEM=[GEMNAME]>

    Chageset 9215에서 추가된 task로서 unpack된 gem(들)을 빌드한다. (native extension)

     

참조