Basic URL opener in Ruby - ruby

I'm trying to create a simple ruby script that opens a bunch of URLs in Bing by looping through simple searches of the numbers 1-40, but when I run this in terminal I get:
"undefined method `<' for nil:NilClass (NoMethodError)"
#!/usr/bin/ruby
num = 0
target = 40
while start < target do
open("http://www.bing.com/search?q=" + $num)
num += 1
end
(Sorry if it's some simple mistake, this is my first ruby program.)
Update: **
Ok, thanks for catching that!
now it's giving me this error:
`+': can't convert Fixnum into String (TypeError)
how do I incorporate the two? Is there some type of parser like in Java?
Thank you Arup and Mischa!

Just do as below to fix your code :
while $num < $target do
open("http://www.bing.com/search?q=#{$num}")
$num += 1
end
You didn't define any where the variable $start. I think you should use there $num. I would recommend to use only local variable for this purposes, like num,target. Don't need global variables.
open("http://www.bing.com/search?q=" + $num) also wouldn't work. As you are trying to concat a number with a string. Either convert the number to a string using #to_s or use string interpolation, as I did below.
Without global variable write as :
while num < target do
open("http://www.bing.com/search?q=#{num}") # better
# or write as open( "http://www.bing.com/search?q=" + num.to_s )
num += 1
end

Related

Writing a Ruby class method and getting unexpected token kEND error

I am writing a class, Wrapper, and am giving it a class method self.wrap. I am getting an unexpected end-of-input error. I have been staring at the code forever and can't see where the mistake might be. I think I have all of my end's in place. What am I missing?
require 'pry'
class Wrapper
def self.wrap(input_string, column_number)
position = 0
num_inserted = 0
while (position + column_number < line.length) do
last_space_index = input_string.rindex(" ", position + column_number)
if last_space_index > position - 1
input_string[num_inserted + last_space_index] = "\n"
else
input_string.insert(num_inserted + position + column_number, "\n")
position += column_number
num_inserted ++
end
end
end
end
There is no ++ operator in Ruby.
Instead, you can write:
num_inserted = num_inserted + 1
Or for short:
num_inserted += 1
The error message you're seeing is admittedly quite confusing/misleading.
However, if you use an IDE with language-aware syntax highlighting (something I would highly recommend all programmers, in all languages, set up as a high priority for development) then this should at least highlight exactly which line of code is causing the problem.
For example, entering your code in my local setup reveals the error:
`+' after local variable or literal is interpreted as binary operator
even though it seems like unary operator

bad value in range argument error - regarding range construction in ruby

I wrote the following snippet.
def add_me(num)
result = 0
(1..num).each { |i| result += i}
result
end
puts add_me(STDIN.gets)
I received an argument error list_sum.rb:6:in 'AddMe': bad value for range (ArgumentError) the line # corresponds to line # in my editor.
I also experimented with things like foo = (1..num).to_a. But still receive the same error. What is going on? Ruby version 2.3.3. What am I missing? I should be able to use variables in ranges, no?
gets returns a string. You need to do gets.to_i, in order to turn the input into a number for your numeric range. Right now you’re trying to make a range where the start is the number 1 and the end is some string, and that is raising an ArgumentError.
Also as an aside, ruby convention would tell you that your function should be named add_me. Ruby uses snake case, and anything that starts with a capital letter is typically assumed to be a class or constant (constant being all caps).

undefined method `split' for nil:NilClass (NoMethodError) for an array

I am trying to read a file which contains some numbers. And then i want to convert them into integer. When i'm trying like below, it is ok.
input = IO.readlines(filename)
size = input[0].split(/\s/).map(&:to_i)
But, when i'm trying like below, it gives me that error.
input = IO.readlines(filename)
lnth = input.length
i=0
while i<=lnth
size = input[i].split(/\s/).map(&:to_i)
i=i+1
end
undefined method `split' for nil:NilClass (NoMethodError)
How I solve the error now?
Obviously while i<lnth not <=:
while i<lnth
size = input[i].split(/\s/).map(&:to_i)
i=i+1
end
but preferably use:
size = line.split(/\s/).map(&:to_i)
I wonder what this is supposed to do?
size = line.split(/\s/).map(&:to_i)
It will split a string like "321 123 432" and return an array like [321, 123, 432].
Also the variable size is initialized again on each round.
Ignoring that, here's a more Ruby-like version:
File.readlines(filename).each do |line|
size = line.split(/\s/).map(&:to_i)
end
In Ruby you don't usually use anything like for i in item_count .. or while i<item_count since we have the Enumerators like .each.
This should do it:
def nil.split *args
nil # splitting of nil, in any imaginable way, can only result again in nil
end
Convert it to string before splitting, i.e input[i].to_s.split(/\s/)
may be input[i] is nil, so convert it to string
ref

Plus equals with ruby send message

I'm getting familiar with ruby send method, but for some reason, I can't do something like this
a = 4
a.send(:+=, 1)
For some reason this doesn't work. Then I tried something like
a.send(:=, a.send(:+, 1))
But this doesn't work too. What is the proper way to fire plus equals through 'send'?
I think the basic option is only:
a = a.send(:+, 1)
That is because send is for messages to objects. Assignment modifies a variable, not an object.
It is possible to assign direct to variables with some meta-programming, but the code is convoluted, so far the best I can find is:
a = 1
var_name = :a
eval "#{var_name} = #{var_name}.send(:+, 1)"
puts a # 2
Or using instance variables:
#a = 2
var_name = :#a
instance_variable_set( var_name, instance_variable_get( var_name ).send(:+, 1) )
puts #a # 3
See the below :
p 4.respond_to?(:"+=") # false
p 4.respond_to?(:"=") # false
p 4.respond_to?(:"+") # true
a+=1 is syntactic sugar of a = a+1. But there is no direct method +=. = is an assignment operator,not the method as well. On the other hand Object#send takes method name as its argument. Thus your code will not work,the way you are looking for.
It is because Ruby doesn't have = method. In Ruby = don't work like in C/C++ but it rather assign new object reference to variable, not assign new value to variable.
You can't call a method on a, because a is not an object, it's a variable, and variables aren't objects in Ruby. You are calling a method on 4, but 4 is not the thing you want to modify, a is. It's just not possible.
Note: it is certainly possible to define a method named = or += and call it, but of course those methods will only exist on objects, not variables.
class Fixnum
define_method(:'+=') do |n| self + n end
end
a = 4
a.send(:'+=', 1)
# => 5
a
# => 4
This might miss the mark a bit, but I was trying to do this where a is actually a method dynamically called on an object. For example, with attributes like added_count and updated_count for Importer I wrote the following
class Importer
attr_accessor :added_count, :updated_count
def increment(method)
send("#{method}=", (send(method) + 1))
end
end
So I could use importer.increment(:added_count) or importer.increment(:updated_count)
Now this may seem silly if you only have these 2 different counters but in some cases we have a half dozen or more counters and different conditions on which attr to increment so it can be handy.

Read input from console in Ruby?

I want to write a simple A+B program in ruby, but I have no idea how to work with the console.
Are you talking about gets?
puts "Enter A"
a = gets.chomp
puts "Enter B"
b = gets.chomp
c = a.to_i + b.to_i
puts c
Something like that?
Update
Kernel.gets tries to read the params found in ARGV and only asks to console if not ARGV found. To force to read from console even if ARGV is not empty use STDIN.gets
you can also pass the parameters through the command line. Command line arguments are stores in the array ARGV. so ARGV[0] is the first number and ARGV[1] the second number
#!/usr/bin/ruby
first_number = ARGV[0].to_i
second_number = ARGV[1].to_i
puts first_number + second_number
and you call it like this
% ./plus.rb 5 6
==> 11
There are many ways to take input from the users. I personally like
using the method gets. When you use gets, it gets the string
that you typed, and that includes the ENTER key that you pressed
to end your input.
name = gets
"mukesh\n"
You can see this in irb; type this and you will see the \n, which is the “newline” character that the ENTER key produces:
Type name = gets you will see somethings like "mukesh\n"
You can get rid of pesky newline character using chomp method.
The chomp method gives you back the string, but without the terminating newline. Beautiful chomp method life saviour.
name = gets.chomp
"mukesh"
You can also use terminal to read the input. ARGV is a constant defined in the Object class. It is an instance of the Array class and has access to all the array methods. Since it’s an array, even though it’s a constant, its elements can be modified and cleared with no trouble. By default, Ruby captures all the command line arguments passed to a Ruby program (split by spaces) when the command-line binary is invoked and stores them as strings in the ARGV array.
When written inside your Ruby program, ARGV will take take a command line command that looks like this:
test.rb hi my name is mukesh
and create an array that looks like this:
["hi", "my", "name", "is", "mukesh"]
But, if I want to passed limited input then we can use something like this.
test.rb 12 23
and use those input like this in your program:
a = ARGV[0]
b = ARGV[1]
if you want to hold the arguments from Terminal, try the following code:
A = ARGV[0].to_i
B = ARGV[1].to_i
puts "#{A} + #{B} = #{A + B}"
If you want to make interactive console:
#!/usr/bin/env ruby
require "readline"
addends = []
while addend_string = Readline.readline("> ", true)
addends << addend_string.to_i
puts "#{addends.join(' + ')} = #{addends.sum}"
end
Usage (assuming you put above snippet into summator file in current directory):
chmod +x summator
./summator
> 1
1 = 1
> 2
1 + 2 = 3
Use Ctrl + D to exit

Resources