I come across this in Rails source code:
class Object
def duplicable?
true
end
end
class NilClass
begin
nil.dup
rescue TypeError
def duplicable?
false
end
end
end
With this code, even after dup is removed from an object, that object responds to duplicable? with true.
I think it can be rewritten to a simpler code like:
class Object
def duplicable?
repond_to?(:dup)
end
end
What is the merit of defining duplicable? using begin...rescue?
What is the merit of defining duplicable? using begin...rescue?
Ruby before 2.4 raised a TypeError when attempting to nil.dup:
$ rbenv local 2.3.0
$ ruby --version
ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15]
$ ruby -e 'p nil.dup'
-e:1:in `dup': can't dup NilClass (TypeError)
from -e:1:in `<main>'
Starting with Ruby 2.4, nil.dup just returns itself:
$ rbenv local 2.4.0
$ ruby --version
ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-darwin15]
$ ruby -e 'p nil.dup'
nil
Putting the method definition inside rescue ensures that the method is only defined for Ruby versions which raise the TypeError.
I think it can be rewritten to a simpler code like: [...]
Simply checking whether the receiver responds to dup doesn't work, because nil – being an Object – does respond to dup, even in 2.3. The TypeError is (was) raised from within Object#dup:
VALUE rb_obj_dup(VALUE obj)
{
VALUE dup;
if (rb_special_const_p(obj)) {
rb_raise(rb_eTypeError, "can't dup %s", rb_obj_classname(obj));
}
// ...
}
nil responds to dup explicitly throwing the TypeError (which has, in turn, nothing to do with NoMethodError.) [Correction: had responded to dup before 2.4, credits go to #Stefan.]
NilClass.instance_method(:dup)
#⇒ #<UnboundMethod: NilClass(Kernel)#dup>
The goal is to respond to duplicable? with false unless NilClass#dup is overwritten by another monkey patcher in the city. [Correction: read “another monkey patcher” as “Matz” :)]
Related
I have plugin that takes attribute from post's front matter and uses it in permalink. Problem is I need to clean up any accents and diacritics from the string before putting it in to the permalink. Ruby on rails has method called parametrize which does exactly what I need but I have no idea how to use it in plugin.
This is plugins code I have:
module JekyllCustomPermalink
class CustomPermalink < Jekyll::Generator
safe true
priority :low
def generate(site)
# nothing to do, wait for hook
end
Jekyll::Hooks.register :documents, :pre_render do |doc|
begin
# check if jekyll can resolve the url template
doc.url
rescue NoMethodError => error
begin
if !doc.collection.metadata.fetch("custom_permalink_placeholders").is_a?(Array)
raise CustomPermalinkSetupError, "The custom placeholders need to be an array! Check the settings of your '#{doc.collection.label}' collection."
end
def doc.url_template
#custom_url_template ||= collection.metadata.fetch("custom_permalink_placeholders").inject(collection.url_template){|o,m| o.sub ":" + m, data[m].to_s.parameterize}
end
rescue KeyError
# "custom_permalink_placeholders"
raise CustomPermalinkSetupError, "No custom placeholders defined for the '#{doc.collection.label}' collection. Define an array of placeholders under the key 'custom_permalink_placeholders'. \nCaused by: " + error.to_s
end
end
end
end
end
but I get this error:
john#arch-thinkpad ~/P/blog (master)> bundle exec jekyll serve --trace
Configuration file: /home/john/Projects/lyricall/_config.yml
Source: /home/john/Projects/lyricall
Destination: /home/john/Projects/lyricall/_site
Incremental build: disabled. Enable with --incremental
Generating...
Jekyll Feed: Generating feed for posts
Liquid Exception: undefined method `parameterize' for "Žďořšťáčik":String in feed.xml
bundler: failed to load command: jekyll (/home/john/.gem/ruby/3.0.0/bin/jekyll)
/usr/lib/ruby/gems/3.0.0/gems/jekyll_custom_permalink-0.0.1/lib/jekyll_custom_permalink/custom_permalink.rb:20:in `block in url_template': undefined method `parameterize' for "Žďořšťáčik":String (NoMethodError)
What am I doing wrong ? How can I use this method which should be part of a string class but apparently it is not ? How can I achieve same result without ruby on rails framework ?
INFO:
jekyll 4.1.1
ruby 3.0.1p64 (2021-04-05 revision 0fb782ee38) [x86_64-linux]
Thank you for help
Rails additions to base Ruby classes, like String#parameterize, are part of the Active Support Core Extensions. The activesupport gem can be installed and used independent of Rails.
To keep the default footprint low, ActiveSupport allows you to require only the individual extensions you want to use. In your case, you will need to require the string inflection extensions:
require 'active_support/core_ext/string/inflections'
"Kurt Gödel".parameterize
=> "kurt-godel"
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?
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
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.
I don't know why I get this error. Both methods are corrects.
hydra = Typhoeus::Hydra.new
hydra.cache_getter do |request|
Rails.cache.read(request.cache_key) rescue nil
end
hydra.cache_setter do |request|
Rails.cache.write(request.cache_key,request.response, expires_in: request.cache_timeout)
end
ruby 1.9.2p320 (2012-04-20 revision 35421) [x86_64-darwin11.4.2]
Rails 3.2.8
You are getting that error because those methods do not exist on an instance of Typhoeus::Hydra. You can find the full list of available methods at http://rubydoc.info/gems/typhoeus/0.5.0/frames
Update
Those methods were removed between versions 0.4.2 and 0.5.0 via this commit