When do you need a require in a rails Gemfile? - ruby-on-rails

In my gemfile I have things like:
gem 'net-sftp', '2.1.1', :require => 'net/sftp'
gem 'backup', '3.0.27'
gem 'watu_table_builder', :require => 'table_builder'
gem 'browser', '0.1.6'
When in a Gemfile do you need a require? I've also found things like :require => false. Help?

If you omit the :require option, by default Bundler will attempt to require the gem by using the standard name-to-file conversion rule:
dashes are considered namespace separators and underscore classname separators
It means that the following gem statements
gem 'net-sftp'
gem 'backup'
gem 'foo_bar'
are equivalent to
gem 'net-sftp', require: 'net/sftp'
gem 'backup', require: 'backup'
gem 'foo_bar', require: 'foo_bar'
This works well if the gem author has followed the standard conventions. But in some cases, for a variety of reasons, this doesn't happen.
For instance, there are gems called foo-bar where the main filename is /foo_bar.rb or even /foo.rb. In this case you provide the :require option to tell Bundler which file you want to require.
Finally, require: false is used when you want a gem to be part of the bundle, but you don't want Bundler to load it by default.
This is useful, for instance, to lazy-load a gem in case it is used only in certain circumstances. Think about a rake task that includes a heavy gem. You don't want your application to load it on boot, but it needs to be part of the bundle or it will not be found.
In this case you pass the option require: false. Then, in your rake task you will require it manually as usual
require 'library'
The library will be loaded only when the task is invoked, not in the normal application execution.
A good example is whenever. The library must be part of the bundler because it must be bundled when you deploy the app, but it is intended to be run as a command line script. For this reason, you don't want Bundler to require it when the Rails application is started.
There are cases where you use groups instead of require: false.
See also the official Bundler documentation for require.

You need a :require if the name of the file that's required to activate the gem can't be inferred from the gem's name. Ruby convention is to name your gem the same thing as the "require" statement you should use, but not everything follows the convention.
:require => false disables automatic requiring by Bundler, so you'd need to use require 'foo' manually to use the code in foo. This is mainly useful if a gem is large or expensive to activate and only used in certain cases.

This is often used if the name of the library to require is different than the name of the gem. In your case it would download the gem 'watu_table_builder', but would call 'table_builder'.

require specifies other files that would be required on requiring this particular gem.
Documentation says
Each gem MAY specify files that should be used when autorequiring via
Bundler.require. You may pass an array with multiple files, or false
to prevent any file from being autorequired.
Refer to this for whole documentation

Related

Require gem automatically

I created a gem which defines a Rails::Railtie.
Everything works as expected, except that I have to include the main file of the gem (lib/gem.rb) in my application.rb so it is executed.
Is there any way to do this automatically?
I checked some gems, but I could not figure out how.
Solved it.
The name of my gem was slightly different from the files' name (gem-name vs lib/gem_name.rb), so I have to put this to my Gemfile:
gem 'gem-name', require: 'gem_name'

trying to require active_support in gem

I have a ruby gem and I want to use the Hash.from_xml method in the gem that is included in rails active_support module. I have the below code in my gemspec:
gem.add_dependency 'active_support', '~> 3.0.0'
However, when I build and install the gem locally, run irb, require the gem, I am not seeing the methods from active support included?
Any suggestions on what I am doing wrong or how to debug? Thanks!
You need to require the methods you need from ActiveSupport; they aren't added by default.
As Yevgeniy mentioned in a comment, the way to do this is require 'active_support/all' if you need everything - or if, for example, you want only the Hash extensions then use require 'active_support/core_ext/hash'. Note that this usually doesn't go in the gemspec, but rather in whatever file your gem uses to set itself up.
Perhaps even better would be to require the required ActiveSupport files in the actual files needing them, but that's a matter of taste.

how to set gem dependencies without having to declare them on the Gemfile that uses it?

I'm building a gem locally, suppose it name is "MyGem".
Now suppose that MyGem depends on other already built gem, for example "cancan".
So, i've added in my mygem.gemspec the line:
add_runtime_dependency("cancan")
Here is the problem: if I installl MyGem into a new project by adding it into my gemfile like this:
gem "mygem", :path => "path/to/my/local/gem"
then this new project is not being able to use cancan methods, and I have to explicity declare cancan on the new project gemfile in order to use it.
I tried also using gemspec method, but didn't solve my problem either.
Any ideas?
Update
I just wanted to add that when i only have myGem declared in my new application gemfile, after I run bundle install all the dependencies are installed.
That is, if i run gem list the "cancan" gem is displayed, but I still can't access it methods from the application level.
Thanks for the help.
Ok, i've solved this. I'm not sure if this is the best solution but it did work.
Making the application level developer to explicity add the dependencies in his gemfile didn't make any sense. So, as the gems did were being installed, i just required all the gem dependencies in my my_engine.rb file inside my gem.
Following the example, in my my_engine.rb I added the following line
require "cancan"
And that'it...
Even better you could do:
autoload :CanCan, "cancan"
So the module would be loaded only when it is called.
And even better than that, you could load only the file from cancan that you are using (maybe you don't need to load all of it).
You can add that line in you my_gem.rb file or your engine.rb file if you are using engines.
That worked for me, I hope this help someone.
Use add_dependency instead of add_runtime_dependency (this may help with cancan) then run bundle update on your new project.
Does the "cancan" gem name actually match the name to be require'd?
Example for yajl-ruby gem:
Gem::Specification.new do |s|
s.name = %q{yajl-ruby}
...
But when require'ing the library, you'd use a different string:
require 'yajl'
That means in your Gemfile, you have to explicitly require the dependency (which you said you wanted to avoid).
gem 'yajl-ruby', '>=1.0', :require => 'yajl'
To avoid needing to do this, and if you're the author of the "cancan" dependency, you should make the gem name matches the require name.
The only alternative I can think of is require'ing the dependency directly in one of your source files (like you did in your solution).

Loading gem at runtime in Rails 3

I have Rails 3.0.x application. I would like to load gems on runtime, without using Gemfile.
What I would like to accomplish is to load my application as usual, with regular gems being loaded by Bundler. After that I would like to load all gems (Rails Engines) located in a specific directory (but until runtime, I don't know what gems will that be).
Does anybody know if this is possible in Rails, maybe using Bundler API?
What you're trying to do is dangerous. If each of your Rails Engines are also gems - then they would also have Gemfiles with other dependencies, and those would in turn have other dependencies, etc. If you allow Bundler to resolve those, then you would have lesser problems at runtime.
Here's how you would do it without any hacks. Remember that your Gemfile is just Ruby code, and you can have gems which are not loaded by default.
# In your Gemfile, add at the end:
Dir[YOUR_RAILS_ENGINES_SUBFOLDER + "/*/*.gemspec"].each do |gemspec_file|
dir_name = File.dirname(gemspec_file)
gem_name = File.basename(gemspec_file, File.extname(gemspec_file))
# sometimes "-" and "_" are used interchangeably in gems
# for e.g. gemspec_file is "engines/my-engine/my_engine.gemspec"
# dir_name will be engines/my-engine
# gem_name will be my_engine
# Register that engine as a dependency, *without* being required
gem gem_name, :path => dir_name, :require => false
# e.g. this is similar to saying
# gem 'my_engine', :path => 'engines/my-engine', :require => false
end
Now you have all your dynamic Rails engines registered as gem dependencies. Bundler will resolve them, and all their sub-dependencies, so you don't have to worry about anything. Just run bundle install once before running the application, or whenever you add/remove any engine in that folder.
The good thing is, these gems will just be registered, and not loaded. So in your production code, you can now load whatever gem that you choose at runtime simply by saying require <your-engine-name>
Edit: Extra code comments
Try this:
Bundler.with_clean_env do
# require gems...
end

Bundler.require does not work for ActiveRecord in my gem

I just created a new gem (using bundler) and want to add Active Record support. So I added s.add_dependency "activerecord", "~> 3.0" to my gemspec. Then I use Bundler.setup and Bundler.require and thought that I have access to Active Record now, but I haven't. I have to explicitly use require "active_record". Any idea why Bundler.require does not work for me in that case?
Firstly, if you're packaging a gem, do not use Bundler.require. Bundler.require is for apps not gems.
In .gemspec, specify the dependencies of your deployed gem.
In your Gemfile, include the line gemspec to automatically include the dependencies listed in your .gemspec in your Gemfile.
You may also optionally create gem groups for dev and test.
In your code, explicitly require any libraries you need.
I lost a couple of hours on this today so I hope this helps.
(Sources 1, 2)
Secondly, though the ActiveRecord gem is called "activerecord", the lib is called "active_record". This is what you would need in Gemfile.
gem 'activerecord', :require => "active_record"
Unless you include the :require option, ActiveRecord won't be loaded correctly and you won't know about it until you try to use it.
If you want use Bundler you need define your Gemfile with Activerecord
gem 'activerecord', "~> 3.0.0"
Or you need define bundler to use your gemspec with adding gemspec in your Gemfile
gemspec
See http://gembundler.com/rubygems.html
I had this problem, and the issue in my case was that I was naming a directory in my gem active record, as in:
lib ->
active_record ->
base.rb <- containing some monkey patches to base
This was causing mass confusion including sweet error messages like:
Gem Load Error is: uninitialized constant ActiveRecord::Base
Did you mean? ActiveRecord::Base
Simply moving changing the file from lib/active_record/base.rb to lib/active_record_base.rb fixed it for me.

Resources