What is the purpose of Ruby's unknown class? - ruby

I was looking through the Ruby Core API and noticed "unknown" at the bottom of the Classes list. When you go to that class's page at https://ruby-doc.org/core-2.6.1/unknown.html, you will notice that there is no content.
What is the purpose of this class, i.e. when and how would you use it? If there is no purpose, why is it documented on ruby-doc.org?

It looks like this is some kind of artifact of the documentation system and not an actual class in Ruby.
The documentation is produced by parsing the Ruby source code and can often get a little confused about what it's seeing. There's ways of coaching it with additional comments to ignore things it shouldn't document and so on, but tracking down which particular file or line produced this "unknown" reference is not necessarily easy.
You may want to report this as a bug in the documentation. That page isn't helpful, and is more confusing than anything.

There is no unknown class in Ruby. To prove #tadman's point simply run an IRB console:
irb(main):006:0> NilClass
=> NilClass
irb(main):007:0> Object
=> Object
irb(main):008:0> ZeroDivisionError
=> ZeroDivisionError
irb(main):009:0> Unknown
NameError: uninitialized constant Unknown
irb(main):010:0> unknown
NameError: undefined local variable or method `unknown' for main:Object

Related

Where is OpenStruct#attributes coming from? Or how can I find where how a method has been added?

I have a gemfile that includes activerecord, therefore I have .attributes which I can call on my model instances to convert them to hashes.
Through a mix up in my code I ended up passing a OpenStruct instead of a model into one of my methods and got a hard-to-find bug. The cause was that OpenStruct#attributes was returning nil (and not throwing an error, which would have alerted me to the problem).
I have no idea how OpenStruct#attributes is being defined.
[2] pry(main)> show-source OpenStruct#attributes
Error: Couldn't locate a definition for OpenStruct#attributes!
...
(byebug) OpenStruct.new.method(:attributes)
*** NameError Exception: undefined method 'attributes' for class `OpenStruct'
...
(byebug) OpenStruct.new.attributes
nil
How can I find what this method's source code is and how it's being included?
I have a hunch that it's being done with method-missing somewhere, that's why it's so hard to track down. But is it possible to do so?
To clearify a bit, it's not a new method (though it behaves like one).
In ruby 2.4 I inspected, method_missing in ostruct.rb handles call like attr= and attr without defining new methods. Some classes do define method on first use, but OpenStruct is not one of them.
If you can't get it with #method, it's #method_missing. And that is a method like any else, so you can find the source the same way:
OpenStruct.instance_method(:method_missing).source_location
# => ["/Users/wink/.rbenv/versions/2.3.3/lib/ruby/2.3.0/ostruct.rb", 189]
Link to Github
The method attributes is not defined on the OpenStruct, it is just how method_missing works.

What is the private method Object#select?

Like many others, I saw the exception
private method 'select' called for nil:NilClass (NoMethodError)
go by. What struck me as odd is that it didn't say undefined method 'select' for nil:NilClass (NoMethodError). There was indeed such a method, and it was private!
What is this method?
I've found that it's defined on Object, and not just NilClass, but it's not defined on BasicObject. By using #send, I've found that it takes 1..4 arguments. The first three must be an array (or nil). And the last one must be convertible to a "time interval". In any case, when it doesn't throw an argument error, it hangs.
It's not in the ruby documentation because it's private. I don't really know how to read the C source code, and I haven't been able to find anything suggestive there. I expected to see something like the following line in object.c;
rb_define_private_method(rb_cObject, "select", select, 0);
But alas, I cannot.
What is this method?
It's Kernel#select. Per the docs for the Kernel module:
The Kernel module is included by class Object, so its methods are available in every Ruby object.
And in case you're curious what select does:
select(read_array [, write_array [, error_array [, timeout]]]) → array or nil
Calls select(2) system call. It monitors given arrays of IO objects, waits until one or more of IO objects are ready for reading, are ready for writing, and have pending exceptions respectively, and returns an array that contains arrays of those IO objects.
You can read more background on why Object includes Kernel in the answer to this question: Why does the Ruby module Kernel exist?
You can check where method comes from using Object#method and Method#owner:
nil.method(:select)
#=> #<Method: NilClass(Kernel)#select>
nil.method(:select).owner
#=> Kernel
So it is Kernel#select

Rails: How do I require NumberHelper and make it work?

I'm trying to write a simple Sinatra thingy but I need ActionView::Helpers::NumberHelper from action pack.
http://api.rubyonrails.org/classes/ActionView/Helpers/NumberHelper.html
The question is, how do I install and use it?
irb(main):001:0> require 'action_view/helpers/number_helper'
irb(main):002:0> number_with_precision(1)
NoMethodError: undefined method `number_with_precision' for main:Object
irb(main):004:0> ActionView::Helpers::NumberHelper.number_with_precision(1)
NoMethodError: undefined method `number_with_precision' for ActionView::Helpers::NumberHelper:Module
Why doesn't this simple step work?
Moreover, if I require all the crap:
irb(main):001:0> require 'action_pack'
irb(main):004:0> require 'action_view'
irb(main):005:0> include ActionView::Helpers::NumberHelper
irb(main):006:0> number_to_phone(12345)
NoMethodError: undefined method `starts_with?' for "12345":String
How to make sense from all of this? Why does not this module work? Why doesn't it require whatever it needs? What does it need? Where is starts_with?
Google is utterly silent on those questions.
UPD: And now I get the following
number_with_precision(1, :locale => 'fr')
TypeError: wrong argument type nil (expected Fixnum)
It seems to me that my NumberHelper is broken. This isn't a good behavior.
So, after doing a bit of research, I found the following pull request on the master branch of Rails
https://github.com/rails/rails/pull/6315
It pretty much aims to move ActionView::Helpers::NumberHelper from ActionView to ActiveSupport
I also saw a few closed issues that aimed to fix a few problems with allowing inclusion of NumberHelper as standalone. This means require fixes and such. I didn't find an open issue with the number_to_phone but the problem roots at the fact that ActiveSupport adds an alias starts_with? to the String class. I'm not sure if they have caught that bug there yet or not.
In any case, with ActionView version 3.2.13 you can do the following
require 'action_view'
include ActionView::Helpers::NumberHelper
number_with_precision 3.1
#=> "3.100"
As for the number_to_phone, that will still break with the current version. I'm making a PR to fix that issue at this moment.
EDIT
As for the locale issue, it seems that if you specify a local you need to have set the right options in the I18n for it to work. If you don't provide a locale the defaults will look like this {:separator=>".", :delimiter=>"", :precision=>3, :significant=>false, :strip_insignificant_zeros=>false}, otherwise, the hash will be empty and it will cause issues. I can't seem to find any issues about it on Rails though.
Again, this was fixed on a PR on master https://github.com/carlosantoniodasilva/rails/commit/f6b71499e967e03c65d53cc890585f42f3b8aaa2
UPDATE
You can use ActiveSupport now to use these helpers
http://api.rubyonrails.org/classes/ActiveSupport/NumberHelper.html
It changed recently:
require "active_support/all"
module Helpers
extend ActiveSupport::NumberHelper
end
Helpers.number_to_currency(10.23) # => "$10.23"

Ruby: How to handle a Failed or Invalid Initialization

What is the ruby best practice for handling a situation in which an object should fail to initialize owing to being passed invalid initialize arguments?
I realize that in ruby, duck typing means that we're not supposed to be overly concerned with what variable/parameters types but rather concern ourselves with how they behave. However, I am working in MacRuby which is bridged over the Cocoa Objective-C API and some of the Cocoa methods expect typed parameters.
For example, I have a ruby class that calls into the Objective-C API and must pass it an object of the NSURL class. It looks something like this:
class Alpha
attr_accessor :model
def initialize(hopefully_a_NSURL)
# bridged from Objective-C API
#model=NSManagedObjectModel.alloc.initWithContentsOfURL(hopefully_a_NSURL)
end # initialize
end
... and I would call it like so:
#bridged from Objective-C API
u=NSURL.fileURLWithPath(p)
a=Alpha.new(u)
puts "a=#{a.model}" # => a=#<NSManagedObjectModel:0x2004970e0
>
... which works nicely.
However, if I were to slip up:
a=Alpha.new("Whoops, a string not a NSURL" )
... it explodes messily with errors coming from the depths of the Objective-C API.
I can, of course, put in test that will prevent bad parameter for reaching the bridged objects:
class Alpha
attr_accessor :model
def initialize(hopefully_a_NSURL)
if hopefully_a_NSURL.class==NSURL
#model=NSManagedObjectModel.alloc.initWithContentsOfURL(hopefully_a_NSURL)
end
end # initialize
end
u=NSURL.fileURLWithPath(p)
a=Alpha.new("")
puts "a=#{a}" # => a=#<Alpha:0x200399160>
... but I still get a live instance back. I even tried returning nil from initialize but it seems that ruby insist on always returning a live instance.
Everything I've read says that type checking is heavily frowned upon in ruby but perhaps I will have to make an exception in the case of MacRuby. Would this be a good use of exceptions in ruby or is there a more elegant solution? I'm a noob in ruby so assume I am approaching the problem from the wrong perspective.
I'd try to convert the argument and raise a TypeError if no conversion was possible:
Raised when encountering an object that is not of the expected type.
[1, 2, 3].first("two")
raises the exception:
TypeError: can't convert String into Integer
The Ruby core and standard libraries do it so there's no reason you can't do it too. The Ruby core will raise exceptions when you do something you're not supposed to (calling an unsupported method, calling a method with the wrong number of arguments, ...) so throwing a TypeError would make sense. And, if TypeError isn't quite appropriate, there's always ArgumentError.
In your specific case, try to convert the argument to an NSURL by calling to_s and then instantiating an NSURL using that string if they don't give you an NSURL. I don't know my way around MacRuby or the corresponding Mac APIs so I'm sort of guessing on the sensible behavior in this specific case but I think the "convert or raise an exception" idea is sound and sensible.
Of course, you should document the behavior you're going to use in your API documentation too.

Ruby error "Superclass mismatch for for class Cookie" from cgi.rb

I've just updated my ruby installation on my gentoo server to ruby 1.8.6 patchlevel 287 and have started getting an error on one of my eRuby apps. The error given in the apache error_log file is:
[error] mod_ruby: /usr/lib/ruby/1.8/cgi.rb:774: superclass mismatch for class Cookie (TypeError)
The strange thing is that it seems to work sometimes - but other times I get that error. Anyone any ideas?
As the error message says, there is an opening of the Cookie class somewhere in the code that is using a different superclass than the one used in a prior definition or opening of the Cookie class.
Even a class definition that does not explicitly specify a superclass still has a superclass:
class Cookie
end
This defines the Cookie class with the superclass of Object.
I've encountered this error before, and it will occur when you have some code trying to reopen a class without specifying the superclass, and the programmer's assumption is that the class (in this case, Cookie) has already been defined, and that he is simply reopening it to add some functionality. But if the reopening and the definition are in reverse order, you'll get that error because the class will already have been defined as a subclass of Object, but is trying to be redefined or reopened with a different superclass. Try this in irb:
% irb
irb(main):001:0> class C < String; end
=> nil
irb(main):002:0> class C; end
=> nil
irb(main):003:0> exit
% irb
irb(main):001:0> class C; end
=> nil
irb(main):002:0> class C < String; end
TypeError: superclass mismatch for class C
from (irb):2
So, you probably just have to grep for definitions of the Cookie class and try to ensure files are always being require-d in the correct order. This may or may not be easy. :)
That error shows up when you redeclare a class that’s already been declared, most likely because you’re loading two different copies of cgi.rb. See a similar issue in Rails.

Resources