ANSI escape code with html tags in Ruby? - ruby

Interestingly there are built-in ansi escape code in Ruby.
There is also a more powerful version from a gem.
Unfortunately, these logs output to the console. My text is shown in the page so I need HTML tags to wrap around my text.
Would you guys have any idea how to go about it?

I guess what you want is to transform from escape characters to HTML.
I did it once by assuming the following code/colour hash for escape characters:
{ :reset => 0,
:bright => 1,
:dark => 2,
:underline => 4,
:blink => 5,
:negative => 7,
:black => 30,
:red => 31,
:green => 32,
:yellow => 33,
:blue => 34,
:magenta => 35,
:cyan => 36,
:white => 37,
:back_black => 40,
:back_red => 41,
:back_green => 42,
:back_yellow => 43,
:back_blue => 44,
:back_magenta => 45,
:back_cyan => 46,
:back_white => 47}
What I did was the following conversion (far away from being anyhow optimized):
def escape_to_html(data)
{ 1 => :nothing,
2 => :nothing,
4 => :nothing,
5 => :nothing,
7 => :nothing,
30 => :black,
31 => :red,
32 => :green,
33 => :yellow,
34 => :blue,
35 => :magenta,
36 => :cyan,
37 => :white,
40 => :nothing,
41 => :nothing,
43 => :nothing,
44 => :nothing,
45 => :nothing,
46 => :nothing,
47 => :nothing,
}.each do |key, value|
if value != :nothing
data.gsub!(/\e\[#{key}m/,"<span style=\"color:#{value}\">")
else
data.gsub!(/\e\[#{key}m/,"<span>")
end
end
data.gsub!(/\e\[0m/,'</span>')
return data
end
Well, you will need fill the gaps of the colours I am not considering or backgrounds. But I guess you can get the idea.
Hope it helps

Thank you for the link to a cool gem I had not seen. I think what you are looking for, however, is termed Cascading Style Sheets (CSS). Because that google search will bring up about every other page cached on the internet, here are a few links for you that should get you started:
http://www.w3schools.com/css/default.asp - start with the most basic stuff.
http://guides.rubyonrails.org/layouts_and_rendering.html
http://rorrocket.com/ - generalized tutorials
http://nubyonrails.com/articles/dynamic-css - this may or may not be useful but a brief glance might provide some more rails like info on css, including SASS*.
*SASS is a ruby-ized abstraction to CSS used very frequently with ruby/rails

Related

How to count the number of objects created in Ruby

Is it possible to count the total number of objects created in a Ruby application? If so, how can I do it?
I know how to count the number of instances of a given class I create, as of in this post, but is there a way to get the number of objects created of any class in an application (including internal ones)?
You should use
ObjectSpace.count_objects
For example, this is what it outputs on a fresh IRB session:
{
:TOTAL => 30161,
:FREE => 378,
:T_OBJECT => 152,
:T_CLASS => 884,
:T_MODULE => 30,
:T_FLOAT => 4,
:T_STRING => 11517,
:T_REGEXP => 165,
:T_ARRAY => 3395,
:T_HASH => 180,
:T_STRUCT => 2,
:T_BIGNUM => 2,
:T_FILE => 15,
:T_DATA => 1680,
:T_MATCH => 99,
:T_COMPLEX => 1,
:T_NODE => 11620,
:T_ICLASS => 37
}

Stuck on algorithm. words to nums

I'm trying to figure out a homework solution in Ruby. I want the answer obviously but you feel it defeats the purpose if I post it here and someone tells me 'this is how you do it'
I am trying to translate fixnum into English word pronunciations, up until the trillionth sizes. So it handles everything from 0 to 999_999_999_999_999
At first I thought of stacking the string as a FILO queue and simply .pop my way through it with a position 'count' to indicate what 'hundred' or 'thousand ' I am currently to spell out. The words, and denomination are set to class instance global hash values to call and verify as a key.
I'm not sure if it's a stupid question but I'm looking for a way to help me think to understand this small problem.
here's my spaghetti code. an improvement to the orignal of 95+ lines.
class Fixnum
##one_to_teen = {0 => "", 1 => 'one', 2 => "two", 3 => 'three', 4 => "four", 5 => 'five', 6 => 'six', 7=> 'seven', 8 => "eight", 9 => 'nine', 10 => 'ten', 11 => "eleven", 12 => 'twelve', 13 => 'thirteen', 14 => "fourteen", 15 => "fifteen", 16 => 'sixteen', 17 => "seventeen", 18 => "eighteen", 19 => "nineteen"}
##tens = {20 => "twenty", 30 => 'thirty', 40 => 'forty', 50 => 'fifty', 60 => 'sixty', 70 => 'seventy', 80 => 'eighty', 90 => 'ninety'}
##count_flag = {3 => "hundred", 4 => "thousand", 9 => "million", 12 => "billion", 15 => "trillion"}
def in_words
return "zero" if self == 0
return ##one_to_teen[self] if self < 20
#stack up
num_stack = self.to_s.split('')
count = 0
temp_str = ""
in_words_str = ""
final_str = ""
#loop until empty
#i was trying to see if resetting the temp_str after being handle in the if statements helped get rid of the stack being used. not originally part of the logic.
while !num_stack.empty?
#puts num_stack.inspect
temp_str << (num_stack.pop unless num_stack.empty?)
count+=1
if count%4 == 0
in_words_str = "#{##one_to_teen["#{temp_str[temp_str.length-1]}".to_i]} #{##count_flag[count]} "
temp_str = ""
elsif count%3 == 0
if temp_str[temp_str.length-1] != "0"
in_words_str = "#{##one_to_teen["#{temp_str[temp_str.length-1]}".to_i]} #{##count_flag[count]} "
#puts temp_str
end
elsif count%2 == 0
in_words_str = "#{##tens[("#{temp_str[1]}0").to_i]} #{##one_to_teen[check_teens(temp_str).to_i]}"
temp_str = ""
end
final_str = in_words_str + final_str
end
#somewhere in my logic i needed to do this, i was getting double spaces due to concat somewhere. bandaided it for now...
return final_str.strip.gsub(" "," ")
end
def check_teens(temp_str)
#swapping here to get correct "20" or higher wording.
if temp_str.reverse.to_i < 20
#puts temp_str.reverse
return temp_str.reverse
else
return temp_str[0]
end
end
end
If you look at how you say 346,422,378 it's three hundred and forty six million four hundred and twenty two thousand three hundred and seventy eight.
You already have the right idea of mapping the groups of three to ones, tens and hundreds. Those then just get repeated.
So the algorithm might go something like:
Use a hash to map word values to each digits in the ones, tens, and hundreds.
Create another hash that contains "trillion", "billion", etc. position map
Get the number and remove any commas, or other formatting.
Is it zero? Easy, done.
Def a sub_string method which takes a group of three and divides that
into three, using your ones, tens hundred mappings. It could return
and array of the word string for each group.
Def a super_string method that then steps through the array you created
and inserts the appropriate word ('trillion', 'million', etc.) between
the array elements.
return your array using something like arr.join(' ') to get one string.
Here's what I would keep:
edited to comply with original spec
class Fixnum
ONES = {0 => "", 1 => 'one', 2 => "two", 3 => 'three', 4 => "four", 5 => 'five', 6 => 'six', 7=> 'seven', 8 => "eight", 9 => 'nine', 10 => 'ten', 11 => "eleven", 12 => 'twelve', 13 => 'thirteen', 14 => "fourteen", 15 => "fifteen", 16 => 'sixteen', 17 => "seventeen", 18 => "eighteen", 19 => "nineteen"}
TENS = {20 => "twenty", 30 => 'thirty', 40 => 'forty', 50 => 'fifty', 60 => 'sixty', 70 => 'seventy', 80 => 'eighty', 90 => 'ninety'}
COUNTS = {3 => "hundred", 4 => "thousand", 9 => "million", 12 => "billion", 15 => "trillion"}
def self.in_words
#fill in code here that uses the other two methods
end
def num_to_word_array(num)
#chop up your number into the substrings and translate
end
def num_words_join(arr)
#join your array using appropriate words, "billion", "million", etc
#return the final string
end
end
Try to divide it into steps that make sense as methods that can be chained. Post any changes you make and I'll be happy to critique.

scatter_style for drawing a scatter chart using Axlsx gem does not work

I'm using Axlsx gem on rails 4 to draw a scatter plot with marker style. Here's the code that I have:
wb.add_worksheet(:name => "Scatter Chart") do |sheet|
sheet.add_row ["First", 1, 5, 7, 9]
sheet.add_row ["", 1, 25, 49, 81]
sheet.add_row ["Second", 5, 2, 14, 9]
sheet.add_row ["", 5, 10, 15, 20]
sheet.add_chart(Axlsx::ScatterChart, :title => "example 7: Scatter Chart") do |chart|
chart.scatterStyle = :marker
chart.start_at 0, 4
chart.end_at 10, 19
chart.add_series :xData => sheet["B1:E1"], :yData => sheet["B2:E2"], :title => sheet["A1"]
chart.add_series :xData => sheet["B3:E3"], :yData => sheet["B4:E4"], :title => sheet["A3"]
puts chart.scatter_style
end
end
Even though I change the scatterStyle to :marker, the chart is still in lineMarker style. I tried all other possible styles but it does not seem to be working for me. When I print chart.scatterStyle, it gives me "marker" which means the style has been changed, but what I see is again in lineMarker style. Is there something else I should do?

Line not rendering

I am developing some prawn reports and running into an issue where any line I draw with a code like the following will render only in the last page.
horizontal_line(0, 200, :at => y)
It is called once per page.
My code is relatively complex now so I tried to isolate the problem to post here, the isolated code follows
require 'prawn'
a = Prawn::Document.new(:page_size => 'A4', :margin => [20,20,20,20])
a.font('Times-Roman')
a.horizontal_line(10, 400, :at => 140)
a.text_box('Test Text', :size => 50, :at => [2, 100], :width => 400)
puts a.render
For my surprise, it didnĀ“t work even with a single page document. Only the "Test Text" is being rendered. It makes me think I am doing something wrong in the page setup or something like that.
Fond out the problem.
The correct use would be:
require 'prawn'
a = Prawn::Document.new(:page_size => 'A4', :margin => [20,20,20,20])
a.font('Times-Roman')
a.stroke do
a.horizontal_line(10, 400, :at => 140)
end
a.text_box('Test Text', :size => 50, :at => [2, 100], :width => 400)
puts a.render

Ruby Array group and average by hour

We get our data from a sensor which records and stores data like hashes.
At any time it measures a few stuff like that:
{:temperature => 30, :pression => 100, :recorded_at => 14:34:23}
{:temperature => 30, :pression => 101, :recorded_at => 14:34:53}
{:temperature => 31, :pression => 102, :recorded_at => 14:34:24}
{:temperature => 30, :pression => 101, :recorded_at => 14:34:55}
{:temperature => 30, :pression => 102, :recorded_at => 14:34:25}
{:temperature => 31, :pression => 101, :recorded_at => 14:34:56}
We need to be able to export that data on a JSON format, but we have way too much data (the sensor records about every 30 seconds) and we need to remove some of the data. Ideally we'd want to export 1 measure per hour in the last 24 hours so we have something like
{0 => {:temperature => 30, :pression => 100}, 1 => {:temperature => 30, :pression => 100}, 2 => {:temperature => 30, :pression => 100}, 3 => {:temperature => 30, :pression => 100}, 4 => {:temperature => 30, :pression => 100}}
For each hour, the temperature is the average of all temperatures measured within that hour.
Also, if for any reason some data is missing for 1hour, I'd like to to extrapolate it by being the mean between the previous and next hour. Anybody can help?
More functional version (with simple interpolation of missing values)
probs = [{:temperature => .. }] # array of measurings
def average(list, key)
list.reduce(0){|acc,el| acc+el[key]} / list.length unless list.empty
end
prob_groups = probs.group_by{|prob| prob[:recorded_at][0,2].to_i}
average_groups = prob_groups.map do |hour,prob_group|
{ hour => {
:temperature => average(prob_group, :temperature),
:pression => average(prob_group, :pression)
}}
end.reduce{|acc,el| acc.merge(el)}
def interpolate(p, n, key)
(p[key] + n[key])/2 unless p.nil? || n.nil? || p[key].nil? || n[key].nil?
end
resuls = (1..24).map do |hour|
if average_groups[hour]
{ hour => average_groups[hour] }
else
{ hour => {
:temperature => interpolate(average_groups[hour-1], average_groups[hour+1], :temperature),
:pression => interpolate(average_groups[hour-1], average_groups[hour+1], :pression)
}}
end
end.reduce{|acc,el| acc.merge(el)}
Hope it works
something like this
t = [....] - array of measurings
result = {}
(1..24).each do|hour|
# measurings of given hour
measurings = t.select{|measuring| measuring[:recorded_at][0, 2].to_i == hour}
# average temperature of hour
sum = measurings.inject(0){|sum, measuring| sum + measuring[:temperature].to_i}
average_temperature = (measurings.length == 0)? nil: sum/measurings.length.to_f
result[hour] = average_temperature
end
If you are not interested on the history but only on an approximation of actual value(s), consider to use a "moving metric" (http://en.wikipedia.org/wiki/Moving_average).

Resources