Iconv Deprecation Warning with Ruby 1.9.3

How to address DEPRECATION WARNING: ActiveSupport::Memoizable is deprecated and will be removed in future releases?

I traced this down to this rails issue (specifically this comment) and this carrierwave issue.

The solution is to upgrade carrierwave:

Gemfile diff

-gem 'carrierwave', '~> 0.5.8'
+gem 'carrierwave'

Remember to run bundle update.

UTF-8 conversion not working with String#encode but Iconv

In your call to String#encode you don’t specify a source encoding. Ruby is using the strings current encoding as the source, which appears to be UTF-8, and according to the docs:

Please note that conversion from an encoding enc to the same encoding enc is a no-op, i.e. the receiver is returned without any changes, and no exceptions are raised, even if there are invalid bytes.

In other words the call has no effect, and leaves the bytes in the string as they are, encoded as ISO-8859-1. The next call to gsub then tries to interpret these bytes as UTF-8, and since they are invalid (they are unchanged from ISO-8859-1) you get the error you see.

String#encode has a a form that accepts the source encoding as the second parameter, so you can explicitly specify it, similarly to what you are doing with Iconv. Try this:

git_log = git_log.encode(Encoding::UTF_8,
Encoding::ISO_8859_1,
:invalid => :replace,
:undef => :replace,
:replace => '')

You could also use the ! form in this case, which has the same effect:

git_log.encode!(Encoding::UTF_8,
Encoding::ISO_8859_1,
:invalid => :replace,
:undef => :replace,
:replace => '')

Tracing dependency loading in Rails

So, it's probably a little moot because I'm not likely to ever run into the problem again (and the css_parser gem was the only iconv-requiring gems in my current Rails 3.1/Ruby 1.9.3 projects).

But it was a puzzle, so I wanted to find some way of solving it.

The problem is very iconv-specific in this case. There are other ruby deprecations, but for the most part they seem to go through Kernel#warn (if ruby) or rb_warn() (if C) - but the warning in iconv.c is a little different than the others - at any rate it's a puts to rb_stderr.

So maybe I can do the following

  1. Override Kernel#require to capture stderr
  2. Check for an iconv message after calling the original Kernel#require
  3. Raise an exception if the message found, thereby getting a trace
  4. Do this before bundler runs if at all possible.

It turns out I can't do #4 - because Bundler calls Kernel.require directly - but I can use Bundler to parse the Gemfile to give me a list of things to require myself.

So this is what I get - thanks to this stack overflow post for a pointer on capturing standard error - and the rubygems source for the idea on aliasing the original Kernel#require

# override Kernel#require to intercept stderr messages on require
# and raise a custom error if we find one mentioning 'iconv'
require "stringio"

class RequireError < StandardError
end

module Kernel

alias :the_original_require require
private :the_original_require

def capture_stderr
# The output stream must be an IO-like object. In this case we capture it in
# an in-memory IO object so we can return the string value. You can assign any
# IO object here.
previous_stderr, $stderr = $stderr, StringIO.new
yield
$stderr.string
ensure
# Restore the previous value of stderr (typically equal to STDERR).
$stderr = previous_stderr
end

def require(name)
captured_output = capture_stderr do
the_original_require(name)
end

if(captured_output =~ %r{iconv})
raise RequireError, 'iconv requirement found'
end
end
end

require 'bundler'

# load the list of Bundler requirements from the Gemfile
required_libraries = Bundler.definition.dependencies.map(&:name)

# loop through and require each, ignoring all errors other than
# our custom error

required_libraries.each do |requirement|
begin
require(requirement)
rescue Exception => e
if(e.class == RequireError)
raise e
end
end
end

And voila! A trace message that helps track down where the iconv requirement was.

In the end, probably just a search for "require 'iconv'" is still best (once it's clear that's the what was causing the error).

But, as in life. Some Yaks Must Be Shaved.



Related Topics



Leave a reply



Submit