Ruby String to access an object attribute - ruby

I have a text file (objects.txt) which contains Objects and its attributes.
The content of the file is something like:
Object.attribute = "data"
On a different file, I am Loading the objects.txt file and if I type:
puts object.attribute it prints out data
The issue comes when I am trying to access the object and/or the attribute with a string. What I am doing is:
var = "object" + "." + "access"
puts var
It prints out object.access and not the content of it "data".
I have already tried with instance_variable_get and it works, but I have to modify the object.txt and append an # at the beginning to make it an instance variable, but I cannot do this, because I am not the owner of the object.txt file.
As a workaround I can parse the object.txt file and get the data that I need but I don't want to do this, as I want take advantage of what is already there.
Any suggestions?

Yes, puts is correctly spitting out "object.access" because you are creating that string exactly.
In order to evaluate a string as if it were ruby code, you need to use eval()
eg:
var = "object" + "." + "access"
puts eval(var)
=> "data"
Be aware that doing this is quite dangerous if you are evaluating anything that potentially comes from another user.

Related

What's the correct way to read an array from a csv field in Ruby?

I am trying to save some class objects to a csv file, everything works fine. I can save and read back from the csv file, there is only a 'minor' problem with an attribute that is an Array of Strings.
When I save it to the file it appears like this: "[""Dan Brown""]"
CSV.open('documents.csv', "w") do |csv|
csv << %w[ISBN Titre Auteurs Type Disponibilité]
#docs.each { |doc|
csv << [doc.isbn, doc.titre, doc.auteurs, doc.type, doc.empruntable ? "Disponible" : "Emprunté"]
}
end
And when I try to extract the data from the file I end up with something like this: ["[\"Dan Brown\"]"].
table = CSV.parse(File.read("documents.csv"), headers: true)
table.each do |row|
doc = Document.new(row['Titre'], row['ISBN'], row['Type'])
doc.auteurs << row['Auteurs'] #This the array where there is a 'problem'
if row['Disponibilité'] == "Disponible"
doc.empruntable = true
else
doc.empruntable = false
end
#docs.push(doc) #this an array where I save my objects
end
I tried many things to solve this but without any luck. I would be thankful if you can help me find a solution.
Since a CSV file, by it's nature, contains in its fields only strings, not arrays or other data types, the CSV class is applying the to_s method of the objects to turn them into a string before putting them into the CSV.
When you later read them back, you just get this - the string representation of what once had been your array. The only one who knows that 'Auteurs' should end up as an array of strings, is the application, i.e. you.
Hence on reading the CSV, after having extracted the autheurs string, you need to convert it manually back to an Array, because there is no automatic "inverse method" to reverse the to_s.
A cheap, but dangerous way to do it, is to use eval, which indeed would reconstruct your array. However, you need to be sure that nobody had a chance to fiddle manually with the CSV data, because an eval allows sneaking in arbitrary code.
A safer way would be to either write your own conversion function to and from String representation, or use a format such as YAML or JSON for representing the Array as String, instead of using to_s.

How to use get_object in ruby for AWS?

I am very new to ruby. I am able to connect to AWS S3 using ruby. I am using following code
filePath = '/TMEventLogs/stable/DeviceWiFi/20160803/1.0/20160803063600-2f9aa901-2ce7-4932-aafd-f7286cdb9871.csv'
s3.get_object({bucket: "analyticspoc", key:"TMEventLogs/stable/DeviceWiFi/20160803/1.0/"}, target:filePath ) do |chunk|
puts "1"
end
In above code s3 is client. "analyticspoc" is root bucket. My path to csv file is as follows All Buckets /analyticspoc/TMEventLogs/stable/DeviceWiFi/20160803/1.0/20160803063600-2f9aa901-2ce7-4932-aafd-f7286cdb9871.csv.
I have tried above code. I above code I was getting error Error getting objects: [Aws::S3::Errors::NoSuchKey] - The specified key does not exist. Using above code I want to read the contents of a file. How to do that ? Please tell me what is the mistake in above code
Got the answer. You can use list_objects for accessing array of file names in chunk(1000 at a time) where as get_object is used for accessing the content of a single file as follows
BUCKET = "analyticspoc"
path = "TMEventLogs/stable/DeviceWiFi/20160803/1.0/"
s3.list_objects(bucket:BUCKET, prefix: path).each do |response|
contents = response.contents
end
file_name = "TMEventLogs/stable/DeviceWiFi/20160803/1.0/012121212121"
response = s3.get_object(bucket: BUCKET, key: file_name)
As far as I can tell you're passing in the arguments incorrectly. It should be a single options hash according to the documentation for get_object:
s3.get_object(
bucket: "analyticspoc",
key: "TMEventLogs/stable/DeviceWiFi/20160803/1.0/",
target: filePath
) do |chunk|
puts "1"
end
I believe it was trying to use your hash as a string key which is obviously not going to work.
With Ruby the curly braces { } are only necessary in method calls if additional arguments follow that need to be in another hash or are non-hash in nature. This makes the syntax a lot less ugly in most cases where options are deliberately last, and sometimes first and last by virtue of being the only argument.

Use embedded string as variable name

I have a YAML file that uses the encoding __firstname__ as a placeholder which signifies that an existing method firstname should be used, rather than the literal string in a subsequent process.
I am trying to understand the most ruby way to to do this. Basically, I need to extract the part between the underscores and send it to an object. Here is pseudocode:
variable = '__firstname__'
if variable is prefixed and suffixed with underscores
result = object.send(variable.removeunderscores)
else
result = variable
end
puts result
I was about to write this procedurally like this, but this is the type of thing that I think ruby can less clunkily if only I knew the language better.
What is a clean why to write this?
There's nothing wrong with verbose code if it's clear to read IMO.
I'd do something like this using String#start_with? and String#end_with?:
variable = '__firstname__'
if variable.start_with?("__") && variable.end_with?("__")
result = object.send(variable[2...-2])
else
result = variable
end

After performing string.slice() return string with part removed

Im sure this is very obvious but I cant seem to get it work.
I have a Pathname instance and Im attempting to remove the first directory from it and then return the rest of the string, but because slice returns the part removed it seems there is no way of getting the smaller string back.
filepath = Pathname.new("this_folder_needs_to_go/another_folder/file.html")
filedir = filepath.to_s.slice("this_folder_needs_to_go/")
newfilepath = filedir
I would hope newfilepath would be another_folder/file.html but instead it just returns this_folder_needs_to_go/
So how on earth to I get the string that has had the part removed?
Using String#split:
"this_folder_needs_to_go/another_folder/file.html".split('/', 2)[1]
# => "another_folder/file.html"
You can also use .slice! instead of .slice if you're trying to modify your string
filepath = Pathname.new("this_folder_needs_to_go/another_folder/file.html")
filepath.to_s.slice!("this_folder_needs_to_go/")
puts filepath ==> "another_folder/file.html"
Though that will affect your filepath variable irreversibly.
#partition will also work in a similar manner to #split
filepath = Pathname.new("this_folder_needs_to_go/another_folder/file.html")
file_dir = filepath.partition("this_folder_needs_to_go/")[-1]
file_dir
#=> "another_folder/file.html"
#partition returns [head,sep,tail] so this will look like ["","this_folder_needs_to_go","/another_folder/file.html"] the [-1] says get the last element.

ruby block questions loop variables

comics = load_comics( '/comics.txt' )
Popup.make do
h1 "Comics on the Web"
list do
comics.each do |name, url|
link name, url
end
end
end
I am new to ruby. This is a piece of code from a ruby website.
I cant find what 'link' and 'list' keyword in the menu.
can someone explain it a little bit those two keywords, and where is the definition of those two keyword .
I am also confused on how they read the variables name and url, they are reading it by the space at the same line or what?
so if I have
Comics1 link_of_comics_site_1
Comics2 link_of_comics_site_2
Comics3 link_of_comics_site_3
so for the first iteration, name=Comics1, and url =link_of_comics_site_1
Thanks.
That's not just Ruby. That's a template for a webpage using ruby add-on methods for HTML generation.
But presumably, the result of the call to load_comics is a Hash, where the keys are names and the values are URLs. You could make one of those yourself:
my_comics_hash = { "name1" => "url1", "name2" => "url2" }
which you can then iterate over the same way:
my_comics_hash.each do |name, url|
puts "Name #{name} goes with URL #{url}"
end
In your code, it's building up an HTML list inside a popup window, but it's the same idea. The each method iterates over a collection - in this case a Hash - and runs some code on every item in that collection - in this case, each key/value pair. When you call each, you pass it a block of code inside do ... end; that's the code that gets run on each item. The current item is passed to the code block, which declares a variable to hold it inside the pipes right after the word do. Since we're iterating over key/value pairs, we can declare two variables, and the key goes in the first and the value in the second.
In ruby function, parenthesis is optional and the ";" end of statement is also optional. ej
link "click here" , "http://myweb.com"
is equivalent to :
link("click here", "http://myweb.com");
But If you have more than one statement in a line the ";" is a must, ej
link("click here1", "http://myweb.com"); link("click here2", "http://myweb.com");
In your code it could be written in
link(name, url)
or just
link(name, url);
or
link name, url
But it is highly recommended to put parenthesis around function parameters for readability unless you have other reason . The ";" is not common in ruby world .

Resources