How to intercept the call to constructor of class Hash? - ruby

I want to execute a function when a constructor of class Hash is called or when a Hash object is initialized. I have implemented my objective using
class Hash
def initialize
p "Constructor call"
end
end
The code above works fine when a Hash object is initialized as follows:
a = Hash.new(:a1 => "Hi")
However, when I use the following code:
a = {:a1 => "Hi"}
Then, it fails or the constructor is not called. So, how to intercept the call made in the second code snippet?
Thanks in advance.

I'm afraid you can't in MRI, but could probably manage something in Rubinius / JRuby.

Unfortunately, just like in almost every other language, you cannot override literals in Ruby. You'll have to use one of the few languages that allow this, like Ioke:
cell(:{}) = method(+x, "Literal {} called with #{x inspect}" println)
{ :a1 => "Hi" }
;; Literal {} called with [:a1 => "Hi"]
(In fact, Ioke is the only language I can think of right now which allows literal overloading / overriding. I suppose Ioke's cousin Seph will support it, and a couple of years of ago there was some discussion about allowing it in Newspeak, but that's about it.)

Related

When to use (:method) or (&:method)

Why does: respond_to? in:
class Wolf
def howl; end
end
Wolf.new.respond_to?(:howl) # => true
not require & while map in:
["1", "2", "3"].map(&:to_i) # => [1, 2, 3]
does? Also, are there any technical names for this?
When you say :method, you're using some nice syntactical sugar in ruby that creates a new Symbol object. When you throw an ampersand before it (&:method), you're using another piece of sugar. This invokes the to_proc method on the symbol.
So, these two things are identical:
method_proc = &:method
sym = :method
method_proc = method.to_proc
What's the difference between that and the other usage? Well, respond_to? has a single argument -- a symbol. So we can pass :method and be all fine and dandy. (Interestingly, objects do respond to the method named method, but that's a far more confusing question).
By comparison, Enumerable's iterators (like map, select, etc) accept a block. When we pass a Proc, it is interpreted properly as that block. So, these two pieces of code are equivalent:
[1,2,3].map { |i| i.even? }
[1,2,3].map(&:even?)
This equivalence is a little confusing, because of course Symbol has no idea that there's an even? method somewhere. To play around with it, I used evenproc = :even?.to_proc to inspect the resulting proc. It's implemented in C (at least in MRI ruby), and isn't willing to give up its source. However, its arity is -1, which means that it accepts one optional arg. My best guess is that it does something like this:
def to_proc
method_name = self.to_s
->(a) { a.send(method_name) }
end
I could dig further, but I think we've already gone way past the question. ;) Good luck!

Omitting an argument for a method in a block

I wonder, is it possible to do something similar in Ruby to what I can do in Scala or other languages:
someCollection.foreach(x => println(x)) // a full version
someCollection.foreach(println) // a short version
In Ruby I can do:
some_array.each { |x| puts x }
So how can I do this?
some_array.each { puts }
UPDATE:
I'm not talking about puts in particular, it just picked it for example. There might be some_other_method which takes one parameter.
some_array.map { some_other_method }
some_array.map(some_other_method) # ???
def some_other_method a
# ... doing something with a
end
If you look up the rules for implicit η-expansion in the SLS (§6.26.5), it should be immediately obvious that it relies crucially on static type information and thus cannot possibly work in Ruby.
You can, however, explicitly obtain a Method object via reflection. Method objects respond to to_proc and like any object that responds to to_proc can thus be passed as if they were blocks using the unary prefix & operator:
some_array.each(&method(:puts))
Not quite like that, unfortunately. You can send a method name to be called on each object, e.g.:
some_array.each &:print_myself
Which is equivalent to:
some_array.each {|x| x.print_myself}
But I don't know of a clean (read: built-in) way to do what you're asking for. (Edit: #Jörg's answer does this, though it doesn't really save you any typing. There is no automatic partial function application in Ruby)

How can I make a custom Ruby type behave like a string?

If I have a custom Ruby class representing some string type, as in
class MyString
end
Which functions should I implement in order to make the following use cases possible:
Passing a Ruby string whenever a MyString is expected
Passing a MyString whenever a Ruby string is expected
Comparing a Ruby string with a MyString value (it shouldn't matter whether I use s == t or t == s).
I saw various interesting functions like to_s, cmp, == and eq already, but it's not clear to me when each of them is called.
My concrete use case is that I'm writing a Ruby extension using the C API which exposes functions taking (and returning) values of a custom string type (QString, to be precise) which my extension also registers. However, I'd like to make those custom strings behave as intuitive as possible. Unfortunately I can't just return Ruby strings from my C code since it should be possible to call Qt methods on the strings.
There are at least three approaches:
class MyString < String; ...; end
Define #to_s
Define #to_str
Doing both #2 and #3 will make the object act very much like a real String even if it isn't a subclass.
#to_s is an explicit converter, meaning it must appear in Ruby code to work.
#to_str is an implicit converter, meaning the Ruby interpreter will attempt to call it when it wants a String but is given something else.
Update:
Here is an example of some fun you can have with to_str:
begin
open 1, 'r'
rescue TypeError => e
p e
end
class Fixnum
def to_str; to_s; end
end
open 1, 'r'
When run, the first open fails with TypeError but the second proceeds to looking for 1.
#<TypeError: can't convert Fixnum into String>
fun.rb:9:in `initialize': No such file or directory - 1 (Errno::ENOENT)
from fun.rb:9:in `open'
Although it's tempting to sub-class String to give it a new initialize method that will import these QString-type strings, you may just want to tack on an extension to String that helps with the conversion so you don't have to re-implement a version of String itself.
For instance, with two methods you could pretty much have this done:
class String
def self.from_qstring(qstring)
new(...)
end
def to_qstring
# ...
end
end
Having multiple storage types for String is not going to be a problem until you start comparing them, but given that Ruby's String is quite robust, writing a work-alike is difficult.
It's not generally a good idea to subclass classes that were built by someone else in Ruby, because too many things can go wrong. (You might, for example, override an internal method without knowing it.)
1) define Mystring.to_s to get automatic conversion from a Mystring to a String.
2) Not sure what you mean by this. If you want a String method that returns a Mystring, you will have to monkey-patch String:
Class String
def to_mystring
return Mystring.new(self)
end
end
3) to get t == s (assuming s is an instance of String and t an instance of Mystring) define <=>. To get s == t you will have to monkey patch String again, though.
Since I was looking for something similar, but none of the other answers worked for me, I'll post what did work for me.
Found in this blog post which discourage the use of inheriting String and instead use simple delegator.
Inheriting from SimpleDelegator create an object which delegate everything to a string of your choice but on which you add behavior as you see fit.
class ChunkyBacon < SimpleDelegator
def initialize(content)
#content = content
super #content
end
def chunky_bacon?
#content == 'chunky_bacon'
end
end
test = ChunkyBacon.new('choco pizza') # => 'choco pizza'
test.chunky_bacon? # => false

Is there a ruby equivalent to the Scala Option?

How do I model an optional value in ruby? Scala has Option[], which is what I'm looking for in ruby.
There's no equivalent in the standard library. You have to define your own. See this article.
I'm not a Ruby expert, but I don't think there is an Option equivalent. As Ruby is object oriented, nothing stops you from writing your own implementation, but it won't be as useful as in a statically typed language, where the compiler forces you to do a proper check for the empty option, which is one of the main points for using this construct. Of course there are other advantages, like the possibility to chain Option values in several ways.
Have you checked out the Rumonade gem? It gives you an Option class modeled on scala.
require 'rumonade'
[nil, 1, 123].map { |v| Option(v) }
=> [None, #<Rumonade::Some:0x7f2589297768 #value=1>, #<Rumonade::Some:0x7f2589297740 #value=123>]
[nil, 1, 123].map { |v| Option(v).map { |n| n.to_s }.select { |s| s.size > 2 } }.flatten
=> ["123"]
There is an example of a Maybe class in nkpart's adt library under examples/common_adts.rb. There are also other example ADTs and the library makes it easier to define your own.
I have just pushed a gem called nil_be_gone that gives you an Optional that you can wrap objects with. It implements method_missing to check whether the value of the Optional is nil and if so simply return another Optional wrapped nil value, otherwise it calls the method on the object and wraps it again.
nil_be_gone implements bind as and_then which allows you to chain operations on Optional types, it's return methods which retrieves the value from Optional is value and the unit operation which wraps an object in the monad is defined by self.from_value.
I don't know Scala, so I can't assert that's your answer:
In ruby, when you call a method, you can define a default value for a param:
def foo(i_am_mandatory, i_am_optionnal = :banga)
puts i_am_optionnal
end
foo(:pouet, :plip)
=> :plip
foo(:pouet)
=> :banga
In that example, you can omit i_am_optionnal, which has a default value.
HTH.

Changing default Ruby arguments

I want to change the default arguments passed to a Ruby function. For example, instead of each time writing
[1,2,3].do_stuff(:option => ' my option ')
I want to modify the defaults so that I can write
[1,2,3].do_stuff
What is the simplest, cleanest, most Ruby-like way of changing default parameters?
>> [1, 2, 3].do_stuff
=> Result I get
>> [1, 2, 3].do_stuff :an_option => a_value
=> Result I really want, but don't want to specify the argument
I like to use super for this. It allows us to add some functionality to the method apart from just changing default arguments:
class Array
def do_stuff(options = {})
# Verify if caller has not passed the option
options[:argument_i_want_to_change] = default_value_i_want unless options.has_key? :argument_i_want_to_change
# call super
super
end
end
Result:
>> [1, 2, 3].do_stuff
=> Result that I really want
UPDATE: Removed reverse_merge! dependency. (Now looking for a better alternatives to using []= method)
(moved from your original question)
I assume you are talking about a method Array#do_stuff that already exists, but you want to modify it slightly (in your case by changing a default parameter).
A post here gives a nice way of doing it. It doesn't suffer from the same problems as the alias technique, as there isn't a leftover "old" method.
Here how you could use that technique with your example problem (tested with ruby 1.9)
class Array
old_do_stuff = instance_method(:do_stuff)
define_method(:do_stuff) { |options = {}|
options[:option] ||= " option "
old_do_stuff.bind(self).call(options)
}
end
You might also want read up on UnboundMethod if the above code is confusing. Note that old_do_stuff goes out of scope after the end statement, so it isn't a problem for future uses of Array.
Are you wanting a solution for code you didn't write yourself? There are two options I'm aware of.
Code you wrote yourself:
def some_method_you_wrote(options)
becomes:
def some_method_you_wrote(options = { :option1 => 'value' })
(Swanand's answer is nice too)
For code you didn't write, look into aliasing methods. (Rails provides something called alias_method_chain for this purpose, IIRC.)

Resources