如何在 Ruby Gem 中包含数据文件?

12
我正在开发一个使用可配置的“模板”来生成 HTML 的 Ruby gem。我想在 gem 中包含一组基本模板,并允许用户用更好/更定制化的模板覆盖它们。这些模板不是 Ruby 代码,它们只是需要在代码中某个时刻从磁盘上读取的“文件”。
我查看了 RubyGems 文档,但它们做出了(并不完全不合理的)假设,即 gem 只包含代码(好吧,还有一些文档和特定的元数据文件)。没有提及如何创建类似于“/usr/share/…”文件的参考。
最佳实践是如何在 gem 中包含这些文件?我应该将它们简单地包含为“源”部分吗?如果是这样,我该如何发现它们的路径,以便将它们从磁盘读取到模板处理器中?
1个回答

10
假设您有这样的项目结构:
bin/
|__ foobar*
lib/
|__ foobar/
|   |__ templates/
|   |   |__ a/
|   |   |__ b/
|___|__ meta.rb
|___|__ utils.rb

lib/foobar/templates 目录下,您可以找到模板目录或文件。 lib/foobar/meta.rb 文件包含项目名称及其版本。保持它们(特别是版本号)与 gem 规范中的项目名称和版本同步非常重要。(最好的方法是从 Rakefile 读取 meta.rb 并将值传递给规范。)
例如,meta.rb 可能如下所示:
module Foobar
  module Meta
    NAME = 'foobar'
    VERSION = '0.1.2'
  end
end

编写一个函数,无论您是从源目录测试项目还是从RubyGems安装项目,都返回到lib目录的完整路径。

utils.rb

require_relative 'meta'

module Foobar
  module Utils

    # Return a directory with the project libraries.
    def self.gem_libdir
      t = ["#{File.dirname(File.expand_path($0))}/../lib/#{Meta::NAME}",
           "#{Gem.dir}/gems/#{Meta::NAME}-#{Meta::VERSION}/lib/#{Meta::NAME}"]
      t.each {|i| return i if File.readable?(i) }
      raise "both paths are invalid: #{t}"
    end

    # [...]
  end
end

使用 Foobar::Utils.gem_libdir 函数,您可以始终在 bin/foobar 文件中读取模板:

require_relative '../lib/foobar/utils'

puts Dir[Foobar::Utils.gem_libdir + '/*']
puts Foobar::Utils.gem_libdir + '/templates/a/blah-blah'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接