JSON file parse error from delete_user method - ruby

I have a program that saves to a JSON file, this is my first attempt with a JSON file so I apologize if this is a very simple question.
I have a method inside of my program that parses the JSON file and deletes the information that is given by the user, called delete_user. While parsing the file from the delete_user method I get the error:
C:/Ruby22/lib/ruby/2.2.0/json/common.rb:155:in `parse': 776: unexpected token at
'users.json' (JSON::ParserError)
from C:/Ruby22/lib/ruby/2.2.0/json/common.rb:155:in `parse'
from usertool.rb:35:in `delete_user'
from usertool.rb:15:in `menu'
from usertool.rb:66:in `<main>'
I understand that the error is telling me my JSON file isn't parsing, but what I don't understand is why..
The delete_user method that the error is coming from:
def delete_user
hash = JSON.parse('users.json')
delete_data = prompt("Enter username:")
delete_data[:username] = "#{username}"
delete_data.delete[:email_address, :member_status]
new_json = delete_data.to_json
delete_user if restart
end
Is there a issue with how I'm parsing the file, am I doing it wrong? Or is there another issue that's going way over my head?
And here's an example of the JSON file:
{"username":"TEST1","email_address":"TEST1","member_status":"TEST1"}

TR;DL:
This will work:
JSON.parse(File.read('file-name-to-be-read.json'))
Why?
json.parse [string] parses plain JSON, but doesn't load a file. Instead, pass it a file object, and it will read the JSON inside of it.
JSON Is A String
JSON is a way of encoding objects to a string - it is based on how javascript objects are defined (JavaScript-Option-Notation). It's a string - not a file saver, which means you can use it in more applications, like API's, along with saving data to files.

Related

How do I get the file metadata from an AWS S3 file with Ruby?

I'm trying to simply retrieve the meta data from a file uploaded to S3. Specifically I need to the content type.
I know the file has metadata, because I can see it in S3 console. But I'm unable to get it programmatically. I must have some syntax error.
See the code below, the file.key returns the file name correctly. But the file.metadata doesn't seem to return an array with data.
s3 = Aws::S3::Resource.new(region: ENV['REGION'])
file = s3.bucket(sourceS3Bucket).object(sourceS3Key)
puts file.key # this works!
puts file.metadata # this returns an empty array {}
puts file.metadata['content-type'] # empty
As Aleksei Matiushkin suggested file.data[:content_type] will give the file type.

How to declare a ruby constant (RMagick) in a YAML file

I am looking for a possibility to declare a Magick::StyleType constant in a .yml file and then to load this constant into a ruby file.
Or if that's not possible then I need to know how to convert a String into a Magick::StyleType constant in ruby.
Here are the details:
I am trying to write a ruby program, which places some text on a picture and I use the RMagick interface for it.
In my ruby program I have a method which specifies different properties of the text like font-family or font-style. This method includes the line:
self.font_style = ItalicStyle
Now I want to store all changeable parameters in a YAML-config file (config.yml), so this config.yml includes these lines:
#font style (like bold, italic and so on)
:font_style: ItalicStyle
Now I load the config.yml in my ruby file and the above mentioned line in my method reads now
self.font_style = config_file[:font_style]
When I run my ruby file now I get the error message:
`font_style=': wrong enumeration type - expected Magick::StyleType, got String (TypeError)
So after having searched a little about the topic I changed my config.yml first to
:font_style: !/ruby/constant ItalicStyle
which got me the same error message as above and then I tried this:
:font_style: !/ruby/symbol :ItalicStyle
and got this error message:
`font_style=': wrong enumeration type - expected Magick::StyleType, got Symbol (TypeError)
Then I checked in irb:
require 'rmagick' => true
Magick.const_get(ItalicStyle) => ItalicStyle=2
Magick.const_get(ItalicStyle).class => Magick::StyleType
So, finally I get to my question: How do I need to change the line
:font_style: !/ruby/symbol :ItalicStyle
in my config.yml file so that when loaded into my ruby file ItalicStyle will be recognized as a Magick::StyleType constant?
Or when I leave
:font_style: ItalicStyle
in the config.yml and load the ItalicStyle as a String into my ruby file: is there a possibility, to convert ItalicStyle from a String to the Magick:StyleType constant in the ruby file directly?
I would be really happy if someone could help. I have tried for days to find a solution and I really need it for my project.
I would just store a String in the YAML file, because that is easier to write and to read:
:font_style: ItalicStyle
Than I would get the constant by its name to configure Magick:
self.font_style = Object.const_get(config_file[:font_style])

Error in reading YAML in ruby, what to do when the header is missing?

I have a markdown file which should have a YAML front matter in it (a Jekyll post file). I read the YAML part of the file with
yaml = YAML.load_file(filename)
Now when the file contains the YAML part no problem, otherwise exits with an error.
My question is: how do you handle this error in ruby such that the program notifies me of the missing header but still continues to execute the rest of the code?
This might work.
begin
yaml = YAML.load_file(filename)
rescue
#log or notification code here
end

how to convert data URI to file in Ruby

How do I convert a data URI that comes from the result of the FileReader API into an image file that can be saved in the file system in Ruby?
What I'm currently trying to do is using base64 decode to convert the data_uri string which looks like this: data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgA... into base 64 encoded string because according to this stackoverflow answer I need to replace all the instances of spaces into +. The answer is in PHP but I'm currently working on Ruby and Sinatra so I'm not sure if it still applies, but when using the equivalent code:
src = data_uri.gsub! ' ', '+'
src = Base64.decode64(src)
f = File.new('uploads/' + 'sample.png', "w")
f.write(src)
f.close
I get the following error:
undefined method `unpack' for nil:NilClass
What I'm trying to achieve here is to be able to convert the data URI to a file.
There's no need to reinvent the wheel. Use the data_uri gem.
require 'data_uri'
uri = URI::Data.new('data:image/gif;base64,...')
File.write('uploads/file.jpg', uri.data)

How to get a filename from an IO object in ruby

In ruby...
I have an IO object created by an external process, which I need to get the file name from.
However I only seem to be able to get the File descriptor (3), which is not very useful to me.
Is there a way to get the filename from this object or even to get a File Object?
I am getting the IO object from notifier. So this may be a way of getting the file path as well?
There is a similar question on how to get a the filename in C, I will present here the answer to this question in a ruby way.
Getting the filename in Linux
Suppose io is your IO Object. The following code gives you the filename.
File.readlink("/proc/self/fd/#{io.fileno}")
This does not work for example if the file was removed after the io object was created for it. With this solution you have the filename, but not an File object.
Getting a File object which does not know the filename
The method IO#for_fd can create an IO and it's subclasses for any given integer filedescriptor. Your get your File object for your fd by doing:
File.for_fd(io.fileno)
Unfortunely this File object does not know the filename.
File.for_fd(io.fileno).path # => nil
I scanned through the ruby-1.9.2 sources. There seems to be no way in pure ruby to manipulate the path after the file object was created.
Getting a File object which does know the filename
An extension to ruby can be created in C which first calls File#for_fd and afterwards manipulates the Files internal data structures. This sourcecode does work for ruby-1.9.2, for other versions of ruby it may has to be adjustet.
#include "ruby.h"
#include "ruby/io.h"
VALUE file_fd_filename(VALUE self, VALUE fd, VALUE filename) {
VALUE file= rb_funcall3(self, rb_intern("for_fd"), 1, &fd);
rb_io_t *fptr= RFILE(rb_io_taint_check(file))->fptr;
fptr->pathv= rb_str_dup(filename);
return file;
}
void Init_filename() {
rb_define_singleton_method(rb_cFile, "for_fd_with_filename", file_fd_filename, 2);
}
Now you can do after compiling:
require "./filename"
f= File.for_fd_with_filename(io.fileno, File.readlink("/proc/self/fd/#{io.fileno}"))
f.path # => the filename
The readlink could also be put into the File#for_fd_with_filename definiton. This examples is just to show how it works.
If you are sure that the IO object represents a File you could try something like this
path = io.path if io.respond_to?(:path)
See documentation for File#path

Resources