Ruby , I couldn't find how the following code actually works - ruby

class ArrayMine < Array
def join( sep = $,, format = "%s" )
collect do |item|
sprintf( format, item )
end.join( sep )
end
end
=> rooms = ArrayMine[3, 4, 6] #i couldn't understand how this line works
print "We have " + rooms.join( ", ", "%d bed" ) + " rooms available."
i have tried the same with String, but it comes up with an error.
thank you...

ArrayMine inherits from Array and you can initialize Ruby arrays like that.
>> rooms = Array[3,4,6]
=> [3, 4, 6]
is the same as
>> rooms = [3,4,6]
=> [3, 4, 6]
Also the quite strange looking def join( sep = $,, format = "%s" )
is using the pre-defined variable $, that is the output field separator for the print and Array#join.
It could also have been done like this
rooms=["b",52,"s"]
print "We have " + rooms.map{|s| s.to_s+" bed"}.join(", ") + " rooms available."
The reason you can't do what you are trying to do with String is because assignment is not a class method but [] on Array is. Just new it instead.
>> s = Substring.new("abcd")
=> "abcd"
>> s.checking_next
=> "abce"
You can't override assignment in Ruby, it's only so that setter methods looks like assignment but they are actually method calls and as such they can be overridden.
If you are feeling like being tricky and still want a similar behaviour as a=SubArray[1,2,3] you could create a << class method something like this:
class Substring < String
def next_next()
self.next().next()
end
def self.<<(val)
self.new(val)
end
end
>> sub = Substring<<"abcb"
=> "abcb"
>> sub.next_next
=> "abcd"
>> sub<<" the good old <<"
=> "abcb the good old <<"
>> sub.class<<"this is a new string"
=> "this is a new string"

For String, change %d bed to %s bed
irb(main):053:0> rooms = ArrayMine["a","b","c"]
=> ["a", "b", "c"]
irb(main):055:0> print "We have " + rooms.join( ", ", "%s bed" ) + " rooms available."
We have a bed, b bed, c bed rooms available.=> nil

You're just invoking a [] class method:
class Spam
def self.[]( *args )
p args
end
end
>> Spam[3,4,5]
[3, 4, 5]

Related

why i cant put inside an array all the characters i need?

i made a program and i need to put all the possible characters in an array.
here i create my variable just to read the name
print "write your name: "
name1 = gets.chomp
then i try to put all the character inside the array, for example if your name is John, the array would be: J,Jo,Joh,john
arrayNames = []
number = name1.length
number.times {|i|
arrayNames[i] = name1.slice(0,i)
}
arrayNames << name1
then to read it, i wanted to make a permutation program, i write:
numb = name1.length+ 1
numb2 = anotherVariable.length + 1
numb.times {|j|
numb2.times {|k|
perm = [arrayNames[j],theSecondArray[k]]
p perm
file1.puts
}
}
of course i had the file1 made, and i have the exactly same code for the second array than the arrayNamesbut is not working. it doesnt even show an error. ill put all the code together down below
class Data
def initialize
end
def dataIn
print "write your name: "
$name = gets.chomp
print "write your surname: "
$surname = gets.chomp
end
def dataName
$passwordName = []
numb = $name.length
numb.times {|i|
$passwordName[i] = $name.slice(0,i)
$passwordName << $name
end
def dataSurn
$passwordSur = []
numb = $surname.length
numb.times {|i|
$passwordSur[i] = $surname.slice(0,i)
}
$passwordSur << $surname
end
def alg1
numb = $name.length + 1
numb2 = $surname.length + 1
numb.times {|i|
numb2.times {|j|
perm = [$passwordName[i], $passwordSur[j]].permutation.map {|k|
k.join}
p perm
$archivos.puts perm
}
}
end
end
the code itself is a little bit more complicaded, but my question is the same. the method alg1 doesnt work.then i just call them and create the file
data = Data.new()
datos.dataIn
$archivos = File.new("passwords",'w+')
File.open("passwords")
data.datosName
data.datosSurn
data.alg1
gets()
I'm not sure exactly what you are trying to do, but Ruby's built-in Array methods will make your life much easier:
>> name1 = 'John'
=> "John"
>> names = (0...name1.length).map { |i| name1[0..i] }
=> ["J", "Jo", "Joh", "John"]
>> other = ['dog', 'wolf', 'sheep']
=> ["dog", "wolf", "sheep"]
>> result = names.product(other)
=> [["J", "dog"],
["J", "wolf"],
["J", "sheep"],
["Jo", "dog"],
["Jo", "wolf"],
["Jo", "sheep"],
["Joh", "dog"],
["Joh", "wolf"],
["Joh", "sheep"],
["John", "dog"],
["John", "wolf"],
["John", "sheep"]]

.split() method not working on ruby

I'm trying to make a simple algebra calculator app on ruby, but I encountered a problem while coding it. The .split method, which I was using to divide the equation into "sections" (separated by plus and minus signs), did split the equation, eq, with + signs, but it didn't with - signs.
eq = gets.chomp
a = []
a = eq.split("+")
a.each do |n|
case n
when n.include?("-")
a << n.split("-")
end
end
print a[0], ";", a[1]
I used the case when because if I did not, it returned a NoMethod Error. I already made a regular calculator, so I thought this would made a good next-project. I was also wondering if you had any idea to make my code shorter; maybe by creating a method. Below is my regular calculator's code, which I would also like to know how to make shorter.
loop do
print
equation = gets.chomp
if equation.include?"^"
exponent_e = equation.split("^")
result_e = exponent_e[0].to_f ** exponent_e[1].to_f
print " = #{result_e} "
puts
elsif equation.include?"%"
percent_e = equation.split("%")
number = percent_e[0].to_f / 100
result_p = number * percent_e[1].to_f
print " = #{result_p} "
puts
elsif equation.include?"/"
res_d = equation.split("/")
result_d = res_d[0].to_f / res_d[1].to_f
print " = #{result_d} "
puts
elsif equation.include?"*"
res_m = equation.split("*")
result_m = res_m[0].to_f * res_m[1].to_f
print " = #{result_m} "
puts
elsif equation.include?"+"
res_a = equation.split("+")
result_a = res_a[0].to_f + res_a[1].to_f
print " = #{result_a} "
puts
elsif equation.include?"-"
res_s = equation.split("-")
result_s = res_s[0].to_f - res_s[1].to_f
print " = #{result_s} "
puts
else
puts "Input valid equation"
end
end
The argument passed to the split method will split up your string by the argument passed and return an array with everything else all split up.
For example:
"a+b".split("+")
#=> ["a", "b"]
"c-d".split("+")
#=> ["c-d"]
"c-d".split("-")
#=> ["c", "d"]
I would probably refactor the code by either using OOP creating a class Calculator and then creating the methods for each functionality (i.e. plus, minus, divide, etc..). This would make the code more readable and easier to maintain.
Another cool thing to consider is using metaprogramming.
def calculate(fxn, arr_numbers)
if arr_numbers.size == 2
arr_numbers.send(:reduce, fxn)
end
end
Where fxn is a string (i.e. "+", "-", etc..), and arr_numbers is an array of 2 numbers, not strings (i.e. [2, 5])
You can expand this to take multiple numbers as well or add other functionality..

Convert array of Ruby hashes to JSON (pretty) not using stdlib?

As per the question, just wondering how to do this without the use of the Ruby stdlib 'JSON' module (and thus the JSON.pretty_generate method).
So I have an array of hashes that looks like:
[{"h1"=>"a", "h2"=>"b", "h3"=>"c"}, {"h1"=>"d", "h2"=>"e", "h3"=>"f"}]
and I'd like to convert it so that it looks like the following:
[
{
"h1": "a",
"h2": "b",
"h3": "c",
},
{
"h1": "d",
"h2": "e",
"h3": "f",
}
]
I can get the hash-rockets replaced with colon spaces using a simple gsub (array_of_hashes.to_s.gsub!(/=>/, ": ")), but not sure about how to generate it so that it looks like the above example. I had originally thought of doing this use a here-doc approach, but not sure this is the best way, plus i havn't managed to get it working yet either. I'm new to Ruby so apologies if this is obvious! :-)
def to_json_pretty
json_pretty = <<-EOM
[
{
"#{array_of_hashes.each { |hash| puts hash } }"
},
]
EOM
json_pretty
end
In general, working with JSON well without using a library is going to take more than just a few lines of code. That being said, the best way of JSON-ifying things is generally to do it recursively, for example:
def pretty_json(obj)
case obj
when Array
contents = obj.map {|x| pretty_json(x).gsub(/^/, " ") }.join(",\n")
"[\n#{contents}\n]"
when Hash
contents = obj.map {|k, v| "#{pretty_json(k.to_s)}: #{pretty_json(v)}".gsub(/^/, " ") }.join(",\n")
"{\n#{contents}\n}"
else
obj.inspect
end
end
This should work well if you input is exactly in the format you presented and not nested:
a = [{"h1"=>"a", "h2"=>"b", "h3"=>"c"}, {"h1"=>"d", "h2"=>"e", "h3"=>"f"}]
hstart = 0
astart = 0
a.each do |b|
puts "[" if astart == 0
astart+=1
b.each do |key, value|
puts " {" if hstart == 0
hstart += 1
puts " " + key.to_s + ' : ' + value
if hstart % 2 == 0
if hstart == a.collect(&:size).reduce(:+)
puts " }"
else
puts " },\n {"
end
end
end
puts "]" if astart == a.size
end
Output:
[
{
h1 : a
h2 : b
},
{
h3 : c
h1 : d
},
{
h2 : e
h3 : f
}
]
You can take a look at my NeatJSON gem for how I did it. Specifically, look at neatjson.rb, which uses a recursive solution (via a proc).
My code has a lot of variation based on what formatting options you supply, so it obviously does not have to be as complex as this. But the general pattern is to test the type of object supplied to your method/proc, serialize it if it's simple, or (if it's an Array or Hash) re-call the method/proc for each value inside.
Here's a far-simplified version (no indentation, no line wrapping, hard-coded spacing):
def simple_json(object)
js = ->(o) do
case o
when String then o.inspect
when Symbol then o.to_s.inspect
when Numeric then o.to_s
when TrueClass,FalseClass then o.to_s
when NilClass then "null"
when Array then "[ #{o.map{ |v| js[v] }.join ', '} ]"
when Hash then "{ #{o.map{ |k,v| [js[k],js[v]].join ":"}.join ', '} }"
else
raise "I don't know how to deal with #{o.inspect}"
end
end
js[object]
end
puts simple_json({a:1,b:[2,3,4],c:3})
#=> { "a":1, "b":[ 2, 3, 4 ], "c":3 }

Ruby: NoMethodError on call to display method

Greeting, I just started learning Ruby a few weeks with this noob book titled Computer Science Programming Basics in Ruby. I've practiced the exercises in each chapter, haven't had too many error, but I keep getting this error in a class I wrote up for the tic-tac-toe game in the last chapter. Here is the board.rb class file I made:
class Board
BOARD_MAX_INDEX = 2
EMPTY_POS = ' '
def initialize(current_player)
#current_player = current_player
#board = Array.new(BOARD_MAX_INDEX + 1) {
Array.new(BOARD_MAX_INDEX + 1) { EMPTY_POS }
}
end
end
def display
puts "+------+"
for row in 0..BOARD_MAX_INDEX
print "| "
for col in 0..BOARD_MAX_INDEX
s = #board[row][col]
if s == EMPTY_POS
print col + (row * 3) + 1
else
print s
end
print " | "
end
puts "\n+------+"
end
end
The class runs fine, but this is the error message in irb when I attempt to access
the display method call:
irb(main):004:0> require '/home/nick/board.rb'
=> true
irb(main):005:0> puts "Starting tic-tac-toe..."
Starting tic-tac-toe...
=> nil
irb(main):006:0> players = ['X', 'O']
=> ["X", "O"]
irb(main):007:0> current_player = players[rand(2)]
=> "O"
irb(main):008:0> b = Board.new(current_player)
=> #<Board:0x00000001c64868 #current_player="O", #board=[[" ", " ", " "], [" ", " ", " "], [" ", " ", " "]]>
irb(main):009:0> b.display()
NoMethodError: private method `display' called for #<Board:0x00000001c64868>
from (irb):9
from /usr/bin/irb:12:in `<main>'
Why am I getting this error, what do I have to do to get it to display the board?
You should put the definition of the display method inside the class:
end # of class
def display
...
end
Should be:
def display
...
end
end # of class
Hope it helps.

How do I use the for loop in ruby to grab different values from hash tables

This is probably easy to do! I'm not able envision the loop yet, I was thinking about a nested for loop but not quite sure how to alternate between the two hashes.
Lets say I have a class with a def that containts two hash tables:
class Teststuff
def test_stuff
letters = { "0" => " A ", "1" => " B ", "2" => " C " }
position = {"1" => "one ", "2"=> " two ", "3"=> " three ", "4"=>" four " }
my_array=[0,1,2,2] #this represents user input stored in an array valid to 4 elements
array_size = my_array.size #this represents the size of the user inputed array
element_indexer = my_array.size # parellel assignment so I can use same array for array in dex
array_start_index = element_indexer-1 #give me the ability later to get start at index zero for my array
#for loop?? downto upto??
# trying to get loop to grab the first number "0" in element position "0", grab the hash values then
# the loop repeats and grabs the second number "1" in element position "1" grab the hash values
# the loop repeats and grabs the third number "2" in elements position "2" grab the hash values
# the final iteration grabs the fourth number "2" in elements position "3" grab the hash values
# all this gets returned when called. Out put from puts statement after grabing hash values
# is: **A one B two C three C four**
return a_string
end
end
How do I go about returning string output to the screen like this:
**A one B two C three C four**
or simply letter position letter position...
Thanks for the help, put code up so I can try on my editor!
I think I figured out what it is you want, although I still have no idea what array_size, element_indexer, array_start_index and TestStuff are for.
def test_stuff
letters = { "0" => " A ", "1" => " B ", "2" => " C " }
position = {"1" => "one ", "2"=> " two ", "3"=> " three ", "4"=>" four " }
my_array = [0, 1, 2, 2]
"**#{my_array.map.with_index {|e, i|
"#{letters[e.to_s].strip} #{position[(i+1).to_s].strip}"
}.join(' ')}**"
end
[I took the liberty of reformatting your code to standard Ruby coding style.]
However, everything would be much simpler, if there weren't all those type conversions, and all those superfluous spaces. Also, the method would be much more useful, if it actually had a way to return different results, instead of always returning the same thing, because at the moment, it is actually exactly equivalent to
def test_stuff
'**A one B two C three C four**'
end
Something along these lines would make much more sense:
def test_stuff(*args)
letters = %w[A B C]
position = %w[one two three four]
"**#{args.map.with_index {|e, i| "#{letters[e]} #{position[i]}" }.join(' ')}**"
end
test_stuff(0, 1, 2, 2)
# => '**A one B two C three C four**'
If you don't want to pollute the Object namespace with your method, you could do something like this:
def (TestStuff = Object.new).test_stuff(*args)
letters = %w[A B C]
position = %w[one two three four]
"**#{args.map.with_index {|e, i| "#{letters[e]} #{position[i]}" }.join(' ')}**"
end
TestStuff.test_stuff(0, 1, 2, 2)
# => '**A one B two C three C four**'
You can use enumerators, like this:
l = letters.to_enum
p = position.to_enum
a_string = ''
loop do
a_string << l.next[1] << p.next[1]
end
How about :
a_string = ""
my_array.each_with_index { |x, index|
a_string += letters[my_array[index].to_s] + " " + (position.include?((index+1).to_s) ? position[(index+1).to_s] : "nil")
}

Resources