No implicit converson from nil to String - ruby

I am getting an error
ruby/2.1.0/open-uri.rb:36:in `open': no implicit conversion of nil into String (TypeError)
here #filename, #directory and #xmlFile all have String as class type if I print them.
But somehow still in eval_script the above error is thrown. I don't undertstand why?
def execute
...
#result = eval_script(#filename,#xmlFile,#directory)
end
def eval_script filename,xml,directory
proc = Proc.new{}
eval(File.read(filename),proc.binding, filename)
end
Edit:
1) execute method is my rails action controller method.
Script:
# encoding: UTF-8
require 'nokogiri'
require 'open-uri'
doc = Nokogiri::XML(open(ARGV.first))
path = ARGV[1]
print path
File.delete(path + "/testOut.txt") if File.exist?(path + "/testOut.txt")
file = File.open(path + "/testOut.txt", 'w')
doc.css('testcases').each { |node| file.write "#{node['name']}\n" if node.css('results[test="testOut"]').any? }

Well, there's your problem. Line 4 of your script is
doc = Nokogiri::XML(open(ARGV.first))
But there are no ARGV elements being passed, so you're trying to open nil
Since you have the binding available, just refer to the variables defined in the eval_script method.
doc = Nokogiri::XML(open(xml))

Related

How to pass method arguments use as Hash path?

E.G.
def do_the_thing(file_to_load, hash_path)
file = File.read(file)
data = JSON.parse(file, { symbolize_names: true })
data[sections.to_sym]
end
do_the_thing(file_I_want, '[:foo][:bar][0]')
Tried a few methods but failed so far.
Thanks for any help in advance :)
Assuming you missed the parameters names...
Lets assume our file is:
// test.json
{
"foo": {
"bar": ["foobar"]
}
}
Recomended solution
Does your param really need to be a string??
If your code can be more flexible, and pass arguments as they are on ruby, you can use the Hash dig method:
require 'json'
def do_the_thing(file, *hash_path)
file = File.read(file)
data = JSON.parse(file, symbolize_names: true)
data.dig(*hash_path)
end
do_the_thing('test.json', :foo, :bar, 0)
You should get
"foobar"
It should work fine !!
Read the rest of the answer if that doesn't satisfy your question
Alternative solution (using the same argument)
If you REALLY need to use that argument as string, you can;
Treat your params to adapt to the first solution, it won't be a small or fancy code, but it will work:
require 'json'
BRACKET_REGEX = /(\[[^\[]*\])/.freeze
# Treats the literal string to it's correspondent value
def treat_type(param)
# Remove the remaining brackets from the string
# You could do this step directly on the regex if you want to
param = param[1..-2]
case param[0]
# Checks if it is a string
when '\''
param[1..-2]
# Checks if it is a symbol
when ':'
param[1..-1].to_sym
else
begin
Integer(param)
rescue ArgumentError
param
end
end
end
# Converts your param to the accepted pattern of 'dig' method
def string_to_args(param)
# Scan method will break the match results of the regex into an array
param.scan(BRACKET_REGEX).flatten.map { |match| treat_type(match) }
end
def do_the_thing(file, hash_path)
hash_path = string_to_args(hash_path)
file = File.read(file)
data = JSON.parse(file, symbolize_names: true)
data.dig(*hash_path)
end
so:
do_the_thing('test.json', '[:foo][:bar][0]')
returns
"foobar"
This solution though is open to bugs when the "hash_path" is not on an acceptable pattern, and treating it's bugs might make the code even longer
Shortest solution (Not safe)
You can use Kernel eval method which I EXTREMELY discourage to use for security reasons, read the documentation and understand its danger before using it
require 'json'
def do_the_thing(file, hash_path)
file = File.read(file)
data = JSON.parse(file, symbolize_names: true)
eval("data#{hash_path}")
end
do_the_thing('test.json', '[:foo][:bar][0]')
If the procedure you were trying to work with was just extracting the JSON data to an object, you might find yourself using either of the following scenarios:
def do_the_thing(file_to_load)
file = File.read(file)
data = JSON.parse(file, { symbolize_names: true })
data[sections.to_sym]
end
do_the_thing(file_I_want)[:foo][:bar][0]
or use the dig function of Hash :
def do_the_thing(file_to_load, sections)
file = File.read(file)
data = JSON.parse(file, { symbolize_names: true })
data.dig(*sections)
end
do_the_thing(file_I_want, [:foo, :bar, 0])

Using variable declared in one method to open webpage in another method

I am working on a CLI Project and trying to open up a web page by using url variable declared in another method.
def self.open_deal_page(input)
index = input.to_i - 1
#deals = PopularDeals::NewDeals.new_deals
#deals.each do |info|
d = info[index]
#product_url = "#{d.url}"
end
#product_url.to_s
puts "They got me!"
end
def self.deal_page(product_url)
#self.open_deal_page(input)
deal = {}
html = Nokogiri::HTML(open(#product_url))
doc = Nokogiri::HTML(html)
deal[:name] = doc.css(".dealTitle h1").text.strip
deal[:discription] = doc.css(".textDescription").text.strip
deal[:purchase] = doc.css("div a.button").attribute("href")
deal
#binding.pry
end
but I am receiving this error.
`open': no implicit conversion of nil into String (TypeError)
any possible solution? Thank you so much in advance.
Try returning your #product_url within your open_deal_page method, because now you're returning puts "They got me!", and also note that your product_url is being created inside your each block, so, it won't be accessible then, try creating it before as an empty string and then you can return it.
def open_deal_page(input)
...
# Create the variable
product_url = ''
# Assign it the value
deals.each do |info|
product_url = "#{info[index].url}"
end
# And return it
product_url
end
In your deal_page method tell to Nokogiri to open the product_url that you're passing as argument.
def deal_page(product_url)
...
html = Nokogiri::HTML(open(product_url))
...
end

Ruby return with double quotes

Hi I have a string passed back from rspec.
It should show
"alias/public_html/ab1/ab2/"
but I am getting "\"alias/public_html/ab1/ab2/\""
I am getting the rspec error below:
WebServer::HttpdConf#alias_path returns the aliased path
Failure/Error: expect(httpd_file.alias_path('/ab/')).to eq 'alias/public_html/ab1/ab2/'
expected: "alias/public_html/ab1/ab2/"
got: "\"alias/public_html/ab1/ab2/\""
(compared using ==)
# ./spec/lib/config/httpd_conf_spec.rb:90:in `(root)'
And here is my actual program file
def alias_path(path)
#hash_httpd['Alias'][path]
end
Please help
EDIT
Sorry, I am new to RUby, here is the httpd_file
def initialize(httpd_file_content)
#hash_httpd = Hash.new
httpd_file_content.each_line do | line |
#commands = line.split
if #commands.length == 2
#hash_httpd[#commands[0]] = #commands[1]
else
if !#hash_httpd.has_key?(#commands[0])
al = Hash.new
#hash_httpd[#commands[0]] = al
else
al = #hash_httpd[#commands[0]]
end
al[#commands[1]] = #commands[2]
end
end
end
If you are sure that your alias_path output will be "alias/public_html/ab1/ab2/", then you can just modify your alias_path method definition by removing the quotes (if any) from the returned path:
def alias_path(path)
#hash_httpd['Alias'][path].gsub('"', '')
end

Extracting a url comprised of a hash in ruby

I have a query string that looks as follows:
http://localhost:3000/events?appointment_practices%5B10%5D=Injury&appointment_practices%5B18%5D=Immigration&appointment_practices%5B8%5D=Bankruptcy
appointment_practices is actually a hash I inserted into the query string during a redirect:
appointment_practices = practices.reduce({}) do |acc, practice|
acc[practice.id] = practice.class.name
acc
end
redirect_to events_path(appointment_practices: appointment_practices)
Now I want to parse that query string. When I tried to parse it with decode_www_form, it returns an array with a nil element:
[nil]
This is the code that is giving me the nil element:
#http_refer = #_env['HTTP_REFERER']
begin
uri = URI.parse #http_refer
practices = Hash[URI::decode_www_form(uri.query)].values_at('appointment_practices')
puts "practices: #{practices}"
rescue StandardError
end
I am trying to extract the hash. For example, in appointment_practices%5B10%5D=Injury, the id is 10 and the practice is Injury.
What other options do I have besides regex?
You can use Rack::Utils.parse_nested_query:
require 'uri'
require 'rack'
uri = URI.parse('http://localhost:3000/events?appointment_practices%5B10%5D=Injury&appointment_practices%5B18%5D=Immigration&appointment_practices%5B8%5D=Bankruptcy')
Rack::Utils.parse_nested_query(uri.query)
#=> {"appointment_practices"=>{"10"=>"Injury", "18"=>"Immigration", "8"=>"Bankruptcy"}}

Ruby: Method doesn't run outside file where defined - "can't convert Symbol into Integer (TypeError)"

I'm a ruby newbie and this is my first (command-line for now) program.
First, some source.
file: AccessDb.rb
require 'mongo'
require 'json'
(...)
class AccessDb
def initialize dbname, collection #, username, password
#dbname = dbname
#collection = collection
#conn = Mongo::Connection.new
#db = #conn[dbname]
#coll = #db[collection]
end
def upsert_by_meta json
# print json
#coll.update({ :hash_md5 => json[:hash_md5] }, json, :upsert => true)
end
end
using
file: Downloader.rb
require 'curb'
require 'yaml'
require 'json'
(...)
class Downloader
def initialize(directory)
#PASS=nil
#COOKIE=nil
#filename=nil
#full_file_location = nil
#target_dir = directory
File.exists? #target_dir # File.directory? #target_dir
#c = Curl::Easy.new
curl_setup
#mongo = AccessDb.new "meta","meta"
end
def parse_link_info(url)
json = {}
json[:link_requested] = url
if #c.last_effective_url != url
then json[:link_final] = #c.last_effective_url end
json[:link_filename_requested] = #filename
#final_filename = #c.last_effective_url.split(/\?/).first.split(/\//).last
if #final_filename != #filename
then json[:link_filename_delivered] = #final_filename end
json[:link_filetime] = Time.at(#c.file_time).utc.to_s
json[:content_lenght] = #c.downloaded_content_length
json[:content_type] = #c.content_type
#hash = MovieHasher::compute_hash(#save_location)
#hash = MovieHasher::compute_hash(#save_location)
if !#hash.nil?
then json[:hash_bigfile] = #hash end
json[:hash_md5] = Digest::MD5.hexdigest(File.read(#save_location))
JSON.pretty_generate(json)
end
(json is some generated json file)
using code from Downloader.rb in the AccessDb.rb tests works perfectly, but when the method is used in Downloader.rb I get the following output:
D:/Dropbox/#code/PracaInz-Program/AccessDb.rb:20:in `[]': can't convert Symbol into Integer (TypeError)
from D:/Dropbox/#code/PracaInz-Program/AccessDb.rb:20:in `upsert_by_meta'
from D:/Dropbox/#code/PracaInz-Program/Downloader.rbw:158:in `block in add_links'
from D:/Dropbox/#code/PracaInz-Program/Downloader.rbw:148:in `each'
from D:/Dropbox/#code/PracaInz-Program/Downloader.rbw:148:in `add_links'
from D:/Dropbox/#code/PracaInz-Program/Downloader.rbw:189:in `<main>'
[Finished in 4.9s with exit code 1]
in a method code that perfectly works tested inside one file.. How can I write it so it can use symbols but works outside that specific file. Thx
def parse_link_info(url)
json = {}
json[:link_requested] = url
if #c.last_effective_url != url
then json[:link_final] = #c.last_effective_url end
json[:link_filename_requested] = #filename
#final_filename = #c.last_effective_url.split(/\?/).first.split(/\//).last
if #final_filename != #filename
then json[:link_filename_delivered] = #final_filename end
json[:link_filetime] = Time.at(#c.file_time).utc.to_s
json[:content_lenght] = #c.downloaded_content_length
json[:content_type] = #c.content_type
#hash = MovieHasher::compute_hash(#save_location)
#hash = MovieHasher::compute_hash(#save_location)
if !#hash.nil?
then json[:hash_bigfile] = #hash end
json[:hash_md5] = Digest::MD5.hexdigest(File.read(#save_location))
JSON.pretty_generate(json)
end
def add_links(url_array,cred=nil,ref=nil,cookie=nil)
link_setup(cred,ref,cookie)
url_array.each do |single_url|
#c.url=single_url
#filename = single_url.split(/\?/).first.split(/\//).last
#save_location = #target_dir + '\\' + #filename
# puts #save_location
#c.perform
File.open(#save_location,"wb").write #c.body_str
json = parse_link_info single_url
# puts json
id = #mongo.upsert_by_meta json
puts id
json["_id"] = id
File.open(#save_location + :"meta.json","w").write json
end
end
EDIT: more code (json definition), full trace
parse_link_info returns JSON.pretty_generate(json), i.e a string.
You pass the result of that into upsert_by_meta as its json parameter, which tries to access it as a hash (you do json[:hash_md5]) which you can't do with a string. String's [] method expects you to pass an integer (or a pair of integers) hence the method about not being able to convert the symbol to an integer
Looks like the code you have shown would work if parse_link_info just returned your json object rather than calling JSON.pretty_generate

Resources