Cannot call a method using a shortcut - ruby

I have a module that defines a method to log some output in an html file. The module looks like this:
module Htmllog
#htmllogfile = "htmllog/myproject" + Time.now.strftime('%Y%m%d-%H%M%S') + '.html'
def self.add(text, tag)
if tag.length == 0
formattedlog = text
else
formattedlog = "<#{tag}>#{text}</#{tag}>"
puts text
end
File.open(#htmllogfile, "a") do |f|
f.puts formattedlog
end
end
end
I call it in my main.rb file and it works just fine if I call it like this:
Htmllog.add "Hello world!", "h1"
Since I have to log a lot of stuff, I want to add a shortcut to reduce the number of digits and I tried this:
l = Htmllog.add
l "Hello world!", "h1"
But I get this error.
`add': wrong number of arguments (0 for 2) (ArgumentError)
Can't figure out what's wrong.

Do as below using Object#method and Method#call:
l = Htmllog.method(:add)
l.call("Hello world!", "h1")
l.("Hello world!", "h1") # which is same l.call("Hello world!", "h1")
l = Htmllog.add is not valid as per the your method definition of add. So you got error.

If you want l to be available globally, then you should define that as a method on Kernel.
module Kernel
def l *args; Htmllog.add(*args) end
end
l "Hello world!", "h1"
Be careful not to have a conflict with existing methods.

1 When ruby sees l = Htmllog.add , it will first run Htmllog.add with no argument, and then give the result to variable l. That's why you have this error.
2 One way you can do it is to use an anonymous function :
l = ->(text, tag) { Htmllog.add(text, tag) }

Related

Error using yield in Ruby

I am new to ruby and am trying to learn how yield works. I am using yield in the following way to read characters in a file with help of a function. The return value of this function is input to another function which extracts words based on spaces. However, I am getting the following error while execution:
in `block (2 levels) in getchars': no block given (yield) (LocalJumpError)
Here is the code snippet generating error:
def getchars(file)
IO.readlines(file).each {|line| line.each_char {|chrc| yield chrc }}
end
Can someone please help me understand what am I doing wrong? Thanks.
Addition:
This is how I make call:
def getwords(file)
#st_char = true
getchars(file).each {|c|
if #st_char == true
#word = ""
if c.match(/^[[:alnum:]]+$/)
#word = c
#st_char = false
end
else
if c.match(/^[[:alnum:]]+$/)
#word = #word + c
else
#st_char = true
yield #word
end
end
}
end
You need to pass a code block to getchars for it to yield to.
something like,
getchars("example.txt") {|char| puts char}
Then inside your get chars, it will yield each char one at a time to the supplied code block - which simply puts them out.
I think the error message is pretty clear: getchars tries to yield to a block, but whoever called getchars didnt' pass a block.
In line 2 of getwords, you call getchars without passing a block. You need to pass a block to getchars, so it has something to yield to.
file_as_string = File.read("greetings.txt") # => "hey hello hola vanakam"
array_of_words_after_splitting_by_spaces = file_as_string.split(" ") # => ["hey", "hello", "hola", "vanakam"]
Warning: Please don't use such variable names, just used it to explicitly see whats happening

Ruby: Why is 'while (p || (p=exns.shift))' not the same as 'while p ||= exns.shift'?

What's wrong here? I don't see how the two fragments can behave differently, yet they do.
Full code, try with one or the other while:
class T
def initialize
#e=[4,2]
end
def shift
r=#e.shift
puts "[#{r.inspect}]"
r
end
end
exns=T.new
while (p || (p=exns.shift))
#while p ||= exns.shift
puts "p: #{p.inspect}"
p -= 1
p=nil if p<1
puts " #{p.inspect}"
puts "T" if p
end
The 'while (p || (p=exns.shift))' never seems to short-circuit for some reason. I'd like to know the reason.
Your problem is with the letter you chose to name your variable - p is not like other letters (say q), since it is also the name of the Kernel method p():
p
# => nil
q
# NameError: undefined local variable or method `q' for main:Object
for that reason, because you did not define a local variable names p before the while loop, it is actually declared only inside the scope of the loop.
To see how this matters, simply add the following line before the loop:
p = nil
Now, both options act the same.

What's this Ruby syntax?

I just read the following code:
class Dir
def self.create_uniq &b ### Here, & should mean b is a block
u = 0
loop do
begin
fn = b[u] ### But, what does b[u] mean? And b is not called.
FileUtils.mkdir fn
return fn
rescue Errno::EEXIST
u += 1
end
end
io
end
end
I put my confusion as comment in the code.
Defining method with &b on the end allows you to use block passed to the method as Proc object.
Now, if you have Proc instance, [] syntax is shorthand to call:
p = Proc.new { |u| puts u }
p['some string']
# some string
# => nil
Documented here -> Proc#[]
The & prefix operator allow a method to capture a passed block as a named parameter. e.g:
def wrap &b
3.times(&b)
print "\n"
end
now if you call above method like this:
wrap { print "Hi " }
then output would be:
Hi Hi Hi

Use of yield and return in Ruby

Can anyone help me to figure out the the use of yield and return in Ruby. I'm a Ruby beginner, so simple examples are highly appreciated.
Thank you in advance!
The return statement works the same way that it works on other similar programming languages, it just returns from the method it is used on.
You can skip the call to return, since all methods in ruby always return the last statement. So you might find method like this:
def method
"hey there"
end
That's actually the same as doing something like:
def method
return "hey there"
end
The yield on the other hand, excecutes the block given as a parameter to the method. So you can have a method like this:
def method
puts "do somthing..."
yield
end
And then use it like this:
method do
puts "doing something"
end
The result of that, would be printing on screen the following 2 lines:
"do somthing..."
"doing something"
Hope that clears it up a bit. For more info on blocks, you can check out this link.
yield is used to call the block associated with the method. You do this by placing the block (basically just code in curly braces) after the method and its parameters, like so:
[1, 2, 3].each {|elem| puts elem}
return exits from the current method, and uses its "argument" as the return value, like so:
def hello
return :hello if some_test
puts "If it some_test returns false, then this message will be printed."
end
But note that you don't have to use the return keyword in any methods; Ruby will return the last statement evaluated if it encounters no returns. Thus these two are equivelent:
def explicit_return
# ...
return true
end
def implicit_return
# ...
true
end
Here's an example for yield:
# A simple iterator that operates on an array
def each_in(ary)
i = 0
until i >= ary.size
# Calls the block associated with this method and sends the arguments as block parameters.
# Automatically raises LocalJumpError if there is no block, so to make it safe, you can use block_given?
yield(ary[i])
i += 1
end
end
# Reverses an array
result = [] # This block is "tied" to the method
# | | |
# v v v
each_in([:duck, :duck, :duck, :GOOSE]) {|elem| result.insert(0, elem)}
result # => [:GOOSE, :duck, :duck, :duck]
And an example for return, which I will use to implement a method to see if a number is happy:
class Numeric
# Not the real meat of the program
def sum_of_squares
(to_s.split("").collect {|s| s.to_i ** 2}).inject(0) {|sum, i| sum + i}
end
def happy?(cache=[])
# If the number reaches 1, then it is happy.
return true if self == 1
# Can't be happy because we're starting to loop
return false if cache.include?(self)
# Ask the next number if it's happy, with self added to the list of seen numbers
# You don't actually need the return (it works without it); I just add it for symmetry
return sum_of_squares.happy?(cache << self)
end
end
24.happy? # => false
19.happy? # => true
2.happy? # => false
1.happy? # => true
# ... and so on ...
Hope this helps! :)
def cool
return yield
end
p cool {"yes!"}
The yield keyword instructs Ruby to execute the code in the block. In this example, the block returns the string "yes!". An explicit return statement was used in the cool() method, but this could have been implicit as well.

Recursion in yield

So i am trying to do something like this:
def func(x,y)
if x.length == 1 then
n = x.pop()
yield(n,y)
else
n = x.pop()
yield(n,func(x,y))
end
end
calling it like:
a = func([1,2,3,4,5],0) do |x,y|
x+y
end
Is it possible to do something like this? I keep getting no block given (yield) (LocalJumpError).
I even tried doing something a little different:
def func(x,y)
func(x,y) do |tail|
..
end
end
but no luck
Thanks.
Yes, you can take the block as an argument explicitly:
def func(x, y, &block)
You can still yield to it with the yield keyword, but you can also pass it as you recurse:
yield(n, func(x, y, &block))
The & in both cases means that the block argument is not a normal argument, but represents the block that can be attached to any Ruby method call.
You are missing to pass the block in the recursive call.
The recursive call should be like as below:-
yield(n,func(x,y)) { |x,y| x+y})
Since you missed to pass the block in the recursive call, when the code hits:-
if x.length == 1 then
n = x.pop()
yield(n,y) <<<< Here
the method func doesn't have block passed as argument,in the recursive call, but ruby tries to call a non-existent block and hence the error.

Resources