Where to place/access config file in gem?
I'm jumping on this one a little late but I'll leave an example implementation of how I generally handle this, for future reference.
As it was mentioned, you'll normally want to allow configuration through both files and hashes. It's pretty easy and light to include both ways, so you should do it.
Something like this works for me in most scenarios:
require 'yaml'
module MyGem
# Configuration defaults
@config = {
:log_level => "verbose",
:min => 0,
:max => 99
}
@valid_config_keys = @config.keys
# Configure through hash
def self.configure(opts = {})
opts.each {|k,v| @config[k.to_sym] = v if @valid_config_keys.include? k.to_sym}
end
# Configure through yaml file
def self.configure_with(path_to_yaml_file)
begin
config = YAML::load(IO.read(path_to_yaml_file))
rescue Errno::ENOENT
log(:warning, "YAML configuration file couldn't be found. Using defaults."); return
rescue Psych::SyntaxError
log(:warning, "YAML configuration file contains invalid syntax. Using defaults."); return
end
configure(config)
end
def self.config
@config
end
end
An added best practice would be to have defaults for all your configuration keys(as in the example above). That way, you are giving the user ultimate freedom in how they can configure your library.
access configuration in gem
The standard way to configure a gem is to have an initializer in the application where the gem is used.
config/initializers/my_gem.rb:
MyGem.configure do |config|
config.namespace = 'the_namespace'
end
See this answer for an example on how you can implement the configuration API in the gem:
How to use ActiveSupport::Configurable with Rails Engine
How to find where gem files are installed
Use gem environment
to find out about your gem environment:
RubyGems Environment:
- RUBYGEMS VERSION: 2.1.5
- RUBY VERSION: 2.0.0 (2013-06-27 patchlevel 247) [x86_64-darwin12.4.0]
- INSTALLATION DIRECTORY: /Users/ttm/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0
- RUBY EXECUTABLE: /Users/ttm/.rbenv/versions/2.0.0-p247/bin/ruby
- EXECUTABLE DIRECTORY: /Users/ttm/.rbenv/versions/2.0.0-p247/bin
- SPEC CACHE DIRECTORY: /Users/ttm/.gem/specs
- RUBYGEMS PLATFORMS:
- ruby
- x86_64-darwin-12
- GEM PATHS:
- /Users/ttm/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0
- /Users/ttm/.gem/ruby/2.0.0
- GEM CONFIGURATION:
- :update_sources => true
- :verbose => true
- :backtrace => false
- :bulk_threshold => 1000
- REMOTE SOURCES:
- https://rubygems.org/
- SHELL PATH:
- /Users/ttm/.rbenv/versions/2.0.0-p247/bin
- /Users/ttm/.rbenv/libexec
- /Users/ttm/.rbenv/plugins/ruby-build/bin
- /Users/ttm/perl5/perlbrew/bin
- /Users/ttm/perl5/perlbrew/perls/perl-5.18.1/bin
- /Users/ttm/.pyenv/shims
- /Users/ttm/.pyenv/bin
- /Users/ttm/.rbenv/shims
- /Users/ttm/.rbenv/bin
- /Users/ttm/bin
- /usr/local/mysql-5.6.12-osx10.7-x86_64/bin
- /Users/ttm/libsmi/bin
- /usr/local/bin
- /usr/bin
- /bin
- /usr/sbin
- /sbin
- /usr/local/bin
Notice the two sections for:
INSTALLATION DIRECTORY
GEM PATHS
Setting up configuration settings when writing a gem
Try refactoring to:
def self.configuration
@configuration ||= Configuration.new
end
def self.configure
yield(configuration) if block_given?
end
Bundler config to either look for gems in custom path or download from custom source
The syntax for sourcing a gem from a local folder is:
gem 'some-gem-name', path: '/my/custom/path'
And the syntax for specifying a custom source is:
gem 'another-gem-name', source: 'https://a.nice.host'
And to install gems into a specific local folder, you can run:
bundle install --path ./local/relative/path
Now, that's probably all the tools you need, in truth... (And in fact, especially for that last requirement, you may instead wish to look into rvm gemsets
, or using bundle install --deployment
.)
But you did also ask about "looking in a local folder first, and only falling back to a remote source if it doesn't exist". That's quite an odd requirement (usually you'd only want to explicitly opt-in to fetching gems from a local path?!), but to answer this question as you've asked it...
A Gemfile
is literally just ruby code! So you can define this logic using... You guessed it, ruby! For example:
if File.exists?('/my/custom/path')
gem 'some-gem-name', path: '/my/custom/path'
else
gem 'some-gem-name', source: 'https://a.nice.host'
end
If this (unusual) pattern needs to be repeated in multiple places, you could wrap it into some helper method.
For more information on the configuration options of bundler
, please see the documentation.
How to read files (.yml) from a Gem
Solution 1
You can store the root path in a constant from your main gem file and retrieve it in other locations of your code. You must ensure that the gem got initialized before the code in your app runs otherwise you'll have an errors because the constant won't be defined.
# lib/my_gem.rb
GEM_ROOT = File.expand_path("../..", __FILE__)
# app/.../some_class.rb
IO.read("#{GEM_ROOT}/config/test.yml")
Solution 2
The most advisable, you can get the gem path programmatically from Bundler
, then use that root path to retrieve the full path of your yml file.
Have a look at this answer that you can easily adapt to your case
Related Topics
How to Input Integer Value to an Array, Based Preceeding Row + Column Values
Good Cucumber Examples in the Wild
How to Run Shell Commands on Server in Capistrano V3
Phusion Passenger Error: You Have Activated Rack 1.2.1, But Your Gemfile Requires Rack 1.2.2
Is 'Yield Self' the Same as Instance_Eval
Fresh Installs of Rvm and Ruby 2.1.1 - Dyld Library/Pathing Error
How to Authorize a Service Account for Google Calendar API in Ruby
Replacing Text in One CSV Column Using Fastercsv
Rails, How to Render a View/Partial in a Model
Parse Command Line Arguments in a Ruby Script
How to Write a Web Scraper in Ruby
Mongo - Ruby Connection Problem