Ruby Monk - Understanding Inheritance - Alternate solution not accepted? - ruby

I have been coding for three or four months (started in Python) and I am just getting into Ruby on account of Rails popularity.
To help build my understanding of the Ruby language, I have been going through the problems on Ruby Monk. The Ruby Primer: Ascent 1.1 - Understanding Inheritance course has the following problem:
Write a method that takes a class and a subclass as arguments and returns a boolean regarding whether or not the subclass is an ancestor of the class.
Here is what I came up with (note: Ruby Monk decided to go with spelling "klass" for "class"):
def is_ancestor?(klass, subclass)
subclass.ancestors.map{ |ancestor| ancestor.to_s }.include? klass.to_s
end
This code passes all tests except for a special one that states doesn't use any other methods to solve the problem (yes, there's a shortcut :)).
I was really vexed as to how to solve this without using other methods, and so I looked at the proposed solution. Here is what Ruby Monk says that answer should be.
def is_ancestor?(klass, subclass)
current_class = subclass
while !current_class.superclass.nil? && current_class != klass
current_class = current_class.superclass
end
current_class == klass
end
I understand this code. What I don't understand is why this code passes the test requirement of not using methods while my code doesn't. After all, the Ruby Monk proposed answer does use methods (see !current_class.superclass.nil).
Am I missing something here? Perhaps I don't really understand what a method is. Perhaps my code does work and is only failing because Ruby Monk is performing tests that match code 1:1.

Maybe they don't want you to use map and include? since they are not methods of classes. They are methods of arrays.
I guess this shall pass the tests.
def is_ancestor?(klass, subclass)
subclass <= klass
end
Well, strictly speaking, <= is also a method.
BTW, if you can compare classes directly, don't compare their names. You original code can be optimized as
def is_ancestor?(klass, subclass)
subclass.ancestors.include? klass
end

Related

How to override Ruby + method?

Just for learning purpose I am trying to override the Ruby + method, but I am not getting the desired output.
class Integer
def +(my_num)
"Plus method overridden"
end
end
puts 5.+(9)
Please let me know what I am doing wrong here.
It seems you use ruby < 2.4. If so you want to patch Fixnum and not Integer. Be careful as the system itself uses numbers as well.
class Fixnum
alias_method :add, :+
def +(other)
puts 'plus method overridden'
add(other)
end
end
puts 5 + 9
The Ruby Language Specification allows Integer to have implementation-specific subclasses. See Section 15.2.8.1, lines 27-33.
It looks like your implementation does have such subclasses. In that case, the + method may be overridden in a subclass.
My best guess is that you have an implementation which distinguishes between Fixnums and Bignums, and that our Integer#+ gets overridden by Fixnum#+.
By the way, even if what you were trying to do were working, it wouldn't be overriding, it would be overwriting.
Also note that if what you were trying to do were working, you would have most likely broken your Ruby process, since Integers are fundamental and widely-used all over the place in Ruby.

Why does `send` fail with Ruby 2.0 refinement?

Why does this not work?
module StringRefinement
refine String do
def bar
length
end
end
end
using StringRefinement
"abcdefghijklmnopqrstuvwxyz".send(:bar)
#NoMethodError: undefined method 'bar' for "abcdefghijklmnopqrstuvwxyz":String
Can someone explain why send doesn't work here? And is there a way to dynamically call methods defined in a refinement? I can't seem to find a good, full explanation of how refinements work in Ruby 2.0.
Because the specification says so:
Indirect method accesses
Any indirect method access such as Kernel#send, Kernel#method, and Kernel#respond_to? shall not honor refinements in the caller context during method lookup.
I am tempted to say "This is by design". But again it's quite possible this design is not entirely stable. For example, the module and class scoping feature has been removed just a few months ago.
At the moment even on Ruby HEAD the only way is to use the root of all evil:
eval "puts 'abcdefghijklmnopqrstuvwxyz'.bar" # => 26
But really, this is just for the lab, right ? Do not unchain such code, kitten would die.

How can I splattify an anonymous object so I can use &method on it?

I'm wanting to use the &method(:method_name) idiom when there's more than one object required by method_name. Can I do this under Ruby 1.9?
For example, if I've got
def move_file(old_filename, new_filename)
STDERR.puts "Moving #{old_filename.inspect} to #{new_filename.inspect}"
# Implementation for careful moving goes here
end
old_filenames = ["foo.txt", "bar.txt", "hoge.ja.txt"]
new_filenames = ["foo_20110915.txt", "bar_20110915.txt", "hoge_20110915.ja.txt"]
the code
old_filenames.zip(new_filenames).each(&method(:move_file))
works under Ruby 1.8, but not under Ruby 1.9. Under Ruby 1.9, it's trying to do move_file(["foo.txt", "foo_20110915.txt"]) instead of move_file("foo.txt", "foo_20110915.txt").
How do I splattify it so it has the correct arity?
Workarounds I'm aware of:
Replace def move_file(old_filename, new_filename) with def move_file(*arguments)
Replace each(&method(:move_file)) with
each{|old_filename, new_filename| move_file(old_filename, new_filename)}
Instead
each{|old_filename, new_filename| move_file(old_filename, new_filename)}
you should be able to do
each{|pair| move_file(*pair)}
But I don't know how you'd pull off blockless variant (I needed it couple of times as well). I guess &-shorthand was made to make the syntax simpler, and is not meant to be clogged much (whether it will be passed an array as an array, or splatted, for example). :)
How do I splattify it so it has the correct arity?
I don't think there is a way to do this while being compatible to both Ruby versions. What you could do is wrap it into a lambda
move_from_to = Proc.new {|*both| move_files(*both) }
The thing is - block and proc arity is something that got addressed in Ruby 1.9 so there might be a difference in behavior there. Also see prc.lambda? here http://www.ruby-doc.org/core/classes/Proc.html for info on what it does to the arity.
This question is also related to what you want to do (the solution there is to resplat and unsplat manually): Inconsistency of arity between Hash.each and lambdas

Array of Types in Ruby

I am trying to create instances of objects of various types by iterating and checking for validity. I need an array of types so I can do something like this:
def tryClasses(in)
types = [Foo::A, Foo::B, Foo::C]
types.each do |type|
a = type.new(in)
return a != null
end
end
How do I create and array of class types?
Doing it this way I am getting a NoMethodError (undefined method 'A' for Foo)
Apart from the obvious syntactic errors (e.g. in is a reseved word, and null is spelled nil in Ruby), the code you showed should work just fine as it is, and indeed it does when I copy&paste it into my Ruby installation. This assumes, of course, that the classes Foo::A, Foo::B and Foo::C actually exist. If they don't, then the code obviously cannot possibly work.
It is, however, completely un-Rubyish and violates just about every coding convention in the book:
indentation is 2 spaces
method names are snake_case, not camelCase
explicitly checking for equality to nil is a no-no, simply calling #nil? is much preferred
try_classes isn't exactly an intention-revealing method name
and WTF does in mean?
Rubyists much prefer higher-order methods over explicit looping
Here's a more Rubyish version of the code you wrote:
def can_create_object?(*args)
[Foo::A, Foo::B, Foo::C].none? do |klass|
klass.new(*args).nil?
end
end
However, note that I am pretty convinced that the whole idea is fundamentally flawed.

rb_str_modify() equivalent in the Ruby language

I was trying to add a method to the String class. This method should mutate the current string (of course it would be possible to write a not mutating version but I'd prefer the mutating one). I had no idea how to do this and after some googling I found the method rb_str_modify which makes a given string mutable. That's exactly what I need but I couldn't find an equivalent in the Ruby language. Did I miss something or is there really no possibility in the language itself?
Reopening Classes
All classes in Ruby are open for extension so you can simply do this ...
Class String
def my_new_method(args)
# Some sort of modification to self
self.replace "SOME CALCULATED VALUE"
end
end
... somewhere in your code. I've modified string a few times in different applications - usually I just put the modifications into one particular module, making it easy to reuse them or remove them as required.
Modifying individual objects
Modifying a class in its entirety is dangerous as it's very difficult to identify all of the consequences - I once broke Merb by modifying a method in the String class. It's much safer to modify particular objects. This is easy in Ruby - you use the extend keyword. You define a module, add your function and then modify the target object. This example ...
module Humor
def tickle
"hee, hee!"
end
end
a = "Grouchy"
a.extend Humor
a.tickle ยป "hee, hee!"
is taken from the Pickaxe book
Chris

Resources