`File.exist?` won't find file that exists - ruby

I'm trying to use File.exist? to have a dynamic background. When I try to to point File.exist? to a specific file it doesn't seem to find it.
image_path = "../assets/" + city_code + ".jpg"
if
File.exist?('#{image_path}')
#image = image_path
else
#image = "../assets/coastbanner.jpg"
end
If I remove replace city_code with a path that I know exists, it still won't find it. I must bee missing something small.
I wanted to be a little more clear: If I remove the interpolation/variable and replace it with a path that I know works, '../assets/coastbanner.jpg' for example, it still will not work. In fact, no valid path seems to get it to yield a true response.

There are some issues with your code:
String interpolation works only with double quotes
There is no need for a string interpolation when the variable is a string already
the condition belongs in the same line than the if
Furthermore the folder in which the server is running might not be the same folder than the current webpage is served from. That said it might make sense to use absolute path for image links and path including Rails.root for the File.exist? test.
I am not sure about your application's folder structure, but something like the following should work:
image_path = "/assets/#{city_code}.jpg"
if File.exist?(Rails.root.join('app', image_path))
#image = image_path
else
#image = '/assets/coastbanner.jpg'
end
Tip: Test with the coastbanner.jpg to get the image apth correct and then with the File.exist? to get the path in the app.

You need to use double quotes for the string interpolation to work.
File.exist?("#{image_path}")
In this case, you could actually just use the variable since it already is the string you want.
File.exist?(image_path)
If you want to use the #{} feature, a good place to use it is when creating image_path.
image_path = "../assets/#{city_code}.jpg"

if
File.exist?( image_path )

Don't think you can have #{} in a string with single quotes. Try double-quoting it.

I assume you are using with in a Rails application, and if so, the most probable cause would be:
When Rails creates assets it creates a digest. Because of this your image name might have a digest string in the name. So I suggest to use image_path or asset_path
Ex: File.exist?(image_path("#{city_code}.jpg"))
But having said that, proper was to handle these kind of cases would be to have a flag in the database if you want to set the the custom image or not. Because it's much faster than accessing the file system.

Related

What is a good schema for naming screenshots in selenium webdriver + capyabara

First pass: I name my screenshot "x".
Obviously that minimal setup only allows for 1 screenshot
I want to name the screenshots in a way that makes them unique and also reflect the usage.
I can make the filenname fairly unique with
output_directory = 'screenshots'
time = Time.new
page.save_screenshot("#{output_directory}/#{time}.png")
It's a bit ugly but I get
$ ls screenshots/
'019-04-13 07:07:50 -0400.png''
What would be good format to use that would meet the requirements of both unique and also descriptive. Could I include the scenario description somehow?
How could I end up with something like:
scenario_decsription_2019_04_19-08_55_20
The RSpec test definition methods and hooks (scenario, before, after, etc) all receive an optional parameter which is the test example itself. This allows you to get the description of the test, etc for use in naming your file
scenario "my test" do |example|
...
page.save_screenshot("#{example.full_description}.png")
end
Obviously you could transform the description in any way you want (convert spaces to underscores, etc).
Note: you may also want to look at Capybara.save_path which specifies what directory screenshots are stored in, if you don't want to prepend screenshots/ everywhere.
How about something like this?
scenario "#{scenario = 'user_clicks_the_dropdown'}" do
output_directory = 'screenshots'
time = Time.new
suffix = time.to_s(:db).gsub(/[\:\.\_\s]/,'_')
page.save_screenshot("#{output_directory}/#{scenario}_#{suffix}.png")
end

Regex in Ruby for a URL that is an image

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

Filesystem object symbology

What is the most standard Ruby symbology for naming variables containing file names, file names with path and file instances? Completely clear way of doing this would be:
file_name = "bar.txt"
file_name_with_path = "foo", file_name
file = File.open( file_name_with_path )
But it's too long. It is out of question to use :file_name_with_path in method definition:
def quux( file_name_with_path: "foo/bar.txt" )
# ...
end
Having encountered this for umpteenth time, I realized that shortening conventions are needed. I started making personal shortening conventions: :file_name => :fn, :file_name_with_path => :fnwp, :file always refers to a File instance, :fn never includes path, :fnwap means :file_name_with_absolute_path etc. But everyone must be facing this, so I am asking: Is there a public convention for this? More particularly, does Rails code have a convention for this?
But everyone must be facing this...
No, not really, because you're really over-thinking this.
Just use file:, or filename:. It doesn't matter whether your filename contains a relative or absolute path, or whether the path contains directories, and your code should reflect this. A path to a file is just a path to a file, and all paths should be treated identically by your code: It just opens the file, and raises an error if it can't.
You can use filesystem utilities to extract directories and base names from a path, and they'll work just fine on any path, regardless of the presence of directories, regardless of wether the path is absolute or relative. It just doesn't matter.

Get full path in Sinatra route including everything after question mark

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

Ruby: windows path conversion

I often use long paths in my scripts and since i'm on windows i have to convert these long paths to nix style with slashes in stead of backslashes. Nothing difficult but annoying if thereafter you copy that path to go to that folder since in explorer you have to do the opposite again.
So i made a function that does the conversion, now i can use windowspaths that i can copy around and keep Ruby sattisfied.
Question: is there a more elegant solution here ? I don't like the second gsub to handle the double \ at he beginning and also would like to handle a \ at the end (currently not possible). The function should be able to handle network unc's (\..) and local drivepaths (c:..)
class String
def path
self.gsub('\\','/').gsub(/^\//,'//')
end
end
path = '\\server\share\folder'.path
Dir.glob(path+'**/*') do |file|
puts file
end
#=>
#//server/share/folder/file1.txt
#//server/share/folder/file2.txt
The suggestion to use File.join made me try a regular split & join and now i have this version, got rid of the ugly double gsub, now it's longer but can handle an ending slash. Has someone a better version ?
class String
def to_path(end_slash=false)
"#{'/' if self[0]=='\\'}#{self.split('\\').join('/')}#{'/' if end_slash}"
end
end
puts '\\server\share\folder'.to_path(true) #//server/share/folder/
puts 'c:\folder'.to_path #c:/folder
The portable way to write paths is with Ruby's File#join method. This will create OS-independent paths, using the right path separators.
For UNC paths, this previous answer addresses the creation of a custom File#to_unc method:
def File.to_unc( path, server="localhost", share=nil )
parts = path.split(File::SEPARATOR)
parts.shift while parts.first.empty?
if share
parts.unshift share
else
# Assumes the drive will always be a single letter up front
parts[0] = "#{parts[0][0,1]}$"
end
parts.unshift server
"\\\\#{parts.join('\\')}"
end
I haven't tried it myself, but it would appear to be the result you're looking for.

Resources