why I can't using expect equal in my new rspec version - ruby

I'm the new of the ruby code. My team member write a class Deck which implement the game set
class Deck
#array = Array.new
# create a deck of n cards
# n <= 0 returns empty array.
def initialize (n=1)
#array = (0..n-1).to_a
end
end
im trying to write rspec testing which is also new to us, here's the test code:
#!/user/bin/ruby -w
require '../deck'
require 'rspec/expectations'
describe "Deck#new" do
context "with one parameter " do
it "has parameter n = 0" do
expect(Deck.new(0)).to match_array([])
end
it "has parameter n = 1" do
expect(Deck.new(1)).to eq([0])
end
it "has parameter n = 5" do
expect(Deck.new(5))==([0,1,2,3,4])
end
it "has parameter n<0" do
expect(Deck.new(-1))==([])
end
end
end
but when i run this test, it gives me
expected a collection that can be converted to an array with `#to_ary` or `#to_a`, but got #<Deck:0xb82edb74 #array=[]>
and the first two failed, which I don't understand. Did I miss something in my code? Thanks for help. My rspec version is the newest.

You need a method to access the cards:
class Deck
def initialize (n=1)
#array = (0..n-1).to_a
end
def cards
#array
end
end
In this way:
Deck.new(5).cards
#=> [0, 1, 2, 3, 4]
So, change your tests to:
it "has parameter n = 0" do
expect(Deck.new(0).cards).to match_array([])
end
and so on...
UPDATE:
Deck.new(n) returns the whole object
Deck.new(5)
=> #<Deck:0x007fb56b0e82b0 #array=[0, 1, 2, 3, 4]>
For this reason your test will fail... The whole object is not the same as the content of #array ([0, 1, 2, 3, 4]).
UPDATE 2:
You can define any new method, for example the number os cards in a deck:
class Deck
def initialize (n=1)
#array = (0..n-1).to_a
end
def cards
#array
end
def number_of_cards
#array.size
end
end
Deck.new(5).number_of_cards
#=> 5

Related

Why index self instead of instance variable in bracket method

I have:
class Thing
def initialize
#array = [[0, 0, 0], [1, 1, 1]]
end
end
thing = Thing.new
The normal way to access an element in #array is to use [] as in:
#array[0][1] # => 0
I am trying to overwrite [] so as to get results like this:
position_array = [0, 1]
#array[position_array] # => 0
This is my attempt:
class Thing
def [](position_array)
index_row, index_col = position_array
#array[index_row][index_col]
end
def get_value(position_array)
#array[position_array] # doesn't work
# self[position_array] # does work
end
end
thing.get_value([0, 1])
# >> 'get_value': no implicit conversion of Array into Integer (TypeError)
Why do I need to index the Thing object in order to index #array?
Just think of message and receiver.
#array[position_array] sends the message [] to the receiver #array. #array is an instance of Array, so the method Array#[] gets invoked.
self[position_array] sends the message [] to the receiver self. Within instance methods, self refers to that instance. And because self is an instance of Thing, the method Thing#[] gets invoked.
Since Thing is a subclass of Object and not a subclass of Array (nothing wrong here, you shouldn't subclass Array anyway), your implementation of [] does not override Array#[]. Both methods are totally independent of each other, just like String#[] or Hash#[].
This is how I would approach it:
class Thing
def initialize
#array = [[1, 2, 3], [4, 5, 6]]
end
def [](i, j)
#array[i][j]
end
end
thing = Thing.new
thing[0, 1] #=> 2
thing[1, 1] #=> 5
You could use a prepended method to non-invasively override the [] method in Array by duck-typing the parameter passed to the [] method, and then calling the original if its not what you expect. Then you don't need a Thing object at all.
module MyArrayExtension
def [] (*param)
if param.size == 2
row, col = param
raise ArgumentError, 'Row must be an integer' if row.class != Integer
raise ArgumentError, 'Column must be an integer' if col.class != Integer
raise ArgumentError, "Element at row #{row} is not an array" if self[row].class != Array
self[row][col]
else
super
end
end
end
class Array
prepend MyArrayExtension
end
thing = [[1,2,3],[4,5,6]]
puts "The 2D array is: #{thing}"
puts "Extension used on the thing to get at element 1 of first array:"
puts thing[0,1]
puts '-' * 20
normal = [1,2,:blah,4,5]
puts "Normal array is #{normal}"
puts "Original [] method used to get the 3rd element:"
puts normal[2]
puts '-' * 20
puts "Using the extension on the non-2D array:"
puts normal[0,1]
The output of this program is:
The 2D array is: [[1, 2, 3], [4, 5, 6]]
Extension used on the thing to get at element 1 of first array:
2
--------------------
Normal array is [1, 2, :blah, 4, 5]
Original [] method used to get the 3rd element:
blah
--------------------
Using the extension on the non-2D array:
./test.rb:9:in `[]': Element at row 0 is not an array (ArgumentError)
from ./test.rb:35:in `<main>'

Error in sample ruby program to swap element in an array

I created a sample ruby program to swap elements in an array
class Swap
def swp(a,b)
self[a],self[b] = self[b],self[a]
self
end
array = [1,2,3]
array.swp(1,2)
puts array
end
I am getting the following error
NoMethodError: private method `swp' called for [1, 2, 3]:Array
from (irb):77:in `<class:Swap>'
from (irb):71
from /home/rahulv/.rvm/gems/ruby-2.0.0-p481/gems/railties-3.2.16/lib/rails/commands/console.rb:47:in `start'
from /home/rahulv/.rvm/gems/ruby-2.0.0-p481/gems/railties-3.2.16/lib/rails/commands/console.rb:8:in `start'
from /home/rahulv/.rvm/gems/ruby-2.0.0-p481/gems/railties-3.2.16/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
Please help to fix it.
UPDATE
I tried the same program with dynamic array input like this:
class Swap
def swp(a,b)
self[a],self[b] = self[b],self[a]
self
end
end
puts "enter the array elements "
input = gets.chomp
ary = []
while input != 'fin'
ary << input.to_i
input = gets.chomp
end
puts ary
puts "enter the elements to be swapped"
a=gets
b=gets
s=Swap.new
ary = ary.s.swp(a,b)
puts ary
Now the output error is like this:
enter the array elements
1
2
3
4
5
fin
enter the positions to be swapped
1
2
NoMethodError: private method `s' called for [0, 1, 2, 3, 4, 5]:Array
from (irb):17:in `<class:Swap>'
from (irb):1
from /home/rahulv/.rvm/gems/ruby-2.0.0-p481/gems/railties-3.2.16/lib/rails/commands/console.rb:47:in `start'
array.class = Array, you should add swp method for Array class.
class Array
def swp(a,b)
self[a],self[b] = self[b],self[a]
self
end
end
array = [1,2,3]
array.swp(0,1) #The array index start from 0, not 1
puts array.inspect
=> [2, 1, 3]
Update:
class Array
def swp(a,b)
self[a],self[b] = self[b],self[a]
self
end
end
puts "enter the array elements "
ary = []
input = 0
while 1
input = gets.chomp
if input != 'fin'
ary << input.to_i
else
break
end
end
puts "enter the positions to be swapped"
a=gets.to_i
b=gets.to_i
ary.swp(a,b)
puts ary.inspect
I don't like editing classes like that, for example if there's another class in the ancestor tree that implements the actual swp method (for any reason) and you implemented yours, and you try to use the actual documented one, you'll find unexplained behaviour, and it might be uneasy to figure out why it's behaving like that, beacuse your method is hiding, it's more maintainable if you add your methods to the ancestry tree using a module and then including it to the class.
module Swappable
def swp(a, b)
# method goes here
end
end
Then in another file you would do
class Array
include Swappable
end
This way when you call Array.ancestors you'd see your module
Array.ancestors
=> [Array, Swappable, ....]
And when you try something like
Array.instance_method(:swp).owner
you'll get Swappable, while an open class editing would return Array
This is just my oppinion on this matter, you can pick whatever works for you.
You can try the following code blog for take input an array and swap with two positions.
Here I initialize Swap class with an input array and then pass two swap position.
Main Class
class Swap
def initialize(array)
#array = array#[1,2,3,4,5]
end
def swp(a,b)
#array[a],#array[b] = #array[b],#array[a]
#array
end
end
Take Input for array
puts "ArrayInput :: Enter numbers separated by spaces, press 'Enter' to finish:"
array = gets
array = array.split(" ")
Take Input for swap positions
puts "SwapInput:: For FirstPosition, press 'Enter' to finish:"
first_position = gets.to_i
puts "SwapInput:: For SecondPosition, press 'Enter' to finish:"
second_position = gets.to_i
Initialize Swap Class
swap = Swap.new(array)
array = swap.swp(first_position, second_position)
puts "Array after swap:"
puts array

Linked List written in ruby

I'm preparing for a technical interview and will be asked to write the algorithm for a linked list in ruby. I understand linked lists completely, but have struggled writing the code. Can someone show me how this is done? I started it below..
class Node
def initialize(item)
#item = item
#next = nil
end
end
You almost did it, really. I can give you very old-school, Lisp-like implementation, if you are brave enough to show it to your interviewer. In this approach, list is a pair (two elements touple), which first element contains the element, and second contains another pair, etc, etc. The last pair have nil as a second element. And here is the whole implementation of the list in Ruby:
class Pair
attr_reader :car, :cdr
def initialize(car, cdr=nil)
#car = car
#cdr = cdr
end
end
To construct the list, just use a lot of parenthesis, like in old, good Lisp:
list = Pair.new(1, Pair.new(2, Pair.new(3)))
Now, the world is yours. You can do whatever you want with the list, using simple recursion. Here is an example of recursive inspect:
class Pair
def inspect
if cdr.nil?
car.inspect
else
"#{car.inspect}, #{cdr.inspect}"
end
end
end
pry(main)> list = Pair.new(1, Pair.new(2, Pair.new(3)))
=> 1, 2, 3
As you mentioned in a comment, you want to search the list. Here is the code for this:
class Pair
def find(index)
find_ index, 0
end
def find_(index, i)
if index == i
car
else
cdr.find_ index, i+1
end
end
end
pry(main)> list.find 2
=> 3
This is the standard Church Encoding of Lists (and Booleans):
True = ->(iff, _) { iff }
False = ->(_, els) { els }
Pair = ->(first, rest) { -> x { x.(first, rest) }}
First = -> list { list.(True ) }
Rest = -> list { list.(False) }
List = Pair.(1, Pair.(2, nil))
First.(Rest.(List))
# => 2
It's not what you would actually write in Ruby, of course, but it is very simple and demonstrates an understanding of one of the most important principles of programming: code is data and data is code.
Here's a more realistic object-oriented encoding of lists:
class List
include Enumerable
def self.[](*els) els.reverse_each.inject(Empty, &:cons) end
def cons(el) Pair[el, self] end
def prepend(prefix)
case
when empty? then prefix
when prefix.empty? then self
else prepend(prefix.rest).cons(prefix.first)
end
end
def to_s; "List[#{map(&:to_s).join(', ')}]" end
def inspect; "List[#{map(&:inspect).join(', ')}]" end
def each; return enum_for(__method__) unless block_given? end
class << Empty = new
def empty?; true end
alias_method :inspect, def to_s; 'Empty' end
freeze
end
Empty.freeze
class Pair < self
def initialize(first, rest=Empty)
self.first, self.rest = first, rest
freeze
end
def empty?; false end
def each(&blk)
return super unless block_given?
yield first
rest.each(&blk)
end
private
attr_writer :first, :rest
protected
attr_reader :first, :rest
class << self; alias_method :[], :new end
freeze
end
freeze
end
Note that there are absolutely no conditionals and no loops in the code. That is always a good sign for object-oriented code: polymorphic method calls are more powerful than conditionals anyway, oftentimes, there simply is no need for conditionals.
Some examples:
list1 = List::Pair[1, List::Pair[2, List::Pair[3, List::Empty]]]
# => List[1, 2, 3]
list2 = List::Empty.cons(6).cons(5).cons(4)
# => List[4, 5, 6]
list3 = List[7, 8, 9]
# => List[7, 8, 9]
list4 = list3.prepend(list2).prepend(list1)
# => List[1, 2, 3, 4, 5, 6, 7, 8, 9]
list4.partition(&:odd?)
# => [[1, 3, 5, 7, 9], [2, 4, 6, 8]]
Unfortunately, this object-oriented encoding will blow the stack for larger lists (on my system List[*(1..9338)].each {} still works, but 9339 doesn't), even though each is tail-calling itself and thus should run in O(1) stack space. As Guy L. Steele pointed out multiple times, OO languages must support proper tail calls, otherwise you are required to break OO in order to avoid blowing the stack. (prepend is not coded for tail-calls, but it can be rewritten that way.)

Create An Array Class With Certain Operation To Implement

I am currently working on a basic Ruby programming project, that focuses on creating classes, and operations on those classes. I have very little experience, but understand the general idea of Ruby.
My task is making an Array2 class. Creating arrays from the class, perform operations on the arrays. The methods I attempted are a to-string method, and a is-reverse method that has two array parameters, and tests if the first array is the reverse of the second array.
Here is my attempt, I tried but I am having trouble passing the arrays properly into the class. Also I believe that I am having some calling complications.
class Array2
def initialize (a)
#array = Array.new(a)
end
def to_s
return #array
end
def isreverse (array1,array2)
reverasea = Array.new
reverasea = array1.reverse
if (reversea = array2) then
return "The First Array Is The Reverse Of The Second Array"
else
return "The First Array Is Not The Reverse Of The Second Array"
end
end
end
array1 = ["4","5","6","7"]
array2 = ["7","6","5","3"]
a1 = Array2.new(array1)
a2 = Array2.new(array2)
puts a1.to_s
puts a2.to_s
puts a1.isreverse(array1, array2)
You have an assignment where you probably meant equality test:
if (reversea = array2) then
you could dispense with reversea entirely and just test (this requires a reverse method in Array2)
if (array1.reverse == #array) then
I would personally make isreverse a boolean, and eliminate the need to pass in the same array again:
def isreverse? (array1)
return (#array.reverse == array1)
end
then use it like
puts "The First Array Is#{a1.isreverse?(a2)?"":" Not"} The Reverse Of The Second Array"
put it all together and it looks like:
class Array2
def initialize (a)
#array = Array.new(a)
end
def to_s
return #array
end
def reverse
#array.reverse
end
def isreverse? (array1)
return (array1.reverse == #array)
end
end
array1 = ["4","5","6","7"]
array2 = ["7","6","5","3"]
a1 = Array2.new(array1)
a2 = Array2.new(array2)
puts a1.to_s
puts a2.to_s
puts "The First Array Is#{a1.isreverse?(a2)?"":" Not"} The Reverse Of The Second Array"
fiddle
Here are some adjustments to your existing approach. I put in comments where I changed the original::
class Array2
def initialize (a)
#array = Array.new(a)
end
def to_array # to_s is a misnomer: it doesn't return a string
return #array
end
def isreverse (a)
#reverasea = Array.new NOTE this is not needed; the following .reverse creates a new array for you
reversea = a.to_array.reverse # get the reverse of the array represented
# NOTE = is assign, == is compare in this case
# The following compares the reversed of the array `a` with the array value of this class, #array
if (reversea == #array) then
return "The First Array Is The Reverse Of The Second Array"
else
return "The First Array Is Not The Reverse Of The Second Array"
end
end
end
array1 = ["4","5","6","7"]
array2 = ["7","6","5","3"]
a1 = Array2.new(array1)
a2 = Array2.new(array2)
puts a1.to_array # (renamed)
puts a2.to_array # (renamed)
#puts a1.isreverse(array1, array2) NOTE you don't need to pass array1 into class a1 since it is already made from array1
puts a1.isreverse(a2)
I would go for something simpler such as:
Filename: reverser.rb
class Reverser
def self.is_reverse_of(array1,array2)
array1_reversed=array1.reverse
is_or_isnt= (array1_reversed==array2)? 'Not ' : ''
return "The First Array Is #{is_or_isnt}The Reverse Of The Second Array"
end
end
puts Reverser.is_reverse_of(["4","5","6","7"], ["7","6","5","4"])
puts Reverser.is_reverse_of(["4","5","6","7"], ["7","6","5","3"])
ruby reverser.rb
The First Array Is Not The Reverse Of The Second Array
The First Array Is The Reverse Of The Second Array
The idea being to use a class level method and not instantiate as much and have less code.

Rspec testing instance method which require other methods return (stubbing?)

I want those already methods to be tested, but everything I try, doesn't seem to fit with best practices nor do it work.
May be somebody can support me with this?
CODE To be tested
def any_subset_greater?
divisors_sums.any?{|sum| sum > #value}
end
def no_subset_equal?
!divisors_sums.any?{|sum| sum == #value}
end
def check_room
any_subset_greater? && no_subset_equal?
end
RSPEC TRY
first specify seems not to set proper return values for the divisors method and the instance variable #value.
describe "#any_subset_greater?" do
# Examples:
# [1,2] > 4 #=> false
# [1,2,3] > 4 #=> true
specify "returns true, when value in the array is greater" do
number.stub(:divisors){[1,2,3]}
number.stub(:value) {4}
expect(number.any_subset_greater?).to be_true
end
end
describe "#no_subset_equal?" do
# Examples:
# 4 === [1,2,4] #=> false
# 4 === [1,2,3] #=> false
# 4 === [1,2,6] #=> true
end
describe "#check_room" do
# testing condition from methods above
end
Without knowing how your object is setup, this answer is just a guess. I'm going to assume your object looks something like:
class SpecialNumber
attr_reader :divisor_sums
def initialize(n)
#value = n
# #divisor_sums is calculated here
end
# rest of your methods
end
So with this object in mind, the first set of tests could look like:
subject(:special_number) { SpecialNumber.new 4 }
describe "#any_subset_greater?" do
context "no divisor sums greater than value" do
it do
special_number.stub(:divisor_sums).and_return [1, 2]
expect(special_number.any_subset_greater?).to be_false
end
end
context "one divisor sum greater than value" do
it do
special_number.stub(:divisor_sums).and_return [1, 2, 5]
expect(special_number.any_subset_greater?).to be_true
end
end
context "several divisor sums greater than value" do
it do
special_number.stub(:divisor_sums).and_return [1, 2, 5, 6]
expect(special_number.any_subset_greater?).to be_true
end
end
end
But you don't have to stub this. If this is a simple class, simply creating a new object each time, which has expected divisors would be acceptable:
describe "#any_subset_greater?" do
context "no divisor sums greater than value" do
it do
expect(SpecialNumber.new(3).any_subset_greater?).to be_false
end
end
end

Resources