Ruby: How to convert IP range to array of IP's - ruby

Is there any easy way to convert IP range to array of IPs?
def convertIPrange (start_ip, end_ip)
#output: array of ips end
end
e.g. input
('192.168.1.105', '192.168.1.108')
output
['192.168.1.105','192.158.1.106','192.158.1.107','192.158.1.108']

Use the Ruby standard library IPAddr
# I would suggest naming your function using underscore rather than camelcase
# because of Ruby naming conventions
#
require 'ipaddr'
def convert_ip_range(start_ip, end_ip)
start_ip = IPAddr.new(start_ip)
end_ip = IPAddr.new(end_ip)
# map to_s if you like, you can also call to_a,
# IPAddrs have some neat functions regarding IPs,
# be sure to check them out
#
(start_ip..end_ip).map(&:to_s)
end

def convertIPrange first, last
first, last = [first, last]
.map{|s| s.split(".").inject(0){|i, s| i = 256 * i + s.to_i}}
(first..last).map do |q|
a = []
(q, r = q.divmod(256)) && a.unshift(r) until q.zero?
a.join(".")
end
end
convertIPrange('192.168.1.105', '192.168.1.108')
# => ["192.168.1.105", "192.168.1.106", "192.168.1.107", "192.168.1.108"]
convertIPrange('192.255.255.254', '193.0.0.1')
# => ["192.255.255.254", "192.255.255.255", "193.0.0.0", "193.0.0.1"]

Related

How to find duplicated Ruby methods with the same name but different code?

The very large Ruby codebase I am working with has many instances of duplicated methods defined with the same name but some of its code is different (causing a large race condition problem). The eventual end goal is to reconcile the duplicates and have just one version of the same-named method. First I need to find all versions of a method that deviate from the "control" version of that method. Is there an optimal way to search and for and find all instances of duplicated same-named methods that deviate from one defined version?
The duplicated methods are spread out across hundreds of different files and contained in one class. These are essentially helper methods that should have been centralized in one file but instead have been duplicated and often altered, but keeping the same method name. Right now I just need a good way to locate all the instances where these methods have been duplicated and are different from what the method should be.
I think Rubocop only searches for duplicated method names which is only moderately helpful since it could find 237 methods with the same name but I don't know how many of those methods are deviations from my "control" method without manually looking and comparing.
Some examples of a method redefined in files across multiple subdirectories:
def get_field(field_name)
return nil unless field = #global_vars.business.fields.find_by_identifier(field_name)
field.value.present? ? field.value : nil
end
def get_field(field_name)
#global_vars.business.fields.find_by_identifier(field_name).try(:value)
end
def get_field(field_name)
return nil unless field #company.fields.find_by_identifier(field_name)
field.value.present? ? field.value : nil
end
def get_field(field_name)
#property.fields.find_by_identifier(field_name).try(:value)
end
Thanks for your help!
My first thought was to execute each file of interest with additional code added on the fly to build a directory of methods and their locations. That clearly would not work, however, as exceptions could be expected to be raised almost immediately. Even if exceptions were avoided there would be no guarantee that that added code would be executed. In addition, there could be unintended adverse consequences of blinding running code.
I think the only reasonable approach would be to parse the files of interest. There may even be gems that do just that. It's certainly worth a search.
I have constructed a method that parses the files to build a hash containing the information desired. The main requirement for its use is that the files are formatted properly; specifically, the key words class, module and def must be indented the same number of spaces as their corresponding end keywords. It will therefore miss modules, classes and methods that are defined in-line, such as the following.
module M; end
class C; end
def im(n) 2*n end
def self.cm(n) 2*n end
If vertical alignment is a problem there certainly are gems that format code properly.
I chose a particular hash structure, but once that hash has been constructed it could be modified as desired. For example, I've adopted the hierarchy "instance methods->files->containers" ("containers" being modules, classes and top-level). One could easily modify that hash to change the hierarchy to, say, "container->module methods->files". Alternatively, one could enter the information into a database to maintain flexibility on how is used.
Code
The following regular expression is used to parse each line of each file of interest.
R = /
\A # match beginning of string
(?<indent>[ ]*) # capture zero or more spaces, name 'indent'
(?: # begin non-capture group
(?<type>class|module) # capture keyword 'class' or 'module', name 'type'
[ ]+ # match one or more spaces
(?<name>\p{Upper}\p{Alnum}*) # capture an uppercase letter followed by
# >= alphanumeric chars, name 'name'
| # or
(?<type>def) # capture keyword 'def', name 'type'
[ ]+ # match one or more spaces
(?<name> # begin capture group named 'name'
(?:self\.)? # optionally match 'self.'
\p{Lower}\p{Alnum}* # match a lowercase letter followed by
# >= 0 zero alphanumeric chars, name 'name'
) # close capture group 'name'
| # or
(?<type>end) # capture keyword 'end', name 'type'
\b # match a word break
) # end non-capture group
/x # free-spacing regex definition mode
The method used for parsing follows.
def find_methods_by_name(files_of_interest)
files_of_interest.each_with_object({ imethod: {}, cmethod: {} }) do |fname, h|
stack = []
File.readlines(fname).each do |line|
m = line.match R
next if m.nil?
indent, type, name = m[:indent].size, m[:type], m[:name]
case type
when "module", "class"
name = stack.any? ? [stack.last[:name], name].join('::') : name
stack << { indent: indent, type: type, name: name }
when "def"
if name =~ /\Aself\./
stack << { indent: indent, type: :cmethod, name: name[5..-1] }
else
stack << { indent: indent, type: :imethod, name: name }
end
when "end"
next if stack.empty? || stack.last[:indent] != indent
type, name = stack.pop.values_at(:type, :name)
next if type == "module" or type == "class"
((h[type][name] ||= {})[fname] ||= []) << (stack.any? ?
[stack.last[:type], stack.last[:name]].join(' ') : :main)
end
end
raise StandardError, "stack = #{stack} after processing file '#{fname}'" if stack.any?
end
end
Example
The files of interest might be, for example, all files in certain directories. In this example we have just two files.
files_of_interest = ['file1.rb', 'file2.rb']
Those files are as follows.
File.write('file1.rb',
<<_)
def mm
end
module M
def m
end
module N
def self.nm
end
def n
end
def a2
end
end
end
class A
def self.a1c
end
def a1
end
def a2
end
end
class B
include M
def b
end
end
_
#=> 327
File.write('file2.rb',
<<_)
def mm
end
module M
def m
end
module N
def n
end
def a2
end
end
end
module P
def p
end
end
class A
include M::N
def self.a1c
end
def a1
end
end
class B
include P
def b
end
end
_
#=> 335
h = find_methods_by_name(files_of_interest)
#=> {
# :imethod=>{
# "mm"=>{
# "file1.rb"=>[:main],
# "file2.rb"=>[:main]
# },
# "m"=>{
# "file1.rb"=>["module M"],
# "file2.rb"=>["module M"]
# },
# "n"=>{
# "file1.rb"=>["module M::N"],
# "file2.rb"=>["module M::N"]
# },
# "a2"=>{
# "file1.rb"=>["module M::N", "class A"],
# "file2.rb"=>["module M::N"]
# },
# "a1"=>{
# "file1.rb"=>["class A"],
# "file2.rb"=>["class A"]
# },
# "b"=>{
# "file1.rb"=>["class B"],
# "file2.rb"=>["class B"]
# },
# "p"=>{
# "file2.rb"=>["module P"]
# }
# },
# :cmethod=>{
# "nm"=>{
# "file1.rb"=>["module M::N"]
# },
# "a1c"=>{
# "file1.rb"=>["class A"],
# "file2.rb"=>["class A"]
# }
# }
# }
To eliminate files that appear only once, we can perform an additional step.
h.transform_values! { |g| g.reject { |k,v| v.size == 1 && v.values.first.size == 1 } }
This removes the instance method p and the class method nm.

Casting by a variable of class

I can cast a string to float via:
Float("1")
Now I have this:
f = Float
How can I use f to cast a string to float?
Edited
I'm sorry for not being clear.
Here is my scenario:
I'm using Redis DB, via gem redis-rb. Basically redis-db stores values as strings. When I map back values from DB to my objects, I wish to cast them to some primitive types for easy to use.
So I use this:
require 'ostruct'
class Person < OpenStruct
MAP = { :name => String, :age => Fixnum }
##
# This reads data from DB, and converts them to some "primitive" types
# for easy use.
#
def read
MAP.each_pair do |sym, cls|
# read data as string from DB, via key `sym.to_s`
s = ...
# now I have `cls`, how can I "cast" `s` to `cls`?
self[sym] = ???
# I know I can "iterate" all types by this:
#
# if cls.is_a? Float
# self[sym] = s.to_f
# elsif cls.is_a? Fixnum
# self[sym] = s.to_i
# ...
#
# But in Python I can just cast `s` to `cls` in one line...
# So I wonder if there is some way to cast `s` to `cls` in Ruby?
end
end # read
end # Person
Saying "for easy use", I mean I want to:
p = Person.new
p.read
# I want to access `age` as an integer, not a string
if p.age +-*/ ...
You cannot use f to do it. The Float in Float("1") is a method. The Float in f = Float is a class (an object). They are different things.
For what I understood from your question you want this:
result = '1'.to_f #outputs => 1.0
then for string:
result.to_s #outputs => "1.0"
And you can also do it in one step as well:
'1'.to_f.to_s #outputs => "1.0"
For more about strings and ruby you can see ruby doc

Can I use methods for String class within the String class in Ruby?

My new method for a string object in ruby is supposed to return a hash of the count of each character within a string (loaded in from a .txt file) and I am probably trying to go about it the easy way, however I can't seem to make it work without passing the object. I was wondering if there was a way to do this without passing a string. Any help would be appreciated.
Here is my code
class String
def frequency
Object.downcase
Object.gsub("\n", " ")
h = {}
h["A:"] = Object.count('a')
h["B:"] = Object.count('b')
h["C:"] = Object.count('c')
h["D:"] = Object.count('d')
h["E:"] = Object.count('e')
h["F:"] = Object.count('f')
h["G:"] = Object.count('g')
h["H:"] = Object.count('h')
h["I:"] = Object.count('i')
h["J:"] = Object.count('j')
h["K:"] = Object.count('k')
h["L:"] = Object.count('l')
h["M:"] = Object.count('m')
h["N:"] = Object.count('n')
h["O:"] = Object.count('o')
h["P:"] = Object.count('p')
h["Q:"] = Object.count('q')
h["R:"] = Object.count('r')
h["S:"] = Object.count('s')
h["T:"] = Object.count('t')
h["U:"] = Object.count('u')
h["V:"] = Object.count('v')
h["W:"] = Object.count('w')
h["K:"] = Object.count('x')
h["Y:"] = Object.count('y')
h["Z"] = Object.count('z')
return h
end
end
Sounds like you are talking about self, which is the ruby keyword that refers to the current object. Note that self is implied if you just call the method. So to use your example
class String
def frequency
count('a')
end
end
would return the number of as in the string
"asdfa".frequency #=> 2
Just a note, but your current method is very repetitive, and you might want to think about taking advantage of a loop to reduce the amount of code. Also you are not counting capital letters :)
Rather than a very long, un-DRY method that iterates your object 26 times, how about using some Ruby:
def frequency
Hash[downcase.gsub(/[^a-z]/,'').chars.group_by(&:to_s).map{|char, group| ["#{char.upcase}:", group.size]}]
end
You can break this apart onto separate lines if you find it easier to read (and to look up the methods in the API [1]):
def frequency
intermediate_variable = downcase
intermediate_variable = intermediate_variable.gsub(/[^a-z]/,'') # only keep a-z characters
intermediate_variable = intermediate_variable.chars.group_by(&:to_s) # split the string into its component characters and then group that array by the characters (run this on an array to see what it does :-) could also have written it `.group_by{|e|e}`
intermediate_variable = intermediate_variable.map{|char, group| ["#{char.upcase}:", group.size]} # map the array of grouped characters into an array of character and counts (formatting the 'character' how you would like your hash key configured
Hash[intermediate_variable] # make a hash of the characters and their counts
end
[1] http://ruby-doc.org/core-2.0.0/Enumerable.html http://ruby-doc.org/core-2.0.0/String.html
Here is the version I used which is a complete copy of the Rosetta Letter Frequency:
#!/usr/bin/env ruby
def letter_frequency(string)
freq = Hash.new(0)
string.each_char.lazy.grep(/[[:alpha:]]/).map(&:upcase).each_with_object(freq) do |char, freq_map|
freq_map[char] += 1
end
end
In ruby you can just open the class and add the method, like:
class String
def my_method
my_method_code
end
end
Then you just call the method string.my_method. However in your case I would rather use a Ruby module. Here is a code sample, very similar to a class but cleaner imho:
#!/usr/bin/env ruby
module MyString
def self.letter_frequency(string)
freq = Hash.new(0)
string.each_char.lazy.grep(/[[:alpha:]]/).map(&:upcase).each_with_object(freq) do |char, freq_map|
freq_map[char] += 1
end
return freq
end
end
p MyString.letter_frequency('absd')
Modules are more suited for adding your own classes into projects avoiding name colliding and creating mixins.
I would just create a hash like this:
class String
def frequency
chars.each_with_object(Hash.new(0)) do |char, h|
h["#{char.upcase}:"] += 1 if char[/[[:alpha:]]/]
end
end
end

Subclassing Ruby Hash, object has no methods of Hash?

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.

Reading strings from one file and adding to another file with suffix to make unique

I am processing documents in ruby.
I have a document I am extracting specific strings from using regexp and then adding them to another file. When added to the destination file they must be made unique so if that string already exists in the destination file I'am adding a simple suffix e.g. <word>_1. Eventually I want to be referencing the strings by name so random number generation or string from the date is no good.
At present I am storing each word added in an array and then everytime I add a word I check the string doesn't exist in an array which is fine if there is only 1 duplicate however there might be 2 or more so I need to check for the initial string then loop incrementing the suffix until it doesn't exist, (I have simplified my code so there may be bugs)
def add_word(word)
if #added_words include? word
suffix = 1
suffixed_word = word
while added_words include? suffixed_word
suffixed_word = word + "_" + suffix.to_s
suffix += 1
end
word = suffixed_word
end
#added_words << word
end
It looks messy, is there a better algorithm or ruby way of doing this?
Make #added_words a Set (don't forget to require 'set'). This makes for faster lookup as sets are implemented with hashes, while still using include? to check for set membership. It's also easy to extract the highest used suffix:
>> s << 'foo'
#=> #<Set: {"foo"}>
>> s << 'foo_1'
#=> #<Set: {"foo", "foo_1"}>
>> word = 'foo'
#=> "foo"
>> s.max_by { |w| w =~ /#{word}_?(\d+)?/ ; $1 || '' }
#=> "foo_1"
>> s << 'foo_12' #=>
#<Set: {"foo", "foo_1", "foo_12"}>
>> s.max_by { |w| w =~ /#{word}_?(\d+)?/ ; $1 || '' }
#=> "foo_12"
Now to get the next value you can insert, you could just do the following (imagine you already had 12 foos, so the next should be a foo_13):
>> s << s.max_by { |w| w =~ /#{word}_?(\d+)?/ ; $1 || '' }.next
#=> #<Set: {"foo", "foo_1", "foo_12", "foo_13"}
Sorry if the examples are a bit confused, I had anesthesia earlier today. It should be enough to give you an idea of how sets could potentially help you though (most of it would work with array too, but sets have faster lookup).
Change #added_words to a Hash with a default of zero. Then you can do:
#added_words = Hash.new(0)
def add_word( word)
#added_words[word] += 1
end
# put it to work:
list = %w(test foo bar test bar bar)
names = list.map do |w|
"#{w}_#{add_word(w)}"
end
p #added_words
#=> {"test"=>2, "foo"=>1, "bar"=>3}
p names
#=>["test_1", "foo_1", "bar_1", "test_2", "bar_2", "bar_3"]
In that case, I'd probably use a set or hash:
#in your class:
require 'set'
require 'forwardable'
extend Forwardable #I'm just including this to keep your previous api
#elsewhere you're setting up your instance_var, it's probably [] at the moment
def initialize
#added_words = Set.new
end
#then instead of `def add_word(word); #added_words.add(word); end`:
def_delegator :added_words, :add_word, :add
#or just change whatever loop to use ##added_words.add('word') rather than self#add_word('word')
##added_words.add('word') does nothing if 'word' already exists in the set.
If you've got some attributes that you're grouping via these sections, then a hash might be better:
#elsewhere you're setting up your instance_var, it's probably [] at the moment
def initialize
#added_words = {}
end
def add_word(word, attrs={})
#added_words[word] ||= []
#added_words[word].push(attrs)
end
Doing it the "wrong way", but in slightly nicer code:
def add_word(word)
if #added_words.include? word
suffixed_word = 1.upto(1.0/0.0) do |suffix|
candidate = [word, suffix].join("_")
break candidate unless #added_words.include?(candidate)
end
word = suffixed_word
end
#added_words << word
end

Resources