开发者

How to include data files in a Ruby Gem?

I'm working on a Ruby gem that uses configurable "templates" to generate HTML. I want to include a basic set of templates with the gem, and allow the users to override them with bette开发者_开发知识库r/more customized ones. These templates aren't Ruby code, they are "just files" that need to be read from the disk at some point in the code.

I looked over the RubyGems documentation but they make the (not altogether unreasonable) assumption that a gem contains only code (OK, with some documentation and specific meta-data files thrown in for good measure). There's no reference to how to create the equivalent of "/usr/share/..." files.

What is the best practice for including such files in the gem? Should I simply include them as part of the "sources"? If so, how do I discover their path so I can read them from the disk into the template processor?


Suppose you have a project structure like this:

bin/
|__ foobar*
lib/
|__ foobar/
|   |__ templates/
|   |   |__ a/
|   |   |__ b/
|___|__ meta.rb
|___|__ utils.rb

In lib/foobar/teplates directory you have your template directories or files.

lib/foobar/meta.rb file contains the name of your project and its version. It's important to keep them (particularly a version number) synced with the name & the version of the project in your gem specification. (The best way to do this is read meta.rb from Rakefile to pass values to the spec.)

For example, meta.rb may look like:

module Foobar
  module Meta
    NAME = 'foobar'
    VERSION = '0.1.2'
  end
end

Then write a function that return a full path to the lib directory regardless whether you are testing your project from the sources directory or the project is installed from the rubygems.

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

Having Foobar::Utils.gem_libdir function you can always read your templates in bin/foobar file:

require_relative '../lib/foobar/utils'

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜