How to know if a module is defined in Rails? - ruby-on-rails

In Ruby it's easy to see if a module is defined:
defined? MyModule
But in Rails, when you do that Rails tries to load the module (from autoload paths, etc.). So if it does not exists, it throws an error instead of returning false.
I could do
do
defined? MyModule
rescue
# false
end
But it there a better way ?

What version of Ruby and Rails are you using? When I try this, no error is thrown:
ruby-1.9.3-p0 :1 > defined? Rails
=> "constant"
ruby-1.9.3-p0 :2 > defined? NotAConstant
=> nil

Related

Zeitwerk doesn't requires lib classes properly in Rails 6.1.6

I'm trying to update my app from Rails 5.2 to 6.1, and use Zeitwerk autoload, and I am having some issues for autoloading /lib classes.
I included this in config/application.rb:
config.load_defaults 5.2
config.autoloader = :zeitwerk
config.enable_dependency_loading = true
config.autoload_paths += Dir[Rails.root.join('lib/**/*')]
config.eager_load_paths += Dir[Rails.root.join('lib/**/*')]
And, when I run zeitwerk:check, it alerts me that:
Hold on, I am eager loading the application.
expected file lib/facades/coconut/v2/foo.rb to define constant Foo
It is declared as:
# /lib/facades/coconut/v2/foo.rb
module Coconut
module V2
class Foo
# ...
end
end
end
When I try to debug it (putting a binding.pry in some test file), Zeitwerk says it do not defined, until I call it without modules (namespaces):
[1] pry(#<#filename>)> Coconut::V2::Foo
NameError: uninitialized constant Coconut::V2::Foo
from (pry):1:in `setup`
[2] pry(#<#filename>)> Foo
Zeitwerk::NameError: expected file /my-app/lib/api/coconut/v2/foo.rb to define constant Foo, but didn't
from /usr/local/bundle/gems/zeitwerk-2.5.4/lib/zeitwerk/loader/callbacks.rb:25:in `on_file_autoloaded'
[3] pry(#<#filename>)> Coconut::V2::Foo
=> Coconut::V2::Foo
It sounds really strange, because there are another classes in /lib that follows the same structure, but it works well, example
# /lib/api/services/youtube/client.rb
module Services
module Youtube
class Client
# ...
end
end
end
Inspecting it with binding.pry in some test:
pry(#<#filename>)> Services::Youtube::Client
=> Services::Youtube::Client
Has anyone had this problem or know what could be happening?
System:
ruby 2.7.6p219
Rails 6.1.6
Zeitwerk (2.5.4)
An autoload path is a root directory, not its contents.
You need to remove the wildcards as documented here.

Ruby 2.3 load method doesn't return classes loaded anymore - Returns boolean instead

I am migrating a project from Ruby 1.8.7 to Ruby 2.3 and rails from 2 to 4.
I have this code which was working in 1.8.7
class_list = []
original_mechanism = ActiveSupport::Dependencies.mechanism
ActiveSupport::Dependencies.mechanism = :load
begin
class_list += load("/tmp/abc.rb")
rescue Exception => e
debug e.backtrace
end
ActiveSupport::Dependencies.mechanism = original_mechanism
my sample file abc.rb
class Abc
def ...
end
class Def
...
end
In Ruby 1.8.7 class_list is [Abc,Def]
In Ruby 2.3 class_list is [true] - (I had to change the line to 'class_list << load("/tmp/abc.rb")' to make it give this output )
Any of you know how to make it return the old way? All I want is the ClassNames of the classes loaded at the end.
This is not Ruby. Ruby's load always returned true, both in 1.8.7 and 2.3.1. However, there's ActiveSupport load that uses load_dependency (http://apidock.com/rails/v3.0.0/ActiveSupport/Dependencies/Loadable/load_dependency) which does return new constants defined in the file.
Can you try to use load_dependency instead of load here?

undefined method `valid_xml?'

I am new to ruby. I keep getting undefined method 'valid_xml'? What am I doing wrong?
require 'rexml/document'
include REXML
begin
good_xml = %{
<groceries>
<bread>Wheat</bread>
<bread>Quadrotriticale</bread>
</groceries>}
puts(good_xml)
valid_xml?(good_xml)
puts("good read")
rescue Exception => e
puts(e.message)
end
and here is the output
-bash-4.1$ ruby test.rb
<groceries>
<bread>Wheat</bread>
<bread>Quadrotriticale</bread>
</groceries>
undefined method `valid_xml?' for main:Object
Here is the ruby version I have
ruby 1.8.7 (2009-12-24 patchlevel 248) [x86_64-linux]
valid_xml? is not defined in REXML (and neither did you define it). You could define it like this:
def valid_xml?(xml)
REXML::Document.new(xml)
true
rescue REXML::ParseException
false
end

Error using Log4r

I have a problem using Log4r.
uninitialized constant Log4r::Logger::RootLogger
I tried this, but still got an error:
>> require "log4r"
=> true
>> Log4r::DEBUG
NameError: uninitialized constant Log4r::DEBUG
>> Log4r::Logger.root
=> uninitialized constant Log4r::Logger::RootLogger
from /var/lib/gems/1.9.1/gems/log4r-1.1.11/lib/log4r/staticlogger.rb:5:in `root'
from (irb):5
from /usr/bin/irb:12:in `<main>'
Your problem with Log4r::Logger.root is version depending (the actual version 1.1.11 has this problem).
You may use the previous log4r-version 1.1.10:
gem 'log4r', '<=1.1.10' #or '= 1.1.10'
require 'log4r'
Log4r::Logger.root
log4r defines the constants like Log4r::DEBUG with the creation of the first logger.
You need a Log4r::Logger.new('dummy') before you have access to the level constants.
require 'log4r'
p defined? Log4r::INFO #false
Log4r::Logger.new('dummy')
p defined? Log4r::INFO #constant -> is defined
Some background:
There is a constant Log4r::Log4rConfig::LogLevels defining the different levels. The level-constants are defined, when the first logger is created. You may define them also with Log4r.define_levels(*Log4r::Log4rConfig::LogLevels)
This technique allows it to create loggers with different logging levels.
AlthoughLog4r::Logger.root no longer enables the constants, the code included later on in the answer you referred to does introduce the constants:
Log4r.define_levels(*Log4r::Log4rConfig::LogLevels)
per the following:
MacbookAir1:so1 palfvin$ irb
2.0.0p247 :001 > require 'log4r'
=> true
2.0.0p247 :002 > Log4r.define_levels(*Log4r::Log4rConfig::LogLevels)
=> 5
2.0.0p247 :003 > Log4r::DEBUG
=> 1
2.0.0p247 :004 >

Ruby: How to make a public static method?

In Java I might do:
public static void doSomething();
And then I can access the method statically without making an instance:
className.doSomething();
How can I do that in Ruby? this is my class and from my understanding self. makes the method static:
class Ask
def self.make_permalink(phrase)
phrase.strip.downcase.gsub! /\ +/, '-'
end
end
But when i try to call:
Ask.make_permalink("make a slug out of this line")
I get:
undefined method `make_permalink' for Ask:Class
Why is that if i haven't declared the method to be private?
Your given example is working very well
class Ask
def self.make_permalink(phrase)
phrase.strip.downcase.gsub! /\ +/, '-'
end
end
Ask.make_permalink("make a slug out of this line")
I tried in 1.8.7 and also in 1.9.3
Do you have a typo in you original script?
All the best
There is one more syntax which is has the benefit that you can add more static methods
class TestClass
# all methods in this block are static
class << self
def first_method
# body omitted
end
def second_method_etc
# body omitted
end
end
# more typing because of the self. but much clear that the method is static
def self.first_method
# body omitted
end
def self.second_method_etc
# body omitted
end
end
Here's my copy/paste of your code into IRB. Seems to work fine.
$ irb
1.8.7 :001 > class Ask
1.8.7 :002?>
1.8.7 :003 > def self.make_permalink(phrase)
1.8.7 :004?> phrase.strip.downcase.gsub! /\ +/, '-'
1.8.7 :005?> end
1.8.7 :006?>
1.8.7 :007 > end
=> nil
1.8.7 :008 > Ask.make_permalink("make a slug out of this line")
=> "make-a-slug-out-of-this-line"
Seems to work. Test it out in your irb as well, and see what results you're getting. I'm using 1.8.7 in this example, but I also tried it in a Ruby 1.9.3 session and it worked identically.
Are you using MRI as your Ruby implementation (not that I think that should make a difference in this case)?
In irb make a call to Ask.public_methods and make sure your method name is in the list. For example:
1.8.7 :008 > Ask.public_methods
=> [:make_permalink, :allocate, :new, :superclass, :freeze, :===,
...etc, etc.]
Since you also marked this as a ruby-on-rails question, if you want to troubleshoot the actual model in your app, you can of course use the rails console: (bundle exec rails c) and verify the publicness of the method in question.
I am using ruby 1.9.3 and the program is running smoothly in my irb as well.
1.9.3-p286 :001 > class Ask
1.9.3-p286 :002?> def self.make_permalink(phrase)
1.9.3-p286 :003?> phrase.strip.downcase.gsub! /\ +/, '-'
1.9.3-p286 :004?> end
1.9.3-p286 :005?> end
=> nil
1.9.3-p286 :006 > Ask.make_permalink("make a slug out of this line")
=> "make-a-slug-out-of-this-line"
It's also working in my test script. Nothing wrong with your given code.It's fine.

Resources