Ruby Method without Quotes - ruby

I'm writing a ruby method that takes a string input but I don't want to type the quotes.
For example:
def noquotes(input)
puts input
end
noquotes('12Dec11Bel01') # ---> 12Dec11Bel01
noquotes(12Dec11Bel01) # ---> Currently yields an error
What I'd like to be able to do is enter the method input without the quotes (second example) and still get the right result. I tried using .to_str to ensure the input was treated as a string, but it didn't work.

Hehe, sorry, but you can't mangle with the syntax tree in Ruby. If you don't make quotes, it will be parsed as a variable or method call.
What you can do is
def method_missing(meth, *args)
meth.to_s
end
but use that wisely and with scoping, as in
class DSL # You'd use that here
def dsl(&block)
instance_eval(block)
end
def method_missing(meth, *args)
meth.to_s
end
def noquotes(input)
puts input
end
end
def dsl(&block)
DSL.new.dsl(&block)
end
dsl do
noquotes(foobar)
end
Use with caution and only if you know what you're doing! And only in DSL. And not even there. Really. Don't do it.

This isn't possible without doing horrible maintainence-nightmare things. Think about how the Ruby interpreter needs to parse your input. Without the quotes, it has no way to know that 12Dec11Bel01 is intended as a string, and not a call to another method or the name of a variable.
Type the quotes as skip the parentheses. It's the same number of characters.

Related

Evaluate argument at call site

This is somewhat of an esoteric situation that I am not even sure is possible. I have a method that is called by a lot of methods:
def called_by_a_lot_of_methods
# Work
end
I am introducing a feature in which the called_by_a_lot_of_methods will do stuff depends on the caller method, and my current solution is to change all these methods to pass their names when calling called_by_a_lot_of_methods:
def some_method
called_by_a_lot_of_methods(method_name: some_method)
end
Or, alternatively:
def some_method
called_by_a_lot_of_methods(method_name: __method__)
end
But this is becoming tedious, and I was wondering if I can give the method_name parameter a default value:
def called_by_a_lot_of_methods(method_name: __method__)
# Work
end
This does not work because __method__ evaluates immediately giving called_by_a_lot_of_methods, which is obviously not what I want. The question then is, is there a way in Ruby to defer the evaluation of the argument until a useful time when I know it should give the correct result, which is the outer caller method? Thus saving me from having to pass the argument everywhere?

Augmenting the methods with `alias` keyword

Having reading through The Ruby programming language I found an example of using alias keyword for augmenting the methods.
def hello # A nice simple method
puts 'Hello world' # Suppose we want to augment it...
end
alias original_hello hello # Give the method a backup name
def hello # Now we define a new method with the old name
puts "Your attention please" # That does some stuff
original_hello # Then calls the original method
puts "This has been a test" # Then does some more stuff
end
Indeed original hello preserves the old behavior even after the method the it had been referencing to was redefined.
But, to my mind, this example hardly clarifies the real benefit of this technique. Cannot the same be achieved in traditional way (e.g. by providing the block)? Then why applying this idiom? Can anyone provide an example from the real world when augmenting with alias really makes sense?
Rails code is full of those. Imagine the original hello method does not belong to your code base. Somewhere in 3rd-party library there is do_stuff(stuff) method declared on the class Stuffer.
You want to e.g. debug this method. You reopen the class, define an alias and, voilà:
class Stuffer
alias original_do_stuff do_stuff
def do_stuff(stuff)
puts stuff.inspect
original_do_stuff(stuff)
end
end
Now all the code, including original 3rd party code you might be even not aware about, would print out the parameter passed to every single call to do_stuff.
Real-life example (don’t try this at home and in the school :)
class String
alias _inspect inspect
def inspect
puts "I am a string: “#{_inspect}”"
end
end
"abc".inspect
#⇒ I am a string: “"abc"”
Can anyone provide an example from the real world when augmenting with alias really makes sense?
Not really. Today, you would do this (example taken from #mudasobwa's answer):
module WeirdInspectRefinement
module WeirdInspectExtension
def inspect
"I am a string: “#{super}”"
end
end
refine String do
prepend WeirdInspectExtension
end
end
using WeirdInspectRefinement
p 'abc'.inspect
#⇒ 'I am a string: “"abc"”'
But even before Module#prepend and Refinements existed, there was never a reason to use alias for this, which leaves unused methods around polluting the namespace, and Rails abandoned it quite a while ago:
class String
old_inspect = instance_method(:inspect)
define_method(:inspect) do
"I am a string: “#{old_inspect.bind(self).()}”"
end
end
'abc'.inspect
#⇒ 'I am a string: “"abc"”'

Why does `gsub` call `to_hash`?

I am writing a DSL. I don't want users to have to quote the arguments to pass strings, therefore I overwrite method_missing to convert an unknown method to a string. In the following example, create is the DSL method, and I wanted user to type arg1 and arg2 without the quotes.
def method_missing(m, *arg)
m.to_s
end
def create(*args)
arg1.gsub(#do something here)
end
create arg1 arg2
However, this raises and error when I use gsub on the 'string':
'gsub': can't convert String to Hash (String#to_hash gives String) (TypeError)
I guess the method_missing overwriting is messed it up since it looks like gsub is calling String#to_hash, which is not a method in String, thus it is routed to method_missing.
I am wondering why gsub calls String#to_hash, or whether there is any other way to let users of the DSL not have to type quotes, without overwriting method_missing.
String#gsub does different things depending on the argument count and types, and if a block was given:
gsub(pattern, replacement) → new_str
gsub(pattern, hash) → new_str
gsub(pattern) {|match| block } → new_str
gsub(pattern) → enumerator
The second one is documented as:
If the second argument is a Hash, and the matched text is one of its keys, the corresponding value is the replacement string.
But how to distinguish it from the first? Both take two arguments! That's a little bit complicated but in your case Ruby (well, the reference implementation called CRuby or MRI to be exact) starts with checking if the second argument has the internal type T_HASH (it doesn't as it's most likely T_STRING due to #to_s), then it checks if #to_hash can be called. Either because it responds to it or #method_missing can instead. You have defined it so Ruby calls it. However it doesn't return a T_HASH and that is the cause of the exception you've posted.
A possible solution is defining main.method_missing and not Object#method_missing (as String inherits from Object):
def self.method_missing(m, *arg)
m.to_s
end
However I recommend sticking to quotes or writing your own small parser for this kind of file if it shouldn't adhere to Ruby's syntax. Using *_missing may be the cause of confusing or unhelpful error messages. Or even none (I guess create arg1 arg2 should've been create arg1, arg2).
gsub probably uses method_missing itself somewhere, so it seems that defining it globally there is causing internal issues with the method call. If you're going to use method_missing make sure you always define it in a module or a class:
module CoolDSL
def self.method_missing(m, *arg)
m.to_s
end
def self.create(*args)
args[0].gsub(/1/, "2")
end
def self.do_thing
create arg1 arg2
end
end
CoolDSL.do_thing
Naturally, that's not exactly useful as a DSL, so you'll want to learn the power of instance_eval and yield. I like this guide.

Ruby koan 280 - where is the reference to to_str?

I've had a look around and can't find this question:
For ruby koan 280 it's telling me the following underscore section should be false:
def test_to_str_allows_objects_to_be_treated_as_strings
assert_equal __, File.exist?(CanBeTreatedAsString.new) # test passes, if __ is changed to false
end
OK, fine. But how does this test that to_str allows objects to be treated as Strings? Here is the CanBeTreatedAsString class, which DOES include a to_str method:
class CanBeTreatedAsString
def to_s
"string-like"
end
def to_str
to_s
end
end
...but how is that relevant to the assert_equal code above? Is it that .exist? expects a String?
This page:
http://www.ruby-doc.org/core-2.2.0/File.html#method-c-exist-3F
says the parameter can be an IO object. Are some methods specific about the parameter types they receive? And if so, how do I tell?
File.exist? takes a string or an IO. Part of how it does that is by calling to_str on the object. A string returns itself for to_str. Otherwise, it's only supposed to be implemented on objects that can be used as a string.
Due to Ruby's duck typing conventions, there isn't an easy way to tell. However, usually, if a method accepts a string, then it will call String.try_convert (which uses to_str) to allow duck typing. In a similar fashion, many objects that expect an int call Integer.try_convert (which calls to_int) to convert the argument.
Here's more information on the various conversion protocols: http://pivotallabs.com/messages-not-types-exploring-rubys-conversion-protocols/
EDIT: Forgot to add the how can you tell

Use cases for Ruby's EOB construct

I recently came across the Ruby EOB / -EOB construct within this context (from the Ruby id3 library) :
def initialize(...)
# ...
instance_eval <<-EOB
class << self
def parse
# ...
# Method code
# ...
end
EOB
self.parse # now we're using the just defined parsing routine
# ...
end
I understand that the code is used to generate a method on the fly, yet I would like to know if it would be possible to use the EOB snippet within a method. I would like to write a method which generates some other method code , which is to be included in yet another class. This sounds a bit confusing, I'll try to illustrate my intention with some simplified code samples :
# This class reads the code of another
# Ruby class and injects some methods
class ReadAndInject
# The method which defines another method
def get_code_to_be_injected
"\tdef self.foo\n"+
"\t\tputs 'bar'\n"+
"\tend\n"
end
# Main entry point, reads a generated Ruby Class
# and injects specific methods within it
def read_and_inject
# Assume placeholder for currently read line,
# add the generated code within
current_line += "\n#{get_code_to_be_injected}"
end
end # class ReadAndInject
This would work, since the method to be injected is added correctly. Yet I was wondering if using the EOB construct would yield some advantages (e.g. better visibility of the code, since no cumbersome tabs or string concatenations would have to be added.
To conclude, is this a good use case for EOB ?
It seems like a shady yet powerful construct, I've ducked it, googled and stackoverflow'd it yet no significant code samples other than one from RubyCocoa were returned. I've only recently started to use meta constructs in Ruby, so please be gentle :-)
Thanks in advance!
These are called "here documents", which are supported by several languages, and allow you to make a multi-line string. You can actually use any delimiter, not just EOB. Ruby has some extra features for heredocs: for example, the - in <<-EOB allows you to indent the delimiter.
You might use it like this:
def code_to_be_injected
<<-EOS
def self.foo
puts 'bar'
end
EOS
end
Some additional features in Ruby:
myvar = 42
<<EOS
variable: #{myvar}
EOS #=> "variable: 42"
<<'EOS'
variable: #{myvar}
EOS #=> "variable: #{myvar}"
print <<A, <<B
This will appear first
A
and this second
B

Resources