Warning message with Nokogiri and Open-Uri - ruby

Hello I have an error message which is the following :
warning: calling URI.open via Kernel#open is deprecated, call URI.open directly or use URI#open
I don't understand why there is this message, I also tried the URI.open ("link") command. Read
But I have to use Nokogiri.
Here is my code:
require 'nokogiri'
require 'open-uri'
puts "Wait a second data is coming..."
PAGE_URL = "https://coinmarketcap.com/all/views/all/"
page = Nokogiri::HTML(open(PAGE_URL))
currency_name_array = page.xpath("//tr/td/a[contains(#class, 'currency-name-container')]/text()").map {|x| x.to_s }
currency_value_array = page.xpath("//tr/td/a[contains(#class, 'price')]/text()").map {|x| x.to_s }
currency_result = Hash[currency_name_array.zip(currency_value_array)]
puts currency_result
Thanks in advance.

Related

How to fix Ruby Rack SessionId error Error: undefined class/module Rack::Session::SessionId when decoding the rack.session cookie

While writing a ruby script to decode rack session cookies and load the object using the ruby function Marshal load, I am getting the following error:
Error: undefined class/module Rack::Session::SessionId
This is my ruby script:
require 'pp'
require 'base64'
require 'uri'
require 'rack' # solves the error: Error: undefined class/module Rack::
c = gets
cookie, signature = c.split("--")
decoded = Base64.decode64(URI.decode(cookie))
begin
object = Marshal.load(decoded)
pp object
rescue ArgumentError => e
puts "Error: " + e.to_s
end
How do I fix this? I tried looking for solutions on stackoverflow but couldn't figure it out.
Thanks to Louis Nyffenegger (#snyff) who helped me with this
https://twitter.com/snyff/status/1407054131697758211?s=20
This error can be solved by creating a method stub
require 'pp'
require 'base64'
require 'uri'
require 'rack'
class Rack::Session::SessionId
end
c = gets
cookie, signature = c.split("--")
decoded = Base64.decode64(URI.decode(cookie))
begin
object = Marshal.load(decoded)
pp object
rescue ArgumentError => e
puts "Error: " + e.to_s
end
Try clearing all of the cookies for the site.
I think this works because something is causing an exception while loading the Rack::Session::SessionId class.
This type of error happens occasionally when working on Rails applications. A SyntaxError (or any other exception) inside a class definition (e.g. in a model) can then cause an undefined class/module error instead of the real error.

Ruby script sending received email as sms

I have a simple ruby script meant to send all received messages as sms messages. However, somehow for some reason it does not execute.
Here is the sample code;
/etc/aliases
motor: "|/home/motorcare/sms_script.rb"
sms_script.rb
#!/usr/bin/env ruby
require "json"
require "httparty"
require 'net/http'
require 'uri'
require "cgi"
require "mail"
# Reading files
mail = Mail.read(ARGV[0])
destination = mail.subject
message = mail.body.decoded
#first_line = lines[0].strip
if destination =~ /^(256)/
send(destination, message)
else
destination = "256#{destination.gsub(/^0+/,"")}"
send(destination, message)
end
# Sending message
def send(destination, message)
url = "http://xxxxxxxxxx.com/messages?token=c19ae2574be1875f0fa09df13b0dde0b&to=#{phone_number}&from=xxxxxx&message=#{CGI.escape(message)}"
5.times do |i|
response = HTTParty.get(url)
body = JSON.parse(response.body)
if body["status"] == "Success"
break
end
end
end
Anyone with a similar script to assist with this one?
You have 2 errors.
1st error is that send is already defined in Ruby. See this SO post What does send() do in Ruby?
see this code
$ cat send.rb
#!/usr/bin/env ruby
puts defined? send
puts send :class
$ ./send.rb
method
Object
2nd error is that you call the method before it's even defined. See this sample code (calling welcome before def welcome)
$ cat welcome.rb
#!/usr/bin/env ruby
welcome('hello from welcome')
def welcome(msg)
puts msg
end
$ ./welcome.rb
./welcome.rb:3:in `<main>': undefined method `welcome' for main:Object (NoMethodError)
Change the method name from send to something else, e.g. send_sms, and put the definition before calling the method
So this should be sth like:
#!/usr/bin/env ruby
require "json"
require "httparty"
require 'net/http'
require 'uri'
require "cgi"
require "mail"
# Sending message
def send_sms(destination, message)
url = "http://xxxxxxxxxx.com/messages?token=c19ae2574be1875f0fa09df13b0dde0b&to=#{phone_number}&from=xxxxxx&message=#{CGI.escape(message)}"
5.times do |i|
response = HTTParty.get(url)
body = JSON.parse(response.body)
if body["status"] == "Success"
break
end
end
end
# Reading files
mail = Mail.read(ARGV[0])
destination = mail.subject
message = mail.body.decoded
#first_line = lines[0].strip
if destination =~ /^(256)/
send_sms(destination, message)
else
destination = "256#{destination.gsub(/^0+/,"")}"
send_sms(destination, message)
end
And also adding logging to the script would give you info about what's going in inside when it's run and pipped. So you can easily debug the beaviour. Logging is the easies approach to DEBUG.

Em-synchrony sample code not working as expected

The em-synchrony documentation links to this article which implies that this code with fiber:
require 'eventmachine'
require 'fiber'
require 'em-http-request'
def http_get(url)
f = Fiber.current
http = EventMachine::HttpRequest.new(url).get
# resume fiber once http call is done
http.callback { f.resume(http) }
http.errback { f.resume(http) }
return Fiber.yield
end
EventMachine.run do
Fiber.new {
page = http_get('http://myurl')
puts "Fetched page: #{page.response}"
EventMachine.stop
}.resume
end
...is equivalent to this much simpler code using em-synchrony:
require 'em-synchrony'
require 'em-http-request'
EventMachine.synchrony do
page = EventMachine::HttpRequest.new("http://myurl").get
p "No callbacks! Fetched page: #{page.response}"
EventMachine.stop
end
However running the two produces different results. In the first the fiber yields until the HTML response comes back, while the second seems to print immediately without waiting for the response and as a result the printed response is empty. Am I misreading or mistyping, or is the article actually suggesting the wrong thing?
You need to use extended version of EventMachine::HttpRequest that knows how to work with EventMachine.synchrony.
Change
require 'em-http-request'
to
require "em-synchrony/em-http"
This in turn will require "em-http-request" and will patch #get, #head, #post, #delete, #put methods of EventMachine::HttpRequest to work with Fibers.
Here is the link to source code of em-synchrony/em-http.

Convert to string/text ruby

I'm using the following code to download a page through a POST request:
require 'net/http'
require 'uri'
res = Net::HTTP.post_form(URI.parse('http://example.com'),{'post'=>'1'})
puts res.split("Date")
The URL I originally used has been replaced with example.com
It works great, but when I try to call split (last line) it returns an error:
<main>': undefined methodsplit' for # (NoMethodError)
I'm new to ruby, so I'm confused about this error.
The method you are calling returns a HTTPResponse object, so you need to leverage that object's methods to get what you want. maybe something like:
require 'net/http'
require 'uri'
res = Net::HTTP.post_form(URI.parse('http://example.com'),{'post'=>'1'})
puts res.body.split("Date")
Notice the body method.
Or, if you want to see all the data returned:
require 'net/http'
require 'uri'
res = Net::HTTP.post_form(URI.parse('http://example.com'),{'post'=>'1'})
puts res.inspect
Hope this helps!

Retrieve contents of URL as string

For tedious reasons to do with Hpricot, I need to write a function that is passed a URL, and returns the whole contents of the page as a single string.
I'm close. I know I need to use OpenURI, and it should look something like this:
require 'open-uri'
open(url) {
# do something mysterious here to get page_string
}
puts page_string
Can anyone suggest what I need to add?
You can do the same without OpenURI:
require 'net/http'
require 'uri'
def open(url)
Net::HTTP.get(URI.parse(url))
end
page_content = open('http://www.google.com')
puts page_content
Or, more succinctly:
Net::HTTP.get(URI.parse('http://www.google.com'))
The open method passes an IO representation of the resource to your block when it yields. You can read from it using the IO#read method
open([mode [, perm]] [, options]) [{|io| ... }]
open(path) { |io| data = io.read }
require 'open-uri'
open(url) do |f|
page_string = f.read
end
See also the documentation of IO class
I was also very confused what to use for better performance and speedy results. I ran a benchmark for both to make it more clear:
require 'benchmark'
require 'net/http'
require "uri"
require 'open-uri'
url = "http://www.google.com"
Benchmark.bm do |x|
x.report("net-http:") { content = Net::HTTP.get_response(URI.parse(url)).body if url }
x.report("open-uri:") { open(url){|f| content = f.read } if url }
end
Its result is:
user system total real
net-http: 0.000000 0.000000 0.000000 ( 0.097779)
open-uri: 0.030000 0.010000 0.040000 ( 0.864526)
I'd like to say that it depends on what your requirement is and how you want to process.
To make code a little clearer, the OpenURI open method will return the value returned by the block, so you can assign open's return value to your variable. For example:
xml_text = open(url) { |io| io.read }
Starting with Ruby 3.0, calling URI.open via Kernel#open has been removed, so instead call URI.open directly:
require 'open-uri'
page_string = URI.open(url, &:read)
Try the following instead:
require 'open-uri'
content = URI(your_url).read
require 'open-uri'
open(url) {|f| #url must specify the protocol
str = f.read()
}

Resources