Installing and using third party gem - ruby-on-rails

I found a gem and I want to try it. The procedure of gem connecting is described here (in Russian language).
In which file should I write this code, and how can I use this variable in the view?
require 'builder'
xml = Builder::XmlMarkup.new(target: STDOUT, indent: 2)
xml.person(type: "programmer") do
xml.name do
xml.first "Dave"
xml.last "Thomas"
end
xml.location "Texas"
xml.preference("ruby")
end

Related

Rails Minitest / Capybara - adding system integration test for a JS interface element

I have a Rails app that uses this Ion Slider:
https://github.com/IonDen/ion.rangeSlider
I can test the JS calls that this generates but I figured I would add a system integration test that confirms when the user slides the slider.
To date I have stuck to basic controller tests and very new to Capybara and system integration tests. I think I can do this but honestly no clue where to start when it comes to a JS interface element like this.
Looking for either an example of a test that would do this or a pointer to the docs that I must have missed in my searching.
Currently Capybara doesn't have a driver independent method to drag an element by a specific amount, but does have a driver independent method for dragging one element onto another (drag_to). If that will work for your use case then it would just be something like
slider.drag_to(target)
If instead you need to just drag by some number of pixels then you will need to use driver dependent code (generally a bad idea, but not really any other option here). If using the Selenium driver it would be something like
action_builder = page.driver.browser.action
action.drag_and_drop_by(slider.native, 100, 0)
which should drag the slider element 100 pixels to the right
Below is an example ruby script that demos this behavior, using Chrome, on the ion range slider demo page
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'capybara'
gem 'rexml'
gem 'selenium-webdriver'
gem 'webdrivers'
gem 'byebug'
end
require 'selenium-webdriver'
require "capybara/dsl"
require 'byebug'
%i[selenium_chrome selenium_chrome_headless].each do |driver|
puts "Using #{driver}"
sess = Capybara::Session.new(driver)
sess.visit('http://ionden.com/a/plugins/ion.rangeSlider/demo.html')
first_demo = sess.first('.demo__item')
# Capybara driver independent code
puts "Driver independent:"
sess.within(first_demo) do
slider = sess.find('.irs .irs-single')
slider_max = sess.find('.irs .irs-max')
initial_text = slider.text
puts "initial slider text is #{initial_text}"
slider.drag_to(slider_max) # drag and drop the slider onto the max marker - won't actually be the max value since it drops on the center of the marker
sess.assert_selector('.irs .irs-single') do |el|
# example to show one possible way to synchronize with browser
# will ensure the sliders text has changed
el.text != initial_text
end
puts "new slider text is #{slider.text}"
end
# Selenium driver specific code
puts "Driver specific:"
sess.within(first_demo) do
slider = sess.find('.irs .irs-single')
puts "Current slider text is #{slider.text}"
action = sess.driver.browser.action # get selenium specific action builder
action.drag_and_drop_by(slider.native, -100, 0).perform
puts "Updated slider text is #{slider.text}"
end
end

Ruby Net::IMAP - Attachment Filenames with special characters/umlauts [duplicate]

I have the following header:
From: =?iso-8859-1?Q?Marta_Falc=E3o?= <marta.falcao#example.com.br>
I can easily split out the stuff before the <, which leaves me with
"=?iso-8859-1?Q?Marta_Falc=E3o?="
What can I use to turn this into "Marta Falcão"?
Using the newer Mail gem:
Mail::Encodings.value_decode(str) or
Mail::Encodings.unquote_and_convert_to(str, to_encoding)
Thanks to Roland Illig for his comment, which led me to two options:
install rfc2047-ruby and call Rfc2047.decode(header)
install TMail and call TMail::Unquoter.unquote_and_convert_to(header, 'utf-8') or better yet TMail::Address.parse(header).friendly, the latter of which strips out the <email address> part
Use Ruby to implement RFC 2047 isn't hard:
module Rfc2047
TOKEN = /[\041\043-\047\052\053\055\060-\071\101-\132\134\136\137\141-\176]+/.freeze
ENCODED_TEXT = /[\041-\076\100-\176]+/.freeze
ENCODED_WORD = /=\?(?<charset>#{TOKEN})\?(?<encoding>[QB])\?(?<encoded_text>#{ENCODED_TEXT})\?=/i.freeze
class << self
def encode(input)
"=?#{input.encoding}?B?#{[input].pack('m0')}?="
end
def decode(input)
match_data = ENCODED_WORD.match(input)
raise ArgumentError if match_data.nil?
charset, encoding, encoded_text = match_data.captures
decoded =
case encoding
when 'Q', 'q' then encoded_text.unpack1('M')
when 'B', 'b' then encoded_text.unpack1('m')
end
decoded.force_encoding(charset)
end
end
end
Rfc2047.decode '=?iso-8859-1?Q?Marta_Falc=E3o?=' # => Marta_Falcão
Update
mikel/mail is currently having an encoding issue which might not decode the string correctly.
If that really bothers you, you can try new_rfc_2047:
$ gem install new_rfc_2047
$ ruby -rrfc_2047 -e 'puts Rfc2047.decode "From: =?iso-8859-1?Q?Marta_Falc=E3o?= <marta.falcao#example.com.br>"'
From: Marta Falcão <marta.falcao#example.com.br>
Since the source code of mikel/mail is a little too complicated for me to do the modification, I just made my own gem for this.
Gem source is here: https://github.com/tonytonyjan/rfc_2047/

Replacement for URI.escape that avoids Lint/UriEscapeUnescape warnings?

Not sure how to fix Rubocop's Lint/UriEscapeUnescape warning
Tried replacing URI with CGI thinking that was the "drop in" replacement but that blew up the test suite.
Here's the error followed by the line of code where URI is being used:
app/models/media_file.rb:76:5: W: Lint/UriEscapeUnescape: URI.escape method is obsolete and should not be used. Instead, use CGI.escape, URI.encode_www_form or URI.encode_www_form_component depending on your specific use case.
URI ...
^^^
# app/models/media_file.rb
...
def cdn_url(format: nil)
if format.nil?
"#{s3_config.cloudfront_endpoint}/#{escape_url(key)}"
elsif converted_urls.with_indifferent_access[format.to_s]
filename = converted_urls.with_indifferent_access[format.to_s]
if URI.parse(escape_url(filename)).host
filename
else
"#{s3_config.cloudfront_endpoint}/#{escape_url(filename)}"
end
else
converted(url)
end
end
...
private
def escape_url(url)
URI
.escape(url)
.gsub(/\(/, '%28')
.gsub(/\)/, '%29')
.gsub(/\[/, '%5B')
.gsub(/\]/, '%5D')
end
EDIT: Adding sample output of strings escaped with URI and CGI:
url: images/medium/test-image.jpg
URI.escape(url): images/medium/test-image.jpg
CGI.escape(url): images%2Fmedium%2Ftest-image.jpg
url: images/medium/test-image.jpg
URI.escape(url): images/medium/test-image.jpg
CGI.escape(url): images%2Fmedium%2Ftest-image.jpg
It would appear CGI is not a drop in replacement for URI as the listing error might have you believe. Thoughts?
Encounter with the same problem, got it fixed by using addressable lib.
escaped_query = URI.escape(search,
Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
#W: Lint/UriEscapeUnescape: URI.escape method is obsolete and should not be used. Instead, use CGI.escape, URI.encode_www_form or URI.encode_www_form_component depending on your specific use case.
Solved by:
gem addressable gem in gemspec or Gemfile.
gem 'addressable', '~> 2.7'
require addressable/uri
Add appropriate.
escaped_query = Addressable::URI.encode_component(search, Addressable::URI::CharacterClasses::QUERY)

Edit existing pdf file metadata with ruby (Apply Password protection)

I am uploading a pdf file using paperclip to s3. I want to apply password protection on the fly to the uploaded pdf file.
I tried to use the code given in question How to edit or write on existing PDF with Ruby?! to edit existing pdf file (the tmp file used by the paperclip) and try to apply password protection using
Prawn::Document.generate("tmp/abc.pdf",:template => params[:ebook].path) do encrypt_document(:user_password => 'foo', :owner_password => 'bar',
:permissions => { :print_document => false,
:modify_contents => false,
:copy_contents => false,
:modify_annotations => false } end
Is the template support still exist in prawn or it had been deprecated as i didn't find anything regarding template in the prawn manual! ?
Is there any other way or any other gem to do so ?
Thanks.
template was removed in version 0.13.0 because it was too buggy :
Support for templates was dropped in Prawn 0.13.0, disabled by default in 0.14.0, and extracted in 0.15.0.
This gem includes the extracted templates code, which is completely unsupported, but provides the old functionality that was in Prawn 0.12.0 for years.
source : https://github.com/prawnpdf/prawn-templates
As he said, you can try to add the library to your current Prawn installation.
Otherwise you can use pdftk with Open3 module (http://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/) :
require 'open3'
file_name = 'hello_world_1.pdf' # input
file_name_output = 'hello_world_2.pdf' # output
usr = 'foo'
pwd = 'bar'
pdftek = './pdftk.exe' # tested on windows
Open3.popen3("#{pdftek} #{file_name} output #{file_name_output} owner_pw #{pwd} user_pw #{usr}") do |stdin,stdout,stderr|
# ...
end
There is also a wrapper for ruby but I haven't test it yet : https://github.com/tcocca/active_pdftk

Detect MIME type of uploaded file in Ruby

Is there a bullet proof way to detect MIME type of uploaded file in Ruby or Ruby on Rails? I'm uploading JPEGs and PNGs using SWFupload and content_type is always "application/octet-stream"
The ruby-filemagic gem will do it:
require 'filemagic'
puts FileMagic.new(FileMagic::MAGIC_MIME).file(__FILE__)
# => text/x-ruby; charset=us-ascii
This gem does not look at the file extension at all. It reads a bit of the file contents and uses that to guess the file's type.
In Ruby on Rails you can do:
MIME::Types.type_for("filename.gif").first.content_type # => "image/gif"
You can use this reliable method base on the magic header of the file :
def get_image_extension(local_file_path)
png = Regexp.new("\x89PNG".force_encoding("binary"))
jpg = Regexp.new("\xff\xd8\xff\xe0\x00\x10JFIF".force_encoding("binary"))
jpg2 = Regexp.new("\xff\xd8\xff\xe1(.*){2}Exif".force_encoding("binary"))
case IO.read(local_file_path, 10)
when /^GIF8/
'gif'
when /^#{png}/
'png'
when /^#{jpg}/
'jpg'
when /^#{jpg2}/
'jpg'
else
mime_type = `file #{local_file_path} --mime-type`.gsub("\n", '') # Works on linux and mac
raise UnprocessableEntity, "unknown file type" if !mime_type
mime_type.split(':')[1].split('/')[1].gsub('x-', '').gsub(/jpeg/, 'jpg').gsub(/text/, 'txt').gsub(/x-/, '')
end
end
The ruby-filemagic gem is good solution, but requires additional dependencies on libmagic (recently removed from CarrierWave as part of CarrierWave::MagicMimeTypes removal).
If you're interested in a pure ruby implementation, consider the MimeMagic gem! It works well for file types listed in the freedesktop.org mime database:
require 'mimemagic'
MimeMagic.by_magic(File.open('Table-Flip-Guy.jpg')).type # => "image/jpeg"
For Microsoft Office 2007+ formats (xlsx, docx, and pptx), require the overlay (unless you're okay with the generic "application/zip" MIME type for these files)
require 'mimemagic'
require 'mimemagic/overlay'
MimeMagic.by_magic(File.open('big_spreadsheet.xlsx')).type # => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
filemagic gem is good solution but depends lots of unnecessary gems. (rails, aws-sdk-core, ...)
If your app is small and only runs in Linux or OSX, consider to use file program:
require 'shellwords'
mimetype = `file --brief --mime-type - < #{Shellwords.shellescape(__FILE__)}`.strip
Note: Replace __FILE__ with any expr contains the filepath.
As of 2021, I would claim that the best tool to compute mime types based on all the available hints (magic number, file name when the magic number does not suffice, user hints) is Marcel.
To shamelessly quote the documentation itself:
Marcel::MimeType.for Pathname.new("example.gif")
# => "image/gif"
File.open "example.gif" do |file|
Marcel::MimeType.for file
end
# => "image/gif"
Marcel::MimeType.for Pathname.new("unrecognisable-data"), name: "example.pdf"
# => "application/pdf"
Marcel::MimeType.for extension: ".pdf"
# => "application/pdf"
Marcel::MimeType.for Pathname.new("unrecognisable-data"), name: "example", declared_type: "image/png"
# => "image/png"
Marcel::MimeType.for StringIO.new(File.read "unrecognisable-data")
# => "application/octet-stream"
mimemagic gem will also do it
https://github.com/minad/mimemagic
from the oficial documentation
MimeMagic is a library to detect the mime type of a file by extension
or by content. It uses the mime database provided by freedesktop.org
(see http://freedesktop.org/wiki/Software/shared-mime-info/).
require 'mimemagic'
MimeMagic.by_extension('html').text?
MimeMagic.by_extension('.html').child_of? 'text/plain'
MimeMagic.by_path('filename.txt')
MimeMagic.by_magic(File.open('test.html'))
# etc...
in case you are doing this from scratch, install mimemagic gem
gem 'mimemagic'
open stream(bytes of target image)
url="https://i.ebayimg.com/images/g/rbIAAOSwojpgyQz1/s-l500.jpg"
result = URI.parse(url).open
then check data-stream's file type for example:
MimeMagic.by_magic(result).type == "image/jpeg"
even though as mentioned above
%w(JPEG GIF TIFF PNG).include?(MimeMagic.by_magic(result).type)
this might be more elegant
You can use
Mime::Type.lookup_by_extension(extention_name)
Thanks

Resources