URI.parse documentation - ruby

In the documentation for URI.parse is the following code:
require 'uri'
uri = URI.parse("http://www.ruby-lang.org/")
p uri
# => #<URI::HTTP:0x202281be URL:http://www.ruby-lang.org/>
I'm wondering why, in the example, there is the letter p, e.g. p uri.
Also, how is using .parse different from doing uri = URI("http://..."), as in the example at the top of the page?

It seems URI(url) and URI.parse(url) do exactly the same:
u1 = URI("http://stackoverflow.com/")
u2 = URI.parse("http://stackoverflow.com/")
u1 == u2 # => true

Related

How to concatenate url + string + value ? ruby

Trying to parse through all pages in category of products. I want to check every page using original_url+'&p='+value, where value is number of pages.
How to write this properly full_source = url + "&p=" + "#{number_of_page}" ``
I think you want
full_source = "#{url}?p=#{number_of_page}"
Your question had an ampersand:
full_source = "#{url}&p=#{number_of_page}"
A better way to do it would be:
uri = URI.parse(url)
uri.query = URI.encode_www_form({ p: number_of_page })
puts uri.to_s # URL with query params
Here is an example:
url = 'http://google.com/search'
uri = URI.parse(url)
uri.query = URI.encode_www_form({ q: 'ruby' })
puts uri.to_s
# => "http://google.com/search?q=ruby""

Undefined method 'host' in rspec

I have the following methods in a Ruby script:
def parse_endpoint(endpoint)
return URI.parse(endpoint)
end
def verify_url(endpoint, fname)
url = “#{endpoint}#{fname}”
req = Net::HTTP.new(url.host, url.port)
res = req.request_head(url.path)
if res.code == “200”
true
else
puts “#{fname} is an invalid file”
false
end
end
Testing the url manually like so works fine (returns true since the url is indeed valid):
endpoint = parse_endpoint('http://mywebsite.com/mySubdirectory/')
verify_url(endpoint, “myFile.json”)
However, when I try to do the following in rspec
describe 'my functionality'
let (:endpoint) { parse_endpoint(“http://mywebsite.com/mySubdirectory/”) }
it 'should verify valid url' do
expect(verify_url(endpoint, “myFile.json”).to eq(true))
end
end
it gives me this error
“NoMethodError:
undefined method `host' for "http://mysebsite.com/mySubdirectory/myFile.json":String”
What am I doing wrong?
url is a String object, and you are trying to access a method called host which does not exist in String:
url = “#{endpoint}#{fname}”
req = Net::HTTP.new(url.host, url.port)
EDIT you probably need an URI object. I think this is what you want:
2.2.1 :004 > require 'uri'
=> true
2.2.1 :001 > url = 'http://mywebsite.com/mySubdirectory/'
=> "http://mywebsite.com/mySubdirectory/"
2.2.1 :005 > parsed_url = URI.parse url
=> #<URI::HTTP http://mywebsite.com/mySubdirectory/>
2.2.1 :006 > parsed_url.host
=> "mywebsite.com"
So just add url = URI.parse url before using url.host.
Testing the url manually like so works fine (returns true since the url is indeed valid):
endpoint = parse_endpoint('http://mywebsite.com/mySubdirectory/')
verify_url(endpoint, “myFile.json”)
It seems you missed something when you tested code above (maybe you tested old version) because it can't work as it is now.
Look at these lines of code:
url = "#{endpoint}#{fname}"
req = Net::HTTP.new(url.host, url.port)
You're creating a string variable url from other two variables endpoint and fname. So far, so good.
But then you're trying to access method host on url variable, which doesn't exist (but it exists on the endpoint variable), that's why you get this error.
You may want to use this code instead:
def verify_url(endpoint, fname)
url = endpoint.merge(fname)
res = Net::HTTP.start(url.host, url.port) do |http|
http.head(url.path)
end
# it's actually a bad idea to puts some text in a query method
# let's just return value instead
res.code == "200"
end

What is a good way to extract a url within a url in Ruby?

Given url = 'http://www.foo.com/bar?u=http://example.com/yyy/zzz.jpg&aaa=bbb&ccc=ddd'
What is a good way to extract http://example.com/yyy/zzz.jpg?
EDIT:
I would like to extract the second url.
I'd do :-
require 'uri'
url = 'http://www.foo.com/bar?u=http://example.com/yyy/zzz.jpg&aaa=bbb&ccc=ddd'
uri = URI(url)
URI.decode_www_form(uri.query).select { |_,b| b[/^http(s)?/] }.map(&:last)
# => ["http://example.com/yyy/zzz.jpg"]
# or something like
Hash[URI.decode_www_form(uri.query)]['u'] # => "http://example.com/yyy/zzz.jpg"
require "uri"
URI.extract("text here http://foo.example.org/bla and here mailto:test#example.com and here also.")
# => ["http://foo.example.org/bla", "mailto:test#example.com"]
http://www.ruby-doc.org/stdlib-2.1.1/libdoc/uri/rdoc/URI.html
Using Ruby 2.0+:
require 'uri'
url = 'http://www.foo.com/bar?u=http://example.com/yyy/zzz.jpg&aaa=bbb&ccc=ddd'
uri = URI.parse(url)
URI.decode_www_form(uri.query).to_h['u'] # => "http://example.com/yyy/zzz.jpg"
For Ruby < 2.0:
require 'uri'
url = 'http://www.foo.com/bar?u=http://example.com/yyy/zzz.jpg&aaa=bbb&ccc=ddd'
uri = URI.parse(url)
Hash[URI.decode_www_form(uri.query)]['u'] # => "http://example.com/yyy/zzz.jpg"
The Addressable gem is very full-featured, and follows the specs better than URI. The same thing can be done using:
require 'addressable/uri'
url = 'http://www.foo.com/bar?u=http://example.com/yyy/zzz.jpg&aaa=bbb&ccc=ddd'
uri = Addressable::URI.parse(url)
uri.query_values['u'] # => "http://example.com/yyy/zzz.jpg"

Ruby, How to add a param to an URL that you don't know if it has any other param already

I have to add a new param to an indeterminate URL, let's say param=value.
In case the actual URL has already params like this
http://url.com?p1=v1&p2=v2
I should transform the URL to this other:
http://url.com?p1=v1&p2=v2&param=value
But if the URL has not any param yet like this:
http://url.com
I should transform the URL to this other:
http://url.com?param=value
I feel worry to solve this with Regex because I'm not sure that looking for the presence of & could be enough. I'm thinking that maybe I should transform the URL to an URI object, and then add the param and transform it to String again.
Looking for any suggestion from someone who has been already in this situation.
Update
To help with the participation I'm sharing a basic test suite:
require "minitest"
require "minitest/autorun"
def add_param(url, param_name, param_value)
# the code here
"not implemented"
end
class AddParamTest < Minitest::Test
def test_add_param
assert_equal("http://url.com?param=value", add_param("http://url.com", "param", "value"))
assert_equal("http://url.com?p1=v1&p2=v2&param=value", add_param("http://url.com?p1=v1&p2=v2", "param", "value"))
assert_equal("http://url.com?param=value#&tro&lo&lo", add_param("http://url.com#&tro&lo&lo", "param", "value"))
assert_equal("http://url.com?p1=v1&p2=v2&param=value#&tro&lo&lo", add_param("http://url.com?p1=v1&p2=v2#&tro&lo&lo", "param", "value"))
end
end
require 'uri'
uri = URI("http://url.com?p1=v1&p2=2")
ar = URI.decode_www_form(uri.query) << ["param","value"]
uri.query = URI.encode_www_form(ar)
p uri #=> #<URI::HTTP:0xa0c44c8 URL:http://url.com?p1=v1&p2=2&param=value>
uri = URI("http://url.com")
uri.query = "param=value" if uri.query.nil?
p uri #=> #<URI::HTTP:0xa0eaee8 URL:http://url.com?param=value>
EDIT:(by fguillen, to merge all the good propositions and also to make it compatible with his question test suite.)
require 'uri'
def add_param(url, param_name, param_value)
uri = URI(url)
params = URI.decode_www_form(uri.query || "") << [param_name, param_value]
uri.query = URI.encode_www_form(params)
uri.to_s
end
More elegant solution:
url = 'http://example.com?exiting=0'
params = {new_param: 1}
uri = URI.parse url
uri.query = URI.encode_www_form URI.decode_www_form(uri.query || '').concat(params.to_a)
uri.to_s #=> http://example.com?exiting=0&new_param=1
Well, you may also not know if this parameter already exists in url. If you want to replace it with new value in this case, you can do this:
url = 'http://example.com?exists=0&other=3'
params = {'exists' => 1, "not_exists" => 2}
uri = URI.parse url
uri.query = URI.encode_www_form(URI.decode_www_form(uri.query || '').to_h.merge(params))
uri.to_s
You can try to use my gem iri:
Iri.new('http://url.com?p1=v1&p2=v2').add(:param, 'value').to_s

Ruby HTTP get with params

How can I send HTTP GET request with parameters via ruby?
I have tried a lot of examples but all of those failed.
I know this post is old but for the sake of those brought here by google, there is an easier way to encode your parameters in a URL safe manner. I'm not sure why I haven't seen this elsewhere as the method is documented on the Net::HTTP page. I have seen the method described by Arsen7 as the accepted answer on several other questions also.
Mentioned in the Net::HTTP documentation is URI.encode_www_form(params):
# Lets say we have a path and params that look like this:
path = "/search"
params = {q: => "answer"}
# Example 1: Replacing the #path_with_params method from Arsen7
def path_with_params(path, params)
encoded_params = URI.encode_www_form(params)
[path, encoded_params].join("?")
end
# Example 2: A shortcut for the entire example by Arsen7
uri = URI.parse("http://localhost.com" + path)
uri.query = URI.encode_www_form(params)
response = Net::HTTP.get_response(uri)
Which example you choose is very much dependent on your use case. In my current project I am using a method similar to the one recommended by Arsen7 along with the simpler #path_with_params method and without the block format.
# Simplified example implementation without response
# decoding or error handling.
require "net/http"
require "uri"
class Connection
VERB_MAP = {
:get => Net::HTTP::Get,
:post => Net::HTTP::Post,
:put => Net::HTTP::Put,
:delete => Net::HTTP::Delete
}
API_ENDPOINT = "http://dev.random.com"
attr_reader :http
def initialize(endpoint = API_ENDPOINT)
uri = URI.parse(endpoint)
#http = Net::HTTP.new(uri.host, uri.port)
end
def request(method, path, params)
case method
when :get
full_path = path_with_params(path, params)
request = VERB_MAP[method].new(full_path)
else
request = VERB_MAP[method].new(path)
request.set_form_data(params)
end
http.request(request)
end
private
def path_with_params(path, params)
encoded_params = URI.encode_www_form(params)
[path, encoded_params].join("?")
end
end
con = Connection.new
con.request(:post, "/account", {:email => "test#test.com"})
=> #<Net::HTTPCreated 201 Created readbody=true>
I assume that you understand the examples on the Net::HTTP documentation page but you do not know how to pass parameters to the GET request.
You just append the parameters to the requested address, in exactly the same way you type such address in the browser:
require 'net/http'
res = Net::HTTP.start('localhost', 3000) do |http|
http.get('/users?id=1')
end
puts res.body
If you need some generic way to build the parameters string from a hash, you may create a helper like this:
require 'cgi'
def path_with_params(page, params)
return page if params.empty?
page + "?" + params.map {|k,v| CGI.escape(k.to_s)+'='+CGI.escape(v.to_s) }.join("&")
end
path_with_params("/users", :id => 1, :name => "John&Sons")
# => "/users?name=John%26Sons&id=1"

Resources