#245 New Gem with Bundler
- Download:
- source codeProject Files in Zip (3.62 KB)
- mp4Full Size H.264 Video (20.1 MB)
- m4vSmaller H.264 Video (9.2 MB)
- webmFull Size VP8 Video (22.5 MB)
- ogvFull Size Theora Video (16.8 MB)
루비 젬을 만들어 관리하는 방법은 수년에 걸쳐 발전해 왔습니다. 이전 135번[watch, read] 연제에서는 echoe 젬을 사용해서 젬을 작성하였고, 일년후, 183번[watch, read] 연제에서는 Jeweler 젬을 사용했었습니다. 이 두개의 젬 모두에서, 하나의 젬을 릴리스할 때마다 Gemsepc 파일을 생성하는 방법을 제공해 주고 있으며 이 툴을 이용해서 Gemspec 파일을 관리하게 됩니다. 이번 연제에서는 훨씬 더 간단한 메소드를 이용해서 직접 Gemspec 파일을 관리할 것입니다.
이러한 메소드를 사용하더라도, 젬 마다 초기 Gemspec 파일을 생성할 필요가 있습니다. 직접 코딩하여 작성할 수 있고, Bundler와 같은 툴을 이용하여 도움을 받을 수도 있습니다. Bundler는 일반적으로 어플리케이션의 의존성을 관리하는 방법으로 알려져 있지만, 젬을 생성하는 명령도 제공해 줍니다. 사실 이 명령은 잘 알려져 있지 않지만 젬을 제대로 작성해 줍니다. bundle gem 명령에 원하는 젬 이름을 넘겨줍니다. 이 연제의 목적상 lorem이라는 간단한 젬을 만들 것이며 이 젬은 “Lorem ipsum” 텍스트 일부를 생성해 줍니다.
$ bundle gem lorem
create lorem/Gemfile
create lorem/Rakefile
create lorem/.gitignore
create lorem/lorem.gemspec
create lorem/lib/lorem.rb
create lorem/lib/lorem/version.rb
Initializating git repo in /Users/eifion/code/ep245/lorembundle gem 명령은 디렉토리를 새로 만들어 그 위치에 관련 파일들을 생성해 줍니다. 또한 해당 디렉토리에서 git 저장소로 초기화해 줍니다. 이것은 git 사용이 가능한 상태로 만들어 주는데, 그 이유는 잠시 후에 설명하도록 하겠습니다. 먼저 생성된 파일들에 대해 하나하나 알아보도록 하겠습니다. 먼저 lorem.gemspec 파일부터 보도록 하겠습니다.
# -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) require "lorem/version" Gem::Specification.new do |s| s.name = "lorem" s.version = Lorem::VERSION s.platform = Gem::Platform::RUBY s.authors = ["TODO: Write your name"] s.email = ["TODO: Write your email address"] s.homepage = "" s.summary = %q{TODO: Write a gem summary} s.description = %q{TODO: Write a gem description} s.rubyforge_project = "lorem" s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] end
언뜻보아도 알 수 있듯이 이 파일내용 중에 TODO 항목들을 직접 변경하여 사용할 수 있습니다. 이 작업이 끝나면 Gemspec 파일을 바로 사용할 수 있게 될 것입니다. 이 파일에서 흥미로운 것은 파일의 끝에 있는 파일관련 속성들입니다. 이것들은 런타임시에 어떤 파일들이 젬에 포함될 것인지를 결정하기 위해 git을 사용하여 git ls-files 명령을 실행하게 되는데 바로 이것이 bundle gem 명령이 git 저장소를 생성하는 이유인 것입니다. git을 사용할 때 좋은 점은, .gitignore 의 내용을 자동으로 상속받기 때문에 임시파일이나 저장소에 포함시키고 싶지 않은 파일들(따라서 젬에도 포함되지 않는)을 제외시킬 수 있다는 것입니다. 위와 같은 디폴트 상태에서도 대부분의 젬에 대해서 작동을 하지만 제외항목을 관리하고자 할 때는 언제든지 수정할 수 있습니다.
또하나 주목할 것은, 버전 번호를 결정하는 방법에 대한 것입니다. 이것은 Lorem::VERSION이라는 상수형태로 정의되는데 이 버전 값은 lib/lorem 디렉토리의 version.rb이라는 파일에 정의되어 있습니다. 이 파일의 목적은 버전 번호를 정의하는 것입니다.
module Lorem VERSION = "0.0.1" end
기존 젬을 새 버전으로 업데이트할 때는, 이 파일에서 버전 번호를 변경하여 젬을 다시 공개할 수 있습니다.
lib 디렉토리 상에 생성된 파일 중에 lorem.rb라는 것이 있습니다. 이것이 해당 젬을 require할 때 로딩되는 파일입니다. 이 파일에 원하는 코드를 작성할 수 있고, 또는, lib 디렉토리에 다른 파일들을 생성해서 그 파일들을 require할 수도 있습니다. 여기서 작성하는 간단한 기능을 가지는 Lorem 젬에 대해서는, ipsum라는 클래스 메소드를 작성해서 Lorem Ipsum 텍스트 일부를 반환해 줄 것입니다.
module Lorem def self.ipsum "Lorem ipsum dolor sit amet, consectetur adipisicing ...." end end
젬 공개하기
이제 젬 작성을 마무리하고 첫번째 버전을 공개할 것입니다. 이전에 먼저, Gemsepc 파일을 업데이트해서 TODO 텍스트를 변경할 것입니다.
# -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) require "lorem/version" Gem::Specification.new do |s| s.name = "lorem" s.version = Lorem::VERSION s.platform = Gem::Platform::RUBY s.authors = ["Eifion Bedford"] s.email = ["eifion@asciicasts.com"] s.homepage = "" s.summary = %q{Lorem ipsum generator} s.description = %q{Simply generates lorem ipsum text.} s.rubyforge_project = "lorem" s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] end
그리고나서, Gemspec 파일에 대해서 gem build 명령을 실행합니다.
$ gem build lorem.gemspec WARNING: no homepage specified Successfully built RubyGem Name: lorem Version: 0.0.1 File: lorem-0.0.1.gem
이 명령은 .gem 파일을 만들어 줍니다. 그리고 gem push 명령을 실행하면 해당 젬을 RubyGems.org 로 푸시해서 다른 사람들이 사용할 수 있도록 공개할 수 있게 되는 것입니다.
젬 업데이트하기
Gemspec 파일을 이용해서 하나의 젬을 공개하는 일이란 정말 이처럼 쉬운 것입니다. 해당 젬의 새 버전을 릴리스하고자 할 때는, 먼저 코드를 변경한 후에 version.rb 파일에서 버전 번호를 업데이트합니다.
module Lorem VERSION = "0.0.2" end
이제 gem build와 gem push 명령을 다시 실행하면 새 버전을 만든 후 공개할 수 있게 됩니다.
Gemfile 과 Rakefile
아직 언급하지 않았지만 Bundler가 생성하는 파일 중에 2개가 더 있습니다. 바로 Gemfile과 Rakefile입니다. 먼저 Gemfile을 보도록 하겠습니다. 레일스 어플리케이션에서 Gemfile은 Bundler를 이용하여 젬 의존성을 관리하게 됩니다. Gemfile 내용을 보면 gemspec이라는 단 하나의 명령을 보게 됩니다.
source "http://rubygems.org" # Specify your gem's dependencies in lorem.gemspec gemspec
이 명령은 해당 젬의 의존성을 점검하기 위해 이 젬의 Gemspec 파일을 들여다 보고 Bundler를 이용하여 그 파일들을 로드하게 될 것입니다. 따라서 보통은 이 Gemspec파일을 직접 관리할 필요가 없게 됩니다. 사실, 해당 젬의 의존성은 Gemspec 파일내에서 관리하고 Bundler로 하여금 Gemfile을 통해서 자동으로 필요한 젬들을 로드할 수 있도록 하는 것이 더 좋습니다. 예를 들어, 해당 젬을 테스트하기 위해서 RSpec을 사용할 경우입니다. Gemfile에 RSpec을 추가하지 않고 lorem.gemspec 파일에 development dependency로 추가할 것입니다.
Gemspec 파일을 다루는 것이 익숙하지 않을 때는 이 문서를 참조할 만합니다. 여기에는 여러가지 속성들을 설정하기 위해서, Gemspec 파일에서 사용할 수 있는, 여러가지 메소드(RSpec를 추가하기 위해 사용하는 add_development_dependency 메소드를 포함)에 대한 목록을 볼 수 있습니다.
# -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) require "lorem/version" Gem::Specification.new do |s| s.add_development_dependency "rspec" # Other attributes omitted end
Gemfile에서 Gemspec 파일을 참조하도록 해 놓으면, bundle 명령을 실행해서 필요한 모든 젬들이 설치되도록 할 수 있습니다.
$ bundle Fetching source index for http://rubygems.org/ Using diff-lcs (1.1.2) Using lorem (0.0.1) from source at /Users/eifion/Desktop/Dropbox/rails/apps_for_asciicasts/ep245/lorem Installing rspec-core (2.3.1) Installing rspec-expectations (2.3.0) Installing rspec-mocks (2.3.0) Installing rspec (2.3.0) Using bundler (1.0.7) Your bundle is complete! It was installed into /Users/eifion/.rvm/gems/ruby-1.9.2-p0
이러한 방법은, 해당 젬을 공개해서 다른 개발자들도 함께 작업을 할 수 있도록 할 때, README 파일에 bundle 명령을 실행하여 관련 젬을 모두 설치할 수 있도록 방법을 알려 주고자 할 때 유용합니다.
이상으로 Gemfile에 대해 소개했습니다. 그렇다면 이제 Rakefile에 대해 알아보겠습니다. 왜 Bundler는 이 파일을 만들까. 이 파일의 코드를 들여다 보면, Bundler로부터 몇가지 젬 헬퍼 태스크를 추가한다는 것을 알게 될 것입니다.
require 'bundler' Bundler::GemHelper.install_tasks
rake -T 명령을 실행하면 이와 관련된 태스크들을 볼 수 있습니다.
$ rake -T
(in /Users/eifion/code/ep245/lorem)
rake build # Build lorem-0.0.2.gem into the pkg directory
rake install # Build and install lorem-0.0.2.gem into system gems
rake release # Create tag v0.0.2 and build
# and push lorem-0.0.2.gem to RubygemsRakefile에 있는 코드는 3가지 태스크를 생성해 줍니다. 이것은, 젬을 만들어, 설치하고, 릴리스하는 일반적인 태스크입니다. 일반적인 작업과정은, 원하는데로 젬이 작성되었을 때, rake install를 호출하여 로컬머신에 해당 젬을 설치하고, 문제가 없을 때까지 완벽하게 테스트해 볼 수 있습니다. 그리고나서, rake release 명령을 호출하여 릴리스를 표시하고 RubyGems로 해당 젬을 공개하는 것입니다.
기존 젬을 업데이트하기
Bundler를 이용하면 처음부터 직접 젬을 설정할 수 있게 되지만, 이미 만들어진 젬을 이와 같은 작업과정에 적용하고자 한다면 어떻게 될까요. 몇가지 파일에 대해서만 복사하면 간단하게 해결됩니다. 이 때, 필요한 파일은 Gemfile, .gemspec, 그리고, Bundler가 제공하는 rake 작업을 사용할 때는, Rakefile도 포함됩니다. 이러한 파일들을 기존의 젬에 추가하게 되면 이와 같은 작업과정을 사용할 수 있게 될 것입니다.
전체적으로 봤을 때, Bundler는 젬을 만들고 관리하기 위한 훌륭한 방법입니다. 이전 연제에서 소개한 관련 툴들보다도 훨신 간단하게 사용할 수 었어서 젬을 새로 만들 때 Bundler는 사용할 만한 가치가 있습니다.


