Ruby trying to programatically avoid multiple definitions in subclasses - ruby

Quiet new to ruby I can't figure out something.
Here's a Sample code
class Big
def self.metaclass; class << self; self; end; end
def self.convertor b
metaclass.instance_eval do
define_method( :convert ) do |val|
return b val
end
end
end
end
class Small < Big
convertor { |v| v.to_i + 1 }
end
puts Small.convert('18')
The aim is to have a lot of subclass to Big and i like to avoid to define in each
def convert(val)
return conversion_specific_to_subclass(val)
end
Doing the former way i just have one line for each subclass. But can't get it to work.
What is it i'm doing wrong? Is there a better way to accomplish what i wish?
Thanks in advance
edit: As asked here are the errors this code produce (with ruby 2.1.0)
test2.rb:4:in `convertor': wrong number of arguments (0 for 1) (ArgumentError)
from test2.rb:14:in `<class:Small>'`

You're overcomplicating this - since all you want is the ability to bind a block to a specific method name, just do that!
class Big
def self.converter(&block)
define_singleton_method :convert, &block
end
end
class Small < Big
converter {|v| v.to_i + 1 }
end
That way, when you invoke Small::converter, it will define a class method that accepts a parameter list as defined in your block args, and the return value will be the return value of your block.

Try this code:
class Big
def self.metaclass; class << self; self; end; end
def self.convertor(&b)
metaclass.instance_eval do
define_method( :convert ) do |val|
return b[val]
end
end
end
end
class Small < Big
convertor { |v| v.to_i + 1 }
end
puts Small.convert('18')
There were two problems in your code. One, you have to capture the block using an & argument. So, this is the new method declaration:
def self.convertor(&b)
And finally, you have to call the block using block call syntax in your return, like this:
return b[val]
Or this:
return b.call(val)
You cannot call a block like b val.
Also, it's good style in Ruby to always include the parenthesis everywhere.

Related

Ruby .times method called on an integer. How does it know to iterate through each integer as the argument in a block?

I'm reading the "Pickaxe" ruby book and I came across this example:
def meth_three
100.times do |num|
square = num*num
return num, square if square > 1000
end
end
If you call meth_three in irb it returns the first integer between 1 and 100 that has a square > 1000:
meth_three # => [32, 1024]
My question is, how does the times method know how to loop through each integer between 1..100 to pass as the argument to the |num| parameter?
There are many, many different ways of writing iteration in Ruby.
Here is one possible way that it could be implemented recursively:
class Integer
def times(&blk)
return enum_for(__callee__) unless block_given?
return self unless positive?
pred.times(&blk)
yield pred
end
end
Or, using Range#each:
class Integer
def times(&blk)
return enum_for(__callee__) unless block_given?
return self unless positive?
(0...self).each(&blk)
self
end
end
Or, with a loop:
class Integer
def times
return enum_for(__callee__) unless block_given?
return self unless positive?
i = -1
yield i while (i += 1) < self
self
end
end
And a tail-recursive implementation just for the fun of it:
class Integer
def times(&blk)
return enum_for(__callee__) unless block_given?
return self unless positive?
__times_rec(0, &blk)
self
end
private def __times_rec(i, &blk)
return unless i < self
yield i
__times_rec(i.succ, &blk)
end
end
Here is the actual code from an actual Ruby implementation (core/integer.rb from Rubinius):
def times
return to_enum(:times) { self } unless block_given?
i = 0
while i < self
yield i
i += 1
end
self
end
TruffleRuby uses the exact same code as well (see src/main/ruby/truffleruby/core/integer.rb), as does JRuby (see core/src/main/ruby/jruby/ruby_implementations/Integer/times.rb)
Here is another real example from a real Ruby implementation (opal/corelib/number.rb from Opal):
def times(&block)
return enum_for(:times) { self } unless block
%x{
for (var i = 0; i < self; i++) {
block(i);
}
}
self
end
As you can see, there are many ways in which one could write a loop in Ruby.
Some of the comments hint at what is going on. I think it can be explained like this:
Each integer in Ruby is actually an object, more specifically an instance of the Integer class.
You can think of it as a Integer#times method, that could naively be implemented something like this:
class Integer
def times(&block)
if self.value > 0
for i in 0...self.value do
block.call(i)
end
end
end
end
This method is actually implemented in C in the official version of ruby (MRI), as pointed out in one of the comments to your question. I only write something similar here to help explain the concept on how it could have looked in Ruby.
The times method actually returns a value, which is the current iterator with every loop it makes (1, 2, 3 ... 100).
The do keyword catches this iterator, and uses it as the variable num.
Anytime you see the num variable, you are seeing the current iterator that's being returned by times.

Ruby call method on object instead of passing object as argument to method

Trying to understand how to write an instance method that I can call on an object (via the Object#my_method notation). I've only been able to get the desired results by passing my object as an argument to the method, but I'd like to understand an alternate way of writing methods.
class Anagram
attr_reader :test_word
def initialize(test_word)
#test_word = test_word.downcase
end
def word_stats(word)
word.downcase.split("").inject(Hash.new(0)) { |h,v| h[v] += 1; h }
end
def match(word_list)
word_list.delete_if { |word| word.downcase == test_word }
word_list.find_all do |word|
word_stats(test_word) == word_stats(word) # <= ** THIS LINE **
end
end
end
I know I'd need to change the word_stats method, but I'm unsure how to rewrite that line in bold so that I could instead do something like this:
test_word.word_stats == word.word_stats
Is this an appropriate place for send ? Is there a way to write the word_stats method so that it requires no argument?
Thanks!
If my understanding is correct, you need to define word_stats for class word.class, which I expect is String:
class String
def word_stats
self.downcase.split("").inject(Hash.new(0)) { |h,v| h[v] += 1; h }
end
end
"My dog has fleas".word_stats
#=> {"m"=>1, "y"=>1, " "=>3, "d"=>1, "o"=>1, "g"=>1,
# "h=>1, "a"=>2, "s"=>2, "f"=>1, "l"=>1, "e"=>1}
Is that what you are trying to do?
If you don't want your method to require an argument, then don't specify one in its definition. In the method, if you need to refer to the whole object on which it was invoked then you can do so via the self keyword, but usually you need only to access its attributes, which you can do directly.
def word_stats
#test_word.downcase.split("").inject(Hash.new(0)) { |h,v| h[v] += 1; h }
end
There is nothing wrong with MonkeyPatching, especially if you have a small program that only does Anagram stuff. If you aren't working on a large or open source project. Monkey Patch away!
aside: Look up Ruby Refinements for a good way to limit the scope of your monkey patches in Ruby 2.0+
I would suggest changing your method to a boolean and naming it for what it does, check to see if the word is an anagram.
I've also included a slightly more obvious algorithm.
class String
def anagram? ( check_me )
self.downcase.chars.sort == check_me.downcase.chars.sort
end
end
def match(word_list)
word_list.delete_if { |word| word.downcase == test_word.downcase } # might want to downcase test_word as well, unless you know it's downcase already
word_list.find_all do |word|
word.anagram?(test_word)
end
end

Ruby custom iterators

I have a class game which contains some arrays of custom objects (dinosaurs, cacemen etc.), that are returned by different accessors, such as game.dinosaurs, game.cavemen etc.
At present, all these accessors just return the internally stored arrays. But now I'd like to add some custom iteration methods to these arrays returned by those accessors, to be able to write code such as game.dinosaurs.each_carnivore { ... } etc. similarly to each_element and each_attr iterators in LibXML::XML::Node. But the objects returned from my accessors game.dinosaurs and game.cavemen have to behave like arrays still.
How are things like that usually done in Ruby?
Should I make the objects returned from my accessors to be some custom classes derived from Ruby's Array class? Or maybe should I just create a custom class with Enumerable mixed in?
I know I can use map or select externally on my collections, but I wanted to encapsulate these iterations internally that my class's users won't need to bother how to set up an iteration to select only carnivore dinosaurs from the internal array.
Edit: I'm not asking about how to use iterators or how to implement them, but how to add just some custom iterators to object which previously were just plain arrays (and still need to be).
It depends (as always). You could use an array subclass and you you could build a custom class and use composition and delegation. Here's a simple example with an array subclass:
class DinosaurArray < Array
def carnivores
select { |dinosaur| dinosaur.type == :carnivore }
end
def herbivores
select { |dinosaur| dinosaur.type == :herbivore }
end
def each_carnivore(&block)
carnivores.each(&block)
end
def each_herbivore(&block)
herbivores.each(&block)
end
end
And here's a simple one with composition and delegation:
class DinosaurArray
def initialize
#array = []
end
def <<(dinosaur)
#array << dinosaur
end
def carnivores
#array.select { |dinosaur| dinosaur.type == :carnivore }
end
def herbivores
#array.select { |dinosaur| dinosaur.type == :herbivore }
end
def each(&block)
#array.each(&block)
end
def each_carnivore(&block)
carnivores.each(&block)
end
def each_herbivore(&block)
herbivores.each(&block)
end
end
Both implementation can be used like this:
require 'ostruct'
dinosaurs = DinosaurArray.new
dinosaurs << OpenStruct.new(type: :carnivore, name: "Tyrannosaurus")
dinosaurs << OpenStruct.new(type: :carnivore, name: "Allosaurus")
dinosaurs << OpenStruct.new(type: :herbivore, name: "Apatosaurus")
puts "Dinosaurs:"
dinosaurs.each.with_index(1) { |dinosaur, i| puts "#{i}. #{dinosaur.name}" }
puts
But also has custom iterators:
puts "Carnivores:"
dinosaurs.each_carnivore.with_index(1) { |dinosaur, i| puts "#{i}. #{dinosaur.name}" }
puts
puts "Herbivores:"
dinosaurs.each_herbivore.with_index(1) { |dinosaur, i| puts "#{i}. #{dinosaur.name}" }
Output:
Dinosaurs:
1. Tyrannosaurus
2. Allosaurus
3. Apatosaurus
Carnivores:
1. Tyrannosaurus
2. Allosaurus
Herbivores:
1. Apatosaurus
You can do this via using ruby blocks. Read more
Simple example here:
class Game
def initialize
#carnivoures = [1,2,3]
end
def each_carnivoures
#carnivoures.each do |carni|
yield carni
end
end
end
Game.new.each_carnivoures{ |c| p c}
It also would be nice to have a possibility for chaining such filters. You can achieve this simply by wrapping select method into custom one, returning your new class instead of array. You may wrap some other methods as well, e.g. map:
class Units < Array
def select
self.class.new(super)
end
def dinosaurs
select{ |unit| unit.kind == 'dinosaur' }
end
def cavemen
select{ |unit| unit.kind == 'caveman' }
end
def carnivore
select{ |unit| unit.type == 'carnivore' }
end
def herbivore
select{ |unit| unit.type == 'herbivore' }
end
end
Units.dinosaurs.carnivore
Units.cavemen.herbivore

How do I add 'each' method to Ruby object (or should I extend Array)?

I have an object Results that contains an array of result objects along with some cached statistics about the objects in the array. I'd like the Results object to be able to behave like an array. My first cut at this was to add methods like this
def <<(val)
#result_array << val
end
This feels very c-like and I know Ruby has better way.
I'd also like to be able to do this
Results.each do |result|
result.do_stuff
end
but am not sure what the each method is really doing under the hood.
Currently I simply return the underlying array via a method and call each on it which doesn't seem like the most-elegant solution.
Any help would be appreciated.
For the general case of implementing array-like methods, yes, you have to implement them yourself. Vava's answer shows one example of this. In the case you gave, though, what you really want to do is delegate the task of handling each (and maybe some other methods) to the contained array, and that can be automated.
require 'forwardable'
class Results
include Enumerable
extend Forwardable
def_delegators :#result_array, :each, :<<
end
This class will get all of Array's Enumerable behavior as well as the Array << operator and it will all go through the inner array.
Note, that when you switch your code from Array inheritance to this trick, your << methods would start to return not the object intself, like real Array's << did -- this can cost you declaring another variable everytime you use <<.
each just goes through array and call given block with each element, that is simple. Since inside the class you are using array as well, you can just redirect your each method to one from array, that is fast and easy to read/maintain.
class Result
include Enumerable
def initialize
#results_array = []
end
def <<(val)
#results_array << val
end
def each(&block)
#results_array.each(&block)
end
end
r = Result.new
r << 1
r << 2
r.each { |v|
p v
}
#print:
# 1
# 2
Note that I have mixed in Enumerable. That will give you a bunch of array methods like all?, map, etc. for free.
BTW with Ruby you can forget about inheritance. You don't need interface inheritance because duck-typing doesn't really care about actual type, and you don't need code inheritance because mixins are just better for that sort of things.
Your << method is perfectly fine and very Ruby like.
To make a class act like an array, without actually inheriting directly from Array, you can mix-in the Enumerable module and add a few methods.
Here's an example (including Chuck's excellent suggestion to use Forwardable):
# You have to require forwardable to use it
require "forwardable"
class MyArray
include Enumerable
extend Forwardable
def initialize
#values = []
end
# Map some of the common array methods to our internal array
def_delegators :#values, :<<, :[], :[]=, :last
# I want a custom method "add" available for adding values to our internal array
def_delegator :#values, :<<, :add
# You don't need to specify the block variable, yield knows to use a block if passed one
def each
# "each" is the base method called by all the iterators so you only have to define it
#values.each do |value|
# change or manipulate the values in your value array inside this block
yield value
end
end
end
m = MyArray.new
m << "fudge"
m << "icecream"
m.add("cake")
# Notice I didn't create an each_with_index method but since
# I included Enumerable it knows how and uses the proper data.
m.each_with_index{|value, index| puts "m[#{index}] = #{value}"}
puts "What about some nice cabbage?"
m[0] = "cabbage"
puts "m[0] = #{m[0]}"
puts "No! I meant in addition to fudge"
m[0] = "fudge"
m << "cabbage"
puts "m.first = #{m.first}"
puts "m.last = #{m.last}"
Which outputs:
m[0] = fudge
m[1] = icecream
m[2] = cake
What about some nice cabbage?
m[0] = cabbage
No! I meant in addition to fudge
m.first = fudge
m.last = cabbage
This feels very c-like and I know Ruby
has better way.
If you want an object to 'feel' like an array, than overriding << is a good idea and very 'Ruby'-ish.
but am not sure what the each method
is really doing under the hood.
The each method for Array just loops through all the elements (using a for loop, I think). If you want to add your own each method (which is also very 'Ruby'-ish), you could do something like this:
def each
0.upto(#result_array.length - 1) do |x|
yield #result_array[x]
end
end
If you create a class Results that inherit from Array, you will inherit all the functionality.
You can then supplement the methods that need change by redefining them, and you can call super for the old functionality.
For example:
class Results < Array
# Additional functionality
def best
find {|result| result.is_really_good? }
end
# Array functionality that needs change
def compact
delete(ininteresting_result)
super
end
end
Alternatively, you can use the builtin library forwardable. This is particularly useful if you can't inherit from Array because you need to inherit from another class:
require 'forwardable'
class Results
extend Forwardable
def_delegator :#result_array, :<<, :each, :concat # etc...
def best
#result_array.find {|result| result.is_really_good? }
end
# Array functionality that needs change
def compact
#result_array.delete(ininteresting_result)
#result_array.compact
self
end
end
In both of these forms, you can use it as you want:
r = Results.new
r << some_result
r.each do |result|
# ...
end
r.compact
puts "Best result: #{r.best}"
Not sure I'm adding anything new, but decided to show a very short code that I wish I could have found in the answers to quickly show available options. Here it is without the enumerator that #shelvacu talks about.
class Test
def initialize
#data = [1,2,3,4,5,6,7,8,9,0,11,12,12,13,14,15,16,172,28,38]
end
# approach 1
def each_y
#data.each{ |x| yield(x) }
end
#approach 2
def each_b(&block)
#data.each(&block)
end
end
Lets check performance:
require 'benchmark'
test = Test.new
n=1000*1000*100
Benchmark.bm do |b|
b.report { 1000000.times{ test.each_y{|x| #foo=x} } }
b.report { 1000000.times{ test.each_b{|x| #foo=x} } }
end
Here's the result:
user system total real
1.660000 0.000000 1.660000 ( 1.669462)
1.830000 0.000000 1.830000 ( 1.831754)
This means yield is marginally faster than &block what we already know btw.
UPDATE: This is IMO the best way to create an each method which also takes care of returning an enumerator
class Test
def each
if block_given?
#data.each{|x| yield(x)}
else
return #data.each
end
end
end
If you really do want to make your own #each method, and assuming you don't want to forward, you should return an Enumerator if no block is given
class MyArrayLikeClass
include Enumerable
def each(&block)
return enum_for(__method__) if block.nil?
#arr.each do |ob|
block.call(ob)
end
end
end
This will return an Enumerable object if no block is given, allowing Enumerable method chaining

How to create a method like ".find_by_something_and_something_else" using Ruby?

Using Ruby I know you can get pretty creative with how you name your methods. For instance in rails you have .find_by_this_and_that.
How can I do this?
Example:
def get_persons_with_5_things
res = []
persons.each do |person|
if person.number_of_things == %MAGICALLY GET THE NUMBER 5 FROM FUNCTION NAME%
res << person
end
end
return res
end
I'm not even sure how you call this kind of things so any pointers would be appreciated.
I'm a little confused by your example. If you define the method with the hardcoded 5 in the method name, then you don't need to magically figure it out inside the body of the method. If you want to do something dynamic with method missing, it would be something like this:
def method_missing(name, *args)
if name.to_s =~ /get_persons_with_(\d+)_things/
number_of_things = $1.to_i
res = []
persons.each do |person|
if person.number_of_things == number_of_things
res << person
end
end
return res
else
return super(name, *args)
end
end
[EDIT (Jörg W Mittag)]: This is a more Rubyish way of implementing that same method:
def method_missing(name, *args)
return super unless name.to_s =~ /get_persons_with_(\d+)_things/
number_of_things = $1.to_i
return persons.select {|person| person.number_of_things == number_of_things }
end
super without any arguments just passes the original arguments along, no need to pass them explicitly
an early return guarded by a trailing if or unless expression greatly clears up control flow
all the each iterator does, is select items according to a predicate; however, there already is an iterator for selecting items: select
Ruby has different meta programming techniches to do this kind of stuff.
First we need our variable method
class DB
def get_persons_with_x_things(x)
res = []
persons.each do |person|
if person.number_of_things == x
res << person
end
end
return res
end
end
define_method
If there is a finite number of x's. We could use define_method to create all this methods. define_method creates a method. The first argument is the name of the method, the seccond argument or the given block is the stuff, which get's executed when the method is called.
This way, you don't realy create such method's, but It will look for the user if he calls it, as if it existed. But if the user relies on Object#methods and such, he will never see your inifinite number of fake methods.
class DB
99.times do |i|
define_method("get_persons_with_#{i}_things") do
get_persons_with_x_things(i)
end
end
end
method_missing
If there is an infinite numbor of x's method_missing would be better suited for this Task. If someone tries to call a method which does not exist, method_missing is executed instead. The first argument for method_missing is the method name as symbol, the following arguments are the original arguments.
class DB
def method_missing(name, *args)
case name.to_s
when /^get_persons_with_(\d+)_things$/
get_persons_with_x_things($1.to_i)
else
super(name, *args)
end
end
end
method_missing and send
To not use static regexe would be even cooler. But this could have some security implications. The method send I use here, calls a method by it's name.
class DB
def method_missing(name, *args)
name.to_s=~ /\d+/
# always be carefull with $ variables, they are global for this thread, so save everything as fast as you can
new_name= "#{$`}x#{$'}"
number= $1.to_i
if method_defined?(new_name)
send(new_name, number)
else
super(name, *args)
end
end
end
you can do a lot of things like this with method missing:
Ruby Docs
StackOveflow method_missing
Have a look at Ruby's callbacks specially method_missing.

Resources