I have the following path:
http://192.168.56.10:4567/browse/foo/bar?x=100&y=200
I want absolutely everything that comes after "http://192.168.56.10:4567/browse/" in a string.
Using a splat doesn't work (only catches "foo/bar"):
get '/browse/*' do
Neither does the regular expression (also only catches "foo/bar"):
get %r{/browse/(.*)} do
The x and y params are all accessible in the params hash, but doing a .map on the ones I want seems unreasonable and un-ruby-like (also, this is just an example.. my params are actually very dynamic and numerous). Is there a better way to do this?
More info: my path looks this way because it is communicating with an API and I use the route to determine the API call I will make. I need the string to look this way.
If you are willing to ignore hash tag in path param this should work(BTW browser would ignore anything after hash in URL)
updated answer
get "/browse/*" do
p "#{request.path}?#{request.query_string}".split("browse/")[1]
end
Or even simpler
request.fullpath.split("browse/")[1]
get "/browse/*" do
a = "#{params[:splat]}?#{request.env['rack.request.query_string']}"
"Got #{a}"
end
Related
So I'm working on a crawler to get a bunch of images on a page that are saved as links. The relevant code, at the moment, is:
def parse_html(html)
html_doc = Nokogiri::HTML(html)
nodes = html_doc.xpath("//a[#href]")
nodes.inject([]) do |uris, node|
uris << node.attr('href').strip
end.uniq
end
I am current getting a bunch of links, most of which are images, but not all. I want to narrow down the links before downloading with a regex. So far, I haven't been able to come up with a Ruby-Friendly regex for the job. The best I have is:
^https?:\/\/(?:[a-z0-9\-]+\.)+[a-z]{2,6}(?:/[^\/?]+)+\.(?:jpg|gif|png)$.match(nodes)
Admittedly, I got that regex from someone else, and tried to edit it to work and I'm failing. One of the big problems I'm having is the original Regex I took had a few "#"'s in it, which I don't know if that is a character I can escape, or if Ruby is just going to stop reading at that point. Help much appreciated.
I would consider modifying your XPath to include your logic. For example, if you only wanted the a elements that contained an img you can use the following:
"//a[img][#href]"
Or even go further and extract just the URIs directly from the href values:
uris = html_doc.xpath("//a[img]/#href").map(&:value)
As some have said, you may not want to use Regex for this, but if you're determined to:
^http(s?):\/\/.*\.(jpeg|jpg|gif|png)
Is a pretty simple one that will grab anything beginning with http or https and ending with one of the file extensions listed. You should be able to figure out how to extend this one, Rubular.com is good for experimenting with these.
Regexp is a very powerful tool but - compared to simple string comparisons - they are pretty slow.
For your simple example, I would suggest using a simple condition like:
IMAGE_EXTS = %w[gif jpg png]
if IMAGE_EXTS.any? { |ext| uri.end_with?(ext) }
# ...
In the context of your question, you might want to change your method to:
IMAGE_EXTS = %w[gif jpg png]
def parse_html(html)
uris = []
Nokogiri::HTML(html).xpath("//a[#href]").each do |node|
uri = node.attr('href').strip
uris << uri if IMAGE_EXTS.any? { |ext| uri.end_with?(ext) }
end
uris.uniq
end
I am testing browser data via cucumber. I am looking through a list of links on a page, to determine which link I should click.
So let's say I have a list of dessert links and I wanted to find the one for apple sauce. I call a method that goes through the links and finds the one that has apple sauce after I pass the name apple sauce to it.
The string "apple sauce" is stored in #dessert and since #dessert will change often, I need to know if there is a way to find out if say "apple sauce" is stored in the variable #dessert.
when I do #dessert.text.include? "##dessert" i keep getting false. I need this to be true in order to make the decision to click it. When I evaluate #dessert by itself I have "apple sauce"...
How can I get rid of the quotes ( " ) so they are not evaluated? I think this is messing me up!
The standard way to test if a string has another string in it is to either use a regular expression, where you can describe patterns for "close enough" matches, or to search for a literal substring:
#dessert = "apple sauce;pears;walnuts"
#dessert.include?("apple sauce")
# => true
I'm not suer why your question has "##dessert" since that evaluates to a string exactly like that. "#{#dessert}" is probably what you were intending, where #{...} inlines a string value, but that's redundant since you're only testing against a singular variable with no other data. x and "#{x}" evaluate to equivalent strings if x is a string to begin with.
You seem to be comparing #dessert, an object with #dessert.text, an attribute of that object. Also, you are using a form of string interpolation that I, along with others here, would recommend avoiding.
Try
#dessert.text.include? "#{#dessert.text}"
and see if it returns true.
Here's an example where I went into a container and pulled all the links out to see click, be navigated to the page, and then assert that the page titles, url, and breadcrumbs all included the text within the link within the container. You could just add an if statement that will evaluate whether a link has certain text, and if it does, click it.
From lib file
def pull_text_and_href_from_continent_link
#continents.each do |continent|
find(".continents li.#{continent}").hover
page.should have_selector(".#{continent} .continent-wrapper", :visible => true)
page.all(:css, '.continents .continent-wrapper a').each do |nav_link|
#array.push(:text => nav_link.native.attribute("text"), :href => nav_link[:href])
end
end
end
From spec file (this is a suite not using cuke, but the code is still similar)
it "should have the right page title, url, and breadcrumbs" do
#array.each do |info|
if info[:text].include?('See all')
pp "Skipping the see all link for this container"
else
visit_page_logged_out(info[:href])
assert_correct_page_url info[:href]
assert_country_breadcrumbs remove_specials(info[:text])
assert_page_title info[:text]
end
end
I would like to start with a little script that fetches the examination results of me and my friends from our university website.
I would like to pass it the roll number as the post parameter and work with the returned data,
I don't know how to create the post string.
It would be great if someone could tell me where to start, what are the things to learn, links to a tutorial would be most appreciated.
I donĀ“t want someone to write code for me, just guidance on how to get started.
I've written a solution here just as a reference for whatever you might come up with. There are multiple ways of attacking this.
#fetch_scores.rb
require 'open-uri'
#define a constant named URL so if the results URL changes we don't
#need to replace a hardcoded URL everywhere.
URL = "http://www.nitt.edu/prm/ShowResult.html?¶m="
#checking the count of arguments passed to the script.
#it is only taking one, so let's show the user how to use
#the script
if ARGV.length != 1
puts "Usage: fetch_scores.rb student_name"
else
name = ARGV[0] #could drop the ARGV length check and add a default using ||
# or name = ARGV[0] || nikhil
results = open(URL + name).read
end
You might examine Nokogiri or Hpricot to better parse/format your results. Ruby is an "implicit return" language so if you happened to wonder why we didn't have a return statement that's because results will be returned by the script since it was last executed.
You could have a look at the net/http library, included as part of the standard library. See http://www.ruby-doc.org/stdlib/libdoc/net/http/rdoc/index.html for details, there are some examples on that page to get you started.
A very simple way to do this is to use the open-uri library and just put the query parameters in the URL query string:
require 'open-uri'
name = 'nikhil'
results = open("http://www.nitt.edu/prm/ShowResult.html?¶m=#{name}").read
results now contains the body text fetched from the URL.
If you are looking for something more ambitious, look at net/http and the httparty gem.
I am using a gem which uses soap/wsdlDriver.
When I post I get back a SOAP response and am unable to easily parse it.
This is the response I get back:
#<SOAP::Mapping::Object:0x159e95faf098 {}id="27b907f8-da51-f611-ab02-4c5f88a8ec8
8" {}error=#<SOAP::Mapping::Object:0x159e95fae33c {}number="0" {}name="No Error"
{}description="No Error">>
I need to get the entire value in the id="xxxx"
This is what on get on heroku (note: it works locally). This comes from testing various variations of response.id (where response.inspect is what created the output above)
f"
{}error=#>
response[id]
/disk1/home/slugs/220752_47a08bb_10e7/mnt/app/controllers/sugarcrm_controller.rb
:77: warning: Object#id will be
deprecated; use Object#object_id nil
response.id:
/disk1/home/slugs/220752_47a08bb_10e7/mnt/app/controllers/sugarcrm_controller.rb
:79: warning: Object#id will be
deprecated; use Object#object_id
23891500658740
/disk1/home/slugs/220752_47a08bb_10e7/mnt/app/controllers/sugarcrm_controller.rb
:80: warning: Object#id will be
deprecated; use Object#object_id this
is the contact_id: 23891500658740
events:
Ok, I'm 95% sure that is the output of SOAP::Mapping::Object#inspect and not the actual response. And from that class it looks you use the [] method to pull out attributes.
So if I am reading that right, then it looks like you might want:
response_id = response_object['id']
Though each attribute being prefaced with {} seems pretty odd. So if that is actually part of the attribute name, you may need:
response_id = response_object['{}id']
But that seems pretty strange, and may indicate that the SOAP library you are using is not parsing the response properly.
Disclaimer: I've never used this lib before, and posted this from just perusing the docs... This may or may not be very accurate in the ways using this class is described.
I don't know how to do this with ruby, but may be like this code in javascript.
var t = "<SOAP message........>";
var id = t.replace(/.*id=\"(.*?)\".*/, "$1");
Regex details:
.*id=\"(.*?)\".*
.* = anything, 0 or N times.
(.*?) = anything, 0 or N times, stopping at first match.
$1 = first group, the content inside ().
So, everthing will be replaced by id content.
So I've created and published a Sinatra app to Heroku without any issues. I've even tested it locally with rackup to make sure it functions fine. There are a series of API calls to various places after a zip code is consumed from the URL, but Heroku just wants to tell me there is an server error.
I've added an error page that tries to give me more description, however, it tells me it can't perform a `count' for #, which I assume means hash. Here's the code that I think it's trying to execute...
if weather_doc.root.elements["weather"].children.count > 1
curr_temp = weather_doc.root.elements["weather/current_conditions/temp_f"].attributes["data"]
else
raise error(404, "Not A Valid Zip Code!")
end
If anyone wants to bang on it, it can be reached at, http://quiet-journey-14.heroku.com/ , but there's not much to be had.
Hash doesn't have a count method. It has a length method. If # really does refer to a hash object, then the problem is that you're calling a method that doesn't exist.
That # doesn't refer to Hash, it's the first character of #<Array:0x2b2080a3e028>. The part between the < and > is not shown in browsers (hiding the tags themselves), but visible with View Source.
Your real problem is not related to Ruby though, but to your navigation in the HTML or XML document (via DOM). Your statement
weather_doc.root.elements["weather"].children.count > 1
navigates the HTML/XML document, selecting the 'weather' elements, and (tries to) count the children. The result of the children call does not have a method count. Use length instead.
BTW, are you sure that the document contains a tag <weather>? Because that's what your're trying to select.
If you want to see what's behind #, try
raise probably_hash.class.to_s