Posts Tagged ‘ruby’

Parse floating point numbers from a string in ruby

Monday, April 11th, 2016

Given a string like "v 1.2 4.2342 8.2 -1.0e14" (e.g., from a .obj file), you could use the following ruby line to extract an ordered list of the contained floating point numbers:

line.scan(/[+-]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?/).collect{|s| s.to_f}

which would produce

=> [1.2, 4.2342, 8.2, 100000000000000.0]

Continuously refresh markdown output

Tuesday, June 17th, 2014

I had a hard time finding a chrome plugin for a rendering markdown which supported LaTeX equations. Instead I’m using multimarkdown which supports equations with mathjax. However, to render the html output I need to open it in Chrome and refresh it when anything changes. So my pipeline looks like:

repeat
  edit .md files
  run multimarkdown command
  open/refresh .html file in chrome
end

I found this nice ruby/applescript script.
I’ve modified it to support markdown files and to run a command when a file changes:

#!/usr/bin/env ruby
# watch.rb by Brett Terpstra, 2011 <http://brettterpstra.com>
# with credit to Carlo Zottmann <https://github.com/carlo/haml-sass-file-watcher>

trap("SIGINT") { exit }

if ARGV.length < 2
  puts "Usage: #{$0} watch_folder keyword command"
  puts "Example: #{$0} . mywebproject"
  exit
end

dev_extension = 'dev'
filetypes = ['css','html','htm','php','rb','erb','less','js','md']
watch_folder = ARGV[0]
keyword = ARGV[1]
command = ARGV[2]
puts "Watching #{watch_folder} and subfolders for changes in project files..."

while true do
  first = true
  while true do
    files = []
    filetypes.each {|type|
      files += Dir.glob( File.join( watch_folder, "**", "*.#{type}" ) )
    }
    new_hash = files.collect {|f| [ f, File.stat(f).mtime.to_i ] }
    hash ||= new_hash
    diff_hash = new_hash - hash
    if not diff_hash.empty?
      if first and not command.empty?
        val=`#{command}`
        first = false
      else
        break
      end
    else
      sleep 1
    end
  end


  unless diff_hash.empty?
    hash = new_hash

    diff_hash.each do |df|
      puts "Detected change in #{df[0]}, refreshing"
      %x{osascript<<ENDGAME
            tell application "Google Chrome"
    set windowList to every window
    repeat with aWindow in windowList
        set tabList to every tab of aWindow
        repeat with atab in tabList
            if (URL of atab contains "#{keyword}") then
                tell atab to reload
            end if
        end repeat
    end repeat
        end tell
ENDGAME
}
    end
    sleep 1
  end

end

Save this in a file watch.rb and then call with something like:

watch.rb . readme "multimarkdown readme.md -o readme.html"

Sort in bash with capital words at the end

Thursday, September 12th, 2013

I wanted to do a sort of some lines in bash but instead of capitals being treated as coming before minuscules I wanted them after. Normally the sort command:

echo -e "Foo\nfoo\nBar\nbang" | sort

will produce:

Bar
Foo
bang
foo

Instead I wanted Bar and Foo to come after bang and foo. To do this I used:

echo -e "Foo\nfoo\nBar\nbang" | \
  ruby -ne 'puts $_.split("").map{|e| (e>="a"?e.upcase():e.downcase())}.join' | \
  sort | \
  ruby -ne 'puts $_.split("").map{|e| (e>="a"?e.upcase():e.downcase())}.join'

which produces

bang
foo
Bar
Foo

Reverse case with a ruby one-liner

Thursday, September 12th, 2013

I needed to reverse the case of every character. I used a ruby one-liner:

echo "FooBar" | ruby -ne 'puts $_.split("").map{|e| (e>="a"?e.upcase():e.downcase())}.join'

Returns

fOObAR

Smoothly parameterized ease curve

Thursday, May 23rd, 2013

Using polynomial ease curves, it’s easy to create a function f(x) which obtains f(0) = 0 and f(1) = 1 as well as reaching 0 derivatives f'(0) = 0, f'(1) = 0, f”(0) = 0, f”(1) = 0, etc. One can start with a simple cubic polynomial: f(x) = 3x²-2x³ which achieves first order smoothness (i.e. f'(0) = 0 and f'(1) = 0. Then we can compose this to have higher and higher continuity f(f(x)), f(f(f(x))). This creates a 9th and 27th order polynomials. Here’s a sequence of repeated composing this cubic function. The title shows the order: polynomial ease curves We can also derive such a smooth, symmetric polynomial ease curve for any order 2*k+1, k in ℕ+ polynomial. Thus with k we can have finer, albeit incremental, control over the shape of the function. Here’s a ruby script to generate a maple script that will generate the necessary coefficients (there must be a pattern here, but I’m too lazy right now to find it):

#!/opt/local/bin/ruby
# Script to generate Maple code for solving for 2*k+1 order polynomial f(x)
# with value f(0) = 0, f(1) = 2 and d<sup>k</sup>f/dx<sup>k</sup>|<sub>0</sub> = 0 d<sup>c</sup>f/dx<sup>c</sup>|<sub>1</sub> = 1, c=1,...,k
smoothness = 3
(1..smoothness).each do |k|
  as = (k+1..2*k+1).map{|c| "a#{c}"}.join(",");
  puts "f := (#{as},x) -> "
  puts "  #{(k+1..2*k+1).map{|c| "a#{c}*x^#{c}"}.join("+")};"
  puts "solve({"
  puts "  f(#{as},0)=0,"
  puts "  f(#{as},1)=1,"
  diffs = (1..k).map do |c|
    "  eval(diff(f(#{as},x),#{(1..c).map{|d| "x"}.join(",")}),x=0)=0,\n"+
    "  eval(diff(f(#{as},x),#{(1..c).map{|d| "x"}.join(",")}),x=1)=0"
  end
  puts "#{diffs.join(",\n")}},"
  puts "  {#{(k+1..2*k+1).map{|c| "a#{c}"}.join(",")}});"
end

Using these coefficients we can plot the first few: polynomial incremental order smoothness ease fit These sequences converge on a scaled and shifted Heaviside step function. But we only have an integer-valued parameter. It’d be nice to have a smooth parameter. If we only cared about this property of the curve getting steeper in the middle as we increase or parameter (while maintaining interpolation and at least C1 continuity, then we could try to do this with a cubic spline. Now we can smoothly increase the steepness, but before reaching the step function the spline curves to far, losing injectivity when treated as a function of x. spline ease curve The fact the we cannot reproduce the Heaviside function with a cubic spline should have been obvious anyway. The Heaviside function is loosely a degree ∞ polynomial, with ∞ smoothness at 0 and 1. We can achieve what we want by taking a function which indeed converges to the Heaviside step function: f(x) = 1/(1+e-2tx). We can adapt this to our unit square domain and enforce interpolation for any k: g(x) = (f(2x-1)-1/2)/(f(1)-1/2)/2+1/2, or in MATLAB:

g = @(x,t) (1./(1+exp(-2*t*(2*x-1)))-1/2)/(1./(1+exp(-2*t*1))-1/2)/2+1/2);

This function behaves pretty nicely for t in (0,∞), going from a linear function to the Heaviside step function: Exponential ease curve To achieve kth order continuity at our endpoints we can just run this function through (i.e. compose with) one of the 2k+1 order polynomials above. That way, with t we smoothly span a whole space of kth order smooth ease curves. For example, if h(x) = 3x²-2x³ then this is h(g(x)): Exponential smooth ease curve

Backup DVD of television show to .mkv files

Sunday, March 3rd, 2013

I bought some DVDs of a german tv show. With my fancy macbook air, I unfortunately have no way to play them: no DVD drive!

So I dusted off my old laptop and installed vobcopy then I copied each dvd first to the old laptop from the disks using:


vobcopy -m

Then I copied these over to my macbook air. But these are just the raw dvd files (VIDEO_TS/*.VOB), which are rather large and unwieldy. To convert these to .mkv files I know to use Handbrake, but since I want to extract each of the 3 or 4 episodes per DVD, setting up Handbrake for each episode turned out to be too tedious. The presets in Handbrake don’t include options to extract all audio channels and all subtitles by default. Instead I found a ruby script call hb.rb which can set up batch jobs.

So finally to extract my episodes with all subtitles and all audio channels in tact I used:

./hb.rb --verbose --input ~/Downloads/IM_ANGESICHT_DES_VERBRECHENS_D2 --output "~/Downloads/#title#_#pos#.mkv" --min-length 00:10:00 --max-length 00:50:00 --skip-duplicates --audio-copy --skip-commentaries --only-first-track-per-language --autocrop

Homonym translator

Sunday, March 13th, 2011

I wrote a little ruby program that accepts a string and translates as many words as it can to homonyms.
Save this in a file called homotranslate.rb:


#!/usr/local/bin/ruby -w

class Homo
  def initialize(filename)
    lines = File.open(filename, "r").readlines;
    homonyms = lines.collect{|e| e.strip.split(' ')};
    @homo_map = Hash.new;
    homonyms.each{|h| h.each{|e| @homo_map[e] = h - [e]; }; };
  end

  def random_translate(str)
    str.gsub(/\w+/) do |word| 
      lw = word.downcase;
  
      if(@homo_map[lw].nil? || word.size == 0)
        word;
      else
        homonym = @homo_map[lw][rand(@homo_map[lw].size)];
        if(word[0] >= 'A'[0] and word[0] <= 'Z'[0])
          homonym.capitalize!
        end
        homonym;
      end
    end
  end
end


# Default main program
if $0 == __FILE__
  homo = Homo.new("homonyms.txt");
  puts homo.random_translate(ARGF.read);
end
__END__

Then run with:


echo "I owe you." | ruby homotranslate.rb

Or just try it online now:


Random homonym translator web app
Source
ASCII list of homonyms, one set per line, space separated

Ruby plus equals (+=) versus append/concatenation shovel (<<)

Wednesday, September 8th, 2010

I was stunned to watch how slow a recent ruby program was. All it was doing was concatenating a bunch of string literals in a big loop. Originally I was using plus equals:


str = ""
1000.times do |i|
  str += "foo bar"
end

On a whim I tried switching to using an array then joining:


str = ""
str_array = []
1000.times do |i|
  str_array << "foo bar"
end
str = str_array.join

Already this was way faster. I wrote up a little benchmarking program to see just how badly "+=" performs compared to "<<". I compare string +=, to the array set up I have above, and just using "<<" on the string:


str = ""
1000.times do |i|
  str << "foo bar"
end

Here's my little test program.


#!/usr/bin/ruby

power = 20

power.times do |p|
  n = 2**p
  str = ""
  start_time = Time.now
  n.times do |i|
    str += "x"
  end
  duration = Time.now - start_time
  #puts "#{n} string appends took: #{duration}s"
  puts "#{n} #{duration}"
end

power.times do |p|
  n = 2**p
  str3 = ""
  start_time = Time.now
  n.times do |i|
    str3 << "x"
  end
  duration = Time.now - start_time
  puts "#{n} #{duration}"
end

power.times do |p|
  n = 2**p
  str2 = ""
  start_time = Time.now
  str_array = []
  n.times do |i|
    str_array << "x"
  end
  str2 = str_array.join
  duration = Time.now - start_time
  puts "#{n} #{duration}"
end

And here are the results:
ruby plus equals vs append

String += is asymptotically worse than <<. Reading through the ruby doc on strings its clear this is because:


str1 += str2

is syntactic sugar for something like


str1 = str1 + str2

whose "=" creates a new string object, hence the big computational cost.

But why?! I can't think of any reason why "+=" shouldn't be syntactic sugar for "<<". Can you? Update:
I get it!
Here's two short snippets that illustrate the difference:


a = "x"
b = a
b += "y"
a

Which results in "x"


a = "x"
b = a
b << "y"
a

Which results in "xy"

It's subjective whether x+=y should mean "append y to x" or always be syntactic sugar for "x = x + y". My vote is for the later, which means I must be content that in Ruby these operators do different things and thus have different speeds.

Music clock

Monday, January 11th, 2010

The music clock is an invisible clock. It tells the time through musical
tones. For now, it reads the hour and the minutes mod 12. Hopefully I will be
able to explore this idea and come up with a universally understandable and
recognizable system.

I use ajax requests and ruby and sox on the backend to make this work.

“Recipe organizer and sharing interface”

Monday, January 4th, 2010


'Recipe organizer and sharing interface' beta screenshot

“Recipe organizer and sharing interface” is a recipe organizer and sharing web interface. It’s the Ruby on Rails app I wrote for my final class project in my senior year of college.

Use the beta version of “Recipe organizer and sharing interface” I’m hosting on a CIMS linux server machine.