What class does this method (read) come from (open-uri ruby) - ruby

I read some code like:
source = URI.join(uri).read
This basically goes to the URI, and stores the source of the webpage in the variable.
I tried this in IRB:
URI.join(uri).class
and it returned URI::HTTP, but, when I tried URI.join(uri).read.class => String.
I checked String class but there is no read method there.
I want to stub this method but am not able to because I don't know where it comes from.

read is from Ruby's StringIO module, which acts like the normal IO class.
OpenURI provides read via the StringIO class, which is how it fools us, and our code, into thinking the URL is a device we can read from.
URI.join(uri).read.class returns String because the page is read from the site pointed to by the URL, and the content is a string. OpenURI overrides the URI class and adds read to it. If you try:
require 'uri'
URI.join('http://example.com').read
without having required OpenURI, you'll get an error because, by itself, URI doesn't know how to read.
URI.join('http://example.com')
=> #<URI::HTTP:0x0000010292de68 URL:http://example.com>
URI.join('http://example.com').read
NoMethodError: undefined method `read' for #<URI::HTTP:0x0000010218b3b8 URL:http://example.com>

Rather than stub URI.read() (provided by OpenURI as noted in the Tin Man's answer), consider using a library like WebMock that can intercept HTTP requests regardless of the exact mechanism used to make them.

Related

Assistance in understanding the following methods: request.query_string

I've tried searching both the site and the Ruby docs, however, I am unable to find a clear answer to exactly what the above is doing.
From what I understand, 'request' and 'query_string' are two separate methods, however I'm really unsure what they do - the latter in particular.
Any help would be super appreciated!
Thank you.
In Rails, the #request method available in controllers and views returns a ActionDispatch::Request instance. The Request object allows access to data from the HTTP Request.
The #query_string method, defined in Rack::Request::Helpers, returns the query string from the request url. This is the part in the url following the "?" which specifies url encoded data in the format key=value&other_key=other_value.
Note:
ActionDispatch::Request is a Rails class that behaves similarly to a Rack::Request, including Rack::Request::Env and Rack::Request::Helpers in the current version of Rails v 5.0. In previous versions ActionDispatch::Request inherited directly from Rack::Request.
Read more:
https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/request.rb
http://api.rubyonrails.org/classes/ActionDispatch/Request.html
https://github.com/rack/rack/blob/master/lib/rack/request.rb

Rails, rspec: using "send()" to dynamically generate capybara URLs for controller specs

Inside a controller spec for a #show action:
resource_name = "adoption_transfer_type"
it "returns a single resource" do
resource = create(resource_name.to_sym)
# Works
xhr :get, api_v1_lookups_adoption_transfer_type_path(resource.id)
# Does not work
xhr :get, send("api_v1_lookups_#{resource_name}_path(#{resource.id})")
end
It results in the following error:
Failure/Error: xhr :get, send("api_v1_lookups_adoption_transfer_type_path(#{resource.id})")
NoMethodError:
undefined method `api_v1_lookups_adoption_transfer_type_path(66)'
It looks like send(...) is converting it to a string literal instead of executing it as Ruby code, but I thought that was the purpose of the send(...) method.
The broader picture is I'm using a single spec file to generate the specs for several lookup resources, since they are all the same and there's no reason to manage 10+ files when I can do it all in one.
the string interpolates to api_v1_lookups_adoption_transfer_type_path(2) which means you're trying to call some method by that name. Instead you want:
send("api_v1_lookups_#{resource_name}_path", resource.id)
This is how you pass arguments to a send call, also i'd get into the habit of using public_send =)

Ruby basic syntax and Net::HTTP

I am completely new to ruby. I have the following code:
body = "hello"
site = "api.mysite.net"
port = 80
conn = Net::HTTP.new(site, port)
resp, data = conn.post("/v1/profile", body, {})
puts body
my questions are:
Where should I go for a library on how NET::HTTP.new() , conn.post() etc... works?
What does the comma between resp and data mean?
How come puts body gives me nothing even though I have hello defined initially? And when passed through the post(), I figure it would assign it a value? but instead puts resp.body actually gives me the http response.
This is all so new to me, just trying to get a handle on things.
Read the docs I guess, but you will need background knowledge on HTTP to really understand it.
That's shorthand for assigning two variables at the same time, assuming the right-hand side returns an array of 2 (or more) items.
You've posted the body in your request, resp.body is the body in the response. I don't know why body should be empty though. I would double-check that, but it sounds like a side effect of conn.post if anything.
BTW there are several nice 3rd-party gems which make HTTP client development much easier than dealing with Net::HTTP, e.g. RESTClient, Excon, HTTparty. Check these out. Or if you want to use the standard Ruby library, also look at Open URI as a higher-level API.

Ruby WebMock: Getting Actual Parameters Passed Through a Method and Using Them in Spec File

I'm using WebMock to stub out HTTP requests. I have this one particular call where, instead of creating dummy data to pass through, I want to be able to capture the actual parameters I would pass into my send() method. Therefore, I need access to those actual parameters in my spec and I imagine I would need to somehow capture that context.
So, for example, in my application I'm calling this method:
send(method, uri, :body => data_file)
And in my spec file I'm stubbing the method:
FoobarModule.should_receive(:send).with(args)
Is there any way I could -- in WebMock, Rspec -- get the context of when send() is being called in the application and grab those parameters I'm passing through to use them within the spec and replace them with args?
I've looked through the documentation and I don't see much of anything on this. If there's anyone aware of this, I would greatly appreciate your help. Thanks.
Using WebMock you could use request callbacks to capture request data:
WebMock.allow_net_connect!
WebMock.after_request do |request_signature, response|
puts request_signature
end

Local variables in a block that are not passed as parameters [duplicate]

This question already has answers here:
Rails params explained?
(5 answers)
Closed 9 years ago.
I'm trying to understand how to make a variable available to a block that is not passed to the block as a parameter.
For example, how does Sinatra make params hash available?
get '/hello/:name' do
howAmIAccessingThis = params[:name]
end
Where is params coming from? This:
get '/hello/:name' do |params|
#hisName = params[:name]
end
might make sense because params is declared as a block argument, but that's not how it works. Looking through the source I cannot find how the params hash is getting passed to the block without it being a block parameter.
If it is not a local variable or a block variable, then it is a method. I don't know about Sinatra, but there must be a method params defined somewhere.
Using Parameters
Parameters in Sinatra are like everything else--simple and straightforward.
#!/usr/bin/env ruby
require 'rubygems'
require 'sinatra'
get '/hello/:name' do
"Hello #{params[:name]}!"
end
Once you've made this change, you'll need to restart the Sinatra application. Kill it with Ctrl-C and run it again. (There's a way around this, but we'll look at that in a future article.) Now, the parameters are straightforward. We've made an action called /hello/:name. This syntax is imitating what the URLs will look like, so go to http://localhost:4567/hello/Your Name to see it in action.
The /hello portion matches that portion of the URL from the request you made, and :name will absorb any other text you give it and put it in the params hash under the key :name. Parameters are just that easy. There is of course much more you can do with these, including regexp-based parameters, but this is all you'll need in almost every case.
Reference: http://ruby.about.com/od/sinatra/a/sinatra2.htm
EDIT
params values can come from the query string of a GET request, or the form data of a POST request, but there's also a third place they can come from: The path of the URL.
As you might know, Rails uses something called routes to direct requests to their corresponding controller actions. These routes may contain segments that are extracted from the URL and put into params. For example, if you have a route like this:
match 'products/:id', ...
Then a request to a URL like http://example.com/products/42 will set params[:id] to 42
So, whenever an URL GET, POST or Path contains such pattern then params hash is automatically constructed by rails.
Also check the Parameters section(Section 4) here

Resources