I have a problem when trying to include mixin from gem file to be used via console.
require "fertilizer/version"
module Fertilizer
# <-- CONSOLE EXTENSION (CONSOLE ONLY)-->
# Following part of code is active with the start of IRB console.
# Details about features can be seen in console_extensions module.
if defined?(Rails::Console)
require 'fertilizer/console_extensions'
include ConsoleExtensions
end
# <-- OBJECT EXTENSIONS (CONSOLE ONLY)-->
if defined?(Rails::Console)
require 'fertilizer/object_extensions'
end
end
Gem has ruby file fertilizer.rb which executes code above, when I start console I can see code being triggered. But when I try to use methods from mixin, console can't find them.
If I take exact same code and put it in initializer mixin gets loaded (as before) but this time I am able to use methods from mixin in consle.
How can I fix my gem file so that when gem loads, mixin methods are available via console?
More discussion can be found here:
How to automatically include Gem in the path?
Solution is:
Object.send(:include, self)
Not happy with solution but it works.
Related
I'm using the okcomputer gem for a Rails app (All you need to do to use this gem is to place some code in an initializer).
I'd like to wrap this gem inside a custom gem that can be used without an initializer. I hope to be able to use this gem in several dockerized microservices just by installing it.
I read that it's possible to put initializer code in an init.rb file at the root of the gem. In my case, that doesn't seem to be working (the routes generated by okcomputer are not found), but I'm not sure where the issue lies.
In general, can I expect code in init.rb to behave like code in an initializer?
Your best approach is probably to create a Railties and run your code in an after_initialize hook.
module Gemname
class MyCoolRailtie < ::Rails::Railtie
config.after_initialize do
OKComputer::Registry.register "resque_critical",
OKComputer::ResqueBackedUpCheck.new("critical", 10)
end
end
end
https://api.rubyonrails.org/classes/Rails/Railtie.html
I find myself having to type (for example)
include PathHelper
every time I load the Rails Console.
Is there a way to configure the Rails console to automatically include certain modules?
The syntax for configuring rails console has changed. I found this on RailsGuides:
http://guides.rubyonrails.org/configuring.html#rails-general-configuration
console do
# this block is called only when running console,
# so we can safely require pry here
require "pry"
config.console = Pry
end
Just in case anyone still feel confused, the simplest way to do this is:
go to the root directory of your project
create an .irbrc file(if you use rails console) or .pryrc file(if you use pry)
put whatever you need to include in it
For example, if you use the default rails console and need to include PathHelper, just put it in the file:
# RootDirectoryOfYourProject/.irbrc
include PathHelper
The PathHelper will be included automatically when you do rails console
If you are still looking for an answer, this is what I do,
I created a file ~/.irbrc in which you put all the code you want to be auto loaded in your rails console.
This is the content of my file:
require "awesome_print"
include Rails.application.routes.url_helpers
AwesomePrint.irb!
def y(obj)
puts obj.to_yaml
end
I would check out this question.
Basically, modify your config/application.rb file to include the paths to any modules you want to auto-load.
I have written a generator which creates the following ruby file and folder:
app/tests/test.rb
in the test.rb file I have a Test class which looks like this:
class Test < MyCustomModule::MyCustomClass::Base
...
end
Now, I want to use its functionality in one of the show.html.erb files creating new instance like this:
Test.new(...).render(...).html_safe
but I am getting the following error:
uninitialized constant MyCustomModule::MyCustomClass::Base
I have use the following answer to link my gem and my rails application. It seems to work as I am able to use the generator, but the gem module and class are not seen in the rails application.
Could anyone tell how to fix this issue?
I have try to follow the tips posted here but still nothing changed:
Adding config.autoload_paths += Dir["#{config.root}/lib/**/"] in application.rb file
I have created my gem structure looking at CarrierWave gem, so the naming should be correct
I try to disable config.threadsafe! but it is already disabled since config.cache_classes and config.eager_load are set to false in development
DEPRECATION WARNING: config.threadsafe! is deprecated. Rails
applications behave by default as thread safe in production as long as
config.cache_classes and config.eager_load are set to true.
Also, looking at adding-asset-to-your-gems rails documentation, it is said that:
A good example of this is the jquery-rails gem which comes with Rails
as the standard JavaScript library gem. This gem contains an engine
class which inherits from Rails::Engine. By doing this, Rails is
informed that the directory for this gem may contain assets and the
app/assets, lib/assets and vendor/assets directories of this engine
are added to the search path of Sprockets.
So, I have done this, and put my model class file in assets folder, but the result is the same.
The following screenshots demonstrate my real case:
The screenshot below displays my gem file structure
Here you can see how I am loading the gem in my Rails application Gemfile:
gem 'thumbnail_hover_effect', '0.0.3', github: 'thumbnail_hover_effec/thumbnail_hover_effec', branch: 'master'
Then I am using the gem generator a ruby file with a cutstom name in app/thumbnails/test.rb folder with the following code:
class Test < ThumbnailHoverEffect::Image::Base
...
end
and trying to use the Test class gives me uninitialized constant ThumbnailHoverEffect::Image::Base error.
Back in the gem files, these are how the thumbnail_hover_effect file looks like
require 'thumbnail_hover_effect/version'
require 'thumbnail_hover_effect/engine'
require 'thumbnail_hover_effect/image'
module ThumbnailHoverEffect
# Your code goes here...
end
and hoe the image file looks like:
module ThumbnailHoverEffect
#
class Image
...
end
end
From what you've posted here there is no ThumbnailHoverEffect::Image::Base defined. Rails autoloading conventions (which you should not be depending on a gem btw, more on that later) would be looking for this file in thumbnail_hover_effect/image/base.rb, but the directory structure you printed does not have that. Of course you could define the class in thumbnail_hover_effect/image.rb and it would work, but the abridged snippet you posted does not show that. So where is ThumbnailHoverEffect::Image::Base defined?
If it's in thumbnail_hover_effect/image/base.rb then that would indicate the file is not being loaded. You can sanity check this by putting a puts 'loading this stupid file' at the top of thumbnail_hover_effect/image/base.rb. That will allow you to bisect the problem by seeing whether there is a problem with your definition of the class, or whether the problem is with loading the proper files. Debugging is all about bisecting the problem.
I'm using the excellent twitter-bootstrap-rails gem. There is a helper within that gem (NavbarHelper) which is used to generate Bootstrap navbars with a Ruby helper. I want to monkey patch the gem such that the dropdown lists won't have carets.
So, I looked into the source and found the relevant method here. All I have to do is override it. I created a new file in config/initializers called navbar.rb with the following content:
NavbarHelper.module_eval do
def name_and_caret(name)
"HELLO WORLD"
end
end
Presumably, all of the dropdown titles then should be rendered as "HELLO WORLD" in my app (as referenced by the gem source). However, this is not occurring, and the gem does not appear to be monkeypatched at all.
I tried placing puts NavbarHelper.methods - Object.methods in the initializers file, and there were no results, which makes me think that Rails is not loading the gem correctly before the initializers. I have also checked and verified that the gem is not using autoload for its helpers.
Edit
What may be complicating this is the fact that my Gemfile includes the gem in the following manner:
gem 'twitter-bootstrap-rails', git: 'git://github.com/seyhunak/twitter-bootstrap-rails.git', branch: 'bootstrap3'
I'm not sure if this specific versioning means the monkeypatching doesn't work.
Edit #2
It seems there is only one version of the gem on my system, so I don't think that's the issue. Also, I have tried placing require 'twitter-bootstrap-rails at the top of the initializers file, with no results.
The problem is that you patch the method on this module but the module already got included at this point. Try to define this in your application_helper.rb
def name_and_caret(name)
super("blub #{name}")
end
I have written a gem that uses a gem in one of its classes to overwrite Timeout. I only want to overwrite Timeout in this single instance, not globally in my gem and certainly not globally in anyone's project that uses my gem.
The problem I'm running into is when I include my gem in a rails project. It seems that the timeout gem gets instantiated from the get-go (at rails app load) and affects other parts of my Rails app that rely on the standard Timeout.
My question is this: how can I limit the timeout gem's influence to only the single class that I wish to use it in. I've already placed the require statement within the class definition and this didn't seem to help.
Place require: false in your Gemfile. E.g.:
gem 'name-of-gem', require: false
That way the gem won't be required automatically on app load, only when you explicitly call require 'name-of-gem' in your model.
(If that gives you errors you may be using an older version of Ruby, so you'll have to write :require => false instead of require: false)
I think you should fork this gem and add a namespace to Timeout module like this:
require "timeout"
module NewTimeout
module Timeout
#overwrited stuff
end
end
And then use it in your gem directly:
NewTimeout::Timeout.timeout()
Or include in your class:
class SomeClass
include NewTimeout::Timeout
end
And default Timeout module left unchanged
This is not possible without cooperation of the gem author.
When you require a file, the code in the file gets run. Period. If the code in the file monkeypatches a class or modifies the global namespace or whatever, that will happen. Period.
You can use load instead of require which allows you to evaluate the file within the context of an anonymous module. But, of course, using the namespace operator :: the code in the file can still get access to the global namespace and every module and class in it, by just doing something like class ::String; def length; 42 end end.
Now, if the gem author published his gem as a refinement, then you would at least be able to limit the effects to a single script body:
string_with_upper_reverse.rb:
module UpperReverse
def reverse
super.upcase
end
end
module StringWithUpperReverse
refine String do
prepend UpperReverse
end
end
puts 'Hello'.reverse
# olleH
using StringWithUpperReverse
puts 'Hello'.reverse
# OLLEH
test.rb:
puts 'Hello'.reverse
# olleH
require_relative 'string_with_upper_reverse'
puts 'Hello'.reverse
# olleH
using StringWithUpperReverse
puts 'Hello'.reverse
# OLLEH
require_relative 'required'
required.rb:
puts 'Hello'.reverse
# olleH
using StringWithUpperReverse
puts 'Hello'.reverse
# OLLEH
As you can see, neither requireing nor being required by a script which is using the refinement will mean that the refinement is visible inside your script. Only explicitly using the refinement inside a script body will make the refinement visible only from that point on and only within that one script body.
Note, however, that refinements are an experimental feature: their API may change without notice in future versions of Ruby, they may even be removed altogether.
Note also that the version of refinements that ships with Ruby 2.0.0 (and also current development versions of Ruby 2.1) can only be scoped to script bodies. The ability to be scoped to module and class bodies was removed shortly prior to the release of Ruby 2.0.0, together with the Module#using method.
And lastly, note that Object#send ignores refinements:
require_relative 'string_with_upper_reverse'
using StringWithUpperReverse
puts 'Hello'.reverse
# OLLEH
puts 'Hello'.send(:reverse)
# olleH