Rake task occasionally fails, undefined error - ruby

I check out a fresh commit in a repo that works for everyone else. I run a rake task, which calls this code and throws an undefined error, even though Gem.source_index appears to be defined.
module Gem
puts "in module Gem"
def self.source_index=(index)
puts "defining the source index"
##source_index = index
end
end
module Rails
class GemDependency < Gem::Dependency
attr_accessor :lib, :source, :dep
def self.add_frozen_gem_path
puts "Oh hi there"
puts "the source index is " + Gem.source_index // ERROR HERE
end
The output is
in module Gem
Oh hi there
rake aborted!
undefined method `source_index' for Gem:Module
What's wrong?

Gem.source_index was deprecated in Ruby 1.9 and removed in Ruby 2.0*. I suspect you're using Ruby 2.0 now, which would give you that exact error.
Note that you do define a setter for it, but not a getter.
(* Technically it's probably tied to a specific version of Rubygems rather than Ruby. A 1.9.3 installation with an upgraded rubygems installation would amount to the same thing.)

Related

Method name is in list returned by Object#singleton_methods but not accessible using Object#singleton_method

I'm confused with the difference between Object#singleton_method and Object#singleton_methods.
I thought that the result in Object#singleton_methods is the true set of !!Object#singleton_method(:name), but it seems to be different.
Here is the example script:
require "active_support/deprecation"
# [:debug=, :debug]
ActiveSupport::Deprecation.singleton_methods(false).grep(/debug/)
# [:debug=, :debug]
ActiveSupport::Deprecation.singleton_methods.grep(/debug/)
begin
ActiveSupport::Deprecation.singleton_method(:debug) # exception
rescue => e
puts e.backtrace
raise
end
Gemfile is
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
# gem "rails"
gem 'activesupport', '5.1.6'
The result is this:
% bundle install
Fetching gem metadata from https://rubygems.org/..............
Resolving dependencies...
Using concurrent-ruby 1.0.5
Using i18n 1.0.0
Using minitest 5.11.3
Using thread_safe 0.3.6
Using tzinfo 1.2.5
Using activesupport 5.1.6
Using bundler 1.16.1
Bundle complete! 1 Gemfile dependency, 7 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
% bundle exec ruby test.rb
test.rb:8:in `singleton_method'
test.rb:8:in `<main>'
Traceback (most recent call last):
1: from test.rb:8:in `<main>'
test.rb:8:in `singleton_method': undefined singleton method `debug' for `ActiveSupport::Deprecation' (NameError)
I expected that ActiveSupport::Deprecation.singleton_method(:debug) would return #<Method: ActiveSupport::Deprecation.debug>, but raise exception.
I don't understand why. Of course, I know the basic usage in singleton_method and singleton_methods:
# everything is OK!
class Sample; end
class << Sample
def test_method; end
end
# These two expressions behave as I expect.
## [:test_method]
Sample.singleton_methods(false).grep(/test_method/)
## #<Method: Sample.test_method>
Sample.singleton_method(:test_method)
Thanks.
Update: It looks like this is a bug in Ruby. Vasiliy Ermolovich has created an issue along with a patch to address it. The fix has already been merged so this will be resolved in an upcoming update.
This isn't a full answer to your question I'm afraid, but after a bit of digging I've been able to make a minimal example that demonstrates the same thing without the dependency on Active Support. I thought this might still be useful to you for your investigations, or might help someone else who can come along with a complete explanation.
It appears that the unexpected behaviour of singleton_method comes from use of Module.prepend which ActiveSupport::Deprecation uses here.
The same error can be seen with this small example:
module Empty; end
class MyClass
singleton_class.prepend(Empty)
def self.my_method
puts "my method called"
end
end
p MyClass.singleton_methods(:false)
m = MyClass.singleton_method(:my_method)
m.call
Running this gives:
❯ ruby example.rb
[:my_method]
Traceback (most recent call last):
1: from example.rb:11:in `<main>'
example.rb:11:in `singleton_method': undefined singleton method `my_method' for
`MyClass' (NameError)
With the call to prepend removed this runs as you would expect:
❯ ruby example.rb
[:my_method]
my method called

Rails legacy app and Ruby 2 error: can not load translations from the file type yml is not known

I have a legacy Rails application which I want to upgrade to recent Rails and Ruby versions.To start with I am trying to setup the application with Ruby 2.1.2
$ rails -v
Rails 2.3.18
$ ruby -v
ruby 2.1.2p95 (2014-05-08 revision 45877) [i686-linux]
When I tried to run the rake task rake db:schema:load RAILS_ENV=test I encountered following error
can not load translations from /activesupport-2.3.18/lib/active_support/locale/en.yml, the file type yml is not known
Searching through Google I found the following reference https://github.com/rails/rails/issues/10514 which mentioned that there is incompatibility between Rails 2.3 and Ruby 2+ versions.
Can anybody please help me applying a monkey-patch mentioned about in the reference link?
Thanks,
Jignesh
Finally resolved the error
can not load translations from /activesupport-2.3.18/lib/active_support/locale/en.yml, the file type yml is not known
by monkey-patching the Rails’s I18n::Backend::Base#load_file(filename) method.
The solution is as follows:
1.1 Created a file named ruby2.rb at /config/initializers
1.2 Added following contents to /config/initializers/ruby2.rb
if Rails::VERSION::MAJOR == 2 && RUBY_VERSION >= '2.0.0'
module I18n
module Backend
module Base
def load_file(filename)
type = File.extname(filename).tr('.', '').downcase
# As a fix added second argument as true to respond_to? method
raise UnknownFileType.new(type, filename) unless respond_to?(:"load_#{type}", true)
data = send(:"load_#{type}", filename) # TODO raise a meaningful exception if this does not yield a Hash
data.each { |locale, d| store_translations(locale, d) }
end
end
end
end
end
1.3 Finally ran
$ rake db:schema:load RAILS_ENV=test
and the schema was successfully loaded.
Most helpful references I could find and which helped me get to the solution:
https://github.com/rails/rails/issues/10514
https://www.lucascaton.com.br/2014/02/28/have-a-rails-2-app-you-can-run-it-on-the-newest-ruby/

Time methods in Ruby

I'm trying to understand how method invocation works in Ruby objects. Ruby docs list a bunch of methods to execute on ruby objects. When I try one of them
puts RUBY_VERSION
puts Time.new(2008,6,21, 13,30,0, "+09:00").utc.seconds_since_midnight
I get the following output
1.9.3
bin/musor.rb:14:in `<main>': undefined method `seconds_since_midnight' for 2008-06-21 13:30:00 +0900:Time (NoMethodError)
What's wrong with the call I make?
seconds_since_midnight is Time extension added by rails. If you want to use it, you will need to add require 'activesupport/core_ext' and install activesupport gem first.

How to "require" manually installed gems (KDE plasmoid)?

I'm trying to write a Ruby plasmoid for KDE. I need to use barely one rubygem. Whenever I write require 'dbus', it throw me and an error:
code/main.rb:6:in 'require': no such file to load -- dbus (LoadError)
code/main.rb:6:in '<module:TestApp>'
code/main.rb:5:in '<top (required)>'
/usr/share/apps/plasma_scriptengine_ruby/applet.rb:177:in 'load'
/usr/share/apps/plasma_scriptengine_ruby/applet.rb:177:in 'init'
/usr/share/apps/plasma_scriptengine_ruby/applet.rb:201:in 'constraintsEvent': undefined method 'constraintsEvent' for nil:NilClass (NoMethodError)
/usr/share/apps/plasma_scriptengine_ruby/applet.rb:201:in 'constraintsEvent': undefined method 'constraintsEvent' for nil:NilClass (NoMethodError)
Actually, normal "ruby main.rb" works well (regarding on "require" part), but testing plasmoid with "plasmoidviewer" fails. Note, that regular gems from standart Ruby installation works well, i.e. require 'Qt4' or require 'yaml' loads perfectly. I'm using Ruby 1.9.2p180 under Linux.
09:40 PM - UPDATE: Richard Dale, one of the QtRuby developers, just fixed this issue a few minutes ago. Next release of KDE will have patched version of QtRuby.
require 'find'
require 'findUtils'
Find.find(PATH_WHERE_GEM_IS_INSTALLED) do |path|
if FileTest.directory?(path)
$: << File.expand_path(path)
if File.basename(path)[0] == ?. and File.basename(path) != '.'
Find.prune
else
next
end
else
end
end
and after that you can do
require 'dbus'
Have you tried this:
require 'rubygems'
?

Check for Ruby Gem availability

Is there a way to check if some gem is currently installed, via the Gem module? From ruby code, not by executing 'gem list'...
To clarify - I don't want to load the library. I just want to check if it's available, so all the rescue LoadError solutions don't help me. Also I don't care if the gem itself will work or not, only whether it's installed.
In Ruby 1.9.3 only there is also:
Gem.available?('somegem')
You can use regex expressions too. Handy if I want to allow 'rcov' and GitHub variants like 'relevance-rcov':
Gem.available?(/-?rcov$/)
Looking at the Gem API documentation, using Gem::Specification::find_all_by_name to test for gem availability seems reasonable.
if Gem::Specification::find_all_by_name('gemname').any?
do stuff
end
find_all_by_name always returns an array (of Specification objects), as opposed to find_by_name which raises an exception if no match is found.
IMHO the best way is to try to load/require the GEM and rescue the Exception, as Ray has already shown. It's safe to rescue the LoadError exception because it's not raised by the GEM itself but it's the standard behavior of the require command.
You can also use the gem command instead.
begin
gem "somegem"
# with requirements
gem "somegem", ">=2.0"
rescue Gem::LoadError
# not installed
end
The gem command has the same behavior of the require command, with some slight differences. AFAIK, it still tries to autoload the main GEM file.
Digging into the rubygems.rb file (line 310) I found the following execution
matches = Gem.source_index.find_name(gem.name, gem.version_requirements)
report_activate_error(gem) if matches.empty?
It can provide you some hints about how to make a dirty check without actually loading the library.
Since Gem.available? is deprecated (argh!), you have to rescue again (double aaargh). Yes, find_by_name throws an exception if the gem is not found. So to be backwards-compatible with older rubygems, the common solution seems to be :
def gem_available?(name)
Gem::Specification.find_by_name(name)
rescue Gem::LoadError
false
rescue
Gem.available?(name)
end
Note that the new method allows you to pass a specific version to see if that's loaded:
Gem::Specification.find_by_name('rails', '3.0.4')
You could:
begin
require "somegem"
rescue LoadError
# not installed
end
This wouldn't, however, tell you if the module was installed through gem or some other means.
I use this code and it works smoothly.
def gem_available?(gem_name, version = nil)
version.nil? gem(gem_name) : gem(gem_name, version)
rescue Gem::LoadError
false
end
Examples to use
Let's assume you have rack 1.9.1 installed.
puts gem_available?('rack') # => true
puts gem_available?('rack', '>=2') => # false
Didn't see this anywhere here, but you can also pass fuzzy version strings to find_by_name and find_all_by_name:
Gem::Specification.find_all_by_name('gemname', '>= 4.0').any?

Resources