This piece of code is supposed to loop through an array of IP addresses and checks to see if a port is open.
class Ranger
def initialize(port,file)
#port = port
#file = file
#arr = []
end
def regex(f)
reg = IO.read(f)
reg.scan /(?:\d{1,3}\.){3}\d{1,3}/
end
def fileread
if File.exists?(#file)
#arr << regex(#file).to_s
begin
#arr.each do |ip|
sock = Socket.new(:INET, :STREAM)
sockaddr = Socket.sockaddr_in(#port, ip.to_i)
puts "Host: #{ip}:#{#port} Open" if sock.connect(sockaddr)
next
end
rescue Errno::ECONNREFUSED
false
end
end
end
end
The code seems to almost completely work, except for one thing. It prints out the success text i.e "Host: #{ip}:#{#port} Open". The problem is that it prints out the entire array where #{ip} is, like this: ["xx.xx.xx.xx","xx.xx.xx.xx","xx.xx.xx.xx"]:22 Open.
It seems to have something to do with the .to_s and .to_i in the script, but it won't work at all without those.
From what I can see you are only adding ONE thing to the #arr variable...
#arr << regex(#file).to_s
regex() calls string.scan () which returns an array (presumably your 3 IPs
you're then converting the array to a string and appending the string to #arr.
either you want
#arr = regex(#file) # replace
or
#arr += regex(#file) # concatenate
Related
I get the following error when running a simple method that takes in a proper noun string and returns the string properly capitalized.
def format_name(str)
parts = str.split
arr = []
parts.map do |part|
if part[0].upcase
else part[1..-1].downcase
arr << part
end
end
return arr.join(" ")
end
Test cases:
puts format_name("chase WILSON") # => "Chase Wilson"
puts format_name("brian CrAwFoRd scoTT") # => "Brian Crawford Scott"
The only possibility that the above code returns a blank output is because your arr is nil or blank. And the reason your arr is blank(yes it is blank in your case) because of this line of code:
if part[0].upcase
in which the statement would always return true, because with every iteration it would check if the first element of the part string can be upcased or not, which is true.
Hence, your else block never gets executed, even if this got executed this would have returned the same string as the input because you are just putting the plain part into the array arr without any formatting done.
There are some ways you can get the above code working. I'll put two cases:
# one where your map method could work
def format_name(str)
parts = str.split
arr = []
arr = parts.map do |part|
part.capitalize
end
return arr.join(" ")
end
# one where your loop code logic works
def format_name(str)
parts = str.split
arr = []
parts.map do |part|
arr << "#{part[0].upcase}#{part[1..-1].downcase}"
end
return arr.join(" ")
end
There are numerous other ways this could work. I'll also put the one I prefer if I am using just plain ruby:
def format_name(str)
str.split(' ').map(&:capitalize)
end
You could also read more about the Open Classes concept to put this into the String class of ruby
Also, checkout camelize method if you're using rails.
The below combined programs should ask for a number remove the first digit (lets call this new number x) and then compute x % 7. Ex: (1121546 % 7) = 5
This all appears to be working except that the number entered in will always compute to 0. modulo_7.rb works by itself and will print the correct outcome when passed a parameter.
The question is am I not passing the variables/ parameters properly or is there something else that is getting in the way?
class Number_check_interface
def get_cert_number
print "You are about to check receive the check number for a policy/cert id."
#cert_id = nil
until #cert_id.is_a?(Fixnum) do
puts " Enter the policy/cert ID. "
begin
#cert_id = Integer(gets)
rescue ArgumentError
end
end
end
end
class Run_number_check_interface
def run
load 'modulo_7.rb'
n = Number_check_interface.new
n.get_cert_number
checking_policy_number = Get_policy_check_digit.new(#cert_id)
checking_policy_number.create_check_digit
end
end
run = Run_number_check_interface.new
run.run
modulo_7.rb
This program removes the first digit (index 0) of a 7 digit number and returns the difference 7%18 is 4 since 4 is remainder of how many times 7 can fit into 18.
class Get_policy_check_digit
def initialize(cert_id)
#instance variable
#cert = cert_id
end
def create_check_digit
cert_id_6 = #cert.to_s
cert_id_6.slice!(0)
puts cert_id_6
check_digit = cert_id_6.to_i % 7
puts "Your check digit is #{check_digit}"
end
end
# n = Get_policy_check_digit.new(1121546) When uncommented this will create a new instance
# of Get_policy_check_digit with the parameter 1121546
# n.create_check_digit This will run the method create_check_digit with the
# parameter 1121546
Instance variables are scoped to an individual instance of a class. So when you say #cert_id = Integer(gets) inside Number_check_interface, you are only setting #cert_id for that particular instance of Number_check_interface. Then, when you later write Get_policy_check_digit.new(#cert_id) inside Run_number_check_interface, you are referring to an entirely different #cert_id, one which is specific to that particular instance of Run_number_check_interface, and not to the Number_check_interface you stored in n earlier.
The simple solution is to return #cert_id from Number_check_interface#get_cert_number, and then pass the returned value to Get_policy_check_digit.new:
class Number_check_interface
def get_cert_number
print "You are about to check receive the check number for a policy/cert id."
#cert_id = nil # This is an instance variable. It's only accessible
# from inside this instance of `Number_check_interface`
until #cert_id.is_a?(Fixnum) do
puts " Enter the policy/cert ID. "
begin
#cert_id = Integer(gets)
rescue ArgumentError
end
end
return #cert_id # Return the contents of #cert_id
end
end
class Run_number_check_interface
def run
load 'modulo_7.rb'
n = Number_check_interface.new
cert_number = n.get_cert_number # Here we call `get_cert_number` and
# set `cert_number` to it's return
# value.
# Notice how we use `cert_number` here:
checking_policy_number = Get_policy_check_digit.new(cert_number)
checking_policy_number.create_check_digit
end
end
Other tips:
Convention in Ruby is to name classes with CamelCase.
Require dependencies at the top of your files, not in the middle of method calls.
Unless you have a very good reason not to, use require, not load
You might want to think a bit harder about what purpose these classes serve, and what behavior they are intending to encapsulate. The API seems a bit awkward to me right now. Remember, tell, don't ask.
Why are these separate classes? The design here seems strange, is this ported from another language? It's more complicated than it needs to be. Without changing your structure, here's what's wrong:
In Run_number_check_interface you are reading #cert_id, it doesn't have an instance variable named that, but Number_check_interface does. Just return it from get_cert_number:
class Number_check_interface
def get_cert_number
print "You are about to check receive the check number for a policy/cert id."
cert_id = nil
until cert_id.is_a?(Fixnum) do
puts " Enter the policy/cert ID. "
begin
cert_id = Integer(gets)
rescue ArgumentError
end
end
cert_id # <-- returing the value here
end
end
class Run_number_check_interface
def run
load 'modulo_7.rb'
n = Number_check_interface.new
cert_id = n.get_cert_number # <-- saving here
checking_policy_number = Get_policy_check_digit.new(cert_id) # <-- no longer an ivar
checking_policy_number.create_check_digit
end
end
run = Run_number_check_interface.new
run.run
I'm trying to make a text editor in Ruby, but I don't know how to memorize an input with gets.chomp.
Here is my code so far:
outp =
def tor
text = gets.chomp
outp = "#{outp}" += "#{text}"
puts outp
end
while true
tor
end
Ordinary variables , like outp, in a method are only visible (AKA have scope) inside that method.
a = "aaa"
def x
puts a
end
x # =>error: undefined local variable or method `a' for main:Object
Why is that? For one thing, if you are writing a method and you need a counter, you can use a variable named i (or whatever) without worrying about other variables named i outside your method.
But... you want to interact with an outside variable in your method! This is one way:
#outp = "" # note the "", initializing #output to an empty string.
def tor
text = gets.chomp
#outp = #outp + text #not "#{#output}"+"#{text}", come on.
puts #outp
end
while true
tor
end
The # gives this variable a greater visisbility (scope).
This is another way: pass the variable as an argument. It is as saying to your method: "Here, work with this.".
output = ""
def tor(old_text)
old_text + gets.chomp
end
loop do #just another way of saying 'while true'
output = tor(output)
puts output
end
I've been sifting through the prior questions and answers on stackoverflow, and I have gotten most of my question figured out. I figured out that I can't place a function call within a hash, without placing it within a proc, or a similar container.
What I'm ultimately trying to do is have a menu displayed, grab user input, and then iterate through the hash, and run the specified function:
def Main()
menu_titles = {"Answer1" => Proc.new{Choice1()}}
Menu(menu_titles)
end
def Choice1()
puts "Response answer"
end
def Menu(menu_titles)
menu_titles.each_with_index do |(key, value),index|
puts "#{index+1}. #{key}"
end
user_input = 0
menu_titles.each_with_index do |(key, value), index|
if index.eql?(user_input)
menu_titles[value]
break
end
end
end
Main()
The issue I'm having right now is that I'm not entering the functions that my hash calls for. Whether I use a return or a "puts", I either get a blank line or nothing at all. If anyone has other recommendations about my code, I'm all ears also. To be honest, I don't like using procs, but that's mostly because I don't entirely know how they work and where to use them.
Right now for my menus I have:
user_input = 1
if user_input == 1
Choice1()
...
end
Here's how I would refactor this:
class Menu
attr_reader :titles
# initialize sets up a hard-coded titles instance variable,
# but it could easily take an argument.
def initialize
#titles = {
"Answer1" => Proc.new{ puts "choice 1" },
"Answer2" => Proc.new{ puts "choice 2" }
}
end
# This is the only public instance method in your class,
# which should give some idea about what the class is for
# to whoever reads your code
def choose
proc_for_index(display_for_choice)
end
private
# returns the index of the proc.
def display_for_choice
titles.each_with_index { |(key,value), index| puts "#{index + 1}. #{key}" }
gets.chomp.to_i - 1 # gets will return the string value of user input (try it in IRB)
end
# first finds the key for the selected index, then
# performs the hash lookup.
def proc_for_index(index)
titles[titles.keys[index]]
end
end
If you're serious about Ruby (or object-oriented programming in general), I would highly recommend learning about the advantages of packaging your code into behavior-specific classes. This example allows you to do this:
menu = Menu.new
proc = menu.choose
#=> 1. Answer1
#=> 2. Answer2
2 #(user input)
proc.call
#=> choice 2
And you could actually run it on one line:
Menu.new.choose.call
I'm creating a object of hash in order to write a little script that reads in a file a line at a time, and assigns arrays into my hash class. I get wildly different results depending if I subclass Hash or not, plus using super changes things which I don't' understand.
My main issue is that without subclassing hash ( < Hash) it works perfectly, but I get no methods of Hash (like to iterate over the keys and get things out of it.... Subclassing Hash lets me do those things, but it seems that only the last element of the hashed arrays is ever stored.... so any insight into how you get the methods of a subclass. The Dictionary class is a great example I found on this site, and does exactly what I want, so I'm trying to understand how to use it properly.
filename = 'inputfile.txt.'
# ??? class Dictionary < Hash
class Dictionary
def initialize()
#data = Hash.new { |hash, key| hash[key] = [] }
end
def [](key)
#data[key]
end
def []=(key,words)
#data[key] += [words].flatten
#data[key]
# super(key,words)
end
end
listData = Dictionary.new
File.open(filename, 'r').each_line do |line|
line = line.strip.split(/[^[:alpha:]|#|\.]/)
puts "LIST-> #{line[0]} SUB-> #{line[1]} "
listData[line[0]] = ("#{line[1]}")
end
puts '====================================='
puts listData.inspect
puts '====================================='
print listData.reduce('') {|s, (k, v)|
s << "The key is #{k} and the value is #{v}.\n"
}
If anyone understands what is going on here subclassing hash, and has some pointers, that would be excellent.
Running without explicit < Hash:
./list.rb:34:in `<main>': undefined method `reduce' for #<Dictionary:0x007fcf0a8879e0> (NoMethodError)
That is the typical error I see when I try and iterate in any way over my hash.
Here is a sample input file:
listA billg#microsoft.com
listA ed#apple.com
listA frank#lotus.com
listB evanwhite#go.com
listB joespink#go.com
listB fredgrey#stop.com
I can't reproduce your problem using your code:
d = Dictionary.new #=> #<Dictionary:0x007f903a1adef8 #data={}>
d[4] << 5 #=> [5]
d[5] << 6 #=> [6]
d #=> #<Dictionary:0x007f903a1adef8 #data={4=>[5], 5=>[6]}>
d.instance_variable_get(:#data) #=> {4=>[5], 5=>[6]}
But of course you won't get reduce if you don't subclass or include a class/module that defines it, or define it yourself!
The way you have implemented Dictionary is bound to have problems. You should call super instead of reimplementing wherever possible. For example, simply this works:
class Dictionary < Hash
def initialize
super { |hash, key| hash[key] = [] }
end
end
d = Dictionary.new #=> {}
d['answer'] << 42 #=> [42]
d['pi'] << 3.14 #=> [3.14
d #=> {"answer"=>[42], "pi"=>[3.14]}
If you want to reimplement how and where the internal hash is stored (i.e., using #data), you'd have to reimplement at least each (since that is what almost all Enumerable methods call to) and getters/setters. Not worth the effort when you can just change one method instead.
While Andrew Marshall's answer
already correct, You could also try this alternative below.
Going from your code, We could assume that you want to create an object that
act like a Hash, but with a little bit different behaviour. Hence our first
code will be like this.
class Dictionary < Hash
Assigning a new value to some key in the dictionary will be done differently
in here. From your example above, the assignment won't replace the previous
value with a new one, but instead push the new value to the previous or to
a new array that initialized with the new value if the key doesn't exist yet.
Here I use the << operator as the shorthand of push method for Array.
Also, the method return the value since it's what super do (see the if part)
def []=(key, value)
if self[key]
self[key] << value
return value # here we mimic what super do
else
super(key, [value])
end
end
The advantage of using our own class is we could add new method to the class
and it will be accessible to all of it instance. Hence we need not to
monkeypatch the Hash class that considered dangerous thing.
def size_of(key)
return self[key].size if self[key]
return 0 # the case for non existing key
end
Now, if we combine all above we will get this code
class Dictionary < Hash
def []=(key, value)
if self[key]
self[key] << value
return value
else
super(key, [value])
end
end
def size_of(key)
return self[key].size if self[key]
return 0 # the case for non existing key
end
end
player_emails = Dictionary.new
player_emails["SAO"] = "kirito#sao.com" # note no << operator needed here
player_emails["ALO"] = "lyfa#alo.com"
player_emails["SAO"] = "lizbeth#sao.com"
player_emails["SAO"] = "asuna#sao.com"
player_emails.size_of("SAO") #=> 3
player_emails.size_of("ALO") #=> 1
player_emails.size_of("GGO") #=> 0
p listData
#=> {"SAO" => ["kirito#sao.com", "lizbeth#sao.com", "asuna#sao.com"],
#=> "ALO" => ["lyfa#alo.com"] }
But, surely, the class definition could be replaced with this single line
player_emails = Hash.new { [] }
# note that we wont use
#
# player_emails[key] = value
#
# instead
#
# player_emails[key] << value
#
# Oh, if you consider the comment,
# it will no longer considered a single line
While the answer are finished, I wanna comment some of your example code:
filename = 'inputfile.txt.'
# Maybe it's better to use ARGF instead,
# so you could supply the filename in the command line
# and, is the filename ended with a dot? O.o;
File.open(filename, 'r').each_line do |line|
# This line open the file anonimously,
# then access each line of the file.
# Please correct me, Is the file will properly closed? I doubt no.
# Saver version:
File.open(filename, 'r') do |file|
file.each_line do |line|
# ...
end
end # the file will closed when we reach here
# ARGF version:
ARGF.each_line do |line|
# ...
end
# Inside the each_line block
line = line.strip.split(/[^[:alpha:]|#|\.]/)
# I don't know what do you mean by that line,
# but using that regex will result
#
# ["listA", "", "", "billg#microsoft.com"]
#
# Hence, your example will fail since
# line[0] == "listA" and line[1] == ""
# also note that your regex mean
#
# any character except:
# letters, '|', '#', '|', '\.'
#
# If you want to split over one or more
# whitespace characters use \s+ instead.
# Hence we could replace it with:
line = line.strip.split(/\s+/)
puts "LIST-> #{line[0]} SUB-> #{line[1]} "
# OK, Is this supposed to debug the line?
# Tips: the simplest way to debug is:
#
# p line
#
# that's all,
listData[line[0]] = ("#{line[1]}")
# why? using (), then "", then #{}
# I suggest:
listData[line[0]] = line[1]
# But to make more simple, actually you could do this instead
key, value = line.strip.split(/\s+/)
listData[key] = value
# Outside the block:
puts '====================================='
# OK, that's too loooooooooong...
puts '=' * 30
# or better assign it to a variable since you use it twice
a = '=' * 30
puts a
p listData # better way to debug
puts a
# next:
print listData.reduce('') { |s, (k, v)|
s << "The key is #{k} and the value is #{v}.\n"
}
# why using reduce?
# for debugging you could use `p listData` instead.
# but since you are printing it, why not iterate for
# each element then print each of that.
listData.each do |k, v|
puts "The key is #{k} and the value is #{v}."
end
OK, sorry for blabbering so much, Hope it help.