I'm trying to build a simple web server with Ruby Sinatra that respond with your current IP + current time (in HTML). It worked perfectly fine, it's just that I'm not sure how to display the output (my current IP and my current Time) into separated lines.
The following is my code:
require 'sinatra'
require 'socket'
addr_infos = Socket.ip_address_list
final_ip = ''
addr_infos.each do |addr_info|
final_ip = final_ip + ' ' + addr_info.ip_address
end
cur_time = Time.now.ctime
get '/' do
'Current Time: ' + cur_time + ', ' + 'Current IP Address: '+ final_ip
end
The output of my code is :
Current Time: Thu May 20 18:02:30 2021, Current IP Address: *IP NUMBER*
Can somebody help me with this? I'm new to Ruby Sinatra. Thanks!
The HTML tag for a line break is <br> which can be used instead of the comma:
get '/' do
'Current Time: ' + cur_time + '<br>' + 'Current IP Address: '+ final_ip
end
You can also use string interpolation:
get '/' do
"Current Time: #{cur_time}<br>Current IP Address: #{final_ip}"
end
Or a heredoc:
get '/' do
<<~HTML
Current Time: #{cur_time}<br>
Current IP Address: #{final_ip}
HTML
end
The line break after <br> is purely cosmetic.
Related
I've got <br> tags in my client's data that I need to replace with '\n\n' in my Rails API for a React Native app.
Sometimes there are spaces before or after the <br> tag, or both.
I'm looking for a gsub to say "any <br> tag, and also include any whitespace before or after it, replace with '\n\n'.
Right now I'm doing:
module ApiHelper
def parse_newlines(string)
string = string.gsub('<br>', '\n\n')
string = string.gsub(' <br>', '\n\n')
string = string.gsub('<br> ', '\n\n')
string = string.gsub(' <br> ', '\n\n')
end
end
Is there something cleaner?
EDIT: Thanks all. I want to accept both Gavin's and the Tin Man's answers...Gavin because he gave me the down and dirty solution, but Tin Man for such a great/in depth explanation on a more robust way using Nokogiri...
2nd EDIT: I take it back. Tin man...using Nokogiri is actually much more readable. Your argument about using regex's in your comment is valid. In the end your code is easier to understand. Giving you the accepted answer, even though I am using Gavin's for now.
This'll do it:
module ApiHelper
def parse_newlines(string)
# Handles <br>, <br/>, <br />
string.gsub(/\s*<br\s*?\/?>\s*/, "\n\n")
end
end
# irb
> parse_newlines(" <br> ")
=> "\n\n"
> parse_newlines(" <br /> ")
=> "\n\n"
> parse_newlines("<br />")
=> "\n\n"
When messing with HTML or XML it's better to use a parser. I'd start with:
require 'nokogiri'
doc = Nokogiri::HTML::DocumentFragment.parse(<<EOT)
<p>this<br>is<br> some <br>
text<br>and<br >some<br/>more</p>
EOT
doc.search('br').each { |br| br.replace("\n\n") }
doc.to_html
# => "<p>this\n" +
# "\n" +
# "is\n" +
# "\n" +
# " some \n" +
# "\n" +
# "\n" +
# "text\n" +
# "\n" +
# "and\n" +
# "\n" +
# "some\n" +
# "\n" +
# "more</p>\n"
Whitespace in HTML displayed by a browser is gobbled by the browser so space runs, or multiple returns will be reduced to a single space or a single line unless you wrap it with <pre> tags or do something similar.
If you absolutely need to strip spaces before and after where you're inserting new-lines, I'd use an extra step:
require 'nokogiri'
doc = Nokogiri::HTML::DocumentFragment.parse(<<EOT)
<p>this<br>is<br> some <br>
text<br>and<br >some<br/>more</p>
EOT
doc.search('p').each do |p|
p.inner_html = p.inner_html.gsub(/ +</, '<').gsub(/> +/, '>')
end
doc.to_html
# => "<p>this<br>is<br>some<br>\n" +
# "text<br>and<br>some<br>more</p>\n"
doc.search('br').each { |br| br.replace("\n\n") }
doc.to_html
# => "<p>this\n" +
# "\n" +
# "is\n" +
# "\n" +
# "some\n" +
# "\n" +
# "\n" +
# "text\n" +
# "\n" +
# "and\n" +
# "\n" +
# "some\n" +
# "\n" +
# "more</p>\n"
Note: Technically, <br> is equivalent to a single "\n", not "\n\n". <p> would be two new-lines because that constitutes a paragraph.
You can try with:
string = 'Lorem <br> Ipsum'
puts string.gsub(/\s(<br>)\s/, '\n\n')
# => Lorem\n\nIpsum
puts string.gsub(/\s(<br>)\s/, "\n\n")
# Lorem
#
# Ipsum
And note the difference between '\n\n' and "\n\n".
module ApiHelper
def parse_newlines(string)
string.gsub(/\s*<br>\s*/, "\n\n")
end
end
Thanks for click on this post, I have a Dashboard powered by Dashing on my RPI 3 where I have add a widget for my camera IP (D-link DSC 4201).
Camera-widget Link
There is the ruby jobs who catch the snapshot.jpeg of my camera :
require 'net/http'
#cameraDelay = 1 # Needed for image sync.
#fetchNewImageEvery = '3s'
#camera1Host = "192.168.0.20" ## CHANGE
#camera1Port = "80" ## CHANGE
#camera1Username = 'admin' ## CHANGE
#camera1Password ='*****'
#camera1URL = "/dms?nowprofileid=1&"
#newFile1 = "assets/images/cameras/snapshot1_new.jpg"
#oldFile1 = "assets/images/cameras/snapshot1_old.jpg"
def fetch_image(host,old_file,new_file, cam_user, cam_pass, cam_url)
`rm #{old_file}`
`mv #{new_file} #{old_file}`
Net::HTTP.start(host) do |http|
req = Net::HTTP::Get.new(cam_url)
if cam_user != "None" ## if username for any particular camera is set to 'None' then assume auth not required.
req.basic_auth cam_user, cam_pass
end
response = http.request(req)
open(new_file, "wb") do |file|
file.write(response.body)
end
end
new_file
end
def make_web_friendly(file)
"/" + File.basename(File.dirname(file)) + "/" + File.basename(file)
end
SCHEDULER.every #fetchNewImageEvery do
new_file1 = fetch_image(#camera1Host,#oldFile1,#newFile1,#camera1Username,#camera1Password,#camera1URL)
if not File.exists?(#newFile1)
warn "Failed to Get Camera Image"
end
send_event('camera1', image: make_web_friendly(#oldFile1))
sleep(#cameraDelay)
send_event('camera1', image: make_web_friendly(new_file1))
end
Actually my jobs display only the first two images (in #oldFile1,#newFile1) and after he was stock in a loop where he display only the first two images catch on my dashing dashboard.
So, I have looked in the /assets and I see my two snapshots.jpg refresh in real time like my jobs as to did it, But the dashing dashboard doesn't display it.
So why the dashboard don't took the refresh image..?
just ran into this issue today. Ended up rewriting things a bit. Pretty sure this is a browser caching issue in that the file name is the same. Just appended the datetime and pushing it seemed to work.
require 'net/http'
require 'open-uri'
#url = 'http://172.1.1.16/image.jpg'
SCHEDULER.every '4s', :first_in => 0 do |job|
`find '/dashing/f12dash/assets/images/cameras/' -type f -mmin +1 -print0 | xargs -0 rm -f`
#currentTime = Time.now.strftime("%Y-%m-%d_%H-%M-%S")
#newFile1 = "assets/images/cameras/snapshot-" + #currentTime + "_new.jpeg"
open(#url, :http_basic_authentication => ['root', 'CamPW']) do |f|
open(#newFile1,'wb') do |file|
file.puts f.read
end
end
send_event('camera1', image: ("/" + File.basename(File.dirname(#newFile1)) + "/" + File.basename(#newFile1)))
end
First of all I've never used ruby and capifony so this question might be very easy for some of you but not for me. I tried to find examples related to my question but couldn't find any or I'm too new to ruby to miss!
When deploying my Symfony app, the value of a particular key in my parameters file should be dynamically appended so, rather than using exact generic value coming from distribution file below:
parameters_prod.yml.dist
parameters:
my_prefix: my_value_prefix_
Straight after deployment, parameters.yml should read like below:
parameters.yml
parameters:
my_prefix: my_value_prefix_8235647895
8235647895 part above is going to be timestamp.
How can I do this?
My current deploy.rb
namespace :mytest do
desc "Upload the parameters.yml"
task :upload_parameters do
origin_file = parameters_dir + "/" + parameters_file if parameters_dir && parameters_file
origin_file_append = parameters_dir + "/" + parameters_file_append if parameters_dir && parameters_file_append
if origin_file && File.exists?(origin_file)
relative_path = "app/config/parameters.yml"
files = [origin_file]
files << origin_file_append if origin_file_append && File.exists?(origin_file_append)
tmp_origin_file = origin_file + '.tmp'
File.open(tmp_origin_file, 'w') do |fo|
files.each do |file|
File.foreach(file) do |li|
fo.puts li
end
end
end
if shared_files && shared_files.include?(relative_path)
destination_file = shared_path + "/" + relative_path
else
destination_file = latest_release + "/" + relative_path
end
try_sudo "mkdir -p #{File.dirname(destination_file)}"
top.upload(tmp_origin_file, destination_file)
File.delete(tmp_origin_file)
end
end
end
I want to programmatically append a single-line of YAML front data to all the source _posts files.
Background: I currently have a Jekyll-powered website that generates its URLs with the following plugin:
require "Date"
module Jekyll
class PermalinkRewriter < Generator
safe true
priority :low
def generate(site)
# Until Jekyll allows me to use :slug, I have to resort to this
site.posts.each do |item|
day_of_year = item.date.yday.to_s
if item.date.yday < 10
day_of_year = '00'+item.date.yday.to_s
elsif item.date.yday < 100
day_of_year = '0'+item.date.yday.to_s
end
item.data['permalink'] = '/archives/' + item.date.strftime('%g') + day_of_year + '-' + item.slug + '.html'
end
end
end
end
end
All this does is generate a URL like /archives/12001-post-title.html, which is the two-digit year (2012), followed by the day of the year on which the post was written (in this case, January 1st).
(Aside: I like this because it essentially creates a UID for every Jekyll post, which can then be sorted by name in the generated _site folder and end up in chronological order).
However, now I want to change the URL scheme for new posts I write, but I don't want this to break all my existing URLs, when the site is generated. So, I need a way to loop through my source _posts folder and append the plugin-generated ULR to each post's YAML data, with the URL: front matter.
I'm at a loss of how to do this. I know how to append lines to a text file with Ruby, but how do I do that for all my _posts files AND have that line contain the URL that would be generated by the plugin?
Et voilĂ ! Tested on Jekyll 2.2.0
module Jekyll
class PermalinkRewriter < Generator
safe true
priority :low
def generate(site)
#site = site
site.posts.each do |item|
if not item.data['permalink']
# complete string from 1 to 999 with leading zeros (0)
# 1 -> 001 - 20 -> 020
day_of_year = item.date.yday.to_s.rjust(3, '0')
file_name = item.date.strftime('%g') + day_of_year + '-' + item.slug + '.html'
permalink = '/archives/' + file_name
item.data['permalink'] = permalink
# get post's datas
post_path = item.containing_dir(#site.source, "")
full_path = File.join(post_path, item.name)
file_yaml = item.data.to_yaml
file_content = item.content
# rewrites the original post with the new Yaml Front Matter and content
# writes 'in stone !'
File.open(full_path, 'w') do |f|
f.puts file_yaml
f.puts '---'
f.puts "\n\n"
f.puts file_content
end
Jekyll.logger.info "Added permalink " + permalink + " to post " + item.name
end
end
end
end
end
I have written a working ruby script using mechanize for fetching my
Stackoverflow reputation and badges
Twitter tweets and followers
and printing the output to screen.
I run this command on the terminal first :
/Users/cyclotrojan/.rvm/rubies/ruby-1.9.2-p290/bin/ruby /Users/cyclotrojan/Desktop/Snippets/get_so_reputation_and_tw_followers.rb
The output is correctly displayed like this on the terminal:
StackOverflow :
Reputation is : 406
Total Badges : 10
Twitter :
Tweets : 1,494
Followers : 137
Now I wish to display the output of my script on my desktop using GeekTools and set refresh time to 30 minutes, so it keeps running the script over and over thus updating my stats. However when I paste the same command on a geektool shell, no output comes.
Here is the script :
File get_so_reputation_and_tw_followers.rb
require 'mechanize'
def get_stackoverflow_data
url_so = 'https://stackoverflow.com/users/898346/cyclotrojan'
begin
so_page = Mechanize.new.get(url_so)
so_reputation = so_page.link_with(:href => "/users/898346/cyclotrojan?tab=reputation").to_s
so_badges = so_page.search(".badgecount").first
print "StackOverflow :" + "\n"
print " Reputation is : " + so_reputation + "\n"
print " Total Badges : " + so_badges + "\n"
rescue
print "StackOverflow :" + "\n"
print "\tReputation is : " + "NA" + "\n"
print "\tTotal Badges : " + "NA" + "\n"
end
end
def get_twitter_data
url_tw = 'https://twitter.com/cyclotrojan'
begin
tw_page = Mechanize.new.get(url_tw)
tw_tweets = tw_page.link_with( :href => "/" + url_tw.split("/").last).to_s.split(" ").first
tw_followers = tw_page.link_with( :href => "/#!/" + url_tw.split("/").last + "/followers").to_s.split(" ").first
print "Twitter :" + "\n"
print "\tTweets : " + tw_tweets + "\n"
print "\tFollowers : " + tw_followers + "\n"
rescue
print "Twitter :" + "\n"
print "\tTweets : " + "NA" + "\n"
print "\tFollowers : " + "NA" + "\n"
end
end # end function
get_stackoverflow_data()
get_twitter_data()
However, the output simply doesnt show up on my desktop. I know that the problem is not with detecting ruby, since I tested it out using another file test.rb
File test.rb
puts "hello"
This command will work on GeekTool shell and display hello correctly :
/Users/cyclotrojan/.rvm/rubies/ruby-1.9.2-p290/bin/ruby /Users/cyclotrojan/Desktop/Snippets/test.rb;
Output on geektool shell:
hello
I have done some debugging and found that if I remove the line
require 'mechanize'
then the script runs correctly and due to exception the following output is displayed :
StackOverflow :
Reputation is : NA
Total Badges : NA
Twitter :
Tweets : NA
Followers : NA
So the issue is with including mechanize in the script. Please help me in resolving this. Thnx !
These questions didnt help :
How to run Ruby scripts in Geektool? ,
Ruby, Mac, Geektool question, file access rights?
You would be able to tell if you didn't try to rescue the error. It looks like our old friend ssl verify error so try this:
#agent = Mechanize.new
#agent.verify_mode = OpenSSL::SSL::VERIFY_NONE
tw_page = #agent.get url_tw
I should add that you might want to make sure you understand the consequences of OpenSSL::SSL::VERIFY_NONE
Also here is a tip:
tweets = tw_page.at('a[#data-element-term="tweet_stats"] strong').text rescue 'N/A'
followers = tw_page.at('a[#data-element-term="follower_stats"] strong').text rescue 'N/A'
puts "Twitter :" + "\n"
puts "\tTweets : #{tweets}"
puts "\tFollowers : #{followers}"