Traveling Ruby 教程二:处理 Ruby 应用的 gem 依赖
前言
在上一篇文章中,我们介绍了如何使用 Traveling Ruby 打包一个简单的 Ruby 应用程序。本教程将继续深入,讲解如何处理 Ruby 应用中的 gem 依赖问题。通过本教程,你将学会如何将依赖的 gem 打包进你的应用程序中,使其成为一个真正独立的可执行文件。
理解 gem 依赖管理
在 Ruby 开发中,我们通常使用 Bundler 来管理 gem 依赖。但在打包应用时,我们需要特别注意以下几点:
- 开发环境与生产环境的区别:开发时使用的 gem(如测试框架)不应包含在最终包中
- Ruby 版本一致性:打包时必须使用与 Traveling Ruby 相同的 Ruby 版本
- 依赖隔离:确保打包的 gems 不会与用户系统上的 gems 产生冲突
准备工作
让我们从一个简单的示例开始。假设我们想改进之前的"Hello World"应用,让它能够随机生成人名来打招呼。我们将使用 Faker gem 来实现这个功能。
首先创建 Gemfile:
source 'https://rubygems.org'
gem 'faker'
group :development do
gem 'rake'
end
然后修改 hello.rb 文件:
#!/usr/bin/env ruby
require 'faker'
puts "hello #{Faker::Name.name}"
安装依赖并测试:
bundle install
bundle exec ruby hello.rb
为打包准备 gem 依赖
这里有一个关键点:我们需要为打包单独安装一套 gem,而不是直接使用开发环境的 gem。这是因为:
- 我们需要确保 gem 安装在与 Traveling Ruby 兼容的 Ruby 版本下
- 我们需要控制哪些 gem 会被包含在最终包中
执行以下命令来为打包准备 gem:
mkdir packaging/tmp
cp Gemfile Gemfile.lock packaging/tmp/
cd packaging/tmp
BUNDLE_IGNORE_CONFIG=1 bundle install --path ../vendor --without development
cd ../..
rm -rf packaging/tmp
这个命令做了以下几件事:
- 创建临时目录避免污染开发环境
- 使用
--without development
排除开发依赖 - 将 gem 安装到 packaging/vendor 目录
- 清理临时文件
构建包结构
接下来,我们需要将这些 gem 复制到包目录中。使用之前教程中的 Rakefile 创建基础包结构:
rake package DIR_ONLY=1
然后复制 gem 和相关配置:
cp -pR packaging/vendor hello-1.0.0-linux-x86/lib/
cp Gemfile Gemfile.lock hello-1.0.0-linux-x86/lib/vendor/
配置 Bundler 环境
为了让打包后的应用能正确找到 gem,我们需要配置 Bundler。创建 bundler-config 文件:
BUNDLE_PATH: .
BUNDLE_WITHOUT: development
BUNDLE_DISABLE_SHARED_GEMS: '1'
然后将配置复制到包中:
mkdir hello-1.0.0-linux-x86/lib/vendor/.bundle
cp packaging/bundler-config hello-1.0.0-linux-x86/lib/vendor/.bundle/config
更新包装脚本
包装脚本需要告诉 Bundler 在哪里找到 Gemfile 和 gems。更新 packaging/wrapper.sh:
#!/bin/bash
set -e
SELFDIR="`dirname \"$0\"`"
SELFDIR="`cd \"$SELFDIR\" && pwd`"
export BUNDLE_GEMFILE="$SELFDIR/lib/vendor/Gemfile"
unset BUNDLE_IGNORE_CONFIG
exec "$SELFDIR/lib/ruby/bin/ruby" -rbundler/setup "$SELFDIR/lib/app/hello.rb"
自动化打包流程
为了简化流程,我们可以更新 Rakefile 来自动化所有步骤。关键点是:
- 添加 bundle_install 任务来处理 gem 安装
- 更新 create_package 方法包含 gem 相关文件
- 确保使用正确的 Ruby 版本
task :bundle_install do
if RUBY_VERSION !~ /^2\.1\./
abort "必须使用 Ruby 2.1.x 版本进行打包"
end
# ...安装gem的代码...
end
def create_package(target)
# ...基础包结构代码...
sh "cp -pR packaging/vendor #{package_dir}/lib/"
sh "cp Gemfile Gemfile.lock #{package_dir}/lib/vendor/"
sh "mkdir #{package_dir}/lib/vendor/.bundle"
sh "cp packaging/bundler-config #{package_dir}/lib/vendor/.bundle/config"
# ...打包代码...
end
测试与验证
完成打包后,你应该测试生成的文件:
- 解压打包好的文件
- 运行其中的可执行文件
- 确认它能正确加载 Faker gem 并输出随机人名
注意事项
- Ruby 版本一致性:打包时必须使用与 Traveling Ruby 完全相同的 Ruby 版本
- 清理缓存:打包前记得删除 gem 缓存文件以减少包大小
- 开发依赖:确保开发依赖不会被包含在最终包中
- 跨平台兼容性:为每个目标平台单独打包 gem
总结
通过本教程,你已经学会了:
- 如何在 Traveling Ruby 打包过程中处理 gem 依赖
- 使用 Bundler 管理生产环境依赖
- 配置打包环境确保 gem 被正确包含
- 自动化整个打包流程
对于包含原生扩展的 gem,处理方式会有所不同,我们将在下一个教程中介绍。
记住,Traveling Ruby 的目的是创建自包含的 Ruby 应用分发包,正确处理 gem 依赖是实现这一目标的关键步骤。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考