I have a method that prints out a numbered list, yielding to a code block to print a prefix.
arr = %w(a b c)
def print_lines(array)
array.each_with_index do |item, index|
prefix = yield index
puts "#{prefix} #{item}"
end
end
print_lines(arr) do |index|
"(#{index})"
end
This produces the following output:
(0) a
(1) b
(2) c
Now I want to wrap print_lines in another method and call it.
def print_lines_wrapped(array)
puts 'print_lines_wrapped'
print_lines(array)
end
print_lines_wrapped(arr) do |index|
"(#{index})"
end
However, this gives me a LocalJumpError
test_yield.rb:5:in `block in print_lines': no block given (yield) (LocalJumpError)
from test_yield.rb:4:in `each'
from test_yield.rb:4:in `each_with_index'
from test_yield.rb:4:in `print_lines'
from test_yield.rb:16:in `print_lines_wrapped'
from test_yield.rb:19:in `<main>'
Why do I get a LocalJumpError?
How can I implement print_lines_wrapped such that I can call it like this:
print_lines_wrapped(arr) do |index|
"(#{index})"
end
and get the following output:
print_lines_wrapped
(0) a
(1) b
(2) c
?
Your wrapper method also has to accept a block and pass it to the wrapped method. There is no implicit passing of the block:
def print_lines_wrapped(array, &block)
puts 'print_lines_wrapped'
print_lines(array, &block)
end
Example:
def asdf(&block) puts yield(2) end
def qwer(&block)
puts "I am going to call asdf"
asdf &block
end
asdf { |x| x * 3 }
6
=> nil
qwer { |x| x * 5 }
I am going to call asdf
10
=> nil
The & operator converts its operand into a block if possible
qwer &Proc.new { |x| x * 2 }
I am going to call asdf
4
i am new to ruby programming. i wrote a little program to recursively count blobs in a two dimensional array. it contains two classes, cell and blobs. i am getting the following error and i dont know what it means or how to fix it.
attached is my code and the error.
Cell Class
class Cell
attr_accessor :data,:visited,:row,:col
def initialize(data, row, col)
#data = data
#visited = false
#row = row
#col = col
end
def to_s
self.data.to_s
end
end
Blob class
class Blobs
require ./Cell
#cells = Array.new(10){Array.new(10)}
def separate(percentage)
for i in 0..10
for i in 0..10
random = Random.rand(0,100)
if random < percentage
#cells[i][j] = Cell.new('x',i,j)
else
#cells[i][j] = Cell.new(nil, i, j)
end
end
end
end
def markBlob(currentCell)
if currentCell.visited
return
end
currentCell.visited = true
if currentCell.data.nil?
return
end
if currentCell.row >0
markBlob(#cells[currentCell.row-1][currentCell.col])
end
if currentCell.row <#cells.size-1
markBlob(#cells[currentCell.row+1][currentCell.col])
end
if currentCell.col>0
markBlob(#cells[currentCell.row][currentCell.col-1])
end
if currentCell.col<#cells.size-1
markBlob(#cells[currentCell.row][currentCell.col+1])
end
end
def countblobs
count = 0
for i in 0..10
for j in 0..10
cell = #cells[i][j]
if !cell.visited && cell.data.nil?
count++
markBlob(cell)
end
end
end
return count
end
def to_s
for i in 0..10
for j in 0..10
if #cells[i][j].data.nil?
puts '- '
else
puts #cells[i][j].data + ' '
end
end
puts "\n"
end
end
blob = Blobs.new
number = blob
puts number
end
this is the error i am getting:
C:\Ruby22\bin\ruby.exe -e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift) C:/Users/Nechama/RubymineProjects/blobs/blobs.rb
C:/Ruby22/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:38:in `require': wrong number of arguments (0 for 1) (ArgumentError)
from C:/Users/Nechama/RubymineProjects/blobs/blobs.rb:3:in `<class:Blobs>'
from C:/Users/Nechama/RubymineProjects/blobs/blobs.rb:2:in `<top (required)>'
from -e:1:in `load'
from -e:1:in `<main>'
Process finished with exit code 1
require should get string as an argument.
Use require_relative to cell file
require_relative 'cell'
and put it above class Blobs.
More about Including Other Files In Ruby
If I have ruby file maze.rb with
class Maze
def self.x
end
def self.y
end
end
and a rspec file with
require 'maze'
describe "A Maze" do
it "exists" do
expect(Maze).to be
end
it " has x-y dimension" do
expect(Maze.x).to be
expect(Maze.y).to be
end
end
Why does the test for Maze.x fail ?
Failures:
1) A Maze has x-y dimension
Failure/Error: expect(Maze.x).to be
expected nil to evaluate to true
# ./spec/maze_spec.rb:8:in `block (2 levels) in <top (required)>'
It is working.
What's happening is that the class level method isn't doing anything and thus returns nil - as opposed to method not found. Simply adding true as the return value resolves this, i.e.
def x
true
end
I have this rspec test:
it 'has a populated chessboard' do
expect(ChessBoard.new.populate_new_board).to eq [
['pawn','pawn','pawn','pawn','pawn','pawn','pawn','pawn'],
['pawn','pawn','pawn','pawn','pawn','pawn','pawn','pawn'],
['pawn','pawn','pawn','pawn','pawn','pawn','pawn','pawn'],
['pawn','pawn','pawn','pawn','pawn','pawn','pawn','pawn'],
['pawn','pawn','pawn','pawn','pawn','pawn','pawn','pawn'],
['pawn','pawn','pawn','pawn','pawn','pawn','pawn','pawn'],
['pawn','pawn','pawn','pawn','pawn','pawn','pawn','pawn'],
['pawn','pawn','pawn','pawn','pawn','pawn','pawn','pawn']]
end
For this code:
class ChessBoard
def initialize
#board=Array.new(7){Array.new(7)}
end
def populate_new_board
(0..7).each do |row|
(0..7).each do |cell|
#board[row][cell]='pawn'
end
end
#board
end
end
but I'm getting:
1) least number of moves from x to y has a populated chessboard
Failure/Error: expect(ChessBoard.new.populate_new_board).to eq [
NoMethodError:
undefined method `[]=' for nil:NilClass
# ./code.rb:10:in `block (2 levels) in populate_new_board'
# ./code.rb:9:in `each'
# ./code.rb:9:in `block in populate_new_board'
# ./code.rb:8:in `each'
# ./code.rb:8:in `populate_new_board'
# ./code_spec.rb:12:in `block (2 levels) in <top (required)>'
how can I fix this?
btw pawns in every space is not the final result but it's what I want for this test right now (then I can modify it further).
class ChessBoard
def populate_new_board
#board = [['pawn'] * 7] * 7
end
end
Change it to:
def populate_new_board
(0...7).each do |row|
(0...7).each do |cell|
#board[row][cell]='pawn'
end
end
#board
end
As it was denoted that you did a mistake in range, but a strongly advice you to reduce usage of index ranges. You can use :each, and :map methods instead:
class ChessBoard
def initialize
#board = Array.new( 7 ){ Array.new( 7 ) }
end
def populate_new_board
#board.each {| row | row.map! {| _ | 'pawn' } }
end
end
But I'd use more the simple code:
class ChessBoard
def populate_new_board
#board = Array.new( 7 ){Array.new( 7 ) { 'pawn' } }
end
end
To learn Ruby, I'm implementing different data structures starting with nodes and a simple stack. If I matching each def with a corresponding end, there are lots of error about expecting $end (EOF) but getting end. So I could fix it by stacking some ends at the end of the class, but obviously I don't know why that works.
require "Node"
class Stack
attr_accessor :top
def size
#size
end
def push(node)
if node && node.next
node.next = top
top = node
end
size++
def pop()
if top != nil
top = top.next
end
size--
def to_s
if top != nil
temp = top
while temp != nil
puts temp.value
temp = temp.next
end
else
puts "The stack is empty"
end
end
end
end
end
The node class is very simple and shouldn't cause any problems:
class Node
attr_accessor :next
def initialize(value)
#value = value
end
end
Everything works fine on that Frankenstein Stack, except pushing a node results in NoMethodError: undefined method +#' for nil:NilClass. Not sure if that is related, but I'm mostly concerned with the syntax of method/class declaration and using end
You get an error because ruby does not have ++ and -- operators.
Ruby understand the following constructs
size++
def pop()
# and
size--
def to_s()
like
size + +def pop()
# and
size - -def to_s()
Ruby syntax is expression-oriented and method definition is expression in Ruby. Method definition expressions (def pop() and def to_s()) are evaluated to nil (in your code you actually define method pop inside push method body and to_s inside pop method body). And this is why you get NoMethodError: undefined method +#' for nil:NilClass error - it evaluates expression size + +nil and nil does not define unary plus operator. In this expression first + is an Fixnum addition operator (size is Fixnum), and second + is unary plus operator of nil (result of def pop() expression).
Use += 1 and -= 1 instead of ++ and --. Your code should look like this:
class Stack
attr_accessor :top
def size
#size
end
def push(node)
if node && node.next
node.next = top
top = node
end
#size += 1 # #size, not `size` because you have `size` getter and you cannot modify size with getter method
end
def pop()
if top != nil
top = top.next
end
#size -= 1
end
def to_s
if top != nil
temp = top
while temp != nil
puts temp.value
temp = temp.next
end
else
puts "The stack is empty"
end
end
end
Your defs don’t have a matching end. Also, Ruby does not have a ++ operator; you’ll have to use += 1 instead.